Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- include/vkd3d_shader.h | 2 + libs/vkd3d-shader/vkd3d_shader_main.c | 273 +++++++++++++++----------- 2 files changed, 159 insertions(+), 116 deletions(-)
diff --git a/include/vkd3d_shader.h b/include/vkd3d_shader.h index 3efd355f..003da386 100644 --- a/include/vkd3d_shader.h +++ b/include/vkd3d_shader.h @@ -448,6 +448,7 @@ enum vkd3d_shader_source_type * the format used for Direct3D shader model 4 and 5 shaders. */ VKD3D_SHADER_SOURCE_DXBC_TPF, + VKD3D_SHADER_SOURCE_HLSL,
VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_SOURCE_TYPE), }; @@ -466,6 +467,7 @@ enum vkd3d_shader_target_type */ VKD3D_SHADER_TARGET_SPIRV_BINARY, VKD3D_SHADER_TARGET_SPIRV_TEXT, + VKD3D_SHADER_TARGET_DXBC_TPF,
VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_TARGET_TYPE), }; diff --git a/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d-shader/vkd3d_shader_main.c index 16d895ff..e44a80b7 100644 --- a/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d-shader/vkd3d_shader_main.c @@ -299,92 +299,12 @@ void vkd3d_shader_free_messages(char *messages) vkd3d_free(messages); }
-int vkd3d_shader_compile(const struct vkd3d_shader_compile_info *compile_info, - struct vkd3d_shader_code *out, char **messages) -{ - struct vkd3d_shader_scan_descriptor_info scan_descriptor_info; - struct vkd3d_shader_message_context message_context; - struct vkd3d_shader_instruction instruction; - struct vkd3d_shader_compile_info scan_info; - struct vkd3d_dxbc_compiler *spirv_compiler; - struct vkd3d_shader_parser parser; - int ret; - - TRACE("compile_info %p, out %p, messages %p.\n", compile_info, out, messages); - - if (messages) - *messages = NULL; - - if ((ret = vkd3d_shader_validate_compile_info(compile_info)) < 0) - return ret; - - scan_info = *compile_info; - scan_descriptor_info.type = VKD3D_SHADER_STRUCTURE_TYPE_SCAN_DESCRIPTOR_INFO; - scan_descriptor_info.next = scan_info.next; - scan_info.next = &scan_descriptor_info; - - if ((ret = vkd3d_shader_scan(&scan_info, messages)) < 0) - return ret; - if (messages) - { - vkd3d_shader_free_messages(*messages); - *messages = NULL; - } - - if (!vkd3d_shader_message_context_init(&message_context, compile_info->log_level, compile_info->source_name)) - return VKD3D_ERROR; - if ((ret = vkd3d_shader_parser_init(&parser, &compile_info->source, &message_context)) < 0) - goto done; - - vkd3d_shader_dump_shader(parser.shader_version.type, &compile_info->source); - - if (!(spirv_compiler = vkd3d_dxbc_compiler_create(&parser.shader_version, - &parser.shader_desc, compile_info, &scan_descriptor_info, &message_context))) - { - ERR("Failed to create DXBC compiler.\n"); - vkd3d_shader_parser_destroy(&parser); - ret = VKD3D_ERROR; - goto done; - } - - message_context.line = 2; /* Line 1 is the version token. */ - message_context.column = 1; - while (!shader_sm4_is_end(parser.data, &parser.ptr)) - { - shader_sm4_read_instruction(parser.data, &parser.ptr, &instruction); - - if (instruction.handler_idx == VKD3DSIH_INVALID) - { - WARN("Encountered unrecognized or invalid instruction.\n"); - ret = VKD3D_ERROR_INVALID_SHADER; - break; - } - - if ((ret = vkd3d_dxbc_compiler_handle_instruction(spirv_compiler, &instruction)) < 0) - break; - ++message_context.line; - } - - if (ret >= 0) - ret = vkd3d_dxbc_compiler_generate_spirv(spirv_compiler, compile_info, out); - - vkd3d_dxbc_compiler_destroy(spirv_compiler); - vkd3d_shader_parser_destroy(&parser); -done: - vkd3d_shader_message_context_trace_messages(&message_context); - if (messages && !(*messages = vkd3d_shader_message_context_copy_messages(&message_context))) - ret = VKD3D_ERROR_OUT_OF_MEMORY; - vkd3d_shader_message_context_cleanup(&message_context); - vkd3d_shader_free_scan_descriptor_info(&scan_descriptor_info); - return ret; -} - struct vkd3d_shader_scan_context { struct vkd3d_shader_scan_descriptor_info *scan_descriptor_info; size_t descriptors_size;
- struct vkd3d_shader_message_context message_context; + struct vkd3d_shader_message_context *message_context;
struct vkd3d_shader_cf_info { @@ -409,20 +329,19 @@ struct vkd3d_shader_scan_context size_t uav_range_count; };
-static bool vkd3d_shader_scan_context_init(struct vkd3d_shader_scan_context *context, +static void vkd3d_shader_scan_context_init(struct vkd3d_shader_scan_context *context, struct vkd3d_shader_scan_descriptor_info *scan_descriptor_info, - enum vkd3d_shader_log_level log_level, const char *source_name) + struct vkd3d_shader_message_context *message_context) { memset(context, 0, sizeof(*context)); context->scan_descriptor_info = scan_descriptor_info; - return vkd3d_shader_message_context_init(&context->message_context, log_level, source_name); + context->message_context = message_context; }
static void vkd3d_shader_scan_context_cleanup(struct vkd3d_shader_scan_context *context) { vkd3d_free(context->uav_ranges); vkd3d_free(context->cf_info); - vkd3d_shader_message_context_cleanup(&context->message_context); }
static struct vkd3d_shader_cf_info *vkd3d_shader_scan_get_current_cf_info(struct vkd3d_shader_scan_context *context) @@ -706,7 +625,7 @@ static int vkd3d_shader_scan_instruction(struct vkd3d_shader_scan_context *conte case VKD3DSIH_ELSE: if (!(cf_info = vkd3d_shader_scan_get_current_cf_info(context)) || cf_info->type != VKD3D_SHADER_BLOCK_IF) { - vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF, + vkd3d_shader_error(context->message_context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF, "Encountered ‘else’ instruction without corresponding ‘if’ block."); return VKD3D_ERROR_INVALID_SHADER; } @@ -715,7 +634,7 @@ static int vkd3d_shader_scan_instruction(struct vkd3d_shader_scan_context *conte case VKD3DSIH_ENDIF: if (!(cf_info = vkd3d_shader_scan_get_current_cf_info(context)) || cf_info->type != VKD3D_SHADER_BLOCK_IF) { - vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF, + vkd3d_shader_error(context->message_context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF, "Encountered ‘endif’ instruction without corresponding ‘if’ block."); return VKD3D_ERROR_INVALID_SHADER; } @@ -728,7 +647,7 @@ static int vkd3d_shader_scan_instruction(struct vkd3d_shader_scan_context *conte case VKD3DSIH_ENDLOOP: if (!(cf_info = vkd3d_shader_scan_get_current_cf_info(context)) || cf_info->type != VKD3D_SHADER_BLOCK_LOOP) { - vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF, + vkd3d_shader_error(context->message_context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF, "Encountered ‘endloop’ instruction without corresponding ‘loop’ block."); return VKD3D_ERROR_INVALID_SHADER; } @@ -742,7 +661,7 @@ static int vkd3d_shader_scan_instruction(struct vkd3d_shader_scan_context *conte if (!(cf_info = vkd3d_shader_scan_get_current_cf_info(context)) || cf_info->type != VKD3D_SHADER_BLOCK_SWITCH || cf_info->inside_block) { - vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF, + vkd3d_shader_error(context->message_context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF, "Encountered ‘endswitch’ instruction without corresponding ‘switch’ block."); return VKD3D_ERROR_INVALID_SHADER; } @@ -752,7 +671,7 @@ static int vkd3d_shader_scan_instruction(struct vkd3d_shader_scan_context *conte if (!(cf_info = vkd3d_shader_scan_get_current_cf_info(context)) || cf_info->type != VKD3D_SHADER_BLOCK_SWITCH) { - vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF, + vkd3d_shader_error(context->message_context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF, "Encountered ‘case’ instruction outside switch block."); return VKD3D_ERROR_INVALID_SHADER; } @@ -762,13 +681,13 @@ static int vkd3d_shader_scan_instruction(struct vkd3d_shader_scan_context *conte if (!(cf_info = vkd3d_shader_scan_get_current_cf_info(context)) || cf_info->type != VKD3D_SHADER_BLOCK_SWITCH) { - vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF, + vkd3d_shader_error(context->message_context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF, "Encountered ‘default’ instruction outside switch block."); return VKD3D_ERROR_INVALID_SHADER; } if (cf_info->has_default) { - vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF, + vkd3d_shader_error(context->message_context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF, "Encountered duplicate ‘default’ instruction inside the current switch block."); return VKD3D_ERROR_INVALID_SHADER; } @@ -778,7 +697,7 @@ static int vkd3d_shader_scan_instruction(struct vkd3d_shader_scan_context *conte case VKD3DSIH_BREAK: if (!(cf_info = vkd3d_shader_scan_find_innermost_breakable_cf_info(context))) { - vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF, + vkd3d_shader_error(context->message_context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF, "Encountered ‘break’ instruction outside breakable block."); return VKD3D_ERROR_INVALID_SHADER; } @@ -787,7 +706,7 @@ static int vkd3d_shader_scan_instruction(struct vkd3d_shader_scan_context *conte case VKD3DSIH_BREAKP: if (!(cf_info = vkd3d_shader_scan_find_innermost_loop_cf_info(context))) { - vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF, + vkd3d_shader_error(context->message_context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF, "Encountered ‘breakp’ instruction outside loop."); return VKD3D_ERROR_INVALID_SHADER; } @@ -795,7 +714,7 @@ static int vkd3d_shader_scan_instruction(struct vkd3d_shader_scan_context *conte case VKD3DSIH_CONTINUE: if (!(cf_info = vkd3d_shader_scan_find_innermost_loop_cf_info(context))) { - vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF, + vkd3d_shader_error(context->message_context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF, "Encountered ‘continue’ instruction outside loop."); return VKD3D_ERROR_INVALID_SHADER; } @@ -804,7 +723,7 @@ static int vkd3d_shader_scan_instruction(struct vkd3d_shader_scan_context *conte case VKD3DSIH_CONTINUEP: if (!(cf_info = vkd3d_shader_scan_find_innermost_loop_cf_info(context))) { - vkd3d_shader_error(&context->message_context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF, + vkd3d_shader_error(context->message_context, VKD3D_SHADER_ERROR_TPF_MISMATCHED_CF, "Encountered ‘continue’ instruction outside loop."); return VKD3D_ERROR_INVALID_SHADER; } @@ -837,39 +756,25 @@ static int vkd3d_shader_scan_instruction(struct vkd3d_shader_scan_context *conte return VKD3D_OK; }
-int vkd3d_shader_scan(const struct vkd3d_shader_compile_info *compile_info, char **messages) +static int scan_dxbc(const struct vkd3d_shader_compile_info *compile_info, + struct vkd3d_shader_message_context *message_context) { struct vkd3d_shader_scan_descriptor_info *scan_descriptor_info; - struct vkd3d_shader_message_context *message_context; struct vkd3d_shader_instruction instruction; struct vkd3d_shader_scan_context context; struct vkd3d_shader_parser parser; int ret;
- TRACE("compile_info %p, messages %p.\n", compile_info, messages); - - if (messages) - *messages = NULL; - - if ((ret = vkd3d_shader_validate_compile_info(compile_info)) < 0) - return ret; - if ((scan_descriptor_info = vkd3d_find_struct(compile_info->next, SCAN_DESCRIPTOR_INFO))) { scan_descriptor_info->descriptors = NULL; scan_descriptor_info->descriptor_count = 0; }
- if (!vkd3d_shader_scan_context_init(&context, scan_descriptor_info, - compile_info->log_level, compile_info->source_name)) - return VKD3D_ERROR; - message_context = &context.message_context; + vkd3d_shader_scan_context_init(&context, scan_descriptor_info, message_context);
if ((ret = vkd3d_shader_parser_init(&parser, &compile_info->source, message_context)) < 0) { - vkd3d_shader_message_context_trace_messages(message_context); - if (messages && !(*messages = vkd3d_shader_message_context_copy_messages(message_context))) - ret = VKD3D_ERROR_OUT_OF_MEMORY; vkd3d_shader_scan_context_cleanup(&context); return ret; } @@ -904,14 +809,39 @@ int vkd3d_shader_scan(const struct vkd3d_shader_compile_info *compile_info, char ret = VKD3D_OK;
done: - vkd3d_shader_message_context_trace_messages(message_context); - if (messages && !(*messages = vkd3d_shader_message_context_copy_messages(message_context))) - ret = VKD3D_ERROR_OUT_OF_MEMORY; vkd3d_shader_scan_context_cleanup(&context); vkd3d_shader_parser_destroy(&parser); return ret; }
+int vkd3d_shader_scan(const struct vkd3d_shader_compile_info *compile_info, char **messages) +{ + struct vkd3d_shader_message_context message_context; + int ret; + + TRACE("compile_info %p, messages %p.\n", compile_info, messages); + + if (messages) + *messages = NULL; + + if ((ret = vkd3d_shader_validate_compile_info(compile_info)) < 0) + return ret; + + if (!vkd3d_shader_message_context_init(&message_context, compile_info->log_level, compile_info->source_name)) + return VKD3D_ERROR_OUT_OF_MEMORY; + + if (compile_info->source_type == VKD3D_SHADER_SOURCE_DXBC_TPF) + ret = scan_dxbc(compile_info, &message_context); + else if (compile_info->source_type == VKD3D_SHADER_SOURCE_HLSL) + ret = VKD3D_ERROR_NOT_IMPLEMENTED; + + vkd3d_shader_message_context_trace_messages(&message_context); + if (messages && !(*messages = vkd3d_shader_message_context_copy_messages(&message_context))) + ret = VKD3D_ERROR_OUT_OF_MEMORY; + vkd3d_shader_message_context_cleanup(&message_context); + return ret; +} + 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); @@ -919,6 +849,107 @@ void vkd3d_shader_free_scan_descriptor_info(struct vkd3d_shader_scan_descriptor_ vkd3d_free(scan_descriptor_info->descriptors); }
+static int compile_dxbc_to_spirv(const struct vkd3d_shader_compile_info *compile_info, + struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context) +{ + struct vkd3d_shader_scan_descriptor_info scan_descriptor_info; + struct vkd3d_shader_instruction instruction; + struct vkd3d_shader_compile_info scan_info; + struct vkd3d_dxbc_compiler *spirv_compiler; + struct vkd3d_shader_parser parser; + int ret; + + scan_info = *compile_info; + scan_descriptor_info.type = VKD3D_SHADER_STRUCTURE_TYPE_SCAN_DESCRIPTOR_INFO; + scan_descriptor_info.next = scan_info.next; + scan_info.next = &scan_descriptor_info; + + if ((ret = scan_dxbc(&scan_info, message_context)) < 0) + return ret; + + if ((ret = vkd3d_shader_parser_init(&parser, &compile_info->source, message_context)) < 0) + goto done; + + vkd3d_shader_dump_shader(parser.shader_version.type, &compile_info->source); + + if (!(spirv_compiler = vkd3d_dxbc_compiler_create(&parser.shader_version, + &parser.shader_desc, compile_info, &scan_descriptor_info, message_context))) + { + ERR("Failed to create DXBC compiler.\n"); + vkd3d_shader_parser_destroy(&parser); + ret = VKD3D_ERROR; + goto done; + } + + message_context->line = 2; /* Line 1 is the version token. */ + message_context->column = 1; + while (!shader_sm4_is_end(parser.data, &parser.ptr)) + { + shader_sm4_read_instruction(parser.data, &parser.ptr, &instruction); + + if (instruction.handler_idx == VKD3DSIH_INVALID) + { + WARN("Encountered unrecognized or invalid instruction.\n"); + ret = VKD3D_ERROR_INVALID_SHADER; + break; + } + + if ((ret = vkd3d_dxbc_compiler_handle_instruction(spirv_compiler, &instruction)) < 0) + break; + ++message_context->line; + } + + if (ret >= 0) + ret = vkd3d_dxbc_compiler_generate_spirv(spirv_compiler, compile_info, out); + + vkd3d_dxbc_compiler_destroy(spirv_compiler); + vkd3d_shader_parser_destroy(&parser); +done: + vkd3d_shader_free_scan_descriptor_info(&scan_descriptor_info); + return ret; +} + +static int compile_hlsl_to_dxbc(const struct vkd3d_shader_compile_info *compile_info, + struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context) +{ + return VKD3D_ERROR_NOT_IMPLEMENTED; +} + +int vkd3d_shader_compile(const struct vkd3d_shader_compile_info *compile_info, + struct vkd3d_shader_code *out, char **messages) +{ + struct vkd3d_shader_message_context message_context; + int ret; + + TRACE("compile_info %p, out %p, messages %p.\n", compile_info, out, messages); + + if (messages) + *messages = NULL; + + if ((ret = vkd3d_shader_validate_compile_info(compile_info)) < 0) + return ret; + + if (!vkd3d_shader_message_context_init(&message_context, compile_info->log_level, compile_info->source_name)) + return VKD3D_ERROR_OUT_OF_MEMORY; + + if (compile_info->source_type == VKD3D_SHADER_SOURCE_DXBC_TPF + && compile_info->target_type == VKD3D_SHADER_TARGET_SPIRV_BINARY) + ret = compile_dxbc_to_spirv(compile_info, out, &message_context); + else if (compile_info->source_type == VKD3D_SHADER_SOURCE_HLSL + && compile_info->target_type == VKD3D_SHADER_TARGET_DXBC_TPF) + ret = compile_hlsl_to_dxbc(compile_info, out, &message_context); + + vkd3d_shader_message_context_trace_messages(&message_context); + if (messages) + { + vkd3d_shader_free_messages(*messages); + if (!(*messages = vkd3d_shader_message_context_copy_messages(&message_context))) + ret = VKD3D_ERROR_OUT_OF_MEMORY; + } + vkd3d_shader_message_context_cleanup(&message_context); + return ret; +} + void vkd3d_shader_free_shader_code(struct vkd3d_shader_code *shader_code) { TRACE("shader_code %p.\n", shader_code); @@ -1057,6 +1088,7 @@ const enum vkd3d_shader_source_type *vkd3d_shader_get_supported_source_types(uns static const enum vkd3d_shader_source_type types[] = { VKD3D_SHADER_SOURCE_DXBC_TPF, + VKD3D_SHADER_SOURCE_HLSL, };
TRACE("count %p.\n", count); @@ -1076,6 +1108,11 @@ const enum vkd3d_shader_target_type *vkd3d_shader_get_supported_target_types( #endif };
+ static const enum vkd3d_shader_target_type hlsl_types[] = + { + VKD3D_SHADER_TARGET_DXBC_TPF, + }; + TRACE("source_type %#x, count %p.\n", source_type, count);
switch (source_type) @@ -1084,6 +1121,10 @@ const enum vkd3d_shader_target_type *vkd3d_shader_get_supported_target_types( *count = ARRAY_SIZE(dxbc_tpf_types); return dxbc_tpf_types;
+ case VKD3D_SHADER_SOURCE_HLSL: + *count = ARRAY_SIZE(hlsl_types); + return hlsl_types; + default: *count = 0; return NULL;
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- include/vkd3d_shader.h | 159 ++++++++++++++++++++++++++ libs/vkd3d-shader/vkd3d_shader.map | 1 + libs/vkd3d-shader/vkd3d_shader_main.c | 8 ++ 3 files changed, 168 insertions(+)
diff --git a/include/vkd3d_shader.h b/include/vkd3d_shader.h index 003da386..768d6050 100644 --- a/include/vkd3d_shader.h +++ b/include/vkd3d_shader.h @@ -54,6 +54,12 @@ enum vkd3d_shader_structure_type /** The structure is a vkd3d_shader_transform_feedback_info structure. */ VKD3D_SHADER_STRUCTURE_TYPE_TRANSFORM_FEEDBACK_INFO,
+ /** + * The structure is a vkd3d_shader_preprocess_info structure. + * \since 1.3 + */ + VKD3D_SHADER_STRUCTURE_TYPE_PREPROCESS_INFO, + VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_STRUCTURE_TYPE), };
@@ -605,6 +611,130 @@ struct vkd3d_shader_spirv_domain_shader_target_info enum vkd3d_shader_tessellator_partitioning partitioning; };
+/** + * A single preprocessor macro, passed as part of struct + * vkd3d_shader_preprocess_info. + */ +struct vkd3d_shader_macro +{ + /** + * A null-terminated string containing the name of a macro. This macro must + * not be a parameterized (i.e. function-like) macro. If the macro name is + * invalid (for example, if it does not consist solely of alphanumeric + * characters), it will be ignored. + */ + const char *name; + /** A null-terminated string containing the expansion of the macro. */ + const char *value; +}; + +/** + * Type of a callback function which will be used to open preprocessor includes. + * + * This callback function is passed as part of struct + * vkd3d_shader_preprocess_info. + * + * If this function fails, vkd3d-shader will emit a compilation error, and the + * \a pfn_close_include callback will not be called. + * + * \param filename Unquoted string used as an argument to the #include + * directive. + * + * \param local Whether the #include directive is requesting a local (i.e. + * double-quoted) or system (i.e. angle-bracketed) include. + * + * \param parent_data Unprocessed source code of the file in which this + * #include directive is evaluated. This parameter may be NULL. + * + * \param context The user-defined pointer passed to struct + * vkd3d_shader_preprocess_info. + * + * \param out Output location for the full contents of the included file. The + * code need not be allocated using standard vkd3d functions, but must remain + * valid until the corresponding call to \a pfn_close_include. If this function + * fails, the contents of this parameter are ignored. + * + * \return A member of \ref vkd3d_result. + */ +typedef int (*PFN_vkd3d_shader_open_include)(const char *filename, bool local, + const char *parent_data, void *context, struct vkd3d_shader_code *out); +/** + * Type of a callback function which will be used to close preprocessor + * includes. + * + * This callback function is passed as part of struct + * vkd3d_shader_preprocess_info. + * + * \param code Contents of the included file, which were allocated by the + * \ref PFN_vkd3d_shader_open_include callback. The source code was allocated by + * the user and thus need not be freed by vkd3d_shader_free_shader_code(). + * + * \param context The user-defined pointer passed to struct + * vkd3d_shader_preprocess_info. + */ +typedef void (*PFN_vkd3d_shader_close_include)(const struct vkd3d_shader_code *code, void *context); + +/** + * A chained structure containing preprocessing parameters. + * + * This structure is optional. + * + * This structure extends vkd3d_shader_compile_info. + * + * This structure contains only input parameters. + * + * \since 1.3 + */ +struct vkd3d_shader_preprocess_info +{ + /** Must be set to VKD3D_SHADER_STRUCTURE_TYPE_PREPROCESS_INFO. */ + enum vkd3d_shader_structure_type type; + /** Optional pointer to a structure containing further parameters. */ + const void *next; + + /** + * Pointer to an array of predefined macros. Each macro in this array will + * be expanded as if a corresponding #define statement were prepended to the + * source code. + * + * If the same macro is specified multiple itmes, only the first value is + * used. + */ + const struct vkd3d_shader_macro *macros; + /** Size, in elements, of \ref macros. */ + unsigned int macro_count; + + /** + * Optional pointer to a callback function, which will be called in order to + * evaluate #include directives. The function receives parameters + * corresponding to the directive's arguments, and should return the + * complete text of the included file. + * + * If this field is set to NULL, or if this structure is omitted, + * vkd3d-shader will emit a compilation error if any #include directives + * are evaluated. + * + * If this field is set to NULL, the \ref pfn_close_include field must also + * be set to NULL. + */ + PFN_vkd3d_shader_open_include pfn_open_include; + /** + * Optional pointer to a callback function, which will be called whenever an + * included file is closed. This function will be called exactly once for + * each successful call to \ref pfn_open_include, and should be used to free + * any resources allocated thereby. + * + * If this field is set to NULL, the \ref pfn_open_include field must also + * be set to NULL. + */ + PFN_vkd3d_shader_close_include pfn_close_include; + /** + * User-defined pointer which will be passed unmodified to the + * \ref pfn_open_include and \ref pfn_close_include callbacks. + */ + void *include_context; +}; + /* root signature 1.0 */ enum vkd3d_shader_filter { @@ -1448,6 +1578,35 @@ struct vkd3d_shader_signature_element *vkd3d_shader_find_signature_element( */ void vkd3d_shader_free_shader_signature(struct vkd3d_shader_signature *signature);
+/* 1.3 */ + +/** + * Preprocess the given source code. + * + * This function supports the following chained structures: + * - vkd3d_shader_preprocess_info + * + * \param compile_info A chained structure containing compilation parameters. + * + * \param out A pointer to a vkd3d_shader_code structure in which the + * preprocessed code will be stored. + * \n + * The preprocessed shader is allocated by vkd3d-shader and should be freed with + * vkd3d_shader_free_shader_code() when no longer needed. + * + * \param messages Optional output location for error or informational messages + * produced by the compiler. + * \n + * This parameter behaves identically to the \a messages parameter of + * vkd3d_shader_compile(). + * + * \return A member of \ref vkd3d_result. + * + * \since 1.3 + */ +int vkd3d_shader_preprocess(const struct vkd3d_shader_compile_info *compile_info, + struct vkd3d_shader_code *out, char **messages); + #endif /* VKD3D_SHADER_NO_PROTOTYPES */
/** Type of vkd3d_shader_get_version(). */ diff --git a/libs/vkd3d-shader/vkd3d_shader.map b/libs/vkd3d-shader/vkd3d_shader.map index 1937131b..2e49fe24 100644 --- a/libs/vkd3d-shader/vkd3d_shader.map +++ b/libs/vkd3d-shader/vkd3d_shader.map @@ -14,6 +14,7 @@ global: vkd3d_shader_get_version; vkd3d_shader_parse_input_signature; vkd3d_shader_parse_root_signature; + vkd3d_shader_preprocess; vkd3d_shader_scan; vkd3d_shader_serialize_root_signature;
diff --git a/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d-shader/vkd3d_shader_main.c index e44a80b7..e4c0b47c 100644 --- a/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d-shader/vkd3d_shader_main.c @@ -1130,3 +1130,11 @@ const enum vkd3d_shader_target_type *vkd3d_shader_get_supported_target_types( return NULL; } } + +int vkd3d_shader_preprocess(const struct vkd3d_shader_compile_info *compile_info, + struct vkd3d_shader_code *out, char **messages) +{ + TRACE("compile_info %p, out %p, messages %p.\n", compile_info, out, messages); + + return VKD3D_ERROR_NOT_IMPLEMENTED; +}
On Fri, 25 Sep 2020 at 03:00, Zebediah Figura zfigura@codeweavers.com wrote:
+/**
- A single preprocessor macro, passed as part of struct
- vkd3d_shader_preprocess_info.
- */
+struct vkd3d_shader_macro +{
- /**
* A null-terminated string containing the name of a macro. This macro must
* not be a parameterized (i.e. function-like) macro. If the macro name is
* invalid (for example, if it does not consist solely of alphanumeric
* characters), it will be ignored.
*/
Alphanumeric is perhaps not a great term (e.g. "۱۲۳" or "é" would typically not be considered alphanumeric here), but in any case, I think the definition should be that it's a valid macro identifier in the source language. At the same time, if it's not a valid macro name in the source, it would effectively be ignored anyway, because if an invalid name existed in the source compilation should fail.
+struct vkd3d_shader_preprocess_info +{
- /** Must be set to VKD3D_SHADER_STRUCTURE_TYPE_PREPROCESS_INFO. */
- enum vkd3d_shader_structure_type type;
- /** Optional pointer to a structure containing further parameters. */
- const void *next;
- /**
* Pointer to an array of predefined macros. Each macro in this array will
* be expanded as if a corresponding #define statement were prepended to the
* source code.
*
* If the same macro is specified multiple itmes, only the first value is
* used.
*/
"times"
- /**
* Optional pointer to a callback function, which will be called in order to
* evaluate \#include directives. The function receives parameters
* corresponding to the directive's arguments, and should return the
* complete text of the included file.
*
* If this field is set to NULL, or if this structure is omitted,
* vkd3d-shader will emit a compilation error if any \#include directives
* are evaluated.
*
* If this field is set to NULL, the \ref pfn_close_include field must also
* be set to NULL.
*/
- PFN_vkd3d_shader_open_include pfn_open_include;
I think this is fine, but it would also be reasonable to provide a default implementation that tries to open and read the file. Should there be a way for PFN_vkd3d_shader_open_include to pass an error string to its caller? (Which could then in turn add it to the compiler output.)
On 9/25/20 7:59 AM, Henri Verbeet wrote:
On Fri, 25 Sep 2020 at 03:00, Zebediah Figura zfigura@codeweavers.com wrote:
+/**
- A single preprocessor macro, passed as part of struct
- vkd3d_shader_preprocess_info.
- */
+struct vkd3d_shader_macro +{
- /**
* A null-terminated string containing the name of a macro. This macro must
* not be a parameterized (i.e. function-like) macro. If the macro name is
* invalid (for example, if it does not consist solely of alphanumeric
* characters), it will be ignored.
*/
Alphanumeric is perhaps not a great term (e.g. "۱۲۳" or "é" would typically not be considered alphanumeric here), but in any case, I think the definition should be that it's a valid macro identifier in the source language. At the same time, if it's not a valid macro name in the source, it would effectively be ignored anyway, because if an invalid name existed in the source compilation should fail.
+struct vkd3d_shader_preprocess_info +{
- /** Must be set to VKD3D_SHADER_STRUCTURE_TYPE_PREPROCESS_INFO. */
- enum vkd3d_shader_structure_type type;
- /** Optional pointer to a structure containing further parameters. */
- const void *next;
- /**
* Pointer to an array of predefined macros. Each macro in this array will
* be expanded as if a corresponding #define statement were prepended to the
* source code.
*
* If the same macro is specified multiple itmes, only the first value is
* used.
*/
"times"
- /**
* Optional pointer to a callback function, which will be called in order to
* evaluate \#include directives. The function receives parameters
* corresponding to the directive's arguments, and should return the
* complete text of the included file.
*
* If this field is set to NULL, or if this structure is omitted,
* vkd3d-shader will emit a compilation error if any \#include directives
* are evaluated.
*
* If this field is set to NULL, the \ref pfn_close_include field must also
* be set to NULL.
*/
- PFN_vkd3d_shader_open_include pfn_open_include;
I think this is fine, but it would also be reasonable to provide a default implementation that tries to open and read the file.
Using POSIX file APIs, I guess? Sure, that can be done easily.
Should there be a way for PFN_vkd3d_shader_open_include to pass an error string to its caller? (Which could then in turn add it to the compiler output.)
Seems reasonable enoguh.
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- include/vkd3d_shader.h | 53 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+)
diff --git a/include/vkd3d_shader.h b/include/vkd3d_shader.h index 768d6050..a7bb2f9a 100644 --- a/include/vkd3d_shader.h +++ b/include/vkd3d_shader.h @@ -91,6 +91,17 @@ enum vkd3d_shader_compile_option_formatting_flags VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_COMPILE_OPTION_FORMATTING_FLAGS), };
+enum vkd3d_shader_hlsl_compatibility_mode +{ + VKD3D_SHADER_HLSL_COMPATIBILITY_DEFAULT = 0, + VKD3D_SHADER_HLSL_COMPATIBILITY_BACKWARDS_COMPATIBLE = 1, + VKD3D_SHADER_HLSL_COMPATIBILITY_STRICT = 2, + + VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_HLSL_COMPATIBILITY), +}; + +#define VKD3D_SHADER_OPTIMIZE_FLAG_SKIP_OPTIMIZATION 0x80000000 + enum vkd3d_shader_compile_option_name { /** @@ -105,6 +116,48 @@ enum vkd3d_shader_compile_option_name VKD3D_SHADER_COMPILE_OPTION_BUFFER_UAV = 0x00000002, /** \a value is a member of enum vkd3d_shader_compile_option_formatting_flags. */ VKD3D_SHADER_COMPILE_OPTION_FORMATTING = 0x00000003, + /** + * If \a value is nonzero, do not validate the compiled shader for + * correctness. The default value is zero. + * + * This option is supported by vkd3d_shader_compile(). However, not all + * compilers support validation. + */ + VKD3D_SHADER_COMPILE_OPTION_SKIP_VALIDATION, + /** + * Optimize the compiled code. \a value is an unsigned integer which + * describes the level of optimization to apply, and may be between 0 and 3 + * inclusive. The flag VKD3D_SHADER_OPTIMIZE_FLAG_SKIP_OPTIMIZATION may + * be combined via bitwise OR in order to suppress optimization entirely. + */ + VKD3D_SHADER_COMPILE_OPTION_OPTIMIZE, + /** + * If \a value is nonzero, treat warnings as errors. The generated messages + * are not changed (i.e. warnings are still flagged with the string + * "warning"), but vkd3d_shader_compile() will fail if any warnings are + * generated. + */ + VKD3D_SHADER_COMPILE_OPTION_WARNINGS_ARE_ERRORS, + + VKD3D_SHADER_COMPILE_OPTION_HLSL_PACK_MATRIX_ROW_MAJOR, + VKD3D_SHADER_COMPILE_OPTION_HLSL_PACK_MATRIX_COLUMN_MAJOR, + VKD3D_SHADER_COMPILE_OPTION_HLSL_PARTIAL_PRECISION, + VKD3D_SHADER_COMPILE_OPTION_HLSL_FORCE_VS_SOFTWARE_NO_OPT, + VKD3D_SHADER_COMPILE_OPTION_HLSL_FORCE_PS_SOFTWARE_NO_OPT, + VKD3D_SHADER_COMPILE_OPTION_HLSL_NO_PRESHADER, + VKD3D_SHADER_COMPILE_OPTION_HLSL_AVOID_FLOW_CONTROL, + VKD3D_SHADER_COMPILE_OPTION_HLSL_PREFER_FLOW_CONTROL, + /** \a value is a member of enum vkd3d_shader_hlsl_compatibility_mode. */ + VKD3D_SHADER_COMPILE_OPTION_HLSL_COMPATIBILTY_MODE, + VKD3D_SHADER_COMPILE_OPTION_HLSL_IEEE_STRICTNESS, + VKD3D_SHADER_COMPILE_OPTION_HLSL_RESOURCES_MAY_ALIAS, + VKD3D_SHADER_COMPILE_OPTION_HLSL_ENABLE_UNBOUNDED_DESCRIPTOR_TABLES, + VKD3D_SHADER_COMPILE_OPTION_HLSL_ALL_RESOURCES_BOUND, + VKD3D_SHADER_COMPILE_OPTION_HLSL_EFFECT_CHILD_EFFECT, + VKD3D_SHADER_COMPILE_OPTION_HLSL_EFFECT_ALLOW_SLOW_OPS, + VKD3D_SHADER_COMPILE_OPTION_HLSL_MERGE_UAV_SLOTS, + VKD3D_SHADER_COMPILE_OPTION_HLSL_PRESERVE_TEMPLATE_SLOTS, + VKD3D_SHADER_COMPILE_OPTION_HLSL_REQUIRE_TEMPLATE_MATCH,
VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_COMPILE_OPTION_NAME), };
On Fri, 25 Sep 2020 at 03:00, Zebediah Figura zfigura@codeweavers.com wrote:
+enum vkd3d_shader_hlsl_compatibility_mode +{
- VKD3D_SHADER_HLSL_COMPATIBILITY_DEFAULT = 0,
- VKD3D_SHADER_HLSL_COMPATIBILITY_BACKWARDS_COMPATIBLE = 1,
- VKD3D_SHADER_HLSL_COMPATIBILITY_STRICT = 2,
- VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_HLSL_COMPATIBILITY),
+};
Hexadecimal, please. These seem poorly defined, I'd prefer for these to refer to some kind of version/standard, similar to the way that e.g. gcc has "-std=gnu99". As far as I'm concerned it would be fine for that to be something like VKD3D_SHADER_HLSL_COMPATIBILITY_HLSL24 to refer to the version of HLSL in d3dx9_24, if that makes sense for HLSL.
@@ -105,6 +116,48 @@ enum vkd3d_shader_compile_option_name VKD3D_SHADER_COMPILE_OPTION_BUFFER_UAV = 0x00000002, /** \a value is a member of enum vkd3d_shader_compile_option_formatting_flags. */ VKD3D_SHADER_COMPILE_OPTION_FORMATTING = 0x00000003,
/**
* If \a value is nonzero, do not validate the compiled shader for
* correctness. The default value is zero.
*
* This option is supported by vkd3d_shader_compile(). However, not all
* compilers support validation.
*/
VKD3D_SHADER_COMPILE_OPTION_SKIP_VALIDATION,
/**
* Optimize the compiled code. \a value is an unsigned integer which
* describes the level of optimization to apply, and may be between 0 and 3
* inclusive. The flag VKD3D_SHADER_OPTIMIZE_FLAG_SKIP_OPTIMIZATION may
* be combined via bitwise OR in order to suppress optimization entirely.
*/
VKD3D_SHADER_COMPILE_OPTION_OPTIMIZE,
/**
* If \a value is nonzero, treat warnings as errors. The generated messages
* are not changed (i.e. warnings are still flagged with the string
* "warning"), but vkd3d_shader_compile() will fail if any warnings are
* generated.
*/
VKD3D_SHADER_COMPILE_OPTION_WARNINGS_ARE_ERRORS,
VKD3D_SHADER_COMPILE_OPTION_HLSL_PACK_MATRIX_ROW_MAJOR,
VKD3D_SHADER_COMPILE_OPTION_HLSL_PACK_MATRIX_COLUMN_MAJOR,
VKD3D_SHADER_COMPILE_OPTION_HLSL_PARTIAL_PRECISION,
VKD3D_SHADER_COMPILE_OPTION_HLSL_FORCE_VS_SOFTWARE_NO_OPT,
VKD3D_SHADER_COMPILE_OPTION_HLSL_FORCE_PS_SOFTWARE_NO_OPT,
VKD3D_SHADER_COMPILE_OPTION_HLSL_NO_PRESHADER,
VKD3D_SHADER_COMPILE_OPTION_HLSL_AVOID_FLOW_CONTROL,
VKD3D_SHADER_COMPILE_OPTION_HLSL_PREFER_FLOW_CONTROL,
/** \a value is a member of enum vkd3d_shader_hlsl_compatibility_mode. */
VKD3D_SHADER_COMPILE_OPTION_HLSL_COMPATIBILTY_MODE,
VKD3D_SHADER_COMPILE_OPTION_HLSL_IEEE_STRICTNESS,
VKD3D_SHADER_COMPILE_OPTION_HLSL_RESOURCES_MAY_ALIAS,
VKD3D_SHADER_COMPILE_OPTION_HLSL_ENABLE_UNBOUNDED_DESCRIPTOR_TABLES,
VKD3D_SHADER_COMPILE_OPTION_HLSL_ALL_RESOURCES_BOUND,
VKD3D_SHADER_COMPILE_OPTION_HLSL_EFFECT_CHILD_EFFECT,
VKD3D_SHADER_COMPILE_OPTION_HLSL_EFFECT_ALLOW_SLOW_OPS,
VKD3D_SHADER_COMPILE_OPTION_HLSL_MERGE_UAV_SLOTS,
VKD3D_SHADER_COMPILE_OPTION_HLSL_PRESERVE_TEMPLATE_SLOTS,
VKD3D_SHADER_COMPILE_OPTION_HLSL_REQUIRE_TEMPLATE_MATCH,
VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_COMPILE_OPTION_NAME),
};
Nothing particularly objectionable about these, but we probably want to wait with introducing them until they're implemented. Also, we may want to start the HLSL specific options at some offset from the common options (e.g. 0x00010000), so that future common options can still be grouped together with the existing ones. (And likewise for future HLSL options if we end up adding some options specific to e.g. SPIR-V output.)
On 9/25/20 8:00 AM, Henri Verbeet wrote:
On Fri, 25 Sep 2020 at 03:00, Zebediah Figura zfigura@codeweavers.com wrote:
+enum vkd3d_shader_hlsl_compatibility_mode +{
- VKD3D_SHADER_HLSL_COMPATIBILITY_DEFAULT = 0,
- VKD3D_SHADER_HLSL_COMPATIBILITY_BACKWARDS_COMPATIBLE = 1,
- VKD3D_SHADER_HLSL_COMPATIBILITY_STRICT = 2,
- VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_HLSL_COMPATIBILITY),
+};
Hexadecimal, please. These seem poorly defined, I'd prefer for these to refer to some kind of version/standard, similar to the way that e.g. gcc has "-std=gnu99". As far as I'm concerned it would be fine for that to be something like VKD3D_SHADER_HLSL_COMPATIBILITY_HLSL24 to refer to the version of HLSL in d3dx9_24, if that makes sense for HLSL.
Sadly, they are poorly defined :-/
As I'm sure you've guessed, they correspond to the D3DCompile() flags D3DCOMPILE_ENABLE_STRICTNESS and D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY. The latter essentially allows SM1-3 operations [tex2D(), but I don't know any others offhand] to be mapped to analogical SM4-5 operations (instead of producing an error). I don't actually know what ENABLE_STRICTNESS does.
But I'm happy to just ignore all the flags until they're used; there's no harm in it. It does make the "secondary_data" field a bit weird, but...
@@ -105,6 +116,48 @@ enum vkd3d_shader_compile_option_name VKD3D_SHADER_COMPILE_OPTION_BUFFER_UAV = 0x00000002, /** \a value is a member of enum vkd3d_shader_compile_option_formatting_flags. */ VKD3D_SHADER_COMPILE_OPTION_FORMATTING = 0x00000003,
/**
* If \a value is nonzero, do not validate the compiled shader for
* correctness. The default value is zero.
*
* This option is supported by vkd3d_shader_compile(). However, not all
* compilers support validation.
*/
VKD3D_SHADER_COMPILE_OPTION_SKIP_VALIDATION,
/**
* Optimize the compiled code. \a value is an unsigned integer which
* describes the level of optimization to apply, and may be between 0 and 3
* inclusive. The flag VKD3D_SHADER_OPTIMIZE_FLAG_SKIP_OPTIMIZATION may
* be combined via bitwise OR in order to suppress optimization entirely.
*/
VKD3D_SHADER_COMPILE_OPTION_OPTIMIZE,
/**
* If \a value is nonzero, treat warnings as errors. The generated messages
* are not changed (i.e. warnings are still flagged with the string
* "warning"), but vkd3d_shader_compile() will fail if any warnings are
* generated.
*/
VKD3D_SHADER_COMPILE_OPTION_WARNINGS_ARE_ERRORS,
VKD3D_SHADER_COMPILE_OPTION_HLSL_PACK_MATRIX_ROW_MAJOR,
VKD3D_SHADER_COMPILE_OPTION_HLSL_PACK_MATRIX_COLUMN_MAJOR,
VKD3D_SHADER_COMPILE_OPTION_HLSL_PARTIAL_PRECISION,
VKD3D_SHADER_COMPILE_OPTION_HLSL_FORCE_VS_SOFTWARE_NO_OPT,
VKD3D_SHADER_COMPILE_OPTION_HLSL_FORCE_PS_SOFTWARE_NO_OPT,
VKD3D_SHADER_COMPILE_OPTION_HLSL_NO_PRESHADER,
VKD3D_SHADER_COMPILE_OPTION_HLSL_AVOID_FLOW_CONTROL,
VKD3D_SHADER_COMPILE_OPTION_HLSL_PREFER_FLOW_CONTROL,
/** \a value is a member of enum vkd3d_shader_hlsl_compatibility_mode. */
VKD3D_SHADER_COMPILE_OPTION_HLSL_COMPATIBILTY_MODE,
VKD3D_SHADER_COMPILE_OPTION_HLSL_IEEE_STRICTNESS,
VKD3D_SHADER_COMPILE_OPTION_HLSL_RESOURCES_MAY_ALIAS,
VKD3D_SHADER_COMPILE_OPTION_HLSL_ENABLE_UNBOUNDED_DESCRIPTOR_TABLES,
VKD3D_SHADER_COMPILE_OPTION_HLSL_ALL_RESOURCES_BOUND,
VKD3D_SHADER_COMPILE_OPTION_HLSL_EFFECT_CHILD_EFFECT,
VKD3D_SHADER_COMPILE_OPTION_HLSL_EFFECT_ALLOW_SLOW_OPS,
VKD3D_SHADER_COMPILE_OPTION_HLSL_MERGE_UAV_SLOTS,
VKD3D_SHADER_COMPILE_OPTION_HLSL_PRESERVE_TEMPLATE_SLOTS,
VKD3D_SHADER_COMPILE_OPTION_HLSL_REQUIRE_TEMPLATE_MATCH,
VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_COMPILE_OPTION_NAME),
};
Nothing particularly objectionable about these, but we probably want to wait with introducing them until they're implemented. Also, we may want to start the HLSL specific options at some offset from the common options (e.g. 0x00010000), so that future common options can still be grouped together with the existing ones. (And likewise for future HLSL options if we end up adding some options specific to e.g. SPIR-V output.)
On Fri, 25 Sep 2020 at 19:26, Zebediah Figura zfigura@codeweavers.com wrote:
On 9/25/20 8:00 AM, Henri Verbeet wrote:
On Fri, 25 Sep 2020 at 03:00, Zebediah Figura zfigura@codeweavers.com wrote:
+enum vkd3d_shader_hlsl_compatibility_mode +{
- VKD3D_SHADER_HLSL_COMPATIBILITY_DEFAULT = 0,
- VKD3D_SHADER_HLSL_COMPATIBILITY_BACKWARDS_COMPATIBLE = 1,
- VKD3D_SHADER_HLSL_COMPATIBILITY_STRICT = 2,
- VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_HLSL_COMPATIBILITY),
+};
Hexadecimal, please. These seem poorly defined, I'd prefer for these to refer to some kind of version/standard, similar to the way that e.g. gcc has "-std=gnu99". As far as I'm concerned it would be fine for that to be something like VKD3D_SHADER_HLSL_COMPATIBILITY_HLSL24 to refer to the version of HLSL in d3dx9_24, if that makes sense for HLSL.
Sadly, they are poorly defined :-/
As I'm sure you've guessed, they correspond to the D3DCompile() flags D3DCOMPILE_ENABLE_STRICTNESS and D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY. The latter essentially allows SM1-3 operations [tex2D(), but I don't know any others offhand] to be mapped to analogical SM4-5 operations (instead of producing an error). I don't actually know what ENABLE_STRICTNESS does.
Sure, and I wouldn't be surprised at all if D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY enables different behaviour in different versions of d3dcompiler. But presumably the behaviour we would actually implement would be more specific than that.
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- include/vkd3d_shader.h | 46 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+)
diff --git a/include/vkd3d_shader.h b/include/vkd3d_shader.h index a7bb2f9a..a072a0a6 100644 --- a/include/vkd3d_shader.h +++ b/include/vkd3d_shader.h @@ -54,6 +54,11 @@ enum vkd3d_shader_structure_type /** The structure is a vkd3d_shader_transform_feedback_info structure. */ VKD3D_SHADER_STRUCTURE_TYPE_TRANSFORM_FEEDBACK_INFO,
+ /** + * The structure is a vkd3d_shader_hlsl_source_info structure. + * \since 1.3 + */ + VKD3D_SHADER_STRUCTURE_TYPE_HLSL_SOURCE_INFO, /** * The structure is a vkd3d_shader_preprocess_info structure. * \since 1.3 @@ -788,6 +793,47 @@ struct vkd3d_shader_preprocess_info void *include_context; };
+/** + * A chained structure containing HLSL compilation parameters. + * + * This structure is optional. + * + * This structure extends vkd3d_shader_compile_info. + * + * This structure contains only input parameters. + * + * \since 1.3 + */ +struct vkd3d_shader_hlsl_source_info +{ + /** Must be set to VKD3D_SHADER_STRUCTURE_TYPE_HLSL_SOURCE_INFO. */ + enum vkd3d_shader_structure_type type; + /** Optional pointer to a structure containing further parameters. */ + const void *next; + + /** + * Optional pointer to a null-terminated string containing the shader entry + * point. + * + * If this parameter is NULL, vkd3d-shader uses the entry point "main". + */ + const char *entry_point; + /** + * Optional pointer to another compiled shader. This parameter must point to + * a valid shader if any of the following compilation options are used: + * - VKD3D_SHADER_COMPILE_OPTION_HLSL_MERGE_UAV_SLOTS + * - VKD3D_SHADER_COMPILE_OPTION_HLSL_PRESERVE_TEMPLATE_SLOTS + * - VKD3D_SHADER_COMPILE_OPTION_HLSL_REQUIRE_TEMPLATE_MATCH + * If none of the above options are used, this parameter is ignored. + */ + struct vkd3d_shader_code secondary_code; + /** + * Pointer to a null-terminated string containing the target shader + * profile. + */ + const char *profile; +}; + /* root signature 1.0 */ enum vkd3d_shader_filter {
On Fri, 25 Sep 2020 at 03:00, Zebediah Figura zfigura@codeweavers.com wrote:
- /**
* Optional pointer to another compiled shader. This parameter must point to
* a valid shader if any of the following compilation options are used:
* - VKD3D_SHADER_COMPILE_OPTION_HLSL_MERGE_UAV_SLOTS
* - VKD3D_SHADER_COMPILE_OPTION_HLSL_PRESERVE_TEMPLATE_SLOTS
* - VKD3D_SHADER_COMPILE_OPTION_HLSL_REQUIRE_TEMPLATE_MATCH
* If none of the above options are used, this parameter is ignored.
*/
- struct vkd3d_shader_code secondary_code;
Does the secondary code need to be in any particular format?
On 9/25/20 8:01 AM, Henri Verbeet wrote:
On Fri, 25 Sep 2020 at 03:00, Zebediah Figura zfigura@codeweavers.com wrote:
- /**
* Optional pointer to another compiled shader. This parameter must point to
* a valid shader if any of the following compilation options are used:
* - VKD3D_SHADER_COMPILE_OPTION_HLSL_MERGE_UAV_SLOTS
* - VKD3D_SHADER_COMPILE_OPTION_HLSL_PRESERVE_TEMPLATE_SLOTS
* - VKD3D_SHADER_COMPILE_OPTION_HLSL_REQUIRE_TEMPLATE_MATCH
* If none of the above options are used, this parameter is ignored.
*/
- struct vkd3d_shader_code secondary_code;
Does the secondary code need to be in any particular format?
Presumably D3DCompile2() only supports SM4-5 shaders here. We might want to support other things, but it's not obvious to me we'd want to account for a format other than the target type.
On Fri, 25 Sep 2020 at 19:35, Zebediah Figura zfigura@codeweavers.com wrote:
On 9/25/20 8:01 AM, Henri Verbeet wrote:
On Fri, 25 Sep 2020 at 03:00, Zebediah Figura zfigura@codeweavers.com wrote:
- /**
* Optional pointer to another compiled shader. This parameter must point to
* a valid shader if any of the following compilation options are used:
* - VKD3D_SHADER_COMPILE_OPTION_HLSL_MERGE_UAV_SLOTS
* - VKD3D_SHADER_COMPILE_OPTION_HLSL_PRESERVE_TEMPLATE_SLOTS
* - VKD3D_SHADER_COMPILE_OPTION_HLSL_REQUIRE_TEMPLATE_MATCH
* If none of the above options are used, this parameter is ignored.
*/
- struct vkd3d_shader_code secondary_code;
Does the secondary code need to be in any particular format?
Presumably D3DCompile2() only supports SM4-5 shaders here. We might want to support other things, but it's not obvious to me we'd want to account for a format other than the target type.
It's probably fine to specify it as DXBC_TPF (although, can't this also be used with DXBC_DXIL?), but note that that's not necessarily the same as the target type; compiling from HLSL to D3D_ASM or SPIRV_BINARY for example seems entirely legitimate to me. It may have to be defined in terms of the target profile.
On 9/25/20 11:35 AM, Henri Verbeet wrote:
On Fri, 25 Sep 2020 at 19:35, Zebediah Figura zfigura@codeweavers.com wrote:
On 9/25/20 8:01 AM, Henri Verbeet wrote:
On Fri, 25 Sep 2020 at 03:00, Zebediah Figura zfigura@codeweavers.com wrote:
- /**
* Optional pointer to another compiled shader. This parameter must point to
* a valid shader if any of the following compilation options are used:
* - VKD3D_SHADER_COMPILE_OPTION_HLSL_MERGE_UAV_SLOTS
* - VKD3D_SHADER_COMPILE_OPTION_HLSL_PRESERVE_TEMPLATE_SLOTS
* - VKD3D_SHADER_COMPILE_OPTION_HLSL_REQUIRE_TEMPLATE_MATCH
* If none of the above options are used, this parameter is ignored.
*/
- struct vkd3d_shader_code secondary_code;
Does the secondary code need to be in any particular format?
Presumably D3DCompile2() only supports SM4-5 shaders here. We might want to support other things, but it's not obvious to me we'd want to account for a format other than the target type.
It's probably fine to specify it as DXBC_TPF (although, can't this also be used with DXBC_DXIL?), but note that that's not necessarily the same as the target type; compiling from HLSL to D3D_ASM or SPIRV_BINARY for example seems entirely legitimate to me. It may have to be defined in terms of the target profile.
Sure, I was thinking about "type" rather than "profile". There's no reason why you couldn't pass two different types here, but I guess it's not clear why you'd want to...
I can add a vkd3d_shader_target_type field if you think there's call for it, though; I don't feel that strongly.
On Fri, 25 Sep 2020 at 20:48, Zebediah Figura zfigura@codeweavers.com wrote:
On 9/25/20 11:35 AM, Henri Verbeet wrote:
On Fri, 25 Sep 2020 at 19:35, Zebediah Figura zfigura@codeweavers.com wrote:
On 9/25/20 8:01 AM, Henri Verbeet wrote:
On Fri, 25 Sep 2020 at 03:00, Zebediah Figura zfigura@codeweavers.com wrote:
- /**
* Optional pointer to another compiled shader. This parameter must point to
* a valid shader if any of the following compilation options are used:
* - VKD3D_SHADER_COMPILE_OPTION_HLSL_MERGE_UAV_SLOTS
* - VKD3D_SHADER_COMPILE_OPTION_HLSL_PRESERVE_TEMPLATE_SLOTS
* - VKD3D_SHADER_COMPILE_OPTION_HLSL_REQUIRE_TEMPLATE_MATCH
* If none of the above options are used, this parameter is ignored.
*/
- struct vkd3d_shader_code secondary_code;
Does the secondary code need to be in any particular format?
Presumably D3DCompile2() only supports SM4-5 shaders here. We might want to support other things, but it's not obvious to me we'd want to account for a format other than the target type.
It's probably fine to specify it as DXBC_TPF (although, can't this also be used with DXBC_DXIL?), but note that that's not necessarily the same as the target type; compiling from HLSL to D3D_ASM or SPIRV_BINARY for example seems entirely legitimate to me. It may have to be defined in terms of the target profile.
Sure, I was thinking about "type" rather than "profile". There's no reason why you couldn't pass two different types here, but I guess it's not clear why you'd want to...
I can add a vkd3d_shader_target_type field if you think there's call for it, though; I don't feel that strongly.
We probably don't need a vkd3d_shader_target_type field, but the format does need to be specified in some way; if that simply means writing something along the lines of "For shader model 4 and 5 profiles `secondary_code' should be a DXBC_TPF shader; for shader model 6 profiles it should be a DXBC_DXIL shader." in the documentation, that's fine. (Hypothetically of course; we don't support shader model 6.) Defining it in terms of the target type would potentially be problematic though. E.g., suppose you're compiling HLSL to SPIR-V. That would then require "secondary_code" to be SPIR-V as well. That may be reasonable enough for the user of the API, but for the implementation it would impose a requirement to parse SPIR-V and recover the required information from it.
On 9/25/20 12:57 PM, Henri Verbeet wrote:
On Fri, 25 Sep 2020 at 20:48, Zebediah Figura zfigura@codeweavers.com wrote:
On 9/25/20 11:35 AM, Henri Verbeet wrote:
On Fri, 25 Sep 2020 at 19:35, Zebediah Figura zfigura@codeweavers.com wrote:
On 9/25/20 8:01 AM, Henri Verbeet wrote:
On Fri, 25 Sep 2020 at 03:00, Zebediah Figura zfigura@codeweavers.com wrote:
- /**
* Optional pointer to another compiled shader. This parameter must point to
* a valid shader if any of the following compilation options are used:
* - VKD3D_SHADER_COMPILE_OPTION_HLSL_MERGE_UAV_SLOTS
* - VKD3D_SHADER_COMPILE_OPTION_HLSL_PRESERVE_TEMPLATE_SLOTS
* - VKD3D_SHADER_COMPILE_OPTION_HLSL_REQUIRE_TEMPLATE_MATCH
* If none of the above options are used, this parameter is ignored.
*/
- struct vkd3d_shader_code secondary_code;
Does the secondary code need to be in any particular format?
Presumably D3DCompile2() only supports SM4-5 shaders here. We might want to support other things, but it's not obvious to me we'd want to account for a format other than the target type.
It's probably fine to specify it as DXBC_TPF (although, can't this also be used with DXBC_DXIL?), but note that that's not necessarily the same as the target type; compiling from HLSL to D3D_ASM or SPIRV_BINARY for example seems entirely legitimate to me. It may have to be defined in terms of the target profile.
Sure, I was thinking about "type" rather than "profile". There's no reason why you couldn't pass two different types here, but I guess it's not clear why you'd want to...
I can add a vkd3d_shader_target_type field if you think there's call for it, though; I don't feel that strongly.
We probably don't need a vkd3d_shader_target_type field, but the format does need to be specified in some way; if that simply means writing something along the lines of "For shader model 4 and 5 profiles `secondary_code' should be a DXBC_TPF shader; for shader model 6 profiles it should be a DXBC_DXIL shader." in the documentation, that's fine. (Hypothetically of course; we don't support shader model 6.)
Ah, sure, I see what you mean now.
Defining it in terms of the target type would potentially be problematic though. E.g., suppose you're compiling HLSL to SPIR-V. That would then require "secondary_code" to be SPIR-V as well. That may be reasonable enough for the user of the API, but for the implementation it would impose a requirement to parse SPIR-V and recover the required information from it.
On Fri, 25 Sep 2020 at 03:00, Zebediah Figura zfigura@codeweavers.com wrote:
+int vkd3d_shader_compile(const struct vkd3d_shader_compile_info *compile_info,
struct vkd3d_shader_code *out, char **messages)
+{
- struct vkd3d_shader_message_context message_context;
- int ret;
- TRACE("compile_info %p, out %p, messages %p.\n", compile_info, out, messages);
- if (messages)
*messages = NULL;
- if ((ret = vkd3d_shader_validate_compile_info(compile_info)) < 0)
return ret;
- if (!vkd3d_shader_message_context_init(&message_context, compile_info->log_level, compile_info->source_name))
return VKD3D_ERROR_OUT_OF_MEMORY;
- if (compile_info->source_type == VKD3D_SHADER_SOURCE_DXBC_TPF
&& compile_info->target_type == VKD3D_SHADER_TARGET_SPIRV_BINARY)
ret = compile_dxbc_to_spirv(compile_info, out, &message_context);
- else if (compile_info->source_type == VKD3D_SHADER_SOURCE_HLSL
&& compile_info->target_type == VKD3D_SHADER_TARGET_DXBC_TPF)
ret = compile_hlsl_to_dxbc(compile_info, out, &message_context);
I guess this is a rebase glitch, but VKD3D_SHADER_SOURCE_DXBC_TPF also supports VKD3D_SHADER_TARGET_SPIRV_TEXT as target. (And soon VKD3D_SHADER_TARGET_D3D_ASM.) I'd suggest to simply split based on the source type here, and then split on target type if needed in a hypothetical compile_dxbc().
There's probably also room for splitting some of the changes here into their own commits. For example, the "message_context" change in the vkd3d_shader_scan_context structure. (Although it's not immediately clear to me why that would be required at this stage; I guess it allows creating the message context in a single place for both compile_dxbc_to_spirv() and future compile_hlsl_to_dxbc().)
On 9/25/20 7:58 AM, Henri Verbeet wrote:
On Fri, 25 Sep 2020 at 03:00, Zebediah Figura zfigura@codeweavers.com wrote:
+int vkd3d_shader_compile(const struct vkd3d_shader_compile_info *compile_info,
struct vkd3d_shader_code *out, char **messages)
+{
- struct vkd3d_shader_message_context message_context;
- int ret;
- TRACE("compile_info %p, out %p, messages %p.\n", compile_info, out, messages);
- if (messages)
*messages = NULL;
- if ((ret = vkd3d_shader_validate_compile_info(compile_info)) < 0)
return ret;
- if (!vkd3d_shader_message_context_init(&message_context, compile_info->log_level, compile_info->source_name))
return VKD3D_ERROR_OUT_OF_MEMORY;
- if (compile_info->source_type == VKD3D_SHADER_SOURCE_DXBC_TPF
&& compile_info->target_type == VKD3D_SHADER_TARGET_SPIRV_BINARY)
ret = compile_dxbc_to_spirv(compile_info, out, &message_context);
- else if (compile_info->source_type == VKD3D_SHADER_SOURCE_HLSL
&& compile_info->target_type == VKD3D_SHADER_TARGET_DXBC_TPF)
ret = compile_hlsl_to_dxbc(compile_info, out, &message_context);
I guess this is a rebase glitch, but VKD3D_SHADER_SOURCE_DXBC_TPF also supports VKD3D_SHADER_TARGET_SPIRV_TEXT as target. (And soon VKD3D_SHADER_TARGET_D3D_ASM.) I'd suggest to simply split based on the source type here, and then split on target type if needed in a hypothetical compile_dxbc().
Yes, this commit is pretty old...
That seems like a better structure; thanks for the suggestion.
There's probably also room for splitting some of the changes here into their own commits. For example, the "message_context" change in the vkd3d_shader_scan_context structure. (Although it's not immediately clear to me why that would be required at this stage; I guess it allows creating the message context in a single place for both compile_dxbc_to_spirv() and future compile_hlsl_to_dxbc().)
I don't think it's necessary, but in any case it does seem like a nice bit of deduplication.