diff --git a/include/vkd3d_shader.h b/include/vkd3d_shader.h index 1d6cbbf8..d42b6110 100644 --- a/include/vkd3d_shader.h +++ b/include/vkd3d_shader.h @@ -96,6 +96,11 @@ enum vkd3d_shader_structure_type * \since 1.9 */ VKD3D_SHADER_STRUCTURE_TYPE_VARYING_MAP_INFO, + /** + * The structure is a vkd3d_shader_scan_combined_resource_sampler_info structure. + * \since 1.10 + */ + VKD3D_SHADER_STRUCTURE_TYPE_SCAN_COMBINED_RESOURCE_SAMPLER_INFO, VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_STRUCTURE_TYPE), }; @@ -1478,6 +1483,49 @@ struct vkd3d_shader_scan_descriptor_info unsigned int descriptor_count; }; +/** + * This structure describes a single resource-sampler pair. It is returned as + * part of struct vkd3d_shader_scan_combined_resource_sampler_info. + * + * \since 1.10 + */ +struct vkd3d_shader_combined_resource_sampler_info +{ + unsigned int resource_space; + unsigned int resource_index; + unsigned int sampler_space; + unsigned int sampler_index; +}; + +/** + * A chained structure describing the resource-sampler pairs used by a shader. + * + * This structure extends vkd3d_shader_compile_info. + * + * The information returned in this structure can be used to populate the + * \ref vkd3d_shader_interface_info.combined_samplers field. This is + * particularly useful when targeting environments without separate binding + * points for samplers and resources, like OpenGL. + * + * Members of this structure are allocated by vkd3d-shader and should be freed + * with vkd3d_shader_free_scan_combined_resource_sampler_info() when no longer + * needed. + * + * \since 1.10 + */ +struct vkd3d_shader_scan_combined_resource_sampler_info +{ + /** Must be set to VKD3D_SHADER_STRUCTURE_TYPE_SCAN_COMBINED_RESOURCE_SAMPLER_INFO. */ + enum vkd3d_shader_structure_type type; + /** Optional pointer to a structure containing further parameters. */ + const void *next; + + /** Pointer to an array of resource-sampler pairs. */ + struct vkd3d_shader_combined_resource_sampler_info *combined_samplers; + /** The number of resource-sampler pairs in \ref combined_samplers. */ + unsigned int combined_sampler_count; +}; + /** * Data type of a shader varying, returned as part of struct * vkd3d_shader_signature_element. @@ -2379,6 +2427,21 @@ VKD3D_SHADER_API void vkd3d_shader_build_varying_map(const struct vkd3d_shader_s const struct vkd3d_shader_signature *input_signature, unsigned int *count, struct vkd3d_shader_varying_map *varyings); +/** + * Free members of struct vkd3d_shader_scan_combined_resource_sampler_info + * allocated by vkd3d_shader_scan(). + * + * This function may free members of + * vkd3d_shader_scan_combined_resource_sampler_info, but does not free the + * structure itself. + * + * \param info Combined resource-sampler information to free. + * + * \since 1.10 + */ +VKD3D_SHADER_API void vkd3d_shader_free_scan_combined_resource_sampler_info( + struct vkd3d_shader_scan_combined_resource_sampler_info *info); + #endif /* VKD3D_SHADER_NO_PROTOTYPES */ /** Type of vkd3d_shader_get_version(). */ @@ -2451,6 +2514,10 @@ typedef void (*PFN_vkd3d_shader_build_varying_map)(const struct vkd3d_shader_sig /** Type of vkd3d_shader_free_scan_signature_info(). \since 1.9 */ typedef void (*PFN_vkd3d_shader_free_scan_signature_info)(struct vkd3d_shader_scan_signature_info *info); +/** Type of vkd3d_shader_free_scan_combined_resource_sampler_info(). \since 1.10 */ +typedef void (*PFN_vkd3d_shader_free_scan_combined_resource_sampler_info)( + struct vkd3d_shader_scan_combined_resource_sampler_info *info); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/libs/vkd3d-shader/vkd3d_shader.map b/libs/vkd3d-shader/vkd3d_shader.map index a64b98e7..973f9077 100644 --- a/libs/vkd3d-shader/vkd3d_shader.map +++ b/libs/vkd3d-shader/vkd3d_shader.map @@ -8,6 +8,7 @@ global: vkd3d_shader_free_dxbc; vkd3d_shader_free_messages; vkd3d_shader_free_root_signature; + vkd3d_shader_free_scan_combined_resource_sampler_info; vkd3d_shader_free_scan_descriptor_info; vkd3d_shader_free_scan_signature_info; vkd3d_shader_free_shader_code; diff --git a/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d-shader/vkd3d_shader_main.c index 28d647b3..48af5d97 100644 --- a/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d-shader/vkd3d_shader_main.c @@ -617,6 +617,8 @@ static bool vkd3d_shader_signature_from_shader_signature(struct vkd3d_shader_sig struct vkd3d_shader_scan_context { + const struct vkd3d_shader_version *version; + struct vkd3d_shader_scan_descriptor_info1 *scan_descriptor_info; size_t descriptors_size; @@ -638,21 +640,28 @@ struct vkd3d_shader_scan_context size_t cf_info_count; enum vkd3d_shader_api_version api_version; + + struct vkd3d_shader_scan_combined_resource_sampler_info *combined_sampler_info; + size_t combined_samplers_size; }; static void vkd3d_shader_scan_context_init(struct vkd3d_shader_scan_context *context, + const struct vkd3d_shader_version *version, const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_scan_descriptor_info1 *scan_descriptor_info, + struct vkd3d_shader_scan_combined_resource_sampler_info *combined_sampler_info, struct vkd3d_shader_message_context *message_context) { unsigned int i; memset(context, 0, sizeof(*context)); + context->version = version; context->scan_descriptor_info = scan_descriptor_info; context->message_context = message_context; context->location.source_name = compile_info->source_name; context->location.line = 2; /* Line 1 is the version token. */ context->api_version = VKD3D_SHADER_API_VERSION_1_2; + context->combined_sampler_info = combined_sampler_info; for (i = 0; i < compile_info->option_count; ++i) { @@ -861,6 +870,82 @@ static void vkd3d_shader_scan_combined_sampler_declaration( &semantic->resource.range, semantic->resource_type, VKD3D_SHADER_RESOURCE_DATA_FLOAT); } +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) +{ + struct vkd3d_shader_scan_combined_resource_sampler_info *info; + struct vkd3d_shader_combined_resource_sampler_info *s; + unsigned resource_space = 0, sampler_space = 0; + unsigned int resource_idx, sampler_idx, i; + + if (!(info = context->combined_sampler_info)) + return; + + if (resource->type == VKD3DSPR_RESOURCE) + resource_idx = resource->idx[1].offset; + else + resource_idx = resource->idx[0].offset; + + if (!sampler) + sampler_idx = VKD3D_SHADER_DUMMY_SAMPLER_INDEX; + else if (sampler->type == VKD3DSPR_SAMPLER) + sampler_idx = sampler->idx[1].offset; + else + sampler_idx = sampler->idx[0].offset; + + 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; + + 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; + 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; + } + } + } + + for (i = 0; i < info->combined_sampler_count; ++i) + { + s = &info->combined_samplers[i]; + if (s->resource_space == resource_space && s->resource_index == resource_idx + && s->sampler_space == sampler_space && s->sampler_index == sampler_idx) + return; + } + + if (!vkd3d_array_reserve((void **)&info->combined_samplers, &context->combined_samplers_size, + info->combined_sampler_count + 1, sizeof(*info->combined_samplers))) + { + ERR("Failed to allocate combined sampler info.\n"); + return; + } + + s = &info->combined_samplers[info->combined_sampler_count++]; + s->resource_space = resource_space; + s->resource_index = resource_idx; + s->sampler_space = sampler_space; + s->sampler_index = sampler_idx; +} + 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, @@ -954,6 +1039,7 @@ static void vkd3d_shader_scan_error(struct vkd3d_shader_scan_context *context, static int vkd3d_shader_scan_instruction(struct vkd3d_shader_scan_context *context, const struct vkd3d_shader_instruction *instruction) { + const struct vkd3d_shader_register *sampler_reg; struct vkd3d_shader_cf_info *cf_info; unsigned int i; @@ -1102,6 +1188,58 @@ static int vkd3d_shader_scan_instruction(struct vkd3d_shader_scan_context *conte if (context->cf_info_count) context->cf_info[context->cf_info_count - 1].inside_block = false; break; + case VKD3DSIH_TEX: + if (context->version->major == 1) + sampler_reg = &instruction->dst[0].reg; + else + sampler_reg = &instruction->src[1].reg; + vkd3d_shader_scan_combined_sampler_usage(context, sampler_reg, sampler_reg); + break; + case VKD3DSIH_TEXBEM: + case VKD3DSIH_TEXBEML: + case VKD3DSIH_TEXDP3TEX: + case VKD3DSIH_TEXM3x2TEX: + case VKD3DSIH_TEXM3x3SPEC: + case VKD3DSIH_TEXM3x3TEX: + case VKD3DSIH_TEXM3x3VSPEC: + case VKD3DSIH_TEXREG2AR: + case VKD3DSIH_TEXREG2GB: + case VKD3DSIH_TEXREG2RGB: + sampler_reg = &instruction->dst[0].reg; + vkd3d_shader_scan_combined_sampler_usage(context, sampler_reg, sampler_reg); + break; + case VKD3DSIH_GATHER4: + case VKD3DSIH_GATHER4_C: + case VKD3DSIH_SAMPLE: + case VKD3DSIH_SAMPLE_B: + case VKD3DSIH_SAMPLE_C: + case VKD3DSIH_SAMPLE_C_LZ: + case VKD3DSIH_SAMPLE_GRAD: + case VKD3DSIH_SAMPLE_LOD: + vkd3d_shader_scan_combined_sampler_usage(context, &instruction->src[1].reg, &instruction->src[2].reg); + break; + case VKD3DSIH_GATHER4_PO: + case VKD3DSIH_GATHER4_PO_C: + vkd3d_shader_scan_combined_sampler_usage(context, &instruction->src[2].reg, &instruction->src[3].reg); + break; + case VKD3DSIH_LD: + case VKD3DSIH_LD2DMS: + vkd3d_shader_scan_combined_sampler_usage(context, &instruction->src[1].reg, NULL); + break; + case VKD3DSIH_BUFINFO: + case VKD3DSIH_SAMPLE_INFO: + if (instruction->src[0].reg.type == VKD3DSPR_RESOURCE) + vkd3d_shader_scan_combined_sampler_usage(context, &instruction->src[0].reg, NULL); + break; + case VKD3DSIH_LD_RAW: + case VKD3DSIH_RESINFO: + if (instruction->src[1].reg.type == VKD3DSPR_RESOURCE) + vkd3d_shader_scan_combined_sampler_usage(context, &instruction->src[1].reg, NULL); + break; + case VKD3DSIH_LD_STRUCTURED: + if (instruction->src[2].reg.type == VKD3DSPR_RESOURCE) + vkd3d_shader_scan_combined_sampler_usage(context, &instruction->src[2].reg, NULL); + break; default: break; } @@ -1173,6 +1311,7 @@ static int scan_with_parser(const struct vkd3d_shader_compile_info *compile_info struct vkd3d_shader_message_context *message_context, struct vkd3d_shader_scan_descriptor_info1 *descriptor_info1, struct vkd3d_shader_parser *parser) { + struct vkd3d_shader_scan_combined_resource_sampler_info *combined_sampler_info; struct vkd3d_shader_scan_descriptor_info1 local_descriptor_info1 = {0}; struct vkd3d_shader_scan_descriptor_info *descriptor_info; struct vkd3d_shader_scan_signature_info *signature_info; @@ -1193,7 +1332,16 @@ static int scan_with_parser(const struct vkd3d_shader_compile_info *compile_info } signature_info = vkd3d_find_struct(compile_info->next, SCAN_SIGNATURE_INFO); - vkd3d_shader_scan_context_init(&context, compile_info, descriptor_info1, message_context); + if ((combined_sampler_info = vkd3d_find_struct(compile_info->next, SCAN_COMBINED_RESOURCE_SAMPLER_INFO))) + { + combined_sampler_info->combined_samplers = NULL; + combined_sampler_info->combined_sampler_count = 0; + if (!descriptor_info1) + descriptor_info1 = &local_descriptor_info1; + } + + vkd3d_shader_scan_context_init(&context, &parser->shader_version, compile_info, + descriptor_info1, combined_sampler_info, message_context); if (TRACE_ON()) { @@ -1239,6 +1387,8 @@ static int scan_with_parser(const struct vkd3d_shader_compile_info *compile_info if (ret < 0) { + if (combined_sampler_info) + vkd3d_shader_free_scan_combined_resource_sampler_info(combined_sampler_info); if (descriptor_info) vkd3d_shader_free_scan_descriptor_info(descriptor_info); if (descriptor_info1) @@ -1528,6 +1678,14 @@ int vkd3d_shader_compile(const struct vkd3d_shader_compile_info *compile_info, return ret; } +void vkd3d_shader_free_scan_combined_resource_sampler_info( + struct vkd3d_shader_scan_combined_resource_sampler_info *info) +{ + TRACE("info %p.\n", info); + + vkd3d_free(info->combined_samplers); +} + void vkd3d_shader_free_scan_descriptor_info(struct vkd3d_shader_scan_descriptor_info *scan_descriptor_info) { TRACE("scan_descriptor_info %p.\n", scan_descriptor_info); diff --git a/tests/vkd3d_shader_api.c b/tests/vkd3d_shader_api.c index 106bc21c..9fe5eec8 100644 --- a/tests/vkd3d_shader_api.c +++ b/tests/vkd3d_shader_api.c @@ -853,6 +853,132 @@ static void test_build_varying_map(void) ok(map[1].input_mask == 0x3, "Got map[1].input_mask %#x.\n", map[1].input_mask); } +static void test_scan_combined_resource_samplers(void) +{ + struct vkd3d_shader_hlsl_source_info hlsl_info = {.type = VKD3D_SHADER_STRUCTURE_TYPE_HLSL_SOURCE_INFO}; + struct vkd3d_shader_compile_info info = {.type = VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO}; + PFN_vkd3d_shader_free_scan_combined_resource_sampler_info pfn_free_combined_sampler_info; + struct vkd3d_shader_scan_combined_resource_sampler_info combined_sampler_info; + struct vkd3d_shader_combined_resource_sampler_info *s; + struct vkd3d_shader_code d3dbc; + int rc; + + static const char ps_3_0_source[] = + "sampler s[3];\n" + "\n" + "float4 main(float4 coord : TEXCOORD) : COLOR\n" + "{\n" + " float4 r;\n" + "\n" + " r = tex2D(s[0], coord.xy);\n" + " r += tex2D(s[2], coord.xy);\n" + "\n" + " return r;\n" + "}\n"; + + static const uint32_t ps_5_1[] = + { +#if 0 + Texture2D t0[8] : register(t8, space4); + Texture2D t1[4] : register(t9, space5); + SamplerState s2[4] : register(s10, space6); + SamplerState s3[8] : register(s11, space7); + + float4 main(float4 coord : TEXCOORD) : SV_TARGET + { + float4 r; + + r = t0[7].Sample(s2[3], coord.xy); + r += t1[2].Sample(s3[6], coord.xy); + r += t0[4].Load(coord.xyz); + + return r; + } +#endif + 0x43425844, 0x743f5994, 0x0c6d43cf, 0xde114c10, 0xc1adc69a, 0x00000001, 0x000001f8, 0x00000003, + 0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, + 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x0000070f, 0x43584554, 0x44524f4f, 0xababab00, + 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, 0x00000003, + 0x00000000, 0x0000000f, 0x545f5653, 0x45475241, 0xabab0054, 0x58454853, 0x0000015c, 0x00000051, + 0x00000057, 0x0100086a, 0x0600005a, 0x00306e46, 0x00000000, 0x0000000a, 0x0000000d, 0x00000006, + 0x0600005a, 0x00306e46, 0x00000001, 0x0000000b, 0x00000012, 0x00000007, 0x07001858, 0x00307e46, + 0x00000000, 0x00000008, 0x0000000f, 0x00005555, 0x00000004, 0x07001858, 0x00307e46, 0x00000001, + 0x00000009, 0x0000000c, 0x00005555, 0x00000005, 0x03001062, 0x00101072, 0x00000000, 0x03000065, + 0x001020f2, 0x00000000, 0x02000068, 0x00000002, 0x0b000045, 0x001000f2, 0x00000000, 0x00101046, + 0x00000000, 0x00207e46, 0x00000000, 0x0000000f, 0x00206000, 0x00000000, 0x0000000d, 0x0b000045, + 0x001000f2, 0x00000001, 0x00101046, 0x00000000, 0x00207e46, 0x00000001, 0x0000000b, 0x00206000, + 0x00000001, 0x00000011, 0x07000000, 0x001000f2, 0x00000000, 0x00100e46, 0x00000000, 0x00100e46, + 0x00000001, 0x0500001b, 0x001000f2, 0x00000001, 0x00101a46, 0x00000000, 0x0800002d, 0x001000f2, + 0x00000001, 0x00100e46, 0x00000001, 0x00207e46, 0x00000000, 0x0000000c, 0x07000000, 0x001020f2, + 0x00000000, 0x00100e46, 0x00000000, 0x00100e46, 0x00000001, 0x0100003e, + }; + + pfn_free_combined_sampler_info = vkd3d_shader_free_scan_combined_resource_sampler_info; + + hlsl_info.profile = "ps_3_0"; + + info.next = &hlsl_info; + info.source.code = ps_3_0_source; + info.source.size = ARRAY_SIZE(ps_3_0_source); + info.source_type = VKD3D_SHADER_SOURCE_HLSL; + info.target_type = VKD3D_SHADER_TARGET_D3D_BYTECODE; + info.log_level = VKD3D_SHADER_LOG_INFO; + + rc = vkd3d_shader_compile(&info, &d3dbc, NULL); + ok(rc == VKD3D_OK, "Got rc %d.\n", rc); + + combined_sampler_info.type = VKD3D_SHADER_STRUCTURE_TYPE_SCAN_COMBINED_RESOURCE_SAMPLER_INFO; + combined_sampler_info.next = NULL; + + info.next = &combined_sampler_info; + info.source = d3dbc; + info.source_type = VKD3D_SHADER_SOURCE_D3D_BYTECODE; + info.target_type = VKD3D_SHADER_TARGET_NONE; + + rc = vkd3d_shader_scan(&info, NULL); + ok(rc == VKD3D_OK, "Got rc %d.\n", rc); + ok(combined_sampler_info.combined_sampler_count == 2, "Got combined_sampler_count %u.\n", + combined_sampler_info.combined_sampler_count); + s = &combined_sampler_info.combined_samplers[0]; + ok(s->resource_space == 0, "Got resource space %u.\n", s->resource_space); + ok(s->resource_index == 0, "Got resource index %u.\n", s->resource_index); + ok(s->sampler_space == 0, "Got sampler space %u.\n", s->sampler_space); + ok(s->sampler_index == 0, "Got sampler index %u.\n", s->sampler_index); + s = &combined_sampler_info.combined_samplers[1]; + ok(s->resource_space == 0, "Got resource space %u.\n", s->resource_space); + ok(s->resource_index == 2, "Got resource index %u.\n", s->resource_index); + ok(s->sampler_space == 0, "Got sampler space %u.\n", s->sampler_space); + ok(s->sampler_index == 2, "Got sampler index %u.\n", s->sampler_index); + pfn_free_combined_sampler_info(&combined_sampler_info); + + vkd3d_shader_free_shader_code(&d3dbc); + + info.source.code = ps_5_1; + info.source.size = sizeof(ps_5_1); + info.source_type = VKD3D_SHADER_SOURCE_DXBC_TPF; + + rc = vkd3d_shader_scan(&info, NULL); + ok(rc == VKD3D_OK, "Got rc %d.\n", rc); + ok(combined_sampler_info.combined_sampler_count == 3, "Got combined_sampler_count %u.\n", + combined_sampler_info.combined_sampler_count); + s = &combined_sampler_info.combined_samplers[0]; + ok(s->resource_space == 4, "Got resource space %u.\n", s->resource_space); + ok(s->resource_index == 15, "Got resource index %u.\n", s->resource_index); + ok(s->sampler_space == 6, "Got sampler space %u.\n", s->sampler_space); + ok(s->sampler_index == 13, "Got sampler index %u.\n", s->sampler_index); + s = &combined_sampler_info.combined_samplers[1]; + ok(s->resource_space == 5, "Got resource space %u.\n", s->resource_space); + ok(s->resource_index == 11, "Got resource index %u.\n", s->resource_index); + ok(s->sampler_space == 7, "Got sampler space %u.\n", s->sampler_space); + ok(s->sampler_index == 17, "Got sampler index %u.\n", s->sampler_index); + s = &combined_sampler_info.combined_samplers[2]; + ok(s->resource_space == 4, "Got resource space %u.\n", s->resource_space); + ok(s->resource_index == 12, "Got resource index %u.\n", s->resource_index); + ok(s->sampler_space == 0, "Got sampler space %u.\n", s->sampler_space); + ok(s->sampler_index == VKD3D_SHADER_DUMMY_SAMPLER_INDEX, "Got sampler index %u.\n", s->sampler_index); + pfn_free_combined_sampler_info(&combined_sampler_info); +} + START_TEST(vkd3d_shader_api) { setlocale(LC_ALL, ""); @@ -865,4 +991,5 @@ START_TEST(vkd3d_shader_api) run_test(test_scan_signatures); run_test(test_scan_descriptors); run_test(test_build_varying_map); + run_test(test_scan_combined_resource_samplers); }