From 67023ff9d755c33d6d2a21fdaf3647a44871c830 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Fri, 11 Oct 2024 07:30:59 +1100 Subject: [PATCH] Updated vkd3d to cd249a47b86545fe0b3a4b477f854965e858b744. --- libs/vkd3d/include/vkd3d_shader.h | 52 +++ libs/vkd3d/libs/vkd3d-shader/d3dbc.c | 26 +- libs/vkd3d/libs/vkd3d-shader/glsl.c | 297 +++++++++++++-- libs/vkd3d/libs/vkd3d-shader/ir.c | 349 ++++++++++++++++-- libs/vkd3d/libs/vkd3d-shader/msl.c | 226 +++++++++++- libs/vkd3d/libs/vkd3d-shader/spirv.c | 35 +- .../libs/vkd3d-shader/vkd3d_shader_main.c | 5 +- .../libs/vkd3d-shader/vkd3d_shader_private.h | 11 + 8 files changed, 921 insertions(+), 80 deletions(-) diff --git a/libs/vkd3d/include/vkd3d_shader.h b/libs/vkd3d/include/vkd3d_shader.h index d08ee74a3a0..e22f236ecd1 100644 --- a/libs/vkd3d/include/vkd3d_shader.h +++ b/libs/vkd3d/include/vkd3d_shader.h @@ -648,6 +648,58 @@ enum vkd3d_shader_parameter_name VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_5, VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_6, VKD3D_SHADER_PARAMETER_NAME_CLIP_PLANE_7, + /** + * Point size. + * + * When this parameter is provided to a vertex, tessellation, or geometry + * shader, and the source shader does not write point size, it specifies a + * uniform value which will be written to point size. + * If the source shader writes point size, this parameter is ignored. + * + * This parameter can be used to implement fixed function point size, as + * present in Direct3D versions 8 and 9, if the target environment does not + * support point size as part of its own fixed-function API (as Vulkan and + * core OpenGL). + * + * The data type for this parameter must be + * VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32. + * + * \since 1.14 + */ + VKD3D_SHADER_PARAMETER_NAME_POINT_SIZE, + /** + * Minimum point size. + * + * When this parameter is provided to a vertex, tessellation, or geometry + * shader, and the source shader writes point size or uses the + * VKD3D_SHADER_PARAMETER_NAME_POINT_SIZE parameter, the point size will + * be clamped to the provided minimum value. + * If point size is not written in one of these ways, + * this parameter is ignored. + * If this parameter is not provided, the point size will not be clamped + * to a minimum size by vkd3d-shader. + * + * This parameter can be used to implement fixed function point size, as + * present in Direct3D versions 8 and 9, if the target environment does not + * support point size as part of its own fixed-function API (as Vulkan and + * core OpenGL). + * + * The data type for this parameter must be + * VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32. + * + * \since 1.14 + */ + VKD3D_SHADER_PARAMETER_NAME_POINT_SIZE_MIN, + /** + * Maximum point size. + * + * This parameter has identical behaviour to + * VKD3D_SHADER_PARAMETER_NAME_POINT_SIZE_MIN, except that it provides + * the maximum size rather than the minimum. + * + * \since 1.14 + */ + VKD3D_SHADER_PARAMETER_NAME_POINT_SIZE_MAX, VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_PARAMETER_NAME), }; diff --git a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c index 589b800f8c9..44b1714b56b 100644 --- a/libs/vkd3d/libs/vkd3d-shader/d3dbc.c +++ b/libs/vkd3d/libs/vkd3d-shader/d3dbc.c @@ -110,13 +110,6 @@ enum vkd3d_sm1_misc_register VKD3D_SM1_MISC_FACE = 0x1, }; -enum vkd3d_sm1_rastout_register -{ - VKD3D_SM1_RASTOUT_POSITION = 0x0, - VKD3D_SM1_RASTOUT_FOG = 0x1, - VKD3D_SM1_RASTOUT_POINT_SIZE = 0x2, -}; - enum vkd3d_sm1_opcode { VKD3D_SM1_OP_NOP = 0x00, @@ -957,6 +950,9 @@ static void shader_sm1_read_dst_param(struct vkd3d_shader_sm1_parser *sm1, const shader_sm1_parse_src_param(addr_token, NULL, dst_rel_addr); } shader_sm1_parse_dst_param(token, dst_rel_addr, dst_param); + + if (dst_param->reg.type == VKD3DSPR_RASTOUT && dst_param->reg.idx[0].offset == VSIR_RASTOUT_POINT_SIZE) + sm1->p.program->has_point_size = true; } static void shader_sm1_read_semantic(struct vkd3d_shader_sm1_parser *sm1, @@ -1434,17 +1430,17 @@ bool hlsl_sm1_register_from_semantic(const struct vkd3d_shader_version *version, {"vpos", false, VKD3D_SHADER_TYPE_PIXEL, 3, VKD3DSPR_MISCTYPE, VKD3D_SM1_MISC_POSITION}, {"color", true, VKD3D_SHADER_TYPE_VERTEX, 1, VKD3DSPR_ATTROUT}, - {"fog", true, VKD3D_SHADER_TYPE_VERTEX, 1, VKD3DSPR_RASTOUT, VKD3D_SM1_RASTOUT_FOG}, - {"position", true, VKD3D_SHADER_TYPE_VERTEX, 1, VKD3DSPR_RASTOUT, VKD3D_SM1_RASTOUT_POSITION}, - {"psize", true, VKD3D_SHADER_TYPE_VERTEX, 1, VKD3DSPR_RASTOUT, VKD3D_SM1_RASTOUT_POINT_SIZE}, - {"sv_position", true, VKD3D_SHADER_TYPE_VERTEX, 1, VKD3DSPR_RASTOUT, VKD3D_SM1_RASTOUT_POSITION}, + {"fog", true, VKD3D_SHADER_TYPE_VERTEX, 1, VKD3DSPR_RASTOUT, VSIR_RASTOUT_FOG}, + {"position", true, VKD3D_SHADER_TYPE_VERTEX, 1, VKD3DSPR_RASTOUT, VSIR_RASTOUT_POSITION}, + {"psize", true, VKD3D_SHADER_TYPE_VERTEX, 1, VKD3DSPR_RASTOUT, VSIR_RASTOUT_POINT_SIZE}, + {"sv_position", true, VKD3D_SHADER_TYPE_VERTEX, 1, VKD3DSPR_RASTOUT, VSIR_RASTOUT_POSITION}, {"texcoord", true, VKD3D_SHADER_TYPE_VERTEX, 1, VKD3DSPR_TEXCRDOUT}, {"color", true, VKD3D_SHADER_TYPE_VERTEX, 2, VKD3DSPR_ATTROUT}, - {"fog", true, VKD3D_SHADER_TYPE_VERTEX, 2, VKD3DSPR_RASTOUT, VKD3D_SM1_RASTOUT_FOG}, - {"position", true, VKD3D_SHADER_TYPE_VERTEX, 2, VKD3DSPR_RASTOUT, VKD3D_SM1_RASTOUT_POSITION}, - {"psize", true, VKD3D_SHADER_TYPE_VERTEX, 2, VKD3DSPR_RASTOUT, VKD3D_SM1_RASTOUT_POINT_SIZE}, - {"sv_position", true, VKD3D_SHADER_TYPE_VERTEX, 2, VKD3DSPR_RASTOUT, VKD3D_SM1_RASTOUT_POSITION}, + {"fog", true, VKD3D_SHADER_TYPE_VERTEX, 2, VKD3DSPR_RASTOUT, VSIR_RASTOUT_FOG}, + {"position", true, VKD3D_SHADER_TYPE_VERTEX, 2, VKD3DSPR_RASTOUT, VSIR_RASTOUT_POSITION}, + {"psize", true, VKD3D_SHADER_TYPE_VERTEX, 2, VKD3DSPR_RASTOUT, VSIR_RASTOUT_POINT_SIZE}, + {"sv_position", true, VKD3D_SHADER_TYPE_VERTEX, 2, VKD3DSPR_RASTOUT, VSIR_RASTOUT_POSITION}, {"texcoord", true, VKD3D_SHADER_TYPE_VERTEX, 2, VKD3DSPR_TEXCRDOUT}, }; diff --git a/libs/vkd3d/libs/vkd3d-shader/glsl.c b/libs/vkd3d/libs/vkd3d-shader/glsl.c index 91ee355ed39..c8efdae3386 100644 --- a/libs/vkd3d/libs/vkd3d-shader/glsl.c +++ b/libs/vkd3d/libs/vkd3d-shader/glsl.c @@ -22,7 +22,7 @@ struct glsl_resource_type_info { size_t coord_size; bool shadow; - const char *sampler_type; + const char *type_suffix; }; struct glsl_src @@ -102,17 +102,17 @@ static const struct glsl_resource_type_info *shader_glsl_get_resource_type_info( { static const struct glsl_resource_type_info info[] = { - {0, 0, "samplerNone"}, /* VKD3D_SHADER_RESOURCE_NONE */ - {1, 0, "samplerBuffer"}, /* VKD3D_SHADER_RESOURCE_BUFFER */ - {1, 1, "sampler1D"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_1D */ - {2, 1, "sampler2D"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_2D */ - {2, 0, "sampler2DMS"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_2DMS */ - {3, 0, "sampler3D"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_3D */ - {3, 1, "samplerCube"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_CUBE */ - {2, 1, "sampler1DArray"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_1DARRAY */ - {3, 1, "sampler2DArray"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_2DARRAY */ - {3, 0, "sampler2DMSArray"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_2DMSARRAY */ - {4, 1, "samplerCubeArray"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_CUBEARRAY */ + {0, 0, "None"}, /* VKD3D_SHADER_RESOURCE_NONE */ + {1, 0, "Buffer"}, /* VKD3D_SHADER_RESOURCE_BUFFER */ + {1, 1, "1D"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_1D */ + {2, 1, "2D"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_2D */ + {2, 0, "2DMS"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_2DMS */ + {3, 0, "3D"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_3D */ + {3, 1, "Cube"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_CUBE */ + {2, 1, "1DArray"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_1DARRAY */ + {3, 1, "2DArray"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_2DARRAY */ + {3, 0, "2DMSArray"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_2DMSARRAY */ + {4, 1, "CubeArray"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_CUBEARRAY */ }; if (!t || t >= ARRAY_SIZE(info)) @@ -173,6 +173,14 @@ static void shader_glsl_print_combined_sampler_name(struct vkd3d_string_buffer * } } +static void shader_glsl_print_image_name(struct vkd3d_string_buffer *buffer, + struct vkd3d_glsl_generator *gen, unsigned int idx, unsigned int space) +{ + vkd3d_string_buffer_printf(buffer, "%s_image_%u", gen->prefix, idx); + if (space) + vkd3d_string_buffer_printf(buffer, "_%u", space); +} + static void shader_glsl_print_register_name(struct vkd3d_string_buffer *buffer, struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_register *reg) { @@ -363,15 +371,14 @@ static void shader_glsl_print_bitcast(struct vkd3d_string_buffer *dst, struct vk vkd3d_string_buffer_printf(dst, "%s", src); } -static void glsl_src_init(struct glsl_src *glsl_src, struct vkd3d_glsl_generator *gen, - const struct vkd3d_shader_src_param *vsir_src, uint32_t mask) +static void shader_glsl_print_src(struct vkd3d_string_buffer *buffer, struct vkd3d_glsl_generator *gen, + const struct vkd3d_shader_src_param *vsir_src, uint32_t mask, enum vkd3d_data_type data_type) { const struct vkd3d_shader_register *reg = &vsir_src->reg; struct vkd3d_string_buffer *register_name, *str; enum vkd3d_data_type src_data_type; unsigned int size; - glsl_src->str = vkd3d_string_buffer_get(&gen->string_buffers); register_name = vkd3d_string_buffer_get(&gen->string_buffers); if (reg->non_uniform) @@ -386,12 +393,12 @@ static void glsl_src_init(struct glsl_src *glsl_src, struct vkd3d_glsl_generator shader_glsl_print_register_name(register_name, gen, reg); if (!vsir_src->modifiers) - str = glsl_src->str; + str = buffer; else str = vkd3d_string_buffer_get(&gen->string_buffers); size = reg->dimension == VSIR_DIMENSION_VEC4 ? 4 : 1; - shader_glsl_print_bitcast(str, gen, register_name->buffer, reg->data_type, src_data_type, size); + shader_glsl_print_bitcast(str, gen, register_name->buffer, data_type, src_data_type, size); if (reg->dimension == VSIR_DIMENSION_VEC4) shader_glsl_print_swizzle(str, vsir_src->swizzle, mask); @@ -400,24 +407,31 @@ static void glsl_src_init(struct glsl_src *glsl_src, struct vkd3d_glsl_generator case VKD3DSPSM_NONE: break; case VKD3DSPSM_NEG: - vkd3d_string_buffer_printf(glsl_src->str, "-%s", str->buffer); + vkd3d_string_buffer_printf(buffer, "-%s", str->buffer); break; case VKD3DSPSM_ABS: - vkd3d_string_buffer_printf(glsl_src->str, "abs(%s)", str->buffer); + vkd3d_string_buffer_printf(buffer, "abs(%s)", str->buffer); break; default: - vkd3d_string_buffer_printf(glsl_src->str, "(%s)", + vkd3d_string_buffer_printf(buffer, "(%s)", vsir_src->modifiers, str->buffer); vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, "Internal compiler error: Unhandled source modifier(s) %#x.", vsir_src->modifiers); break; } - if (str != glsl_src->str) + if (str != buffer) vkd3d_string_buffer_release(&gen->string_buffers, str); vkd3d_string_buffer_release(&gen->string_buffers, register_name); } +static void glsl_src_init(struct glsl_src *glsl_src, struct vkd3d_glsl_generator *gen, + const struct vkd3d_shader_src_param *vsir_src, uint32_t mask) +{ + glsl_src->str = vkd3d_string_buffer_get(&gen->string_buffers); + shader_glsl_print_src(glsl_src->str, gen, vsir_src, mask, vsir_src->reg.data_type); +} + static void glsl_dst_cleanup(struct glsl_dst *dst, struct vkd3d_string_buffer_cache *cache) { vkd3d_string_buffer_release(cache, dst->mask); @@ -892,6 +906,85 @@ static void shader_glsl_sample(struct vkd3d_glsl_generator *gen, const struct vk glsl_dst_cleanup(&dst, &gen->string_buffers); } +static void shader_glsl_store_uav_typed(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins) +{ + const struct glsl_resource_type_info *resource_type_info; + enum vkd3d_shader_component_type component_type; + const struct vkd3d_shader_descriptor_info1 *d; + enum vkd3d_shader_resource_type resource_type; + unsigned int uav_id, uav_idx, uav_space; + struct vkd3d_string_buffer *image_data; + struct glsl_src image_coord; + uint32_t coord_mask; + + if (ins->dst[0].reg.idx[0].rel_addr || ins->dst[0].reg.idx[1].rel_addr) + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_UNSUPPORTED, + "Descriptor indexing is not supported."); + + uav_id = ins->dst[0].reg.idx[0].offset; + uav_idx = ins->dst[0].reg.idx[1].offset; + if ((d = shader_glsl_get_descriptor_by_id(gen, VKD3D_SHADER_DESCRIPTOR_TYPE_UAV, uav_id))) + { + resource_type = d->resource_type; + uav_space = d->register_space; + component_type = vkd3d_component_type_from_resource_data_type(d->resource_data_type); + } + else + { + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, + "Internal compiler error: Undeclared UAV descriptor %u.", uav_id); + uav_space = 0; + resource_type = VKD3D_SHADER_RESOURCE_TEXTURE_2D; + component_type = VKD3D_SHADER_COMPONENT_FLOAT; + } + + if ((resource_type_info = shader_glsl_get_resource_type_info(resource_type))) + { + coord_mask = vkd3d_write_mask_from_component_count(resource_type_info->coord_size); + } + else + { + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, + "Internal compiler error: Unhandled UAV type %#x.", resource_type); + coord_mask = vkd3d_write_mask_from_component_count(2); + } + + glsl_src_init(&image_coord, gen, &ins->src[0], coord_mask); + image_data = vkd3d_string_buffer_get(&gen->string_buffers); + + if (ins->src[1].reg.dimension == VSIR_DIMENSION_SCALAR) + { + switch (component_type) + { + case VKD3D_SHADER_COMPONENT_UINT: + vkd3d_string_buffer_printf(image_data, "uvec4("); + break; + case VKD3D_SHADER_COMPONENT_INT: + vkd3d_string_buffer_printf(image_data, "ivec4("); + break; + default: + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, + "Internal compiler error: Unhandled component type %#x.", component_type); + /* fall through */ + case VKD3D_SHADER_COMPONENT_FLOAT: + vkd3d_string_buffer_printf(image_data, "vec4("); + break; + } + } + shader_glsl_print_src(image_data, gen, &ins->src[1], VKD3DSP_WRITEMASK_ALL, + vkd3d_data_type_from_component_type(component_type)); + if (ins->src[1].reg.dimension == VSIR_DIMENSION_SCALAR) + vkd3d_string_buffer_printf(image_data, ", 0, 0, 0)"); + + shader_glsl_print_indent(gen->buffer, gen->indent); + vkd3d_string_buffer_printf(gen->buffer, "imageStore("); + shader_glsl_print_image_name(gen->buffer, gen, uav_idx, uav_space); + vkd3d_string_buffer_printf(gen->buffer, ", %s, %s);\n", image_coord.str->buffer, image_data->buffer); + + vkd3d_string_buffer_release(&gen->string_buffers, image_data); + glsl_src_cleanup(&image_coord, &gen->string_buffers); +} + static void shader_glsl_unary_op(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins, const char *op) { @@ -1336,6 +1429,9 @@ static void vkd3d_glsl_handle_instruction(struct vkd3d_glsl_generator *gen, case VKD3DSIH_SQRT: shader_glsl_intrinsic(gen, ins, "sqrt"); break; + case VKD3DSIH_STORE_UAV_TYPED: + shader_glsl_store_uav_typed(gen, ins); + break; case VKD3DSIH_SWITCH: shader_glsl_switch(gen, ins); break; @@ -1372,6 +1468,137 @@ static bool shader_glsl_check_shader_visibility(const struct vkd3d_glsl_generato } } +static bool shader_glsl_get_uav_binding(const struct vkd3d_glsl_generator *gen, unsigned int register_space, + unsigned int register_idx, enum vkd3d_shader_resource_type resource_type, unsigned int *binding_idx) +{ + const struct vkd3d_shader_interface_info *interface_info = gen->interface_info; + const struct vkd3d_shader_resource_binding *binding; + enum vkd3d_shader_binding_flag resource_type_flag; + unsigned int i; + + if (!interface_info) + return false; + + resource_type_flag = resource_type == VKD3D_SHADER_RESOURCE_BUFFER + ? VKD3D_SHADER_BINDING_FLAG_BUFFER : VKD3D_SHADER_BINDING_FLAG_IMAGE; + + for (i = 0; i < interface_info->binding_count; ++i) + { + binding = &interface_info->bindings[i]; + + if (binding->type != VKD3D_SHADER_DESCRIPTOR_TYPE_UAV) + continue; + if (binding->register_space != register_space) + continue; + if (binding->register_index != register_idx) + continue; + if (!shader_glsl_check_shader_visibility(gen, binding->shader_visibility)) + continue; + if (!(binding->flags & resource_type_flag)) + continue; + *binding_idx = i; + return true; + } + + return false; +} + +static void shader_glsl_generate_uav_declaration(struct vkd3d_glsl_generator *gen, + const struct vkd3d_shader_descriptor_info1 *uav) +{ + const struct glsl_resource_type_info *resource_type_info; + const char *image_type_prefix, *image_type, *read_format; + const struct vkd3d_shader_descriptor_binding *binding; + const struct vkd3d_shader_descriptor_offset *offset; + struct vkd3d_string_buffer *buffer = gen->buffer; + enum vkd3d_shader_component_type component_type; + unsigned int binding_idx; + + if (uav->count != 1) + { + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_UNSUPPORTED, + "UAV %u has unsupported descriptor array size %u.", uav->register_id, uav->count); + return; + } + + if (!shader_glsl_get_uav_binding(gen, uav->register_space, + uav->register_index, uav->resource_type, &binding_idx)) + { + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_BINDING_NOT_FOUND, + "No descriptor binding specified for UAV %u.", uav->register_id); + return; + } + + binding = &gen->interface_info->bindings[binding_idx].binding; + + if (binding->set != 0) + { + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_BINDING_NOT_FOUND, + "Unsupported binding set %u specified for UAV %u.", binding->set, uav->register_id); + return; + } + + if (binding->count != 1) + { + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_BINDING_NOT_FOUND, + "Unsupported binding count %u specified for UAV %u.", binding->count, uav->register_id); + return; + } + + if (gen->offset_info && gen->offset_info->binding_offsets) + { + offset = &gen->offset_info->binding_offsets[binding_idx]; + if (offset->static_offset || offset->dynamic_offset_index != ~0u) + { + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, + "Internal compiler error: Unhandled descriptor offset specified for UAV %u.", + uav->register_id); + return; + } + } + + if ((resource_type_info = shader_glsl_get_resource_type_info(uav->resource_type))) + { + image_type = resource_type_info->type_suffix; + } + else + { + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, + "Internal compiler error: Unhandled UAV type %#x.", uav->resource_type); + image_type = ""; + } + + switch ((component_type = vkd3d_component_type_from_resource_data_type(uav->resource_data_type))) + { + case VKD3D_SHADER_COMPONENT_UINT: + image_type_prefix = "u"; + read_format = "r32ui"; + break; + case VKD3D_SHADER_COMPONENT_INT: + image_type_prefix = "i"; + read_format = "r32i"; + break; + default: + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, + "Internal compiler error: Unhandled component type %#x for UAV %u.", + component_type, uav->register_id); + /* fall through */ + case VKD3D_SHADER_COMPONENT_FLOAT: + image_type_prefix = ""; + read_format = "r32f"; + break; + } + + vkd3d_string_buffer_printf(buffer, "layout(binding = %u", binding->binding); + if (uav->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_READ) + vkd3d_string_buffer_printf(buffer, ", %s) ", read_format); + else + vkd3d_string_buffer_printf(buffer, ") writeonly "); + vkd3d_string_buffer_printf(buffer, "uniform %simage%s ", image_type_prefix, image_type); + shader_glsl_print_image_name(buffer, gen, uav->register_index, uav->register_space); + vkd3d_string_buffer_printf(buffer, ";\n"); +} + static bool shader_glsl_get_cbv_binding(const struct vkd3d_glsl_generator *gen, unsigned int register_space, unsigned int register_idx, unsigned int *binding_idx) { @@ -1415,7 +1642,7 @@ static void shader_glsl_generate_cbv_declaration(struct vkd3d_glsl_generator *ge if (cbv->count != 1) { - vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_BINDING_NOT_FOUND, + vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_UNSUPPORTED, "Constant buffer %u has unsupported descriptor array size %u.", cbv->register_id, cbv->count); return; } @@ -1540,7 +1767,7 @@ static void shader_glsl_generate_sampler_declaration(struct vkd3d_glsl_generator if ((resource_type_info = shader_glsl_get_resource_type_info(srv->resource_type))) { - sampler_type = resource_type_info->sampler_type; + sampler_type = resource_type_info->type_suffix; if (shadow && !resource_type_info->shadow) vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_UNSUPPORTED, "Comparison samplers are not supported with resource type %#x.", srv->resource_type); @@ -1603,7 +1830,7 @@ static void shader_glsl_generate_sampler_declaration(struct vkd3d_glsl_generator return; } - vkd3d_string_buffer_printf(buffer, "layout(binding = %u) uniform %s%s%s ", + vkd3d_string_buffer_printf(buffer, "layout(binding = %u) uniform %ssampler%s%s ", binding->binding, sampler_type_prefix, sampler_type, shadow ? "Shadow" : ""); shader_glsl_print_combined_sampler_name(buffer, gen, crs->resource_index, crs->resource_space, crs->sampler_index, crs->sampler_space); @@ -1628,6 +1855,10 @@ static void shader_glsl_generate_descriptor_declarations(struct vkd3d_glsl_gener /* GLSL uses combined resource/sampler descriptors.*/ break; + case VKD3D_SHADER_DESCRIPTOR_TYPE_UAV: + shader_glsl_generate_uav_declaration(gen, descriptor); + break; + case VKD3D_SHADER_DESCRIPTOR_TYPE_CBV: shader_glsl_generate_cbv_declaration(gen, descriptor); break; @@ -1820,7 +2051,7 @@ static void shader_glsl_generate_output_declarations(struct vkd3d_glsl_generator "Internal compiler error: Unhandled output component type %#x.", e->component_type); break; } - vkd3d_string_buffer_printf(buffer, " shader_out_%u;\n", i); + vkd3d_string_buffer_printf(buffer, " shader_out_%u;\n", e->semantic_index); ++count; } if (count) @@ -1837,6 +2068,14 @@ static void shader_glsl_generate_declarations(struct vkd3d_glsl_generator *gen) { const struct vsir_program *program = gen->program; struct vkd3d_string_buffer *buffer = gen->buffer; + const struct vsir_thread_group_size *group_size; + + if (program->shader_version.type == VKD3D_SHADER_TYPE_COMPUTE) + { + group_size = &program->thread_group_size; + vkd3d_string_buffer_printf(buffer, "layout(local_size_x = %u, local_size_y = %u, local_size_z = %u) in;\n\n", + group_size->x, group_size->y, group_size->z); + } shader_glsl_generate_descriptor_declarations(gen); shader_glsl_generate_input_declarations(gen); @@ -1918,6 +2157,10 @@ static void shader_glsl_init_limits(struct vkd3d_glsl_generator *gen, const stru limits->input_count = 32; limits->output_count = 8; break; + case VKD3D_SHADER_TYPE_COMPUTE: + limits->input_count = 0; + limits->output_count = 0; + break; default: vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL, "Internal compiler error: Unhandled shader type %#x.", version->type); @@ -1948,8 +2191,8 @@ static void vkd3d_glsl_generator_init(struct vkd3d_glsl_generator *gen, gen->prefix = "unknown"; } shader_glsl_init_limits(gen, &program->shader_version); - gen->interstage_input = type != VKD3D_SHADER_TYPE_VERTEX; - gen->interstage_output = type != VKD3D_SHADER_TYPE_PIXEL; + gen->interstage_input = type != VKD3D_SHADER_TYPE_VERTEX && type != VKD3D_SHADER_TYPE_COMPUTE; + gen->interstage_output = type != VKD3D_SHADER_TYPE_PIXEL && type != VKD3D_SHADER_TYPE_COMPUTE; gen->interface_info = vkd3d_find_struct(compile_info->next, INTERFACE_INFO); gen->offset_info = vkd3d_find_struct(compile_info->next, DESCRIPTOR_OFFSET_INFO); diff --git a/libs/vkd3d/libs/vkd3d-shader/ir.c b/libs/vkd3d/libs/vkd3d-shader/ir.c index affbae3ea4e..9d24126fba8 100644 --- a/libs/vkd3d/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d/libs/vkd3d-shader/ir.c @@ -203,6 +203,12 @@ static void src_param_init_ssa_bool(struct vkd3d_shader_src_param *src, unsigned src->reg.idx[0].offset = idx; } +static void src_param_init_ssa_float(struct vkd3d_shader_src_param *src, unsigned int idx) +{ + vsir_src_param_init(src, VKD3DSPR_SSA, VKD3D_DATA_FLOAT, 1); + src->reg.idx[0].offset = idx; +} + static void src_param_init_temp_bool(struct vkd3d_shader_src_param *src, unsigned int idx) { vsir_src_param_init(src, VKD3DSPR_TEMP, VKD3D_DATA_BOOL, 1); @@ -244,6 +250,12 @@ static void dst_param_init_ssa_bool(struct vkd3d_shader_dst_param *dst, unsigned dst->reg.idx[0].offset = idx; } +static void dst_param_init_ssa_float(struct vkd3d_shader_dst_param *dst, unsigned int idx) +{ + vsir_dst_param_init(dst, VKD3DSPR_SSA, VKD3D_DATA_FLOAT, 1); + dst->reg.idx[0].offset = idx; +} + static void dst_param_init_temp_bool(struct vkd3d_shader_dst_param *dst, unsigned int idx) { vsir_dst_param_init(dst, VKD3DSPR_TEMP, VKD3D_DATA_BOOL, 1); @@ -254,7 +266,6 @@ static void dst_param_init_temp_uint(struct vkd3d_shader_dst_param *dst, unsigne { vsir_dst_param_init(dst, VKD3DSPR_TEMP, VKD3D_DATA_UINT, 1); dst->reg.idx[0].offset = idx; - dst->write_mask = VKD3DSP_WRITEMASK_0; } void vsir_instruction_init(struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_location *location, @@ -682,6 +693,7 @@ static enum vkd3d_result vsir_program_lower_instructions(struct vsir_program *pr case VKD3DSIH_DCL_SAMPLER: case VKD3DSIH_DCL_TEMPS: case VKD3DSIH_DCL_THREAD_GROUP: + case VKD3DSIH_DCL_UAV_TYPED: vkd3d_shader_instruction_make_nop(ins); break; @@ -1221,7 +1233,7 @@ static bool shader_signature_find_element_for_reg(const struct shader_signature unsigned int reg_idx, unsigned int write_mask, unsigned int *element_idx) { const struct signature_element *e; - unsigned int i, base_write_mask; + unsigned int i; for (i = 0; i < signature->element_count; ++i) { @@ -1234,14 +1246,6 @@ static bool shader_signature_find_element_for_reg(const struct shader_signature } } - /* 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, element_idx); - return false; } @@ -1655,6 +1659,9 @@ static bool shader_dst_param_io_normalise(struct vkd3d_shader_dst_param *dst_par break; case VKD3DSPR_RASTOUT: + /* Leave point size as a system value for the backends to consume. */ + if (reg->idx[0].offset == VSIR_RASTOUT_POINT_SIZE) + return true; reg_idx = SM1_RASTOUT_REGISTER_OFFSET + reg->idx[0].offset; signature = normaliser->output_signature; reg->type = VKD3DSPR_OUTPUT; @@ -5777,11 +5784,12 @@ static enum vkd3d_result insert_clip_planes_before_ret(struct vsir_program *prog return VKD3D_OK; } -static bool find_position_signature_idx(const struct shader_signature *signature, uint32_t *idx) +static bool find_sysval_signature_idx(const struct shader_signature *signature, + enum vkd3d_shader_sysval_semantic sysval, uint32_t *idx) { for (unsigned int i = 0; i < signature->element_count; ++i) { - if (signature->elements[i].sysval_semantic == VKD3D_SHADER_SV_POSITION) + if (signature->elements[i].sysval_semantic == sysval) { *idx = i; return true; @@ -5846,7 +5854,7 @@ static enum vkd3d_result vsir_program_insert_clip_planes(struct vsir_program *pr } } - if (!find_position_signature_idx(signature, &position_signature_idx)) + if (!find_sysval_signature_idx(signature, VKD3D_SHADER_SV_POSITION, &position_signature_idx)) { vkd3d_shader_error(ctx->message_context, &no_loc, VKD3D_SHADER_ERROR_VSIR_MISSING_SEMANTIC, "Shader does not write position."); @@ -5923,6 +5931,191 @@ static enum vkd3d_result vsir_program_insert_clip_planes(struct vsir_program *pr return VKD3D_OK; } +static enum vkd3d_result insert_point_size_before_ret(struct vsir_program *program, + const struct vkd3d_shader_instruction *ret, size_t *ret_pos) +{ + struct vkd3d_shader_instruction_array *instructions = &program->instructions; + size_t pos = ret - instructions->elements; + struct vkd3d_shader_instruction *ins; + + if (!shader_instruction_array_insert_at(&program->instructions, pos, 1)) + return VKD3D_ERROR_OUT_OF_MEMORY; + + ins = &program->instructions.elements[pos]; + + vsir_instruction_init_with_params(program, ins, &ret->location, VKD3DSIH_MOV, 1, 1); + vsir_dst_param_init(&ins->dst[0], VKD3DSPR_RASTOUT, VKD3D_DATA_FLOAT, 1); + ins->dst[0].reg.idx[0].offset = VSIR_RASTOUT_POINT_SIZE; + src_param_init_parameter(&ins->src[0], VKD3D_SHADER_PARAMETER_NAME_POINT_SIZE, VKD3D_DATA_FLOAT); + + *ret_pos = pos + 1; + return VKD3D_OK; +} + +static enum vkd3d_result vsir_program_insert_point_size(struct vsir_program *program, + struct vsir_transformation_context *ctx) +{ + const struct vkd3d_shader_parameter1 *size_parameter = NULL; + static const struct vkd3d_shader_location no_loc; + + if (program->has_point_size) + return VKD3D_OK; + + if (program->shader_version.type != VKD3D_SHADER_TYPE_VERTEX + && program->shader_version.type != VKD3D_SHADER_TYPE_GEOMETRY + && program->shader_version.type != VKD3D_SHADER_TYPE_HULL + && program->shader_version.type != VKD3D_SHADER_TYPE_DOMAIN) + return VKD3D_OK; + + for (unsigned int i = 0; i < program->parameter_count; ++i) + { + const struct vkd3d_shader_parameter1 *parameter = &program->parameters[i]; + + if (parameter->name == VKD3D_SHADER_PARAMETER_NAME_POINT_SIZE) + size_parameter = parameter; + } + + if (!size_parameter) + return VKD3D_OK; + + if (size_parameter->data_type != VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32) + { + vkd3d_shader_error(ctx->message_context, &no_loc, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, + "Invalid point size parameter data type %#x.", size_parameter->data_type); + return VKD3D_ERROR_INVALID_ARGUMENT; + } + + program->has_point_size = true; + + /* Append a point size write before each ret. */ + for (size_t i = 0; i < program->instructions.count; ++i) + { + struct vkd3d_shader_instruction *ins = &program->instructions.elements[i]; + + if (ins->opcode == VKD3DSIH_RET) + { + size_t new_pos; + int ret; + + if ((ret = insert_point_size_before_ret(program, ins, &new_pos)) < 0) + return ret; + i = new_pos; + } + } + + return VKD3D_OK; +} + +static enum vkd3d_result vsir_program_insert_point_size_clamp(struct vsir_program *program, + struct vsir_transformation_context *ctx) +{ + const struct vkd3d_shader_parameter1 *min_parameter = NULL, *max_parameter = NULL; + static const struct vkd3d_shader_location no_loc; + + if (!program->has_point_size) + return VKD3D_OK; + + if (program->shader_version.type != VKD3D_SHADER_TYPE_VERTEX + && program->shader_version.type != VKD3D_SHADER_TYPE_GEOMETRY + && program->shader_version.type != VKD3D_SHADER_TYPE_HULL + && program->shader_version.type != VKD3D_SHADER_TYPE_DOMAIN) + return VKD3D_OK; + + for (unsigned int i = 0; i < program->parameter_count; ++i) + { + const struct vkd3d_shader_parameter1 *parameter = &program->parameters[i]; + + if (parameter->name == VKD3D_SHADER_PARAMETER_NAME_POINT_SIZE_MIN) + min_parameter = parameter; + else if (parameter->name == VKD3D_SHADER_PARAMETER_NAME_POINT_SIZE_MAX) + max_parameter = parameter; + } + + if (!min_parameter && !max_parameter) + return VKD3D_OK; + + if (min_parameter && min_parameter->data_type != VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32) + { + vkd3d_shader_error(ctx->message_context, &no_loc, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, + "Invalid minimum point size parameter data type %#x.", min_parameter->data_type); + return VKD3D_ERROR_INVALID_ARGUMENT; + } + + if (max_parameter && max_parameter->data_type != VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32) + { + vkd3d_shader_error(ctx->message_context, &no_loc, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE, + "Invalid maximum point size parameter data type %#x.", max_parameter->data_type); + return VKD3D_ERROR_INVALID_ARGUMENT; + } + + /* Replace writes to the point size by inserting a clamp before each write. */ + + for (size_t i = 0; i < program->instructions.count; ++i) + { + struct vkd3d_shader_instruction *ins = &program->instructions.elements[i]; + const struct vkd3d_shader_location *loc; + unsigned int ssa_value; + bool clamp = false; + + if (vsir_instruction_is_dcl(ins)) + continue; + + for (size_t j = 0; j < ins->dst_count; ++j) + { + struct vkd3d_shader_dst_param *dst = &ins->dst[j]; + + /* Note we run after I/O normalization. */ + if (dst->reg.type == VKD3DSPR_RASTOUT) + { + dst_param_init_ssa_float(dst, program->ssa_count); + ssa_value = program->ssa_count++; + clamp = true; + } + } + + if (!clamp) + continue; + + if (!shader_instruction_array_insert_at(&program->instructions, i + 1, !!min_parameter + !!max_parameter)) + return VKD3D_ERROR_OUT_OF_MEMORY; + + loc = &program->instructions.elements[i].location; + ins = &program->instructions.elements[i + 1]; + + if (min_parameter) + { + vsir_instruction_init_with_params(program, ins, loc, VKD3DSIH_MAX, 1, 2); + src_param_init_ssa_float(&ins->src[0], ssa_value); + src_param_init_parameter(&ins->src[1], VKD3D_SHADER_PARAMETER_NAME_POINT_SIZE_MIN, VKD3D_DATA_FLOAT); + if (max_parameter) + { + dst_param_init_ssa_float(&ins->dst[0], program->ssa_count); + ssa_value = program->ssa_count++; + } + else + { + vsir_dst_param_init(&ins->dst[0], VKD3DSPR_RASTOUT, VKD3D_DATA_FLOAT, 1); + ins->dst[0].reg.idx[0].offset = VSIR_RASTOUT_POINT_SIZE; + } + ++ins; + ++i; + } + + if (max_parameter) + { + vsir_instruction_init_with_params(program, ins, loc, VKD3DSIH_MIN, 1, 2); + src_param_init_ssa_float(&ins->src[0], ssa_value); + src_param_init_parameter(&ins->src[1], VKD3D_SHADER_PARAMETER_NAME_POINT_SIZE_MAX, VKD3D_DATA_FLOAT); + vsir_dst_param_init(&ins->dst[0], VKD3DSPR_RASTOUT, VKD3D_DATA_FLOAT, 1); + ins->dst[0].reg.idx[0].offset = VSIR_RASTOUT_POINT_SIZE; + + ++i; + } + } + + return VKD3D_OK; +} + struct validation_context { struct vkd3d_shader_message_context *message_context; @@ -6395,23 +6588,18 @@ static void vsir_validate_dst_param(struct validation_context *ctx, 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; - case VKD3DSPR_SAMPLER: + case VKD3DSPR_RESOURCE: + case VKD3DSPR_INPUT: validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, - "Invalid SAMPLER register used as destination parameter."); + "Invalid %#x register used as destination parameter.", dst->reg.type); break; - case VKD3DSPR_RESOURCE: - validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, - "Invalid RESOURCE register used as destination parameter."); + case VKD3DSPR_PATCHCONST: + if (ctx->program->shader_version.type != VKD3D_SHADER_TYPE_HULL) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, + "PATCHCONST register used as destination parameters are only allowed in Hull Shaders."); break; default: @@ -6454,6 +6642,20 @@ static void vsir_validate_src_param(struct validation_context *ctx, "Invalid NULL register used as source parameter."); break; + case VKD3DSPR_OUTPUT: + if (ctx->program->shader_version.type != VKD3D_SHADER_TYPE_HULL + || (ctx->phase != VKD3DSIH_HS_FORK_PHASE && ctx->phase != VKD3DSIH_HS_JOIN_PHASE)) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, + "Invalid OUTPUT register used as source parameter."); + break; + + case VKD3DSPR_PATCHCONST: + if (ctx->program->shader_version.type != VKD3D_SHADER_TYPE_DOMAIN + && ctx->program->shader_version.type != VKD3D_SHADER_TYPE_HULL) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_REGISTER_TYPE, + "PATCHCONST register used as source parameters are only allowed in Hull and Domain Shaders."); + break; + default: break; } @@ -6510,6 +6712,7 @@ static void vsir_validate_signature_element(struct validation_context *ctx, unsigned int idx) { const struct signature_element *element = &signature->elements[idx]; + bool integer_type = false; if (element->register_count == 0) validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SIGNATURE, @@ -6518,6 +6721,97 @@ static void vsir_validate_signature_element(struct validation_context *ctx, if (element->mask == 0 || (element->mask & ~0xf)) validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SIGNATURE, "element %u of %s signature: Invalid mask %#x.", idx, signature_type, element->mask); + + /* Here we'd likely want to validate that the usage mask is a subset of the + * signature mask. Unfortunately the D3DBC parser sometimes violates this. + * For example I've seen a shader like this: + * ps_3_0 + * [...] + * dcl_texcoord0 v0 + * [...] + * texld r2.xyzw, v0.xyzw, s1.xyzw + * [...] + * + * The dcl_textcoord0 instruction secretly has a .xy mask, which is used to + * compute the signature mask, but the texld instruction apparently uses all + * the components. Of course the last two components are ignored, but + * formally they seem to be used. So we end up with a signature element with + * mask .xy and usage mask .xyzw. + * + * The correct fix would probably be to make the D3DBC parser aware of which + * components are really used for each instruction, but that would take some + * time. */ + if (element->used_mask & ~0xf) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SIGNATURE, + "element %u of %s signature: Invalid usage mask %#x.", + idx, signature_type, element->used_mask); + + switch (element->sysval_semantic) + { + case VKD3D_SHADER_SV_NONE: + case VKD3D_SHADER_SV_POSITION: + case VKD3D_SHADER_SV_CLIP_DISTANCE: + case VKD3D_SHADER_SV_CULL_DISTANCE: + case VKD3D_SHADER_SV_RENDER_TARGET_ARRAY_INDEX: + case VKD3D_SHADER_SV_VIEWPORT_ARRAY_INDEX: + case VKD3D_SHADER_SV_VERTEX_ID: + case VKD3D_SHADER_SV_PRIMITIVE_ID: + case VKD3D_SHADER_SV_INSTANCE_ID: + case VKD3D_SHADER_SV_IS_FRONT_FACE: + case VKD3D_SHADER_SV_SAMPLE_INDEX: + case VKD3D_SHADER_SV_TESS_FACTOR_QUADEDGE: + case VKD3D_SHADER_SV_TESS_FACTOR_QUADINT: + case VKD3D_SHADER_SV_TESS_FACTOR_TRIEDGE: + case VKD3D_SHADER_SV_TESS_FACTOR_TRIINT: + case VKD3D_SHADER_SV_TESS_FACTOR_LINEDET: + case VKD3D_SHADER_SV_TESS_FACTOR_LINEDEN: + case VKD3D_SHADER_SV_TARGET: + case VKD3D_SHADER_SV_DEPTH: + case VKD3D_SHADER_SV_COVERAGE: + case VKD3D_SHADER_SV_DEPTH_GREATER_EQUAL: + case VKD3D_SHADER_SV_DEPTH_LESS_EQUAL: + case VKD3D_SHADER_SV_STENCIL_REF: + break; + + default: + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SIGNATURE, + "element %u of %s signature: Invalid system value semantic %#x.", + idx, signature_type, element->sysval_semantic); + break; + } + + switch (element->component_type) + { + case VKD3D_SHADER_COMPONENT_INT: + case VKD3D_SHADER_COMPONENT_UINT: + integer_type = true; + break; + + case VKD3D_SHADER_COMPONENT_FLOAT: + break; + + default: + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SIGNATURE, + "element %u of %s signature: Invalid component type %#x.", + idx, signature_type, element->component_type); + break; + } + + if (element->min_precision >= VKD3D_SHADER_MINIMUM_PRECISION_COUNT) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SIGNATURE, + "element %u of %s signature: Invalid minimum precision %#x.", + idx, signature_type, element->min_precision); + + if (element->interpolation_mode >= VKD3DSIM_COUNT) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SIGNATURE, + "element %u of %s signature: Invalid interpolation mode %#x.", + idx, signature_type, element->interpolation_mode); + + if (integer_type && element->interpolation_mode != VKD3DSIM_NONE + && element->interpolation_mode != VKD3DSIM_CONSTANT) + validator_error(ctx, VKD3D_SHADER_ERROR_VSIR_INVALID_SIGNATURE, + "element %u of %s signature: Invalid interpolation mode %#x for integer component type.", + idx, signature_type, element->interpolation_mode); } static void vsir_validate_signature(struct validation_context *ctx, @@ -7060,6 +7354,7 @@ enum vkd3d_result vsir_program_validate(struct vsir_program *program, uint64_t c .null_location = {.source_name = source_name}, .status = VKD3D_OK, .phase = VKD3DSIH_INVALID, + .invalid_instruction_idx = true, }; unsigned int i; @@ -7088,6 +7383,8 @@ enum vkd3d_result vsir_program_validate(struct vsir_program *program, uint64_t c if (!(ctx.ssas = vkd3d_calloc(ctx.program->ssa_count, sizeof(*ctx.ssas)))) goto fail; + ctx.invalid_instruction_idx = false; + for (ctx.instruction_idx = 0; ctx.instruction_idx < program->instructions.count && ctx.status != VKD3D_ERROR_OUT_OF_MEMORY; ++ctx.instruction_idx) vsir_validate_instruction(&ctx); @@ -7190,6 +7487,8 @@ enum vkd3d_result vsir_program_transform(struct vsir_program *program, uint64_t vsir_transform(&ctx, vsir_program_insert_alpha_test); vsir_transform(&ctx, vsir_program_insert_clip_planes); + vsir_transform(&ctx, vsir_program_insert_point_size); + vsir_transform(&ctx, vsir_program_insert_point_size_clamp); if (TRACE_ON()) vsir_program_trace(program); diff --git a/libs/vkd3d/libs/vkd3d-shader/msl.c b/libs/vkd3d/libs/vkd3d-shader/msl.c index bfc013959e7..36750de1fd8 100644 --- a/libs/vkd3d/libs/vkd3d-shader/msl.c +++ b/libs/vkd3d/libs/vkd3d-shader/msl.c @@ -39,6 +39,8 @@ struct msl_generator struct vkd3d_shader_message_context *message_context; unsigned int indent; const char *prefix; + const struct vkd3d_shader_interface_info *interface_info; + const struct vkd3d_shader_scan_descriptor_info1 *descriptor_info; }; static void VKD3D_PRINTF_FUNC(3, 4) msl_compiler_error(struct msl_generator *gen, @@ -109,6 +111,64 @@ static void msl_print_register_name(struct vkd3d_string_buffer *buffer, vkd3d_string_buffer_printf(buffer, "r[%u]", reg->idx[0].offset); msl_print_register_datatype(buffer, gen, reg->data_type); break; + + case VKD3DSPR_INPUT: + if (reg->idx_count != 1) + { + msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, + "Internal compiler error: Unhandled input register index count %u.", reg->idx_count); + vkd3d_string_buffer_printf(buffer, "", reg->type); + break; + } + if (reg->idx[0].rel_addr) + { + msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, + "Internal compiler error: Unhandled input register indirect addressing."); + vkd3d_string_buffer_printf(buffer, "", reg->type); + break; + } + vkd3d_string_buffer_printf(buffer, "v[%u]", reg->idx[0].offset); + msl_print_register_datatype(buffer, gen, reg->data_type); + break; + + case VKD3DSPR_OUTPUT: + if (reg->idx_count != 1) + { + msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, + "Internal compiler error: Unhandled output register index count %u.", reg->idx_count); + vkd3d_string_buffer_printf(buffer, "", reg->type); + break; + } + if (reg->idx[0].rel_addr) + { + msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, + "Internal compiler error: Unhandled output register indirect addressing."); + vkd3d_string_buffer_printf(buffer, "", reg->type); + break; + } + vkd3d_string_buffer_printf(buffer, "o[%u]", reg->idx[0].offset); + msl_print_register_datatype(buffer, gen, reg->data_type); + break; + + case VKD3DSPR_CONSTBUFFER: + if (reg->idx_count != 3) + { + msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, + "Internal compiler error: Unhandled constant buffer register index count %u.", reg->idx_count); + vkd3d_string_buffer_printf(buffer, "", reg->type); + break; + } + if (reg->idx[0].rel_addr || reg->idx[2].rel_addr) + { + msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, + "Internal compiler error: Unhandled constant buffer register indirect addressing."); + vkd3d_string_buffer_printf(buffer, "", reg->type); + break; + } + vkd3d_string_buffer_printf(buffer, "descriptors.cb_%u[%u]", reg->idx[0].offset, reg->idx[2].offset); + msl_print_register_datatype(buffer, gen, reg->data_type); + break; + default: msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, "Internal compiler error: Unhandled register type %#x.", reg->type); @@ -266,6 +326,144 @@ static void msl_handle_instruction(struct msl_generator *gen, const struct vkd3d } } +static bool msl_check_shader_visibility(const struct msl_generator *gen, + enum vkd3d_shader_visibility visibility) +{ + enum vkd3d_shader_type t = gen->program->shader_version.type; + + switch (visibility) + { + case VKD3D_SHADER_VISIBILITY_ALL: + return true; + case VKD3D_SHADER_VISIBILITY_VERTEX: + return t == VKD3D_SHADER_TYPE_VERTEX; + case VKD3D_SHADER_VISIBILITY_HULL: + return t == VKD3D_SHADER_TYPE_HULL; + case VKD3D_SHADER_VISIBILITY_DOMAIN: + return t == VKD3D_SHADER_TYPE_DOMAIN; + case VKD3D_SHADER_VISIBILITY_GEOMETRY: + return t == VKD3D_SHADER_TYPE_GEOMETRY; + case VKD3D_SHADER_VISIBILITY_PIXEL: + return t == VKD3D_SHADER_TYPE_PIXEL; + case VKD3D_SHADER_VISIBILITY_COMPUTE: + return t == VKD3D_SHADER_TYPE_COMPUTE; + default: + WARN("Invalid shader visibility %#x.\n", visibility); + return false; + } +} + +static bool msl_get_cbv_binding(const struct msl_generator *gen, + unsigned int register_space, unsigned int register_idx, unsigned int *binding_idx) +{ + const struct vkd3d_shader_interface_info *interface_info = gen->interface_info; + const struct vkd3d_shader_resource_binding *binding; + unsigned int i; + + if (!interface_info) + return false; + + for (i = 0; i < interface_info->binding_count; ++i) + { + binding = &interface_info->bindings[i]; + + if (binding->type != VKD3D_SHADER_DESCRIPTOR_TYPE_CBV) + continue; + if (binding->register_space != register_space) + continue; + if (binding->register_index != register_idx) + continue; + if (!msl_check_shader_visibility(gen, binding->shader_visibility)) + continue; + if (!(binding->flags & VKD3D_SHADER_BINDING_FLAG_BUFFER)) + continue; + *binding_idx = i; + return true; + } + + return false; +} + +static void msl_generate_cbv_declaration(struct msl_generator *gen, + const struct vkd3d_shader_descriptor_info1 *cbv) +{ + const struct vkd3d_shader_descriptor_binding *binding; + struct vkd3d_string_buffer *buffer = gen->buffer; + unsigned int binding_idx; + size_t size; + + if (cbv->count != 1) + { + msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_BINDING_NOT_FOUND, + "Constant buffer %u has unsupported descriptor array size %u.", cbv->register_id, cbv->count); + return; + } + + if (!msl_get_cbv_binding(gen, cbv->register_space, cbv->register_index, &binding_idx)) + { + msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_BINDING_NOT_FOUND, + "No descriptor binding specified for constant buffer %u.", cbv->register_id); + return; + } + + binding = &gen->interface_info->bindings[binding_idx].binding; + + if (binding->set != 0) + { + msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_BINDING_NOT_FOUND, + "Unsupported binding set %u specified for constant buffer %u.", binding->set, cbv->register_id); + return; + } + + if (binding->count != 1) + { + msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_BINDING_NOT_FOUND, + "Unsupported binding count %u specified for constant buffer %u.", binding->count, cbv->register_id); + return; + } + + size = align(cbv->buffer_size, VKD3D_VEC4_SIZE * sizeof(uint32_t)); + size /= VKD3D_VEC4_SIZE * sizeof(uint32_t); + + vkd3d_string_buffer_printf(buffer, + "constant vkd3d_vec4 (&cb_%u)[%zu] [[id(%u)]];", cbv->register_id, size, binding->binding); +}; + +static void msl_generate_descriptor_struct_declarations(struct msl_generator *gen) +{ + const struct vkd3d_shader_scan_descriptor_info1 *info = gen->descriptor_info; + const struct vkd3d_shader_descriptor_info1 *descriptor; + struct vkd3d_string_buffer *buffer = gen->buffer; + unsigned int i; + + if (!info->descriptor_count) + return; + + vkd3d_string_buffer_printf(buffer, "struct vkd3d_%s_descriptors\n{\n", gen->prefix); + + for (i = 0; i < info->descriptor_count; ++i) + { + descriptor = &info->descriptors[i]; + + msl_print_indent(buffer, 1); + switch (descriptor->type) + { + case VKD3D_SHADER_DESCRIPTOR_TYPE_CBV: + msl_generate_cbv_declaration(gen, descriptor); + break; + + default: + vkd3d_string_buffer_printf(buffer, "/* */", descriptor->type); + msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, + "Internal compiler error: Unhandled descriptor type %#x.", descriptor->type); + break; + } + vkd3d_string_buffer_printf(buffer, "\n"); + } + + vkd3d_string_buffer_printf(buffer, "};\n\n"); +} + static void msl_generate_input_struct_declarations(struct msl_generator *gen) { const struct shader_signature *signature = &gen->program->input_signature; @@ -550,9 +748,15 @@ static void msl_generate_entrypoint(struct msl_generator *gen) vkd3d_string_buffer_printf(gen->buffer, "vkd3d_%s_out shader_entry(\n", gen->prefix); - /* TODO: descriptor declaration */ + if (gen->descriptor_info->descriptor_count) + { + msl_print_indent(gen->buffer, 2); + /* TODO: Configurable argument buffer binding location. */ + vkd3d_string_buffer_printf(gen->buffer, + "constant vkd3d_%s_descriptors& descriptors [[buffer(0)]],\n", gen->prefix); + } - msl_print_indent(gen->buffer, 1); + msl_print_indent(gen->buffer, 2); vkd3d_string_buffer_printf(gen->buffer, "vkd3d_%s_in input [[stage_in]])\n{\n", gen->prefix); /* TODO: declare #maximum_register + 1 */ @@ -562,7 +766,10 @@ static void msl_generate_entrypoint(struct msl_generator *gen) msl_generate_entrypoint_prologue(gen); - vkd3d_string_buffer_printf(gen->buffer, " %s_main(%s_in, %s_out);\n", gen->prefix, gen->prefix, gen->prefix); + vkd3d_string_buffer_printf(gen->buffer, " %s_main(%s_in, %s_out", gen->prefix, gen->prefix, gen->prefix); + if (gen->descriptor_info->descriptor_count) + vkd3d_string_buffer_printf(gen->buffer, ", descriptors"); + vkd3d_string_buffer_printf(gen->buffer, ");\n"); msl_generate_entrypoint_epilogue(gen); @@ -583,13 +790,17 @@ static void msl_generator_generate(struct msl_generator *gen) vkd3d_string_buffer_printf(gen->buffer, " int4 i;\n"); vkd3d_string_buffer_printf(gen->buffer, " float4 f;\n};\n\n"); + msl_generate_descriptor_struct_declarations(gen); msl_generate_input_struct_declarations(gen); msl_generate_output_struct_declarations(gen); vkd3d_string_buffer_printf(gen->buffer, "void %s_main(thread vkd3d_vec4 *v, " - "thread vkd3d_vec4 *o)\n{\n", + "thread vkd3d_vec4 *o", gen->prefix); + if (gen->descriptor_info->descriptor_count) + vkd3d_string_buffer_printf(gen->buffer, ", constant vkd3d_%s_descriptors& descriptors", gen->prefix); + vkd3d_string_buffer_printf(gen->buffer, ")\n{\n"); ++gen->indent; @@ -621,6 +832,8 @@ static void msl_generator_cleanup(struct msl_generator *gen) } static int msl_generator_init(struct msl_generator *gen, struct vsir_program *program, + const struct vkd3d_shader_compile_info *compile_info, + const struct vkd3d_shader_scan_descriptor_info1 *descriptor_info, struct vkd3d_shader_message_context *message_context) { enum vkd3d_shader_type type = program->shader_version.type; @@ -640,11 +853,14 @@ static int msl_generator_init(struct msl_generator *gen, struct vsir_program *pr "Internal compiler error: Unhandled shader type %#x.", type); return VKD3D_ERROR_INVALID_SHADER; } + gen->interface_info = vkd3d_find_struct(compile_info->next, INTERFACE_INFO); + gen->descriptor_info = descriptor_info; return VKD3D_OK; } int msl_compile(struct vsir_program *program, uint64_t config_flags, + const struct vkd3d_shader_scan_descriptor_info1 *descriptor_info, const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_message_context *message_context) { struct msl_generator generator; @@ -653,7 +869,7 @@ int msl_compile(struct vsir_program *program, uint64_t config_flags, if ((ret = vsir_program_transform(program, config_flags, compile_info, message_context)) < 0) return ret; - if ((ret = msl_generator_init(&generator, program, message_context)) < 0) + if ((ret = msl_generator_init(&generator, program, compile_info, descriptor_info, message_context)) < 0) return ret; msl_generator_generate(&generator); msl_generator_cleanup(&generator); diff --git a/libs/vkd3d/libs/vkd3d-shader/spirv.c b/libs/vkd3d/libs/vkd3d-shader/spirv.c index 692432d5513..1efd717e970 100644 --- a/libs/vkd3d/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d/libs/vkd3d-shader/spirv.c @@ -2662,8 +2662,6 @@ static struct spirv_compiler *spirv_compiler_create(const struct vsir_program *p 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) @@ -2690,6 +2688,11 @@ static struct spirv_compiler *spirv_compiler_create(const struct vsir_program *p } } + if (compiler->shader_type == VKD3D_SHADER_TYPE_VERTEX) + compiler->emit_point_size = true; + else if (compiler->shader_type != VKD3D_SHADER_TYPE_GEOMETRY) + compiler->emit_point_size = compiler->xfb_info && compiler->xfb_info->element_count; + compiler->scan_descriptor_info = scan_descriptor_info; compiler->phase = VKD3DSIH_INVALID; @@ -4860,6 +4863,10 @@ static const struct vkd3d_spirv_builtin vkd3d_pixel_shader_position_builtin = { VKD3D_SHADER_COMPONENT_FLOAT, 4, SpvBuiltInFragCoord, frag_coord_fixup, }; +static const struct vkd3d_spirv_builtin vkd3d_output_point_size_builtin = +{ + VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInPointSize, +}; static const struct { enum vkd3d_shader_register_type reg_type; @@ -5449,7 +5456,11 @@ static void spirv_compiler_emit_output_register(struct spirv_compiler *compiler, VKD3D_ASSERT(!reg->idx_count || !reg->idx[0].rel_addr); VKD3D_ASSERT(reg->idx_count < 2); - if (!(builtin = get_spirv_builtin_for_register(reg->type))) + if (reg->type == VKD3DSPR_RASTOUT && reg->idx[0].offset == VSIR_RASTOUT_POINT_SIZE) + { + builtin = &vkd3d_output_point_size_builtin; + } + else if (!(builtin = get_spirv_builtin_for_register(reg->type))) { FIXME("Unhandled register %#x.\n", reg->type); return; @@ -6746,7 +6757,8 @@ static void spirv_compiler_emit_dcl_input_primitive(struct spirv_compiler *compi static void spirv_compiler_emit_point_size(struct spirv_compiler *compiler) { - static const struct vkd3d_spirv_builtin point_size = {VKD3D_SHADER_COMPONENT_FLOAT, 1, SpvBuiltInPointSize}; + if (compiler->program->has_point_size) + return; /* Set the point size. Point sprites are not supported in d3d10+, but * point primitives can still be used with e.g. stream output. Vulkan @@ -6760,7 +6772,8 @@ static void spirv_compiler_emit_point_size(struct spirv_compiler *compiler) || compiler->write_tess_geom_point_size) { vkd3d_spirv_build_op_store(&compiler->spirv_builder, - spirv_compiler_emit_builtin_variable(compiler, &point_size, SpvStorageClassOutput, 0), + spirv_compiler_emit_builtin_variable(compiler, + &vkd3d_output_point_size_builtin, SpvStorageClassOutput, 0), spirv_compiler_get_constant_float(compiler, 1.0f), SpvMemoryAccessMaskNone); } } @@ -7427,7 +7440,7 @@ static void spirv_compiler_emit_mov(struct spirv_compiler *compiler, uint32_t components[VKD3D_VEC4_SIZE]; if (register_is_constant_or_undef(&src->reg) || src->reg.type == VKD3DSPR_SSA || dst->reg.type == VKD3DSPR_SSA - || dst->modifiers || src->modifiers) + || src->reg.type == VKD3DSPR_PARAMETER || dst->modifiers || src->modifiers) goto general_implementation; spirv_compiler_get_register_info(compiler, &dst->reg, &dst_reg_info); @@ -10538,7 +10551,6 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, case VKD3DSIH_DCL_RESOURCE_STRUCTURED: case VKD3DSIH_DCL_UAV_RAW: case VKD3DSIH_DCL_UAV_STRUCTURED: - case VKD3DSIH_DCL_UAV_TYPED: case VKD3DSIH_HS_DECLS: case VKD3DSIH_NOP: /* nothing to do */ @@ -10575,6 +10587,15 @@ static void spirv_compiler_emit_io_declarations(struct spirv_compiler *compiler) else spirv_compiler_emit_input(compiler, VKD3DSPR_PATCHCONST, i); } + + if (compiler->program->has_point_size) + { + struct vkd3d_shader_dst_param dst; + + vsir_dst_param_init(&dst, VKD3DSPR_RASTOUT, VKD3D_DATA_FLOAT, 1); + dst.reg.idx[0].offset = VSIR_RASTOUT_POINT_SIZE; + spirv_compiler_emit_output_register(compiler, &dst); + } } static void spirv_compiler_emit_descriptor_declarations(struct spirv_compiler *compiler) diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c index f84ac551272..cde8dc3146c 100644 --- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_main.c @@ -1655,7 +1655,10 @@ int vsir_program_compile(struct vsir_program *program, uint64_t config_flags, break; case VKD3D_SHADER_TARGET_MSL: - ret = msl_compile(program, config_flags, compile_info, message_context); + if ((ret = vsir_program_scan(program, &scan_info, message_context, &scan_descriptor_info)) < 0) + return ret; + ret = msl_compile(program, config_flags, &scan_descriptor_info, compile_info, message_context); + vkd3d_shader_free_scan_descriptor_info1(&scan_descriptor_info); break; default: diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h index 41b879af4b4..9ca3c328147 100644 --- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h @@ -60,6 +60,7 @@ #define VKD3D_DVEC2_SIZE 2 #define VKD3D_SHADER_COMPONENT_TYPE_COUNT (VKD3D_SHADER_COMPONENT_UINT64 + 1) +#define VKD3D_SHADER_MINIMUM_PRECISION_COUNT (VKD3D_SHADER_MINIMUM_PRECISION_UINT_16 + 1) enum vkd3d_shader_error { @@ -250,6 +251,7 @@ enum vkd3d_shader_error VKD3D_SHADER_WARNING_VSIR_DYNAMIC_DESCRIPTOR_ARRAY = 9300, VKD3D_SHADER_ERROR_MSL_INTERNAL = 10000, + VKD3D_SHADER_ERROR_MSL_BINDING_NOT_FOUND = 10001, }; enum vkd3d_shader_opcode @@ -648,6 +650,13 @@ enum vkd3d_shader_register_type VKD3DSPR_INVALID = ~0u, }; +enum vsir_rastout_register +{ + VSIR_RASTOUT_POSITION = 0x0, + VSIR_RASTOUT_FOG = 0x1, + VSIR_RASTOUT_POINT_SIZE = 0x2, +}; + enum vkd3d_shader_register_precision { VKD3D_SHADER_REGISTER_PRECISION_DEFAULT, @@ -1400,6 +1409,7 @@ struct vsir_program unsigned int temp_count; unsigned int ssa_count; bool use_vocp; + bool has_point_size; enum vsir_control_flow_type cf_type; const char **block_names; @@ -1617,6 +1627,7 @@ int spirv_compile(struct vsir_program *program, uint64_t config_flags, struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context); int msl_compile(struct vsir_program *program, uint64_t config_flags, + const struct vkd3d_shader_scan_descriptor_info1 *descriptor_info, const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_message_context *message_context); enum vkd3d_md5_variant -- 2.45.2