Skip to content
Snippets Groups Projects

tests/shader_runner_metal: Implement texture support.

Closed Feifan He requested to merge Feifan/vkd3d:msl-texture-sampler into master
4 unresolved threads
Files
10
+ 219
6
@@ -47,6 +47,22 @@ struct msl_generator
const struct vkd3d_shader_scan_descriptor_info1 *descriptor_info;
};
struct msl_resource_type_info
{
/* The number of coordinates needed to sample the resource type. */
size_t sample_coord_size;
/* The number of coordinates needed to read the resource type. */
size_t read_coord_size;
/* Whether the resource type is an array type. */
bool array;
/* Whether the resource type is a cube type. */
bool cube;
/* Whether the resource type supports lod. */
bool lod;
/* The type suffix for resource type. I.e., the "2d" part of "texture2d" */
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, ...)
{
@@ -58,6 +74,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[] =
{
{0, 0, 0, 0, 0, "none"}, /* VKD3D_SHADER_RESOURCE_NONE */
{1, 1, 0, 0, 0, "_buffer"}, /* VKD3D_SHADER_RESOURCE_BUFFER */
{1, 1, 0, 0, 0, "1d"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_1D */
{2, 2, 0, 0, 1, "2d"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_2D */
{2, 2, 0, 0, 0, "2d_ms"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_2DMS */
{3, 3, 0, 0, 1, "3d"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_3D */
{3, 2, 0, 1, 1, "cube"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_CUBE */
{1, 1, 1, 0, 0, "1d_array"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_1DARRAY */
{2, 2, 1, 0, 1, "2d_array"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_2DARRAY */
{2, 2, 1, 0, 0, "2d_ms_array"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_2DMSARRAY */
{3, 2, 1, 1, 1, "cube_array"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_CUBEARRAY */
};
if (!t || t >= ARRAY_SIZE(info))
return NULL;
return &info[t];
}
static const char *msl_get_prefix(enum vkd3d_shader_type type)
{
switch (type)
@@ -79,11 +119,51 @@ static const char *msl_get_prefix(enum vkd3d_shader_type type)
}
}
static const struct vkd3d_shader_descriptor_info1 *msl_get_descriptor_by_id(
struct msl_generator *gen, enum vkd3d_shader_descriptor_type type, unsigned int id)
{
const struct vkd3d_shader_scan_descriptor_info1 *info = gen->descriptor_info;
for (unsigned int i = 0; i < info->descriptor_count; ++i)
{
const struct vkd3d_shader_descriptor_info1 *d = &info->descriptors[i];
if (d->type == type && d->register_id == id)
return d;
}
return NULL;
}
static void msl_print_indent(struct vkd3d_string_buffer *buffer, unsigned int indent)
{
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)
{
@@ -531,6 +611,80 @@ 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;
unsigned int resource_id, resource_idx, resource_space;
const struct vkd3d_shader_descriptor_info1 *d;
enum vkd3d_shader_resource_type resource_type;
struct msl_src coord, array_index, lod;
struct vkd3d_string_buffer *fetch;
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 ((d = msl_get_descriptor_by_id(gen, VKD3D_SHADER_DESCRIPTOR_TYPE_SRV, resource_id)))
{
resource_type = d->resource_type;
resource_space = d->register_space;
}
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;
}
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);
}
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);
fetch = vkd3d_string_buffer_get(&gen->string_buffers);
vkd3d_string_buffer_printf(fetch, "as_type<uint4>(descriptors.srv_%u.read(", resource_id);
if (resource_type_info->read_coord_size > 1)
vkd3d_string_buffer_printf(fetch, "as_type<uint%zu>(%s)", resource_type_info->read_coord_size, coord.str->buffer);
else
vkd3d_string_buffer_printf(fetch, "as_type<uint>(%s)", coord.str->buffer);
if (resource_type_info->array)
vkd3d_string_buffer_printf(fetch, ", as_type<uint>(%s)", array_index.str->buffer);
if (resource_type_info->lod)
vkd3d_string_buffer_printf(fetch, ", as_type<uint>(%s)", lod.str->buffer);
vkd3d_string_buffer_printf(fetch, "))");
msl_print_swizzle(fetch, ins->src[1].swizzle, ins->dst[0].write_mask);
msl_print_assignment(gen, &dst, "%s", fetch->buffer);
vkd3d_string_buffer_release(&gen->string_buffers, fetch);
msl_src_cleanup(&lod, &gen->string_buffers);
msl_src_cleanup(&coord, &gen->string_buffers);
msl_src_cleanup(&array_index, &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;
@@ -671,6 +825,9 @@ static void msl_handle_instruction(struct msl_generator *gen, const struct vkd3d
case VKD3DSIH_ITOF:
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");
@@ -744,8 +901,9 @@ static bool msl_check_shader_visibility(const struct msl_generator *gen,
}
}
static bool msl_get_cbv_binding(const struct msl_generator *gen,
unsigned int register_space, unsigned int register_idx, unsigned int *binding_idx)
static bool msl_get_descriptor_binding(const struct msl_generator *gen, enum vkd3d_shader_descriptor_type type,
enum vkd3d_shader_binding_flag flags, 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;
@@ -758,7 +916,7 @@ static bool msl_get_cbv_binding(const struct msl_generator *gen,
{
binding = &interface_info->bindings[i];
if (binding->type != VKD3D_SHADER_DESCRIPTOR_TYPE_CBV)
if (binding->type != type)
continue;
if (binding->register_space != register_space)
continue;
@@ -766,7 +924,7 @@ static bool msl_get_cbv_binding(const struct msl_generator *gen,
continue;
if (!msl_check_shader_visibility(gen, binding->shader_visibility))
continue;
if (!(binding->flags & VKD3D_SHADER_BINDING_FLAG_BUFFER))
if ((binding->flags & flags) != flags)
continue;
*binding_idx = i;
return true;
@@ -790,7 +948,8 @@ static void msl_generate_cbv_declaration(struct msl_generator *gen,
return;
}
if (!msl_get_cbv_binding(gen, cbv->register_space, cbv->register_index, &binding_idx))
if (!msl_get_descriptor_binding(gen, VKD3D_SHADER_DESCRIPTOR_TYPE_CBV, VKD3D_SHADER_BINDING_FLAG_BUFFER,
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);
@@ -820,6 +979,56 @@ static void msl_generate_cbv_declaration(struct msl_generator *gen,
"constant vkd3d_vec4 *cb_%u [[id(%u)]];", cbv->register_id, binding->binding);
};
static void msl_generate_srv_declaration(struct msl_generator *gen,
const struct vkd3d_shader_descriptor_info1 *srv)
{
const struct msl_resource_type_info *resource_type_info;
const struct vkd3d_shader_descriptor_binding *binding;
struct vkd3d_string_buffer *buffer = gen->buffer;
unsigned int binding_idx;
if (srv->count != 1)
{
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_BINDING_NOT_FOUND,
"SRV %u has unsupported descriptor array size %u.", srv->register_id, srv->count);
return;
}
if (!msl_get_descriptor_binding(gen, VKD3D_SHADER_DESCRIPTOR_TYPE_SRV, VKD3D_SHADER_BINDING_FLAG_IMAGE,
srv->register_space, srv->register_index, &binding_idx))
{
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_BINDING_NOT_FOUND,
"No descriptor binding specified for SRV %u.", srv->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 SRV %u.", binding->set, srv->register_id);
return;
}
if (binding->count != 1)
{
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_BINDING_NOT_FOUND,
"Unsupported binding count %u specified for SRV %u.", binding->count, srv->register_id);
return;
}
if (!(resource_type_info = msl_get_resource_type_info(srv->resource_type))) {
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
"Internal compiler error: Unhandled resource type %#x.", srv->resource_type);
return;
}
vkd3d_string_buffer_printf(buffer, "texture%s<", resource_type_info->type_suffix);
msl_print_resource_datatype(gen, buffer, srv->resource_data_type);
vkd3d_string_buffer_printf(buffer, ", access::read> srv_%u [[id(%u)]];", srv->register_id, binding->binding);
};
static void msl_generate_descriptor_struct_declarations(struct msl_generator *gen)
{
const struct vkd3d_shader_scan_descriptor_info1 *info = gen->descriptor_info;
@@ -842,6 +1051,9 @@ static void msl_generate_descriptor_struct_declarations(struct msl_generator *ge
case VKD3D_SHADER_DESCRIPTOR_TYPE_CBV:
msl_generate_cbv_declaration(gen, descriptor);
break;
case VKD3D_SHADER_DESCRIPTOR_TYPE_SRV:
msl_generate_srv_declaration(gen, descriptor);
break;
default:
vkd3d_string_buffer_printf(buffer, "/* <unhandled descriptor type %#x> */", descriptor->type);
@@ -1213,7 +1425,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)
Loading