diff --git a/libs/vkd3d-shader/msl.c b/libs/vkd3d-shader/msl.c index d477bfa1c1bed72b0ba2d4637aa5d8c4747cd376..55e5aa2b96c497729fe9f58e169127549a5bac11 100644 --- a/libs/vkd3d-shader/msl.c +++ b/libs/vkd3d-shader/msl.c @@ -46,6 +46,14 @@ struct msl_generator const struct vkd3d_shader_interface_info *interface_info; }; +struct msl_resource_type_info +{ + size_t read_coord_size; + bool array; + bool lod; + const char *type_suffix; +}; + static void VKD3D_PRINTF_FUNC(3, 4) msl_compiler_error(struct msl_generator *gen, enum vkd3d_shader_error error, const char *fmt, ...) { @@ -57,6 +65,30 @@ static void VKD3D_PRINTF_FUNC(3, 4) msl_compiler_error(struct msl_generator *gen gen->failed = true; } +static const struct msl_resource_type_info *msl_get_resource_type_info(enum vkd3d_shader_resource_type t) +{ + static const struct msl_resource_type_info info[] = + { + [VKD3D_SHADER_RESOURCE_NONE] = {0, false, false, "none"}, + [VKD3D_SHADER_RESOURCE_BUFFER] = {1, false, false, "_buffer"}, + [VKD3D_SHADER_RESOURCE_TEXTURE_1D] = {1, false, false, "1d"}, + [VKD3D_SHADER_RESOURCE_TEXTURE_2D] = {2, false, true, "2d"}, + [VKD3D_SHADER_RESOURCE_TEXTURE_2DMS] = {2, false, false, "2d_ms"}, + [VKD3D_SHADER_RESOURCE_TEXTURE_3D] = {3, false, true, "3d"}, + [VKD3D_SHADER_RESOURCE_TEXTURE_CUBE] = {2, false, true, "cube"}, + [VKD3D_SHADER_RESOURCE_TEXTURE_1DARRAY] = {1, true, false, "1d_array"}, + [VKD3D_SHADER_RESOURCE_TEXTURE_2DARRAY] = {2, true, true, "2d_array"}, + [VKD3D_SHADER_RESOURCE_TEXTURE_2DMSARRAY] = {2, true, false, "2d_ms_array"}, + [VKD3D_SHADER_RESOURCE_TEXTURE_CUBEARRAY] = {2, true, true, "cube_array"}, + }; + + if (!t || t >= ARRAY_SIZE(info)) + return NULL; + + return &info[t]; +} + + static const char *msl_get_prefix(enum vkd3d_shader_type type) { switch (type) @@ -83,6 +115,30 @@ static void msl_print_indent(struct vkd3d_string_buffer *buffer, unsigned int in vkd3d_string_buffer_printf(buffer, "%*s", 4 * indent, ""); } +static void msl_print_resource_datatype(struct msl_generator *gen, + struct vkd3d_string_buffer *buffer, enum vkd3d_shader_resource_data_type data_type) +{ + switch (data_type) + { + case VKD3D_SHADER_RESOURCE_DATA_FLOAT: + case VKD3D_SHADER_RESOURCE_DATA_UNORM: + case VKD3D_SHADER_RESOURCE_DATA_SNORM: + vkd3d_string_buffer_printf(buffer, "float"); + break; + case VKD3D_SHADER_RESOURCE_DATA_INT: + vkd3d_string_buffer_printf(buffer, "int"); + break; + case VKD3D_SHADER_RESOURCE_DATA_UINT: + vkd3d_string_buffer_printf(buffer, "uint"); + break; + default: + msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, + "Internal compiler error: Unhandled resource datatype %#x.", data_type); + vkd3d_string_buffer_printf(buffer, "<unrecognised resource datatype %#x>", data_type); + break; + } +} + static void msl_print_register_datatype(struct vkd3d_string_buffer *buffer, struct msl_generator *gen, enum vkd3d_data_type data_type) { @@ -106,6 +162,112 @@ static void msl_print_register_datatype(struct vkd3d_string_buffer *buffer, } } +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 const struct vkd3d_shader_descriptor_binding *msl_get_cbv_binding(const struct msl_generator *gen, + unsigned int register_space, unsigned int register_idx) +{ + const struct vkd3d_shader_interface_info *interface_info = gen->interface_info; + unsigned int i; + + if (!interface_info) + return NULL; + + for (i = 0; i < interface_info->binding_count; ++i) + { + const struct vkd3d_shader_resource_binding *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; + + return &binding->binding; + } + + return NULL; +} + +static const struct vkd3d_shader_descriptor_binding *msl_get_srv_binding(const struct msl_generator *gen, + unsigned int register_space, unsigned int register_idx, enum vkd3d_shader_resource_type resource_type) +{ + const struct vkd3d_shader_interface_info *interface_info = gen->interface_info; + enum vkd3d_shader_binding_flag resource_type_flag; + unsigned int i; + + if (!interface_info) + return NULL; + + 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) + { + const struct vkd3d_shader_resource_binding *binding = &interface_info->bindings[i]; + + if (binding->type != VKD3D_SHADER_DESCRIPTOR_TYPE_SRV) + 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 & resource_type_flag)) + continue; + + return &binding->binding; + } + + return NULL; +} + +static void msl_print_cbv_name(struct vkd3d_string_buffer *buffer, unsigned int binding) +{ + vkd3d_string_buffer_printf(buffer, "descriptors[%u].buf<vkd3d_vec4>()", binding); +} + +static void msl_print_srv_name(struct vkd3d_string_buffer *buffer, struct msl_generator *gen, + unsigned int binding, const struct msl_resource_type_info *resource_type_info, + enum vkd3d_shader_resource_data_type resource_data_type) +{ + vkd3d_string_buffer_printf(buffer, "descriptors[%u].tex<texture%s<", + binding, resource_type_info->type_suffix); + msl_print_resource_datatype(gen, buffer, resource_data_type); + vkd3d_string_buffer_printf(buffer, ">>()"); +} + static void msl_print_register_name(struct vkd3d_string_buffer *buffer, struct msl_generator *gen, const struct vkd3d_shader_register *reg) { @@ -220,23 +382,36 @@ static void msl_print_register_name(struct vkd3d_string_buffer *buffer, 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, "<unhandled register %#x>", 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, "<unhandled register %#x>", reg->type); + const struct vkd3d_shader_descriptor_binding *binding; + + 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, "<unhandled register %#x>", reg->type); + break; + } + if (reg->idx[0].rel_addr || reg->idx[1].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, "<unhandled register %#x>", reg->type); + break; + } + if (!(binding = msl_get_cbv_binding(gen, 0, reg->idx[1].offset))) + { + msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_BINDING_NOT_FOUND, + "Cannot finding binding for CBV register %u.", reg->idx[0].offset); + vkd3d_string_buffer_printf(buffer, "<unhandled register %#x>", reg->type); + break; + } + msl_print_cbv_name(buffer, binding->binding); + vkd3d_string_buffer_printf(buffer, "[%u]", reg->idx[2].offset); + msl_print_register_datatype(buffer, gen, reg->data_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, @@ -529,6 +704,96 @@ static void msl_else(struct msl_generator *gen) msl_begin_block(gen); } +static void msl_ld(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins) +{ + const struct msl_resource_type_info *resource_type_info; + enum vkd3d_shader_resource_data_type resource_data_type; + unsigned int resource_id, resource_idx, resource_space; + const struct vkd3d_shader_descriptor_info1 *descriptor; + const struct vkd3d_shader_descriptor_binding *binding; + enum vkd3d_shader_resource_type resource_type; + struct msl_src coord, array_index, lod; + struct vkd3d_string_buffer *read; + uint32_t coord_mask; + struct msl_dst dst; + + if (vkd3d_shader_instruction_has_texel_offset(ins)) + msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, + "Internal compiler error: Unhandled texel fetch offset."); + + if (ins->src[1].reg.idx[0].rel_addr || ins->src[1].reg.idx[1].rel_addr) + msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_UNSUPPORTED, + "Descriptor indexing is not supported."); + + resource_id = ins->src[1].reg.idx[0].offset; + resource_idx = ins->src[1].reg.idx[1].offset; + if ((descriptor = vkd3d_shader_find_descriptor(&gen->program->descriptors, + VKD3D_SHADER_DESCRIPTOR_TYPE_SRV, resource_id))) + { + resource_type = descriptor->resource_type; + resource_space = descriptor->register_space; + resource_data_type = descriptor->resource_data_type; + } + else + { + msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, + "Internal compiler error: Undeclared resource descriptor %u.", resource_id); + resource_space = 0; + resource_type = VKD3D_SHADER_RESOURCE_TEXTURE_2D; + resource_data_type = VKD3D_SHADER_RESOURCE_DATA_FLOAT; + } + + if ((resource_type_info = msl_get_resource_type_info(resource_type))) + { + coord_mask = vkd3d_write_mask_from_component_count(resource_type_info->read_coord_size); + } + else + { + msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL, + "Internal compiler error: Unhandled resource type %#x.", resource_type); + coord_mask = vkd3d_write_mask_from_component_count(2); + } + + if (!(binding = msl_get_srv_binding(gen, resource_space, resource_idx, resource_type))) + { + msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_BINDING_NOT_FOUND, + "Cannot finding binding for SRV register %u index %u space %u.", + resource_id, resource_idx, resource_space); + return; + } + + msl_dst_init(&dst, gen, ins, &ins->dst[0]); + msl_src_init(&coord, gen, &ins->src[0], coord_mask); + /* `coord_mask + 1` gives exactly the array index component mask if it is an array resource */ + /* Or it's simply unused, saving some branches */ + msl_src_init(&array_index, gen, &ins->src[0], coord_mask + 1); + msl_src_init(&lod, gen, &ins->src[0], VKD3DSP_WRITEMASK_3); + read = vkd3d_string_buffer_get(&gen->string_buffers); + + vkd3d_string_buffer_printf(read, "as_type<uint4>("); + msl_print_srv_name(read, gen, binding->binding, resource_type_info, resource_data_type); + vkd3d_string_buffer_printf(read, ".read("); + if (resource_type_info->read_coord_size > 1) + vkd3d_string_buffer_printf(read, "as_type<uint%zu>(%s)", + resource_type_info->read_coord_size, coord.str->buffer); + else + vkd3d_string_buffer_printf(read, "as_type<uint>(%s)", coord.str->buffer); + if (resource_type_info->array) + vkd3d_string_buffer_printf(read, ", as_type<uint>(%s)", array_index.str->buffer); + if (resource_type_info->lod) + vkd3d_string_buffer_printf(read, ", as_type<uint>(%s)", lod.str->buffer); + vkd3d_string_buffer_printf(read, "))"); + msl_print_swizzle(read, ins->src[1].swizzle, ins->dst[0].write_mask); + + msl_print_assignment(gen, &dst, "%s", read->buffer); + + vkd3d_string_buffer_release(&gen->string_buffers, read); + msl_src_cleanup(&lod, &gen->string_buffers); + msl_src_cleanup(&array_index, &gen->string_buffers); + msl_src_cleanup(&coord, &gen->string_buffers); + msl_dst_cleanup(&dst, &gen->string_buffers); +} + static void msl_unary_op(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins, const char *op) { struct msl_src src; @@ -670,6 +935,9 @@ static void msl_handle_instruction(struct msl_generator *gen, const struct vkd3d case VKD3DSIH_UTOF: msl_cast(gen, ins, "float"); break; + case VKD3DSIH_LD: + msl_ld(gen, ins); + break; case VKD3DSIH_LOG: msl_intrinsic(gen, ins, "log2"); break; @@ -715,144 +983,6 @@ 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 [[id(%u)]];", cbv->register_id, binding->binding); -}; - -static void msl_generate_descriptor_struct_declarations(struct msl_generator *gen) -{ - const struct vkd3d_shader_scan_descriptor_info1 *info = &gen->program->descriptors; - 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, "/* <unhandled descriptor type %#x> */", 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; @@ -1175,7 +1305,7 @@ static void msl_generate_entrypoint(struct msl_generator *gen) 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); + "constant descriptor *descriptors [[buffer(0)]],\n"); } msl_print_indent(gen->buffer, 2); @@ -1211,7 +1341,8 @@ static int msl_generator_generate(struct msl_generator *gen, struct vkd3d_shader MESSAGE("Generating a MSL shader. This is unsupported; you get to keep all the pieces if it breaks.\n"); vkd3d_string_buffer_printf(gen->buffer, "/* Generated by %s. */\n\n", vkd3d_shader_get_version(NULL, NULL)); - vkd3d_string_buffer_printf(gen->buffer, "#include <metal_common>\n\n"); + vkd3d_string_buffer_printf(gen->buffer, "#include <metal_common>\n"); + vkd3d_string_buffer_printf(gen->buffer, "#include <metal_texture>\n\n"); vkd3d_string_buffer_printf(gen->buffer, "using namespace metal;\n\n"); if (gen->program->global_flags) @@ -1223,7 +1354,28 @@ static int msl_generator_generate(struct msl_generator *gen, struct vkd3d_shader 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); + if (gen->program->descriptors.descriptor_count > 0) + { + vkd3d_string_buffer_printf(gen->buffer, + "struct descriptor\n" + "{\n" + " const device void *ptr;\n" + "\n" + " template<typename T>\n" + " constant T &tex() constant\n" + " {\n" + " return reinterpret_cast<constant T &>(this->ptr);\n" + " }\n" + "\n" + " template<typename T>\n" + " const device T * constant &buf() constant\n" + " {\n" + " return reinterpret_cast<const device T * constant &>(this->ptr);\n" + " }\n" + "};\n" + "\n"); + } + msl_generate_input_struct_declarations(gen); msl_generate_output_struct_declarations(gen); @@ -1234,7 +1386,7 @@ static int msl_generator_generate(struct msl_generator *gen, struct vkd3d_shader if (gen->write_depth) vkd3d_string_buffer_printf(gen->buffer, ", thread float& o_depth"); if (gen->program->descriptors.descriptor_count) - vkd3d_string_buffer_printf(gen->buffer, ", constant vkd3d_%s_descriptors& descriptors", gen->prefix); + vkd3d_string_buffer_printf(gen->buffer, ", constant descriptor *descriptors"); vkd3d_string_buffer_printf(gen->buffer, ")\n{\n"); ++gen->indent; diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 168c40bd302736f91c7a53a0e866884931f2f647..03dc0217474d327d324cf32b0a6c6de949f81559 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -262,6 +262,7 @@ enum vkd3d_shader_error VKD3D_SHADER_ERROR_MSL_INTERNAL = 10000, VKD3D_SHADER_ERROR_MSL_BINDING_NOT_FOUND = 10001, + VKD3D_SHADER_ERROR_MSL_UNSUPPORTED = 10002, VKD3D_SHADER_ERROR_FX_NOT_IMPLEMENTED = 11000, VKD3D_SHADER_ERROR_FX_INVALID_VERSION = 11001, diff --git a/tests/hlsl/cbuffer.shader_test b/tests/hlsl/cbuffer.shader_test index cdba5e2820960290db7ca07ceffcac2e727f41e0..c0caeefd9b379c892d18b35066a86855e21d20c8 100644 --- a/tests/hlsl/cbuffer.shader_test +++ b/tests/hlsl/cbuffer.shader_test @@ -619,7 +619,7 @@ float4 main() : sv_target } [test] -todo(msl) draw quad +draw quad probe (0, 0) rgba (1.0, 1.0, 1.0, 1.0) @@ -850,7 +850,7 @@ uniform 4 float4 4.0 5.0 6.0 7.0 uniform 8 float4 8.0 9.0 10.0 11.0 uniform 12 float4 12.0 13.0 14.0 15.0 uniform 16 float4 16.0 17.0 18.0 19.0 -todo(msl) draw quad +draw quad probe (0, 0) rgba (124.0, 135.0, 146.0, 150.5) [require] diff --git a/tests/hlsl/initializer-objects.shader_test b/tests/hlsl/initializer-objects.shader_test index aea171549e84d27e1b44e2d2b4220a20c5dd2ad7..6156233da2f8e01fd38156037223c27049465f63 100644 --- a/tests/hlsl/initializer-objects.shader_test +++ b/tests/hlsl/initializer-objects.shader_test @@ -25,7 +25,7 @@ float4 main() : sv_target } [test] -todo(msl) draw quad +draw quad probe (0, 0) rgba (0.2, 0.2, 0.2, 0.1) @@ -48,7 +48,7 @@ float4 main() : sv_target } [test] -todo(msl) draw quad +draw quad probe (0, 0) rgba (31.1, 41.1, 51.1, 61.1) 1 diff --git a/tests/hlsl/load-level.shader_test b/tests/hlsl/load-level.shader_test index 99a86d71d770265ca1ae05ae70f80c9223bf0d11..668fe4e3397e052e5f380b5656b8711738fd7451 100644 --- a/tests/hlsl/load-level.shader_test +++ b/tests/hlsl/load-level.shader_test @@ -22,10 +22,10 @@ float4 main() : sv_target [test] uniform 0 uint 0 -todo(msl) draw quad +draw quad probe (0, 0) rgba (1.0, 0.0, 1.0, 0.0) uniform 0 uint 1 -todo(msl) draw quad +draw quad probe (0, 0) rgba (0.0, 0.0, 1.0, 0.0) [pixel shader fail] @@ -47,5 +47,5 @@ float4 main() : sv_target } [test] -todo(msl) draw quad +draw quad probe (0, 0) rgba (1.0, 0.0, 1.0, 0.0) diff --git a/tests/hlsl/object-references.shader_test b/tests/hlsl/object-references.shader_test index 79355c7d257ca70f040c67e18e2d60c57166ede4..ef126b61102749d919996d8d10016d4dfd4f7427 100644 --- a/tests/hlsl/object-references.shader_test +++ b/tests/hlsl/object-references.shader_test @@ -111,7 +111,7 @@ float4 main() : sv_target } [test] -todo(msl) draw quad +draw quad probe (0, 0) rgba (312, 312, 312, 111) @@ -134,7 +134,7 @@ float4 main() : sv_target } [test] -todo(msl) draw quad +draw quad probe (0, 0) rgba (2132, 2132, 2132, 1111) diff --git a/tests/hlsl/register-reservations-resources.shader_test b/tests/hlsl/register-reservations-resources.shader_test index fa4968d28a0456183dc1782bceb89d8ef681d9a7..b94eee4bd81f9a8f55edde40f4a806f5a212804a 100644 --- a/tests/hlsl/register-reservations-resources.shader_test +++ b/tests/hlsl/register-reservations-resources.shader_test @@ -34,7 +34,7 @@ float4 main() : sv_target } [test] -todo(msl) draw quad +draw quad probe (0, 0) rgba (41.0, 41.0, 41.0, 1089.0) @@ -50,7 +50,7 @@ float4 main() : sv_target } [test] -todo(msl) draw quad +draw quad probe (0, 0) rgba (0.0, 0.0, 0.0, 99.0) @@ -65,7 +65,7 @@ float4 main() : sv_target } [test] -todo(msl) draw quad +draw quad probe (0, 0) rgba (1.0, 1.0, 1.0, 99.0) @@ -84,7 +84,7 @@ shader model >= 4.0 shader model < 6.0 [test] -todo(msl) draw quad +draw quad probe (0, 0) rgba (0.0, 0.0, 0.0, 99.0) [require] @@ -110,7 +110,7 @@ float4 main() : sv_target [test] -todo(msl) draw quad +draw quad probe (0, 0) rgba (0.0, 0.0, 0.0, 99.0) [pixel shader] @@ -123,7 +123,7 @@ float4 main() : sv_target } [test] -todo(msl) draw quad +draw quad probe (0, 0) rgba (4.0, 4.0, 4.0, 99.0) @@ -139,7 +139,7 @@ float4 main() : sv_target } [test] -todo(msl) draw quad +draw quad probe (0, 0) rgba (1.0, 1.0, 1.0, 99.0) @@ -154,7 +154,7 @@ float4 main() : sv_target } [test] -todo(msl) draw quad +draw quad probe (0, 0) rgba (2.0, 2.0, 2.0, 99.0) @@ -168,7 +168,7 @@ float4 main() : sv_target } [test] -todo(msl) draw quad +draw quad probe (0, 0) rgba (2.0, 2.0, 2.0, 99.0) @@ -241,5 +241,5 @@ float4 main() : sv_target } [test] -todo(msl) draw quad +draw quad probe (0, 0) rgba (1.0, 1.0, 1.0, 99.0) diff --git a/tests/hlsl/texture-load-typed.shader_test b/tests/hlsl/texture-load-typed.shader_test index d08783944e9069ddfa4b33d4faccdf6af442faa6..8ca4a915edc81b8ea562893ca36e13a245ee9395 100644 --- a/tests/hlsl/texture-load-typed.shader_test +++ b/tests/hlsl/texture-load-typed.shader_test @@ -48,7 +48,7 @@ float4 main() : sv_target } [test] -todo(msl) draw quad +draw quad probe (0, 0) rgba (0.8, -3.0, 4294967295.0, 123.0) % lowercase 'texture2D' @@ -65,7 +65,7 @@ float4 main() : sv_target } [test] -todo(msl) draw quad +draw quad probe (0, 0) rgba (0.8, -3.0, 4294967295.0, 123.0) [require] diff --git a/tests/shader_runner_metal.m b/tests/shader_runner_metal.m index 8b0f646d1a17f31217667f765da851bc16921aa1..92175eab6efcc5e736bce11264d0605de57d80c3 100644 --- a/tests/shader_runner_metal.m +++ b/tests/shader_runner_metal.m @@ -27,7 +27,6 @@ #undef BOOL static const MTLResourceOptions DEFAULT_BUFFER_RESOURCE_OPTIONS = MTLResourceCPUCacheModeDefaultCache - | MTLResourceStorageModeShared | MTLResourceHazardTrackingModeDefault; struct metal_resource @@ -66,8 +65,13 @@ static MTLPixelFormat get_metal_pixel_format(DXGI_FORMAT format) return MTLPixelFormatRGBA32Uint; case DXGI_FORMAT_R32G32B32A32_SINT: return MTLPixelFormatRGBA32Sint; + case DXGI_FORMAT_R32G32_UINT: + return MTLPixelFormatRG32Uint; case DXGI_FORMAT_R32_FLOAT: return MTLPixelFormatR32Float; + case DXGI_FORMAT_R32_SINT: + return MTLPixelFormatR32Sint; + case DXGI_FORMAT_R32_TYPELESS: case DXGI_FORMAT_R32_UINT: return MTLPixelFormatR32Uint; case DXGI_FORMAT_D32_FLOAT: @@ -164,12 +168,29 @@ static void init_resource_buffer(struct metal_runner *runner, { id<MTLDevice> device = runner->device; + resource->buffer = [device newBufferWithLength:params->data_size + options:DEFAULT_BUFFER_RESOURCE_OPTIONS | MTLResourceStorageModePrivate]; + if (params->data) - resource->buffer = [device newBufferWithBytes:params->data + { + id<MTLCommandBuffer> command_buffer; + id<MTLBlitCommandEncoder> blit; + id<MTLBuffer> upload_buffer; + + upload_buffer = [[device newBufferWithBytes:params->data length:params->data_size - options:DEFAULT_BUFFER_RESOURCE_OPTIONS]; - else - resource->buffer = [device newBufferWithLength:params->data_size options:DEFAULT_BUFFER_RESOURCE_OPTIONS]; + options:DEFAULT_BUFFER_RESOURCE_OPTIONS | MTLResourceStorageModeManaged] autorelease]; + + command_buffer = [runner->queue commandBuffer]; + + blit = [command_buffer blitCommandEncoder]; + [blit copyFromBuffer:upload_buffer sourceOffset:0 toBuffer:resource->buffer + destinationOffset:0 size:params->data_size]; + [blit endEncoding]; + + [command_buffer commit]; + [command_buffer waitUntilCompleted]; + } } static void init_resource_texture(struct metal_runner *runner, @@ -178,8 +199,17 @@ static void init_resource_texture(struct metal_runner *runner, id<MTLDevice> device = runner->device; MTLTextureDescriptor *desc; - if (params->desc.type != RESOURCE_TYPE_RENDER_TARGET && params->desc.type != RESOURCE_TYPE_DEPTH_STENCIL) - return; + switch (params->desc.type) + { + case RESOURCE_TYPE_RENDER_TARGET: + case RESOURCE_TYPE_DEPTH_STENCIL: + case RESOURCE_TYPE_TEXTURE: + break; + + case RESOURCE_TYPE_UAV: + case RESOURCE_TYPE_VERTEX_BUFFER: + return; + } if (params->desc.sample_count > 1) { @@ -194,14 +224,12 @@ static void init_resource_texture(struct metal_runner *runner, } } - if (params->data) - fatal_error("Initial texture resource data not implemented.\n"); - desc = [[MTLTextureDescriptor alloc] init]; if (params->desc.sample_count > 1) - desc.textureType = MTLTextureType2DMultisample; - else if (params->desc.depth > 1) - desc.textureType = MTLTextureType2DArray; + desc.textureType = params->desc.depth > 1 ? MTLTextureType2DMultisampleArray + : MTLTextureType2DMultisample; + else + desc.textureType = params->desc.depth > 1 ? MTLTextureType2DArray : MTLTextureType2D; desc.pixelFormat = get_metal_pixel_format(params->desc.format); ok(desc.pixelFormat != MTLPixelFormatInvalid, "Unhandled pixel format %#x.\n", params->desc.format); desc.width = params->desc.width; @@ -210,10 +238,64 @@ static void init_resource_texture(struct metal_runner *runner, desc.mipmapLevelCount = params->desc.level_count; desc.sampleCount = max(params->desc.sample_count, 1); desc.storageMode = MTLStorageModePrivate; - desc.usage = MTLTextureUsageRenderTarget; + + switch (params->desc.type) + { + case RESOURCE_TYPE_RENDER_TARGET: + case RESOURCE_TYPE_DEPTH_STENCIL: + desc.usage = MTLTextureUsageRenderTarget; + break; + + case RESOURCE_TYPE_TEXTURE: + desc.usage = MTLTextureUsageShaderRead; + break; + + case RESOURCE_TYPE_UAV: + case RESOURCE_TYPE_VERTEX_BUFFER: + break; + } resource->texture = [device newTextureWithDescriptor:desc]; ok(resource->texture, "Failed to create texture.\n"); + + if (params->data) + { + unsigned int buffer_offset = 0, level, level_width, level_height; + id<MTLCommandBuffer> command_buffer; + id<MTLBlitCommandEncoder> blit; + id<MTLTexture> upload_texture; + + if (params->desc.sample_count > 1) + fatal_error("Cannot upload data to a multisampled texture.\n"); + if (params->desc.depth > 1) + fatal_error("Uploading data to a texture array is not supported.\n"); + + desc.storageMode = MTLStorageModeManaged; + upload_texture = [[device newTextureWithDescriptor:desc] autorelease]; + + for (level = 0; level < params->desc.level_count; ++level) + { + level_width = get_level_dimension(params->desc.width, level); + level_height = get_level_dimension(params->desc.height, level); + [upload_texture replaceRegion:MTLRegionMake2D(0, 0, level_width, level_height) + mipmapLevel:level + slice:0 + withBytes:¶ms->data[buffer_offset] + bytesPerRow:level_width * params->desc.texel_size + bytesPerImage:level_height * level_width * params->desc.texel_size]; + buffer_offset += level_height * level_width * params->desc.texel_size; + } + + command_buffer = [runner->queue commandBuffer]; + + blit = [command_buffer blitCommandEncoder]; + [blit copyFromTexture:upload_texture toTexture:resource->texture]; + [blit endEncoding]; + + [command_buffer commit]; + [command_buffer waitUntilCompleted]; + } + [desc release]; } @@ -246,9 +328,9 @@ static bool compile_shader(struct metal_runner *runner, enum shader_type type, s { struct vkd3d_shader_interface_info interface_info = {.type = VKD3D_SHADER_STRUCTURE_TYPE_INTERFACE_INFO}; struct vkd3d_shader_compile_info info = {.type = VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO}; - struct vkd3d_shader_resource_binding bindings[MAX_RESOURCES + MAX_SAMPLERS]; + struct vkd3d_shader_resource_binding bindings[MAX_RESOURCES + MAX_SAMPLERS + 1 /* CBV */]; struct vkd3d_shader_resource_binding *binding; - unsigned int descriptor_binding = 0; + unsigned int i; char *messages; int ret; @@ -272,15 +354,47 @@ static bool compile_shader(struct metal_runner *runner, enum shader_type type, s if (runner->r.uniform_count) { - binding = &bindings[interface_info.binding_count++]; + binding = &bindings[interface_info.binding_count]; binding->type = VKD3D_SHADER_DESCRIPTOR_TYPE_CBV; binding->register_space = 0; binding->register_index = 0; binding->shader_visibility = VKD3D_SHADER_VISIBILITY_ALL; binding->flags = VKD3D_SHADER_BINDING_FLAG_BUFFER; binding->binding.set = 0; - binding->binding.binding = descriptor_binding++; + binding->binding.binding = interface_info.binding_count; binding->binding.count = 1; + ++interface_info.binding_count; + } + + for (i = 0; i < runner->r.resource_count; ++i) + { + const struct metal_resource *resource = metal_resource(runner->r.resources[i]); + + switch (resource->r.desc.type) + { + case RESOURCE_TYPE_TEXTURE: + binding = &bindings[interface_info.binding_count]; + binding->type = VKD3D_SHADER_DESCRIPTOR_TYPE_SRV; + binding->register_space = 0; + binding->register_index = resource->r.desc.slot; + binding->shader_visibility = VKD3D_SHADER_VISIBILITY_ALL; + if (resource->r.desc.dimension == RESOURCE_DIMENSION_BUFFER) + binding->flags = VKD3D_SHADER_BINDING_FLAG_BUFFER; + else + binding->flags = VKD3D_SHADER_BINDING_FLAG_IMAGE; + binding->binding.set = 0; + binding->binding.binding = interface_info.binding_count; + binding->binding.count = 1; + ++interface_info.binding_count; + break; + + case RESOURCE_TYPE_RENDER_TARGET: + case RESOURCE_TYPE_DEPTH_STENCIL: + case RESOURCE_TYPE_UAV: + case RESOURCE_TYPE_VERTEX_BUFFER: + break; + + } } interface_info.bindings = bindings; @@ -318,6 +432,105 @@ static id<MTLFunction> compile_stage(struct metal_runner *runner, enum shader_ty return [function autorelease]; } +static bool encode_argument_buffer(struct metal_runner *runner, + id<MTLRenderCommandEncoder> command_encoder) +{ + NSMutableArray<MTLArgumentDescriptor *> *argument_descriptors; + id<MTLDevice> device = runner->device; + MTLArgumentDescriptor *arg_desc; + id<MTLArgumentEncoder> encoder; + id<MTLBuffer> argument_buffer; + unsigned int i, index = 0; + + argument_descriptors = [[[NSMutableArray alloc] init] autorelease]; + + if (runner->r.uniform_count) + { + arg_desc = [MTLArgumentDescriptor argumentDescriptor]; + arg_desc.dataType = MTLDataTypePointer; + arg_desc.index = 0; + arg_desc.access = MTLBindingAccessReadOnly; + [argument_descriptors addObject:arg_desc]; + } + + for (i = 0; i < runner->r.resource_count; ++i) + { + struct metal_resource *resource = metal_resource(runner->r.resources[i]); + + switch (resource->r.desc.type) + { + case RESOURCE_TYPE_TEXTURE: + arg_desc = [MTLArgumentDescriptor argumentDescriptor]; + arg_desc.dataType = MTLDataTypeTexture; + arg_desc.index = [argument_descriptors count]; + arg_desc.access = MTLBindingAccessReadOnly; + arg_desc.textureType = [resource->texture textureType]; + [argument_descriptors addObject:arg_desc]; + break; + + case RESOURCE_TYPE_RENDER_TARGET: + case RESOURCE_TYPE_DEPTH_STENCIL: + case RESOURCE_TYPE_UAV: + case RESOURCE_TYPE_VERTEX_BUFFER: + break; + } + } + + if (![argument_descriptors count]) + return true; + + encoder = [[device newArgumentEncoderWithArguments:argument_descriptors] autorelease]; + argument_buffer = [[device newBufferWithLength:encoder.encodedLength + options:DEFAULT_BUFFER_RESOURCE_OPTIONS | MTLResourceStorageModeManaged] autorelease]; + [encoder setArgumentBuffer:argument_buffer offset:0]; + + if (runner->r.uniform_count) + { + id<MTLBuffer> cb; + + cb = [[device newBufferWithBytes:runner->r.uniforms + length:runner->r.uniform_count * sizeof(*runner->r.uniforms) + options:DEFAULT_BUFFER_RESOURCE_OPTIONS | MTLResourceStorageModeManaged] autorelease]; + [encoder setBuffer:cb offset:0 atIndex:index++]; + [command_encoder useResource:cb + usage:MTLResourceUsageRead + stages:MTLRenderStageVertex | MTLRenderStageFragment]; + } + + for (i = 0; i < runner->r.resource_count; ++i) + { + struct metal_resource *resource = metal_resource(runner->r.resources[i]); + + switch (resource->r.desc.type) + { + case RESOURCE_TYPE_TEXTURE: + [encoder setTexture:resource->texture atIndex:index++]; + if (!resource->texture) + { + trace("Unsupported buffer texture\n"); + return false; + } + [command_encoder useResource:resource->texture + usage:MTLResourceUsageRead + stages:MTLRenderStageVertex | MTLRenderStageFragment]; + break; + + case RESOURCE_TYPE_RENDER_TARGET: + case RESOURCE_TYPE_DEPTH_STENCIL: + case RESOURCE_TYPE_UAV: + case RESOURCE_TYPE_VERTEX_BUFFER: + break; + } + } + + [argument_buffer didModifyRange:NSMakeRange(0, encoder.encodedLength)]; + + [command_encoder setVertexBuffer:argument_buffer offset:0 atIndex:0]; + [command_encoder setFragmentBuffer:argument_buffer offset:0 atIndex:0]; + + return true; +} + static bool metal_runner_dispatch(struct shader_runner *r, unsigned int x, unsigned int y, unsigned int z) { return false; @@ -379,13 +592,9 @@ static bool metal_runner_draw(struct shader_runner *r, D3D_PRIMITIVE_TOPOLOGY to id<MTLCommandBuffer> command_buffer; MTLDepthStencilDescriptor *ds_desc; MTLRenderPassDescriptor *pass_desc; - id<MTLArgumentEncoder> descriptors; MTLVertexDescriptor *vertex_desc; struct metal_resource *resource; - MTLArgumentDescriptor *cbv_desc; id<MTLRenderPipelineState> pso; - id<MTLBuffer> argument_buffer; - id<MTLBuffer> cb; bool ret = false; NSError *err; @@ -481,26 +690,11 @@ static bool metal_runner_draw(struct shader_runner *r, D3D_PRIMITIVE_TOPOLOGY to command_buffer = [runner->queue commandBuffer]; encoder = [command_buffer renderCommandEncoderWithDescriptor:pass_desc]; - if (r->uniform_count) + if (!encode_argument_buffer(runner, encoder)) { - cb = [[device newBufferWithBytes:r->uniforms - length:runner->r.uniform_count * sizeof(*runner->r.uniforms) - options:DEFAULT_BUFFER_RESOURCE_OPTIONS] autorelease]; - - cbv_desc = [MTLArgumentDescriptor argumentDescriptor]; - cbv_desc.dataType = MTLDataTypePointer; - cbv_desc.index = 0; - cbv_desc.access = MTLBindingAccessReadOnly; - - descriptors = [[device newArgumentEncoderWithArguments:@[cbv_desc]] autorelease]; - argument_buffer = [[device newBufferWithLength:descriptors.encodedLength - options:DEFAULT_BUFFER_RESOURCE_OPTIONS] autorelease]; - [descriptors setArgumentBuffer:argument_buffer offset:0]; - [descriptors setBuffer:cb offset:0 atIndex:0]; - - [encoder setVertexBuffer:argument_buffer offset:0 atIndex:0]; - [encoder setFragmentBuffer:argument_buffer offset:0 atIndex:0]; - [encoder useResource:cb usage:MTLResourceUsageRead stages:MTLRenderStageVertex | MTLRenderStageFragment]; + [encoder endEncoding]; + ret = false; + goto done; } if (runner->r.input_element_count > 32) @@ -596,7 +790,7 @@ static struct resource_readback *metal_runner_get_resource_readback(struct shade rb->rb.depth = 1; rb->rb.row_pitch = rb->rb.width * resource->r.desc.texel_size; rb->buffer = [runner->device newBufferWithLength:rb->rb.row_pitch * rb->rb.height - options:DEFAULT_BUFFER_RESOURCE_OPTIONS]; + options:DEFAULT_BUFFER_RESOURCE_OPTIONS | MTLResourceStorageModeManaged]; level = sub_resource_idx % resource->r.desc.level_count; layer = sub_resource_idx / resource->r.desc.level_count; @@ -615,6 +809,7 @@ static struct resource_readback *metal_runner_get_resource_readback(struct shade destinationOffset:0 destinationBytesPerRow:rb->rb.row_pitch destinationBytesPerImage:0]; + [blit synchronizeResource:rb->buffer]; [blit endEncoding]; [command_buffer commit];