wine-staging/patches/vkd3d-latest/0001-Updated-vkd3d-to-5c917552c927835c6f446dbecf1aa6ff2cc.patch
2024-03-06 16:04:05 +11:00

19888 lines
835 KiB
Diff

From 481cf752dacf2a815b265a9a79175e7dde8207ca Mon Sep 17 00:00:00 2001
From: Alistair Leslie-Hughes <leslie_alistair@hotmail.com>
Date: Fri, 8 Dec 2023 13:21:19 +1100
Subject: [PATCH] Updated vkd3d to 5c917552c927835c6f446dbecf1aa6ff2cc30cbe.
---
libs/vkd3d/Makefile.in | 1 +
libs/vkd3d/include/private/list.h | 270 ++
libs/vkd3d/include/private/rbtree.h | 378 +++
libs/vkd3d/include/private/vkd3d_common.h | 51 +-
libs/vkd3d/include/private/vkd3d_debug.h | 27 +
libs/vkd3d/include/private/vkd3d_test.h | 430 +++
libs/vkd3d/include/vkd3d_d3d9types.h | 237 ++
libs/vkd3d/include/vkd3d_d3dcompiler.h | 97 +
libs/vkd3d/include/vkd3d_d3dcompiler_types.h | 45 +
libs/vkd3d/include/vkd3d_shader.h | 38 +-
libs/vkd3d/include/vkd3d_utils.h | 128 +
libs/vkd3d/include/vkd3d_windows.h | 289 ++
libs/vkd3d/libs/vkd3d-common/blob.c | 8 +-
libs/vkd3d/libs/vkd3d-common/debug.c | 6 +-
libs/vkd3d/libs/vkd3d-shader/d3d_asm.c | 237 +-
libs/vkd3d/libs/vkd3d-shader/d3dbc.c | 128 +-
libs/vkd3d/libs/vkd3d-shader/dxbc.c | 38 +-
libs/vkd3d/libs/vkd3d-shader/dxil.c | 2521 +++++++++++++++--
libs/vkd3d/libs/vkd3d-shader/fx.c | 515 ++++
libs/vkd3d/libs/vkd3d-shader/glsl.c | 6 +-
libs/vkd3d/libs/vkd3d-shader/hlsl.c | 103 +-
libs/vkd3d/libs/vkd3d-shader/hlsl.h | 38 +-
libs/vkd3d/libs/vkd3d-shader/hlsl.l | 1 +
libs/vkd3d/libs/vkd3d-shader/hlsl.y | 352 ++-
libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c | 216 +-
libs/vkd3d/libs/vkd3d-shader/ir.c | 2492 ++++++++++++++--
libs/vkd3d/libs/vkd3d-shader/spirv.c | 1840 ++++++------
libs/vkd3d/libs/vkd3d-shader/tpf.c | 183 +-
.../libs/vkd3d-shader/vkd3d_shader_main.c | 171 +-
.../libs/vkd3d-shader/vkd3d_shader_private.h | 264 +-
libs/vkd3d/libs/vkd3d/command.c | 100 +-
libs/vkd3d/libs/vkd3d/device.c | 727 +++--
libs/vkd3d/libs/vkd3d/resource.c | 163 +-
libs/vkd3d/libs/vkd3d/state.c | 72 +-
libs/vkd3d/libs/vkd3d/utils.c | 24 +-
libs/vkd3d/libs/vkd3d/vkd3d_main.c | 34 +-
libs/vkd3d/libs/vkd3d/vkd3d_private.h | 120 +-
37 files changed, 10153 insertions(+), 2197 deletions(-)
create mode 100644 libs/vkd3d/include/private/list.h
create mode 100644 libs/vkd3d/include/private/rbtree.h
create mode 100644 libs/vkd3d/include/private/vkd3d_test.h
create mode 100644 libs/vkd3d/include/vkd3d_d3d9types.h
create mode 100644 libs/vkd3d/include/vkd3d_d3dcompiler.h
create mode 100644 libs/vkd3d/include/vkd3d_d3dcompiler_types.h
create mode 100644 libs/vkd3d/include/vkd3d_utils.h
create mode 100644 libs/vkd3d/include/vkd3d_windows.h
create mode 100644 libs/vkd3d/libs/vkd3d-shader/fx.c
diff --git a/libs/vkd3d/Makefile.in b/libs/vkd3d/Makefile.in
index dbc10594f62..448e9a0e61d 100644
--- a/libs/vkd3d/Makefile.in
+++ b/libs/vkd3d/Makefile.in
@@ -17,6 +17,7 @@ SOURCES = \
libs/vkd3d-shader/d3dbc.c \
libs/vkd3d-shader/dxbc.c \
libs/vkd3d-shader/dxil.c \
+ libs/vkd3d-shader/fx.c \
libs/vkd3d-shader/glsl.c \
libs/vkd3d-shader/hlsl.c \
libs/vkd3d-shader/hlsl.l \
diff --git a/libs/vkd3d/include/private/list.h b/libs/vkd3d/include/private/list.h
new file mode 100644
index 00000000000..2e1d95f3fd4
--- /dev/null
+++ b/libs/vkd3d/include/private/list.h
@@ -0,0 +1,270 @@
+/*
+ * Linked lists support
+ *
+ * Copyright (C) 2002 Alexandre Julliard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __WINE_SERVER_LIST_H
+#define __WINE_SERVER_LIST_H
+
+#include <stddef.h>
+
+struct list
+{
+ struct list *next;
+ struct list *prev;
+};
+
+/* Define a list like so:
+ *
+ * struct gadget
+ * {
+ * struct list entry; <-- doesn't have to be the first item in the struct
+ * int a, b;
+ * };
+ *
+ * static struct list global_gadgets = LIST_INIT( global_gadgets );
+ *
+ * or
+ *
+ * struct some_global_thing
+ * {
+ * struct list gadgets;
+ * };
+ *
+ * list_init( &some_global_thing->gadgets );
+ *
+ * Manipulate it like this:
+ *
+ * list_add_head( &global_gadgets, &new_gadget->entry );
+ * list_remove( &new_gadget->entry );
+ * list_add_after( &some_random_gadget->entry, &new_gadget->entry );
+ *
+ * And to iterate over it:
+ *
+ * struct gadget *gadget;
+ * LIST_FOR_EACH_ENTRY( gadget, &global_gadgets, struct gadget, entry )
+ * {
+ * ...
+ * }
+ *
+ */
+
+/* add an element after the specified one */
+static inline void list_add_after( struct list *elem, struct list *to_add )
+{
+ to_add->next = elem->next;
+ to_add->prev = elem;
+ elem->next->prev = to_add;
+ elem->next = to_add;
+}
+
+/* add an element before the specified one */
+static inline void list_add_before( struct list *elem, struct list *to_add )
+{
+ to_add->next = elem;
+ to_add->prev = elem->prev;
+ elem->prev->next = to_add;
+ elem->prev = to_add;
+}
+
+/* add element at the head of the list */
+static inline void list_add_head( struct list *list, struct list *elem )
+{
+ list_add_after( list, elem );
+}
+
+/* add element at the tail of the list */
+static inline void list_add_tail( struct list *list, struct list *elem )
+{
+ list_add_before( list, elem );
+}
+
+/* remove an element from its list */
+static inline void list_remove( struct list *elem )
+{
+ elem->next->prev = elem->prev;
+ elem->prev->next = elem->next;
+}
+
+/* get the next element */
+static inline struct list *list_next( const struct list *list, const struct list *elem )
+{
+ struct list *ret = elem->next;
+ if (elem->next == list) ret = NULL;
+ return ret;
+}
+
+/* get the previous element */
+static inline struct list *list_prev( const struct list *list, const struct list *elem )
+{
+ struct list *ret = elem->prev;
+ if (elem->prev == list) ret = NULL;
+ return ret;
+}
+
+/* get the first element */
+static inline struct list *list_head( const struct list *list )
+{
+ return list_next( list, list );
+}
+
+/* get the last element */
+static inline struct list *list_tail( const struct list *list )
+{
+ return list_prev( list, list );
+}
+
+/* check if a list is empty */
+static inline int list_empty( const struct list *list )
+{
+ return list->next == list;
+}
+
+/* initialize a list */
+static inline void list_init( struct list *list )
+{
+ list->next = list->prev = list;
+}
+
+/* count the elements of a list */
+static inline unsigned int list_count( const struct list *list )
+{
+ unsigned count = 0;
+ const struct list *ptr;
+ for (ptr = list->next; ptr != list; ptr = ptr->next) count++;
+ return count;
+}
+
+/* move all elements from src to before the specified element */
+static inline void list_move_before( struct list *dst, struct list *src )
+{
+ if (list_empty(src)) return;
+
+ dst->prev->next = src->next;
+ src->next->prev = dst->prev;
+ dst->prev = src->prev;
+ src->prev->next = dst;
+ list_init(src);
+}
+
+/* move all elements from src to after the specified element */
+static inline void list_move_after( struct list *dst, struct list *src )
+{
+ if (list_empty(src)) return;
+
+ dst->next->prev = src->prev;
+ src->prev->next = dst->next;
+ dst->next = src->next;
+ src->next->prev = dst;
+ list_init(src);
+}
+
+/* move all elements from src to the head of dst */
+static inline void list_move_head( struct list *dst, struct list *src )
+{
+ list_move_after( dst, src );
+}
+
+/* move all elements from src to the tail of dst */
+static inline void list_move_tail( struct list *dst, struct list *src )
+{
+ list_move_before( dst, src );
+}
+
+/* move the slice of elements from begin to end inclusive to the head of dst */
+static inline void list_move_slice_head( struct list *dst, struct list *begin, struct list *end )
+{
+ struct list *dst_next = dst->next;
+ begin->prev->next = end->next;
+ end->next->prev = begin->prev;
+ dst->next = begin;
+ dst_next->prev = end;
+ begin->prev = dst;
+ end->next = dst_next;
+}
+
+/* move the slice of elements from begin to end inclusive to the tail of dst */
+static inline void list_move_slice_tail( struct list *dst, struct list *begin, struct list *end )
+{
+ struct list *dst_prev = dst->prev;
+ begin->prev->next = end->next;
+ end->next->prev = begin->prev;
+ dst_prev->next = begin;
+ dst->prev = end;
+ begin->prev = dst_prev;
+ end->next = dst;
+}
+
+/* iterate through the list */
+#define LIST_FOR_EACH(cursor,list) \
+ for ((cursor) = (list)->next; (cursor) != (list); (cursor) = (cursor)->next)
+
+/* iterate through the list, with safety against removal */
+#define LIST_FOR_EACH_SAFE(cursor, cursor2, list) \
+ for ((cursor) = (list)->next, (cursor2) = (cursor)->next; \
+ (cursor) != (list); \
+ (cursor) = (cursor2), (cursor2) = (cursor)->next)
+
+/* iterate through the list using a list entry */
+#define LIST_FOR_EACH_ENTRY(elem, list, type, field) \
+ for ((elem) = LIST_ENTRY((list)->next, type, field); \
+ &(elem)->field != (list); \
+ (elem) = LIST_ENTRY((elem)->field.next, type, field))
+
+/* iterate through the list using a list entry, with safety against removal */
+#define LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, list, type, field) \
+ for ((cursor) = LIST_ENTRY((list)->next, type, field), \
+ (cursor2) = LIST_ENTRY((cursor)->field.next, type, field); \
+ &(cursor)->field != (list); \
+ (cursor) = (cursor2), \
+ (cursor2) = LIST_ENTRY((cursor)->field.next, type, field))
+
+/* iterate through the list in reverse order */
+#define LIST_FOR_EACH_REV(cursor,list) \
+ for ((cursor) = (list)->prev; (cursor) != (list); (cursor) = (cursor)->prev)
+
+/* iterate through the list in reverse order, with safety against removal */
+#define LIST_FOR_EACH_SAFE_REV(cursor, cursor2, list) \
+ for ((cursor) = (list)->prev, (cursor2) = (cursor)->prev; \
+ (cursor) != (list); \
+ (cursor) = (cursor2), (cursor2) = (cursor)->prev)
+
+/* iterate through the list in reverse order using a list entry */
+#define LIST_FOR_EACH_ENTRY_REV(elem, list, type, field) \
+ for ((elem) = LIST_ENTRY((list)->prev, type, field); \
+ &(elem)->field != (list); \
+ (elem) = LIST_ENTRY((elem)->field.prev, type, field))
+
+/* iterate through the list in reverse order using a list entry, with safety against removal */
+#define LIST_FOR_EACH_ENTRY_SAFE_REV(cursor, cursor2, list, type, field) \
+ for ((cursor) = LIST_ENTRY((list)->prev, type, field), \
+ (cursor2) = LIST_ENTRY((cursor)->field.prev, type, field); \
+ &(cursor)->field != (list); \
+ (cursor) = (cursor2), \
+ (cursor2) = LIST_ENTRY((cursor)->field.prev, type, field))
+
+/* macros for statically initialized lists */
+#undef LIST_INIT
+#define LIST_INIT(list) { &(list), &(list) }
+
+/* get pointer to object containing list element */
+#undef LIST_ENTRY
+#define LIST_ENTRY(elem, type, field) \
+ ((type *)((char *)(elem) - offsetof(type, field)))
+
+#endif /* __WINE_SERVER_LIST_H */
diff --git a/libs/vkd3d/include/private/rbtree.h b/libs/vkd3d/include/private/rbtree.h
new file mode 100644
index 00000000000..b5d38bca54c
--- /dev/null
+++ b/libs/vkd3d/include/private/rbtree.h
@@ -0,0 +1,378 @@
+/*
+ * Red-black search tree support
+ *
+ * Copyright 2009 Henri Verbeet
+ * Copyright 2009 Andrew Riedi
+ * Copyright 2016 Jacek Caban for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __WINE_WINE_RBTREE_H
+#define __WINE_WINE_RBTREE_H
+
+#define RB_ENTRY_VALUE(element, type, field) \
+ ((type *)((char *)(element) - offsetof(type, field)))
+
+struct rb_entry
+{
+ struct rb_entry *parent;
+ struct rb_entry *left;
+ struct rb_entry *right;
+ unsigned int flags;
+};
+
+typedef int (*rb_compare_func)(const void *key, const struct rb_entry *entry);
+
+struct rb_tree
+{
+ rb_compare_func compare;
+ struct rb_entry *root;
+};
+
+typedef void (rb_traverse_func)(struct rb_entry *entry, void *context);
+
+#define RB_FLAG_RED 0x1
+
+static inline int rb_is_red(struct rb_entry *entry)
+{
+ return entry && (entry->flags & RB_FLAG_RED);
+}
+
+static inline void rb_rotate_left(struct rb_tree *tree, struct rb_entry *e)
+{
+ struct rb_entry *right = e->right;
+
+ if (!e->parent)
+ tree->root = right;
+ else if (e->parent->left == e)
+ e->parent->left = right;
+ else
+ e->parent->right = right;
+
+ e->right = right->left;
+ if (e->right) e->right->parent = e;
+ right->left = e;
+ right->parent = e->parent;
+ e->parent = right;
+}
+
+static inline void rb_rotate_right(struct rb_tree *tree, struct rb_entry *e)
+{
+ struct rb_entry *left = e->left;
+
+ if (!e->parent)
+ tree->root = left;
+ else if (e->parent->left == e)
+ e->parent->left = left;
+ else
+ e->parent->right = left;
+
+ e->left = left->right;
+ if (e->left) e->left->parent = e;
+ left->right = e;
+ left->parent = e->parent;
+ e->parent = left;
+}
+
+static inline void rb_flip_color(struct rb_entry *entry)
+{
+ entry->flags ^= RB_FLAG_RED;
+ entry->left->flags ^= RB_FLAG_RED;
+ entry->right->flags ^= RB_FLAG_RED;
+}
+
+static inline struct rb_entry *rb_head(struct rb_entry *iter)
+{
+ if (!iter) return NULL;
+ while (iter->left) iter = iter->left;
+ return iter;
+}
+
+static inline struct rb_entry *rb_next(struct rb_entry *iter)
+{
+ if (iter->right) return rb_head(iter->right);
+ while (iter->parent && iter->parent->right == iter) iter = iter->parent;
+ return iter->parent;
+}
+
+static inline struct rb_entry *rb_postorder_head(struct rb_entry *iter)
+{
+ if (!iter) return NULL;
+
+ for (;;) {
+ while (iter->left) iter = iter->left;
+ if (!iter->right) return iter;
+ iter = iter->right;
+ }
+}
+
+static inline struct rb_entry *rb_postorder_next(struct rb_entry *iter)
+{
+ if (!iter->parent) return NULL;
+ if (iter == iter->parent->right || !iter->parent->right) return iter->parent;
+ return rb_postorder_head(iter->parent->right);
+}
+
+/* iterate through the tree */
+#define RB_FOR_EACH(cursor, tree) \
+ for ((cursor) = rb_head((tree)->root); (cursor); (cursor) = rb_next(cursor))
+
+/* iterate through the tree using a tree entry */
+#define RB_FOR_EACH_ENTRY(elem, tree, type, field) \
+ for ((elem) = RB_ENTRY_VALUE(rb_head((tree)->root), type, field); \
+ (elem) != RB_ENTRY_VALUE(0, type, field); \
+ (elem) = RB_ENTRY_VALUE(rb_next(&elem->field), type, field))
+
+/* iterate through the tree using using postorder, making it safe to free the entry */
+#define RB_FOR_EACH_DESTRUCTOR(cursor, cursor2, tree) \
+ for ((cursor) = rb_postorder_head((tree)->root); \
+ (cursor) && (((cursor2) = rb_postorder_next(cursor)) || 1); \
+ (cursor) = (cursor2))
+
+/* iterate through the tree using a tree entry and postorder, making it safe to free the entry */
+#define RB_FOR_EACH_ENTRY_DESTRUCTOR(elem, elem2, tree, type, field) \
+ for ((elem) = RB_ENTRY_VALUE(rb_postorder_head((tree)->root), type, field); \
+ (elem) != WINE_RB_ENTRY_VALUE(0, type, field) \
+ && (((elem2) = RB_ENTRY_VALUE(rb_postorder_next(&(elem)->field), type, field)) || 1); \
+ (elem) = (elem2))
+
+
+static inline void rb_postorder(struct rb_tree *tree, rb_traverse_func *callback, void *context)
+{
+ struct rb_entry *iter, *next;
+ RB_FOR_EACH_DESTRUCTOR(iter, next, tree) callback(iter, context);
+}
+
+static inline void rb_init(struct rb_tree *tree, rb_compare_func compare)
+{
+ tree->compare = compare;
+ tree->root = NULL;
+}
+
+static inline void rb_for_each_entry(struct rb_tree *tree, rb_traverse_func *callback, void *context)
+{
+ struct rb_entry *iter;
+ RB_FOR_EACH(iter, tree) callback(iter, context);
+}
+
+static inline void rb_clear(struct rb_tree *tree, rb_traverse_func *callback, void *context)
+{
+ /* Note that we use postorder here because the callback will likely free the entry. */
+ if (callback) rb_postorder(tree, callback, context);
+ tree->root = NULL;
+}
+
+static inline void rb_destroy(struct rb_tree *tree, rb_traverse_func *callback, void *context)
+{
+ rb_clear(tree, callback, context);
+}
+
+static inline struct rb_entry *rb_get(const struct rb_tree *tree, const void *key)
+{
+ struct rb_entry *entry = tree->root;
+ while (entry)
+ {
+ int c = tree->compare(key, entry);
+ if (!c) return entry;
+ entry = c < 0 ? entry->left : entry->right;
+ }
+ return NULL;
+}
+
+static inline int rb_put(struct rb_tree *tree, const void *key, struct rb_entry *entry)
+{
+ struct rb_entry **iter = &tree->root, *parent = tree->root;
+
+ while (*iter)
+ {
+ int c;
+
+ parent = *iter;
+ c = tree->compare(key, parent);
+ if (!c) return -1;
+ else if (c < 0) iter = &parent->left;
+ else iter = &parent->right;
+ }
+
+ entry->flags = RB_FLAG_RED;
+ entry->parent = parent;
+ entry->left = NULL;
+ entry->right = NULL;
+ *iter = entry;
+
+ while (rb_is_red(entry->parent))
+ {
+ if (entry->parent == entry->parent->parent->left)
+ {
+ if (rb_is_red(entry->parent->parent->right))
+ {
+ rb_flip_color(entry->parent->parent);
+ entry = entry->parent->parent;
+ }
+ else
+ {
+ if (entry == entry->parent->right)
+ {
+ entry = entry->parent;
+ rb_rotate_left(tree, entry);
+ }
+ entry->parent->flags &= ~RB_FLAG_RED;
+ entry->parent->parent->flags |= RB_FLAG_RED;
+ rb_rotate_right(tree, entry->parent->parent);
+ }
+ }
+ else
+ {
+ if (rb_is_red(entry->parent->parent->left))
+ {
+ rb_flip_color(entry->parent->parent);
+ entry = entry->parent->parent;
+ }
+ else
+ {
+ if (entry == entry->parent->left)
+ {
+ entry = entry->parent;
+ rb_rotate_right(tree, entry);
+ }
+ entry->parent->flags &= ~RB_FLAG_RED;
+ entry->parent->parent->flags |= RB_FLAG_RED;
+ rb_rotate_left(tree, entry->parent->parent);
+ }
+ }
+ }
+
+ tree->root->flags &= ~RB_FLAG_RED;
+
+ return 0;
+}
+
+static inline void rb_remove(struct rb_tree *tree, struct rb_entry *entry)
+{
+ struct rb_entry *iter, *child, *parent, *w;
+ int need_fixup;
+
+ if (entry->right && entry->left)
+ for(iter = entry->right; iter->left; iter = iter->left);
+ else
+ iter = entry;
+
+ child = iter->left ? iter->left : iter->right;
+
+ if (!iter->parent)
+ tree->root = child;
+ else if (iter == iter->parent->left)
+ iter->parent->left = child;
+ else
+ iter->parent->right = child;
+
+ if (child) child->parent = iter->parent;
+ parent = iter->parent;
+
+ need_fixup = !rb_is_red(iter);
+
+ if (entry != iter)
+ {
+ *iter = *entry;
+ if (!iter->parent)
+ tree->root = iter;
+ else if (entry == iter->parent->left)
+ iter->parent->left = iter;
+ else
+ iter->parent->right = iter;
+
+ if (iter->right) iter->right->parent = iter;
+ if (iter->left) iter->left->parent = iter;
+ if (parent == entry) parent = iter;
+ }
+
+ if (need_fixup)
+ {
+ while (parent && !rb_is_red(child))
+ {
+ if (child == parent->left)
+ {
+ w = parent->right;
+ if (rb_is_red(w))
+ {
+ w->flags &= ~RB_FLAG_RED;
+ parent->flags |= RB_FLAG_RED;
+ rb_rotate_left(tree, parent);
+ w = parent->right;
+ }
+ if (rb_is_red(w->left) || rb_is_red(w->right))
+ {
+ if (!rb_is_red(w->right))
+ {
+ w->left->flags &= ~RB_FLAG_RED;
+ w->flags |= RB_FLAG_RED;
+ rb_rotate_right(tree, w);
+ w = parent->right;
+ }
+ w->flags = (w->flags & ~RB_FLAG_RED) | (parent->flags & RB_FLAG_RED);
+ parent->flags &= ~RB_FLAG_RED;
+ if (w->right)
+ w->right->flags &= ~RB_FLAG_RED;
+ rb_rotate_left(tree, parent);
+ child = NULL;
+ break;
+ }
+ }
+ else
+ {
+ w = parent->left;
+ if (rb_is_red(w))
+ {
+ w->flags &= ~RB_FLAG_RED;
+ parent->flags |= RB_FLAG_RED;
+ rb_rotate_right(tree, parent);
+ w = parent->left;
+ }
+ if (rb_is_red(w->left) || rb_is_red(w->right))
+ {
+ if (!rb_is_red(w->left))
+ {
+ w->right->flags &= ~RB_FLAG_RED;
+ w->flags |= RB_FLAG_RED;
+ rb_rotate_left(tree, w);
+ w = parent->left;
+ }
+ w->flags = (w->flags & ~RB_FLAG_RED) | (parent->flags & RB_FLAG_RED);
+ parent->flags &= ~RB_FLAG_RED;
+ if (w->left)
+ w->left->flags &= ~RB_FLAG_RED;
+ rb_rotate_right(tree, parent);
+ child = NULL;
+ break;
+ }
+ }
+ w->flags |= RB_FLAG_RED;
+ child = parent;
+ parent = child->parent;
+ }
+ if (child) child->flags &= ~RB_FLAG_RED;
+ }
+
+ if (tree->root) tree->root->flags &= ~RB_FLAG_RED;
+}
+
+static inline void rb_remove_key(struct rb_tree *tree, const void *key)
+{
+ struct rb_entry *entry = rb_get(tree, key);
+ if (entry) rb_remove(tree, entry);
+}
+
+#endif /* __WINE_WINE_RBTREE_H */
diff --git a/libs/vkd3d/include/private/vkd3d_common.h b/libs/vkd3d/include/private/vkd3d_common.h
index 34fde1a2aa0..b5a8240d28e 100644
--- a/libs/vkd3d/include/private/vkd3d_common.h
+++ b/libs/vkd3d/include/private/vkd3d_common.h
@@ -52,6 +52,7 @@
#define TAG_AON9 VKD3D_MAKE_TAG('A', 'o', 'n', '9')
#define TAG_DXBC VKD3D_MAKE_TAG('D', 'X', 'B', 'C')
#define TAG_DXIL VKD3D_MAKE_TAG('D', 'X', 'I', 'L')
+#define TAG_FX10 VKD3D_MAKE_TAG('F', 'X', '1', '0')
#define TAG_ISG1 VKD3D_MAKE_TAG('I', 'S', 'G', '1')
#define TAG_ISGN VKD3D_MAKE_TAG('I', 'S', 'G', 'N')
#define TAG_OSG1 VKD3D_MAKE_TAG('O', 'S', 'G', '1')
@@ -70,7 +71,7 @@
#define TAG_XNAP VKD3D_MAKE_TAG('X', 'N', 'A', 'P')
#define TAG_XNAS VKD3D_MAKE_TAG('X', 'N', 'A', 'S')
-static inline size_t align(size_t addr, size_t alignment)
+static inline uint64_t align(uint64_t addr, size_t alignment)
{
return (addr + (alignment - 1)) & ~(alignment - 1);
}
@@ -80,7 +81,7 @@ static inline size_t align(size_t addr, size_t alignment)
# ifdef __MINGW_PRINTF_FORMAT
# define VKD3D_PRINTF_FUNC(fmt, args) __attribute__((format(__MINGW_PRINTF_FORMAT, fmt, args)))
# else
-# define VKD3D_PRINTF_FUNC(fmt, args) /* __attribute__((format(printf, fmt, args))) */
+# define VKD3D_PRINTF_FUNC(fmt, args) __attribute__((format(printf, fmt, args)))
# endif
# define VKD3D_UNUSED __attribute__((unused))
# define VKD3D_UNREACHABLE __builtin_unreachable()
@@ -107,7 +108,7 @@ static inline unsigned int vkd3d_popcount(unsigned int v)
{
#ifdef _MSC_VER
return __popcnt(v);
-#elif defined(__MINGW32__)
+#elif defined(HAVE_BUILTIN_POPCOUNT)
return __builtin_popcount(v);
#else
v -= (v >> 1) & 0x55555555;
@@ -266,34 +267,42 @@ static inline int ascii_strcasecmp(const char *a, const char *b)
return c_a - c_b;
}
-#ifndef _WIN32
-# if HAVE_SYNC_ADD_AND_FETCH
-static inline LONG InterlockedIncrement(LONG volatile *x)
+static inline uint64_t vkd3d_atomic_add_fetch_u64(uint64_t volatile *x, uint64_t val)
{
- return __sync_add_and_fetch(x, 1);
+#if HAVE_SYNC_ADD_AND_FETCH
+ return __sync_add_and_fetch(x, val);
+#elif defined(_WIN32)
+ return InterlockedAdd64((LONG64 *)x, val);
+#else
+# error "vkd3d_atomic_add_fetch_u64() not implemented for this platform"
+#endif
}
-static inline LONG64 InterlockedIncrement64(LONG64 volatile *x)
+
+static inline uint32_t vkd3d_atomic_add_fetch_u32(uint32_t volatile *x, uint32_t val)
{
- return __sync_add_and_fetch(x, 1);
+#if HAVE_SYNC_ADD_AND_FETCH
+ return __sync_add_and_fetch(x, val);
+#elif defined(_WIN32)
+ return InterlockedAdd((LONG *)x, val);
+#else
+# error "vkd3d_atomic_add_fetch_u32() not implemented for this platform"
+#endif
}
-static inline LONG InterlockedAdd(LONG volatile *x, LONG val)
+
+static inline uint64_t vkd3d_atomic_increment_u64(uint64_t volatile *x)
{
- return __sync_add_and_fetch(x, val);
+ return vkd3d_atomic_add_fetch_u64(x, 1);
}
-# else
-# error "InterlockedIncrement() not implemented for this platform"
-# endif /* HAVE_SYNC_ADD_AND_FETCH */
-# if HAVE_SYNC_SUB_AND_FETCH
-static inline LONG InterlockedDecrement(LONG volatile *x)
+static inline uint32_t vkd3d_atomic_decrement_u32(uint32_t volatile *x)
{
- return __sync_sub_and_fetch(x, 1);
+ return vkd3d_atomic_add_fetch_u32(x, ~0u);
}
-# else
-# error "InterlockedDecrement() not implemented for this platform"
-# endif
-#endif /* _WIN32 */
+static inline uint32_t vkd3d_atomic_increment_u32(uint32_t volatile *x)
+{
+ return vkd3d_atomic_add_fetch_u32(x, 1);
+}
static inline void vkd3d_parse_version(const char *version, int *major, int *minor)
{
diff --git a/libs/vkd3d/include/private/vkd3d_debug.h b/libs/vkd3d/include/private/vkd3d_debug.h
index 6708cad344f..c5b6ccedf81 100644
--- a/libs/vkd3d/include/private/vkd3d_debug.h
+++ b/libs/vkd3d/include/private/vkd3d_debug.h
@@ -89,6 +89,10 @@ const char *debugstr_w(const WCHAR *wstr, size_t wchar_size);
#define TRACE_ON() (vkd3d_dbg_get_level() == VKD3D_DBG_LEVEL_TRACE)
#endif
+#ifndef WARN_ON
+#define WARN_ON() (vkd3d_dbg_get_level() >= VKD3D_DBG_LEVEL_WARN)
+#endif
+
#define FIXME_ONCE VKD3D_DBG_LOG_ONCE(FIXME, WARN)
#define VKD3D_DEBUG_ENV_NAME(name) const char *const vkd3d_dbg_env_name = name
@@ -104,6 +108,29 @@ static inline const char *debugstr_guid(const GUID *guid)
guid->Data4[5], guid->Data4[6], guid->Data4[7]);
}
+static inline const char *debugstr_hresult(HRESULT hr)
+{
+ switch (hr)
+ {
+#define TO_STR(u) case u: return #u;
+ TO_STR(S_OK)
+ TO_STR(S_FALSE)
+ TO_STR(E_NOTIMPL)
+ TO_STR(E_NOINTERFACE)
+ TO_STR(E_POINTER)
+ TO_STR(E_ABORT)
+ TO_STR(E_FAIL)
+ TO_STR(E_OUTOFMEMORY)
+ TO_STR(E_INVALIDARG)
+ TO_STR(DXGI_ERROR_NOT_FOUND)
+ TO_STR(DXGI_ERROR_MORE_DATA)
+ TO_STR(DXGI_ERROR_UNSUPPORTED)
+#undef TO_STR
+ default:
+ return vkd3d_dbg_sprintf("%#x", (int)hr);
+ }
+}
+
unsigned int vkd3d_env_var_as_uint(const char *name, unsigned int default_value);
struct vkd3d_debug_option
diff --git a/libs/vkd3d/include/private/vkd3d_test.h b/libs/vkd3d/include/private/vkd3d_test.h
new file mode 100644
index 00000000000..a337ac07269
--- /dev/null
+++ b/libs/vkd3d/include/private/vkd3d_test.h
@@ -0,0 +1,430 @@
+/*
+ * Copyright 2016 Józef Kucia for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __VKD3D_TEST_H
+#define __VKD3D_TEST_H
+
+#include "vkd3d_common.h"
+#include <assert.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+extern const char *vkd3d_test_name;
+extern const char *vkd3d_test_platform;
+
+static void vkd3d_test_start_todo(bool is_todo);
+static int vkd3d_test_loop_todo(void);
+static void vkd3d_test_end_todo(void);
+
+#define START_TEST(name) \
+ const char *vkd3d_test_name = #name; \
+ static void vkd3d_test_main(int argc, char **argv)
+
+/*
+ * Use assert_that() for conditions that should always be true.
+ * todo_if() and bug_if() do not influence assert_that().
+ */
+#define assert_that assert_that_(__LINE__)
+
+#define ok ok_(__LINE__)
+
+#define skip skip_(__LINE__)
+
+#define trace trace_(__LINE__)
+
+#define assert_that_(line) \
+ do { \
+ unsigned int vkd3d_line = line; \
+ VKD3D_TEST_ASSERT_THAT
+
+#define VKD3D_TEST_ASSERT_THAT(...) \
+ vkd3d_test_assert_that(vkd3d_line, __VA_ARGS__); } while (0)
+
+#define ok_(line) \
+ do { \
+ unsigned int vkd3d_line = line; \
+ VKD3D_TEST_OK
+
+#define VKD3D_TEST_OK(...) \
+ vkd3d_test_ok(vkd3d_line, __VA_ARGS__); } while (0)
+
+#define todo_(line) \
+ do { \
+ unsigned int vkd3d_line = line; \
+ VKD3D_TEST_TODO
+
+#define VKD3D_TEST_TODO(...) \
+ vkd3d_test_todo(vkd3d_line, __VA_ARGS__); } while (0)
+
+#define skip_(line) \
+ do { \
+ unsigned int vkd3d_line = line; \
+ VKD3D_TEST_SKIP
+
+#define VKD3D_TEST_SKIP(...) \
+ vkd3d_test_skip(vkd3d_line, __VA_ARGS__); } while (0)
+
+#define trace_(line) \
+ do { \
+ unsigned int vkd3d_line = line; \
+ VKD3D_TEST_TRACE
+
+#define VKD3D_TEST_TRACE(...) \
+ vkd3d_test_trace(vkd3d_line, __VA_ARGS__); } while (0)
+
+#define todo_if(is_todo) \
+ for (vkd3d_test_start_todo(is_todo); vkd3d_test_loop_todo(); vkd3d_test_end_todo())
+
+#define bug_if(is_bug) \
+ for (vkd3d_test_start_bug(is_bug); vkd3d_test_loop_bug(); vkd3d_test_end_bug())
+
+#define todo todo_if(true)
+
+struct vkd3d_test_state
+{
+ unsigned int success_count;
+ unsigned int failure_count;
+ unsigned int skip_count;
+ unsigned int todo_count;
+ unsigned int todo_success_count;
+ unsigned int bug_count;
+
+ unsigned int debug_level;
+
+ unsigned int todo_level;
+ bool todo_do_loop;
+
+ unsigned int bug_level;
+ bool bug_do_loop;
+ bool bug_enabled;
+
+ const char *test_name_filter;
+ char context[8][128];
+ unsigned int context_count;
+};
+extern struct vkd3d_test_state vkd3d_test_state;
+
+static bool
+vkd3d_test_platform_is_windows(void)
+{
+ return !strcmp(vkd3d_test_platform, "windows");
+}
+
+static inline bool
+broken(bool condition)
+{
+ return condition && vkd3d_test_platform_is_windows();
+}
+
+static void vkd3d_test_printf(unsigned int line, const char *msg)
+{
+ unsigned int i;
+
+ printf("%s:%u: ", vkd3d_test_name, line);
+ for (i = 0; i < vkd3d_test_state.context_count; ++i)
+ printf("%s: ", vkd3d_test_state.context[i]);
+ printf("%s", msg);
+}
+
+static void
+vkd3d_test_check_assert_that(unsigned int line, bool result, const char *fmt, va_list args)
+{
+ if (result)
+ {
+ vkd3d_atomic_increment_u32(&vkd3d_test_state.success_count);
+ if (vkd3d_test_state.debug_level > 1)
+ vkd3d_test_printf(line, "Test succeeded.\n");
+ }
+ else
+ {
+ vkd3d_atomic_increment_u32(&vkd3d_test_state.failure_count);
+ vkd3d_test_printf(line, "Test failed: ");
+ vprintf(fmt, args);
+ }
+}
+
+static void VKD3D_PRINTF_FUNC(3, 4) VKD3D_UNUSED
+vkd3d_test_assert_that(unsigned int line, bool result, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ vkd3d_test_check_assert_that(line, result, fmt, args);
+ va_end(args);
+}
+
+static void
+vkd3d_test_check_ok(unsigned int line, bool result, const char *fmt, va_list args)
+{
+ bool is_todo = vkd3d_test_state.todo_level && !vkd3d_test_platform_is_windows();
+ bool is_bug = vkd3d_test_state.bug_level && !vkd3d_test_platform_is_windows();
+
+ if (is_bug && vkd3d_test_state.bug_enabled)
+ {
+ vkd3d_atomic_increment_u32(&vkd3d_test_state.bug_count);
+ if (is_todo)
+ result = !result;
+ if (result)
+ vkd3d_test_printf(line, "Fixed bug: ");
+ else
+ vkd3d_test_printf(line, "Bug: ");
+ vprintf(fmt, args);
+ }
+ else if (is_todo)
+ {
+ if (result)
+ {
+ vkd3d_atomic_increment_u32(&vkd3d_test_state.todo_success_count);
+ vkd3d_test_printf(line, "Todo succeeded: ");
+ }
+ else
+ {
+ vkd3d_atomic_increment_u32(&vkd3d_test_state.todo_count);
+ vkd3d_test_printf(line, "Todo: ");
+ }
+ vprintf(fmt, args);
+ }
+ else
+ {
+ vkd3d_test_check_assert_that(line, result, fmt, args);
+ }
+}
+
+static void VKD3D_PRINTF_FUNC(3, 4) VKD3D_UNUSED
+vkd3d_test_ok(unsigned int line, bool result, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ vkd3d_test_check_ok(line, result, fmt, args);
+ va_end(args);
+}
+
+static void VKD3D_PRINTF_FUNC(2, 3) VKD3D_UNUSED
+vkd3d_test_skip(unsigned int line, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ vkd3d_test_printf(line, "Test skipped: ");
+ vprintf(fmt, args);
+ va_end(args);
+ vkd3d_atomic_increment_u32(&vkd3d_test_state.skip_count);
+}
+
+static void VKD3D_PRINTF_FUNC(2, 3) VKD3D_UNUSED
+vkd3d_test_trace(unsigned int line, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ vkd3d_test_printf(line, "");
+ vprintf(fmt, args);
+ va_end(args);
+}
+
+static void VKD3D_PRINTF_FUNC(1, 2) VKD3D_UNUSED
+vkd3d_test_debug(const char *fmt, ...)
+{
+ char buffer[512];
+ va_list args;
+ int size;
+
+ size = snprintf(buffer, sizeof(buffer), "%s: ", vkd3d_test_name);
+ if (0 < size && size < sizeof(buffer))
+ {
+ va_start(args, fmt);
+ vsnprintf(buffer + size, sizeof(buffer) - size, fmt, args);
+ va_end(args);
+ }
+ buffer[sizeof(buffer) - 1] = '\0';
+
+#ifdef _WIN32
+ OutputDebugStringA(buffer);
+#endif
+
+ if (vkd3d_test_state.debug_level > 0)
+ printf("%s\n", buffer);
+}
+
+#ifndef VKD3D_TEST_NO_DEFS
+const char *vkd3d_test_platform = "other";
+struct vkd3d_test_state vkd3d_test_state;
+
+static void vkd3d_test_main(int argc, char **argv);
+
+int main(int argc, char **argv)
+{
+ const char *test_filter = getenv("VKD3D_TEST_FILTER");
+ const char *debug_level = getenv("VKD3D_TEST_DEBUG");
+ char *test_platform = getenv("VKD3D_TEST_PLATFORM");
+ const char *bug = getenv("VKD3D_TEST_BUG");
+
+ memset(&vkd3d_test_state, 0, sizeof(vkd3d_test_state));
+ vkd3d_test_state.debug_level = debug_level ? atoi(debug_level) : 0;
+ vkd3d_test_state.bug_enabled = bug ? atoi(bug) : true;
+ vkd3d_test_state.test_name_filter = test_filter;
+
+ if (test_platform)
+ {
+ test_platform = strdup(test_platform);
+ vkd3d_test_platform = test_platform;
+ }
+
+ if (vkd3d_test_state.debug_level > 1)
+ printf("Test platform: '%s'.\n", vkd3d_test_platform);
+
+ vkd3d_test_main(argc, argv);
+
+ printf("%s: %u tests executed (%u failures, %u skipped, %u todo, %u bugs).\n",
+ vkd3d_test_name,
+ vkd3d_test_state.success_count + vkd3d_test_state.failure_count
+ + vkd3d_test_state.todo_count + vkd3d_test_state.todo_success_count,
+ vkd3d_test_state.failure_count + vkd3d_test_state.todo_success_count,
+ vkd3d_test_state.skip_count,
+ vkd3d_test_state.todo_count,
+ vkd3d_test_state.bug_count);
+
+ if (test_platform)
+ free(test_platform);
+
+ return vkd3d_test_state.failure_count || vkd3d_test_state.todo_success_count;
+}
+
+#ifdef _WIN32
+static char *vkd3d_test_strdupWtoA(WCHAR *str)
+{
+ char *out;
+ int len;
+
+ if (!(len = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL)))
+ return NULL;
+ if (!(out = malloc(len)))
+ return NULL;
+ WideCharToMultiByte(CP_ACP, 0, str, -1, out, len, NULL, NULL);
+
+ return out;
+}
+
+static bool running_under_wine(void)
+{
+ HMODULE module = GetModuleHandleA("ntdll.dll");
+ return module && GetProcAddress(module, "wine_server_call");
+}
+
+int wmain(int argc, WCHAR **wargv)
+{
+ char **argv;
+ int i, ret;
+
+ argv = malloc(argc * sizeof(*argv));
+ assert(argv);
+ for (i = 0; i < argc; ++i)
+ {
+ if (!(argv[i] = vkd3d_test_strdupWtoA(wargv[i])))
+ break;
+ }
+ assert(i == argc);
+
+ vkd3d_test_platform = running_under_wine() ? "wine" : "windows";
+
+ ret = main(argc, argv);
+
+ for (i = 0; i < argc; ++i)
+ free(argv[i]);
+ free(argv);
+
+ return ret;
+}
+#endif /* _WIN32 */
+#endif /* VKD3D_TEST_NO_DEFS */
+
+typedef void (*vkd3d_test_pfn)(void);
+
+static inline void vkd3d_run_test(const char *name, vkd3d_test_pfn test_pfn)
+{
+ if (vkd3d_test_state.test_name_filter && !strstr(name, vkd3d_test_state.test_name_filter))
+ return;
+
+ vkd3d_test_debug("%s", name);
+ test_pfn();
+}
+
+static inline void vkd3d_test_start_todo(bool is_todo)
+{
+ vkd3d_test_state.todo_level = (vkd3d_test_state.todo_level << 1) | is_todo;
+ vkd3d_test_state.todo_do_loop = true;
+}
+
+static inline int vkd3d_test_loop_todo(void)
+{
+ bool do_loop = vkd3d_test_state.todo_do_loop;
+ vkd3d_test_state.todo_do_loop = false;
+ return do_loop;
+}
+
+static inline void vkd3d_test_end_todo(void)
+{
+ vkd3d_test_state.todo_level >>= 1;
+}
+
+static inline void vkd3d_test_start_bug(bool is_bug)
+{
+ vkd3d_test_state.bug_level = (vkd3d_test_state.bug_level << 1) | is_bug;
+ vkd3d_test_state.bug_do_loop = true;
+}
+
+static inline int vkd3d_test_loop_bug(void)
+{
+ bool do_loop = vkd3d_test_state.bug_do_loop;
+ vkd3d_test_state.bug_do_loop = false;
+ return do_loop;
+}
+
+static inline void vkd3d_test_end_bug(void)
+{
+ vkd3d_test_state.bug_level >>= 1;
+}
+
+static inline void vkd3d_test_push_context(const char *fmt, ...)
+{
+ va_list args;
+
+ if (vkd3d_test_state.context_count < ARRAY_SIZE(vkd3d_test_state.context))
+ {
+ va_start(args, fmt);
+ vsnprintf(vkd3d_test_state.context[vkd3d_test_state.context_count],
+ sizeof(vkd3d_test_state.context), fmt, args);
+ va_end(args);
+ vkd3d_test_state.context[vkd3d_test_state.context_count][sizeof(vkd3d_test_state.context[0]) - 1] = '\0';
+ }
+ ++vkd3d_test_state.context_count;
+}
+
+static inline void vkd3d_test_pop_context(void)
+{
+ if (vkd3d_test_state.context_count)
+ --vkd3d_test_state.context_count;
+}
+
+#define run_test(test_pfn) \
+ vkd3d_run_test(#test_pfn, test_pfn)
+
+#endif /* __VKD3D_TEST_H */
diff --git a/libs/vkd3d/include/vkd3d_d3d9types.h b/libs/vkd3d/include/vkd3d_d3d9types.h
new file mode 100644
index 00000000000..75d0461409d
--- /dev/null
+++ b/libs/vkd3d/include/vkd3d_d3d9types.h
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2002-2003 Jason Edmeades
+ * Copyright 2002-2003 Raphael Junqueira
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __VKD3D_D3D9TYPES_H
+#define __VKD3D_D3D9TYPES_H
+#ifndef _d3d9TYPES_H_
+
+#ifndef MAKEFOURCC
+#define MAKEFOURCC(ch0, ch1, ch2, ch3) \
+ ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
+ ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24 ))
+#endif
+
+#define D3DSI_INSTLENGTH_SHIFT 24
+
+#define D3DSP_DCL_USAGE_SHIFT 0
+#define D3DSP_DCL_USAGEINDEX_SHIFT 16
+#define D3DSP_DSTMOD_SHIFT 20
+
+#define D3DSP_SRCMOD_SHIFT 24
+
+#define D3DSP_REGTYPE_SHIFT 28
+#define D3DSP_REGTYPE_SHIFT2 8
+#define D3DSP_REGTYPE_MASK (0x7 << D3DSP_REGTYPE_SHIFT)
+#define D3DSP_REGTYPE_MASK2 0x00001800
+
+#define D3DSP_WRITEMASK_0 0x00010000
+#define D3DSP_WRITEMASK_1 0x00020000
+#define D3DSP_WRITEMASK_2 0x00040000
+#define D3DSP_WRITEMASK_3 0x00080000
+#define D3DSP_WRITEMASK_ALL 0x000f0000
+
+#define D3DPS_VERSION(major, minor) (0xffff0000 | ((major) << 8) | (minor))
+#define D3DVS_VERSION(major, minor) (0xfffe0000 | ((major) << 8) | (minor))
+
+typedef enum _D3DDECLUSAGE
+{
+ D3DDECLUSAGE_POSITION = 0x0,
+ D3DDECLUSAGE_BLENDWEIGHT = 0x1,
+ D3DDECLUSAGE_BLENDINDICES = 0x2,
+ D3DDECLUSAGE_NORMAL = 0x3,
+ D3DDECLUSAGE_PSIZE = 0x4,
+ D3DDECLUSAGE_TEXCOORD = 0x5,
+ D3DDECLUSAGE_TANGENT = 0x6,
+ D3DDECLUSAGE_BINORMAL = 0x7,
+ D3DDECLUSAGE_TESSFACTOR = 0x8,
+ D3DDECLUSAGE_POSITIONT = 0x9,
+ D3DDECLUSAGE_COLOR = 0xa,
+ D3DDECLUSAGE_FOG = 0xb,
+ D3DDECLUSAGE_DEPTH = 0xc,
+ D3DDECLUSAGE_SAMPLE = 0xd,
+} D3DDECLUSAGE;
+
+typedef enum _D3DSHADER_INSTRUCTION_OPCODE_TYPE
+{
+ D3DSIO_NOP = 0x00,
+ D3DSIO_MOV = 0x01,
+ D3DSIO_ADD = 0x02,
+ D3DSIO_SUB = 0x03,
+ D3DSIO_MAD = 0x04,
+ D3DSIO_MUL = 0x05,
+ D3DSIO_RCP = 0x06,
+ D3DSIO_RSQ = 0x07,
+ D3DSIO_DP3 = 0x08,
+ D3DSIO_DP4 = 0x09,
+ D3DSIO_MIN = 0x0a,
+ D3DSIO_MAX = 0x0b,
+ D3DSIO_SLT = 0x0c,
+ D3DSIO_SGE = 0x0d,
+ D3DSIO_EXP = 0x0e,
+ D3DSIO_LOG = 0x0f,
+ D3DSIO_LIT = 0x10,
+ D3DSIO_DST = 0x11,
+ D3DSIO_LRP = 0x12,
+ D3DSIO_FRC = 0x13,
+ D3DSIO_M4x4 = 0x14,
+ D3DSIO_M4x3 = 0x15,
+ D3DSIO_M3x4 = 0x16,
+ D3DSIO_M3x3 = 0x17,
+ D3DSIO_M3x2 = 0x18,
+ D3DSIO_CALL = 0x19,
+ D3DSIO_CALLNZ = 0x1a,
+ D3DSIO_LOOP = 0x1b,
+ D3DSIO_RET = 0x1c,
+ D3DSIO_ENDLOOP = 0x1d,
+ D3DSIO_LABEL = 0x1e,
+ D3DSIO_DCL = 0x1f,
+ D3DSIO_POW = 0x20,
+ D3DSIO_CRS = 0x21,
+ D3DSIO_SGN = 0x22,
+ D3DSIO_ABS = 0x23,
+ D3DSIO_NRM = 0x24,
+ D3DSIO_SINCOS = 0x25,
+ D3DSIO_REP = 0x26,
+ D3DSIO_ENDREP = 0x27,
+ D3DSIO_IF = 0x28,
+ D3DSIO_IFC = 0x29,
+ D3DSIO_ELSE = 0x2a,
+ D3DSIO_ENDIF = 0x2b,
+ D3DSIO_BREAK = 0x2c,
+ D3DSIO_BREAKC = 0x2d,
+ D3DSIO_MOVA = 0x2e,
+ D3DSIO_DEFB = 0x2f,
+ D3DSIO_DEFI = 0x30,
+
+ D3DSIO_TEXCOORD = 0x40,
+ D3DSIO_TEXKILL = 0x41,
+ D3DSIO_TEX = 0x42,
+ D3DSIO_TEXBEM = 0x43,
+ D3DSIO_TEXBEML = 0x44,
+ D3DSIO_TEXREG2AR = 0x45,
+ D3DSIO_TEXREG2GB = 0x46,
+ D3DSIO_TEXM3x2PAD = 0x47,
+ D3DSIO_TEXM3x2TEX = 0x48,
+ D3DSIO_TEXM3x3PAD = 0x49,
+ D3DSIO_TEXM3x3TEX = 0x4a,
+ D3DSIO_TEXM3x3DIFF = 0x4b,
+ D3DSIO_TEXM3x3SPEC = 0x4c,
+ D3DSIO_TEXM3x3VSPEC = 0x4d,
+ D3DSIO_EXPP = 0x4e,
+ D3DSIO_LOGP = 0x4f,
+ D3DSIO_CND = 0x50,
+ D3DSIO_DEF = 0x51,
+ D3DSIO_TEXREG2RGB = 0x52,
+ D3DSIO_TEXDP3TEX = 0x53,
+ D3DSIO_TEXM3x2DEPTH = 0x54,
+ D3DSIO_TEXDP3 = 0x55,
+ D3DSIO_TEXM3x3 = 0x56,
+ D3DSIO_TEXDEPTH = 0x57,
+ D3DSIO_CMP = 0x58,
+ D3DSIO_BEM = 0x59,
+ D3DSIO_DP2ADD = 0x5a,
+ D3DSIO_DSX = 0x5b,
+ D3DSIO_DSY = 0x5c,
+ D3DSIO_TEXLDD = 0x5d,
+ D3DSIO_SETP = 0x5e,
+ D3DSIO_TEXLDL = 0x5f,
+ D3DSIO_BREAKP = 0x60,
+
+ D3DSIO_PHASE = 0xfffd,
+ D3DSIO_COMMENT = 0xfffe,
+ D3DSIO_END = 0xffff,
+
+ D3DSIO_FORCE_DWORD = 0x7fffffff,
+} D3DSHADER_INSTRUCTION_OPCODE_TYPE;
+
+typedef enum _D3DSHADER_PARAM_DSTMOD_TYPE
+{
+ D3DSPDM_NONE = 0 << D3DSP_DSTMOD_SHIFT,
+ D3DSPDM_SATURATE = 1 << D3DSP_DSTMOD_SHIFT,
+ D3DSPDM_PARTIALPRECISION = 2 << D3DSP_DSTMOD_SHIFT,
+ D3DSPDM_MSAMPCENTROID = 4 << D3DSP_DSTMOD_SHIFT,
+
+ D3DSPDM_FORCE_DWORD = 0x7fffffff,
+} D3DSHADER_PARAM_DSTMOD_TYPE;
+
+typedef enum _D3DSHADER_PARAM_REGISTER_TYPE
+{
+ D3DSPR_TEMP = 0x00,
+ D3DSPR_INPUT = 0x01,
+ D3DSPR_CONST = 0x02,
+ D3DSPR_ADDR = 0x03,
+ D3DSPR_TEXTURE = 0x03,
+ D3DSPR_RASTOUT = 0x04,
+ D3DSPR_ATTROUT = 0x05,
+ D3DSPR_TEXCRDOUT = 0x06,
+ D3DSPR_OUTPUT = 0x06,
+ D3DSPR_CONSTINT = 0x07,
+ D3DSPR_COLOROUT = 0x08,
+ D3DSPR_DEPTHOUT = 0x09,
+ D3DSPR_SAMPLER = 0x0a,
+ D3DSPR_CONST2 = 0x0b,
+ D3DSPR_CONST3 = 0x0c,
+ D3DSPR_CONST4 = 0x0d,
+ D3DSPR_CONSTBOOL = 0x0e,
+ D3DSPR_LOOP = 0x0f,
+ D3DSPR_TEMPFLOAT16 = 0x10,
+ D3DSPR_MISCTYPE = 0x11,
+ D3DSPR_LABEL = 0x12,
+ D3DSPR_PREDICATE = 0x13,
+
+ D3DSPR_FORCE_DWORD = 0x7fffffff,
+} D3DSHADER_PARAM_REGISTER_TYPE;
+
+typedef enum _D3DSHADER_PARAM_SRCMOD_TYPE
+{
+ D3DSPSM_NONE = 0x0 << D3DSP_SRCMOD_SHIFT,
+ D3DSPSM_NEG = 0x1 << D3DSP_SRCMOD_SHIFT,
+ D3DSPSM_BIAS = 0x2 << D3DSP_SRCMOD_SHIFT,
+ D3DSPSM_BIASNEG = 0x3 << D3DSP_SRCMOD_SHIFT,
+ D3DSPSM_SIGN = 0x4 << D3DSP_SRCMOD_SHIFT,
+ D3DSPSM_SIGNNEG = 0x5 << D3DSP_SRCMOD_SHIFT,
+ D3DSPSM_COMP = 0x6 << D3DSP_SRCMOD_SHIFT,
+ D3DSPSM_X2 = 0x7 << D3DSP_SRCMOD_SHIFT,
+ D3DSPSM_X2NEG = 0x8 << D3DSP_SRCMOD_SHIFT,
+ D3DSPSM_DZ = 0x9 << D3DSP_SRCMOD_SHIFT,
+ D3DSPSM_DW = 0xa << D3DSP_SRCMOD_SHIFT,
+ D3DSPSM_ABS = 0xb << D3DSP_SRCMOD_SHIFT,
+ D3DSPSM_ABSNEG = 0xc << D3DSP_SRCMOD_SHIFT,
+ D3DSPSM_NOT = 0xd << D3DSP_SRCMOD_SHIFT,
+
+ D3DSPSM_FORCE_DWORD = 0x7fffffff,
+} D3DSHADER_PARAM_SRCMOD_TYPE;
+
+typedef enum _D3DSHADER_MISCTYPE_OFFSETS
+{
+ D3DSMO_POSITION = 0x0,
+ D3DSMO_FACE = 0x1,
+} D3DSHADER_MISCTYPE_OFFSETS;
+
+typedef enum _D3DVS_RASTOUT_OFFSETS
+{
+ D3DSRO_POSITION = 0x0,
+ D3DSRO_FOG = 0x1,
+ D3DSRO_POINT_SIZE = 0x2,
+
+ D3DSRO_FORCE_DWORD = 0x7fffffff,
+} D3DVS_RASTOUT_OFFSETS;
+
+#endif /* _d3d9TYPES_H_ */
+#endif /* __VKD3D_D3D9TYPES_H */
diff --git a/libs/vkd3d/include/vkd3d_d3dcompiler.h b/libs/vkd3d/include/vkd3d_d3dcompiler.h
new file mode 100644
index 00000000000..872a90bbc4b
--- /dev/null
+++ b/libs/vkd3d/include/vkd3d_d3dcompiler.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2010 Matteo Bruni for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __VKD3D_D3DCOMPILER_H
+#define __VKD3D_D3DCOMPILER_H
+#ifndef __D3DCOMPILER_H__
+
+#include <vkd3d_d3dcompiler_types.h>
+
+#define D3DCOMPILE_DEBUG 0x00000001
+#define D3DCOMPILE_SKIP_VALIDATION 0x00000002
+#define D3DCOMPILE_SKIP_OPTIMIZATION 0x00000004
+#define D3DCOMPILE_PACK_MATRIX_ROW_MAJOR 0x00000008
+#define D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR 0x00000010
+#define D3DCOMPILE_PARTIAL_PRECISION 0x00000020
+#define D3DCOMPILE_FORCE_VS_SOFTWARE_NO_OPT 0x00000040
+#define D3DCOMPILE_FORCE_PS_SOFTWARE_NO_OPT 0x00000080
+#define D3DCOMPILE_NO_PRESHADER 0x00000100
+#define D3DCOMPILE_AVOID_FLOW_CONTROL 0x00000200
+#define D3DCOMPILE_PREFER_FLOW_CONTROL 0x00000400
+#define D3DCOMPILE_ENABLE_STRICTNESS 0x00000800
+#define D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY 0x00001000
+#define D3DCOMPILE_IEEE_STRICTNESS 0x00002000
+#define D3DCOMPILE_OPTIMIZATION_LEVEL0 0x00004000
+#define D3DCOMPILE_OPTIMIZATION_LEVEL1 0x00000000
+#define D3DCOMPILE_OPTIMIZATION_LEVEL2 0x0000c000
+#define D3DCOMPILE_OPTIMIZATION_LEVEL3 0x00008000
+#define D3DCOMPILE_RESERVED16 0x00010000
+#define D3DCOMPILE_RESERVED17 0x00020000
+#define D3DCOMPILE_WARNINGS_ARE_ERRORS 0x00040000
+#define D3DCOMPILE_RESOURCES_MAY_ALIAS 0x00080000
+#define D3DCOMPILE_ENABLE_UNBOUNDED_DESCRIPTOR_TABLES 0x00100000
+#define D3DCOMPILE_ALL_RESOURCES_BOUND 0x00200000
+#define D3DCOMPILE_DEBUG_NAME_FOR_SOURCE 0x00400000
+#define D3DCOMPILE_DEBUG_NAME_FOR_BINARY 0x00800000
+
+#define D3DCOMPILE_EFFECT_CHILD_EFFECT 0x00000001
+#define D3DCOMPILE_EFFECT_ALLOW_SLOW_OPS 0x00000002
+
+#define D3DCOMPILE_FLAGS2_FORCE_ROOT_SIGNATURE_LATEST 0x00000000
+#define D3DCOMPILE_FLAGS2_FORCE_ROOT_SIGNATURE_1_0 0x00000010
+#define D3DCOMPILE_FLAGS2_FORCE_ROOT_SIGNATURE_1_1 0x00000020
+
+#define D3DCOMPILE_SECDATA_MERGE_UAV_SLOTS 0x00000001
+#define D3DCOMPILE_SECDATA_PRESERVE_TEMPLATE_SLOTS 0x00000002
+#define D3DCOMPILE_SECDATA_REQUIRE_TEMPLATE_MATCH 0x00000004
+
+typedef enum D3DCOMPILER_STRIP_FLAGS
+{
+ D3DCOMPILER_STRIP_REFLECTION_DATA = 0x00000001,
+ D3DCOMPILER_STRIP_DEBUG_INFO = 0x00000002,
+ D3DCOMPILER_STRIP_TEST_BLOBS = 0x00000004,
+ D3DCOMPILER_STRIP_PRIVATE_DATA = 0x00000008,
+ D3DCOMPILER_STRIP_ROOT_SIGNATURE = 0x00000010,
+ D3DCOMPILER_STRIP_FORCE_DWORD = 0x7fffffff,
+} D3DCOMPILER_STRIP_FLAGS;
+
+HRESULT WINAPI D3DCompile(const void *data, SIZE_T data_size, const char *filename,
+ const D3D_SHADER_MACRO *macros, ID3DInclude *include, const char *entrypoint,
+ const char *profile, UINT flags, UINT effect_flags, ID3DBlob **shader, ID3DBlob **error_messages);
+HRESULT WINAPI D3DCompile2(const void *data, SIZE_T data_size, const char *filename,
+ const D3D_SHADER_MACRO *macros, ID3DInclude *include, const char *entrypoint,
+ const char *profile, UINT flags, UINT effect_flags, UINT secondary_flags,
+ const void *secondary_data, SIZE_T secondary_data_size, ID3DBlob **shader,
+ ID3DBlob **error_messages);
+HRESULT WINAPI D3DCreateBlob(SIZE_T size, ID3DBlob **blob);
+HRESULT WINAPI D3DDisassemble(const void *data, SIZE_T data_size, UINT flags, const char *comments, ID3DBlob **blob);
+HRESULT WINAPI D3DGetBlobPart(const void *data, SIZE_T data_size, D3D_BLOB_PART part, UINT flags, ID3DBlob **blob);
+HRESULT WINAPI D3DGetDebugInfo(const void *data, SIZE_T data_size, ID3DBlob **blob);
+HRESULT WINAPI D3DGetInputAndOutputSignatureBlob(const void *data, SIZE_T data_size, ID3DBlob **blob);
+HRESULT WINAPI D3DGetInputSignatureBlob(const void *data, SIZE_T data_size, ID3DBlob **blob);
+HRESULT WINAPI D3DGetOutputSignatureBlob(const void *data, SIZE_T data_size, ID3DBlob **blob);
+HRESULT WINAPI D3DPreprocess(const void *data, SIZE_T size, const char *filename, const D3D_SHADER_MACRO *macros,
+ ID3DInclude *include, ID3DBlob **shader, ID3DBlob **error_messages);
+HRESULT WINAPI D3DReflect(const void *data, SIZE_T data_size, REFIID iid, void **reflection);
+HRESULT WINAPI D3DStripShader(const void *data, SIZE_T data_size, UINT flags, ID3DBlob **blob);
+
+typedef HRESULT (WINAPI *pD3DDisassemble)(const void *data, SIZE_T data_size,
+ UINT flags, const char *comments, ID3DBlob **blob);
+
+#endif /* __D3DCOMPILER_H__ */
+#endif /* __VKD3D_D3DCOMPILER_H */
diff --git a/libs/vkd3d/include/vkd3d_d3dcompiler_types.h b/libs/vkd3d/include/vkd3d_d3dcompiler_types.h
new file mode 100644
index 00000000000..b3a47cdd912
--- /dev/null
+++ b/libs/vkd3d/include/vkd3d_d3dcompiler_types.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2010 Matteo Bruni for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __VKD3D_D3DCOMPILER_TYPES_H
+#define __VKD3D_D3DCOMPILER_TYPES_H
+#ifndef __D3DCOMPILER_H__
+
+typedef enum D3D_BLOB_PART
+{
+ D3D_BLOB_INPUT_SIGNATURE_BLOB,
+ D3D_BLOB_OUTPUT_SIGNATURE_BLOB,
+ D3D_BLOB_INPUT_AND_OUTPUT_SIGNATURE_BLOB,
+ D3D_BLOB_PATCH_CONSTANT_SIGNATURE_BLOB,
+ D3D_BLOB_ALL_SIGNATURE_BLOB,
+ D3D_BLOB_DEBUG_INFO,
+ D3D_BLOB_LEGACY_SHADER,
+ D3D_BLOB_XNA_PREPASS_SHADER,
+ D3D_BLOB_XNA_SHADER,
+ D3D_BLOB_PDB,
+ D3D_BLOB_PRIVATE_DATA,
+ D3D_BLOB_ROOT_SIGNATURE,
+ D3D_BLOB_DEBUG_NAME,
+ D3D_BLOB_TEST_ALTERNATE_SHADER = 0x8000,
+ D3D_BLOB_TEST_COMPILE_DETAILS,
+ D3D_BLOB_TEST_COMPILE_PERF,
+ D3D_BLOB_TEST_COMPILE_REPORT
+} D3D_BLOB_PART;
+
+#endif /* __D3DCOMPILER_H__ */
+#endif /* __VKD3D_D3DCOMPILER_TYPES_H */
diff --git a/libs/vkd3d/include/vkd3d_shader.h b/libs/vkd3d/include/vkd3d_shader.h
index 290f9085d2d..2f4478a7983 100644
--- a/libs/vkd3d/include/vkd3d_shader.h
+++ b/libs/vkd3d/include/vkd3d_shader.h
@@ -196,6 +196,15 @@ enum vkd3d_shader_compile_option_fragment_coordinate_origin
VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_COMPILE_OPTION_FRAGMENT_COORDINATE_ORIGIN),
};
+/** Advertises feature availability. \since 1.11 */
+enum vkd3d_shader_compile_option_feature_flags
+{
+ VKD3D_SHADER_COMPILE_OPTION_FEATURE_INT64 = 0x00000001,
+ VKD3D_SHADER_COMPILE_OPTION_FEATURE_FLOAT64 = 0x00000002,
+
+ VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_COMPILE_OPTION_FEATURE_FLAGS),
+};
+
enum vkd3d_shader_compile_option_name
{
/**
@@ -253,6 +262,16 @@ enum vkd3d_shader_compile_option_name
* \since 1.10
*/
VKD3D_SHADER_COMPILE_OPTION_FRAGMENT_COORDINATE_ORIGIN = 0x00000009,
+ /**
+ * This option specifies the shader features available in the target
+ * environment. These are not extensions, i.e. they are always supported
+ * by the driver, but may not be supported by the available hardware.
+ *
+ * \a value is a member of enum vkd3d_shader_compile_option_feature_flags.
+ *
+ * \since 1.11
+ */
+ VKD3D_SHADER_COMPILE_OPTION_FEATURE = 0x0000000a,
VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_COMPILE_OPTION_NAME),
};
@@ -767,6 +786,11 @@ enum vkd3d_shader_target_type
* An 'OpenGL Shading Language' shader. \since 1.3
*/
VKD3D_SHADER_TARGET_GLSL,
+ /**
+ * Binary format used by Direct3D 9/10.x/11 effects profiles.
+ * Output is a raw FX section without container. \since 1.11
+ */
+ VKD3D_SHADER_TARGET_FX,
VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_TARGET_TYPE),
};
@@ -853,6 +877,8 @@ enum vkd3d_shader_spirv_extension
VKD3D_SHADER_SPIRV_EXTENSION_EXT_DESCRIPTOR_INDEXING,
/** \since 1.3 */
VKD3D_SHADER_SPIRV_EXTENSION_EXT_STENCIL_EXPORT,
+ /** \since 1.11 */
+ VKD3D_SHADER_SPIRV_EXTENSION_EXT_VIEWPORT_INDEX_LAYER,
VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_SPIRV_EXTENSION),
};
@@ -1252,6 +1278,8 @@ enum vkd3d_shader_descriptor_range_flags
VKD3D_SHADER_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE = 0x2,
VKD3D_SHADER_DESCRIPTOR_RANGE_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE = 0x4,
VKD3D_SHADER_DESCRIPTOR_RANGE_FLAG_DATA_STATIC = 0x8,
+ /** \since 1.11 */
+ VKD3D_SHADER_DESCRIPTOR_RANGE_FLAG_DESCRIPTORS_STATIC_KEEPING_BUFFER_BOUNDS_CHECKS = 0x10000,
VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_DESCRIPTOR_RANGE_FLAGS),
};
@@ -1551,6 +1579,8 @@ enum vkd3d_shader_component_type
VKD3D_SHADER_COMPONENT_BOOL = 0x4,
/** 64-bit IEEE floating-point. */
VKD3D_SHADER_COMPONENT_DOUBLE = 0x5,
+ /** 64-bit unsigned integer. \since 1.11 */
+ VKD3D_SHADER_COMPONENT_UINT64 = 0x6,
VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_COMPONENT_TYPE),
};
@@ -1747,10 +1777,10 @@ struct vkd3d_shader_dxbc_desc
* \endcode
*/
#define VKD3D_SHADER_SWIZZLE(x, y, z, w) \
- vkd3d_shader_create_swizzle(VKD3D_SHADER_SWIZZLE_ ## x, \
- VKD3D_SHADER_SWIZZLE_ ## y, \
- VKD3D_SHADER_SWIZZLE_ ## z, \
- VKD3D_SHADER_SWIZZLE_ ## w)
+ (VKD3D_SHADER_SWIZZLE_ ## x << VKD3D_SHADER_SWIZZLE_SHIFT(0) \
+ | VKD3D_SHADER_SWIZZLE_ ## y << VKD3D_SHADER_SWIZZLE_SHIFT(1) \
+ | VKD3D_SHADER_SWIZZLE_ ## z << VKD3D_SHADER_SWIZZLE_SHIFT(2) \
+ | VKD3D_SHADER_SWIZZLE_ ## w << VKD3D_SHADER_SWIZZLE_SHIFT(3))
/** The identity swizzle ".xyzw". */
#define VKD3D_SHADER_NO_SWIZZLE VKD3D_SHADER_SWIZZLE(X, Y, Z, W)
diff --git a/libs/vkd3d/include/vkd3d_utils.h b/libs/vkd3d/include/vkd3d_utils.h
new file mode 100644
index 00000000000..7616a3f3c46
--- /dev/null
+++ b/libs/vkd3d/include/vkd3d_utils.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2016 Józef Kucia for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __VKD3D_UTILS_H
+#define __VKD3D_UTILS_H
+
+#include <vkd3d.h>
+#include <vkd3d_d3dcompiler_types.h>
+
+#ifndef VKD3D_UTILS_API_VERSION
+#define VKD3D_UTILS_API_VERSION VKD3D_API_VERSION_1_0
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * \file vkd3d_utils.h
+ *
+ * This file contains definitions for the vkd3d-utils library.
+ *
+ * The vkd3d-utils library is a collections of routines to ease the
+ * porting of a Direct3D 12 application to vkd3d.
+ *
+ * \since 1.0
+ */
+
+#define VKD3D_WAIT_OBJECT_0 (0)
+#define VKD3D_WAIT_TIMEOUT (1)
+#define VKD3D_WAIT_FAILED (~0u)
+#define VKD3D_INFINITE (~0u)
+
+#ifdef LIBVKD3D_UTILS_SOURCE
+# define VKD3D_UTILS_API VKD3D_EXPORT
+#else
+# define VKD3D_UTILS_API VKD3D_IMPORT
+#endif
+
+/* 1.0 */
+VKD3D_UTILS_API HANDLE vkd3d_create_event(void);
+VKD3D_UTILS_API HRESULT vkd3d_signal_event(HANDLE event);
+VKD3D_UTILS_API unsigned int vkd3d_wait_event(HANDLE event, unsigned int milliseconds);
+VKD3D_UTILS_API void vkd3d_destroy_event(HANDLE event);
+
+#define D3D12CreateDevice(a, b, c, d) D3D12CreateDeviceVKD3D(a, b, c, d, VKD3D_UTILS_API_VERSION)
+VKD3D_UTILS_API HRESULT WINAPI D3D12CreateRootSignatureDeserializer(
+ const void *data, SIZE_T data_size, REFIID iid, void **deserializer);
+VKD3D_UTILS_API HRESULT WINAPI D3D12GetDebugInterface(REFIID iid, void **debug);
+VKD3D_UTILS_API HRESULT WINAPI D3D12SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC *desc,
+ D3D_ROOT_SIGNATURE_VERSION version, ID3DBlob **blob, ID3DBlob **error_blob);
+
+/* 1.2 */
+VKD3D_UTILS_API HRESULT WINAPI D3D12CreateDeviceVKD3D(IUnknown *adapter, D3D_FEATURE_LEVEL feature_level,
+ REFIID iid, void **device, enum vkd3d_api_version api_version);
+VKD3D_UTILS_API HRESULT WINAPI D3D12CreateVersionedRootSignatureDeserializer(const void *data,
+ SIZE_T data_size, REFIID iid, void **deserializer);
+VKD3D_UTILS_API HRESULT WINAPI D3D12SerializeVersionedRootSignature(const D3D12_VERSIONED_ROOT_SIGNATURE_DESC *desc,
+ ID3DBlob **blob, ID3DBlob **error_blob);
+
+/* 1.3 */
+VKD3D_UTILS_API HRESULT WINAPI D3DCompile(const void *data, SIZE_T data_size, const char *filename,
+ const D3D_SHADER_MACRO *defines, ID3DInclude *include, const char *entrypoint,
+ const char *target, UINT flags, UINT effect_flags, ID3DBlob **shader, ID3DBlob **error_messages);
+VKD3D_UTILS_API HRESULT WINAPI D3DCompile2(const void *data, SIZE_T data_size, const char *filename,
+ const D3D_SHADER_MACRO *defines, ID3DInclude *include, const char *entrypoint,
+ const char *target, UINT flags, UINT effect_flags, UINT secondary_flags,
+ const void *secondary_data, SIZE_T secondary_data_size, ID3DBlob **shader,
+ ID3DBlob **error_messages);
+VKD3D_UTILS_API HRESULT WINAPI D3DCreateBlob(SIZE_T data_size, ID3DBlob **blob);
+VKD3D_UTILS_API HRESULT WINAPI D3DPreprocess(const void *data, SIZE_T size, const char *filename,
+ const D3D_SHADER_MACRO *defines, ID3DInclude *include,
+ ID3DBlob **shader, ID3DBlob **error_messages);
+
+/**
+ * Set a callback to be called when vkd3d-utils outputs debug logging.
+ *
+ * If NULL, or if this function has not been called, libvkd3d-utils will print
+ * all enabled log output to stderr.
+ *
+ * Calling this function will also set the log callback for libvkd3d and
+ * libvkd3d-shader.
+ *
+ * \param callback Callback function to set.
+ *
+ * \since 1.4
+ */
+VKD3D_UTILS_API void vkd3d_utils_set_log_callback(PFN_vkd3d_log callback);
+
+/** \since 1.10 */
+VKD3D_UTILS_API HRESULT WINAPI D3DGetBlobPart(const void *data,
+ SIZE_T data_size, D3D_BLOB_PART part, UINT flags, ID3DBlob **blob);
+/** \since 1.10 */
+VKD3D_UTILS_API HRESULT WINAPI D3DGetDebugInfo(const void *data, SIZE_T data_size, ID3DBlob **blob);
+/** \since 1.10 */
+VKD3D_UTILS_API HRESULT WINAPI D3DGetInputAndOutputSignatureBlob(const void *data, SIZE_T data_size, ID3DBlob **blob);
+/** \since 1.10 */
+VKD3D_UTILS_API HRESULT WINAPI D3DGetInputSignatureBlob(const void *data, SIZE_T data_size, ID3DBlob **blob);
+/** \since 1.10 */
+VKD3D_UTILS_API HRESULT WINAPI D3DGetOutputSignatureBlob(const void *data, SIZE_T data_size, ID3DBlob **blob);
+/** \since 1.10 */
+VKD3D_UTILS_API HRESULT WINAPI D3DStripShader(const void *data, SIZE_T data_size, UINT flags, ID3DBlob **blob);
+
+/** \since 1.11 */
+VKD3D_UTILS_API HRESULT WINAPI D3DDisassemble(const void *data,
+ SIZE_T data_size, UINT flags, const char *comments, ID3DBlob **blob);
+VKD3D_UTILS_API HRESULT WINAPI D3DReflect(const void *data, SIZE_T data_size, REFIID iid, void **reflection);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __VKD3D_UTILS_H */
diff --git a/libs/vkd3d/include/vkd3d_windows.h b/libs/vkd3d/include/vkd3d_windows.h
new file mode 100644
index 00000000000..7b0e972d828
--- /dev/null
+++ b/libs/vkd3d/include/vkd3d_windows.h
@@ -0,0 +1,289 @@
+/*
+ * Copyright 2016 Józef Kucia for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __VKD3D_WINDOWS_H
+#define __VKD3D_WINDOWS_H
+#ifndef _INC_WINDOWS
+
+/* Nameless unions */
+#ifndef __C89_NAMELESS
+# ifdef NONAMELESSUNION
+# define __C89_NAMELESS
+# define __C89_NAMELESSUNIONNAME u
+# else
+# define __C89_NAMELESS
+# define __C89_NAMELESSUNIONNAME
+# endif /* NONAMELESSUNION */
+#endif /* __C89_NAMELESS */
+
+#if !defined(_WIN32) || defined(__WIDL__)
+
+# if !defined(__WIDL__)
+# if !defined(VKD3D_WIN32_WCHAR)
+# include <wchar.h>
+# endif
+# include <stdint.h>
+# endif
+
+# ifdef __GNUC__
+# define DECLSPEC_ALIGN(x) __attribute__((aligned(x)))
+# endif
+
+/* HRESULT */
+typedef int HRESULT;
+# define SUCCEEDED(hr) ((HRESULT)(hr) >= 0)
+# define FAILED(hr) ((HRESULT)(hr) < 0)
+
+# define _HRESULT_TYPEDEF_(x) ((HRESULT)x)
+
+# define S_OK _HRESULT_TYPEDEF_(0)
+# define S_FALSE _HRESULT_TYPEDEF_(1)
+
+# define E_NOTIMPL _HRESULT_TYPEDEF_(0x80004001)
+# define E_NOINTERFACE _HRESULT_TYPEDEF_(0x80004002)
+# define E_POINTER _HRESULT_TYPEDEF_(0x80004003)
+# define E_ABORT _HRESULT_TYPEDEF_(0x80004004)
+# define E_FAIL _HRESULT_TYPEDEF_(0x80004005)
+# define E_OUTOFMEMORY _HRESULT_TYPEDEF_(0x8007000E)
+# define E_INVALIDARG _HRESULT_TYPEDEF_(0x80070057)
+
+# define DXGI_ERROR_NOT_FOUND _HRESULT_TYPEDEF_(0x887a0002)
+# define DXGI_ERROR_MORE_DATA _HRESULT_TYPEDEF_(0x887a0003)
+# define DXGI_ERROR_UNSUPPORTED _HRESULT_TYPEDEF_(0x887a0004)
+
+# define D3DERR_INVALIDCALL _HRESULT_TYPEDEF_(0x8876086c)
+
+/* Basic types */
+typedef unsigned char BYTE;
+typedef unsigned int DWORD;
+typedef int INT;
+typedef unsigned int UINT;
+typedef int LONG;
+typedef unsigned int ULONG;
+typedef float FLOAT;
+typedef LONG BOOL;
+
+/* Assuming LP64 model */
+typedef char INT8;
+typedef unsigned char UINT8;
+typedef short INT16;
+typedef unsigned short UINT16;
+typedef int INT32;
+typedef unsigned int UINT32;
+# if defined(__WIDL__)
+typedef __int64 INT64;
+typedef unsigned __int64 UINT64;
+# else
+typedef int64_t DECLSPEC_ALIGN(8) INT64;
+typedef uint64_t DECLSPEC_ALIGN(8) UINT64;
+# endif
+typedef INT64 LONG64;
+typedef long LONG_PTR;
+typedef unsigned long ULONG_PTR;
+
+typedef ULONG_PTR SIZE_T;
+
+# ifdef VKD3D_WIN32_WCHAR
+typedef unsigned short WCHAR;
+# else
+typedef wchar_t WCHAR;
+# endif /* VKD3D_WIN32_WCHAR */
+typedef void *HANDLE;
+
+/* GUID */
+# ifdef __WIDL__
+typedef struct
+{
+ unsigned long Data1;
+ unsigned short Data2;
+ unsigned short Data3;
+ unsigned char Data4[8];
+} GUID;
+# else
+typedef struct _GUID
+{
+ unsigned int Data1;
+ unsigned short Data2;
+ unsigned short Data3;
+ unsigned char Data4[8];
+} GUID;
+# endif
+
+typedef GUID IID;
+typedef GUID CLSID;
+typedef GUID UUID;
+
+# ifdef INITGUID
+# ifndef __cplusplus
+# define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+ const GUID name DECLSPEC_HIDDEN; \
+ const GUID name = \
+ { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 }}
+# else
+# define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+ EXTERN_C const GUID name DECLSPEC_HIDDEN; \
+ EXTERN_C const GUID name = \
+ { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 }}
+# endif
+# else
+# define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+ EXTERN_C const GUID name DECLSPEC_HIDDEN;
+# endif /* INITGUID */
+
+/* __uuidof emulation */
+#if defined(__cplusplus) && !defined(_MSC_VER)
+
+extern "C++"
+{
+ template<typename T> const GUID &__vkd3d_uuidof();
+}
+
+# define __CRT_UUID_DECL(type, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+ extern "C++" \
+ { \
+ template<> inline const GUID &__vkd3d_uuidof<type>() \
+ { \
+ static const IID __uuid_inst = {l, w1, w2, {b1, b2, b3, b4, b5, b6, b7, b8}}; \
+ return __uuid_inst; \
+ } \
+ template<> inline const GUID &__vkd3d_uuidof<type *>() \
+ { \
+ return __vkd3d_uuidof<type>(); \
+ } \
+ }
+
+# define __uuidof(type) __vkd3d_uuidof<typeof(type)>()
+#else
+# define __CRT_UUID_DECL(type, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8)
+#endif /* defined(__cplusplus) && !defined(_MSC_VER) */
+
+typedef struct SECURITY_ATTRIBUTES SECURITY_ATTRIBUTES;
+#endif /* !defined(_WIN32) || defined(__WIDL__) */
+
+
+#ifndef _WIN32
+# include <stddef.h>
+# include <stdlib.h>
+# include <string.h>
+
+# define COM_NO_WINDOWS_H
+
+# define FORCEINLINE inline
+
+# define CONTAINING_RECORD(address, type, field) \
+ ((type *)((char *)(address) - offsetof(type, field)))
+
+# ifdef __x86_64__
+# define __stdcall __attribute__((ms_abi))
+# else
+# if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 2)) || defined(__APPLE__)
+# define __stdcall __attribute__((__stdcall__)) __attribute__((__force_align_arg_pointer__))
+# else
+# define __stdcall __attribute__((__stdcall__))
+# endif
+# endif
+
+# define WINAPI __stdcall
+# define STDMETHODCALLTYPE __stdcall
+
+# ifdef __GNUC__
+# define DECLSPEC_SELECTANY __attribute__((weak))
+# endif
+
+/* Macros for COM interfaces */
+# define interface struct
+# define BEGIN_INTERFACE
+# define END_INTERFACE
+# define MIDL_INTERFACE(x) struct
+
+# ifdef __cplusplus
+# define EXTERN_C extern "C"
+# else
+# define EXTERN_C extern
+# endif
+
+# define CONST_VTBL const
+
+# define TRUE 1
+# define FALSE 0
+
+# if defined(__cplusplus) && !defined(CINTERFACE)
+# define REFIID const IID &
+# define REFGUID const GUID &
+# define REFCLSID const CLSID &
+# else
+# define REFIID const IID * const
+# define REFGUID const GUID * const
+# define REFCLSID const CLSID * const
+# endif
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+# define IsEqualGUID(guid1, guid2) (!memcmp(&(guid1), &(guid2), sizeof(GUID)))
+#else
+# define IsEqualGUID(guid1, guid2) (!memcmp(guid1, guid2, sizeof(GUID)))
+#endif
+
+#elif !defined(__WIDL__)
+
+# include <windows.h>
+
+#endif /* _WIN32 */
+
+
+/* Define DECLSPEC_HIDDEN */
+#ifndef DECLSPEC_HIDDEN
+# if defined(__MINGW32__)
+# define DECLSPEC_HIDDEN
+# elif defined(__GNUC__)
+# define DECLSPEC_HIDDEN __attribute__((visibility("hidden")))
+# else
+# define DECLSPEC_HIDDEN
+# endif
+#endif /* DECLSPEC_HIDDEN */
+
+/* Define min() & max() macros */
+#ifndef NOMINMAX
+# ifndef min
+# define min(a, b) (((a) <= (b)) ? (a) : (b))
+# endif
+
+# ifndef max
+# define max(a, b) (((a) >= (b)) ? (a) : (b))
+# endif
+#endif /* NOMINMAX */
+
+#ifndef DEFINE_ENUM_FLAG_OPERATORS
+#ifdef __cplusplus
+# define DEFINE_ENUM_FLAG_OPERATORS(type) \
+extern "C++" \
+{ \
+ inline type operator &(type x, type y) { return (type)((int)x & (int)y); } \
+ inline type operator &=(type &x, type y) { return (type &)((int &)x &= (int)y); } \
+ inline type operator ~(type x) { return (type)~(int)x; } \
+ inline type operator |(type x, type y) { return (type)((int)x | (int)y); } \
+ inline type operator |=(type &x, type y) { return (type &)((int &)x |= (int)y); } \
+ inline type operator ^(type x, type y) { return (type)((int)x ^ (int)y); } \
+ inline type operator ^=(type &x, type y) { return (type &)((int &)x ^= (int)y); } \
+}
+#else
+# define DEFINE_ENUM_FLAG_OPERATORS(type)
+#endif
+#endif /* DEFINE_ENUM_FLAG_OPERATORS */
+
+#endif /* _INC_WINDOWS */
+#endif /* __VKD3D_WINDOWS_H */
diff --git a/libs/vkd3d/libs/vkd3d-common/blob.c b/libs/vkd3d/libs/vkd3d-common/blob.c
index 71ab9a2c51e..dbb26de7d73 100644
--- a/libs/vkd3d/libs/vkd3d-common/blob.c
+++ b/libs/vkd3d/libs/vkd3d-common/blob.c
@@ -17,16 +17,18 @@
*/
#define COBJMACROS
+
#define CONST_VTABLE
#include "vkd3d.h"
#include "vkd3d_blob.h"
#include "vkd3d_debug.h"
#include "vkd3d_memory.h"
+#include "d3d12shader.h"
struct vkd3d_blob
{
ID3D10Blob ID3DBlob_iface;
- LONG refcount;
+ unsigned int refcount;
void *buffer;
SIZE_T size;
@@ -58,7 +60,7 @@ static HRESULT STDMETHODCALLTYPE vkd3d_blob_QueryInterface(ID3DBlob *iface, REFI
static ULONG STDMETHODCALLTYPE vkd3d_blob_AddRef(ID3DBlob *iface)
{
struct vkd3d_blob *blob = impl_from_ID3DBlob(iface);
- ULONG refcount = InterlockedIncrement(&blob->refcount);
+ unsigned int refcount = vkd3d_atomic_increment_u32(&blob->refcount);
TRACE("%p increasing refcount to %u.\n", blob, refcount);
@@ -68,7 +70,7 @@ static ULONG STDMETHODCALLTYPE vkd3d_blob_AddRef(ID3DBlob *iface)
static ULONG STDMETHODCALLTYPE vkd3d_blob_Release(ID3DBlob *iface)
{
struct vkd3d_blob *blob = impl_from_ID3DBlob(iface);
- ULONG refcount = InterlockedDecrement(&blob->refcount);
+ unsigned int refcount = vkd3d_atomic_decrement_u32(&blob->refcount);
TRACE("%p decreasing refcount to %u.\n", blob, refcount);
diff --git a/libs/vkd3d/libs/vkd3d-common/debug.c b/libs/vkd3d/libs/vkd3d-common/debug.c
index aa7df5bd764..e12cd39450a 100644
--- a/libs/vkd3d/libs/vkd3d-common/debug.c
+++ b/libs/vkd3d/libs/vkd3d-common/debug.c
@@ -126,10 +126,10 @@ void vkd3d_dbg_set_log_callback(PFN_vkd3d_log callback)
static char *get_buffer(void)
{
static char buffers[VKD3D_DEBUG_BUFFER_COUNT][VKD3D_DEBUG_BUFFER_SIZE];
- static LONG buffer_index;
- LONG current_index;
+ static unsigned int buffer_index;
+ unsigned int current_index;
- current_index = InterlockedIncrement(&buffer_index) % ARRAY_SIZE(buffers);
+ current_index = vkd3d_atomic_increment_u32(&buffer_index) % ARRAY_SIZE(buffers);
return buffers[current_index];
}
diff --git a/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c b/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c
index 82d1d71d9d3..3f86bd45960 100644
--- a/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c
+++ b/libs/vkd3d/libs/vkd3d-shader/d3d_asm.c
@@ -30,8 +30,11 @@
static const char * const shader_opcode_names[] =
{
[VKD3DSIH_ABS ] = "abs",
+ [VKD3DSIH_ACOS ] = "acos",
[VKD3DSIH_ADD ] = "add",
[VKD3DSIH_AND ] = "and",
+ [VKD3DSIH_ASIN ] = "asin",
+ [VKD3DSIH_ATAN ] = "atan",
[VKD3DSIH_ATOMIC_AND ] = "atomic_and",
[VKD3DSIH_ATOMIC_CMP_STORE ] = "atomic_cmp_store",
[VKD3DSIH_ATOMIC_IADD ] = "atomic_iadd",
@@ -44,6 +47,7 @@ static const char * const shader_opcode_names[] =
[VKD3DSIH_BEM ] = "bem",
[VKD3DSIH_BFI ] = "bfi",
[VKD3DSIH_BFREV ] = "bfrev",
+ [VKD3DSIH_BRANCH ] = "branch",
[VKD3DSIH_BREAK ] = "break",
[VKD3DSIH_BREAKC ] = "breakc",
[VKD3DSIH_BREAKP ] = "breakp",
@@ -167,10 +171,13 @@ static const char * const shader_opcode_names[] =
[VKD3DSIH_GATHER4_S ] = "gather4_s",
[VKD3DSIH_GEO ] = "ge",
[VKD3DSIH_GEU ] = "ge_unord",
+ [VKD3DSIH_HCOS ] = "hcos",
[VKD3DSIH_HS_CONTROL_POINT_PHASE ] = "hs_control_point_phase",
[VKD3DSIH_HS_DECLS ] = "hs_decls",
[VKD3DSIH_HS_FORK_PHASE ] = "hs_fork_phase",
[VKD3DSIH_HS_JOIN_PHASE ] = "hs_join_phase",
+ [VKD3DSIH_HSIN ] = "hsin",
+ [VKD3DSIH_HTAN ] = "htan",
[VKD3DSIH_IADD ] = "iadd",
[VKD3DSIH_IBFE ] = "ibfe",
[VKD3DSIH_IDIV ] = "idiv",
@@ -197,8 +204,11 @@ static const char * const shader_opcode_names[] =
[VKD3DSIH_IMUL ] = "imul",
[VKD3DSIH_INE ] = "ine",
[VKD3DSIH_INEG ] = "ineg",
+ [VKD3DSIH_ISFINITE ] = "isfinite",
[VKD3DSIH_ISHL ] = "ishl",
[VKD3DSIH_ISHR ] = "ishr",
+ [VKD3DSIH_ISINF ] = "isinf",
+ [VKD3DSIH_ISNAN ] = "isnan",
[VKD3DSIH_ITOD ] = "itod",
[VKD3DSIH_ITOF ] = "itof",
[VKD3DSIH_ITOI ] = "itoi",
@@ -241,6 +251,7 @@ static const char * const shader_opcode_names[] =
[VKD3DSIH_NRM ] = "nrm",
[VKD3DSIH_OR ] = "or",
[VKD3DSIH_PHASE ] = "phase",
+ [VKD3DSIH_PHI ] = "phi",
[VKD3DSIH_POW ] = "pow",
[VKD3DSIH_RCP ] = "rcp",
[VKD3DSIH_REP ] = "rep",
@@ -278,7 +289,9 @@ static const char * const shader_opcode_names[] =
[VKD3DSIH_SUB ] = "sub",
[VKD3DSIH_SWAPC ] = "swapc",
[VKD3DSIH_SWITCH ] = "switch",
+ [VKD3DSIH_SWITCH_MONOLITHIC ] = "switch",
[VKD3DSIH_SYNC ] = "sync",
+ [VKD3DSIH_TAN ] = "tan",
[VKD3DSIH_TEX ] = "texld",
[VKD3DSIH_TEXBEM ] = "texbem",
[VKD3DSIH_TEXBEML ] = "texbeml",
@@ -364,6 +377,8 @@ struct vkd3d_d3d_asm_compiler
struct vkd3d_string_buffer buffer;
struct vkd3d_shader_version shader_version;
struct vkd3d_d3d_asm_colours colours;
+ enum vsir_asm_dialect dialect;
+ const struct vkd3d_shader_instruction *current;
};
static int VKD3D_PRINTF_FUNC(2, 3) shader_addline(struct vkd3d_string_buffer *buffer, const char *format, ...)
@@ -437,6 +452,11 @@ static void shader_dump_sync_flags(struct vkd3d_d3d_asm_compiler *compiler, uint
vkd3d_string_buffer_printf(&compiler->buffer, "_uglobal");
sync_flags &= ~VKD3DSSF_GLOBAL_UAV;
}
+ if (sync_flags & VKD3DSSF_THREAD_GROUP_UAV)
+ {
+ vkd3d_string_buffer_printf(&compiler->buffer, "_ugroup");
+ sync_flags &= ~VKD3DSSF_THREAD_GROUP_UAV;
+ }
if (sync_flags & VKD3DSSF_GROUP_SHARED_MEMORY)
{
vkd3d_string_buffer_printf(&compiler->buffer, "_g");
@@ -606,7 +626,7 @@ static void shader_dump_resource_type(struct vkd3d_d3d_asm_compiler *compiler, e
vkd3d_string_buffer_printf(&compiler->buffer, "unknown");
}
-static void shader_dump_data_type(struct vkd3d_d3d_asm_compiler *compiler, const enum vkd3d_data_type *type)
+static void shader_dump_data_type(struct vkd3d_d3d_asm_compiler *compiler, enum vkd3d_data_type type)
{
static const char *const data_type_names[] =
{
@@ -623,19 +643,31 @@ static void shader_dump_data_type(struct vkd3d_d3d_asm_compiler *compiler, const
[VKD3D_DATA_DOUBLE ] = "double",
[VKD3D_DATA_CONTINUED] = "<continued>",
[VKD3D_DATA_UNUSED ] = "<unused>",
+ [VKD3D_DATA_UINT8 ] = "uint8",
+ [VKD3D_DATA_UINT64 ] = "uint64",
+ [VKD3D_DATA_BOOL ] = "bool",
};
+
const char *name;
+
+ if (type < ARRAY_SIZE(data_type_names))
+ name = data_type_names[type];
+ else
+ name = "<unknown>";
+
+ vkd3d_string_buffer_printf(&compiler->buffer, "%s", name);
+}
+
+static void shader_dump_resource_data_type(struct vkd3d_d3d_asm_compiler *compiler, const enum vkd3d_data_type *type)
+{
int i;
vkd3d_string_buffer_printf(&compiler->buffer, "(");
for (i = 0; i < 4; i++)
{
- if (type[i] < ARRAY_SIZE(data_type_names))
- name = data_type_names[type[i]];
- else
- name = "unknown";
- vkd3d_string_buffer_printf(&compiler->buffer, "%s%s", i == 0 ? "" : ",", name);
+ vkd3d_string_buffer_printf(&compiler->buffer, "%s", i == 0 ? "" : ",");
+ shader_dump_data_type(compiler, type[i]);
}
vkd3d_string_buffer_printf(&compiler->buffer, ")");
@@ -682,7 +714,7 @@ static void shader_dump_decl_usage(struct vkd3d_d3d_asm_compiler *compiler,
if (semantic->resource.reg.reg.type == VKD3DSPR_UAV)
shader_dump_uav_flags(compiler, flags);
shader_addline(buffer, " ");
- shader_dump_data_type(compiler, semantic->resource_data_type);
+ shader_dump_resource_data_type(compiler, semantic->resource_data_type);
}
else
{
@@ -814,6 +846,13 @@ static void shader_print_uint_literal(struct vkd3d_d3d_asm_compiler *compiler,
prefix, compiler->colours.literal, i, compiler->colours.reset, suffix);
}
+static void shader_print_uint64_literal(struct vkd3d_d3d_asm_compiler *compiler,
+ const char *prefix, uint64_t i, const char *suffix)
+{
+ vkd3d_string_buffer_printf(&compiler->buffer, "%s%s%"PRIu64"%s%s",
+ prefix, compiler->colours.literal, i, compiler->colours.reset, suffix);
+}
+
static void shader_print_hex_literal(struct vkd3d_d3d_asm_compiler *compiler,
const char *prefix, unsigned int i, const char *suffix)
{
@@ -828,6 +867,27 @@ static void shader_print_bool_literal(struct vkd3d_d3d_asm_compiler *compiler,
compiler->colours.literal, b ? "true" : "false", compiler->colours.reset, suffix);
}
+static void shader_print_untyped_literal(struct vkd3d_d3d_asm_compiler *compiler,
+ const char *prefix, uint32_t u, const char *suffix)
+{
+ union
+ {
+ uint32_t u;
+ float f;
+ } value;
+ unsigned int exponent = (u >> 23) & 0xff;
+
+ value.u = u;
+
+ if (exponent != 0 && exponent != 0xff)
+ return shader_print_float_literal(compiler, prefix, value.f, suffix);
+
+ if (u <= 10000)
+ return shader_print_uint_literal(compiler, prefix, value.u, suffix);
+
+ return shader_print_hex_literal(compiler, prefix, value.u, suffix);
+}
+
static void shader_print_subscript(struct vkd3d_d3d_asm_compiler *compiler,
unsigned int offset, const struct vkd3d_shader_src_param *rel_addr)
{
@@ -1089,6 +1149,19 @@ static void shader_dump_register(struct vkd3d_d3d_asm_compiler *compiler, const
if (reg->type == VKD3DSPR_IMMCONST)
{
+ bool untyped = false;
+
+ switch (compiler->current->handler_idx)
+ {
+ case VKD3DSIH_MOV:
+ case VKD3DSIH_MOVC:
+ untyped = true;
+ break;
+
+ default:
+ break;
+ }
+
shader_addline(buffer, "%s(", compiler->colours.reset);
switch (reg->dimension)
{
@@ -1096,15 +1169,18 @@ static void shader_dump_register(struct vkd3d_d3d_asm_compiler *compiler, const
switch (reg->data_type)
{
case VKD3D_DATA_FLOAT:
- shader_print_float_literal(compiler, "", reg->u.immconst_float[0], "");
+ if (untyped)
+ shader_print_untyped_literal(compiler, "", reg->u.immconst_u32[0], "");
+ else
+ shader_print_float_literal(compiler, "", reg->u.immconst_f32[0], "");
break;
case VKD3D_DATA_INT:
- shader_print_int_literal(compiler, "", reg->u.immconst_uint[0], "");
+ shader_print_int_literal(compiler, "", reg->u.immconst_u32[0], "");
break;
case VKD3D_DATA_RESOURCE:
case VKD3D_DATA_SAMPLER:
case VKD3D_DATA_UINT:
- shader_print_uint_literal(compiler, "", reg->u.immconst_uint[0], "");
+ shader_print_uint_literal(compiler, "", reg->u.immconst_u32[0], "");
break;
default:
shader_addline(buffer, "<unhandled data type %#x>", reg->data_type);
@@ -1116,24 +1192,34 @@ static void shader_dump_register(struct vkd3d_d3d_asm_compiler *compiler, const
switch (reg->data_type)
{
case VKD3D_DATA_FLOAT:
- shader_print_float_literal(compiler, "", reg->u.immconst_float[0], "");
- shader_print_float_literal(compiler, ", ", reg->u.immconst_float[1], "");
- shader_print_float_literal(compiler, ", ", reg->u.immconst_float[2], "");
- shader_print_float_literal(compiler, ", ", reg->u.immconst_float[3], "");
+ if (untyped)
+ {
+ shader_print_untyped_literal(compiler, "", reg->u.immconst_u32[0], "");
+ shader_print_untyped_literal(compiler, ", ", reg->u.immconst_u32[1], "");
+ shader_print_untyped_literal(compiler, ", ", reg->u.immconst_u32[2], "");
+ shader_print_untyped_literal(compiler, ", ", reg->u.immconst_u32[3], "");
+ }
+ else
+ {
+ shader_print_float_literal(compiler, "", reg->u.immconst_f32[0], "");
+ shader_print_float_literal(compiler, ", ", reg->u.immconst_f32[1], "");
+ shader_print_float_literal(compiler, ", ", reg->u.immconst_f32[2], "");
+ shader_print_float_literal(compiler, ", ", reg->u.immconst_f32[3], "");
+ }
break;
case VKD3D_DATA_INT:
- shader_print_int_literal(compiler, "", reg->u.immconst_uint[0], "");
- shader_print_int_literal(compiler, ", ", reg->u.immconst_uint[1], "");
- shader_print_int_literal(compiler, ", ", reg->u.immconst_uint[2], "");
- shader_print_int_literal(compiler, ", ", reg->u.immconst_uint[3], "");
+ shader_print_int_literal(compiler, "", reg->u.immconst_u32[0], "");
+ shader_print_int_literal(compiler, ", ", reg->u.immconst_u32[1], "");
+ shader_print_int_literal(compiler, ", ", reg->u.immconst_u32[2], "");
+ shader_print_int_literal(compiler, ", ", reg->u.immconst_u32[3], "");
break;
case VKD3D_DATA_RESOURCE:
case VKD3D_DATA_SAMPLER:
case VKD3D_DATA_UINT:
- shader_print_uint_literal(compiler, "", reg->u.immconst_uint[0], "");
- shader_print_uint_literal(compiler, ", ", reg->u.immconst_uint[1], "");
- shader_print_uint_literal(compiler, ", ", reg->u.immconst_uint[2], "");
- shader_print_uint_literal(compiler, ", ", reg->u.immconst_uint[3], "");
+ shader_print_uint_literal(compiler, "", reg->u.immconst_u32[0], "");
+ shader_print_uint_literal(compiler, ", ", reg->u.immconst_u32[1], "");
+ shader_print_uint_literal(compiler, ", ", reg->u.immconst_u32[2], "");
+ shader_print_uint_literal(compiler, ", ", reg->u.immconst_u32[3], "");
break;
default:
shader_addline(buffer, "<unhandled data type %#x>", reg->data_type);
@@ -1155,9 +1241,15 @@ static void shader_dump_register(struct vkd3d_d3d_asm_compiler *compiler, const
{
if (reg->data_type == VKD3D_DATA_DOUBLE)
{
- shader_print_double_literal(compiler, "", reg->u.immconst_double[0], "");
+ shader_print_double_literal(compiler, "", reg->u.immconst_f64[0], "");
+ if (reg->dimension == VSIR_DIMENSION_VEC4)
+ shader_print_double_literal(compiler, ", ", reg->u.immconst_f64[1], "");
+ }
+ else if (reg->data_type == VKD3D_DATA_UINT64)
+ {
+ shader_print_uint64_literal(compiler, "", reg->u.immconst_u64[0], "");
if (reg->dimension == VSIR_DIMENSION_VEC4)
- shader_print_double_literal(compiler, ", ", reg->u.immconst_double[1], "");
+ shader_print_uint64_literal(compiler, "", reg->u.immconst_u64[1], "");
}
else
{
@@ -1265,6 +1357,32 @@ static void shader_print_non_uniform(struct vkd3d_d3d_asm_compiler *compiler, co
compiler->colours.modifier, compiler->colours.reset);
}
+static void shader_dump_reg_type(struct vkd3d_d3d_asm_compiler *compiler,
+ const struct vkd3d_shader_register *reg)
+{
+ static const char *dimensions[] =
+ {
+ [VSIR_DIMENSION_NONE] = "",
+ [VSIR_DIMENSION_SCALAR] = "s:",
+ [VSIR_DIMENSION_VEC4] = "v4:",
+ };
+
+ struct vkd3d_string_buffer *buffer = &compiler->buffer;
+ const char *dimension;
+
+ if (compiler->dialect != VSIR_ASM_VSIR)
+ return;
+
+ if (reg->dimension < ARRAY_SIZE(dimensions))
+ dimension = dimensions[reg->dimension];
+ else
+ dimension = "??";
+
+ shader_addline(buffer, " <%s", dimension);
+ shader_dump_data_type(compiler, reg->data_type);
+ shader_addline(buffer, ">");
+}
+
static void shader_dump_dst_param(struct vkd3d_d3d_asm_compiler *compiler,
const struct vkd3d_shader_dst_param *param, bool is_declaration)
{
@@ -1277,8 +1395,8 @@ static void shader_dump_dst_param(struct vkd3d_d3d_asm_compiler *compiler,
{
static const char write_mask_chars[] = "xyzw";
- if (param->reg.data_type == VKD3D_DATA_DOUBLE)
- write_mask = vkd3d_write_mask_32_from_64(write_mask);
+ if (data_type_is_64_bit(param->reg.data_type))
+ write_mask = vsir_write_mask_32_from_64(write_mask);
shader_addline(buffer, ".%s", compiler->colours.write_mask);
if (write_mask & VKD3DSP_WRITEMASK_0)
@@ -1294,6 +1412,7 @@ static void shader_dump_dst_param(struct vkd3d_d3d_asm_compiler *compiler,
shader_print_precision(compiler, &param->reg);
shader_print_non_uniform(compiler, &param->reg);
+ shader_dump_reg_type(compiler, &param->reg);
}
static void shader_dump_src_param(struct vkd3d_d3d_asm_compiler *compiler,
@@ -1341,13 +1460,18 @@ static void shader_dump_src_param(struct vkd3d_d3d_asm_compiler *compiler,
if (param->reg.type != VKD3DSPR_IMMCONST && param->reg.type != VKD3DSPR_IMMCONST64
&& param->reg.dimension == VSIR_DIMENSION_VEC4)
{
- unsigned int swizzle_x = vkd3d_swizzle_get_component(swizzle, 0);
- unsigned int swizzle_y = vkd3d_swizzle_get_component(swizzle, 1);
- unsigned int swizzle_z = vkd3d_swizzle_get_component(swizzle, 2);
- unsigned int swizzle_w = vkd3d_swizzle_get_component(swizzle, 3);
-
static const char swizzle_chars[] = "xyzw";
+ unsigned int swizzle_x, swizzle_y, swizzle_z, swizzle_w;
+
+ if (data_type_is_64_bit(param->reg.data_type))
+ swizzle = vsir_swizzle_32_from_64(swizzle);
+
+ swizzle_x = vsir_swizzle_get_component(swizzle, 0);
+ swizzle_y = vsir_swizzle_get_component(swizzle, 1);
+ swizzle_z = vsir_swizzle_get_component(swizzle, 2);
+ swizzle_w = vsir_swizzle_get_component(swizzle, 3);
+
if (swizzle_x == swizzle_y
&& swizzle_x == swizzle_z
&& swizzle_x == swizzle_w)
@@ -1367,6 +1491,7 @@ static void shader_dump_src_param(struct vkd3d_d3d_asm_compiler *compiler,
shader_print_precision(compiler, &param->reg);
shader_print_non_uniform(compiler, &param->reg);
+ shader_dump_reg_type(compiler, &param->reg);
}
static void shader_dump_ins_modifiers(struct vkd3d_d3d_asm_compiler *compiler,
@@ -1577,6 +1702,12 @@ static void shader_dump_instruction_flags(struct vkd3d_d3d_asm_compiler *compile
shader_addline(buffer, "p");
break;
+ case VKD3DSIH_ISHL:
+ case VKD3DSIH_ISHR:
+ case VKD3DSIH_USHR:
+ if (ins->flags & VKD3DSI_SHIFT_UNMASKED)
+ shader_addline(buffer, "_unmasked");
+ /* fall through */
default:
shader_dump_precise_flags(compiler, ins->flags);
break;
@@ -1631,6 +1762,8 @@ static void shader_dump_instruction(struct vkd3d_d3d_asm_compiler *compiler,
struct vkd3d_string_buffer *buffer = &compiler->buffer;
unsigned int i;
+ compiler->current = ins;
+
if (ins->predicate)
{
vkd3d_string_buffer_printf(buffer, "(");
@@ -1835,25 +1968,25 @@ static void shader_dump_instruction(struct vkd3d_d3d_asm_compiler *compiler,
vkd3d_string_buffer_printf(buffer, " %sc%u%s", compiler->colours.reg,
shader_get_float_offset(ins->dst[0].reg.type, ins->dst[0].reg.idx[0].offset),
compiler->colours.reset);
- shader_print_float_literal(compiler, " = ", ins->src[0].reg.u.immconst_float[0], "");
- shader_print_float_literal(compiler, ", ", ins->src[0].reg.u.immconst_float[1], "");
- shader_print_float_literal(compiler, ", ", ins->src[0].reg.u.immconst_float[2], "");
- shader_print_float_literal(compiler, ", ", ins->src[0].reg.u.immconst_float[3], "");
+ shader_print_float_literal(compiler, " = ", ins->src[0].reg.u.immconst_f32[0], "");
+ shader_print_float_literal(compiler, ", ", ins->src[0].reg.u.immconst_f32[1], "");
+ shader_print_float_literal(compiler, ", ", ins->src[0].reg.u.immconst_f32[2], "");
+ shader_print_float_literal(compiler, ", ", ins->src[0].reg.u.immconst_f32[3], "");
break;
case VKD3DSIH_DEFI:
vkd3d_string_buffer_printf(buffer, " %si%u%s", compiler->colours.reg,
ins->dst[0].reg.idx[0].offset, compiler->colours.reset);
- shader_print_int_literal(compiler, " = ", ins->src[0].reg.u.immconst_uint[0], "");
- shader_print_int_literal(compiler, ", ", ins->src[0].reg.u.immconst_uint[1], "");
- shader_print_int_literal(compiler, ", ", ins->src[0].reg.u.immconst_uint[2], "");
- shader_print_int_literal(compiler, ", ", ins->src[0].reg.u.immconst_uint[3], "");
+ shader_print_int_literal(compiler, " = ", ins->src[0].reg.u.immconst_u32[0], "");
+ shader_print_int_literal(compiler, ", ", ins->src[0].reg.u.immconst_u32[1], "");
+ shader_print_int_literal(compiler, ", ", ins->src[0].reg.u.immconst_u32[2], "");
+ shader_print_int_literal(compiler, ", ", ins->src[0].reg.u.immconst_u32[3], "");
break;
case VKD3DSIH_DEFB:
vkd3d_string_buffer_printf(buffer, " %sb%u%s", compiler->colours.reg,
ins->dst[0].reg.idx[0].offset, compiler->colours.reset);
- shader_print_bool_literal(compiler, " = ", ins->src[0].reg.u.immconst_uint[0], "");
+ shader_print_bool_literal(compiler, " = ", ins->src[0].reg.u.immconst_u32[0], "");
break;
default:
@@ -1883,7 +2016,7 @@ static void shader_dump_instruction(struct vkd3d_d3d_asm_compiler *compiler,
|| ins->resource_data_type[1] != VKD3D_DATA_FLOAT
|| ins->resource_data_type[2] != VKD3D_DATA_FLOAT
|| ins->resource_data_type[3] != VKD3D_DATA_FLOAT)
- shader_dump_data_type(compiler, ins->resource_data_type);
+ shader_dump_resource_data_type(compiler, ins->resource_data_type);
for (i = 0; i < ins->dst_count; ++i)
{
@@ -1904,12 +2037,16 @@ static void shader_dump_instruction(struct vkd3d_d3d_asm_compiler *compiler,
shader_addline(buffer, "\n");
}
-enum vkd3d_result vkd3d_dxbc_binary_to_text(const struct vkd3d_shader_instruction_array *instructions,
- const struct vkd3d_shader_version *shader_version, const struct vkd3d_shader_compile_info *compile_info,
- struct vkd3d_shader_code *out)
+enum vkd3d_result vkd3d_dxbc_binary_to_text(const struct vsir_program *program,
+ const struct vkd3d_shader_compile_info *compile_info,
+ struct vkd3d_shader_code *out, enum vsir_asm_dialect dialect)
{
+ const struct vkd3d_shader_version *shader_version = &program->shader_version;
enum vkd3d_shader_compile_option_formatting_flags formatting;
- struct vkd3d_d3d_asm_compiler compiler;
+ struct vkd3d_d3d_asm_compiler compiler =
+ {
+ .dialect = dialect,
+ };
enum vkd3d_result result = VKD3D_OK;
struct vkd3d_string_buffer *buffer;
unsigned int indent, i, j;
@@ -1973,9 +2110,9 @@ enum vkd3d_result vkd3d_dxbc_binary_to_text(const struct vkd3d_shader_instructio
shader_version->minor, compiler.colours.reset);
indent = 0;
- for (i = 0; i < instructions->count; ++i)
+ for (i = 0; i < program->instructions.count; ++i)
{
- struct vkd3d_shader_instruction *ins = &instructions->elements[i];
+ struct vkd3d_shader_instruction *ins = &program->instructions.elements[i];
switch (ins->handler_idx)
{
@@ -2002,6 +2139,7 @@ enum vkd3d_result vkd3d_dxbc_binary_to_text(const struct vkd3d_shader_instructio
{
case VKD3DSIH_ELSE:
case VKD3DSIH_IF:
+ case VKD3DSIH_IFC:
case VKD3DSIH_LOOP:
case VKD3DSIH_SWITCH:
++indent;
@@ -2028,13 +2166,12 @@ enum vkd3d_result vkd3d_dxbc_binary_to_text(const struct vkd3d_shader_instructio
return result;
}
-void vkd3d_shader_trace(const struct vkd3d_shader_instruction_array *instructions,
- const struct vkd3d_shader_version *shader_version)
+void vkd3d_shader_trace(const struct vsir_program *program)
{
const char *p, *q, *end;
struct vkd3d_shader_code code;
- if (vkd3d_dxbc_binary_to_text(instructions, shader_version, NULL, &code) != VKD3D_OK)
+ if (vkd3d_dxbc_binary_to_text(program, NULL, &code, VSIR_ASM_VSIR) != VKD3D_OK)
return;
end = (const char *)code.code + code.size;
diff --git a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c
index 3d139416b61..9ad9f735dd1 100644
--- a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c
+++ b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c
@@ -414,6 +414,7 @@ static bool has_relative_address(uint32_t param)
static const struct vkd3d_sm1_opcode_info *shader_sm1_get_opcode_info(
const struct vkd3d_shader_sm1_parser *sm1, enum vkd3d_sm1_opcode opcode)
{
+ const struct vkd3d_shader_version *version = &sm1->p.program.shader_version;
const struct vkd3d_sm1_opcode_info *info;
unsigned int i = 0;
@@ -424,8 +425,8 @@ static const struct vkd3d_sm1_opcode_info *shader_sm1_get_opcode_info(
return NULL;
if (opcode == info->sm1_opcode
- && vkd3d_shader_ver_ge(&sm1->p.shader_version, info->min_version.major, info->min_version.minor)
- && (vkd3d_shader_ver_le(&sm1->p.shader_version, info->max_version.major, info->max_version.minor)
+ && vkd3d_shader_ver_ge(version, info->min_version.major, info->min_version.minor)
+ && (vkd3d_shader_ver_le(version, info->max_version.major, info->max_version.minor)
|| !info->max_version.major))
return info;
}
@@ -444,7 +445,7 @@ static uint32_t swizzle_from_sm1(uint32_t swizzle)
shader_sm1_get_swizzle_component(swizzle, 3));
}
-static void shader_sm1_parse_src_param(uint32_t param, const struct vkd3d_shader_src_param *rel_addr,
+static void shader_sm1_parse_src_param(uint32_t param, struct vkd3d_shader_src_param *rel_addr,
struct vkd3d_shader_src_param *src)
{
enum vkd3d_shader_register_type reg_type = ((param & VKD3D_SM1_REGISTER_TYPE_MASK) >> VKD3D_SM1_REGISTER_TYPE_SHIFT)
@@ -465,7 +466,7 @@ static void shader_sm1_parse_src_param(uint32_t param, const struct vkd3d_shader
src->modifiers = (param & VKD3D_SM1_SRC_MODIFIER_MASK) >> VKD3D_SM1_SRC_MODIFIER_SHIFT;
}
-static void shader_sm1_parse_dst_param(uint32_t param, const struct vkd3d_shader_src_param *rel_addr,
+static void shader_sm1_parse_dst_param(uint32_t param, struct vkd3d_shader_src_param *rel_addr,
struct vkd3d_shader_dst_param *dst)
{
enum vkd3d_shader_register_type reg_type = ((param & VKD3D_SM1_REGISTER_TYPE_MASK) >> VKD3D_SM1_REGISTER_TYPE_SHIFT)
@@ -482,9 +483,23 @@ static void shader_sm1_parse_dst_param(uint32_t param, const struct vkd3d_shader
dst->reg.dimension = VSIR_DIMENSION_SCALAR;
else
dst->reg.dimension = VSIR_DIMENSION_VEC4;
- dst->write_mask = (param & VKD3D_SM1_WRITEMASK_MASK) >> VKD3D_SM1_WRITEMASK_SHIFT;
dst->modifiers = (param & VKD3D_SM1_DST_MODIFIER_MASK) >> VKD3D_SM1_DST_MODIFIER_SHIFT;
dst->shift = (param & VKD3D_SM1_DSTSHIFT_MASK) >> VKD3D_SM1_DSTSHIFT_SHIFT;
+
+ switch (dst->reg.dimension)
+ {
+ case VSIR_DIMENSION_SCALAR:
+ dst->write_mask = VKD3DSP_WRITEMASK_0;
+ break;
+
+ case VSIR_DIMENSION_VEC4:
+ dst->write_mask = (param & VKD3D_SM1_WRITEMASK_MASK) >> VKD3D_SM1_WRITEMASK_SHIFT;
+ break;
+
+ default:
+ dst->write_mask = 0;
+ break;
+ }
}
static struct signature_element *find_signature_element(const struct shader_signature *signature,
@@ -518,8 +533,6 @@ static struct signature_element *find_signature_element_by_register_index(
return NULL;
}
-#define SM1_COLOR_REGISTER_OFFSET 8
-
static bool add_signature_element(struct vkd3d_shader_sm1_parser *sm1, bool output,
const char *name, unsigned int index, enum vkd3d_shader_sysval_semantic sysval,
unsigned int register_index, bool is_dcl, unsigned int mask)
@@ -555,7 +568,7 @@ static bool add_signature_element(struct vkd3d_shader_sm1_parser *sm1, bool outp
element->register_count = 1;
element->mask = mask;
element->used_mask = is_dcl ? 0 : mask;
- if (sm1->p.shader_version.type == VKD3D_SHADER_TYPE_PIXEL && !output)
+ if (sm1->p.program.shader_version.type == VKD3D_SHADER_TYPE_PIXEL && !output)
element->interpolation_mode = VKD3DSIM_LINEAR;
return true;
@@ -574,7 +587,7 @@ static void add_signature_mask(struct vkd3d_shader_sm1_parser *sm1, bool output,
if (!(element = find_signature_element_by_register_index(signature, register_index)))
{
- vkd3d_shader_parser_error(&sm1->p, VKD3D_SHADER_ERROR_D3DBC_UNDECLARED_SEMANTIC,
+ vkd3d_shader_parser_warning(&sm1->p, VKD3D_SHADER_ERROR_D3DBC_UNDECLARED_SEMANTIC,
"%s register %u was used without being declared.", output ? "Output" : "Input", register_index);
return;
}
@@ -585,20 +598,20 @@ static void add_signature_mask(struct vkd3d_shader_sm1_parser *sm1, bool output,
static bool add_signature_element_from_register(struct vkd3d_shader_sm1_parser *sm1,
const struct vkd3d_shader_register *reg, bool is_dcl, unsigned int mask)
{
+ const struct vkd3d_shader_version *version = &sm1->p.program.shader_version;
unsigned int register_index = reg->idx[0].offset;
switch (reg->type)
{
case VKD3DSPR_TEMP:
- if (sm1->p.shader_version.type == VKD3D_SHADER_TYPE_PIXEL
- && sm1->p.shader_version.major == 1 && !register_index)
+ if (version->type == VKD3D_SHADER_TYPE_PIXEL && version->major == 1 && !register_index)
return add_signature_element(sm1, true, "COLOR", 0, VKD3D_SHADER_SV_TARGET, 0, is_dcl, mask);
return true;
case VKD3DSPR_INPUT:
/* For vertex shaders or sm3 pixel shaders, we should have already
* had a DCL instruction. Otherwise, this is a colour input. */
- if (sm1->p.shader_version.type == VKD3D_SHADER_TYPE_VERTEX || sm1->p.shader_version.major == 3)
+ if (version->type == VKD3D_SHADER_TYPE_VERTEX || version->major == 3)
{
add_signature_mask(sm1, false, register_index, mask);
return true;
@@ -608,19 +621,19 @@ static bool add_signature_element_from_register(struct vkd3d_shader_sm1_parser *
case VKD3DSPR_TEXTURE:
/* For vertex shaders, this is ADDR. */
- if (sm1->p.shader_version.type == VKD3D_SHADER_TYPE_VERTEX)
+ if (version->type == VKD3D_SHADER_TYPE_VERTEX)
return true;
return add_signature_element(sm1, false, "TEXCOORD", register_index,
VKD3D_SHADER_SV_NONE, register_index, is_dcl, mask);
case VKD3DSPR_OUTPUT:
- if (sm1->p.shader_version.type == VKD3D_SHADER_TYPE_VERTEX)
+ if (version->type == VKD3D_SHADER_TYPE_VERTEX)
{
/* For sm < 2 vertex shaders, this is TEXCRDOUT.
*
* For sm3 vertex shaders, this is OUTPUT, but we already
* should have had a DCL instruction. */
- if (sm1->p.shader_version.major == 3)
+ if (version->major == 3)
{
add_signature_mask(sm1, true, register_index, mask);
return true;
@@ -647,15 +660,15 @@ static bool add_signature_element_from_register(struct vkd3d_shader_sm1_parser *
{
case 0:
return add_signature_element(sm1, true, "POSITION", 0,
- VKD3D_SHADER_SV_POSITION, register_index, is_dcl, mask);
+ VKD3D_SHADER_SV_POSITION, SM1_RASTOUT_REGISTER_OFFSET + register_index, is_dcl, mask);
case 1:
return add_signature_element(sm1, true, "FOG", 0,
- VKD3D_SHADER_SV_NONE, register_index, is_dcl, 0x1);
+ VKD3D_SHADER_SV_NONE, SM1_RASTOUT_REGISTER_OFFSET + register_index, is_dcl, 0x1);
case 2:
return add_signature_element(sm1, true, "PSIZE", 0,
- VKD3D_SHADER_SV_NONE, register_index, is_dcl, 0x1);
+ VKD3D_SHADER_SV_NONE, SM1_RASTOUT_REGISTER_OFFSET + register_index, is_dcl, 0x1);
default:
vkd3d_shader_parser_error(&sm1->p, VKD3D_SHADER_ERROR_D3DBC_INVALID_REGISTER_INDEX,
@@ -688,6 +701,7 @@ static bool add_signature_element_from_register(struct vkd3d_shader_sm1_parser *
static bool add_signature_element_from_semantic(struct vkd3d_shader_sm1_parser *sm1,
const struct vkd3d_shader_semantic *semantic)
{
+ const struct vkd3d_shader_version *version = &sm1->p.program.shader_version;
const struct vkd3d_shader_register *reg = &semantic->resource.reg.reg;
enum vkd3d_shader_sysval_semantic sysval = VKD3D_SHADER_SV_NONE;
unsigned int mask = semantic->resource.reg.write_mask;
@@ -719,13 +733,13 @@ static bool add_signature_element_from_semantic(struct vkd3d_shader_sm1_parser *
return add_signature_element_from_register(sm1, reg, true, mask);
/* sm2 pixel shaders use DCL but don't provide a semantic. */
- if (sm1->p.shader_version.type == VKD3D_SHADER_TYPE_PIXEL && sm1->p.shader_version.major == 2)
+ if (version->type == VKD3D_SHADER_TYPE_PIXEL && version->major == 2)
return add_signature_element_from_register(sm1, reg, true, mask);
/* With the exception of vertex POSITION output, none of these are system
* values. Pixel POSITION input is not equivalent to SV_Position; the closer
* equivalent is VPOS, which is not declared as a semantic. */
- if (sm1->p.shader_version.type == VKD3D_SHADER_TYPE_VERTEX
+ if (version->type == VKD3D_SHADER_TYPE_VERTEX
&& output && semantic->usage == VKD3D_DECL_USAGE_POSITION)
sysval = VKD3D_SHADER_SV_POSITION;
@@ -751,13 +765,13 @@ static void record_constant_register(struct vkd3d_shader_sm1_parser *sm1,
static void shader_sm1_scan_register(struct vkd3d_shader_sm1_parser *sm1,
const struct vkd3d_shader_register *reg, unsigned int mask, bool from_def)
{
- struct vkd3d_shader_desc *desc = &sm1->p.shader_desc;
+ struct vsir_program *program = &sm1->p.program;
uint32_t register_index = reg->idx[0].offset;
switch (reg->type)
{
case VKD3DSPR_TEMP:
- desc->temp_count = max(desc->temp_count, register_index + 1);
+ program->temp_count = max(program->temp_count, register_index + 1);
break;
case VKD3DSPR_CONST:
@@ -812,7 +826,7 @@ static void shader_sm1_read_param(struct vkd3d_shader_sm1_parser *sm1,
* VS >= 2.0 have relative addressing (with token)
* VS >= 1.0 < 2.0 have relative addressing (without token)
* The version check below should work in general. */
- if (sm1->p.shader_version.major < 2)
+ if (sm1->p.program.shader_version.major < 2)
{
*addr_token = (1u << 31)
| ((VKD3DSPR_ADDR << VKD3D_SM1_REGISTER_TYPE_SHIFT2) & VKD3D_SM1_REGISTER_TYPE_MASK2)
@@ -841,7 +855,7 @@ static void shader_sm1_skip_opcode(const struct vkd3d_shader_sm1_parser *sm1, co
/* Version 2.0+ shaders may contain address tokens, but fortunately they
* have a useful length mask - use it here. Version 1.x shaders contain no
* such tokens. */
- if (sm1->p.shader_version.major >= 2)
+ if (sm1->p.program.shader_version.major >= 2)
{
length = (opcode_token & VKD3D_SM1_INSTRUCTION_LENGTH_MASK) >> VKD3D_SM1_INSTRUCTION_LENGTH_SHIFT;
*ptr += length;
@@ -871,7 +885,7 @@ static void shader_sm1_destroy(struct vkd3d_shader_parser *parser)
{
struct vkd3d_shader_sm1_parser *sm1 = vkd3d_shader_sm1_parser(parser);
- shader_instruction_array_destroy(&parser->instructions);
+ vsir_program_cleanup(&parser->program);
free_shader_desc(&sm1->p.shader_desc);
vkd3d_free(sm1);
}
@@ -885,7 +899,7 @@ static void shader_sm1_read_src_param(struct vkd3d_shader_sm1_parser *sm1, const
shader_sm1_read_param(sm1, ptr, &token, &addr_token);
if (has_relative_address(token))
{
- if (!(src_rel_addr = shader_parser_get_src_params(&sm1->p, 1)))
+ if (!(src_rel_addr = vsir_program_get_src_params(&sm1->p.program, 1)))
{
vkd3d_shader_parser_error(&sm1->p, VKD3D_SHADER_ERROR_D3DBC_OUT_OF_MEMORY,
"Out of memory.");
@@ -906,7 +920,7 @@ static void shader_sm1_read_dst_param(struct vkd3d_shader_sm1_parser *sm1, const
shader_sm1_read_param(sm1, ptr, &token, &addr_token);
if (has_relative_address(token))
{
- if (!(dst_rel_addr = shader_parser_get_src_params(&sm1->p, 1)))
+ if (!(dst_rel_addr = vsir_program_get_src_params(&sm1->p.program, 1)))
{
vkd3d_shader_parser_error(&sm1->p, VKD3D_SHADER_ERROR_D3DBC_OUT_OF_MEMORY,
"Out of memory.");
@@ -987,7 +1001,7 @@ static void shader_sm1_read_immconst(struct vkd3d_shader_sm1_parser *sm1, const
src_param->reg.idx[2].rel_addr = NULL;
src_param->reg.idx_count = 0;
src_param->reg.dimension = dimension;
- memcpy(src_param->reg.u.immconst_uint, *ptr, count * sizeof(uint32_t));
+ memcpy(src_param->reg.u.immconst_u32, *ptr, count * sizeof(uint32_t));
src_param->swizzle = VKD3D_SHADER_NO_SWIZZLE;
src_param->modifiers = 0;
@@ -1063,18 +1077,19 @@ static void shader_sm1_validate_instruction(struct vkd3d_shader_sm1_parser *sm1,
}
}
-static unsigned int mask_from_swizzle(unsigned int swizzle)
+static unsigned int mask_from_swizzle(uint32_t swizzle)
{
- return (1u << vkd3d_swizzle_get_component(swizzle, 0))
- | (1u << vkd3d_swizzle_get_component(swizzle, 1))
- | (1u << vkd3d_swizzle_get_component(swizzle, 2))
- | (1u << vkd3d_swizzle_get_component(swizzle, 3));
+ return (1u << vsir_swizzle_get_component(swizzle, 0))
+ | (1u << vsir_swizzle_get_component(swizzle, 1))
+ | (1u << vsir_swizzle_get_component(swizzle, 2))
+ | (1u << vsir_swizzle_get_component(swizzle, 3));
}
static void shader_sm1_read_instruction(struct vkd3d_shader_sm1_parser *sm1, struct vkd3d_shader_instruction *ins)
{
struct vkd3d_shader_src_param *src_params, *predicate;
const struct vkd3d_sm1_opcode_info *opcode_info;
+ struct vsir_program *program = &sm1->p.program;
struct vkd3d_shader_dst_param *dst_param;
const uint32_t **ptr = &sm1->ptr;
uint32_t opcode_token;
@@ -1097,7 +1112,7 @@ static void shader_sm1_read_instruction(struct vkd3d_shader_sm1_parser *sm1, str
vkd3d_shader_parser_error(&sm1->p, VKD3D_SHADER_ERROR_D3DBC_INVALID_OPCODE,
"Invalid opcode %#x (token 0x%08x, shader version %u.%u).",
opcode_token & VKD3D_SM1_OPCODE_MASK, opcode_token,
- sm1->p.shader_version.major, sm1->p.shader_version.minor);
+ program->shader_version.major, program->shader_version.minor);
goto fail;
}
@@ -1107,11 +1122,11 @@ static void shader_sm1_read_instruction(struct vkd3d_shader_sm1_parser *sm1, str
ins->raw = false;
ins->structured = false;
predicated = !!(opcode_token & VKD3D_SM1_INSTRUCTION_PREDICATED);
- ins->predicate = predicate = predicated ? shader_parser_get_src_params(&sm1->p, 1) : NULL;
+ ins->predicate = predicate = predicated ? vsir_program_get_src_params(program, 1) : NULL;
ins->dst_count = opcode_info->dst_count;
- ins->dst = dst_param = shader_parser_get_dst_params(&sm1->p, ins->dst_count);
+ ins->dst = dst_param = vsir_program_get_dst_params(program, ins->dst_count);
ins->src_count = opcode_info->src_count;
- ins->src = src_params = shader_parser_get_src_params(&sm1->p, ins->src_count);
+ ins->src = src_params = vsir_program_get_src_params(program, ins->src_count);
if ((!predicate && predicated) || (!src_params && ins->src_count) || (!dst_param && ins->dst_count))
{
vkd3d_shader_parser_error(&sm1->p, VKD3D_SHADER_ERROR_D3DBC_OUT_OF_MEMORY, "Out of memory.");
@@ -1322,7 +1337,7 @@ int vkd3d_shader_sm1_parser_create(const struct vkd3d_shader_compile_info *compi
return ret;
}
- instructions = &sm1->p.instructions;
+ instructions = &sm1->p.program.instructions;
while (!shader_sm1_is_end(sm1))
{
if (!shader_instruction_array_reserve(instructions, instructions->count + 1))
@@ -1348,18 +1363,21 @@ int vkd3d_shader_sm1_parser_create(const struct vkd3d_shader_compile_info *compi
sm1->p.shader_desc.flat_constant_count[i].external = get_external_constant_count(sm1, i);
if (!sm1->p.failed)
- vsir_validate(&sm1->p);
+ ret = vsir_validate(&sm1->p);
+
+ if (sm1->p.failed && ret >= 0)
+ ret = VKD3D_ERROR_INVALID_SHADER;
- if (sm1->p.failed)
+ if (ret < 0)
{
WARN("Failed to parse shader.\n");
shader_sm1_destroy(&sm1->p);
- return VKD3D_ERROR_INVALID_SHADER;
+ return ret;
}
*parser = &sm1->p;
- return VKD3D_OK;
+ return ret;
}
bool hlsl_sm1_register_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_semantic *semantic,
@@ -1374,7 +1392,7 @@ bool hlsl_sm1_register_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_sem
enum vkd3d_shader_type shader_type;
unsigned int major_version;
D3DSHADER_PARAM_REGISTER_TYPE type;
- DWORD offset;
+ unsigned int offset;
}
register_table[] =
{
@@ -2253,7 +2271,7 @@ static void write_sm1_jump(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *b
{
struct hlsl_reg *reg = &jump->condition.node->reg;
- struct sm1_instruction instr =
+ struct sm1_instruction sm1_instr =
{
.opcode = D3DSIO_TEXKILL,
@@ -2263,7 +2281,7 @@ static void write_sm1_jump(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *b
.has_dst = 1,
};
- write_sm1_instruction(ctx, buffer, &instr);
+ write_sm1_instruction(ctx, buffer, &sm1_instr);
break;
}
@@ -2328,8 +2346,6 @@ static void write_sm1_resource_load(struct hlsl_ctx *ctx, struct vkd3d_bytecode_
sm1_instr = (struct sm1_instruction)
{
- .opcode = D3DSIO_TEX,
-
.dst.type = D3DSPR_TEMP,
.dst.reg = instr->reg.id,
.dst.writemask = instr->reg.writemask,
@@ -2345,8 +2361,22 @@ static void write_sm1_resource_load(struct hlsl_ctx *ctx, struct vkd3d_bytecode_
.src_count = 2,
};
- if (load->load_type == HLSL_RESOURCE_SAMPLE_PROJ)
- sm1_instr.opcode |= VKD3DSI_TEXLD_PROJECT << VKD3D_SM1_INSTRUCTION_FLAGS_SHIFT;
+
+ switch (load->load_type)
+ {
+ case HLSL_RESOURCE_SAMPLE:
+ sm1_instr.opcode = D3DSIO_TEX;
+ break;
+
+ case HLSL_RESOURCE_SAMPLE_PROJ:
+ sm1_instr.opcode = D3DSIO_TEX;
+ sm1_instr.opcode |= VKD3DSI_TEXLD_PROJECT << VKD3D_SM1_INSTRUCTION_FLAGS_SHIFT;
+ break;
+
+ default:
+ hlsl_fixme(ctx, &instr->loc, "Resource load type %u\n", load->load_type);
+ return;
+ }
assert(instr->reg.allocated);
diff --git a/libs/vkd3d/libs/vkd3d-shader/dxbc.c b/libs/vkd3d/libs/vkd3d-shader/dxbc.c
index 7834c1e1615..37ebc73c099 100644
--- a/libs/vkd3d/libs/vkd3d-shader/dxbc.c
+++ b/libs/vkd3d/libs/vkd3d-shader/dxbc.c
@@ -130,13 +130,13 @@ static void skip_dword_unknown(const char **ptr, unsigned int count)
}
}
-static const char *shader_get_string(const char *data, size_t data_size, DWORD offset)
+static const char *shader_get_string(const char *data, size_t data_size, size_t offset)
{
size_t len, max_len;
if (offset >= data_size)
{
- WARN("Invalid offset %#x (data size %#lx).\n", offset, (long)data_size);
+ WARN("Invalid offset %#zx (data size %#zx).\n", offset, data_size);
return NULL;
}
@@ -230,7 +230,7 @@ static int parse_dxbc(const struct vkd3d_shader_code *dxbc, struct vkd3d_shader_
chunk_offset = read_u32(&ptr);
TRACE("chunk %u at offset %#x\n", i, chunk_offset);
- if (chunk_offset >= data_size || !require_space(chunk_offset, 2, sizeof(DWORD), data_size))
+ if (chunk_offset >= data_size || !require_space(chunk_offset, 2, sizeof(uint32_t), data_size))
{
WARN("Invalid chunk offset %#x (data size %zu).\n", chunk_offset, data_size);
vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXBC_INVALID_CHUNK_OFFSET,
@@ -399,7 +399,8 @@ static int shader_parse_signature(const struct vkd3d_shader_dxbc_section_desc *s
for (i = 0; i < count; ++i)
{
- uint32_t name_offset, mask;
+ size_t name_offset;
+ uint32_t mask;
e[i].sort_index = i;
@@ -411,7 +412,7 @@ static int shader_parse_signature(const struct vkd3d_shader_dxbc_section_desc *s
name_offset = read_u32(&ptr);
if (!(e[i].semantic_name = shader_get_string(data, section->data.size, name_offset)))
{
- WARN("Invalid name offset %#x (data size %#zx).\n", name_offset, section->data.size);
+ WARN("Invalid name offset %#zx (data size %#zx).\n", name_offset, section->data.size);
vkd3d_free(e);
return VKD3D_ERROR_INVALID_ARGUMENT;
}
@@ -431,10 +432,6 @@ static int shader_parse_signature(const struct vkd3d_shader_dxbc_section_desc *s
case TAG_OSG5:
if (e[i].sysval_semantic == VKD3D_SHADER_SV_NONE)
e[i].sysval_semantic = map_fragment_output_sysval(e[i].semantic_name);
- /* Fall through. */
- case TAG_PCSG:
- case TAG_PSG1:
- e[i].used_mask = e[i].mask & ~e[i].used_mask;
break;
}
@@ -596,7 +593,7 @@ static int shader_parse_descriptor_ranges(struct root_signature_parser_context *
const char *ptr;
unsigned int i;
- if (!require_space(offset, 5 * count, sizeof(DWORD), context->data_size))
+ if (!require_space(offset, 5 * count, sizeof(uint32_t), context->data_size))
{
WARN("Invalid data size %#x (offset %u, count %u).\n", context->data_size, offset, count);
return VKD3D_ERROR_INVALID_ARGUMENT;
@@ -627,7 +624,8 @@ static void shader_validate_descriptor_range1(const struct vkd3d_shader_descript
| VKD3D_SHADER_DESCRIPTOR_RANGE_FLAG_DESCRIPTORS_VOLATILE
| VKD3D_SHADER_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE
| VKD3D_SHADER_DESCRIPTOR_RANGE_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE
- | VKD3D_SHADER_DESCRIPTOR_RANGE_FLAG_DATA_STATIC);
+ | VKD3D_SHADER_DESCRIPTOR_RANGE_FLAG_DATA_STATIC
+ | VKD3D_SHADER_DESCRIPTOR_RANGE_FLAG_DESCRIPTORS_STATIC_KEEPING_BUFFER_BOUNDS_CHECKS);
if (unknown_flags)
FIXME("Unknown descriptor range flags %#x.\n", unknown_flags);
@@ -674,7 +672,7 @@ static int shader_parse_descriptor_table(struct root_signature_parser_context *c
unsigned int count;
const char *ptr;
- if (!require_space(offset, 2, sizeof(DWORD), context->data_size))
+ if (!require_space(offset, 2, sizeof(uint32_t), context->data_size))
{
WARN("Invalid data size %#x (offset %u).\n", context->data_size, offset);
return VKD3D_ERROR_INVALID_ARGUMENT;
@@ -701,7 +699,7 @@ static int shader_parse_descriptor_table1(struct root_signature_parser_context *
unsigned int count;
const char *ptr;
- if (!require_space(offset, 2, sizeof(DWORD), context->data_size))
+ if (!require_space(offset, 2, sizeof(uint32_t), context->data_size))
{
WARN("Invalid data size %#x (offset %u).\n", context->data_size, offset);
return VKD3D_ERROR_INVALID_ARGUMENT;
@@ -726,7 +724,7 @@ static int shader_parse_root_constants(struct root_signature_parser_context *con
{
const char *ptr;
- if (!require_space(offset, 3, sizeof(DWORD), context->data_size))
+ if (!require_space(offset, 3, sizeof(uint32_t), context->data_size))
{
WARN("Invalid data size %#x (offset %u).\n", context->data_size, offset);
return VKD3D_ERROR_INVALID_ARGUMENT;
@@ -748,7 +746,7 @@ static int shader_parse_root_descriptor(struct root_signature_parser_context *co
{
const char *ptr;
- if (!require_space(offset, 2, sizeof(DWORD), context->data_size))
+ if (!require_space(offset, 2, sizeof(uint32_t), context->data_size))
{
WARN("Invalid data size %#x (offset %u).\n", context->data_size, offset);
return VKD3D_ERROR_INVALID_ARGUMENT;
@@ -780,7 +778,7 @@ static int shader_parse_root_descriptor1(struct root_signature_parser_context *c
{
const char *ptr;
- if (!require_space(offset, 3, sizeof(DWORD), context->data_size))
+ if (!require_space(offset, 3, sizeof(uint32_t), context->data_size))
{
WARN("Invalid data size %#x (offset %u).\n", context->data_size, offset);
return VKD3D_ERROR_INVALID_ARGUMENT;
@@ -806,7 +804,7 @@ static int shader_parse_root_parameters(struct root_signature_parser_context *co
unsigned int i;
int ret;
- if (!require_space(offset, 3 * count, sizeof(DWORD), context->data_size))
+ if (!require_space(offset, 3 * count, sizeof(uint32_t), context->data_size))
{
WARN("Invalid data size %#x (offset %u, count %u).\n", context->data_size, offset, count);
return VKD3D_ERROR_INVALID_ARGUMENT;
@@ -848,13 +846,13 @@ static int shader_parse_root_parameters(struct root_signature_parser_context *co
}
static int shader_parse_root_parameters1(struct root_signature_parser_context *context,
- uint32_t offset, DWORD count, struct vkd3d_shader_root_parameter1 *parameters)
+ uint32_t offset, unsigned int count, struct vkd3d_shader_root_parameter1 *parameters)
{
const char *ptr;
unsigned int i;
int ret;
- if (!require_space(offset, 3 * count, sizeof(DWORD), context->data_size))
+ if (!require_space(offset, 3 * count, sizeof(uint32_t), context->data_size))
{
WARN("Invalid data size %#x (offset %u, count %u).\n", context->data_size, offset, count);
return VKD3D_ERROR_INVALID_ARGUMENT;
@@ -901,7 +899,7 @@ static int shader_parse_static_samplers(struct root_signature_parser_context *co
const char *ptr;
unsigned int i;
- if (!require_space(offset, 13 * count, sizeof(DWORD), context->data_size))
+ if (!require_space(offset, 13 * count, sizeof(uint32_t), context->data_size))
{
WARN("Invalid data size %#x (offset %u, count %u).\n", context->data_size, offset, count);
return VKD3D_ERROR_INVALID_ARGUMENT;
diff --git a/libs/vkd3d/libs/vkd3d-shader/dxil.c b/libs/vkd3d/libs/vkd3d-shader/dxil.c
index beb9ae574dc..a001f6f0642 100644
--- a/libs/vkd3d/libs/vkd3d-shader/dxil.c
+++ b/libs/vkd3d/libs/vkd3d-shader/dxil.c
@@ -29,10 +29,18 @@ static const uint64_t MAX_ALIGNMENT_EXPONENT = 29;
static const uint64_t GLOBALVAR_FLAG_IS_CONSTANT = 1;
static const uint64_t GLOBALVAR_FLAG_EXPLICIT_TYPE = 2;
static const unsigned int GLOBALVAR_ADDRESS_SPACE_SHIFT = 2;
+static const uint64_t ALLOCA_FLAG_IN_ALLOCA = 0x20;
+static const uint64_t ALLOCA_FLAG_EXPLICIT_TYPE = 0x40;
+static const uint64_t ALLOCA_ALIGNMENT_MASK = ALLOCA_FLAG_IN_ALLOCA - 1;
static const unsigned int SHADER_DESCRIPTOR_TYPE_COUNT = 4;
+static const size_t MAX_IR_INSTRUCTIONS_PER_DXIL_INSTRUCTION = 5;
static const unsigned int dx_max_thread_group_size[3] = {1024, 1024, 64};
+#define VKD3D_SHADER_SWIZZLE_64_MASK \
+ (VKD3D_SHADER_SWIZZLE_MASK << VKD3D_SHADER_SWIZZLE_SHIFT(0) \
+ | VKD3D_SHADER_SWIZZLE_MASK << VKD3D_SHADER_SWIZZLE_SHIFT(1))
+
enum bitcode_block_id
{
BLOCKINFO_BLOCK = 0,
@@ -168,6 +176,35 @@ enum bitcode_linkage
LINKAGE_INTERNAL = 3,
};
+enum dxil_resource_kind
+{
+ RESOURCE_KIND_INVALID = 0,
+ RESOURCE_KIND_TEXTURE1D = 1,
+ RESOURCE_KIND_TEXTURE2D = 2,
+ RESOURCE_KIND_TEXTURE2DMS = 3,
+ RESOURCE_KIND_TEXTURE3D = 4,
+ RESOURCE_KIND_TEXTURECUBE = 5,
+ RESOURCE_KIND_TEXTURE1DARRAY = 6,
+ RESOURCE_KIND_TEXTURE2DARRAY = 7,
+ RESOURCE_KIND_TEXTURE2DMSARRAY = 8,
+ RESOURCE_KIND_TEXTURECUBEARRAY = 9,
+ RESOURCE_KIND_TYPEDBUFFER = 10,
+ RESOURCE_KIND_RAWBUFFER = 11,
+ RESOURCE_KIND_STRUCTUREDBUFFER = 12,
+ RESOURCE_KIND_CBUFFER = 13,
+ RESOURCE_KIND_SAMPLER = 14,
+ RESOURCE_KIND_TBUFFER = 15,
+ RESOURCE_KIND_RTACCELERATIONSTRUCTURE = 16,
+ RESOURCE_KIND_FEEDBACKTEXTURE2D = 17,
+ RESOURCE_KIND_FEEDBACKTEXTURE2DARRAY = 18,
+};
+
+enum dxil_resource_type
+{
+ RESOURCE_TYPE_NON_RAW_STRUCTURED = 0,
+ RESOURCE_TYPE_RAW_STRUCTURED = 1,
+};
+
enum dxil_component_type
{
COMPONENT_TYPE_INVALID = 0,
@@ -296,8 +333,53 @@ enum dx_intrinsic_opcode
{
DX_LOAD_INPUT = 4,
DX_STORE_OUTPUT = 5,
+ DX_ISNAN = 8,
+ DX_ISINF = 9,
+ DX_ISFINITE = 10,
+ DX_COS = 12,
+ DX_SIN = 13,
+ DX_TAN = 14,
+ DX_ACOS = 15,
+ DX_ASIN = 16,
+ DX_ATAN = 17,
+ DX_HCOS = 18,
+ DX_HSIN = 19,
+ DX_HTAN = 20,
+ DX_EXP = 21,
+ DX_FRC = 22,
+ DX_LOG = 23,
+ DX_SQRT = 24,
+ DX_RSQRT = 25,
+ DX_ROUND_NE = 26,
+ DX_ROUND_NI = 27,
+ DX_ROUND_PI = 28,
+ DX_ROUND_Z = 29,
+ DX_BFREV = 30,
+ DX_COUNT_BITS = 31,
+ DX_FIRST_BIT_LO = 32,
+ DX_FIRST_BIT_HI = 33,
+ DX_FIRST_BIT_SHI = 34,
+ DX_FMAX = 35,
+ DX_FMIN = 36,
+ DX_IMAX = 37,
+ DX_IMIN = 38,
+ DX_UMAX = 39,
+ DX_UMIN = 40,
+ DX_IBFE = 51,
+ DX_UBFE = 52,
DX_CREATE_HANDLE = 57,
DX_CBUFFER_LOAD_LEGACY = 59,
+ DX_TEXTURE_LOAD = 66,
+ DX_TEXTURE_STORE = 67,
+ DX_BUFFER_LOAD = 68,
+ DX_DERIV_COARSEX = 83,
+ DX_DERIV_COARSEY = 84,
+ DX_DERIV_FINEX = 85,
+ DX_DERIV_FINEY = 86,
+ DX_SPLIT_DOUBLE = 102,
+ DX_LEGACY_F32TOF16 = 130,
+ DX_LEGACY_F16TOF32 = 131,
+ DX_RAW_BUFFER_LOAD = 139,
};
enum dxil_cast_code
@@ -439,6 +521,7 @@ struct dxil_record
{
unsigned int code;
unsigned int operand_count;
+ const struct dxil_record *attachment;
uint64_t operands[];
};
@@ -448,18 +531,67 @@ struct sm6_symbol
const char *name;
};
+struct incoming_value
+{
+ const struct sm6_block *block;
+ struct vkd3d_shader_register reg;
+};
+
+struct sm6_phi
+{
+ struct vkd3d_shader_register reg;
+ struct incoming_value *incoming;
+ size_t incoming_capacity;
+ size_t incoming_count;
+};
+
+enum sm6_block_terminator_type
+{
+ TERMINATOR_UNCOND_BR,
+ TERMINATOR_COND_BR,
+ TERMINATOR_SWITCH,
+ TERMINATOR_RET,
+};
+
+struct terminator_case
+{
+ const struct sm6_block *block;
+ uint64_t value;
+ bool is_default;
+};
+
+struct sm6_block_terminator
+{
+ struct vkd3d_shader_register conditional_reg;
+ enum sm6_block_terminator_type type;
+ const struct sm6_block *true_block;
+ const struct sm6_block *false_block;
+ struct terminator_case *cases;
+ unsigned int case_count;
+};
+
struct sm6_block
{
struct vkd3d_shader_instruction *instructions;
size_t instruction_capacity;
size_t instruction_count;
+
+ /* A nonzero id. */
+ unsigned int id;
+
+ struct sm6_phi *phi;
+ size_t phi_capacity;
+ size_t phi_count;
+
+ struct sm6_block_terminator terminator;
};
struct sm6_function
{
const struct sm6_value *declaration;
- struct sm6_block *blocks[1];
+ struct sm6_block **blocks;
+ size_t block_capacity;
size_t block_count;
size_t value_count;
@@ -541,6 +673,11 @@ struct sm6_descriptor_info
enum vkd3d_shader_descriptor_type type;
unsigned int id;
struct vkd3d_shader_register_range range;
+ enum vkd3d_shader_resource_type resource_type;
+ enum dxil_resource_kind kind;
+ enum vkd3d_data_type resource_data_type;
+ enum vkd3d_shader_register_type reg_type;
+ enum vkd3d_data_type reg_data_type;
};
struct sm6_parser
@@ -581,6 +718,7 @@ struct sm6_parser
size_t descriptor_count;
unsigned int indexable_temp_count;
+ unsigned int icb_count;
struct sm6_value *values;
size_t value_count;
@@ -796,6 +934,7 @@ static enum vkd3d_result sm6_parser_read_unabbrev_record(struct sm6_parser *sm6)
record->code = code;
record->operand_count = count;
+ record->attachment = NULL;
for (i = 0; i < count; ++i)
record->operands[i] = sm6_parser_read_vbr(sm6, 6);
@@ -1012,6 +1151,7 @@ static enum vkd3d_result sm6_parser_read_abbrev_record(struct sm6_parser *sm6, u
if (!abbrev->operands[i + 1].read_operand(sm6, abbrev->operands[i + 1].context, &record->operands[i]))
goto fail;
record->operand_count = count;
+ record->attachment = NULL;
/* An array can occur only as the last operand. */
if (abbrev->is_array)
@@ -1210,7 +1350,7 @@ static size_t dxil_block_compute_module_decl_count(const struct dxil_block *bloc
size_t i, count;
for (i = 0, count = 0; i < block->record_count; ++i)
- count += block->records[i]->code == MODULE_CODE_FUNCTION;
+ count += block->records[i]->code == MODULE_CODE_FUNCTION || block->records[i]->code == MODULE_CODE_GLOBALVAR;
return count;
}
@@ -1517,7 +1657,7 @@ static enum vkd3d_result sm6_parser_type_table_init(struct sm6_parser *sm6)
break;
}
- if (!ascii_strcasecmp(struct_name, "dx.types.Handle"))
+ if (!strcmp(struct_name, "dx.types.Handle"))
sm6->handle_type = type;
type->u.struc->name = struct_name;
@@ -1572,6 +1712,11 @@ static bool sm6_type_is_bool_i16_i32_i64(const struct sm6_type *type)
return type->class == TYPE_CLASS_INTEGER && (type->u.width == 1 || type->u.width >= 16);
}
+static bool sm6_type_is_i16_i32_i64(const struct sm6_type *type)
+{
+ return type->class == TYPE_CLASS_INTEGER && type->u.width >= 16;
+}
+
static bool sm6_type_is_bool(const struct sm6_type *type)
{
return type->class == TYPE_CLASS_INTEGER && type->u.width == 1;
@@ -1587,6 +1732,21 @@ static inline bool sm6_type_is_i32(const struct sm6_type *type)
return type->class == TYPE_CLASS_INTEGER && type->u.width == 32;
}
+static bool sm6_type_is_float(const struct sm6_type *type)
+{
+ return type->class == TYPE_CLASS_FLOAT && type->u.width == 32;
+}
+
+static bool sm6_type_is_f16_f32(const struct sm6_type *type)
+{
+ return type->class == TYPE_CLASS_FLOAT && (type->u.width == 16 || type->u.width == 32);
+}
+
+static bool sm6_type_is_double(const struct sm6_type *type)
+{
+ return type->class == TYPE_CLASS_FLOAT && type->u.width == 64;
+}
+
static inline bool sm6_type_is_floating_point(const struct sm6_type *type)
{
return type->class == TYPE_CLASS_FLOAT;
@@ -1844,12 +2004,12 @@ static unsigned int register_get_uint_value(const struct vkd3d_shader_register *
if (reg->type == VKD3DSPR_IMMCONST64)
{
- if (reg->u.immconst_uint64[0] > UINT_MAX)
+ if (reg->u.immconst_u64[0] > UINT_MAX)
FIXME("Truncating 64-bit value.\n");
- return reg->u.immconst_uint64[0];
+ return reg->u.immconst_u64[0];
}
- return reg->u.immconst_uint[0];
+ return reg->u.immconst_u32[0];
}
static uint64_t register_get_uint64_value(const struct vkd3d_shader_register *reg)
@@ -1860,7 +2020,7 @@ static uint64_t register_get_uint64_value(const struct vkd3d_shader_register *re
if (reg->dimension == VSIR_DIMENSION_VEC4)
WARN("Returning vec4.x.\n");
- return (reg->type == VKD3DSPR_IMMCONST64) ? reg->u.immconst_uint64[0] : reg->u.immconst_uint[0];
+ return (reg->type == VKD3DSPR_IMMCONST64) ? reg->u.immconst_u64[0] : reg->u.immconst_u32[0];
}
static inline bool sm6_value_is_function_dcl(const struct sm6_value *value)
@@ -1895,6 +2055,12 @@ static inline bool sm6_value_is_constant(const struct sm6_value *value)
return sm6_value_is_register(value) && register_is_constant(&value->u.reg);
}
+static bool sm6_value_is_constant_zero(const struct sm6_value *value)
+{
+ /* Constant vectors do not occur. */
+ return sm6_value_is_register(value) && register_is_scalar_constant_zero(&value->u.reg);
+}
+
static inline bool sm6_value_is_undef(const struct sm6_value *value)
{
return sm6_value_is_register(value) && value->u.reg.type == VKD3DSPR_UNDEF;
@@ -1905,6 +2071,11 @@ static bool sm6_value_is_icb(const struct sm6_value *value)
return value->value_type == VALUE_TYPE_ICB;
}
+static bool sm6_value_is_ssa(const struct sm6_value *value)
+{
+ return sm6_value_is_register(value) && register_is_ssa(&value->u.reg);
+}
+
static inline unsigned int sm6_value_get_constant_uint(const struct sm6_value *value)
{
if (!sm6_value_is_constant(value))
@@ -1912,16 +2083,33 @@ static inline unsigned int sm6_value_get_constant_uint(const struct sm6_value *v
return register_get_uint_value(&value->u.reg);
}
+static uint64_t sm6_value_get_constant_uint64(const struct sm6_value *value)
+{
+ if (!sm6_value_is_constant(value))
+ return UINT64_MAX;
+ return register_get_uint64_value(&value->u.reg);
+}
+
static unsigned int sm6_parser_alloc_ssa_id(struct sm6_parser *sm6)
{
return sm6->ssa_next_id++;
}
+static void instruction_init_with_resource(struct vkd3d_shader_instruction *ins,
+ enum vkd3d_shader_opcode handler_idx, const struct sm6_value *resource, struct sm6_parser *sm6)
+{
+ vsir_instruction_init(ins, &sm6->p.location, handler_idx);
+ ins->resource_type = resource->u.handle.d->resource_type;
+ ins->raw = resource->u.handle.d->kind == RESOURCE_KIND_RAWBUFFER;
+ ins->structured = resource->u.handle.d->kind == RESOURCE_KIND_STRUCTUREDBUFFER;
+}
+
static struct vkd3d_shader_src_param *instruction_src_params_alloc(struct vkd3d_shader_instruction *ins,
unsigned int count, struct sm6_parser *sm6)
{
- struct vkd3d_shader_src_param *params = shader_parser_get_src_params(&sm6->p, count);
- if (!params)
+ struct vkd3d_shader_src_param *params;
+
+ if (!(params = vsir_program_get_src_params(&sm6->p.program, count)))
{
ERR("Failed to allocate src params.\n");
vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY,
@@ -1936,8 +2124,9 @@ static struct vkd3d_shader_src_param *instruction_src_params_alloc(struct vkd3d_
static struct vkd3d_shader_dst_param *instruction_dst_params_alloc(struct vkd3d_shader_instruction *ins,
unsigned int count, struct sm6_parser *sm6)
{
- struct vkd3d_shader_dst_param *params = shader_parser_get_dst_params(&sm6->p, count);
- if (!params)
+ struct vkd3d_shader_dst_param *params;
+
+ if (!(params = vsir_program_get_dst_params(&sm6->p.program, count)))
{
ERR("Failed to allocate dst params.\n");
vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY,
@@ -1994,21 +2183,29 @@ static enum vkd3d_data_type vkd3d_data_type_from_sm6_type(const struct sm6_type
}
static void register_init_ssa_vector(struct vkd3d_shader_register *reg, const struct sm6_type *type,
- unsigned int component_count, struct sm6_parser *sm6)
+ unsigned int component_count, struct sm6_value *value, struct sm6_parser *sm6)
{
enum vkd3d_data_type data_type;
unsigned int id;
- id = sm6_parser_alloc_ssa_id(sm6);
+ if (value && register_is_ssa(&value->u.reg) && value->u.reg.idx[0].offset)
+ {
+ id = value->u.reg.idx[0].offset;
+ TRACE("Using forward-allocated id %u.\n", id);
+ }
+ else
+ {
+ id = sm6_parser_alloc_ssa_id(sm6);
+ }
data_type = vkd3d_data_type_from_sm6_type(sm6_type_get_scalar_type(type, 0));
register_init_with_id(reg, VKD3DSPR_SSA, data_type, id);
reg->dimension = component_count > 1 ? VSIR_DIMENSION_VEC4 : VSIR_DIMENSION_SCALAR;
}
static void register_init_ssa_scalar(struct vkd3d_shader_register *reg, const struct sm6_type *type,
- struct sm6_parser *sm6)
+ struct sm6_value *value, struct sm6_parser *sm6)
{
- register_init_ssa_vector(reg, type, 1, sm6);
+ register_init_ssa_vector(reg, sm6_type_get_scalar_type(type, 0), 1, value, sm6);
}
static void dst_param_init(struct vkd3d_shader_dst_param *param)
@@ -2018,6 +2215,13 @@ static void dst_param_init(struct vkd3d_shader_dst_param *param)
param->shift = 0;
}
+static void dst_param_init_with_mask(struct vkd3d_shader_dst_param *param, unsigned int mask)
+{
+ param->write_mask = mask;
+ param->modifiers = 0;
+ param->shift = 0;
+}
+
static inline void dst_param_init_scalar(struct vkd3d_shader_dst_param *param, unsigned int component_idx)
{
param->write_mask = 1u << component_idx;
@@ -2033,10 +2237,10 @@ static void dst_param_init_vector(struct vkd3d_shader_dst_param *param, unsigned
}
static void dst_param_init_ssa_scalar(struct vkd3d_shader_dst_param *param, const struct sm6_type *type,
- struct sm6_parser *sm6)
+ struct sm6_value *value, struct sm6_parser *sm6)
{
dst_param_init(param);
- register_init_ssa_scalar(&param->reg, type, sm6);
+ register_init_ssa_scalar(&param->reg, type, value, sm6);
}
static inline void src_param_init(struct vkd3d_shader_src_param *param)
@@ -2048,6 +2252,8 @@ static inline void src_param_init(struct vkd3d_shader_src_param *param)
static void src_param_init_scalar(struct vkd3d_shader_src_param *param, unsigned int component_idx)
{
param->swizzle = vkd3d_shader_create_swizzle(component_idx, component_idx, component_idx, component_idx);
+ if (data_type_is_64_bit(param->reg.data_type))
+ param->swizzle &= VKD3D_SHADER_SWIZZLE_64_MASK;
param->modifiers = VKD3DSPSM_NONE;
}
@@ -2078,7 +2284,7 @@ static void register_index_address_init(struct vkd3d_shader_register_index *idx,
}
else
{
- struct vkd3d_shader_src_param *rel_addr = shader_parser_get_src_params(&sm6->p, 1);
+ struct vkd3d_shader_src_param *rel_addr = vsir_program_get_src_params(&sm6->p.program, 1);
if (rel_addr)
src_param_init_from_value(rel_addr, address);
idx->offset = 0;
@@ -2091,7 +2297,7 @@ static void instruction_dst_param_init_ssa_scalar(struct vkd3d_shader_instructio
struct vkd3d_shader_dst_param *param = instruction_dst_params_alloc(ins, 1, sm6);
struct sm6_value *dst = sm6_parser_get_current_value(sm6);
- dst_param_init_ssa_scalar(param, dst->type, sm6);
+ dst_param_init_ssa_scalar(param, dst->type, dst, sm6);
param->write_mask = VKD3DSP_WRITEMASK_0;
dst->u.reg = param->reg;
}
@@ -2103,7 +2309,7 @@ static void instruction_dst_param_init_ssa_vector(struct vkd3d_shader_instructio
struct sm6_value *dst = sm6_parser_get_current_value(sm6);
dst_param_init_vector(param, component_count);
- register_init_ssa_vector(&param->reg, sm6_type_get_scalar_type(dst->type, 0), component_count, sm6);
+ register_init_ssa_vector(&param->reg, sm6_type_get_scalar_type(dst->type, 0), component_count, dst, sm6);
dst->u.reg = param->reg;
}
@@ -2195,6 +2401,26 @@ static bool sm6_value_validate_is_handle(const struct sm6_value *value, struct s
return true;
}
+static bool sm6_value_validate_is_texture_handle(const struct sm6_value *value, enum dx_intrinsic_opcode op,
+ struct sm6_parser *sm6)
+{
+ enum dxil_resource_kind kind;
+
+ if (!sm6_value_validate_is_handle(value, sm6))
+ return false;
+
+ kind = value->u.handle.d->kind;
+ if (kind < RESOURCE_KIND_TEXTURE1D || kind > RESOURCE_KIND_TEXTURECUBEARRAY)
+ {
+ WARN("Resource kind %u for op %u is not a texture.\n", kind, op);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCE_HANDLE,
+ "Resource kind %u for texture operation %u is not a texture.", kind, op);
+ return false;
+ }
+
+ return true;
+}
+
static bool sm6_value_validate_is_pointer(const struct sm6_value *value, struct sm6_parser *sm6)
{
if (!sm6_type_is_pointer(value->type))
@@ -2246,6 +2472,7 @@ static const struct sm6_value *sm6_parser_get_value_safe(struct sm6_parser *sm6,
static size_t sm6_parser_get_value_idx_by_ref(struct sm6_parser *sm6, const struct dxil_record *record,
const struct sm6_type *fwd_type, unsigned int *rec_idx)
{
+ struct sm6_value *value;
unsigned int idx;
uint64_t val_ref;
size_t operand;
@@ -2259,23 +2486,39 @@ static size_t sm6_parser_get_value_idx_by_ref(struct sm6_parser *sm6, const stru
if (operand == SIZE_MAX)
return SIZE_MAX;
- if (operand >= sm6->value_count)
+ if (operand >= sm6->value_count && !fwd_type)
+ {
+ /* Forward references are followed by a type id unless an earlier operand set the type,
+ * or it is contained in a function declaration. */
+ if (!dxil_record_validate_operand_min_count(record, idx + 1, sm6))
+ return SIZE_MAX;
+ if (!(fwd_type = sm6_parser_get_type(sm6, record->operands[idx++])))
+ return SIZE_MAX;
+ }
+ *rec_idx = idx;
+
+ if (fwd_type)
{
- if (!fwd_type)
+ value = &sm6->values[operand];
+ if (value->type)
{
- /* Forward references are followed by a type id unless an earlier operand set the type,
- * or it is contained in a function declaration. */
- if (!dxil_record_validate_operand_min_count(record, idx + 1, sm6))
- return SIZE_MAX;
- if (!(fwd_type = sm6_parser_get_type(sm6, record->operands[idx++])))
- return SIZE_MAX;
+ if (value->type != fwd_type)
+ {
+ WARN("Value already has a mismatching type.\n");
+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH,
+ "The type of a source value does not match the predefined type.");
+ }
+ }
+ else
+ {
+ value->type = fwd_type;
+ value->value_type = VALUE_TYPE_REG;
+ register_init_with_id(&value->u.reg, VKD3DSPR_SSA, vkd3d_data_type_from_sm6_type(
+ sm6_type_get_scalar_type(fwd_type, 0)), sm6_parser_alloc_ssa_id(sm6));
+ value->u.reg.dimension = sm6_type_is_scalar(fwd_type) ? VSIR_DIMENSION_SCALAR
+ : VSIR_DIMENSION_VEC4;
}
- FIXME("Forward value references are not supported yet.\n");
- vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
- "Unsupported value forward reference.");
- return SIZE_MAX;
}
- *rec_idx = idx;
return operand;
}
@@ -2289,8 +2532,8 @@ static const struct sm6_value *sm6_parser_get_value_by_ref(struct sm6_parser *sm
static bool sm6_parser_declare_function(struct sm6_parser *sm6, const struct dxil_record *record)
{
+ const struct sm6_type *type, *ret_type;
const unsigned int max_count = 15;
- const struct sm6_type *ret_type;
struct sm6_value *fn;
unsigned int i, j;
@@ -2305,18 +2548,18 @@ static bool sm6_parser_declare_function(struct sm6_parser *sm6, const struct dxi
fn->u.function.name = "";
}
- if (!(fn->type = sm6_parser_get_type(sm6, record->operands[0])))
+ if (!(type = sm6_parser_get_type(sm6, record->operands[0])))
return false;
- if (!sm6_type_is_function(fn->type))
+ if (!sm6_type_is_function(type))
{
WARN("Type is not a function.\n");
return false;
}
- ret_type = fn->type->u.function->ret_type;
+ ret_type = type->u.function->ret_type;
- if (!(fn->type = sm6_type_get_pointer_to_type(fn->type, ADDRESS_SPACE_DEFAULT, sm6)))
+ if (!(fn->type = sm6_type_get_pointer_to_type(type, ADDRESS_SPACE_DEFAULT, sm6)))
{
- WARN("Failed to get pointer type for type %u.\n", fn->type->class);
+ WARN("Failed to get pointer type for type %u.\n", type->class);
return false;
}
@@ -2412,7 +2655,7 @@ static enum vkd3d_result value_allocate_constant_array(struct sm6_value *dst, co
return VKD3D_ERROR_INVALID_SHADER;
}
size = max(size, sizeof(icb->data[0]));
- count = type->u.array.count * size / sizeof(icb->data[0]);
+ count = operands ? type->u.array.count * size / sizeof(icb->data[0]) : 0;
if (!(icb = vkd3d_malloc(offsetof(struct vkd3d_shader_immediate_constant_buffer, data[count]))))
{
@@ -2421,7 +2664,7 @@ static enum vkd3d_result value_allocate_constant_array(struct sm6_value *dst, co
"Out of memory allocating an immediate constant buffer of count %u.", count);
return VKD3D_ERROR_OUT_OF_MEMORY;
}
- if (!shader_instruction_array_add_icb(&sm6->p.instructions, icb))
+ if (!shader_instruction_array_add_icb(&sm6->p.program.instructions, icb))
{
ERR("Failed to store icb object.\n");
vkd3d_free(icb);
@@ -2433,9 +2676,14 @@ static enum vkd3d_result value_allocate_constant_array(struct sm6_value *dst, co
dst->value_type = VALUE_TYPE_ICB;
dst->u.icb = icb;
+ icb->register_idx = sm6->icb_count++;
icb->data_type = vkd3d_data_type_from_sm6_type(elem_type);
icb->element_count = type->u.array.count;
icb->component_count = 1;
+ icb->is_null = !operands;
+
+ if (!operands)
+ return VKD3D_OK;
count = type->u.array.count;
if (size > sizeof(icb->data[0]))
@@ -2510,12 +2758,10 @@ static enum vkd3d_result sm6_parser_constants_init(struct sm6_parser *sm6, const
switch (record->code)
{
case CST_CODE_NULL:
- if (sm6_type_is_array(type))
+ if (sm6_type_is_array(type)
+ && (ret = value_allocate_constant_array(dst, type, NULL, sm6)) < 0)
{
- FIXME("Constant null arrays are not supported.\n");
- vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
- "Constant null arrays are not supported.");
- return VKD3D_ERROR_INVALID_SHADER;
+ return ret;
}
/* For non-aggregates, register constant data is already zero-filled. */
break;
@@ -2532,9 +2778,9 @@ static enum vkd3d_result sm6_parser_constants_init(struct sm6_parser *sm6, const
value = decode_rotated_signed_value(record->operands[0]);
if (type->u.width <= 32)
- dst->u.reg.u.immconst_uint[0] = value & ((1ull << type->u.width) - 1);
+ dst->u.reg.u.immconst_u32[0] = value & ((1ull << type->u.width) - 1);
else
- dst->u.reg.u.immconst_uint64[0] = value;
+ dst->u.reg.u.immconst_u64[0] = value;
break;
@@ -2551,9 +2797,9 @@ static enum vkd3d_result sm6_parser_constants_init(struct sm6_parser *sm6, const
if (type->u.width == 16)
FIXME("Half float type is not supported yet.\n");
else if (type->u.width == 32)
- dst->u.reg.u.immconst_float[0] = bitcast_uint64_to_float(record->operands[0]);
+ dst->u.reg.u.immconst_f32[0] = bitcast_uint64_to_float(record->operands[0]);
else if (type->u.width == 64)
- dst->u.reg.u.immconst_double[0] = bitcast_uint64_to_double(record->operands[0]);
+ dst->u.reg.u.immconst_f64[0] = bitcast_uint64_to_double(record->operands[0]);
else
vkd3d_unreachable();
@@ -2588,6 +2834,13 @@ static enum vkd3d_result sm6_parser_constants_init(struct sm6_parser *sm6, const
break;
}
+ if (record->attachment)
+ {
+ WARN("Ignoring metadata attachment.\n");
+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_ATTACHMENT,
+ "Ignoring a metadata attachment for a constant.");
+ }
+
++sm6->value_count;
}
@@ -2607,12 +2860,12 @@ static bool bitcode_parse_alignment(uint64_t encoded_alignment, unsigned int *al
static struct vkd3d_shader_instruction *sm6_parser_require_space(struct sm6_parser *sm6, size_t extra)
{
- if (!shader_instruction_array_reserve(&sm6->p.instructions, sm6->p.instructions.count + extra))
+ if (!shader_instruction_array_reserve(&sm6->p.program.instructions, sm6->p.program.instructions.count + extra))
{
ERR("Failed to allocate instruction.\n");
return NULL;
}
- return &sm6->p.instructions.elements[sm6->p.instructions.count];
+ return &sm6->p.program.instructions.elements[sm6->p.program.instructions.count];
}
/* Space should be reserved before calling this. It is intended to require no checking of the returned pointer. */
@@ -2622,22 +2875,38 @@ static struct vkd3d_shader_instruction *sm6_parser_add_instruction(struct sm6_pa
struct vkd3d_shader_instruction *ins = sm6_parser_require_space(sm6, 1);
assert(ins);
vsir_instruction_init(ins, &sm6->p.location, handler_idx);
- ++sm6->p.instructions.count;
+ ++sm6->p.program.instructions.count;
return ins;
}
-static void sm6_parser_declare_indexable_temp(struct sm6_parser *sm6, const struct sm6_type *elem_type,
- unsigned int count, unsigned int alignment, unsigned int init, struct sm6_value *dst)
+static void sm6_parser_declare_icb(struct sm6_parser *sm6, const struct sm6_type *elem_type, unsigned int count,
+ unsigned int alignment, unsigned int init, struct sm6_value *dst)
{
enum vkd3d_data_type data_type = vkd3d_data_type_from_sm6_type(elem_type);
struct vkd3d_shader_instruction *ins;
- ins = sm6_parser_add_instruction(sm6, VKD3DSIH_DCL_INDEXABLE_TEMP);
+ ins = sm6_parser_add_instruction(sm6, VKD3DSIH_DCL_IMMEDIATE_CONSTANT_BUFFER);
+ /* The icb value index will be resolved later so forward references can be handled. */
+ ins->declaration.icb = (void *)(intptr_t)init;
+ register_init_with_id(&dst->u.reg, VKD3DSPR_IMMCONSTBUFFER, data_type, init);
+}
+
+static void sm6_parser_declare_indexable_temp(struct sm6_parser *sm6, const struct sm6_type *elem_type,
+ unsigned int count, unsigned int alignment, bool has_function_scope, unsigned int init,
+ struct vkd3d_shader_instruction *ins, struct sm6_value *dst)
+{
+ enum vkd3d_data_type data_type = vkd3d_data_type_from_sm6_type(elem_type);
+
+ if (ins)
+ vsir_instruction_init(ins, &sm6->p.location, VKD3DSIH_DCL_INDEXABLE_TEMP);
+ else
+ ins = sm6_parser_add_instruction(sm6, VKD3DSIH_DCL_INDEXABLE_TEMP);
ins->declaration.indexable_temp.register_idx = sm6->indexable_temp_count++;
ins->declaration.indexable_temp.register_size = count;
ins->declaration.indexable_temp.alignment = alignment;
ins->declaration.indexable_temp.data_type = data_type;
ins->declaration.indexable_temp.component_count = 1;
+ ins->declaration.indexable_temp.has_function_scope = has_function_scope;
/* The initialiser value index will be resolved later so forward references can be handled. */
ins->declaration.indexable_temp.initialiser = (void *)(uintptr_t)init;
@@ -2762,7 +3031,10 @@ static bool sm6_parser_declare_global(struct sm6_parser *sm6, const struct dxil_
if (address_space == ADDRESS_SPACE_DEFAULT)
{
- sm6_parser_declare_indexable_temp(sm6, scalar_type, count, alignment, init, dst);
+ if (is_constant)
+ sm6_parser_declare_icb(sm6, scalar_type, count, alignment, init, dst);
+ else
+ sm6_parser_declare_indexable_temp(sm6, scalar_type, count, alignment, false, init, NULL, dst);
}
else if (address_space == ADDRESS_SPACE_GROUPSHARED)
{
@@ -2790,31 +3062,37 @@ static const struct vkd3d_shader_immediate_constant_buffer *resolve_forward_init
assert(index);
--index;
- if (!(value = sm6_parser_get_value_safe(sm6, index)) || !sm6_value_is_icb(value))
+ if (!(value = sm6_parser_get_value_safe(sm6, index)) || (!sm6_value_is_icb(value) && !sm6_value_is_undef(value)))
{
WARN("Invalid initialiser index %zu.\n", index);
vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
"Global variable initialiser value index %zu is invalid.", index);
return NULL;
}
- else
+ else if (sm6_value_is_icb(value))
{
return value->u.icb;
}
+ /* In VSIR, initialisation with undefined values of objects is implied, not explicit. */
+ return NULL;
}
static enum vkd3d_result sm6_parser_globals_init(struct sm6_parser *sm6)
{
+ size_t i, count, base_value_idx = sm6->value_count;
const struct dxil_block *block = &sm6->root_block;
struct vkd3d_shader_instruction *ins;
const struct dxil_record *record;
enum vkd3d_result ret;
uint64_t version;
- size_t i;
sm6->p.location.line = block->id;
sm6->p.location.column = 0;
+ for (i = 0, count = 0; i < block->record_count; ++i)
+ count += block->records[i]->code == MODULE_CODE_GLOBALVAR;
+ sm6_parser_require_space(sm6, count);
+
for (i = 0; i < block->record_count; ++i)
{
sm6->p.location.column = i;
@@ -2860,14 +3138,29 @@ static enum vkd3d_result sm6_parser_globals_init(struct sm6_parser *sm6)
}
/* Resolve initialiser forward references. */
- for (i = 0; i < sm6->p.instructions.count; ++i)
+ for (i = 0; i < sm6->p.program.instructions.count; ++i)
{
- ins = &sm6->p.instructions.elements[i];
+ ins = &sm6->p.program.instructions.elements[i];
if (ins->handler_idx == VKD3DSIH_DCL_INDEXABLE_TEMP && ins->declaration.indexable_temp.initialiser)
{
ins->declaration.indexable_temp.initialiser = resolve_forward_initialiser(
(uintptr_t)ins->declaration.indexable_temp.initialiser, sm6);
}
+ else if (ins->handler_idx == VKD3DSIH_DCL_IMMEDIATE_CONSTANT_BUFFER)
+ {
+ ins->declaration.icb = resolve_forward_initialiser((uintptr_t)ins->declaration.icb, sm6);
+ }
+ }
+ for (i = base_value_idx; i < sm6->value_count; ++i)
+ {
+ const struct vkd3d_shader_immediate_constant_buffer *icb;
+ struct sm6_value *value = &sm6->values[i];
+
+ if (!sm6_value_is_register(value) || value->u.reg.type != VKD3DSPR_IMMCONSTBUFFER)
+ continue;
+
+ if ((icb = resolve_forward_initialiser(value->u.reg.idx[0].offset, sm6)))
+ value->u.reg.idx[0].offset = icb->register_idx;
}
return VKD3D_OK;
@@ -2887,6 +3180,15 @@ static void dst_param_io_init(struct vkd3d_shader_dst_param *param,
param->reg.dimension = VSIR_DIMENSION_VEC4;
}
+static void src_params_init_from_operands(struct vkd3d_shader_src_param *src_params,
+ const struct sm6_value **operands, unsigned int count)
+{
+ unsigned int i;
+
+ for (i = 0; i < count; ++i)
+ src_param_init_from_value(&src_params[i], operands[i]);
+}
+
static void sm6_parser_init_signature(struct sm6_parser *sm6, const struct shader_signature *s,
enum vkd3d_shader_register_type reg_type, struct vkd3d_shader_dst_param *params)
{
@@ -2908,45 +3210,6 @@ static void sm6_parser_init_signature(struct sm6_parser *sm6, const struct shade
}
}
-static void sm6_parser_emit_signature(struct sm6_parser *sm6, const struct shader_signature *s,
- enum vkd3d_shader_opcode handler_idx, enum vkd3d_shader_opcode siv_handler_idx,
- struct vkd3d_shader_dst_param *params)
-{
- struct vkd3d_shader_instruction *ins;
- struct vkd3d_shader_dst_param *param;
- const struct signature_element *e;
- unsigned int i;
-
- for (i = 0; i < s->element_count; ++i)
- {
- e = &s->elements[i];
-
- /* Do not check e->used_mask because in some cases it is zero for used elements.
- * TODO: scan ahead for used I/O elements. */
-
- if (e->sysval_semantic != VKD3D_SHADER_SV_NONE && e->sysval_semantic != VKD3D_SHADER_SV_TARGET)
- {
- ins = sm6_parser_add_instruction(sm6, siv_handler_idx);
- param = &ins->declaration.register_semantic.reg;
- ins->declaration.register_semantic.sysval_semantic = vkd3d_siv_from_sysval(e->sysval_semantic);
- }
- else
- {
- ins = sm6_parser_add_instruction(sm6, handler_idx);
- param = &ins->declaration.dst;
- }
-
- ins->flags = e->interpolation_mode;
- *param = params[i];
-
- if (e->register_count > 1)
- {
- param->reg.idx[0].rel_addr = NULL;
- param->reg.idx[0].offset = e->register_count;
- }
- }
-}
-
static void sm6_parser_init_output_signature(struct sm6_parser *sm6, const struct shader_signature *output_signature)
{
sm6_parser_init_signature(sm6, output_signature, VKD3DSPR_OUTPUT, sm6->output_params);
@@ -2957,19 +3220,6 @@ static void sm6_parser_init_input_signature(struct sm6_parser *sm6, const struct
sm6_parser_init_signature(sm6, input_signature, VKD3DSPR_INPUT, sm6->input_params);
}
-static void sm6_parser_emit_output_signature(struct sm6_parser *sm6, const struct shader_signature *output_signature)
-{
- sm6_parser_emit_signature(sm6, output_signature, VKD3DSIH_DCL_OUTPUT, VKD3DSIH_DCL_OUTPUT_SIV, sm6->output_params);
-}
-
-static void sm6_parser_emit_input_signature(struct sm6_parser *sm6, const struct shader_signature *input_signature)
-{
- sm6_parser_emit_signature(sm6, input_signature,
- (sm6->p.shader_version.type == VKD3D_SHADER_TYPE_PIXEL) ? VKD3DSIH_DCL_INPUT_PS : VKD3DSIH_DCL_INPUT,
- (sm6->p.shader_version.type == VKD3D_SHADER_TYPE_PIXEL) ? VKD3DSIH_DCL_INPUT_PS_SIV : VKD3DSIH_DCL_INPUT_SIV,
- sm6->input_params);
-}
-
static const struct sm6_value *sm6_parser_next_function_definition(struct sm6_parser *sm6)
{
size_t i, count = sm6->function_count;
@@ -2992,6 +3242,108 @@ static struct sm6_block *sm6_block_create()
return block;
}
+static struct sm6_phi *sm6_block_phi_require_space(struct sm6_block *block, struct sm6_parser *sm6)
+{
+ struct sm6_phi *phi;
+
+ if (!vkd3d_array_reserve((void **)&block->phi, &block->phi_capacity, block->phi_count + 1, sizeof(*block->phi)))
+ {
+ ERR("Failed to allocate phi array.\n");
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY,
+ "Out of memory allocating a phi instruction.");
+ return NULL;
+ }
+ phi = &block->phi[block->phi_count++];
+
+ phi->incoming = NULL;
+ phi->incoming_capacity = 0;
+ phi->incoming_count = 0;
+
+ return phi;
+}
+
+struct function_emission_state
+{
+ struct sm6_block *code_block;
+ struct vkd3d_shader_instruction *ins;
+ unsigned int temp_idx;
+};
+
+static void sm6_parser_emit_alloca(struct sm6_parser *sm6, const struct dxil_record *record,
+ struct vkd3d_shader_instruction *ins, struct sm6_value *dst)
+{
+ const struct sm6_type *type[2], *elem_type;
+ const struct sm6_value *size;
+ unsigned int i, alignment;
+ uint64_t packed_operands;
+
+ if (!dxil_record_validate_operand_count(record, 4, 4, sm6))
+ return;
+
+ for (i = 0; i < 2; ++i)
+ {
+ if (!(type[i] = sm6_parser_get_type(sm6, record->operands[i])))
+ return;
+ }
+
+ packed_operands = record->operands[3];
+ if (packed_operands & ALLOCA_FLAG_IN_ALLOCA)
+ WARN("Ignoring in_alloca flag.\n");
+ if (!(packed_operands & ALLOCA_FLAG_EXPLICIT_TYPE))
+ {
+ FIXME("Unhandled implicit type.\n");
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
+ "Implicit result type for ALLOCA instructions is not supported.");
+ return;
+ }
+ packed_operands &= ~(ALLOCA_FLAG_IN_ALLOCA | ALLOCA_FLAG_EXPLICIT_TYPE);
+
+ if (!sm6_type_is_array(type[0]) || !sm6_type_is_numeric(elem_type = type[0]->u.array.elem_type))
+ {
+ WARN("Type is not a numeric array.\n");
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
+ "Result type of an ALLOCA instruction is not a numeric array.");
+ return;
+ }
+ /* The second type operand is the type of the allocation size operand, in case it is a
+ * forward reference. We only support a constant size, so no forward ref support is needed. */
+ if (!sm6_type_is_integer(type[1]))
+ {
+ WARN("Size operand type is not scalar integer.\n");
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
+ "The type of the allocation size operand of an ALLOCA instruction is not scalar integer.");
+ return;
+ }
+
+ if (!(dst->type = sm6_type_get_pointer_to_type(type[0], ADDRESS_SPACE_DEFAULT, sm6)))
+ {
+ WARN("Failed to get pointer type for type class %u.\n", type[0]->class);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE,
+ "Module does not define a pointer type for an ALLOCA instruction.");
+ return;
+ }
+
+ if (!(size = sm6_parser_get_value_safe(sm6, record->operands[2])))
+ return;
+ /* A size of 1 means one instance of type[0], i.e. one array. */
+ if (sm6_value_get_constant_uint(size) != 1)
+ {
+ FIXME("Allocation size is not 1.\n");
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
+ "ALLOCA instruction allocation sizes other than 1 are not supported.");
+ return;
+ }
+
+ if (!bitcode_parse_alignment(packed_operands & ALLOCA_ALIGNMENT_MASK, &alignment))
+ WARN("Invalid alignment %"PRIu64".\n", packed_operands);
+ packed_operands &= ~ALLOCA_ALIGNMENT_MASK;
+
+ if (packed_operands)
+ WARN("Ignoring flags %#"PRIx64".\n", packed_operands);
+
+ sm6_parser_declare_indexable_temp(sm6, elem_type, type[0]->u.array.count, alignment, true, 0, ins, dst);
+}
+
static enum vkd3d_shader_opcode map_binary_op(uint64_t code, const struct sm6_type *type_a,
const struct sm6_type *type_b, struct sm6_parser *sm6)
{
@@ -3092,8 +3444,10 @@ static void sm6_parser_emit_binop(struct sm6_parser *sm6, const struct dxil_reco
unsigned int i = 0;
a = sm6_parser_get_value_by_ref(sm6, record, NULL, &i);
+ if (!a)
+ return;
b = sm6_parser_get_value_by_ref(sm6, record, a->type, &i);
- if (!a || !b)
+ if (!b)
return;
if (!dxil_record_validate_operand_count(record, i + 1, i + 2, sm6))
@@ -3161,52 +3515,322 @@ static void sm6_parser_emit_binop(struct sm6_parser *sm6, const struct dxil_reco
dst_param_init(&dst_params[0]);
dst_param_init(&dst_params[1]);
- register_init_ssa_scalar(&dst_params[index].reg, a->type, sm6);
+ register_init_ssa_scalar(&dst_params[index].reg, a->type, dst, sm6);
vsir_register_init(&dst_params[index ^ 1].reg, VKD3DSPR_NULL, VKD3D_DATA_UNUSED, 0);
dst->u.reg = dst_params[index].reg;
}
else
{
+ if (handler_idx == VKD3DSIH_ISHL || handler_idx == VKD3DSIH_ISHR || handler_idx == VKD3DSIH_USHR)
+ {
+ /* DXC emits AND instructions where necessary to mask shift counts. Shift binops
+ * do not imply masking the shift as the TPF equivalents do. */
+ ins->flags |= VKD3DSI_SHIFT_UNMASKED;
+ }
instruction_dst_param_init_ssa_scalar(ins, sm6);
}
}
-static void sm6_parser_emit_dx_cbuffer_load(struct sm6_parser *sm6, struct sm6_block *code_block,
- enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct vkd3d_shader_instruction *ins)
+static const struct sm6_block *sm6_function_get_block(const struct sm6_function *function, uint64_t index,
+ struct sm6_parser *sm6)
{
- struct sm6_value *dst = sm6_parser_get_current_value(sm6);
- struct vkd3d_shader_src_param *src_param;
- const struct sm6_value *buffer;
- const struct sm6_type *type;
-
- buffer = operands[0];
- if (!sm6_value_validate_is_handle(buffer, sm6))
- return;
-
- vsir_instruction_init(ins, &sm6->p.location, VKD3DSIH_MOV);
-
- src_param = instruction_src_params_alloc(ins, 1, sm6);
- src_param_init_vector_from_reg(src_param, &buffer->u.handle.reg);
- register_index_address_init(&src_param->reg.idx[2], operands[1], sm6);
- assert(src_param->reg.idx_count == 3);
-
- type = sm6_type_get_scalar_type(dst->type, 0);
- assert(type);
- src_param->reg.data_type = vkd3d_data_type_from_sm6_type(type);
-
- instruction_dst_param_init_ssa_vector(ins, sm6_type_max_vector_size(type), sm6);
+ if (index >= function->block_count)
+ {
+ WARN("Invalid code block index %#"PRIx64".\n", index);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT,
+ "Invalid code block index %#"PRIx64" for a control flow instruction.", index);
+ return NULL;
+ }
+ return function->blocks[index];
}
-static const struct sm6_descriptor_info *sm6_parser_get_descriptor(struct sm6_parser *sm6,
- enum vkd3d_shader_descriptor_type type, unsigned int id, const struct sm6_value *address)
+static void sm6_parser_emit_br(struct sm6_parser *sm6, const struct dxil_record *record,
+ struct sm6_function *function, struct sm6_block *code_block, struct vkd3d_shader_instruction *ins)
{
- const struct sm6_descriptor_info *d;
- unsigned int register_index;
- size_t i;
+ const struct sm6_value *value;
+ unsigned int i = 2;
- for (i = 0; i < sm6->descriptor_count; ++i)
+ if (record->operand_count != 1 && record->operand_count < 3)
{
- d = &sm6->descriptors[i];
+ WARN("Invalid operand count %u.\n", record->operand_count);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT,
+ "Invalid operand count %u for a branch instruction.", record->operand_count);
+ return;
+ }
+
+ if (record->operand_count == 1)
+ {
+ code_block->terminator.type = TERMINATOR_UNCOND_BR;
+ code_block->terminator.true_block = sm6_function_get_block(function, record->operands[0], sm6);
+ }
+ else
+ {
+ if (!sm6->bool_type)
+ {
+ WARN("Bool type not found.\n");
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE,
+ "Module does not define a boolean type for conditions.");
+ return;
+ }
+ if (!(value = sm6_parser_get_value_by_ref(sm6, record, sm6->bool_type, &i))
+ || !sm6_value_validate_is_bool(value, sm6))
+ return;
+ dxil_record_validate_operand_max_count(record, i, sm6);
+
+ code_block->terminator.type = TERMINATOR_COND_BR;
+ code_block->terminator.conditional_reg = value->u.reg;
+ code_block->terminator.true_block = sm6_function_get_block(function, record->operands[0], sm6);
+ code_block->terminator.false_block = sm6_function_get_block(function, record->operands[1], sm6);
+ }
+
+ ins->handler_idx = VKD3DSIH_NOP;
+}
+
+static bool sm6_parser_emit_reg_composite_construct(struct sm6_parser *sm6, const struct vkd3d_shader_register **operand_regs,
+ unsigned int component_count, struct function_emission_state *state, struct vkd3d_shader_register *reg)
+{
+ struct vkd3d_shader_instruction *ins = state->ins;
+ struct vkd3d_shader_src_param *src_params;
+ struct vkd3d_shader_dst_param *dst_param;
+ bool all_constant = true;
+ unsigned int i;
+
+ if (component_count == 1)
+ {
+ *reg = *operand_regs[0];
+ return true;
+ }
+
+ for (i = 0; i < component_count; ++i)
+ all_constant &= register_is_constant(operand_regs[i]);
+
+ if (all_constant)
+ {
+ vsir_register_init(reg, VKD3DSPR_IMMCONST, operand_regs[0]->data_type, 0);
+ reg->dimension = VSIR_DIMENSION_VEC4;
+ for (i = 0; i < component_count; ++i)
+ reg->u.immconst_u32[i] = operand_regs[i]->u.immconst_u32[0];
+ for (; i < VKD3D_VEC4_SIZE; ++i)
+ reg->u.immconst_u32[i] = 0;
+ return true;
+ }
+
+ register_init_with_id(reg, VKD3DSPR_TEMP, operand_regs[0]->data_type, state->temp_idx++);
+ reg->dimension = VSIR_DIMENSION_VEC4;
+
+ for (i = 0; i < component_count; ++i, ++ins)
+ {
+ vsir_instruction_init(ins, &sm6->p.location, VKD3DSIH_MOV);
+
+ if (!(src_params = instruction_src_params_alloc(ins, 1, sm6)))
+ return false;
+
+ src_param_init(&src_params[0]);
+ src_params[0].reg = *operand_regs[i];
+
+ if (!(dst_param = instruction_dst_params_alloc(ins, 1, sm6)))
+ return false;
+
+ dst_param_init_scalar(dst_param, i);
+ dst_param->reg = *reg;
+ }
+
+ state->ins = ins;
+ state->code_block->instruction_count += component_count;
+
+ return true;
+}
+
+static bool sm6_parser_emit_composite_construct(struct sm6_parser *sm6, const struct sm6_value **operands,
+ unsigned int component_count, struct function_emission_state *state, struct vkd3d_shader_register *reg)
+{
+ const struct vkd3d_shader_register *operand_regs[VKD3D_VEC4_SIZE];
+ unsigned int i;
+
+ for (i = 0; i < component_count; ++i)
+ operand_regs[i] = &operands[i]->u.reg;
+
+ return sm6_parser_emit_reg_composite_construct(sm6, operand_regs, component_count, state, reg);
+}
+
+static bool sm6_parser_emit_coordinate_construct(struct sm6_parser *sm6, const struct sm6_value **operands,
+ const struct sm6_value *z_operand, struct function_emission_state *state,
+ struct vkd3d_shader_register *reg)
+{
+ const struct vkd3d_shader_register *operand_regs[VKD3D_VEC4_SIZE];
+ const unsigned int max_operands = 3;
+ unsigned int component_count;
+
+ for (component_count = 0; component_count < max_operands; ++component_count)
+ {
+ if (!z_operand && operands[component_count]->is_undefined)
+ break;
+ operand_regs[component_count] = &operands[component_count]->u.reg;
+ }
+ if (z_operand)
+ {
+ operand_regs[component_count++] = &z_operand->u.reg;
+ }
+
+ return sm6_parser_emit_reg_composite_construct(sm6, operand_regs, component_count, state, reg);
+}
+
+static enum vkd3d_shader_opcode map_dx_unary_op(enum dx_intrinsic_opcode op)
+{
+ switch (op)
+ {
+ case DX_ISNAN:
+ return VKD3DSIH_ISNAN;
+ case DX_ISINF:
+ return VKD3DSIH_ISINF;
+ case DX_ISFINITE:
+ return VKD3DSIH_ISFINITE;
+ case DX_TAN:
+ return VKD3DSIH_TAN;
+ case DX_ACOS:
+ return VKD3DSIH_ACOS;
+ case DX_ASIN:
+ return VKD3DSIH_ASIN;
+ case DX_ATAN:
+ return VKD3DSIH_ATAN;
+ case DX_HCOS:
+ return VKD3DSIH_HCOS;
+ case DX_HSIN:
+ return VKD3DSIH_HSIN;
+ case DX_HTAN:
+ return VKD3DSIH_HTAN;
+ case DX_EXP:
+ return VKD3DSIH_EXP;
+ case DX_FRC:
+ return VKD3DSIH_FRC;
+ case DX_LOG:
+ return VKD3DSIH_LOG;
+ case DX_SQRT:
+ return VKD3DSIH_SQRT;
+ case DX_RSQRT:
+ return VKD3DSIH_RSQ;
+ case DX_ROUND_NE:
+ return VKD3DSIH_ROUND_NE;
+ case DX_ROUND_NI:
+ return VKD3DSIH_ROUND_NI;
+ case DX_ROUND_PI:
+ return VKD3DSIH_ROUND_PI;
+ case DX_ROUND_Z:
+ return VKD3DSIH_ROUND_Z;
+ case DX_BFREV:
+ return VKD3DSIH_BFREV;
+ case DX_COUNT_BITS:
+ return VKD3DSIH_COUNTBITS;
+ case DX_FIRST_BIT_LO:
+ return VKD3DSIH_FIRSTBIT_LO;
+ case DX_FIRST_BIT_HI:
+ return VKD3DSIH_FIRSTBIT_HI;
+ case DX_FIRST_BIT_SHI:
+ return VKD3DSIH_FIRSTBIT_SHI;
+ case DX_DERIV_COARSEX:
+ return VKD3DSIH_DSX_COARSE;
+ case DX_DERIV_COARSEY:
+ return VKD3DSIH_DSY_COARSE;
+ case DX_DERIV_FINEX:
+ return VKD3DSIH_DSX_FINE;
+ case DX_DERIV_FINEY:
+ return VKD3DSIH_DSY_FINE;
+ case DX_LEGACY_F32TOF16:
+ return VKD3DSIH_F32TOF16;
+ case DX_LEGACY_F16TOF32:
+ return VKD3DSIH_F16TOF32;
+ default:
+ vkd3d_unreachable();
+ }
+}
+
+static void sm6_parser_emit_dx_unary(struct sm6_parser *sm6, enum dx_intrinsic_opcode op,
+ const struct sm6_value **operands, struct function_emission_state *state)
+{
+ struct vkd3d_shader_instruction *ins = state->ins;
+ struct vkd3d_shader_src_param *src_param;
+
+ vsir_instruction_init(ins, &sm6->p.location, map_dx_unary_op(op));
+ src_param = instruction_src_params_alloc(ins, 1, sm6);
+ src_param_init_from_value(src_param, operands[0]);
+
+ instruction_dst_param_init_ssa_scalar(ins, sm6);
+}
+
+static enum vkd3d_shader_opcode map_dx_binary_op(enum dx_intrinsic_opcode op, const struct sm6_type *type)
+{
+ switch (op)
+ {
+ case DX_FMAX:
+ return type->u.width == 64 ? VKD3DSIH_DMAX : VKD3DSIH_MAX;
+ case DX_FMIN:
+ return type->u.width == 64 ? VKD3DSIH_DMIN : VKD3DSIH_MIN;
+ case DX_IMAX:
+ return VKD3DSIH_IMAX;
+ case DX_IMIN:
+ return VKD3DSIH_IMIN;
+ case DX_UMAX:
+ return VKD3DSIH_UMAX;
+ case DX_UMIN:
+ return VKD3DSIH_UMIN;
+ default:
+ vkd3d_unreachable();
+ }
+}
+
+static void sm6_parser_emit_dx_binary(struct sm6_parser *sm6, enum dx_intrinsic_opcode op,
+ const struct sm6_value **operands, struct function_emission_state *state)
+{
+ struct vkd3d_shader_instruction *ins = state->ins;
+ struct vkd3d_shader_src_param *src_params;
+
+ vsir_instruction_init(ins, &sm6->p.location, map_dx_binary_op(op, operands[0]->type));
+ src_params = instruction_src_params_alloc(ins, 2, sm6);
+ src_param_init_from_value(&src_params[0], operands[0]);
+ src_param_init_from_value(&src_params[1], operands[1]);
+
+ instruction_dst_param_init_ssa_scalar(ins, sm6);
+}
+
+static void sm6_parser_emit_dx_cbuffer_load(struct sm6_parser *sm6, enum dx_intrinsic_opcode op,
+ const struct sm6_value **operands, struct function_emission_state *state)
+{
+ struct sm6_value *dst = sm6_parser_get_current_value(sm6);
+ struct vkd3d_shader_instruction *ins = state->ins;
+ struct vkd3d_shader_src_param *src_param;
+ const struct sm6_value *buffer;
+ const struct sm6_type *type;
+
+ buffer = operands[0];
+ if (!sm6_value_validate_is_handle(buffer, sm6))
+ return;
+
+ vsir_instruction_init(ins, &sm6->p.location, VKD3DSIH_MOV);
+
+ src_param = instruction_src_params_alloc(ins, 1, sm6);
+ src_param_init_vector_from_reg(src_param, &buffer->u.handle.reg);
+ register_index_address_init(&src_param->reg.idx[2], operands[1], sm6);
+ assert(src_param->reg.idx_count == 3);
+
+ type = sm6_type_get_scalar_type(dst->type, 0);
+ assert(type);
+ src_param->reg.data_type = vkd3d_data_type_from_sm6_type(type);
+ if (data_type_is_64_bit(src_param->reg.data_type))
+ src_param->swizzle = vsir_swizzle_64_from_32(src_param->swizzle);
+
+ instruction_dst_param_init_ssa_vector(ins, sm6_type_max_vector_size(type), sm6);
+}
+
+static const struct sm6_descriptor_info *sm6_parser_get_descriptor(struct sm6_parser *sm6,
+ enum vkd3d_shader_descriptor_type type, unsigned int id, const struct sm6_value *address)
+{
+ const struct sm6_descriptor_info *d;
+ unsigned int register_index;
+ size_t i;
+
+ for (i = 0; i < sm6->descriptor_count; ++i)
+ {
+ d = &sm6->descriptors[i];
if (d->type != type || d->id != id)
continue;
@@ -3222,9 +3846,10 @@ static const struct sm6_descriptor_info *sm6_parser_get_descriptor(struct sm6_pa
return NULL;
}
-static void sm6_parser_emit_dx_create_handle(struct sm6_parser *sm6, struct sm6_block *code_block,
- enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct vkd3d_shader_instruction *ins)
+static void sm6_parser_emit_dx_create_handle(struct sm6_parser *sm6, enum dx_intrinsic_opcode op,
+ const struct sm6_value **operands, struct function_emission_state *state)
{
+ struct vkd3d_shader_instruction *ins = state->ins;
enum vkd3d_shader_descriptor_type type;
const struct sm6_descriptor_info *d;
struct vkd3d_shader_register *reg;
@@ -3246,9 +3871,9 @@ static void sm6_parser_emit_dx_create_handle(struct sm6_parser *sm6, struct sm6_
dst->u.handle.d = d;
reg = &dst->u.handle.reg;
- /* Set idx_count to 3 for use with load instructions.
- * TODO: set register type from resource type when other types are supported. */
- vsir_register_init(reg, VKD3DSPR_CONSTBUFFER, VKD3D_DATA_FLOAT, 3);
+ /* Set idx_count to 3 for use with load/store instructions. */
+ vsir_register_init(reg, d->reg_type, d->reg_data_type, 3);
+ reg->dimension = VSIR_DIMENSION_VEC4;
reg->idx[0].offset = id;
register_index_address_init(&reg->idx[1], operands[2], sm6);
reg->non_uniform = !!sm6_value_get_constant_uint(operands[3]);
@@ -3257,9 +3882,38 @@ static void sm6_parser_emit_dx_create_handle(struct sm6_parser *sm6, struct sm6_
ins->handler_idx = VKD3DSIH_NOP;
}
-static void sm6_parser_emit_dx_load_input(struct sm6_parser *sm6, struct sm6_block *code_block,
- enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct vkd3d_shader_instruction *ins)
+static enum vkd3d_shader_opcode sm6_dx_map_tertiary_op(enum dx_intrinsic_opcode op)
+{
+ switch (op)
+ {
+ case DX_IBFE:
+ return VKD3DSIH_IBFE;
+ case DX_UBFE:
+ return VKD3DSIH_UBFE;
+ default:
+ vkd3d_unreachable();
+ }
+}
+
+static void sm6_parser_emit_dx_tertiary(struct sm6_parser *sm6, enum dx_intrinsic_opcode op,
+ const struct sm6_value **operands, struct function_emission_state *state)
+{
+ struct vkd3d_shader_instruction *ins = state->ins;
+ struct vkd3d_shader_src_param *src_params;
+ unsigned int i;
+
+ vsir_instruction_init(ins, &sm6->p.location, sm6_dx_map_tertiary_op(op));
+ src_params = instruction_src_params_alloc(ins, 3, sm6);
+ for (i = 0; i < 3; ++i)
+ src_param_init_from_value(&src_params[i], operands[i]);
+
+ instruction_dst_param_init_ssa_scalar(ins, sm6);
+}
+
+static void sm6_parser_emit_dx_load_input(struct sm6_parser *sm6, enum dx_intrinsic_opcode op,
+ const struct sm6_value **operands, struct function_emission_state *state)
{
+ struct vkd3d_shader_instruction *ins = state->ins;
struct vkd3d_shader_src_param *src_param;
const struct shader_signature *signature;
unsigned int row_index, column_index;
@@ -3289,9 +3943,142 @@ static void sm6_parser_emit_dx_load_input(struct sm6_parser *sm6, struct sm6_blo
instruction_dst_param_init_ssa_scalar(ins, sm6);
}
-static void sm6_parser_emit_dx_store_output(struct sm6_parser *sm6, struct sm6_block *code_block,
- enum dx_intrinsic_opcode op, const struct sm6_value **operands, struct vkd3d_shader_instruction *ins)
+static void sm6_parser_emit_dx_raw_buffer_load(struct sm6_parser *sm6, enum dx_intrinsic_opcode op,
+ const struct sm6_value **operands, struct function_emission_state *state)
+{
+ unsigned int operand_count, write_mask, component_count = VKD3D_VEC4_SIZE;
+ struct vkd3d_shader_instruction *ins = state->ins;
+ struct vkd3d_shader_src_param *src_params;
+ const struct sm6_value *resource;
+ bool raw;
+
+ resource = operands[0];
+ if (!sm6_value_validate_is_handle(resource, sm6))
+ return;
+ raw = resource->u.handle.d->kind == RESOURCE_KIND_RAWBUFFER;
+
+ if (op == DX_RAW_BUFFER_LOAD)
+ {
+ write_mask = sm6_value_get_constant_uint(operands[3]);
+ if (!write_mask || write_mask > VKD3DSP_WRITEMASK_ALL)
+ {
+ WARN("Invalid write mask %#x.\n", write_mask);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
+ "Write mask %#x for a raw/structured buffer load operation is invalid.", write_mask);
+ return;
+ }
+ else if (write_mask & (write_mask + 1))
+ {
+ FIXME("Unhandled write mask %#x.\n", write_mask);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
+ "Write mask %#x for a raw/structured buffer load operation is unhandled.", write_mask);
+ }
+ component_count = vsir_write_mask_component_count(write_mask);
+ }
+
+ instruction_init_with_resource(ins, raw ? VKD3DSIH_LD_RAW : VKD3DSIH_LD_STRUCTURED, resource, sm6);
+ operand_count = 2 + !raw;
+ if (!(src_params = instruction_src_params_alloc(ins, operand_count, sm6)))
+ return;
+ src_params_init_from_operands(src_params, &operands[1], operand_count - 1);
+ src_param_init_vector_from_reg(&src_params[operand_count - 1], &resource->u.handle.reg);
+
+ instruction_dst_param_init_ssa_vector(ins, component_count, sm6);
+}
+
+static void sm6_parser_emit_dx_buffer_load(struct sm6_parser *sm6, enum dx_intrinsic_opcode op,
+ const struct sm6_value **operands, struct function_emission_state *state)
+{
+ struct vkd3d_shader_instruction *ins = state->ins;
+ struct vkd3d_shader_src_param *src_params;
+ const struct sm6_value *resource;
+
+ resource = operands[0];
+ if (!sm6_value_validate_is_handle(resource, sm6))
+ return;
+
+ if (resource->u.handle.d->kind == RESOURCE_KIND_RAWBUFFER
+ || resource->u.handle.d->kind == RESOURCE_KIND_STRUCTUREDBUFFER)
+ {
+ return sm6_parser_emit_dx_raw_buffer_load(sm6, op, operands, state);
+ }
+
+ if (resource->u.handle.d->kind != RESOURCE_KIND_TYPEDBUFFER)
+ {
+ WARN("Resource is not a typed buffer.\n");
+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_INVALID_OPERATION,
+ "Resource for a typed buffer load is not a typed buffer.");
+ }
+
+ instruction_init_with_resource(ins, (resource->u.handle.d->type == VKD3D_SHADER_DESCRIPTOR_TYPE_UAV)
+ ? VKD3DSIH_LD_UAV_TYPED : VKD3DSIH_LD, resource, sm6);
+
+ src_params = instruction_src_params_alloc(ins, 2, sm6);
+ src_param_init_from_value(&src_params[0], operands[1]);
+ if (!sm6_value_is_undef(operands[2]))
+ {
+ /* Constant zero would be ok, but is not worth checking for unless it shows up. */
+ WARN("Ignoring structure offset.\n");
+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS,
+ "Ignoring structure offset for a typed buffer load.");
+ }
+ src_param_init_vector_from_reg(&src_params[1], &resource->u.handle.reg);
+
+ instruction_dst_param_init_ssa_vector(ins, VKD3D_VEC4_SIZE, sm6);
+}
+
+static unsigned int sm6_value_get_texel_offset(const struct sm6_value *value)
+{
+ return sm6_value_is_undef(value) ? 0 : sm6_value_get_constant_uint(value);
+}
+
+static void instruction_set_texel_offset(struct vkd3d_shader_instruction *ins,
+ const struct sm6_value **operands, struct sm6_parser *sm6)
+{
+ ins->texel_offset.u = sm6_value_get_texel_offset(operands[0]);
+ ins->texel_offset.v = sm6_value_get_texel_offset(operands[1]);
+ ins->texel_offset.w = sm6_value_get_texel_offset(operands[2]);
+}
+
+static void sm6_parser_emit_dx_sincos(struct sm6_parser *sm6, enum dx_intrinsic_opcode op,
+ const struct sm6_value **operands, struct function_emission_state *state)
+{
+ struct sm6_value *dst = sm6_parser_get_current_value(sm6);
+ struct vkd3d_shader_instruction *ins = state->ins;
+ struct vkd3d_shader_dst_param *dst_params;
+ struct vkd3d_shader_src_param *src_param;
+ unsigned int index;
+
+ vsir_instruction_init(ins, &sm6->p.location, VKD3DSIH_SINCOS);
+ src_param = instruction_src_params_alloc(ins, 1, sm6);
+ src_param_init_from_value(src_param, operands[0]);
+
+ index = op == DX_COS;
+ dst_params = instruction_dst_params_alloc(ins, 2, sm6);
+ dst_param_init(&dst_params[0]);
+ dst_param_init(&dst_params[1]);
+ register_init_ssa_scalar(&dst_params[index].reg, dst->type, dst, sm6);
+ vsir_register_init(&dst_params[index ^ 1].reg, VKD3DSPR_NULL, VKD3D_DATA_UNUSED, 0);
+ dst->u.reg = dst_params[index].reg;
+}
+
+static void sm6_parser_emit_dx_split_double(struct sm6_parser *sm6, enum dx_intrinsic_opcode op,
+ const struct sm6_value **operands, struct function_emission_state *state)
+{
+ struct vkd3d_shader_instruction *ins = state->ins;
+ struct vkd3d_shader_src_param *src_param;
+
+ vsir_instruction_init(ins, &sm6->p.location, VKD3DSIH_MOV);
+ src_param = instruction_src_params_alloc(ins, 1, sm6);
+ src_param_init_from_value(src_param, operands[0]);
+
+ instruction_dst_param_init_ssa_vector(ins, 2, sm6);
+}
+
+static void sm6_parser_emit_dx_store_output(struct sm6_parser *sm6, enum dx_intrinsic_opcode op,
+ const struct sm6_value **operands, struct function_emission_state *state)
{
+ struct vkd3d_shader_instruction *ins = state->ins;
struct vkd3d_shader_src_param *src_param;
struct vkd3d_shader_dst_param *dst_param;
const struct shader_signature *signature;
@@ -3342,33 +4129,181 @@ static void sm6_parser_emit_dx_store_output(struct sm6_parser *sm6, struct sm6_b
src_param_init_from_value(src_param, value);
}
+static void sm6_parser_emit_dx_texture_load(struct sm6_parser *sm6, enum dx_intrinsic_opcode op,
+ const struct sm6_value **operands, struct function_emission_state *state)
+{
+ const struct sm6_value *resource, *mip_level_or_sample_count;
+ enum vkd3d_shader_resource_type resource_type;
+ struct vkd3d_shader_src_param *src_params;
+ struct vkd3d_shader_instruction *ins;
+ struct vkd3d_shader_register coord;
+ bool is_multisample, is_uav;
+ unsigned int i;
+
+ resource = operands[0];
+ if (!sm6_value_validate_is_texture_handle(resource, op, sm6))
+ return;
+
+ resource_type = resource->u.handle.d->resource_type;
+ is_multisample = resource_type == VKD3D_SHADER_RESOURCE_TEXTURE_2DMS
+ || resource_type == VKD3D_SHADER_RESOURCE_TEXTURE_2DMSARRAY;
+ is_uav = resource->u.handle.d->type == VKD3D_SHADER_DESCRIPTOR_TYPE_UAV;
+
+ mip_level_or_sample_count = (resource_type != VKD3D_SHADER_RESOURCE_BUFFER) ? operands[1] : NULL;
+ if (!sm6_parser_emit_coordinate_construct(sm6, &operands[2],
+ is_multisample ? NULL : mip_level_or_sample_count, state, &coord))
+ {
+ return;
+ }
+
+ ins = state->ins;
+ instruction_init_with_resource(ins, is_uav ? VKD3DSIH_LD_UAV_TYPED
+ : is_multisample ? VKD3DSIH_LD2DMS : VKD3DSIH_LD, resource, sm6);
+ instruction_set_texel_offset(ins, &operands[5], sm6);
+
+ for (i = 0; i < VKD3D_VEC4_SIZE; ++i)
+ ins->resource_data_type[i] = resource->u.handle.d->resource_data_type;
+
+ src_params = instruction_src_params_alloc(ins, 2 + is_multisample, sm6);
+ src_param_init_vector_from_reg(&src_params[0], &coord);
+ src_param_init_vector_from_reg(&src_params[1], &resource->u.handle.reg);
+ if (is_multisample)
+ src_param_init_from_value(&src_params[2], mip_level_or_sample_count);
+
+ instruction_dst_param_init_ssa_vector(ins, VKD3D_VEC4_SIZE, sm6);
+}
+
+static void sm6_parser_emit_dx_texture_store(struct sm6_parser *sm6, enum dx_intrinsic_opcode op,
+ const struct sm6_value **operands, struct function_emission_state *state)
+{
+ struct vkd3d_shader_register coord, texel;
+ struct vkd3d_shader_src_param *src_params;
+ struct vkd3d_shader_dst_param *dst_param;
+ unsigned int write_mask, component_count;
+ struct vkd3d_shader_instruction *ins;
+ const struct sm6_value *resource;
+
+ resource = operands[0];
+ if (!sm6_value_validate_is_texture_handle(resource, op, sm6))
+ return;
+
+ if (!sm6_parser_emit_coordinate_construct(sm6, &operands[1], NULL, state, &coord))
+ return;
+
+ write_mask = sm6_value_get_constant_uint(operands[8]);
+ if (!write_mask || write_mask > VKD3DSP_WRITEMASK_ALL)
+ {
+ WARN("Invalid write mask %#x.\n", write_mask);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
+ "Write mask %#x for a texture store operation is invalid.", write_mask);
+ return;
+ }
+ else if (write_mask & (write_mask + 1))
+ {
+ /* In this case, it is unclear which source operands will be defined unless we encounter it in a shader. */
+ FIXME("Unhandled write mask %#x.\n", write_mask);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
+ "Write mask %#x for a texture store operation is unhandled.", write_mask);
+ }
+ component_count = vsir_write_mask_component_count(write_mask);
+
+ if (!sm6_parser_emit_composite_construct(sm6, &operands[4], component_count, state, &texel))
+ return;
+
+ ins = state->ins;
+ vsir_instruction_init(ins, &sm6->p.location, VKD3DSIH_STORE_UAV_TYPED);
+
+ if (!(src_params = instruction_src_params_alloc(ins, 2, sm6)))
+ return;
+ src_param_init_vector_from_reg(&src_params[0], &coord);
+ src_param_init_vector_from_reg(&src_params[1], &texel);
+
+ dst_param = instruction_dst_params_alloc(ins, 1, sm6);
+ dst_param->reg = resource->u.handle.reg;
+ dst_param_init_with_mask(dst_param, write_mask);
+}
+
struct sm6_dx_opcode_info
{
- const char ret_type;
+ const char *ret_type;
const char *operand_info;
- void (*handler)(struct sm6_parser *, struct sm6_block *, enum dx_intrinsic_opcode,
- const struct sm6_value **, struct vkd3d_shader_instruction *);
+ void (*handler)(struct sm6_parser *, enum dx_intrinsic_opcode, const struct sm6_value **,
+ struct function_emission_state *);
};
/*
+ 1 -> int1
8 -> int8
b -> constant int1
c -> constant int8/16/32
+ C -> constant or undefined int8/16/32
i -> int32
+ m -> int16/32/64
+ f -> float
+ d -> double
+ e -> half/float
+ g -> half/float/double
H -> handle
+ S -> splitdouble
v -> void
o -> overloaded
+ R -> matches the return type
*/
static const struct sm6_dx_opcode_info sm6_dx_op_table[] =
{
- [DX_CBUFFER_LOAD_LEGACY ] = {'o', "Hi", sm6_parser_emit_dx_cbuffer_load},
- [DX_CREATE_HANDLE ] = {'H', "ccib", sm6_parser_emit_dx_create_handle},
- [DX_LOAD_INPUT ] = {'o', "ii8i", sm6_parser_emit_dx_load_input},
- [DX_STORE_OUTPUT ] = {'v', "ii8o", sm6_parser_emit_dx_store_output},
+ [DX_ACOS ] = {"g", "R", sm6_parser_emit_dx_unary},
+ [DX_ASIN ] = {"g", "R", sm6_parser_emit_dx_unary},
+ [DX_ATAN ] = {"g", "R", sm6_parser_emit_dx_unary},
+ [DX_BFREV ] = {"m", "R", sm6_parser_emit_dx_unary},
+ [DX_BUFFER_LOAD ] = {"o", "Hii", sm6_parser_emit_dx_buffer_load},
+ [DX_CBUFFER_LOAD_LEGACY ] = {"o", "Hi", sm6_parser_emit_dx_cbuffer_load},
+ [DX_COS ] = {"g", "R", sm6_parser_emit_dx_sincos},
+ [DX_COUNT_BITS ] = {"i", "m", sm6_parser_emit_dx_unary},
+ [DX_CREATE_HANDLE ] = {"H", "ccib", sm6_parser_emit_dx_create_handle},
+ [DX_DERIV_COARSEX ] = {"e", "R", sm6_parser_emit_dx_unary},
+ [DX_DERIV_COARSEY ] = {"e", "R", sm6_parser_emit_dx_unary},
+ [DX_DERIV_FINEX ] = {"e", "R", sm6_parser_emit_dx_unary},
+ [DX_DERIV_FINEY ] = {"e", "R", sm6_parser_emit_dx_unary},
+ [DX_EXP ] = {"g", "R", sm6_parser_emit_dx_unary},
+ [DX_FIRST_BIT_HI ] = {"i", "m", sm6_parser_emit_dx_unary},
+ [DX_FIRST_BIT_LO ] = {"i", "m", sm6_parser_emit_dx_unary},
+ [DX_FIRST_BIT_SHI ] = {"i", "m", sm6_parser_emit_dx_unary},
+ [DX_FMAX ] = {"g", "RR", sm6_parser_emit_dx_binary},
+ [DX_FMIN ] = {"g", "RR", sm6_parser_emit_dx_binary},
+ [DX_FRC ] = {"g", "R", sm6_parser_emit_dx_unary},
+ [DX_IBFE ] = {"m", "iiR", sm6_parser_emit_dx_tertiary},
+ [DX_HCOS ] = {"g", "R", sm6_parser_emit_dx_unary},
+ [DX_HSIN ] = {"g", "R", sm6_parser_emit_dx_unary},
+ [DX_HTAN ] = {"g", "R", sm6_parser_emit_dx_unary},
+ [DX_IMAX ] = {"m", "RR", sm6_parser_emit_dx_binary},
+ [DX_IMIN ] = {"m", "RR", sm6_parser_emit_dx_binary},
+ [DX_ISFINITE ] = {"1", "g", sm6_parser_emit_dx_unary},
+ [DX_ISINF ] = {"1", "g", sm6_parser_emit_dx_unary},
+ [DX_ISNAN ] = {"1", "g", sm6_parser_emit_dx_unary},
+ [DX_LEGACY_F16TOF32 ] = {"f", "i", sm6_parser_emit_dx_unary},
+ [DX_LEGACY_F32TOF16 ] = {"i", "f", sm6_parser_emit_dx_unary},
+ [DX_LOAD_INPUT ] = {"o", "ii8i", sm6_parser_emit_dx_load_input},
+ [DX_LOG ] = {"g", "R", sm6_parser_emit_dx_unary},
+ [DX_RAW_BUFFER_LOAD ] = {"o", "Hii8i", sm6_parser_emit_dx_raw_buffer_load},
+ [DX_ROUND_NE ] = {"g", "R", sm6_parser_emit_dx_unary},
+ [DX_ROUND_NI ] = {"g", "R", sm6_parser_emit_dx_unary},
+ [DX_ROUND_PI ] = {"g", "R", sm6_parser_emit_dx_unary},
+ [DX_ROUND_Z ] = {"g", "R", sm6_parser_emit_dx_unary},
+ [DX_RSQRT ] = {"g", "R", sm6_parser_emit_dx_unary},
+ [DX_SIN ] = {"g", "R", sm6_parser_emit_dx_sincos},
+ [DX_SPLIT_DOUBLE ] = {"S", "d", sm6_parser_emit_dx_split_double},
+ [DX_SQRT ] = {"g", "R", sm6_parser_emit_dx_unary},
+ [DX_STORE_OUTPUT ] = {"v", "ii8o", sm6_parser_emit_dx_store_output},
+ [DX_TAN ] = {"g", "R", sm6_parser_emit_dx_unary},
+ [DX_TEXTURE_LOAD ] = {"o", "HiiiiCCC", sm6_parser_emit_dx_texture_load},
+ [DX_TEXTURE_STORE ] = {"v", "Hiiiooooc", sm6_parser_emit_dx_texture_store},
+ [DX_UBFE ] = {"m", "iiR", sm6_parser_emit_dx_tertiary},
+ [DX_UMAX ] = {"m", "RR", sm6_parser_emit_dx_binary},
+ [DX_UMIN ] = {"m", "RR", sm6_parser_emit_dx_binary},
};
static bool sm6_parser_validate_operand_type(struct sm6_parser *sm6, const struct sm6_value *value, char info_type,
- bool is_return)
+ const struct sm6_type *ret_type, bool is_return)
{
const struct sm6_type *type = value->type;
@@ -3380,6 +4315,8 @@ static bool sm6_parser_validate_operand_type(struct sm6_parser *sm6, const struc
case 0:
FIXME("Invalid operand count.\n");
return false;
+ case '1':
+ return sm6_type_is_bool(type);
case '8':
return sm6_type_is_i8(type);
case 'b':
@@ -3387,15 +4324,32 @@ static bool sm6_parser_validate_operand_type(struct sm6_parser *sm6, const struc
case 'c':
return sm6_value_is_constant(value) && sm6_type_is_integer(type) && type->u.width >= 8
&& type->u.width <= 32;
+ case 'C':
+ return (sm6_value_is_constant(value) || sm6_value_is_undef(value))
+ && sm6_type_is_integer(type) && type->u.width >= 8 && type->u.width <= 32;
case 'i':
return sm6_type_is_i32(type);
+ case 'm':
+ return sm6_type_is_i16_i32_i64(type);
+ case 'f':
+ return sm6_type_is_float(type);
+ case 'd':
+ return sm6_type_is_double(type);
+ case 'e':
+ return sm6_type_is_f16_f32(type);
+ case 'g':
+ return sm6_type_is_floating_point(type);
case 'H':
return (is_return || sm6_value_is_handle(value)) && type == sm6->handle_type;
+ case 'S':
+ return sm6_type_is_struct(type) && !strcmp(type->u.struc->name, "dx.types.splitdouble");
case 'v':
return !type;
case 'o':
/* TODO: some type checking may be possible */
return true;
+ case 'R':
+ return type == ret_type;
default:
FIXME("Unhandled operand code '%c'.\n", info_type);
return false;
@@ -3410,7 +4364,8 @@ static bool sm6_parser_validate_dx_op(struct sm6_parser *sm6, enum dx_intrinsic_
info = &sm6_dx_op_table[op];
- if (!sm6_parser_validate_operand_type(sm6, dst, info->ret_type, true))
+ assert(info->ret_type[0]);
+ if (!sm6_parser_validate_operand_type(sm6, dst, info->ret_type[0], NULL, true))
{
WARN("Failed to validate return type for dx intrinsic id %u, '%s'.\n", op, name);
/* Return type validation failure is not so critical. We only need to set
@@ -3420,7 +4375,7 @@ static bool sm6_parser_validate_dx_op(struct sm6_parser *sm6, enum dx_intrinsic_
for (i = 0; i < operand_count; ++i)
{
const struct sm6_value *value = operands[i];
- if (!sm6_parser_validate_operand_type(sm6, value, info->operand_info[i], false))
+ if (!sm6_parser_validate_operand_type(sm6, value, info->operand_info[i], dst->type, false))
{
WARN("Failed to validate operand %u for dx intrinsic id %u, '%s'.\n", i + 1, op, name);
vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
@@ -3454,27 +4409,27 @@ static void sm6_parser_emit_unhandled(struct sm6_parser *sm6, struct vkd3d_shade
/* dst->is_undefined is not set here because it flags only explicitly undefined values. */
}
-static void sm6_parser_decode_dx_op(struct sm6_parser *sm6, struct sm6_block *code_block, enum dx_intrinsic_opcode op,
+static void sm6_parser_decode_dx_op(struct sm6_parser *sm6, enum dx_intrinsic_opcode op,
const char *name, const struct sm6_value **operands, unsigned int operand_count,
- struct vkd3d_shader_instruction *ins, struct sm6_value *dst)
+ struct function_emission_state *state, struct sm6_value *dst)
{
if (op >= ARRAY_SIZE(sm6_dx_op_table) || !sm6_dx_op_table[op].operand_info)
{
FIXME("Unhandled dx intrinsic function id %u, '%s'.\n", op, name);
vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_UNHANDLED_INTRINSIC,
"Call to intrinsic function %s is unhandled.", name);
- sm6_parser_emit_unhandled(sm6, ins, dst);
+ sm6_parser_emit_unhandled(sm6, state->ins, dst);
return;
}
if (sm6_parser_validate_dx_op(sm6, op, name, operands, operand_count, dst))
- sm6_dx_op_table[op].handler(sm6, code_block, op, operands, ins);
+ sm6_dx_op_table[op].handler(sm6, op, operands, state);
else
- sm6_parser_emit_unhandled(sm6, ins, dst);
+ sm6_parser_emit_unhandled(sm6, state->ins, dst);
}
static void sm6_parser_emit_call(struct sm6_parser *sm6, const struct dxil_record *record,
- struct sm6_block *code_block, struct vkd3d_shader_instruction *ins, struct sm6_value *dst)
+ struct function_emission_state *state, struct sm6_value *dst)
{
const struct sm6_value *operands[DXIL_OP_MAX_OPERANDS];
const struct sm6_value *fn_value, *op_value;
@@ -3556,8 +4511,8 @@ static void sm6_parser_emit_call(struct sm6_parser *sm6, const struct dxil_recor
"Expected a constant integer dx intrinsic function id.");
return;
}
- sm6_parser_decode_dx_op(sm6, code_block, register_get_uint_value(&op_value->u.reg),
- fn_value->u.function.name, &operands[1], operand_count - 1, ins, dst);
+ sm6_parser_decode_dx_op(sm6, register_get_uint_value(&op_value->u.reg),
+ fn_value->u.function.name, &operands[1], operand_count - 1, state, dst);
}
static enum vkd3d_shader_opcode sm6_map_cast_op(uint64_t code, const struct sm6_type *from,
@@ -3700,6 +4655,9 @@ static void sm6_parser_emit_cast(struct sm6_parser *sm6, const struct dxil_recor
if (handler_idx == VKD3DSIH_NOP)
{
dst->u.reg = value->u.reg;
+ /* Set the result type for casts from 16-bit min precision. */
+ if (type->u.width != 16)
+ dst->u.reg.data_type = vkd3d_data_type_from_sm6_type(type);
return;
}
@@ -3775,8 +4733,10 @@ static void sm6_parser_emit_cmp2(struct sm6_parser *sm6, const struct dxil_recor
}
a = sm6_parser_get_value_by_ref(sm6, record, NULL, &i);
+ if (!a)
+ return;
b = sm6_parser_get_value_by_ref(sm6, record, a->type, &i);
- if (!a || !b)
+ if (!b)
return;
if (!dxil_record_validate_operand_count(record, i + 1, i + 2, sm6))
@@ -3896,8 +4856,8 @@ static void sm6_parser_emit_extractval(struct sm6_parser *sm6, const struct dxil
vsir_instruction_init(ins, &sm6->p.location, VKD3DSIH_MOV);
src_param = instruction_src_params_alloc(ins, 1, sm6);
- src_param_init_from_value(src_param, src);
- src_param->swizzle = vkd3d_shader_create_swizzle(elem_idx, elem_idx, elem_idx, elem_idx);
+ src_param->reg = src->u.reg;
+ src_param_init_scalar(src_param, elem_idx);
instruction_dst_param_init_ssa_scalar(ins, sm6);
}
@@ -4053,25 +5013,257 @@ static void sm6_parser_emit_load(struct sm6_parser *sm6, const struct dxil_recor
instruction_dst_param_init_ssa_scalar(ins, sm6);
}
-static void sm6_parser_emit_ret(struct sm6_parser *sm6, const struct dxil_record *record,
- struct sm6_block *code_block, struct vkd3d_shader_instruction *ins)
+static int phi_incoming_compare(const void *a, const void *b)
{
- if (!dxil_record_validate_operand_count(record, 0, 1, sm6))
- return;
-
- if (record->operand_count)
- FIXME("Non-void return is not implemented.\n");
+ const struct incoming_value *incoming_a = a, *incoming_b = b;
- ins->handler_idx = VKD3DSIH_NOP;
+ return (incoming_a->block > incoming_b->block) - (incoming_a->block < incoming_b->block);
}
-static void sm6_parser_emit_vselect(struct sm6_parser *sm6, const struct dxil_record *record,
- struct vkd3d_shader_instruction *ins, struct sm6_value *dst)
+static void sm6_parser_emit_phi(struct sm6_parser *sm6, const struct dxil_record *record,
+ struct sm6_function *function, struct sm6_block *code_block, struct vkd3d_shader_instruction *ins,
+ struct sm6_value *dst)
{
- struct vkd3d_shader_src_param *src_params;
- const struct sm6_value *src[3];
- unsigned int i = 0;
-
+ struct incoming_value *incoming;
+ const struct sm6_type *type;
+ struct sm6_phi *phi;
+ unsigned int i, j;
+ uint64_t src_idx;
+
+ if (!(record->operand_count & 1))
+ {
+ WARN("Invalid operand count %u.\n", record->operand_count);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT,
+ "Invalid operand count %u for phi instruction.", record->operand_count);
+ return;
+ }
+
+ if (!(type = sm6_parser_get_type(sm6, record->operands[0])))
+ return;
+ if (!sm6_type_is_numeric(type))
+ {
+ /* dxc doesn't seem to use buffer/resource read return types here. */
+ FIXME("Only scalar numeric types are supported.\n");
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT,
+ "Result type class %u of a phi instruction is not scalar numeric.", type->class);
+ return;
+ }
+
+ dst->type = type;
+ register_init_ssa_scalar(&dst->u.reg, type, dst, sm6);
+
+ if (!(phi = sm6_block_phi_require_space(code_block, sm6)))
+ return;
+ phi->reg = dst->u.reg;
+ phi->incoming_count = record->operand_count / 2u;
+
+ if (!vkd3d_array_reserve((void **)&phi->incoming, &phi->incoming_capacity, phi->incoming_count,
+ sizeof(*phi->incoming)))
+ {
+ ERR("Failed to allocate phi incoming array.\n");
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY,
+ "Out of memory allocating a phi incoming array.");
+ return;
+ }
+ incoming = phi->incoming;
+
+ for (i = 1; i < record->operand_count; i += 2)
+ {
+ src_idx = sm6->value_count - decode_rotated_signed_value(record->operands[i]);
+ /* May be a forward reference. */
+ if (src_idx >= sm6->cur_max_value)
+ {
+ WARN("Invalid value index %"PRIu64".\n", src_idx);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
+ "Invalid value index %"PRIu64" for a phi incoming value.", src_idx);
+ return;
+ }
+
+ j = i / 2u;
+ /* Store the value index in the register for later resolution. */
+ incoming[j].reg.idx[0].offset = src_idx;
+ incoming[j].block = sm6_function_get_block(function, record->operands[i + 1], sm6);
+ }
+
+ ins->handler_idx = VKD3DSIH_NOP;
+
+ qsort(incoming, phi->incoming_count, sizeof(*incoming), phi_incoming_compare);
+
+ for (i = 1, j = 1; i < phi->incoming_count; ++i)
+ {
+ if (incoming[i].block != incoming[i - 1].block)
+ {
+ incoming[j++] = incoming[i];
+ continue;
+ }
+
+ if (incoming[i].reg.idx[0].offset != incoming[i - 1].reg.idx[0].offset)
+ {
+ WARN("PHI conflict.\n");
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
+ "Two phi incomings have the same block but different values.");
+ }
+ }
+ /* if (j == 1) we should be able to set dst->u.reg to incoming[0].reg, but structurisation
+ * may potentially add new incomings. */
+ phi->incoming_count = j;
+}
+
+static void sm6_parser_emit_ret(struct sm6_parser *sm6, const struct dxil_record *record,
+ struct sm6_block *code_block, struct vkd3d_shader_instruction *ins)
+{
+ if (!dxil_record_validate_operand_count(record, 0, 1, sm6))
+ return;
+
+ if (record->operand_count)
+ FIXME("Non-void return is not implemented.\n");
+
+ code_block->terminator.type = TERMINATOR_RET;
+
+ ins->handler_idx = VKD3DSIH_NOP;
+}
+
+static void sm6_parser_emit_store(struct sm6_parser *sm6, const struct dxil_record *record,
+ struct vkd3d_shader_instruction *ins, struct sm6_value *dst)
+{
+ struct vkd3d_shader_src_param *src_param;
+ struct vkd3d_shader_dst_param *dst_param;
+ const struct sm6_type *pointee_type;
+ const struct sm6_value *ptr, *src;
+ unsigned int i = 0, alignment;
+ uint64_t alignment_code;
+
+ if (!(ptr = sm6_parser_get_value_by_ref(sm6, record, NULL, &i))
+ || !sm6_value_validate_is_register(ptr, sm6)
+ || !sm6_value_validate_is_pointer(ptr, sm6))
+ {
+ return;
+ }
+
+ pointee_type = ptr->type->u.pointer.type;
+ if (!(src = sm6_parser_get_value_by_ref(sm6, record, pointee_type, &i)))
+ return;
+ if (!sm6_value_validate_is_numeric(src, sm6))
+ return;
+
+ if (pointee_type != src->type)
+ {
+ WARN("Type mismatch.\n");
+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH,
+ "Type mismatch in pointer store arguments.");
+ }
+
+ if (!dxil_record_validate_operand_count(record, i + 2, i + 2, sm6))
+ return;
+
+ alignment_code = record->operands[i++];
+ if (!bitcode_parse_alignment(alignment_code, &alignment))
+ WARN("Invalid alignment %"PRIu64".\n", alignment_code);
+
+ if (record->operands[i])
+ WARN("Ignoring volatile modifier.\n");
+
+ vsir_instruction_init(ins, &sm6->p.location, VKD3DSIH_MOV);
+
+ src_param = instruction_src_params_alloc(ins, 1, sm6);
+ src_param_init_from_value(&src_param[0], src);
+
+ dst_param = instruction_dst_params_alloc(ins, 1, sm6);
+ dst_param_init(dst_param);
+ dst_param->reg = ptr->u.reg;
+ dst_param->reg.alignment = alignment;
+}
+
+static void sm6_parser_emit_switch(struct sm6_parser *sm6, const struct dxil_record *record,
+ struct sm6_function *function, struct sm6_block *code_block, struct vkd3d_shader_instruction *ins)
+{
+ struct sm6_block_terminator *terminator = &code_block->terminator;
+ const struct sm6_type *type;
+ const struct sm6_value *src;
+ unsigned int i = 1, j;
+
+ if (record->operand_count < 3 || !(record->operand_count & 1))
+ {
+ WARN("Invalid operand count %u.\n", record->operand_count);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT,
+ "Invalid operand count %u for a switch instruction.", record->operand_count);
+ return;
+ }
+
+ if (!(type = sm6_parser_get_type(sm6, record->operands[0])))
+ return;
+
+ if (!(src = sm6_parser_get_value_by_ref(sm6, record, type, &i))
+ || !sm6_value_validate_is_register(src, sm6))
+ return;
+ assert(i == 2);
+
+ if (src->type != type)
+ {
+ WARN("Type mismatch.\n");
+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH,
+ "The type of a switch selector value does not match the selector type.");
+ }
+ if (!sm6_type_is_integer(type))
+ {
+ WARN("Selector is not scalar integer.\n");
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
+ "Selector type class %u of a switch instruction is not scalar integer.", type->class);
+ return;
+ }
+
+ terminator->conditional_reg = src->u.reg;
+ terminator->type = TERMINATOR_SWITCH;
+
+ terminator->case_count = record->operand_count / 2u;
+ if (!(terminator->cases = vkd3d_calloc(terminator->case_count, sizeof(*terminator->cases))))
+ {
+ ERR("Failed to allocate case array.\n");
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY,
+ "Out of memory allocating a switch case array.");
+ return;
+ }
+
+ /* Executes 'operand_count / 2' times because operand_count is uneven. */
+ for (; i < record->operand_count; i += 2)
+ {
+ j = i / 2u - 1;
+ terminator->cases[j].block = sm6_function_get_block(function, record->operands[i], sm6);
+ /* For structurisation it is convenient to store the default in the case array. */
+ terminator->cases[j].is_default = !j;
+ }
+
+ for (i = 3; i < record->operand_count; i += 2)
+ {
+ if (!(src = sm6_parser_get_value_safe(sm6, record->operands[i])))
+ return;
+
+ if (src->type != type)
+ {
+ WARN("Type mismatch.\n");
+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH,
+ "The type of a switch case value does not match the selector type.");
+ }
+ if (!sm6_value_is_constant(src))
+ {
+ WARN("Case value is not a constant.\n");
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
+ "A switch case value is not a constant.");
+ }
+
+ terminator->cases[i / 2u].value = sm6_value_get_constant_uint64(src);
+ }
+
+ ins->handler_idx = VKD3DSIH_NOP;
+}
+
+static void sm6_parser_emit_vselect(struct sm6_parser *sm6, const struct dxil_record *record,
+ struct vkd3d_shader_instruction *ins, struct sm6_value *dst)
+{
+ struct vkd3d_shader_src_param *src_params;
+ const struct sm6_value *src[3];
+ unsigned int i = 0;
+
if (!(src[1] = sm6_parser_get_value_by_ref(sm6, record, NULL, &i))
|| !(src[2] = sm6_parser_get_value_by_ref(sm6, record, src[1]->type, &i))
|| !(src[0] = sm6_parser_get_value_by_ref(sm6, record, NULL, &i)))
@@ -4115,6 +5307,12 @@ static bool sm6_metadata_value_is_string(const struct sm6_metadata_value *m)
return m && m->type == VKD3D_METADATA_STRING;
}
+static bool sm6_metadata_value_is_zero_or_undef(const struct sm6_metadata_value *m)
+{
+ return sm6_metadata_value_is_value(m)
+ && (sm6_value_is_undef(m->u.value) || sm6_value_is_constant_zero(m->u.value));
+}
+
static bool sm6_metadata_get_uint_value(const struct sm6_parser *sm6,
const struct sm6_metadata_value *m, unsigned int *u)
{
@@ -4153,12 +5351,279 @@ static bool sm6_metadata_get_uint64_value(const struct sm6_parser *sm6,
return true;
}
+static void sm6_parser_metadata_attachment_block_init(struct sm6_parser *sm6, const struct dxil_block *target_block,
+ const struct dxil_block *block)
+{
+ struct dxil_record *target_record;
+ const struct dxil_record *record;
+ unsigned int i;
+ uint64_t index;
+
+ for (i = 0; i < block->record_count; ++i)
+ {
+ record = block->records[i];
+ if (record->code != METADATA_ATTACHMENT)
+ {
+ WARN("Ignoring record with code %u.\n", record->code);
+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_ATTACHMENT,
+ "Ignoring a metadata attachment record with code %u.", record->code);
+ continue;
+ }
+ if (!(record->operand_count & 1))
+ {
+ WARN("Ignoring function attachment.\n");
+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_ATTACHMENT,
+ "Ignoring a metadata function attachment.");
+ continue;
+ }
+
+ index = record->operands[0];
+ if (!target_block->record_count || index >= target_block->record_count - 1)
+ {
+ WARN("Invalid record index %"PRIu64".\n", index);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
+ "Invalid record index %"PRIu64" for a metadata attachment.", index);
+ continue;
+ }
+ /* 'index' is an instruction index, but records[0] is DECLAREBLOCKS, not an instruction. */
+ target_record = target_block->records[index + 1];
+ if (target_record->attachment)
+ {
+ WARN("Overwriting record attachment.\n");
+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_ATTACHMENT,
+ "The target record for a metadata attachment already has an attachment.");
+ }
+ target_record->attachment = record;
+ }
+}
+
+static void sm6_parser_metadata_attachments_init(struct sm6_parser *sm6, const struct dxil_block *block)
+{
+ unsigned int i;
+
+ for (i = 0; i < block->child_block_count; ++i)
+ {
+ if (block->child_blocks[i]->id == METADATA_ATTACHMENT_BLOCK)
+ sm6_parser_metadata_attachment_block_init(sm6, block, block->child_blocks[i]);
+ }
+}
+
+static const struct sm6_metadata_value *sm6_parser_find_metadata_kind(const struct sm6_parser *sm6, uint64_t id)
+{
+ unsigned int i, j;
+
+ for (i = 0; i < ARRAY_SIZE(sm6->metadata_tables); ++i)
+ {
+ for (j = 0; j < sm6->metadata_tables[i].count; ++j)
+ {
+ if (sm6->metadata_tables[i].values[j].type == VKD3D_METADATA_KIND
+ && sm6->metadata_tables[i].values[j].u.kind.id == id)
+ return &sm6->metadata_tables[i].values[j];
+ }
+ }
+
+ return NULL;
+}
+
+static const struct sm6_metadata_value *sm6_parser_metadata_get_value(const struct sm6_parser *sm6, uint64_t index)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(sm6->metadata_tables); ++i)
+ {
+ if (sm6->metadata_tables[i].count > index)
+ break;
+ index -= sm6->metadata_tables[i].count;
+ }
+
+ return (index < sm6->metadata_tables[i].count) ? &sm6->metadata_tables[i].values[index] : NULL;
+}
+
+static bool metadata_node_get_unary_uint(const struct sm6_metadata_node *node, unsigned int *operand,
+ struct sm6_parser *sm6)
+{
+ if (node->operand_count != 1)
+ {
+ FIXME("Ignoring node with %u operands.\n", node->operand_count);
+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_ATTACHMENT,
+ "Ignoring metadata attachment node with %u operands; expected unary.", node->operand_count);
+ return false;
+ }
+ if (!sm6_metadata_value_is_value(node->operands[0])
+ || !sm6_metadata_get_uint_value(sm6, node->operands[0], operand))
+ {
+ WARN("Failed to get operand value.\n");
+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_ATTACHMENT,
+ "Failed to get a metadata attachment operand value; ignoring the attachment.");
+ return false;
+ }
+
+ return true;
+}
+
+static void metadata_attachment_record_apply(const struct dxil_record *record, enum bitcode_function_code func_code,
+ struct vkd3d_shader_instruction *ins, struct sm6_value *dst, struct sm6_parser *sm6)
+{
+ static const char *ignored_names[] =
+ {
+ "alias.scope",
+ "dx.controlflow.hints",
+ "llvm.loop",
+ "noalias",
+ "tbaa",
+ "range",
+ };
+ const struct sm6_metadata_node *node;
+ const struct sm6_metadata_value *m;
+ unsigned int i, j, operand;
+ bool ignored = false;
+ const char *name;
+
+ if (record->attachment)
+ {
+ WARN("Ignoring nested metadata attachment.\n");
+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_ATTACHMENT,
+ "Ignoring a nested metadata attachment.");
+ }
+
+ assert(record->operand_count & 1);
+ for (i = 1; i < record->operand_count; i += 2)
+ {
+ if (!(m = sm6_parser_find_metadata_kind(sm6, record->operands[i])))
+ {
+ WARN("Failed to find metadata kind %"PRIx64".\n", record->operands[i]);
+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_ATTACHMENT,
+ "Failed to find metadata kind %"PRIx64" for an attachment.", record->operands[i]);
+ continue;
+ }
+ name = m->u.kind.name;
+
+ m = sm6_parser_metadata_get_value(sm6, record->operands[i + 1]);
+ if (!m || !sm6_metadata_value_is_node(m))
+ {
+ WARN("Failed to retrieve metadata attachment node.\n");
+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_ATTACHMENT,
+ "Failed to retrieve a metadata attachment node.");
+ continue;
+ }
+ node = m->u.node;
+
+ if (!strcmp(name, "dx.precise"))
+ {
+ if (!sm6_value_is_register(dst))
+ {
+ WARN("Precise value is not a register.\n");
+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_ATTACHMENT,
+ "A value marked as precise is not a register.");
+ }
+ else if (metadata_node_get_unary_uint(node, &operand, sm6) && operand)
+ {
+ ins->flags |= sm6_type_is_scalar(dst->type) ? VKD3DSI_PRECISE_X : VKD3DSI_PRECISE_XYZW;
+ }
+ }
+ else if (!strcmp(name, "dx.nonuniform"))
+ {
+ if (!sm6_value_is_register(dst))
+ {
+ WARN("Non-uniform value is not a register.\n");
+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_ATTACHMENT,
+ "A value marked as non-uniform is not a register.");
+ }
+ else if (metadata_node_get_unary_uint(node, &operand, sm6))
+ {
+ dst->u.reg.non_uniform = !!operand;
+ }
+ }
+ else
+ {
+ for (j = 0; j < ARRAY_SIZE(ignored_names); ++j)
+ if (!strcmp(name, ignored_names[j]))
+ break;
+ if (j == ARRAY_SIZE(ignored_names))
+ {
+ WARN("Ignoring metadata attachment '%s'.\n", name);
+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_ATTACHMENT,
+ "Ignoring a metadata attachment named '%s'.", name);
+ }
+ ignored = true;
+ }
+
+ if (func_code != FUNC_CODE_INST_CALL && !ignored)
+ WARN("Metadata attachment target is not a function call.\n");
+ }
+}
+
+static bool sm6_function_blocks_reserve(struct sm6_function *function, unsigned int reserve)
+{
+ if (!vkd3d_array_reserve((void **)&function->blocks, &function->block_capacity,
+ reserve, sizeof(*function->blocks)))
+ {
+ ERR("Failed to allocate code block array.\n");
+ return false;
+ }
+ return true;
+}
+
+static struct sm6_block *sm6_function_create_block(struct sm6_function *function)
+{
+ struct sm6_block *block;
+
+ if (!(block = sm6_block_create()))
+ return NULL;
+
+ function->blocks[function->block_count++] = block;
+ /* Set the id to the array index + 1. */
+ block->id = function->block_count;
+
+ return block;
+}
+
+static enum vkd3d_result sm6_function_resolve_phi_incomings(const struct sm6_function *function,
+ struct sm6_parser *sm6)
+{
+ const struct sm6_block *block;
+ size_t i, j, block_idx;
+
+ for (block_idx = 0; block_idx < function->block_count; ++block_idx)
+ {
+ block = function->blocks[block_idx];
+
+ for (i = 0; i < block->phi_count; ++i)
+ {
+ struct sm6_phi *phi = &block->phi[i];
+ const struct sm6_value *src;
+
+ for (j = 0; j < phi->incoming_count; ++j)
+ {
+ src = &sm6->values[phi->incoming[j].reg.idx[0].offset];
+ if (!sm6_value_is_constant(src) && !sm6_value_is_undef(src) && !sm6_value_is_ssa(src))
+ {
+ FIXME("PHI incoming value is not a constant or SSA register.\n");
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
+ "A PHI incoming value is not a constant or SSA register.");
+ return VKD3D_ERROR_INVALID_SHADER;
+ }
+ if (src->u.reg.data_type != phi->reg.data_type)
+ {
+ WARN("Type mismatch.\n");
+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH,
+ "The type of a phi incoming value does not match the result type.");
+ }
+ phi->incoming[j].reg = src->u.reg;
+ }
+ }
+ }
+
+ return VKD3D_OK;
+}
+
static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const struct dxil_block *block,
struct sm6_function *function)
{
struct vkd3d_shader_instruction *ins;
size_t i, block_idx, block_count;
const struct dxil_record *record;
+ const struct sm6_type *fwd_type;
bool ret_found, is_terminator;
struct sm6_block *code_block;
struct sm6_value *dst;
@@ -4192,16 +5657,18 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const
WARN("Function contains no blocks.\n");
return VKD3D_ERROR_INVALID_SHADER;
}
- if (block_count > 1)
- {
- FIXME("Branched shaders are not supported yet.\n");
- return VKD3D_ERROR_INVALID_SHADER;
- }
- if (!(function->blocks[0] = sm6_block_create()))
- {
- ERR("Failed to allocate code block.\n");
+ if (!sm6_function_blocks_reserve(function, block_count))
return VKD3D_ERROR_OUT_OF_MEMORY;
+
+ /* Pre-allocate all blocks to simplify instruction parsing. */
+ for (i = 0; i < block_count; ++i)
+ {
+ if (!sm6_function_create_block(function))
+ {
+ ERR("Failed to allocate code block.\n");
+ return VKD3D_ERROR_OUT_OF_MEMORY;
+ }
}
function->block_count = block_count;
code_block = function->blocks[0];
@@ -4220,10 +5687,10 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const
return VKD3D_ERROR_INVALID_SHADER;
}
- /* block->record_count - 1 is the instruction count, but some instructions
- * can emit >1 IR instruction, so extra may be used. */
+ /* Some instructions can emit >1 IR instruction, so extra may be used. */
if (!vkd3d_array_reserve((void **)&code_block->instructions, &code_block->instruction_capacity,
- max(code_block->instruction_count + 1, block->record_count), sizeof(*code_block->instructions)))
+ code_block->instruction_count + MAX_IR_INSTRUCTIONS_PER_DXIL_INSTRUCTION,
+ sizeof(*code_block->instructions)))
{
ERR("Failed to allocate instructions.\n");
return VKD3D_ERROR_OUT_OF_MEMORY;
@@ -4233,6 +5700,7 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const
ins->handler_idx = VKD3DSIH_INVALID;
dst = sm6_parser_get_current_value(sm6);
+ fwd_type = dst->type;
dst->type = NULL;
dst->value_type = VALUE_TYPE_REG;
is_terminator = false;
@@ -4240,12 +5708,23 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const
record = block->records[i];
switch (record->code)
{
+ case FUNC_CODE_INST_ALLOCA:
+ sm6_parser_emit_alloca(sm6, record, ins, dst);
+ break;
case FUNC_CODE_INST_BINOP:
sm6_parser_emit_binop(sm6, record, ins, dst);
break;
+ case FUNC_CODE_INST_BR:
+ sm6_parser_emit_br(sm6, record, function, code_block, ins);
+ is_terminator = true;
+ break;
case FUNC_CODE_INST_CALL:
- sm6_parser_emit_call(sm6, record, code_block, ins, dst);
+ {
+ struct function_emission_state state = {code_block, ins};
+ sm6_parser_emit_call(sm6, record, &state, dst);
+ sm6->p.program.temp_count = max(sm6->p.program.temp_count, state.temp_idx);
break;
+ }
case FUNC_CODE_INST_CAST:
sm6_parser_emit_cast(sm6, record, ins, dst);
break;
@@ -4261,11 +5740,21 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const
case FUNC_CODE_INST_LOAD:
sm6_parser_emit_load(sm6, record, ins, dst);
break;
+ case FUNC_CODE_INST_PHI:
+ sm6_parser_emit_phi(sm6, record, function, code_block, ins, dst);
+ break;
case FUNC_CODE_INST_RET:
sm6_parser_emit_ret(sm6, record, code_block, ins);
is_terminator = true;
ret_found = true;
break;
+ case FUNC_CODE_INST_STORE:
+ sm6_parser_emit_store(sm6, record, ins, dst);
+ break;
+ case FUNC_CODE_INST_SWITCH:
+ sm6_parser_emit_switch(sm6, record, function, code_block, ins);
+ is_terminator = true;
+ break;
case FUNC_CODE_INST_VSELECT:
sm6_parser_emit_vselect(sm6, record, ins, dst);
break;
@@ -4278,41 +5767,159 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const
return VKD3D_ERROR;
assert(ins->handler_idx != VKD3DSIH_INVALID);
- if (is_terminator)
- {
- ++block_idx;
- code_block = (block_idx < function->block_count) ? function->blocks[block_idx] : NULL;
- }
- if (code_block)
- code_block->instruction_count += ins->handler_idx != VKD3DSIH_NOP;
- else
- assert(ins->handler_idx == VKD3DSIH_NOP);
+ if (record->attachment)
+ metadata_attachment_record_apply(record->attachment, record->code, ins, dst, sm6);
+
+ if (is_terminator)
+ {
+ ++block_idx;
+ code_block = (block_idx < function->block_count) ? function->blocks[block_idx] : NULL;
+ }
+ if (code_block)
+ code_block->instruction_count += ins->handler_idx != VKD3DSIH_NOP;
+ else
+ assert(ins->handler_idx == VKD3DSIH_NOP);
+
+ if (dst->type && fwd_type && dst->type != fwd_type)
+ {
+ WARN("Type mismatch.\n");
+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH,
+ "The type of a result value does not match the type defined by a forward reference.");
+ }
+
+ sm6->value_count += !!dst->type;
+ }
+
+ if (!ret_found)
+ {
+ WARN("Function contains no RET instruction.\n");
+ return VKD3D_ERROR_INVALID_SHADER;
+ }
+
+ return sm6_function_resolve_phi_incomings(function, sm6);
+}
+
+static void sm6_block_emit_terminator(const struct sm6_block *block, struct sm6_parser *sm6)
+{
+ struct vkd3d_shader_src_param *src_params;
+ struct vkd3d_shader_instruction *ins;
+ unsigned int i, count;
+
+ switch (block->terminator.type)
+ {
+ case TERMINATOR_UNCOND_BR:
+ if (!block->terminator.true_block)
+ return;
+ ins = sm6_parser_add_instruction(sm6, VKD3DSIH_BRANCH);
+ if (!(src_params = instruction_src_params_alloc(ins, 1, sm6)))
+ return;
+ vsir_src_param_init_label(&src_params[0], block->terminator.true_block->id);
+ break;
+
+ case TERMINATOR_COND_BR:
+ if (!block->terminator.true_block || !block->terminator.false_block)
+ return;
+ ins = sm6_parser_add_instruction(sm6, VKD3DSIH_BRANCH);
+ if (!(src_params = instruction_src_params_alloc(ins, 3, sm6)))
+ return;
+ src_param_init(&src_params[0]);
+ src_params[0].reg = block->terminator.conditional_reg;
+ vsir_src_param_init_label(&src_params[1], block->terminator.true_block->id);
+ vsir_src_param_init_label(&src_params[2], block->terminator.false_block->id);
+ break;
+
+ case TERMINATOR_SWITCH:
+ ins = sm6_parser_add_instruction(sm6, VKD3DSIH_SWITCH_MONOLITHIC);
+ if (!(src_params = instruction_src_params_alloc(ins, block->terminator.case_count * 2u + 1, sm6)))
+ return;
+ src_param_init(&src_params[0]);
+ src_params[0].reg = block->terminator.conditional_reg;
+ /* TODO: emit the merge block id. */
+ vsir_src_param_init_label(&src_params[2], 0);
+
+ for (i = 0, count = 3; i < block->terminator.case_count; ++i)
+ {
+ const struct terminator_case *switch_case;
+ const struct sm6_block *case_block;
+
+ switch_case = &block->terminator.cases[i];
+ if (!(case_block = switch_case->block))
+ {
+ assert(sm6->p.failed);
+ continue;
+ }
+ if (switch_case->is_default)
+ {
+ vsir_src_param_init_label(&src_params[1], case_block->id);
+ continue;
+ }
+
+ if (src_params[0].reg.data_type == VKD3D_DATA_UINT64)
+ {
+ vsir_src_param_init(&src_params[count], VKD3DSPR_IMMCONST64, VKD3D_DATA_UINT64, 0);
+ src_params[count++].reg.u.immconst_u64[0] = switch_case->value;
+ }
+ else
+ {
+ if (switch_case->value > UINT_MAX)
+ {
+ WARN("Truncating 64-bit constant %"PRIx64".\n", switch_case->value);
+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH,
+ "Truncating 64-bit switch case value %"PRIx64" to 32 bits.", switch_case->value);
+ }
+ vsir_src_param_init(&src_params[count], VKD3DSPR_IMMCONST, VKD3D_DATA_UINT, 0);
+ src_params[count++].reg.u.immconst_u32[0] = switch_case->value;
+ }
+ vsir_src_param_init_label(&src_params[count++], case_block->id);
+ }
+
+ break;
- sm6->value_count += !!dst->type;
- }
+ case TERMINATOR_RET:
+ sm6_parser_add_instruction(sm6, VKD3DSIH_RET);
+ break;
- if (!ret_found)
- {
- WARN("Function contains no RET instruction.\n");
- return VKD3D_ERROR_INVALID_SHADER;
+ default:
+ vkd3d_unreachable();
}
-
- return VKD3D_OK;
}
-static bool sm6_block_emit_instructions(struct sm6_block *block, struct sm6_parser *sm6)
+static void sm6_block_emit_phi(const struct sm6_block *block, struct sm6_parser *sm6)
{
- struct vkd3d_shader_instruction *ins = sm6_parser_require_space(sm6, block->instruction_count + 1);
+ struct vkd3d_shader_instruction *ins;
+ unsigned int i, j, incoming_count;
+ const struct sm6_phi *src_phi;
- if (!ins)
- return false;
+ for (i = 0; i < block->phi_count; ++i)
+ {
+ struct vkd3d_shader_src_param *src_params;
+ struct vkd3d_shader_dst_param *dst_param;
- memcpy(ins, block->instructions, block->instruction_count * sizeof(*block->instructions));
- sm6->p.instructions.count += block->instruction_count;
+ src_phi = &block->phi[i];
+ incoming_count = src_phi->incoming_count;
- sm6_parser_add_instruction(sm6, VKD3DSIH_RET);
+ ins = sm6_parser_add_instruction(sm6, VKD3DSIH_PHI);
+ if (!(src_params = instruction_src_params_alloc(ins, incoming_count * 2u, sm6)))
+ return;
+ if (!(dst_param = instruction_dst_params_alloc(ins, 1, sm6)))
+ return;
- return true;
+ for (j = 0; j < incoming_count; ++j)
+ {
+ const struct sm6_block *incoming_block = src_phi->incoming[j].block;
+ unsigned int index = j * 2;
+
+ src_param_init(&src_params[index]);
+ src_params[index].reg = src_phi->incoming[j].reg;
+ if (incoming_block)
+ vsir_src_param_init_label(&src_params[index + 1], incoming_block->id);
+ else
+ assert(sm6->p.failed);
+ }
+
+ dst_param_init(dst_param);
+ dst_param->reg = src_phi->reg;
+ }
}
static enum vkd3d_result sm6_parser_module_init(struct sm6_parser *sm6, const struct dxil_block *block,
@@ -4331,6 +5938,8 @@ static enum vkd3d_result sm6_parser_module_init(struct sm6_parser *sm6, const st
sm6->p.location.line = block->id;
sm6->p.location.column = 0;
+ sm6_parser_metadata_attachments_init(sm6, block);
+
switch (block->id)
{
case CONSTANTS_BLOCK:
@@ -4370,6 +5979,48 @@ static enum vkd3d_result sm6_parser_module_init(struct sm6_parser *sm6, const st
return VKD3D_OK;
}
+static void sm6_parser_emit_label(struct sm6_parser *sm6, unsigned int label_id)
+{
+ struct vkd3d_shader_src_param *src_param;
+ struct vkd3d_shader_instruction *ins;
+
+ ins = sm6_parser_add_instruction(sm6, VKD3DSIH_LABEL);
+
+ if (!(src_param = instruction_src_params_alloc(ins, 1, sm6)))
+ return;
+ vsir_src_param_init_label(src_param, label_id);
+}
+
+static enum vkd3d_result sm6_function_emit_blocks(const struct sm6_function *function, struct sm6_parser *sm6)
+{
+ unsigned int i;
+
+ sm6->p.program.block_count = function->block_count;
+
+ for (i = 0; i < function->block_count; ++i)
+ {
+ const struct sm6_block *block = function->blocks[i];
+
+ /* Space for the label and terminator. */
+ if (!sm6_parser_require_space(sm6, block->instruction_count + block->phi_count + 2))
+ {
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY,
+ "Out of memory emitting shader instructions.");
+ return VKD3D_ERROR_OUT_OF_MEMORY;
+ }
+ sm6_parser_emit_label(sm6, block->id);
+ sm6_block_emit_phi(block, sm6);
+
+ memcpy(&sm6->p.program.instructions.elements[sm6->p.program.instructions.count], block->instructions,
+ block->instruction_count * sizeof(*block->instructions));
+ sm6->p.program.instructions.count += block->instruction_count;
+
+ sm6_block_emit_terminator(block, sm6);
+ }
+
+ return VKD3D_OK;
+}
+
static bool sm6_parser_allocate_named_metadata(struct sm6_parser *sm6)
{
struct dxil_block *block;
@@ -4644,8 +6295,10 @@ static enum vkd3d_shader_minimum_precision minimum_precision_from_dxil_component
static const enum vkd3d_shader_sysval_semantic sysval_semantic_table[] =
{
[SEMANTIC_KIND_ARBITRARY] = VKD3D_SHADER_SV_NONE,
+ [SEMANTIC_KIND_VERTEXID] = VKD3D_SHADER_SV_VERTEX_ID,
[SEMANTIC_KIND_POSITION] = VKD3D_SHADER_SV_POSITION,
- [SEMANTIC_KIND_TARGET] = VKD3D_SHADER_SV_NONE,
+ [SEMANTIC_KIND_ISFRONTFACE] = VKD3D_SHADER_SV_IS_FRONT_FACE,
+ [SEMANTIC_KIND_TARGET] = VKD3D_SHADER_SV_TARGET,
};
static enum vkd3d_shader_sysval_semantic sysval_semantic_from_dxil_semantic_kind(enum dxil_semantic_kind kind)
@@ -4727,6 +6380,332 @@ static bool sm6_parser_resources_load_register_range(struct sm6_parser *sm6,
return true;
}
+static bool resource_kind_is_texture(enum dxil_resource_kind kind)
+{
+ return kind >= RESOURCE_KIND_TEXTURE1D && kind <= RESOURCE_KIND_TEXTURECUBEARRAY;
+}
+
+static bool resource_kind_is_multisampled(enum dxil_resource_kind kind)
+{
+ return kind == RESOURCE_KIND_TEXTURE2DMS || kind == RESOURCE_KIND_TEXTURE2DMSARRAY;
+}
+
+static enum vkd3d_shader_resource_type shader_resource_type_from_dxil_resource_kind(enum dxil_resource_kind kind)
+{
+ if (resource_kind_is_texture(kind))
+ return kind + 1;
+
+ switch (kind)
+ {
+ case RESOURCE_KIND_TYPEDBUFFER:
+ case RESOURCE_KIND_RAWBUFFER:
+ case RESOURCE_KIND_STRUCTUREDBUFFER:
+ return VKD3D_SHADER_RESOURCE_BUFFER;
+ default:
+ return VKD3D_SHADER_RESOURCE_NONE;
+ }
+}
+
+static const enum vkd3d_data_type data_type_table[] =
+{
+ [COMPONENT_TYPE_INVALID] = VKD3D_DATA_UNUSED,
+ [COMPONENT_TYPE_I1] = VKD3D_DATA_UNUSED,
+ [COMPONENT_TYPE_I16] = VKD3D_DATA_INT,
+ [COMPONENT_TYPE_U16] = VKD3D_DATA_UINT,
+ [COMPONENT_TYPE_I32] = VKD3D_DATA_INT,
+ [COMPONENT_TYPE_U32] = VKD3D_DATA_UINT,
+ [COMPONENT_TYPE_I64] = VKD3D_DATA_UNUSED,
+ [COMPONENT_TYPE_U64] = VKD3D_DATA_UNUSED,
+ [COMPONENT_TYPE_F16] = VKD3D_DATA_FLOAT,
+ [COMPONENT_TYPE_F32] = VKD3D_DATA_FLOAT,
+ [COMPONENT_TYPE_F64] = VKD3D_DATA_DOUBLE,
+ [COMPONENT_TYPE_SNORMF16] = VKD3D_DATA_SNORM,
+ [COMPONENT_TYPE_UNORMF16] = VKD3D_DATA_UNORM,
+ [COMPONENT_TYPE_SNORMF32] = VKD3D_DATA_SNORM,
+ [COMPONENT_TYPE_UNORMF32] = VKD3D_DATA_UNORM,
+ [COMPONENT_TYPE_SNORMF64] = VKD3D_DATA_DOUBLE,
+ [COMPONENT_TYPE_UNORMF64] = VKD3D_DATA_DOUBLE,
+ [COMPONENT_TYPE_PACKEDS8X32] = VKD3D_DATA_UNUSED,
+ [COMPONENT_TYPE_PACKEDU8X32] = VKD3D_DATA_UNUSED,
+};
+
+static enum vkd3d_data_type vkd3d_data_type_from_dxil_component_type(enum dxil_component_type type,
+ struct sm6_parser *sm6)
+{
+ enum vkd3d_data_type data_type;
+
+ if (type >= ARRAY_SIZE(data_type_table) || (data_type = data_type_table[type]) == VKD3D_DATA_UNUSED)
+ {
+ FIXME("Unhandled component type %u.\n", type);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES,
+ "Resource descriptor component type %u is unhandled.", type);
+ return VKD3D_DATA_FLOAT;
+ }
+
+ return data_type;
+}
+
+static struct vkd3d_shader_resource *sm6_parser_resources_load_common_info(struct sm6_parser *sm6,
+ const struct sm6_metadata_value *type_value, bool is_uav, enum dxil_resource_kind kind,
+ const struct sm6_metadata_value *m, struct vkd3d_shader_instruction *ins)
+{
+ enum vkd3d_shader_resource_type resource_type;
+ enum dxil_resource_type dxil_resource_type;
+ const struct sm6_metadata_node *node;
+ enum vkd3d_data_type data_type;
+ unsigned int i, values[2];
+
+ if (!(resource_type = shader_resource_type_from_dxil_resource_kind(kind)))
+ {
+ FIXME("Unhandled resource kind %u.\n", kind);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES,
+ "Resource kind %u is unhandled.", kind);
+ return NULL;
+ }
+ ins->resource_type = resource_type;
+
+ if (!m)
+ {
+ ins->handler_idx = is_uav ? VKD3DSIH_DCL_UAV_RAW : VKD3DSIH_DCL_RESOURCE_RAW;
+ ins->declaration.raw_resource.resource.reg.write_mask = 0;
+ return &ins->declaration.raw_resource.resource;
+ }
+
+ if (!sm6_metadata_value_is_node(m))
+ {
+ WARN("Resource metadata list is not a node.\n");
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES,
+ "Resource descriptor metadata list is not a node.");
+ return NULL;
+ }
+
+ node = m->u.node;
+
+ if (node->operand_count < 2)
+ {
+ WARN("Invalid operand count %u.\n", node->operand_count);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT,
+ "Invalid operand count %u for a resource descriptor.", node->operand_count);
+ return NULL;
+ }
+ if (node->operand_count > 2)
+ {
+ WARN("Ignoring %u extra operands.\n", node->operand_count - 2);
+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS,
+ "Ignoring %u extra operands for a resource descriptor.", node->operand_count - 2);
+ }
+
+ for (i = 0; i < 2; ++i)
+ {
+ if (!sm6_metadata_get_uint_value(sm6, node->operands[i], &values[i]))
+ {
+ WARN("Failed to load uint value at index %u.\n", i);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES,
+ "A resource descriptor operand metadata value is not an integer.");
+ return NULL;
+ }
+ }
+
+ if ((dxil_resource_type = values[0]) == RESOURCE_TYPE_NON_RAW_STRUCTURED)
+ {
+ if (kind != RESOURCE_KIND_TYPEDBUFFER && !resource_kind_is_texture(kind))
+ {
+ WARN("Unhandled resource kind %u.\n", kind);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES,
+ "Resource kind %u for a typed resource is unhandled.", kind);
+ return NULL;
+ }
+
+ data_type = vkd3d_data_type_from_dxil_component_type(values[1], sm6);
+ ins->handler_idx = is_uav ? VKD3DSIH_DCL_UAV_TYPED : VKD3DSIH_DCL;
+ for (i = 0; i < VKD3D_VEC4_SIZE; ++i)
+ ins->declaration.semantic.resource_data_type[i] = data_type;
+ ins->declaration.semantic.resource_type = resource_type;
+ ins->declaration.semantic.resource.reg.write_mask = VKD3DSP_WRITEMASK_ALL;
+
+ return &ins->declaration.semantic.resource;
+ }
+ else if (dxil_resource_type == RESOURCE_TYPE_RAW_STRUCTURED)
+ {
+ if (kind == RESOURCE_KIND_RAWBUFFER)
+ {
+ ins->handler_idx = is_uav ? VKD3DSIH_DCL_UAV_RAW : VKD3DSIH_DCL_RESOURCE_RAW;
+ ins->declaration.raw_resource.resource.reg.write_mask = 0;
+
+ return &ins->declaration.raw_resource.resource;
+ }
+
+ if (kind != RESOURCE_KIND_STRUCTUREDBUFFER)
+ {
+ WARN("Unhandled resource kind %u.\n", kind);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES,
+ "Resource kind %u for a raw or structured buffer is unhandled.", kind);
+ return NULL;
+ }
+
+ ins->handler_idx = is_uav ? VKD3DSIH_DCL_UAV_STRUCTURED : VKD3DSIH_DCL_RESOURCE_STRUCTURED;
+ ins->declaration.structured_resource.byte_stride = values[1];
+ ins->declaration.structured_resource.resource.reg.write_mask = 0;
+
+ /* TODO: 16-bit resources. */
+ if (ins->declaration.structured_resource.byte_stride % 4u)
+ {
+ WARN("Byte stride %u is not a multiple of 4.\n", ins->declaration.structured_resource.byte_stride);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES,
+ "Structured resource byte stride %u is not a multiple of 4.",
+ ins->declaration.structured_resource.byte_stride);
+ }
+
+ return &ins->declaration.structured_resource.resource;
+ }
+ else
+ {
+ FIXME("Unhandled resource type %u.\n", dxil_resource_type);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES,
+ "Resource type %u is unhandled.", dxil_resource_type);
+ }
+
+ return NULL;
+}
+
+static void init_resource_declaration(struct vkd3d_shader_resource *resource,
+ enum vkd3d_shader_register_type reg_type, enum vkd3d_data_type data_type, unsigned int id,
+ const struct vkd3d_shader_register_range *range)
+{
+ struct vkd3d_shader_dst_param *param = &resource->reg;
+
+ param->modifiers = 0;
+ param->shift = 0;
+ vsir_register_init(&param->reg, reg_type, data_type, 3);
+ param->reg.idx[0].offset = id;
+ param->reg.idx[1].offset = range->first;
+ param->reg.idx[2].offset = range->last;
+
+ resource->range = *range;
+}
+
+static enum vkd3d_result sm6_parser_resources_load_srv(struct sm6_parser *sm6,
+ const struct sm6_metadata_node *node, struct sm6_descriptor_info *d, struct vkd3d_shader_instruction *ins)
+{
+ struct vkd3d_shader_resource *resource;
+ unsigned int kind;
+
+ if (node->operand_count < 9)
+ {
+ WARN("Invalid operand count %u.\n", node->operand_count);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT,
+ "Invalid operand count %u for an SRV descriptor.", node->operand_count);
+ return VKD3D_ERROR_INVALID_SHADER;
+ }
+ if (node->operand_count > 9)
+ {
+ WARN("Ignoring %u extra operands.\n", node->operand_count - 9);
+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS,
+ "Ignoring %u extra operands for an SRV descriptor.", node->operand_count - 9);
+ }
+
+ if (!sm6_metadata_get_uint_value(sm6, node->operands[6], &kind))
+ {
+ WARN("Failed to load resource type.\n");
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES,
+ "SRV resource type metadata value is not an integer.");
+ return VKD3D_ERROR_INVALID_SHADER;
+ }
+
+ vsir_instruction_init(ins, &sm6->p.location, VKD3DSIH_INVALID);
+
+ if (!(resource = sm6_parser_resources_load_common_info(sm6, node->operands[1], false, kind,
+ node->operands[8], ins)))
+ {
+ return VKD3D_ERROR_INVALID_SHADER;
+ }
+
+ d->resource_type = ins->resource_type;
+ d->kind = kind;
+ d->reg_type = VKD3DSPR_RESOURCE;
+ d->reg_data_type = (ins->resource_type == VKD3D_SHADER_RESOURCE_BUFFER) ? VKD3D_DATA_UINT : VKD3D_DATA_RESOURCE;
+ d->resource_data_type = (ins->handler_idx == VKD3DSIH_DCL)
+ ? ins->declaration.semantic.resource_data_type[0] : VKD3D_DATA_UNUSED;
+
+ init_resource_declaration(resource, VKD3DSPR_RESOURCE, d->reg_data_type, d->id, &d->range);
+
+ if (resource_kind_is_multisampled(kind))
+ {
+ if (!sm6_metadata_get_uint_value(sm6, node->operands[7], &ins->declaration.semantic.sample_count))
+ {
+ WARN("Failed to load sample count.\n");
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES,
+ "SRV sample count metadata value is not an integer.");
+ return VKD3D_ERROR_INVALID_SHADER;
+ }
+ }
+ else if (!sm6_metadata_value_is_zero_or_undef(node->operands[7]))
+ {
+ WARN("Ignoring sample count value.\n");
+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS,
+ "Ignoring an SRV descriptor sample count metadata value which is not constant zero or undefined.");
+ }
+
+ return VKD3D_OK;
+}
+
+static enum vkd3d_result sm6_parser_resources_load_uav(struct sm6_parser *sm6,
+ const struct sm6_metadata_node *node, struct sm6_descriptor_info *d, struct vkd3d_shader_instruction *ins)
+{
+ struct vkd3d_shader_resource *resource;
+ unsigned int i, values[4];
+
+ if (node->operand_count < 11)
+ {
+ WARN("Invalid operand count %u.\n", node->operand_count);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT,
+ "Invalid operand count %u for a UAV descriptor.", node->operand_count);
+ return VKD3D_ERROR_INVALID_SHADER;
+ }
+ if (node->operand_count > 11)
+ {
+ WARN("Ignoring %u extra operands.\n", node->operand_count - 11);
+ vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS,
+ "Ignoring %u extra operands for a UAV descriptor.", node->operand_count - 11);
+ }
+
+ for (i = 6; i < 10; ++i)
+ {
+ if (!sm6_metadata_get_uint_value(sm6, node->operands[i], &values[i - 6]))
+ {
+ WARN("Failed to load uint value at index %u.\n", i);
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES,
+ "A UAV descriptor operand metadata value is not an integer.");
+ return VKD3D_ERROR_INVALID_SHADER;
+ }
+ }
+
+ vsir_instruction_init(ins, &sm6->p.location, VKD3DSIH_INVALID);
+ if (values[1])
+ ins->flags = VKD3DSUF_GLOBALLY_COHERENT;
+ if (values[2])
+ ins->flags |= VKD3DSUF_ORDER_PRESERVING_COUNTER;
+ if (values[3])
+ ins->flags |= VKD3DSUF_RASTERISER_ORDERED_VIEW;
+
+ if (!(resource = sm6_parser_resources_load_common_info(sm6, node->operands[1], true, values[0],
+ node->operands[10], ins)))
+ {
+ return VKD3D_ERROR_INVALID_SHADER;
+ }
+
+ d->resource_type = ins->resource_type;
+ d->kind = values[0];
+ d->reg_type = VKD3DSPR_UAV;
+ d->reg_data_type = (ins->resource_type == VKD3D_SHADER_RESOURCE_BUFFER) ? VKD3D_DATA_UINT : VKD3D_DATA_UAV;
+ d->resource_data_type = (ins->handler_idx == VKD3DSIH_DCL_UAV_TYPED)
+ ? ins->declaration.semantic.resource_data_type[0] : VKD3D_DATA_UNUSED;
+
+ init_resource_declaration(resource, VKD3DSPR_UAV, d->reg_data_type, d->id, &d->range);
+
+ return VKD3D_OK;
+}
+
static enum vkd3d_result sm6_parser_resources_load_cbv(struct sm6_parser *sm6,
const struct sm6_metadata_node *node, struct sm6_descriptor_info *d, struct vkd3d_shader_instruction *ins)
{
@@ -4769,6 +6748,10 @@ static enum vkd3d_result sm6_parser_resources_load_cbv(struct sm6_parser *sm6,
ins->declaration.cb.range = d->range;
+ d->reg_type = VKD3DSPR_CONSTBUFFER;
+ d->reg_data_type = VKD3D_DATA_FLOAT;
+ d->resource_data_type = VKD3D_DATA_FLOAT;
+
return VKD3D_OK;
}
@@ -4840,6 +6823,14 @@ static enum vkd3d_result sm6_parser_descriptor_type_init(struct sm6_parser *sm6,
if ((ret = sm6_parser_resources_load_cbv(sm6, node, d, ins)) < 0)
return ret;
break;
+ case VKD3D_SHADER_DESCRIPTOR_TYPE_SRV:
+ if ((ret = sm6_parser_resources_load_srv(sm6, node, d, ins)) < 0)
+ return ret;
+ break;
+ case VKD3D_SHADER_DESCRIPTOR_TYPE_UAV:
+ if ((ret = sm6_parser_resources_load_uav(sm6, node, d, ins)) < 0)
+ return ret;
+ break;
default:
FIXME("Unsupported descriptor type %u.\n", type);
vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_RESOURCES,
@@ -4848,7 +6839,7 @@ static enum vkd3d_result sm6_parser_descriptor_type_init(struct sm6_parser *sm6,
}
++sm6->descriptor_count;
- ++sm6->p.instructions.count;
+ ++sm6->p.program.instructions.count;
}
return VKD3D_OK;
@@ -5198,9 +7189,9 @@ static enum vkd3d_result sm6_parser_emit_thread_group(struct sm6_parser *sm6, co
unsigned int group_sizes[3];
unsigned int i;
- if (sm6->p.shader_version.type != VKD3D_SHADER_TYPE_COMPUTE)
+ if (sm6->p.program.shader_version.type != VKD3D_SHADER_TYPE_COMPUTE)
{
- WARN("Shader of type %#x has thread group dimensions.\n", sm6->p.shader_version.type);
+ WARN("Shader of type %#x has thread group dimensions.\n", sm6->p.program.shader_version.type);
vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_PROPERTIES,
"Shader has thread group dimensions but is not a compute shader.");
return VKD3D_ERROR_INVALID_SHADER;
@@ -5285,7 +7276,7 @@ static enum vkd3d_result sm6_parser_entry_point_init(struct sm6_parser *sm6)
sm6->entry_point = value->u.function.name;
if (!sm6_metadata_value_is_string(entry_node->operands[1])
- || ascii_strcasecmp(sm6->entry_point, entry_node->operands[1]->u.string_value))
+ || strcmp(sm6->entry_point, entry_node->operands[1]->u.string_value))
{
WARN("Entry point function name %s mismatch.\n", sm6->entry_point);
vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_ENTRY_POINT_MISMATCH,
@@ -5419,9 +7410,20 @@ static void sm6_symtab_cleanup(struct sm6_symbol *symbols, size_t count)
vkd3d_free(symbols);
}
+static void sm6_phi_destroy(struct sm6_phi *phi)
+{
+ vkd3d_free(phi->incoming);
+}
+
static void sm6_block_destroy(struct sm6_block *block)
{
+ unsigned int i;
+
vkd3d_free(block->instructions);
+ for (i = 0; i < block->phi_count; ++i)
+ sm6_phi_destroy(&block->phi[i]);
+ vkd3d_free(block->phi);
+ vkd3d_free(block->terminator.cases);
vkd3d_free(block);
}
@@ -5433,6 +7435,7 @@ static void sm6_functions_cleanup(struct sm6_function *functions, size_t count)
{
for (j = 0; j < functions[i].block_count; ++j)
sm6_block_destroy(functions[i].blocks[j]);
+ vkd3d_free(functions[i].blocks);
}
vkd3d_free(functions);
}
@@ -5443,7 +7446,7 @@ static void sm6_parser_destroy(struct vkd3d_shader_parser *parser)
dxil_block_destroy(&sm6->root_block);
dxil_global_abbrevs_cleanup(sm6->abbrevs, sm6->abbrev_count);
- shader_instruction_array_destroy(&parser->instructions);
+ vsir_program_cleanup(&parser->program);
sm6_type_table_cleanup(sm6->types, sm6->type_count);
sm6_symtab_cleanup(sm6->global_symbols, sm6->global_symbol_count);
sm6_functions_cleanup(sm6->functions, sm6->function_count);
@@ -5463,7 +7466,7 @@ static struct sm6_function *sm6_parser_get_function(const struct sm6_parser *sm6
{
size_t i;
for (i = 0; i < sm6->function_count; ++i)
- if (!ascii_strcasecmp(sm6->functions[i].declaration->u.function.name, name))
+ if (!strcmp(sm6->functions[i].declaration->u.function.name, name))
return &sm6->functions[i];
return NULL;
}
@@ -5538,7 +7541,7 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t
if ((magic = sm6->start[0]) != BITCODE_MAGIC)
{
WARN("Unknown magic number 0x%08x.\n", magic);
- vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_UNKNOWN_MAGIC_NUMBER,
+ vkd3d_shader_warning(message_context, &location, VKD3D_SHADER_WARNING_DXIL_UNKNOWN_MAGIC_NUMBER,
"DXIL bitcode chunk magic number 0x%08x is not the expected 0x%08x.", magic, BITCODE_MAGIC);
}
@@ -5547,7 +7550,7 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t
if ((version.type = version_token >> 16) >= VKD3D_SHADER_TYPE_COUNT)
{
FIXME("Unknown shader type %#x.\n", version.type);
- vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_UNKNOWN_SHADER_TYPE,
+ vkd3d_shader_warning(message_context, &location, VKD3D_SHADER_WARNING_DXIL_UNKNOWN_SHADER_TYPE,
"Unknown shader type %#x.", version.type);
}
@@ -5573,10 +7576,10 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t
if ((ret = dxil_block_init(block, NULL, sm6)) < 0)
{
if (ret == VKD3D_ERROR_OUT_OF_MEMORY)
- vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY,
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY,
"Out of memory parsing DXIL bitcode chunk.");
else if (ret == VKD3D_ERROR_INVALID_SHADER)
- vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_BITCODE,
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_BITCODE,
"DXIL bitcode chunk has invalid bitcode.");
else
vkd3d_unreachable();
@@ -5606,10 +7609,10 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t
if ((ret = sm6_parser_type_table_init(sm6)) < 0)
{
if (ret == VKD3D_ERROR_OUT_OF_MEMORY)
- vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY,
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY,
"Out of memory parsing DXIL type table.");
else if (ret == VKD3D_ERROR_INVALID_SHADER)
- vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_TYPE_TABLE,
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_TYPE_TABLE,
"DXIL type table is invalid.");
else
vkd3d_unreachable();
@@ -5619,21 +7622,21 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t
if ((ret = sm6_parser_symtab_init(sm6)) < 0)
{
if (ret == VKD3D_ERROR_OUT_OF_MEMORY)
- vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY,
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY,
"Out of memory parsing DXIL value symbol table.");
else if (ret == VKD3D_ERROR_INVALID_SHADER)
- vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_VALUE_SYMTAB,
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_VALUE_SYMTAB,
"DXIL value symbol table is invalid.");
else
vkd3d_unreachable();
return ret;
}
- if (!(sm6->output_params = shader_parser_get_dst_params(&sm6->p, output_signature->element_count))
- || !(sm6->input_params = shader_parser_get_dst_params(&sm6->p, input_signature->element_count)))
+ if (!(sm6->output_params = vsir_program_get_dst_params(&sm6->p.program, output_signature->element_count))
+ || !(sm6->input_params = vsir_program_get_dst_params(&sm6->p.program, input_signature->element_count)))
{
ERR("Failed to allocate input/output parameters.\n");
- vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY,
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY,
"Out of memory allocating input/output parameters.");
return VKD3D_ERROR_OUT_OF_MEMORY;
}
@@ -5642,7 +7645,7 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t
if (!(sm6->functions = vkd3d_calloc(function_count, sizeof(*sm6->functions))))
{
ERR("Failed to allocate function array.\n");
- vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY,
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY,
"Out of memory allocating DXIL function array.");
return VKD3D_ERROR_OUT_OF_MEMORY;
}
@@ -5650,14 +7653,14 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t
if (sm6_parser_compute_max_value_count(sm6, &sm6->root_block, 0) == SIZE_MAX)
{
WARN("Value array count overflowed.\n");
- vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE,
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE,
"Overflow occurred in the DXIL module value count.");
return VKD3D_ERROR_INVALID_SHADER;
}
if (!(sm6->values = vkd3d_calloc(sm6->value_capacity, sizeof(*sm6->values))))
{
ERR("Failed to allocate value array.\n");
- vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY,
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY,
"Out of memory allocating DXIL value array.");
return VKD3D_ERROR_OUT_OF_MEMORY;
}
@@ -5684,7 +7687,7 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t
if (j == ARRAY_SIZE(sm6->metadata_tables))
{
FIXME("Too many metadata tables.\n");
- vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_METADATA,
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_METADATA,
"A metadata table count greater than %zu is unsupported.", ARRAY_SIZE(sm6->metadata_tables));
return VKD3D_ERROR_INVALID_SHADER;
}
@@ -5702,24 +7705,22 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t
if ((ret = sm6_parser_module_init(sm6, &sm6->root_block, 0)) < 0)
{
if (ret == VKD3D_ERROR_OUT_OF_MEMORY)
- vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY,
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY,
"Out of memory parsing DXIL module.");
else if (ret == VKD3D_ERROR_INVALID_SHADER)
- vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE,
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE,
"DXIL module is invalid.");
return ret;
}
if (!sm6_parser_require_space(sm6, output_signature->element_count + input_signature->element_count))
{
- vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY,
+ vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY,
"Out of memory emitting shader signature declarations.");
return VKD3D_ERROR_OUT_OF_MEMORY;
}
- sm6_parser_emit_output_signature(sm6, output_signature);
- sm6_parser_emit_input_signature(sm6, input_signature);
- sm6->p.shader_desc.ssa_count = sm6->ssa_next_id;
+ sm6->p.program.ssa_count = sm6->ssa_next_id;
if (!(fn = sm6_parser_get_function(sm6, sm6->entry_point)))
{
@@ -5730,12 +7731,8 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t
}
assert(sm6->function_count == 1);
- if (!sm6_block_emit_instructions(fn->blocks[0], sm6))
- {
- vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY,
- "Out of memory emitting shader instructions.");
- return VKD3D_ERROR_OUT_OF_MEMORY;
- }
+ if ((ret = sm6_function_emit_blocks(fn, sm6)) < 0)
+ return ret;
dxil_block_destroy(&sm6->root_block);
@@ -5786,7 +7783,7 @@ int vkd3d_shader_sm6_parser_create(const struct vkd3d_shader_compile_info *compi
vkd3d_free(byte_code);
if (!sm6->p.failed && ret >= 0)
- vsir_validate(&sm6->p);
+ ret = vsir_validate(&sm6->p);
if (sm6->p.failed && ret >= 0)
ret = VKD3D_ERROR_INVALID_SHADER;
diff --git a/libs/vkd3d/libs/vkd3d-shader/fx.c b/libs/vkd3d/libs/vkd3d-shader/fx.c
new file mode 100644
index 00000000000..e1459f76c14
--- /dev/null
+++ b/libs/vkd3d/libs/vkd3d-shader/fx.c
@@ -0,0 +1,515 @@
+/*
+ * FX (Direct3D 9/10/11 effect) support
+ *
+ * Copyright 2023 Nikolay Sivov for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "hlsl.h"
+
+struct string_entry
+{
+ struct rb_entry entry;
+ /* String points to original data, should not be freed. */
+ const char *string;
+ uint32_t offset;
+};
+
+static int string_storage_compare(const void *key, const struct rb_entry *entry)
+{
+ struct string_entry *string_entry = RB_ENTRY_VALUE(entry, struct string_entry, entry);
+ const char *string = key;
+
+ return strcmp(string, string_entry->string);
+}
+
+static void string_storage_destroy(struct rb_entry *entry, void *context)
+{
+ struct string_entry *string_entry = RB_ENTRY_VALUE(entry, struct string_entry, entry);
+
+ vkd3d_free(string_entry);
+}
+
+struct fx_write_context;
+
+struct fx_write_context_ops
+{
+ uint32_t (*write_string)(const char *string, struct fx_write_context *fx);
+ void (*write_technique)(struct hlsl_ir_var *var, struct fx_write_context *fx);
+ void (*write_pass)(struct hlsl_ir_var *var, struct fx_write_context *fx);
+};
+
+struct fx_write_context
+{
+ struct hlsl_ctx *ctx;
+
+ struct vkd3d_bytecode_buffer unstructured;
+ struct vkd3d_bytecode_buffer structured;
+
+ struct rb_tree strings;
+
+ unsigned int min_technique_version;
+ unsigned int max_technique_version;
+
+ uint32_t technique_count;
+ uint32_t group_count;
+ int status;
+
+ const struct fx_write_context_ops *ops;
+};
+
+static uint32_t write_string(const char *string, struct fx_write_context *fx)
+{
+ return fx->ops->write_string(string, fx);
+}
+
+static void write_pass(struct hlsl_ir_var *var, struct fx_write_context *fx)
+{
+ fx->ops->write_pass(var, fx);
+}
+
+static void fx_write_context_init(struct hlsl_ctx *ctx, const struct fx_write_context_ops *ops,
+ struct fx_write_context *fx)
+{
+ unsigned int version = ctx->profile->major_version;
+
+ memset(fx, 0, sizeof(*fx));
+
+ fx->ctx = ctx;
+ fx->ops = ops;
+ if (version == 2)
+ {
+ fx->min_technique_version = 9;
+ fx->max_technique_version = 9;
+ }
+ else if (version == 4)
+ {
+ fx->min_technique_version = 10;
+ fx->max_technique_version = 10;
+ }
+ else if (version == 5)
+ {
+ fx->min_technique_version = 10;
+ fx->max_technique_version = 11;
+ }
+
+ rb_init(&fx->strings, string_storage_compare);
+}
+
+static int fx_write_context_cleanup(struct fx_write_context *fx)
+{
+ int status = fx->status;
+ rb_destroy(&fx->strings, string_storage_destroy, NULL);
+
+ return status;
+}
+
+static bool technique_matches_version(const struct hlsl_ir_var *var, const struct fx_write_context *fx)
+{
+ const struct hlsl_type *type = var->data_type;
+
+ if (type->base_type != HLSL_TYPE_TECHNIQUE)
+ return false;
+
+ return type->e.version >= fx->min_technique_version && type->e.version <= fx->max_technique_version;
+}
+
+static uint32_t write_fx_4_string(const char *string, struct fx_write_context *fx)
+{
+ struct string_entry *string_entry;
+ struct rb_entry *entry;
+
+ /* NULLs are emitted as empty strings using the same 4 bytes at the start of the section. */
+ if (!string)
+ return 0;
+
+ if ((entry = rb_get(&fx->strings, string)))
+ {
+ string_entry = RB_ENTRY_VALUE(entry, struct string_entry, entry);
+ return string_entry->offset;
+ }
+
+ if (!(string_entry = hlsl_alloc(fx->ctx, sizeof(*string_entry))))
+ return 0;
+
+ string_entry->offset = put_string(&fx->unstructured, string);
+ string_entry->string = string;
+
+ rb_put(&fx->strings, string, &string_entry->entry);
+
+ return string_entry->offset;
+}
+
+static void write_fx_4_pass(struct hlsl_ir_var *var, struct fx_write_context *fx)
+{
+ struct vkd3d_bytecode_buffer *buffer = &fx->structured;
+ uint32_t name_offset;
+
+ name_offset = write_string(var->name, fx);
+ put_u32(buffer, name_offset);
+ put_u32(buffer, 0); /* Assignment count. */
+ put_u32(buffer, 0); /* Annotation count. */
+
+ /* TODO: annotations */
+ /* TODO: assignments */
+}
+
+static void write_fx_2_pass(struct hlsl_ir_var *var, struct fx_write_context *fx)
+{
+ struct vkd3d_bytecode_buffer *buffer = &fx->structured;
+ uint32_t name_offset;
+
+ name_offset = write_string(var->name, fx);
+ put_u32(buffer, name_offset);
+ put_u32(buffer, 0); /* Annotation count. */
+ put_u32(buffer, 0); /* Assignment count. */
+
+ /* TODO: annotations */
+ /* TODO: assignments */
+}
+
+static void write_fx_4_technique(struct hlsl_ir_var *var, struct fx_write_context *fx)
+{
+ struct vkd3d_bytecode_buffer *buffer = &fx->structured;
+ uint32_t name_offset, count = 0;
+ struct hlsl_ir_var *pass;
+ uint32_t count_offset;
+
+ name_offset = write_string(var->name, fx);
+ put_u32(buffer, name_offset);
+ count_offset = put_u32(buffer, 0);
+ put_u32(buffer, 0); /* Annotation count. */
+
+ LIST_FOR_EACH_ENTRY(pass, &var->scope->vars, struct hlsl_ir_var, scope_entry)
+ {
+ write_pass(pass, fx);
+ ++count;
+ }
+
+ set_u32(buffer, count_offset, count);
+}
+
+static void set_status(struct fx_write_context *fx, int status)
+{
+ if (fx->status < 0)
+ return;
+ if (status < 0)
+ fx->status = status;
+}
+
+static void write_techniques(struct hlsl_scope *scope, struct fx_write_context *fx)
+{
+ struct hlsl_ir_var *var;
+
+ LIST_FOR_EACH_ENTRY(var, &scope->vars, struct hlsl_ir_var, scope_entry)
+ {
+ if (technique_matches_version(var, fx))
+ {
+ fx->ops->write_technique(var, fx);
+ ++fx->technique_count;
+ }
+ }
+
+ set_status(fx, fx->unstructured.status);
+ set_status(fx, fx->structured.status);
+}
+
+static void write_group(struct hlsl_scope *scope, const char *name, struct fx_write_context *fx)
+{
+ struct vkd3d_bytecode_buffer *buffer = &fx->structured;
+ uint32_t name_offset = write_string(name, fx);
+ uint32_t count_offset, count;
+
+ put_u32(buffer, name_offset);
+ count_offset = put_u32(buffer, 0); /* Technique count */
+ put_u32(buffer, 0); /* Annotation count */
+
+ count = fx->technique_count;
+ write_techniques(scope, fx);
+ set_u32(buffer, count_offset, fx->technique_count - count);
+
+ ++fx->group_count;
+}
+
+static void write_groups(struct hlsl_scope *scope, struct fx_write_context *fx)
+{
+ bool needs_default_group = false;
+ struct hlsl_ir_var *var;
+
+ LIST_FOR_EACH_ENTRY(var, &scope->vars, struct hlsl_ir_var, scope_entry)
+ {
+ if (technique_matches_version(var, fx))
+ {
+ needs_default_group = true;
+ break;
+ }
+ }
+
+ if (needs_default_group)
+ write_group(scope, NULL, fx);
+ LIST_FOR_EACH_ENTRY(var, &scope->vars, struct hlsl_ir_var, scope_entry)
+ {
+ const struct hlsl_type *type = var->data_type;
+
+ if (type->base_type == HLSL_TYPE_EFFECT_GROUP)
+ write_group(var->scope, var->name, fx);
+ }
+}
+
+static uint32_t write_fx_2_string(const char *string, struct fx_write_context *fx)
+{
+ struct vkd3d_bytecode_buffer *buffer = &fx->unstructured;
+ const char *s = string ? string : "";
+ uint32_t size, offset;
+
+ size = strlen(s) + 1;
+ offset = put_u32(buffer, size);
+ bytecode_put_bytes(buffer, s, size);
+ return offset;
+}
+
+static void write_fx_2_technique(struct hlsl_ir_var *var, struct fx_write_context *fx)
+{
+ struct vkd3d_bytecode_buffer *buffer = &fx->structured;
+ uint32_t name_offset, count_offset, count = 0;
+ struct hlsl_ir_var *pass;
+
+ name_offset = write_string(var->name, fx);
+ put_u32(buffer, name_offset);
+ put_u32(buffer, 0); /* Annotation count. */
+ count_offset = put_u32(buffer, 0); /* Pass count. */
+
+ /* FIXME: annotations */
+
+ LIST_FOR_EACH_ENTRY(pass, &var->scope->vars, struct hlsl_ir_var, scope_entry)
+ {
+ write_pass(pass, fx);
+ ++count;
+ }
+
+ set_u32(buffer, count_offset, count);
+}
+
+static const struct fx_write_context_ops fx_2_ops =
+{
+ .write_string = write_fx_2_string,
+ .write_technique = write_fx_2_technique,
+ .write_pass = write_fx_2_pass,
+};
+
+static int hlsl_fx_2_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out)
+{
+ struct vkd3d_bytecode_buffer buffer = { 0 };
+ struct vkd3d_bytecode_buffer *structured;
+ uint32_t offset, size, technique_count;
+ struct fx_write_context fx;
+
+ fx_write_context_init(ctx, &fx_2_ops, &fx);
+ structured = &fx.structured;
+
+ /* First entry is always zeroed and skipped. */
+ put_u32(&fx.unstructured, 0);
+
+ put_u32(&buffer, 0xfeff0901); /* Version. */
+ offset = put_u32(&buffer, 0);
+
+ put_u32(structured, 0); /* Parameter count */
+ technique_count = put_u32(structured, 0);
+ put_u32(structured, 0); /* Unknown */
+ put_u32(structured, 0); /* Object count */
+
+ /* TODO: parameters */
+
+ write_techniques(ctx->globals, &fx);
+ set_u32(structured, technique_count, fx.technique_count);
+
+ put_u32(structured, 0); /* String count */
+ put_u32(structured, 0); /* Resource count */
+
+ /* TODO: strings */
+ /* TODO: resources */
+
+ size = align(fx.unstructured.size, 4);
+ set_u32(&buffer, offset, size);
+
+ bytecode_put_bytes(&buffer, fx.unstructured.data, fx.unstructured.size);
+ bytecode_put_bytes(&buffer, fx.structured.data, fx.structured.size);
+
+ vkd3d_free(fx.unstructured.data);
+ vkd3d_free(fx.structured.data);
+
+ if (!fx.status)
+ {
+ out->code = buffer.data;
+ out->size = buffer.size;
+ }
+
+ if (fx.status < 0)
+ ctx->result = fx.status;
+
+ return fx_write_context_cleanup(&fx);
+}
+
+static const struct fx_write_context_ops fx_4_ops =
+{
+ .write_string = write_fx_4_string,
+ .write_technique = write_fx_4_technique,
+ .write_pass = write_fx_4_pass,
+};
+
+static int hlsl_fx_4_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out)
+{
+ struct vkd3d_bytecode_buffer buffer = { 0 };
+ struct fx_write_context fx;
+ uint32_t size_offset, size;
+
+ fx_write_context_init(ctx, &fx_4_ops, &fx);
+
+ put_u32(&fx.unstructured, 0); /* Empty string placeholder. */
+
+ /* TODO: buffers */
+ /* TODO: objects */
+ /* TODO: shared buffers */
+ /* TODO: shared objects */
+
+ write_techniques(ctx->globals, &fx);
+
+ put_u32(&buffer, ctx->profile->minor_version == 0 ? 0xfeff1001 : 0xfeff1011); /* Version. */
+ put_u32(&buffer, 0); /* Buffer count. */
+ put_u32(&buffer, 0); /* Variable count. */
+ put_u32(&buffer, 0); /* Object count. */
+ put_u32(&buffer, 0); /* Pool buffer count. */
+ put_u32(&buffer, 0); /* Pool variable count. */
+ put_u32(&buffer, 0); /* Pool object count. */
+ put_u32(&buffer, fx.technique_count);
+ size_offset = put_u32(&buffer, 0); /* Unstructured size. */
+ put_u32(&buffer, 0); /* String count. */
+ put_u32(&buffer, 0); /* Texture object count. */
+ put_u32(&buffer, 0); /* Depth stencil state count. */
+ put_u32(&buffer, 0); /* Blend state count. */
+ put_u32(&buffer, 0); /* Rasterizer state count. */
+ put_u32(&buffer, 0); /* Sampler state count. */
+ put_u32(&buffer, 0); /* Rendertarget view count. */
+ put_u32(&buffer, 0); /* Depth stencil view count. */
+ put_u32(&buffer, 0); /* Shader count. */
+ put_u32(&buffer, 0); /* Inline shader count. */
+
+ size = align(fx.unstructured.size, 4);
+ set_u32(&buffer, size_offset, size);
+
+ bytecode_put_bytes(&buffer, fx.unstructured.data, fx.unstructured.size);
+ bytecode_put_bytes(&buffer, fx.structured.data, fx.structured.size);
+
+ vkd3d_free(fx.unstructured.data);
+ vkd3d_free(fx.structured.data);
+
+ set_status(&fx, buffer.status);
+
+ if (!fx.status)
+ {
+ out->code = buffer.data;
+ out->size = buffer.size;
+ }
+
+ if (fx.status < 0)
+ ctx->result = fx.status;
+
+ return fx_write_context_cleanup(&fx);
+}
+
+static int hlsl_fx_5_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out)
+{
+ struct vkd3d_bytecode_buffer buffer = { 0 };
+ struct fx_write_context fx;
+ uint32_t size_offset, size;
+
+ fx_write_context_init(ctx, &fx_4_ops, &fx);
+
+ put_u32(&fx.unstructured, 0); /* Empty string placeholder. */
+
+ /* TODO: buffers */
+ /* TODO: objects */
+ /* TODO: interface variables */
+
+ write_groups(ctx->globals, &fx);
+
+ put_u32(&buffer, 0xfeff2001); /* Version. */
+ put_u32(&buffer, 0); /* Buffer count. */
+ put_u32(&buffer, 0); /* Variable count. */
+ put_u32(&buffer, 0); /* Object count. */
+ put_u32(&buffer, 0); /* Pool buffer count. */
+ put_u32(&buffer, 0); /* Pool variable count. */
+ put_u32(&buffer, 0); /* Pool object count. */
+ put_u32(&buffer, fx.technique_count);
+ size_offset = put_u32(&buffer, 0); /* Unstructured size. */
+ put_u32(&buffer, 0); /* String count. */
+ put_u32(&buffer, 0); /* Texture object count. */
+ put_u32(&buffer, 0); /* Depth stencil state count. */
+ put_u32(&buffer, 0); /* Blend state count. */
+ put_u32(&buffer, 0); /* Rasterizer state count. */
+ put_u32(&buffer, 0); /* Sampler state count. */
+ put_u32(&buffer, 0); /* Rendertarget view count. */
+ put_u32(&buffer, 0); /* Depth stencil view count. */
+ put_u32(&buffer, 0); /* Shader count. */
+ put_u32(&buffer, 0); /* Inline shader count. */
+ put_u32(&buffer, fx.group_count); /* Group count. */
+ put_u32(&buffer, 0); /* UAV count. */
+ put_u32(&buffer, 0); /* Interface variables count. */
+ put_u32(&buffer, 0); /* Interface variable element count. */
+ put_u32(&buffer, 0); /* Class instance elements count. */
+
+ size = align(fx.unstructured.size, 4);
+ set_u32(&buffer, size_offset, size);
+
+ bytecode_put_bytes(&buffer, fx.unstructured.data, fx.unstructured.size);
+ bytecode_put_bytes(&buffer, fx.structured.data, fx.structured.size);
+
+ vkd3d_free(fx.unstructured.data);
+ vkd3d_free(fx.structured.data);
+
+ set_status(&fx, buffer.status);
+
+ if (!fx.status)
+ {
+ out->code = buffer.data;
+ out->size = buffer.size;
+ }
+
+ if (fx.status < 0)
+ ctx->result = fx.status;
+
+ return fx_write_context_cleanup(&fx);
+}
+
+int hlsl_emit_effect_binary(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out)
+{
+ if (ctx->profile->major_version == 2)
+ {
+ return hlsl_fx_2_write(ctx, out);
+ }
+ else if (ctx->profile->major_version == 4)
+ {
+ return hlsl_fx_4_write(ctx, out);
+ }
+ else if (ctx->profile->major_version == 5)
+ {
+ return hlsl_fx_5_write(ctx, out);
+ }
+ else
+ {
+ vkd3d_unreachable();
+ }
+}
diff --git a/libs/vkd3d/libs/vkd3d-shader/glsl.c b/libs/vkd3d/libs/vkd3d-shader/glsl.c
index f8d68b5a798..bdd03c1e72a 100644
--- a/libs/vkd3d/libs/vkd3d-shader/glsl.c
+++ b/libs/vkd3d/libs/vkd3d-shader/glsl.c
@@ -91,7 +91,7 @@ static void vkd3d_glsl_handle_instruction(struct vkd3d_glsl_generator *generator
}
int vkd3d_glsl_generator_generate(struct vkd3d_glsl_generator *generator,
- struct vkd3d_shader_parser *parser, struct vkd3d_shader_code *out)
+ struct vsir_program *program, struct vkd3d_shader_code *out)
{
unsigned int i;
void *code;
@@ -100,10 +100,10 @@ int vkd3d_glsl_generator_generate(struct vkd3d_glsl_generator *generator,
vkd3d_string_buffer_printf(&generator->buffer, "void main()\n{\n");
generator->location.column = 0;
- for (i = 0; i < parser->instructions.count; ++i)
+ for (i = 0; i < program->instructions.count; ++i)
{
generator->location.line = i + 1;
- vkd3d_glsl_handle_instruction(generator, &parser->instructions.elements[i]);
+ vkd3d_glsl_handle_instruction(generator, &program->instructions.elements[i]);
}
if (generator->failed)
diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.c b/libs/vkd3d/libs/vkd3d-shader/hlsl.c
index da3bbda1bc3..04c37498d84 100644
--- a/libs/vkd3d/libs/vkd3d-shader/hlsl.c
+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.c
@@ -98,19 +98,22 @@ bool hlsl_add_var(struct hlsl_ctx *ctx, struct hlsl_ir_var *decl, bool local_var
struct hlsl_scope *scope = ctx->cur_scope;
struct hlsl_ir_var *var;
- LIST_FOR_EACH_ENTRY(var, &scope->vars, struct hlsl_ir_var, scope_entry)
+ if (decl->name)
{
- if (!strcmp(decl->name, var->name))
- return false;
- }
- if (local_var && scope->upper->upper == ctx->globals)
- {
- /* Check whether the variable redefines a function parameter. */
- LIST_FOR_EACH_ENTRY(var, &scope->upper->vars, struct hlsl_ir_var, scope_entry)
+ LIST_FOR_EACH_ENTRY(var, &scope->vars, struct hlsl_ir_var, scope_entry)
{
- if (!strcmp(decl->name, var->name))
+ if (var->name && !strcmp(decl->name, var->name))
return false;
}
+ if (local_var && scope->upper->upper == ctx->globals)
+ {
+ /* Check whether the variable redefines a function parameter. */
+ LIST_FOR_EACH_ENTRY(var, &scope->upper->vars, struct hlsl_ir_var, scope_entry)
+ {
+ if (var->name && !strcmp(decl->name, var->name))
+ return false;
+ }
+ }
}
list_add_tail(&scope->vars, &decl->scope_entry);
@@ -123,7 +126,7 @@ struct hlsl_ir_var *hlsl_get_var(struct hlsl_scope *scope, const char *name)
LIST_FOR_EACH_ENTRY(var, &scope->vars, struct hlsl_ir_var, scope_entry)
{
- if (!strcmp(name, var->name))
+ if (var->name && !strcmp(name, var->name))
return var;
}
if (!scope->upper)
@@ -915,12 +918,17 @@ bool hlsl_types_are_equal(const struct hlsl_type *t1, const struct hlsl_type *t2
if (t1->class == HLSL_CLASS_ARRAY)
return t1->e.array.elements_count == t2->e.array.elements_count
&& hlsl_types_are_equal(t1->e.array.type, t2->e.array.type);
+ if (t1->class == HLSL_CLASS_OBJECT)
+ {
+ if (t1->base_type == HLSL_TYPE_TECHNIQUE && t1->e.version != t2->e.version)
+ return false;
+ }
return true;
}
struct hlsl_type *hlsl_type_clone(struct hlsl_ctx *ctx, struct hlsl_type *old,
- unsigned int default_majority, unsigned int modifiers)
+ unsigned int default_majority, uint32_t modifiers)
{
struct hlsl_type *type;
@@ -945,6 +953,8 @@ struct hlsl_type *hlsl_type_clone(struct hlsl_ctx *ctx, struct hlsl_type *old,
type->modifiers |= default_majority;
type->sampler_dim = old->sampler_dim;
type->is_minimum_precision = old->is_minimum_precision;
+ type->sample_count = old->sample_count;
+
switch (old->class)
{
case HLSL_CLASS_ARRAY:
@@ -993,6 +1003,13 @@ struct hlsl_type *hlsl_type_clone(struct hlsl_ctx *ctx, struct hlsl_type *old,
break;
}
+ case HLSL_CLASS_OBJECT:
+ if (type->base_type == HLSL_TYPE_TECHNIQUE)
+ type->e.version = old->e.version;
+ if (old->base_type == HLSL_TYPE_TEXTURE || old->base_type == HLSL_TYPE_UAV)
+ type->e.resource_format = old->e.resource_format;
+ break;
+
default:
break;
}
@@ -1030,7 +1047,7 @@ struct hlsl_ir_node *hlsl_new_copy(struct hlsl_ctx *ctx, struct hlsl_ir_node *no
}
struct hlsl_ir_var *hlsl_new_var(struct hlsl_ctx *ctx, const char *name, struct hlsl_type *type,
- const struct vkd3d_shader_location *loc, const struct hlsl_semantic *semantic, unsigned int modifiers,
+ const struct vkd3d_shader_location *loc, const struct hlsl_semantic *semantic, uint32_t modifiers,
const struct hlsl_reg_reservation *reg_reservation)
{
struct hlsl_ir_var *var;
@@ -1505,7 +1522,7 @@ struct hlsl_ir_node *hlsl_new_resource_store(struct hlsl_ctx *ctx, const struct
return &store->node;
}
-struct hlsl_ir_node *hlsl_new_swizzle(struct hlsl_ctx *ctx, DWORD s, unsigned int components,
+struct hlsl_ir_node *hlsl_new_swizzle(struct hlsl_ctx *ctx, uint32_t s, unsigned int components,
struct hlsl_ir_node *val, const struct vkd3d_shader_location *loc)
{
struct hlsl_ir_swizzle *swizzle;
@@ -2246,7 +2263,7 @@ const char *debug_hlsl_type(struct hlsl_ctx *ctx, const struct hlsl_type *type)
return ret;
}
-struct vkd3d_string_buffer *hlsl_modifiers_to_string(struct hlsl_ctx *ctx, unsigned int modifiers)
+struct vkd3d_string_buffer *hlsl_modifiers_to_string(struct hlsl_ctx *ctx, uint32_t modifiers)
{
struct vkd3d_string_buffer *string;
@@ -2432,7 +2449,7 @@ const char *debug_hlsl_writemask(unsigned int writemask)
return vkd3d_dbg_sprintf(".%s", string);
}
-const char *debug_hlsl_swizzle(unsigned int swizzle, unsigned int size)
+const char *debug_hlsl_swizzle(uint32_t swizzle, unsigned int size)
{
static const char components[] = {'x', 'y', 'z', 'w'};
char string[5];
@@ -3147,9 +3164,10 @@ void hlsl_add_function(struct hlsl_ctx *ctx, char *name, struct hlsl_ir_function
rb_put(&ctx->functions, func->name, &func->entry);
}
-unsigned int hlsl_map_swizzle(unsigned int swizzle, unsigned int writemask)
+uint32_t hlsl_map_swizzle(uint32_t swizzle, unsigned int writemask)
{
- unsigned int i, ret = 0;
+ uint32_t ret = 0;
+ unsigned int i;
/* Leave replicate swizzles alone; some instructions need them. */
if (swizzle == HLSL_SWIZZLE(X, X, X, X)
@@ -3169,7 +3187,7 @@ unsigned int hlsl_map_swizzle(unsigned int swizzle, unsigned int writemask)
return ret;
}
-unsigned int hlsl_swizzle_from_writemask(unsigned int writemask)
+uint32_t hlsl_swizzle_from_writemask(unsigned int writemask)
{
static const unsigned int swizzles[16] =
{
@@ -3210,9 +3228,10 @@ unsigned int hlsl_combine_writemasks(unsigned int first, unsigned int second)
return ret;
}
-unsigned int hlsl_combine_swizzles(unsigned int first, unsigned int second, unsigned int dim)
+uint32_t hlsl_combine_swizzles(uint32_t first, uint32_t second, unsigned int dim)
{
- unsigned int ret = 0, i;
+ uint32_t ret = 0;
+ unsigned int i;
for (i = 0; i < dim; ++i)
{
unsigned int s = hlsl_swizzle_get_component(second, i);
@@ -3346,15 +3365,28 @@ static void declare_predefined_types(struct hlsl_ctx *ctx)
effect_types[] =
{
{"dword", HLSL_CLASS_SCALAR, HLSL_TYPE_UINT, 1, 1},
- {"float", HLSL_CLASS_SCALAR, HLSL_TYPE_FLOAT, 1, 1},
{"vector", HLSL_CLASS_VECTOR, HLSL_TYPE_FLOAT, 4, 1},
{"matrix", HLSL_CLASS_MATRIX, HLSL_TYPE_FLOAT, 4, 4},
+ {"fxgroup", HLSL_CLASS_OBJECT, HLSL_TYPE_EFFECT_GROUP, 1, 1},
+ {"pass", HLSL_CLASS_OBJECT, HLSL_TYPE_PASS, 1, 1},
{"STRING", HLSL_CLASS_OBJECT, HLSL_TYPE_STRING, 1, 1},
{"TEXTURE", HLSL_CLASS_OBJECT, HLSL_TYPE_TEXTURE, 1, 1},
{"PIXELSHADER", HLSL_CLASS_OBJECT, HLSL_TYPE_PIXELSHADER, 1, 1},
{"VERTEXSHADER", HLSL_CLASS_OBJECT, HLSL_TYPE_VERTEXSHADER, 1, 1},
};
+ static const struct
+ {
+ char *name;
+ unsigned int version;
+ }
+ technique_types[] =
+ {
+ {"technique", 9},
+ {"technique10", 10},
+ {"technique11", 11},
+ };
+
for (bt = 0; bt <= HLSL_TYPE_LAST_SCALAR; ++bt)
{
for (y = 1; y <= 4; ++y)
@@ -3459,6 +3491,13 @@ static void declare_predefined_types(struct hlsl_ctx *ctx)
effect_types[i].base_type, effect_types[i].dimx, effect_types[i].dimy);
hlsl_scope_add_type(ctx->globals, type);
}
+
+ for (i = 0; i < ARRAY_SIZE(technique_types); ++i)
+ {
+ type = hlsl_new_type(ctx, technique_types[i].name, HLSL_CLASS_OBJECT, HLSL_TYPE_TECHNIQUE, 1, 1);
+ type->e.version = technique_types[i].version;
+ hlsl_scope_add_type(ctx->globals, type);
+ }
}
static bool hlsl_ctx_init(struct hlsl_ctx *ctx, const struct vkd3d_shader_compile_info *compile_info,
@@ -3594,7 +3633,13 @@ int hlsl_compile_shader(const struct vkd3d_shader_code *hlsl, const struct vkd3d
return VKD3D_ERROR_NOT_IMPLEMENTED;
}
- if (compile_info->target_type == VKD3D_SHADER_TARGET_D3D_BYTECODE && profile->major_version > 3)
+ if (compile_info->target_type != VKD3D_SHADER_TARGET_FX && profile->type == VKD3D_SHADER_TYPE_EFFECT)
+ {
+ vkd3d_shader_error(message_context, NULL, VKD3D_SHADER_ERROR_HLSL_INCOMPATIBLE_PROFILE,
+ "The '%s' target profile is only compatible with the 'fx' target type.", profile->name);
+ return VKD3D_ERROR_INVALID_ARGUMENT;
+ }
+ else if (compile_info->target_type == VKD3D_SHADER_TARGET_D3D_BYTECODE && profile->major_version > 3)
{
vkd3d_shader_error(message_context, NULL, VKD3D_SHADER_ERROR_HLSL_INCOMPATIBLE_PROFILE,
"The '%s' target profile is incompatible with the 'd3dbc' target type.", profile->name);
@@ -3606,6 +3651,12 @@ int hlsl_compile_shader(const struct vkd3d_shader_code *hlsl, const struct vkd3d
"The '%s' target profile is incompatible with the 'dxbc-tpf' target type.", profile->name);
return VKD3D_ERROR_INVALID_ARGUMENT;
}
+ else if (compile_info->target_type == VKD3D_SHADER_TARGET_FX && profile->type != VKD3D_SHADER_TYPE_EFFECT)
+ {
+ vkd3d_shader_error(message_context, NULL, VKD3D_SHADER_ERROR_HLSL_INCOMPATIBLE_PROFILE,
+ "The '%s' target profile is incompatible with the 'fx' target type.", profile->name);
+ return VKD3D_ERROR_INVALID_ARGUMENT;
+ }
if (!hlsl_ctx_init(&ctx, compile_info, profile, message_context))
return VKD3D_ERROR_OUT_OF_MEMORY;
@@ -3630,6 +3681,14 @@ int hlsl_compile_shader(const struct vkd3d_shader_code *hlsl, const struct vkd3d
return VKD3D_ERROR_NOT_IMPLEMENTED;
}
+ if (ctx.profile->type == VKD3D_SHADER_TYPE_EFFECT)
+ {
+ ret = hlsl_emit_effect_binary(&ctx, out);
+
+ hlsl_ctx_cleanup(&ctx);
+ return ret;
+ }
+
if ((func = hlsl_get_function(&ctx, entry_point)))
{
LIST_FOR_EACH_ENTRY(decl, &func->overloads, struct hlsl_ir_function_decl, entry)
diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.h b/libs/vkd3d/libs/vkd3d-shader/hlsl.h
index ca75a1936f1..984ac7e4883 100644
--- a/libs/vkd3d/libs/vkd3d-shader/hlsl.h
+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.h
@@ -65,7 +65,7 @@
#define HLSL_SWIZZLE_MASK (0x3u)
#define HLSL_SWIZZLE_SHIFT(idx) (2u * (idx))
-static inline unsigned int hlsl_swizzle_get_component(unsigned int swizzle, unsigned int idx)
+static inline unsigned int hlsl_swizzle_get_component(uint32_t swizzle, unsigned int idx)
{
return (swizzle >> HLSL_SWIZZLE_SHIFT(idx)) & HLSL_SWIZZLE_MASK;
}
@@ -95,6 +95,9 @@ enum hlsl_base_type
HLSL_TYPE_UAV,
HLSL_TYPE_PIXELSHADER,
HLSL_TYPE_VERTEXSHADER,
+ HLSL_TYPE_PASS,
+ HLSL_TYPE_TECHNIQUE,
+ HLSL_TYPE_EFFECT_GROUP,
HLSL_TYPE_STRING,
HLSL_TYPE_VOID,
};
@@ -138,8 +141,10 @@ struct hlsl_type
struct rb_entry scope_entry;
enum hlsl_type_class class;
- /* If type is <= HLSL_CLASS_LAST_NUMERIC, then base_type is <= HLSL_TYPE_LAST_SCALAR.
- * If type is HLSL_CLASS_OBJECT, then base_type is > HLSL_TYPE_LAST_SCALAR.
+ /* If class is <= HLSL_CLASS_LAST_NUMERIC, then base_type is <= HLSL_TYPE_LAST_SCALAR.
+ * If class is HLSL_CLASS_OBJECT, then base_type is > HLSL_TYPE_LAST_SCALAR.
+ * If class is HLSL_CLASS_OBJECT and base_type is HLSL_TYPE_TECHNIQUE, additional version
+ * field is used to distinguish between technique types.
* Otherwise, base_type is not used. */
enum hlsl_base_type base_type;
@@ -155,7 +160,7 @@ struct hlsl_type
/* Bitfield for storing type modifiers, subset of HLSL_TYPE_MODIFIERS_MASK.
* Modifiers that don't fall inside this mask are to be stored in the variable in
* hlsl_ir_var.modifiers, or in the struct field in hlsl_ir_field.modifiers. */
- unsigned int modifiers;
+ uint32_t modifiers;
/* Size of the type values on each dimension. For non-numeric types, they are set for the
* convenience of the sm1/sm4 backends.
* If type is HLSL_CLASS_SCALAR, then both dimx = 1 and dimy = 1.
@@ -191,6 +196,8 @@ struct hlsl_type
/* Format of the data contained within the type if the base_type is HLSL_TYPE_TEXTURE or
* HLSL_TYPE_UAV. */
struct hlsl_type *resource_format;
+ /* Additional field to distinguish object types. Currently used only for technique types. */
+ unsigned int version;
} e;
/* Number of numeric register components used by one value of this type, for each regset.
@@ -234,7 +241,7 @@ struct hlsl_struct_field
/* Bitfield for storing modifiers that are not in HLSL_TYPE_MODIFIERS_MASK (these are stored in
* type->modifiers instead) and that also are specific to the field and not the whole variable.
* In particular, interpolation modifiers. */
- unsigned int storage_modifiers;
+ uint32_t storage_modifiers;
/* Offset of the field within the type it belongs to, in register components, for each regset. */
unsigned int reg_offset[HLSL_REGSET_LAST + 1];
@@ -392,7 +399,7 @@ struct hlsl_ir_var
/* Buffer where the variable's value is stored, in case it is uniform. */
struct hlsl_buffer *buffer;
/* Bitfield for storage modifiers (type modifiers are stored in data_type->modifiers). */
- unsigned int storage_modifiers;
+ uint32_t storage_modifiers;
/* Optional reservations of registers and/or offsets for variables within constant buffers. */
struct hlsl_reg_reservation reg_reservation;
@@ -400,6 +407,10 @@ struct hlsl_ir_var
struct list scope_entry;
/* Item entry in hlsl_ctx.extern_vars, if the variable is extern. */
struct list extern_entry;
+ /* Scope that variable itself defines, used to provide a container for techniques and passes. */
+ struct hlsl_scope *scope;
+ /* Scope that contains annotations for this variable. */
+ struct hlsl_scope *annotations;
/* Indexes of the IR instructions where the variable is first written and last read (liveness
* range). The IR instructions are numerated starting from 2, because 0 means unused, and 1
@@ -622,7 +633,7 @@ struct hlsl_ir_swizzle
{
struct hlsl_ir_node node;
struct hlsl_src val;
- DWORD swizzle;
+ uint32_t swizzle;
};
struct hlsl_ir_index
@@ -1160,6 +1171,7 @@ void hlsl_dump_function(struct hlsl_ctx *ctx, const struct hlsl_ir_function_decl
int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func,
enum vkd3d_shader_target_type target_type, struct vkd3d_shader_code *out);
+int hlsl_emit_effect_binary(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out);
bool hlsl_init_deref_from_index_chain(struct hlsl_ctx *ctx, struct hlsl_deref *deref, struct hlsl_ir_node *chain);
bool hlsl_copy_deref(struct hlsl_ctx *ctx, struct hlsl_deref *deref, const struct hlsl_deref *other);
@@ -1250,7 +1262,7 @@ struct hlsl_ir_node *hlsl_new_resource_store(struct hlsl_ctx *ctx, const struct
struct hlsl_ir_node *coords, struct hlsl_ir_node *value, const struct vkd3d_shader_location *loc);
struct hlsl_type *hlsl_new_struct_type(struct hlsl_ctx *ctx, const char *name,
struct hlsl_struct_field *fields, size_t field_count);
-struct hlsl_ir_node *hlsl_new_swizzle(struct hlsl_ctx *ctx, DWORD s, unsigned int components,
+struct hlsl_ir_node *hlsl_new_swizzle(struct hlsl_ctx *ctx, uint32_t s, unsigned int components,
struct hlsl_ir_node *val, const struct vkd3d_shader_location *loc);
struct hlsl_ir_var *hlsl_new_synthetic_var(struct hlsl_ctx *ctx, const char *template,
struct hlsl_type *type, const struct vkd3d_shader_location *loc);
@@ -1264,7 +1276,7 @@ struct hlsl_ir_node *hlsl_new_uint_constant(struct hlsl_ctx *ctx, unsigned int n
struct hlsl_ir_node *hlsl_new_unary_expr(struct hlsl_ctx *ctx, enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg,
const struct vkd3d_shader_location *loc);
struct hlsl_ir_var *hlsl_new_var(struct hlsl_ctx *ctx, const char *name, struct hlsl_type *type,
- const struct vkd3d_shader_location *loc, const struct hlsl_semantic *semantic, unsigned int modifiers,
+ const struct vkd3d_shader_location *loc, const struct hlsl_semantic *semantic, uint32_t modifiers,
const struct hlsl_reg_reservation *reg_reservation);
struct hlsl_ir_switch_case *hlsl_new_switch_case(struct hlsl_ctx *ctx, unsigned int value, bool is_default,
struct hlsl_block *body, const struct vkd3d_shader_location *loc);
@@ -1286,7 +1298,7 @@ void hlsl_pop_scope(struct hlsl_ctx *ctx);
bool hlsl_scope_add_type(struct hlsl_scope *scope, struct hlsl_type *type);
struct hlsl_type *hlsl_type_clone(struct hlsl_ctx *ctx, struct hlsl_type *old,
- unsigned int default_majority, unsigned int modifiers);
+ unsigned int default_majority, uint32_t modifiers);
unsigned int hlsl_type_component_count(const struct hlsl_type *type);
unsigned int hlsl_type_get_array_element_reg_size(const struct hlsl_type *type, enum hlsl_regset regset);
struct hlsl_type *hlsl_type_get_component_type(struct hlsl_ctx *ctx, struct hlsl_type *type,
@@ -1304,10 +1316,10 @@ bool hlsl_types_are_equal(const struct hlsl_type *t1, const struct hlsl_type *t2
const struct hlsl_type *hlsl_get_multiarray_element_type(const struct hlsl_type *type);
unsigned int hlsl_get_multiarray_size(const struct hlsl_type *type);
-unsigned int hlsl_combine_swizzles(unsigned int first, unsigned int second, unsigned int dim);
+uint32_t hlsl_combine_swizzles(uint32_t first, uint32_t second, unsigned int dim);
unsigned int hlsl_combine_writemasks(unsigned int first, unsigned int second);
-unsigned int hlsl_map_swizzle(unsigned int swizzle, unsigned int writemask);
-unsigned int hlsl_swizzle_from_writemask(unsigned int writemask);
+uint32_t hlsl_map_swizzle(uint32_t swizzle, unsigned int writemask);
+uint32_t hlsl_swizzle_from_writemask(unsigned int writemask);
struct hlsl_type *hlsl_deref_get_type(struct hlsl_ctx *ctx, const struct hlsl_deref *deref);
enum hlsl_regset hlsl_deref_get_regset(struct hlsl_ctx *ctx, const struct hlsl_deref *deref);
diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.l b/libs/vkd3d/libs/vkd3d-shader/hlsl.l
index fe838750747..6cef0e02eff 100644
--- a/libs/vkd3d/libs/vkd3d-shader/hlsl.l
+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.l
@@ -89,6 +89,7 @@ else {return KW_ELSE; }
extern {return KW_EXTERN; }
false {return KW_FALSE; }
for {return KW_FOR; }
+fxgroup {return KW_FXGROUP; }
GeometryShader {return KW_GEOMETRYSHADER; }
groupshared {return KW_GROUPSHARED; }
if {return KW_IF; }
diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.y b/libs/vkd3d/libs/vkd3d-shader/hlsl.y
index 0dde4c18587..8dc353e11c0 100644
--- a/libs/vkd3d/libs/vkd3d-shader/hlsl.y
+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.y
@@ -40,7 +40,7 @@ struct parse_parameter
const char *name;
struct hlsl_semantic semantic;
struct hlsl_reg_reservation reg_reservation;
- unsigned int modifiers;
+ uint32_t modifiers;
};
struct parse_colon_attribute
@@ -75,7 +75,7 @@ struct parse_variable_def
struct parse_initializer initializer;
struct hlsl_type *basic_type;
- unsigned int modifiers;
+ uint32_t modifiers;
struct vkd3d_shader_location modifiers_loc;
};
@@ -292,6 +292,21 @@ static bool implicit_compatible_data_types(struct hlsl_ctx *ctx, struct hlsl_typ
return hlsl_types_are_componentwise_equal(ctx, src, dst);
}
+static void check_condition_type(struct hlsl_ctx *ctx, const struct hlsl_ir_node *cond)
+{
+ const struct hlsl_type *type = cond->data_type;
+
+ if (type->class > HLSL_CLASS_LAST_NUMERIC || type->dimx > 1 || type->dimy > 1)
+ {
+ struct vkd3d_string_buffer *string;
+
+ if ((string = hlsl_type_to_string(ctx, type)))
+ hlsl_error(ctx, &cond->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE,
+ "Condition type '%s' is not a scalar numeric type.", string->buffer);
+ hlsl_release_string_buffer(ctx, string);
+ }
+}
+
static struct hlsl_ir_node *add_cast(struct hlsl_ctx *ctx, struct hlsl_block *block,
struct hlsl_ir_node *node, struct hlsl_type *dst_type, const struct vkd3d_shader_location *loc)
{
@@ -405,7 +420,7 @@ static struct hlsl_ir_node *add_implicit_conversion(struct hlsl_ctx *ctx, struct
return add_cast(ctx, block, node, dst_type, loc);
}
-static DWORD add_modifiers(struct hlsl_ctx *ctx, DWORD modifiers, DWORD mod,
+static uint32_t add_modifiers(struct hlsl_ctx *ctx, uint32_t modifiers, uint32_t mod,
const struct vkd3d_shader_location *loc)
{
if (modifiers & mod)
@@ -431,6 +446,9 @@ static bool append_conditional_break(struct hlsl_ctx *ctx, struct hlsl_block *co
return true;
condition = node_from_block(cond_block);
+
+ check_condition_type(ctx, condition);
+
if (!(not = hlsl_new_unary_expr(ctx, HLSL_OP1_LOGIC_NOT, condition, &condition->loc)))
return false;
hlsl_block_add_instr(cond_block, not);
@@ -487,27 +505,27 @@ static void resolve_loop_continue(struct hlsl_ctx *ctx, struct hlsl_block *block
else if (instr->type == HLSL_IR_JUMP)
{
struct hlsl_ir_jump *jump = hlsl_ir_jump(instr);
- struct hlsl_block block;
+ struct hlsl_block cond_block;
if (jump->type != HLSL_IR_JUMP_UNRESOLVED_CONTINUE)
continue;
if (type == LOOP_DO_WHILE)
{
- if (!hlsl_clone_block(ctx, &block, cond))
+ if (!hlsl_clone_block(ctx, &cond_block, cond))
return;
- if (!append_conditional_break(ctx, &block))
+ if (!append_conditional_break(ctx, &cond_block))
{
- hlsl_block_cleanup(&block);
+ hlsl_block_cleanup(&cond_block);
return;
}
- list_move_before(&instr->entry, &block.instrs);
+ list_move_before(&instr->entry, &cond_block.instrs);
}
else if (type == LOOP_FOR)
{
- if (!hlsl_clone_block(ctx, &block, iter))
+ if (!hlsl_clone_block(ctx, &cond_block, iter))
return;
- list_move_before(&instr->entry, &block.instrs);
+ list_move_before(&instr->entry, &cond_block.instrs);
}
jump->type = HLSL_IR_JUMP_CONTINUE;
}
@@ -868,7 +886,7 @@ static const struct hlsl_struct_field *get_struct_field(const struct hlsl_struct
}
static struct hlsl_type *apply_type_modifiers(struct hlsl_ctx *ctx, struct hlsl_type *type,
- unsigned int *modifiers, bool force_majority, const struct vkd3d_shader_location *loc)
+ uint32_t *modifiers, bool force_majority, const struct vkd3d_shader_location *loc)
{
unsigned int default_majority = 0;
struct hlsl_type *new_type;
@@ -926,7 +944,7 @@ static bool shader_profile_version_lt(const struct hlsl_ctx *ctx, unsigned int m
}
static bool gen_struct_fields(struct hlsl_ctx *ctx, struct parse_fields *fields,
- struct hlsl_type *type, unsigned int modifiers, struct list *defs)
+ struct hlsl_type *type, uint32_t modifiers, struct list *defs)
{
struct parse_variable_def *v, *v_next;
size_t i = 0;
@@ -1019,7 +1037,7 @@ static bool add_typedef(struct hlsl_ctx *ctx, struct hlsl_type *const orig_type,
}
else
{
- unsigned int var_modifiers = 0;
+ uint32_t var_modifiers = 0;
if (!(type = apply_type_modifiers(ctx, orig_type, &var_modifiers, true, &v->loc)))
{
@@ -1096,6 +1114,83 @@ static bool add_func_parameter(struct hlsl_ctx *ctx, struct hlsl_func_parameters
return true;
}
+static bool add_pass(struct hlsl_ctx *ctx, const char *name, struct hlsl_scope *annotations,
+ const struct vkd3d_shader_location *loc)
+{
+ struct hlsl_ir_var *var;
+ struct hlsl_type *type;
+
+ type = hlsl_get_type(ctx->globals, "pass", false, false);
+ if (!(var = hlsl_new_var(ctx, name, type, loc, NULL, 0, NULL)))
+ return false;
+ var->annotations = annotations;
+
+ if (!hlsl_add_var(ctx, var, false))
+ {
+ struct hlsl_ir_var *old = hlsl_get_var(ctx->cur_scope, var->name);
+
+ hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_REDEFINED,
+ "Identifier \"%s\" was already declared in this scope.", var->name);
+ hlsl_note(ctx, &old->loc, VKD3D_SHADER_LOG_ERROR, "\"%s\" was previously declared here.", old->name);
+ hlsl_free_var(var);
+ return false;
+ }
+
+ return true;
+}
+
+static bool add_technique(struct hlsl_ctx *ctx, const char *name, struct hlsl_scope *scope,
+ struct hlsl_scope *annotations, const char *typename, const struct vkd3d_shader_location *loc)
+{
+ struct hlsl_ir_var *var;
+ struct hlsl_type *type;
+
+ type = hlsl_get_type(ctx->globals, typename, false, false);
+ if (!(var = hlsl_new_var(ctx, name, type, loc, NULL, 0, NULL)))
+ return false;
+ var->scope = scope;
+ var->annotations = annotations;
+
+ if (!hlsl_add_var(ctx, var, false))
+ {
+ struct hlsl_ir_var *old = hlsl_get_var(ctx->cur_scope, var->name);
+
+ hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_REDEFINED,
+ "Identifier \"%s\" was already declared in this scope.", var->name);
+ hlsl_note(ctx, &old->loc, VKD3D_SHADER_LOG_ERROR, "\"%s\" was previously declared here.", old->name);
+ hlsl_free_var(var);
+ return false;
+ }
+
+ return true;
+}
+
+static bool add_effect_group(struct hlsl_ctx *ctx, const char *name, struct hlsl_scope *scope,
+ struct hlsl_scope *annotations, const struct vkd3d_shader_location *loc)
+{
+ struct hlsl_ir_var *var;
+ struct hlsl_type *type;
+
+ type = hlsl_get_type(ctx->globals, "fxgroup", false, false);
+ if (!(var = hlsl_new_var(ctx, name, type, loc, NULL, 0, NULL)))
+ return false;
+ var->scope = scope;
+ var->annotations = annotations;
+
+ if (!hlsl_add_var(ctx, var, false))
+ {
+ struct hlsl_ir_var *old = hlsl_get_var(ctx->cur_scope, var->name);
+
+ hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_REDEFINED,
+ "Identifier \"%s\" was already declared in this scope.", var->name);
+ hlsl_note(ctx, &old->loc, VKD3D_SHADER_LOG_ERROR, "\"%s\" was previously declared here.", old->name);
+ hlsl_free_var(var);
+ return false;
+ }
+
+ return true;
+}
+
static struct hlsl_reg_reservation parse_reg_reservation(const char *reg_string)
{
struct hlsl_reg_reservation reservation = {0};
@@ -1717,7 +1812,7 @@ static enum hlsl_ir_expr_op op_from_assignment(enum parse_assign_op op)
return ops[op];
}
-static bool invert_swizzle(unsigned int *swizzle, unsigned int *writemask, unsigned int *ret_width)
+static bool invert_swizzle(uint32_t *swizzle, unsigned int *writemask, unsigned int *ret_width)
{
unsigned int i, j, bit = 0, inverted = 0, width, new_writemask = 0, new_swizzle = 0;
@@ -1791,8 +1886,9 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct hlsl_blo
else if (lhs->type == HLSL_IR_SWIZZLE)
{
struct hlsl_ir_swizzle *swizzle = hlsl_ir_swizzle(lhs);
- unsigned int width, s = swizzle->swizzle;
struct hlsl_ir_node *new_swizzle;
+ uint32_t s = swizzle->swizzle;
+ unsigned int width;
if (lhs->data_type->class == HLSL_CLASS_MATRIX)
hlsl_fixme(ctx, &lhs->loc, "Matrix assignment with a writemask.");
@@ -3553,7 +3649,7 @@ static bool intrinsic_tex(struct hlsl_ctx *ctx, const struct parse_initializer *
{
struct hlsl_resource_load_params load_params = { 0 };
const struct hlsl_type *sampler_type;
- struct hlsl_ir_node *coords, *load;
+ struct hlsl_ir_node *coords, *sample;
if (params->args_count != 2 && params->args_count != 4)
{
@@ -3688,9 +3784,9 @@ static bool intrinsic_tex(struct hlsl_ctx *ctx, const struct parse_initializer *
load_params.format = hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, 4);
load_params.sampling_dim = dim;
- if (!(load = hlsl_new_resource_load(ctx, &load_params, loc)))
+ if (!(sample = hlsl_new_resource_load(ctx, &load_params, loc)))
return false;
- hlsl_block_add_instr(params->instrs, load);
+ hlsl_block_add_instr(params->instrs, sample);
return true;
}
@@ -4034,6 +4130,89 @@ static struct hlsl_block *add_constructor(struct hlsl_ctx *ctx, struct hlsl_type
return params->instrs;
}
+static bool add_ternary(struct hlsl_ctx *ctx, struct hlsl_block *block,
+ struct hlsl_ir_node *cond, struct hlsl_ir_node *first, struct hlsl_ir_node *second)
+{
+ struct hlsl_ir_node *args[HLSL_MAX_OPERANDS] = {0};
+ struct hlsl_type *cond_type = cond->data_type;
+ struct hlsl_type *common_type;
+
+ if (cond_type->class > HLSL_CLASS_LAST_NUMERIC)
+ {
+ struct vkd3d_string_buffer *string;
+
+ if ((string = hlsl_type_to_string(ctx, cond_type)))
+ hlsl_error(ctx, &cond->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE,
+ "Ternary condition type '%s' is not numeric.", string->buffer);
+ hlsl_release_string_buffer(ctx, string);
+ }
+
+ if (first->data_type->class <= HLSL_CLASS_LAST_NUMERIC
+ && second->data_type->class <= HLSL_CLASS_LAST_NUMERIC)
+ {
+ if (!(common_type = get_common_numeric_type(ctx, first, second, &first->loc)))
+ return false;
+
+ if (cond_type->dimx == 1 && cond_type->dimy == 1)
+ {
+ cond_type = hlsl_get_numeric_type(ctx, common_type->class,
+ HLSL_TYPE_BOOL, common_type->dimx, common_type->dimy);
+ if (!(cond = add_implicit_conversion(ctx, block, cond, cond_type, &cond->loc)))
+ return false;
+ }
+ else if (common_type->dimx == 1 && common_type->dimy == 1)
+ {
+ common_type = hlsl_get_numeric_type(ctx, cond_type->class,
+ common_type->base_type, cond_type->dimx, cond_type->dimy);
+ }
+ else if (cond_type->dimx != common_type->dimx || cond_type->dimy != common_type->dimy)
+ {
+ /* This condition looks wrong but is correct.
+ * floatN is compatible with float1xN, but not with floatNx1. */
+
+ struct vkd3d_string_buffer *cond_string, *value_string;
+
+ cond_string = hlsl_type_to_string(ctx, cond_type);
+ value_string = hlsl_type_to_string(ctx, common_type);
+ if (cond_string && value_string)
+ hlsl_error(ctx, &first->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE,
+ "Ternary condition type '%s' is not compatible with value type '%s'.",
+ cond_string->buffer, value_string->buffer);
+ hlsl_release_string_buffer(ctx, cond_string);
+ hlsl_release_string_buffer(ctx, value_string);
+ }
+
+ if (!(first = add_implicit_conversion(ctx, block, first, common_type, &first->loc)))
+ return false;
+
+ if (!(second = add_implicit_conversion(ctx, block, second, common_type, &second->loc)))
+ return false;
+ }
+ else
+ {
+ struct vkd3d_string_buffer *first_string, *second_string;
+
+ if (!hlsl_types_are_equal(first->data_type, second->data_type))
+ {
+ first_string = hlsl_type_to_string(ctx, first->data_type);
+ second_string = hlsl_type_to_string(ctx, second->data_type);
+ if (first_string && second_string)
+ hlsl_error(ctx, &first->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE,
+ "Ternary argument types '%s' and '%s' do not match.",
+ first_string->buffer, second_string->buffer);
+ hlsl_release_string_buffer(ctx, first_string);
+ hlsl_release_string_buffer(ctx, second_string);
+ }
+
+ common_type = first->data_type;
+ }
+
+ args[0] = cond;
+ args[1] = first;
+ args[2] = second;
+ return add_expr(ctx, block, HLSL_OP3_TERNARY, args, common_type, &first->loc);
+}
+
static unsigned int hlsl_offset_dim_count(enum hlsl_sampler_dim dim)
{
switch (dim)
@@ -4844,7 +5023,7 @@ static void check_duplicated_switch_cases(struct hlsl_ctx *ctx, const struct hls
FLOAT floatval;
bool boolval;
char *name;
- DWORD modifiers;
+ uint32_t modifiers;
struct hlsl_ir_node *instr;
struct hlsl_block *block;
struct list *list;
@@ -4865,6 +5044,7 @@ static void check_duplicated_switch_cases(struct hlsl_ctx *ctx, const struct hls
struct hlsl_attribute *attr;
struct parse_attribute_list attr_list;
struct hlsl_ir_switch_case *switch_case;
+ struct hlsl_scope *scope;
}
%token KW_BLENDSTATE
@@ -4887,6 +5067,7 @@ static void check_duplicated_switch_cases(struct hlsl_ctx *ctx, const struct hls
%token KW_EXTERN
%token KW_FALSE
%token KW_FOR
+%token KW_FXGROUP
%token KW_GEOMETRYSHADER
%token KW_GROUPSHARED
%token KW_IF
@@ -4989,6 +5170,8 @@ static void check_duplicated_switch_cases(struct hlsl_ctx *ctx, const struct hls
%token <name> STRING
%token <name> TYPE_IDENTIFIER
+%type <scope> annotations_opt
+
%type <arrays> arrays
%type <assign_op> assign_op
@@ -5051,7 +5234,7 @@ static void check_duplicated_switch_cases(struct hlsl_ctx *ctx, const struct hls
%type <name> any_identifier
%type <name> var_identifier
-%type <name> technique_name
+%type <name> name_opt
%type <parameter> parameter
@@ -5093,50 +5276,114 @@ hlsl_prog:
destroy_block($2);
}
| hlsl_prog preproc_directive
- | hlsl_prog technique
+ | hlsl_prog global_technique
+ | hlsl_prog effect_group
| hlsl_prog ';'
-technique_name:
+name_opt:
%empty
{
$$ = NULL;
}
| any_identifier
-pass_list:
+pass:
+ KW_PASS name_opt annotations_opt '{' '}'
+ {
+ if (!add_pass(ctx, $2, $3, &@1))
+ YYABORT;
+ }
+
+annotations_list:
+ variables_def_typed ';'
+ | annotations_list variables_def_typed ';'
+
+annotations_opt:
%empty
+ {
+ $$ = NULL;
+ }
+ | '<' scope_start '>'
+ {
+ hlsl_pop_scope(ctx);
+ $$ = NULL;
+ }
+ | '<' scope_start annotations_list '>'
+ {
+ struct hlsl_scope *scope = ctx->cur_scope;
+
+ hlsl_pop_scope(ctx);
+ $$ = scope;
+ }
+
+pass_list:
+ pass
+ | pass_list pass
+
+passes:
+ scope_start
+ | scope_start pass_list
technique9:
- KW_TECHNIQUE technique_name '{' pass_list '}'
+ KW_TECHNIQUE name_opt annotations_opt '{' passes '}'
{
- hlsl_fixme(ctx, &@$, "Unsupported \'technique\' declaration.");
+ struct hlsl_scope *scope = ctx->cur_scope;
+ hlsl_pop_scope(ctx);
+
+ if (!add_technique(ctx, $2, scope, $3, "technique", &@1))
+ YYABORT;
}
technique10:
- KW_TECHNIQUE10 technique_name '{' pass_list '}'
+ KW_TECHNIQUE10 name_opt annotations_opt '{' passes '}'
{
+ struct hlsl_scope *scope = ctx->cur_scope;
+ hlsl_pop_scope(ctx);
+
if (ctx->profile->type == VKD3D_SHADER_TYPE_EFFECT && ctx->profile->major_version == 2)
hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX,
"The 'technique10' keyword is invalid for this profile.");
- hlsl_fixme(ctx, &@$, "Unsupported \'technique10\' declaration.");
+ if (!add_technique(ctx, $2, scope, $3, "technique10", &@1))
+ YYABORT;
}
technique11:
- KW_TECHNIQUE11 technique_name '{' pass_list '}'
+ KW_TECHNIQUE11 name_opt annotations_opt '{' passes '}'
{
+ struct hlsl_scope *scope = ctx->cur_scope;
+ hlsl_pop_scope(ctx);
+
if (ctx->profile->type == VKD3D_SHADER_TYPE_EFFECT && ctx->profile->major_version == 2)
hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX,
"The 'technique11' keyword is invalid for this profile.");
- hlsl_fixme(ctx, &@$, "Unsupported \'technique11\' declaration.");
+ if (!add_technique(ctx, $2, scope, $3, "technique11", &@1))
+ YYABORT;
}
-technique:
+global_technique:
technique9
| technique10
| technique11
+group_technique:
+ technique10
+ | technique11
+
+group_techniques:
+ group_technique
+ | group_techniques group_technique
+
+effect_group:
+ KW_FXGROUP any_identifier annotations_opt '{' scope_start group_techniques '}'
+ {
+ struct hlsl_scope *scope = ctx->cur_scope;
+ hlsl_pop_scope(ctx);
+ if (!(add_effect_group(ctx, $2, scope, $3, &@2)))
+ YYABORT;
+ }
+
buffer_declaration:
buffer_type any_identifier colon_attribute
{
@@ -5282,7 +5529,7 @@ field:
var_modifiers field_type variables_def ';'
{
struct hlsl_type *type;
- unsigned int modifiers = $1;
+ uint32_t modifiers = $1;
if (!(type = apply_type_modifiers(ctx, $2, &modifiers, true, &@1)))
YYABORT;
@@ -5435,7 +5682,7 @@ func_prototype_no_attrs:
/* var_modifiers is necessary to avoid shift/reduce conflicts. */
var_modifiers type var_identifier '(' parameters ')' colon_attribute
{
- unsigned int modifiers = $1;
+ uint32_t modifiers = $1;
struct hlsl_ir_var *var;
struct hlsl_type *type;
@@ -5709,7 +5956,7 @@ param_list:
parameter:
var_modifiers type_no_void any_identifier arrays colon_attribute
{
- unsigned int modifiers = $1;
+ uint32_t modifiers = $1;
struct hlsl_type *type;
unsigned int i;
@@ -6023,7 +6270,7 @@ typedef:
KW_TYPEDEF var_modifiers typedef_type type_specs ';'
{
struct parse_variable_def *v, *v_next;
- unsigned int modifiers = $2;
+ uint32_t modifiers = $2;
struct hlsl_type *type;
if (!(type = apply_type_modifiers(ctx, $3, &modifiers, false, &@2)))
@@ -6160,7 +6407,7 @@ variable_def:
variable_def_typed:
var_modifiers struct_spec variable_def
{
- unsigned int modifiers = $1;
+ uint32_t modifiers = $1;
struct hlsl_type *type;
if (!(type = apply_type_modifiers(ctx, $2, &modifiers, true, &@1)))
@@ -6175,7 +6422,7 @@ variable_def_typed:
}
| var_modifiers type variable_def
{
- unsigned int modifiers = $1;
+ uint32_t modifiers = $1;
struct hlsl_type *type;
if (!(type = apply_type_modifiers(ctx, $2, &modifiers, true, &@1)))
@@ -6516,6 +6763,15 @@ selection_statement:
}
}
+ check_condition_type(ctx, condition);
+
+ if (!(condition = add_cast(ctx, $4, condition, hlsl_get_scalar_type(ctx, HLSL_TYPE_BOOL), &@4)))
+ {
+ destroy_block($6.then_block);
+ destroy_block($6.else_block);
+ YYABORT;
+ }
+
if (!(instr = hlsl_new_if(ctx, condition, $6.then_block, $6.else_block, &@2)))
{
destroy_block($6.then_block);
@@ -6524,15 +6780,7 @@ selection_statement:
}
destroy_block($6.then_block);
destroy_block($6.else_block);
- if (condition->data_type->dimx > 1 || condition->data_type->dimy > 1)
- {
- struct vkd3d_string_buffer *string;
- if ((string = hlsl_type_to_string(ctx, condition->data_type)))
- hlsl_error(ctx, &instr->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE,
- "if condition type %s is not scalar.", string->buffer);
- hlsl_release_string_buffer(ctx, string);
- }
$$ = $4;
hlsl_block_add_instr($$, instr);
}
@@ -7112,27 +7360,13 @@ conditional_expr:
struct hlsl_ir_node *cond = node_from_block($1);
struct hlsl_ir_node *first = node_from_block($3);
struct hlsl_ir_node *second = node_from_block($5);
- struct hlsl_ir_node *args[HLSL_MAX_OPERANDS] = { 0 };
- struct hlsl_type *common_type;
hlsl_block_add_block($1, $3);
hlsl_block_add_block($1, $5);
destroy_block($3);
destroy_block($5);
- if (!(common_type = get_common_numeric_type(ctx, first, second, &@3)))
- YYABORT;
-
- if (!(first = add_implicit_conversion(ctx, $1, first, common_type, &@3)))
- YYABORT;
-
- if (!(second = add_implicit_conversion(ctx, $1, second, common_type, &@5)))
- YYABORT;
-
- args[0] = cond;
- args[1] = first;
- args[2] = second;
- if (!add_expr(ctx, $1, HLSL_OP3_TERNARY, args, common_type, &@1))
+ if (!add_ternary(ctx, $1, cond, first, second))
YYABORT;
$$ = $1;
}
diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c
index 4a622185741..6ad60e4c6c2 100644
--- a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c
+++ b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c
@@ -32,6 +32,11 @@ static struct hlsl_ir_node *new_offset_from_path_index(struct hlsl_ctx *ctx, str
switch (type->class)
{
case HLSL_CLASS_VECTOR:
+ if (idx->type != HLSL_IR_CONSTANT)
+ {
+ hlsl_fixme(ctx, &idx->loc, "Non-constant vector addressing.");
+ break;
+ }
*offset_component += hlsl_ir_constant(idx)->value.u[0].u;
break;
@@ -263,7 +268,7 @@ static bool types_are_semantic_equivalent(struct hlsl_ctx *ctx, const struct hls
}
static struct hlsl_ir_var *add_semantic_var(struct hlsl_ctx *ctx, struct hlsl_ir_var *var,
- struct hlsl_type *type, unsigned int modifiers, struct hlsl_semantic *semantic,
+ struct hlsl_type *type, uint32_t modifiers, struct hlsl_semantic *semantic,
uint32_t index, bool output, const struct vkd3d_shader_location *loc)
{
struct hlsl_semantic new_semantic;
@@ -331,7 +336,7 @@ static struct hlsl_ir_var *add_semantic_var(struct hlsl_ctx *ctx, struct hlsl_ir
}
static void prepend_input_copy(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_load *lhs,
- unsigned int modifiers, struct hlsl_semantic *semantic, uint32_t semantic_index)
+ uint32_t modifiers, struct hlsl_semantic *semantic, uint32_t semantic_index)
{
struct hlsl_type *type = lhs->node.data_type, *vector_type_src, *vector_type_dst;
struct vkd3d_shader_location *loc = &lhs->node.loc;
@@ -395,7 +400,7 @@ static void prepend_input_copy(struct hlsl_ctx *ctx, struct hlsl_block *block, s
}
static void prepend_input_copy_recurse(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_load *lhs,
- unsigned int modifiers, struct hlsl_semantic *semantic, uint32_t semantic_index)
+ uint32_t modifiers, struct hlsl_semantic *semantic, uint32_t semantic_index)
{
struct vkd3d_shader_location *loc = &lhs->node.loc;
struct hlsl_type *type = lhs->node.data_type;
@@ -411,7 +416,7 @@ static void prepend_input_copy_recurse(struct hlsl_ctx *ctx, struct hlsl_block *
for (i = 0; i < hlsl_type_element_count(type); ++i)
{
- unsigned int element_modifiers = modifiers;
+ uint32_t element_modifiers = modifiers;
if (type->class == HLSL_CLASS_ARRAY)
{
@@ -473,7 +478,7 @@ static void prepend_input_var_copy(struct hlsl_ctx *ctx, struct hlsl_block *bloc
}
static void append_output_copy(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_load *rhs,
- unsigned int modifiers, struct hlsl_semantic *semantic, uint32_t semantic_index)
+ uint32_t modifiers, struct hlsl_semantic *semantic, uint32_t semantic_index)
{
struct hlsl_type *type = rhs->node.data_type, *vector_type;
struct vkd3d_shader_location *loc = &rhs->node.loc;
@@ -529,7 +534,7 @@ static void append_output_copy(struct hlsl_ctx *ctx, struct hlsl_block *block, s
}
static void append_output_copy_recurse(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_load *rhs,
- unsigned int modifiers, struct hlsl_semantic *semantic, uint32_t semantic_index)
+ uint32_t modifiers, struct hlsl_semantic *semantic, uint32_t semantic_index)
{
struct vkd3d_shader_location *loc = &rhs->node.loc;
struct hlsl_type *type = rhs->node.data_type;
@@ -1090,7 +1095,7 @@ static bool lower_index_loads(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr,
unsigned int dim_count = hlsl_sampler_dim_count(val->data_type->sampler_dim);
struct hlsl_ir_node *coords = index->idx.node;
struct hlsl_resource_load_params params = {0};
- struct hlsl_ir_node *load;
+ struct hlsl_ir_node *resource_load;
assert(coords->data_type->class == HLSL_CLASS_VECTOR);
assert(coords->data_type->base_type == HLSL_TYPE_UINT);
@@ -1104,9 +1109,9 @@ static bool lower_index_loads(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr,
params.coords = coords;
params.format = val->data_type->e.resource_format;
- if (!(load = hlsl_new_resource_load(ctx, &params, &instr->loc)))
+ if (!(resource_load = hlsl_new_resource_load(ctx, &params, &instr->loc)))
return false;
- hlsl_block_add_instr(block, load);
+ hlsl_block_add_instr(block, resource_load);
return true;
}
@@ -1519,7 +1524,7 @@ static void copy_propagation_set_value(struct hlsl_ctx *ctx, struct copy_propaga
static bool copy_propagation_replace_with_single_instr(struct hlsl_ctx *ctx,
const struct copy_propagation_state *state, const struct hlsl_ir_load *load,
- unsigned int swizzle, struct hlsl_ir_node *instr)
+ uint32_t swizzle, struct hlsl_ir_node *instr)
{
const unsigned int instr_component_count = hlsl_type_component_count(instr->data_type);
const struct hlsl_deref *deref = &load->src;
@@ -1527,7 +1532,7 @@ static bool copy_propagation_replace_with_single_instr(struct hlsl_ctx *ctx,
struct hlsl_ir_node *new_instr = NULL;
unsigned int time = load->node.index;
unsigned int start, count, i;
- unsigned int ret_swizzle = 0;
+ uint32_t ret_swizzle = 0;
if (!hlsl_component_index_range_from_deref(ctx, deref, &start, &count))
return false;
@@ -1573,7 +1578,7 @@ static bool copy_propagation_replace_with_single_instr(struct hlsl_ctx *ctx,
static bool copy_propagation_replace_with_constant_vector(struct hlsl_ctx *ctx,
const struct copy_propagation_state *state, const struct hlsl_ir_load *load,
- unsigned int swizzle, struct hlsl_ir_node *instr)
+ uint32_t swizzle, struct hlsl_ir_node *instr)
{
const unsigned int instr_component_count = hlsl_type_component_count(instr->data_type);
const struct hlsl_deref *deref = &load->src;
@@ -2239,7 +2244,7 @@ static bool fold_swizzle_chains(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr
if (next_instr->type == HLSL_IR_SWIZZLE)
{
struct hlsl_ir_node *new_swizzle;
- unsigned int combined_swizzle;
+ uint32_t combined_swizzle;
combined_swizzle = hlsl_combine_swizzles(hlsl_ir_swizzle(next_instr)->swizzle,
swizzle->swizzle, instr->data_type->dimx);
@@ -2301,7 +2306,6 @@ static bool normalize_switch_cases(struct hlsl_ctx *ctx, struct hlsl_ir_node *in
struct hlsl_ir_switch_case *c, *def = NULL;
bool missing_terminal_break = false;
struct hlsl_ir_node *node;
- struct hlsl_ir_jump *jump;
struct hlsl_ir_switch *s;
if (instr->type != HLSL_IR_SWITCH)
@@ -2320,10 +2324,7 @@ static bool normalize_switch_cases(struct hlsl_ctx *ctx, struct hlsl_ir_node *in
{
node = LIST_ENTRY(list_tail(&c->body.instrs), struct hlsl_ir_node, entry);
if (node->type == HLSL_IR_JUMP)
- {
- jump = hlsl_ir_jump(node);
- terminal_break = jump->type == HLSL_IR_JUMP_BREAK;
- }
+ terminal_break = (hlsl_ir_jump(node)->type == HLSL_IR_JUMP_BREAK);
}
missing_terminal_break |= !terminal_break;
@@ -2482,6 +2483,38 @@ static bool lower_nonconstant_vector_derefs(struct hlsl_ctx *ctx, struct hlsl_ir
return false;
}
+static bool validate_nonconstant_vector_store_derefs(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, struct hlsl_block *block)
+{
+ struct hlsl_ir_node *idx;
+ struct hlsl_deref *deref;
+ struct hlsl_type *type;
+ unsigned int i;
+
+ if (instr->type != HLSL_IR_STORE)
+ return false;
+
+ deref = &hlsl_ir_store(instr)->lhs;
+ assert(deref->var);
+
+ if (deref->path_len == 0)
+ return false;
+
+ type = deref->var->data_type;
+ for (i = 0; i < deref->path_len - 1; ++i)
+ type = hlsl_get_element_type_from_path_index(ctx, type, deref->path[i].node);
+
+ idx = deref->path[deref->path_len - 1].node;
+
+ if (type->class == HLSL_CLASS_VECTOR && idx->type != HLSL_IR_CONSTANT)
+ {
+ /* We should turn this into an hlsl_error after we implement unrolling, because if we get
+ * here after that, it means that the HLSL is invalid. */
+ hlsl_fixme(ctx, &instr->loc, "Non-constant vector addressing on store. Unrolling may be missing.");
+ }
+
+ return false;
+}
+
/* Lower combined samples and sampler variables to synthesized separated textures and samplers.
* That is, translate SM1-style samples in the source to SM4-style samples in the bytecode. */
static bool lower_combined_samples(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context)
@@ -2857,6 +2890,12 @@ static bool lower_ternary(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, stru
first = expr->operands[1].node;
second = expr->operands[2].node;
+ if (cond->data_type->class > HLSL_CLASS_VECTOR || instr->data_type->class > HLSL_CLASS_VECTOR)
+ {
+ hlsl_fixme(ctx, &instr->loc, "Lower ternary of type other than scalar or vector.\n");
+ return false;
+ }
+
if (ctx->profile->major_version < 4 && ctx->profile->type == VKD3D_SHADER_TYPE_PIXEL)
{
struct hlsl_ir_node *abs, *neg;
@@ -3149,7 +3188,7 @@ static bool lower_int_dot(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, stru
for (i = 0; i < dimx; ++i)
{
- unsigned int s = hlsl_swizzle_from_writemask(1 << i);
+ uint32_t s = hlsl_swizzle_from_writemask(1 << i);
if (!(comps[i] = hlsl_new_swizzle(ctx, s, 1, mult, &instr->loc)))
return false;
@@ -4084,13 +4123,46 @@ static void allocate_const_registers(struct hlsl_ctx *ctx, struct hlsl_ir_functi
LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry)
{
- if (var->is_uniform && var->last_read)
+ unsigned int reg_size = var->data_type->reg_size[HLSL_REGSET_NUMERIC];
+
+ if (!var->is_uniform || !var->last_read || reg_size == 0)
+ continue;
+
+ if (var->reg_reservation.reg_type == 'c')
{
- unsigned int reg_size = var->data_type->reg_size[HLSL_REGSET_NUMERIC];
+ unsigned int reg_idx = var->reg_reservation.reg_index;
+ unsigned int i;
- if (reg_size == 0)
- continue;
+ assert(reg_size % 4 == 0);
+ for (i = 0; i < reg_size / 4; ++i)
+ {
+ if (get_available_writemask(&allocator, 1, UINT_MAX, reg_idx + i) != VKD3DSP_WRITEMASK_ALL)
+ {
+ hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_RESERVATION,
+ "Overlapping register() reservations on 'c%u'.", reg_idx + i);
+ }
+
+ record_allocation(ctx, &allocator, reg_idx + i, VKD3DSP_WRITEMASK_ALL, 1, UINT_MAX);
+ }
+
+ var->regs[HLSL_REGSET_NUMERIC].id = reg_idx;
+ var->regs[HLSL_REGSET_NUMERIC].allocation_size = reg_size / 4;
+ var->regs[HLSL_REGSET_NUMERIC].writemask = VKD3DSP_WRITEMASK_ALL;
+ var->regs[HLSL_REGSET_NUMERIC].allocated = true;
+ TRACE("Allocated reserved %s to %s.\n", var->name,
+ debug_register('c', var->regs[HLSL_REGSET_NUMERIC], var->data_type));
+ }
+ }
+ LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry)
+ {
+ unsigned int reg_size = var->data_type->reg_size[HLSL_REGSET_NUMERIC];
+
+ if (!var->is_uniform || !var->last_read || reg_size == 0)
+ continue;
+
+ if (!var->regs[HLSL_REGSET_NUMERIC].allocated)
+ {
var->regs[HLSL_REGSET_NUMERIC] = allocate_numeric_registers_for_type(ctx, &allocator,
1, UINT_MAX, var->data_type);
TRACE("Allocated %s to %s.\n", var->name,
@@ -4230,45 +4302,52 @@ static const struct hlsl_buffer *get_reserved_buffer(struct hlsl_ctx *ctx, uint3
return NULL;
}
-static void calculate_buffer_offset(struct hlsl_ctx *ctx, struct hlsl_ir_var *var)
+static void calculate_buffer_offset(struct hlsl_ctx *ctx, struct hlsl_ir_var *var, bool register_reservation)
{
unsigned int var_reg_size = var->data_type->reg_size[HLSL_REGSET_NUMERIC];
enum hlsl_type_class var_class = var->data_type->class;
struct hlsl_buffer *buffer = var->buffer;
- if (var->reg_reservation.offset_type == 'c')
+ if (register_reservation)
+ {
+ var->buffer_offset = 4 * var->reg_reservation.reg_index;
+ }
+ else
{
- if (var->reg_reservation.offset_index % 4)
+ if (var->reg_reservation.offset_type == 'c')
{
- if (var_class == HLSL_CLASS_MATRIX)
- {
- hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_RESERVATION,
- "packoffset() reservations with matrix types must be aligned with the beginning of a register.");
- }
- else if (var_class == HLSL_CLASS_ARRAY)
+ if (var->reg_reservation.offset_index % 4)
{
- hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_RESERVATION,
- "packoffset() reservations with array types must be aligned with the beginning of a register.");
- }
- else if (var_class == HLSL_CLASS_STRUCT)
- {
- hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_RESERVATION,
- "packoffset() reservations with struct types must be aligned with the beginning of a register.");
- }
- else if (var_class == HLSL_CLASS_VECTOR)
- {
- unsigned int aligned_offset = hlsl_type_get_sm4_offset(var->data_type, var->reg_reservation.offset_index);
-
- if (var->reg_reservation.offset_index != aligned_offset)
+ if (var_class == HLSL_CLASS_MATRIX)
+ {
hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_RESERVATION,
- "packoffset() reservations with vector types cannot span multiple registers.");
+ "packoffset() reservations with matrix types must be aligned with the beginning of a register.");
+ }
+ else if (var_class == HLSL_CLASS_ARRAY)
+ {
+ hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_RESERVATION,
+ "packoffset() reservations with array types must be aligned with the beginning of a register.");
+ }
+ else if (var_class == HLSL_CLASS_STRUCT)
+ {
+ hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_RESERVATION,
+ "packoffset() reservations with struct types must be aligned with the beginning of a register.");
+ }
+ else if (var_class == HLSL_CLASS_VECTOR)
+ {
+ unsigned int aligned_offset = hlsl_type_get_sm4_offset(var->data_type, var->reg_reservation.offset_index);
+
+ if (var->reg_reservation.offset_index != aligned_offset)
+ hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_RESERVATION,
+ "packoffset() reservations with vector types cannot span multiple registers.");
+ }
}
+ var->buffer_offset = var->reg_reservation.offset_index;
+ }
+ else
+ {
+ var->buffer_offset = hlsl_type_get_sm4_offset(var->data_type, buffer->size);
}
- var->buffer_offset = var->reg_reservation.offset_index;
- }
- else
- {
- var->buffer_offset = hlsl_type_get_sm4_offset(var->data_type, buffer->size);
}
TRACE("Allocated buffer offset %u to %s.\n", var->buffer_offset, var->name);
@@ -4337,6 +4416,11 @@ static void validate_buffer_offsets(struct hlsl_ctx *ctx)
}
}
+static bool var_has_buffer_offset_register_reservation(struct hlsl_ctx *ctx, const struct hlsl_ir_var *var)
+{
+ return var->reg_reservation.reg_type == 'c' && var->buffer == ctx->globals_buffer;
+}
+
static void allocate_buffers(struct hlsl_ctx *ctx)
{
struct hlsl_buffer *buffer;
@@ -4345,13 +4429,29 @@ static void allocate_buffers(struct hlsl_ctx *ctx)
LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry)
{
- if (var->is_uniform && !hlsl_type_is_resource(var->data_type))
- {
- if (var->is_param)
- var->buffer = ctx->params_buffer;
+ if (!var->is_uniform || hlsl_type_is_resource(var->data_type))
+ continue;
- calculate_buffer_offset(ctx, var);
- }
+ if (var->is_param)
+ var->buffer = ctx->params_buffer;
+ }
+
+ LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry)
+ {
+ if (!var->is_uniform || hlsl_type_is_resource(var->data_type))
+ continue;
+
+ if (var_has_buffer_offset_register_reservation(ctx, var))
+ calculate_buffer_offset(ctx, var, true);
+ }
+
+ LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry)
+ {
+ if (!var->is_uniform || hlsl_type_is_resource(var->data_type))
+ continue;
+
+ if (!var_has_buffer_offset_register_reservation(ctx, var))
+ calculate_buffer_offset(ctx, var, false);
}
validate_buffer_offsets(ctx);
@@ -4973,6 +5073,8 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry
lower_ir(ctx, lower_abs, body);
}
+ lower_ir(ctx, validate_nonconstant_vector_store_derefs, body);
+
/* TODO: move forward, remove when no longer needed */
transform_derefs(ctx, replace_deref_path_with_offset, body);
while (hlsl_transform_ir(ctx, hlsl_fold_constant_exprs, body, NULL));
diff --git a/libs/vkd3d/libs/vkd3d-shader/ir.c b/libs/vkd3d/libs/vkd3d-shader/ir.c
index 710811c6761..88634487482 100644
--- a/libs/vkd3d/libs/vkd3d-shader/ir.c
+++ b/libs/vkd3d/libs/vkd3d-shader/ir.c
@@ -18,15 +18,32 @@
#include "vkd3d_shader_private.h"
+bool vsir_program_init(struct vsir_program *program, const struct vkd3d_shader_version *version, unsigned int reserve)
+{
+ program->shader_version = *version;
+ return shader_instruction_array_init(&program->instructions, reserve);
+}
+
+void vsir_program_cleanup(struct vsir_program *program)
+{
+ size_t i;
+
+ for (i = 0; i < program->block_name_count; ++i)
+ vkd3d_free((void *)program->block_names[i]);
+ vkd3d_free(program->block_names);
+ shader_instruction_array_destroy(&program->instructions);
+}
+
static inline bool shader_register_is_phase_instance_id(const struct vkd3d_shader_register *reg)
{
return reg->type == VKD3DSPR_FORKINSTID || reg->type == VKD3DSPR_JOININSTID;
}
-static bool shader_instruction_is_dcl(const struct vkd3d_shader_instruction *ins)
+static bool vsir_instruction_is_dcl(const struct vkd3d_shader_instruction *instruction)
{
- return (VKD3DSIH_DCL <= ins->handler_idx && ins->handler_idx <= VKD3DSIH_DCL_VERTICES_OUT)
- || ins->handler_idx == VKD3DSIH_HS_DECLS;
+ enum vkd3d_shader_opcode handler_idx = instruction->handler_idx;
+ return (VKD3DSIH_DCL <= handler_idx && handler_idx <= VKD3DSIH_DCL_VERTICES_OUT)
+ || handler_idx == VKD3DSIH_HS_DECLS;
}
static void vkd3d_shader_instruction_make_nop(struct vkd3d_shader_instruction *ins)
@@ -36,6 +53,129 @@ static void vkd3d_shader_instruction_make_nop(struct vkd3d_shader_instruction *i
vsir_instruction_init(ins, &location, VKD3DSIH_NOP);
}
+static void remove_dcl_temps(struct vsir_program *program)
+{
+ unsigned int i;
+
+ for (i = 0; i < program->instructions.count; ++i)
+ {
+ struct vkd3d_shader_instruction *ins = &program->instructions.elements[i];
+
+ if (ins->handler_idx == VKD3DSIH_DCL_TEMPS)
+ vkd3d_shader_instruction_make_nop(ins);
+ }
+}
+
+static bool vsir_instruction_init_with_params(struct vsir_program *program,
+ struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_location *location,
+ enum vkd3d_shader_opcode handler_idx, unsigned int dst_count, unsigned int src_count)
+{
+ vsir_instruction_init(ins, location, handler_idx);
+ ins->dst_count = dst_count;
+ ins->src_count = src_count;
+
+ if (!(ins->dst = vsir_program_get_dst_params(program, ins->dst_count)))
+ {
+ ERR("Failed to allocate %u destination parameters.\n", dst_count);
+ return false;
+ }
+
+ if (!(ins->src = vsir_program_get_src_params(program, ins->src_count)))
+ {
+ ERR("Failed to allocate %u source parameters.\n", src_count);
+ return false;
+ }
+
+ memset(ins->dst, 0, sizeof(*ins->dst) * ins->dst_count);
+ memset(ins->src, 0, sizeof(*ins->src) * ins->src_count);
+ return true;
+}
+
+static enum vkd3d_result instruction_array_lower_texkills(struct vkd3d_shader_parser *parser)
+{
+ struct vsir_program *program = &parser->program;
+ struct vkd3d_shader_instruction_array *instructions = &program->instructions;
+ struct vkd3d_shader_instruction *texkill_ins, *ins;
+ unsigned int components_read = 3 + (program->shader_version.major >= 2);
+ unsigned int tmp_idx = ~0u;
+ unsigned int i, k;
+
+ for (i = 0; i < instructions->count; ++i)
+ {
+ texkill_ins = &instructions->elements[i];
+
+ if (texkill_ins->handler_idx != VKD3DSIH_TEXKILL)
+ continue;
+
+ if (!shader_instruction_array_insert_at(instructions, i + 1, components_read + 1))
+ return VKD3D_ERROR_OUT_OF_MEMORY;
+
+ if (tmp_idx == ~0u)
+ tmp_idx = program->temp_count++;
+
+ /* tmp = ins->dst[0] < 0 */
+
+ ins = &instructions->elements[i + 1];
+ if (!vsir_instruction_init_with_params(program, ins, &texkill_ins->location, VKD3DSIH_LTO, 1, 2))
+ return VKD3D_ERROR_OUT_OF_MEMORY;
+
+ vsir_register_init(&ins->dst[0].reg, VKD3DSPR_TEMP, VKD3D_DATA_UINT, 1);
+ ins->dst[0].reg.dimension = VSIR_DIMENSION_VEC4;
+ ins->dst[0].reg.idx[0].offset = tmp_idx;
+ ins->dst[0].write_mask = VKD3DSP_WRITEMASK_ALL;
+
+ ins->src[0].reg = texkill_ins->dst[0].reg;
+ vsir_register_init(&ins->src[1].reg, VKD3DSPR_IMMCONST, VKD3D_DATA_FLOAT, 0);
+ ins->src[1].reg.dimension = VSIR_DIMENSION_VEC4;
+ ins->src[1].reg.u.immconst_f32[0] = 0.0f;
+ ins->src[1].reg.u.immconst_f32[1] = 0.0f;
+ ins->src[1].reg.u.immconst_f32[2] = 0.0f;
+ ins->src[1].reg.u.immconst_f32[3] = 0.0f;
+
+ /* tmp.x = tmp.x || tmp.y */
+ /* tmp.x = tmp.x || tmp.z */
+ /* tmp.x = tmp.x || tmp.w, if sm >= 2.0 */
+
+ for (k = 1; k < components_read; ++k)
+ {
+ ins = &instructions->elements[i + 1 + k];
+ if (!(vsir_instruction_init_with_params(program, ins, &texkill_ins->location, VKD3DSIH_OR, 1, 2)))
+ return VKD3D_ERROR_OUT_OF_MEMORY;
+
+ vsir_register_init(&ins->dst[0].reg, VKD3DSPR_TEMP, VKD3D_DATA_UINT, 1);
+ ins->dst[0].reg.dimension = VSIR_DIMENSION_VEC4;
+ ins->dst[0].reg.idx[0].offset = tmp_idx;
+ ins->dst[0].write_mask = VKD3DSP_WRITEMASK_0;
+
+ vsir_register_init(&ins->src[0].reg, VKD3DSPR_TEMP, VKD3D_DATA_UINT, 1);
+ ins->src[0].reg.dimension = VSIR_DIMENSION_VEC4;
+ ins->src[0].reg.idx[0].offset = tmp_idx;
+ ins->src[0].swizzle = VKD3D_SHADER_SWIZZLE(X, X, X, X);
+ vsir_register_init(&ins->src[1].reg, VKD3DSPR_TEMP, VKD3D_DATA_UINT, 1);
+ ins->src[1].reg.dimension = VSIR_DIMENSION_VEC4;
+ ins->src[1].reg.idx[0].offset = tmp_idx;
+ ins->src[1].swizzle = vkd3d_shader_create_swizzle(k, k, k, k);
+ }
+
+ /* discard_nz tmp.x */
+
+ ins = &instructions->elements[i + 1 + components_read];
+ if (!(vsir_instruction_init_with_params(program, ins, &texkill_ins->location, VKD3DSIH_DISCARD, 0, 1)))
+ return VKD3D_ERROR_OUT_OF_MEMORY;
+ ins->flags = VKD3D_SHADER_CONDITIONAL_OP_NZ;
+
+ vsir_register_init(&ins->src[0].reg, VKD3DSPR_TEMP, VKD3D_DATA_UINT, 1);
+ ins->src[0].reg.dimension = VSIR_DIMENSION_VEC4;
+ ins->src[0].reg.idx[0].offset = tmp_idx;
+ ins->src[0].swizzle = VKD3D_SHADER_SWIZZLE(X, X, X, X);
+
+ /* Make the original instruction no-op */
+ vkd3d_shader_instruction_make_nop(texkill_ins);
+ }
+
+ return VKD3D_OK;
+}
+
static void shader_register_eliminate_phase_addressing(struct vkd3d_shader_register *reg,
unsigned int instance_id)
{
@@ -63,7 +203,7 @@ static void shader_instruction_eliminate_phase_instance_id(struct vkd3d_shader_i
if (shader_register_is_phase_instance_id(reg))
{
vsir_register_init(reg, VKD3DSPR_IMMCONST, reg->data_type, 0);
- reg->u.immconst_uint[0] = instance_id;
+ reg->u.immconst_u32[0] = instance_id;
continue;
}
shader_register_eliminate_phase_addressing(reg, instance_id);
@@ -143,9 +283,6 @@ struct hull_flattener
{
struct vkd3d_shader_instruction_array instructions;
- unsigned int max_temp_count;
- unsigned int temp_dcl_idx;
-
unsigned int instance_count;
unsigned int phase_body_idx;
enum vkd3d_shader_opcode phase;
@@ -203,23 +340,8 @@ static void flattener_eliminate_phase_related_dcls(struct hull_flattener *normal
vkd3d_shader_instruction_make_nop(ins);
return;
}
- else if (ins->handler_idx == VKD3DSIH_DCL_TEMPS && normaliser->phase != VKD3DSIH_INVALID)
- {
- /* Leave only the first temp declaration and set it to the max count later. */
- if (!normaliser->max_temp_count)
- {
- normaliser->max_temp_count = ins->declaration.count;
- normaliser->temp_dcl_idx = index;
- }
- else
- {
- normaliser->max_temp_count = max(normaliser->max_temp_count, ins->declaration.count);
- vkd3d_shader_instruction_make_nop(ins);
- }
- return;
- }
- if (normaliser->phase == VKD3DSIH_INVALID || shader_instruction_is_dcl(ins))
+ if (normaliser->phase == VKD3DSIH_INVALID || vsir_instruction_is_dcl(ins))
return;
if (normaliser->phase_body_idx == ~0u)
@@ -312,6 +434,61 @@ void vsir_register_init(struct vkd3d_shader_register *reg, enum vkd3d_shader_reg
reg->alignment = 0;
}
+void vsir_src_param_init(struct vkd3d_shader_src_param *param, enum vkd3d_shader_register_type reg_type,
+ enum vkd3d_data_type data_type, unsigned int idx_count)
+{
+ vsir_register_init(&param->reg, reg_type, data_type, idx_count);
+ param->swizzle = 0;
+ param->modifiers = VKD3DSPSM_NONE;
+}
+
+void vsir_dst_param_init(struct vkd3d_shader_dst_param *param, enum vkd3d_shader_register_type reg_type,
+ enum vkd3d_data_type data_type, unsigned int idx_count)
+{
+ vsir_register_init(&param->reg, reg_type, data_type, idx_count);
+ param->write_mask = VKD3DSP_WRITEMASK_0;
+ param->modifiers = VKD3DSPDM_NONE;
+ param->shift = 0;
+}
+
+void vsir_src_param_init_label(struct vkd3d_shader_src_param *param, unsigned int label_id)
+{
+ vsir_src_param_init(param, VKD3DSPR_LABEL, VKD3D_DATA_UINT, 1);
+ param->reg.dimension = VSIR_DIMENSION_NONE;
+ param->reg.idx[0].offset = label_id;
+}
+
+static void src_param_init_ssa_bool(struct vkd3d_shader_src_param *src, unsigned int idx)
+{
+ vsir_src_param_init(src, VKD3DSPR_SSA, VKD3D_DATA_BOOL, 1);
+ src->reg.idx[0].offset = idx;
+}
+
+static void dst_param_init_ssa_bool(struct vkd3d_shader_dst_param *dst, unsigned int idx)
+{
+ vsir_dst_param_init(dst, VKD3DSPR_SSA, VKD3D_DATA_BOOL, 1);
+ dst->reg.idx[0].offset = idx;
+}
+
+static void dst_param_init_temp_uint(struct vkd3d_shader_dst_param *dst, unsigned int idx)
+{
+ vsir_dst_param_init(dst, VKD3DSPR_TEMP, VKD3D_DATA_UINT, 1);
+ dst->reg.idx[0].offset = idx;
+ dst->write_mask = VKD3DSP_WRITEMASK_0;
+}
+
+static void src_param_init_temp_uint(struct vkd3d_shader_src_param *src, unsigned int idx)
+{
+ vsir_src_param_init(src, VKD3DSPR_TEMP, VKD3D_DATA_UINT, 1);
+ src->reg.idx[0].offset = idx;
+}
+
+static void src_param_init_const_uint(struct vkd3d_shader_src_param *src, uint32_t value)
+{
+ vsir_src_param_init(src, VKD3DSPR_IMMCONST, VKD3D_DATA_UINT, 0);
+ src->reg.u.immconst_u32[0] = value;
+}
+
void vsir_instruction_init(struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_location *location,
enum vkd3d_shader_opcode handler_idx)
{
@@ -320,6 +497,23 @@ void vsir_instruction_init(struct vkd3d_shader_instruction *ins, const struct vk
ins->handler_idx = handler_idx;
}
+static bool vsir_instruction_init_label(struct vkd3d_shader_instruction *ins,
+ const struct vkd3d_shader_location *location, unsigned int label_id, struct vsir_program *program)
+{
+ struct vkd3d_shader_src_param *src_param;
+
+ if (!(src_param = vsir_program_get_src_params(program, 1)))
+ return false;
+
+ vsir_src_param_init_label(src_param, label_id);
+
+ vsir_instruction_init(ins, location, VKD3DSIH_LABEL);
+ ins->src = src_param;
+ ins->src_count = 1;
+
+ return true;
+}
+
static enum vkd3d_result instruction_array_flatten_hull_shader_phases(struct vkd3d_shader_instruction_array *src_instructions)
{
struct hull_flattener flattener = {*src_instructions};
@@ -339,9 +533,6 @@ static enum vkd3d_result instruction_array_flatten_hull_shader_phases(struct vkd
if (flattener.phase != VKD3DSIH_INVALID)
{
- if (flattener.temp_dcl_idx)
- instructions->elements[flattener.temp_dcl_idx].declaration.count = flattener.max_temp_count;
-
if (!shader_instruction_array_reserve(&flattener.instructions, flattener.instructions.count + 1))
return VKD3D_ERROR_OUT_OF_MEMORY;
vsir_instruction_init(&instructions->elements[instructions->count++], &flattener.last_ret_location, VKD3DSIH_RET);
@@ -463,6 +654,7 @@ static enum vkd3d_result instruction_array_normalise_hull_shader_control_point_i
struct vkd3d_shader_instruction_array *instructions;
struct control_point_normaliser normaliser;
unsigned int input_control_point_count;
+ struct vkd3d_shader_location location;
struct vkd3d_shader_instruction *ins;
enum vkd3d_result ret;
unsigned int i, j;
@@ -488,10 +680,10 @@ static enum vkd3d_result instruction_array_normalise_hull_shader_control_point_i
normaliser.phase = ins->handler_idx;
break;
default:
- if (shader_instruction_is_dcl(ins))
+ if (vsir_instruction_is_dcl(ins))
break;
for (j = 0; j < ins->dst_count; ++j)
- shader_dst_param_normalise_outpointid((struct vkd3d_shader_dst_param *)&ins->dst[j], &normaliser);
+ shader_dst_param_normalise_outpointid(&ins->dst[j], &normaliser);
break;
}
}
@@ -513,8 +705,10 @@ static enum vkd3d_result instruction_array_normalise_hull_shader_control_point_i
return VKD3D_OK;
case VKD3DSIH_HS_FORK_PHASE:
case VKD3DSIH_HS_JOIN_PHASE:
+ /* ins may be relocated if the instruction array expands. */
+ location = ins->location;
ret = control_point_normaliser_emit_hs_input(&normaliser, input_signature,
- input_control_point_count, i, &ins->location);
+ input_control_point_count, i, &location);
*src_instructions = normaliser.instructions;
return ret;
default:
@@ -530,13 +724,11 @@ struct io_normaliser
{
struct vkd3d_shader_instruction_array instructions;
enum vkd3d_shader_type shader_type;
+ uint8_t major;
struct shader_signature *input_signature;
struct shader_signature *output_signature;
struct shader_signature *patch_constant_signature;
- unsigned int max_temp_count;
- unsigned int temp_dcl_idx;
-
unsigned int instance_count;
unsigned int phase_body_idx;
enum vkd3d_shader_opcode phase;
@@ -567,7 +759,7 @@ static bool io_normaliser_is_in_control_point_phase(const struct io_normaliser *
static unsigned int shader_signature_find_element_for_reg(const struct shader_signature *signature,
unsigned int reg_idx, unsigned int write_mask)
{
- unsigned int i;
+ unsigned int i, base_write_mask;
for (i = 0; i < signature->element_count; ++i)
{
@@ -579,7 +771,14 @@ static unsigned int shader_signature_find_element_for_reg(const struct shader_si
}
}
- /* Validated in the TPF reader. */
+ /* Validated in the TPF reader, but failure in signature_element_range_expand_mask()
+ * can land us here on an unmatched vector mask. */
+ FIXME("Failed to find signature element for register index %u, mask %#x; using scalar mask.\n",
+ reg_idx, write_mask);
+ base_write_mask = 1u << vsir_write_mask_get_component_idx(write_mask);
+ if (base_write_mask != write_mask)
+ return shader_signature_find_element_for_reg(signature, reg_idx, base_write_mask);
+
vkd3d_unreachable();
}
@@ -590,19 +789,19 @@ struct signature_element *vsir_signature_find_element_for_reg(const struct shade
}
static unsigned int range_map_get_register_count(uint8_t range_map[][VKD3D_VEC4_SIZE],
- unsigned int register_idx, unsigned int write_mask)
+ unsigned int register_idx, uint32_t write_mask)
{
- return range_map[register_idx][vkd3d_write_mask_get_component_idx(write_mask)];
+ return range_map[register_idx][vsir_write_mask_get_component_idx(write_mask)];
}
static void range_map_set_register_range(uint8_t range_map[][VKD3D_VEC4_SIZE], unsigned int register_idx,
- unsigned int register_count, unsigned int write_mask, bool is_dcl_indexrange)
+ unsigned int register_count, uint32_t write_mask, bool is_dcl_indexrange)
{
unsigned int i, j, r, c, component_idx, component_count;
assert(write_mask <= VKD3DSP_WRITEMASK_ALL);
- component_idx = vkd3d_write_mask_get_component_idx(write_mask);
- component_count = vkd3d_write_mask_component_count(write_mask);
+ component_idx = vsir_write_mask_get_component_idx(write_mask);
+ component_count = vsir_write_mask_component_count(write_mask);
assert(register_idx < MAX_REG_OUTPUT && MAX_REG_OUTPUT - register_idx >= register_count);
@@ -746,12 +945,58 @@ static int signature_element_index_compare(const void *a, const void *b)
return vkd3d_u32_compare(e->sort_index, f->sort_index);
}
+static unsigned int signature_element_range_expand_mask(struct signature_element *e, unsigned int register_count,
+ uint8_t range_map[][VKD3D_VEC4_SIZE])
+{
+ unsigned int i, j, component_idx, component_count, merged_write_mask = e->mask;
+
+ /* dcl_indexrange instructions can declare a subset of the full mask, and the masks of
+ * the elements within the range may differ. TPF's handling of arrayed inputs with
+ * dcl_indexrange is really just a hack. Here we create a mask which covers all element
+ * masks, and check for collisions with other ranges. */
+
+ for (i = 1; i < register_count; ++i)
+ merged_write_mask |= e[i].mask;
+
+ if (merged_write_mask == e->mask)
+ return merged_write_mask;
+
+ /* Reaching this point is very rare to begin with, and collisions are even rarer or
+ * impossible. If the latter shows up, the fallback in shader_signature_find_element_for_reg()
+ * may be sufficient. */
+
+ component_idx = vsir_write_mask_get_component_idx(e->mask);
+ component_count = vsir_write_mask_component_count(e->mask);
+
+ for (i = e->register_index; i < e->register_index + register_count; ++i)
+ {
+ for (j = 0; j < component_idx; ++j)
+ if (range_map[i][j])
+ break;
+ for (j = component_idx + component_count; j < VKD3D_VEC4_SIZE; ++j)
+ if (range_map[i][j])
+ break;
+ }
+
+ if (i == register_count)
+ {
+ WARN("Expanding mask %#x to %#x for %s, base reg %u, count %u.\n", e->mask, merged_write_mask,
+ e->semantic_name, e->register_index, register_count);
+ return merged_write_mask;
+ }
+
+ WARN("Cannot expand mask %#x to %#x for %s, base reg %u, count %u.\n", e->mask, merged_write_mask,
+ e->semantic_name, e->register_index, register_count);
+ return e->mask;
+}
+
static bool shader_signature_merge(struct shader_signature *s, uint8_t range_map[][VKD3D_VEC4_SIZE],
bool is_patch_constant)
{
unsigned int i, j, element_count, new_count, register_count;
struct signature_element *elements;
struct signature_element *e, *f;
+ bool used;
element_count = s->element_count;
if (!(elements = vkd3d_malloc(element_count * sizeof(*elements))))
@@ -772,14 +1017,15 @@ static bool shader_signature_merge(struct shader_signature *s, uint8_t range_map
if (range_map_get_register_count(range_map, e->register_index, e->mask) > 1)
continue;
+ used = e->used_mask;
+
for (; j < element_count; ++j)
{
f = &elements[j];
/* Merge different components of the same register unless sysvals are different,
- * interpolation modes are different, or it will be relative-addressed. */
+ * or it will be relative-addressed. */
if (f->register_index != e->register_index || f->sysval_semantic != e->sysval_semantic
- || f->interpolation_mode != e->interpolation_mode
|| range_map_get_register_count(range_map, f->register_index, f->mask) > 1)
break;
@@ -790,6 +1036,16 @@ static bool shader_signature_merge(struct shader_signature *s, uint8_t range_map
e->mask |= f->mask;
e->used_mask |= f->used_mask;
e->semantic_index = min(e->semantic_index, f->semantic_index);
+
+ /* The first element may have no interpolation mode if it is unused. Elements which
+ * actually have different interpolation modes are assigned different registers. */
+ if (f->used_mask && !used)
+ {
+ if (e->interpolation_mode && e->interpolation_mode != f->interpolation_mode)
+ FIXME("Mismatching interpolation modes %u and %u.\n", e->interpolation_mode, f->interpolation_mode);
+ else
+ e->interpolation_mode = f->interpolation_mode;
+ }
}
}
element_count = new_count;
@@ -816,6 +1072,7 @@ static bool shader_signature_merge(struct shader_signature *s, uint8_t range_map
{
TRACE("Merging %s, base reg %u, count %u.\n", e->semantic_name, e->register_index, register_count);
e->register_count = register_count;
+ e->mask = signature_element_range_expand_mask(e, register_count, range_map);
}
}
element_count = new_count;
@@ -840,6 +1097,13 @@ static unsigned int shader_register_normalise_arrayed_addressing(struct vkd3d_sh
reg->idx[id_idx + 1].rel_addr = NULL;
reg->idx[id_idx + 1].offset = reg->idx[id_idx].offset;
reg->idx[id_idx].offset -= register_index;
+ if (id_idx)
+ {
+ /* idx[id_idx] now contains the array index, which must be moved below the control point id. */
+ struct vkd3d_shader_register_index tmp = reg->idx[id_idx];
+ reg->idx[id_idx] = reg->idx[id_idx - 1];
+ reg->idx[id_idx - 1] = tmp;
+ }
++id_idx;
}
/* Otherwise we have no address for the arrayed register, so insert one. This happens e.g. where
@@ -864,39 +1128,70 @@ static bool shader_dst_param_io_normalise(struct vkd3d_shader_dst_param *dst_par
const struct shader_signature *signature;
const struct signature_element *e;
- if ((reg->type == VKD3DSPR_OUTPUT && io_normaliser_is_in_fork_or_join_phase(normaliser))
- || reg->type == VKD3DSPR_PATCHCONST)
- {
- signature = normaliser->patch_constant_signature;
- /* Convert patch constant outputs to the patch constant register type to avoid the need
- * to convert compiler symbols when accessed as inputs in a later stage. */
- reg->type = VKD3DSPR_PATCHCONST;
- dcl_params = normaliser->pc_dcl_params;
- }
- else if (reg->type == VKD3DSPR_OUTPUT || dst_param->reg.type == VKD3DSPR_COLOROUT)
- {
- signature = normaliser->output_signature;
- reg->type = VKD3DSPR_OUTPUT;
- dcl_params = normaliser->output_dcl_params;
- }
- else if (dst_param->reg.type == VKD3DSPR_INCONTROLPOINT || dst_param->reg.type == VKD3DSPR_INPUT)
- {
- signature = normaliser->input_signature;
- reg->type = VKD3DSPR_INPUT;
- dcl_params = normaliser->input_dcl_params;
- }
- else
+ switch (reg->type)
{
- return true;
+ case VKD3DSPR_OUTPUT:
+ reg_idx = reg->idx[reg->idx_count - 1].offset;
+ if (io_normaliser_is_in_fork_or_join_phase(normaliser))
+ {
+ signature = normaliser->patch_constant_signature;
+ /* Convert patch constant outputs to the patch constant register type to avoid the need
+ * to convert compiler symbols when accessed as inputs in a later stage. */
+ reg->type = VKD3DSPR_PATCHCONST;
+ dcl_params = normaliser->pc_dcl_params;
+ }
+ else
+ {
+ signature = normaliser->output_signature;
+ dcl_params = normaliser->output_dcl_params;
+ }
+ break;
+
+ case VKD3DSPR_PATCHCONST:
+ reg_idx = reg->idx[reg->idx_count - 1].offset;
+ signature = normaliser->patch_constant_signature;
+ dcl_params = normaliser->pc_dcl_params;
+ break;
+
+ case VKD3DSPR_COLOROUT:
+ reg_idx = reg->idx[0].offset;
+ signature = normaliser->output_signature;
+ reg->type = VKD3DSPR_OUTPUT;
+ dcl_params = normaliser->output_dcl_params;
+ break;
+
+ case VKD3DSPR_INCONTROLPOINT:
+ case VKD3DSPR_INPUT:
+ reg_idx = reg->idx[reg->idx_count - 1].offset;
+ signature = normaliser->input_signature;
+ reg->type = VKD3DSPR_INPUT;
+ dcl_params = normaliser->input_dcl_params;
+ break;
+
+ case VKD3DSPR_ATTROUT:
+ reg_idx = SM1_COLOR_REGISTER_OFFSET + reg->idx[0].offset;
+ signature = normaliser->output_signature;
+ reg->type = VKD3DSPR_OUTPUT;
+ dcl_params = normaliser->output_dcl_params;
+ break;
+
+ case VKD3DSPR_RASTOUT:
+ reg_idx = SM1_RASTOUT_REGISTER_OFFSET + reg->idx[0].offset;
+ signature = normaliser->output_signature;
+ reg->type = VKD3DSPR_OUTPUT;
+ dcl_params = normaliser->output_dcl_params;
+ break;
+
+ default:
+ return true;
}
id_idx = reg->idx_count - 1;
- reg_idx = reg->idx[id_idx].offset;
write_mask = dst_param->write_mask;
element_idx = shader_signature_find_element_for_reg(signature, reg_idx, write_mask);
e = &signature->elements[element_idx];
- dst_param->write_mask >>= vkd3d_write_mask_get_component_idx(e->mask);
+ dst_param->write_mask >>= vsir_write_mask_get_component_idx(e->mask);
if (is_io_dcl)
{
/* Validated in the TPF reader. */
@@ -979,27 +1274,43 @@ static void shader_src_param_io_normalise(struct vkd3d_shader_src_param *src_par
switch (reg->type)
{
case VKD3DSPR_PATCHCONST:
+ reg_idx = reg->idx[reg->idx_count - 1].offset;
signature = normaliser->patch_constant_signature;
break;
+
case VKD3DSPR_INCONTROLPOINT:
reg->type = VKD3DSPR_INPUT;
/* fall through */
case VKD3DSPR_INPUT:
+ if (normaliser->major < 3 && normaliser->shader_type == VKD3D_SHADER_TYPE_PIXEL)
+ reg_idx = SM1_COLOR_REGISTER_OFFSET + reg->idx[0].offset;
+ else
+ reg_idx = reg->idx[reg->idx_count - 1].offset;
signature = normaliser->input_signature;
break;
+
case VKD3DSPR_OUTCONTROLPOINT:
reg->type = VKD3DSPR_OUTPUT;
/* fall through */
case VKD3DSPR_OUTPUT:
+ reg_idx = reg->idx[reg->idx_count - 1].offset;
signature = normaliser->output_signature;
break;
+
+ case VKD3DSPR_TEXTURE:
+ if (normaliser->shader_type != VKD3D_SHADER_TYPE_PIXEL)
+ return;
+ reg->type = VKD3DSPR_INPUT;
+ reg_idx = reg->idx[0].offset;
+ signature = normaliser->input_signature;
+ break;
+
default:
return;
}
id_idx = reg->idx_count - 1;
- reg_idx = reg->idx[id_idx].offset;
- write_mask = VKD3DSP_WRITEMASK_0 << vkd3d_swizzle_get_component(src_param->swizzle, 0);
+ write_mask = VKD3DSP_WRITEMASK_0 << vsir_swizzle_get_component(src_param->swizzle, 0);
element_idx = shader_signature_find_element_for_reg(signature, reg_idx, write_mask);
e = &signature->elements[element_idx];
@@ -1008,10 +1319,10 @@ static void shader_src_param_io_normalise(struct vkd3d_shader_src_param *src_par
reg->idx[id_idx].offset = element_idx;
reg->idx_count = id_idx + 1;
- if ((component_idx = vkd3d_write_mask_get_component_idx(e->mask)))
+ if ((component_idx = vsir_write_mask_get_component_idx(e->mask)))
{
for (i = 0; i < VKD3D_VEC4_SIZE; ++i)
- if (vkd3d_swizzle_get_component(src_param->swizzle, i))
+ if (vsir_swizzle_get_component(src_param->swizzle, i))
src_param->swizzle -= component_idx << VKD3D_SHADER_SWIZZLE_SHIFT(i);
}
}
@@ -1062,32 +1373,34 @@ static void shader_instruction_normalise_io_params(struct vkd3d_shader_instructi
memset(normaliser->pc_dcl_params, 0, sizeof(normaliser->pc_dcl_params));
break;
default:
- if (shader_instruction_is_dcl(ins))
+ if (vsir_instruction_is_dcl(ins))
break;
for (i = 0; i < ins->dst_count; ++i)
- shader_dst_param_io_normalise((struct vkd3d_shader_dst_param *)&ins->dst[i], false, normaliser);
+ shader_dst_param_io_normalise(&ins->dst[i], false, normaliser);
for (i = 0; i < ins->src_count; ++i)
- shader_src_param_io_normalise((struct vkd3d_shader_src_param *)&ins->src[i], normaliser);
+ shader_src_param_io_normalise(&ins->src[i], normaliser);
break;
}
}
static enum vkd3d_result shader_normalise_io_registers(struct vkd3d_shader_parser *parser)
{
- struct io_normaliser normaliser = {parser->instructions};
+ struct io_normaliser normaliser = {parser->program.instructions};
+ struct vsir_program *program = &parser->program;
struct vkd3d_shader_instruction *ins;
bool has_control_point_phase;
unsigned int i, j;
normaliser.phase = VKD3DSIH_INVALID;
- normaliser.shader_type = parser->shader_version.type;
+ normaliser.shader_type = program->shader_version.type;
+ normaliser.major = program->shader_version.major;
normaliser.input_signature = &parser->shader_desc.input_signature;
normaliser.output_signature = &parser->shader_desc.output_signature;
normaliser.patch_constant_signature = &parser->shader_desc.patch_constant_signature;
- for (i = 0, has_control_point_phase = false; i < parser->instructions.count; ++i)
+ for (i = 0, has_control_point_phase = false; i < program->instructions.count; ++i)
{
- ins = &parser->instructions.elements[i];
+ ins = &program->instructions.elements[i];
switch (ins->handler_idx)
{
@@ -1130,7 +1443,7 @@ static enum vkd3d_result shader_normalise_io_registers(struct vkd3d_shader_parse
|| !shader_signature_merge(&parser->shader_desc.output_signature, normaliser.output_range_map, false)
|| !shader_signature_merge(&parser->shader_desc.patch_constant_signature, normaliser.pc_range_map, true))
{
- parser->instructions = normaliser.instructions;
+ program->instructions = normaliser.instructions;
return VKD3D_ERROR_OUT_OF_MEMORY;
}
@@ -1138,8 +1451,8 @@ static enum vkd3d_result shader_normalise_io_registers(struct vkd3d_shader_parse
for (i = 0; i < normaliser.instructions.count; ++i)
shader_instruction_normalise_io_params(&normaliser.instructions.elements[i], &normaliser);
- parser->instructions = normaliser.instructions;
- parser->shader_desc.use_vocp = normaliser.use_vocp;
+ program->instructions = normaliser.instructions;
+ program->use_vocp = normaliser.use_vocp;
return VKD3D_OK;
}
@@ -1152,7 +1465,6 @@ struct flat_constant_def
struct flat_constants_normaliser
{
- struct vkd3d_shader_parser *parser;
struct flat_constant_def *defs;
size_t def_count, defs_capacity;
};
@@ -1215,7 +1527,7 @@ static void shader_register_normalise_flat_constants(struct vkd3d_shader_src_par
param->reg.idx_count = 0;
param->reg.dimension = VSIR_DIMENSION_VEC4;
for (j = 0; j < 4; ++j)
- param->reg.u.immconst_uint[j] = normaliser->defs[i].value[j];
+ param->reg.u.immconst_u32[j] = normaliser->defs[i].value[j];
return;
}
}
@@ -1227,14 +1539,14 @@ static void shader_register_normalise_flat_constants(struct vkd3d_shader_src_par
param->reg.idx_count = 3;
}
-static enum vkd3d_result instruction_array_normalise_flat_constants(struct vkd3d_shader_parser *parser)
+static enum vkd3d_result instruction_array_normalise_flat_constants(struct vsir_program *program)
{
- struct flat_constants_normaliser normaliser = {.parser = parser};
+ struct flat_constants_normaliser normaliser = {0};
unsigned int i, j;
- for (i = 0; i < parser->instructions.count; ++i)
+ for (i = 0; i < program->instructions.count; ++i)
{
- struct vkd3d_shader_instruction *ins = &parser->instructions.elements[i];
+ struct vkd3d_shader_instruction *ins = &program->instructions.elements[i];
if (ins->handler_idx == VKD3DSIH_DEF || ins->handler_idx == VKD3DSIH_DEFI || ins->handler_idx == VKD3DSIH_DEFB)
{
@@ -1251,14 +1563,14 @@ static enum vkd3d_result instruction_array_normalise_flat_constants(struct vkd3d
get_flat_constant_register_type((struct vkd3d_shader_register *)&ins->dst[0].reg, &def->set, &def->index);
for (j = 0; j < 4; ++j)
- def->value[j] = ins->src[0].reg.u.immconst_uint[j];
+ def->value[j] = ins->src[0].reg.u.immconst_u32[j];
vkd3d_shader_instruction_make_nop(ins);
}
else
{
for (j = 0; j < ins->src_count; ++j)
- shader_register_normalise_flat_constants((struct vkd3d_shader_src_param *)&ins->src[j], &normaliser);
+ shader_register_normalise_flat_constants(&ins->src[j], &normaliser);
}
}
@@ -1266,14 +1578,14 @@ static enum vkd3d_result instruction_array_normalise_flat_constants(struct vkd3d
return VKD3D_OK;
}
-static void remove_dead_code(struct vkd3d_shader_parser *parser)
+static void remove_dead_code(struct vsir_program *program)
{
size_t i, depth = 0;
bool dead = false;
- for (i = 0; i < parser->instructions.count; ++i)
+ for (i = 0; i < program->instructions.count; ++i)
{
- struct vkd3d_shader_instruction *ins = &parser->instructions.elements[i];
+ struct vkd3d_shader_instruction *ins = &program->instructions.elements[i];
switch (ins->handler_idx)
{
@@ -1360,15 +1672,15 @@ static enum vkd3d_result normalise_combined_samplers(struct vkd3d_shader_parser
{
unsigned int i;
- for (i = 0; i < parser->instructions.count; ++i)
+ for (i = 0; i < parser->program.instructions.count; ++i)
{
- struct vkd3d_shader_instruction *ins = &parser->instructions.elements[i];
+ struct vkd3d_shader_instruction *ins = &parser->program.instructions.elements[i];
struct vkd3d_shader_src_param *srcs;
switch (ins->handler_idx)
{
case VKD3DSIH_TEX:
- if (!(srcs = shader_src_param_allocator_get(&parser->instructions.src_params, 3)))
+ if (!(srcs = shader_src_param_allocator_get(&parser->program.instructions.src_params, 3)))
return VKD3D_ERROR_OUT_OF_MEMORY;
memset(srcs, 0, sizeof(*srcs) * 3);
@@ -1424,95 +1736,1420 @@ static enum vkd3d_result normalise_combined_samplers(struct vkd3d_shader_parser
return VKD3D_OK;
}
-enum vkd3d_result vkd3d_shader_normalise(struct vkd3d_shader_parser *parser,
- const struct vkd3d_shader_compile_info *compile_info)
+struct cf_flattener_if_info
{
- struct vkd3d_shader_instruction_array *instructions = &parser->instructions;
- enum vkd3d_result result = VKD3D_OK;
-
- if (parser->shader_desc.is_dxil)
- return result;
+ struct vkd3d_shader_src_param *false_param;
+ unsigned int id;
+ uint32_t merge_block_id;
+ unsigned int else_block_id;
+};
- if (parser->shader_version.type != VKD3D_SHADER_TYPE_PIXEL
- && (result = remap_output_signature(parser, compile_info)) < 0)
- return result;
+struct cf_flattener_loop_info
+{
+ unsigned int header_block_id;
+ unsigned int continue_block_id;
+ uint32_t merge_block_id;
+};
- if (parser->shader_version.type == VKD3D_SHADER_TYPE_HULL
- && (result = instruction_array_flatten_hull_shader_phases(instructions)) >= 0)
- {
- result = instruction_array_normalise_hull_shader_control_point_io(instructions,
- &parser->shader_desc.input_signature);
- }
- if (result >= 0)
- result = shader_normalise_io_registers(parser);
+struct cf_flattener_switch_case
+{
+ unsigned int value;
+ unsigned int block_id;
+};
- if (result >= 0)
- result = instruction_array_normalise_flat_constants(parser);
+struct cf_flattener_switch_info
+{
+ size_t ins_location;
+ const struct vkd3d_shader_src_param *condition;
+ unsigned int id;
+ unsigned int merge_block_id;
+ unsigned int default_block_id;
+ struct cf_flattener_switch_case *cases;
+ size_t cases_size;
+ unsigned int cases_count;
+};
- if (result >= 0)
- remove_dead_code(parser);
+struct cf_flattener_info
+{
+ union
+ {
+ struct cf_flattener_if_info if_;
+ struct cf_flattener_loop_info loop;
+ struct cf_flattener_switch_info switch_;
+ } u;
- if (result >= 0)
- result = normalise_combined_samplers(parser);
+ enum
+ {
+ VKD3D_BLOCK_IF,
+ VKD3D_BLOCK_LOOP,
+ VKD3D_BLOCK_SWITCH,
+ } current_block;
+ bool inside_block;
+};
- if (result >= 0 && TRACE_ON())
- vkd3d_shader_trace(instructions, &parser->shader_version);
+struct cf_flattener
+{
+ struct vkd3d_shader_parser *parser;
- if (result >= 0 && !parser->failed)
- vsir_validate(parser);
+ struct vkd3d_shader_location location;
+ bool allocation_failed;
- if (result >= 0 && parser->failed)
- result = VKD3D_ERROR_INVALID_SHADER;
+ struct vkd3d_shader_instruction *instructions;
+ size_t instruction_capacity;
+ size_t instruction_count;
- return result;
-}
+ unsigned int block_id;
+ const char **block_names;
+ size_t block_name_capacity;
+ size_t block_name_count;
-struct validation_context
-{
- struct vkd3d_shader_parser *parser;
- size_t instruction_idx;
- bool dcl_temps_found;
- unsigned int temp_count;
- enum vkd3d_shader_opcode phase;
+ unsigned int branch_id;
+ unsigned int loop_id;
+ unsigned int switch_id;
- enum vkd3d_shader_opcode *blocks;
- size_t depth;
- size_t blocks_capacity;
+ unsigned int control_flow_depth;
+ struct cf_flattener_info *control_flow_info;
+ size_t control_flow_info_size;
};
-static void VKD3D_PRINTF_FUNC(3, 4) validator_error(struct validation_context *ctx,
- enum vkd3d_shader_error error, const char *format, ...)
+static struct vkd3d_shader_instruction *cf_flattener_require_space(struct cf_flattener *flattener, size_t count)
{
- struct vkd3d_string_buffer buf;
- va_list args;
+ if (!vkd3d_array_reserve((void **)&flattener->instructions, &flattener->instruction_capacity,
+ flattener->instruction_count + count, sizeof(*flattener->instructions)))
+ {
+ ERR("Failed to allocate instructions.\n");
+ flattener->allocation_failed = true;
+ return NULL;
+ }
+ return &flattener->instructions[flattener->instruction_count];
+}
- vkd3d_string_buffer_init(&buf);
+static bool cf_flattener_copy_instruction(struct cf_flattener *flattener,
+ const struct vkd3d_shader_instruction *instruction)
+{
+ struct vkd3d_shader_instruction *dst_ins;
- va_start(args, format);
- vkd3d_string_buffer_vprintf(&buf, format, args);
- va_end(args);
+ if (instruction->handler_idx == VKD3DSIH_NOP)
+ return true;
- vkd3d_shader_parser_error(ctx->parser, error, "instruction %zu: %s", ctx->instruction_idx + 1, buf.buffer);
- ERR("VSIR validation error: instruction %zu: %s\n", ctx->instruction_idx + 1, buf.buffer);
+ if (!(dst_ins = cf_flattener_require_space(flattener, 1)))
+ return false;
- vkd3d_string_buffer_cleanup(&buf);
+ *dst_ins = *instruction;
+ ++flattener->instruction_count;
+ return true;
}
-static void vsir_validate_src_param(struct validation_context *ctx,
- const struct vkd3d_shader_src_param *src);
-
-static void vsir_validate_register(struct validation_context *ctx,
- const struct vkd3d_shader_register *reg)
+static unsigned int cf_flattener_alloc_block_id(struct cf_flattener *flattener)
{
- unsigned int i, temp_count = ctx->temp_count;
+ return ++flattener->block_id;
+}
- /* SM1-3 shaders do not include a DCL_TEMPS instruction. */
- if (ctx->parser->shader_version.major <= 3)
- temp_count = ctx->parser->shader_desc.temp_count;
+static struct vkd3d_shader_src_param *instruction_src_params_alloc(struct vkd3d_shader_instruction *ins,
+ unsigned int count, struct cf_flattener *flattener)
+{
+ struct vkd3d_shader_src_param *params;
- if (reg->type >= VKD3DSPR_COUNT)
- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, "Invalid register type %#x.",
- reg->type);
+ if (!(params = vsir_program_get_src_params(&flattener->parser->program, count)))
+ {
+ flattener->allocation_failed = true;
+ return NULL;
+ }
+ ins->src = params;
+ ins->src_count = count;
+ return params;
+}
+
+static void cf_flattener_emit_label(struct cf_flattener *flattener, unsigned int label_id)
+{
+ struct vkd3d_shader_instruction *ins;
+
+ if (!(ins = cf_flattener_require_space(flattener, 1)))
+ return;
+ if (vsir_instruction_init_label(ins, &flattener->location, label_id, &flattener->parser->program))
+ ++flattener->instruction_count;
+ else
+ flattener->allocation_failed = true;
+}
+
+/* For conditional branches, this returns the false target branch parameter. */
+static struct vkd3d_shader_src_param *cf_flattener_emit_branch(struct cf_flattener *flattener,
+ unsigned int merge_block_id, unsigned int continue_block_id,
+ const struct vkd3d_shader_src_param *condition, unsigned int true_id, unsigned int false_id,
+ unsigned int flags)
+{
+ struct vkd3d_shader_src_param *src_params, *false_branch_param;
+ struct vkd3d_shader_instruction *ins;
+
+ if (!(ins = cf_flattener_require_space(flattener, 1)))
+ return NULL;
+ vsir_instruction_init(ins, &flattener->location, VKD3DSIH_BRANCH);
+
+ if (condition)
+ {
+ if (!(src_params = instruction_src_params_alloc(ins, 4 + !!continue_block_id, flattener)))
+ return NULL;
+ src_params[0] = *condition;
+ if (flags == VKD3D_SHADER_CONDITIONAL_OP_Z)
+ {
+ vsir_src_param_init_label(&src_params[1], false_id);
+ vsir_src_param_init_label(&src_params[2], true_id);
+ false_branch_param = &src_params[1];
+ }
+ else
+ {
+ vsir_src_param_init_label(&src_params[1], true_id);
+ vsir_src_param_init_label(&src_params[2], false_id);
+ false_branch_param = &src_params[2];
+ }
+ vsir_src_param_init_label(&src_params[3], merge_block_id);
+ if (continue_block_id)
+ vsir_src_param_init_label(&src_params[4], continue_block_id);
+ }
+ else
+ {
+ if (!(src_params = instruction_src_params_alloc(ins, merge_block_id ? 3 : 1, flattener)))
+ return NULL;
+ vsir_src_param_init_label(&src_params[0], true_id);
+ if (merge_block_id)
+ {
+ /* An unconditional branch may only have merge information for a loop, which
+ * must have both a merge block and continue block. */
+ vsir_src_param_init_label(&src_params[1], merge_block_id);
+ vsir_src_param_init_label(&src_params[2], continue_block_id);
+ }
+ false_branch_param = NULL;
+ }
+
+ ++flattener->instruction_count;
+
+ return false_branch_param;
+}
+
+static void cf_flattener_emit_conditional_branch_and_merge(struct cf_flattener *flattener,
+ const struct vkd3d_shader_src_param *condition, unsigned int true_id, unsigned int flags)
+{
+ unsigned int merge_block_id;
+
+ merge_block_id = cf_flattener_alloc_block_id(flattener);
+ cf_flattener_emit_branch(flattener, merge_block_id, 0, condition, true_id, merge_block_id, flags);
+ cf_flattener_emit_label(flattener, merge_block_id);
+}
+
+static void cf_flattener_emit_unconditional_branch(struct cf_flattener *flattener, unsigned int target_block_id)
+{
+ cf_flattener_emit_branch(flattener, 0, 0, NULL, target_block_id, 0, 0);
+}
+
+static struct cf_flattener_info *cf_flattener_push_control_flow_level(struct cf_flattener *flattener)
+{
+ if (!vkd3d_array_reserve((void **)&flattener->control_flow_info, &flattener->control_flow_info_size,
+ flattener->control_flow_depth + 1, sizeof(*flattener->control_flow_info)))
+ {
+ ERR("Failed to allocate control flow info structure.\n");
+ flattener->allocation_failed = true;
+ return NULL;
+ }
+
+ return &flattener->control_flow_info[flattener->control_flow_depth++];
+}
+
+static void cf_flattener_pop_control_flow_level(struct cf_flattener *flattener)
+{
+ struct cf_flattener_info *cf_info;
+
+ cf_info = &flattener->control_flow_info[--flattener->control_flow_depth];
+ memset(cf_info, 0, sizeof(*cf_info));
+}
+
+static struct cf_flattener_info *cf_flattener_find_innermost_loop(struct cf_flattener *flattener)
+{
+ int depth;
+
+ for (depth = flattener->control_flow_depth - 1; depth >= 0; --depth)
+ {
+ if (flattener->control_flow_info[depth].current_block == VKD3D_BLOCK_LOOP)
+ return &flattener->control_flow_info[depth];
+ }
+
+ return NULL;
+}
+
+static struct cf_flattener_info *cf_flattener_find_innermost_breakable_cf_construct(struct cf_flattener *flattener)
+{
+ int depth;
+
+ for (depth = flattener->control_flow_depth - 1; depth >= 0; --depth)
+ {
+ if (flattener->control_flow_info[depth].current_block == VKD3D_BLOCK_LOOP
+ || flattener->control_flow_info[depth].current_block == VKD3D_BLOCK_SWITCH)
+ return &flattener->control_flow_info[depth];
+ }
+
+ return NULL;
+}
+
+static void VKD3D_PRINTF_FUNC(3, 4) cf_flattener_create_block_name(struct cf_flattener *flattener,
+ unsigned int block_id, const char *fmt, ...)
+{
+ struct vkd3d_string_buffer buffer;
+ size_t block_name_count;
+ va_list args;
+
+ --block_id;
+
+ block_name_count = max(flattener->block_name_count, block_id + 1);
+ if (!vkd3d_array_reserve((void **)&flattener->block_names, &flattener->block_name_capacity,
+ block_name_count, sizeof(*flattener->block_names)))
+ return;
+ memset(&flattener->block_names[flattener->block_name_count], 0,
+ (block_name_count - flattener->block_name_count) * sizeof(*flattener->block_names));
+ flattener->block_name_count = block_name_count;
+
+ vkd3d_string_buffer_init(&buffer);
+ va_start(args, fmt);
+ vkd3d_string_buffer_vprintf(&buffer, fmt, args);
+ va_end(args);
+
+ flattener->block_names[block_id] = buffer.buffer;
+}
+
+static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flattener *flattener)
+{
+ bool main_block_open, is_hull_shader, after_declarations_section;
+ struct vkd3d_shader_parser *parser = flattener->parser;
+ struct vkd3d_shader_instruction_array *instructions;
+ struct vsir_program *program = &parser->program;
+ struct vkd3d_shader_instruction *dst_ins;
+ size_t i;
+
+ instructions = &program->instructions;
+ is_hull_shader = program->shader_version.type == VKD3D_SHADER_TYPE_HULL;
+ main_block_open = !is_hull_shader;
+ after_declarations_section = is_hull_shader;
+
+ if (!cf_flattener_require_space(flattener, instructions->count + 1))
+ return VKD3D_ERROR_OUT_OF_MEMORY;
+
+ for (i = 0; i < instructions->count; ++i)
+ {
+ unsigned int loop_header_block_id, loop_body_block_id, continue_block_id, merge_block_id, true_block_id;
+ const struct vkd3d_shader_instruction *instruction = &instructions->elements[i];
+ const struct vkd3d_shader_src_param *src = instruction->src;
+ struct cf_flattener_info *cf_info;
+
+ flattener->location = instruction->location;
+
+ /* Declarations should occur before the first code block, which in hull shaders is marked by the first
+ * phase instruction, and in all other shader types begins with the first label instruction. */
+ if (!after_declarations_section && !vsir_instruction_is_dcl(instruction)
+ && instruction->handler_idx != VKD3DSIH_NOP)
+ {
+ after_declarations_section = true;
+ cf_flattener_emit_label(flattener, cf_flattener_alloc_block_id(flattener));
+ }
+
+ cf_info = flattener->control_flow_depth
+ ? &flattener->control_flow_info[flattener->control_flow_depth - 1] : NULL;
+
+ switch (instruction->handler_idx)
+ {
+ case VKD3DSIH_HS_CONTROL_POINT_PHASE:
+ case VKD3DSIH_HS_FORK_PHASE:
+ case VKD3DSIH_HS_JOIN_PHASE:
+ if (!cf_flattener_copy_instruction(flattener, instruction))
+ return VKD3D_ERROR_OUT_OF_MEMORY;
+ if (instruction->handler_idx != VKD3DSIH_HS_CONTROL_POINT_PHASE || !instruction->flags)
+ after_declarations_section = false;
+ break;
+
+ case VKD3DSIH_LABEL:
+ vkd3d_shader_parser_error(parser, VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED,
+ "Aborting due to not yet implemented feature: Label instruction.");
+ return VKD3D_ERROR_NOT_IMPLEMENTED;
+
+ case VKD3DSIH_IF:
+ if (!(cf_info = cf_flattener_push_control_flow_level(flattener)))
+ return VKD3D_ERROR_OUT_OF_MEMORY;
+
+ true_block_id = cf_flattener_alloc_block_id(flattener);
+ merge_block_id = cf_flattener_alloc_block_id(flattener);
+ cf_info->u.if_.false_param = cf_flattener_emit_branch(flattener, merge_block_id, 0,
+ src, true_block_id, merge_block_id, instruction->flags);
+ if (!cf_info->u.if_.false_param)
+ return VKD3D_ERROR_OUT_OF_MEMORY;
+
+ cf_flattener_emit_label(flattener, true_block_id);
+
+ cf_info->u.if_.id = flattener->branch_id;
+ cf_info->u.if_.merge_block_id = merge_block_id;
+ cf_info->u.if_.else_block_id = 0;
+ cf_info->inside_block = true;
+ cf_info->current_block = VKD3D_BLOCK_IF;
+
+ cf_flattener_create_block_name(flattener, merge_block_id, "branch%u_merge", flattener->branch_id);
+ cf_flattener_create_block_name(flattener, true_block_id, "branch%u_true", flattener->branch_id);
+ ++flattener->branch_id;
+ break;
+
+ case VKD3DSIH_ELSE:
+ if (cf_info->inside_block)
+ cf_flattener_emit_unconditional_branch(flattener, cf_info->u.if_.merge_block_id);
+
+ cf_info->u.if_.else_block_id = cf_flattener_alloc_block_id(flattener);
+ cf_info->u.if_.false_param->reg.idx[0].offset = cf_info->u.if_.else_block_id;
+
+ cf_flattener_create_block_name(flattener,
+ cf_info->u.if_.else_block_id, "branch%u_false", cf_info->u.if_.id);
+ cf_flattener_emit_label(flattener, cf_info->u.if_.else_block_id);
+
+ cf_info->inside_block = true;
+ break;
+
+ case VKD3DSIH_ENDIF:
+ if (cf_info->inside_block)
+ cf_flattener_emit_unconditional_branch(flattener, cf_info->u.if_.merge_block_id);
+
+ cf_flattener_emit_label(flattener, cf_info->u.if_.merge_block_id);
+
+ cf_flattener_pop_control_flow_level(flattener);
+ break;
+
+ case VKD3DSIH_LOOP:
+ if (!(cf_info = cf_flattener_push_control_flow_level(flattener)))
+ return VKD3D_ERROR_OUT_OF_MEMORY;
+
+ loop_header_block_id = cf_flattener_alloc_block_id(flattener);
+ loop_body_block_id = cf_flattener_alloc_block_id(flattener);
+ continue_block_id = cf_flattener_alloc_block_id(flattener);
+ merge_block_id = cf_flattener_alloc_block_id(flattener);
+
+ cf_flattener_emit_unconditional_branch(flattener, loop_header_block_id);
+ cf_flattener_emit_label(flattener, loop_header_block_id);
+ cf_flattener_emit_branch(flattener, merge_block_id, continue_block_id,
+ NULL, loop_body_block_id, 0, 0);
+
+ cf_flattener_emit_label(flattener, loop_body_block_id);
+
+ cf_info->u.loop.header_block_id = loop_header_block_id;
+ cf_info->u.loop.continue_block_id = continue_block_id;
+ cf_info->u.loop.merge_block_id = merge_block_id;
+ cf_info->current_block = VKD3D_BLOCK_LOOP;
+ cf_info->inside_block = true;
+
+ cf_flattener_create_block_name(flattener, loop_header_block_id, "loop%u_header", flattener->loop_id);
+ cf_flattener_create_block_name(flattener, loop_body_block_id, "loop%u_body", flattener->loop_id);
+ cf_flattener_create_block_name(flattener, continue_block_id, "loop%u_continue", flattener->loop_id);
+ cf_flattener_create_block_name(flattener, merge_block_id, "loop%u_merge", flattener->loop_id);
+ ++flattener->loop_id;
+ break;
+
+ case VKD3DSIH_ENDLOOP:
+ if (cf_info->inside_block)
+ cf_flattener_emit_unconditional_branch(flattener, cf_info->u.loop.continue_block_id);
+
+ cf_flattener_emit_label(flattener, cf_info->u.loop.continue_block_id);
+ cf_flattener_emit_unconditional_branch(flattener, cf_info->u.loop.header_block_id);
+ cf_flattener_emit_label(flattener, cf_info->u.loop.merge_block_id);
+
+ cf_flattener_pop_control_flow_level(flattener);
+ break;
+
+ case VKD3DSIH_SWITCH:
+ if (!(cf_info = cf_flattener_push_control_flow_level(flattener)))
+ return VKD3D_ERROR_OUT_OF_MEMORY;
+
+ merge_block_id = cf_flattener_alloc_block_id(flattener);
+
+ cf_info->u.switch_.ins_location = flattener->instruction_count;
+ cf_info->u.switch_.condition = src;
+
+ if (!(dst_ins = cf_flattener_require_space(flattener, 1)))
+ return VKD3D_ERROR_OUT_OF_MEMORY;
+ vsir_instruction_init(dst_ins, &instruction->location, VKD3DSIH_SWITCH_MONOLITHIC);
+ ++flattener->instruction_count;
+
+ cf_info->u.switch_.id = flattener->switch_id;
+ cf_info->u.switch_.merge_block_id = merge_block_id;
+ cf_info->u.switch_.cases = NULL;
+ cf_info->u.switch_.cases_size = 0;
+ cf_info->u.switch_.cases_count = 0;
+ cf_info->u.switch_.default_block_id = 0;
+ cf_info->inside_block = false;
+ cf_info->current_block = VKD3D_BLOCK_SWITCH;
+
+ cf_flattener_create_block_name(flattener, merge_block_id, "switch%u_merge", flattener->switch_id);
+ ++flattener->switch_id;
+
+ if (!vkd3d_array_reserve((void **)&cf_info->u.switch_.cases, &cf_info->u.switch_.cases_size,
+ 10, sizeof(*cf_info->u.switch_.cases)))
+ return VKD3D_ERROR_OUT_OF_MEMORY;
+
+ break;
+
+ case VKD3DSIH_ENDSWITCH:
+ {
+ struct vkd3d_shader_src_param *src_params;
+ unsigned int j;
+
+ if (!cf_info->u.switch_.default_block_id)
+ cf_info->u.switch_.default_block_id = cf_info->u.switch_.merge_block_id;
+
+ cf_flattener_emit_label(flattener, cf_info->u.switch_.merge_block_id);
+
+ /* The SWITCH instruction is completed when the endswitch
+ * instruction is processed because we do not know the number
+ * of case statements or the default block id in advance.*/
+ dst_ins = &flattener->instructions[cf_info->u.switch_.ins_location];
+ if (!(src_params = instruction_src_params_alloc(dst_ins, cf_info->u.switch_.cases_count * 2 + 3, flattener)))
+ {
+ vkd3d_free(cf_info->u.switch_.cases);
+ return VKD3D_ERROR_OUT_OF_MEMORY;
+ }
+ src_params[0] = *cf_info->u.switch_.condition;
+ vsir_src_param_init_label(&src_params[1], cf_info->u.switch_.default_block_id);
+ vsir_src_param_init_label(&src_params[2], cf_info->u.switch_.merge_block_id);
+ for (j = 0; j < cf_info->u.switch_.cases_count; ++j)
+ {
+ unsigned int index = j * 2 + 3;
+ vsir_src_param_init(&src_params[index], VKD3DSPR_IMMCONST, VKD3D_DATA_UINT, 0);
+ src_params[index].reg.u.immconst_u32[0] = cf_info->u.switch_.cases[j].value;
+ vsir_src_param_init_label(&src_params[index + 1], cf_info->u.switch_.cases[j].block_id);
+ }
+ vkd3d_free(cf_info->u.switch_.cases);
+
+ cf_flattener_pop_control_flow_level(flattener);
+ break;
+ }
+
+ case VKD3DSIH_CASE:
+ {
+ unsigned int label_id, value;
+
+ if (src->swizzle != VKD3D_SHADER_SWIZZLE(X, X, X, X))
+ {
+ WARN("Unexpected src swizzle %#x.\n", src->swizzle);
+ vkd3d_shader_parser_error(parser, VKD3D_SHADER_ERROR_VSIR_INVALID_SWIZZLE,
+ "The swizzle for a switch case value is not scalar X.");
+ }
+ value = *src->reg.u.immconst_u32;
+
+ if (!vkd3d_array_reserve((void **)&cf_info->u.switch_.cases, &cf_info->u.switch_.cases_size,
+ cf_info->u.switch_.cases_count + 1, sizeof(*cf_info->u.switch_.cases)))
+ return VKD3D_ERROR_OUT_OF_MEMORY;
+
+ label_id = cf_flattener_alloc_block_id(flattener);
+ if (cf_info->inside_block) /* fall-through */
+ cf_flattener_emit_unconditional_branch(flattener, label_id);
+
+ cf_info->u.switch_.cases[cf_info->u.switch_.cases_count].value = value;
+ cf_info->u.switch_.cases[cf_info->u.switch_.cases_count].block_id = label_id;
+ ++cf_info->u.switch_.cases_count;
+
+ cf_flattener_emit_label(flattener, label_id);
+ cf_flattener_create_block_name(flattener, label_id, "switch%u_case%u", cf_info->u.switch_.id, value);
+ cf_info->inside_block = true;
+ break;
+ }
+
+ case VKD3DSIH_DEFAULT:
+ cf_info->u.switch_.default_block_id = cf_flattener_alloc_block_id(flattener);
+ if (cf_info->inside_block) /* fall-through */
+ cf_flattener_emit_unconditional_branch(flattener, cf_info->u.switch_.default_block_id);
+
+ cf_flattener_emit_label(flattener, cf_info->u.switch_.default_block_id);
+
+ cf_flattener_create_block_name(flattener, cf_info->u.switch_.default_block_id,
+ "switch%u_default", cf_info->u.switch_.id);
+ cf_info->inside_block = true;
+ break;
+
+ case VKD3DSIH_BREAK:
+ {
+ struct cf_flattener_info *breakable_cf_info;
+
+ if (!(breakable_cf_info = cf_flattener_find_innermost_breakable_cf_construct(flattener)))
+ {
+ FIXME("Unhandled break instruction.\n");
+ return VKD3D_ERROR_INVALID_SHADER;
+ }
+
+ if (breakable_cf_info->current_block == VKD3D_BLOCK_LOOP)
+ {
+ cf_flattener_emit_unconditional_branch(flattener, breakable_cf_info->u.loop.merge_block_id);
+ }
+ else if (breakable_cf_info->current_block == VKD3D_BLOCK_SWITCH)
+ {
+ cf_flattener_emit_unconditional_branch(flattener, breakable_cf_info->u.switch_.merge_block_id);
+ }
+
+ cf_info->inside_block = false;
+ break;
+ }
+
+ case VKD3DSIH_BREAKP:
+ {
+ struct cf_flattener_info *loop_cf_info;
+
+ if (!(loop_cf_info = cf_flattener_find_innermost_loop(flattener)))
+ {
+ ERR("Invalid 'breakc' instruction outside loop.\n");
+ return VKD3D_ERROR_INVALID_SHADER;
+ }
+
+ cf_flattener_emit_conditional_branch_and_merge(flattener,
+ src, loop_cf_info->u.loop.merge_block_id, instruction->flags);
+ break;
+ }
+
+ case VKD3DSIH_CONTINUE:
+ {
+ struct cf_flattener_info *loop_cf_info;
+
+ if (!(loop_cf_info = cf_flattener_find_innermost_loop(flattener)))
+ {
+ ERR("Invalid 'continue' instruction outside loop.\n");
+ return VKD3D_ERROR_INVALID_SHADER;
+ }
+
+ cf_flattener_emit_unconditional_branch(flattener, loop_cf_info->u.loop.continue_block_id);
+
+ cf_info->inside_block = false;
+ break;
+ }
+
+ case VKD3DSIH_CONTINUEP:
+ {
+ struct cf_flattener_info *loop_cf_info;
+
+ if (!(loop_cf_info = cf_flattener_find_innermost_loop(flattener)))
+ {
+ ERR("Invalid 'continuec' instruction outside loop.\n");
+ return VKD3D_ERROR_INVALID_SHADER;
+ }
+
+ cf_flattener_emit_conditional_branch_and_merge(flattener,
+ src, loop_cf_info->u.loop.continue_block_id, instruction->flags);
+ break;
+ }
+
+ case VKD3DSIH_RET:
+ if (!cf_flattener_copy_instruction(flattener, instruction))
+ return VKD3D_ERROR_OUT_OF_MEMORY;
+
+ if (cf_info)
+ cf_info->inside_block = false;
+ else
+ main_block_open = false;
+ break;
+
+ default:
+ if (!cf_flattener_copy_instruction(flattener, instruction))
+ return VKD3D_ERROR_OUT_OF_MEMORY;
+ break;
+ }
+ }
+
+ if (main_block_open)
+ {
+ if (!(dst_ins = cf_flattener_require_space(flattener, 1)))
+ return VKD3D_ERROR_OUT_OF_MEMORY;
+ vsir_instruction_init(dst_ins, &flattener->location, VKD3DSIH_RET);
+ ++flattener->instruction_count;
+ }
+
+ return flattener->allocation_failed ? VKD3D_ERROR_OUT_OF_MEMORY : VKD3D_OK;
+}
+
+static enum vkd3d_result flatten_control_flow_constructs(struct vkd3d_shader_parser *parser)
+{
+ struct vsir_program *program = &parser->program;
+ struct cf_flattener flattener = {0};
+ enum vkd3d_result result;
+
+ flattener.parser = parser;
+ result = cf_flattener_iterate_instruction_array(&flattener);
+
+ if (result >= 0)
+ {
+ vkd3d_free(parser->program.instructions.elements);
+ program->instructions.elements = flattener.instructions;
+ program->instructions.capacity = flattener.instruction_capacity;
+ program->instructions.count = flattener.instruction_count;
+ program->block_count = flattener.block_id;
+ }
+ else
+ {
+ vkd3d_free(flattener.instructions);
+ }
+
+ vkd3d_free(flattener.control_flow_info);
+ /* Simpler to always free these in vsir_program_cleanup(). */
+ program->block_names = flattener.block_names;
+ program->block_name_count = flattener.block_name_count;
+
+ return result;
+}
+
+static unsigned int label_from_src_param(const struct vkd3d_shader_src_param *param)
+{
+ assert(param->reg.type == VKD3DSPR_LABEL);
+ return param->reg.idx[0].offset;
+}
+
+static bool reserve_instructions(struct vkd3d_shader_instruction **instructions, size_t *capacity, size_t count)
+{
+ if (!vkd3d_array_reserve((void **)instructions, capacity, count, sizeof(**instructions)))
+ {
+ ERR("Failed to allocate instructions.\n");
+ return false;
+ }
+
+ return true;
+}
+
+/* A record represents replacing a jump from block `switch_label' to
+ * block `target_label' with a jump from block `if_label' to block
+ * `target_label'. */
+struct lower_switch_to_if_ladder_block_mapping
+{
+ unsigned int switch_label;
+ unsigned int if_label;
+ unsigned int target_label;
+};
+
+static bool lower_switch_to_if_ladder_add_block_mapping(struct lower_switch_to_if_ladder_block_mapping **block_map,
+ size_t *map_capacity, size_t *map_count, unsigned int switch_label, unsigned int if_label, unsigned int target_label)
+{
+ if (!vkd3d_array_reserve((void **)block_map, map_capacity, *map_count + 1, sizeof(**block_map)))
+ {
+ ERR("Failed to allocate block mapping.\n");
+ return false;
+ }
+
+ (*block_map)[*map_count].switch_label = switch_label;
+ (*block_map)[*map_count].if_label = if_label;
+ (*block_map)[*map_count].target_label = target_label;
+
+ *map_count += 1;
+
+ return true;
+}
+
+static enum vkd3d_result lower_switch_to_if_ladder(struct vsir_program *program)
+{
+ unsigned int block_count = program->block_count, ssa_count = program->ssa_count, current_label = 0, if_label;
+ size_t ins_capacity = 0, ins_count = 0, i, map_capacity = 0, map_count = 0;
+ struct vkd3d_shader_instruction *instructions = NULL;
+ struct lower_switch_to_if_ladder_block_mapping *block_map = NULL;
+
+ if (!reserve_instructions(&instructions, &ins_capacity, program->instructions.count))
+ goto fail;
+
+ /* First subpass: convert SWITCH_MONOLITHIC instructions to
+ * selection ladders, keeping a map between blocks before and
+ * after the subpass. */
+ for (i = 0; i < program->instructions.count; ++i)
+ {
+ struct vkd3d_shader_instruction *ins = &program->instructions.elements[i];
+ unsigned int case_count, j, default_label;
+
+ switch (ins->handler_idx)
+ {
+ case VKD3DSIH_LABEL:
+ current_label = label_from_src_param(&ins->src[0]);
+ if (!reserve_instructions(&instructions, &ins_capacity, ins_count + 1))
+ goto fail;
+ instructions[ins_count++] = *ins;
+ continue;
+
+ case VKD3DSIH_SWITCH_MONOLITHIC:
+ break;
+
+ default:
+ if (!reserve_instructions(&instructions, &ins_capacity, ins_count + 1))
+ goto fail;
+ instructions[ins_count++] = *ins;
+ continue;
+ }
+
+ case_count = (ins->src_count - 3) / 2;
+ default_label = label_from_src_param(&ins->src[1]);
+
+ /* In principle we can have a switch with no cases, and we
+ * just have to jump to the default label. */
+ if (case_count == 0)
+ {
+ if (!reserve_instructions(&instructions, &ins_capacity, ins_count + 1))
+ goto fail;
+
+ if (!vsir_instruction_init_with_params(program, &instructions[ins_count],
+ &ins->location, VKD3DSIH_BRANCH, 0, 1))
+ goto fail;
+ vsir_src_param_init_label(&instructions[ins_count].src[0], default_label);
+ ++ins_count;
+ }
+
+ if (!reserve_instructions(&instructions, &ins_capacity, ins_count + 3 * case_count - 1))
+ goto fail;
+
+ if_label = current_label;
+
+ for (j = 0; j < case_count; ++j)
+ {
+ unsigned int fallthrough_label, case_label = label_from_src_param(&ins->src[3 + 2 * j + 1]);
+
+ if (!vsir_instruction_init_with_params(program,
+ &instructions[ins_count], &ins->location, VKD3DSIH_IEQ, 1, 2))
+ goto fail;
+ dst_param_init_ssa_bool(&instructions[ins_count].dst[0], ssa_count);
+ instructions[ins_count].src[0] = ins->src[0];
+ instructions[ins_count].src[1] = ins->src[3 + 2 * j];
+ ++ins_count;
+
+ /* For all cases except the last one we fall through to
+ * the following case; the last one has to jump to the
+ * default label. */
+ if (j == case_count - 1)
+ fallthrough_label = default_label;
+ else
+ fallthrough_label = block_count + 1;
+
+ if (!vsir_instruction_init_with_params(program, &instructions[ins_count],
+ &ins->location, VKD3DSIH_BRANCH, 0, 3))
+ goto fail;
+ src_param_init_ssa_bool(&instructions[ins_count].src[0], ssa_count);
+ vsir_src_param_init_label(&instructions[ins_count].src[1], case_label);
+ vsir_src_param_init_label(&instructions[ins_count].src[2], fallthrough_label);
+ ++ins_count;
+
+ ++ssa_count;
+
+ if (!lower_switch_to_if_ladder_add_block_mapping(&block_map, &map_capacity, &map_count,
+ current_label, if_label, case_label))
+ goto fail;
+
+ if (j == case_count - 1)
+ {
+ if (!lower_switch_to_if_ladder_add_block_mapping(&block_map, &map_capacity, &map_count,
+ current_label, if_label, default_label))
+ goto fail;
+ }
+ else
+ {
+ if (!vsir_instruction_init_with_params(program,
+ &instructions[ins_count], &ins->location, VKD3DSIH_LABEL, 0, 1))
+ goto fail;
+ vsir_src_param_init_label(&instructions[ins_count].src[0], ++block_count);
+ ++ins_count;
+
+ if_label = block_count;
+ }
+ }
+ }
+
+ /* Second subpass: creating new blocks might have broken
+ * references in PHI instructions, so we use the block map to fix
+ * them. */
+ current_label = 0;
+ for (i = 0; i < ins_count; ++i)
+ {
+ struct vkd3d_shader_instruction *ins = &instructions[i];
+ struct vkd3d_shader_src_param *new_src;
+ unsigned int j, l, new_src_count = 0;
+
+ switch (ins->handler_idx)
+ {
+ case VKD3DSIH_LABEL:
+ current_label = label_from_src_param(&ins->src[0]);
+ continue;
+
+ case VKD3DSIH_PHI:
+ break;
+
+ default:
+ continue;
+ }
+
+ /* First count how many source parameters we need. */
+ for (j = 0; j < ins->src_count; j += 2)
+ {
+ unsigned int source_label = label_from_src_param(&ins->src[j + 1]);
+ size_t k, match_count = 0;
+
+ for (k = 0; k < map_count; ++k)
+ {
+ struct lower_switch_to_if_ladder_block_mapping *mapping = &block_map[k];
+
+ if (mapping->switch_label == source_label && mapping->target_label == current_label)
+ match_count += 1;
+ }
+
+ new_src_count += (match_count != 0) ? 2 * match_count : 2;
+ }
+
+ assert(new_src_count >= ins->src_count);
+
+ /* Allocate more source parameters if needed. */
+ if (new_src_count == ins->src_count)
+ {
+ new_src = ins->src;
+ }
+ else
+ {
+ if (!(new_src = vsir_program_get_src_params(program, new_src_count)))
+ {
+ ERR("Failed to allocate %u source parameters.\n", new_src_count);
+ goto fail;
+ }
+ }
+
+ /* Then do the copy. */
+ for (j = 0, l = 0; j < ins->src_count; j += 2)
+ {
+ unsigned int source_label = label_from_src_param(&ins->src[j + 1]);
+ size_t k, match_count = 0;
+
+ for (k = 0; k < map_count; ++k)
+ {
+ struct lower_switch_to_if_ladder_block_mapping *mapping = &block_map[k];
+
+ if (mapping->switch_label == source_label && mapping->target_label == current_label)
+ {
+ match_count += 1;
+
+ new_src[l] = ins->src[j];
+ new_src[l + 1] = ins->src[j + 1];
+ new_src[l + 1].reg.idx[0].offset = mapping->if_label;
+ l += 2;
+ }
+ }
+
+ if (match_count == 0)
+ {
+ new_src[l] = ins->src[j];
+ new_src[l + 1] = ins->src[j + 1];
+ l += 2;
+ }
+ }
+
+ assert(l == new_src_count);
+
+ ins->src_count = new_src_count;
+ ins->src = new_src;
+ }
+
+ vkd3d_free(program->instructions.elements);
+ vkd3d_free(block_map);
+ program->instructions.elements = instructions;
+ program->instructions.capacity = ins_capacity;
+ program->instructions.count = ins_count;
+ program->block_count = block_count;
+ program->ssa_count = ssa_count;
+
+ return VKD3D_OK;
+
+fail:
+ vkd3d_free(instructions);
+ vkd3d_free(block_map);
+
+ return VKD3D_ERROR_OUT_OF_MEMORY;
+}
+
+static void materialize_ssas_to_temps_process_src_param(struct vkd3d_shader_parser *parser, struct vkd3d_shader_src_param *src);
+
+/* This is idempotent: it can be safely applied more than once on the
+ * same register. */
+static void materialize_ssas_to_temps_process_reg(struct vkd3d_shader_parser *parser, struct vkd3d_shader_register *reg)
+{
+ unsigned int i;
+
+ if (reg->type == VKD3DSPR_SSA)
+ {
+ reg->type = VKD3DSPR_TEMP;
+ reg->idx[0].offset += parser->program.temp_count;
+ }
+
+ for (i = 0; i < reg->idx_count; ++i)
+ if (reg->idx[i].rel_addr)
+ materialize_ssas_to_temps_process_src_param(parser, reg->idx[i].rel_addr);
+}
+
+static void materialize_ssas_to_temps_process_dst_param(struct vkd3d_shader_parser *parser, struct vkd3d_shader_dst_param *dst)
+{
+ materialize_ssas_to_temps_process_reg(parser, &dst->reg);
+}
+
+static void materialize_ssas_to_temps_process_src_param(struct vkd3d_shader_parser *parser, struct vkd3d_shader_src_param *src)
+{
+ materialize_ssas_to_temps_process_reg(parser, &src->reg);
+}
+
+static const struct vkd3d_shader_src_param *materialize_ssas_to_temps_compute_source(struct vkd3d_shader_instruction *ins,
+ unsigned int label)
+{
+ unsigned int i;
+
+ assert(ins->handler_idx == VKD3DSIH_PHI);
+
+ for (i = 0; i < ins->src_count; i += 2)
+ {
+ if (label_from_src_param(&ins->src[i + 1]) == label)
+ return &ins->src[i];
+ }
+
+ vkd3d_unreachable();
+}
+
+static bool materialize_ssas_to_temps_synthesize_mov(struct vkd3d_shader_parser *parser,
+ struct vkd3d_shader_instruction *instruction, const struct vkd3d_shader_location *loc,
+ const struct vkd3d_shader_dst_param *dest, const struct vkd3d_shader_src_param *cond,
+ const struct vkd3d_shader_src_param *source, bool invert)
+{
+ struct vkd3d_shader_src_param *src;
+ struct vkd3d_shader_dst_param *dst;
+
+ if (!vsir_instruction_init_with_params(&parser->program, instruction, loc,
+ cond ? VKD3DSIH_MOVC : VKD3DSIH_MOV, 1, cond ? 3 : 1))
+ return false;
+
+ dst = instruction->dst;
+ src = instruction->src;
+
+ dst[0] = *dest;
+ materialize_ssas_to_temps_process_dst_param(parser, &dst[0]);
+
+ assert(dst[0].write_mask == VKD3DSP_WRITEMASK_0);
+ assert(dst[0].modifiers == 0);
+ assert(dst[0].shift == 0);
+
+ if (cond)
+ {
+ src[0] = *cond;
+ src[1 + invert] = *source;
+ memset(&src[2 - invert], 0, sizeof(src[2 - invert]));
+ src[2 - invert].reg = dst[0].reg;
+ materialize_ssas_to_temps_process_src_param(parser, &src[1]);
+ materialize_ssas_to_temps_process_src_param(parser, &src[2]);
+ }
+ else
+ {
+ src[0] = *source;
+ materialize_ssas_to_temps_process_src_param(parser, &src[0]);
+ }
+
+ return true;
+}
+
+static enum vkd3d_result materialize_ssas_to_temps(struct vkd3d_shader_parser *parser)
+{
+ struct vkd3d_shader_instruction *instructions = NULL;
+ struct materialize_ssas_to_temps_block_data
+ {
+ size_t phi_begin;
+ size_t phi_count;
+ } *block_index = NULL;
+ size_t ins_capacity = 0, ins_count = 0, i;
+ unsigned int current_label = 0;
+
+ if (!reserve_instructions(&instructions, &ins_capacity, parser->program.instructions.count))
+ goto fail;
+
+ if (!(block_index = vkd3d_calloc(parser->program.block_count, sizeof(*block_index))))
+ {
+ ERR("Failed to allocate block index.\n");
+ goto fail;
+ }
+
+ for (i = 0; i < parser->program.instructions.count; ++i)
+ {
+ struct vkd3d_shader_instruction *ins = &parser->program.instructions.elements[i];
+
+ switch (ins->handler_idx)
+ {
+ case VKD3DSIH_LABEL:
+ current_label = label_from_src_param(&ins->src[0]);
+ break;
+
+ case VKD3DSIH_PHI:
+ assert(current_label != 0);
+ assert(i != 0);
+ if (block_index[current_label - 1].phi_begin == 0)
+ block_index[current_label - 1].phi_begin = i;
+ block_index[current_label - 1].phi_count += 1;
+ break;
+
+ default:
+ current_label = 0;
+ break;
+ }
+ }
+
+ for (i = 0; i < parser->program.instructions.count; ++i)
+ {
+ struct vkd3d_shader_instruction *ins = &parser->program.instructions.elements[i];
+ size_t j;
+
+ for (j = 0; j < ins->dst_count; ++j)
+ materialize_ssas_to_temps_process_dst_param(parser, &ins->dst[j]);
+
+ for (j = 0; j < ins->src_count; ++j)
+ materialize_ssas_to_temps_process_src_param(parser, &ins->src[j]);
+
+ switch (ins->handler_idx)
+ {
+ case VKD3DSIH_LABEL:
+ current_label = label_from_src_param(&ins->src[0]);
+ break;
+
+ case VKD3DSIH_BRANCH:
+ {
+ if (vsir_register_is_label(&ins->src[0].reg))
+ {
+ const struct materialize_ssas_to_temps_block_data *data = &block_index[label_from_src_param(&ins->src[0]) - 1];
+
+ if (!reserve_instructions(&instructions, &ins_capacity, ins_count + data->phi_count))
+ goto fail;
+
+ for (j = data->phi_begin; j < data->phi_begin + data->phi_count; ++j)
+ {
+ const struct vkd3d_shader_src_param *source;
+
+ source = materialize_ssas_to_temps_compute_source(&parser->program.instructions.elements[j], current_label);
+ if (!materialize_ssas_to_temps_synthesize_mov(parser, &instructions[ins_count], &ins->location,
+ &parser->program.instructions.elements[j].dst[0], NULL, source, false))
+ goto fail;
+
+ ++ins_count;
+ }
+ }
+ else
+ {
+ struct materialize_ssas_to_temps_block_data *data_true = &block_index[label_from_src_param(&ins->src[1]) - 1],
+ *data_false = &block_index[label_from_src_param(&ins->src[2]) - 1];
+ const struct vkd3d_shader_src_param *cond = &ins->src[0];
+
+ if (!reserve_instructions(&instructions, &ins_capacity,
+ ins_count + data_true->phi_count + data_false->phi_count))
+ goto fail;
+
+ for (j = data_true->phi_begin; j < data_true->phi_begin + data_true->phi_count; ++j)
+ {
+ const struct vkd3d_shader_src_param *source;
+
+ source = materialize_ssas_to_temps_compute_source(&parser->program.instructions.elements[j], current_label);
+ if (!materialize_ssas_to_temps_synthesize_mov(parser, &instructions[ins_count], &ins->location,
+ &parser->program.instructions.elements[j].dst[0], cond, source, false))
+ goto fail;
+
+ ++ins_count;
+ }
+
+ for (j = data_false->phi_begin; j < data_false->phi_begin + data_false->phi_count; ++j)
+ {
+ const struct vkd3d_shader_src_param *source;
+
+ source = materialize_ssas_to_temps_compute_source(&parser->program.instructions.elements[j], current_label);
+ if (!materialize_ssas_to_temps_synthesize_mov(parser, &instructions[ins_count], &ins->location,
+ &parser->program.instructions.elements[j].dst[0], cond, source, true))
+ goto fail;
+
+ ++ins_count;
+ }
+ }
+ break;
+ }
+
+ case VKD3DSIH_PHI:
+ continue;
+
+ default:
+ break;
+ }
+
+ if (!reserve_instructions(&instructions, &ins_capacity, ins_count + 1))
+ goto fail;
+
+ instructions[ins_count++] = *ins;
+ }
+
+ vkd3d_free(parser->program.instructions.elements);
+ vkd3d_free(block_index);
+ parser->program.instructions.elements = instructions;
+ parser->program.instructions.capacity = ins_capacity;
+ parser->program.instructions.count = ins_count;
+ parser->program.temp_count += parser->program.ssa_count;
+ parser->program.ssa_count = 0;
+
+ return VKD3D_OK;
+
+fail:
+ vkd3d_free(instructions);
+ vkd3d_free(block_index);
+
+ return VKD3D_ERROR_OUT_OF_MEMORY;
+}
+
+static enum vkd3d_result simple_structurizer_run(struct vkd3d_shader_parser *parser)
+{
+ const unsigned int block_temp_idx = parser->program.temp_count;
+ struct vkd3d_shader_instruction *instructions = NULL;
+ const struct vkd3d_shader_location no_loc = {0};
+ size_t ins_capacity = 0, ins_count = 0, i;
+ bool first_label_found = false;
+
+ if (!reserve_instructions(&instructions, &ins_capacity, parser->program.instructions.count))
+ goto fail;
+
+ for (i = 0; i < parser->program.instructions.count; ++i)
+ {
+ struct vkd3d_shader_instruction *ins = &parser->program.instructions.elements[i];
+
+ switch (ins->handler_idx)
+ {
+ case VKD3DSIH_PHI:
+ case VKD3DSIH_SWITCH_MONOLITHIC:
+ vkd3d_unreachable();
+
+ case VKD3DSIH_LABEL:
+ if (!reserve_instructions(&instructions, &ins_capacity, ins_count + 4))
+ goto fail;
+
+ if (!first_label_found)
+ {
+ first_label_found = true;
+
+ if (!vsir_instruction_init_with_params(&parser->program, &instructions[ins_count], &no_loc, VKD3DSIH_MOV, 1, 1))
+ goto fail;
+ dst_param_init_temp_uint(&instructions[ins_count].dst[0], block_temp_idx);
+ src_param_init_const_uint(&instructions[ins_count].src[0], label_from_src_param(&ins->src[0]));
+ ins_count++;
+
+ if (!vsir_instruction_init_with_params(&parser->program, &instructions[ins_count], &no_loc, VKD3DSIH_LOOP, 0, 0))
+ goto fail;
+ ins_count++;
+
+ if (!vsir_instruction_init_with_params(&parser->program, &instructions[ins_count], &no_loc, VKD3DSIH_SWITCH, 0, 1))
+ goto fail;
+ src_param_init_temp_uint(&instructions[ins_count].src[0], block_temp_idx);
+ ins_count++;
+ }
+
+ if (!vsir_instruction_init_with_params(&parser->program, &instructions[ins_count], &no_loc, VKD3DSIH_CASE, 0, 1))
+ goto fail;
+ src_param_init_const_uint(&instructions[ins_count].src[0], label_from_src_param(&ins->src[0]));
+ ins_count++;
+ break;
+
+ case VKD3DSIH_BRANCH:
+ if (!reserve_instructions(&instructions, &ins_capacity, ins_count + 2))
+ goto fail;
+
+ if (vsir_register_is_label(&ins->src[0].reg))
+ {
+ if (!vsir_instruction_init_with_params(&parser->program, &instructions[ins_count], &no_loc, VKD3DSIH_MOV, 1, 1))
+ goto fail;
+ dst_param_init_temp_uint(&instructions[ins_count].dst[0], block_temp_idx);
+ src_param_init_const_uint(&instructions[ins_count].src[0], label_from_src_param(&ins->src[0]));
+ ins_count++;
+ }
+ else
+ {
+ if (!vsir_instruction_init_with_params(&parser->program, &instructions[ins_count], &no_loc, VKD3DSIH_MOVC, 1, 3))
+ goto fail;
+ dst_param_init_temp_uint(&instructions[ins_count].dst[0], block_temp_idx);
+ instructions[ins_count].src[0] = ins->src[0];
+ src_param_init_const_uint(&instructions[ins_count].src[1], label_from_src_param(&ins->src[1]));
+ src_param_init_const_uint(&instructions[ins_count].src[2], label_from_src_param(&ins->src[2]));
+ ins_count++;
+ }
+
+ if (!vsir_instruction_init_with_params(&parser->program, &instructions[ins_count], &no_loc, VKD3DSIH_BREAK, 0, 0))
+ goto fail;
+ ins_count++;
+ break;
+
+ case VKD3DSIH_RET:
+ default:
+ if (!reserve_instructions(&instructions, &ins_capacity, ins_count + 1))
+ goto fail;
+
+ instructions[ins_count++] = *ins;
+ break;
+ }
+ }
+
+ assert(first_label_found);
+
+ if (!reserve_instructions(&instructions, &ins_capacity, ins_count + 3))
+ goto fail;
+
+ if (!vsir_instruction_init_with_params(&parser->program, &instructions[ins_count], &no_loc, VKD3DSIH_ENDSWITCH, 0, 0))
+ goto fail;
+ ins_count++;
+
+ if (!vsir_instruction_init_with_params(&parser->program, &instructions[ins_count], &no_loc, VKD3DSIH_ENDLOOP, 0, 0))
+ goto fail;
+ ins_count++;
+
+ if (!vsir_instruction_init_with_params(&parser->program, &instructions[ins_count], &no_loc, VKD3DSIH_RET, 0, 0))
+ goto fail;
+ ins_count++;
+
+ vkd3d_free(parser->program.instructions.elements);
+ parser->program.instructions.elements = instructions;
+ parser->program.instructions.capacity = ins_capacity;
+ parser->program.instructions.count = ins_count;
+ parser->program.temp_count += 1;
+
+ return VKD3D_OK;
+
+fail:
+ vkd3d_free(instructions);
+ return VKD3D_ERROR_OUT_OF_MEMORY;
+}
+
+enum vkd3d_result vkd3d_shader_normalise(struct vkd3d_shader_parser *parser,
+ const struct vkd3d_shader_compile_info *compile_info)
+{
+ struct vkd3d_shader_instruction_array *instructions = &parser->program.instructions;
+ enum vkd3d_result result = VKD3D_OK;
+
+ remove_dcl_temps(&parser->program);
+
+ if ((result = instruction_array_lower_texkills(parser)) < 0)
+ return result;
+
+ if (parser->shader_desc.is_dxil)
+ {
+ if ((result = lower_switch_to_if_ladder(&parser->program)) < 0)
+ return result;
+
+ if ((result = materialize_ssas_to_temps(parser)) < 0)
+ return result;
+
+ if ((result = simple_structurizer_run(parser)) < 0)
+ return result;
+ }
+ else
+ {
+ if (parser->program.shader_version.type != VKD3D_SHADER_TYPE_PIXEL)
+ {
+ if ((result = remap_output_signature(parser, compile_info)) < 0)
+ return result;
+ }
+
+ if (parser->program.shader_version.type == VKD3D_SHADER_TYPE_HULL)
+ {
+ if ((result = instruction_array_flatten_hull_shader_phases(instructions)) < 0)
+ return result;
+
+ if ((result = instruction_array_normalise_hull_shader_control_point_io(instructions,
+ &parser->shader_desc.input_signature)) < 0)
+ return result;
+ }
+
+ if ((result = shader_normalise_io_registers(parser)) < 0)
+ return result;
+
+ if ((result = instruction_array_normalise_flat_constants(&parser->program)) < 0)
+ return result;
+
+ remove_dead_code(&parser->program);
+
+ if ((result = normalise_combined_samplers(parser)) < 0)
+ return result;
+ }
+
+ if ((result = flatten_control_flow_constructs(parser)) < 0)
+ return result;
+
+ if (TRACE_ON())
+ vkd3d_shader_trace(&parser->program);
+
+ if (!parser->failed && (result = vsir_validate(parser)) < 0)
+ return result;
+
+ if (parser->failed)
+ result = VKD3D_ERROR_INVALID_SHADER;
+
+ return result;
+}
+
+struct validation_context
+{
+ struct vkd3d_shader_parser *parser;
+ const struct vsir_program *program;
+ size_t instruction_idx;
+ bool invalid_instruction_idx;
+ bool dcl_temps_found;
+ enum vkd3d_shader_opcode phase;
+ enum cf_type
+ {
+ CF_TYPE_UNKNOWN = 0,
+ CF_TYPE_STRUCTURED,
+ CF_TYPE_BLOCKS,
+ } cf_type;
+ bool inside_block;
+
+ struct validation_context_temp_data
+ {
+ enum vsir_dimension dimension;
+ size_t first_seen;
+ } *temps;
+
+ struct validation_context_ssa_data
+ {
+ enum vsir_dimension dimension;
+ enum vkd3d_data_type data_type;
+ size_t first_seen;
+ uint32_t write_mask;
+ uint32_t read_mask;
+ size_t first_assigned;
+ } *ssas;
+
+ enum vkd3d_shader_opcode *blocks;
+ size_t depth;
+ size_t blocks_capacity;
+};
+
+static void VKD3D_PRINTF_FUNC(3, 4) validator_error(struct validation_context *ctx,
+ enum vkd3d_shader_error error, const char *format, ...)
+{
+ struct vkd3d_string_buffer buf;
+ va_list args;
+
+ vkd3d_string_buffer_init(&buf);
+
+ va_start(args, format);
+ vkd3d_string_buffer_vprintf(&buf, format, args);
+ va_end(args);
+
+ if (ctx->invalid_instruction_idx)
+ {
+ vkd3d_shader_parser_error(ctx->parser, error, "%s", buf.buffer);
+ ERR("VSIR validation error: %s\n", buf.buffer);
+ }
+ else
+ {
+ vkd3d_shader_parser_error(ctx->parser, error, "instruction %zu: %s", ctx->instruction_idx + 1, buf.buffer);
+ ERR("VSIR validation error: instruction %zu: %s\n", ctx->instruction_idx + 1, buf.buffer);
+ }
+
+ vkd3d_string_buffer_cleanup(&buf);
+}
+
+static void vsir_validate_src_param(struct validation_context *ctx,
+ const struct vkd3d_shader_src_param *src);
+
+static void vsir_validate_register(struct validation_context *ctx,
+ const struct vkd3d_shader_register *reg)
+{
+ unsigned int i;
+
+ if (reg->type >= VKD3DSPR_COUNT)
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, "Invalid register type %#x.",
+ reg->type);
if (reg->precision >= VKD3D_SHADER_REGISTER_PRECISION_COUNT)
validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_PRECISION, "Invalid register precision %#x.",
@@ -1540,16 +3177,135 @@ static void vsir_validate_register(struct validation_context *ctx,
switch (reg->type)
{
case VKD3DSPR_TEMP:
+ {
+ struct validation_context_temp_data *data;
+
if (reg->idx_count != 1)
+ {
validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, "Invalid index count %u for a TEMP register.",
reg->idx_count);
+ break;
+ }
- if (reg->idx_count >= 1 && reg->idx[0].rel_addr)
+ if (reg->idx[0].rel_addr)
validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, "Non-NULL relative address for a TEMP register.");
- if (reg->idx_count >= 1 && reg->idx[0].offset >= temp_count)
+ if (reg->idx[0].offset >= ctx->parser->program.temp_count)
+ {
validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, "TEMP register index %u exceeds the maximum count %u.",
- reg->idx[0].offset, temp_count);
+ reg->idx[0].offset, ctx->parser->program.temp_count);
+ break;
+ }
+
+ data = &ctx->temps[reg->idx[0].offset];
+
+ if (reg->dimension == VSIR_DIMENSION_NONE)
+ {
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, "Invalid dimension NONE for a TEMP register.");
+ break;
+ }
+
+ /* TEMP registers can be scalar or vec4, provided that
+ * each individual register always appears with the same
+ * dimension. */
+ if (data->dimension == VSIR_DIMENSION_NONE)
+ {
+ data->dimension = reg->dimension;
+ data->first_seen = ctx->instruction_idx;
+ }
+ else if (data->dimension != reg->dimension)
+ {
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, "Invalid dimension %#x for a TEMP register: "
+ "it has already been seen with dimension %#x at instruction %zu.",
+ reg->dimension, data->dimension, data->first_seen);
+ }
+ break;
+ }
+
+ case VKD3DSPR_SSA:
+ {
+ struct validation_context_ssa_data *data;
+
+ if (reg->idx_count != 1)
+ {
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, "Invalid index count %u for a SSA register.",
+ reg->idx_count);
+ break;
+ }
+
+ if (reg->idx[0].rel_addr)
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, "Non-NULL relative address for a SSA register.");
+
+ if (reg->idx[0].offset >= ctx->program->ssa_count)
+ {
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX,
+ "SSA register index %u exceeds the maximum count %u.",
+ reg->idx[0].offset, ctx->program->ssa_count);
+ break;
+ }
+
+ data = &ctx->ssas[reg->idx[0].offset];
+
+ if (reg->dimension == VSIR_DIMENSION_NONE)
+ {
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, "Invalid dimension NONE for a SSA register.");
+ break;
+ }
+
+ /* SSA registers can be scalar or vec4, provided that each
+ * individual register always appears with the same
+ * dimension. */
+ if (data->dimension == VSIR_DIMENSION_NONE)
+ {
+ data->dimension = reg->dimension;
+ data->data_type = reg->data_type;
+ data->first_seen = ctx->instruction_idx;
+ }
+ else
+ {
+ if (data->dimension != reg->dimension)
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, "Invalid dimension %#x for a SSA register: "
+ "it has already been seen with dimension %#x at instruction %zu.",
+ reg->dimension, data->dimension, data->first_seen);
+
+ if (data_type_is_64_bit(data->data_type) != data_type_is_64_bit(reg->data_type))
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, "Invalid data type %#x for a SSA register: "
+ "it has already been seen with data type %#x at instruction %zu.",
+ reg->data_type, data->data_type, data->first_seen);
+ }
+ break;
+ }
+
+ case VKD3DSPR_LABEL:
+ if (reg->precision != VKD3D_SHADER_REGISTER_PRECISION_DEFAULT)
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_PRECISION, "Invalid precision %#x for a LABEL register.",
+ reg->precision);
+
+ if (reg->data_type != VKD3D_DATA_UINT)
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, "Invalid data type %#x for a LABEL register.",
+ reg->data_type);
+
+ if (reg->dimension != VSIR_DIMENSION_NONE)
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION, "Invalid dimension %#x for a LABEL register.",
+ reg->dimension);
+
+ if (reg->idx_count != 1)
+ {
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, "Invalid index count %u for a LABEL register.",
+ reg->idx_count);
+ break;
+ }
+
+ if (reg->idx[0].rel_addr)
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX, "Non-NULL relative address for a LABEL register.");
+
+ /* Index == 0 is invalid, but it is temporarily allowed
+ * for intermediate stages. Once we support validation
+ * dialects we can selectively check for that. */
+ if (reg->idx[0].offset > ctx->program->block_count)
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX,
+ "LABEL register index %u exceeds the maximum count %u.",
+ reg->idx[0].offset, ctx->program->block_count);
break;
case VKD3DSPR_NULL:
@@ -1584,6 +3340,26 @@ static void vsir_validate_dst_param(struct validation_context *ctx,
validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_WRITE_MASK, "Destination has invalid write mask %#x.",
dst->write_mask);
+ switch (dst->reg.dimension)
+ {
+ case VSIR_DIMENSION_SCALAR:
+ if (dst->write_mask != VKD3DSP_WRITEMASK_0)
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_WRITE_MASK, "Scalar destination has invalid write mask %#x.",
+ dst->write_mask);
+ break;
+
+ case VSIR_DIMENSION_VEC4:
+ if (dst->write_mask == 0)
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_WRITE_MASK, "Vec4 destination has empty write mask.");
+ break;
+
+ default:
+ if (dst->write_mask != 0)
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_WRITE_MASK, "Destination of dimension %u has invalid write mask %#x.",
+ dst->reg.dimension, dst->write_mask);
+ break;
+ }
+
if (dst->modifiers & ~VKD3DSPDM_MASK)
validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_MODIFIERS, "Destination has invalid modifiers %#x.",
dst->modifiers);
@@ -1603,6 +3379,41 @@ static void vsir_validate_dst_param(struct validation_context *ctx,
validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SHIFT, "Destination has invalid shift %#x.",
dst->shift);
}
+
+ switch (dst->reg.type)
+ {
+ case VKD3DSPR_SSA:
+ if (dst->reg.idx[0].offset < ctx->parser->program.ssa_count)
+ {
+ struct validation_context_ssa_data *data = &ctx->ssas[dst->reg.idx[0].offset];
+
+ if (data->write_mask == 0)
+ {
+ data->write_mask = dst->write_mask;
+ data->first_assigned = ctx->instruction_idx;
+ }
+ else
+ {
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SSA_USAGE,
+ "SSA register is already assigned at instruction %zu.",
+ data->first_assigned);
+ }
+ }
+ break;
+
+ case VKD3DSPR_IMMCONST:
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE,
+ "Invalid IMMCONST register used as destination parameter.");
+ break;
+
+ case VKD3DSPR_IMMCONST64:
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE,
+ "Invalid IMMCONST64 register used as destination parameter.");
+ break;
+
+ default:
+ break;
+ }
}
static void vsir_validate_src_param(struct validation_context *ctx,
@@ -1614,9 +3425,30 @@ static void vsir_validate_src_param(struct validation_context *ctx,
validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SWIZZLE, "Source has invalid swizzle %#x.",
src->swizzle);
+ if (src->reg.dimension != VSIR_DIMENSION_VEC4 && src->swizzle != 0)
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SWIZZLE, "Source of dimension %u has invalid swizzle %#x.",
+ src->reg.dimension, src->swizzle);
+
if (src->modifiers >= VKD3DSPSM_COUNT)
validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_MODIFIERS, "Source has invalid modifiers %#x.",
src->modifiers);
+
+ switch (src->reg.type)
+ {
+ case VKD3DSPR_SSA:
+ if (src->reg.idx[0].offset < ctx->parser->program.ssa_count)
+ {
+ struct validation_context_ssa_data *data = &ctx->ssas[src->reg.idx[0].offset];
+ unsigned int i;
+
+ for (i = 0; i < VKD3D_VEC4_SIZE; ++i)
+ data->read_mask |= (1u << vsir_swizzle_get_component(src->swizzle, i));
+ }
+ break;
+
+ default:
+ break;
+ }
}
static void vsir_validate_dst_count(struct validation_context *ctx,
@@ -1637,11 +3469,64 @@ static void vsir_validate_src_count(struct validation_context *ctx,
instruction->src_count, instruction->handler_idx, count);
}
+static bool vsir_validate_src_min_count(struct validation_context *ctx,
+ const struct vkd3d_shader_instruction *instruction, unsigned int count)
+{
+ if (instruction->src_count < count)
+ {
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SOURCE_COUNT,
+ "Invalid source count %u for an instruction of type %#x, expected at least %u.",
+ instruction->src_count, instruction->handler_idx, count);
+ return false;
+ }
+
+ return true;
+}
+
+static bool vsir_validate_src_max_count(struct validation_context *ctx,
+ const struct vkd3d_shader_instruction *instruction, unsigned int count)
+{
+ if (instruction->src_count > count)
+ {
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SOURCE_COUNT,
+ "Invalid source count %u for an instruction of type %#x, expected at most %u.",
+ instruction->src_count, instruction->handler_idx, count);
+ return false;
+ }
+
+ return true;
+}
+
+static const char *name_from_cf_type(enum cf_type type)
+{
+ switch (type)
+ {
+ case CF_TYPE_STRUCTURED:
+ return "structured";
+ case CF_TYPE_BLOCKS:
+ return "block-based";
+ default:
+ vkd3d_unreachable();
+ }
+}
+
+static void vsir_validate_cf_type(struct validation_context *ctx,
+ const struct vkd3d_shader_instruction *instruction, enum cf_type expected_type)
+{
+ assert(ctx->cf_type != CF_TYPE_UNKNOWN);
+ assert(expected_type != CF_TYPE_UNKNOWN);
+ if (ctx->cf_type != expected_type)
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "Invalid instruction %#x in %s shader.",
+ instruction->handler_idx, name_from_cf_type(ctx->cf_type));
+}
+
static void vsir_validate_instruction(struct validation_context *ctx)
{
- const struct vkd3d_shader_instruction *instruction = &ctx->parser->instructions.elements[ctx->instruction_idx];
+ const struct vkd3d_shader_version *version = &ctx->program->shader_version;
+ const struct vkd3d_shader_instruction *instruction;
size_t i;
+ instruction = &ctx->program->instructions.elements[ctx->instruction_idx];
ctx->parser->location = instruction->location;
for (i = 0; i < instruction->dst_count; ++i)
@@ -1664,26 +3549,68 @@ static void vsir_validate_instruction(struct validation_context *ctx)
case VKD3DSIH_HS_JOIN_PHASE:
vsir_validate_dst_count(ctx, instruction, 0);
vsir_validate_src_count(ctx, instruction, 0);
- if (ctx->parser->shader_version.type != VKD3D_SHADER_TYPE_HULL)
+ if (version->type != VKD3D_SHADER_TYPE_HULL)
validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_HANDLER, "Phase instruction %#x is only valid in a hull shader.",
instruction->handler_idx);
if (ctx->depth != 0)
- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INSTRUCTION_NESTING, "Phase instruction %#x must appear to top level.",
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "Phase instruction %#x must appear to top level.",
instruction->handler_idx);
ctx->phase = instruction->handler_idx;
ctx->dcl_temps_found = false;
- ctx->temp_count = 0;
return;
default:
break;
}
- if (ctx->parser->shader_version.type == VKD3D_SHADER_TYPE_HULL &&
- ctx->phase == VKD3DSIH_INVALID)
- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_HANDLER, "Instruction %#x appear before any phase instruction in a hull shader.",
+ if (version->type == VKD3D_SHADER_TYPE_HULL && ctx->phase == VKD3DSIH_INVALID)
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_HANDLER,
+ "Instruction %#x appear before any phase instruction in a hull shader.",
instruction->handler_idx);
+ /* We support two different control flow types in shaders:
+ * block-based, like DXIL and SPIR-V, and structured, like D3DBC
+ * and TPF. The shader is detected as block-based when its first
+ * instruction, except for DCL_* and phases, is a LABEL. Currently
+ * we mandate that each shader is either purely block-based or
+ * purely structured. In principle we could allow structured
+ * constructs in a block, provided they are confined in a single
+ * block, but need for that hasn't arisen yet, so we don't. */
+ if (ctx->cf_type == CF_TYPE_UNKNOWN && !vsir_instruction_is_dcl(instruction))
+ {
+ if (instruction->handler_idx == VKD3DSIH_LABEL)
+ ctx->cf_type = CF_TYPE_BLOCKS;
+ else
+ ctx->cf_type = CF_TYPE_STRUCTURED;
+ }
+
+ if (ctx->cf_type == CF_TYPE_BLOCKS && !vsir_instruction_is_dcl(instruction))
+ {
+ switch (instruction->handler_idx)
+ {
+ case VKD3DSIH_LABEL:
+ if (ctx->inside_block)
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "Invalid LABEL instruction inside a block.");
+ ctx->inside_block = true;
+ break;
+
+ case VKD3DSIH_RET:
+ case VKD3DSIH_BRANCH:
+ case VKD3DSIH_SWITCH_MONOLITHIC:
+ if (!ctx->inside_block)
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "Invalid instruction %#x outside any block.",
+ instruction->handler_idx);
+ ctx->inside_block = false;
+ break;
+
+ default:
+ if (!ctx->inside_block)
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "Invalid instruction %#x outside any block.",
+ instruction->handler_idx);
+ break;
+ }
+ }
+
switch (instruction->handler_idx)
{
case VKD3DSIH_DCL_TEMPS:
@@ -1691,14 +3618,15 @@ static void vsir_validate_instruction(struct validation_context *ctx)
vsir_validate_src_count(ctx, instruction, 0);
if (ctx->dcl_temps_found)
validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_DUPLICATE_DCL_TEMPS, "Duplicate DCL_TEMPS instruction.");
- if (instruction->declaration.count > ctx->parser->shader_desc.temp_count)
- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DCL_TEMPS, "Invalid DCL_TEMPS count %u, expected at most %u.",
- instruction->declaration.count, ctx->parser->shader_desc.temp_count);
+ if (instruction->declaration.count > ctx->program->temp_count)
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DCL_TEMPS,
+ "Invalid DCL_TEMPS count %u, expected at most %u.",
+ instruction->declaration.count, ctx->program->temp_count);
ctx->dcl_temps_found = true;
- ctx->temp_count = instruction->declaration.count;
break;
case VKD3DSIH_IF:
+ vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED);
vsir_validate_dst_count(ctx, instruction, 0);
vsir_validate_src_count(ctx, instruction, 1);
if (!vkd3d_array_reserve((void **)&ctx->blocks, &ctx->blocks_capacity, ctx->depth + 1, sizeof(*ctx->blocks)))
@@ -1707,6 +3635,7 @@ static void vsir_validate_instruction(struct validation_context *ctx)
break;
case VKD3DSIH_IFC:
+ vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED);
vsir_validate_dst_count(ctx, instruction, 0);
vsir_validate_src_count(ctx, instruction, 2);
if (!vkd3d_array_reserve((void **)&ctx->blocks, &ctx->blocks_capacity, ctx->depth + 1, sizeof(*ctx->blocks)))
@@ -1715,41 +3644,46 @@ static void vsir_validate_instruction(struct validation_context *ctx)
break;
case VKD3DSIH_ELSE:
+ vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED);
vsir_validate_dst_count(ctx, instruction, 0);
vsir_validate_src_count(ctx, instruction, 0);
if (ctx->depth == 0 || ctx->blocks[ctx->depth - 1] != VKD3DSIH_IF)
- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INSTRUCTION_NESTING, "ELSE instruction doesn't terminate IF block.");
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "ELSE instruction doesn't terminate IF block.");
else
ctx->blocks[ctx->depth - 1] = instruction->handler_idx;
break;
case VKD3DSIH_ENDIF:
+ vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED);
vsir_validate_dst_count(ctx, instruction, 0);
vsir_validate_src_count(ctx, instruction, 0);
if (ctx->depth == 0 || (ctx->blocks[ctx->depth - 1] != VKD3DSIH_IF && ctx->blocks[ctx->depth - 1] != VKD3DSIH_ELSE))
- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INSTRUCTION_NESTING, "ENDIF instruction doesn't terminate IF/ELSE block.");
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "ENDIF instruction doesn't terminate IF/ELSE block.");
else
--ctx->depth;
break;
case VKD3DSIH_LOOP:
+ vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED);
vsir_validate_dst_count(ctx, instruction, 0);
- vsir_validate_src_count(ctx, instruction, ctx->parser->shader_version.major <= 3 ? 2 : 0);
+ vsir_validate_src_count(ctx, instruction, version->major <= 3 ? 2 : 0);
if (!vkd3d_array_reserve((void **)&ctx->blocks, &ctx->blocks_capacity, ctx->depth + 1, sizeof(*ctx->blocks)))
return;
ctx->blocks[ctx->depth++] = instruction->handler_idx;
break;
case VKD3DSIH_ENDLOOP:
+ vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED);
vsir_validate_dst_count(ctx, instruction, 0);
vsir_validate_src_count(ctx, instruction, 0);
if (ctx->depth == 0 || ctx->blocks[ctx->depth - 1] != VKD3DSIH_LOOP)
- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INSTRUCTION_NESTING, "ENDLOOP instruction doesn't terminate LOOP block.");
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "ENDLOOP instruction doesn't terminate LOOP block.");
else
--ctx->depth;
break;
case VKD3DSIH_REP:
+ vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED);
vsir_validate_dst_count(ctx, instruction, 0);
vsir_validate_src_count(ctx, instruction, 1);
if (!vkd3d_array_reserve((void **)&ctx->blocks, &ctx->blocks_capacity, ctx->depth + 1, sizeof(*ctx->blocks)))
@@ -1758,15 +3692,17 @@ static void vsir_validate_instruction(struct validation_context *ctx)
break;
case VKD3DSIH_ENDREP:
+ vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED);
vsir_validate_dst_count(ctx, instruction, 0);
vsir_validate_src_count(ctx, instruction, 0);
if (ctx->depth == 0 || ctx->blocks[ctx->depth - 1] != VKD3DSIH_REP)
- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INSTRUCTION_NESTING, "ENDREP instruction doesn't terminate REP block.");
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "ENDREP instruction doesn't terminate REP block.");
else
--ctx->depth;
break;
case VKD3DSIH_SWITCH:
+ vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED);
vsir_validate_dst_count(ctx, instruction, 0);
vsir_validate_src_count(ctx, instruction, 1);
if (!vkd3d_array_reserve((void **)&ctx->blocks, &ctx->blocks_capacity, ctx->depth + 1, sizeof(*ctx->blocks)))
@@ -1775,35 +3711,223 @@ static void vsir_validate_instruction(struct validation_context *ctx)
break;
case VKD3DSIH_ENDSWITCH:
+ vsir_validate_cf_type(ctx, instruction, CF_TYPE_STRUCTURED);
vsir_validate_dst_count(ctx, instruction, 0);
vsir_validate_src_count(ctx, instruction, 0);
if (ctx->depth == 0 || ctx->blocks[ctx->depth - 1] != VKD3DSIH_SWITCH)
- validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INSTRUCTION_NESTING, "ENDSWITCH instruction doesn't terminate SWITCH block.");
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "ENDSWITCH instruction doesn't terminate SWITCH block.");
else
--ctx->depth;
break;
+ case VKD3DSIH_RET:
+ vsir_validate_dst_count(ctx, instruction, 0);
+ vsir_validate_src_count(ctx, instruction, 0);
+ break;
+
+ case VKD3DSIH_LABEL:
+ vsir_validate_cf_type(ctx, instruction, CF_TYPE_BLOCKS);
+ vsir_validate_dst_count(ctx, instruction, 0);
+ vsir_validate_src_count(ctx, instruction, 1);
+ if (instruction->src_count >= 1 && !vsir_register_is_label(&instruction->src[0].reg))
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE,
+ "Invalid register of type %#x in a LABEL instruction, expected LABEL.",
+ instruction->src[0].reg.type);
+ break;
+
+ case VKD3DSIH_BRANCH:
+ vsir_validate_cf_type(ctx, instruction, CF_TYPE_BLOCKS);
+ vsir_validate_dst_count(ctx, instruction, 0);
+ if (!vsir_validate_src_min_count(ctx, instruction, 1))
+ break;
+ if (vsir_register_is_label(&instruction->src[0].reg))
+ {
+ /* Unconditional branch: parameters are jump label,
+ * optional merge label, optional continue label. */
+ vsir_validate_src_max_count(ctx, instruction, 3);
+
+ for (i = 0; i < instruction->src_count; ++i)
+ {
+ if (!vsir_register_is_label(&instruction->src[i].reg))
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE,
+ "Invalid register of type %#x in unconditional BRANCH instruction, expected LABEL.",
+ instruction->src[i].reg.type);
+ }
+ }
+ else
+ {
+ /* Conditional branch: parameters are condition, true
+ * jump label, false jump label, optional merge label,
+ * optional continue label. */
+ vsir_validate_src_min_count(ctx, instruction, 3);
+ vsir_validate_src_max_count(ctx, instruction, 5);
+
+ for (i = 1; i < instruction->src_count; ++i)
+ {
+ if (!vsir_register_is_label(&instruction->src[i].reg))
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE,
+ "Invalid register of type %#x in conditional BRANCH instruction, expected LABEL.",
+ instruction->src[i].reg.type);
+ }
+ }
+ break;
+
+ case VKD3DSIH_SWITCH_MONOLITHIC:
+ {
+ unsigned int case_count;
+
+ vsir_validate_cf_type(ctx, instruction, CF_TYPE_BLOCKS);
+ vsir_validate_dst_count(ctx, instruction, 0);
+ /* Parameters are source, default label, merge label and
+ * then pairs of constant value and case label. */
+ if (!vsir_validate_src_min_count(ctx, instruction, 3))
+ break;
+ if (instruction->src_count % 2 != 1)
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SOURCE_COUNT,
+ "Invalid source count %u for a monolithic SWITCH instruction, it must be an odd number.",
+ instruction->src_count);
+
+ if (!vsir_register_is_label(&instruction->src[1].reg))
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE,
+ "Invalid default label register of type %#x in monolithic SWITCH instruction, expected LABEL.",
+ instruction->src[1].reg.type);
+
+ if (!vsir_register_is_label(&instruction->src[2].reg))
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE,
+ "Invalid merge label register of type %#x in monolithic SWITCH instruction, expected LABEL.",
+ instruction->src[2].reg.type);
+
+ case_count = (instruction->src_count - 3) / 2;
+
+ for (i = 0; i < case_count; ++i)
+ {
+ unsigned int value_idx = 3 + 2 * i;
+ unsigned int label_idx = 3 + 2 * i + 1;
+
+ if (!register_is_constant(&instruction->src[value_idx].reg))
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE,
+ "Invalid value register for case %zu of type %#x in monolithic SWITCH instruction, "
+ "expected IMMCONST or IMMCONST64.", i, instruction->src[value_idx].reg.type);
+
+ if (!vsir_register_is_label(&instruction->src[label_idx].reg))
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE,
+ "Invalid label register for case %zu of type %#x in monolithic SWITCH instruction, "
+ "expected LABEL.", i, instruction->src[value_idx].reg.type);
+ }
+ break;
+ }
+
+ case VKD3DSIH_PHI:
+ {
+ unsigned int incoming_count;
+
+ vsir_validate_cf_type(ctx, instruction, CF_TYPE_BLOCKS);
+ vsir_validate_dst_count(ctx, instruction, 1);
+ vsir_validate_src_min_count(ctx, instruction, 2);
+ if (instruction->src_count % 2 != 0)
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SOURCE_COUNT,
+ "Invalid source count %u for a PHI instruction, it must be an even number.",
+ instruction->src_count);
+ incoming_count = instruction->src_count / 2;
+
+ if (!register_is_ssa(&instruction->dst[0].reg))
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE,
+ "Invalid destination of type %#x in PHI instruction, expected SSA.",
+ instruction->dst[0].reg.type);
+
+ if (instruction->dst[0].reg.dimension != VSIR_DIMENSION_SCALAR)
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION,
+ "Invalid destination dimension %#x in PHI instruction, expected scalar.",
+ instruction->dst[0].reg.dimension);
+
+ if (instruction->dst[0].modifiers != VKD3DSPDM_NONE)
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_MODIFIERS,
+ "Invalid modifiers %#x for the destination of a PHI instruction, expected none.",
+ instruction->dst[0].modifiers);
+
+ if (instruction->dst[0].shift != 0)
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SHIFT,
+ "Invalid shift %#x for the destination of a PHI instruction, expected none.",
+ instruction->dst[0].shift);
+
+ for (i = 0; i < incoming_count; ++i)
+ {
+ unsigned int value_idx = 2 * i;
+ unsigned int label_idx = 2 * i + 1;
+
+ if (!register_is_constant(&instruction->src[value_idx].reg) && !register_is_ssa(&instruction->src[value_idx].reg))
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE,
+ "Invalid value register for incoming %zu of type %#x in PHI instruction, "
+ "expected SSA, IMMCONST or IMMCONST64.", i, instruction->src[value_idx].reg.type);
+
+ if (instruction->src[value_idx].reg.dimension != VSIR_DIMENSION_SCALAR)
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_DIMENSION,
+ "Invalid value dimension %#x for incoming %zu in PHI instruction, expected scalar.",
+ instruction->src[value_idx].reg.dimension, i);
+
+ if (!vsir_register_is_label(&instruction->src[label_idx].reg))
+ validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE,
+ "Invalid label register for case %zu of type %#x in PHI instruction, "
+ "expected LABEL.", i, instruction->src[value_idx].reg.type);
+ }
+ break;
+ }
+
default:
break;
}
}
-void vsir_validate(struct vkd3d_shader_parser *parser)
+enum vkd3d_result vsir_validate(struct vkd3d_shader_parser *parser)
{
struct validation_context ctx =
{
.parser = parser,
+ .program = &parser->program,
.phase = VKD3DSIH_INVALID,
};
+ unsigned int i;
if (!(parser->config_flags & VKD3D_SHADER_CONFIG_FLAG_FORCE_VALIDATION))
- return;
+ return VKD3D_OK;
- for (ctx.instruction_idx = 0; ctx.instruction_idx < parser->instructions.count; ++ctx.instruction_idx)
+ if (!(ctx.temps = vkd3d_calloc(ctx.program->temp_count, sizeof(*ctx.temps))))
+ goto fail;
+
+ if (!(ctx.ssas = vkd3d_calloc(ctx.program->ssa_count, sizeof(*ctx.ssas))))
+ goto fail;
+
+ for (ctx.instruction_idx = 0; ctx.instruction_idx < parser->program.instructions.count; ++ctx.instruction_idx)
vsir_validate_instruction(&ctx);
+ ctx.invalid_instruction_idx = true;
+
if (ctx.depth != 0)
- validator_error(&ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_INSTRUCTION_NESTING, "%zu nested blocks were not closed.", ctx.depth);
+ validator_error(&ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "%zu nested blocks were not closed.", ctx.depth);
+
+ if (ctx.inside_block)
+ validator_error(&ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW, "Last block was not closed.");
+
+ for (i = 0; i < ctx.program->ssa_count; ++i)
+ {
+ struct validation_context_ssa_data *data = &ctx.ssas[i];
+
+ if ((data->write_mask | data->read_mask) != data->write_mask)
+ validator_error(&ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SSA_USAGE,
+ "SSA register %u has invalid read mask %#x, which is not a subset of the write mask %#x "
+ "at the point of definition.", i, data->read_mask, data->write_mask);
+ }
+
+ vkd3d_free(ctx.blocks);
+ vkd3d_free(ctx.temps);
+ vkd3d_free(ctx.ssas);
+
+ return VKD3D_OK;
+
+fail:
+ vkd3d_free(ctx.blocks);
+ vkd3d_free(ctx.temps);
+ vkd3d_free(ctx.ssas);
- free(ctx.blocks);
+ return VKD3D_ERROR_OUT_OF_MEMORY;
}
diff --git a/libs/vkd3d/libs/vkd3d-shader/spirv.c b/libs/vkd3d/libs/vkd3d-shader/spirv.c
index c8a43adbe03..6c92b03b216 100644
--- a/libs/vkd3d/libs/vkd3d-shader/spirv.c
+++ b/libs/vkd3d/libs/vkd3d-shader/spirv.c
@@ -133,7 +133,7 @@ static void vkd3d_spirv_dump(const struct vkd3d_shader_code *spirv,
}
}
-static void vkd3d_spirv_validate(const struct vkd3d_shader_code *spirv,
+static bool vkd3d_spirv_validate(struct vkd3d_string_buffer *buffer, const struct vkd3d_shader_code *spirv,
enum vkd3d_shader_spirv_environment environment)
{
spv_diagnostic diagnostic = NULL;
@@ -145,12 +145,13 @@ static void vkd3d_spirv_validate(const struct vkd3d_shader_code *spirv,
if ((ret = spvValidateBinary(context, spirv->code, spirv->size / sizeof(uint32_t),
&diagnostic)))
{
- FIXME("Failed to validate SPIR-V binary, ret %d.\n", ret);
- FIXME("Diagnostic message: %s.\n", debugstr_a(diagnostic->error));
+ vkd3d_string_buffer_printf(buffer, "%s", diagnostic->error);
}
spvDiagnosticDestroy(diagnostic);
spvContextDestroy(context);
+
+ return !ret;
}
#else
@@ -163,8 +164,11 @@ static enum vkd3d_result vkd3d_spirv_binary_to_text(const struct vkd3d_shader_co
}
static void vkd3d_spirv_dump(const struct vkd3d_shader_code *spirv,
enum vkd3d_shader_spirv_environment environment) {}
-static void vkd3d_spirv_validate(const struct vkd3d_shader_code *spirv,
- enum vkd3d_shader_spirv_environment environment) {}
+static bool vkd3d_spirv_validate(struct vkd3d_string_buffer *buffer, const struct vkd3d_shader_code *spirv,
+ enum vkd3d_shader_spirv_environment environment)
+{
+ return true;
+}
#endif /* HAVE_SPIRV_TOOLS */
@@ -219,16 +223,6 @@ enum vkd3d_shader_input_sysval_semantic vkd3d_siv_from_sysval_indexed(enum vkd3d
}
}
-static inline bool register_is_undef(const struct vkd3d_shader_register *reg)
-{
- return reg->type == VKD3DSPR_UNDEF;
-}
-
-static inline bool register_is_constant_or_undef(const struct vkd3d_shader_register *reg)
-{
- return register_is_constant(reg) || register_is_undef(reg);
-}
-
#define VKD3D_SPIRV_VERSION 0x00010000
#define VKD3D_SPIRV_GENERATOR_ID 18
#define VKD3D_SPIRV_GENERATOR_VERSION 10
@@ -851,20 +845,6 @@ static void vkd3d_spirv_end_function_stream_insertion(struct vkd3d_spirv_builder
builder->insertion_location = ~(size_t)0;
}
-struct vkd3d_spirv_op_branch_conditional
-{
- uint32_t opcode;
- uint32_t condition_id;
- uint32_t true_label;
- uint32_t false_label;
-};
-
-static struct vkd3d_spirv_op_branch_conditional *vkd3d_spirv_as_op_branch_conditional(
- struct vkd3d_spirv_stream *stream, size_t location)
-{
- return (struct vkd3d_spirv_op_branch_conditional *)&stream->words[location];
-}
-
static void vkd3d_spirv_build_op_capability(struct vkd3d_spirv_stream *stream,
SpvCapability cap)
{
@@ -1194,6 +1174,16 @@ static uint32_t vkd3d_spirv_get_op_constant64(struct vkd3d_spirv_builder *builde
(const uint32_t *)&value, 2, vkd3d_spirv_build_op_constant64);
}
+static uint32_t vkd3d_spirv_build_op_constant_null(struct vkd3d_spirv_builder *builder, uint32_t result_type)
+{
+ return vkd3d_spirv_build_op_tr(builder, &builder->global_stream, SpvOpConstantNull, result_type);
+}
+
+static uint32_t vkd3d_spirv_get_op_constant_null(struct vkd3d_spirv_builder *builder, uint32_t result_type)
+{
+ return vkd3d_spirv_build_once1(builder, SpvOpConstantNull, result_type, vkd3d_spirv_build_op_constant_null);
+}
+
static uint32_t vkd3d_spirv_build_op_constant_composite(struct vkd3d_spirv_builder *builder,
uint32_t result_type, const uint32_t *constituents, unsigned int constituent_count)
{
@@ -1515,6 +1505,25 @@ static uint32_t vkd3d_spirv_build_op_uless_than_equal(struct vkd3d_spirv_builder
SpvOpULessThanEqual, result_type, operand0, operand1);
}
+static uint32_t vkd3d_spirv_build_op_is_inf(struct vkd3d_spirv_builder *builder,
+ uint32_t result_type, uint32_t operand)
+{
+ return vkd3d_spirv_build_op_tr1(builder, &builder->function_stream, SpvOpIsInf, result_type, operand);
+}
+
+static uint32_t vkd3d_spirv_build_op_is_nan(struct vkd3d_spirv_builder *builder,
+ uint32_t result_type, uint32_t operand)
+{
+ return vkd3d_spirv_build_op_tr1(builder, &builder->function_stream, SpvOpIsNan, result_type, operand);
+}
+
+static uint32_t vkd3d_spirv_build_op_logical_equal(struct vkd3d_spirv_builder *builder,
+ uint32_t result_type, uint32_t operand0, uint32_t operand1)
+{
+ return vkd3d_spirv_build_op_tr2(builder, &builder->function_stream,
+ SpvOpLogicalEqual, result_type, operand0, operand1);
+}
+
static uint32_t vkd3d_spirv_build_op_convert_utof(struct vkd3d_spirv_builder *builder,
uint32_t result_type, uint32_t unsigned_value)
{
@@ -1750,6 +1759,15 @@ static uint32_t vkd3d_spirv_build_op_glsl_std450_max(struct vkd3d_spirv_builder
GLSLstd450NMax, operands, ARRAY_SIZE(operands));
}
+static uint32_t vkd3d_spirv_build_op_glsl_std450_umin(struct vkd3d_spirv_builder *builder,
+ uint32_t result_type, uint32_t x, uint32_t y)
+{
+ uint32_t glsl_std450_id = vkd3d_spirv_get_glsl_std450_instr_set(builder);
+ uint32_t operands[] = {x, y};
+ return vkd3d_spirv_build_op_ext_inst(builder, result_type, glsl_std450_id,
+ GLSLstd450UMin, operands, ARRAY_SIZE(operands));
+}
+
static uint32_t vkd3d_spirv_build_op_glsl_std450_nclamp(struct vkd3d_spirv_builder *builder,
uint32_t result_type, uint32_t x, uint32_t min, uint32_t max)
{
@@ -1783,6 +1801,8 @@ static uint32_t vkd3d_spirv_get_type_id(struct vkd3d_spirv_builder *builder,
break;
case VKD3D_SHADER_COMPONENT_DOUBLE:
return vkd3d_spirv_get_op_type_float(builder, 64);
+ case VKD3D_SHADER_COMPONENT_UINT64:
+ return vkd3d_spirv_get_op_type_int(builder, 64, 0);
default:
FIXME("Unhandled component type %#x.\n", component_type);
return 0;
@@ -1816,6 +1836,8 @@ static uint32_t vkd3d_spirv_get_type_id_for_data_type(struct vkd3d_spirv_builder
break;
case VKD3D_DATA_DOUBLE:
return vkd3d_spirv_get_op_type_float(builder, 64);
+ case VKD3D_DATA_UINT64:
+ return vkd3d_spirv_get_op_type_int(builder, 64, 0);
case VKD3D_DATA_BOOL:
return vkd3d_spirv_get_op_type_bool(builder);
default:
@@ -1858,8 +1880,6 @@ static void vkd3d_spirv_builder_begin_main_function(struct vkd3d_spirv_builder *
vkd3d_spirv_build_op_function(builder, void_id,
builder->main_function_id, SpvFunctionControlMaskNone, function_type_id);
- vkd3d_spirv_build_op_label(builder, vkd3d_spirv_alloc_id(builder));
- builder->main_function_location = vkd3d_spirv_stream_current_location(&builder->function_stream);
}
static void vkd3d_spirv_builder_free(struct vkd3d_spirv_builder *builder)
@@ -1922,6 +1942,8 @@ static bool vkd3d_spirv_compile_module(struct vkd3d_spirv_builder *builder,
vkd3d_spirv_build_op_extension(&stream, "SPV_EXT_descriptor_indexing");
if (vkd3d_spirv_capability_is_enabled(builder, SpvCapabilityStencilExportEXT))
vkd3d_spirv_build_op_extension(&stream, "SPV_EXT_shader_stencil_export");
+ if (vkd3d_spirv_capability_is_enabled(builder, SpvCapabilityShaderViewportIndexLayerEXT))
+ vkd3d_spirv_build_op_extension(&stream, "SPV_EXT_shader_viewport_index_layer");
if (builder->ext_instr_set_glsl_450)
vkd3d_spirv_build_op_ext_inst_import(&stream, builder->ext_instr_set_glsl_450, "GLSL.std.450");
@@ -2152,6 +2174,7 @@ static void vkd3d_symbol_make_register(struct vkd3d_symbol *symbol,
break;
case VKD3DSPR_IMMCONSTBUFFER:
+ symbol->key.reg.idx = reg->idx_count > 1 ? reg->idx[0].offset : 0;
break;
default:
@@ -2159,9 +2182,18 @@ static void vkd3d_symbol_make_register(struct vkd3d_symbol *symbol,
}
}
+static void vkd3d_symbol_make_io(struct vkd3d_symbol *symbol,
+ enum vkd3d_shader_register_type type, unsigned int index)
+{
+ symbol->type = VKD3D_SYMBOL_REGISTER;
+ memset(&symbol->key, 0, sizeof(symbol->key));
+ symbol->key.reg.type = type;
+ symbol->key.reg.idx = index;
+}
+
static void vkd3d_symbol_set_register_info(struct vkd3d_symbol *symbol,
uint32_t val_id, SpvStorageClass storage_class,
- enum vkd3d_shader_component_type component_type, DWORD write_mask)
+ enum vkd3d_shader_component_type component_type, uint32_t write_mask)
{
symbol->id = val_id;
symbol->descriptor_array = NULL;
@@ -2230,51 +2262,6 @@ static const char *debug_vkd3d_symbol(const struct vkd3d_symbol *symbol)
}
}
-struct vkd3d_if_cf_info
-{
- size_t stream_location;
- unsigned int id;
- uint32_t merge_block_id;
- uint32_t else_block_id;
-};
-
-struct vkd3d_loop_cf_info
-{
- uint32_t header_block_id;
- uint32_t continue_block_id;
- uint32_t merge_block_id;
-};
-
-struct vkd3d_switch_cf_info
-{
- size_t stream_location;
- unsigned int id;
- uint32_t selector_id;
- uint32_t merge_block_id;
- uint32_t default_block_id;
- uint32_t *case_blocks;
- size_t case_blocks_size;
- unsigned int case_block_count;
-};
-
-struct vkd3d_control_flow_info
-{
- union
- {
- struct vkd3d_if_cf_info if_;
- struct vkd3d_loop_cf_info loop;
- struct vkd3d_switch_cf_info switch_;
- } u;
-
- enum
- {
- VKD3D_BLOCK_IF,
- VKD3D_BLOCK_LOOP,
- VKD3D_BLOCK_SWITCH,
- } current_block;
- bool inside_block;
-};
-
struct vkd3d_push_constant_buffer_binding
{
struct vkd3d_shader_register reg;
@@ -2328,13 +2315,6 @@ struct spirv_compiler
enum vkd3d_shader_type shader_type;
- unsigned int branch_id;
- unsigned int loop_id;
- unsigned int switch_id;
- unsigned int control_flow_depth;
- struct vkd3d_control_flow_info *control_flow_info;
- size_t control_flow_info_size;
-
struct vkd3d_shader_interface_info shader_interface;
struct vkd3d_shader_descriptor_offset_info offset_info;
uint32_t descriptor_offsets_member_id;
@@ -2343,8 +2323,7 @@ struct spirv_compiler
struct vkd3d_push_constant_buffer_binding *push_constants;
const struct vkd3d_shader_spirv_target_info *spirv_target_info;
- bool main_block_open;
- bool after_declarations_section;
+ bool prolog_emitted;
struct shader_signature input_signature;
struct shader_signature output_signature;
struct shader_signature patch_constant_signature;
@@ -2358,13 +2337,16 @@ struct spirv_compiler
uint32_t private_output_variable[MAX_REG_OUTPUT + 1]; /* 1 entry for oDepth */
uint32_t private_output_variable_write_mask[MAX_REG_OUTPUT + 1]; /* 1 entry for oDepth */
uint32_t epilogue_function_id;
+ uint32_t discard_function_id;
uint32_t binding_idx;
const struct vkd3d_shader_scan_descriptor_info1 *scan_descriptor_info;
unsigned int input_control_point_count;
unsigned int output_control_point_count;
+
bool use_vocp;
+ bool emit_point_size;
enum vkd3d_shader_opcode phase;
bool emit_default_control_point_phase;
@@ -2376,12 +2358,21 @@ struct spirv_compiler
struct vkd3d_shader_spec_constant *spec_constants;
size_t spec_constants_size;
enum vkd3d_shader_compile_option_formatting_flags formatting;
+ enum vkd3d_shader_compile_option_feature_flags features;
+ enum vkd3d_shader_api_version api_version;
bool write_tess_geom_point_size;
struct vkd3d_string_buffer_cache string_buffers;
struct ssa_register_info *ssa_register_info;
unsigned int ssa_register_count;
+
+ uint64_t config_flags;
+
+ uint32_t *block_label_ids;
+ unsigned int block_count;
+ const char **block_names;
+ size_t block_name_count;
};
static bool is_in_default_phase(const struct spirv_compiler *compiler)
@@ -2400,6 +2391,9 @@ static bool is_in_fork_or_join_phase(const struct spirv_compiler *compiler)
}
static void spirv_compiler_emit_initial_declarations(struct spirv_compiler *compiler);
+static size_t spirv_compiler_get_current_function_location(struct spirv_compiler *compiler);
+static void spirv_compiler_emit_main_prolog(struct spirv_compiler *compiler);
+static void spirv_compiler_emit_io_declarations(struct spirv_compiler *compiler);
static const char *spirv_compiler_get_entry_point_name(const struct spirv_compiler *compiler)
{
@@ -2410,8 +2404,6 @@ static const char *spirv_compiler_get_entry_point_name(const struct spirv_compil
static void spirv_compiler_destroy(struct spirv_compiler *compiler)
{
- vkd3d_free(compiler->control_flow_info);
-
vkd3d_free(compiler->output_info);
vkd3d_free(compiler->push_constants);
@@ -2430,6 +2422,7 @@ static void spirv_compiler_destroy(struct spirv_compiler *compiler)
shader_signature_cleanup(&compiler->patch_constant_signature);
vkd3d_free(compiler->ssa_register_info);
+ vkd3d_free(compiler->block_label_ids);
vkd3d_free(compiler);
}
@@ -2437,7 +2430,8 @@ static void spirv_compiler_destroy(struct spirv_compiler *compiler)
static struct spirv_compiler *spirv_compiler_create(const struct vkd3d_shader_version *shader_version,
struct vkd3d_shader_desc *shader_desc, const struct vkd3d_shader_compile_info *compile_info,
const struct vkd3d_shader_scan_descriptor_info1 *scan_descriptor_info,
- struct vkd3d_shader_message_context *message_context, const struct vkd3d_shader_location *location)
+ struct vkd3d_shader_message_context *message_context, const struct vkd3d_shader_location *location,
+ uint64_t config_flags)
{
const struct shader_signature *patch_constant_signature = &shader_desc->patch_constant_signature;
const struct shader_signature *output_signature = &shader_desc->output_signature;
@@ -2454,6 +2448,7 @@ static struct spirv_compiler *spirv_compiler_create(const struct vkd3d_shader_ve
memset(compiler, 0, sizeof(*compiler));
compiler->message_context = message_context;
compiler->location = *location;
+ compiler->config_flags = config_flags;
if ((target_info = vkd3d_find_struct(compile_info->next, SPIRV_TARGET_INFO)))
{
@@ -2509,6 +2504,7 @@ static struct spirv_compiler *spirv_compiler_create(const struct vkd3d_shader_ve
break;
case VKD3D_SHADER_COMPILE_OPTION_API_VERSION:
+ compiler->api_version = option->value;
break;
case VKD3D_SHADER_COMPILE_OPTION_TYPED_UAV:
@@ -2533,12 +2529,20 @@ static struct spirv_compiler *spirv_compiler_create(const struct vkd3d_shader_ve
WARN("Ignoring unrecognised value %#x for option %#x.\n", option->value, option->name);
break;
+ case VKD3D_SHADER_COMPILE_OPTION_FEATURE:
+ compiler->features = option->value;
+ break;
+
default:
WARN("Ignoring unrecognised option %#x with value %#x.\n", option->name, option->value);
break;
}
}
+ /* Explicit enabling of float64 was not required for API versions <= 1.10. */
+ if (compiler->api_version <= VKD3D_SHADER_API_VERSION_1_10)
+ compiler->features |= VKD3D_SHADER_COMPILE_OPTION_FEATURE_FLOAT64;
+
rb_init(&compiler->symbol_table, vkd3d_symbol_compare);
compiler->shader_type = shader_version->type;
@@ -2546,6 +2550,8 @@ static struct spirv_compiler *spirv_compiler_create(const struct vkd3d_shader_ve
if ((shader_interface = vkd3d_find_struct(compile_info->next, INTERFACE_INFO)))
{
compiler->xfb_info = vkd3d_find_struct(compile_info->next, TRANSFORM_FEEDBACK_INFO);
+ compiler->emit_point_size = compiler->xfb_info && compiler->xfb_info->element_count
+ && compiler->shader_type != VKD3D_SHADER_TYPE_GEOMETRY;
compiler->shader_interface = *shader_interface;
if (shader_interface->push_constant_buffer_count)
@@ -2759,6 +2765,14 @@ static struct vkd3d_string_buffer *vkd3d_shader_register_range_string(struct spi
return buffer;
}
+static uint32_t spirv_compiler_get_label_id(struct spirv_compiler *compiler, unsigned int block_id)
+{
+ --block_id;
+ if (!compiler->block_label_ids[block_id])
+ compiler->block_label_ids[block_id] = vkd3d_spirv_alloc_id(&compiler->spirv_builder);
+ return compiler->block_label_ids[block_id];
+}
+
static struct vkd3d_shader_descriptor_binding spirv_compiler_get_descriptor_binding(
struct spirv_compiler *compiler, const struct vkd3d_shader_register *reg,
const struct vkd3d_shader_register_range *range, enum vkd3d_shader_resource_type resource_type,
@@ -2955,7 +2969,7 @@ static uint32_t spirv_compiler_get_constant64(struct spirv_compiler *compiler,
assert(0 < component_count && component_count <= VKD3D_DVEC2_SIZE);
type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count);
- if (component_type != VKD3D_SHADER_COMPONENT_DOUBLE)
+ if (component_type != VKD3D_SHADER_COMPONENT_DOUBLE && component_type != VKD3D_SHADER_COMPONENT_UINT64)
{
FIXME("Unhandled component_type %#x.\n", component_type);
return vkd3d_spirv_get_op_undef(builder, type_id);
@@ -3015,14 +3029,21 @@ static uint32_t spirv_compiler_get_constant_double_vector(struct spirv_compiler
component_count, (const uint64_t *)values);
}
+static uint32_t spirv_compiler_get_constant_uint64_vector(struct spirv_compiler *compiler,
+ uint64_t value, unsigned int component_count)
+{
+ const uint64_t values[] = {value, value};
+ return spirv_compiler_get_constant64(compiler, VKD3D_SHADER_COMPONENT_UINT64, component_count, values);
+}
+
static uint32_t spirv_compiler_get_type_id_for_reg(struct spirv_compiler *compiler,
- const struct vkd3d_shader_register *reg, DWORD write_mask)
+ const struct vkd3d_shader_register *reg, uint32_t write_mask)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
return vkd3d_spirv_get_type_id(builder,
vkd3d_component_type_from_data_type(reg->data_type),
- vkd3d_write_mask_component_count(write_mask));
+ vsir_write_mask_component_count(write_mask));
}
static uint32_t spirv_compiler_get_type_id_for_dst(struct spirv_compiler *compiler,
@@ -3317,7 +3338,7 @@ static uint32_t spirv_compiler_emit_construct_vector(struct spirv_compiler *comp
}
static uint32_t spirv_compiler_emit_load_src(struct spirv_compiler *compiler,
- const struct vkd3d_shader_src_param *src, DWORD write_mask);
+ const struct vkd3d_shader_src_param *src, uint32_t write_mask);
static uint32_t spirv_compiler_emit_register_addressing(struct spirv_compiler *compiler,
const struct vkd3d_shader_register_index *reg_index)
@@ -3467,11 +3488,13 @@ static uint32_t spirv_compiler_get_descriptor_index(struct spirv_compiler *compi
index_ids[0] = compiler->descriptor_offsets_member_id;
index_ids[1] = spirv_compiler_get_constant_uint(compiler, push_constant_index);
ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassPushConstant, type_id);
+ vkd3d_spirv_begin_function_stream_insertion(builder,
+ spirv_compiler_get_current_function_location(compiler));
ptr_id = vkd3d_spirv_build_op_in_bounds_access_chain(builder, ptr_type_id,
compiler->push_constants_var_id, index_ids, 2);
offset_id = vkd3d_spirv_build_op_load(builder, type_id, ptr_id, SpvMemoryAccessMaskNone);
- if (!compiler->control_flow_depth)
- compiler->descriptor_offset_ids[push_constant_index] = offset_id;
+ vkd3d_spirv_end_function_stream_insertion(builder);
+ compiler->descriptor_offset_ids[push_constant_index] = offset_id;
}
index_id = vkd3d_spirv_build_op_iadd(builder, type_id, index_id, offset_id);
}
@@ -3498,7 +3521,7 @@ static void spirv_compiler_emit_dereference_register(struct spirv_compiler *comp
}
else if (reg->type == VKD3DSPR_IMMCONSTBUFFER)
{
- indexes[index_count++] = spirv_compiler_emit_register_addressing(compiler, &reg->idx[0]);
+ indexes[index_count++] = spirv_compiler_emit_register_addressing(compiler, &reg->idx[reg->idx_count - 1]);
}
else if (reg->type == VKD3DSPR_IDXTEMP)
{
@@ -3530,7 +3553,7 @@ static void spirv_compiler_emit_dereference_register(struct spirv_compiler *comp
if (index_count)
{
- component_count = vkd3d_write_mask_component_count(register_info->write_mask);
+ component_count = vsir_write_mask_component_count(register_info->write_mask);
type_id = vkd3d_spirv_get_type_id(builder, register_info->component_type, component_count);
ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, register_info->storage_class, type_id);
register_info->id = vkd3d_spirv_build_op_access_chain(builder, ptr_type_id,
@@ -3556,30 +3579,35 @@ static uint32_t spirv_compiler_get_register_id(struct spirv_compiler *compiler,
SpvStorageClassPrivate, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE);
}
-static bool vkd3d_swizzle_is_equal(unsigned int dst_write_mask,
- unsigned int swizzle, unsigned int write_mask)
+static bool vkd3d_swizzle_is_equal(uint32_t dst_write_mask, uint32_t swizzle, uint32_t write_mask)
{
return vkd3d_compact_swizzle(VKD3D_SHADER_NO_SWIZZLE, dst_write_mask) == vkd3d_compact_swizzle(swizzle, write_mask);
}
-static bool vkd3d_swizzle_is_scalar(unsigned int swizzle)
+static bool vkd3d_swizzle_is_scalar(uint32_t swizzle, const struct vkd3d_shader_register *reg)
{
- unsigned int component_idx = vkd3d_swizzle_get_component(swizzle, 0);
- return vkd3d_swizzle_get_component(swizzle, 1) == component_idx
- && vkd3d_swizzle_get_component(swizzle, 2) == component_idx
- && vkd3d_swizzle_get_component(swizzle, 3) == component_idx;
+ unsigned int component_idx = vsir_swizzle_get_component(swizzle, 0);
+
+ if (vsir_swizzle_get_component(swizzle, 1) != component_idx)
+ return false;
+
+ if (data_type_is_64_bit(reg->data_type))
+ return true;
+
+ return vsir_swizzle_get_component(swizzle, 2) == component_idx
+ && vsir_swizzle_get_component(swizzle, 3) == component_idx;
}
static uint32_t spirv_compiler_emit_swizzle(struct spirv_compiler *compiler,
- uint32_t val_id, unsigned int val_write_mask, enum vkd3d_shader_component_type component_type,
- unsigned int swizzle, unsigned int write_mask)
+ uint32_t val_id, uint32_t val_write_mask, enum vkd3d_shader_component_type component_type,
+ uint32_t swizzle, uint32_t write_mask)
{
unsigned int i, component_idx, component_count, val_component_count;
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t type_id, components[VKD3D_VEC4_SIZE];
- component_count = vkd3d_write_mask_component_count(write_mask);
- val_component_count = vkd3d_write_mask_component_count(val_write_mask);
+ component_count = vsir_write_mask_component_count(write_mask);
+ val_component_count = vsir_write_mask_component_count(val_write_mask);
if (component_count == val_component_count
&& (component_count == 1 || vkd3d_swizzle_is_equal(val_write_mask, swizzle, write_mask)))
@@ -3589,9 +3617,9 @@ static uint32_t spirv_compiler_emit_swizzle(struct spirv_compiler *compiler,
if (component_count == 1)
{
- component_idx = vkd3d_write_mask_get_component_idx(write_mask);
- component_idx = vkd3d_swizzle_get_component(swizzle, component_idx);
- component_idx -= vkd3d_write_mask_get_component_idx(val_write_mask);
+ component_idx = vsir_write_mask_get_component_idx(write_mask);
+ component_idx = vsir_swizzle_get_component(swizzle, component_idx);
+ component_idx -= vsir_write_mask_get_component_idx(val_write_mask);
return vkd3d_spirv_build_op_composite_extract1(builder, type_id, val_id, component_idx);
}
@@ -3601,7 +3629,7 @@ static uint32_t spirv_compiler_emit_swizzle(struct spirv_compiler *compiler,
{
if (write_mask & (VKD3DSP_WRITEMASK_0 << i))
{
- assert(VKD3DSP_WRITEMASK_0 << vkd3d_swizzle_get_component(swizzle, i) == val_write_mask);
+ assert(VKD3DSP_WRITEMASK_0 << vsir_swizzle_get_component(swizzle, i) == val_write_mask);
components[component_idx++] = val_id;
}
}
@@ -3611,14 +3639,14 @@ static uint32_t spirv_compiler_emit_swizzle(struct spirv_compiler *compiler,
for (i = 0, component_idx = 0; i < VKD3D_VEC4_SIZE; ++i)
{
if (write_mask & (VKD3DSP_WRITEMASK_0 << i))
- components[component_idx++] = vkd3d_swizzle_get_component(swizzle, i);
+ components[component_idx++] = vsir_swizzle_get_component(swizzle, i);
}
return vkd3d_spirv_build_op_vector_shuffle(builder,
type_id, val_id, val_id, components, component_count);
}
static uint32_t spirv_compiler_emit_vector_shuffle(struct spirv_compiler *compiler,
- uint32_t vector1_id, uint32_t vector2_id, unsigned int swizzle, unsigned int write_mask,
+ uint32_t vector1_id, uint32_t vector2_id, uint32_t swizzle, uint32_t write_mask,
enum vkd3d_shader_component_type component_type, unsigned int component_count)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
@@ -3631,9 +3659,9 @@ static uint32_t spirv_compiler_emit_vector_shuffle(struct spirv_compiler *compil
for (i = 0; i < component_count; ++i)
{
if (write_mask & (VKD3DSP_WRITEMASK_0 << i))
- components[i] = vkd3d_swizzle_get_component(swizzle, i);
+ components[i] = vsir_swizzle_get_component(swizzle, i);
else
- components[i] = VKD3D_VEC4_SIZE + vkd3d_swizzle_get_component(swizzle, i);
+ components[i] = VKD3D_VEC4_SIZE + vsir_swizzle_get_component(swizzle, i);
}
type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count);
@@ -3641,10 +3669,77 @@ static uint32_t spirv_compiler_emit_vector_shuffle(struct spirv_compiler *compil
type_id, vector1_id, vector2_id, components, component_count);
}
+static uint32_t spirv_compiler_emit_int_to_bool(struct spirv_compiler *compiler,
+ enum vkd3d_shader_conditional_op condition, enum vkd3d_data_type data_type,
+ unsigned int component_count, uint32_t val_id)
+{
+ struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+ uint32_t type_id;
+ SpvOp op;
+
+ assert(!(condition & ~(VKD3D_SHADER_CONDITIONAL_OP_NZ | VKD3D_SHADER_CONDITIONAL_OP_Z)));
+
+ type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_BOOL, component_count);
+ op = condition & VKD3D_SHADER_CONDITIONAL_OP_Z ? SpvOpIEqual : SpvOpINotEqual;
+ return vkd3d_spirv_build_op_tr2(builder, &builder->function_stream, op, type_id, val_id,
+ data_type == VKD3D_DATA_UINT64
+ ? spirv_compiler_get_constant_uint64_vector(compiler, 0, component_count)
+ : spirv_compiler_get_constant_uint_vector(compiler, 0, component_count));
+}
+
+static uint32_t spirv_compiler_emit_bool_to_int(struct spirv_compiler *compiler,
+ unsigned int component_count, uint32_t val_id, bool signedness)
+{
+ struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+ uint32_t type_id, true_id, false_id;
+
+ true_id = spirv_compiler_get_constant_uint_vector(compiler, signedness ? 0xffffffff : 1, component_count);
+ false_id = spirv_compiler_get_constant_uint_vector(compiler, 0, component_count);
+ type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, component_count);
+ return vkd3d_spirv_build_op_select(builder, type_id, val_id, true_id, false_id);
+}
+
+static uint32_t spirv_compiler_emit_bool_to_int64(struct spirv_compiler *compiler,
+ unsigned int component_count, uint32_t val_id, bool signedness)
+{
+ struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+ uint32_t type_id, true_id, false_id;
+
+ true_id = spirv_compiler_get_constant_uint64_vector(compiler, signedness ? UINT64_MAX : 1,
+ component_count);
+ false_id = spirv_compiler_get_constant_uint64_vector(compiler, 0, component_count);
+ type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT64, component_count);
+ return vkd3d_spirv_build_op_select(builder, type_id, val_id, true_id, false_id);
+}
+
+static uint32_t spirv_compiler_emit_bool_to_float(struct spirv_compiler *compiler,
+ unsigned int component_count, uint32_t val_id, bool signedness)
+{
+ struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+ uint32_t type_id, true_id, false_id;
+
+ true_id = spirv_compiler_get_constant_float_vector(compiler, signedness ? -1.0f : 1.0f, component_count);
+ false_id = spirv_compiler_get_constant_float_vector(compiler, 0.0f, component_count);
+ type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, component_count);
+ return vkd3d_spirv_build_op_select(builder, type_id, val_id, true_id, false_id);
+}
+
+static uint32_t spirv_compiler_emit_bool_to_double(struct spirv_compiler *compiler,
+ unsigned int component_count, uint32_t val_id, bool signedness)
+{
+ struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+ uint32_t type_id, true_id, false_id;
+
+ true_id = spirv_compiler_get_constant_double_vector(compiler, signedness ? -1.0 : 1.0, component_count);
+ false_id = spirv_compiler_get_constant_double_vector(compiler, 0.0, component_count);
+ type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_DOUBLE, component_count);
+ return vkd3d_spirv_build_op_select(builder, type_id, val_id, true_id, false_id);
+}
+
static uint32_t spirv_compiler_emit_load_constant(struct spirv_compiler *compiler,
- const struct vkd3d_shader_register *reg, DWORD swizzle, DWORD write_mask)
+ const struct vkd3d_shader_register *reg, uint32_t swizzle, uint32_t write_mask)
{
- unsigned int component_count = vkd3d_write_mask_component_count(write_mask);
+ unsigned int component_count = vsir_write_mask_component_count(write_mask);
uint32_t values[VKD3D_VEC4_SIZE] = {0};
unsigned int i, j;
@@ -3653,14 +3748,14 @@ static uint32_t spirv_compiler_emit_load_constant(struct spirv_compiler *compile
if (reg->dimension == VSIR_DIMENSION_SCALAR)
{
for (i = 0; i < component_count; ++i)
- values[i] = *reg->u.immconst_uint;
+ values[i] = *reg->u.immconst_u32;
}
else
{
for (i = 0, j = 0; i < VKD3D_VEC4_SIZE; ++i)
{
if (write_mask & (VKD3DSP_WRITEMASK_0 << i))
- values[j++] = reg->u.immconst_uint[vkd3d_swizzle_get_component(swizzle, i)];
+ values[j++] = reg->u.immconst_u32[vsir_swizzle_get_component(swizzle, i)];
}
}
@@ -3669,9 +3764,9 @@ static uint32_t spirv_compiler_emit_load_constant(struct spirv_compiler *compile
}
static uint32_t spirv_compiler_emit_load_constant64(struct spirv_compiler *compiler,
- const struct vkd3d_shader_register *reg, DWORD swizzle, DWORD write_mask)
+ const struct vkd3d_shader_register *reg, uint32_t swizzle, uint32_t write_mask)
{
- unsigned int component_count = vkd3d_write_mask_component_count(write_mask);
+ unsigned int component_count = vsir_write_mask_component_count(write_mask);
uint64_t values[VKD3D_DVEC2_SIZE] = {0};
unsigned int i, j;
@@ -3680,14 +3775,14 @@ static uint32_t spirv_compiler_emit_load_constant64(struct spirv_compiler *compi
if (reg->dimension == VSIR_DIMENSION_SCALAR)
{
for (i = 0; i < component_count; ++i)
- values[i] = *reg->u.immconst_uint64;
+ values[i] = *reg->u.immconst_u64;
}
else
{
for (i = 0, j = 0; i < VKD3D_DVEC2_SIZE; ++i)
{
if (write_mask & (VKD3DSP_WRITEMASK_0 << i))
- values[j++] = reg->u.immconst_uint64[vkd3d_swizzle_get_component64(swizzle, i)];
+ values[j++] = reg->u.immconst_u64[vsir_swizzle_get_component(swizzle, i)];
}
}
@@ -3696,9 +3791,9 @@ static uint32_t spirv_compiler_emit_load_constant64(struct spirv_compiler *compi
}
static uint32_t spirv_compiler_emit_load_undef(struct spirv_compiler *compiler,
- const struct vkd3d_shader_register *reg, DWORD write_mask)
+ const struct vkd3d_shader_register *reg, uint32_t write_mask)
{
- unsigned int component_count = vkd3d_write_mask_component_count(write_mask);
+ unsigned int component_count = vsir_write_mask_component_count(write_mask);
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t type_id;
@@ -3709,28 +3804,28 @@ static uint32_t spirv_compiler_emit_load_undef(struct spirv_compiler *compiler,
}
static uint32_t spirv_compiler_emit_load_scalar(struct spirv_compiler *compiler,
- const struct vkd3d_shader_register *reg, DWORD swizzle, DWORD write_mask,
+ const struct vkd3d_shader_register *reg, uint32_t swizzle, uint32_t write_mask,
const struct vkd3d_shader_register_info *reg_info)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t type_id, ptr_type_id, index, reg_id, val_id;
unsigned int component_idx, reg_component_count;
enum vkd3d_shader_component_type component_type;
- unsigned int skipped_component_mask;
+ uint32_t skipped_component_mask;
assert(!register_is_constant_or_undef(reg));
- assert(vkd3d_write_mask_component_count(write_mask) == 1);
+ assert(vsir_write_mask_component_count(write_mask) == 1);
- component_idx = vkd3d_write_mask_get_component_idx(write_mask);
- component_idx = vkd3d_swizzle_get_component(swizzle, component_idx);
+ component_idx = vsir_write_mask_get_component_idx(write_mask);
+ component_idx = vsir_swizzle_get_component(swizzle, component_idx);
skipped_component_mask = ~reg_info->write_mask & ((VKD3DSP_WRITEMASK_0 << component_idx) - 1);
if (skipped_component_mask)
- component_idx -= vkd3d_write_mask_component_count(skipped_component_mask);
+ component_idx -= vsir_write_mask_component_count(skipped_component_mask);
component_type = vkd3d_component_type_from_data_type(reg->data_type);
- reg_component_count = vkd3d_write_mask_component_count(reg_info->write_mask);
+ reg_component_count = vsir_write_mask_component_count(reg_info->write_mask);
- if (component_idx >= vkd3d_write_mask_component_count(reg_info->write_mask))
+ if (component_idx >= vsir_write_mask_component_count(reg_info->write_mask))
{
ERR("Invalid component_idx %u for register %#x, %u (write_mask %#x).\n",
component_idx, reg->type, reg->idx[0].offset, reg_info->write_mask);
@@ -3749,13 +3844,89 @@ static uint32_t spirv_compiler_emit_load_scalar(struct spirv_compiler *compiler,
if (component_type != reg_info->component_type)
{
- type_id = vkd3d_spirv_get_type_id(builder, component_type, 1);
- val_id = vkd3d_spirv_build_op_bitcast(builder, type_id, val_id);
+ if (component_type == VKD3D_SHADER_COMPONENT_BOOL)
+ {
+ if (reg_info->component_type != VKD3D_SHADER_COMPONENT_UINT)
+ {
+ type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, 1);
+ val_id = vkd3d_spirv_build_op_bitcast(builder, type_id, val_id);
+ }
+ val_id = spirv_compiler_emit_int_to_bool(compiler, VKD3D_SHADER_CONDITIONAL_OP_NZ,
+ VKD3D_DATA_UINT, 1, val_id);
+ }
+ else
+ {
+ type_id = vkd3d_spirv_get_type_id(builder, component_type, 1);
+ val_id = vkd3d_spirv_build_op_bitcast(builder, type_id, val_id);
+ }
}
return val_id;
}
+static uint32_t spirv_compiler_emit_constant_array(struct spirv_compiler *compiler,
+ const struct vkd3d_shader_immediate_constant_buffer *icb, uint32_t *type_id_out)
+{
+ uint32_t *elements, elem_type_id, length_id, type_id, const_id;
+ struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+ enum vkd3d_shader_component_type component_type;
+ unsigned int i, element_count, component_count;
+
+ element_count = icb->element_count;
+
+ component_type = vkd3d_component_type_from_data_type(icb->data_type);
+ component_count = icb->component_count;
+ elem_type_id = vkd3d_spirv_get_type_id_for_data_type(builder, icb->data_type, component_count);
+ length_id = spirv_compiler_get_constant_uint(compiler, element_count);
+ type_id = vkd3d_spirv_get_op_type_array(builder, elem_type_id, length_id);
+
+ if (type_id_out)
+ *type_id_out = type_id;
+
+ if (icb->is_null)
+ {
+ /* All values are null. Workgroup memory initialisers require OpConstantNull. */
+ return vkd3d_spirv_get_op_constant_null(builder, type_id);
+ }
+
+ if (!(elements = vkd3d_calloc(element_count, sizeof(*elements))))
+ {
+ ERR("Failed to allocate %u elements.", element_count);
+ spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_OUT_OF_MEMORY,
+ "Failed to allocate %u constant array elements.", element_count);
+ return 0;
+ }
+
+ switch (icb->data_type)
+ {
+ case VKD3D_DATA_FLOAT:
+ case VKD3D_DATA_INT:
+ case VKD3D_DATA_UINT:
+ for (i = 0; i < element_count; ++i)
+ elements[i] = spirv_compiler_get_constant(compiler, component_type, component_count,
+ &icb->data[component_count * i]);
+ break;
+ case VKD3D_DATA_DOUBLE:
+ case VKD3D_DATA_UINT64:
+ {
+ uint64_t *data = (uint64_t *)icb->data;
+ for (i = 0; i < element_count; ++i)
+ elements[i] = spirv_compiler_get_constant64(compiler, component_type, component_count,
+ &data[component_count * i]);
+ break;
+ }
+ default:
+ FIXME("Unhandled data type %u.\n", icb->data_type);
+ spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_INVALID_TYPE,
+ "Immediate constant buffer data type %u is unhandled.", icb->data_type);
+ break;
+ }
+
+ const_id = vkd3d_spirv_build_op_constant_composite(builder, type_id, elements, element_count);
+ vkd3d_free(elements);
+ return const_id;
+}
+
static const struct ssa_register_info *spirv_compiler_get_ssa_register_info(const struct spirv_compiler *compiler,
const struct vkd3d_shader_register *reg)
{
@@ -3775,7 +3946,7 @@ static void spirv_compiler_set_ssa_register_info(const struct spirv_compiler *co
static uint32_t spirv_compiler_emit_load_ssa_reg(struct spirv_compiler *compiler,
const struct vkd3d_shader_register *reg, enum vkd3d_shader_component_type component_type,
- unsigned int swizzle)
+ uint32_t swizzle)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
enum vkd3d_shader_component_type reg_component_type;
@@ -3785,12 +3956,18 @@ static uint32_t spirv_compiler_emit_load_ssa_reg(struct spirv_compiler *compiler
ssa = spirv_compiler_get_ssa_register_info(compiler, reg);
val_id = ssa->id;
- assert(val_id);
- assert(vkd3d_swizzle_is_scalar(swizzle));
+ if (!val_id)
+ {
+ /* Should only be from a missing instruction implementation. */
+ assert(compiler->failed);
+ return 0;
+ }
+ assert(vkd3d_swizzle_is_scalar(swizzle, reg));
+
+ reg_component_type = vkd3d_component_type_from_data_type(ssa->data_type);
if (reg->dimension == VSIR_DIMENSION_SCALAR)
{
- reg_component_type = vkd3d_component_type_from_data_type(ssa->data_type);
if (component_type != reg_component_type)
{
type_id = vkd3d_spirv_get_type_id(builder, component_type, 1);
@@ -3800,20 +3977,28 @@ static uint32_t spirv_compiler_emit_load_ssa_reg(struct spirv_compiler *compiler
return val_id;
}
+ if (component_type != reg_component_type)
+ {
+ /* Required for resource loads with sampled type int, because DXIL has no signedness.
+ * Only 128-bit vector sizes are used. */
+ type_id = vkd3d_spirv_get_type_id(builder, component_type, VKD3D_VEC4_SIZE);
+ val_id = vkd3d_spirv_build_op_bitcast(builder, type_id, val_id);
+ }
+
type_id = vkd3d_spirv_get_type_id(builder, component_type, 1);
- component_idx = vkd3d_swizzle_get_component(swizzle, 0);
+ component_idx = vsir_swizzle_get_component(swizzle, 0);
return vkd3d_spirv_build_op_composite_extract1(builder, type_id, val_id, component_idx);
}
static uint32_t spirv_compiler_emit_load_reg(struct spirv_compiler *compiler,
- const struct vkd3d_shader_register *reg, DWORD swizzle, DWORD write_mask)
+ const struct vkd3d_shader_register *reg, uint32_t swizzle, uint32_t write_mask)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
enum vkd3d_shader_component_type component_type;
struct vkd3d_shader_register_info reg_info;
unsigned int component_count;
- unsigned int write_mask32;
uint32_t type_id, val_id;
+ uint32_t write_mask32;
if (reg->type == VKD3DSPR_IMMCONST)
return spirv_compiler_emit_load_constant(compiler, reg, swizzle, write_mask);
@@ -3822,7 +4007,7 @@ static uint32_t spirv_compiler_emit_load_reg(struct spirv_compiler *compiler,
else if (reg->type == VKD3DSPR_UNDEF)
return spirv_compiler_emit_load_undef(compiler, reg, write_mask);
- component_count = vkd3d_write_mask_component_count(write_mask);
+ component_count = vsir_write_mask_component_count(write_mask);
component_type = vkd3d_component_type_from_data_type(reg->data_type);
if (reg->type == VKD3DSPR_SSA)
@@ -3836,31 +4021,45 @@ static uint32_t spirv_compiler_emit_load_reg(struct spirv_compiler *compiler,
assert(reg_info.component_type != VKD3D_SHADER_COMPONENT_DOUBLE);
spirv_compiler_emit_dereference_register(compiler, reg, &reg_info);
- write_mask32 = (reg->data_type == VKD3D_DATA_DOUBLE) ? vkd3d_write_mask_32_from_64(write_mask) : write_mask;
+ write_mask32 = data_type_is_64_bit(reg->data_type) ? vsir_write_mask_32_from_64(write_mask) : write_mask;
/* Intermediate value (no storage class). */
if (reg_info.storage_class == SpvStorageClassMax)
{
val_id = reg_info.id;
}
- else if (vkd3d_write_mask_component_count(write_mask32) == 1)
+ else if (vsir_write_mask_component_count(write_mask32) == 1)
{
return spirv_compiler_emit_load_scalar(compiler, reg, swizzle, write_mask, &reg_info);
}
else
{
type_id = vkd3d_spirv_get_type_id(builder,
- reg_info.component_type, vkd3d_write_mask_component_count(reg_info.write_mask));
+ reg_info.component_type, vsir_write_mask_component_count(reg_info.write_mask));
val_id = vkd3d_spirv_build_op_load(builder, type_id, reg_info.id, SpvMemoryAccessMaskNone);
}
+ swizzle = data_type_is_64_bit(reg->data_type) ? vsir_swizzle_32_from_64(swizzle) : swizzle;
val_id = spirv_compiler_emit_swizzle(compiler,
val_id, reg_info.write_mask, reg_info.component_type, swizzle, write_mask32);
if (component_type != reg_info.component_type)
{
- type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count);
- val_id = vkd3d_spirv_build_op_bitcast(builder, type_id, val_id);
+ if (component_type == VKD3D_SHADER_COMPONENT_BOOL)
+ {
+ if (reg_info.component_type != VKD3D_SHADER_COMPONENT_UINT)
+ {
+ type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, component_count);
+ val_id = vkd3d_spirv_build_op_bitcast(builder, type_id, val_id);
+ }
+ val_id = spirv_compiler_emit_int_to_bool(compiler, VKD3D_SHADER_CONDITIONAL_OP_NZ,
+ VKD3D_DATA_UINT, component_count, val_id);
+ }
+ else
+ {
+ type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count);
+ val_id = vkd3d_spirv_build_op_bitcast(builder, type_id, val_id);
+ }
}
return val_id;
@@ -3882,7 +4081,7 @@ static void spirv_compiler_emit_execution_mode1(struct spirv_compiler *compiler,
}
static uint32_t spirv_compiler_emit_abs(struct spirv_compiler *compiler,
- const struct vkd3d_shader_register *reg, DWORD write_mask, uint32_t val_id)
+ const struct vkd3d_shader_register *reg, uint32_t write_mask, uint32_t val_id)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t type_id;
@@ -3896,7 +4095,7 @@ static uint32_t spirv_compiler_emit_abs(struct spirv_compiler *compiler,
}
static uint32_t spirv_compiler_emit_neg(struct spirv_compiler *compiler,
- const struct vkd3d_shader_register *reg, DWORD write_mask, uint32_t val_id)
+ const struct vkd3d_shader_register *reg, uint32_t write_mask, uint32_t val_id)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t type_id;
@@ -3904,7 +4103,7 @@ static uint32_t spirv_compiler_emit_neg(struct spirv_compiler *compiler,
type_id = spirv_compiler_get_type_id_for_reg(compiler, reg, write_mask);
if (reg->data_type == VKD3D_DATA_FLOAT || reg->data_type == VKD3D_DATA_DOUBLE)
return vkd3d_spirv_build_op_fnegate(builder, type_id, val_id);
- else if (reg->data_type == VKD3D_DATA_INT || reg->data_type == VKD3D_DATA_UINT)
+ else if (data_type_is_integer(reg->data_type))
return vkd3d_spirv_build_op_snegate(builder, type_id, val_id);
FIXME("Unhandled data type %#x.\n", reg->data_type);
@@ -3912,7 +4111,7 @@ static uint32_t spirv_compiler_emit_neg(struct spirv_compiler *compiler,
}
static uint32_t spirv_compiler_emit_src_modifier(struct spirv_compiler *compiler,
- const struct vkd3d_shader_register *reg, DWORD write_mask,
+ const struct vkd3d_shader_register *reg, uint32_t write_mask,
enum vkd3d_shader_src_modifier modifier, uint32_t val_id)
{
switch (modifier)
@@ -3935,7 +4134,7 @@ static uint32_t spirv_compiler_emit_src_modifier(struct spirv_compiler *compiler
}
static uint32_t spirv_compiler_emit_load_src(struct spirv_compiler *compiler,
- const struct vkd3d_shader_src_param *src, DWORD write_mask)
+ const struct vkd3d_shader_src_param *src, uint32_t write_mask)
{
uint32_t val_id;
@@ -3944,7 +4143,7 @@ static uint32_t spirv_compiler_emit_load_src(struct spirv_compiler *compiler,
}
static uint32_t spirv_compiler_emit_load_src_with_type(struct spirv_compiler *compiler,
- const struct vkd3d_shader_src_param *src, DWORD write_mask, enum vkd3d_shader_component_type component_type)
+ const struct vkd3d_shader_src_param *src, uint32_t write_mask, enum vkd3d_shader_component_type component_type)
{
struct vkd3d_shader_src_param src_param = *src;
@@ -3953,19 +4152,19 @@ static uint32_t spirv_compiler_emit_load_src_with_type(struct spirv_compiler *co
}
static void spirv_compiler_emit_store_scalar(struct spirv_compiler *compiler,
- uint32_t dst_id, unsigned int dst_write_mask, enum vkd3d_shader_component_type component_type,
- SpvStorageClass storage_class, unsigned int write_mask, uint32_t val_id)
+ uint32_t dst_id, uint32_t dst_write_mask, enum vkd3d_shader_component_type component_type,
+ SpvStorageClass storage_class, uint32_t write_mask, uint32_t val_id)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t type_id, ptr_type_id, index;
unsigned int component_idx;
- if (vkd3d_write_mask_component_count(dst_write_mask) > 1)
+ if (vsir_write_mask_component_count(dst_write_mask) > 1)
{
type_id = vkd3d_spirv_get_type_id(builder, component_type, 1);
ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, type_id);
- component_idx = vkd3d_write_mask_get_component_idx(write_mask);
- component_idx -= vkd3d_write_mask_get_component_idx(dst_write_mask);
+ component_idx = vsir_write_mask_get_component_idx(write_mask);
+ component_idx -= vsir_write_mask_get_component_idx(dst_write_mask);
index = spirv_compiler_get_constant_uint(compiler, component_idx);
dst_id = vkd3d_spirv_build_op_in_bounds_access_chain1(builder, ptr_type_id, dst_id, index);
}
@@ -3974,8 +4173,8 @@ static void spirv_compiler_emit_store_scalar(struct spirv_compiler *compiler,
}
static void spirv_compiler_emit_store(struct spirv_compiler *compiler,
- uint32_t dst_id, unsigned int dst_write_mask, enum vkd3d_shader_component_type component_type,
- SpvStorageClass storage_class, unsigned int write_mask, uint32_t val_id)
+ uint32_t dst_id, uint32_t dst_write_mask, enum vkd3d_shader_component_type component_type,
+ SpvStorageClass storage_class, uint32_t write_mask, uint32_t val_id)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
unsigned int component_count, dst_component_count;
@@ -3985,14 +4184,14 @@ static void spirv_compiler_emit_store(struct spirv_compiler *compiler,
assert(write_mask);
- component_count = vkd3d_write_mask_component_count(write_mask);
- dst_component_count = vkd3d_write_mask_component_count(dst_write_mask);
+ component_count = vsir_write_mask_component_count(write_mask);
+ dst_component_count = vsir_write_mask_component_count(dst_write_mask);
if (dst_component_count == 1 && component_count != 1)
{
type_id = vkd3d_spirv_get_type_id(builder, component_type, 1);
val_id = vkd3d_spirv_build_op_composite_extract1(builder, type_id, val_id,
- vkd3d_write_mask_get_component_idx(dst_write_mask));
+ vsir_write_mask_get_component_idx(dst_write_mask));
write_mask &= dst_write_mask;
component_count = 1;
}
@@ -4029,12 +4228,12 @@ static void spirv_compiler_emit_store(struct spirv_compiler *compiler,
}
static void spirv_compiler_emit_store_reg(struct spirv_compiler *compiler,
- const struct vkd3d_shader_register *reg, unsigned int write_mask, uint32_t val_id)
+ const struct vkd3d_shader_register *reg, uint32_t write_mask, uint32_t val_id)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
enum vkd3d_shader_component_type component_type;
struct vkd3d_shader_register_info reg_info;
- unsigned int src_write_mask = write_mask;
+ uint32_t src_write_mask = write_mask;
uint32_t type_id;
assert(!register_is_constant_or_undef(reg));
@@ -4052,10 +4251,13 @@ static void spirv_compiler_emit_store_reg(struct spirv_compiler *compiler,
component_type = vkd3d_component_type_from_data_type(reg->data_type);
if (component_type != reg_info.component_type)
{
- if (reg->data_type == VKD3D_DATA_DOUBLE)
- src_write_mask = vkd3d_write_mask_32_from_64(write_mask);
+ if (data_type_is_64_bit(reg->data_type))
+ src_write_mask = vsir_write_mask_32_from_64(write_mask);
+ if (component_type == VKD3D_SHADER_COMPONENT_BOOL)
+ val_id = spirv_compiler_emit_bool_to_int(compiler,
+ vsir_write_mask_component_count(src_write_mask), val_id, false);
type_id = vkd3d_spirv_get_type_id(builder, reg_info.component_type,
- vkd3d_write_mask_component_count(src_write_mask));
+ vsir_write_mask_component_count(src_write_mask));
val_id = vkd3d_spirv_build_op_bitcast(builder, type_id, val_id);
component_type = reg_info.component_type;
}
@@ -4065,9 +4267,9 @@ static void spirv_compiler_emit_store_reg(struct spirv_compiler *compiler,
}
static uint32_t spirv_compiler_emit_sat(struct spirv_compiler *compiler,
- const struct vkd3d_shader_register *reg, DWORD write_mask, uint32_t val_id)
+ const struct vkd3d_shader_register *reg, uint32_t write_mask, uint32_t val_id)
{
- unsigned int component_count = vkd3d_write_mask_component_count(write_mask);
+ unsigned int component_count = vsir_write_mask_component_count(write_mask);
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t type_id, zero_id, one_id;
@@ -4102,7 +4304,7 @@ static void spirv_compiler_emit_store_dst(struct spirv_compiler *compiler,
static void spirv_compiler_emit_store_dst_swizzled(struct spirv_compiler *compiler,
const struct vkd3d_shader_dst_param *dst, uint32_t val_id,
- enum vkd3d_shader_component_type component_type, DWORD swizzle)
+ enum vkd3d_shader_component_type component_type, uint32_t swizzle)
{
struct vkd3d_shader_dst_param typed_dst = *dst;
val_id = spirv_compiler_emit_swizzle(compiler,
@@ -4118,7 +4320,7 @@ static void spirv_compiler_emit_store_dst_components(struct spirv_compiler *comp
const struct vkd3d_shader_dst_param *dst, enum vkd3d_shader_component_type component_type,
uint32_t *component_ids)
{
- unsigned int component_count = vkd3d_write_mask_component_count(dst->write_mask);
+ unsigned int component_count = vsir_write_mask_component_count(dst->write_mask);
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t type_id, val_id;
@@ -4137,16 +4339,16 @@ static void spirv_compiler_emit_store_dst_components(struct spirv_compiler *comp
static void spirv_compiler_emit_store_dst_scalar(struct spirv_compiler *compiler,
const struct vkd3d_shader_dst_param *dst, uint32_t val_id,
- enum vkd3d_shader_component_type component_type, DWORD swizzle)
+ enum vkd3d_shader_component_type component_type, uint32_t swizzle)
{
- unsigned int component_count = vkd3d_write_mask_component_count(dst->write_mask);
+ unsigned int component_count = vsir_write_mask_component_count(dst->write_mask);
uint32_t component_ids[VKD3D_VEC4_SIZE];
unsigned int component_idx, i;
- component_idx = vkd3d_write_mask_get_component_idx(dst->write_mask);
+ component_idx = vsir_write_mask_get_component_idx(dst->write_mask);
for (i = 0; i < component_count; ++i)
{
- if (vkd3d_swizzle_get_component(swizzle, component_idx + i))
+ if (vsir_swizzle_get_component(swizzle, component_idx + i))
ERR("Invalid swizzle %#x for scalar value, write mask %#x.\n", swizzle, dst->write_mask);
component_ids[i] = val_id;
@@ -4169,10 +4371,58 @@ static void spirv_compiler_decorate_builtin(struct spirv_compiler *compiler,
spirv_compiler_emit_execution_mode(compiler, SpvExecutionModeDepthReplacing, NULL, 0);
break;
case SpvBuiltInLayer:
- vkd3d_spirv_enable_capability(builder, SpvCapabilityGeometry);
+ switch (compiler->shader_type)
+ {
+ case VKD3D_SHADER_TYPE_PIXEL:
+ case VKD3D_SHADER_TYPE_GEOMETRY:
+ vkd3d_spirv_enable_capability(builder, SpvCapabilityGeometry);
+ break;
+
+ case VKD3D_SHADER_TYPE_VERTEX:
+ case VKD3D_SHADER_TYPE_DOMAIN:
+ if (!spirv_compiler_is_target_extension_supported(compiler,
+ VKD3D_SHADER_SPIRV_EXTENSION_EXT_VIEWPORT_INDEX_LAYER))
+ {
+ FIXME("The target environment does not support decoration Layer.\n");
+ spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_UNSUPPORTED_FEATURE,
+ "Cannot use SV_RenderTargetArrayIndex. "
+ "The target environment does not support decoration Layer.");
+ }
+ vkd3d_spirv_enable_capability(builder, SpvCapabilityShaderViewportIndexLayerEXT);
+ break;
+
+ default:
+ spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_INVALID_SHADER,
+ "Invalid use of SV_RenderTargetArrayIndex.");
+ break;
+ }
break;
case SpvBuiltInViewportIndex:
- vkd3d_spirv_enable_capability(builder, SpvCapabilityMultiViewport);
+ switch (compiler->shader_type)
+ {
+ case VKD3D_SHADER_TYPE_PIXEL:
+ case VKD3D_SHADER_TYPE_GEOMETRY:
+ vkd3d_spirv_enable_capability(builder, SpvCapabilityMultiViewport);
+ break;
+
+ case VKD3D_SHADER_TYPE_VERTEX:
+ case VKD3D_SHADER_TYPE_DOMAIN:
+ if (!spirv_compiler_is_target_extension_supported(compiler,
+ VKD3D_SHADER_SPIRV_EXTENSION_EXT_VIEWPORT_INDEX_LAYER))
+ {
+ FIXME("The target environment does not support decoration ViewportIndex.\n");
+ spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_UNSUPPORTED_FEATURE,
+ "Cannot use SV_ViewportArrayIndex. "
+ "The target environment does not support decoration ViewportIndex.");
+ }
+ vkd3d_spirv_enable_capability(builder, SpvCapabilityShaderViewportIndexLayerEXT);
+ break;
+
+ default:
+ spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_INVALID_SHADER,
+ "Invalid use of SV_ViewportArrayIndex.");
+ break;
+ }
break;
case SpvBuiltInSampleId:
vkd3d_spirv_enable_capability(builder, SpvCapabilitySampleRateShading);
@@ -4191,14 +4441,18 @@ static void spirv_compiler_decorate_builtin(struct spirv_compiler *compiler,
}
static void spirv_compiler_emit_interpolation_decorations(struct spirv_compiler *compiler,
- uint32_t id, enum vkd3d_shader_interpolation_mode mode)
+ enum vkd3d_shader_component_type component_type, uint32_t id, enum vkd3d_shader_interpolation_mode mode)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
switch (mode)
{
case VKD3DSIM_NONE:
- break;
+ /* VUID-StandaloneSpirv-Flat-04744: integer or double types must be
+ * decorated 'Flat' for fragment shaders. */
+ if (compiler->shader_type != VKD3D_SHADER_TYPE_PIXEL || component_type == VKD3D_SHADER_COMPONENT_FLOAT)
+ break;
+ /* fall through */
case VKD3DSIM_CONSTANT:
vkd3d_spirv_build_op_decorate(builder, id, SpvDecorationFlat, NULL, 0);
break;
@@ -4225,87 +4479,36 @@ static void spirv_compiler_emit_interpolation_decorations(struct spirv_compiler
}
}
-static uint32_t spirv_compiler_emit_int_to_bool(struct spirv_compiler *compiler,
- enum vkd3d_shader_conditional_op condition, unsigned int component_count, uint32_t val_id)
+typedef uint32_t (*vkd3d_spirv_builtin_fixup_pfn)(struct spirv_compiler *compiler,
+ uint32_t val_id);
+
+static uint32_t spirv_compiler_emit_draw_parameter_fixup(struct spirv_compiler *compiler,
+ uint32_t index_id, SpvBuiltIn base)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
- uint32_t type_id;
- SpvOp op;
+ uint32_t base_var_id, base_id, type_id;
- assert(!(condition & ~(VKD3D_SHADER_CONDITIONAL_OP_NZ | VKD3D_SHADER_CONDITIONAL_OP_Z)));
+ vkd3d_spirv_enable_capability(builder, SpvCapabilityDrawParameters);
- type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_BOOL, component_count);
- op = condition & VKD3D_SHADER_CONDITIONAL_OP_Z ? SpvOpIEqual : SpvOpINotEqual;
- return vkd3d_spirv_build_op_tr2(builder, &builder->function_stream, op, type_id, val_id,
- spirv_compiler_get_constant_uint_vector(compiler, 0, component_count));
-}
+ base_var_id = spirv_compiler_emit_variable(compiler, &builder->global_stream,
+ SpvStorageClassInput, VKD3D_SHADER_COMPONENT_INT, 1);
+ vkd3d_spirv_add_iface_variable(builder, base_var_id);
+ spirv_compiler_decorate_builtin(compiler, base_var_id, base);
-static uint32_t spirv_compiler_emit_bool_to_int(struct spirv_compiler *compiler,
- unsigned int component_count, uint32_t val_id, bool signedness)
-{
- struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
- uint32_t type_id, true_id, false_id;
+ type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_INT, 1);
+ base_id = vkd3d_spirv_build_op_load(builder,
+ type_id, base_var_id, SpvMemoryAccessMaskNone);
- true_id = spirv_compiler_get_constant_uint_vector(compiler, signedness ? 0xffffffff : 1, component_count);
- false_id = spirv_compiler_get_constant_uint_vector(compiler, 0, component_count);
- type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, component_count);
- return vkd3d_spirv_build_op_select(builder, type_id, val_id, true_id, false_id);
+ return vkd3d_spirv_build_op_isub(builder, type_id, index_id, base_id);
}
-static uint32_t spirv_compiler_emit_bool_to_float(struct spirv_compiler *compiler,
- unsigned int component_count, uint32_t val_id, bool signedness)
+/* Substitute "VertexIndex - BaseVertex" for SV_VertexID. */
+static uint32_t sv_vertex_id_fixup(struct spirv_compiler *compiler,
+ uint32_t vertex_index_id)
{
- struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
- uint32_t type_id, true_id, false_id;
-
- true_id = spirv_compiler_get_constant_float_vector(compiler, signedness ? -1.0f : 1.0f, component_count);
- false_id = spirv_compiler_get_constant_float_vector(compiler, 0.0f, component_count);
- type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, component_count);
- return vkd3d_spirv_build_op_select(builder, type_id, val_id, true_id, false_id);
-}
-
-static uint32_t spirv_compiler_emit_bool_to_double(struct spirv_compiler *compiler,
- unsigned int component_count, uint32_t val_id, bool signedness)
-{
- struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
- uint32_t type_id, true_id, false_id;
-
- true_id = spirv_compiler_get_constant_double_vector(compiler, signedness ? -1.0 : 1.0, component_count);
- false_id = spirv_compiler_get_constant_double_vector(compiler, 0.0, component_count);
- type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_DOUBLE, component_count);
- return vkd3d_spirv_build_op_select(builder, type_id, val_id, true_id, false_id);
-}
-
-typedef uint32_t (*vkd3d_spirv_builtin_fixup_pfn)(struct spirv_compiler *compiler,
- uint32_t val_id);
-
-static uint32_t spirv_compiler_emit_draw_parameter_fixup(struct spirv_compiler *compiler,
- uint32_t index_id, SpvBuiltIn base)
-{
- struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
- uint32_t base_var_id, base_id, type_id;
-
- vkd3d_spirv_enable_capability(builder, SpvCapabilityDrawParameters);
-
- base_var_id = spirv_compiler_emit_variable(compiler, &builder->global_stream,
- SpvStorageClassInput, VKD3D_SHADER_COMPONENT_INT, 1);
- vkd3d_spirv_add_iface_variable(builder, base_var_id);
- spirv_compiler_decorate_builtin(compiler, base_var_id, base);
-
- type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_INT, 1);
- base_id = vkd3d_spirv_build_op_load(builder,
- type_id, base_var_id, SpvMemoryAccessMaskNone);
-
- return vkd3d_spirv_build_op_isub(builder, type_id, index_id, base_id);
-}
-
-/* Substitute "VertexIndex - BaseVertex" for SV_VertexID. */
-static uint32_t sv_vertex_id_fixup(struct spirv_compiler *compiler,
- uint32_t vertex_index_id)
-{
- return spirv_compiler_emit_draw_parameter_fixup(compiler,
- vertex_index_id, SpvBuiltInBaseVertex);
-}
+ return spirv_compiler_emit_draw_parameter_fixup(compiler,
+ vertex_index_id, SpvBuiltInBaseVertex);
+}
/* Substitute "InstanceIndex - BaseInstance" for SV_InstanceID. */
static uint32_t sv_instance_id_fixup(struct spirv_compiler *compiler,
@@ -4422,9 +4625,9 @@ vkd3d_register_builtins[] =
};
static void spirv_compiler_emit_register_execution_mode(struct spirv_compiler *compiler,
- const struct vkd3d_shader_register *reg)
+ enum vkd3d_shader_register_type type)
{
- switch (reg->type)
+ switch (type)
{
case VKD3DSPR_DEPTHOUTGE:
spirv_compiler_emit_execution_mode(compiler, SpvExecutionModeDepthGreater, NULL, 0);
@@ -4437,9 +4640,9 @@ static void spirv_compiler_emit_register_execution_mode(struct spirv_compiler *c
VKD3D_SHADER_SPIRV_EXTENSION_EXT_STENCIL_EXPORT))
{
FIXME("The target environment does not support stencil export.\n");
- spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_STENCIL_EXPORT_UNSUPPORTED,
- "Cannot export stencil reference value for register id %u. "
- "The target environment does not support stencil export.", reg->idx[0].offset);
+ spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_UNSUPPORTED_FEATURE,
+ "Cannot export stencil reference value. "
+ "The target environment does not support stencil export.");
}
vkd3d_spirv_enable_capability(&compiler->spirv_builder, SpvCapabilityStencilExportEXT);
spirv_compiler_emit_execution_mode(compiler, SpvExecutionModeStencilRefReplacingEXT, NULL, 0);
@@ -4635,7 +4838,7 @@ static uint32_t spirv_compiler_emit_builtin_variable_v(struct spirv_compiler *co
assert(size_count <= ARRAY_SIZE(sizes));
memcpy(sizes, array_sizes, size_count * sizeof(sizes[0]));
array_sizes = sizes;
- sizes[size_count - 1] = max(sizes[size_count - 1], builtin->spirv_array_size);
+ sizes[0] = max(sizes[0], builtin->spirv_array_size);
id = spirv_compiler_emit_array_variable(compiler, &builder->global_stream, storage_class,
builtin->component_type, builtin->component_count, array_sizes, size_count);
@@ -4674,17 +4877,16 @@ static unsigned int shader_signature_next_location(const struct shader_signature
}
static uint32_t spirv_compiler_emit_input(struct spirv_compiler *compiler,
- const struct vkd3d_shader_dst_param *dst)
+ enum vkd3d_shader_register_type reg_type, unsigned int element_idx)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
- const struct vkd3d_shader_register *reg = &dst->reg;
unsigned int component_idx, input_component_count;
const struct signature_element *signature_element;
const struct shader_signature *shader_signature;
enum vkd3d_shader_component_type component_type;
const struct vkd3d_spirv_builtin *builtin;
enum vkd3d_shader_sysval_semantic sysval;
- unsigned int write_mask, reg_write_mask;
+ uint32_t write_mask, reg_write_mask;
struct vkd3d_symbol *symbol = NULL;
uint32_t val_id, input_id, var_id;
uint32_t type_id, float_type_id;
@@ -4693,31 +4895,26 @@ static uint32_t spirv_compiler_emit_input(struct spirv_compiler *compiler,
struct rb_entry *entry = NULL;
bool use_private_var = false;
unsigned int array_sizes[2];
- unsigned int element_idx;
-
- assert(!reg->idx_count || !reg->idx[0].rel_addr);
- assert(reg->idx_count < 2 || !reg->idx[1].rel_addr);
- shader_signature = reg->type == VKD3DSPR_PATCHCONST
+ shader_signature = reg_type == VKD3DSPR_PATCHCONST
? &compiler->patch_constant_signature : &compiler->input_signature;
- element_idx = reg->idx[reg->idx_count - 1].offset;
signature_element = &shader_signature->elements[element_idx];
sysval = signature_element->sysval_semantic;
/* The Vulkan spec does not explicitly forbid passing varyings from the
* TCS to the TES via builtins. However, Mesa doesn't seem to handle it
* well, and we don't actually need them to be in builtins. */
- if (compiler->shader_type == VKD3D_SHADER_TYPE_DOMAIN && reg->type != VKD3DSPR_PATCHCONST)
+ if (compiler->shader_type == VKD3D_SHADER_TYPE_DOMAIN && reg_type != VKD3DSPR_PATCHCONST)
sysval = VKD3D_SHADER_SV_NONE;
builtin = get_spirv_builtin_for_sysval(compiler, sysval);
- array_sizes[0] = (reg->type == VKD3DSPR_PATCHCONST ? 0 : compiler->input_control_point_count);
- array_sizes[1] = signature_element->register_count;
- if (array_sizes[1] == 1 && !vsir_sysval_semantic_is_tess_factor(signature_element->sysval_semantic)
- && (!vsir_sysval_semantic_is_clip_cull(signature_element->sysval_semantic) || array_sizes[0]))
+ array_sizes[0] = signature_element->register_count;
+ array_sizes[1] = (reg_type == VKD3DSPR_PATCHCONST ? 0 : compiler->input_control_point_count);
+ if (array_sizes[0] == 1 && !vsir_sysval_semantic_is_tess_factor(signature_element->sysval_semantic)
+ && (!vsir_sysval_semantic_is_clip_cull(signature_element->sysval_semantic) || array_sizes[1]))
{
- array_sizes[1] = 0;
+ array_sizes[0] = 0;
}
write_mask = signature_element->mask;
@@ -4731,8 +4928,8 @@ static uint32_t spirv_compiler_emit_input(struct spirv_compiler *compiler,
else
{
component_type = signature_element->component_type;
- input_component_count = vkd3d_write_mask_component_count(signature_element->mask);
- component_idx = vkd3d_write_mask_get_component_idx(signature_element->mask);
+ input_component_count = vsir_write_mask_component_count(signature_element->mask);
+ component_idx = vsir_write_mask_get_component_idx(signature_element->mask);
}
if (needs_private_io_variable(builtin))
@@ -4742,13 +4939,13 @@ static uint32_t spirv_compiler_emit_input(struct spirv_compiler *compiler,
}
else
{
- component_idx = vkd3d_write_mask_get_component_idx(write_mask);
+ component_idx = vsir_write_mask_get_component_idx(write_mask);
reg_write_mask = write_mask >> component_idx;
}
storage_class = SpvStorageClassInput;
- vkd3d_symbol_make_register(&reg_symbol, reg);
+ vkd3d_symbol_make_io(&reg_symbol, reg_type, element_idx);
if ((entry = rb_get(&compiler->symbol_table, &reg_symbol)))
{
@@ -4756,7 +4953,7 @@ static uint32_t spirv_compiler_emit_input(struct spirv_compiler *compiler,
* duplicate declarations are: a single register split into multiple declarations having
* different components, which should have been merged, and declarations in one phase
* being repeated in another (i.e. vcp/vocp), which should have been deleted. */
- if (reg->type != VKD3DSPR_INPUT || !is_in_fork_or_join_phase(compiler))
+ if (reg_type != VKD3DSPR_INPUT || !is_in_fork_or_join_phase(compiler))
FIXME("Duplicate input definition found.\n");
symbol = RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry);
return symbol->id;
@@ -4765,7 +4962,7 @@ static uint32_t spirv_compiler_emit_input(struct spirv_compiler *compiler,
if (builtin)
{
input_id = spirv_compiler_emit_builtin_variable_v(compiler, builtin, storage_class, array_sizes, 2);
- if (reg->type == VKD3DSPR_PATCHCONST)
+ if (reg_type == VKD3DSPR_PATCHCONST)
vkd3d_spirv_build_op_decorate(builder, input_id, SpvDecorationPatch, NULL, 0);
}
else
@@ -4775,7 +4972,7 @@ static uint32_t spirv_compiler_emit_input(struct spirv_compiler *compiler,
input_id = spirv_compiler_emit_array_variable(compiler, &builder->global_stream,
storage_class, component_type, input_component_count, array_sizes, 2);
vkd3d_spirv_add_iface_variable(builder, input_id);
- if (reg->type == VKD3DSPR_PATCHCONST)
+ if (reg_type == VKD3DSPR_PATCHCONST)
{
vkd3d_spirv_build_op_decorate(builder, input_id, SpvDecorationPatch, NULL, 0);
location += shader_signature_next_location(&compiler->input_signature);
@@ -4784,7 +4981,8 @@ static uint32_t spirv_compiler_emit_input(struct spirv_compiler *compiler,
if (component_idx)
vkd3d_spirv_build_op_decorate1(builder, input_id, SpvDecorationComponent, component_idx);
- spirv_compiler_emit_interpolation_decorations(compiler, input_id, signature_element->interpolation_mode);
+ spirv_compiler_emit_interpolation_decorations(compiler, component_type, input_id,
+ signature_element->interpolation_mode);
}
var_id = input_id;
@@ -4802,12 +5000,14 @@ static uint32_t spirv_compiler_emit_input(struct spirv_compiler *compiler,
assert(!builtin || !builtin->spirv_array_size || use_private_var || array_sizes[0] || array_sizes[1]);
spirv_compiler_put_symbol(compiler, &reg_symbol);
- spirv_compiler_emit_register_debug_name(builder, var_id, reg);
+ vkd3d_spirv_build_op_name(builder, var_id, reg_type == VKD3DSPR_PATCHCONST ? "vpc%u" : "v%u", element_idx);
if (use_private_var)
{
- struct vkd3d_shader_register dst_reg = *reg;
- dst_reg.data_type = VKD3D_DATA_FLOAT;
+ struct vkd3d_shader_register dst_reg;
+
+ vsir_register_init(&dst_reg, reg_type, VKD3D_DATA_FLOAT, 1);
+ dst_reg.idx[0].offset = element_idx;
type_id = vkd3d_spirv_get_type_id(builder, component_type, input_component_count);
@@ -4824,9 +5024,9 @@ static uint32_t spirv_compiler_emit_input(struct spirv_compiler *compiler,
val_id = spirv_compiler_emit_swizzle(compiler, val_id,
vkd3d_write_mask_from_component_count(input_component_count),
- VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_SHADER_NO_SWIZZLE, dst->write_mask >> component_idx);
+ VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_SHADER_NO_SWIZZLE, signature_element->mask >> component_idx);
- spirv_compiler_emit_store_reg(compiler, &dst_reg, dst->write_mask, val_id);
+ spirv_compiler_emit_store_reg(compiler, &dst_reg, signature_element->mask, val_id);
}
return input_id;
@@ -4896,7 +5096,7 @@ static void calculate_clip_or_cull_distance_mask(const struct signature_element
return;
}
- write_mask = e->mask >> vkd3d_write_mask_get_component_idx(e->mask);
+ write_mask = e->mask >> vsir_write_mask_get_component_idx(e->mask);
*mask |= (write_mask & VKD3DSP_WRITEMASK_ALL) << (VKD3D_VEC4_SIZE * e->semantic_index);
}
@@ -4995,7 +5195,7 @@ static void spirv_compiler_emit_output_register(struct spirv_compiler *compiler,
SpvStorageClassOutput, builtin->component_type, write_mask);
reg_symbol.info.reg.is_aggregate = builtin->spirv_array_size;
spirv_compiler_put_symbol(compiler, &reg_symbol);
- spirv_compiler_emit_register_execution_mode(compiler, reg);
+ spirv_compiler_emit_register_execution_mode(compiler, reg->type);
spirv_compiler_emit_register_debug_name(builder, output_id, reg);
}
@@ -5024,46 +5224,44 @@ static uint32_t spirv_compiler_emit_shader_phase_builtin_variable(struct spirv_c
return id;
}
-static void spirv_compiler_emit_output(struct spirv_compiler *compiler, const struct vkd3d_shader_dst_param *dst)
+static void spirv_compiler_emit_output(struct spirv_compiler *compiler,
+ enum vkd3d_shader_register_type reg_type, unsigned int element_idx)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
- const struct vkd3d_shader_register *reg = &dst->reg;
unsigned int component_idx, output_component_count;
const struct signature_element *signature_element;
enum vkd3d_shader_component_type component_type;
const struct shader_signature *shader_signature;
const struct vkd3d_spirv_builtin *builtin;
enum vkd3d_shader_sysval_semantic sysval;
- unsigned int write_mask, reg_write_mask;
+ uint32_t write_mask, reg_write_mask;
bool use_private_variable = false;
struct vkd3d_symbol reg_symbol;
SpvStorageClass storage_class;
unsigned int array_sizes[2];
- unsigned int element_idx;
bool is_patch_constant;
uint32_t id, var_id;
- is_patch_constant = is_in_fork_or_join_phase(compiler);
+ is_patch_constant = (reg_type == VKD3DSPR_PATCHCONST);
shader_signature = is_patch_constant ? &compiler->patch_constant_signature : &compiler->output_signature;
- element_idx = reg->idx[reg->idx_count - 1].offset;
signature_element = &shader_signature->elements[element_idx];
sysval = signature_element->sysval_semantic;
/* Don't use builtins for TCS -> TES varyings. See spirv_compiler_emit_input(). */
if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL && !is_patch_constant)
sysval = VKD3D_SHADER_SV_NONE;
- array_sizes[0] = (reg->type == VKD3DSPR_PATCHCONST ? 0 : compiler->output_control_point_count);
- array_sizes[1] = signature_element->register_count;
- if (array_sizes[1] == 1 && !vsir_sysval_semantic_is_tess_factor(signature_element->sysval_semantic))
- array_sizes[1] = 0;
+ array_sizes[0] = signature_element->register_count;
+ array_sizes[1] = (reg_type == VKD3DSPR_PATCHCONST ? 0 : compiler->output_control_point_count);
+ if (array_sizes[0] == 1 && !vsir_sysval_semantic_is_tess_factor(signature_element->sysval_semantic))
+ array_sizes[0] = 0;
- builtin = vkd3d_get_spirv_builtin(compiler, dst->reg.type, sysval);
+ builtin = vkd3d_get_spirv_builtin(compiler, reg_type, sysval);
write_mask = signature_element->mask;
- component_idx = vkd3d_write_mask_get_component_idx(write_mask);
- output_component_count = vkd3d_write_mask_component_count(write_mask);
+ component_idx = vsir_write_mask_get_component_idx(write_mask);
+ output_component_count = vsir_write_mask_component_count(write_mask);
if (builtin)
{
component_type = builtin->component_type;
@@ -5077,15 +5275,18 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler, const st
storage_class = SpvStorageClassOutput;
- if (get_shader_output_swizzle(compiler, signature_element->register_index) != VKD3D_SHADER_NO_SWIZZLE
- || (compiler->output_info[element_idx].id && compiler->output_info[element_idx].array_element_mask)
- || needs_private_io_variable(builtin))
+ if (needs_private_io_variable(builtin))
+ use_private_variable = true;
+
+ if (!is_patch_constant
+ && (get_shader_output_swizzle(compiler, signature_element->register_index) != VKD3D_SHADER_NO_SWIZZLE
+ || (compiler->output_info[element_idx].id && compiler->output_info[element_idx].array_element_mask)))
{
use_private_variable = true;
}
reg_write_mask = write_mask >> component_idx;
- vkd3d_symbol_make_register(&reg_symbol, reg);
+ vkd3d_symbol_make_io(&reg_symbol, reg_type, element_idx);
if (rb_get(&compiler->symbol_table, &reg_symbol))
{
@@ -5094,7 +5295,7 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler, const st
return;
}
- if (compiler->output_info[element_idx].id)
+ if (!is_patch_constant && compiler->output_info[element_idx].id)
{
id = compiler->output_info[element_idx].id;
}
@@ -5105,7 +5306,7 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler, const st
else
id = spirv_compiler_emit_builtin_variable_v(compiler, builtin, storage_class, array_sizes, 2);
- spirv_compiler_emit_register_execution_mode(compiler, &dst->reg);
+ spirv_compiler_emit_register_execution_mode(compiler, reg_type);
}
else if (signature_element->target_location == SIGNATURE_TARGET_LOCATION_UNUSED)
{
@@ -5146,8 +5347,11 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler, const st
spirv_compiler_decorate_xfb_output(compiler, id, output_component_count, signature_element);
- compiler->output_info[element_idx].id = id;
- compiler->output_info[element_idx].component_type = component_type;
+ if (!is_patch_constant)
+ {
+ compiler->output_info[element_idx].id = id;
+ compiler->output_info[element_idx].component_type = component_type;
+ }
var_id = id;
if (use_private_variable)
@@ -5165,8 +5369,7 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler, const st
spirv_compiler_put_symbol(compiler, &reg_symbol);
- if (!is_patch_constant)
- spirv_compiler_emit_register_debug_name(builder, var_id, reg);
+ vkd3d_spirv_build_op_name(builder, var_id, reg_type == VKD3DSPR_PATCHCONST ? "vpc%u" : "o%u", element_idx);
if (use_private_variable)
{
@@ -5198,9 +5401,9 @@ static uint32_t spirv_compiler_get_output_array_index(struct spirv_compiler *com
static void spirv_compiler_emit_store_shader_output(struct spirv_compiler *compiler,
const struct shader_signature *signature, const struct signature_element *output,
const struct vkd3d_shader_output_info *output_info,
- uint32_t output_index_id, uint32_t val_id, unsigned int write_mask)
+ uint32_t output_index_id, uint32_t val_id, uint32_t write_mask)
{
- unsigned int dst_write_mask, use_mask, uninit_mask, swizzle, mask;
+ uint32_t dst_write_mask, use_mask, uninit_mask, swizzle, mask;
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t type_id, zero_id, ptr_type_id, chain_id, object_id;
const struct signature_element *element;
@@ -5222,7 +5425,7 @@ static void spirv_compiler_emit_store_shader_output(struct spirv_compiler *compi
use_mask |= element->used_mask;
}
}
- index = vkd3d_write_mask_get_component_idx(output->mask);
+ index = vsir_write_mask_get_component_idx(output->mask);
dst_write_mask >>= index;
use_mask >>= index;
write_mask &= dst_write_mask;
@@ -5246,7 +5449,7 @@ static void spirv_compiler_emit_store_shader_output(struct spirv_compiler *compi
output_info->component_type, VKD3D_VEC4_SIZE, 0);
val_id = spirv_compiler_emit_vector_shuffle(compiler,
zero_id, val_id, swizzle, uninit_mask, output_info->component_type,
- vkd3d_write_mask_component_count(write_mask));
+ vsir_write_mask_component_count(write_mask));
}
else
{
@@ -5258,7 +5461,7 @@ static void spirv_compiler_emit_store_shader_output(struct spirv_compiler *compi
if (output_index_id)
{
type_id = vkd3d_spirv_get_type_id(builder,
- output_info->component_type, vkd3d_write_mask_component_count(dst_write_mask));
+ output_info->component_type, vsir_write_mask_component_count(dst_write_mask));
ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassOutput, type_id);
output_id = vkd3d_spirv_build_op_access_chain1(builder, ptr_type_id, output_id, output_index_id);
}
@@ -5412,7 +5615,6 @@ static void spirv_compiler_emit_initial_declarations(struct spirv_compiler *comp
if (compiler->shader_type != VKD3D_SHADER_TYPE_HULL)
{
vkd3d_spirv_builder_begin_main_function(builder);
- compiler->main_block_open = true;
}
}
@@ -5440,10 +5642,34 @@ static void spirv_compiler_emit_dcl_global_flags(struct spirv_compiler *compiler
if (flags & (VKD3DSGF_ENABLE_DOUBLE_PRECISION_FLOAT_OPS | VKD3DSGF_ENABLE_11_1_DOUBLE_EXTENSIONS))
{
- vkd3d_spirv_enable_capability(&compiler->spirv_builder, SpvCapabilityFloat64);
+ if (compiler->features & VKD3D_SHADER_COMPILE_OPTION_FEATURE_FLOAT64)
+ {
+ vkd3d_spirv_enable_capability(&compiler->spirv_builder, SpvCapabilityFloat64);
+ }
+ else
+ {
+ WARN("Unsupported 64-bit float ops.\n");
+ spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_UNSUPPORTED_FEATURE,
+ "The target environment does not support 64-bit floating point.");
+ }
flags &= ~(VKD3DSGF_ENABLE_DOUBLE_PRECISION_FLOAT_OPS | VKD3DSGF_ENABLE_11_1_DOUBLE_EXTENSIONS);
}
+ if (flags & VKD3DSGF_ENABLE_INT64)
+ {
+ if (compiler->features & VKD3D_SHADER_COMPILE_OPTION_FEATURE_INT64)
+ {
+ vkd3d_spirv_enable_capability(&compiler->spirv_builder, SpvCapabilityInt64);
+ }
+ else
+ {
+ WARN("Unsupported 64-bit integer ops.\n");
+ spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_UNSUPPORTED_FEATURE,
+ "The target environment does not support 64-bit integers.");
+ }
+ flags &= ~VKD3DSGF_ENABLE_INT64;
+ }
+
if (flags & ~(VKD3DSGF_REFACTORING_ALLOWED | VKD3DSGF_ENABLE_RAW_AND_STRUCTURED_BUFFERS))
FIXME("Unhandled global flags %#"PRIx64".\n", (uint64_t)flags);
else
@@ -5493,39 +5719,43 @@ static void spirv_compiler_emit_dcl_indexable_temp(struct spirv_compiler *compil
{
const struct vkd3d_shader_indexable_temp *temp = &instruction->declaration.indexable_temp;
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+ uint32_t id, type_id, length_id, ptr_type_id, init_id = 0;
+ enum vkd3d_shader_component_type component_type;
struct vkd3d_shader_register reg;
struct vkd3d_symbol reg_symbol;
+ SpvStorageClass storage_class;
size_t function_location;
- uint32_t id;
- if (temp->component_count != 4)
- FIXME("Unhandled component count %u.\n", temp->component_count);
+ /* Indexable temps may be used by more than one function in hull shaders, and
+ * declarations generally should not occur within VSIR code blocks unless function
+ * scope is specified, e.g. DXIL alloca. */
+ storage_class = temp->has_function_scope ? SpvStorageClassFunction : SpvStorageClassPrivate;
vsir_register_init(&reg, VKD3DSPR_IDXTEMP, VKD3D_DATA_FLOAT, 1);
reg.idx[0].offset = temp->register_idx;
if (temp->alignment)
WARN("Ignoring alignment %u.\n", temp->alignment);
- if (temp->initialiser)
- {
- FIXME("Initialisers are not supported.\n");
- spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_NOT_IMPLEMENTED,
- "Initialisers for indexable temps are not supported.");
- }
function_location = spirv_compiler_get_current_function_location(compiler);
vkd3d_spirv_begin_function_stream_insertion(builder, function_location);
- id = spirv_compiler_emit_array_variable(compiler, &builder->function_stream,
- SpvStorageClassFunction, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE, &temp->register_size, 1);
+ component_type = vkd3d_component_type_from_data_type(temp->data_type);
+ type_id = vkd3d_spirv_get_type_id(builder, component_type, temp->component_count);
+ length_id = spirv_compiler_get_constant_uint(compiler, temp->register_size);
+ type_id = vkd3d_spirv_get_op_type_array(builder, type_id, length_id);
+ ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, type_id);
+ if (temp->initialiser)
+ init_id = spirv_compiler_emit_constant_array(compiler, temp->initialiser, NULL);
+ id = vkd3d_spirv_build_op_variable(builder, &builder->function_stream, ptr_type_id, storage_class, init_id);
spirv_compiler_emit_register_debug_name(builder, id, &reg);
vkd3d_spirv_end_function_stream_insertion(builder);
vkd3d_symbol_make_register(&reg_symbol, &reg);
- vkd3d_symbol_set_register_info(&reg_symbol, id,
- SpvStorageClassFunction, VKD3D_SHADER_COMPONENT_FLOAT, VKD3DSP_WRITEMASK_ALL);
+ vkd3d_symbol_set_register_info(&reg_symbol, id, storage_class,
+ component_type, vkd3d_write_mask_from_component_count(temp->component_count));
spirv_compiler_put_symbol(compiler, &reg_symbol);
}
@@ -5743,34 +5973,24 @@ static void spirv_compiler_emit_dcl_immediate_constant_buffer(struct spirv_compi
const struct vkd3d_shader_instruction *instruction)
{
const struct vkd3d_shader_immediate_constant_buffer *icb = instruction->declaration.icb;
- uint32_t *elements, length_id, type_id, const_id, ptr_type_id, icb_id;
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+ uint32_t type_id, const_id, ptr_type_id, icb_id;
struct vkd3d_shader_register reg;
struct vkd3d_symbol reg_symbol;
- unsigned int i;
-
- assert(icb->data_type == VKD3D_DATA_FLOAT);
- assert(icb->component_count == VKD3D_VEC4_SIZE);
- if (!(elements = vkd3d_calloc(icb->element_count, sizeof(*elements))))
- return;
- for (i = 0; i < icb->element_count; ++i)
- elements[i] = spirv_compiler_get_constant(compiler,
- VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE, &icb->data[4 * i]);
- type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, VKD3D_VEC4_SIZE);
- length_id = spirv_compiler_get_constant_uint(compiler, icb->element_count);
- type_id = vkd3d_spirv_get_op_type_array(builder, type_id, length_id);
- const_id = vkd3d_spirv_build_op_constant_composite(builder, type_id, elements, icb->element_count);
+ const_id = spirv_compiler_emit_constant_array(compiler, icb, &type_id);
ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassPrivate, type_id);
icb_id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream,
ptr_type_id, SpvStorageClassPrivate, const_id);
vkd3d_spirv_build_op_name(builder, icb_id, "icb");
- vkd3d_free(elements);
- vsir_register_init(&reg, VKD3DSPR_IMMCONSTBUFFER, VKD3D_DATA_FLOAT, 0);
+ /* Set an index count of 2 so vkd3d_symbol_make_register() uses idx[0] as a buffer id. */
+ vsir_register_init(&reg, VKD3DSPR_IMMCONSTBUFFER, VKD3D_DATA_FLOAT, 2);
+ reg.idx[0].offset = icb->register_idx;
vkd3d_symbol_make_register(&reg_symbol, &reg);
vkd3d_symbol_set_register_info(&reg_symbol, icb_id, SpvStorageClassPrivate,
- VKD3D_SHADER_COMPONENT_FLOAT, VKD3DSP_WRITEMASK_ALL);
+ vkd3d_component_type_from_data_type(icb->data_type),
+ vkd3d_write_mask_from_component_count(icb->component_count));
spirv_compiler_put_symbol(compiler, &reg_symbol);
}
@@ -6052,6 +6272,9 @@ static void spirv_compiler_emit_resource_declaration(struct spirv_compiler *comp
if (!(d->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_READ))
vkd3d_spirv_build_op_decorate(builder, var_id, SpvDecorationNonReadable, NULL, 0);
+ if (d->uav_flags & VKD3DSUF_GLOBALLY_COHERENT)
+ vkd3d_spirv_build_op_decorate(builder, var_id, SpvDecorationCoherent, NULL, 0);
+
if (d->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_COUNTER)
{
assert(structure_stride); /* counters are valid only for structured buffers */
@@ -6147,37 +6370,22 @@ static void spirv_compiler_emit_dcl_input(struct spirv_compiler *compiler,
{
const struct vkd3d_shader_dst_param *dst = &instruction->declaration.dst;
- /* OUTPOINTID is handled in spirv_compiler_emit_hull_shader_builtins(). */
- if (dst->reg.type == VKD3DSPR_INPUT || dst->reg.type == VKD3DSPR_PATCHCONST)
- spirv_compiler_emit_input(compiler, dst);
- else if (dst->reg.type != VKD3DSPR_OUTPOINTID)
+ /* INPUT and PATCHCONST are handled in spirv_compiler_emit_io_declarations().
+ * OUTPOINTID is handled in spirv_compiler_emit_hull_shader_builtins(). */
+ if (dst->reg.type != VKD3DSPR_INPUT && dst->reg.type != VKD3DSPR_PATCHCONST
+ && dst->reg.type != VKD3DSPR_OUTPOINTID)
spirv_compiler_emit_input_register(compiler, dst);
}
-static void spirv_compiler_emit_dcl_input_sysval(struct spirv_compiler *compiler,
- const struct vkd3d_shader_instruction *instruction)
-{
- spirv_compiler_emit_input(compiler, &instruction->declaration.register_semantic.reg);
-}
-
static void spirv_compiler_emit_dcl_output(struct spirv_compiler *compiler,
const struct vkd3d_shader_instruction *instruction)
{
const struct vkd3d_shader_dst_param *dst = &instruction->declaration.dst;
- if (dst->reg.type == VKD3DSPR_OUTPUT
- || (is_in_fork_or_join_phase(compiler) && dst->reg.type == VKD3DSPR_PATCHCONST))
- spirv_compiler_emit_output(compiler, dst);
- else
+ if (dst->reg.type != VKD3DSPR_OUTPUT && dst->reg.type != VKD3DSPR_PATCHCONST)
spirv_compiler_emit_output_register(compiler, dst);
}
-static void spirv_compiler_emit_dcl_output_siv(struct spirv_compiler *compiler,
- const struct vkd3d_shader_instruction *instruction)
-{
- spirv_compiler_emit_output(compiler, &instruction->declaration.register_semantic.reg);
-}
-
static void spirv_compiler_emit_dcl_stream(struct spirv_compiler *compiler,
const struct vkd3d_shader_instruction *instruction)
{
@@ -6256,7 +6464,7 @@ static void spirv_compiler_emit_dcl_output_topology(struct spirv_compiler *compi
{
case VKD3D_PT_POINTLIST:
mode = SpvExecutionModeOutputPoints;
- spirv_compiler_emit_point_size(compiler);
+ compiler->emit_point_size = true;
break;
case VKD3D_PT_LINESTRIP:
mode = SpvExecutionModeOutputLineStrip;
@@ -6377,7 +6585,6 @@ static void spirv_compiler_emit_default_control_point_phase(struct spirv_compile
static void spirv_compiler_leave_shader_phase(struct spirv_compiler *compiler)
{
- const struct shader_signature *signature = &compiler->output_signature;
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
if (is_in_control_point_phase(compiler) && compiler->emit_default_control_point_phase)
@@ -6395,7 +6602,6 @@ static void spirv_compiler_leave_shader_phase(struct spirv_compiler *compiler)
/* Fork and join phases share output registers (patch constants).
* Control point phase has separate output registers. */
- memset(compiler->output_info, 0, signature->element_count * sizeof(*compiler->output_info));
memset(compiler->private_output_variable, 0, sizeof(compiler->private_output_variable));
memset(compiler->private_output_variable_write_mask, 0, sizeof(compiler->private_output_variable_write_mask));
}
@@ -6420,35 +6626,59 @@ static void spirv_compiler_enter_shader_phase(struct spirv_compiler *compiler,
vkd3d_spirv_build_op_function(builder, void_id, function_id,
SpvFunctionControlMaskNone, function_type_id);
- vkd3d_spirv_build_op_label(builder, vkd3d_spirv_alloc_id(builder));
-
compiler->phase = instruction->handler_idx;
spirv_compiler_emit_shader_phase_name(compiler, function_id, NULL);
phase = (instruction->handler_idx == VKD3DSIH_HS_CONTROL_POINT_PHASE)
? &compiler->control_point_phase : &compiler->patch_constant_phase;
phase->function_id = function_id;
- phase->function_location = vkd3d_spirv_stream_current_location(&builder->function_stream);
+ /* The insertion location must be set after the label is emitted. */
+ phase->function_location = 0;
if (instruction->handler_idx == VKD3DSIH_HS_CONTROL_POINT_PHASE)
compiler->emit_default_control_point_phase = instruction->flags;
}
+static void spirv_compiler_initialise_block(struct spirv_compiler *compiler)
+{
+ struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+
+ /* Insertion locations must point immediately after the function's initial label. */
+ if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL)
+ {
+ struct vkd3d_shader_phase *phase = (compiler->phase == VKD3DSIH_HS_CONTROL_POINT_PHASE)
+ ? &compiler->control_point_phase : &compiler->patch_constant_phase;
+ if (!phase->function_location)
+ phase->function_location = vkd3d_spirv_stream_current_location(&builder->function_stream);
+ }
+ else if (!builder->main_function_location)
+ {
+ builder->main_function_location = vkd3d_spirv_stream_current_location(&builder->function_stream);
+ }
+
+ /* I/O declarations can result in emission of fixups, which must occur after the initial label. */
+ if (!compiler->prolog_emitted)
+ {
+ spirv_compiler_emit_main_prolog(compiler);
+ spirv_compiler_emit_io_declarations(compiler);
+ compiler->prolog_emitted = true;
+ }
+}
+
static void spirv_compiler_emit_default_control_point_phase(struct spirv_compiler *compiler)
{
const struct shader_signature *output_signature = &compiler->output_signature;
const struct shader_signature *input_signature = &compiler->input_signature;
+ uint32_t type_id, output_ptr_type_id, input_id, dst_id, invocation_id;
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
enum vkd3d_shader_component_type component_type;
struct vkd3d_shader_src_param invocation;
struct vkd3d_shader_register input_reg;
- uint32_t type_id, output_ptr_type_id;
- uint32_t input_id, output_id, dst_id;
unsigned int component_count;
- unsigned int array_sizes[2];
- uint32_t invocation_id;
unsigned int i;
+ vkd3d_spirv_build_op_label(builder, vkd3d_spirv_alloc_id(builder));
+ spirv_compiler_initialise_block(compiler);
invocation_id = spirv_compiler_emit_load_invocation_id(compiler);
memset(&invocation, 0, sizeof(invocation));
@@ -6466,6 +6696,8 @@ static void spirv_compiler_emit_default_control_point_phase(struct spirv_compile
{
const struct signature_element *output = &output_signature->elements[i];
const struct signature_element *input = &input_signature->elements[i];
+ struct vkd3d_shader_register_info output_reg_info;
+ struct vkd3d_shader_register output_reg;
assert(input->mask == output->mask);
assert(input->component_type == output->component_type);
@@ -6473,22 +6705,16 @@ static void spirv_compiler_emit_default_control_point_phase(struct spirv_compile
input_reg.idx[1].offset = i;
input_id = spirv_compiler_get_register_id(compiler, &input_reg);
+ vsir_register_init(&output_reg, VKD3DSPR_OUTPUT, VKD3D_DATA_FLOAT, 1);
+ output_reg.idx[0].offset = i;
+ spirv_compiler_get_register_info(compiler, &output_reg, &output_reg_info);
+
component_type = output->component_type;
- component_count = vkd3d_write_mask_component_count(output->mask);
+ component_count = vsir_write_mask_component_count(output->mask);
type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count);
- if ((array_sizes[0] = (input->register_count > 1) ? input->register_count : 0))
- type_id = vkd3d_spirv_get_op_type_array(builder, type_id, spirv_compiler_get_constant_uint(compiler,
- array_sizes[0]));
-
- array_sizes[1] = compiler->output_control_point_count;
- output_id = spirv_compiler_emit_array_variable(compiler, &builder->global_stream, SpvStorageClassOutput,
- component_type, component_count, array_sizes, 2);
- vkd3d_spirv_add_iface_variable(builder, output_id);
- vkd3d_spirv_build_op_decorate1(builder, output_id, SpvDecorationLocation, output->register_index);
- vkd3d_spirv_build_op_name(builder, output_id, "vocp%u", output->register_index);
-
output_ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassOutput, type_id);
- dst_id = vkd3d_spirv_build_op_access_chain1(builder, output_ptr_type_id, output_id, invocation_id);
+
+ dst_id = vkd3d_spirv_build_op_access_chain1(builder, output_ptr_type_id, output_reg_info.id, invocation_id);
vkd3d_spirv_build_op_copy_memory(builder, dst_id, input_id, SpvMemoryAccessMaskNone);
}
@@ -6547,7 +6773,11 @@ static void spirv_compiler_emit_hull_shader_main(struct spirv_compiler *compiler
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t void_id;
+ /* If a patch constant function used descriptor indexing the offsets must be reloaded. */
+ memset(compiler->descriptor_offset_ids, 0, compiler->offset_info.descriptor_table_count
+ * sizeof(*compiler->descriptor_offset_ids));
vkd3d_spirv_builder_begin_main_function(builder);
+ vkd3d_spirv_build_op_label(builder, vkd3d_spirv_alloc_id(builder));
void_id = vkd3d_spirv_get_op_type_void(builder);
@@ -6591,14 +6821,18 @@ static SpvOp spirv_compiler_map_alu_instruction(const struct vkd3d_shader_instru
{VKD3DSIH_INEG, SpvOpSNegate},
{VKD3DSIH_ISHL, SpvOpShiftLeftLogical},
{VKD3DSIH_ISHR, SpvOpShiftRightArithmetic},
+ {VKD3DSIH_ISINF, SpvOpIsInf},
+ {VKD3DSIH_ISNAN, SpvOpIsNan},
{VKD3DSIH_ITOD, SpvOpConvertSToF},
{VKD3DSIH_ITOF, SpvOpConvertSToF},
+ {VKD3DSIH_ITOI, SpvOpSConvert},
{VKD3DSIH_MUL, SpvOpFMul},
{VKD3DSIH_NOT, SpvOpNot},
{VKD3DSIH_OR, SpvOpBitwiseOr},
{VKD3DSIH_USHR, SpvOpShiftRightLogical},
{VKD3DSIH_UTOD, SpvOpConvertUToF},
{VKD3DSIH_UTOF, SpvOpConvertUToF},
+ {VKD3DSIH_UTOU, SpvOpUConvert},
{VKD3DSIH_XOR, SpvOpBitwiseXor},
};
unsigned int i;
@@ -6650,6 +6884,10 @@ static void spirv_compiler_emit_bool_cast(struct spirv_compiler *compiler,
{
val_id = spirv_compiler_emit_bool_to_int(compiler, 1, val_id, instruction->handler_idx == VKD3DSIH_ITOI);
}
+ else if (dst->reg.data_type == VKD3D_DATA_UINT64)
+ {
+ val_id = spirv_compiler_emit_bool_to_int64(compiler, 1, val_id, instruction->handler_idx == VKD3DSIH_ITOI);
+ }
else
{
WARN("Unhandled data type %u.\n", dst->reg.data_type);
@@ -6715,11 +6953,11 @@ static enum vkd3d_result spirv_compiler_emit_alu_instruction(struct spirv_compil
* Microsoft fxc will compile immediate constants larger than 5 bits.
* Fixing up the constants would be more elegant, but the simplest way is
* to let this handle constants too. */
- if (instruction->handler_idx == VKD3DSIH_ISHL || instruction->handler_idx == VKD3DSIH_ISHR
- || instruction->handler_idx == VKD3DSIH_USHR)
+ if (!(instruction->flags & VKD3DSI_SHIFT_UNMASKED) && (instruction->handler_idx == VKD3DSIH_ISHL
+ || instruction->handler_idx == VKD3DSIH_ISHR || instruction->handler_idx == VKD3DSIH_USHR))
{
uint32_t mask_id = spirv_compiler_get_constant_vector(compiler,
- VKD3D_SHADER_COMPONENT_UINT, vkd3d_write_mask_component_count(dst->write_mask), 0x1f);
+ VKD3D_SHADER_COMPONENT_UINT, vsir_write_mask_component_count(dst->write_mask), 0x1f);
src_ids[1] = vkd3d_spirv_build_op_and(builder, type_id, src_ids[1], mask_id);
}
@@ -6732,6 +6970,23 @@ static enum vkd3d_result spirv_compiler_emit_alu_instruction(struct spirv_compil
return VKD3D_OK;
}
+static void spirv_compiler_emit_isfinite(struct spirv_compiler *compiler,
+ const struct vkd3d_shader_instruction *instruction)
+{
+ struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+ const struct vkd3d_shader_dst_param *dst = instruction->dst;
+ const struct vkd3d_shader_src_param *src = instruction->src;
+ uint32_t type_id, src_id, isinf_id, isnan_id, val_id;
+
+ type_id = spirv_compiler_get_type_id_for_dst(compiler, dst);
+ src_id = spirv_compiler_emit_load_src(compiler, src, dst->write_mask);
+ /* OpIsFinite is only available in Kernel mode. */
+ isinf_id = vkd3d_spirv_build_op_is_inf(builder, type_id, src_id);
+ isnan_id = vkd3d_spirv_build_op_is_nan(builder, type_id, src_id);
+ val_id = vkd3d_spirv_build_op_logical_equal(builder, type_id, isinf_id, isnan_id);
+ spirv_compiler_emit_store_dst(compiler, dst, val_id);
+}
+
static enum GLSLstd450 spirv_compiler_map_ext_glsl_instruction(
const struct vkd3d_shader_instruction *instruction)
{
@@ -6742,6 +6997,9 @@ static enum GLSLstd450 spirv_compiler_map_ext_glsl_instruction(
}
glsl_insts[] =
{
+ {VKD3DSIH_ACOS, GLSLstd450Acos},
+ {VKD3DSIH_ASIN, GLSLstd450Asin},
+ {VKD3DSIH_ATAN, GLSLstd450Atan},
{VKD3DSIH_DFMA, GLSLstd450Fma},
{VKD3DSIH_DMAX, GLSLstd450NMax},
{VKD3DSIH_DMIN, GLSLstd450NMin},
@@ -6750,6 +7008,9 @@ static enum GLSLstd450 spirv_compiler_map_ext_glsl_instruction(
{VKD3DSIH_FIRSTBIT_LO, GLSLstd450FindILsb},
{VKD3DSIH_FIRSTBIT_SHI, GLSLstd450FindSMsb},
{VKD3DSIH_FRC, GLSLstd450Fract},
+ {VKD3DSIH_HCOS, GLSLstd450Cosh},
+ {VKD3DSIH_HSIN, GLSLstd450Sinh},
+ {VKD3DSIH_HTAN, GLSLstd450Tanh},
{VKD3DSIH_IMAX, GLSLstd450SMax},
{VKD3DSIH_IMIN, GLSLstd450SMin},
{VKD3DSIH_LOG, GLSLstd450Log2},
@@ -6762,6 +7023,7 @@ static enum GLSLstd450 spirv_compiler_map_ext_glsl_instruction(
{VKD3DSIH_ROUND_Z, GLSLstd450Trunc},
{VKD3DSIH_RSQ, GLSLstd450InverseSqrt},
{VKD3DSIH_SQRT, GLSLstd450Sqrt},
+ {VKD3DSIH_TAN, GLSLstd450Tan},
{VKD3DSIH_UMAX, GLSLstd450UMax},
{VKD3DSIH_UMIN, GLSLstd450UMin},
};
@@ -6779,13 +7041,13 @@ static enum GLSLstd450 spirv_compiler_map_ext_glsl_instruction(
static void spirv_compiler_emit_ext_glsl_instruction(struct spirv_compiler *compiler,
const struct vkd3d_shader_instruction *instruction)
{
+ uint32_t instr_set_id, type_id, val_id, rev_val_id, uint_max_id, condition_id;
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
const struct vkd3d_shader_dst_param *dst = instruction->dst;
const struct vkd3d_shader_src_param *src = instruction->src;
uint32_t src_id[SPIRV_MAX_SRC_COUNT];
- uint32_t instr_set_id, type_id, val_id;
+ unsigned int i, component_count;
enum GLSLstd450 glsl_inst;
- unsigned int i;
glsl_inst = spirv_compiler_map_ext_glsl_instruction(instruction);
if (glsl_inst == GLSLstd450Bad)
@@ -6811,8 +7073,13 @@ static void spirv_compiler_emit_ext_glsl_instruction(struct spirv_compiler *comp
|| instruction->handler_idx == VKD3DSIH_FIRSTBIT_SHI)
{
/* In D3D bits are numbered from the most significant bit. */
- val_id = vkd3d_spirv_build_op_isub(builder, type_id,
- spirv_compiler_get_constant_uint(compiler, 31), val_id);
+ component_count = vsir_write_mask_component_count(dst->write_mask);
+ uint_max_id = spirv_compiler_get_constant_uint_vector(compiler, UINT32_MAX, component_count);
+ condition_id = vkd3d_spirv_build_op_tr2(builder, &builder->function_stream, SpvOpIEqual,
+ vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_BOOL, component_count), val_id, uint_max_id);
+ rev_val_id = vkd3d_spirv_build_op_isub(builder, type_id,
+ spirv_compiler_get_constant_uint_vector(compiler, 31, component_count), val_id);
+ val_id = vkd3d_spirv_build_op_select(builder, type_id, condition_id, val_id, rev_val_id);
}
spirv_compiler_emit_store_dst(compiler, dst, val_id);
@@ -6821,11 +7088,11 @@ static void spirv_compiler_emit_ext_glsl_instruction(struct spirv_compiler *comp
static void spirv_compiler_emit_mov(struct spirv_compiler *compiler,
const struct vkd3d_shader_instruction *instruction)
{
+ uint32_t val_id, dst_val_id, type_id, dst_id, src_id, write_mask32, swizzle32;
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
struct vkd3d_shader_register_info dst_reg_info, src_reg_info;
const struct vkd3d_shader_dst_param *dst = instruction->dst;
const struct vkd3d_shader_src_param *src = instruction->src;
- uint32_t val_id, dst_val_id, type_id, dst_id, src_id;
uint32_t components[VKD3D_VEC4_SIZE];
unsigned int i, component_count;
@@ -6849,7 +7116,9 @@ static void spirv_compiler_emit_mov(struct spirv_compiler *compiler,
return;
}
- component_count = vkd3d_write_mask_component_count(dst->write_mask);
+ write_mask32 = data_type_is_64_bit(dst->reg.data_type) ? vsir_write_mask_32_from_64(dst->write_mask) : dst->write_mask;
+ swizzle32 = data_type_is_64_bit(src->reg.data_type) ? vsir_swizzle_32_from_64(src->swizzle) : src->swizzle;
+ component_count = vsir_write_mask_component_count(write_mask32);
if (component_count != 1 && component_count != VKD3D_VEC4_SIZE
&& dst_reg_info.write_mask == VKD3DSP_WRITEMASK_ALL)
{
@@ -6862,8 +7131,8 @@ static void spirv_compiler_emit_mov(struct spirv_compiler *compiler,
for (i = 0; i < ARRAY_SIZE(components); ++i)
{
- if (dst->write_mask & (VKD3DSP_WRITEMASK_0 << i))
- components[i] = VKD3D_VEC4_SIZE + vkd3d_swizzle_get_component(src->swizzle, i);
+ if (write_mask32 & (VKD3DSP_WRITEMASK_0 << i))
+ components[i] = VKD3D_VEC4_SIZE + vsir_swizzle_get_component(swizzle32, i);
else
components[i] = i;
}
@@ -6877,6 +7146,11 @@ static void spirv_compiler_emit_mov(struct spirv_compiler *compiler,
general_implementation:
val_id = spirv_compiler_emit_load_src(compiler, src, dst->write_mask);
+ if (dst->reg.data_type != src->reg.data_type)
+ {
+ val_id = vkd3d_spirv_build_op_bitcast(builder, vkd3d_spirv_get_type_id_for_data_type(builder,
+ dst->reg.data_type, vsir_write_mask_component_count(dst->write_mask)), val_id);
+ }
spirv_compiler_emit_store_dst(compiler, dst, val_id);
}
@@ -6893,12 +7167,12 @@ static void spirv_compiler_emit_movc(struct spirv_compiler *compiler,
src1_id = spirv_compiler_emit_load_src(compiler, &src[1], dst->write_mask);
src2_id = spirv_compiler_emit_load_src(compiler, &src[2], dst->write_mask);
- component_count = vkd3d_write_mask_component_count(dst->write_mask);
+ component_count = vsir_write_mask_component_count(dst->write_mask);
type_id = spirv_compiler_get_type_id_for_dst(compiler, dst);
if (src[0].reg.data_type != VKD3D_DATA_BOOL)
condition_id = spirv_compiler_emit_int_to_bool(compiler,
- VKD3D_SHADER_CONDITIONAL_OP_NZ, component_count, condition_id);
+ VKD3D_SHADER_CONDITIONAL_OP_NZ, src[0].reg.data_type, component_count, condition_id);
val_id = vkd3d_spirv_build_op_select(builder, type_id, condition_id, src1_id, src2_id);
spirv_compiler_emit_store_dst(compiler, dst, val_id);
@@ -6919,11 +7193,11 @@ static void spirv_compiler_emit_swapc(struct spirv_compiler *compiler,
src1_id = spirv_compiler_emit_load_src(compiler, &src[1], dst->write_mask);
src2_id = spirv_compiler_emit_load_src(compiler, &src[2], dst->write_mask);
- component_count = vkd3d_write_mask_component_count(dst->write_mask);
+ component_count = vsir_write_mask_component_count(dst->write_mask);
type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, component_count);
condition_id = spirv_compiler_emit_int_to_bool(compiler,
- VKD3D_SHADER_CONDITIONAL_OP_NZ, component_count, condition_id);
+ VKD3D_SHADER_CONDITIONAL_OP_NZ, src[0].reg.data_type, component_count, condition_id);
val_id = vkd3d_spirv_build_op_select(builder, type_id, condition_id, src2_id, src1_id);
spirv_compiler_emit_store_dst(compiler, &dst[0], val_id);
@@ -6940,9 +7214,9 @@ static void spirv_compiler_emit_dot(struct spirv_compiler *compiler,
enum vkd3d_shader_component_type component_type;
uint32_t type_id, val_id, src_ids[2];
unsigned int component_count, i;
- DWORD write_mask;
+ uint32_t write_mask;
- component_count = vkd3d_write_mask_component_count(dst->write_mask);
+ component_count = vsir_write_mask_component_count(dst->write_mask);
component_type = vkd3d_component_type_from_data_type(dst->reg.data_type);
if (instruction->handler_idx == VKD3DSIH_DP4)
@@ -6980,7 +7254,7 @@ static void spirv_compiler_emit_rcp(struct spirv_compiler *compiler,
uint32_t type_id, src_id, val_id, div_id;
unsigned int component_count;
- component_count = vkd3d_write_mask_component_count(dst->write_mask);
+ component_count = vsir_write_mask_component_count(dst->write_mask);
type_id = spirv_compiler_get_type_id_for_dst(compiler, dst);
src_id = spirv_compiler_emit_load_src(compiler, src, dst->write_mask);
@@ -7060,7 +7334,7 @@ static void spirv_compiler_emit_imad(struct spirv_compiler *compiler,
uint32_t type_id, val_id, src_ids[3];
unsigned int i, component_count;
- component_count = vkd3d_write_mask_component_count(dst->write_mask);
+ component_count = vsir_write_mask_component_count(dst->write_mask);
type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_INT, component_count);
for (i = 0; i < ARRAY_SIZE(src_ids); ++i)
@@ -7087,16 +7361,18 @@ static void spirv_compiler_emit_int_div(struct spirv_compiler *compiler,
if (dst[0].reg.type != VKD3DSPR_NULL)
{
- component_count = vkd3d_write_mask_component_count(dst[0].write_mask);
+ component_count = vsir_write_mask_component_count(dst[0].write_mask);
type_id = spirv_compiler_get_type_id_for_dst(compiler, &dst[0]);
src0_id = spirv_compiler_emit_load_src(compiler, &src[0], dst[0].write_mask);
src1_id = spirv_compiler_emit_load_src(compiler, &src[1], dst[0].write_mask);
condition_id = spirv_compiler_emit_int_to_bool(compiler,
- VKD3D_SHADER_CONDITIONAL_OP_NZ, component_count, src1_id);
- uint_max_id = spirv_compiler_get_constant_uint_vector(compiler,
- 0xffffffff, component_count);
+ VKD3D_SHADER_CONDITIONAL_OP_NZ, src[1].reg.data_type, component_count, src1_id);
+ if (dst[0].reg.data_type == VKD3D_DATA_UINT64)
+ uint_max_id = spirv_compiler_get_constant_uint64_vector(compiler, UINT64_MAX, component_count);
+ else
+ uint_max_id = spirv_compiler_get_constant_uint_vector(compiler, 0xffffffff, component_count);
val_id = vkd3d_spirv_build_op_tr2(builder, &builder->function_stream, div_op, type_id, src0_id, src1_id);
/* The SPIR-V spec says: "The resulting value is undefined if Operand 2 is 0." */
@@ -7109,16 +7385,18 @@ static void spirv_compiler_emit_int_div(struct spirv_compiler *compiler,
{
if (!component_count || dst[0].write_mask != dst[1].write_mask)
{
- component_count = vkd3d_write_mask_component_count(dst[1].write_mask);
+ component_count = vsir_write_mask_component_count(dst[1].write_mask);
type_id = spirv_compiler_get_type_id_for_dst(compiler, &dst[1]);
src0_id = spirv_compiler_emit_load_src(compiler, &src[0], dst[1].write_mask);
src1_id = spirv_compiler_emit_load_src(compiler, &src[1], dst[1].write_mask);
condition_id = spirv_compiler_emit_int_to_bool(compiler,
- VKD3D_SHADER_CONDITIONAL_OP_NZ, component_count, src1_id);
- uint_max_id = spirv_compiler_get_constant_uint_vector(compiler,
- 0xffffffff, component_count);
+ VKD3D_SHADER_CONDITIONAL_OP_NZ, src[1].reg.data_type, component_count, src1_id);
+ if (dst[1].reg.data_type == VKD3D_DATA_UINT64)
+ uint_max_id = spirv_compiler_get_constant_uint64_vector(compiler, UINT64_MAX, component_count);
+ else
+ uint_max_id = spirv_compiler_get_constant_uint_vector(compiler, 0xffffffff, component_count);
}
val_id = vkd3d_spirv_build_op_tr2(builder, &builder->function_stream, mod_op, type_id, src0_id, src1_id);
@@ -7147,7 +7425,7 @@ static void spirv_compiler_emit_ftoi(struct spirv_compiler *compiler,
* as a signed integer, but Direct3D expects the result to saturate,
* and for NaN to yield zero. */
- component_count = vkd3d_write_mask_component_count(dst->write_mask);
+ component_count = vsir_write_mask_component_count(dst->write_mask);
src_type_id = spirv_compiler_get_type_id_for_reg(compiler, &src->reg, dst->write_mask);
dst_type_id = spirv_compiler_get_type_id_for_dst(compiler, dst);
src_id = spirv_compiler_emit_load_src(compiler, src, dst->write_mask);
@@ -7200,7 +7478,7 @@ static void spirv_compiler_emit_ftou(struct spirv_compiler *compiler,
* as an unsigned integer, but Direct3D expects the result to saturate,
* and for NaN to yield zero. */
- component_count = vkd3d_write_mask_component_count(dst->write_mask);
+ component_count = vsir_write_mask_component_count(dst->write_mask);
src_type_id = spirv_compiler_get_type_id_for_reg(compiler, &src->reg, dst->write_mask);
dst_type_id = spirv_compiler_get_type_id_for_dst(compiler, dst);
src_id = spirv_compiler_emit_load_src(compiler, src, dst->write_mask);
@@ -7232,13 +7510,13 @@ static void spirv_compiler_emit_ftou(struct spirv_compiler *compiler,
static void spirv_compiler_emit_bitfield_instruction(struct spirv_compiler *compiler,
const struct vkd3d_shader_instruction *instruction)
{
- uint32_t src_ids[4], constituents[VKD3D_VEC4_SIZE], type_id, mask_id;
+ uint32_t src_ids[4], constituents[VKD3D_VEC4_SIZE], type_id, mask_id, size_id, max_count_id;
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
const struct vkd3d_shader_dst_param *dst = instruction->dst;
const struct vkd3d_shader_src_param *src = instruction->src;
enum vkd3d_shader_component_type component_type;
- unsigned int i, j, k, src_count;
- DWORD write_mask;
+ unsigned int i, j, k, src_count, size;
+ uint32_t write_mask;
SpvOp op;
src_count = instruction->src_count;
@@ -7246,7 +7524,9 @@ static void spirv_compiler_emit_bitfield_instruction(struct spirv_compiler *comp
component_type = vkd3d_component_type_from_data_type(dst->reg.data_type);
type_id = vkd3d_spirv_get_type_id(builder, component_type, 1);
- mask_id = spirv_compiler_get_constant_uint(compiler, 0x1f);
+ size = (src[src_count - 1].reg.data_type == VKD3D_DATA_UINT64) ? 0x40 : 0x20;
+ mask_id = spirv_compiler_get_constant_uint(compiler, size - 1);
+ size_id = spirv_compiler_get_constant_uint(compiler, size);
switch (instruction->handler_idx)
{
@@ -7275,6 +7555,9 @@ static void spirv_compiler_emit_bitfield_instruction(struct spirv_compiler *comp
{
src_ids[j] = vkd3d_spirv_build_op_and(builder, type_id, src_ids[j], mask_id);
}
+ max_count_id = vkd3d_spirv_build_op_isub(builder, type_id, size_id, src_ids[src_count - 2]);
+ src_ids[src_count - 1] = vkd3d_spirv_build_op_glsl_std450_umin(builder, type_id,
+ src_ids[src_count - 1], max_count_id);
constituents[k++] = vkd3d_spirv_build_op_trv(builder, &builder->function_stream,
op, type_id, src_ids, src_count);
@@ -7291,8 +7574,8 @@ static void spirv_compiler_emit_f16tof32(struct spirv_compiler *compiler,
const struct vkd3d_shader_dst_param *dst = instruction->dst;
const struct vkd3d_shader_src_param *src = instruction->src;
uint32_t components[VKD3D_VEC4_SIZE];
+ uint32_t write_mask;
unsigned int i, j;
- DWORD write_mask;
instr_set_id = vkd3d_spirv_get_glsl_std450_instr_set(builder);
type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, 2);
@@ -7324,8 +7607,8 @@ static void spirv_compiler_emit_f32tof16(struct spirv_compiler *compiler,
const struct vkd3d_shader_dst_param *dst = instruction->dst;
const struct vkd3d_shader_src_param *src = instruction->src;
uint32_t components[VKD3D_VEC4_SIZE];
+ uint32_t write_mask;
unsigned int i, j;
- DWORD write_mask;
instr_set_id = vkd3d_spirv_get_glsl_std450_instr_set(builder);
type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, 2);
@@ -7387,7 +7670,7 @@ static void spirv_compiler_emit_comparison_instruction(struct spirv_compiler *co
return;
}
- component_count = vkd3d_write_mask_component_count(dst->write_mask);
+ component_count = vsir_write_mask_component_count(dst->write_mask);
src0_id = spirv_compiler_emit_load_src(compiler, &src[0], dst->write_mask);
src1_id = spirv_compiler_emit_load_src(compiler, &src[1], dst->write_mask);
@@ -7409,7 +7692,7 @@ static uint32_t spirv_compiler_emit_conditional_branch(struct spirv_compiler *co
uint32_t condition_id, merge_block_id;
condition_id = spirv_compiler_emit_load_src(compiler, src, VKD3DSP_WRITEMASK_0);
- condition_id = spirv_compiler_emit_int_to_bool(compiler, instruction->flags, 1, condition_id);
+ condition_id = spirv_compiler_emit_int_to_bool(compiler, instruction->flags, src->reg.data_type, 1, condition_id);
merge_block_id = vkd3d_spirv_alloc_id(builder);
@@ -7445,16 +7728,39 @@ static void spirv_compiler_emit_retc(struct spirv_compiler *compiler,
vkd3d_spirv_build_op_label(builder, merge_block_id);
}
-static void spirv_compiler_emit_kill(struct spirv_compiler *compiler,
- const struct vkd3d_shader_instruction *instruction)
+static uint32_t spirv_compiler_get_discard_function_id(struct spirv_compiler *compiler)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
- uint32_t target_id, merge_block_id;
- target_id = vkd3d_spirv_alloc_id(builder);
- merge_block_id = spirv_compiler_emit_conditional_branch(compiler, instruction, target_id);
+ if (!compiler->discard_function_id)
+ compiler->discard_function_id = vkd3d_spirv_alloc_id(builder);
- vkd3d_spirv_build_op_label(builder, target_id);
+ return compiler->discard_function_id;
+}
+
+static void spirv_compiler_emit_discard_function(struct spirv_compiler *compiler)
+{
+ uint32_t void_id, bool_id, function_type_id, condition_id, target_block_id, merge_block_id;
+ struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+
+ vkd3d_spirv_build_op_name(builder, compiler->discard_function_id, "discard");
+
+ void_id = vkd3d_spirv_get_op_type_void(builder);
+ bool_id = vkd3d_spirv_get_op_type_bool(builder);
+ function_type_id = vkd3d_spirv_get_op_type_function(builder, void_id, &bool_id, 1);
+
+ vkd3d_spirv_build_op_function(builder, void_id, compiler->discard_function_id,
+ SpvFunctionControlMaskNone, function_type_id);
+ condition_id = vkd3d_spirv_build_op_function_parameter(builder, bool_id);
+
+ vkd3d_spirv_build_op_label(builder, vkd3d_spirv_alloc_id(builder));
+
+ target_block_id = vkd3d_spirv_alloc_id(builder);
+ merge_block_id = vkd3d_spirv_alloc_id(builder);
+ vkd3d_spirv_build_op_selection_merge(builder, merge_block_id, SpvSelectionControlMaskNone);
+ vkd3d_spirv_build_op_branch_conditional(builder, condition_id, target_block_id, merge_block_id);
+
+ vkd3d_spirv_build_op_label(builder, target_block_id);
if (spirv_compiler_is_target_extension_supported(compiler,
VKD3D_SHADER_SPIRV_EXTENSION_EXT_DEMOTE_TO_HELPER_INVOCATION))
@@ -7469,381 +7775,158 @@ static void spirv_compiler_emit_kill(struct spirv_compiler *compiler,
}
vkd3d_spirv_build_op_label(builder, merge_block_id);
+ vkd3d_spirv_build_op_return(builder);
+ vkd3d_spirv_build_op_function_end(builder);
}
-static struct vkd3d_control_flow_info *spirv_compiler_push_control_flow_level(
- struct spirv_compiler *compiler)
+static void spirv_compiler_emit_discard(struct spirv_compiler *compiler,
+ const struct vkd3d_shader_instruction *instruction)
{
- if (!vkd3d_array_reserve((void **)&compiler->control_flow_info, &compiler->control_flow_info_size,
- compiler->control_flow_depth + 1, sizeof(*compiler->control_flow_info)))
- {
- ERR("Failed to allocate control flow info structure.\n");
- return NULL;
- }
+ struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+ const struct vkd3d_shader_src_param *src = instruction->src;
+ uint32_t condition_id, void_id;
- return &compiler->control_flow_info[compiler->control_flow_depth++];
+ /* discard is not a block terminator in VSIR, and emitting it as such in SPIR-V would cause
+ * a mismatch between the VSIR structure and the SPIR-V one, which would cause problems if
+ * structurisation is necessary. Therefore we emit it as a function call. */
+ condition_id = spirv_compiler_emit_load_src(compiler, src, VKD3DSP_WRITEMASK_0);
+ condition_id = spirv_compiler_emit_int_to_bool(compiler,
+ instruction->flags, src->reg.data_type, 1, condition_id);
+ void_id = vkd3d_spirv_get_op_type_void(builder);
+ vkd3d_spirv_build_op_function_call(builder, void_id, spirv_compiler_get_discard_function_id(compiler),
+ &condition_id, 1);
}
-static void spirv_compiler_pop_control_flow_level(struct spirv_compiler *compiler)
+static bool spirv_compiler_init_blocks(struct spirv_compiler *compiler, unsigned int block_count)
{
- struct vkd3d_control_flow_info *cf_info;
+ compiler->block_count = block_count;
- assert(compiler->control_flow_depth);
+ if (!(compiler->block_label_ids = vkd3d_calloc(block_count, sizeof(*compiler->block_label_ids))))
+ return false;
- cf_info = &compiler->control_flow_info[--compiler->control_flow_depth];
- memset(cf_info, 0, sizeof(*cf_info));
+ return true;
}
-static struct vkd3d_control_flow_info *spirv_compiler_find_innermost_loop(
- struct spirv_compiler *compiler)
+static void spirv_compiler_emit_label(struct spirv_compiler *compiler,
+ const struct vkd3d_shader_instruction *instruction)
{
- int depth;
+ struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+ const struct vkd3d_shader_src_param *src = instruction->src;
+ unsigned int block_id = src->reg.idx[0].offset;
+ uint32_t label_id;
- for (depth = compiler->control_flow_depth - 1; depth >= 0; --depth)
- {
- if (compiler->control_flow_info[depth].current_block == VKD3D_BLOCK_LOOP)
- return &compiler->control_flow_info[depth];
- }
+ label_id = spirv_compiler_get_label_id(compiler, block_id);
+ vkd3d_spirv_build_op_label(builder, label_id);
- return NULL;
+ --block_id;
+ if (block_id < compiler->block_name_count && compiler->block_names[block_id])
+ vkd3d_spirv_build_op_name(builder, label_id, compiler->block_names[block_id]);
+
+ spirv_compiler_initialise_block(compiler);
}
-static struct vkd3d_control_flow_info *spirv_compiler_find_innermost_breakable_cf_construct(
- struct spirv_compiler *compiler)
+static void spirv_compiler_emit_merge(struct spirv_compiler *compiler,
+ uint32_t merge_block_id, uint32_t continue_block_id)
{
- int depth;
+ struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+
+ if (!merge_block_id)
+ return;
- for (depth = compiler->control_flow_depth - 1; depth >= 0; --depth)
+ merge_block_id = spirv_compiler_get_label_id(compiler, merge_block_id);
+ if (!continue_block_id)
{
- if (compiler->control_flow_info[depth].current_block == VKD3D_BLOCK_LOOP
- || compiler->control_flow_info[depth].current_block == VKD3D_BLOCK_SWITCH)
- return &compiler->control_flow_info[depth];
+ vkd3d_spirv_build_op_selection_merge(builder, merge_block_id, SpvSelectionControlMaskNone);
+ }
+ else
+ {
+ continue_block_id = spirv_compiler_get_label_id(compiler, continue_block_id);
+ vkd3d_spirv_build_op_loop_merge(builder, merge_block_id, continue_block_id, SpvLoopControlMaskNone);
}
-
- return NULL;
}
-static int spirv_compiler_emit_control_flow_instruction(struct spirv_compiler *compiler,
+static void spirv_compiler_emit_branch(struct spirv_compiler *compiler,
const struct vkd3d_shader_instruction *instruction)
{
- uint32_t loop_header_block_id, loop_body_block_id, continue_block_id;
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
const struct vkd3d_shader_src_param *src = instruction->src;
- uint32_t merge_block_id, val_id, condition_id, true_label;
- struct vkd3d_control_flow_info *cf_info;
-
- cf_info = compiler->control_flow_depth
- ? &compiler->control_flow_info[compiler->control_flow_depth - 1] : NULL;
+ uint32_t condition_id;
- switch (instruction->handler_idx)
+ if (vsir_register_is_label(&src[0].reg))
{
- case VKD3DSIH_IF:
- if (!(cf_info = spirv_compiler_push_control_flow_level(compiler)))
- return VKD3D_ERROR_OUT_OF_MEMORY;
-
- val_id = spirv_compiler_emit_load_src(compiler, src, VKD3DSP_WRITEMASK_0);
- condition_id = spirv_compiler_emit_int_to_bool(compiler, instruction->flags, 1, val_id);
-
- true_label = vkd3d_spirv_alloc_id(builder);
- merge_block_id = vkd3d_spirv_alloc_id(builder);
- vkd3d_spirv_build_op_selection_merge(builder, merge_block_id, SpvSelectionControlMaskNone);
- cf_info->u.if_.stream_location = vkd3d_spirv_stream_current_location(&builder->function_stream);
- vkd3d_spirv_build_op_branch_conditional(builder, condition_id, true_label, merge_block_id);
-
- vkd3d_spirv_build_op_label(builder, true_label);
-
- cf_info->u.if_.id = compiler->branch_id;
- cf_info->u.if_.merge_block_id = merge_block_id;
- cf_info->u.if_.else_block_id = 0;
- cf_info->inside_block = true;
- cf_info->current_block = VKD3D_BLOCK_IF;
-
- vkd3d_spirv_build_op_name(builder, merge_block_id, "branch%u_merge", compiler->branch_id);
- vkd3d_spirv_build_op_name(builder, true_label, "branch%u_true", compiler->branch_id);
- ++compiler->branch_id;
- break;
-
- case VKD3DSIH_ELSE:
- assert(compiler->control_flow_depth);
- assert(cf_info->current_block == VKD3D_BLOCK_IF);
-
- if (cf_info->inside_block)
- vkd3d_spirv_build_op_branch(builder, cf_info->u.if_.merge_block_id);
-
- cf_info->u.if_.else_block_id = vkd3d_spirv_alloc_id(builder);
- vkd3d_spirv_as_op_branch_conditional(&builder->function_stream,
- cf_info->u.if_.stream_location)->false_label = cf_info->u.if_.else_block_id;
- vkd3d_spirv_build_op_name(builder,
- cf_info->u.if_.else_block_id, "branch%u_false", cf_info->u.if_.id);
- vkd3d_spirv_build_op_label(builder, cf_info->u.if_.else_block_id);
- cf_info->inside_block = true;
- break;
-
- case VKD3DSIH_ENDIF:
- assert(compiler->control_flow_depth);
- assert(cf_info->current_block == VKD3D_BLOCK_IF);
-
- if (cf_info->inside_block)
- vkd3d_spirv_build_op_branch(builder, cf_info->u.if_.merge_block_id);
-
- vkd3d_spirv_build_op_label(builder, cf_info->u.if_.merge_block_id);
-
- spirv_compiler_pop_control_flow_level(compiler);
- break;
-
- case VKD3DSIH_LOOP:
- if (!(cf_info = spirv_compiler_push_control_flow_level(compiler)))
- return VKD3D_ERROR_OUT_OF_MEMORY;
-
- loop_header_block_id = vkd3d_spirv_alloc_id(builder);
- loop_body_block_id = vkd3d_spirv_alloc_id(builder);
- continue_block_id = vkd3d_spirv_alloc_id(builder);
- merge_block_id = vkd3d_spirv_alloc_id(builder);
-
- vkd3d_spirv_build_op_branch(builder, loop_header_block_id);
- vkd3d_spirv_build_op_label(builder, loop_header_block_id);
- vkd3d_spirv_build_op_loop_merge(builder, merge_block_id, continue_block_id, SpvLoopControlMaskNone);
- vkd3d_spirv_build_op_branch(builder, loop_body_block_id);
-
- vkd3d_spirv_build_op_label(builder, loop_body_block_id);
-
- cf_info->u.loop.header_block_id = loop_header_block_id;
- cf_info->u.loop.continue_block_id = continue_block_id;
- cf_info->u.loop.merge_block_id = merge_block_id;
- cf_info->current_block = VKD3D_BLOCK_LOOP;
- cf_info->inside_block = true;
-
- vkd3d_spirv_build_op_name(builder, loop_header_block_id, "loop%u_header", compiler->loop_id);
- vkd3d_spirv_build_op_name(builder, loop_body_block_id, "loop%u_body", compiler->loop_id);
- vkd3d_spirv_build_op_name(builder, continue_block_id, "loop%u_continue", compiler->loop_id);
- vkd3d_spirv_build_op_name(builder, merge_block_id, "loop%u_merge", compiler->loop_id);
- ++compiler->loop_id;
- break;
-
- case VKD3DSIH_ENDLOOP:
- assert(compiler->control_flow_depth);
- assert(cf_info->current_block == VKD3D_BLOCK_LOOP);
-
- /* The loop block may have already been ended by an unconditional
- * break instruction right before the end of the loop. */
- if (cf_info->inside_block)
- vkd3d_spirv_build_op_branch(builder, cf_info->u.loop.continue_block_id);
-
- vkd3d_spirv_build_op_label(builder, cf_info->u.loop.continue_block_id);
- vkd3d_spirv_build_op_branch(builder, cf_info->u.loop.header_block_id);
- vkd3d_spirv_build_op_label(builder, cf_info->u.loop.merge_block_id);
-
- spirv_compiler_pop_control_flow_level(compiler);
- break;
-
- case VKD3DSIH_SWITCH:
- if (!(cf_info = spirv_compiler_push_control_flow_level(compiler)))
- return VKD3D_ERROR_OUT_OF_MEMORY;
-
- merge_block_id = vkd3d_spirv_alloc_id(builder);
-
- assert(src->reg.data_type == VKD3D_DATA_INT);
- val_id = spirv_compiler_emit_load_src(compiler, src, VKD3DSP_WRITEMASK_0);
-
- vkd3d_spirv_build_op_selection_merge(builder, merge_block_id, SpvSelectionControlMaskNone);
-
- cf_info->u.switch_.id = compiler->switch_id;
- cf_info->u.switch_.merge_block_id = merge_block_id;
- cf_info->u.switch_.stream_location = vkd3d_spirv_stream_current_location(&builder->function_stream);
- cf_info->u.switch_.selector_id = val_id;
- cf_info->u.switch_.case_blocks = NULL;
- cf_info->u.switch_.case_blocks_size = 0;
- cf_info->u.switch_.case_block_count = 0;
- cf_info->u.switch_.default_block_id = 0;
- cf_info->inside_block = false;
- cf_info->current_block = VKD3D_BLOCK_SWITCH;
-
- vkd3d_spirv_build_op_name(builder, merge_block_id, "switch%u_merge", compiler->switch_id);
-
- ++compiler->switch_id;
-
- if (!vkd3d_array_reserve((void **)&cf_info->u.switch_.case_blocks, &cf_info->u.switch_.case_blocks_size,
- 10, sizeof(*cf_info->u.switch_.case_blocks)))
- return VKD3D_ERROR_OUT_OF_MEMORY;
-
- break;
-
- case VKD3DSIH_ENDSWITCH:
- assert(compiler->control_flow_depth);
- assert(cf_info->current_block == VKD3D_BLOCK_SWITCH);
- assert(!cf_info->inside_block);
-
- if (!cf_info->u.switch_.default_block_id)
- cf_info->u.switch_.default_block_id = cf_info->u.switch_.merge_block_id;
-
- vkd3d_spirv_build_op_label(builder, cf_info->u.switch_.merge_block_id);
-
- /* The OpSwitch instruction is inserted when the endswitch
- * instruction is processed because we do not know the number
- * of case statements in advance.*/
- vkd3d_spirv_begin_function_stream_insertion(builder, cf_info->u.switch_.stream_location);
- vkd3d_spirv_build_op_switch(builder, cf_info->u.switch_.selector_id,
- cf_info->u.switch_.default_block_id, cf_info->u.switch_.case_blocks,
- cf_info->u.switch_.case_block_count);
- vkd3d_spirv_end_function_stream_insertion(builder);
-
- vkd3d_free(cf_info->u.switch_.case_blocks);
- spirv_compiler_pop_control_flow_level(compiler);
- break;
-
- case VKD3DSIH_CASE:
+ if (instruction->src_count > 1)
{
- uint32_t label_id, value;
-
- assert(compiler->control_flow_depth);
- assert(cf_info->current_block == VKD3D_BLOCK_SWITCH);
-
- if (src->swizzle != VKD3D_SHADER_SWIZZLE(X, X, X, X))
- {
- WARN("Unexpected src swizzle %#x.\n", src->swizzle);
- spirv_compiler_warning(compiler, VKD3D_SHADER_WARNING_SPV_INVALID_SWIZZLE,
- "The swizzle for a switch case value is not scalar.");
- }
- assert(src->reg.type == VKD3DSPR_IMMCONST);
- value = *src->reg.u.immconst_uint;
-
- if (!vkd3d_array_reserve((void **)&cf_info->u.switch_.case_blocks, &cf_info->u.switch_.case_blocks_size,
- 2 * (cf_info->u.switch_.case_block_count + 1), sizeof(*cf_info->u.switch_.case_blocks)))
- return VKD3D_ERROR_OUT_OF_MEMORY;
-
- label_id = vkd3d_spirv_alloc_id(builder);
- if (cf_info->inside_block) /* fall-through */
- vkd3d_spirv_build_op_branch(builder, label_id);
-
- cf_info->u.switch_.case_blocks[2 * cf_info->u.switch_.case_block_count + 0] = value;
- cf_info->u.switch_.case_blocks[2 * cf_info->u.switch_.case_block_count + 1] = label_id;
- ++cf_info->u.switch_.case_block_count;
-
- vkd3d_spirv_build_op_label(builder, label_id);
- cf_info->inside_block = true;
- vkd3d_spirv_build_op_name(builder, label_id, "switch%u_case%u", cf_info->u.switch_.id, value);
- break;
- }
-
- case VKD3DSIH_DEFAULT:
- assert(compiler->control_flow_depth);
- assert(cf_info->current_block == VKD3D_BLOCK_SWITCH);
- assert(!cf_info->u.switch_.default_block_id);
-
- cf_info->u.switch_.default_block_id = vkd3d_spirv_alloc_id(builder);
- if (cf_info->inside_block) /* fall-through */
- vkd3d_spirv_build_op_branch(builder, cf_info->u.switch_.default_block_id);
-
- vkd3d_spirv_build_op_label(builder, cf_info->u.switch_.default_block_id);
- vkd3d_spirv_build_op_name(builder, cf_info->u.switch_.default_block_id,
- "switch%u_default", cf_info->u.switch_.id);
- cf_info->inside_block = true;
- break;
-
- case VKD3DSIH_BREAK:
- {
- struct vkd3d_control_flow_info *breakable_cf_info;
-
- assert(compiler->control_flow_depth);
-
- if (!(breakable_cf_info = spirv_compiler_find_innermost_breakable_cf_construct(compiler)))
- {
- FIXME("Unhandled break instruction.\n");
- return VKD3D_ERROR_INVALID_SHADER;
- }
-
- if (breakable_cf_info->current_block == VKD3D_BLOCK_LOOP)
- {
- vkd3d_spirv_build_op_branch(builder, breakable_cf_info->u.loop.merge_block_id);
- }
- else if (breakable_cf_info->current_block == VKD3D_BLOCK_SWITCH)
- {
- /* The current case block may have already been ended by an
- * unconditional continue instruction. */
- if (breakable_cf_info->inside_block)
- vkd3d_spirv_build_op_branch(builder, breakable_cf_info->u.switch_.merge_block_id);
- }
-
- cf_info->inside_block = false;
- break;
- }
-
- case VKD3DSIH_BREAKP:
- {
- struct vkd3d_control_flow_info *loop_cf_info;
-
- assert(compiler->control_flow_depth);
-
- if (!(loop_cf_info = spirv_compiler_find_innermost_loop(compiler)))
- {
- ERR("Invalid 'breakc' instruction outside loop.\n");
- return VKD3D_ERROR_INVALID_SHADER;
- }
-
- merge_block_id = spirv_compiler_emit_conditional_branch(compiler,
- instruction, loop_cf_info->u.loop.merge_block_id);
- vkd3d_spirv_build_op_label(builder, merge_block_id);
- break;
- }
-
- case VKD3DSIH_CONTINUE:
- {
- struct vkd3d_control_flow_info *loop_cf_info;
-
- assert(compiler->control_flow_depth);
-
- if (!(loop_cf_info = spirv_compiler_find_innermost_loop(compiler)))
- {
- ERR("Invalid 'continue' instruction outside loop.\n");
- return VKD3D_ERROR_INVALID_SHADER;
- }
-
- vkd3d_spirv_build_op_branch(builder, loop_cf_info->u.loop.continue_block_id);
-
- cf_info->inside_block = false;
- break;
+ /* Loop merge only. Must have a merge block and a continue block. */
+ if (instruction->src_count == 3)
+ spirv_compiler_emit_merge(compiler, src[1].reg.idx[0].offset, src[2].reg.idx[0].offset);
+ else
+ ERR("Invalid branch with %u sources.\n", instruction->src_count);
}
+ vkd3d_spirv_build_op_branch(builder, spirv_compiler_get_label_id(compiler, src[0].reg.idx[0].offset));
+ return;
+ }
- case VKD3DSIH_CONTINUEP:
- {
- struct vkd3d_control_flow_info *loop_cf_info;
-
- if (!(loop_cf_info = spirv_compiler_find_innermost_loop(compiler)))
- {
- ERR("Invalid 'continuec' instruction outside loop.\n");
- return VKD3D_ERROR_INVALID_SHADER;
- }
+ if (!vkd3d_swizzle_is_scalar(src->swizzle, &src->reg))
+ {
+ WARN("Unexpected src swizzle %#x.\n", src->swizzle);
+ spirv_compiler_warning(compiler, VKD3D_SHADER_WARNING_SPV_INVALID_SWIZZLE,
+ "The swizzle for a branch condition value is not scalar.");
+ }
- merge_block_id = spirv_compiler_emit_conditional_branch(compiler,
- instruction, loop_cf_info->u.loop.continue_block_id);
- vkd3d_spirv_build_op_label(builder, merge_block_id);
- break;
- }
+ condition_id = spirv_compiler_emit_load_src(compiler, &src[0], VKD3DSP_WRITEMASK_0);
+ if (src[0].reg.data_type != VKD3D_DATA_BOOL)
+ condition_id = spirv_compiler_emit_int_to_bool(compiler,
+ VKD3D_SHADER_CONDITIONAL_OP_NZ, src[0].reg.data_type, 1, condition_id);
+ /* Emit the merge immediately before the branch instruction. */
+ if (instruction->src_count >= 4)
+ spirv_compiler_emit_merge(compiler, src[3].reg.idx[0].offset,
+ (instruction->src_count > 4) ? src[4].reg.idx[0].offset : 0);
+ else
+ ERR("Invalid branch with %u sources.\n", instruction->src_count);
+ vkd3d_spirv_build_op_branch_conditional(builder, condition_id,
+ spirv_compiler_get_label_id(compiler, src[1].reg.idx[0].offset),
+ spirv_compiler_get_label_id(compiler, src[2].reg.idx[0].offset));
+}
- case VKD3DSIH_RET:
- spirv_compiler_emit_return(compiler, instruction);
+static void spirv_compiler_emit_switch(struct spirv_compiler *compiler,
+ const struct vkd3d_shader_instruction *instruction)
+{
+ struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+ const struct vkd3d_shader_src_param *src = instruction->src;
+ uint32_t val_id, default_id;
+ unsigned int i, word_count;
+ uint32_t *cases;
- if (cf_info)
- cf_info->inside_block = false;
- else
- compiler->main_block_open = false;
- break;
+ if (!vkd3d_swizzle_is_scalar(src[0].swizzle, &src[0].reg))
+ {
+ WARN("Unexpected src swizzle %#x.\n", src[0].swizzle);
+ spirv_compiler_warning(compiler, VKD3D_SHADER_WARNING_SPV_INVALID_SWIZZLE,
+ "The swizzle for a switch value is not scalar.");
+ }
- case VKD3DSIH_RETP:
- spirv_compiler_emit_retc(compiler, instruction);
- break;
+ word_count = instruction->src_count - 3;
+ if (!(cases = vkd3d_calloc(word_count, sizeof(*cases))))
+ {
+ spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_OUT_OF_MEMORY,
+ "Failed to allocate %u words for switch cases.", word_count);
+ return;
+ }
- case VKD3DSIH_DISCARD:
- case VKD3DSIH_TEXKILL:
- spirv_compiler_emit_kill(compiler, instruction);
- break;
+ val_id = spirv_compiler_emit_load_src(compiler, &src[0], VKD3DSP_WRITEMASK_0);
+ default_id = spirv_compiler_get_label_id(compiler, src[1].reg.idx[0].offset);
+ /* No instructions may occur between the merge and the switch. */
+ spirv_compiler_emit_merge(compiler, src[2].reg.idx[0].offset, 0);
- default:
- ERR("Unexpected instruction %#x.\n", instruction->handler_idx);
- break;
+ src = &src[3];
+ for (i = 0; i < word_count; i += 2)
+ {
+ cases[i] = src[i].reg.u.immconst_u32[0];
+ cases[i + 1] = spirv_compiler_get_label_id(compiler, src[i + 1].reg.idx[0].offset);
}
- return VKD3D_OK;
+ vkd3d_spirv_build_op_switch(builder, val_id, default_id, cases, word_count / 2u);
+
+ vkd3d_free(cases);
}
static void spirv_compiler_emit_deriv_instruction(struct spirv_compiler *compiler,
@@ -8090,7 +8173,7 @@ static void spirv_compiler_emit_ld(struct spirv_compiler *compiler,
unsigned int image_operand_count = 0;
struct vkd3d_shader_image image;
uint32_t image_operands[2];
- DWORD coordinate_mask;
+ uint32_t coordinate_mask;
bool multisample;
multisample = instruction->handler_idx == VKD3DSIH_LD2DMS;
@@ -8164,7 +8247,7 @@ static void spirv_compiler_emit_sample(struct spirv_compiler *compiler,
unsigned int image_operand_count = 0;
struct vkd3d_shader_image image;
uint32_t image_operands[3];
- DWORD coordinate_mask;
+ uint32_t coordinate_mask;
SpvOp op;
resource = &src[1];
@@ -8280,7 +8363,7 @@ static void spirv_compiler_emit_gather4(struct spirv_compiler *compiler,
struct vkd3d_shader_image image;
unsigned int component_idx;
uint32_t image_operands[1];
- DWORD coordinate_mask;
+ uint32_t coordinate_mask;
bool extended_offset;
if (instruction->handler_idx == VKD3DSIH_GATHER4_C
@@ -8325,7 +8408,7 @@ static void spirv_compiler_emit_gather4(struct spirv_compiler *compiler,
}
else
{
- component_idx = vkd3d_swizzle_get_component(sampler->swizzle, 0);
+ component_idx = vsir_swizzle_get_component(sampler->swizzle, 0);
/* Nvidia driver requires signed integer type. */
component_id = spirv_compiler_get_constant(compiler,
VKD3D_SHADER_COMPONENT_INT, 1, &component_idx);
@@ -8340,13 +8423,13 @@ static void spirv_compiler_emit_gather4(struct spirv_compiler *compiler,
static uint32_t spirv_compiler_emit_raw_structured_addressing(
struct spirv_compiler *compiler, uint32_t type_id, unsigned int stride,
- const struct vkd3d_shader_src_param *src0, DWORD src0_mask,
- const struct vkd3d_shader_src_param *src1, DWORD src1_mask)
+ const struct vkd3d_shader_src_param *src0, uint32_t src0_mask,
+ const struct vkd3d_shader_src_param *src1, uint32_t src1_mask)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
const struct vkd3d_shader_src_param *offset;
uint32_t structure_id = 0, offset_id;
- DWORD offset_write_mask;
+ uint32_t offset_write_mask;
if (stride)
{
@@ -8403,7 +8486,7 @@ static void spirv_compiler_emit_ld_raw_structured_srv_uav(struct spirv_compiler
if (!(dst->write_mask & (VKD3DSP_WRITEMASK_0 << i)))
continue;
- component_idx = vkd3d_swizzle_get_component(resource->swizzle, i);
+ component_idx = vsir_swizzle_get_component(resource->swizzle, i);
coordinate_id = base_coordinate_id;
if (component_idx)
coordinate_id = vkd3d_spirv_build_op_iadd(builder, type_id,
@@ -8435,7 +8518,7 @@ static void spirv_compiler_emit_ld_raw_structured_srv_uav(struct spirv_compiler
if (!(dst->write_mask & (VKD3DSP_WRITEMASK_0 << i)))
continue;
- component_idx = vkd3d_swizzle_get_component(resource->swizzle, i);
+ component_idx = vsir_swizzle_get_component(resource->swizzle, i);
coordinate_id = base_coordinate_id;
if (component_idx)
coordinate_id = vkd3d_spirv_build_op_iadd(builder, type_id,
@@ -8447,7 +8530,6 @@ static void spirv_compiler_emit_ld_raw_structured_srv_uav(struct spirv_compiler
type_id, val_id, 0);
}
}
- assert(dst->reg.data_type == VKD3D_DATA_UINT);
spirv_compiler_emit_store_dst_components(compiler, dst, VKD3D_SHADER_COMPONENT_UINT, constituents);
}
@@ -8479,7 +8561,7 @@ static void spirv_compiler_emit_ld_tgsm(struct spirv_compiler *compiler,
if (!(dst->write_mask & (VKD3DSP_WRITEMASK_0 << i)))
continue;
- component_idx = vkd3d_swizzle_get_component(resource->swizzle, i);
+ component_idx = vsir_swizzle_get_component(resource->swizzle, i);
coordinate_id = base_coordinate_id;
if (component_idx)
coordinate_id = vkd3d_spirv_build_op_iadd(builder, type_id,
@@ -8540,7 +8622,7 @@ static void spirv_compiler_emit_store_uav_raw_structured(struct spirv_compiler *
assert(data->reg.data_type == VKD3D_DATA_UINT);
val_id = spirv_compiler_emit_load_src(compiler, data, dst->write_mask);
- component_count = vkd3d_write_mask_component_count(dst->write_mask);
+ component_count = vsir_write_mask_component_count(dst->write_mask);
for (component_idx = 0; component_idx < component_count; ++component_idx)
{
data_id = component_count > 1 ?
@@ -8569,7 +8651,7 @@ static void spirv_compiler_emit_store_uav_raw_structured(struct spirv_compiler *
assert(data->reg.data_type == VKD3D_DATA_UINT);
val_id = spirv_compiler_emit_load_src(compiler, data, dst->write_mask);
- component_count = vkd3d_write_mask_component_count(dst->write_mask);
+ component_count = vsir_write_mask_component_count(dst->write_mask);
for (component_idx = 0; component_idx < component_count; ++component_idx)
{
/* Mesa Vulkan drivers require the texel parameter to be a vector. */
@@ -8613,7 +8695,7 @@ static void spirv_compiler_emit_store_tgsm(struct spirv_compiler *compiler,
assert(data->reg.data_type == VKD3D_DATA_UINT);
val_id = spirv_compiler_emit_load_src(compiler, data, dst->write_mask);
- component_count = vkd3d_write_mask_component_count(dst->write_mask);
+ component_count = vsir_write_mask_component_count(dst->write_mask);
for (component_idx = 0; component_idx < component_count; ++component_idx)
{
data_id = component_count > 1 ?
@@ -8655,7 +8737,7 @@ static void spirv_compiler_emit_ld_uav_typed(struct spirv_compiler *compiler,
const struct vkd3d_shader_src_param *src = instruction->src;
const struct vkd3d_symbol *resource_symbol;
struct vkd3d_shader_image image;
- DWORD coordinate_mask;
+ uint32_t coordinate_mask;
uint32_t indices[2];
resource_symbol = spirv_compiler_find_resource(compiler, &src[1].reg);
@@ -8698,7 +8780,7 @@ static void spirv_compiler_emit_store_uav_typed(struct spirv_compiler *compiler,
const struct vkd3d_shader_src_param *src = instruction->src;
const struct vkd3d_symbol *resource_symbol;
struct vkd3d_shader_image image;
- DWORD coordinate_mask;
+ uint32_t coordinate_mask;
uint32_t indices[2];
resource_symbol = spirv_compiler_find_resource(compiler, &dst->reg);
@@ -8864,7 +8946,7 @@ static void spirv_compiler_emit_atomic_instruction(struct spirv_compiler *compil
struct vkd3d_shader_register_info reg_info;
struct vkd3d_shader_image image;
unsigned int structure_stride;
- DWORD coordinate_mask;
+ uint32_t coordinate_mask;
uint32_t operands[6];
unsigned int i = 0;
SpvScope scope;
@@ -9275,7 +9357,7 @@ static void spirv_compiler_emit_eval_attrib(struct spirv_compiler *compiler,
}
type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT,
- vkd3d_write_mask_component_count(register_info.write_mask));
+ vsir_write_mask_component_count(register_info.write_mask));
instr_set_id = vkd3d_spirv_get_glsl_std450_instr_set(builder);
val_id = vkd3d_spirv_build_op_ext_inst(builder, type_id, instr_set_id, op, src_ids, src_count);
@@ -9296,9 +9378,9 @@ static void spirv_compiler_emit_sync(struct spirv_compiler *compiler,
const struct vkd3d_shader_instruction *instruction)
{
unsigned int memory_semantics = SpvMemorySemanticsAcquireReleaseMask;
- unsigned int flags = instruction->flags;
SpvScope execution_scope = SpvScopeMax;
SpvScope memory_scope = SpvScopeDevice;
+ uint32_t flags = instruction->flags;
if (flags & VKD3DSSF_GROUP_SHARED_MEMORY)
{
@@ -9313,11 +9395,20 @@ static void spirv_compiler_emit_sync(struct spirv_compiler *compiler,
flags &= ~VKD3DSSF_THREAD_GROUP;
}
- if (flags & VKD3DSSF_GLOBAL_UAV)
+ if (flags & (VKD3DSSF_THREAD_GROUP_UAV | VKD3DSSF_GLOBAL_UAV))
{
- memory_scope = SpvScopeDevice;
- memory_semantics |= SpvMemorySemanticsImageMemoryMask;
- flags &= ~VKD3DSSF_GLOBAL_UAV;
+ bool group_uav = flags & VKD3DSSF_THREAD_GROUP_UAV;
+ bool global_uav = flags & VKD3DSSF_GLOBAL_UAV;
+
+ if (group_uav && global_uav)
+ {
+ WARN("Invalid UAV sync flag combination; assuming global.\n");
+ spirv_compiler_warning(compiler, VKD3D_SHADER_WARNING_SPV_INVALID_UAV_FLAGS,
+ "The flags for a UAV sync instruction are contradictory; assuming global sync.");
+ }
+ memory_scope = global_uav ? SpvScopeDevice : SpvScopeWorkgroup;
+ memory_semantics |= SpvMemorySemanticsUniformMemoryMask | SpvMemorySemanticsImageMemoryMask;
+ flags &= ~(VKD3DSSF_THREAD_GROUP_UAV | VKD3DSSF_GLOBAL_UAV);
}
if (flags)
@@ -9382,28 +9473,15 @@ static void spirv_compiler_emit_main_prolog(struct spirv_compiler *compiler)
{
spirv_compiler_emit_push_constant_buffers(compiler);
- if (compiler->xfb_info && compiler->xfb_info->element_count
- && compiler->shader_type != VKD3D_SHADER_TYPE_GEOMETRY)
+ if (compiler->emit_point_size)
spirv_compiler_emit_point_size(compiler);
}
-static bool is_dcl_instruction(enum vkd3d_shader_opcode handler_idx)
-{
- return (VKD3DSIH_DCL <= handler_idx && handler_idx <= VKD3DSIH_DCL_VERTICES_OUT)
- || handler_idx == VKD3DSIH_HS_DECLS;
-}
-
static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler,
const struct vkd3d_shader_instruction *instruction)
{
int ret = VKD3D_OK;
- if (!is_dcl_instruction(instruction->handler_idx) && !compiler->after_declarations_section)
- {
- compiler->after_declarations_section = true;
- spirv_compiler_emit_main_prolog(compiler);
- }
-
switch (instruction->handler_idx)
{
case VKD3DSIH_DCL_GLOBAL_FLAGS:
@@ -9425,18 +9503,9 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler,
case VKD3DSIH_DCL_INPUT:
spirv_compiler_emit_dcl_input(compiler, instruction);
break;
- case VKD3DSIH_DCL_INPUT_PS_SGV:
- case VKD3DSIH_DCL_INPUT_PS_SIV:
- case VKD3DSIH_DCL_INPUT_SGV:
- case VKD3DSIH_DCL_INPUT_SIV:
- spirv_compiler_emit_dcl_input_sysval(compiler, instruction);
- break;
case VKD3DSIH_DCL_OUTPUT:
spirv_compiler_emit_dcl_output(compiler, instruction);
break;
- case VKD3DSIH_DCL_OUTPUT_SIV:
- spirv_compiler_emit_dcl_output_siv(compiler, instruction);
- break;
case VKD3DSIH_DCL_STREAM:
spirv_compiler_emit_dcl_stream(compiler, instruction);
break;
@@ -9500,6 +9569,8 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler,
case VKD3DSIH_INEG:
case VKD3DSIH_ISHL:
case VKD3DSIH_ISHR:
+ case VKD3DSIH_ISINF:
+ case VKD3DSIH_ISNAN:
case VKD3DSIH_ITOD:
case VKD3DSIH_ITOF:
case VKD3DSIH_ITOI:
@@ -9513,6 +9584,15 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler,
case VKD3DSIH_XOR:
ret = spirv_compiler_emit_alu_instruction(compiler, instruction);
break;
+ case VKD3DSIH_ISFINITE:
+ spirv_compiler_emit_isfinite(compiler, instruction);
+ break;
+ case VKD3DSIH_ACOS:
+ case VKD3DSIH_ASIN:
+ case VKD3DSIH_ATAN:
+ case VKD3DSIH_HCOS:
+ case VKD3DSIH_HSIN:
+ case VKD3DSIH_HTAN:
case VKD3DSIH_DFMA:
case VKD3DSIH_DMAX:
case VKD3DSIH_DMIN:
@@ -9533,6 +9613,7 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler,
case VKD3DSIH_ROUND_Z:
case VKD3DSIH_RSQ:
case VKD3DSIH_SQRT:
+ case VKD3DSIH_TAN:
case VKD3DSIH_UMAX:
case VKD3DSIH_UMIN:
spirv_compiler_emit_ext_glsl_instruction(compiler, instruction);
@@ -9599,24 +9680,23 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler,
case VKD3DSIH_F32TOF16:
spirv_compiler_emit_f32tof16(compiler, instruction);
break;
- case VKD3DSIH_BREAK:
- case VKD3DSIH_BREAKP:
- case VKD3DSIH_CASE:
- case VKD3DSIH_CONTINUE:
- case VKD3DSIH_CONTINUEP:
- case VKD3DSIH_DEFAULT:
- case VKD3DSIH_DISCARD:
- case VKD3DSIH_ELSE:
- case VKD3DSIH_ENDIF:
- case VKD3DSIH_ENDLOOP:
- case VKD3DSIH_ENDSWITCH:
- case VKD3DSIH_IF:
- case VKD3DSIH_LOOP:
case VKD3DSIH_RET:
+ spirv_compiler_emit_return(compiler, instruction);
+ break;
case VKD3DSIH_RETP:
- case VKD3DSIH_SWITCH:
- case VKD3DSIH_TEXKILL:
- ret = spirv_compiler_emit_control_flow_instruction(compiler, instruction);
+ spirv_compiler_emit_retc(compiler, instruction);
+ break;
+ case VKD3DSIH_DISCARD:
+ spirv_compiler_emit_discard(compiler, instruction);
+ break;
+ case VKD3DSIH_LABEL:
+ spirv_compiler_emit_label(compiler, instruction);
+ break;
+ case VKD3DSIH_BRANCH:
+ spirv_compiler_emit_branch(compiler, instruction);
+ break;
+ case VKD3DSIH_SWITCH_MONOLITHIC:
+ spirv_compiler_emit_switch(compiler, instruction);
break;
case VKD3DSIH_DSX:
case VKD3DSIH_DSX_COARSE:
@@ -9719,10 +9799,14 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler,
case VKD3DSIH_DCL_CONSTANT_BUFFER:
case VKD3DSIH_DCL_HS_MAX_TESSFACTOR:
case VKD3DSIH_DCL_INPUT_CONTROL_POINT_COUNT:
+ case VKD3DSIH_DCL_INPUT_SGV:
+ case VKD3DSIH_DCL_INPUT_SIV:
+ case VKD3DSIH_DCL_INPUT_PS_SGV:
+ case VKD3DSIH_DCL_INPUT_PS_SIV:
+ case VKD3DSIH_DCL_OUTPUT_SIV:
case VKD3DSIH_DCL_RESOURCE_RAW:
case VKD3DSIH_DCL_RESOURCE_STRUCTURED:
case VKD3DSIH_DCL_SAMPLER:
- case VKD3DSIH_DCL_TEMPS:
case VKD3DSIH_DCL_UAV_RAW:
case VKD3DSIH_DCL_UAV_STRUCTURED:
case VKD3DSIH_DCL_UAV_TYPED:
@@ -9740,6 +9824,30 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler,
return ret;
}
+static void spirv_compiler_emit_io_declarations(struct spirv_compiler *compiler)
+{
+ for (unsigned int i = 0; i < compiler->input_signature.element_count; ++i)
+ spirv_compiler_emit_input(compiler, VKD3DSPR_INPUT, i);
+
+ for (unsigned int i = 0; i < compiler->output_signature.element_count; ++i)
+ {
+ /* PS outputs other than TARGET have dedicated registers and therefore
+ * go through spirv_compiler_emit_dcl_output() for now. */
+ if (compiler->shader_type == VKD3D_SHADER_TYPE_PIXEL
+ && compiler->output_signature.elements[i].sysval_semantic != VKD3D_SHADER_SV_TARGET)
+ continue;
+ spirv_compiler_emit_output(compiler, VKD3DSPR_OUTPUT, i);
+ }
+
+ for (unsigned int i = 0; i < compiler->patch_constant_signature.element_count; ++i)
+ {
+ if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL)
+ spirv_compiler_emit_output(compiler, VKD3DSPR_PATCHCONST, i);
+ else
+ spirv_compiler_emit_input(compiler, VKD3DSPR_PATCHCONST, i);
+ }
+}
+
static void spirv_compiler_emit_descriptor_declarations(struct spirv_compiler *compiler)
{
unsigned int i;
@@ -9793,24 +9901,28 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler,
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
struct vkd3d_shader_desc *shader_desc = &parser->shader_desc;
struct vkd3d_shader_instruction_array instructions;
+ struct vsir_program *program = &parser->program;
enum vkd3d_result result = VKD3D_OK;
unsigned int i;
- if (parser->shader_desc.temp_count)
- spirv_compiler_emit_temps(compiler, parser->shader_desc.temp_count);
- if (parser->shader_desc.ssa_count)
- spirv_compiler_allocate_ssa_register_ids(compiler, parser->shader_desc.ssa_count);
+ if ((result = vkd3d_shader_normalise(parser, compile_info)) < 0)
+ return result;
+
+ if (program->temp_count)
+ spirv_compiler_emit_temps(compiler, program->temp_count);
+ if (program->ssa_count)
+ spirv_compiler_allocate_ssa_register_ids(compiler, program->ssa_count);
spirv_compiler_emit_descriptor_declarations(compiler);
compiler->location.column = 0;
compiler->location.line = 1;
- if ((result = vkd3d_shader_normalise(parser, compile_info)) < 0)
- return result;
+ if (program->block_count && !spirv_compiler_init_blocks(compiler, program->block_count))
+ return VKD3D_ERROR_OUT_OF_MEMORY;
- instructions = parser->instructions;
- memset(&parser->instructions, 0, sizeof(parser->instructions));
+ instructions = program->instructions;
+ memset(&program->instructions, 0, sizeof(program->instructions));
compiler->input_signature = shader_desc->input_signature;
compiler->output_signature = shader_desc->output_signature;
@@ -9818,10 +9930,12 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler,
memset(&shader_desc->input_signature, 0, sizeof(shader_desc->input_signature));
memset(&shader_desc->output_signature, 0, sizeof(shader_desc->output_signature));
memset(&shader_desc->patch_constant_signature, 0, sizeof(shader_desc->patch_constant_signature));
- compiler->use_vocp = parser->shader_desc.use_vocp;
+ compiler->use_vocp = program->use_vocp;
+ compiler->block_names = program->block_names;
+ compiler->block_name_count = program->block_name_count;
- compiler->input_control_point_count = shader_desc->input_control_point_count;
- compiler->output_control_point_count = shader_desc->output_control_point_count;
+ compiler->input_control_point_count = program->input_control_point_count;
+ compiler->output_control_point_count = program->output_control_point_count;
if (compiler->shader_type != VKD3D_SHADER_TYPE_HULL)
spirv_compiler_emit_shader_signature_outputs(compiler);
@@ -9837,9 +9951,6 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler,
if (result < 0)
return result;
- if (compiler->main_block_open)
- vkd3d_spirv_build_op_return(builder);
-
if (!is_in_default_phase(compiler))
spirv_compiler_leave_shader_phase(compiler);
else
@@ -9862,6 +9973,9 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler,
}
}
+ if (compiler->discard_function_id)
+ spirv_compiler_emit_discard_function(compiler);
+
if (compiler->epilogue_function_id)
{
vkd3d_spirv_build_op_name(builder, compiler->epilogue_function_id, "epilogue");
@@ -9874,11 +9988,28 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler,
if (!vkd3d_spirv_compile_module(builder, spirv, spirv_compiler_get_entry_point_name(compiler)))
return VKD3D_ERROR;
- if (TRACE_ON())
+ if (TRACE_ON() || parser->config_flags & VKD3D_SHADER_CONFIG_FLAG_FORCE_VALIDATION)
{
enum vkd3d_shader_spirv_environment environment = spirv_compiler_get_target_environment(compiler);
- vkd3d_spirv_dump(spirv, environment);
- vkd3d_spirv_validate(spirv, environment);
+ struct vkd3d_string_buffer buffer;
+
+ if (TRACE_ON())
+ vkd3d_spirv_dump(spirv, environment);
+
+ vkd3d_string_buffer_init(&buffer);
+ if (!vkd3d_spirv_validate(&buffer, spirv, environment))
+ {
+ FIXME("Failed to validate SPIR-V binary.\n");
+ vkd3d_shader_trace_text(buffer.buffer, buffer.content_size);
+
+ if (compiler->config_flags & VKD3D_SHADER_CONFIG_FLAG_FORCE_VALIDATION)
+ {
+ spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_INVALID_SHADER,
+ "Execution generated an invalid shader, failing compilation:\n%s",
+ buffer.buffer);
+ }
+ }
+ vkd3d_string_buffer_cleanup(&buffer);
}
if (compiler->failed)
@@ -9890,6 +10021,7 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler,
enum vkd3d_shader_spirv_environment environment = spirv_compiler_get_target_environment(compiler);
if (vkd3d_spirv_binary_to_text(spirv, environment, compiler->formatting, &text) != VKD3D_OK)
return VKD3D_ERROR;
+ vkd3d_shader_free_shader_code(spirv);
*spirv = text;
}
@@ -9904,8 +10036,8 @@ int spirv_compile(struct vkd3d_shader_parser *parser,
struct spirv_compiler *spirv_compiler;
int ret;
- if (!(spirv_compiler = spirv_compiler_create(&parser->shader_version, &parser->shader_desc,
- compile_info, scan_descriptor_info, message_context, &parser->location)))
+ if (!(spirv_compiler = spirv_compiler_create(&parser->program.shader_version, &parser->shader_desc,
+ compile_info, scan_descriptor_info, message_context, &parser->location, parser->config_flags)))
{
ERR("Failed to create SPIR-V compiler.\n");
return VKD3D_ERROR;
diff --git a/libs/vkd3d/libs/vkd3d-shader/tpf.c b/libs/vkd3d/libs/vkd3d-shader/tpf.c
index 80f8ab98c08..adfddd32036 100644
--- a/libs/vkd3d/libs/vkd3d-shader/tpf.c
+++ b/libs/vkd3d/libs/vkd3d-shader/tpf.c
@@ -711,7 +711,7 @@ static struct vkd3d_shader_sm4_parser *vkd3d_shader_sm4_parser(struct vkd3d_shad
static bool shader_is_sm_5_1(const struct vkd3d_shader_sm4_parser *sm4)
{
- const struct vkd3d_shader_version *version = &sm4->p.shader_version;
+ const struct vkd3d_shader_version *version = &sm4->p.program.shader_version;
return version->major >= 5 && version->minor >= 1;
}
@@ -742,8 +742,7 @@ static bool shader_sm4_read_register_space(struct vkd3d_shader_sm4_parser *priv,
static void shader_sm4_read_conditional_op(struct vkd3d_shader_instruction *ins, uint32_t opcode,
uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *priv)
{
- shader_sm4_read_src_param(priv, &tokens, &tokens[token_count], VKD3D_DATA_UINT,
- (struct vkd3d_shader_src_param *)&ins->src[0]);
+ shader_sm4_read_src_param(priv, &tokens, &tokens[token_count], VKD3D_DATA_UINT, &ins->src[0]);
ins->flags = (opcode_token & VKD3D_SM4_CONDITIONAL_NZ) ?
VKD3D_SHADER_CONDITIONAL_OP_NZ : VKD3D_SHADER_CONDITIONAL_OP_Z;
}
@@ -751,8 +750,7 @@ static void shader_sm4_read_conditional_op(struct vkd3d_shader_instruction *ins,
static void shader_sm4_read_case_condition(struct vkd3d_shader_instruction *ins, uint32_t opcode,
uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *priv)
{
- shader_sm4_read_src_param(priv, &tokens, &tokens[token_count], VKD3D_DATA_UINT,
- (struct vkd3d_shader_src_param *)&ins->src[0]);
+ shader_sm4_read_src_param(priv, &tokens, &tokens[token_count], VKD3D_DATA_UINT, &ins->src[0]);
if (ins->src[0].reg.type != VKD3DSPR_IMMCONST)
{
FIXME("Switch case value is not a 32-bit constant.\n");
@@ -792,11 +790,13 @@ static void shader_sm4_read_shader_data(struct vkd3d_shader_instruction *ins, ui
ins->handler_idx = VKD3DSIH_INVALID;
return;
}
+ icb->register_idx = 0;
icb->data_type = VKD3D_DATA_FLOAT;
icb->component_count = VKD3D_VEC4_SIZE;
icb->element_count = icb_size / VKD3D_VEC4_SIZE;
+ icb->is_null = false;
memcpy(icb->data, tokens, sizeof(*tokens) * icb_size);
- shader_instruction_array_add_icb(&priv->p.instructions, icb);
+ shader_instruction_array_add_icb(&priv->p.program.instructions, icb);
ins->declaration.icb = icb;
}
@@ -821,7 +821,7 @@ static void shader_sm4_read_dcl_resource(struct vkd3d_shader_instruction *ins, u
const uint32_t *end = &tokens[token_count];
enum vkd3d_sm4_data_type data_type;
enum vkd3d_data_type reg_data_type;
- DWORD components;
+ uint32_t components;
unsigned int i;
resource_type = (opcode_token & VKD3D_SM4_RESOURCE_TYPE_MASK) >> VKD3D_SM4_RESOURCE_TYPE_SHIFT;
@@ -918,10 +918,12 @@ static void shader_sm4_read_dcl_index_range(struct vkd3d_shader_instruction *ins
uint32_t opcode_token, const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *priv)
{
struct vkd3d_shader_index_range *index_range = &ins->declaration.index_range;
- unsigned int i, register_idx, register_count, write_mask;
+ unsigned int i, register_idx, register_count;
+ const struct shader_signature *signature;
enum vkd3d_shader_register_type type;
struct sm4_index_range_array *ranges;
unsigned int *io_masks;
+ uint32_t write_mask;
shader_sm4_read_dst_param(priv, &tokens, &tokens[token_count], VKD3D_DATA_OPAQUE,
&index_range->dst);
@@ -931,40 +933,38 @@ static void shader_sm4_read_dcl_index_range(struct vkd3d_shader_instruction *ins
register_count = index_range->register_count;
write_mask = index_range->dst.write_mask;
- if (vkd3d_write_mask_component_count(write_mask) != 1)
- {
- WARN("Unhandled write mask %#x.\n", write_mask);
- vkd3d_shader_parser_warning(&priv->p, VKD3D_SHADER_WARNING_TPF_UNHANDLED_INDEX_RANGE_MASK,
- "Index range mask %#x is not scalar.", write_mask);
- }
-
switch ((type = index_range->dst.reg.type))
{
case VKD3DSPR_INPUT:
case VKD3DSPR_INCONTROLPOINT:
io_masks = priv->input_register_masks;
ranges = &priv->input_index_ranges;
+ signature = &priv->p.shader_desc.input_signature;
break;
case VKD3DSPR_OUTPUT:
if (sm4_parser_is_in_fork_or_join_phase(priv))
{
io_masks = priv->patch_constant_register_masks;
ranges = &priv->patch_constant_index_ranges;
+ signature = &priv->p.shader_desc.patch_constant_signature;
}
else
{
io_masks = priv->output_register_masks;
ranges = &priv->output_index_ranges;
+ signature = &priv->p.shader_desc.output_signature;
}
break;
case VKD3DSPR_COLOROUT:
case VKD3DSPR_OUTCONTROLPOINT:
io_masks = priv->output_register_masks;
ranges = &priv->output_index_ranges;
+ signature = &priv->p.shader_desc.output_signature;
break;
case VKD3DSPR_PATCHCONST:
io_masks = priv->patch_constant_register_masks;
ranges = &priv->patch_constant_index_ranges;
+ signature = &priv->p.shader_desc.patch_constant_signature;
break;
default:
@@ -1002,6 +1002,18 @@ static void shader_sm4_read_dcl_index_range(struct vkd3d_shader_instruction *ins
for (i = 0; i < register_count; ++i)
{
+ const struct signature_element *e = vsir_signature_find_element_for_reg(signature, register_idx + i, write_mask);
+ /* Index ranges should not contain non-arrayed sysvals. FXC tries to forbid this but it is buggy,
+ * and can emit a range containing a sysval if the sysval is not actually accessed. */
+ if (e && e->sysval_semantic && register_count > 1 && !vsir_sysval_semantic_is_tess_factor(e->sysval_semantic)
+ && !vsir_sysval_semantic_is_clip_cull(e->sysval_semantic))
+ {
+ WARN("Sysval %u included in an index range declaration.\n", e->sysval_semantic);
+ vkd3d_shader_parser_error(&priv->p, VKD3D_SHADER_ERROR_TPF_INVALID_INDEX_RANGE_DCL,
+ "Index range base %u, count %u, mask %#x contains sysval %u.",
+ register_idx, register_count, write_mask, e->sysval_semantic);
+ return;
+ }
if ((io_masks[register_idx + i] & write_mask) != write_mask)
{
WARN("No matching declaration for index range base %u, count %u, mask %#x.\n",
@@ -1039,7 +1051,7 @@ static void shader_sm4_read_dcl_input_primitive(struct vkd3d_shader_instruction
{
ins->declaration.primitive_type.type = VKD3D_PT_PATCH;
ins->declaration.primitive_type.patch_vertex_count = primitive_type - VKD3D_SM5_INPUT_PT_PATCH1 + 1;
- priv->p.shader_desc.input_control_point_count = ins->declaration.primitive_type.patch_vertex_count;
+ priv->p.program.input_control_point_count = ins->declaration.primitive_type.patch_vertex_count;
}
else if (primitive_type >= ARRAY_SIZE(input_primitive_type_table))
{
@@ -1048,7 +1060,7 @@ static void shader_sm4_read_dcl_input_primitive(struct vkd3d_shader_instruction
else
{
ins->declaration.primitive_type.type = input_primitive_type_table[primitive_type].vkd3d_type;
- priv->p.shader_desc.input_control_point_count = input_primitive_type_table[primitive_type].control_point_count;
+ priv->p.program.input_control_point_count = input_primitive_type_table[primitive_type].control_point_count;
}
if (ins->declaration.primitive_type.type == VKD3D_PT_UNDEFINED)
@@ -1060,7 +1072,7 @@ static void shader_sm4_read_declaration_count(struct vkd3d_shader_instruction *i
{
ins->declaration.count = *tokens;
if (opcode == VKD3D_SM4_OP_DCL_TEMPS)
- priv->p.shader_desc.temp_count = max(priv->p.shader_desc.temp_count, *tokens);
+ priv->p.program.temp_count = max(priv->p.program.temp_count, *tokens);
}
static void shader_sm4_read_declaration_dst(struct vkd3d_shader_instruction *ins, uint32_t opcode,
@@ -1116,6 +1128,7 @@ static void shader_sm4_read_dcl_indexable_temp(struct vkd3d_shader_instruction *
ins->declaration.indexable_temp.alignment = 0;
ins->declaration.indexable_temp.data_type = VKD3D_DATA_FLOAT;
ins->declaration.indexable_temp.component_count = *tokens;
+ ins->declaration.indexable_temp.has_function_scope = false;
}
static void shader_sm4_read_dcl_global_flags(struct vkd3d_shader_instruction *ins, uint32_t opcode,
@@ -1127,9 +1140,8 @@ static void shader_sm4_read_dcl_global_flags(struct vkd3d_shader_instruction *in
static void shader_sm5_read_fcall(struct vkd3d_shader_instruction *ins, uint32_t opcode, uint32_t opcode_token,
const uint32_t *tokens, unsigned int token_count, struct vkd3d_shader_sm4_parser *priv)
{
- struct vkd3d_shader_src_param *src_params = (struct vkd3d_shader_src_param *)ins->src;
- src_params[0].reg.u.fp_body_idx = *tokens++;
- shader_sm4_read_src_param(priv, &tokens, &tokens[token_count], VKD3D_DATA_OPAQUE, &src_params[0]);
+ ins->src[0].reg.u.fp_body_idx = *tokens++;
+ shader_sm4_read_src_param(priv, &tokens, &tokens[token_count], VKD3D_DATA_OPAQUE, &ins->src[0]);
}
static void shader_sm5_read_dcl_function_body(struct vkd3d_shader_instruction *ins, uint32_t opcode,
@@ -1162,9 +1174,9 @@ static void shader_sm5_read_control_point_count(struct vkd3d_shader_instruction
>> VKD3D_SM5_CONTROL_POINT_COUNT_SHIFT;
if (opcode == VKD3D_SM5_OP_DCL_INPUT_CONTROL_POINT_COUNT)
- priv->p.shader_desc.input_control_point_count = ins->declaration.count;
+ priv->p.program.input_control_point_count = ins->declaration.count;
else
- priv->p.shader_desc.output_control_point_count = ins->declaration.count;
+ priv->p.program.output_control_point_count = ins->declaration.count;
}
static void shader_sm5_read_dcl_tessellator_domain(struct vkd3d_shader_instruction *ins, uint32_t opcode,
@@ -1720,7 +1732,7 @@ static void shader_sm4_destroy(struct vkd3d_shader_parser *parser)
{
struct vkd3d_shader_sm4_parser *sm4 = vkd3d_shader_sm4_parser(parser);
- shader_instruction_array_destroy(&parser->instructions);
+ vsir_program_cleanup(&parser->program);
free_shader_desc(&parser->shader_desc);
vkd3d_free(sm4);
}
@@ -1730,7 +1742,7 @@ static bool shader_sm4_read_reg_idx(struct vkd3d_shader_sm4_parser *priv, const
{
if (addressing & VKD3D_SM4_ADDRESSING_RELATIVE)
{
- struct vkd3d_shader_src_param *rel_addr = shader_parser_get_src_params(&priv->p, 1);
+ struct vkd3d_shader_src_param *rel_addr = vsir_program_get_src_params(&priv->p.program, 1);
if (!(reg_idx->rel_addr = rel_addr))
{
@@ -1759,11 +1771,11 @@ static bool shader_sm4_read_param(struct vkd3d_shader_sm4_parser *priv, const ui
const struct vkd3d_sm4_register_type_info *register_type_info;
enum vkd3d_shader_register_type vsir_register_type;
enum vkd3d_sm4_register_precision precision;
+ uint32_t token, order, extended, addressing;
enum vkd3d_sm4_register_type register_type;
enum vkd3d_sm4_extended_operand_type type;
- enum vkd3d_sm4_register_modifier m;
enum vkd3d_sm4_dimension sm4_dimension;
- uint32_t token, order, extended;
+ enum vkd3d_sm4_register_modifier m;
if (*ptr >= end)
{
@@ -1861,7 +1873,7 @@ static bool shader_sm4_read_param(struct vkd3d_shader_sm4_parser *priv, const ui
if (order >= 1)
{
- DWORD addressing = (token & VKD3D_SM4_ADDRESSING_MASK0) >> VKD3D_SM4_ADDRESSING_SHIFT0;
+ addressing = (token & VKD3D_SM4_ADDRESSING_MASK0) >> VKD3D_SM4_ADDRESSING_SHIFT0;
if (!(shader_sm4_read_reg_idx(priv, ptr, end, addressing, &param->idx[0])))
{
ERR("Failed to read register index.\n");
@@ -1871,7 +1883,7 @@ static bool shader_sm4_read_param(struct vkd3d_shader_sm4_parser *priv, const ui
if (order >= 2)
{
- DWORD addressing = (token & VKD3D_SM4_ADDRESSING_MASK1) >> VKD3D_SM4_ADDRESSING_SHIFT1;
+ addressing = (token & VKD3D_SM4_ADDRESSING_MASK1) >> VKD3D_SM4_ADDRESSING_SHIFT1;
if (!(shader_sm4_read_reg_idx(priv, ptr, end, addressing, &param->idx[1])))
{
ERR("Failed to read register index.\n");
@@ -1881,7 +1893,7 @@ static bool shader_sm4_read_param(struct vkd3d_shader_sm4_parser *priv, const ui
if (order >= 3)
{
- DWORD addressing = (token & VKD3D_SM4_ADDRESSING_MASK2) >> VKD3D_SM4_ADDRESSING_SHIFT2;
+ addressing = (token & VKD3D_SM4_ADDRESSING_MASK2) >> VKD3D_SM4_ADDRESSING_SHIFT2;
if (!(shader_sm4_read_reg_idx(priv, ptr, end, addressing, &param->idx[2])))
{
ERR("Failed to read register index.\n");
@@ -1900,19 +1912,19 @@ static bool shader_sm4_read_param(struct vkd3d_shader_sm4_parser *priv, const ui
if (register_type == VKD3D_SM4_RT_IMMCONST || register_type == VKD3D_SM4_RT_IMMCONST64)
{
- unsigned int dword_count;
+ unsigned int u32_count;
switch (param->dimension)
{
case VSIR_DIMENSION_SCALAR:
- dword_count = 1 + (register_type == VKD3D_SM4_RT_IMMCONST64);
- if (end - *ptr < dword_count)
+ u32_count = 1 + (register_type == VKD3D_SM4_RT_IMMCONST64);
+ if (end - *ptr < u32_count)
{
WARN("Invalid ptr %p, end %p.\n", *ptr, end);
return false;
}
- memcpy(param->u.immconst_uint, *ptr, dword_count * sizeof(DWORD));
- *ptr += dword_count;
+ memcpy(param->u.immconst_u32, *ptr, u32_count * sizeof(uint32_t));
+ *ptr += u32_count;
break;
case VSIR_DIMENSION_VEC4:
@@ -1921,7 +1933,7 @@ static bool shader_sm4_read_param(struct vkd3d_shader_sm4_parser *priv, const ui
WARN("Invalid ptr %p, end %p.\n", *ptr, end);
return false;
}
- memcpy(param->u.immconst_uint, *ptr, VKD3D_VEC4_SIZE * sizeof(DWORD));
+ memcpy(param->u.immconst_u32, *ptr, VKD3D_VEC4_SIZE * sizeof(uint32_t));
*ptr += 4;
break;
@@ -1930,6 +1942,15 @@ static bool shader_sm4_read_param(struct vkd3d_shader_sm4_parser *priv, const ui
break;
}
}
+ else if (register_type == VKD3D_SM4_RT_IMMCONSTBUFFER)
+ {
+ if (param->idx_count != 1)
+ {
+ WARN("Unexpected idx count %u.\n", param->idx_count);
+ vkd3d_shader_parser_error(&priv->p, VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_INDEX_COUNT,
+ "Invalid index count %u for immediate const buffer register; expected count 1.", param->idx_count);
+ }
+ }
else if (!shader_is_sm_5_1(priv) && vsir_register_is_descriptor(param))
{
/* SM5.1 places a symbol identifier in idx[0] and moves
@@ -1970,10 +1991,10 @@ static uint32_t swizzle_from_sm4(uint32_t s)
static uint32_t swizzle_to_sm4(uint32_t s)
{
uint32_t ret = 0;
- ret |= ((vkd3d_swizzle_get_component(s, 0)) & 0x3);
- ret |= ((vkd3d_swizzle_get_component(s, 1)) & 0x3) << 2;
- ret |= ((vkd3d_swizzle_get_component(s, 2)) & 0x3) << 4;
- ret |= ((vkd3d_swizzle_get_component(s, 3)) & 0x3) << 6;
+ ret |= ((vsir_swizzle_get_component(s, 0)) & 0x3);
+ ret |= ((vsir_swizzle_get_component(s, 1)) & 0x3) << 2;
+ ret |= ((vsir_swizzle_get_component(s, 2)) & 0x3) << 4;
+ ret |= ((vsir_swizzle_get_component(s, 3)) & 0x3) << 6;
return ret;
}
@@ -1999,15 +2020,15 @@ static bool register_is_control_point_input(const struct vkd3d_shader_register *
{
return reg->type == VKD3DSPR_INCONTROLPOINT || reg->type == VKD3DSPR_OUTCONTROLPOINT
|| (reg->type == VKD3DSPR_INPUT && (priv->phase == VKD3DSIH_HS_CONTROL_POINT_PHASE
- || priv->p.shader_version.type == VKD3D_SHADER_TYPE_GEOMETRY));
+ || priv->p.program.shader_version.type == VKD3D_SHADER_TYPE_GEOMETRY));
}
-static unsigned int mask_from_swizzle(unsigned int swizzle)
+static uint32_t mask_from_swizzle(uint32_t swizzle)
{
- return (1u << vkd3d_swizzle_get_component(swizzle, 0))
- | (1u << vkd3d_swizzle_get_component(swizzle, 1))
- | (1u << vkd3d_swizzle_get_component(swizzle, 2))
- | (1u << vkd3d_swizzle_get_component(swizzle, 3));
+ return (1u << vsir_swizzle_get_component(swizzle, 0))
+ | (1u << vsir_swizzle_get_component(swizzle, 1))
+ | (1u << vsir_swizzle_get_component(swizzle, 2))
+ | (1u << vsir_swizzle_get_component(swizzle, 3));
}
static bool shader_sm4_validate_input_output_register(struct vkd3d_shader_sm4_parser *priv,
@@ -2066,7 +2087,7 @@ static bool shader_sm4_read_src_param(struct vkd3d_shader_sm4_parser *priv, cons
const uint32_t *end, enum vkd3d_data_type data_type, struct vkd3d_shader_src_param *src_param)
{
unsigned int dimension, mask;
- DWORD token;
+ uint32_t token;
if (*ptr >= end)
{
@@ -2140,6 +2161,9 @@ static bool shader_sm4_read_src_param(struct vkd3d_shader_sm4_parser *priv, cons
break;
}
+ if (data_type_is_64_bit(data_type))
+ src_param->swizzle = vsir_swizzle_64_from_32(src_param->swizzle);
+
if (register_is_input_output(&src_param->reg) && !shader_sm4_validate_input_output_register(priv,
&src_param->reg, mask_from_swizzle(src_param->swizzle)))
return false;
@@ -2153,7 +2177,7 @@ static bool shader_sm4_read_dst_param(struct vkd3d_shader_sm4_parser *priv, cons
enum vkd3d_sm4_swizzle_type swizzle_type;
enum vkd3d_shader_src_modifier modifier;
unsigned int dimension, swizzle;
- DWORD token;
+ uint32_t token;
if (*ptr >= end)
{
@@ -2219,7 +2243,7 @@ static bool shader_sm4_read_dst_param(struct vkd3d_shader_sm4_parser *priv, cons
}
if (data_type == VKD3D_DATA_DOUBLE)
- dst_param->write_mask = vkd3d_write_mask_64_from_32(dst_param->write_mask);
+ dst_param->write_mask = vsir_write_mask_64_from_32(dst_param->write_mask);
/* Some scalar registers are declared with no write mask in shader bytecode. */
if (!dst_param->write_mask && shader_sm4_is_scalar_register(&dst_param->reg))
dst_param->write_mask = VKD3DSP_WRITEMASK_0;
@@ -2233,7 +2257,7 @@ static bool shader_sm4_read_dst_param(struct vkd3d_shader_sm4_parser *priv, cons
return true;
}
-static void shader_sm4_read_instruction_modifier(DWORD modifier, struct vkd3d_shader_instruction *ins)
+static void shader_sm4_read_instruction_modifier(uint32_t modifier, struct vkd3d_shader_instruction *ins)
{
enum vkd3d_sm4_instruction_modifier modifier_type = modifier & VKD3D_SM4_MODIFIER_MASK;
@@ -2241,7 +2265,7 @@ static void shader_sm4_read_instruction_modifier(DWORD modifier, struct vkd3d_sh
{
case VKD3D_SM4_MODIFIER_AOFFIMMI:
{
- static const DWORD recognized_bits = VKD3D_SM4_INSTRUCTION_MODIFIER
+ static const uint32_t recognized_bits = VKD3D_SM4_INSTRUCTION_MODIFIER
| VKD3D_SM4_MODIFIER_MASK
| VKD3D_SM4_AOFFIMMI_U_MASK
| VKD3D_SM4_AOFFIMMI_V_MASK
@@ -2269,7 +2293,7 @@ static void shader_sm4_read_instruction_modifier(DWORD modifier, struct vkd3d_sh
case VKD3D_SM5_MODIFIER_DATA_TYPE:
{
- DWORD components = (modifier & VKD3D_SM5_MODIFIER_DATA_TYPE_MASK) >> VKD3D_SM5_MODIFIER_DATA_TYPE_SHIFT;
+ uint32_t components = (modifier & VKD3D_SM5_MODIFIER_DATA_TYPE_MASK) >> VKD3D_SM5_MODIFIER_DATA_TYPE_SHIFT;
unsigned int i;
for (i = 0; i < VKD3D_VEC4_SIZE; i++)
@@ -2320,14 +2344,15 @@ static void shader_sm4_read_instruction_modifier(DWORD modifier, struct vkd3d_sh
static void shader_sm4_read_instruction(struct vkd3d_shader_sm4_parser *sm4, struct vkd3d_shader_instruction *ins)
{
const struct vkd3d_sm4_opcode_info *opcode_info;
+ struct vsir_program *program = &sm4->p.program;
uint32_t opcode_token, opcode, previous_token;
struct vkd3d_shader_dst_param *dst_params;
struct vkd3d_shader_src_param *src_params;
const uint32_t **ptr = &sm4->ptr;
unsigned int i, len;
- size_t remaining;
const uint32_t *p;
- DWORD precise;
+ uint32_t precise;
+ size_t remaining;
if (*ptr >= sm4->end)
{
@@ -2378,7 +2403,7 @@ static void shader_sm4_read_instruction(struct vkd3d_shader_sm4_parser *sm4, str
ins->predicate = NULL;
ins->dst_count = strnlen(opcode_info->dst_info, SM4_MAX_DST_COUNT);
ins->src_count = strnlen(opcode_info->src_info, SM4_MAX_SRC_COUNT);
- ins->src = src_params = shader_parser_get_src_params(&sm4->p, ins->src_count);
+ ins->src = src_params = vsir_program_get_src_params(program, ins->src_count);
if (!src_params && ins->src_count)
{
ERR("Failed to allocate src parameters.\n");
@@ -2420,7 +2445,7 @@ static void shader_sm4_read_instruction(struct vkd3d_shader_sm4_parser *sm4, str
precise = (opcode_token & VKD3D_SM5_PRECISE_MASK) >> VKD3D_SM5_PRECISE_SHIFT;
ins->flags |= precise << VKD3DSI_PRECISE_SHIFT;
- ins->dst = dst_params = shader_parser_get_dst_params(&sm4->p, ins->dst_count);
+ ins->dst = dst_params = vsir_program_get_dst_params(program, ins->dst_count);
if (!dst_params && ins->dst_count)
{
ERR("Failed to allocate dst parameters.\n");
@@ -2533,6 +2558,16 @@ static bool shader_sm4_init(struct vkd3d_shader_sm4_parser *sm4, const uint32_t
return true;
}
+static void uninvert_used_masks(struct shader_signature *signature)
+{
+ for (unsigned int i = 0; i < signature->element_count; ++i)
+ {
+ struct signature_element *e = &signature->elements[i];
+
+ e->used_mask = e->mask & ~e->used_mask;
+ }
+}
+
static bool shader_sm4_parser_validate_signature(struct vkd3d_shader_sm4_parser *sm4,
const struct shader_signature *signature, unsigned int *masks, const char *name)
{
@@ -2628,6 +2663,12 @@ int vkd3d_shader_sm4_parser_create(const struct vkd3d_shader_compile_info *compi
return VKD3D_ERROR_INVALID_ARGUMENT;
}
+ /* DXBC stores used masks inverted for output signatures, for some reason.
+ * We return them un-inverted. */
+ uninvert_used_masks(&shader_desc->output_signature);
+ if (sm4->p.program.shader_version.type == VKD3D_SHADER_TYPE_HULL)
+ uninvert_used_masks(&shader_desc->patch_constant_signature);
+
if (!shader_sm4_parser_validate_signature(sm4, &shader_desc->input_signature,
sm4->input_register_masks, "Input")
|| !shader_sm4_parser_validate_signature(sm4, &shader_desc->output_signature,
@@ -2639,7 +2680,7 @@ int vkd3d_shader_sm4_parser_create(const struct vkd3d_shader_compile_info *compi
return VKD3D_ERROR_INVALID_SHADER;
}
- instructions = &sm4->p.instructions;
+ instructions = &sm4->p.program.instructions;
while (sm4->ptr != sm4->end)
{
if (!shader_instruction_array_reserve(instructions, instructions->count + 1))
@@ -2660,7 +2701,8 @@ int vkd3d_shader_sm4_parser_create(const struct vkd3d_shader_compile_info *compi
}
++instructions->count;
}
- if (sm4->p.shader_version.type == VKD3D_SHADER_TYPE_HULL && !sm4->has_control_point_phase && !sm4->p.failed)
+ if (sm4->p.program.shader_version.type == VKD3D_SHADER_TYPE_HULL
+ && !sm4->has_control_point_phase && !sm4->p.failed)
shader_sm4_validate_default_phase_index_ranges(sm4);
if (!sm4->p.failed)
@@ -2769,6 +2811,8 @@ bool hlsl_sm4_usage_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_semant
{"position", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_POSITION},
{"sv_position", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_POSITION},
{"sv_isfrontface", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_IS_FRONT_FACE},
+ {"sv_rendertargetarrayindex", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_RENDER_TARGET_ARRAY_INDEX},
+ {"sv_viewportarrayindex", false, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_VIEWPORT_ARRAY_INDEX},
{"color", true, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_TARGET},
{"depth", true, VKD3D_SHADER_TYPE_PIXEL, D3D_NAME_DEPTH},
@@ -2777,9 +2821,12 @@ bool hlsl_sm4_usage_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_semant
{"sv_position", false, VKD3D_SHADER_TYPE_VERTEX, D3D_NAME_UNDEFINED},
{"sv_vertexid", false, VKD3D_SHADER_TYPE_VERTEX, D3D_NAME_VERTEX_ID},
+ {"sv_instanceid", false, VKD3D_SHADER_TYPE_VERTEX, D3D_NAME_INSTANCE_ID},
{"position", true, VKD3D_SHADER_TYPE_VERTEX, D3D_NAME_POSITION},
{"sv_position", true, VKD3D_SHADER_TYPE_VERTEX, D3D_NAME_POSITION},
+ {"sv_rendertargetarrayindex", true, VKD3D_SHADER_TYPE_VERTEX, D3D_NAME_RENDER_TARGET_ARRAY_INDEX},
+ {"sv_viewportarrayindex", true, VKD3D_SHADER_TYPE_VERTEX, D3D_NAME_VIEWPORT_ARRAY_INDEX},
};
bool needs_compat_mapping = ascii_strncasecmp(semantic->name, "sv_", 3);
@@ -3842,7 +3889,7 @@ static void sm4_src_from_constant_value(struct vkd3d_shader_src_param *src,
if (width == 1)
{
src->reg.dimension = VSIR_DIMENSION_SCALAR;
- src->reg.u.immconst_uint[0] = value->u[0].u;
+ src->reg.u.immconst_u32[0] = value->u[0].u;
}
else
{
@@ -3852,9 +3899,9 @@ static void sm4_src_from_constant_value(struct vkd3d_shader_src_param *src,
for (i = 0; i < 4; ++i)
{
if ((map_writemask & (1u << i)) && (j < width))
- src->reg.u.immconst_uint[i] = value->u[j++].u;
+ src->reg.u.immconst_u32[i] = value->u[j++].u;
else
- src->reg.u.immconst_uint[i] = 0;
+ src->reg.u.immconst_u32[i] = 0;
}
}
}
@@ -4049,12 +4096,12 @@ static void sm4_write_src_register(const struct tpf_writer *tpf, const struct vk
if (src->reg.type == VKD3DSPR_IMMCONST)
{
- put_u32(buffer, src->reg.u.immconst_uint[0]);
+ put_u32(buffer, src->reg.u.immconst_u32[0]);
if (src->reg.dimension == VSIR_DIMENSION_VEC4)
{
- put_u32(buffer, src->reg.u.immconst_uint[1]);
- put_u32(buffer, src->reg.u.immconst_uint[2]);
- put_u32(buffer, src->reg.u.immconst_uint[3]);
+ put_u32(buffer, src->reg.u.immconst_u32[1]);
+ put_u32(buffer, src->reg.u.immconst_u32[2]);
+ put_u32(buffer, src->reg.u.immconst_u32[3]);
}
}
}
@@ -4589,7 +4636,7 @@ static void write_sm4_ld(const struct tpf_writer *tpf, const struct hlsl_ir_node
memset(&instr.srcs[2], 0, sizeof(instr.srcs[2]));
reg->type = VKD3DSPR_IMMCONST;
reg->dimension = VSIR_DIMENSION_SCALAR;
- reg->u.immconst_uint[0] = index->value.u[0].u;
+ reg->u.immconst_u32[0] = index->value.u[0].u;
}
else if (tpf->ctx->profile->major_version == 4 && tpf->ctx->profile->minor_version == 0)
{
@@ -4750,7 +4797,7 @@ static void write_sm4_cast_from_bool(const struct tpf_writer *tpf, const struct
sm4_src_from_node(tpf, &instr.srcs[0], arg, instr.dsts[0].write_mask);
instr.srcs[1].reg.type = VKD3DSPR_IMMCONST;
instr.srcs[1].reg.dimension = VSIR_DIMENSION_SCALAR;
- instr.srcs[1].reg.u.immconst_uint[0] = mask;
+ instr.srcs[1].reg.u.immconst_u32[0] = mask;
instr.src_count = 2;
write_sm4_instruction(tpf, &instr);
@@ -5460,7 +5507,7 @@ static void write_sm4_loop(const struct tpf_writer *tpf, const struct hlsl_ir_lo
static void write_sm4_gather(const struct tpf_writer *tpf, const struct hlsl_ir_node *dst,
const struct hlsl_deref *resource, const struct hlsl_deref *sampler,
- const struct hlsl_ir_node *coords, DWORD swizzle, const struct hlsl_ir_node *texel_offset)
+ const struct hlsl_ir_node *coords, uint32_t swizzle, const struct hlsl_ir_node *texel_offset)
{
struct vkd3d_shader_src_param *src;
struct sm4_instruction instr;
diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c
index 8fd8945151f..d0fd6b047b1 100644
--- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c
+++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c
@@ -23,6 +23,8 @@
#include <stdio.h>
#include <math.h>
+/* VKD3D_DEBUG_ENV_NAME("VKD3D_SHADER_DEBUG"); */
+
static inline int char_to_int(char c)
{
if ('0' <= c && c <= '9')
@@ -305,6 +307,16 @@ void vkd3d_shader_vwarning(struct vkd3d_shader_message_context *context, const s
vkd3d_string_buffer_printf(&context->messages, "\n");
}
+void vkd3d_shader_warning(struct vkd3d_shader_message_context *context, const struct vkd3d_shader_location *location,
+ enum vkd3d_shader_error error, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ vkd3d_shader_vwarning(context, location, error, format, args);
+ va_end(args);
+}
+
void vkd3d_shader_verror(struct vkd3d_shader_message_context *context, const struct vkd3d_shader_location *location,
enum vkd3d_shader_error error, const char *format, va_list args)
{
@@ -371,24 +383,53 @@ size_t bytecode_put_bytes(struct vkd3d_bytecode_buffer *buffer, const void *byte
return offset;
}
-void set_u32(struct vkd3d_bytecode_buffer *buffer, size_t offset, uint32_t value)
+size_t bytecode_reserve_bytes(struct vkd3d_bytecode_buffer *buffer, size_t size)
+{
+ size_t offset = bytecode_align(buffer);
+
+ if (buffer->status)
+ return offset;
+
+ if (!vkd3d_array_reserve((void **)&buffer->data, &buffer->capacity, offset + size, 1))
+ {
+ buffer->status = VKD3D_ERROR_OUT_OF_MEMORY;
+ return offset;
+ }
+
+ memset(buffer->data + offset, 0, size);
+ buffer->size = offset + size;
+ return offset;
+}
+
+static void bytecode_set_bytes(struct vkd3d_bytecode_buffer *buffer, size_t offset,
+ const void *value, size_t size)
{
if (buffer->status)
return;
- assert(vkd3d_bound_range(offset, sizeof(value), buffer->size));
- memcpy(buffer->data + offset, &value, sizeof(value));
+ assert(vkd3d_bound_range(offset, size, buffer->size));
+ memcpy(buffer->data + offset, value, size);
+}
+
+void set_u32(struct vkd3d_bytecode_buffer *buffer, size_t offset, uint32_t value)
+{
+ bytecode_set_bytes(buffer, offset, &value, sizeof(value));
+}
+
+void set_string(struct vkd3d_bytecode_buffer *buffer, size_t offset, const char *string, size_t length)
+{
+ bytecode_set_bytes(buffer, offset, string, length);
}
static void vkd3d_shader_dump_blob(const char *path, const char *profile,
const char *suffix, const void *data, size_t size)
{
- static LONG shader_id = 0;
+ static unsigned int shader_id = 0;
char filename[1024];
unsigned int id;
FILE *f;
- id = InterlockedIncrement(&shader_id) - 1;
+ id = vkd3d_atomic_increment_u32(&shader_id) - 1;
if (profile)
snprintf(filename, ARRAY_SIZE(filename), "%s/vkd3d-shader-%u-%s.%s", path, id, profile, suffix);
@@ -498,10 +539,9 @@ bool vkd3d_shader_parser_init(struct vkd3d_shader_parser *parser,
parser->location.source_name = source_name;
parser->location.line = 1;
parser->location.column = 0;
- parser->shader_version = *version;
parser->ops = ops;
parser->config_flags = vkd3d_shader_init_config_flags();
- return shader_instruction_array_init(&parser->instructions, instruction_reserve);
+ return vsir_program_init(&parser->program, version, instruction_reserve);
}
void VKD3D_PRINTF_FUNC(3, 4) vkd3d_shader_parser_error(struct vkd3d_shader_parser *parser,
@@ -888,6 +928,21 @@ static void vkd3d_shader_scan_combined_sampler_declaration(
&semantic->resource.range, semantic->resource_type, VKD3D_SHADER_RESOURCE_DATA_FLOAT);
}
+static const struct vkd3d_shader_descriptor_info1 *find_descriptor(
+ const struct vkd3d_shader_scan_descriptor_info1 *info,
+ enum vkd3d_shader_descriptor_type type, unsigned int register_id)
+{
+ for (unsigned int i = 0; i < info->descriptor_count; ++i)
+ {
+ const struct vkd3d_shader_descriptor_info1 *d = &info->descriptors[i];
+
+ if (d->type == type && d->register_id == register_id)
+ return d;
+ }
+
+ return NULL;
+}
+
static void vkd3d_shader_scan_combined_sampler_usage(struct vkd3d_shader_scan_context *context,
const struct vkd3d_shader_register *resource, const struct vkd3d_shader_register *sampler)
{
@@ -913,7 +968,6 @@ static void vkd3d_shader_scan_combined_sampler_usage(struct vkd3d_shader_scan_co
if (vkd3d_shader_ver_ge(context->version, 5, 1))
{
- const struct vkd3d_shader_scan_descriptor_info1 *info = context->scan_descriptor_info;
const struct vkd3d_shader_descriptor_info1 *d;
bool dynamic_resource, dynamic_sampler;
@@ -928,30 +982,13 @@ static void vkd3d_shader_scan_combined_sampler_usage(struct vkd3d_shader_scan_co
if (dynamic_resource || dynamic_sampler)
return;
- for (i = 0; i < info->descriptor_count; ++i)
- {
- d = &info->descriptors[i];
- if (d->type != VKD3D_SHADER_DESCRIPTOR_TYPE_SRV)
- continue;
- if (d->register_id != resource->idx[0].offset)
- continue;
+ if ((d = find_descriptor(context->scan_descriptor_info,
+ VKD3D_SHADER_DESCRIPTOR_TYPE_SRV, resource->idx[0].offset)))
resource_space = d->register_space;
- break;
- }
- if (sampler)
- {
- for (i = 0; i < info->descriptor_count; ++i)
- {
- d = &info->descriptors[i];
- if (d->type != VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER)
- continue;
- if (d->register_id != sampler->idx[0].offset)
- continue;
- sampler_space = d->register_space;
- break;
- }
- }
+ if (sampler && (d = find_descriptor(context->scan_descriptor_info,
+ VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER, sampler->idx[0].offset)))
+ sampler_space = d->register_space;
}
for (i = 0; i < info->combined_sampler_count; ++i)
@@ -979,7 +1016,7 @@ static void vkd3d_shader_scan_combined_sampler_usage(struct vkd3d_shader_scan_co
static void vkd3d_shader_scan_resource_declaration(struct vkd3d_shader_scan_context *context,
const struct vkd3d_shader_resource *resource, enum vkd3d_shader_resource_type resource_type,
enum vkd3d_shader_resource_data_type resource_data_type,
- unsigned int sample_count, unsigned int structure_stride, bool raw)
+ unsigned int sample_count, unsigned int structure_stride, bool raw, uint32_t flags)
{
struct vkd3d_shader_descriptor_info1 *d;
enum vkd3d_shader_descriptor_type type;
@@ -995,6 +1032,8 @@ static void vkd3d_shader_scan_resource_declaration(struct vkd3d_shader_scan_cont
d->structure_stride = structure_stride;
if (raw)
d->flags |= VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_RAW_BUFFER;
+ if (type == VKD3D_SHADER_DESCRIPTOR_TYPE_UAV)
+ d->uav_flags = flags;
}
static void vkd3d_shader_scan_typed_resource_declaration(struct vkd3d_shader_scan_context *context,
@@ -1053,7 +1092,7 @@ static void vkd3d_shader_scan_typed_resource_declaration(struct vkd3d_shader_sca
}
vkd3d_shader_scan_resource_declaration(context, &semantic->resource,
- semantic->resource_type, resource_data_type, semantic->sample_count, 0, false);
+ semantic->resource_type, resource_data_type, semantic->sample_count, 0, false, instruction->flags);
}
static int vkd3d_shader_scan_instruction(struct vkd3d_shader_scan_context *context,
@@ -1074,6 +1113,9 @@ static int vkd3d_shader_scan_instruction(struct vkd3d_shader_scan_context *conte
vkd3d_shader_scan_sampler_declaration(context, instruction);
break;
case VKD3DSIH_DCL:
+ if (instruction->declaration.semantic.resource_type == VKD3D_SHADER_RESOURCE_NONE)
+ break;
+
if (instruction->declaration.semantic.resource.reg.reg.type == VKD3DSPR_COMBINED_SAMPLER)
{
vkd3d_shader_scan_combined_sampler_declaration(context, &instruction->declaration.semantic);
@@ -1086,15 +1128,16 @@ static int vkd3d_shader_scan_instruction(struct vkd3d_shader_scan_context *conte
case VKD3DSIH_DCL_RESOURCE_RAW:
case VKD3DSIH_DCL_UAV_RAW:
vkd3d_shader_scan_resource_declaration(context, &instruction->declaration.raw_resource.resource,
- VKD3D_SHADER_RESOURCE_BUFFER, VKD3D_SHADER_RESOURCE_DATA_UINT, 0, 0, true);
+ VKD3D_SHADER_RESOURCE_BUFFER, VKD3D_SHADER_RESOURCE_DATA_UINT, 0, 0, true, instruction->flags);
break;
case VKD3DSIH_DCL_RESOURCE_STRUCTURED:
case VKD3DSIH_DCL_UAV_STRUCTURED:
vkd3d_shader_scan_resource_declaration(context, &instruction->declaration.structured_resource.resource,
VKD3D_SHADER_RESOURCE_BUFFER, VKD3D_SHADER_RESOURCE_DATA_UINT, 0,
- instruction->declaration.structured_resource.byte_stride, false);
+ instruction->declaration.structured_resource.byte_stride, false, instruction->flags);
break;
case VKD3DSIH_IF:
+ case VKD3DSIH_IFC:
cf_info = vkd3d_shader_scan_push_cf_info(context);
cf_info->type = VKD3D_SHADER_BLOCK_IF;
cf_info->inside_block = true;
@@ -1361,17 +1404,15 @@ static int scan_with_parser(const struct vkd3d_shader_compile_info *compile_info
descriptor_info1 = &local_descriptor_info1;
}
- vkd3d_shader_scan_context_init(&context, &parser->shader_version, compile_info,
+ vkd3d_shader_scan_context_init(&context, &parser->program.shader_version, compile_info,
descriptor_info1, combined_sampler_info, message_context);
if (TRACE_ON())
- {
- vkd3d_shader_trace(&parser->instructions, &parser->shader_version);
- }
+ vkd3d_shader_trace(&parser->program);
- for (i = 0; i < parser->instructions.count; ++i)
+ for (i = 0; i < parser->program.instructions.count; ++i)
{
- instruction = &parser->instructions.elements[i];
+ instruction = &parser->program.instructions.elements[i];
if ((ret = vkd3d_shader_scan_instruction(&context, instruction)) < 0)
break;
}
@@ -1541,17 +1582,16 @@ static int vkd3d_shader_parser_compile(struct vkd3d_shader_parser *parser,
scan_info = *compile_info;
- if ((ret = scan_with_parser(&scan_info, message_context, &scan_descriptor_info, parser)) < 0)
- return ret;
-
switch (compile_info->target_type)
{
case VKD3D_SHADER_TARGET_D3D_ASM:
- ret = vkd3d_dxbc_binary_to_text(&parser->instructions, &parser->shader_version, compile_info, out);
+ ret = vkd3d_dxbc_binary_to_text(&parser->program, compile_info, out, VSIR_ASM_D3D);
break;
case VKD3D_SHADER_TARGET_GLSL:
- if (!(glsl_generator = vkd3d_glsl_generator_create(&parser->shader_version,
+ if ((ret = scan_with_parser(&scan_info, message_context, &scan_descriptor_info, parser)) < 0)
+ return ret;
+ if (!(glsl_generator = vkd3d_glsl_generator_create(&parser->program.shader_version,
message_context, &parser->location)))
{
ERR("Failed to create GLSL generator.\n");
@@ -1559,21 +1599,24 @@ static int vkd3d_shader_parser_compile(struct vkd3d_shader_parser *parser,
return VKD3D_ERROR;
}
- ret = vkd3d_glsl_generator_generate(glsl_generator, parser, out);
+ ret = vkd3d_glsl_generator_generate(glsl_generator, &parser->program, out);
vkd3d_glsl_generator_destroy(glsl_generator);
+ vkd3d_shader_free_scan_descriptor_info1(&scan_descriptor_info);
break;
case VKD3D_SHADER_TARGET_SPIRV_BINARY:
case VKD3D_SHADER_TARGET_SPIRV_TEXT:
+ if ((ret = scan_with_parser(&scan_info, message_context, &scan_descriptor_info, parser)) < 0)
+ return ret;
ret = spirv_compile(parser, &scan_descriptor_info, compile_info, out, message_context);
+ vkd3d_shader_free_scan_descriptor_info1(&scan_descriptor_info);
break;
default:
/* Validation should prevent us from reaching this. */
- assert(0);
+ vkd3d_unreachable();
}
- vkd3d_shader_free_scan_descriptor_info1(&scan_descriptor_info);
return ret;
}
@@ -1622,14 +1665,10 @@ static int compile_d3d_bytecode(const struct vkd3d_shader_compile_info *compile_
return ret;
}
- if (compile_info->target_type == VKD3D_SHADER_TARGET_D3D_ASM)
- {
- ret = vkd3d_dxbc_binary_to_text(&parser->instructions, &parser->shader_version, compile_info, out);
- vkd3d_shader_parser_destroy(parser);
- return ret;
- }
+ ret = vkd3d_shader_parser_compile(parser, compile_info, out, message_context);
- return VKD3D_ERROR;
+ vkd3d_shader_parser_destroy(parser);
+ return ret;
}
static int compile_dxbc_dxil(const struct vkd3d_shader_compile_info *compile_info,
@@ -1903,10 +1942,15 @@ const enum vkd3d_shader_target_type *vkd3d_shader_get_supported_target_types(
{
VKD3D_SHADER_TARGET_D3D_BYTECODE,
VKD3D_SHADER_TARGET_DXBC_TPF,
+ VKD3D_SHADER_TARGET_FX,
};
static const enum vkd3d_shader_target_type d3dbc_types[] =
{
+ VKD3D_SHADER_TARGET_SPIRV_BINARY,
+#ifdef HAVE_SPIRV_TOOLS
+ VKD3D_SHADER_TARGET_SPIRV_TEXT,
+#endif
VKD3D_SHADER_TARGET_D3D_ASM,
};
@@ -2043,6 +2087,23 @@ bool shader_instruction_array_reserve(struct vkd3d_shader_instruction_array *ins
return true;
}
+bool shader_instruction_array_insert_at(struct vkd3d_shader_instruction_array *instructions,
+ unsigned int idx, unsigned int count)
+{
+ assert(idx <= instructions->count);
+
+ if (!shader_instruction_array_reserve(instructions, instructions->count + count))
+ return false;
+
+ memmove(&instructions->elements[idx + count], &instructions->elements[idx],
+ (instructions->count - idx) * sizeof(*instructions->elements));
+ memset(&instructions->elements[idx], 0, count * sizeof(*instructions->elements));
+
+ instructions->count += count;
+
+ return true;
+}
+
bool shader_instruction_array_add_icb(struct vkd3d_shader_instruction_array *instructions,
struct vkd3d_shader_immediate_constant_buffer *icb)
{
diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h
index a93fa7160f7..acfd39b7643 100644
--- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h
+++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h
@@ -91,13 +91,15 @@ enum vkd3d_shader_error
VKD3D_SHADER_ERROR_SPV_INVALID_REGISTER_TYPE = 2001,
VKD3D_SHADER_ERROR_SPV_INVALID_DESCRIPTOR_BINDING = 2002,
VKD3D_SHADER_ERROR_SPV_DESCRIPTOR_IDX_UNSUPPORTED = 2003,
- VKD3D_SHADER_ERROR_SPV_STENCIL_EXPORT_UNSUPPORTED = 2004,
+ VKD3D_SHADER_ERROR_SPV_UNSUPPORTED_FEATURE = 2004,
VKD3D_SHADER_ERROR_SPV_OUT_OF_MEMORY = 2005,
VKD3D_SHADER_ERROR_SPV_INVALID_TYPE = 2006,
VKD3D_SHADER_ERROR_SPV_INVALID_HANDLER = 2007,
VKD3D_SHADER_ERROR_SPV_NOT_IMPLEMENTED = 2008,
+ VKD3D_SHADER_ERROR_SPV_INVALID_SHADER = 2009,
VKD3D_SHADER_WARNING_SPV_INVALID_SWIZZLE = 2300,
+ VKD3D_SHADER_WARNING_SPV_INVALID_UAV_FLAGS = 2301,
VKD3D_SHADER_ERROR_RS_OUT_OF_MEMORY = 3000,
VKD3D_SHADER_ERROR_RS_INVALID_VERSION = 3001,
@@ -196,6 +198,7 @@ enum vkd3d_shader_error
VKD3D_SHADER_WARNING_DXIL_ENTRY_POINT_MISMATCH = 8306,
VKD3D_SHADER_WARNING_DXIL_INVALID_MASK = 8307,
VKD3D_SHADER_WARNING_DXIL_INVALID_OPERATION = 8308,
+ VKD3D_SHADER_WARNING_DXIL_IGNORING_ATTACHMENT = 8309,
VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED = 9000,
VKD3D_SHADER_ERROR_VSIR_INVALID_HANDLER = 9001,
@@ -213,7 +216,8 @@ enum vkd3d_shader_error
VKD3D_SHADER_ERROR_VSIR_DUPLICATE_DCL_TEMPS = 9013,
VKD3D_SHADER_ERROR_VSIR_INVALID_DCL_TEMPS = 9014,
VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX = 9015,
- VKD3D_SHADER_ERROR_VSIR_INVALID_INSTRUCTION_NESTING = 9016,
+ VKD3D_SHADER_ERROR_VSIR_INVALID_CONTROL_FLOW = 9016,
+ VKD3D_SHADER_ERROR_VSIR_INVALID_SSA_USAGE = 9017,
VKD3D_SHADER_WARNING_VSIR_DYNAMIC_DESCRIPTOR_ARRAY = 9300,
};
@@ -221,8 +225,11 @@ enum vkd3d_shader_error
enum vkd3d_shader_opcode
{
VKD3DSIH_ABS,
+ VKD3DSIH_ACOS,
VKD3DSIH_ADD,
VKD3DSIH_AND,
+ VKD3DSIH_ASIN,
+ VKD3DSIH_ATAN,
VKD3DSIH_ATOMIC_AND,
VKD3DSIH_ATOMIC_CMP_STORE,
VKD3DSIH_ATOMIC_IADD,
@@ -235,6 +242,7 @@ enum vkd3d_shader_opcode
VKD3DSIH_BEM,
VKD3DSIH_BFI,
VKD3DSIH_BFREV,
+ VKD3DSIH_BRANCH,
VKD3DSIH_BREAK,
VKD3DSIH_BREAKC,
VKD3DSIH_BREAKP,
@@ -358,10 +366,13 @@ enum vkd3d_shader_opcode
VKD3DSIH_GATHER4_S,
VKD3DSIH_GEO,
VKD3DSIH_GEU,
+ VKD3DSIH_HCOS,
VKD3DSIH_HS_CONTROL_POINT_PHASE,
VKD3DSIH_HS_DECLS,
VKD3DSIH_HS_FORK_PHASE,
VKD3DSIH_HS_JOIN_PHASE,
+ VKD3DSIH_HSIN,
+ VKD3DSIH_HTAN,
VKD3DSIH_IADD,
VKD3DSIH_IBFE,
VKD3DSIH_IDIV,
@@ -388,8 +399,11 @@ enum vkd3d_shader_opcode
VKD3DSIH_IMUL,
VKD3DSIH_INE,
VKD3DSIH_INEG,
+ VKD3DSIH_ISFINITE,
VKD3DSIH_ISHL,
VKD3DSIH_ISHR,
+ VKD3DSIH_ISINF,
+ VKD3DSIH_ISNAN,
VKD3DSIH_ITOD,
VKD3DSIH_ITOF,
VKD3DSIH_ITOI,
@@ -432,6 +446,7 @@ enum vkd3d_shader_opcode
VKD3DSIH_NRM,
VKD3DSIH_OR,
VKD3DSIH_PHASE,
+ VKD3DSIH_PHI,
VKD3DSIH_POW,
VKD3DSIH_RCP,
VKD3DSIH_REP,
@@ -469,7 +484,9 @@ enum vkd3d_shader_opcode
VKD3DSIH_SUB,
VKD3DSIH_SWAPC,
VKD3DSIH_SWITCH,
+ VKD3DSIH_SWITCH_MONOLITHIC,
VKD3DSIH_SYNC,
+ VKD3DSIH_TAN,
VKD3DSIH_TEX,
VKD3DSIH_TEXBEM,
VKD3DSIH_TEXBEML,
@@ -618,6 +635,11 @@ static inline bool data_type_is_bool(enum vkd3d_data_type data_type)
return data_type == VKD3D_DATA_BOOL;
}
+static inline bool data_type_is_64_bit(enum vkd3d_data_type data_type)
+{
+ return data_type == VKD3D_DATA_DOUBLE || data_type == VKD3D_DATA_UINT64;
+}
+
enum vsir_dimension
{
VSIR_DIMENSION_NONE,
@@ -716,6 +738,7 @@ enum vkd3d_shader_sync_flags
{
VKD3DSSF_THREAD_GROUP = 0x1,
VKD3DSSF_GROUP_SHARED_MEMORY = 0x2,
+ VKD3DSSF_THREAD_GROUP_UAV = 0x4,
VKD3DSSF_GLOBAL_UAV = 0x8,
};
@@ -740,6 +763,7 @@ enum vkd3d_tessellator_domain
#define VKD3DSI_RESINFO_UINT 0x2
#define VKD3DSI_SAMPLE_INFO_UINT 0x1
#define VKD3DSI_SAMPLER_COMPARISON_MODE 0x1
+#define VKD3DSI_SHIFT_UNMASKED 0x1
#define VKD3DSI_PRECISE_X 0x100
#define VKD3DSI_PRECISE_Y 0x200
@@ -793,10 +817,12 @@ struct vkd3d_shader_version
struct vkd3d_shader_immediate_constant_buffer
{
+ unsigned int register_idx;
enum vkd3d_data_type data_type;
/* total count is element_count * component_count */
unsigned int element_count;
unsigned int component_count;
+ bool is_null;
uint32_t data[];
};
@@ -807,12 +833,13 @@ struct vkd3d_shader_indexable_temp
unsigned int alignment;
enum vkd3d_data_type data_type;
unsigned int component_count;
+ bool has_function_scope;
const struct vkd3d_shader_immediate_constant_buffer *initialiser;
};
struct vkd3d_shader_register_index
{
- const struct vkd3d_shader_src_param *rel_addr;
+ struct vkd3d_shader_src_param *rel_addr;
unsigned int offset;
/* address is known to fall within the object (for optimisation) */
bool is_in_bounds;
@@ -831,10 +858,10 @@ struct vkd3d_shader_register
unsigned int alignment;
union
{
- DWORD immconst_uint[VKD3D_VEC4_SIZE];
- float immconst_float[VKD3D_VEC4_SIZE];
- uint64_t immconst_uint64[VKD3D_DVEC2_SIZE];
- double immconst_double[VKD3D_DVEC2_SIZE];
+ uint32_t immconst_u32[VKD3D_VEC4_SIZE];
+ float immconst_f32[VKD3D_VEC4_SIZE];
+ uint64_t immconst_u64[VKD3D_DVEC2_SIZE];
+ double immconst_f64[VKD3D_DVEC2_SIZE];
unsigned fp_body_idx;
} u;
};
@@ -861,17 +888,23 @@ struct vkd3d_shader_dst_param
{
struct vkd3d_shader_register reg;
uint32_t write_mask;
- DWORD modifiers;
- DWORD shift;
+ uint32_t modifiers;
+ unsigned int shift;
};
struct vkd3d_shader_src_param
{
struct vkd3d_shader_register reg;
- DWORD swizzle;
+ uint32_t swizzle;
enum vkd3d_shader_src_modifier modifiers;
};
+void vsir_src_param_init(struct vkd3d_shader_src_param *param, enum vkd3d_shader_register_type reg_type,
+ enum vkd3d_data_type data_type, unsigned int idx_count);
+void vsir_dst_param_init(struct vkd3d_shader_dst_param *param, enum vkd3d_shader_register_type reg_type,
+ enum vkd3d_data_type data_type, unsigned int idx_count);
+void vsir_src_param_init_label(struct vkd3d_shader_src_param *param, unsigned int label_id);
+
struct vkd3d_shader_index_range
{
struct vkd3d_shader_dst_param dst;
@@ -945,6 +978,9 @@ enum vkd3d_shader_input_sysval_semantic
VKD3D_SIV_LINE_DENSITY_TESS_FACTOR = 22,
};
+#define SM1_COLOR_REGISTER_OFFSET 8
+#define SM1_RASTOUT_REGISTER_OFFSET 10
+
#define SIGNATURE_TARGET_LOCATION_UNUSED (~0u)
struct signature_element
@@ -998,17 +1034,10 @@ struct vkd3d_shader_desc
struct shader_signature output_signature;
struct shader_signature patch_constant_signature;
- unsigned int input_control_point_count, output_control_point_count;
-
- uint32_t temp_count;
- unsigned int ssa_count;
-
struct
{
uint32_t used, external;
} flat_constant_count[3];
-
- bool use_vocp;
};
struct vkd3d_shader_register_semantic
@@ -1110,11 +1139,11 @@ struct vkd3d_shader_instruction
{
struct vkd3d_shader_location location;
enum vkd3d_shader_opcode handler_idx;
- DWORD flags;
+ uint32_t flags;
unsigned int dst_count;
unsigned int src_count;
- const struct vkd3d_shader_dst_param *dst;
- const struct vkd3d_shader_src_param *src;
+ struct vkd3d_shader_dst_param *dst;
+ struct vkd3d_shader_src_param *src;
struct vkd3d_shader_texel_offset texel_offset;
enum vkd3d_shader_resource_type resource_type;
unsigned int resource_stride;
@@ -1171,6 +1200,32 @@ static inline bool register_is_constant(const struct vkd3d_shader_register *reg)
return (reg->type == VKD3DSPR_IMMCONST || reg->type == VKD3DSPR_IMMCONST64);
}
+static inline bool register_is_undef(const struct vkd3d_shader_register *reg)
+{
+ return reg->type == VKD3DSPR_UNDEF;
+}
+
+static inline bool register_is_constant_or_undef(const struct vkd3d_shader_register *reg)
+{
+ return register_is_constant(reg) || register_is_undef(reg);
+}
+
+static inline bool register_is_scalar_constant_zero(const struct vkd3d_shader_register *reg)
+{
+ return register_is_constant(reg) && reg->dimension == VSIR_DIMENSION_SCALAR
+ && (data_type_is_64_bit(reg->data_type) ? !reg->u.immconst_u64[0] : !reg->u.immconst_u32[0]);
+}
+
+static inline bool vsir_register_is_label(const struct vkd3d_shader_register *reg)
+{
+ return reg->type == VKD3DSPR_LABEL;
+}
+
+static inline bool register_is_ssa(const struct vkd3d_shader_register *reg)
+{
+ return reg->type == VKD3DSPR_SSA;
+}
+
struct vkd3d_shader_param_node
{
struct vkd3d_shader_param_node *next;
@@ -1217,6 +1272,8 @@ struct vkd3d_shader_instruction_array
bool shader_instruction_array_init(struct vkd3d_shader_instruction_array *instructions, unsigned int reserve);
bool shader_instruction_array_reserve(struct vkd3d_shader_instruction_array *instructions, unsigned int reserve);
+bool shader_instruction_array_insert_at(struct vkd3d_shader_instruction_array *instructions,
+ unsigned int idx, unsigned int count);
bool shader_instruction_array_add_icb(struct vkd3d_shader_instruction_array *instructions,
struct vkd3d_shader_immediate_constant_buffer *icb);
bool shader_instruction_array_clone_instruction(struct vkd3d_shader_instruction_array *instructions,
@@ -1228,6 +1285,36 @@ enum vkd3d_shader_config_flags
VKD3D_SHADER_CONFIG_FLAG_FORCE_VALIDATION = 0x00000001,
};
+struct vsir_program
+{
+ struct vkd3d_shader_version shader_version;
+ struct vkd3d_shader_instruction_array instructions;
+
+ unsigned int input_control_point_count, output_control_point_count;
+ unsigned int block_count;
+ unsigned int temp_count;
+ unsigned int ssa_count;
+ bool use_vocp;
+
+ const char **block_names;
+ size_t block_name_count;
+};
+
+bool vsir_program_init(struct vsir_program *program, const struct vkd3d_shader_version *version, unsigned int reserve);
+void vsir_program_cleanup(struct vsir_program *program);
+
+static inline struct vkd3d_shader_dst_param *vsir_program_get_dst_params(
+ struct vsir_program *program, unsigned int count)
+{
+ return shader_dst_param_allocator_get(&program->instructions.dst_params, count);
+}
+
+static inline struct vkd3d_shader_src_param *vsir_program_get_src_params(
+ struct vsir_program *program, unsigned int count)
+{
+ return shader_src_param_allocator_get(&program->instructions.src_params, count);
+}
+
struct vkd3d_shader_parser
{
struct vkd3d_shader_message_context *message_context;
@@ -1235,9 +1322,8 @@ struct vkd3d_shader_parser
bool failed;
struct vkd3d_shader_desc shader_desc;
- struct vkd3d_shader_version shader_version;
const struct vkd3d_shader_parser_ops *ops;
- struct vkd3d_shader_instruction_array instructions;
+ struct vsir_program program;
uint64_t config_flags;
};
@@ -1256,18 +1342,6 @@ bool vkd3d_shader_parser_init(struct vkd3d_shader_parser *parser,
void vkd3d_shader_parser_warning(struct vkd3d_shader_parser *parser,
enum vkd3d_shader_error error, const char *format, ...) VKD3D_PRINTF_FUNC(3, 4);
-static inline struct vkd3d_shader_dst_param *shader_parser_get_dst_params(
- struct vkd3d_shader_parser *parser, unsigned int count)
-{
- return shader_dst_param_allocator_get(&parser->instructions.dst_params, count);
-}
-
-static inline struct vkd3d_shader_src_param *shader_parser_get_src_params(
- struct vkd3d_shader_parser *parser, unsigned int count)
-{
- return shader_src_param_allocator_get(&parser->instructions.src_params, count);
-}
-
static inline void vkd3d_shader_parser_destroy(struct vkd3d_shader_parser *parser)
{
parser->ops->parser_destroy(parser);
@@ -1286,6 +1360,7 @@ struct vkd3d_shader_descriptor_info1
unsigned int buffer_size;
unsigned int structure_stride;
unsigned int count;
+ uint32_t uav_flags;
};
struct vkd3d_shader_scan_descriptor_info1
@@ -1294,8 +1369,7 @@ struct vkd3d_shader_scan_descriptor_info1
unsigned int descriptor_count;
};
-void vkd3d_shader_trace(const struct vkd3d_shader_instruction_array *instructions,
- const struct vkd3d_shader_version *shader_version);
+void vkd3d_shader_trace(const struct vsir_program *program);
const char *shader_get_type_prefix(enum vkd3d_shader_type type);
@@ -1311,9 +1385,15 @@ struct vkd3d_string_buffer_cache
size_t count, max_count, capacity;
};
-enum vkd3d_result vkd3d_dxbc_binary_to_text(const struct vkd3d_shader_instruction_array *instructions,
- const struct vkd3d_shader_version *shader_version, const struct vkd3d_shader_compile_info *compile_info,
- struct vkd3d_shader_code *out);
+enum vsir_asm_dialect
+{
+ VSIR_ASM_VSIR,
+ VSIR_ASM_D3D,
+};
+
+enum vkd3d_result vkd3d_dxbc_binary_to_text(const struct vsir_program *program,
+ const struct vkd3d_shader_compile_info *compile_info,
+ struct vkd3d_shader_code *out, enum vsir_asm_dialect dialect);
void vkd3d_string_buffer_cleanup(struct vkd3d_string_buffer *buffer);
struct vkd3d_string_buffer *vkd3d_string_buffer_get(struct vkd3d_string_buffer_cache *list);
void vkd3d_string_buffer_init(struct vkd3d_string_buffer *buffer);
@@ -1338,7 +1418,9 @@ struct vkd3d_bytecode_buffer
/* Align to the next 4-byte offset, and return that offset. */
size_t bytecode_align(struct vkd3d_bytecode_buffer *buffer);
size_t bytecode_put_bytes(struct vkd3d_bytecode_buffer *buffer, const void *bytes, size_t size);
+size_t bytecode_reserve_bytes(struct vkd3d_bytecode_buffer *buffer, size_t size);
void set_u32(struct vkd3d_bytecode_buffer *buffer, size_t offset, uint32_t value);
+void set_string(struct vkd3d_bytecode_buffer *buffer, size_t offset, const char *string, size_t length);
static inline size_t put_u32(struct vkd3d_bytecode_buffer *buffer, uint32_t value)
{
@@ -1382,6 +1464,8 @@ void vkd3d_shader_verror(struct vkd3d_shader_message_context *context, const str
enum vkd3d_shader_error error, const char *format, va_list args);
void vkd3d_shader_vnote(struct vkd3d_shader_message_context *context, const struct vkd3d_shader_location *location,
enum vkd3d_shader_log_level level, const char *format, va_list args);
+void vkd3d_shader_warning(struct vkd3d_shader_message_context *context, const struct vkd3d_shader_location *location,
+ enum vkd3d_shader_error error, const char *format, ...) VKD3D_PRINTF_FUNC(4, 5);
void vkd3d_shader_vwarning(struct vkd3d_shader_message_context *context, const struct vkd3d_shader_location *location,
enum vkd3d_shader_error error, const char *format, va_list args);
@@ -1409,7 +1493,7 @@ struct vkd3d_glsl_generator;
struct vkd3d_glsl_generator *vkd3d_glsl_generator_create(const struct vkd3d_shader_version *version,
struct vkd3d_shader_message_context *message_context, const struct vkd3d_shader_location *location);
int vkd3d_glsl_generator_generate(struct vkd3d_glsl_generator *generator,
- struct vkd3d_shader_parser *parser, struct vkd3d_shader_code *out);
+ struct vsir_program *program, struct vkd3d_shader_code *out);
void vkd3d_glsl_generator_destroy(struct vkd3d_glsl_generator *generator);
#define SPIRV_MAX_SRC_COUNT 6
@@ -1427,7 +1511,7 @@ int preproc_lexer_parse(const struct vkd3d_shader_compile_info *compile_info,
int hlsl_compile_shader(const struct vkd3d_shader_code *hlsl, const struct vkd3d_shader_compile_info *compile_info,
struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context);
-void vsir_validate(struct vkd3d_shader_parser *parser);
+enum vkd3d_result vsir_validate(struct vkd3d_shader_parser *parser);
static inline enum vkd3d_shader_component_type vkd3d_component_type_from_data_type(
enum vkd3d_data_type data_type)
@@ -1444,6 +1528,8 @@ static inline enum vkd3d_shader_component_type vkd3d_component_type_from_data_ty
return VKD3D_SHADER_COMPONENT_INT;
case VKD3D_DATA_DOUBLE:
return VKD3D_SHADER_COMPONENT_DOUBLE;
+ case VKD3D_DATA_UINT64:
+ return VKD3D_SHADER_COMPONENT_UINT64;
case VKD3D_DATA_BOOL:
return VKD3D_SHADER_COMPONENT_BOOL;
default:
@@ -1505,7 +1591,7 @@ static inline enum vkd3d_shader_input_sysval_semantic vkd3d_siv_from_sysval(enum
return vkd3d_siv_from_sysval_indexed(sysval, 0);
}
-static inline unsigned int vkd3d_write_mask_get_component_idx(DWORD write_mask)
+static inline unsigned int vsir_write_mask_get_component_idx(uint32_t write_mask)
{
unsigned int i;
@@ -1520,7 +1606,7 @@ static inline unsigned int vkd3d_write_mask_get_component_idx(DWORD write_mask)
return 0;
}
-static inline unsigned int vkd3d_write_mask_component_count(DWORD write_mask)
+static inline unsigned int vsir_write_mask_component_count(uint32_t write_mask)
{
unsigned int count = vkd3d_popcount(write_mask & VKD3DSP_WRITEMASK_ALL);
assert(1 <= count && count <= VKD3D_VEC4_SIZE);
@@ -1533,32 +1619,94 @@ static inline unsigned int vkd3d_write_mask_from_component_count(unsigned int co
return (VKD3DSP_WRITEMASK_0 << component_count) - 1;
}
-static inline unsigned int vkd3d_write_mask_64_from_32(DWORD write_mask32)
+static inline uint32_t vsir_write_mask_64_from_32(uint32_t write_mask32)
{
- unsigned int write_mask64 = write_mask32 | (write_mask32 >> 1);
- return (write_mask64 & VKD3DSP_WRITEMASK_0) | ((write_mask64 & VKD3DSP_WRITEMASK_2) >> 1);
+ switch (write_mask32)
+ {
+ case VKD3DSP_WRITEMASK_0 | VKD3DSP_WRITEMASK_1:
+ return VKD3DSP_WRITEMASK_0;
+
+ case VKD3DSP_WRITEMASK_2 | VKD3DSP_WRITEMASK_3:
+ return VKD3DSP_WRITEMASK_1;
+
+ case VKD3DSP_WRITEMASK_0 | VKD3DSP_WRITEMASK_1 | VKD3DSP_WRITEMASK_2 | VKD3DSP_WRITEMASK_3:
+ return VKD3DSP_WRITEMASK_0 | VKD3DSP_WRITEMASK_1;
+
+ default:
+ ERR("Invalid 32 bit writemask when converting to 64 bit: %#x.\n", write_mask32);
+ return VKD3DSP_WRITEMASK_0;
+ }
}
-static inline unsigned int vkd3d_write_mask_32_from_64(unsigned int write_mask64)
+static inline uint32_t vsir_write_mask_32_from_64(uint32_t write_mask64)
{
- unsigned int write_mask32 = (write_mask64 | (write_mask64 << 1))
- & (VKD3DSP_WRITEMASK_0 | VKD3DSP_WRITEMASK_2);
- return write_mask32 | (write_mask32 << 1);
+ switch (write_mask64)
+ {
+ case VKD3DSP_WRITEMASK_0:
+ return VKD3DSP_WRITEMASK_0 | VKD3DSP_WRITEMASK_1;
+
+ case VKD3DSP_WRITEMASK_1:
+ return VKD3DSP_WRITEMASK_2 | VKD3DSP_WRITEMASK_3;
+
+ case VKD3DSP_WRITEMASK_0 | VKD3DSP_WRITEMASK_1:
+ return VKD3DSP_WRITEMASK_0 | VKD3DSP_WRITEMASK_1 | VKD3DSP_WRITEMASK_2 | VKD3DSP_WRITEMASK_3;
+
+ default:
+ ERR("Invalid 64 bit writemask: %#x.\n", write_mask64);
+ return VKD3DSP_WRITEMASK_0;
+ }
}
-static inline unsigned int vkd3d_swizzle_get_component(DWORD swizzle,
- unsigned int idx)
+static inline uint32_t vsir_swizzle_64_from_32(uint32_t swizzle32)
{
- return (swizzle >> VKD3D_SHADER_SWIZZLE_SHIFT(idx)) & VKD3D_SHADER_SWIZZLE_MASK;
+ switch (swizzle32)
+ {
+ case VKD3D_SHADER_SWIZZLE(X, Y, X, Y):
+ return VKD3D_SHADER_SWIZZLE(X, X, X, X);
+
+ case VKD3D_SHADER_SWIZZLE(X, Y, Z, W):
+ return VKD3D_SHADER_SWIZZLE(X, Y, X, X);
+
+ case VKD3D_SHADER_SWIZZLE(Z, W, X, Y):
+ return VKD3D_SHADER_SWIZZLE(Y, X, X, X);
+
+ case VKD3D_SHADER_SWIZZLE(Z, W, Z, W):
+ return VKD3D_SHADER_SWIZZLE(Y, Y, X, X);
+
+ default:
+ ERR("Invalid 32 bit swizzle when converting to 64 bit: %#x.\n", swizzle32);
+ return VKD3D_SHADER_SWIZZLE(X, X, X, X);
+ }
}
-static inline unsigned int vkd3d_swizzle_get_component64(DWORD swizzle,
- unsigned int idx)
+static inline uint32_t vsir_swizzle_32_from_64(uint32_t swizzle64)
{
- return ((swizzle >> VKD3D_SHADER_SWIZZLE_SHIFT(idx * 2)) & VKD3D_SHADER_SWIZZLE_MASK) / 2u;
+ switch (swizzle64)
+ {
+ case VKD3D_SHADER_SWIZZLE(X, X, X, X):
+ return VKD3D_SHADER_SWIZZLE(X, Y, X, Y);
+
+ case VKD3D_SHADER_SWIZZLE(X, Y, X, X):
+ return VKD3D_SHADER_SWIZZLE(X, Y, Z, W);
+
+ case VKD3D_SHADER_SWIZZLE(Y, X, X, X):
+ return VKD3D_SHADER_SWIZZLE(Z, W, X, Y);
+
+ case VKD3D_SHADER_SWIZZLE(Y, Y, X, X):
+ return VKD3D_SHADER_SWIZZLE(Z, W, Z, W);
+
+ default:
+ ERR("Invalid 64 bit swizzle: %#x.\n", swizzle64);
+ return VKD3D_SHADER_SWIZZLE(X, Y, X, Y);
+ }
+}
+
+static inline unsigned int vsir_swizzle_get_component(uint32_t swizzle, unsigned int idx)
+{
+ return (swizzle >> VKD3D_SHADER_SWIZZLE_SHIFT(idx)) & VKD3D_SHADER_SWIZZLE_MASK;
}
-static inline unsigned int vkd3d_compact_swizzle(unsigned int swizzle, unsigned int write_mask)
+static inline unsigned int vkd3d_compact_swizzle(uint32_t swizzle, uint32_t write_mask)
{
unsigned int i, compacted_swizzle = 0;
@@ -1567,7 +1715,7 @@ static inline unsigned int vkd3d_compact_swizzle(unsigned int swizzle, unsigned
if (write_mask & (VKD3DSP_WRITEMASK_0 << i))
{
compacted_swizzle <<= VKD3D_SHADER_SWIZZLE_SHIFT(1);
- compacted_swizzle |= vkd3d_swizzle_get_component(swizzle, i);
+ compacted_swizzle |= vsir_swizzle_get_component(swizzle, i);
}
}
diff --git a/libs/vkd3d/libs/vkd3d/command.c b/libs/vkd3d/libs/vkd3d/command.c
index 15c8317b191..8a47dc494f7 100644
--- a/libs/vkd3d/libs/vkd3d/command.c
+++ b/libs/vkd3d/libs/vkd3d/command.c
@@ -313,7 +313,7 @@ static void vkd3d_wait_for_gpu_fence(struct vkd3d_fence_worker *worker,
TRACE("Signaling fence %p value %#"PRIx64".\n", waiting_fence->fence, waiting_fence->value);
if (FAILED(hr = d3d12_fence_signal(waiting_fence->fence, waiting_fence->value, waiting_fence->u.vk_fence, false)))
- ERR("Failed to signal D3D12 fence, hr %#x.\n", hr);
+ ERR("Failed to signal d3d12 fence, hr %s.\n", debugstr_hresult(hr));
d3d12_fence_decref(waiting_fence->fence);
@@ -926,7 +926,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_fence_QueryInterface(ID3D12Fence1 *iface,
static ULONG STDMETHODCALLTYPE d3d12_fence_AddRef(ID3D12Fence1 *iface)
{
struct d3d12_fence *fence = impl_from_ID3D12Fence1(iface);
- ULONG refcount = InterlockedIncrement(&fence->refcount);
+ unsigned int refcount = vkd3d_atomic_increment_u32(&fence->refcount);
TRACE("%p increasing refcount to %u.\n", fence, refcount);
@@ -935,13 +935,13 @@ static ULONG STDMETHODCALLTYPE d3d12_fence_AddRef(ID3D12Fence1 *iface)
static void d3d12_fence_incref(struct d3d12_fence *fence)
{
- InterlockedIncrement(&fence->internal_refcount);
+ vkd3d_atomic_increment_u32(&fence->internal_refcount);
}
static ULONG STDMETHODCALLTYPE d3d12_fence_Release(ID3D12Fence1 *iface)
{
struct d3d12_fence *fence = impl_from_ID3D12Fence1(iface);
- ULONG refcount = InterlockedDecrement(&fence->refcount);
+ unsigned int refcount = vkd3d_atomic_decrement_u32(&fence->refcount);
TRACE("%p decreasing refcount to %u.\n", fence, refcount);
@@ -953,24 +953,24 @@ static ULONG STDMETHODCALLTYPE d3d12_fence_Release(ID3D12Fence1 *iface)
static void d3d12_fence_decref(struct d3d12_fence *fence)
{
- ULONG internal_refcount = InterlockedDecrement(&fence->internal_refcount);
+ struct d3d12_device *device;
- if (!internal_refcount)
- {
- struct d3d12_device *device = fence->device;
+ if (vkd3d_atomic_decrement_u32(&fence->internal_refcount))
+ return;
- vkd3d_private_store_destroy(&fence->private_store);
+ device = fence->device;
- d3d12_fence_destroy_vk_objects(fence);
+ vkd3d_private_store_destroy(&fence->private_store);
- vkd3d_free(fence->events);
- vkd3d_free(fence->semaphores);
- vkd3d_mutex_destroy(&fence->mutex);
- vkd3d_cond_destroy(&fence->null_event_cond);
- vkd3d_free(fence);
+ d3d12_fence_destroy_vk_objects(fence);
- d3d12_device_release(device);
- }
+ vkd3d_free(fence->events);
+ vkd3d_free(fence->semaphores);
+ vkd3d_mutex_destroy(&fence->mutex);
+ vkd3d_cond_destroy(&fence->null_event_cond);
+ vkd3d_free(fence);
+
+ d3d12_device_release(device);
}
static HRESULT STDMETHODCALLTYPE d3d12_fence_GetPrivateData(ID3D12Fence1 *iface,
@@ -1635,7 +1635,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_command_allocator_QueryInterface(ID3D12Co
static ULONG STDMETHODCALLTYPE d3d12_command_allocator_AddRef(ID3D12CommandAllocator *iface)
{
struct d3d12_command_allocator *allocator = impl_from_ID3D12CommandAllocator(iface);
- ULONG refcount = InterlockedIncrement(&allocator->refcount);
+ unsigned int refcount = vkd3d_atomic_increment_u32(&allocator->refcount);
TRACE("%p increasing refcount to %u.\n", allocator, refcount);
@@ -1645,7 +1645,7 @@ static ULONG STDMETHODCALLTYPE d3d12_command_allocator_AddRef(ID3D12CommandAlloc
static ULONG STDMETHODCALLTYPE d3d12_command_allocator_Release(ID3D12CommandAllocator *iface)
{
struct d3d12_command_allocator *allocator = impl_from_ID3D12CommandAllocator(iface);
- ULONG refcount = InterlockedDecrement(&allocator->refcount);
+ unsigned int refcount = vkd3d_atomic_decrement_u32(&allocator->refcount);
TRACE("%p decreasing refcount to %u.\n", allocator, refcount);
@@ -1921,12 +1921,12 @@ HRESULT d3d12_command_allocator_create(struct d3d12_device *device,
static void d3d12_command_signature_incref(struct d3d12_command_signature *signature)
{
- vkd3d_atomic_increment(&signature->internal_refcount);
+ vkd3d_atomic_increment_u32(&signature->internal_refcount);
}
static void d3d12_command_signature_decref(struct d3d12_command_signature *signature)
{
- unsigned int refcount = vkd3d_atomic_decrement(&signature->internal_refcount);
+ unsigned int refcount = vkd3d_atomic_decrement_u32(&signature->internal_refcount);
if (!refcount)
{
@@ -2320,7 +2320,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_command_list_QueryInterface(ID3D12Graphic
static ULONG STDMETHODCALLTYPE d3d12_command_list_AddRef(ID3D12GraphicsCommandList5 *iface)
{
struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList5(iface);
- ULONG refcount = InterlockedIncrement(&list->refcount);
+ unsigned int refcount = vkd3d_atomic_increment_u32(&list->refcount);
TRACE("%p increasing refcount to %u.\n", list, refcount);
@@ -2335,7 +2335,7 @@ static void vkd3d_pipeline_bindings_cleanup(struct vkd3d_pipeline_bindings *bind
static ULONG STDMETHODCALLTYPE d3d12_command_list_Release(ID3D12GraphicsCommandList5 *iface)
{
struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList5(iface);
- ULONG refcount = InterlockedDecrement(&list->refcount);
+ unsigned int refcount = vkd3d_atomic_decrement_u32(&list->refcount);
TRACE("%p decreasing refcount to %u.\n", list, refcount);
@@ -2644,6 +2644,8 @@ static bool d3d12_command_list_update_compute_pipeline(struct d3d12_command_list
{
const struct vkd3d_vk_device_procs *vk_procs = &list->device->vk_procs;
+ vkd3d_cond_signal(&list->device->worker_cond);
+
if (list->current_pipeline != VK_NULL_HANDLE)
return true;
@@ -2665,6 +2667,8 @@ static bool d3d12_command_list_update_graphics_pipeline(struct d3d12_command_lis
VkRenderPass vk_render_pass;
VkPipeline vk_pipeline;
+ vkd3d_cond_signal(&list->device->worker_cond);
+
if (list->current_pipeline != VK_NULL_HANDLE)
return true;
@@ -3266,7 +3270,8 @@ static void d3d12_command_list_bind_descriptor_heap(struct d3d12_command_list *l
{
VkDescriptorSet vk_descriptor_set = heap->vk_descriptor_sets[set].vk_set;
- if (!vk_descriptor_set)
+ /* Null vk_set_layout means set 0 uses mutable descriptors, and this set is unused. */
+ if (!vk_descriptor_set || !list->device->vk_descriptor_heap_layouts[set].vk_set_layout)
continue;
VK_CALL(vkCmdBindDescriptorSets(list->vk_command_buffer, bindings->vk_bind_point, rs->vk_pipeline_layout,
@@ -3701,7 +3706,7 @@ static void d3d12_command_list_copy_incompatible_texture_region(struct d3d12_com
buffer_image_copy.imageExtent.height * buffer_image_copy.imageExtent.depth * layer_count;
if (FAILED(hr = d3d12_command_list_allocate_transfer_buffer(list, buffer_size, &transfer_buffer)))
{
- ERR("Failed to allocate transfer buffer, hr %#x.\n", hr);
+ ERR("Failed to allocate transfer buffer, hr %s.\n", debugstr_hresult(hr));
return;
}
@@ -4494,8 +4499,8 @@ static void STDMETHODCALLTYPE d3d12_command_list_SetComputeRootDescriptorTable(I
{
struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList5(iface);
- TRACE("iface %p, root_parameter_index %u, base_descriptor %#"PRIx64".\n",
- iface, root_parameter_index, base_descriptor.ptr);
+ TRACE("iface %p, root_parameter_index %u, base_descriptor %s.\n",
+ iface, root_parameter_index, debug_gpu_handle(base_descriptor));
d3d12_command_list_set_descriptor_table(list, VKD3D_PIPELINE_BIND_POINT_COMPUTE,
root_parameter_index, base_descriptor);
@@ -4506,8 +4511,8 @@ static void STDMETHODCALLTYPE d3d12_command_list_SetGraphicsRootDescriptorTable(
{
struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList5(iface);
- TRACE("iface %p, root_parameter_index %u, base_descriptor %#"PRIx64".\n",
- iface, root_parameter_index, base_descriptor.ptr);
+ TRACE("iface %p, root_parameter_index %u, base_descriptor %s.\n",
+ iface, root_parameter_index, debug_gpu_handle(base_descriptor));
d3d12_command_list_set_descriptor_table(list, VKD3D_PIPELINE_BIND_POINT_GRAPHICS,
root_parameter_index, base_descriptor);
@@ -5127,8 +5132,8 @@ static void STDMETHODCALLTYPE d3d12_command_list_ClearDepthStencilView(ID3D12Gra
struct VkAttachmentDescription attachment_desc;
struct VkAttachmentReference ds_reference;
- TRACE("iface %p, dsv %#lx, flags %#x, depth %.8e, stencil 0x%02x, rect_count %u, rects %p.\n",
- iface, dsv.ptr, flags, depth, stencil, rect_count, rects);
+ TRACE("iface %p, dsv %s, flags %#x, depth %.8e, stencil 0x%02x, rect_count %u, rects %p.\n",
+ iface, debug_cpu_handle(dsv), flags, depth, stencil, rect_count, rects);
d3d12_command_list_track_resource_usage(list, dsv_desc->resource);
@@ -5175,8 +5180,8 @@ static void STDMETHODCALLTYPE d3d12_command_list_ClearRenderTargetView(ID3D12Gra
struct VkAttachmentReference color_reference;
VkClearValue clear_value;
- TRACE("iface %p, rtv %#lx, color %p, rect_count %u, rects %p.\n",
- iface, rtv.ptr, color, rect_count, rects);
+ TRACE("iface %p, rtv %s, color %p, rect_count %u, rects %p.\n",
+ iface, debug_cpu_handle(rtv), color, rect_count, rects);
d3d12_command_list_track_resource_usage(list, rtv_desc->resource);
@@ -5427,8 +5432,8 @@ static void STDMETHODCALLTYPE d3d12_command_list_ClearUnorderedAccessViewUint(ID
struct d3d12_resource *resource_impl;
VkClearColorValue colour;
- TRACE("iface %p, gpu_handle %#"PRIx64", cpu_handle %lx, resource %p, values %p, rect_count %u, rects %p.\n",
- iface, gpu_handle.ptr, cpu_handle.ptr, resource, values, rect_count, rects);
+ TRACE("iface %p, gpu_handle %s, cpu_handle %s, resource %p, values %p, rect_count %u, rects %p.\n",
+ iface, debug_gpu_handle(gpu_handle), debug_cpu_handle(cpu_handle), resource, values, rect_count, rects);
resource_impl = unsafe_impl_from_ID3D12Resource(resource);
if (!(descriptor = d3d12_desc_from_cpu_handle(cpu_handle)->s.u.view))
@@ -5491,8 +5496,8 @@ static void STDMETHODCALLTYPE d3d12_command_list_ClearUnorderedAccessViewFloat(I
VkClearColorValue colour;
struct vkd3d_view *view;
- TRACE("iface %p, gpu_handle %#"PRIx64", cpu_handle %lx, resource %p, values %p, rect_count %u, rects %p.\n",
- iface, gpu_handle.ptr, cpu_handle.ptr, resource, values, rect_count, rects);
+ TRACE("iface %p, gpu_handle %s, cpu_handle %s, resource %p, values %p, rect_count %u, rects %p.\n",
+ iface, debug_gpu_handle(gpu_handle), debug_cpu_handle(cpu_handle), resource, values, rect_count, rects);
resource_impl = unsafe_impl_from_ID3D12Resource(resource);
if (!(view = d3d12_desc_from_cpu_handle(cpu_handle)->s.u.view))
@@ -5958,15 +5963,15 @@ static void STDMETHODCALLTYPE d3d12_command_list_EndRenderPass(ID3D12GraphicsCom
static void STDMETHODCALLTYPE d3d12_command_list_InitializeMetaCommand(ID3D12GraphicsCommandList5 *iface,
ID3D12MetaCommand *meta_command, const void *parameters_data, SIZE_T data_size_in_bytes)
{
- FIXME("iface %p, meta_command %p, parameters_data %p, data_size_in_bytes %lu stub!\n", iface,
- meta_command, parameters_data, data_size_in_bytes);
+ FIXME("iface %p, meta_command %p, parameters_data %p, data_size_in_bytes %"PRIuPTR" stub!\n", iface,
+ meta_command, parameters_data, (uintptr_t)data_size_in_bytes);
}
static void STDMETHODCALLTYPE d3d12_command_list_ExecuteMetaCommand(ID3D12GraphicsCommandList5 *iface,
ID3D12MetaCommand *meta_command, const void *parameters_data, SIZE_T data_size_in_bytes)
{
- FIXME("iface %p, meta_command %p, parameters_data %p, data_size_in_bytes %lu stub!\n", iface,
- meta_command, parameters_data, data_size_in_bytes);
+ FIXME("iface %p, meta_command %p, parameters_data %p, data_size_in_bytes %"PRIuPTR" stub!\n", iface,
+ meta_command, parameters_data, (uintptr_t)data_size_in_bytes);
}
static void STDMETHODCALLTYPE d3d12_command_list_BuildRaytracingAccelerationStructure(ID3D12GraphicsCommandList5 *iface,
@@ -6225,7 +6230,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_command_queue_QueryInterface(ID3D12Comman
static ULONG STDMETHODCALLTYPE d3d12_command_queue_AddRef(ID3D12CommandQueue *iface)
{
struct d3d12_command_queue *command_queue = impl_from_ID3D12CommandQueue(iface);
- ULONG refcount = InterlockedIncrement(&command_queue->refcount);
+ unsigned int refcount = vkd3d_atomic_increment_u32(&command_queue->refcount);
TRACE("%p increasing refcount to %u.\n", command_queue, refcount);
@@ -6267,7 +6272,7 @@ static void d3d12_command_queue_op_array_destroy(struct d3d12_command_queue_op_a
static ULONG STDMETHODCALLTYPE d3d12_command_queue_Release(ID3D12CommandQueue *iface)
{
struct d3d12_command_queue *command_queue = impl_from_ID3D12CommandQueue(iface);
- ULONG refcount = InterlockedDecrement(&command_queue->refcount);
+ unsigned int refcount = vkd3d_atomic_decrement_u32(&command_queue->refcount);
TRACE("%p decreasing refcount to %u.\n", command_queue, refcount);
@@ -6508,7 +6513,7 @@ static void STDMETHODCALLTYPE d3d12_command_queue_CopyTileMappings(ID3D12Command
if (!(op = d3d12_command_queue_op_array_require_space(&command_queue->op_queue)))
{
ERR("Failed to add op.\n");
- return;
+ goto unlock_mutex;
}
op->opcode = VKD3D_CS_OP_COPY_MAPPINGS;
op->u.copy_mappings.dst_resource = dst_resource_impl;
@@ -6520,6 +6525,7 @@ static void STDMETHODCALLTYPE d3d12_command_queue_CopyTileMappings(ID3D12Command
d3d12_command_queue_submit_locked(command_queue);
+unlock_mutex:
vkd3d_mutex_unlock(&command_queue->op_mutex);
}
@@ -6558,7 +6564,7 @@ static void d3d12_command_queue_submit_locked(struct d3d12_command_queue *queue)
if (queue->op_queue.count == 1 && !queue->is_flushing)
{
if (FAILED(hr = d3d12_command_queue_flush_ops_locked(queue, &flushed_any)))
- ERR("Cannot flush queue, hr %#x.\n", hr);
+ ERR("Failed to flush queue, hr %s.\n", debugstr_hresult(hr));
}
}
@@ -7436,7 +7442,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_command_signature_QueryInterface(ID3D12Co
static ULONG STDMETHODCALLTYPE d3d12_command_signature_AddRef(ID3D12CommandSignature *iface)
{
struct d3d12_command_signature *signature = impl_from_ID3D12CommandSignature(iface);
- ULONG refcount = InterlockedIncrement(&signature->refcount);
+ unsigned int refcount = vkd3d_atomic_increment_u32(&signature->refcount);
TRACE("%p increasing refcount to %u.\n", signature, refcount);
@@ -7446,7 +7452,7 @@ static ULONG STDMETHODCALLTYPE d3d12_command_signature_AddRef(ID3D12CommandSigna
static ULONG STDMETHODCALLTYPE d3d12_command_signature_Release(ID3D12CommandSignature *iface)
{
struct d3d12_command_signature *signature = impl_from_ID3D12CommandSignature(iface);
- ULONG refcount = InterlockedDecrement(&signature->refcount);
+ unsigned int refcount = vkd3d_atomic_decrement_u32(&signature->refcount);
TRACE("%p decreasing refcount to %u.\n", signature, refcount);
diff --git a/libs/vkd3d/libs/vkd3d/device.c b/libs/vkd3d/libs/vkd3d/device.c
index 5c801ca4676..90272818b3d 100644
--- a/libs/vkd3d/libs/vkd3d/device.c
+++ b/libs/vkd3d/libs/vkd3d/device.c
@@ -94,9 +94,11 @@ static const struct vkd3d_optional_extension_info optional_device_extensions[] =
VK_EXTENSION(EXT_DEBUG_MARKER, EXT_debug_marker),
VK_EXTENSION(EXT_DEPTH_CLIP_ENABLE, EXT_depth_clip_enable),
VK_EXTENSION(EXT_DESCRIPTOR_INDEXING, EXT_descriptor_indexing),
+ VK_EXTENSION(EXT_MUTABLE_DESCRIPTOR_TYPE, EXT_mutable_descriptor_type),
VK_EXTENSION(EXT_ROBUSTNESS_2, EXT_robustness2),
VK_EXTENSION(EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION, EXT_shader_demote_to_helper_invocation),
VK_EXTENSION(EXT_SHADER_STENCIL_EXPORT, EXT_shader_stencil_export),
+ VK_EXTENSION(EXT_SHADER_VIEWPORT_INDEX_LAYER, EXT_shader_viewport_index_layer),
VK_EXTENSION(EXT_TEXEL_BUFFER_ALIGNMENT, EXT_texel_buffer_alignment),
VK_EXTENSION(EXT_TRANSFORM_FEEDBACK, EXT_transform_feedback),
VK_EXTENSION(EXT_VERTEX_ATTRIBUTE_DIVISOR, EXT_vertex_attribute_divisor),
@@ -106,13 +108,32 @@ static HRESULT vkd3d_create_vk_descriptor_heap_layout(struct d3d12_device *devic
{
const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
VkDescriptorSetLayoutBindingFlagsCreateInfoEXT flags_info;
+ VkMutableDescriptorTypeCreateInfoEXT mutable_info;
+ VkMutableDescriptorTypeListEXT type_list;
VkDescriptorSetLayoutCreateInfo set_desc;
VkDescriptorBindingFlagsEXT set_flags;
VkDescriptorSetLayoutBinding binding;
VkResult vr;
+ static const VkDescriptorType descriptor_types[] =
+ {
+ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+ VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
+ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
+ VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
+ VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
+ };
+
+ if (device->vk_info.EXT_mutable_descriptor_type && index && index != VKD3D_SET_INDEX_UAV_COUNTER
+ && device->vk_descriptor_heap_layouts[index].applicable_heap_type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV)
+ {
+ device->vk_descriptor_heap_layouts[index].vk_set_layout = VK_NULL_HANDLE;
+ return S_OK;
+ }
+
binding.binding = 0;
- binding.descriptorType = device->vk_descriptor_heap_layouts[index].type;
+ binding.descriptorType = (device->vk_info.EXT_mutable_descriptor_type && !index)
+ ? VK_DESCRIPTOR_TYPE_MUTABLE_EXT : device->vk_descriptor_heap_layouts[index].type;
binding.descriptorCount = device->vk_descriptor_heap_layouts[index].count;
binding.stageFlags = VK_SHADER_STAGE_ALL;
binding.pImmutableSamplers = NULL;
@@ -132,6 +153,17 @@ static HRESULT vkd3d_create_vk_descriptor_heap_layout(struct d3d12_device *devic
flags_info.bindingCount = 1;
flags_info.pBindingFlags = &set_flags;
+ if (binding.descriptorType == VK_DESCRIPTOR_TYPE_MUTABLE_EXT)
+ {
+ type_list.descriptorTypeCount = ARRAY_SIZE(descriptor_types);
+ type_list.pDescriptorTypes = descriptor_types;
+ mutable_info.sType = VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_EXT;
+ mutable_info.pNext = NULL;
+ mutable_info.mutableDescriptorTypeListCount = 1;
+ mutable_info.pMutableDescriptorTypeLists = &type_list;
+ flags_info.pNext = &mutable_info;
+ }
+
if ((vr = VK_CALL(vkCreateDescriptorSetLayout(device->vk_device, &set_desc, NULL,
&device->vk_descriptor_heap_layouts[index].vk_set_layout))) < 0)
{
@@ -562,7 +594,7 @@ static HRESULT vkd3d_instance_init(struct vkd3d_instance *instance,
if (FAILED(hr = vkd3d_init_vk_global_procs(instance, create_info->pfn_vkGetInstanceProcAddr)))
{
- ERR("Failed to initialize Vulkan global procs, hr %#x.\n", hr);
+ ERR("Failed to initialise Vulkan global procs, hr %s.\n", debugstr_hresult(hr));
return hr;
}
@@ -642,7 +674,7 @@ static HRESULT vkd3d_instance_init(struct vkd3d_instance *instance,
if (FAILED(hr = vkd3d_load_vk_instance_procs(&instance->vk_procs, vk_global_procs, vk_instance)))
{
- ERR("Failed to load instance procs, hr %#x.\n", hr);
+ ERR("Failed to load instance procs, hr %s.\n", debugstr_hresult(hr));
if (instance->vk_procs.vkDestroyInstance)
instance->vk_procs.vkDestroyInstance(vk_instance, NULL);
if (instance->libvulkan)
@@ -718,7 +750,7 @@ static void vkd3d_destroy_instance(struct vkd3d_instance *instance)
ULONG vkd3d_instance_incref(struct vkd3d_instance *instance)
{
- ULONG refcount = InterlockedIncrement(&instance->refcount);
+ unsigned int refcount = vkd3d_atomic_increment_u32(&instance->refcount);
TRACE("%p increasing refcount to %u.\n", instance, refcount);
@@ -727,7 +759,7 @@ ULONG vkd3d_instance_incref(struct vkd3d_instance *instance)
ULONG vkd3d_instance_decref(struct vkd3d_instance *instance)
{
- ULONG refcount = InterlockedDecrement(&instance->refcount);
+ unsigned int refcount = vkd3d_atomic_decrement_u32(&instance->refcount);
TRACE("%p decreasing refcount to %u.\n", instance, refcount);
@@ -763,6 +795,7 @@ struct vkd3d_physical_device_info
VkPhysicalDeviceTransformFeedbackFeaturesEXT xfb_features;
VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT vertex_divisor_features;
VkPhysicalDeviceTimelineSemaphoreFeaturesKHR timeline_semaphore_features;
+ VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT mutable_features;
VkPhysicalDeviceFeatures2 features2;
};
@@ -780,6 +813,7 @@ static void vkd3d_physical_device_info_init(struct vkd3d_physical_device_info *i
VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT *buffer_alignment_features;
VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT *demote_features;
VkPhysicalDeviceTimelineSemaphoreFeaturesKHR *timeline_semaphore_features;
+ VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT *mutable_features;
VkPhysicalDeviceDepthClipEnableFeaturesEXT *depth_clip_features;
VkPhysicalDeviceMaintenance3Properties *maintenance3_properties;
VkPhysicalDeviceTransformFeedbackPropertiesEXT *xfb_properties;
@@ -800,6 +834,7 @@ static void vkd3d_physical_device_info_init(struct vkd3d_physical_device_info *i
vertex_divisor_features = &info->vertex_divisor_features;
vertex_divisor_properties = &info->vertex_divisor_properties;
timeline_semaphore_features = &info->timeline_semaphore_features;
+ mutable_features = &info->mutable_features;
xfb_features = &info->xfb_features;
xfb_properties = &info->xfb_properties;
@@ -823,6 +858,8 @@ static void vkd3d_physical_device_info_init(struct vkd3d_physical_device_info *i
vk_prepend_struct(&info->features2, vertex_divisor_features);
timeline_semaphore_features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR;
vk_prepend_struct(&info->features2, timeline_semaphore_features);
+ mutable_features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT;
+ vk_prepend_struct(&info->features2, mutable_features);
if (vulkan_info->KHR_get_physical_device_properties2)
VK_CALL(vkGetPhysicalDeviceFeatures2KHR(physical_device, &info->features2));
@@ -1510,8 +1547,6 @@ static HRESULT vkd3d_init_device_caps(struct d3d12_device *device,
device->feature_options.StandardSwizzle64KBSupported = FALSE;
device->feature_options.CrossNodeSharingTier = D3D12_CROSS_NODE_SHARING_TIER_NOT_SUPPORTED;
device->feature_options.CrossAdapterRowMajorTextureSupported = FALSE;
- /* SPV_EXT_shader_viewport_index_layer */
- device->feature_options.VPAndRTArrayIndexFromAnyShaderFeedingRasterizerSupportedWithoutGSEmulation = FALSE;
device->feature_options.ResourceHeapTier = D3D12_RESOURCE_HEAP_TIER_2;
/* Shader Model 6 support. */
@@ -1594,6 +1629,8 @@ static HRESULT vkd3d_init_device_caps(struct d3d12_device *device,
vulkan_info->EXT_shader_demote_to_helper_invocation = false;
if (!physical_device_info->texel_buffer_alignment_features.texelBufferAlignment)
vulkan_info->EXT_texel_buffer_alignment = false;
+ if (!physical_device_info->mutable_features.mutableDescriptorType)
+ vulkan_info->EXT_mutable_descriptor_type = false;
if (!physical_device_info->timeline_semaphore_features.timelineSemaphore)
vulkan_info->KHR_timeline_semaphore = false;
@@ -1615,6 +1652,8 @@ static HRESULT vkd3d_init_device_caps(struct d3d12_device *device,
vkd3d_free(vk_extensions);
device->feature_options.PSSpecifiedStencilRefSupported = vulkan_info->EXT_shader_stencil_export;
+ device->feature_options.VPAndRTArrayIndexFromAnyShaderFeedingRasterizerSupportedWithoutGSEmulation =
+ vulkan_info->EXT_shader_viewport_index_layer;
vkd3d_init_feature_level(vulkan_info, features, &device->feature_options);
if (vulkan_info->max_feature_level < create_info->minimum_feature_level)
@@ -1640,6 +1679,10 @@ static HRESULT vkd3d_init_device_caps(struct d3d12_device *device,
vulkan_info->shader_extensions[vulkan_info->shader_extension_count++]
= VKD3D_SHADER_SPIRV_EXTENSION_EXT_STENCIL_EXPORT;
+ if (vulkan_info->EXT_shader_viewport_index_layer)
+ vulkan_info->shader_extensions[vulkan_info->shader_extension_count++]
+ = VKD3D_SHADER_SPIRV_EXTENSION_EXT_VIEWPORT_INDEX_LAYER;
+
/* Disable unused Vulkan features. */
features->shaderTessellationAndGeometryPointSize = VK_FALSE;
@@ -1926,7 +1969,7 @@ static HRESULT vkd3d_select_queues(const struct vkd3d_instance *vkd3d_instance,
* which applies to resources of a total size of 4 MiB or less. */
static bool d3d12_is_64k_msaa_supported(struct d3d12_device *device)
{
- D3D12_RESOURCE_ALLOCATION_INFO info;
+ struct vkd3d_resource_allocation_info info;
D3D12_RESOURCE_DESC resource_desc;
memset(&resource_desc, 0, sizeof(resource_desc));
@@ -1943,7 +1986,7 @@ static bool d3d12_is_64k_msaa_supported(struct d3d12_device *device)
* resources, which must have 0x10000 in their description, so we might
* reasonably return true here for 0x20000 or 0x40000. */
return SUCCEEDED(vkd3d_get_image_allocation_info(device, &resource_desc, &info))
- && info.Alignment <= 0x10000;
+ && info.alignment <= 0x10000;
}
static HRESULT vkd3d_create_vk_device(struct d3d12_device *device,
@@ -2028,7 +2071,7 @@ static HRESULT vkd3d_create_vk_device(struct d3d12_device *device,
if (FAILED(hr = vkd3d_load_vk_device_procs(&device->vk_procs, vk_procs, vk_device)))
{
- ERR("Failed to load device procs, hr %#x.\n", hr);
+ ERR("Failed to load device procs, hr %s.\n", debugstr_hresult(hr));
if (device->vk_procs.vkDestroyDevice)
device->vk_procs.vkDestroyDevice(vk_device, NULL);
return hr;
@@ -2038,7 +2081,7 @@ static HRESULT vkd3d_create_vk_device(struct d3d12_device *device,
if (FAILED(hr = d3d12_device_create_vkd3d_queues(device, &device_queue_info)))
{
- ERR("Failed to create queues, hr %#x.\n", hr);
+ ERR("Failed to create queues, hr %s.\n", debugstr_hresult(hr));
device->vk_procs.vkDestroyDevice(vk_device, NULL);
return hr;
}
@@ -2056,7 +2099,7 @@ static HRESULT d3d12_device_init_pipeline_cache(struct d3d12_device *device)
VkPipelineCacheCreateInfo cache_info;
VkResult vr;
- vkd3d_mutex_init(&device->mutex);
+ vkd3d_mutex_init(&device->pipeline_cache_mutex);
cache_info.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
cache_info.pNext = NULL;
@@ -2080,7 +2123,7 @@ static void d3d12_device_destroy_pipeline_cache(struct d3d12_device *device)
if (device->vk_pipeline_cache)
VK_CALL(vkDestroyPipelineCache(device->vk_device, device->vk_pipeline_cache, NULL));
- vkd3d_mutex_destroy(&device->mutex);
+ vkd3d_mutex_destroy(&device->pipeline_cache_mutex);
}
#define VKD3D_VA_FALLBACK_BASE 0x8000000000000000ull
@@ -2090,7 +2133,7 @@ static void d3d12_device_destroy_pipeline_cache(struct d3d12_device *device)
#define VKD3D_VA_SLAB_COUNT (64 * 1024)
static D3D12_GPU_VIRTUAL_ADDRESS vkd3d_gpu_va_allocator_allocate_slab(struct vkd3d_gpu_va_allocator *allocator,
- size_t aligned_size, void *ptr)
+ uint64_t aligned_size, void *ptr)
{
struct vkd3d_gpu_va_slab *slab;
D3D12_GPU_VIRTUAL_ADDRESS address;
@@ -2106,13 +2149,13 @@ static D3D12_GPU_VIRTUAL_ADDRESS vkd3d_gpu_va_allocator_allocate_slab(struct vkd
slab_idx = slab - allocator->slabs;
address = VKD3D_VA_SLAB_BASE + slab_idx * VKD3D_VA_SLAB_SIZE;
- TRACE("Allocated address %#"PRIx64", slab %u, size %zu.\n", address, slab_idx, aligned_size);
+ TRACE("Allocated address %#"PRIx64", slab %u, size %"PRIu64".\n", address, slab_idx, aligned_size);
return address;
}
static D3D12_GPU_VIRTUAL_ADDRESS vkd3d_gpu_va_allocator_allocate_fallback(struct vkd3d_gpu_va_allocator *allocator,
- size_t alignment, size_t aligned_size, void *ptr)
+ size_t alignment, uint64_t aligned_size, void *ptr)
{
struct vkd3d_gpu_va_allocation *allocation;
D3D12_GPU_VIRTUAL_ADDRESS base, ceiling;
@@ -2138,17 +2181,17 @@ static D3D12_GPU_VIRTUAL_ADDRESS vkd3d_gpu_va_allocator_allocate_fallback(struct
* only fail once we have exhausted 63 bits of address space. */
allocator->fallback_floor = base + aligned_size;
- TRACE("Allocated address %#"PRIx64", size %zu.\n", base, aligned_size);
+ TRACE("Allocated address %#"PRIx64", size %"PRIu64".\n", base, aligned_size);
return base;
}
D3D12_GPU_VIRTUAL_ADDRESS vkd3d_gpu_va_allocator_allocate(struct vkd3d_gpu_va_allocator *allocator,
- size_t alignment, size_t size, void *ptr)
+ size_t alignment, uint64_t size, void *ptr)
{
D3D12_GPU_VIRTUAL_ADDRESS address;
- if (size > ~(size_t)0 - (alignment - 1))
+ if (size > ~(uint64_t)0 - (alignment - 1))
return 0;
size = align(size, alignment);
@@ -2184,7 +2227,7 @@ static void *vkd3d_gpu_va_allocator_dereference_slab(struct vkd3d_gpu_va_allocat
base_offset -= slab_idx * VKD3D_VA_SLAB_SIZE;
if (base_offset >= slab->size)
{
- ERR("Address %#"PRIx64" is %#"PRIx64" bytes into slab %u of size %zu.\n",
+ ERR("Address %#"PRIx64" is %#"PRIx64" bytes into slab %u of size %"PRIu64".\n",
address, base_offset, slab_idx, slab->size);
return NULL;
}
@@ -2455,17 +2498,19 @@ static void vkd3d_desc_object_cache_cleanup(struct vkd3d_desc_object_cache *cach
}
/* ID3D12Device */
-static inline struct d3d12_device *impl_from_ID3D12Device5(ID3D12Device5 *iface)
+static inline struct d3d12_device *impl_from_ID3D12Device7(ID3D12Device7 *iface)
{
- return CONTAINING_RECORD(iface, struct d3d12_device, ID3D12Device5_iface);
+ return CONTAINING_RECORD(iface, struct d3d12_device, ID3D12Device7_iface);
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_QueryInterface(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_QueryInterface(ID3D12Device7 *iface,
REFIID riid, void **object)
{
TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
- if (IsEqualGUID(riid, &IID_ID3D12Device5)
+ if (IsEqualGUID(riid, &IID_ID3D12Device7)
+ || IsEqualGUID(riid, &IID_ID3D12Device6)
+ || IsEqualGUID(riid, &IID_ID3D12Device5)
|| IsEqualGUID(riid, &IID_ID3D12Device4)
|| IsEqualGUID(riid, &IID_ID3D12Device3)
|| IsEqualGUID(riid, &IID_ID3D12Device2)
@@ -2485,20 +2530,42 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_QueryInterface(ID3D12Device5 *ifac
return E_NOINTERFACE;
}
-static ULONG STDMETHODCALLTYPE d3d12_device_AddRef(ID3D12Device5 *iface)
+static ULONG STDMETHODCALLTYPE d3d12_device_AddRef(ID3D12Device7 *iface)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
- ULONG refcount = InterlockedIncrement(&device->refcount);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
+ unsigned int refcount = vkd3d_atomic_increment_u32(&device->refcount);
TRACE("%p increasing refcount to %u.\n", device, refcount);
return refcount;
}
-static ULONG STDMETHODCALLTYPE d3d12_device_Release(ID3D12Device5 *iface)
+static HRESULT device_worker_stop(struct d3d12_device *device)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
- ULONG refcount = InterlockedDecrement(&device->refcount);
+ HRESULT hr;
+
+ TRACE("device %p.\n", device);
+
+ vkd3d_mutex_lock(&device->worker_mutex);
+
+ device->worker_should_exit = true;
+ vkd3d_cond_signal(&device->worker_cond);
+
+ vkd3d_mutex_unlock(&device->worker_mutex);
+
+ if (FAILED(hr = vkd3d_join_thread(device->vkd3d_instance, &device->worker_thread)))
+ return hr;
+
+ vkd3d_mutex_destroy(&device->worker_mutex);
+ vkd3d_cond_destroy(&device->worker_cond);
+
+ return S_OK;
+}
+
+static ULONG STDMETHODCALLTYPE d3d12_device_Release(ID3D12Device7 *iface)
+{
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
+ unsigned int refcount = vkd3d_atomic_decrement_u32(&device->refcount);
TRACE("%p decreasing refcount to %u.\n", device, refcount);
@@ -2520,6 +2587,9 @@ static ULONG STDMETHODCALLTYPE d3d12_device_Release(ID3D12Device5 *iface)
d3d12_device_destroy_vkd3d_queues(device);
vkd3d_desc_object_cache_cleanup(&device->view_desc_cache);
vkd3d_desc_object_cache_cleanup(&device->cbuffer_desc_cache);
+ if (device->use_vk_heaps)
+ device_worker_stop(device);
+ vkd3d_free(device->heaps);
VK_CALL(vkDestroyDevice(device->vk_device, NULL));
if (device->parent)
IUnknown_Release(device->parent);
@@ -2531,10 +2601,10 @@ static ULONG STDMETHODCALLTYPE d3d12_device_Release(ID3D12Device5 *iface)
return refcount;
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_GetPrivateData(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_GetPrivateData(ID3D12Device7 *iface,
REFGUID guid, UINT *data_size, void *data)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
TRACE("iface %p, guid %s, data_size %p, data %p.\n",
iface, debugstr_guid(guid), data_size, data);
@@ -2542,10 +2612,10 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_GetPrivateData(ID3D12Device5 *ifac
return vkd3d_get_private_data(&device->private_store, guid, data_size, data);
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_SetPrivateData(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_SetPrivateData(ID3D12Device7 *iface,
REFGUID guid, UINT data_size, const void *data)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
TRACE("iface %p, guid %s, data_size %u, data %p.\n",
iface, debugstr_guid(guid), data_size, data);
@@ -2553,19 +2623,19 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_SetPrivateData(ID3D12Device5 *ifac
return vkd3d_set_private_data(&device->private_store, guid, data_size, data);
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_SetPrivateDataInterface(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_SetPrivateDataInterface(ID3D12Device7 *iface,
REFGUID guid, const IUnknown *data)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
TRACE("iface %p, guid %s, data %p.\n", iface, debugstr_guid(guid), data);
return vkd3d_set_private_data_interface(&device->private_store, guid, data);
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_SetName(ID3D12Device5 *iface, const WCHAR *name)
+static HRESULT STDMETHODCALLTYPE d3d12_device_SetName(ID3D12Device7 *iface, const WCHAR *name)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
TRACE("iface %p, name %s.\n", iface, debugstr_w(name, device->wchar_size));
@@ -2573,17 +2643,17 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_SetName(ID3D12Device5 *iface, cons
VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, name);
}
-static UINT STDMETHODCALLTYPE d3d12_device_GetNodeCount(ID3D12Device5 *iface)
+static UINT STDMETHODCALLTYPE d3d12_device_GetNodeCount(ID3D12Device7 *iface)
{
TRACE("iface %p.\n", iface);
return 1;
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_CreateCommandQueue(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateCommandQueue(ID3D12Device7 *iface,
const D3D12_COMMAND_QUEUE_DESC *desc, REFIID riid, void **command_queue)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
struct d3d12_command_queue *object;
HRESULT hr;
@@ -2597,10 +2667,10 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateCommandQueue(ID3D12Device5 *
riid, command_queue);
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_CreateCommandAllocator(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateCommandAllocator(ID3D12Device7 *iface,
D3D12_COMMAND_LIST_TYPE type, REFIID riid, void **command_allocator)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
struct d3d12_command_allocator *object;
HRESULT hr;
@@ -2614,10 +2684,10 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateCommandAllocator(ID3D12Devic
riid, command_allocator);
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_CreateGraphicsPipelineState(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateGraphicsPipelineState(ID3D12Device7 *iface,
const D3D12_GRAPHICS_PIPELINE_STATE_DESC *desc, REFIID riid, void **pipeline_state)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
struct d3d12_pipeline_state *object;
HRESULT hr;
@@ -2631,10 +2701,10 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateGraphicsPipelineState(ID3D12
&IID_ID3D12PipelineState, riid, pipeline_state);
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_CreateComputePipelineState(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateComputePipelineState(ID3D12Device7 *iface,
const D3D12_COMPUTE_PIPELINE_STATE_DESC *desc, REFIID riid, void **pipeline_state)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
struct d3d12_pipeline_state *object;
HRESULT hr;
@@ -2648,11 +2718,11 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateComputePipelineState(ID3D12D
&IID_ID3D12PipelineState, riid, pipeline_state);
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_CreateCommandList(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateCommandList(ID3D12Device7 *iface,
UINT node_mask, D3D12_COMMAND_LIST_TYPE type, ID3D12CommandAllocator *command_allocator,
ID3D12PipelineState *initial_pipeline_state, REFIID riid, void **command_list)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
struct d3d12_command_list *object;
HRESULT hr;
@@ -2775,10 +2845,10 @@ bool d3d12_device_is_uma(struct d3d12_device *device, bool *coherent)
return true;
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_CheckFeatureSupport(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_CheckFeatureSupport(ID3D12Device7 *iface,
D3D12_FEATURE feature, void *feature_data, UINT feature_data_size)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
TRACE("iface %p, feature %#x, feature_data %p, feature_data_size %u.\n",
iface, feature, feature_data, feature_data_size);
@@ -3278,16 +3348,101 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CheckFeatureSupport(ID3D12Device5
return S_OK;
}
+ case D3D12_FEATURE_D3D12_OPTIONS6:
+ {
+ D3D12_FEATURE_DATA_D3D12_OPTIONS6 *data = feature_data;
+
+ if (feature_data_size != sizeof(*data))
+ {
+ WARN("Invalid size %u.\n", feature_data_size);
+ return E_INVALIDARG;
+ }
+
+ data->AdditionalShadingRatesSupported = FALSE;
+ data->PerPrimitiveShadingRateSupportedWithViewportIndexing = FALSE;
+ data->VariableShadingRateTier = D3D12_VARIABLE_SHADING_RATE_TIER_NOT_SUPPORTED;
+ data->ShadingRateImageTileSize = 0;
+ data->BackgroundProcessingSupported = FALSE;
+
+ TRACE("Additional shading rates support %#x.\n", data->AdditionalShadingRatesSupported);
+ TRACE("Per-primitive shading rates with viewport indexing %#x.\n",
+ data->PerPrimitiveShadingRateSupportedWithViewportIndexing);
+ TRACE("Variable shading rate tier %#x.\n", data->VariableShadingRateTier);
+ TRACE("Shading rate image tile size %#x.\n", data->ShadingRateImageTileSize);
+ TRACE("Background processing support %#x.\n", data->BackgroundProcessingSupported);
+ return S_OK;
+ }
+
+ case D3D12_FEATURE_D3D12_OPTIONS7:
+ {
+ D3D12_FEATURE_DATA_D3D12_OPTIONS7 *data = feature_data;
+
+ if (feature_data_size != sizeof(*data))
+ {
+ WARN("Invalid size %u.\n", feature_data_size);
+ return E_INVALIDARG;
+ }
+
+ data->MeshShaderTier = D3D12_MESH_SHADER_TIER_NOT_SUPPORTED;
+ data->SamplerFeedbackTier = D3D12_SAMPLER_FEEDBACK_TIER_NOT_SUPPORTED;
+
+ TRACE("Mesh shading tier %#x.\n", data->MeshShaderTier);
+ TRACE("Sampler feedback tier %#x.\n", data->SamplerFeedbackTier);
+ return S_OK;
+ }
+
+ case D3D12_FEATURE_D3D12_OPTIONS8:
+ {
+ D3D12_FEATURE_DATA_D3D12_OPTIONS8 *data = feature_data;
+
+ if (feature_data_size != sizeof(*data))
+ {
+ WARN("Invalid size %u.\n", feature_data_size);
+ return E_INVALIDARG;
+ }
+
+ data->UnalignedBlockTexturesSupported = FALSE;
+
+ TRACE("Unaligned block texture support %#x.\n", data->UnalignedBlockTexturesSupported);
+ return S_OK;
+ }
+
+ case D3D12_FEATURE_D3D12_OPTIONS9:
+ {
+ D3D12_FEATURE_DATA_D3D12_OPTIONS9 *data = feature_data;
+
+ if (feature_data_size != sizeof(*data))
+ {
+ WARN("Invalid size %u.\n", feature_data_size);
+ return E_INVALIDARG;
+ }
+
+ data->MeshShaderPipelineStatsSupported = FALSE;
+ data->MeshShaderSupportsFullRangeRenderTargetArrayIndex = FALSE;
+ data->AtomicInt64OnTypedResourceSupported = FALSE;
+ data->AtomicInt64OnGroupSharedSupported = FALSE;
+ data->DerivativesInMeshAndAmplificationShadersSupported = FALSE;
+ data->WaveMMATier = D3D12_WAVE_MMA_TIER_NOT_SUPPORTED;
+
+ TRACE("Mesh shader pipeline stats support %#x.\n", data->MeshShaderPipelineStatsSupported);
+ TRACE("Mesh shader RT array index full range %#x.\n", data->MeshShaderSupportsFullRangeRenderTargetArrayIndex);
+ TRACE("Atomic int64 on typed resource %#x.\n", data->AtomicInt64OnTypedResourceSupported);
+ TRACE("Atomic int64 on group shared mem %#x.\n", data->AtomicInt64OnGroupSharedSupported);
+ TRACE("Derivatives in mesh and amp shaders %#x.\n", data->DerivativesInMeshAndAmplificationShadersSupported);
+ TRACE("Wave MMA tier %#x.\n", data->WaveMMATier);
+ return S_OK;
+ }
+
default:
FIXME("Unhandled feature %#x.\n", feature);
return E_NOTIMPL;
}
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_CreateDescriptorHeap(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateDescriptorHeap(ID3D12Device7 *iface,
const D3D12_DESCRIPTOR_HEAP_DESC *desc, REFIID riid, void **descriptor_heap)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
struct d3d12_descriptor_heap *object;
HRESULT hr;
@@ -3301,7 +3456,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateDescriptorHeap(ID3D12Device5
&IID_ID3D12DescriptorHeap, riid, descriptor_heap);
}
-static UINT STDMETHODCALLTYPE d3d12_device_GetDescriptorHandleIncrementSize(ID3D12Device5 *iface,
+static UINT STDMETHODCALLTYPE d3d12_device_GetDescriptorHandleIncrementSize(ID3D12Device7 *iface,
D3D12_DESCRIPTOR_HEAP_TYPE descriptor_heap_type)
{
TRACE("iface %p, descriptor_heap_type %#x.\n", iface, descriptor_heap_type);
@@ -3324,16 +3479,16 @@ static UINT STDMETHODCALLTYPE d3d12_device_GetDescriptorHandleIncrementSize(ID3D
}
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_CreateRootSignature(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateRootSignature(ID3D12Device7 *iface,
UINT node_mask, const void *bytecode, SIZE_T bytecode_length,
REFIID riid, void **root_signature)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
struct d3d12_root_signature *object;
HRESULT hr;
- TRACE("iface %p, node_mask 0x%08x, bytecode %p, bytecode_length %lu, riid %s, root_signature %p.\n",
- iface, node_mask, bytecode, bytecode_length, debugstr_guid(riid), root_signature);
+ TRACE("iface %p, node_mask 0x%08x, bytecode %p, bytecode_length %"PRIuPTR", riid %s, root_signature %p.\n",
+ iface, node_mask, bytecode, (uintptr_t)bytecode_length, debugstr_guid(riid), root_signature);
debug_ignored_node_mask(node_mask);
@@ -3344,89 +3499,89 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateRootSignature(ID3D12Device5
&IID_ID3D12RootSignature, riid, root_signature);
}
-static void STDMETHODCALLTYPE d3d12_device_CreateConstantBufferView(ID3D12Device5 *iface,
+static void STDMETHODCALLTYPE d3d12_device_CreateConstantBufferView(ID3D12Device7 *iface,
const D3D12_CONSTANT_BUFFER_VIEW_DESC *desc, D3D12_CPU_DESCRIPTOR_HANDLE descriptor)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
struct d3d12_desc tmp = {0};
- TRACE("iface %p, desc %p, descriptor %#lx.\n", iface, desc, descriptor.ptr);
+ TRACE("iface %p, desc %p, descriptor %s.\n", iface, desc, debug_cpu_handle(descriptor));
d3d12_desc_create_cbv(&tmp, device, desc);
d3d12_desc_write_atomic(d3d12_desc_from_cpu_handle(descriptor), &tmp, device);
}
-static void STDMETHODCALLTYPE d3d12_device_CreateShaderResourceView(ID3D12Device5 *iface,
+static void STDMETHODCALLTYPE d3d12_device_CreateShaderResourceView(ID3D12Device7 *iface,
ID3D12Resource *resource, const D3D12_SHADER_RESOURCE_VIEW_DESC *desc,
D3D12_CPU_DESCRIPTOR_HANDLE descriptor)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
struct d3d12_desc tmp = {0};
- TRACE("iface %p, resource %p, desc %p, descriptor %#lx.\n",
- iface, resource, desc, descriptor.ptr);
+ TRACE("iface %p, resource %p, desc %p, descriptor %s.\n",
+ iface, resource, desc, debug_cpu_handle(descriptor));
d3d12_desc_create_srv(&tmp, device, unsafe_impl_from_ID3D12Resource(resource), desc);
d3d12_desc_write_atomic(d3d12_desc_from_cpu_handle(descriptor), &tmp, device);
}
-static void STDMETHODCALLTYPE d3d12_device_CreateUnorderedAccessView(ID3D12Device5 *iface,
+static void STDMETHODCALLTYPE d3d12_device_CreateUnorderedAccessView(ID3D12Device7 *iface,
ID3D12Resource *resource, ID3D12Resource *counter_resource,
const D3D12_UNORDERED_ACCESS_VIEW_DESC *desc, D3D12_CPU_DESCRIPTOR_HANDLE descriptor)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
struct d3d12_desc tmp = {0};
- TRACE("iface %p, resource %p, counter_resource %p, desc %p, descriptor %#lx.\n",
- iface, resource, counter_resource, desc, descriptor.ptr);
+ TRACE("iface %p, resource %p, counter_resource %p, desc %p, descriptor %s.\n",
+ iface, resource, counter_resource, desc, debug_cpu_handle(descriptor));
d3d12_desc_create_uav(&tmp, device, unsafe_impl_from_ID3D12Resource(resource),
unsafe_impl_from_ID3D12Resource(counter_resource), desc);
d3d12_desc_write_atomic(d3d12_desc_from_cpu_handle(descriptor), &tmp, device);
}
-static void STDMETHODCALLTYPE d3d12_device_CreateRenderTargetView(ID3D12Device5 *iface,
+static void STDMETHODCALLTYPE d3d12_device_CreateRenderTargetView(ID3D12Device7 *iface,
ID3D12Resource *resource, const D3D12_RENDER_TARGET_VIEW_DESC *desc,
D3D12_CPU_DESCRIPTOR_HANDLE descriptor)
{
- TRACE("iface %p, resource %p, desc %p, descriptor %#lx.\n",
- iface, resource, desc, descriptor.ptr);
+ TRACE("iface %p, resource %p, desc %p, descriptor %s.\n",
+ iface, resource, desc, debug_cpu_handle(descriptor));
d3d12_rtv_desc_create_rtv(d3d12_rtv_desc_from_cpu_handle(descriptor),
- impl_from_ID3D12Device5(iface), unsafe_impl_from_ID3D12Resource(resource), desc);
+ impl_from_ID3D12Device7(iface), unsafe_impl_from_ID3D12Resource(resource), desc);
}
-static void STDMETHODCALLTYPE d3d12_device_CreateDepthStencilView(ID3D12Device5 *iface,
+static void STDMETHODCALLTYPE d3d12_device_CreateDepthStencilView(ID3D12Device7 *iface,
ID3D12Resource *resource, const D3D12_DEPTH_STENCIL_VIEW_DESC *desc,
D3D12_CPU_DESCRIPTOR_HANDLE descriptor)
{
- TRACE("iface %p, resource %p, desc %p, descriptor %#lx.\n",
- iface, resource, desc, descriptor.ptr);
+ TRACE("iface %p, resource %p, desc %p, descriptor %s.\n",
+ iface, resource, desc, debug_cpu_handle(descriptor));
d3d12_dsv_desc_create_dsv(d3d12_dsv_desc_from_cpu_handle(descriptor),
- impl_from_ID3D12Device5(iface), unsafe_impl_from_ID3D12Resource(resource), desc);
+ impl_from_ID3D12Device7(iface), unsafe_impl_from_ID3D12Resource(resource), desc);
}
-static void STDMETHODCALLTYPE d3d12_device_CreateSampler(ID3D12Device5 *iface,
+static void STDMETHODCALLTYPE d3d12_device_CreateSampler(ID3D12Device7 *iface,
const D3D12_SAMPLER_DESC *desc, D3D12_CPU_DESCRIPTOR_HANDLE descriptor)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
struct d3d12_desc tmp = {0};
- TRACE("iface %p, desc %p, descriptor %#lx.\n", iface, desc, descriptor.ptr);
+ TRACE("iface %p, desc %p, descriptor %s.\n", iface, desc, debug_cpu_handle(descriptor));
d3d12_desc_create_sampler(&tmp, device, desc);
d3d12_desc_write_atomic(d3d12_desc_from_cpu_handle(descriptor), &tmp, device);
}
-static void STDMETHODCALLTYPE d3d12_device_CopyDescriptors(ID3D12Device5 *iface,
+static void STDMETHODCALLTYPE d3d12_device_CopyDescriptors(ID3D12Device7 *iface,
UINT dst_descriptor_range_count, const D3D12_CPU_DESCRIPTOR_HANDLE *dst_descriptor_range_offsets,
const UINT *dst_descriptor_range_sizes,
UINT src_descriptor_range_count, const D3D12_CPU_DESCRIPTOR_HANDLE *src_descriptor_range_offsets,
const UINT *src_descriptor_range_sizes,
D3D12_DESCRIPTOR_HEAP_TYPE descriptor_heap_type)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
unsigned int dst_range_idx, dst_idx, src_range_idx, src_idx;
unsigned int dst_range_size, src_range_size;
struct d3d12_descriptor_heap *dst_heap;
@@ -3482,101 +3637,126 @@ static void STDMETHODCALLTYPE d3d12_device_CopyDescriptors(ID3D12Device5 *iface,
}
}
-static void STDMETHODCALLTYPE d3d12_device_CopyDescriptorsSimple(ID3D12Device5 *iface,
+static void STDMETHODCALLTYPE d3d12_device_CopyDescriptorsSimple(ID3D12Device7 *iface,
UINT descriptor_count, const D3D12_CPU_DESCRIPTOR_HANDLE dst_descriptor_range_offset,
const D3D12_CPU_DESCRIPTOR_HANDLE src_descriptor_range_offset,
D3D12_DESCRIPTOR_HEAP_TYPE descriptor_heap_type)
{
- TRACE("iface %p, descriptor_count %u, dst_descriptor_range_offset %#lx, "
- "src_descriptor_range_offset %#lx, descriptor_heap_type %#x.\n",
- iface, descriptor_count, dst_descriptor_range_offset.ptr, src_descriptor_range_offset.ptr,
- descriptor_heap_type);
+ TRACE("iface %p, descriptor_count %u, dst_descriptor_range_offset %s, "
+ "src_descriptor_range_offset %s, descriptor_heap_type %#x.\n",
+ iface, descriptor_count, debug_cpu_handle(dst_descriptor_range_offset),
+ debug_cpu_handle(src_descriptor_range_offset), descriptor_heap_type);
d3d12_device_CopyDescriptors(iface, 1, &dst_descriptor_range_offset, &descriptor_count,
1, &src_descriptor_range_offset, &descriptor_count, descriptor_heap_type);
}
-static D3D12_RESOURCE_ALLOCATION_INFO * STDMETHODCALLTYPE d3d12_device_GetResourceAllocationInfo(
- ID3D12Device5 *iface, D3D12_RESOURCE_ALLOCATION_INFO *info, UINT visible_mask,
- UINT count, const D3D12_RESOURCE_DESC *resource_descs)
+static void d3d12_resource_allocation_info1_from_vkd3d(D3D12_RESOURCE_ALLOCATION_INFO1 *result,
+ const struct vkd3d_resource_allocation_info *info)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ result->Offset = info->offset;
+ result->Alignment = info->alignment;
+ result->SizeInBytes = info->size_in_bytes;
+}
+
+static void d3d12_device_get_resource_allocation_info(struct d3d12_device *device,
+ D3D12_RESOURCE_ALLOCATION_INFO1 *infos1, unsigned int count, const D3D12_RESOURCE_DESC *resource_descs,
+ D3D12_RESOURCE_ALLOCATION_INFO *result)
+{
+ struct vkd3d_resource_allocation_info info;
const D3D12_RESOURCE_DESC *desc;
uint64_t requested_alignment;
+ unsigned int i;
- TRACE("iface %p, info %p, visible_mask 0x%08x, count %u, resource_descs %p.\n",
- iface, info, visible_mask, count, resource_descs);
-
- debug_ignored_node_mask(visible_mask);
-
- info->SizeInBytes = 0;
- info->Alignment = 0;
+ result->Alignment = 0;
+ result->SizeInBytes = 0;
- if (count != 1)
- {
- FIXME("Multiple resource descriptions not supported.\n");
- return info;
- }
+ info.offset = 0;
- desc = &resource_descs[0];
-
- if (FAILED(d3d12_resource_validate_desc(desc, device)))
+ for (i = 0; i < count; ++i)
{
- WARN("Invalid resource desc.\n");
- goto invalid;
- }
+ desc = &resource_descs[i];
- if (desc->Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
- {
- info->SizeInBytes = align(desc->Width, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT);
- info->Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
- }
- else
- {
- if (FAILED(vkd3d_get_image_allocation_info(device, desc, info)))
+ if (FAILED(d3d12_resource_validate_desc(desc, device)))
{
- WARN("Failed to get allocation info for texture.\n");
+ WARN("Invalid resource desc.\n");
goto invalid;
}
- requested_alignment = desc->Alignment
- ? desc->Alignment : D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
- info->Alignment = max(info->Alignment, requested_alignment);
+ if (desc->Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
+ {
+ info.alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
+ info.offset = align(info.offset, info.alignment);
+ info.size_in_bytes = align(desc->Width, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT);
+ }
+ else
+ {
+ if (FAILED(vkd3d_get_image_allocation_info(device, desc, &info)))
+ {
+ WARN("Failed to get allocation info for texture.\n");
+ goto invalid;
+ }
- info->SizeInBytes = align(info->SizeInBytes, info->Alignment);
+ requested_alignment = desc->Alignment
+ ? desc->Alignment : D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
+ info.alignment = max(info.alignment, requested_alignment);
+ info.size_in_bytes = align(info.size_in_bytes, info.alignment);
- /* Pad by the maximum heap offset increase which may be needed to align to a higher
- * Vulkan requirement an offset supplied by the calling application. This allows
- * us to return the standard D3D12 alignment and adjust resource placement later. */
- if (info->Alignment > requested_alignment)
- {
- info->SizeInBytes += info->Alignment - requested_alignment;
- info->Alignment = requested_alignment;
+ /* Pad by the maximum heap offset increase which may be needed to align to a higher
+ * Vulkan requirement an offset supplied by the calling application. This allows
+ * us to return the standard D3D12 alignment and adjust resource placement later. */
+ if (info.alignment > requested_alignment)
+ {
+ info.size_in_bytes += info.alignment - requested_alignment;
+ info.alignment = requested_alignment;
+ }
+
+ info.offset = align(info.offset, info.alignment);
}
- }
- TRACE("Size %#"PRIx64", alignment %#"PRIx64".\n", info->SizeInBytes, info->Alignment);
+ if (infos1)
+ d3d12_resource_allocation_info1_from_vkd3d(&infos1[i], &info);
- return info;
+ info.offset += info.size_in_bytes;
+
+ result->Alignment = max(result->Alignment, info.alignment);
+ result->SizeInBytes = info.offset;
+ }
+
+ return;
invalid:
- info->SizeInBytes = ~(uint64_t)0;
+ result->SizeInBytes = UINT64_MAX;
- /* FIXME: Should we support D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT for small MSSA resources? */
+ /* FIXME: Should we support D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT for small MSAA resources? */
if (desc->SampleDesc.Count != 1)
- info->Alignment = D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT;
+ result->Alignment = D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT;
else
- info->Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
+ result->Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
+
+ TRACE("Alignment %#"PRIx64".\n", result->Alignment);
+}
+
+static D3D12_RESOURCE_ALLOCATION_INFO * STDMETHODCALLTYPE d3d12_device_GetResourceAllocationInfo(
+ ID3D12Device7 *iface, D3D12_RESOURCE_ALLOCATION_INFO *info, UINT visible_mask,
+ UINT count, const D3D12_RESOURCE_DESC *resource_descs)
+{
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
- TRACE("Alignment %#"PRIx64".\n", info->Alignment);
+ TRACE("iface %p, info %p, visible_mask 0x%08x, count %u, resource_descs %p.\n",
+ iface, info, visible_mask, count, resource_descs);
+
+ debug_ignored_node_mask(visible_mask);
+
+ d3d12_device_get_resource_allocation_info(device, NULL, count, resource_descs, info);
return info;
}
-static D3D12_HEAP_PROPERTIES * STDMETHODCALLTYPE d3d12_device_GetCustomHeapProperties(ID3D12Device5 *iface,
+static D3D12_HEAP_PROPERTIES * STDMETHODCALLTYPE d3d12_device_GetCustomHeapProperties(ID3D12Device7 *iface,
D3D12_HEAP_PROPERTIES *heap_properties, UINT node_mask, D3D12_HEAP_TYPE heap_type)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
bool coherent;
TRACE("iface %p, heap_properties %p, node_mask 0x%08x, heap_type %#x.\n",
@@ -3616,12 +3796,12 @@ static D3D12_HEAP_PROPERTIES * STDMETHODCALLTYPE d3d12_device_GetCustomHeapPrope
return heap_properties;
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_CreateCommittedResource(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateCommittedResource(ID3D12Device7 *iface,
const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags,
const D3D12_RESOURCE_DESC *desc, D3D12_RESOURCE_STATES initial_state,
const D3D12_CLEAR_VALUE *optimized_clear_value, REFIID iid, void **resource)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
struct d3d12_resource *object;
HRESULT hr;
@@ -3640,10 +3820,10 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateCommittedResource(ID3D12Devi
return return_interface(&object->ID3D12Resource1_iface, &IID_ID3D12Resource1, iid, resource);
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_CreateHeap(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateHeap(ID3D12Device7 *iface,
const D3D12_HEAP_DESC *desc, REFIID iid, void **heap)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
struct d3d12_heap *object;
HRESULT hr;
@@ -3659,12 +3839,12 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateHeap(ID3D12Device5 *iface,
return return_interface(&object->ID3D12Heap_iface, &IID_ID3D12Heap, iid, heap);
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_CreatePlacedResource(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreatePlacedResource(ID3D12Device7 *iface,
ID3D12Heap *heap, UINT64 heap_offset,
const D3D12_RESOURCE_DESC *desc, D3D12_RESOURCE_STATES initial_state,
const D3D12_CLEAR_VALUE *optimized_clear_value, REFIID iid, void **resource)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
struct d3d12_heap *heap_object;
struct d3d12_resource *object;
HRESULT hr;
@@ -3683,11 +3863,11 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreatePlacedResource(ID3D12Device5
return return_interface(&object->ID3D12Resource1_iface, &IID_ID3D12Resource1, iid, resource);
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_CreateReservedResource(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateReservedResource(ID3D12Device7 *iface,
const D3D12_RESOURCE_DESC *desc, D3D12_RESOURCE_STATES initial_state,
const D3D12_CLEAR_VALUE *optimized_clear_value, REFIID iid, void **resource)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
struct d3d12_resource *object;
HRESULT hr;
@@ -3701,11 +3881,11 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateReservedResource(ID3D12Devic
return return_interface(&object->ID3D12Resource1_iface, &IID_ID3D12Resource1, iid, resource);
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_CreateSharedHandle(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateSharedHandle(ID3D12Device7 *iface,
ID3D12DeviceChild *object, const SECURITY_ATTRIBUTES *attributes, DWORD access,
const WCHAR *name, HANDLE *handle)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
FIXME("iface %p, object %p, attributes %p, access %#x, name %s, handle %p stub!\n",
iface, object, attributes, access, debugstr_w(name, device->wchar_size), handle);
@@ -3713,7 +3893,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateSharedHandle(ID3D12Device5 *
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_OpenSharedHandle(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_OpenSharedHandle(ID3D12Device7 *iface,
HANDLE handle, REFIID riid, void **object)
{
FIXME("iface %p, handle %p, riid %s, object %p stub!\n",
@@ -3722,10 +3902,10 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_OpenSharedHandle(ID3D12Device5 *if
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_OpenSharedHandleByName(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_OpenSharedHandleByName(ID3D12Device7 *iface,
const WCHAR *name, DWORD access, HANDLE *handle)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
FIXME("iface %p, name %s, access %#x, handle %p stub!\n",
iface, debugstr_w(name, device->wchar_size), access, handle);
@@ -3733,7 +3913,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_OpenSharedHandleByName(ID3D12Devic
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_MakeResident(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_MakeResident(ID3D12Device7 *iface,
UINT object_count, ID3D12Pageable * const *objects)
{
ID3D12Fence *fence;
@@ -3741,17 +3921,17 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_MakeResident(ID3D12Device5 *iface,
TRACE("iface %p, object_count %u, objects %p.\n", iface, object_count, objects);
- if (FAILED(hr = ID3D12Device5_CreateFence(iface, 0, 0, &IID_ID3D12Fence, (void **)&fence)))
+ if (FAILED(hr = ID3D12Device7_CreateFence(iface, 0, 0, &IID_ID3D12Fence, (void **)&fence)))
return hr;
- hr = ID3D12Device5_EnqueueMakeResident(iface, 0, object_count, objects, fence, 1);
+ hr = ID3D12Device7_EnqueueMakeResident(iface, 0, object_count, objects, fence, 1);
if (SUCCEEDED(hr))
ID3D12Fence_SetEventOnCompletion(fence, 1, NULL);
ID3D12Fence_Release(fence);
return hr;
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_Evict(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_Evict(ID3D12Device7 *iface,
UINT object_count, ID3D12Pageable * const *objects)
{
FIXME_ONCE("iface %p, object_count %u, objects %p stub!\n",
@@ -3760,10 +3940,10 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_Evict(ID3D12Device5 *iface,
return S_OK;
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_CreateFence(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateFence(ID3D12Device7 *iface,
UINT64 initial_value, D3D12_FENCE_FLAGS flags, REFIID riid, void **fence)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
struct d3d12_fence *object;
HRESULT hr;
@@ -3776,21 +3956,21 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateFence(ID3D12Device5 *iface,
return return_interface(&object->ID3D12Fence1_iface, &IID_ID3D12Fence1, riid, fence);
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_GetDeviceRemovedReason(ID3D12Device5 *iface)
+static HRESULT STDMETHODCALLTYPE d3d12_device_GetDeviceRemovedReason(ID3D12Device7 *iface)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
TRACE("iface %p.\n", iface);
return device->removed_reason;
}
-static void STDMETHODCALLTYPE d3d12_device_GetCopyableFootprints(ID3D12Device5 *iface,
+static void STDMETHODCALLTYPE d3d12_device_GetCopyableFootprints(ID3D12Device7 *iface,
const D3D12_RESOURCE_DESC *desc, UINT first_sub_resource, UINT sub_resource_count,
UINT64 base_offset, D3D12_PLACED_SUBRESOURCE_FOOTPRINT *layouts,
UINT *row_counts, UINT64 *row_sizes, UINT64 *total_bytes)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
unsigned int i, sub_resource_idx, miplevel_idx, row_count, row_size, row_pitch;
unsigned int width, height, depth, plane_count, sub_resources_per_plane;
@@ -3870,10 +4050,10 @@ static void STDMETHODCALLTYPE d3d12_device_GetCopyableFootprints(ID3D12Device5 *
*total_bytes = total;
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_CreateQueryHeap(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateQueryHeap(ID3D12Device7 *iface,
const D3D12_QUERY_HEAP_DESC *desc, REFIID iid, void **heap)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
struct d3d12_query_heap *object;
HRESULT hr;
@@ -3886,18 +4066,18 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateQueryHeap(ID3D12Device5 *ifa
return return_interface(&object->ID3D12QueryHeap_iface, &IID_ID3D12QueryHeap, iid, heap);
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_SetStablePowerState(ID3D12Device5 *iface, BOOL enable)
+static HRESULT STDMETHODCALLTYPE d3d12_device_SetStablePowerState(ID3D12Device7 *iface, BOOL enable)
{
FIXME("iface %p, enable %#x stub!\n", iface, enable);
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_CreateCommandSignature(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateCommandSignature(ID3D12Device7 *iface,
const D3D12_COMMAND_SIGNATURE_DESC *desc, ID3D12RootSignature *root_signature,
REFIID iid, void **command_signature)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
struct d3d12_command_signature *object;
HRESULT hr;
@@ -3911,14 +4091,14 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateCommandSignature(ID3D12Devic
&IID_ID3D12CommandSignature, iid, command_signature);
}
-static void STDMETHODCALLTYPE d3d12_device_GetResourceTiling(ID3D12Device5 *iface,
+static void STDMETHODCALLTYPE d3d12_device_GetResourceTiling(ID3D12Device7 *iface,
ID3D12Resource *resource, UINT *total_tile_count,
D3D12_PACKED_MIP_INFO *packed_mip_info, D3D12_TILE_SHAPE *standard_tile_shape,
UINT *sub_resource_tiling_count, UINT first_sub_resource_tiling,
D3D12_SUBRESOURCE_TILING *sub_resource_tilings)
{
const struct d3d12_resource *resource_impl = impl_from_ID3D12Resource(resource);
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
TRACE("iface %p, resource %p, total_tile_count %p, packed_mip_info %p, "
"standard_title_shape %p, sub_resource_tiling_count %p, "
@@ -3931,9 +4111,9 @@ static void STDMETHODCALLTYPE d3d12_device_GetResourceTiling(ID3D12Device5 *ifac
sub_resource_tiling_count, first_sub_resource_tiling, sub_resource_tilings);
}
-static LUID * STDMETHODCALLTYPE d3d12_device_GetAdapterLuid(ID3D12Device5 *iface, LUID *luid)
+static LUID * STDMETHODCALLTYPE d3d12_device_GetAdapterLuid(ID3D12Device7 *iface, LUID *luid)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
TRACE("iface %p, luid %p.\n", iface, luid);
@@ -3942,15 +4122,16 @@ static LUID * STDMETHODCALLTYPE d3d12_device_GetAdapterLuid(ID3D12Device5 *iface
return luid;
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_CreatePipelineLibrary(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreatePipelineLibrary(ID3D12Device7 *iface,
const void *blob, SIZE_T blob_size, REFIID iid, void **lib)
{
- FIXME("iface %p, blob %p, blob_size %lu, iid %s, lib %p stub!\n", iface, blob, blob_size, debugstr_guid(iid), lib);
+ FIXME("iface %p, blob %p, blob_size %"PRIuPTR", iid %s, lib %p stub!\n",
+ iface, blob, (uintptr_t)blob_size, debugstr_guid(iid), lib);
return DXGI_ERROR_UNSUPPORTED;
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_SetEventOnMultipleFenceCompletion(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_SetEventOnMultipleFenceCompletion(ID3D12Device7 *iface,
ID3D12Fence *const *fences, const UINT64 *values, UINT fence_count,
D3D12_MULTIPLE_FENCE_WAIT_FLAGS flags, HANDLE event)
{
@@ -3960,7 +4141,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_SetEventOnMultipleFenceCompletion(
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_SetResidencyPriority(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_SetResidencyPriority(ID3D12Device7 *iface,
UINT object_count, ID3D12Pageable *const *objects, const D3D12_RESIDENCY_PRIORITY *priorities)
{
FIXME_ONCE("iface %p, object_count %u, objects %p, priorities %p stub!\n", iface, object_count, objects, priorities);
@@ -3968,10 +4149,10 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_SetResidencyPriority(ID3D12Device5
return S_OK;
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_CreatePipelineState(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreatePipelineState(ID3D12Device7 *iface,
const D3D12_PIPELINE_STATE_STREAM_DESC *desc, REFIID iid, void **pipeline_state)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
struct d3d12_pipeline_state *object;
HRESULT hr;
@@ -3983,7 +4164,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreatePipelineState(ID3D12Device5
return return_interface(&object->ID3D12PipelineState_iface, &IID_ID3D12PipelineState, iid, pipeline_state);
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_OpenExistingHeapFromAddress(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_OpenExistingHeapFromAddress(ID3D12Device7 *iface,
const void *address, REFIID iid, void **heap)
{
FIXME("iface %p, address %p, iid %s, heap %p stub!\n", iface, address, debugstr_guid(iid), heap);
@@ -3991,7 +4172,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_OpenExistingHeapFromAddress(ID3D12
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_OpenExistingHeapFromFileMapping(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_OpenExistingHeapFromFileMapping(ID3D12Device7 *iface,
HANDLE file_mapping, REFIID iid, void **heap)
{
FIXME("iface %p, file_mapping %p, iid %s, heap %p stub!\n", iface, file_mapping, debugstr_guid(iid), heap);
@@ -3999,7 +4180,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_OpenExistingHeapFromFileMapping(ID
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_EnqueueMakeResident(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_EnqueueMakeResident(ID3D12Device7 *iface,
D3D12_RESIDENCY_FLAGS flags, UINT num_objects, ID3D12Pageable *const *objects,
ID3D12Fence *fence, UINT64 fence_value)
{
@@ -4010,7 +4191,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_EnqueueMakeResident(ID3D12Device5
return S_OK;
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_CreateCommandList1(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateCommandList1(ID3D12Device7 *iface,
UINT node_mask, D3D12_COMMAND_LIST_TYPE type, D3D12_COMMAND_LIST_FLAGS flags,
REFIID iid, void **command_list)
{
@@ -4020,7 +4201,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateCommandList1(ID3D12Device5 *
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_CreateProtectedResourceSession(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateProtectedResourceSession(ID3D12Device7 *iface,
const D3D12_PROTECTED_RESOURCE_SESSION_DESC *desc, REFIID iid, void **session)
{
FIXME("iface %p, desc %p, iid %s, session %p stub!\n", iface, desc, debugstr_guid(iid), session);
@@ -4028,13 +4209,13 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateProtectedResourceSession(ID3
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_CreateCommittedResource1(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateCommittedResource1(ID3D12Device7 *iface,
const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags,
const D3D12_RESOURCE_DESC *desc, D3D12_RESOURCE_STATES initial_state,
const D3D12_CLEAR_VALUE *optimized_clear_value,
ID3D12ProtectedResourceSession *protected_session, REFIID iid, void **resource)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
struct d3d12_resource *object;
HRESULT hr;
@@ -4053,11 +4234,11 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateCommittedResource1(ID3D12Dev
return return_interface(&object->ID3D12Resource1_iface, &IID_ID3D12Resource1, iid, resource);
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_CreateHeap1(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateHeap1(ID3D12Device7 *iface,
const D3D12_HEAP_DESC *desc, ID3D12ProtectedResourceSession *protected_session,
REFIID iid, void **heap)
{
- struct d3d12_device *device = impl_from_ID3D12Device5(iface);
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
struct d3d12_heap *object;
HRESULT hr;
@@ -4073,7 +4254,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateHeap1(ID3D12Device5 *iface,
return return_interface(&object->ID3D12Heap_iface, &IID_ID3D12Heap, iid, heap);
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_CreateReservedResource1(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateReservedResource1(ID3D12Device7 *iface,
const D3D12_RESOURCE_DESC *desc, D3D12_RESOURCE_STATES initial_state,
const D3D12_CLEAR_VALUE *optimized_clear_value,
ID3D12ProtectedResourceSession *protected_session, REFIID iid, void **resource)
@@ -4087,17 +4268,23 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateReservedResource1(ID3D12Devi
}
static D3D12_RESOURCE_ALLOCATION_INFO * STDMETHODCALLTYPE d3d12_device_GetResourceAllocationInfo1(
- ID3D12Device5 *iface, D3D12_RESOURCE_ALLOCATION_INFO *info, UINT visible_mask,
+ ID3D12Device7 *iface, D3D12_RESOURCE_ALLOCATION_INFO *info, UINT visible_mask,
UINT count, const D3D12_RESOURCE_DESC *resource_descs,
D3D12_RESOURCE_ALLOCATION_INFO1 *info1)
{
- FIXME("iface %p, info %p, visible_mask 0x%08x, count %u, resource_descs %p, info1 %p stub!\n",
+ struct d3d12_device *device = impl_from_ID3D12Device7(iface);
+
+ TRACE("iface %p, info %p, visible_mask 0x%08x, count %u, resource_descs %p, info1 %p.\n",
iface, info, visible_mask, count, resource_descs, info1);
+ debug_ignored_node_mask(visible_mask);
+
+ d3d12_device_get_resource_allocation_info(device, info1, count, resource_descs, info);
+
return info;
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_CreateLifetimeTracker(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateLifetimeTracker(ID3D12Device7 *iface,
ID3D12LifetimeOwner *owner, REFIID iid, void **tracker)
{
FIXME("iface %p, owner %p, iid %s, tracker %p stub!\n", iface, owner, debugstr_guid(iid), tracker);
@@ -4105,12 +4292,12 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateLifetimeTracker(ID3D12Device
return E_NOTIMPL;
}
-static void STDMETHODCALLTYPE d3d12_device_RemoveDevice(ID3D12Device5 *iface)
+static void STDMETHODCALLTYPE d3d12_device_RemoveDevice(ID3D12Device7 *iface)
{
FIXME("iface %p stub!\n", iface);
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_EnumerateMetaCommands(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_EnumerateMetaCommands(ID3D12Device7 *iface,
UINT *num_meta_commands, D3D12_META_COMMAND_DESC *command_desc)
{
FIXME("iface %p, num_meta_commands %p, command_desc %p stub!\n", iface,
@@ -4119,7 +4306,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_EnumerateMetaCommands(ID3D12Device
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_EnumerateMetaCommandParameters(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_EnumerateMetaCommandParameters(ID3D12Device7 *iface,
REFGUID command_id, D3D12_META_COMMAND_PARAMETER_STAGE stage,
UINT *size_in_bytes, UINT *parameter_count,
D3D12_META_COMMAND_PARAMETER_DESC *parameter_desc)
@@ -4131,19 +4318,19 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_EnumerateMetaCommandParameters(ID3
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_CreateMetaCommand(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateMetaCommand(ID3D12Device7 *iface,
REFGUID command_id, UINT node_mask, const void *parameters_data,
SIZE_T data_size_in_bytes, REFIID iid, void **meta_command)
{
FIXME("iface %p, command_id %s, node_mask %#x, parameters_data %p, "
- "data_size_in_bytes %lu, iid %s, meta_command %p stub!\n", iface,
+ "data_size_in_bytes %"PRIuPTR", iid %s, meta_command %p stub!\n", iface,
debugstr_guid(command_id), node_mask, parameters_data,
- data_size_in_bytes, debugstr_guid(iid), meta_command);
+ (uintptr_t)data_size_in_bytes, debugstr_guid(iid), meta_command);
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE d3d12_device_CreateStateObject(ID3D12Device5 *iface,
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateStateObject(ID3D12Device7 *iface,
const D3D12_STATE_OBJECT_DESC *desc, REFIID iid, void **state_object)
{
FIXME("iface %p, desc %p, iid %s, state_object %p stub!\n", iface, desc, debugstr_guid(iid), state_object);
@@ -4151,14 +4338,14 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateStateObject(ID3D12Device5 *i
return E_NOTIMPL;
}
-static void STDMETHODCALLTYPE d3d12_device_GetRaytracingAccelerationStructurePrebuildInfo(ID3D12Device5 *iface,
+static void STDMETHODCALLTYPE d3d12_device_GetRaytracingAccelerationStructurePrebuildInfo(ID3D12Device7 *iface,
const D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS *desc,
D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO *info)
{
FIXME("iface %p, desc %p, info %p stub!\n", iface, desc, info);
}
-static D3D12_DRIVER_MATCHING_IDENTIFIER_STATUS STDMETHODCALLTYPE d3d12_device_CheckDriverMatchingIdentifier(ID3D12Device5 *iface,
+static D3D12_DRIVER_MATCHING_IDENTIFIER_STATUS STDMETHODCALLTYPE d3d12_device_CheckDriverMatchingIdentifier(ID3D12Device7 *iface,
D3D12_SERIALIZED_DATA_TYPE data_type, const D3D12_SERIALIZED_DATA_DRIVER_MATCHING_IDENTIFIER *identifier)
{
FIXME("iface %p, data_type %u, identifier %p stub!\n", iface, data_type, identifier);
@@ -4166,7 +4353,35 @@ static D3D12_DRIVER_MATCHING_IDENTIFIER_STATUS STDMETHODCALLTYPE d3d12_device_Ch
return D3D12_DRIVER_MATCHING_IDENTIFIER_UNRECOGNIZED;
}
-static const struct ID3D12Device5Vtbl d3d12_device_vtbl =
+static HRESULT STDMETHODCALLTYPE d3d12_device_SetBackgroundProcessingMode(ID3D12Device7 *iface,
+ D3D12_BACKGROUND_PROCESSING_MODE mode, D3D12_MEASUREMENTS_ACTION action, HANDLE event,
+ BOOL *further_measurements_desired)
+{
+ FIXME("iface %p, mode %#x, action %#x, event %p, further_measurements_desired %p stub!\n",
+ iface, mode, action, event, further_measurements_desired);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_device_AddToStateObject(ID3D12Device7 *iface,
+ const D3D12_STATE_OBJECT_DESC *addition, ID3D12StateObject *state_object_to_grow_from,
+ REFIID riid, void **new_state_object)
+{
+ FIXME("iface %p, addition %p, state_object_to_grow_from %p, riid %s, new_state_object %p stub!\n",
+ iface, addition, state_object_to_grow_from, debugstr_guid(riid), new_state_object);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_device_CreateProtectedResourceSession1(ID3D12Device7 *iface,
+ const D3D12_PROTECTED_RESOURCE_SESSION_DESC1 *desc, REFIID riid, void **session)
+{
+ FIXME("iface %p, desc %p, riid %s, session %p stub!\n", iface, desc, debugstr_guid(riid), session);
+
+ return E_NOTIMPL;
+}
+
+static const struct ID3D12Device7Vtbl d3d12_device_vtbl =
{
/* IUnknown methods */
d3d12_device_QueryInterface,
@@ -4241,14 +4456,53 @@ static const struct ID3D12Device5Vtbl d3d12_device_vtbl =
d3d12_device_CreateStateObject,
d3d12_device_GetRaytracingAccelerationStructurePrebuildInfo,
d3d12_device_CheckDriverMatchingIdentifier,
+ /* ID3D12Device6 methods */
+ d3d12_device_SetBackgroundProcessingMode,
+ /* ID3D12Device7 methods */
+ d3d12_device_AddToStateObject,
+ d3d12_device_CreateProtectedResourceSession1,
};
-struct d3d12_device *unsafe_impl_from_ID3D12Device5(ID3D12Device5 *iface)
+struct d3d12_device *unsafe_impl_from_ID3D12Device7(ID3D12Device7 *iface)
{
if (!iface)
return NULL;
assert(iface->lpVtbl == &d3d12_device_vtbl);
- return impl_from_ID3D12Device5(iface);
+ return impl_from_ID3D12Device7(iface);
+}
+
+static void *device_worker_main(void *arg)
+{
+ struct d3d12_descriptor_heap *heap;
+ struct d3d12_device *device = arg;
+ size_t i;
+
+ vkd3d_set_thread_name("device_worker");
+
+ vkd3d_mutex_lock(&device->worker_mutex);
+
+ while (!device->worker_should_exit)
+ {
+ for (i = 0; i < device->heap_count; ++i)
+ {
+ /* Descriptor updates are not written to Vulkan descriptor sets until a command list
+ * is submitted to a queue, while the client is free to write d3d12 descriptors earlier,
+ * from any thread. This causes a delay right before command list execution, so
+ * handling these updates in a worker thread can speed up execution significantly. */
+ heap = device->heaps[i];
+ if (heap->dirty_list_head == UINT_MAX)
+ continue;
+ vkd3d_mutex_lock(&heap->vk_sets_mutex);
+ d3d12_desc_flush_vk_heap_updates_locked(heap, device);
+ vkd3d_mutex_unlock(&heap->vk_sets_mutex);
+ }
+
+ vkd3d_cond_wait(&device->worker_cond, &device->worker_mutex);
+ }
+
+ vkd3d_mutex_unlock(&device->worker_mutex);
+
+ return NULL;
}
static HRESULT d3d12_device_init(struct d3d12_device *device,
@@ -4257,7 +4511,7 @@ static HRESULT d3d12_device_init(struct d3d12_device *device,
const struct vkd3d_vk_device_procs *vk_procs;
HRESULT hr;
- device->ID3D12Device5_iface.lpVtbl = &d3d12_device_vtbl;
+ device->ID3D12Device7_iface.lpVtbl = &d3d12_device_vtbl;
device->refcount = 1;
vkd3d_instance_incref(device->vkd3d_instance = instance);
@@ -4270,6 +4524,14 @@ static HRESULT d3d12_device_init(struct d3d12_device *device,
device->vk_device = VK_NULL_HANDLE;
+ device->heaps = NULL;
+ device->heap_capacity = 0;
+ device->heap_count = 0;
+ memset(&device->worker_thread, 0, sizeof(device->worker_thread));
+ device->worker_should_exit = false;
+ vkd3d_mutex_init(&device->worker_mutex);
+ vkd3d_cond_init(&device->worker_cond);
+
if (FAILED(hr = vkd3d_create_vk_device(device, create_info)))
goto out_free_instance;
@@ -4291,6 +4553,13 @@ static HRESULT d3d12_device_init(struct d3d12_device *device,
if (FAILED(hr = vkd3d_vk_descriptor_heap_layouts_init(device)))
goto out_cleanup_uav_clear_state;
+ if (device->use_vk_heaps && FAILED(hr = vkd3d_create_thread(device->vkd3d_instance,
+ device_worker_main, device, &device->worker_thread)))
+ {
+ WARN("Failed to create worker thread, hr %s.\n", debugstr_hresult(hr));
+ goto out_cleanup_descriptor_heap_layouts;
+ }
+
vkd3d_render_pass_cache_init(&device->render_pass_cache);
vkd3d_gpu_va_allocator_init(&device->gpu_va_allocator);
vkd3d_time_domains_init(device);
@@ -4308,6 +4577,8 @@ static HRESULT d3d12_device_init(struct d3d12_device *device,
return S_OK;
+out_cleanup_descriptor_heap_layouts:
+ vkd3d_vk_descriptor_heap_layouts_cleanup(device);
out_cleanup_uav_clear_state:
vkd3d_uav_clear_state_cleanup(&device->uav_clear_state, device);
out_destroy_null_resources:
@@ -4354,13 +4625,47 @@ void d3d12_device_mark_as_removed(struct d3d12_device *device, HRESULT reason,
va_list args;
va_start(args, message);
- WARN("Device %p is lost (reason %#x, \"%s\").\n",
- device, reason, vkd3d_dbg_vsprintf(message, args));
+ WARN("Device %p is lost (reason %s, \"%s\").\n",
+ device, debugstr_hresult(reason), vkd3d_dbg_vsprintf(message, args));
va_end(args);
device->removed_reason = reason;
}
+HRESULT d3d12_device_add_descriptor_heap(struct d3d12_device *device, struct d3d12_descriptor_heap *heap)
+{
+ vkd3d_mutex_lock(&device->worker_mutex);
+
+ if (!vkd3d_array_reserve((void **)&device->heaps, &device->heap_capacity, device->heap_count + 1,
+ sizeof(*device->heaps)))
+ {
+ vkd3d_mutex_unlock(&device->worker_mutex);
+ return E_OUTOFMEMORY;
+ }
+ device->heaps[device->heap_count++] = heap;
+
+ vkd3d_mutex_unlock(&device->worker_mutex);
+
+ return S_OK;
+}
+
+void d3d12_device_remove_descriptor_heap(struct d3d12_device *device, struct d3d12_descriptor_heap *heap)
+{
+ size_t i;
+
+ vkd3d_mutex_lock(&device->worker_mutex);
+
+ for (i = 0; i < device->heap_count; ++i)
+ {
+ if (device->heaps[i] == heap)
+ {
+ device->heaps[i] = device->heaps[--device->heap_count];
+ break;
+ }
+ }
+
+ vkd3d_mutex_unlock(&device->worker_mutex);
+}
#ifdef _WIN32
struct thread_data
@@ -4403,7 +4708,7 @@ HRESULT vkd3d_create_thread(struct vkd3d_instance *instance,
thread_data->data = data;
if (!(thread->handle = CreateThread(NULL, 0, call_thread_main, thread_data, 0, NULL)))
{
- ERR("Failed to create thread, error %d.\n", GetLastError());
+ ERR("Failed to create thread, error %lu.\n", GetLastError());
vkd3d_free(thread_data);
hr = E_FAIL;
}
@@ -4429,7 +4734,7 @@ HRESULT vkd3d_join_thread(struct vkd3d_instance *instance, union vkd3d_thread_ha
if (instance->join_thread)
{
if (FAILED(hr = instance->join_thread(thread->handle)))
- ERR("Failed to join thread, hr %#x.\n", hr);
+ ERR("Failed to join thread, hr %s.\n", debugstr_hresult(hr));
}
else
{
@@ -4454,28 +4759,28 @@ HRESULT vkd3d_join_thread(struct vkd3d_instance *instance, union vkd3d_thread_ha
IUnknown *vkd3d_get_device_parent(ID3D12Device *device)
{
- struct d3d12_device *d3d12_device = impl_from_ID3D12Device5((ID3D12Device5 *)device);
+ struct d3d12_device *d3d12_device = impl_from_ID3D12Device7((ID3D12Device7 *)device);
return d3d12_device->parent;
}
VkDevice vkd3d_get_vk_device(ID3D12Device *device)
{
- struct d3d12_device *d3d12_device = impl_from_ID3D12Device5((ID3D12Device5 *)device);
+ struct d3d12_device *d3d12_device = impl_from_ID3D12Device7((ID3D12Device7 *)device);
return d3d12_device->vk_device;
}
VkPhysicalDevice vkd3d_get_vk_physical_device(ID3D12Device *device)
{
- struct d3d12_device *d3d12_device = impl_from_ID3D12Device5((ID3D12Device5 *)device);
+ struct d3d12_device *d3d12_device = impl_from_ID3D12Device7((ID3D12Device7 *)device);
return d3d12_device->vk_physical_device;
}
struct vkd3d_instance *vkd3d_instance_from_device(ID3D12Device *device)
{
- struct d3d12_device *d3d12_device = impl_from_ID3D12Device5((ID3D12Device5 *)device);
+ struct d3d12_device *d3d12_device = impl_from_ID3D12Device7((ID3D12Device7 *)device);
return d3d12_device->vkd3d_instance;
}
diff --git a/libs/vkd3d/libs/vkd3d/resource.c b/libs/vkd3d/libs/vkd3d/resource.c
index abbdfbe2015..8f4d18358d2 100644
--- a/libs/vkd3d/libs/vkd3d/resource.c
+++ b/libs/vkd3d/libs/vkd3d/resource.c
@@ -22,7 +22,7 @@
#define VKD3D_NULL_BUFFER_SIZE 16
#define VKD3D_NULL_VIEW_FORMAT DXGI_FORMAT_R8G8B8A8_UNORM
-LONG64 object_global_serial_id;
+uint64_t object_global_serial_id;
static inline bool is_cpu_accessible_heap(const D3D12_HEAP_PROPERTIES *properties)
{
@@ -308,7 +308,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_heap_QueryInterface(ID3D12Heap *iface,
static ULONG STDMETHODCALLTYPE d3d12_heap_AddRef(ID3D12Heap *iface)
{
struct d3d12_heap *heap = impl_from_ID3D12Heap(iface);
- ULONG refcount = InterlockedIncrement(&heap->refcount);
+ unsigned int refcount = vkd3d_atomic_increment_u32(&heap->refcount);
TRACE("%p increasing refcount to %u.\n", heap, refcount);
@@ -345,7 +345,7 @@ static void d3d12_heap_destroy(struct d3d12_heap *heap)
static ULONG STDMETHODCALLTYPE d3d12_heap_Release(ID3D12Heap *iface)
{
struct d3d12_heap *heap = impl_from_ID3D12Heap(iface);
- ULONG refcount = InterlockedDecrement(&heap->refcount);
+ unsigned int refcount = vkd3d_atomic_decrement_u32(&heap->refcount);
TRACE("%p decreasing refcount to %u.\n", heap, refcount);
@@ -358,7 +358,7 @@ static ULONG STDMETHODCALLTYPE d3d12_heap_Release(ID3D12Heap *iface)
static void d3d12_heap_resource_destroyed(struct d3d12_heap *heap)
{
- if (!InterlockedDecrement(&heap->resource_count) && (!heap->refcount || heap->is_private))
+ if (!vkd3d_atomic_decrement_u32(&heap->resource_count) && (!heap->refcount || heap->is_private))
d3d12_heap_destroy(heap);
}
@@ -940,7 +940,7 @@ static HRESULT vkd3d_create_image(struct d3d12_device *device,
}
HRESULT vkd3d_get_image_allocation_info(struct d3d12_device *device,
- const D3D12_RESOURCE_DESC *desc, D3D12_RESOURCE_ALLOCATION_INFO *allocation_info)
+ const D3D12_RESOURCE_DESC *desc, struct vkd3d_resource_allocation_info *allocation_info)
{
static const D3D12_HEAP_PROPERTIES heap_properties = {D3D12_HEAP_TYPE_DEFAULT};
const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
@@ -968,8 +968,8 @@ HRESULT vkd3d_get_image_allocation_info(struct d3d12_device *device,
VK_CALL(vkGetImageMemoryRequirements(device->vk_device, vk_image, &requirements));
VK_CALL(vkDestroyImage(device->vk_device, vk_image, NULL));
- allocation_info->SizeInBytes = requirements.size;
- allocation_info->Alignment = requirements.alignment;
+ allocation_info->size_in_bytes = requirements.size;
+ allocation_info->alignment = requirements.alignment;
}
return hr;
@@ -1003,7 +1003,7 @@ static void d3d12_resource_destroy(struct d3d12_resource *resource, struct d3d12
static ULONG d3d12_resource_incref(struct d3d12_resource *resource)
{
- ULONG refcount = InterlockedIncrement(&resource->internal_refcount);
+ unsigned int refcount = vkd3d_atomic_increment_u32(&resource->internal_refcount);
TRACE("%p increasing refcount to %u.\n", resource, refcount);
@@ -1012,7 +1012,7 @@ static ULONG d3d12_resource_incref(struct d3d12_resource *resource)
static ULONG d3d12_resource_decref(struct d3d12_resource *resource)
{
- ULONG refcount = InterlockedDecrement(&resource->internal_refcount);
+ unsigned int refcount = vkd3d_atomic_decrement_u32(&resource->internal_refcount);
TRACE("%p decreasing refcount to %u.\n", resource, refcount);
@@ -1284,7 +1284,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_resource_QueryInterface(ID3D12Resource1 *
static ULONG STDMETHODCALLTYPE d3d12_resource_AddRef(ID3D12Resource1 *iface)
{
struct d3d12_resource *resource = impl_from_ID3D12Resource1(iface);
- ULONG refcount = InterlockedIncrement(&resource->refcount);
+ unsigned int refcount = vkd3d_atomic_increment_u32(&resource->refcount);
TRACE("%p increasing refcount to %u.\n", resource, refcount);
@@ -1302,7 +1302,7 @@ static ULONG STDMETHODCALLTYPE d3d12_resource_AddRef(ID3D12Resource1 *iface)
static ULONG STDMETHODCALLTYPE d3d12_resource_Release(ID3D12Resource1 *iface)
{
struct d3d12_resource *resource = impl_from_ID3D12Resource1(iface);
- ULONG refcount = InterlockedDecrement(&resource->refcount);
+ unsigned int refcount = vkd3d_atomic_decrement_u32(&resource->refcount);
TRACE("%p decreasing refcount to %u.\n", resource, refcount);
@@ -2174,7 +2174,7 @@ static HRESULT vkd3d_bind_heap_memory(struct d3d12_device *device,
{
resource->heap = heap;
resource->heap_offset = heap_offset;
- InterlockedIncrement(&heap->resource_count);
+ vkd3d_atomic_increment_u32(&heap->resource_count);
}
else
{
@@ -2239,7 +2239,7 @@ HRESULT d3d12_reserved_resource_create(struct d3d12_device *device,
HRESULT vkd3d_create_image_resource(ID3D12Device *device,
const struct vkd3d_image_resource_create_info *create_info, ID3D12Resource **resource)
{
- struct d3d12_device *d3d12_device = unsafe_impl_from_ID3D12Device5((ID3D12Device5 *)device);
+ struct d3d12_device *d3d12_device = unsafe_impl_from_ID3D12Device7((ID3D12Device7 *)device);
struct d3d12_resource *object;
HRESULT hr;
@@ -2314,14 +2314,14 @@ static void *vkd3d_desc_object_cache_get(struct vkd3d_desc_object_cache *cache)
STATIC_ASSERT(!(ARRAY_SIZE(cache->heads) & HEAD_INDEX_MASK));
- i = (vkd3d_atomic_increment(&cache->next_index)) & HEAD_INDEX_MASK;
+ i = vkd3d_atomic_increment_u32(&cache->next_index) & HEAD_INDEX_MASK;
for (;;)
{
if (vkd3d_atomic_compare_exchange(&cache->heads[i].spinlock, 0, 1))
{
if ((u.object = cache->heads[i].head))
{
- vkd3d_atomic_decrement(&cache->free_count);
+ vkd3d_atomic_decrement_u32(&cache->free_count);
cache->heads[i].head = u.header->next;
vkd3d_atomic_exchange(&cache->heads[i].spinlock, 0);
return u.object;
@@ -2345,7 +2345,7 @@ static void vkd3d_desc_object_cache_push(struct vkd3d_desc_object_cache *cache,
/* Using the same index as above may result in a somewhat uneven distribution,
* but the main objective is to avoid costly spinlock contention. */
- i = (vkd3d_atomic_increment(&cache->next_index)) & HEAD_INDEX_MASK;
+ i = vkd3d_atomic_increment_u32(&cache->next_index) & HEAD_INDEX_MASK;
for (;;)
{
if (vkd3d_atomic_compare_exchange(&cache->heads[i].spinlock, 0, 1))
@@ -2357,7 +2357,7 @@ static void vkd3d_desc_object_cache_push(struct vkd3d_desc_object_cache *cache,
u.header->next = head;
cache->heads[i].head = u.object;
vkd3d_atomic_exchange(&cache->heads[i].spinlock, 0);
- vkd3d_atomic_increment(&cache->free_count);
+ vkd3d_atomic_increment_u32(&cache->free_count);
}
#undef HEAD_INDEX_MASK
@@ -2429,7 +2429,7 @@ void vkd3d_view_decref(void *view, struct d3d12_device *device)
{
union d3d12_desc_object u = {view};
- if (vkd3d_atomic_decrement(&u.header->refcount))
+ if (vkd3d_atomic_decrement_u32(&u.header->refcount))
return;
if (u.header->magic != VKD3D_DESCRIPTOR_MAGIC_CBV)
@@ -2470,12 +2470,14 @@ static void d3d12_desc_write_vk_heap_null_descriptor(struct d3d12_descriptor_hea
{
const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
struct d3d12_descriptor_heap_vk_set *descriptor_set;
- enum vkd3d_vk_descriptor_set_index set;
+ enum vkd3d_vk_descriptor_set_index set, end;
unsigned int i = writes->count;
+ end = device->vk_info.EXT_mutable_descriptor_type ? VKD3D_SET_INDEX_UNIFORM_BUFFER
+ : VKD3D_SET_INDEX_STORAGE_IMAGE;
/* Binding a shader with the wrong null descriptor type works in Windows.
* To support that here we must write one to all applicable Vulkan sets. */
- for (set = VKD3D_SET_INDEX_UNIFORM_BUFFER; set <= VKD3D_SET_INDEX_STORAGE_IMAGE; ++set)
+ for (set = VKD3D_SET_INDEX_UNIFORM_BUFFER; set <= end; ++set)
{
descriptor_set = &descriptor_heap->vk_descriptor_sets[set];
writes->vk_descriptor_writes[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
@@ -2632,20 +2634,18 @@ void d3d12_desc_flush_vk_heap_updates_locked(struct d3d12_descriptor_heap *descr
for (; i != UINT_MAX; i = next)
{
src = &descriptors[i];
- next = (int)src->next >> 1;
+ next = vkd3d_atomic_exchange(&src->next, 0);
+ next = (int)next >> 1;
+ /* A race exists here between updating src->next and getting the current object. The best
+ * we can do is get the object last, which may result in a harmless rewrite later. */
u.object = d3d12_desc_get_object_ref(src, device);
if (!u.object)
- {
- vkd3d_atomic_exchange(&src->next, 0);
continue;
- }
writes.held_refs[writes.held_ref_count++] = u.object;
d3d12_desc_write_vk_heap(descriptor_heap, i, &writes, u.object, device);
-
- vkd3d_atomic_exchange(&src->next, 0);
}
/* Avoid thunk calls wherever possible. */
@@ -3446,6 +3446,7 @@ static void vkd3d_create_null_uav(struct d3d12_desc *descriptor,
vkd3d_desc.miplevel_count = 1;
vkd3d_desc.layer_idx = 0;
vkd3d_desc.layer_count = 1;
+ vkd3d_desc.vk_image_aspect = VK_IMAGE_ASPECT_COLOR_BIT;
vkd3d_desc.components.r = VK_COMPONENT_SWIZZLE_R;
vkd3d_desc.components.g = VK_COMPONENT_SWIZZLE_G;
vkd3d_desc.components.b = VK_COMPONENT_SWIZZLE_B;
@@ -3663,11 +3664,27 @@ static VkSamplerAddressMode vk_address_mode_from_d3d12(const struct d3d12_device
}
}
+static VkBorderColor vk_border_colour_from_d3d12(D3D12_STATIC_BORDER_COLOR colour)
+{
+ switch (colour)
+ {
+ case D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK:
+ return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
+ case D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK:
+ return VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
+ case D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE:
+ return VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
+ default:
+ FIXME("Unhandled border colour %#x.\n", colour);
+ return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
+ }
+}
+
static VkResult d3d12_create_sampler(struct d3d12_device *device, D3D12_FILTER filter,
D3D12_TEXTURE_ADDRESS_MODE address_u, D3D12_TEXTURE_ADDRESS_MODE address_v,
D3D12_TEXTURE_ADDRESS_MODE address_w, float mip_lod_bias, unsigned int max_anisotropy,
- D3D12_COMPARISON_FUNC comparison_func, float min_lod, float max_lod,
- VkSampler *vk_sampler)
+ D3D12_COMPARISON_FUNC comparison_func, D3D12_STATIC_BORDER_COLOR border_colour,
+ float min_lod, float max_lod, VkSampler *vk_sampler)
{
const struct vkd3d_vk_device_procs *vk_procs;
struct VkSamplerCreateInfo sampler_desc;
@@ -3697,15 +3714,48 @@ static VkResult d3d12_create_sampler(struct d3d12_device *device, D3D12_FILTER f
sampler_desc.maxLod = max_lod;
sampler_desc.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
sampler_desc.unnormalizedCoordinates = VK_FALSE;
+
+ if (address_u == D3D12_TEXTURE_ADDRESS_MODE_BORDER || address_v == D3D12_TEXTURE_ADDRESS_MODE_BORDER
+ || address_w == D3D12_TEXTURE_ADDRESS_MODE_BORDER)
+ sampler_desc.borderColor = vk_border_colour_from_d3d12(border_colour);
+
if ((vr = VK_CALL(vkCreateSampler(device->vk_device, &sampler_desc, NULL, vk_sampler))) < 0)
WARN("Failed to create Vulkan sampler, vr %d.\n", vr);
return vr;
}
+static D3D12_STATIC_BORDER_COLOR d3d12_static_border_colour(const float *colour)
+{
+ unsigned int i;
+
+ static const struct
+ {
+ float colour[4];
+ D3D12_STATIC_BORDER_COLOR static_colour;
+ }
+ colours[] =
+ {
+ {{0.0f, 0.0f, 0.0f, 0.0f}, D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK},
+ {{0.0f, 0.0f, 0.0f, 1.0f}, D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK},
+ {{1.0f, 1.0f, 1.0f, 1.0f}, D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(colours); ++i)
+ {
+ if (!memcmp(colour, colours[i].colour, sizeof(colours[i].colour)))
+ return colours[i].static_colour;
+ }
+
+ FIXME("Unhandled border colour {%.8e, %.8e, %.8e, %.8e}.\n", colour[0], colour[1], colour[2], colour[3]);
+
+ return D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK;
+}
+
void d3d12_desc_create_sampler(struct d3d12_desc *sampler,
struct d3d12_device *device, const D3D12_SAMPLER_DESC *desc)
{
+ D3D12_STATIC_BORDER_COLOR static_colour = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK;
struct vkd3d_view *view;
if (!desc)
@@ -3717,8 +3767,7 @@ void d3d12_desc_create_sampler(struct d3d12_desc *sampler,
if (desc->AddressU == D3D12_TEXTURE_ADDRESS_MODE_BORDER
|| desc->AddressV == D3D12_TEXTURE_ADDRESS_MODE_BORDER
|| desc->AddressW == D3D12_TEXTURE_ADDRESS_MODE_BORDER)
- FIXME("Ignoring border color {%.8e, %.8e, %.8e, %.8e}.\n",
- desc->BorderColor[0], desc->BorderColor[1], desc->BorderColor[2], desc->BorderColor[3]);
+ static_colour = d3d12_static_border_colour(desc->BorderColor);
if (!(view = vkd3d_view_create(VKD3D_DESCRIPTOR_MAGIC_SAMPLER, VK_DESCRIPTOR_TYPE_SAMPLER,
VKD3D_VIEW_TYPE_SAMPLER, device)))
@@ -3726,9 +3775,9 @@ void d3d12_desc_create_sampler(struct d3d12_desc *sampler,
view->v.u.vk_sampler = VK_NULL_HANDLE;
view->v.format = NULL;
- if (d3d12_create_sampler(device, desc->Filter, desc->AddressU,
- desc->AddressV, desc->AddressW, desc->MipLODBias, desc->MaxAnisotropy,
- desc->ComparisonFunc, desc->MinLOD, desc->MaxLOD, &view->v.u.vk_sampler) < 0)
+ if (d3d12_create_sampler(device, desc->Filter, desc->AddressU, desc->AddressV,
+ desc->AddressW, desc->MipLODBias, desc->MaxAnisotropy, desc->ComparisonFunc,
+ static_colour, desc->MinLOD, desc->MaxLOD, &view->v.u.vk_sampler) < 0)
{
vkd3d_view_decref(view, device);
return;
@@ -3742,14 +3791,9 @@ HRESULT vkd3d_create_static_sampler(struct d3d12_device *device,
{
VkResult vr;
- if (desc->AddressU == D3D12_TEXTURE_ADDRESS_MODE_BORDER
- || desc->AddressV == D3D12_TEXTURE_ADDRESS_MODE_BORDER
- || desc->AddressW == D3D12_TEXTURE_ADDRESS_MODE_BORDER)
- FIXME("Ignoring border %#x.\n", desc->BorderColor);
-
- vr = d3d12_create_sampler(device, desc->Filter, desc->AddressU,
- desc->AddressV, desc->AddressW, desc->MipLODBias, desc->MaxAnisotropy,
- desc->ComparisonFunc, desc->MinLOD, desc->MaxLOD, vk_sampler);
+ vr = d3d12_create_sampler(device, desc->Filter, desc->AddressU, desc->AddressV,
+ desc->AddressW, desc->MipLODBias, desc->MaxAnisotropy, desc->ComparisonFunc,
+ desc->BorderColor, desc->MinLOD, desc->MaxLOD, vk_sampler);
return hresult_from_vk_result(vr);
}
@@ -3966,7 +4010,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_descriptor_heap_QueryInterface(ID3D12Desc
static ULONG STDMETHODCALLTYPE d3d12_descriptor_heap_AddRef(ID3D12DescriptorHeap *iface)
{
struct d3d12_descriptor_heap *heap = impl_from_ID3D12DescriptorHeap(iface);
- ULONG refcount = InterlockedIncrement(&heap->refcount);
+ unsigned int refcount = vkd3d_atomic_increment_u32(&heap->refcount);
TRACE("%p increasing refcount to %u.\n", heap, refcount);
@@ -3976,7 +4020,7 @@ static ULONG STDMETHODCALLTYPE d3d12_descriptor_heap_AddRef(ID3D12DescriptorHeap
static ULONG STDMETHODCALLTYPE d3d12_descriptor_heap_Release(ID3D12DescriptorHeap *iface)
{
struct d3d12_descriptor_heap *heap = impl_from_ID3D12DescriptorHeap(iface);
- ULONG refcount = InterlockedDecrement(&heap->refcount);
+ unsigned int refcount = vkd3d_atomic_decrement_u32(&heap->refcount);
TRACE("%p decreasing refcount to %u.\n", heap, refcount);
@@ -3997,6 +4041,9 @@ static ULONG STDMETHODCALLTYPE d3d12_descriptor_heap_Release(ID3D12DescriptorHea
{
struct d3d12_desc *descriptors = (struct d3d12_desc *)heap->descriptors;
+ if (heap->use_vk_heaps)
+ d3d12_device_remove_descriptor_heap(device, heap);
+
for (i = 0; i < heap->desc.NumDescriptors; ++i)
{
d3d12_desc_destroy(&descriptors[i], device);
@@ -4175,9 +4222,11 @@ static HRESULT d3d12_descriptor_heap_create_descriptor_pool(struct d3d12_descrip
for (set = 0, pool_desc.poolSizeCount = 0; set < ARRAY_SIZE(device->vk_descriptor_heap_layouts); ++set)
{
- if (device->vk_descriptor_heap_layouts[set].applicable_heap_type == desc->Type)
+ if (device->vk_descriptor_heap_layouts[set].applicable_heap_type == desc->Type
+ && device->vk_descriptor_heap_layouts[set].vk_set_layout)
{
- pool_sizes[pool_desc.poolSizeCount].type = device->vk_descriptor_heap_layouts[set].type;
+ pool_sizes[pool_desc.poolSizeCount].type = (device->vk_info.EXT_mutable_descriptor_type && !set)
+ ? VK_DESCRIPTOR_TYPE_MUTABLE_EXT : device->vk_descriptor_heap_layouts[set].type;
pool_sizes[pool_desc.poolSizeCount++].descriptorCount = desc->NumDescriptors;
}
}
@@ -4203,6 +4252,16 @@ static HRESULT d3d12_descriptor_heap_create_descriptor_set(struct d3d12_descript
VkDescriptorSetAllocateInfo set_desc;
VkResult vr;
+ if (!device->vk_descriptor_heap_layouts[set].vk_set_layout)
+ {
+ /* Set 0 uses mutable descriptors, and this set is unused. */
+ if (!descriptor_heap->vk_descriptor_sets[0].vk_set)
+ d3d12_descriptor_heap_create_descriptor_set(descriptor_heap, device, 0);
+ descriptor_set->vk_set = descriptor_heap->vk_descriptor_sets[0].vk_set;
+ descriptor_set->vk_type = device->vk_descriptor_heap_layouts[set].type;
+ return S_OK;
+ }
+
set_desc.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
set_desc.pNext = &set_size;
set_desc.descriptorPool = descriptor_heap->vk_descriptor_pool;
@@ -4255,7 +4314,7 @@ static HRESULT d3d12_descriptor_heap_init(struct d3d12_descriptor_heap *descript
descriptor_heap->ID3D12DescriptorHeap_iface.lpVtbl = &d3d12_descriptor_heap_vtbl;
descriptor_heap->refcount = 1;
- descriptor_heap->serial_id = InterlockedIncrement64(&object_global_serial_id);
+ descriptor_heap->serial_id = vkd3d_atomic_increment_u64(&object_global_serial_id);
descriptor_heap->desc = *desc;
@@ -4320,6 +4379,12 @@ HRESULT d3d12_descriptor_heap_create(struct d3d12_device *device,
dst[i].next = 0;
}
object->dirty_list_head = UINT_MAX;
+
+ if (object->use_vk_heaps && FAILED(hr = d3d12_device_add_descriptor_heap(device, object)))
+ {
+ vkd3d_free(object);
+ return hr;
+ }
}
else
{
@@ -4364,7 +4429,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_query_heap_QueryInterface(ID3D12QueryHeap
static ULONG STDMETHODCALLTYPE d3d12_query_heap_AddRef(ID3D12QueryHeap *iface)
{
struct d3d12_query_heap *heap = impl_from_ID3D12QueryHeap(iface);
- ULONG refcount = InterlockedIncrement(&heap->refcount);
+ unsigned int refcount = vkd3d_atomic_increment_u32(&heap->refcount);
TRACE("%p increasing refcount to %u.\n", heap, refcount);
@@ -4374,7 +4439,7 @@ static ULONG STDMETHODCALLTYPE d3d12_query_heap_AddRef(ID3D12QueryHeap *iface)
static ULONG STDMETHODCALLTYPE d3d12_query_heap_Release(ID3D12QueryHeap *iface)
{
struct d3d12_query_heap *heap = impl_from_ID3D12QueryHeap(iface);
- ULONG refcount = InterlockedDecrement(&heap->refcount);
+ unsigned int refcount = vkd3d_atomic_decrement_u32(&heap->refcount);
TRACE("%p decreasing refcount to %u.\n", heap, refcount);
@@ -4858,7 +4923,7 @@ HRESULT vkd3d_init_null_resources(struct vkd3d_null_resources *null_resources,
return vkd3d_init_null_resources_data(null_resources, device);
fail:
- ERR("Failed to initialize NULL resources, hr %#x.\n", hr);
+ ERR("Failed to initialise NULL resources, hr %s.\n", debugstr_hresult(hr));
vkd3d_destroy_null_resources(null_resources, device);
return hr;
}
diff --git a/libs/vkd3d/libs/vkd3d/state.c b/libs/vkd3d/libs/vkd3d/state.c
index fc3187f4bea..3428742dd7f 100644
--- a/libs/vkd3d/libs/vkd3d/state.c
+++ b/libs/vkd3d/libs/vkd3d/state.c
@@ -52,7 +52,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_root_signature_QueryInterface(ID3D12RootS
static ULONG STDMETHODCALLTYPE d3d12_root_signature_AddRef(ID3D12RootSignature *iface)
{
struct d3d12_root_signature *root_signature = impl_from_ID3D12RootSignature(iface);
- ULONG refcount = InterlockedIncrement(&root_signature->refcount);
+ unsigned int refcount = vkd3d_atomic_increment_u32(&root_signature->refcount);
TRACE("%p increasing refcount to %u.\n", root_signature, refcount);
@@ -110,7 +110,7 @@ static void d3d12_root_signature_cleanup(struct d3d12_root_signature *root_signa
static ULONG STDMETHODCALLTYPE d3d12_root_signature_Release(ID3D12RootSignature *iface)
{
struct d3d12_root_signature *root_signature = impl_from_ID3D12RootSignature(iface);
- ULONG refcount = InterlockedDecrement(&root_signature->refcount);
+ unsigned int refcount = vkd3d_atomic_decrement_u32(&root_signature->refcount);
TRACE("%p decreasing refcount to %u.\n", root_signature, refcount);
@@ -515,7 +515,7 @@ static HRESULT d3d12_root_signature_init_push_constants(struct d3d12_root_signat
assert(p->ShaderVisibility <= D3D12_SHADER_VISIBILITY_PIXEL);
push_constants[p->ShaderVisibility].stageFlags = use_vk_heaps ? VK_SHADER_STAGE_ALL
: stage_flags_from_visibility(p->ShaderVisibility);
- push_constants[p->ShaderVisibility].size += p->u.Constants.Num32BitValues * sizeof(uint32_t);
+ push_constants[p->ShaderVisibility].size += align(p->u.Constants.Num32BitValues, 4) * sizeof(uint32_t);
}
if (push_constants[D3D12_SHADER_VISIBILITY_ALL].size)
{
@@ -564,7 +564,7 @@ static HRESULT d3d12_root_signature_init_push_constants(struct d3d12_root_signat
idx = push_constant_count == 1 ? 0 : p->ShaderVisibility;
offset = push_constants_offset[idx];
- push_constants_offset[idx] += p->u.Constants.Num32BitValues * sizeof(uint32_t);
+ push_constants_offset[idx] += align(p->u.Constants.Num32BitValues, 4) * sizeof(uint32_t);
root_signature->parameters[i].parameter_type = p->ParameterType;
root_constant->stage_flags = push_constant_count == 1
@@ -848,7 +848,20 @@ static void vkd3d_descriptor_heap_binding_from_descriptor_range(const struct d3d
const struct vkd3d_device_descriptor_limits *descriptor_limits = &root_signature->device->vk_info.descriptor_limits;
unsigned int descriptor_set_size;
- switch (range->type)
+ if (root_signature->device->vk_info.EXT_mutable_descriptor_type)
+ {
+ if (range->type == VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER)
+ {
+ binding->set = VKD3D_SET_INDEX_SAMPLER;
+ descriptor_set_size = descriptor_limits->sampler_max_descriptors;
+ }
+ else
+ {
+ binding->set = 0;
+ descriptor_set_size = descriptor_limits->sampled_image_max_descriptors;
+ }
+ }
+ else switch (range->type)
{
case VKD3D_SHADER_DESCRIPTOR_TYPE_SRV:
binding->set = is_buffer ? VKD3D_SET_INDEX_UNIFORM_TEXEL_BUFFER : VKD3D_SET_INDEX_SAMPLED_IMAGE;
@@ -1368,8 +1381,14 @@ static unsigned int d3d12_root_signature_copy_descriptor_set_layouts(const struc
if (device->use_vk_heaps)
{
+ VkDescriptorSetLayout mutable_layout = device->vk_descriptor_heap_layouts[0].vk_set_layout;
+
for (set = 0; set < ARRAY_SIZE(device->vk_descriptor_heap_layouts); ++set)
- vk_set_layouts[i++] = device->vk_descriptor_heap_layouts[set].vk_set_layout;
+ {
+ VkDescriptorSetLayout vk_set_layout = device->vk_descriptor_heap_layouts[set].vk_set_layout;
+ /* All layouts must be valid, so if null, just set it to the mutable one. */
+ vk_set_layouts[i++] = vk_set_layout ? vk_set_layout : mutable_layout;
+ }
}
return i;
@@ -1691,7 +1710,7 @@ HRESULT vkd3d_render_pass_cache_find(struct vkd3d_render_pass_cache *cache,
HRESULT hr = S_OK;
unsigned int i;
- vkd3d_mutex_lock(&device->mutex);
+ vkd3d_mutex_lock(&device->pipeline_cache_mutex);
for (i = 0; i < cache->render_pass_count; ++i)
{
@@ -1708,7 +1727,7 @@ HRESULT vkd3d_render_pass_cache_find(struct vkd3d_render_pass_cache *cache,
if (!found)
hr = vkd3d_render_pass_cache_create_pass_locked(cache, device, key, vk_render_pass);
- vkd3d_mutex_unlock(&device->mutex);
+ vkd3d_mutex_unlock(&device->pipeline_cache_mutex);
return hr;
}
@@ -1965,7 +1984,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_pipeline_state_QueryInterface(ID3D12Pipel
static ULONG STDMETHODCALLTYPE d3d12_pipeline_state_AddRef(ID3D12PipelineState *iface)
{
struct d3d12_pipeline_state *state = impl_from_ID3D12PipelineState(iface);
- ULONG refcount = InterlockedIncrement(&state->refcount);
+ unsigned int refcount = vkd3d_atomic_increment_u32(&state->refcount);
TRACE("%p increasing refcount to %u.\n", state, refcount);
@@ -2008,7 +2027,7 @@ static void d3d12_pipeline_uav_counter_state_cleanup(struct d3d12_pipeline_uav_c
static ULONG STDMETHODCALLTYPE d3d12_pipeline_state_Release(ID3D12PipelineState *iface)
{
struct d3d12_pipeline_state *state = impl_from_ID3D12PipelineState(iface);
- ULONG refcount = InterlockedDecrement(&state->refcount);
+ unsigned int refcount = vkd3d_atomic_decrement_u32(&state->refcount);
TRACE("%p decreasing refcount to %u.\n", state, refcount);
@@ -2129,6 +2148,18 @@ static inline unsigned int typed_uav_compile_option(const struct d3d12_device *d
: VKD3D_SHADER_COMPILE_OPTION_TYPED_UAV_READ_FORMAT_R32;
}
+static unsigned int feature_flags_compile_option(const struct d3d12_device *device)
+{
+ unsigned int flags = 0;
+
+ if (device->feature_options1.Int64ShaderOps)
+ flags |= VKD3D_SHADER_COMPILE_OPTION_FEATURE_INT64;
+ if (device->feature_options.DoublePrecisionFloatShaderOps)
+ flags |= VKD3D_SHADER_COMPILE_OPTION_FEATURE_FLOAT64;
+
+ return flags;
+}
+
static HRESULT create_shader_stage(struct d3d12_device *device,
struct VkPipelineShaderStageCreateInfo *stage_desc, enum VkShaderStageFlagBits stage,
const D3D12_SHADER_BYTECODE *code, const struct vkd3d_shader_interface_info *shader_interface)
@@ -2145,6 +2176,7 @@ static HRESULT create_shader_stage(struct d3d12_device *device,
{VKD3D_SHADER_COMPILE_OPTION_API_VERSION, VKD3D_SHADER_API_VERSION_1_10},
{VKD3D_SHADER_COMPILE_OPTION_TYPED_UAV, typed_uav_compile_option(device)},
{VKD3D_SHADER_COMPILE_OPTION_WRITE_TESS_GEOM_POINT_SIZE, 0},
+ {VKD3D_SHADER_COMPILE_OPTION_FEATURE, feature_flags_compile_option(device)},
};
stage_desc->sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
@@ -2240,7 +2272,7 @@ static HRESULT vkd3d_create_compute_pipeline(struct d3d12_device *device,
VK_CALL(vkDestroyShaderModule(device->vk_device, pipeline_info.stage.module, NULL));
if (vr < 0)
{
- WARN("Failed to create Vulkan compute pipeline, hr %#x.\n", hr);
+ WARN("Failed to create Vulkan compute pipeline, hr %s.\n", debugstr_hresult(hr));
return hresult_from_vk_result(vr);
}
@@ -2368,7 +2400,7 @@ static HRESULT d3d12_pipeline_state_find_and_init_uav_counters(struct d3d12_pipe
}
if (FAILED(hr = d3d12_pipeline_state_init_uav_counters(state, device, root_signature, &shader_info, stage_flags)))
- WARN("Failed to create descriptor set layout for UAV counters, hr %#x.\n", hr);
+ WARN("Failed to create descriptor set layout for UAV counters, hr %s.\n", debugstr_hresult(hr));
vkd3d_shader_free_scan_descriptor_info(&shader_info);
@@ -2442,7 +2474,7 @@ static HRESULT d3d12_pipeline_state_init_compute(struct d3d12_pipeline_state *st
if (FAILED(hr = vkd3d_create_compute_pipeline(device, &desc->cs, &shader_interface,
vk_pipeline_layout, &state->u.compute.vk_pipeline)))
{
- WARN("Failed to create Vulkan compute pipeline, hr %#x.\n", hr);
+ WARN("Failed to create Vulkan compute pipeline, hr %s.\n", debugstr_hresult(hr));
d3d12_pipeline_uav_counter_state_cleanup(&state->uav_counters, device);
return hr;
}
@@ -3615,7 +3647,7 @@ static VkPipeline d3d12_pipeline_state_find_compiled_pipeline(const struct d3d12
*vk_render_pass = VK_NULL_HANDLE;
- vkd3d_mutex_lock(&device->mutex);
+ vkd3d_mutex_lock(&device->pipeline_cache_mutex);
LIST_FOR_EACH_ENTRY(current, &graphics->compiled_pipelines, struct vkd3d_compiled_pipeline, entry)
{
@@ -3627,7 +3659,7 @@ static VkPipeline d3d12_pipeline_state_find_compiled_pipeline(const struct d3d12
}
}
- vkd3d_mutex_unlock(&device->mutex);
+ vkd3d_mutex_unlock(&device->pipeline_cache_mutex);
return vk_pipeline;
}
@@ -3646,7 +3678,7 @@ static bool d3d12_pipeline_state_put_pipeline_to_cache(struct d3d12_pipeline_sta
compiled_pipeline->vk_pipeline = vk_pipeline;
compiled_pipeline->vk_render_pass = vk_render_pass;
- vkd3d_mutex_lock(&device->mutex);
+ vkd3d_mutex_lock(&device->pipeline_cache_mutex);
LIST_FOR_EACH_ENTRY(current, &graphics->compiled_pipelines, struct vkd3d_compiled_pipeline, entry)
{
@@ -3661,7 +3693,7 @@ static bool d3d12_pipeline_state_put_pipeline_to_cache(struct d3d12_pipeline_sta
if (compiled_pipeline)
list_add_tail(&graphics->compiled_pipelines, &compiled_pipeline->entry);
- vkd3d_mutex_unlock(&device->mutex);
+ vkd3d_mutex_unlock(&device->pipeline_cache_mutex);
return compiled_pipeline;
}
@@ -3996,14 +4028,14 @@ HRESULT vkd3d_uav_clear_state_init(struct vkd3d_uav_clear_state *state, struct d
if (FAILED(hr = vkd3d_create_descriptor_set_layout(device, 0,
1, false, &set_binding, set_layouts[i].set_layout)))
{
- ERR("Failed to create descriptor set layout %u, hr %#x.\n", i, hr);
+ ERR("Failed to create descriptor set layout %u, hr %s.\n", i, debugstr_hresult(hr));
goto fail;
}
if (FAILED(hr = vkd3d_create_pipeline_layout(device, 1, set_layouts[i].set_layout,
1, &push_constant_range, set_layouts[i].pipeline_layout)))
{
- ERR("Failed to create pipeline layout %u, hr %#x.\n", i, hr);
+ ERR("Failed to create pipeline layout %u, hr %s.\n", i, debugstr_hresult(hr));
goto fail;
}
}
@@ -4041,7 +4073,7 @@ HRESULT vkd3d_uav_clear_state_init(struct vkd3d_uav_clear_state *state, struct d
vkd3d_shader_free_shader_code(&dxbc);
if (FAILED(hr))
{
- ERR("Failed to create compute pipeline %u, hr %#x.\n", i, hr);
+ ERR("Failed to create compute pipeline %u, hr %s.\n", i, debugstr_hresult(hr));
goto fail;
}
}
diff --git a/libs/vkd3d/libs/vkd3d/utils.c b/libs/vkd3d/libs/vkd3d/utils.c
index 9b28068be51..ac79ae5ddff 100644
--- a/libs/vkd3d/libs/vkd3d/utils.c
+++ b/libs/vkd3d/libs/vkd3d/utils.c
@@ -539,6 +539,7 @@ bool is_valid_feature_level(D3D_FEATURE_LEVEL feature_level)
{
static const D3D_FEATURE_LEVEL valid_feature_levels[] =
{
+ D3D_FEATURE_LEVEL_12_2,
D3D_FEATURE_LEVEL_12_1,
D3D_FEATURE_LEVEL_12_0,
D3D_FEATURE_LEVEL_11_1,
@@ -548,6 +549,7 @@ bool is_valid_feature_level(D3D_FEATURE_LEVEL feature_level)
D3D_FEATURE_LEVEL_9_3,
D3D_FEATURE_LEVEL_9_2,
D3D_FEATURE_LEVEL_9_1,
+ D3D_FEATURE_LEVEL_1_0_CORE,
};
unsigned int i;
@@ -630,6 +632,11 @@ HRESULT return_interface(void *iface, REFIID iface_iid,
return hr;
}
+const char *debug_cpu_handle(D3D12_CPU_DESCRIPTOR_HANDLE handle)
+{
+ return vkd3d_dbg_sprintf("{%#"PRIxPTR"}", (uintptr_t)handle.ptr);
+}
+
const char *debug_d3d12_box(const D3D12_BOX *box)
{
if (!box)
@@ -671,6 +678,11 @@ const char *debug_d3d12_shader_component_mapping(unsigned int mapping)
debug_d3d12_shader_component(D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(3, mapping)));
}
+const char *debug_gpu_handle(D3D12_GPU_DESCRIPTOR_HANDLE handle)
+{
+ return vkd3d_dbg_sprintf("{%#"PRIx64"}", handle.ptr);
+}
+
const char *debug_vk_extent_3d(VkExtent3D extent)
{
return vkd3d_dbg_sprintf("(%u, %u, %u)",
@@ -681,7 +693,7 @@ const char *debug_vk_extent_3d(VkExtent3D extent)
const char *debug_vk_queue_flags(VkQueueFlags flags)
{
- char buffer[120];
+ char buffer[159];
buffer[0] = '\0';
#define FLAG_TO_STR(f) if (flags & f) { strcat(buffer, " | "#f); flags &= ~f; }
@@ -689,6 +701,10 @@ const char *debug_vk_queue_flags(VkQueueFlags flags)
FLAG_TO_STR(VK_QUEUE_COMPUTE_BIT)
FLAG_TO_STR(VK_QUEUE_TRANSFER_BIT)
FLAG_TO_STR(VK_QUEUE_SPARSE_BINDING_BIT)
+ FLAG_TO_STR(VK_QUEUE_PROTECTED_BIT)
+#undef FLAG_TO_STR
+#define FLAG_TO_STR(f, n) if (flags & f) { strcat(buffer, " | "#n); flags &= ~f; }
+ FLAG_TO_STR(0x20, VK_QUEUE_VIDEO_DECODE_BIT_KHR)
#undef FLAG_TO_STR
if (flags)
FIXME("Unrecognized flag(s) %#x.\n", flags);
@@ -727,10 +743,8 @@ const char *debug_vk_memory_property_flags(VkMemoryPropertyFlags flags)
FLAG_TO_STR(VK_MEMORY_PROPERTY_HOST_CACHED_BIT)
FLAG_TO_STR(VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT)
FLAG_TO_STR(VK_MEMORY_PROPERTY_PROTECTED_BIT)
-#undef FLAG_TO_STR
-#define FLAG_TO_STR(f, n) if (flags & f) { strcat(buffer, " | "#n); flags &= ~f; }
- FLAG_TO_STR(0x40, VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD)
- FLAG_TO_STR(0x80, VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD)
+ FLAG_TO_STR(VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD)
+ FLAG_TO_STR(VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD)
#undef FLAG_TO_STR
if (flags)
FIXME("Unrecognized flag(s) %#x.\n", flags);
diff --git a/libs/vkd3d/libs/vkd3d/vkd3d_main.c b/libs/vkd3d/libs/vkd3d/vkd3d_main.c
index 245edb5aeac..7919b7d8760 100644
--- a/libs/vkd3d/libs/vkd3d/vkd3d_main.c
+++ b/libs/vkd3d/libs/vkd3d/vkd3d_main.c
@@ -60,7 +60,7 @@ HRESULT vkd3d_create_device(const struct vkd3d_device_create_info *create_info,
}
else if (FAILED(hr = vkd3d_create_instance(create_info->instance_create_info, &instance)))
{
- WARN("Failed to create instance, hr %#x.\n", hr);
+ WARN("Failed to create instance, hr %s.\n", debugstr_hresult(hr));
return E_FAIL;
}
@@ -71,18 +71,18 @@ HRESULT vkd3d_create_device(const struct vkd3d_device_create_info *create_info,
if (!device)
{
- ID3D12Device_Release(&object->ID3D12Device5_iface);
+ ID3D12Device_Release(&object->ID3D12Device7_iface);
return S_FALSE;
}
- return return_interface(&object->ID3D12Device5_iface, &IID_ID3D12Device, iid, device);
+ return return_interface(&object->ID3D12Device7_iface, &IID_ID3D12Device, iid, device);
}
/* ID3D12RootSignatureDeserializer */
struct d3d12_root_signature_deserializer
{
ID3D12RootSignatureDeserializer ID3D12RootSignatureDeserializer_iface;
- LONG refcount;
+ unsigned int refcount;
union
{
@@ -123,7 +123,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_root_signature_deserializer_QueryInterfac
static ULONG STDMETHODCALLTYPE d3d12_root_signature_deserializer_AddRef(ID3D12RootSignatureDeserializer *iface)
{
struct d3d12_root_signature_deserializer *deserializer = impl_from_ID3D12RootSignatureDeserializer(iface);
- ULONG refcount = InterlockedIncrement(&deserializer->refcount);
+ unsigned int refcount = vkd3d_atomic_increment_u32(&deserializer->refcount);
TRACE("%p increasing refcount to %u.\n", deserializer, refcount);
@@ -133,7 +133,7 @@ static ULONG STDMETHODCALLTYPE d3d12_root_signature_deserializer_AddRef(ID3D12Ro
static ULONG STDMETHODCALLTYPE d3d12_root_signature_deserializer_Release(ID3D12RootSignatureDeserializer *iface)
{
struct d3d12_root_signature_deserializer *deserializer = impl_from_ID3D12RootSignatureDeserializer(iface);
- ULONG refcount = InterlockedDecrement(&deserializer->refcount);
+ unsigned int refcount = vkd3d_atomic_decrement_u32(&deserializer->refcount);
TRACE("%p decreasing refcount to %u.\n", deserializer, refcount);
@@ -222,8 +222,8 @@ HRESULT vkd3d_create_root_signature_deserializer(const void *data, SIZE_T data_s
struct d3d12_root_signature_deserializer *object;
HRESULT hr;
- TRACE("data %p, data_size %lu, iid %s, deserializer %p.\n",
- data, data_size, debugstr_guid(iid), deserializer);
+ TRACE("data %p, data_size %"PRIuPTR", iid %s, deserializer %p.\n",
+ data, (uintptr_t)data_size, debugstr_guid(iid), deserializer);
if (!(object = vkd3d_malloc(sizeof(*object))))
return E_OUTOFMEMORY;
@@ -242,7 +242,7 @@ HRESULT vkd3d_create_root_signature_deserializer(const void *data, SIZE_T data_s
struct d3d12_versioned_root_signature_deserializer
{
ID3D12VersionedRootSignatureDeserializer ID3D12VersionedRootSignatureDeserializer_iface;
- LONG refcount;
+ unsigned int refcount;
union
{
@@ -284,7 +284,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_versioned_root_signature_deserializer_Que
static ULONG STDMETHODCALLTYPE d3d12_versioned_root_signature_deserializer_AddRef(ID3D12VersionedRootSignatureDeserializer *iface)
{
struct d3d12_versioned_root_signature_deserializer *deserializer = impl_from_ID3D12VersionedRootSignatureDeserializer(iface);
- ULONG refcount = InterlockedIncrement(&deserializer->refcount);
+ unsigned int refcount = vkd3d_atomic_increment_u32(&deserializer->refcount);
TRACE("%p increasing refcount to %u.\n", deserializer, refcount);
@@ -294,7 +294,7 @@ static ULONG STDMETHODCALLTYPE d3d12_versioned_root_signature_deserializer_AddRe
static ULONG STDMETHODCALLTYPE d3d12_versioned_root_signature_deserializer_Release(ID3D12VersionedRootSignatureDeserializer *iface)
{
struct d3d12_versioned_root_signature_deserializer *deserializer = impl_from_ID3D12VersionedRootSignatureDeserializer(iface);
- ULONG refcount = InterlockedDecrement(&deserializer->refcount);
+ unsigned int refcount = vkd3d_atomic_decrement_u32(&deserializer->refcount);
TRACE("%p decreasing refcount to %u.\n", deserializer, refcount);
@@ -406,8 +406,8 @@ HRESULT vkd3d_create_versioned_root_signature_deserializer(const void *data, SIZ
struct vkd3d_shader_code dxbc = {data, data_size};
HRESULT hr;
- TRACE("data %p, data_size %lu, iid %s, deserializer %p.\n",
- data, data_size, debugstr_guid(iid), deserializer);
+ TRACE("data %p, data_size %"PRIuPTR", iid %s, deserializer %p.\n",
+ data, (uintptr_t)data_size, debugstr_guid(iid), deserializer);
if (!(object = vkd3d_malloc(sizeof(*object))))
return E_OUTOFMEMORY;
@@ -456,7 +456,7 @@ HRESULT vkd3d_serialize_root_signature(const D3D12_ROOT_SIGNATURE_DESC *desc,
if (error_blob && messages)
{
if (FAILED(hr = vkd3d_blob_create(messages, strlen(messages), error_blob)))
- ERR("Failed to create error blob, hr %#x.\n", hr);
+ ERR("Failed to create error blob, hr %s.\n", debugstr_hresult(hr));
}
return hresult_from_vkd3d_result(ret);
}
@@ -464,7 +464,7 @@ HRESULT vkd3d_serialize_root_signature(const D3D12_ROOT_SIGNATURE_DESC *desc,
if (FAILED(hr = vkd3d_blob_create((void *)dxbc.code, dxbc.size, blob)))
{
- WARN("Failed to create blob object, hr %#x.\n", hr);
+ WARN("Failed to create blob object, hr %s.\n", debugstr_hresult(hr));
vkd3d_shader_free_shader_code(&dxbc);
}
return hr;
@@ -497,7 +497,7 @@ HRESULT vkd3d_serialize_versioned_root_signature(const D3D12_VERSIONED_ROOT_SIGN
if (error_blob && messages)
{
if (FAILED(hr = vkd3d_blob_create(messages, strlen(messages), error_blob)))
- ERR("Failed to create error blob, hr %#x.\n", hr);
+ ERR("Failed to create error blob, hr %s.\n", debugstr_hresult(hr));
}
return hresult_from_vkd3d_result(ret);
}
@@ -505,7 +505,7 @@ HRESULT vkd3d_serialize_versioned_root_signature(const D3D12_VERSIONED_ROOT_SIGN
if (FAILED(hr = vkd3d_blob_create((void *)dxbc.code, dxbc.size, blob)))
{
- WARN("Failed to create blob object, hr %#x.\n", hr);
+ WARN("Failed to create blob object, hr %s.\n", debugstr_hresult(hr));
vkd3d_shader_free_shader_code(&dxbc);
}
return hr;
diff --git a/libs/vkd3d/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/libs/vkd3d/vkd3d_private.h
index f06f564d6ea..78f4f3514e2 100644
--- a/libs/vkd3d/libs/vkd3d/vkd3d_private.h
+++ b/libs/vkd3d/libs/vkd3d/vkd3d_private.h
@@ -55,7 +55,7 @@
#define VKD3D_MAX_COMPATIBLE_FORMAT_COUNT 6u
#define VKD3D_MAX_QUEUE_FAMILY_COUNT 3u
-#define VKD3D_MAX_SHADER_EXTENSIONS 3u
+#define VKD3D_MAX_SHADER_EXTENSIONS 4u
#define VKD3D_MAX_SHADER_STAGES 5u
#define VKD3D_MAX_VK_SYNC_OBJECTS 4u
#define VKD3D_MAX_DEVICE_BLOCKED_QUEUES 16u
@@ -67,7 +67,7 @@
* this number to prevent excessive pool memory use. */
#define VKD3D_MAX_VIRTUAL_HEAP_DESCRIPTORS_PER_TYPE (16 * 1024u)
-extern LONG64 object_global_serial_id;
+extern uint64_t object_global_serial_id;
struct d3d12_command_list;
struct d3d12_device;
@@ -133,9 +133,11 @@ struct vkd3d_vulkan_info
bool EXT_debug_marker;
bool EXT_depth_clip_enable;
bool EXT_descriptor_indexing;
+ bool EXT_mutable_descriptor_type;
bool EXT_robustness2;
bool EXT_shader_demote_to_helper_invocation;
bool EXT_shader_stencil_export;
+ bool EXT_shader_viewport_index_layer;
bool EXT_texel_buffer_alignment;
bool EXT_transform_feedback;
bool EXT_vertex_attribute_divisor;
@@ -190,7 +192,7 @@ struct vkd3d_instance
uint64_t host_ticks_per_second;
- LONG refcount;
+ unsigned int refcount;
};
#ifdef _WIN32
@@ -248,23 +250,13 @@ static inline void vkd3d_cond_broadcast(struct vkd3d_cond *cond)
static inline void vkd3d_cond_wait(struct vkd3d_cond *cond, struct vkd3d_mutex *lock)
{
if (!SleepConditionVariableCS(&cond->cond, &lock->lock, INFINITE))
- ERR("Could not sleep on the condition variable, error %u.\n", GetLastError());
+ ERR("Could not sleep on the condition variable, error %lu.\n", GetLastError());
}
static inline void vkd3d_cond_destroy(struct vkd3d_cond *cond)
{
}
-static inline unsigned int vkd3d_atomic_increment(unsigned int volatile *x)
-{
- return InterlockedIncrement((LONG volatile *)x);
-}
-
-static inline unsigned int vkd3d_atomic_decrement(unsigned int volatile *x)
-{
- return InterlockedDecrement((LONG volatile *)x);
-}
-
static inline bool vkd3d_atomic_compare_exchange(unsigned int volatile *x, unsigned int cmp, unsigned int xchg)
{
return InterlockedCompareExchange((LONG volatile *)x, xchg, cmp) == cmp;
@@ -387,24 +379,6 @@ static inline void vkd3d_cond_destroy(struct vkd3d_cond *cond)
ERR("Could not destroy the condition variable, error %d.\n", ret);
}
-# if HAVE_SYNC_SUB_AND_FETCH
-static inline unsigned int vkd3d_atomic_decrement(unsigned int volatile *x)
-{
- return __sync_sub_and_fetch(x, 1);
-}
-# else
-# error "vkd3d_atomic_decrement() not implemented for this platform"
-# endif /* HAVE_SYNC_SUB_AND_FETCH */
-
-# if HAVE_SYNC_ADD_AND_FETCH
-static inline unsigned int vkd3d_atomic_increment(unsigned int volatile *x)
-{
- return __sync_add_and_fetch(x, 1);
-}
-# else
-# error "vkd3d_atomic_increment() not implemented for this platform"
-# endif /* HAVE_SYNC_ADD_AND_FETCH */
-
# if HAVE_SYNC_BOOL_COMPARE_AND_SWAP
static inline bool vkd3d_atomic_compare_exchange(unsigned int volatile *x, unsigned int cmp, unsigned int xchg)
{
@@ -491,13 +465,13 @@ struct vkd3d_fence_worker
struct vkd3d_gpu_va_allocation
{
D3D12_GPU_VIRTUAL_ADDRESS base;
- size_t size;
+ uint64_t size;
void *ptr;
};
struct vkd3d_gpu_va_slab
{
- size_t size;
+ uint64_t size;
void *ptr;
};
@@ -515,7 +489,7 @@ struct vkd3d_gpu_va_allocator
};
D3D12_GPU_VIRTUAL_ADDRESS vkd3d_gpu_va_allocator_allocate(struct vkd3d_gpu_va_allocator *allocator,
- size_t alignment, size_t size, void *ptr);
+ size_t alignment, uint64_t size, void *ptr);
void *vkd3d_gpu_va_allocator_dereference(struct vkd3d_gpu_va_allocator *allocator, D3D12_GPU_VIRTUAL_ADDRESS address);
void vkd3d_gpu_va_allocator_free(struct vkd3d_gpu_va_allocator *allocator, D3D12_GPU_VIRTUAL_ADDRESS address);
@@ -619,8 +593,8 @@ struct vkd3d_signaled_semaphore
struct d3d12_fence
{
ID3D12Fence1 ID3D12Fence1_iface;
- LONG internal_refcount;
- LONG refcount;
+ unsigned int internal_refcount;
+ unsigned int refcount;
D3D12_FENCE_FLAGS flags;
@@ -663,8 +637,8 @@ VkResult vkd3d_create_timeline_semaphore(const struct d3d12_device *device, uint
struct d3d12_heap
{
ID3D12Heap ID3D12Heap_iface;
- LONG refcount;
- LONG resource_count;
+ unsigned int refcount;
+ unsigned int resource_count;
bool is_private;
D3D12_HEAP_DESC desc;
@@ -719,8 +693,8 @@ struct d3d12_resource_tile_info
struct d3d12_resource
{
ID3D12Resource1 ID3D12Resource1_iface;
- LONG refcount;
- LONG internal_refcount;
+ unsigned int refcount;
+ unsigned int internal_refcount;
D3D12_RESOURCE_DESC desc;
const struct vkd3d_format *format;
@@ -768,6 +742,13 @@ static inline bool d3d12_resource_is_texture(const struct d3d12_resource *resour
return resource->desc.Dimension != D3D12_RESOURCE_DIMENSION_BUFFER;
}
+struct vkd3d_resource_allocation_info
+{
+ uint64_t offset;
+ uint64_t alignment;
+ uint64_t size_in_bytes;
+};
+
bool d3d12_resource_is_cpu_accessible(const struct d3d12_resource *resource);
HRESULT d3d12_resource_validate_desc(const D3D12_RESOURCE_DESC *desc, struct d3d12_device *device);
void d3d12_resource_get_tiling(struct d3d12_device *device, const struct d3d12_resource *resource,
@@ -795,7 +776,7 @@ HRESULT vkd3d_create_buffer(struct d3d12_device *device,
const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags,
const D3D12_RESOURCE_DESC *desc, VkBuffer *vk_buffer);
HRESULT vkd3d_get_image_allocation_info(struct d3d12_device *device,
- const D3D12_RESOURCE_DESC *desc, D3D12_RESOURCE_ALLOCATION_INFO *allocation_info);
+ const D3D12_RESOURCE_DESC *desc, struct vkd3d_resource_allocation_info *allocation_info);
enum vkd3d_view_type
{
@@ -1044,7 +1025,7 @@ struct d3d12_descriptor_heap_vk_set
struct d3d12_descriptor_heap
{
ID3D12DescriptorHeap ID3D12DescriptorHeap_iface;
- LONG refcount;
+ unsigned int refcount;
uint64_t serial_id;
D3D12_DESCRIPTOR_HEAP_DESC desc;
@@ -1083,7 +1064,7 @@ HRESULT d3d12_descriptor_heap_create(struct d3d12_device *device,
struct d3d12_query_heap
{
ID3D12QueryHeap ID3D12QueryHeap_iface;
- LONG refcount;
+ unsigned int refcount;
VkQueryPool vk_query_pool;
@@ -1170,7 +1151,7 @@ struct d3d12_descriptor_set_layout
struct d3d12_root_signature
{
ID3D12RootSignature ID3D12RootSignature_iface;
- LONG refcount;
+ unsigned int refcount;
VkPipelineLayout vk_pipeline_layout;
struct d3d12_descriptor_set_layout descriptor_set_layouts[VKD3D_MAX_DESCRIPTOR_SETS];
@@ -1279,7 +1260,7 @@ struct d3d12_pipeline_uav_counter_state
struct d3d12_pipeline_state
{
ID3D12PipelineState ID3D12PipelineState_iface;
- LONG refcount;
+ unsigned int refcount;
union
{
@@ -1363,7 +1344,7 @@ struct vkd3d_buffer
struct d3d12_command_allocator
{
ID3D12CommandAllocator ID3D12CommandAllocator_iface;
- LONG refcount;
+ unsigned int refcount;
D3D12_COMMAND_LIST_TYPE type;
VkQueueFlags vk_queue_flags;
@@ -1464,7 +1445,7 @@ enum vkd3d_pipeline_bind_point
struct d3d12_command_list
{
ID3D12GraphicsCommandList5 ID3D12GraphicsCommandList5_iface;
- LONG refcount;
+ unsigned int refcount;
D3D12_COMMAND_LIST_TYPE type;
VkQueueFlags vk_queue_flags;
@@ -1620,7 +1601,7 @@ struct d3d12_command_queue_op_array
struct d3d12_command_queue
{
ID3D12CommandQueue ID3D12CommandQueue_iface;
- LONG refcount;
+ unsigned int refcount;
D3D12_COMMAND_QUEUE_DESC desc;
@@ -1655,7 +1636,7 @@ HRESULT d3d12_command_queue_create(struct d3d12_device *device,
struct d3d12_command_signature
{
ID3D12CommandSignature ID3D12CommandSignature_iface;
- LONG refcount;
+ unsigned int refcount;
unsigned int internal_refcount;
D3D12_COMMAND_SIGNATURE_DESC desc;
@@ -1746,8 +1727,8 @@ struct vkd3d_desc_object_cache
/* ID3D12Device */
struct d3d12_device
{
- ID3D12Device5 ID3D12Device5_iface;
- LONG refcount;
+ ID3D12Device7 ID3D12Device7_iface;
+ unsigned int refcount;
VkDevice vk_device;
VkPhysicalDevice vk_physical_device;
@@ -1757,9 +1738,23 @@ struct d3d12_device
struct vkd3d_gpu_va_allocator gpu_va_allocator;
- struct vkd3d_mutex mutex;
struct vkd3d_desc_object_cache view_desc_cache;
struct vkd3d_desc_object_cache cbuffer_desc_cache;
+
+ VkDescriptorPoolSize vk_pool_sizes[VKD3D_DESCRIPTOR_POOL_COUNT];
+ unsigned int vk_pool_count;
+ struct vkd3d_vk_descriptor_heap_layout vk_descriptor_heap_layouts[VKD3D_SET_INDEX_COUNT];
+ bool use_vk_heaps;
+
+ struct d3d12_descriptor_heap **heaps;
+ size_t heap_capacity;
+ size_t heap_count;
+ union vkd3d_thread_handle worker_thread;
+ struct vkd3d_mutex worker_mutex;
+ struct vkd3d_cond worker_cond;
+ bool worker_should_exit;
+
+ struct vkd3d_mutex pipeline_cache_mutex;
struct vkd3d_render_pass_cache render_pass_cache;
VkPipelineCache vk_pipeline_cache;
@@ -1799,11 +1794,6 @@ struct d3d12_device
const struct vkd3d_format_compatibility_list *format_compatibility_lists;
struct vkd3d_null_resources null_resources;
struct vkd3d_uav_clear_state uav_clear_state;
-
- VkDescriptorPoolSize vk_pool_sizes[VKD3D_DESCRIPTOR_POOL_COUNT];
- unsigned int vk_pool_count;
- struct vkd3d_vk_descriptor_heap_layout vk_descriptor_heap_layouts[VKD3D_SET_INDEX_COUNT];
- bool use_vk_heaps;
};
HRESULT d3d12_device_create(struct vkd3d_instance *instance,
@@ -1812,27 +1802,29 @@ struct vkd3d_queue *d3d12_device_get_vkd3d_queue(struct d3d12_device *device, D3
bool d3d12_device_is_uma(struct d3d12_device *device, bool *coherent);
void d3d12_device_mark_as_removed(struct d3d12_device *device, HRESULT reason,
const char *message, ...) VKD3D_PRINTF_FUNC(3, 4);
-struct d3d12_device *unsafe_impl_from_ID3D12Device5(ID3D12Device5 *iface);
+struct d3d12_device *unsafe_impl_from_ID3D12Device7(ID3D12Device7 *iface);
+HRESULT d3d12_device_add_descriptor_heap(struct d3d12_device *device, struct d3d12_descriptor_heap *heap);
+void d3d12_device_remove_descriptor_heap(struct d3d12_device *device, struct d3d12_descriptor_heap *heap);
static inline HRESULT d3d12_device_query_interface(struct d3d12_device *device, REFIID iid, void **object)
{
- return ID3D12Device5_QueryInterface(&device->ID3D12Device5_iface, iid, object);
+ return ID3D12Device7_QueryInterface(&device->ID3D12Device7_iface, iid, object);
}
static inline ULONG d3d12_device_add_ref(struct d3d12_device *device)
{
- return ID3D12Device5_AddRef(&device->ID3D12Device5_iface);
+ return ID3D12Device7_AddRef(&device->ID3D12Device7_iface);
}
static inline ULONG d3d12_device_release(struct d3d12_device *device)
{
- return ID3D12Device5_Release(&device->ID3D12Device5_iface);
+ return ID3D12Device7_Release(&device->ID3D12Device7_iface);
}
static inline unsigned int d3d12_device_get_descriptor_handle_increment_size(struct d3d12_device *device,
D3D12_DESCRIPTOR_HEAP_TYPE descriptor_type)
{
- return ID3D12Device5_GetDescriptorHandleIncrementSize(&device->ID3D12Device5_iface, descriptor_type);
+ return ID3D12Device7_GetDescriptorHandleIncrementSize(&device->ID3D12Device7_iface, descriptor_type);
}
/* utils */
@@ -1940,8 +1932,10 @@ bool is_write_resource_state(D3D12_RESOURCE_STATES state);
HRESULT return_interface(void *iface, REFIID iface_iid, REFIID requested_iid, void **object);
+const char *debug_cpu_handle(D3D12_CPU_DESCRIPTOR_HANDLE handle);
const char *debug_d3d12_box(const D3D12_BOX *box);
const char *debug_d3d12_shader_component_mapping(unsigned int mapping);
+const char *debug_gpu_handle(D3D12_GPU_DESCRIPTOR_HANDLE handle);
const char *debug_vk_extent_3d(VkExtent3D extent);
const char *debug_vk_memory_heap_flags(VkMemoryHeapFlags flags);
const char *debug_vk_memory_property_flags(VkMemoryPropertyFlags flags);
--
2.43.0