From: Zebediah Figura zfigura@codeweavers.com
--- include/private/vkd3d_common.h | 15 ++++ libs/vkd3d-shader/d3dbc.c | 82 ++++++++++++++++++-- libs/vkd3d-shader/vkd3d_shader_main.c | 9 +++ libs/vkd3d-shader/vkd3d_shader_private.h | 5 ++ tests/vkd3d_shader_api.c | 95 ++++++++++++++++++++++++ 5 files changed, 201 insertions(+), 5 deletions(-)
diff --git a/include/private/vkd3d_common.h b/include/private/vkd3d_common.h index 6be3cee8..eec63bcc 100644 --- a/include/private/vkd3d_common.h +++ b/include/private/vkd3d_common.h @@ -188,6 +188,21 @@ static inline int vkd3d_u32_compare(uint32_t x, uint32_t y) return (x > y) - (x < y); }
+static inline bool bitmap_clear(uint32_t *map, unsigned int idx) +{ + return map[idx >> 5] &= ~(1u << (idx & 0x1f)); +} + +static inline bool bitmap_set(uint32_t *map, unsigned int idx) +{ + return map[idx >> 5] |= (1u << (idx & 0x1f)); +} + +static inline bool bitmap_is_set(const uint32_t *map, unsigned int idx) +{ + return map[idx >> 5] & (1u << (idx & 0x1f)); +} + static inline int ascii_isupper(int c) { return 'A' <= c && c <= 'Z'; diff --git a/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d-shader/d3dbc.c index 369112ce..0b1c7bca 100644 --- a/libs/vkd3d-shader/d3dbc.c +++ b/libs/vkd3d-shader/d3dbc.c @@ -214,6 +214,9 @@ struct vkd3d_shader_sm1_parser bool abort;
struct vkd3d_shader_parser p; + +#define MAX_CONSTANT_COUNT 8192 + uint32_t constant_def_mask[3][MAX_CONSTANT_COUNT / 32]; };
/* This table is not order or position dependent. */ @@ -729,12 +732,60 @@ static bool add_signature_element_from_semantic(struct vkd3d_shader_sm1_parser * semantic->usage_idx, sysval, reg->idx[0].offset, true, mask); }
-static void shader_sm1_scan_register(struct vkd3d_shader_sm1_parser *sm1, const struct vkd3d_shader_register *reg, unsigned int mask) +static void record_constant_register(struct vkd3d_shader_sm1_parser *sm1, + enum vkd3d_shader_d3dbc_constant_register set, uint32_t index, bool from_def) { + struct vkd3d_shader_desc *desc = &sm1->p.shader_desc; + + desc->flat_constant_count[set].used = max(desc->flat_constant_count[set].used, index + 1); + if (from_def) + { + /* d3d shaders have a maximum of 8192 constants; we should not overrun + * this array. */ + assert((index / 32) <= ARRAY_SIZE(sm1->constant_def_mask[set])); + bitmap_set(sm1->constant_def_mask[set], index); + } +} + +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; uint32_t register_index = reg->idx[0].offset;
- if (reg->type == VKD3DSPR_TEMP) - sm1->p.shader_desc.temp_count = max(sm1->p.shader_desc.temp_count, register_index + 1); + switch (reg->type) + { + case VKD3DSPR_TEMP: + desc->temp_count = max(desc->temp_count, register_index + 1); + break; + + case VKD3DSPR_CONST: + record_constant_register(sm1, VKD3D_SHADER_D3DBC_FLOAT_CONSTANT_REGISTER, register_index, from_def); + break; + + case VKD3DSPR_CONST2: + record_constant_register(sm1, VKD3D_SHADER_D3DBC_FLOAT_CONSTANT_REGISTER, 2048 + register_index, from_def); + break; + + case VKD3DSPR_CONST3: + record_constant_register(sm1, VKD3D_SHADER_D3DBC_FLOAT_CONSTANT_REGISTER, 4096 + register_index, from_def); + break; + + case VKD3DSPR_CONST4: + record_constant_register(sm1, VKD3D_SHADER_D3DBC_FLOAT_CONSTANT_REGISTER, 6144 + register_index, from_def); + break; + + case VKD3DSPR_CONSTINT: + record_constant_register(sm1, VKD3D_SHADER_D3DBC_INT_CONSTANT_REGISTER, register_index, from_def); + break; + + case VKD3DSPR_CONSTBOOL: + record_constant_register(sm1, VKD3D_SHADER_D3DBC_BOOL_CONSTANT_REGISTER, register_index, from_def); + break; + + default: + break; + }
add_signature_element_from_register(sm1, reg, false, mask); } @@ -1076,16 +1127,19 @@ static void shader_sm1_read_instruction(struct vkd3d_shader_sm1_parser *sm1, str { shader_sm1_read_dst_param(sm1, &p, dst_param); shader_sm1_read_immconst(sm1, &p, &src_params[0], VKD3D_IMMCONST_VEC4, VKD3D_DATA_FLOAT); + shader_sm1_scan_register(sm1, &dst_param->reg, dst_param->write_mask, true); } else if (ins->handler_idx == VKD3DSIH_DEFB) { shader_sm1_read_dst_param(sm1, &p, dst_param); shader_sm1_read_immconst(sm1, &p, &src_params[0], VKD3D_IMMCONST_SCALAR, VKD3D_DATA_UINT); + shader_sm1_scan_register(sm1, &dst_param->reg, dst_param->write_mask, true); } else if (ins->handler_idx == VKD3DSIH_DEFI) { shader_sm1_read_dst_param(sm1, &p, dst_param); shader_sm1_read_immconst(sm1, &p, &src_params[0], VKD3D_IMMCONST_VEC4, VKD3D_DATA_INT); + shader_sm1_scan_register(sm1, &dst_param->reg, dst_param->write_mask, true); } else { @@ -1093,7 +1147,7 @@ static void shader_sm1_read_instruction(struct vkd3d_shader_sm1_parser *sm1, str if (ins->dst_count) { shader_sm1_read_dst_param(sm1, &p, dst_param); - shader_sm1_scan_register(sm1, &dst_param->reg, dst_param->write_mask); + shader_sm1_scan_register(sm1, &dst_param->reg, dst_param->write_mask, false); }
/* Predication token */ @@ -1104,7 +1158,7 @@ static void shader_sm1_read_instruction(struct vkd3d_shader_sm1_parser *sm1, str for (i = 0; i < ins->src_count; ++i) { shader_sm1_read_src_param(sm1, &p, &src_params[i]); - shader_sm1_scan_register(sm1, &src_params[i].reg, mask_from_swizzle(src_params[i].swizzle)); + shader_sm1_scan_register(sm1, &src_params[i].reg, mask_from_swizzle(src_params[i].swizzle), false); } }
@@ -1212,12 +1266,27 @@ static enum vkd3d_result shader_sm1_init(struct vkd3d_shader_sm1_parser *sm1, return VKD3D_OK; }
+static uint32_t get_external_constant_count(struct vkd3d_shader_sm1_parser *sm1, + enum vkd3d_shader_d3dbc_constant_register set) +{ + unsigned int j; + + for (j = sm1->p.shader_desc.flat_constant_count[set].used; j > 0; --j) + { + if (!bitmap_is_set(sm1->constant_def_mask[set], j - 1)) + return j; + } + + return 0; +} + int vkd3d_shader_sm1_parser_create(const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_message_context *message_context, struct vkd3d_shader_parser **parser) { struct vkd3d_shader_instruction_array *instructions; struct vkd3d_shader_instruction *ins; struct vkd3d_shader_sm1_parser *sm1; + unsigned int i; int ret;
if (!(sm1 = vkd3d_calloc(1, sizeof(*sm1)))) @@ -1257,6 +1326,9 @@ int vkd3d_shader_sm1_parser_create(const struct vkd3d_shader_compile_info *compi
*parser = &sm1->p;
+ for (i = 0; i < ARRAY_SIZE(sm1->p.shader_desc.flat_constant_count); ++i) + sm1->p.shader_desc.flat_constant_count[i].external = get_external_constant_count(sm1, i); + return sm1->p.failed ? VKD3D_ERROR_INVALID_SHADER : VKD3D_OK; }
diff --git a/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d-shader/vkd3d_shader_main.c index f26050bb..e8259181 100644 --- a/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d-shader/vkd3d_shader_main.c @@ -1152,6 +1152,15 @@ static int scan_with_parser(const struct vkd3d_shader_compile_info *compile_info } }
+ for (i = 0; i < ARRAY_SIZE(parser->shader_desc.flat_constant_count); ++i) + { + struct vkd3d_shader_register_range range = {.space = 0, .first = i, .last = i}; + + if (parser->shader_desc.flat_constant_count[i].external) + vkd3d_shader_scan_add_descriptor(&context, VKD3D_SHADER_DESCRIPTOR_TYPE_CBV, + &range, VKD3D_SHADER_RESOURCE_BUFFER, VKD3D_SHADER_RESOURCE_DATA_UINT, 0); + } + if (!ret && signature_info) { if (!vkd3d_shader_signature_from_shader_signature(&signature_info->input, &parser->shader_desc.input_signature) diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 85fca964..9bf585b7 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -831,6 +831,11 @@ struct vkd3d_shader_desc struct shader_signature patch_constant_signature;
uint32_t temp_count; + + struct + { + uint32_t used, external; + } flat_constant_count[3]; };
struct vkd3d_shader_register_semantic diff --git a/tests/vkd3d_shader_api.c b/tests/vkd3d_shader_api.c index f9a3f717..8bd728d9 100644 --- a/tests/vkd3d_shader_api.c +++ b/tests/vkd3d_shader_api.c @@ -729,6 +729,100 @@ static void test_scan_signatures(void) } }
+static void test_scan_descriptors(void) +{ + struct vkd3d_shader_scan_descriptor_info descriptor_info = {.type = VKD3D_SHADER_STRUCTURE_TYPE_SCAN_DESCRIPTOR_INFO}; + struct vkd3d_shader_hlsl_source_info hlsl_info = {.type = VKD3D_SHADER_STRUCTURE_TYPE_HLSL_SOURCE_INFO}; + struct vkd3d_shader_compile_info compile_info = {.type = VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO}; + struct vkd3d_shader_code dxbc; + size_t i, j; + int rc; + + static const char ps1_source[] = + "float4 main(uniform float4 u, uniform float4 v) : sv_target\n" + "{\n" + " return u * v + 1.0;\n" + "}"; + + static const char ps2_source[] = + "float4 main() : sv_target\n" + "{\n" + " return 1.0;\n" + "}"; + + static const struct vkd3d_shader_descriptor_info ps1_descriptors[] = + { + {VKD3D_SHADER_DESCRIPTOR_TYPE_CBV, 0, VKD3D_SHADER_D3DBC_FLOAT_CONSTANT_REGISTER, + VKD3D_SHADER_RESOURCE_BUFFER, VKD3D_SHADER_RESOURCE_DATA_UINT, 0, 1}, + }; + + static const struct + { + const char *source; + bool sm4; + const char *profile; + const struct vkd3d_shader_descriptor_info *descriptors; + size_t descriptor_count; + } + tests[] = + { + {ps1_source, false, "ps_2_0", ps1_descriptors, ARRAY_SIZE(ps1_descriptors)}, + {ps2_source, false, "ps_2_0", NULL, 0}, + }; + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + vkd3d_test_push_context("test %u", i); + + compile_info.source.code = tests[i].source; + compile_info.source.size = strlen(tests[i].source); + compile_info.source_type = VKD3D_SHADER_SOURCE_HLSL; + compile_info.target_type = tests[i].sm4 ? VKD3D_SHADER_TARGET_DXBC_TPF : VKD3D_SHADER_TARGET_D3D_BYTECODE; + compile_info.log_level = VKD3D_SHADER_LOG_INFO; + + compile_info.next = &hlsl_info; + hlsl_info.profile = tests[i].profile; + + rc = vkd3d_shader_compile(&compile_info, &dxbc, NULL); + ok(rc == VKD3D_OK, "Got unexpected error code %d.\n", rc); + + compile_info.source_type = tests[i].sm4 ? VKD3D_SHADER_SOURCE_DXBC_TPF : VKD3D_SHADER_SOURCE_D3D_BYTECODE; + compile_info.source = dxbc; + + compile_info.next = &descriptor_info; + + rc = vkd3d_shader_scan(&compile_info, NULL); + ok(rc == VKD3D_OK, "Got unexpected error code %d.\n", rc); + + ok(descriptor_info.descriptor_count == tests[i].descriptor_count, + "Got descriptor count %u.\n", descriptor_info.descriptor_count); + for (j = 0; j < descriptor_info.descriptor_count; ++j) + { + const struct vkd3d_shader_descriptor_info *descriptor = &descriptor_info.descriptors[j]; + const struct vkd3d_shader_descriptor_info *expect = &tests[i].descriptors[j]; + + vkd3d_test_push_context("descriptor %u", j); + + ok(descriptor->type == expect->type, "Got type %#x.\n", descriptor->type); + ok(descriptor->register_space == expect->register_space, "Got space %u.\n", descriptor->register_space); + ok(descriptor->register_index == expect->register_index, "Got index %u.\n", descriptor->register_index); + ok(descriptor->resource_type == expect->resource_type, + "Got resource type %#x.\n", descriptor->resource_type); + ok(descriptor->resource_data_type == expect->resource_data_type, + "Got data type %#x.\n", descriptor->resource_data_type); + ok(descriptor->flags == expect->flags, "Got flags %#x.\n", descriptor->flags); + ok(descriptor->count == expect->count, "Got count %u.\n", descriptor->count); + + vkd3d_test_pop_context(); + } + + vkd3d_shader_free_scan_descriptor_info(&descriptor_info); + vkd3d_shader_free_shader_code(&dxbc); + + vkd3d_test_pop_context(); + } +} + START_TEST(vkd3d_shader_api) { setlocale(LC_ALL, ""); @@ -739,4 +833,5 @@ START_TEST(vkd3d_shader_api) run_test(test_d3dbc); run_test(test_dxbc); run_test(test_scan_signatures); + run_test(test_scan_descriptors); }