From 65f5978cdf827d674f90160484af94c32cbf540a Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes 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 + +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 +#include +#include +#include +#include +#include +#include + +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 + +#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 +#include + +#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 +# endif +# include +# 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 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() \ + { \ + 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() \ + { \ + return __vkd3d_uuidof(); \ + } \ + } + +# define __uuidof(type) __vkd3d_uuidof() +#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 +# include +# include + +# 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 + +#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] = "", [VKD3D_DATA_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 = ""; + + 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, "", 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, "", 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, ¶m->reg); shader_print_non_uniform(compiler, ¶m->reg); + shader_dump_reg_type(compiler, ¶m->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, ¶m->reg); shader_print_non_uniform(compiler, ¶m->reg); + shader_dump_reg_type(compiler, ¶m->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(¶m->reg, type, sm6); + register_init_ssa_scalar(¶m->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(¶m->reg, sm6_type_get_scalar_type(dst->type, 0), component_count, sm6); + register_init_ssa_vector(¶m->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(®->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(¶m->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 STRING %token TYPE_IDENTIFIER +%type annotations_opt + %type arrays %type assign_op @@ -5051,7 +5234,7 @@ static void check_duplicated_switch_cases(struct hlsl_ctx *ctx, const struct hls %type any_identifier %type var_identifier -%type technique_name +%type name_opt %type 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, ¶ms, &instr->loc))) + if (!(resource_load = hlsl_new_resource_load(ctx, ¶ms, &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(¶m->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(¶m->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, ®->idx[0]); + indexes[index_count++] = spirv_compiler_emit_register_addressing(compiler, ®->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, ®_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, ®_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(®_symbol, reg); + vkd3d_symbol_make_io(®_symbol, reg_type, element_idx); if ((entry = rb_get(&compiler->symbol_table, ®_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, ®_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, ®_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(®_symbol, reg); + vkd3d_symbol_make_io(®_symbol, reg_type, element_idx); if (rb_get(&compiler->symbol_table, ®_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, ®_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(®, 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, ®); vkd3d_spirv_end_function_stream_insertion(builder); vkd3d_symbol_make_register(®_symbol, ®); - vkd3d_symbol_set_register_info(®_symbol, id, - SpvStorageClassFunction, VKD3D_SHADER_COMPONENT_FLOAT, VKD3DSP_WRITEMASK_ALL); + vkd3d_symbol_set_register_info(®_symbol, id, storage_class, + component_type, vkd3d_write_mask_from_component_count(temp->component_count)); spirv_compiler_put_symbol(compiler, ®_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(®, 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(®, VKD3DSPR_IMMCONSTBUFFER, VKD3D_DATA_FLOAT, 2); + reg.idx[0].offset = icb->register_idx; vkd3d_symbol_make_register(®_symbol, ®); vkd3d_symbol_set_register_info(®_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, ®_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, ¶m->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, ¶m->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, ¶m->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 #include +/* 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