2024-08-27 10:34:57 +08:00
|
|
|
/*
|
|
|
|
* Copyright 2024 Feifan He for CodeWeavers
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "vkd3d_shader_private.h"
|
|
|
|
|
2025-04-28 15:20:52 +02:00
|
|
|
enum msl_data_type
|
|
|
|
{
|
|
|
|
MSL_DATA_FLOAT,
|
|
|
|
MSL_DATA_UINT,
|
|
|
|
MSL_DATA_UNION,
|
|
|
|
};
|
|
|
|
|
2024-09-17 20:50:44 +08:00
|
|
|
struct msl_src
|
|
|
|
{
|
|
|
|
struct vkd3d_string_buffer *str;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct msl_dst
|
|
|
|
{
|
|
|
|
const struct vkd3d_shader_dst_param *vsir;
|
|
|
|
struct vkd3d_string_buffer *register_name;
|
|
|
|
struct vkd3d_string_buffer *mask;
|
|
|
|
};
|
|
|
|
|
2024-08-29 01:21:22 +08:00
|
|
|
struct msl_generator
|
2024-08-27 10:34:57 +08:00
|
|
|
{
|
2024-08-29 01:21:22 +08:00
|
|
|
struct vsir_program *program;
|
|
|
|
struct vkd3d_string_buffer_cache string_buffers;
|
|
|
|
struct vkd3d_string_buffer *buffer;
|
|
|
|
struct vkd3d_shader_location location;
|
|
|
|
struct vkd3d_shader_message_context *message_context;
|
2024-09-16 18:35:55 +08:00
|
|
|
unsigned int indent;
|
2024-09-30 10:58:02 +08:00
|
|
|
const char *prefix;
|
2024-10-20 21:25:10 +08:00
|
|
|
bool failed;
|
|
|
|
|
2024-11-22 15:45:54 +08:00
|
|
|
bool write_depth;
|
|
|
|
|
2024-10-09 16:36:06 +08:00
|
|
|
const struct vkd3d_shader_interface_info *interface_info;
|
2024-08-29 01:21:22 +08:00
|
|
|
};
|
|
|
|
|
2024-12-12 15:02:51 +08:00
|
|
|
struct msl_resource_type_info
|
|
|
|
{
|
|
|
|
size_t read_coord_size;
|
|
|
|
bool array;
|
|
|
|
bool lod;
|
|
|
|
const char *type_suffix;
|
|
|
|
};
|
|
|
|
|
2024-08-29 01:21:22 +08:00
|
|
|
static void VKD3D_PRINTF_FUNC(3, 4) msl_compiler_error(struct msl_generator *gen,
|
|
|
|
enum vkd3d_shader_error error, const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
va_start(args, fmt);
|
|
|
|
vkd3d_shader_verror(gen->message_context, &gen->location, error, fmt, args);
|
|
|
|
va_end(args);
|
2024-10-20 21:25:10 +08:00
|
|
|
gen->failed = true;
|
2024-08-29 01:21:22 +08:00
|
|
|
}
|
|
|
|
|
2024-12-12 15:02:51 +08:00
|
|
|
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];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-09-30 10:58:02 +08:00
|
|
|
static const char *msl_get_prefix(enum vkd3d_shader_type type)
|
|
|
|
{
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case VKD3D_SHADER_TYPE_VERTEX:
|
|
|
|
return "vs";
|
|
|
|
case VKD3D_SHADER_TYPE_HULL:
|
|
|
|
return "hs";
|
|
|
|
case VKD3D_SHADER_TYPE_DOMAIN:
|
|
|
|
return "ds";
|
|
|
|
case VKD3D_SHADER_TYPE_GEOMETRY:
|
|
|
|
return "gs";
|
|
|
|
case VKD3D_SHADER_TYPE_PIXEL:
|
|
|
|
return "ps";
|
|
|
|
case VKD3D_SHADER_TYPE_COMPUTE:
|
|
|
|
return "cs";
|
|
|
|
default:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-16 18:35:55 +08:00
|
|
|
static void msl_print_indent(struct vkd3d_string_buffer *buffer, unsigned int indent)
|
|
|
|
{
|
|
|
|
vkd3d_string_buffer_printf(buffer, "%*s", 4 * indent, "");
|
|
|
|
}
|
|
|
|
|
2024-12-12 15:02:51 +08:00
|
|
|
static void msl_print_resource_datatype(struct msl_generator *gen,
|
2025-04-03 22:46:57 +02:00
|
|
|
struct vkd3d_string_buffer *buffer, enum vkd3d_data_type data_type)
|
2024-12-12 15:02:51 +08:00
|
|
|
{
|
|
|
|
switch (data_type)
|
|
|
|
{
|
2025-04-03 22:46:57 +02:00
|
|
|
case VKD3D_DATA_FLOAT:
|
|
|
|
case VKD3D_DATA_UNORM:
|
|
|
|
case VKD3D_DATA_SNORM:
|
2024-12-12 15:02:51 +08:00
|
|
|
vkd3d_string_buffer_printf(buffer, "float");
|
|
|
|
break;
|
2025-04-03 22:46:57 +02:00
|
|
|
case VKD3D_DATA_INT:
|
2024-12-12 15:02:51 +08:00
|
|
|
vkd3d_string_buffer_printf(buffer, "int");
|
|
|
|
break;
|
2025-04-03 22:46:57 +02:00
|
|
|
case VKD3D_DATA_UINT:
|
2024-12-12 15:02:51 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-24 02:53:23 +08:00
|
|
|
static void msl_print_register_datatype(struct vkd3d_string_buffer *buffer,
|
2024-09-30 11:51:26 +08:00
|
|
|
struct msl_generator *gen, enum vkd3d_data_type data_type)
|
2024-09-24 02:53:23 +08:00
|
|
|
{
|
|
|
|
vkd3d_string_buffer_printf(buffer, ".");
|
2024-09-30 11:51:26 +08:00
|
|
|
switch (data_type)
|
2024-09-24 02:53:23 +08:00
|
|
|
{
|
|
|
|
case VKD3D_DATA_FLOAT:
|
|
|
|
vkd3d_string_buffer_printf(buffer, "f");
|
|
|
|
break;
|
|
|
|
case VKD3D_DATA_INT:
|
|
|
|
vkd3d_string_buffer_printf(buffer, "i");
|
|
|
|
break;
|
|
|
|
case VKD3D_DATA_UINT:
|
|
|
|
vkd3d_string_buffer_printf(buffer, "u");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
2024-09-30 11:51:26 +08:00
|
|
|
"Internal compiler error: Unhandled register datatype %#x.", data_type);
|
|
|
|
vkd3d_string_buffer_printf(buffer, "<unrecognised register datatype %#x>", data_type);
|
2024-09-24 02:53:23 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
vkd3d-shader/msl: Access descriptors with a type-erased array.
Currently a descriptor set is represented with a structure
whose fields are the various descriptors that the shader is
going to use, each of them qualified with its type. This model
doesn't match very well what happens with D3D12 and with Vulkan
and descriptor indexing and mutable descriptors, where many
descriptor of different types can overlap, and only at shader
runtime it is decided which of them must be used.
Therefore with this patch a descriptor is represented as a
structure whose fields carry no intrinsic typing information,
but are reinterpreted according to the shader behavior on
each access. For the moment there is just one field, but more
will be added to account for fancier descriptor types and
to workaround Metal limitations.
When completed, this design will be similar in spirit to what
the Metal shader converter does, with little technical
differences.
This choice has a couple of drawbacks:
1. shader debugging with Xcode is less comfortable, because
the shader doesn't carry static descriptor typing
information and Xcode is therefore less able to provide
useful context;
2. it requires tier 2 argument buffer support and macOS
version >= 13, which includes guarantees on the runtime
layout for descriptors.
Supporting descriptor indexing and mutable descriptors is
considered to be worthy of those drawbacks, though, is
effectively required by many applications and appears to be
the first goal we should aim for. If needed, in the future
we might also add support for older hardware, at least for
shaders that do not make use of advanced features.
2025-03-11 21:53:10 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2024-12-12 15:02:51 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
vkd3d-shader/msl: Access descriptors with a type-erased array.
Currently a descriptor set is represented with a structure
whose fields are the various descriptors that the shader is
going to use, each of them qualified with its type. This model
doesn't match very well what happens with D3D12 and with Vulkan
and descriptor indexing and mutable descriptors, where many
descriptor of different types can overlap, and only at shader
runtime it is decided which of them must be used.
Therefore with this patch a descriptor is represented as a
structure whose fields carry no intrinsic typing information,
but are reinterpreted according to the shader behavior on
each access. For the moment there is just one field, but more
will be added to account for fancier descriptor types and
to workaround Metal limitations.
When completed, this design will be similar in spirit to what
the Metal shader converter does, with little technical
differences.
This choice has a couple of drawbacks:
1. shader debugging with Xcode is less comfortable, because
the shader doesn't carry static descriptor typing
information and Xcode is therefore less able to provide
useful context;
2. it requires tier 2 argument buffer support and macOS
version >= 13, which includes guarantees on the runtime
layout for descriptors.
Supporting descriptor indexing and mutable descriptors is
considered to be worthy of those drawbacks, though, is
effectively required by many applications and appears to be
the first goal we should aim for. If needed, in the future
we might also add support for older hardware, at least for
shaders that do not make use of advanced features.
2025-03-11 21:53:10 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2025-04-03 22:46:57 +02:00
|
|
|
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_data_type resource_data_type)
|
2024-12-12 15:02:51 +08:00
|
|
|
{
|
|
|
|
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, ">>()");
|
|
|
|
}
|
|
|
|
|
2025-04-28 15:20:52 +02:00
|
|
|
static enum msl_data_type msl_print_register_name(struct vkd3d_string_buffer *buffer,
|
2024-09-17 20:50:44 +08:00
|
|
|
struct msl_generator *gen, const struct vkd3d_shader_register *reg)
|
|
|
|
{
|
2024-09-24 02:53:23 +08:00
|
|
|
switch (reg->type)
|
|
|
|
{
|
|
|
|
case VKD3DSPR_TEMP:
|
|
|
|
vkd3d_string_buffer_printf(buffer, "r[%u]", reg->idx[0].offset);
|
2025-04-28 15:20:52 +02:00
|
|
|
return MSL_DATA_UNION;
|
2024-10-09 16:41:52 +08:00
|
|
|
|
2024-10-09 16:45:05 +08:00
|
|
|
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, "<unhandled register %#x>", reg->type);
|
2025-04-28 15:20:52 +02:00
|
|
|
return MSL_DATA_UNION;
|
2024-10-09 16:45:05 +08:00
|
|
|
}
|
|
|
|
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, "<unhandled register %#x>", reg->type);
|
2025-04-28 15:20:52 +02:00
|
|
|
return MSL_DATA_UNION;
|
2024-10-09 16:45:05 +08:00
|
|
|
}
|
|
|
|
vkd3d_string_buffer_printf(buffer, "v[%u]", reg->idx[0].offset);
|
2025-04-28 15:20:52 +02:00
|
|
|
return MSL_DATA_UNION;
|
2024-10-09 16:45:05 +08:00
|
|
|
|
2024-10-09 16:45:31 +08:00
|
|
|
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, "<unhandled register %#x>", reg->type);
|
2025-04-28 15:20:52 +02:00
|
|
|
return MSL_DATA_UNION;
|
2024-10-09 16:45:31 +08:00
|
|
|
}
|
|
|
|
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, "<unhandled register %#x>", reg->type);
|
2025-04-28 15:20:52 +02:00
|
|
|
return MSL_DATA_UNION;
|
2024-10-09 16:45:31 +08:00
|
|
|
}
|
|
|
|
vkd3d_string_buffer_printf(buffer, "o[%u]", reg->idx[0].offset);
|
2025-04-28 15:20:52 +02:00
|
|
|
return MSL_DATA_UNION;
|
2024-10-09 16:45:31 +08:00
|
|
|
|
2024-11-22 15:45:54 +08:00
|
|
|
case VKD3DSPR_DEPTHOUT:
|
|
|
|
if (gen->program->shader_version.type != VKD3D_SHADER_TYPE_PIXEL)
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled depth output in shader type #%x.",
|
|
|
|
gen->program->shader_version.type);
|
|
|
|
vkd3d_string_buffer_printf(buffer, "o_depth");
|
2025-04-28 15:20:52 +02:00
|
|
|
return MSL_DATA_FLOAT;
|
2024-11-22 15:45:54 +08:00
|
|
|
|
2024-11-22 15:45:54 +08:00
|
|
|
case VKD3DSPR_IMMCONST:
|
|
|
|
switch (reg->dimension)
|
|
|
|
{
|
|
|
|
case VSIR_DIMENSION_SCALAR:
|
2025-04-28 15:20:52 +02:00
|
|
|
vkd3d_string_buffer_printf(buffer, "%#xu", reg->u.immconst_u32[0]);
|
|
|
|
return MSL_DATA_UINT;
|
2024-11-22 15:45:54 +08:00
|
|
|
|
|
|
|
case VSIR_DIMENSION_VEC4:
|
2025-04-28 15:20:52 +02:00
|
|
|
vkd3d_string_buffer_printf(buffer, "uint4(%#xu, %#xu, %#xu, %#xu)",
|
|
|
|
reg->u.immconst_u32[0], reg->u.immconst_u32[1],
|
|
|
|
reg->u.immconst_u32[2], reg->u.immconst_u32[3]);
|
|
|
|
return MSL_DATA_UINT;
|
2024-11-22 15:45:54 +08:00
|
|
|
|
|
|
|
default:
|
|
|
|
vkd3d_string_buffer_printf(buffer, "<unhandled_dimension %#x>", reg->dimension);
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled dimension %#x.", reg->dimension);
|
2025-04-28 15:20:52 +02:00
|
|
|
return MSL_DATA_UINT;
|
2024-11-22 15:45:54 +08:00
|
|
|
}
|
|
|
|
|
2024-10-09 16:41:52 +08:00
|
|
|
case VKD3DSPR_CONSTBUFFER:
|
|
|
|
{
|
vkd3d-shader/msl: Access descriptors with a type-erased array.
Currently a descriptor set is represented with a structure
whose fields are the various descriptors that the shader is
going to use, each of them qualified with its type. This model
doesn't match very well what happens with D3D12 and with Vulkan
and descriptor indexing and mutable descriptors, where many
descriptor of different types can overlap, and only at shader
runtime it is decided which of them must be used.
Therefore with this patch a descriptor is represented as a
structure whose fields carry no intrinsic typing information,
but are reinterpreted according to the shader behavior on
each access. For the moment there is just one field, but more
will be added to account for fancier descriptor types and
to workaround Metal limitations.
When completed, this design will be similar in spirit to what
the Metal shader converter does, with little technical
differences.
This choice has a couple of drawbacks:
1. shader debugging with Xcode is less comfortable, because
the shader doesn't carry static descriptor typing
information and Xcode is therefore less able to provide
useful context;
2. it requires tier 2 argument buffer support and macOS
version >= 13, which includes guarantees on the runtime
layout for descriptors.
Supporting descriptor indexing and mutable descriptors is
considered to be worthy of those drawbacks, though, is
effectively required by many applications and appears to be
the first goal we should aim for. If needed, in the future
we might also add support for older hardware, at least for
shaders that do not make use of advanced features.
2025-03-11 21:53:10 +01:00
|
|
|
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);
|
2025-04-28 15:20:52 +02:00
|
|
|
return MSL_DATA_UNION;
|
vkd3d-shader/msl: Access descriptors with a type-erased array.
Currently a descriptor set is represented with a structure
whose fields are the various descriptors that the shader is
going to use, each of them qualified with its type. This model
doesn't match very well what happens with D3D12 and with Vulkan
and descriptor indexing and mutable descriptors, where many
descriptor of different types can overlap, and only at shader
runtime it is decided which of them must be used.
Therefore with this patch a descriptor is represented as a
structure whose fields carry no intrinsic typing information,
but are reinterpreted according to the shader behavior on
each access. For the moment there is just one field, but more
will be added to account for fancier descriptor types and
to workaround Metal limitations.
When completed, this design will be similar in spirit to what
the Metal shader converter does, with little technical
differences.
This choice has a couple of drawbacks:
1. shader debugging with Xcode is less comfortable, because
the shader doesn't carry static descriptor typing
information and Xcode is therefore less able to provide
useful context;
2. it requires tier 2 argument buffer support and macOS
version >= 13, which includes guarantees on the runtime
layout for descriptors.
Supporting descriptor indexing and mutable descriptors is
considered to be worthy of those drawbacks, though, is
effectively required by many applications and appears to be
the first goal we should aim for. If needed, in the future
we might also add support for older hardware, at least for
shaders that do not make use of advanced features.
2025-03-11 21:53:10 +01:00
|
|
|
}
|
|
|
|
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);
|
2025-04-28 15:20:52 +02:00
|
|
|
return MSL_DATA_UNION;
|
vkd3d-shader/msl: Access descriptors with a type-erased array.
Currently a descriptor set is represented with a structure
whose fields are the various descriptors that the shader is
going to use, each of them qualified with its type. This model
doesn't match very well what happens with D3D12 and with Vulkan
and descriptor indexing and mutable descriptors, where many
descriptor of different types can overlap, and only at shader
runtime it is decided which of them must be used.
Therefore with this patch a descriptor is represented as a
structure whose fields carry no intrinsic typing information,
but are reinterpreted according to the shader behavior on
each access. For the moment there is just one field, but more
will be added to account for fancier descriptor types and
to workaround Metal limitations.
When completed, this design will be similar in spirit to what
the Metal shader converter does, with little technical
differences.
This choice has a couple of drawbacks:
1. shader debugging with Xcode is less comfortable, because
the shader doesn't carry static descriptor typing
information and Xcode is therefore less able to provide
useful context;
2. it requires tier 2 argument buffer support and macOS
version >= 13, which includes guarantees on the runtime
layout for descriptors.
Supporting descriptor indexing and mutable descriptors is
considered to be worthy of those drawbacks, though, is
effectively required by many applications and appears to be
the first goal we should aim for. If needed, in the future
we might also add support for older hardware, at least for
shaders that do not make use of advanced features.
2025-03-11 21:53:10 +01:00
|
|
|
}
|
|
|
|
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);
|
2025-04-28 15:20:52 +02:00
|
|
|
return MSL_DATA_UNION;
|
vkd3d-shader/msl: Access descriptors with a type-erased array.
Currently a descriptor set is represented with a structure
whose fields are the various descriptors that the shader is
going to use, each of them qualified with its type. This model
doesn't match very well what happens with D3D12 and with Vulkan
and descriptor indexing and mutable descriptors, where many
descriptor of different types can overlap, and only at shader
runtime it is decided which of them must be used.
Therefore with this patch a descriptor is represented as a
structure whose fields carry no intrinsic typing information,
but are reinterpreted according to the shader behavior on
each access. For the moment there is just one field, but more
will be added to account for fancier descriptor types and
to workaround Metal limitations.
When completed, this design will be similar in spirit to what
the Metal shader converter does, with little technical
differences.
This choice has a couple of drawbacks:
1. shader debugging with Xcode is less comfortable, because
the shader doesn't carry static descriptor typing
information and Xcode is therefore less able to provide
useful context;
2. it requires tier 2 argument buffer support and macOS
version >= 13, which includes guarantees on the runtime
layout for descriptors.
Supporting descriptor indexing and mutable descriptors is
considered to be worthy of those drawbacks, though, is
effectively required by many applications and appears to be
the first goal we should aim for. If needed, in the future
we might also add support for older hardware, at least for
shaders that do not make use of advanced features.
2025-03-11 21:53:10 +01:00
|
|
|
}
|
|
|
|
msl_print_cbv_name(buffer, binding->binding);
|
|
|
|
vkd3d_string_buffer_printf(buffer, "[%u]", reg->idx[2].offset);
|
2025-04-28 15:20:52 +02:00
|
|
|
return MSL_DATA_UNION;
|
2024-10-09 16:41:52 +08:00
|
|
|
}
|
|
|
|
|
2024-09-24 02:53:23 +08:00
|
|
|
default:
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled register type %#x.", reg->type);
|
|
|
|
vkd3d_string_buffer_printf(buffer, "<unrecognised register %#x>", reg->type);
|
2025-04-28 15:20:52 +02:00
|
|
|
return MSL_DATA_UINT;
|
2024-09-24 02:53:23 +08:00
|
|
|
}
|
2024-09-17 20:50:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void msl_print_swizzle(struct vkd3d_string_buffer *buffer, uint32_t swizzle, uint32_t mask)
|
|
|
|
{
|
|
|
|
const char swizzle_chars[] = "xyzw";
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
vkd3d_string_buffer_printf(buffer, ".");
|
|
|
|
for (i = 0; i < VKD3D_VEC4_SIZE; ++i)
|
|
|
|
{
|
|
|
|
if (mask & (VKD3DSP_WRITEMASK_0 << i))
|
|
|
|
vkd3d_string_buffer_printf(buffer, "%c", swizzle_chars[vsir_swizzle_get_component(swizzle, i)]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void msl_print_write_mask(struct vkd3d_string_buffer *buffer, uint32_t write_mask)
|
|
|
|
{
|
|
|
|
vkd3d_string_buffer_printf(buffer, ".");
|
|
|
|
if (write_mask & VKD3DSP_WRITEMASK_0)
|
|
|
|
vkd3d_string_buffer_printf(buffer, "x");
|
|
|
|
if (write_mask & VKD3DSP_WRITEMASK_1)
|
|
|
|
vkd3d_string_buffer_printf(buffer, "y");
|
|
|
|
if (write_mask & VKD3DSP_WRITEMASK_2)
|
|
|
|
vkd3d_string_buffer_printf(buffer, "z");
|
|
|
|
if (write_mask & VKD3DSP_WRITEMASK_3)
|
|
|
|
vkd3d_string_buffer_printf(buffer, "w");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void msl_src_cleanup(struct msl_src *src, struct vkd3d_string_buffer_cache *cache)
|
|
|
|
{
|
|
|
|
vkd3d_string_buffer_release(cache, src->str);
|
|
|
|
}
|
|
|
|
|
2025-04-28 15:20:52 +02:00
|
|
|
static void msl_print_bitcast(struct vkd3d_string_buffer *dst, struct msl_generator *gen, const char *src,
|
|
|
|
enum vkd3d_data_type dst_data_type, enum msl_data_type src_data_type, enum vsir_dimension dimension)
|
|
|
|
{
|
|
|
|
bool write_cast = false;
|
|
|
|
|
|
|
|
if (dst_data_type == VKD3D_DATA_UNORM || dst_data_type == VKD3D_DATA_SNORM)
|
|
|
|
dst_data_type = VKD3D_DATA_FLOAT;
|
|
|
|
|
|
|
|
switch (src_data_type)
|
|
|
|
{
|
|
|
|
case MSL_DATA_FLOAT:
|
|
|
|
write_cast = dst_data_type != VKD3D_DATA_FLOAT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MSL_DATA_UINT:
|
|
|
|
write_cast = dst_data_type != VKD3D_DATA_UINT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MSL_DATA_UNION:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (write_cast)
|
|
|
|
{
|
|
|
|
vkd3d_string_buffer_printf(dst, "as_type<");
|
|
|
|
msl_print_resource_datatype(gen, dst, dst_data_type);
|
|
|
|
vkd3d_string_buffer_printf(dst, "%s>(", dimension == VSIR_DIMENSION_VEC4 ? "4" : "");
|
|
|
|
}
|
|
|
|
|
|
|
|
vkd3d_string_buffer_printf(dst, "%s", src);
|
|
|
|
|
|
|
|
if (write_cast)
|
|
|
|
vkd3d_string_buffer_printf(dst, ")");
|
|
|
|
|
|
|
|
if (src_data_type == MSL_DATA_UNION)
|
|
|
|
msl_print_register_datatype(dst, gen, dst_data_type);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void msl_print_src_with_type(struct vkd3d_string_buffer *buffer, struct msl_generator *gen,
|
|
|
|
const struct vkd3d_shader_src_param *vsir_src, uint32_t mask, enum vkd3d_data_type data_type)
|
2024-09-17 20:50:44 +08:00
|
|
|
{
|
|
|
|
const struct vkd3d_shader_register *reg = &vsir_src->reg;
|
2025-04-28 15:20:52 +02:00
|
|
|
struct vkd3d_string_buffer *register_name, *str;
|
|
|
|
enum msl_data_type src_data_type;
|
|
|
|
|
|
|
|
register_name = vkd3d_string_buffer_get(&gen->string_buffers);
|
2024-09-17 20:50:44 +08:00
|
|
|
|
|
|
|
if (reg->non_uniform)
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled 'non-uniform' modifier.");
|
|
|
|
|
2024-11-22 15:45:54 +08:00
|
|
|
if (!vsir_src->modifiers)
|
2025-04-28 14:33:23 +02:00
|
|
|
str = buffer;
|
2024-11-22 15:45:54 +08:00
|
|
|
else
|
|
|
|
str = vkd3d_string_buffer_get(&gen->string_buffers);
|
|
|
|
|
2025-04-28 15:20:52 +02:00
|
|
|
src_data_type = msl_print_register_name(register_name, gen, reg);
|
|
|
|
msl_print_bitcast(str, gen, register_name->buffer, data_type, src_data_type, reg->dimension);
|
2024-09-17 20:50:44 +08:00
|
|
|
if (reg->dimension == VSIR_DIMENSION_VEC4)
|
2024-11-22 15:45:54 +08:00
|
|
|
msl_print_swizzle(str, vsir_src->swizzle, mask);
|
|
|
|
|
|
|
|
switch (vsir_src->modifiers)
|
|
|
|
{
|
|
|
|
case VKD3DSPSM_NONE:
|
|
|
|
break;
|
2024-11-22 15:45:54 +08:00
|
|
|
case VKD3DSPSM_NEG:
|
2025-04-28 14:33:23 +02:00
|
|
|
vkd3d_string_buffer_printf(buffer, "-%s", str->buffer);
|
2024-11-22 15:45:54 +08:00
|
|
|
break;
|
2024-11-22 15:45:54 +08:00
|
|
|
case VKD3DSPSM_ABS:
|
2025-04-28 14:33:23 +02:00
|
|
|
vkd3d_string_buffer_printf(buffer, "abs(%s)", str->buffer);
|
2024-11-22 15:45:54 +08:00
|
|
|
break;
|
|
|
|
default:
|
2025-04-28 14:33:23 +02:00
|
|
|
vkd3d_string_buffer_printf(buffer, "<unhandled modifier %#x>(%s)",
|
2024-11-22 15:45:54 +08:00
|
|
|
vsir_src->modifiers, str->buffer);
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled source modifier(s) %#x.", vsir_src->modifiers);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2025-04-28 14:33:23 +02:00
|
|
|
if (str != buffer)
|
2024-11-22 15:45:54 +08:00
|
|
|
vkd3d_string_buffer_release(&gen->string_buffers, str);
|
2024-09-17 20:50:44 +08:00
|
|
|
}
|
|
|
|
|
2025-04-28 14:33:23 +02:00
|
|
|
static void msl_src_init(struct msl_src *msl_src, struct msl_generator *gen,
|
|
|
|
const struct vkd3d_shader_src_param *vsir_src, uint32_t mask)
|
|
|
|
{
|
|
|
|
msl_src->str = vkd3d_string_buffer_get(&gen->string_buffers);
|
2025-04-28 15:20:52 +02:00
|
|
|
msl_print_src_with_type(msl_src->str, gen, vsir_src, mask, vsir_src->reg.data_type);
|
2025-04-28 14:33:23 +02:00
|
|
|
}
|
|
|
|
|
2024-09-17 20:50:44 +08:00
|
|
|
static void msl_dst_cleanup(struct msl_dst *dst, struct vkd3d_string_buffer_cache *cache)
|
|
|
|
{
|
|
|
|
vkd3d_string_buffer_release(cache, dst->mask);
|
|
|
|
vkd3d_string_buffer_release(cache, dst->register_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t msl_dst_init(struct msl_dst *msl_dst, struct msl_generator *gen,
|
|
|
|
const struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_dst_param *vsir_dst)
|
|
|
|
{
|
|
|
|
uint32_t write_mask = vsir_dst->write_mask;
|
2025-04-28 15:20:52 +02:00
|
|
|
enum msl_data_type dst_data_type;
|
2024-09-17 20:50:44 +08:00
|
|
|
|
|
|
|
if (ins->flags & VKD3DSI_PRECISE_XYZW)
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled 'precise' modifier.");
|
|
|
|
if (vsir_dst->reg.non_uniform)
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled 'non-uniform' modifier.");
|
|
|
|
|
|
|
|
msl_dst->vsir = vsir_dst;
|
|
|
|
msl_dst->register_name = vkd3d_string_buffer_get(&gen->string_buffers);
|
|
|
|
msl_dst->mask = vkd3d_string_buffer_get(&gen->string_buffers);
|
|
|
|
|
2025-04-28 15:20:52 +02:00
|
|
|
dst_data_type = msl_print_register_name(msl_dst->register_name, gen, &vsir_dst->reg);
|
|
|
|
if (dst_data_type == MSL_DATA_UNION)
|
|
|
|
msl_print_register_datatype(msl_dst->mask, gen, vsir_dst->reg.data_type);
|
2024-11-22 15:45:54 +08:00
|
|
|
if (vsir_dst->reg.dimension == VSIR_DIMENSION_VEC4)
|
|
|
|
msl_print_write_mask(msl_dst->mask, write_mask);
|
2024-09-17 20:50:44 +08:00
|
|
|
|
|
|
|
return write_mask;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void VKD3D_PRINTF_FUNC(3, 4) msl_print_assignment(
|
|
|
|
struct msl_generator *gen, struct msl_dst *dst, const char *format, ...)
|
|
|
|
{
|
2024-12-03 01:01:59 +08:00
|
|
|
uint32_t modifiers = dst->vsir->modifiers;
|
2024-09-17 20:50:44 +08:00
|
|
|
va_list args;
|
|
|
|
|
|
|
|
if (dst->vsir->shift)
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled destination shift %#x.", dst->vsir->shift);
|
2024-12-03 01:01:59 +08:00
|
|
|
if (modifiers & ~VKD3DSPDM_SATURATE)
|
2024-09-17 20:50:44 +08:00
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
2024-12-03 01:01:59 +08:00
|
|
|
"Internal compiler error: Unhandled destination modifier(s) %#x.", modifiers);
|
2024-09-17 20:50:44 +08:00
|
|
|
|
|
|
|
msl_print_indent(gen->buffer, gen->indent);
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "%s%s = ", dst->register_name->buffer, dst->mask->buffer);
|
|
|
|
|
2024-12-03 01:01:59 +08:00
|
|
|
if (modifiers & VKD3DSPDM_SATURATE)
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "saturate(");
|
|
|
|
|
2024-09-17 20:50:44 +08:00
|
|
|
va_start(args, format);
|
|
|
|
vkd3d_string_buffer_vprintf(gen->buffer, format, args);
|
|
|
|
va_end(args);
|
|
|
|
|
2024-12-03 01:01:59 +08:00
|
|
|
if (modifiers & VKD3DSPDM_SATURATE)
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, ")");
|
|
|
|
|
2024-09-17 20:50:44 +08:00
|
|
|
vkd3d_string_buffer_printf(gen->buffer, ";\n");
|
|
|
|
}
|
2024-09-16 18:35:55 +08:00
|
|
|
|
2024-08-29 01:21:22 +08:00
|
|
|
static void msl_unhandled(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins)
|
|
|
|
{
|
2024-09-16 18:35:55 +08:00
|
|
|
msl_print_indent(gen->buffer, gen->indent);
|
2024-08-29 01:21:22 +08:00
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "/* <unhandled instruction %#x> */\n", ins->opcode);
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled instruction %#x.", ins->opcode);
|
|
|
|
}
|
|
|
|
|
2024-11-22 15:45:54 +08:00
|
|
|
static void msl_binop(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins, const char *op)
|
|
|
|
{
|
|
|
|
struct msl_src src[2];
|
|
|
|
struct msl_dst dst;
|
|
|
|
uint32_t mask;
|
|
|
|
|
|
|
|
mask = msl_dst_init(&dst, gen, ins, &ins->dst[0]);
|
|
|
|
msl_src_init(&src[0], gen, &ins->src[0], mask);
|
|
|
|
msl_src_init(&src[1], gen, &ins->src[1], mask);
|
|
|
|
|
|
|
|
msl_print_assignment(gen, &dst, "%s %s %s", src[0].str->buffer, op, src[1].str->buffer);
|
|
|
|
|
|
|
|
msl_src_cleanup(&src[1], &gen->string_buffers);
|
|
|
|
msl_src_cleanup(&src[0], &gen->string_buffers);
|
|
|
|
msl_dst_cleanup(&dst, &gen->string_buffers);
|
|
|
|
}
|
|
|
|
|
2024-11-22 15:45:54 +08:00
|
|
|
static void msl_dot(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins, uint32_t src_mask)
|
|
|
|
{
|
|
|
|
unsigned int component_count;
|
|
|
|
struct msl_src src[2];
|
|
|
|
struct msl_dst dst;
|
|
|
|
uint32_t dst_mask;
|
|
|
|
|
|
|
|
dst_mask = msl_dst_init(&dst, gen, ins, &ins->dst[0]);
|
|
|
|
msl_src_init(&src[0], gen, &ins->src[0], src_mask);
|
|
|
|
msl_src_init(&src[1], gen, &ins->src[1], src_mask);
|
|
|
|
|
|
|
|
if ((component_count = vsir_write_mask_component_count(dst_mask)) > 1)
|
|
|
|
msl_print_assignment(gen, &dst, "float%u(dot(%s, %s))",
|
|
|
|
component_count, src[0].str->buffer, src[1].str->buffer);
|
|
|
|
else
|
|
|
|
msl_print_assignment(gen, &dst, "dot(%s, %s)", src[0].str->buffer, src[1].str->buffer);
|
|
|
|
|
|
|
|
msl_src_cleanup(&src[1], &gen->string_buffers);
|
|
|
|
msl_src_cleanup(&src[0], &gen->string_buffers);
|
|
|
|
msl_dst_cleanup(&dst, &gen->string_buffers);
|
|
|
|
}
|
|
|
|
|
2024-11-22 15:45:54 +08:00
|
|
|
static void msl_intrinsic(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins, const char *op)
|
|
|
|
{
|
2024-12-03 00:46:35 +08:00
|
|
|
struct vkd3d_string_buffer *args;
|
2024-11-22 15:45:54 +08:00
|
|
|
struct msl_src src;
|
|
|
|
struct msl_dst dst;
|
2024-12-03 00:46:35 +08:00
|
|
|
unsigned int i;
|
2024-11-22 15:45:54 +08:00
|
|
|
uint32_t mask;
|
|
|
|
|
|
|
|
mask = msl_dst_init(&dst, gen, ins, &ins->dst[0]);
|
2024-12-03 00:46:35 +08:00
|
|
|
args = vkd3d_string_buffer_get(&gen->string_buffers);
|
2024-11-22 15:45:54 +08:00
|
|
|
|
2024-12-03 00:46:35 +08:00
|
|
|
for (i = 0; i < ins->src_count; ++i)
|
|
|
|
{
|
|
|
|
msl_src_init(&src, gen, &ins->src[i], mask);
|
|
|
|
vkd3d_string_buffer_printf(args, "%s%s", i ? ", " : "", src.str->buffer);
|
|
|
|
msl_src_cleanup(&src, &gen->string_buffers);
|
|
|
|
}
|
2024-11-22 15:45:54 +08:00
|
|
|
|
2024-12-03 00:46:35 +08:00
|
|
|
msl_print_assignment(gen, &dst, "%s(%s)", op, args->buffer);
|
|
|
|
|
|
|
|
vkd3d_string_buffer_release(&gen->string_buffers, args);
|
2024-11-22 15:45:54 +08:00
|
|
|
msl_dst_cleanup(&dst, &gen->string_buffers);
|
|
|
|
}
|
|
|
|
|
2024-11-22 15:45:54 +08:00
|
|
|
static void msl_relop(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins, const char *op)
|
|
|
|
{
|
|
|
|
unsigned int mask_size;
|
|
|
|
struct msl_src src[2];
|
|
|
|
struct msl_dst dst;
|
|
|
|
uint32_t mask;
|
|
|
|
|
|
|
|
mask = msl_dst_init(&dst, gen, ins, &ins->dst[0]);
|
|
|
|
msl_src_init(&src[0], gen, &ins->src[0], mask);
|
|
|
|
msl_src_init(&src[1], gen, &ins->src[1], mask);
|
|
|
|
|
|
|
|
if ((mask_size = vsir_write_mask_component_count(mask)) > 1)
|
|
|
|
msl_print_assignment(gen, &dst, "select(uint%u(0u), uint%u(0xffffffffu), bool%u(%s %s %s))",
|
|
|
|
mask_size, mask_size, mask_size, src[0].str->buffer, op, src[1].str->buffer);
|
|
|
|
else
|
|
|
|
msl_print_assignment(gen, &dst, "%s %s %s ? 0xffffffffu : 0u",
|
|
|
|
src[0].str->buffer, op, src[1].str->buffer);
|
|
|
|
|
|
|
|
msl_src_cleanup(&src[1], &gen->string_buffers);
|
|
|
|
msl_src_cleanup(&src[0], &gen->string_buffers);
|
|
|
|
msl_dst_cleanup(&dst, &gen->string_buffers);
|
|
|
|
}
|
|
|
|
|
2024-11-22 15:45:54 +08:00
|
|
|
static void msl_cast(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins, const char *constructor)
|
|
|
|
{
|
|
|
|
unsigned int component_count;
|
|
|
|
struct msl_src src;
|
|
|
|
struct msl_dst dst;
|
|
|
|
uint32_t mask;
|
|
|
|
|
|
|
|
mask = msl_dst_init(&dst, gen, ins, &ins->dst[0]);
|
|
|
|
msl_src_init(&src, gen, &ins->src[0], mask);
|
|
|
|
|
|
|
|
if ((component_count = vsir_write_mask_component_count(mask)) > 1)
|
|
|
|
msl_print_assignment(gen, &dst, "%s%u(%s)", constructor, component_count, src.str->buffer);
|
|
|
|
else
|
|
|
|
msl_print_assignment(gen, &dst, "%s(%s)", constructor, src.str->buffer);
|
|
|
|
|
|
|
|
msl_src_cleanup(&src, &gen->string_buffers);
|
|
|
|
msl_dst_cleanup(&dst, &gen->string_buffers);
|
|
|
|
}
|
|
|
|
|
2024-12-03 00:58:19 +08:00
|
|
|
static void msl_end_block(struct msl_generator *gen)
|
|
|
|
{
|
|
|
|
--gen->indent;
|
|
|
|
msl_print_indent(gen->buffer, gen->indent);
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "}\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void msl_begin_block(struct msl_generator *gen)
|
|
|
|
{
|
|
|
|
msl_print_indent(gen->buffer, gen->indent);
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "{\n");
|
|
|
|
++gen->indent;
|
|
|
|
}
|
|
|
|
|
2024-12-03 00:06:32 +08:00
|
|
|
static void msl_if(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins)
|
|
|
|
{
|
|
|
|
const char *condition;
|
|
|
|
struct msl_src src;
|
|
|
|
|
|
|
|
msl_src_init(&src, gen, &ins->src[0], VKD3DSP_WRITEMASK_0);
|
|
|
|
|
|
|
|
msl_print_indent(gen->buffer, gen->indent);
|
|
|
|
condition = ins->flags == VKD3D_SHADER_CONDITIONAL_OP_NZ ? "bool" : "!bool";
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "if (%s(%s))\n", condition, src.str->buffer);
|
|
|
|
|
|
|
|
msl_src_cleanup(&src, &gen->string_buffers);
|
|
|
|
|
2024-12-03 00:58:19 +08:00
|
|
|
msl_begin_block(gen);
|
2024-12-03 00:06:32 +08:00
|
|
|
}
|
|
|
|
|
2024-12-03 00:58:19 +08:00
|
|
|
static void msl_else(struct msl_generator *gen)
|
2024-12-03 00:06:32 +08:00
|
|
|
{
|
2024-12-03 00:58:19 +08:00
|
|
|
msl_end_block(gen);
|
2024-12-03 00:06:32 +08:00
|
|
|
msl_print_indent(gen->buffer, gen->indent);
|
2024-12-03 00:58:19 +08:00
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "else\n");
|
|
|
|
msl_begin_block(gen);
|
2024-12-03 00:06:32 +08:00
|
|
|
}
|
|
|
|
|
2024-12-12 15:02:51 +08:00
|
|
|
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 *descriptor;
|
|
|
|
const struct vkd3d_shader_descriptor_binding *binding;
|
|
|
|
enum vkd3d_shader_resource_type resource_type;
|
|
|
|
struct vkd3d_string_buffer *read;
|
2025-04-03 22:46:57 +02:00
|
|
|
enum vkd3d_data_type data_type;
|
2024-12-12 15:02:51 +08:00
|
|
|
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;
|
2025-04-03 22:46:57 +02:00
|
|
|
data_type = descriptor->resource_data_type;
|
2024-12-12 15:02:51 +08:00
|
|
|
}
|
|
|
|
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;
|
2025-04-03 22:46:57 +02:00
|
|
|
data_type = VKD3D_DATA_FLOAT;
|
2024-12-12 15:02:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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]);
|
|
|
|
read = vkd3d_string_buffer_get(&gen->string_buffers);
|
|
|
|
|
|
|
|
vkd3d_string_buffer_printf(read, "as_type<uint4>(");
|
2025-04-03 22:46:57 +02:00
|
|
|
msl_print_srv_name(read, gen, binding->binding, resource_type_info, data_type);
|
2024-12-12 15:02:51 +08:00
|
|
|
vkd3d_string_buffer_printf(read, ".read(");
|
2025-04-28 15:33:57 +02:00
|
|
|
msl_print_src_with_type(read, gen, &ins->src[0], coord_mask, VKD3D_DATA_UINT);
|
2024-12-12 15:02:51 +08:00
|
|
|
if (resource_type_info->array)
|
2025-04-28 15:33:57 +02:00
|
|
|
{
|
|
|
|
vkd3d_string_buffer_printf(read, ", ");
|
|
|
|
msl_print_src_with_type(read, gen, &ins->src[0], coord_mask + 1, VKD3D_DATA_UINT);
|
|
|
|
}
|
2024-12-12 15:02:51 +08:00
|
|
|
if (resource_type_info->lod)
|
2025-04-28 15:33:57 +02:00
|
|
|
{
|
|
|
|
vkd3d_string_buffer_printf(read, ", ");
|
|
|
|
msl_print_src_with_type(read, gen, &ins->src[0], VKD3DSP_WRITEMASK_3, VKD3D_DATA_UINT);
|
|
|
|
}
|
2024-12-12 15:02:51 +08:00
|
|
|
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_dst_cleanup(&dst, &gen->string_buffers);
|
|
|
|
}
|
|
|
|
|
2024-12-03 00:55:22 +08:00
|
|
|
static void msl_unary_op(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins, const char *op)
|
|
|
|
{
|
|
|
|
struct msl_src src;
|
|
|
|
struct msl_dst dst;
|
|
|
|
uint32_t mask;
|
|
|
|
|
|
|
|
mask = msl_dst_init(&dst, gen, ins, &ins->dst[0]);
|
|
|
|
msl_src_init(&src, gen, &ins->src[0], mask);
|
|
|
|
|
|
|
|
msl_print_assignment(gen, &dst, "%s%s", op, src.str->buffer);
|
|
|
|
|
|
|
|
msl_src_cleanup(&src, &gen->string_buffers);
|
|
|
|
msl_dst_cleanup(&dst, &gen->string_buffers);
|
|
|
|
}
|
|
|
|
|
2024-09-17 20:50:44 +08:00
|
|
|
static void msl_mov(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins)
|
|
|
|
{
|
|
|
|
struct msl_src src;
|
|
|
|
struct msl_dst dst;
|
|
|
|
uint32_t mask;
|
|
|
|
|
|
|
|
mask = msl_dst_init(&dst, gen, ins, &ins->dst[0]);
|
|
|
|
msl_src_init(&src, gen, &ins->src[0], mask);
|
|
|
|
|
|
|
|
msl_print_assignment(gen, &dst, "%s", src.str->buffer);
|
|
|
|
|
|
|
|
msl_src_cleanup(&src, &gen->string_buffers);
|
|
|
|
msl_dst_cleanup(&dst, &gen->string_buffers);
|
|
|
|
}
|
|
|
|
|
2024-11-22 15:45:54 +08:00
|
|
|
static void msl_movc(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins)
|
|
|
|
{
|
|
|
|
unsigned int component_count;
|
|
|
|
struct msl_src src[3];
|
|
|
|
struct msl_dst dst;
|
|
|
|
uint32_t mask;
|
|
|
|
|
|
|
|
mask = msl_dst_init(&dst, gen, ins, &ins->dst[0]);
|
|
|
|
msl_src_init(&src[0], gen, &ins->src[0], mask);
|
|
|
|
msl_src_init(&src[1], gen, &ins->src[1], mask);
|
|
|
|
msl_src_init(&src[2], gen, &ins->src[2], mask);
|
|
|
|
|
|
|
|
if ((component_count = vsir_write_mask_component_count(mask)) > 1)
|
|
|
|
msl_print_assignment(gen, &dst, "select(%s, %s, bool%u(%s))",
|
|
|
|
src[2].str->buffer, src[1].str->buffer, component_count, src[0].str->buffer);
|
|
|
|
else
|
|
|
|
msl_print_assignment(gen, &dst, "select(%s, %s, bool(%s))",
|
|
|
|
src[2].str->buffer, src[1].str->buffer, src[0].str->buffer);
|
|
|
|
|
|
|
|
msl_src_cleanup(&src[2], &gen->string_buffers);
|
|
|
|
msl_src_cleanup(&src[1], &gen->string_buffers);
|
|
|
|
msl_src_cleanup(&src[0], &gen->string_buffers);
|
|
|
|
msl_dst_cleanup(&dst, &gen->string_buffers);
|
|
|
|
}
|
|
|
|
|
2024-09-16 19:15:39 +08:00
|
|
|
static void msl_ret(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins)
|
|
|
|
{
|
|
|
|
msl_print_indent(gen->buffer, gen->indent);
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "return;\n");
|
|
|
|
}
|
|
|
|
|
2024-08-29 01:21:22 +08:00
|
|
|
static void msl_handle_instruction(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins)
|
|
|
|
{
|
|
|
|
gen->location = ins->location;
|
2024-09-16 18:37:58 +08:00
|
|
|
|
|
|
|
switch (ins->opcode)
|
|
|
|
{
|
2024-11-22 15:45:54 +08:00
|
|
|
case VKD3DSIH_ADD:
|
|
|
|
msl_binop(gen, ins, "+");
|
|
|
|
break;
|
2024-11-22 15:45:54 +08:00
|
|
|
case VKD3DSIH_AND:
|
|
|
|
msl_binop(gen, ins, "&");
|
|
|
|
break;
|
2024-09-16 18:37:58 +08:00
|
|
|
case VKD3DSIH_NOP:
|
|
|
|
break;
|
2024-11-22 15:45:54 +08:00
|
|
|
case VKD3DSIH_DIV:
|
|
|
|
msl_binop(gen, ins, "/");
|
|
|
|
break;
|
2024-11-22 15:45:54 +08:00
|
|
|
case VKD3DSIH_DP2:
|
|
|
|
msl_dot(gen, ins, vkd3d_write_mask_from_component_count(2));
|
|
|
|
break;
|
2024-11-22 15:45:54 +08:00
|
|
|
case VKD3DSIH_DP3:
|
|
|
|
msl_dot(gen, ins, vkd3d_write_mask_from_component_count(3));
|
|
|
|
break;
|
2024-11-22 15:45:54 +08:00
|
|
|
case VKD3DSIH_DP4:
|
|
|
|
msl_dot(gen, ins, VKD3DSP_WRITEMASK_ALL);
|
|
|
|
break;
|
2024-12-03 00:58:19 +08:00
|
|
|
case VKD3DSIH_ELSE:
|
|
|
|
msl_else(gen);
|
|
|
|
break;
|
2024-12-03 00:06:32 +08:00
|
|
|
case VKD3DSIH_ENDIF:
|
2024-12-03 00:58:19 +08:00
|
|
|
msl_end_block(gen);
|
2024-12-03 00:06:32 +08:00
|
|
|
break;
|
2024-12-02 23:52:13 +08:00
|
|
|
case VKD3DSIH_IEQ:
|
|
|
|
msl_relop(gen, ins, "==");
|
|
|
|
break;
|
2024-12-02 23:53:45 +08:00
|
|
|
case VKD3DSIH_EXP:
|
|
|
|
msl_intrinsic(gen, ins, "exp2");
|
|
|
|
break;
|
2024-11-22 15:45:54 +08:00
|
|
|
case VKD3DSIH_FRC:
|
|
|
|
msl_intrinsic(gen, ins, "fract");
|
|
|
|
break;
|
2024-11-22 15:45:54 +08:00
|
|
|
case VKD3DSIH_FTOI:
|
|
|
|
msl_cast(gen, ins, "int");
|
|
|
|
break;
|
2024-11-22 15:45:54 +08:00
|
|
|
case VKD3DSIH_FTOU:
|
|
|
|
msl_cast(gen, ins, "uint");
|
|
|
|
break;
|
2024-11-22 15:45:54 +08:00
|
|
|
case VKD3DSIH_GEO:
|
|
|
|
msl_relop(gen, ins, ">=");
|
|
|
|
break;
|
2024-12-03 00:06:32 +08:00
|
|
|
case VKD3DSIH_IF:
|
|
|
|
msl_if(gen, ins);
|
|
|
|
break;
|
2024-12-03 01:12:13 +08:00
|
|
|
case VKD3DSIH_ISHL:
|
|
|
|
msl_binop(gen, ins, "<<");
|
|
|
|
break;
|
2024-12-03 01:13:10 +08:00
|
|
|
case VKD3DSIH_ISHR:
|
2024-12-03 01:13:55 +08:00
|
|
|
case VKD3DSIH_USHR:
|
2024-12-03 01:13:10 +08:00
|
|
|
msl_binop(gen, ins, ">>");
|
|
|
|
break;
|
2024-12-02 23:55:28 +08:00
|
|
|
case VKD3DSIH_LTO:
|
|
|
|
msl_relop(gen, ins, "<");
|
|
|
|
break;
|
2024-12-03 01:09:44 +08:00
|
|
|
case VKD3DSIH_MAD:
|
|
|
|
msl_intrinsic(gen, ins, "fma");
|
|
|
|
break;
|
2024-12-03 00:46:35 +08:00
|
|
|
case VKD3DSIH_MAX:
|
|
|
|
msl_intrinsic(gen, ins, "max");
|
|
|
|
break;
|
2024-12-03 00:49:05 +08:00
|
|
|
case VKD3DSIH_MIN:
|
|
|
|
msl_intrinsic(gen, ins, "min");
|
|
|
|
break;
|
2024-11-22 15:45:54 +08:00
|
|
|
case VKD3DSIH_INE:
|
2024-11-22 15:45:54 +08:00
|
|
|
case VKD3DSIH_NEU:
|
|
|
|
msl_relop(gen, ins, "!=");
|
|
|
|
break;
|
2024-11-22 15:45:54 +08:00
|
|
|
case VKD3DSIH_ITOF:
|
2024-11-22 15:45:54 +08:00
|
|
|
case VKD3DSIH_UTOF:
|
2024-11-22 15:45:54 +08:00
|
|
|
msl_cast(gen, ins, "float");
|
|
|
|
break;
|
2024-12-12 15:02:51 +08:00
|
|
|
case VKD3DSIH_LD:
|
|
|
|
msl_ld(gen, ins);
|
|
|
|
break;
|
2024-12-03 00:41:31 +08:00
|
|
|
case VKD3DSIH_LOG:
|
|
|
|
msl_intrinsic(gen, ins, "log2");
|
|
|
|
break;
|
2024-09-17 20:50:44 +08:00
|
|
|
case VKD3DSIH_MOV:
|
|
|
|
msl_mov(gen, ins);
|
|
|
|
break;
|
2024-11-22 15:45:54 +08:00
|
|
|
case VKD3DSIH_MOVC:
|
|
|
|
msl_movc(gen, ins);
|
|
|
|
break;
|
2024-11-22 15:45:54 +08:00
|
|
|
case VKD3DSIH_MUL:
|
|
|
|
msl_binop(gen, ins, "*");
|
|
|
|
break;
|
2024-12-03 00:55:22 +08:00
|
|
|
case VKD3DSIH_NOT:
|
|
|
|
msl_unary_op(gen, ins, "~");
|
|
|
|
break;
|
2024-11-22 15:45:54 +08:00
|
|
|
case VKD3DSIH_OR:
|
|
|
|
msl_binop(gen, ins, "|");
|
|
|
|
break;
|
2024-09-16 19:15:39 +08:00
|
|
|
case VKD3DSIH_RET:
|
|
|
|
msl_ret(gen, ins);
|
|
|
|
break;
|
2024-12-03 00:09:01 +08:00
|
|
|
case VKD3DSIH_ROUND_NE:
|
|
|
|
msl_intrinsic(gen, ins, "rint");
|
|
|
|
break;
|
2024-12-03 00:04:03 +08:00
|
|
|
case VKD3DSIH_ROUND_NI:
|
|
|
|
msl_intrinsic(gen, ins, "floor");
|
|
|
|
break;
|
2024-11-22 15:45:54 +08:00
|
|
|
case VKD3DSIH_ROUND_PI:
|
|
|
|
msl_intrinsic(gen, ins, "ceil");
|
|
|
|
break;
|
2024-11-22 15:45:54 +08:00
|
|
|
case VKD3DSIH_ROUND_Z:
|
|
|
|
msl_intrinsic(gen, ins, "trunc");
|
|
|
|
break;
|
2024-12-03 00:50:47 +08:00
|
|
|
case VKD3DSIH_RSQ:
|
|
|
|
msl_intrinsic(gen, ins, "rsqrt");
|
|
|
|
break;
|
2024-11-22 15:45:54 +08:00
|
|
|
case VKD3DSIH_SQRT:
|
|
|
|
msl_intrinsic(gen, ins, "sqrt");
|
|
|
|
break;
|
2024-09-16 18:37:58 +08:00
|
|
|
default:
|
|
|
|
msl_unhandled(gen, ins);
|
|
|
|
break;
|
|
|
|
}
|
2024-08-29 01:21:22 +08:00
|
|
|
}
|
|
|
|
|
2024-09-30 11:05:26 +08:00
|
|
|
static void msl_generate_input_struct_declarations(struct msl_generator *gen)
|
|
|
|
{
|
|
|
|
const struct shader_signature *signature = &gen->program->input_signature;
|
|
|
|
enum vkd3d_shader_type type = gen->program->shader_version.type;
|
|
|
|
struct vkd3d_string_buffer *buffer = gen->buffer;
|
|
|
|
const struct signature_element *e;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
vkd3d_string_buffer_printf(buffer, "struct vkd3d_%s_in\n{\n", gen->prefix);
|
|
|
|
|
|
|
|
for (i = 0; i < signature->element_count; ++i)
|
|
|
|
{
|
|
|
|
e = &signature->elements[i];
|
|
|
|
|
|
|
|
if (e->target_location == SIGNATURE_TARGET_LOCATION_UNUSED)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (e->sysval_semantic)
|
|
|
|
{
|
2024-12-03 00:31:48 +08:00
|
|
|
if (e->sysval_semantic == VKD3D_SHADER_SV_IS_FRONT_FACE)
|
|
|
|
{
|
|
|
|
if (type != VKD3D_SHADER_TYPE_PIXEL)
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled SV_IS_FRONT_FACE in shader type #%x.", type);
|
|
|
|
|
|
|
|
msl_print_indent(gen->buffer, 1);
|
|
|
|
vkd3d_string_buffer_printf(buffer, "bool is_front_face [[front_facing]];\n");
|
|
|
|
continue;
|
|
|
|
}
|
2024-09-30 11:05:26 +08:00
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled system value %#x.", e->sysval_semantic);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (e->min_precision != VKD3D_SHADER_MINIMUM_PRECISION_NONE)
|
|
|
|
{
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled minimum precision %#x.", e->min_precision);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(e->register_count > 1)
|
|
|
|
{
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled register count %u.", e->register_count);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
msl_print_indent(gen->buffer, 1);
|
|
|
|
|
|
|
|
switch(e->component_type)
|
|
|
|
{
|
|
|
|
case VKD3D_SHADER_COMPONENT_FLOAT:
|
|
|
|
vkd3d_string_buffer_printf(buffer, "float4 ");
|
|
|
|
break;
|
|
|
|
case VKD3D_SHADER_COMPONENT_INT:
|
|
|
|
vkd3d_string_buffer_printf(buffer, "int4 ");
|
|
|
|
break;
|
|
|
|
case VKD3D_SHADER_COMPONENT_UINT:
|
|
|
|
vkd3d_string_buffer_printf(buffer, "uint4 ");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
vkd3d_string_buffer_printf(buffer, "<unhandled component type %#x> ", e->component_type);
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled component type %#x.", e->component_type);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
vkd3d_string_buffer_printf(buffer, "shader_in_%u ", i);
|
|
|
|
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case VKD3D_SHADER_TYPE_VERTEX:
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "[[attribute(%u)]]", e->target_location);
|
|
|
|
break;
|
|
|
|
case VKD3D_SHADER_TYPE_PIXEL:
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "[[user(locn%u)]]", e->target_location);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled shader type %#x.", type);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-11-22 15:45:54 +08:00
|
|
|
switch (e->interpolation_mode)
|
|
|
|
{
|
|
|
|
/* The default interpolation attribute. */
|
|
|
|
case VKD3DSIM_LINEAR:
|
|
|
|
case VKD3DSIM_NONE:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled interpolation mode %#x.", e->interpolation_mode);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-09-30 11:05:26 +08:00
|
|
|
vkd3d_string_buffer_printf(buffer, ";\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
vkd3d_string_buffer_printf(buffer, "};\n\n");
|
|
|
|
}
|
|
|
|
|
2024-09-30 10:58:02 +08:00
|
|
|
static void msl_generate_vertex_output_element_attribute(struct msl_generator *gen, const struct signature_element *e)
|
|
|
|
{
|
|
|
|
switch (e->sysval_semantic)
|
|
|
|
{
|
|
|
|
case VKD3D_SHADER_SV_POSITION:
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "[[position]]");
|
|
|
|
break;
|
|
|
|
case VKD3D_SHADER_SV_NONE:
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "[[user(locn%u)]]", e->target_location);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled vertex shader system value %#x.", e->sysval_semantic);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void msl_generate_pixel_output_element_attribute(struct msl_generator *gen, const struct signature_element *e)
|
|
|
|
{
|
|
|
|
switch (e->sysval_semantic)
|
|
|
|
{
|
|
|
|
case VKD3D_SHADER_SV_TARGET:
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "[[color(%u)]]", e->target_location);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled pixel shader system value %#x.", e->sysval_semantic);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void msl_generate_output_struct_declarations(struct msl_generator *gen)
|
|
|
|
{
|
|
|
|
const struct shader_signature *signature = &gen->program->output_signature;
|
|
|
|
enum vkd3d_shader_type type = gen->program->shader_version.type;
|
|
|
|
struct vkd3d_string_buffer *buffer = gen->buffer;
|
|
|
|
const struct signature_element *e;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
vkd3d_string_buffer_printf(buffer, "struct vkd3d_%s_out\n{\n", gen->prefix);
|
|
|
|
|
|
|
|
for (i = 0; i < signature->element_count; ++i)
|
|
|
|
{
|
|
|
|
e = &signature->elements[i];
|
|
|
|
|
2024-11-22 15:45:54 +08:00
|
|
|
if (e->sysval_semantic == VKD3D_SHADER_SV_DEPTH)
|
|
|
|
{
|
|
|
|
gen->write_depth = true;
|
|
|
|
msl_print_indent(gen->buffer, 1);
|
|
|
|
vkd3d_string_buffer_printf(buffer, "float shader_out_depth [[depth(any)]];\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2024-09-30 10:58:02 +08:00
|
|
|
if (e->target_location == SIGNATURE_TARGET_LOCATION_UNUSED)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (e->min_precision != VKD3D_SHADER_MINIMUM_PRECISION_NONE)
|
|
|
|
{
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled minimum precision %#x.", e->min_precision);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (e->interpolation_mode != VKD3DSIM_NONE)
|
|
|
|
{
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled interpolation mode %#x.", e->interpolation_mode);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(e->register_count > 1)
|
|
|
|
{
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled register count %u.", e->register_count);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
msl_print_indent(gen->buffer, 1);
|
|
|
|
|
|
|
|
switch(e->component_type)
|
|
|
|
{
|
|
|
|
case VKD3D_SHADER_COMPONENT_FLOAT:
|
|
|
|
vkd3d_string_buffer_printf(buffer, "float4 ");
|
|
|
|
break;
|
|
|
|
case VKD3D_SHADER_COMPONENT_INT:
|
|
|
|
vkd3d_string_buffer_printf(buffer, "int4 ");
|
|
|
|
break;
|
|
|
|
case VKD3D_SHADER_COMPONENT_UINT:
|
|
|
|
vkd3d_string_buffer_printf(buffer, "uint4 ");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
vkd3d_string_buffer_printf(buffer, "<unhandled component type %#x> ", e->component_type);
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled component type %#x.", e->component_type);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
vkd3d_string_buffer_printf(buffer, "shader_out_%u ", i);
|
|
|
|
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case VKD3D_SHADER_TYPE_VERTEX:
|
|
|
|
msl_generate_vertex_output_element_attribute(gen, e);
|
|
|
|
break;
|
|
|
|
case VKD3D_SHADER_TYPE_PIXEL:
|
|
|
|
msl_generate_pixel_output_element_attribute(gen, e);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled shader type %#x.", type);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
vkd3d_string_buffer_printf(buffer, ";\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
vkd3d_string_buffer_printf(buffer, "};\n\n");
|
|
|
|
}
|
|
|
|
|
2024-09-30 11:52:49 +08:00
|
|
|
static void msl_generate_entrypoint_prologue(struct msl_generator *gen)
|
|
|
|
{
|
|
|
|
const struct shader_signature *signature = &gen->program->input_signature;
|
|
|
|
struct vkd3d_string_buffer *buffer = gen->buffer;
|
|
|
|
const struct signature_element *e;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
for (i = 0; i < signature->element_count; ++i)
|
|
|
|
{
|
|
|
|
e = &signature->elements[i];
|
|
|
|
|
|
|
|
if (e->target_location == SIGNATURE_TARGET_LOCATION_UNUSED)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
vkd3d_string_buffer_printf(buffer, " %s_in[%u]", gen->prefix, e->register_index);
|
|
|
|
if (e->sysval_semantic == VKD3D_SHADER_SV_NONE)
|
|
|
|
{
|
|
|
|
msl_print_register_datatype(buffer, gen, vkd3d_data_type_from_component_type(e->component_type));
|
2024-09-30 12:25:53 +08:00
|
|
|
msl_print_write_mask(buffer, e->mask);
|
2024-09-30 11:52:49 +08:00
|
|
|
vkd3d_string_buffer_printf(buffer, " = input.shader_in_%u", i);
|
2024-09-30 12:25:53 +08:00
|
|
|
msl_print_write_mask(buffer, e->mask);
|
2024-09-30 11:52:49 +08:00
|
|
|
}
|
2024-12-03 00:31:48 +08:00
|
|
|
else if (e->sysval_semantic == VKD3D_SHADER_SV_IS_FRONT_FACE)
|
|
|
|
{
|
|
|
|
vkd3d_string_buffer_printf(buffer, ".u = uint4(input.is_front_face ? 0xffffffffu : 0u, 0, 0, 0)");
|
|
|
|
}
|
2024-09-30 11:52:49 +08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
vkd3d_string_buffer_printf(buffer, " = <unhandled sysval %#x>", e->sysval_semantic);
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled system value %#x input.", e->sysval_semantic);
|
|
|
|
}
|
|
|
|
vkd3d_string_buffer_printf(buffer, ";\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-30 11:51:26 +08:00
|
|
|
static void msl_generate_entrypoint_epilogue(struct msl_generator *gen)
|
|
|
|
{
|
|
|
|
const struct shader_signature *signature = &gen->program->output_signature;
|
|
|
|
struct vkd3d_string_buffer *buffer = gen->buffer;
|
|
|
|
const struct signature_element *e;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
for (i = 0; i < signature->element_count; ++i)
|
|
|
|
{
|
|
|
|
e = &signature->elements[i];
|
|
|
|
|
2024-11-22 15:45:54 +08:00
|
|
|
if (e->sysval_semantic == VKD3D_SHADER_SV_DEPTH)
|
|
|
|
{
|
|
|
|
vkd3d_string_buffer_printf(buffer, " output.shader_out_depth = shader_out_depth;\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2024-09-30 11:51:26 +08:00
|
|
|
if (e->target_location == SIGNATURE_TARGET_LOCATION_UNUSED)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
switch (e->sysval_semantic)
|
|
|
|
{
|
|
|
|
case VKD3D_SHADER_SV_NONE:
|
|
|
|
case VKD3D_SHADER_SV_TARGET:
|
|
|
|
case VKD3D_SHADER_SV_POSITION:
|
2024-09-30 12:25:53 +08:00
|
|
|
vkd3d_string_buffer_printf(buffer, " output.shader_out_%u", i);
|
|
|
|
msl_print_write_mask(buffer, e->mask);
|
2024-10-20 20:59:14 +08:00
|
|
|
vkd3d_string_buffer_printf(buffer, " = %s_out[%u]", gen->prefix, e->register_index);
|
2024-09-30 11:51:26 +08:00
|
|
|
msl_print_register_datatype(buffer, gen, vkd3d_data_type_from_component_type(e->component_type));
|
2024-09-30 12:25:53 +08:00
|
|
|
msl_print_write_mask(buffer, e->mask);
|
2024-09-30 11:51:26 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
vkd3d_string_buffer_printf(buffer, " <unhandled sysval %#x>", e->sysval_semantic);
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled system value %#x input.", e->sysval_semantic);
|
|
|
|
}
|
|
|
|
vkd3d_string_buffer_printf(buffer, ";\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-30 11:37:15 +08:00
|
|
|
static void msl_generate_entrypoint(struct msl_generator *gen)
|
|
|
|
{
|
|
|
|
enum vkd3d_shader_type type = gen->program->shader_version.type;
|
|
|
|
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case VKD3D_SHADER_TYPE_VERTEX:
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "vertex ");
|
|
|
|
break;
|
|
|
|
case VKD3D_SHADER_TYPE_PIXEL:
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "fragment ");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled shader type %#x.", type);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "vkd3d_%s_out shader_entry(\n", gen->prefix);
|
|
|
|
|
2025-03-14 23:14:06 +01:00
|
|
|
if (gen->program->descriptors.descriptor_count)
|
2024-10-09 16:36:06 +08:00
|
|
|
{
|
|
|
|
msl_print_indent(gen->buffer, 2);
|
|
|
|
/* TODO: Configurable argument buffer binding location. */
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer,
|
vkd3d-shader/msl: Access descriptors with a type-erased array.
Currently a descriptor set is represented with a structure
whose fields are the various descriptors that the shader is
going to use, each of them qualified with its type. This model
doesn't match very well what happens with D3D12 and with Vulkan
and descriptor indexing and mutable descriptors, where many
descriptor of different types can overlap, and only at shader
runtime it is decided which of them must be used.
Therefore with this patch a descriptor is represented as a
structure whose fields carry no intrinsic typing information,
but are reinterpreted according to the shader behavior on
each access. For the moment there is just one field, but more
will be added to account for fancier descriptor types and
to workaround Metal limitations.
When completed, this design will be similar in spirit to what
the Metal shader converter does, with little technical
differences.
This choice has a couple of drawbacks:
1. shader debugging with Xcode is less comfortable, because
the shader doesn't carry static descriptor typing
information and Xcode is therefore less able to provide
useful context;
2. it requires tier 2 argument buffer support and macOS
version >= 13, which includes guarantees on the runtime
layout for descriptors.
Supporting descriptor indexing and mutable descriptors is
considered to be worthy of those drawbacks, though, is
effectively required by many applications and appears to be
the first goal we should aim for. If needed, in the future
we might also add support for older hardware, at least for
shaders that do not make use of advanced features.
2025-03-11 21:53:10 +01:00
|
|
|
"constant descriptor *descriptors [[buffer(0)]],\n");
|
2024-10-09 16:36:06 +08:00
|
|
|
}
|
2024-09-30 11:37:15 +08:00
|
|
|
|
2024-10-09 16:36:06 +08:00
|
|
|
msl_print_indent(gen->buffer, 2);
|
2024-09-30 11:37:15 +08:00
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "vkd3d_%s_in input [[stage_in]])\n{\n", gen->prefix);
|
|
|
|
|
|
|
|
/* TODO: declare #maximum_register + 1 */
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, " vkd3d_vec4 %s_in[%u];\n", gen->prefix, 32);
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, " vkd3d_vec4 %s_out[%u];\n", gen->prefix, 32);
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, " vkd3d_%s_out output;\n", gen->prefix);
|
|
|
|
|
2024-11-22 15:45:54 +08:00
|
|
|
if (gen->write_depth)
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, " float shader_out_depth;\n");
|
|
|
|
|
2024-09-30 11:52:49 +08:00
|
|
|
msl_generate_entrypoint_prologue(gen);
|
2024-09-30 11:37:15 +08:00
|
|
|
|
2024-10-09 16:36:06 +08:00
|
|
|
vkd3d_string_buffer_printf(gen->buffer, " %s_main(%s_in, %s_out", gen->prefix, gen->prefix, gen->prefix);
|
2024-11-22 15:45:54 +08:00
|
|
|
if (gen->write_depth)
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, ", shader_out_depth");
|
2025-03-14 23:14:06 +01:00
|
|
|
if (gen->program->descriptors.descriptor_count)
|
2024-10-09 16:36:06 +08:00
|
|
|
vkd3d_string_buffer_printf(gen->buffer, ", descriptors");
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, ");\n");
|
2024-09-30 11:37:15 +08:00
|
|
|
|
2024-09-30 11:51:26 +08:00
|
|
|
msl_generate_entrypoint_epilogue(gen);
|
2024-09-30 11:37:15 +08:00
|
|
|
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, " return output;\n}\n");
|
|
|
|
}
|
|
|
|
|
2024-10-20 21:25:10 +08:00
|
|
|
static int msl_generator_generate(struct msl_generator *gen, struct vkd3d_shader_code *out)
|
2024-08-29 01:21:22 +08:00
|
|
|
{
|
|
|
|
const struct vkd3d_shader_instruction_array *instructions = &gen->program->instructions;
|
|
|
|
unsigned int i;
|
|
|
|
|
2024-08-27 10:34:57 +08:00
|
|
|
MESSAGE("Generating a MSL shader. This is unsupported; you get to keep all the pieces if it breaks.\n");
|
|
|
|
|
2024-09-16 18:37:08 +08:00
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "/* Generated by %s. */\n\n", vkd3d_shader_get_version(NULL, NULL));
|
2024-12-12 15:02:51 +08:00
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "#include <metal_common>\n");
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "#include <metal_texture>\n\n");
|
2024-11-22 15:45:54 +08:00
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "using namespace metal;\n\n");
|
2024-09-16 18:37:08 +08:00
|
|
|
|
2024-10-18 22:38:45 +02:00
|
|
|
if (gen->program->global_flags)
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled global flags %#"PRIx64".", (uint64_t)gen->program->global_flags);
|
|
|
|
|
2024-09-24 02:53:23 +08:00
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "union vkd3d_vec4\n{\n");
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, " uint4 u;\n");
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, " int4 i;\n");
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, " float4 f;\n};\n\n");
|
|
|
|
|
vkd3d-shader/msl: Access descriptors with a type-erased array.
Currently a descriptor set is represented with a structure
whose fields are the various descriptors that the shader is
going to use, each of them qualified with its type. This model
doesn't match very well what happens with D3D12 and with Vulkan
and descriptor indexing and mutable descriptors, where many
descriptor of different types can overlap, and only at shader
runtime it is decided which of them must be used.
Therefore with this patch a descriptor is represented as a
structure whose fields carry no intrinsic typing information,
but are reinterpreted according to the shader behavior on
each access. For the moment there is just one field, but more
will be added to account for fancier descriptor types and
to workaround Metal limitations.
When completed, this design will be similar in spirit to what
the Metal shader converter does, with little technical
differences.
This choice has a couple of drawbacks:
1. shader debugging with Xcode is less comfortable, because
the shader doesn't carry static descriptor typing
information and Xcode is therefore less able to provide
useful context;
2. it requires tier 2 argument buffer support and macOS
version >= 13, which includes guarantees on the runtime
layout for descriptors.
Supporting descriptor indexing and mutable descriptors is
considered to be worthy of those drawbacks, though, is
effectively required by many applications and appears to be
the first goal we should aim for. If needed, in the future
we might also add support for older hardware, at least for
shaders that do not make use of advanced features.
2025-03-11 21:53:10 +01:00
|
|
|
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"
|
2024-12-12 15:02:51 +08:00
|
|
|
" constant T &tex() constant\n"
|
|
|
|
" {\n"
|
|
|
|
" return reinterpret_cast<constant T &>(this->ptr);\n"
|
|
|
|
" }\n"
|
|
|
|
"\n"
|
|
|
|
" template<typename T>\n"
|
vkd3d-shader/msl: Access descriptors with a type-erased array.
Currently a descriptor set is represented with a structure
whose fields are the various descriptors that the shader is
going to use, each of them qualified with its type. This model
doesn't match very well what happens with D3D12 and with Vulkan
and descriptor indexing and mutable descriptors, where many
descriptor of different types can overlap, and only at shader
runtime it is decided which of them must be used.
Therefore with this patch a descriptor is represented as a
structure whose fields carry no intrinsic typing information,
but are reinterpreted according to the shader behavior on
each access. For the moment there is just one field, but more
will be added to account for fancier descriptor types and
to workaround Metal limitations.
When completed, this design will be similar in spirit to what
the Metal shader converter does, with little technical
differences.
This choice has a couple of drawbacks:
1. shader debugging with Xcode is less comfortable, because
the shader doesn't carry static descriptor typing
information and Xcode is therefore less able to provide
useful context;
2. it requires tier 2 argument buffer support and macOS
version >= 13, which includes guarantees on the runtime
layout for descriptors.
Supporting descriptor indexing and mutable descriptors is
considered to be worthy of those drawbacks, though, is
effectively required by many applications and appears to be
the first goal we should aim for. If needed, in the future
we might also add support for older hardware, at least for
shaders that do not make use of advanced features.
2025-03-11 21:53:10 +01:00
|
|
|
" const device T * constant &buf() constant\n"
|
|
|
|
" {\n"
|
|
|
|
" return reinterpret_cast<const device T * constant &>(this->ptr);\n"
|
|
|
|
" }\n"
|
|
|
|
"};\n"
|
|
|
|
"\n");
|
|
|
|
}
|
|
|
|
|
2024-09-30 11:05:26 +08:00
|
|
|
msl_generate_input_struct_declarations(gen);
|
2024-09-30 10:58:02 +08:00
|
|
|
msl_generate_output_struct_declarations(gen);
|
|
|
|
|
2024-09-30 11:37:15 +08:00
|
|
|
vkd3d_string_buffer_printf(gen->buffer,
|
|
|
|
"void %s_main(thread vkd3d_vec4 *v, "
|
2024-10-09 16:36:06 +08:00
|
|
|
"thread vkd3d_vec4 *o",
|
2024-09-30 11:37:15 +08:00
|
|
|
gen->prefix);
|
2024-11-22 15:45:54 +08:00
|
|
|
if (gen->write_depth)
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, ", thread float& o_depth");
|
2025-03-14 23:14:06 +01:00
|
|
|
if (gen->program->descriptors.descriptor_count)
|
vkd3d-shader/msl: Access descriptors with a type-erased array.
Currently a descriptor set is represented with a structure
whose fields are the various descriptors that the shader is
going to use, each of them qualified with its type. This model
doesn't match very well what happens with D3D12 and with Vulkan
and descriptor indexing and mutable descriptors, where many
descriptor of different types can overlap, and only at shader
runtime it is decided which of them must be used.
Therefore with this patch a descriptor is represented as a
structure whose fields carry no intrinsic typing information,
but are reinterpreted according to the shader behavior on
each access. For the moment there is just one field, but more
will be added to account for fancier descriptor types and
to workaround Metal limitations.
When completed, this design will be similar in spirit to what
the Metal shader converter does, with little technical
differences.
This choice has a couple of drawbacks:
1. shader debugging with Xcode is less comfortable, because
the shader doesn't carry static descriptor typing
information and Xcode is therefore less able to provide
useful context;
2. it requires tier 2 argument buffer support and macOS
version >= 13, which includes guarantees on the runtime
layout for descriptors.
Supporting descriptor indexing and mutable descriptors is
considered to be worthy of those drawbacks, though, is
effectively required by many applications and appears to be
the first goal we should aim for. If needed, in the future
we might also add support for older hardware, at least for
shaders that do not make use of advanced features.
2025-03-11 21:53:10 +01:00
|
|
|
vkd3d_string_buffer_printf(gen->buffer, ", constant descriptor *descriptors");
|
2024-10-09 16:36:06 +08:00
|
|
|
vkd3d_string_buffer_printf(gen->buffer, ")\n{\n");
|
2024-09-16 18:35:55 +08:00
|
|
|
|
|
|
|
++gen->indent;
|
2024-09-24 02:53:23 +08:00
|
|
|
|
|
|
|
if (gen->program->temp_count)
|
|
|
|
{
|
|
|
|
msl_print_indent(gen->buffer, gen->indent);
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "vkd3d_vec4 r[%u];\n\n", gen->program->temp_count);
|
|
|
|
}
|
|
|
|
|
2024-08-29 01:21:22 +08:00
|
|
|
for (i = 0; i < instructions->count; ++i)
|
|
|
|
{
|
|
|
|
msl_handle_instruction(gen, &instructions->elements[i]);
|
|
|
|
}
|
|
|
|
|
2024-09-30 11:37:15 +08:00
|
|
|
--gen->indent;
|
|
|
|
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "}\n\n");
|
|
|
|
|
|
|
|
msl_generate_entrypoint(gen);
|
2024-09-16 18:35:55 +08:00
|
|
|
|
2024-08-29 01:21:22 +08:00
|
|
|
if (TRACE_ON())
|
|
|
|
vkd3d_string_buffer_trace(gen->buffer);
|
2024-10-20 21:25:10 +08:00
|
|
|
|
|
|
|
if (gen->failed)
|
|
|
|
return VKD3D_ERROR_INVALID_SHADER;
|
|
|
|
|
|
|
|
vkd3d_shader_code_from_string_buffer(out, gen->buffer);
|
|
|
|
|
|
|
|
return VKD3D_OK;
|
2024-08-29 01:21:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void msl_generator_cleanup(struct msl_generator *gen)
|
|
|
|
{
|
|
|
|
vkd3d_string_buffer_release(&gen->string_buffers, gen->buffer);
|
|
|
|
vkd3d_string_buffer_cache_cleanup(&gen->string_buffers);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int msl_generator_init(struct msl_generator *gen, struct vsir_program *program,
|
2024-10-09 16:36:06 +08:00
|
|
|
const struct vkd3d_shader_compile_info *compile_info,
|
2024-08-29 01:21:22 +08:00
|
|
|
struct vkd3d_shader_message_context *message_context)
|
|
|
|
{
|
2024-09-30 10:58:02 +08:00
|
|
|
enum vkd3d_shader_type type = program->shader_version.type;
|
|
|
|
|
2024-08-29 01:21:22 +08:00
|
|
|
memset(gen, 0, sizeof(*gen));
|
|
|
|
gen->program = program;
|
|
|
|
vkd3d_string_buffer_cache_init(&gen->string_buffers);
|
|
|
|
if (!(gen->buffer = vkd3d_string_buffer_get(&gen->string_buffers)))
|
|
|
|
{
|
|
|
|
vkd3d_string_buffer_cache_cleanup(&gen->string_buffers);
|
|
|
|
return VKD3D_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
gen->message_context = message_context;
|
2024-09-30 10:58:02 +08:00
|
|
|
if (!(gen->prefix = msl_get_prefix(type)))
|
|
|
|
{
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled shader type %#x.", type);
|
2025-04-08 21:32:07 +02:00
|
|
|
gen->prefix = "unknown";
|
2024-09-30 10:58:02 +08:00
|
|
|
}
|
2024-10-09 16:36:06 +08:00
|
|
|
gen->interface_info = vkd3d_find_struct(compile_info->next, INTERFACE_INFO);
|
2024-08-29 01:21:22 +08:00
|
|
|
|
|
|
|
return VKD3D_OK;
|
|
|
|
}
|
|
|
|
|
2024-08-29 01:21:39 +08:00
|
|
|
int msl_compile(struct vsir_program *program, uint64_t config_flags,
|
2024-10-20 21:25:10 +08:00
|
|
|
const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_code *out,
|
|
|
|
struct vkd3d_shader_message_context *message_context)
|
2024-08-29 01:21:22 +08:00
|
|
|
{
|
|
|
|
struct msl_generator generator;
|
|
|
|
int ret;
|
|
|
|
|
2024-08-29 01:21:39 +08:00
|
|
|
if ((ret = vsir_program_transform(program, config_flags, compile_info, message_context)) < 0)
|
|
|
|
return ret;
|
|
|
|
|
2024-12-10 20:18:07 +01:00
|
|
|
VKD3D_ASSERT(program->normalisation_level == VSIR_NORMALISED_SM6);
|
2025-03-15 16:03:50 +01:00
|
|
|
VKD3D_ASSERT(program->has_descriptor_info);
|
2024-10-02 14:44:38 +02:00
|
|
|
|
2025-03-14 23:14:06 +01:00
|
|
|
if ((ret = msl_generator_init(&generator, program, compile_info, message_context)) < 0)
|
2024-08-29 01:21:22 +08:00
|
|
|
return ret;
|
2024-10-20 21:25:10 +08:00
|
|
|
ret = msl_generator_generate(&generator, out);
|
2024-08-29 01:21:22 +08:00
|
|
|
msl_generator_cleanup(&generator);
|
2024-08-27 10:34:57 +08:00
|
|
|
|
2024-10-20 21:25:10 +08:00
|
|
|
return ret;
|
2024-08-27 10:34:57 +08:00
|
|
|
}
|