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-07-27 15:06:06 +02:00
|
|
|
#define MAX_IO_REG_COUNT 32
|
|
|
|
|
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;
|
|
|
|
|
2025-05-19 00:40:37 +02:00
|
|
|
bool read_vertex_id;
|
2024-11-22 15:45:54 +08:00
|
|
|
|
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
|
|
|
|
{
|
2025-05-26 00:18:05 +02:00
|
|
|
/* The number of coordinates needed to address/sample the resource type. */
|
2025-05-24 19:46:59 +02:00
|
|
|
size_t coord_size;
|
2025-05-26 00:18:05 +02:00
|
|
|
/* Whether the resource type is an array type. */
|
2024-12-12 15:02:51 +08:00
|
|
|
bool array;
|
2025-05-26 00:18:05 +02:00
|
|
|
/* Whether the resource type has a shadow/comparison variant. */
|
|
|
|
bool comparison;
|
2025-05-26 21:11:13 +02:00
|
|
|
/* Whether the resource type supports texel sample offsets. */
|
|
|
|
bool offset;
|
2025-05-26 10:12:51 +02:00
|
|
|
/* The type suffix for the resource type. I.e., the "2d_ms" part of
|
|
|
|
* "texture2d_ms_array" or "depth2d_ms_array". */
|
2024-12-12 15:02:51 +08:00
|
|
|
const char *type_suffix;
|
|
|
|
};
|
|
|
|
|
2025-05-18 22:49:16 +02:00
|
|
|
static void msl_print_subscript(struct vkd3d_string_buffer *buffer, struct msl_generator *gen,
|
|
|
|
const struct vkd3d_shader_src_param *rel_addr, unsigned int offset);
|
|
|
|
|
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[] =
|
|
|
|
{
|
2025-05-26 21:11:13 +02:00
|
|
|
[VKD3D_SHADER_RESOURCE_NONE] = {0, 0, 0, 0, "none"},
|
|
|
|
[VKD3D_SHADER_RESOURCE_BUFFER] = {1, 0, 0, 0, "_buffer"},
|
|
|
|
[VKD3D_SHADER_RESOURCE_TEXTURE_1D] = {1, 0, 0, 0, "1d"},
|
|
|
|
[VKD3D_SHADER_RESOURCE_TEXTURE_2D] = {2, 0, 1, 1, "2d"},
|
|
|
|
[VKD3D_SHADER_RESOURCE_TEXTURE_2DMS] = {2, 0, 1, 0, "2d_ms"},
|
|
|
|
[VKD3D_SHADER_RESOURCE_TEXTURE_3D] = {3, 0, 0, 1, "3d"},
|
|
|
|
[VKD3D_SHADER_RESOURCE_TEXTURE_CUBE] = {3, 0, 1, 0, "cube"},
|
|
|
|
[VKD3D_SHADER_RESOURCE_TEXTURE_1DARRAY] = {1, 1, 0, 0, "1d"},
|
|
|
|
[VKD3D_SHADER_RESOURCE_TEXTURE_2DARRAY] = {2, 1, 1, 1, "2d"},
|
|
|
|
[VKD3D_SHADER_RESOURCE_TEXTURE_2DMSARRAY] = {2, 1, 1, 0, "2d_ms"},
|
|
|
|
[VKD3D_SHADER_RESOURCE_TEXTURE_CUBEARRAY] = {3, 1, 1, 0, "cube"},
|
2024-12-12 15:02:51 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
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-07-17 15:22:54 +02:00
|
|
|
struct vkd3d_string_buffer *buffer, enum vsir_data_type data_type)
|
2024-12-12 15:02:51 +08:00
|
|
|
{
|
|
|
|
switch (data_type)
|
|
|
|
{
|
2025-07-17 15:55:17 +02:00
|
|
|
case VSIR_DATA_F32:
|
2025-07-21 15:09:30 +02:00
|
|
|
case VSIR_DATA_SNORM:
|
2025-07-21 15:05:46 +02:00
|
|
|
case VSIR_DATA_UNORM:
|
2024-12-12 15:02:51 +08:00
|
|
|
vkd3d_string_buffer_printf(buffer, "float");
|
|
|
|
break;
|
2025-07-17 16:29:38 +02:00
|
|
|
case VSIR_DATA_I32:
|
2024-12-12 15:02:51 +08:00
|
|
|
vkd3d_string_buffer_printf(buffer, "int");
|
|
|
|
break;
|
2025-07-17 16:47:43 +02:00
|
|
|
case VSIR_DATA_U32:
|
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,
|
2025-07-17 15:22:54 +02:00
|
|
|
struct msl_generator *gen, enum vsir_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
|
|
|
{
|
2025-07-17 15:55:17 +02:00
|
|
|
case VSIR_DATA_F32:
|
2024-09-24 02:53:23 +08:00
|
|
|
vkd3d_string_buffer_printf(buffer, "f");
|
|
|
|
break;
|
2025-07-17 16:29:38 +02:00
|
|
|
case VSIR_DATA_I32:
|
2024-09-24 02:53:23 +08:00
|
|
|
vkd3d_string_buffer_printf(buffer, "i");
|
|
|
|
break;
|
2025-07-17 16:47:43 +02:00
|
|
|
case VSIR_DATA_U32:
|
2024-09-24 02:53:23 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2025-05-24 19:46:59 +02:00
|
|
|
static const struct vkd3d_shader_descriptor_binding *msl_get_sampler_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;
|
|
|
|
const struct vkd3d_shader_resource_binding *binding;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
if (!interface_info)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
for (i = 0; i < interface_info->binding_count; ++i)
|
|
|
|
{
|
|
|
|
binding = &interface_info->bindings[i];
|
|
|
|
|
|
|
|
if (binding->type != VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER)
|
|
|
|
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;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2025-05-28 22:52:18 +02:00
|
|
|
static const struct vkd3d_shader_descriptor_binding *msl_get_uav_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;
|
|
|
|
const struct vkd3d_shader_resource_binding *binding;
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
binding = &interface_info->bindings[i];
|
|
|
|
|
|
|
|
if (binding->type != VKD3D_SHADER_DESCRIPTOR_TYPE_UAV)
|
|
|
|
continue;
|
|
|
|
if (binding->register_space != register_space)
|
|
|
|
continue;
|
|
|
|
if (binding->register_index != register_idx)
|
|
|
|
continue;
|
|
|
|
if (!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-05-24 19:46:59 +02:00
|
|
|
static void msl_print_sampler_name(struct vkd3d_string_buffer *buffer, unsigned int binding)
|
|
|
|
{
|
|
|
|
vkd3d_string_buffer_printf(buffer, "descriptors[%u].as<sampler>()", 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,
|
2025-07-17 15:22:54 +02:00
|
|
|
const struct msl_resource_type_info *resource_type_info, enum vsir_data_type resource_data_type, bool compare)
|
2024-12-12 15:02:51 +08:00
|
|
|
{
|
2025-05-26 10:12:51 +02:00
|
|
|
vkd3d_string_buffer_printf(buffer, "descriptors[%u].as<%s%s%s<",
|
|
|
|
binding, compare ? "depth" : "texture", resource_type_info->type_suffix,
|
|
|
|
resource_type_info->array ? "_array" : "");
|
2024-12-12 15:02:51 +08:00
|
|
|
msl_print_resource_datatype(gen, buffer, resource_data_type);
|
|
|
|
vkd3d_string_buffer_printf(buffer, ">>()");
|
|
|
|
}
|
|
|
|
|
2025-05-28 22:52:18 +02:00
|
|
|
static void msl_print_uav_name(struct vkd3d_string_buffer *buffer, struct msl_generator *gen, unsigned int binding,
|
2025-07-17 15:22:54 +02:00
|
|
|
const struct msl_resource_type_info *resource_type_info, enum vsir_data_type resource_data_type)
|
2025-05-28 22:52:18 +02:00
|
|
|
{
|
|
|
|
vkd3d_string_buffer_printf(buffer, "descriptors[%u].as<texture%s%s<",
|
|
|
|
binding, resource_type_info->type_suffix,
|
|
|
|
resource_type_info->array ? "_array" : "");
|
|
|
|
msl_print_resource_datatype(gen, buffer, resource_data_type);
|
|
|
|
vkd3d_string_buffer_printf(buffer, ", access::read_write>>()");
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
2025-05-18 22:49:16 +02:00
|
|
|
if (reg->idx[0].rel_addr || reg->idx[1].rel_addr)
|
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_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
|
|
|
}
|
2025-05-26 14:10:45 +02:00
|
|
|
/* FIXME: This should use vkd3d_shader_find_descriptor() to
|
|
|
|
* find the resource index/space from the resource ID. */
|
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,
|
2025-05-26 14:10:45 +02:00
|
|
|
"No descriptor binding specified for CBV %u.", reg->idx[0].offset);
|
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(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);
|
2025-05-18 22:49:16 +02:00
|
|
|
msl_print_subscript(buffer, gen, reg->idx[2].rel_addr, reg->idx[2].offset);
|
2025-04-28 15:20:52 +02:00
|
|
|
return MSL_DATA_UNION;
|
2024-10-09 16:41:52 +08:00
|
|
|
}
|
|
|
|
|
2025-05-22 22:37:28 +02:00
|
|
|
case VKD3DSPR_IDXTEMP:
|
|
|
|
vkd3d_string_buffer_printf(buffer, "x%u", reg->idx[0].offset);
|
|
|
|
msl_print_subscript(buffer, gen, reg->idx[1].rel_addr, reg->idx[1].offset);
|
|
|
|
return MSL_DATA_UNION;
|
|
|
|
|
2025-05-23 09:32:21 +02:00
|
|
|
case VKD3DSPR_SAMPLEMASK:
|
|
|
|
if (gen->program->shader_version.type != VKD3D_SHADER_TYPE_PIXEL)
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled sample coverage mask in shader type #%x.",
|
|
|
|
gen->program->shader_version.type);
|
|
|
|
vkd3d_string_buffer_printf(buffer, "o_mask");
|
2025-07-15 20:59:34 +02:00
|
|
|
return MSL_DATA_UNION;
|
2025-05-23 09:32:21 +02: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,
|
2025-07-17 15:22:54 +02:00
|
|
|
enum vsir_data_type dst_data_type, enum msl_data_type src_data_type, enum vsir_dimension dimension)
|
2025-04-28 15:20:52 +02:00
|
|
|
{
|
|
|
|
bool write_cast = false;
|
|
|
|
|
2025-07-21 15:09:30 +02:00
|
|
|
if (dst_data_type == VSIR_DATA_UNORM || dst_data_type == VSIR_DATA_SNORM)
|
2025-07-17 15:55:17 +02:00
|
|
|
dst_data_type = VSIR_DATA_F32;
|
2025-04-28 15:20:52 +02:00
|
|
|
|
|
|
|
switch (src_data_type)
|
|
|
|
{
|
|
|
|
case MSL_DATA_FLOAT:
|
2025-07-17 15:55:17 +02:00
|
|
|
write_cast = dst_data_type != VSIR_DATA_F32;
|
2025-04-28 15:20:52 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MSL_DATA_UINT:
|
2025-07-17 16:47:43 +02:00
|
|
|
write_cast = dst_data_type != VSIR_DATA_U32;
|
2025-04-28 15:20:52 +02:00
|
|
|
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,
|
2025-07-17 15:22:54 +02:00
|
|
|
const struct vkd3d_shader_src_param *vsir_src, uint32_t mask, enum vsir_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;
|
2025-05-29 21:46:30 +02:00
|
|
|
case VKD3DSPSM_ABSNEG:
|
|
|
|
vkd3d_string_buffer_printf(buffer, "-abs(%s)", str->buffer);
|
|
|
|
break;
|
2024-11-22 15:45:54 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2025-05-18 22:49:16 +02:00
|
|
|
static void msl_print_subscript(struct vkd3d_string_buffer *buffer, struct msl_generator *gen,
|
|
|
|
const struct vkd3d_shader_src_param *rel_addr, unsigned int offset)
|
|
|
|
{
|
|
|
|
struct msl_src r;
|
|
|
|
|
|
|
|
if (!rel_addr)
|
|
|
|
{
|
|
|
|
vkd3d_string_buffer_printf(buffer, "[%u]", offset);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
msl_src_init(&r, gen, rel_addr, VKD3DSP_WRITEMASK_0);
|
|
|
|
vkd3d_string_buffer_printf(buffer, "[%s", r.str->buffer);
|
|
|
|
if (offset)
|
|
|
|
vkd3d_string_buffer_printf(buffer, " + %u", offset);
|
|
|
|
vkd3d_string_buffer_printf(buffer, "]");
|
|
|
|
msl_src_cleanup(&r, &gen->string_buffers);
|
|
|
|
}
|
|
|
|
|
2024-09-17 20:50:44 +08:00
|
|
|
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;
|
|
|
|
|
2025-05-29 21:47:38 +02:00
|
|
|
/* It is always legitimate to ignore _pp. */
|
|
|
|
modifiers &= ~VKD3DSPDM_PARTIALPRECISION;
|
|
|
|
|
2024-09-17 20:50:44 +08:00
|
|
|
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)
|
|
|
|
{
|
2025-06-03 13:55:11 +02:00
|
|
|
const char *name = vsir_opcode_get_name(ins->opcode, "<unknown>");
|
|
|
|
|
2024-09-16 18:35:55 +08:00
|
|
|
msl_print_indent(gen->buffer, gen->indent);
|
2025-06-03 13:55:11 +02:00
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "/* <unhandled instruction \"%s\" (%#x)> */\n", name, ins->opcode);
|
2024-08-29 01:21:22 +08:00
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
2025-06-03 13:55:11 +02:00
|
|
|
"Internal compiler error: Unhandled instruction \"%s\" (%#x).", name, ins->opcode);
|
2024-08-29 01:21:22 +08:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2025-05-23 16:53:38 +02:00
|
|
|
static void msl_print_condition(struct vkd3d_string_buffer *buffer, struct msl_generator *gen,
|
|
|
|
enum vkd3d_shader_conditional_op op, const struct vkd3d_shader_src_param *arg)
|
2024-12-03 00:06:32 +08:00
|
|
|
{
|
|
|
|
const char *condition;
|
|
|
|
struct msl_src src;
|
|
|
|
|
2025-05-23 16:53:38 +02:00
|
|
|
msl_src_init(&src, gen, arg, VKD3DSP_WRITEMASK_0);
|
2024-12-03 00:06:32 +08:00
|
|
|
|
2025-05-23 16:53:38 +02:00
|
|
|
condition = op == VKD3D_SHADER_CONDITIONAL_OP_NZ ? "bool" : "!bool";
|
|
|
|
vkd3d_string_buffer_printf(buffer, "if (%s(%s))\n", condition, src.str->buffer);
|
2024-12-03 00:06:32 +08:00
|
|
|
|
|
|
|
msl_src_cleanup(&src, &gen->string_buffers);
|
2025-05-23 16:53:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void msl_discard(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins)
|
|
|
|
{
|
|
|
|
/* Note that discard_fragment() in Metal 2.2 and earlier behaves like
|
|
|
|
* SPIR-V OpKill, while in Metal 2.3 and later it behaves like
|
|
|
|
* OpDemoteToHelperInvocationEXT. We assume we have at least Metal 3
|
|
|
|
* here. */
|
|
|
|
msl_print_indent(gen->buffer, gen->indent);
|
|
|
|
msl_print_condition(gen->buffer, gen, ins->flags, &ins->src[0]);
|
|
|
|
msl_print_indent(gen->buffer, gen->indent + 1);
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "discard_fragment();\n");
|
|
|
|
}
|
2024-12-03 00:06:32 +08:00
|
|
|
|
2025-05-23 16:53:38 +02:00
|
|
|
static void msl_if(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins)
|
|
|
|
{
|
|
|
|
msl_print_indent(gen->buffer, gen->indent);
|
|
|
|
msl_print_condition(gen->buffer, gen, ins->flags, &ins->src[0]);
|
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
|
|
|
}
|
|
|
|
|
2025-05-23 15:45:11 +02:00
|
|
|
static void msl_loop(struct msl_generator *gen)
|
|
|
|
{
|
|
|
|
msl_print_indent(gen->buffer, gen->indent);
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "for (;;)\n");
|
|
|
|
msl_begin_block(gen);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void msl_break(struct msl_generator *gen)
|
|
|
|
{
|
|
|
|
msl_print_indent(gen->buffer, gen->indent);
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "break;\n");
|
|
|
|
}
|
|
|
|
|
2025-05-28 10:14:33 +02:00
|
|
|
static void msl_continue(struct msl_generator *gen)
|
|
|
|
{
|
|
|
|
msl_print_indent(gen->buffer, gen->indent);
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "continue;\n");
|
|
|
|
}
|
|
|
|
|
2025-05-23 16:15:49 +02:00
|
|
|
static void msl_switch(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins)
|
|
|
|
{
|
|
|
|
struct msl_src src;
|
|
|
|
|
|
|
|
msl_src_init(&src, gen, &ins->src[0], VKD3DSP_WRITEMASK_0);
|
|
|
|
|
|
|
|
msl_print_indent(gen->buffer, gen->indent);
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "switch (%s)\n", src.str->buffer);
|
|
|
|
msl_begin_block(gen);
|
|
|
|
|
|
|
|
msl_src_cleanup(&src, &gen->string_buffers);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void msl_case(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins)
|
|
|
|
{
|
|
|
|
struct msl_src src;
|
|
|
|
|
|
|
|
msl_src_init(&src, gen, &ins->src[0], VKD3DSP_WRITEMASK_0);
|
|
|
|
|
|
|
|
msl_print_indent(gen->buffer, gen->indent);
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "case %s:\n", src.str->buffer);
|
|
|
|
|
|
|
|
msl_src_cleanup(&src, &gen->string_buffers);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void msl_default(struct msl_generator *gen)
|
|
|
|
{
|
|
|
|
msl_print_indent(gen->buffer, gen->indent);
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "default:\n");
|
|
|
|
}
|
|
|
|
|
2025-05-27 23:56:53 +02:00
|
|
|
static void msl_print_texel_offset(struct vkd3d_string_buffer *buffer, struct msl_generator *gen,
|
|
|
|
unsigned int offset_size, const struct vkd3d_shader_texel_offset *offset)
|
|
|
|
{
|
|
|
|
switch (offset_size)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
vkd3d_string_buffer_printf(buffer, "%d", offset->u);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
vkd3d_string_buffer_printf(buffer, "int2(%d, %d)", offset->u, offset->v);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Invalid texel offset size %u.", offset_size);
|
|
|
|
/* fall through */
|
|
|
|
case 3:
|
|
|
|
vkd3d_string_buffer_printf(buffer, "int3(%d, %d, %d)", offset->u, offset->v, offset->w);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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;
|
2025-07-27 15:39:33 +02:00
|
|
|
uint32_t coord_mask, write_mask_size;
|
2024-12-12 15:02:51 +08:00
|
|
|
struct vkd3d_string_buffer *read;
|
2025-07-17 15:22:54 +02:00
|
|
|
enum vsir_data_type data_type;
|
2025-05-26 14:28:10 +02:00
|
|
|
unsigned int srv_binding;
|
2024-12-12 15:02:51 +08:00
|
|
|
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-07-17 15:55:17 +02:00
|
|
|
data_type = VSIR_DATA_F32;
|
2024-12-12 15:02:51 +08:00
|
|
|
}
|
|
|
|
|
2025-05-26 22:15:36 +02:00
|
|
|
if (resource_type == VKD3D_SHADER_RESOURCE_TEXTURE_CUBE
|
|
|
|
|| resource_type == VKD3D_SHADER_RESOURCE_TEXTURE_CUBEARRAY
|
2025-06-24 13:11:57 +02:00
|
|
|
|| (ins->opcode != VSIR_OP_LD2DMS
|
2025-05-26 22:15:36 +02:00
|
|
|
&& (resource_type == VKD3D_SHADER_RESOURCE_TEXTURE_2DMS
|
|
|
|
|| resource_type == VKD3D_SHADER_RESOURCE_TEXTURE_2DMSARRAY)))
|
2025-05-26 13:14:19 +02:00
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_UNSUPPORTED,
|
|
|
|
"Texel fetches from resource type %#x are not supported.", resource_type);
|
|
|
|
|
2025-05-26 13:10:03 +02:00
|
|
|
if (!(resource_type_info = msl_get_resource_type_info(resource_type)))
|
2024-12-12 15:02:51 +08:00
|
|
|
{
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled resource type %#x.", resource_type);
|
2025-05-26 13:10:03 +02:00
|
|
|
resource_type_info = msl_get_resource_type_info(VKD3D_SHADER_RESOURCE_TEXTURE_2D);
|
2024-12-12 15:02:51 +08:00
|
|
|
}
|
2025-05-24 19:46:59 +02:00
|
|
|
coord_mask = vkd3d_write_mask_from_component_count(resource_type_info->coord_size);
|
2024-12-12 15:02:51 +08:00
|
|
|
|
2025-05-26 14:28:10 +02:00
|
|
|
if ((binding = msl_get_srv_binding(gen, resource_space, resource_idx, resource_type)))
|
|
|
|
{
|
|
|
|
srv_binding = binding->binding;
|
|
|
|
}
|
|
|
|
else
|
2024-12-12 15:02:51 +08:00
|
|
|
{
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_BINDING_NOT_FOUND,
|
2025-05-26 14:10:45 +02:00
|
|
|
"No descriptor binding specified for SRV %u (index %u, space %u).",
|
2024-12-12 15:02:51 +08:00
|
|
|
resource_id, resource_idx, resource_space);
|
2025-05-26 14:28:10 +02:00
|
|
|
srv_binding = 0;
|
2024-12-12 15:02:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
msl_dst_init(&dst, gen, ins, &ins->dst[0]);
|
|
|
|
read = vkd3d_string_buffer_get(&gen->string_buffers);
|
|
|
|
|
2025-07-27 15:39:33 +02:00
|
|
|
vkd3d_string_buffer_printf(read, "as_type<");
|
|
|
|
msl_print_resource_datatype(gen, read, ins->dst[0].reg.data_type);
|
|
|
|
write_mask_size = vkd3d_popcount(ins->dst[0].write_mask);
|
|
|
|
if (write_mask_size != 1)
|
|
|
|
vkd3d_string_buffer_printf(read, "%u", write_mask_size);
|
|
|
|
vkd3d_string_buffer_printf(read, ">(");
|
2025-05-26 00:18:05 +02:00
|
|
|
msl_print_srv_name(read, gen, srv_binding, resource_type_info, data_type, false);
|
2024-12-12 15:02:51 +08:00
|
|
|
vkd3d_string_buffer_printf(read, ".read(");
|
2025-07-17 16:47:43 +02:00
|
|
|
msl_print_src_with_type(read, gen, &ins->src[0], coord_mask, VSIR_DATA_U32);
|
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, ", ");
|
2025-07-17 16:47:43 +02:00
|
|
|
msl_print_src_with_type(read, gen, &ins->src[0], coord_mask + 1, VSIR_DATA_U32);
|
2025-04-28 15:33:57 +02:00
|
|
|
}
|
2025-05-26 13:34:23 +02:00
|
|
|
if (resource_type != VKD3D_SHADER_RESOURCE_BUFFER)
|
2025-04-28 15:33:57 +02:00
|
|
|
{
|
|
|
|
vkd3d_string_buffer_printf(read, ", ");
|
2025-06-24 13:11:57 +02:00
|
|
|
if (ins->opcode != VSIR_OP_LD2DMS)
|
2025-07-17 16:47:43 +02:00
|
|
|
msl_print_src_with_type(read, gen, &ins->src[0], VKD3DSP_WRITEMASK_3, VSIR_DATA_U32);
|
2025-05-26 22:15:36 +02:00
|
|
|
else
|
2025-07-17 16:47:43 +02:00
|
|
|
msl_print_src_with_type(read, gen, &ins->src[2], VKD3DSP_WRITEMASK_0, VSIR_DATA_U32);
|
2025-04-28 15:33:57 +02:00
|
|
|
}
|
2025-07-27 15:39:33 +02:00
|
|
|
vkd3d_string_buffer_printf(read, ")");
|
2024-12-12 15:02:51 +08:00
|
|
|
msl_print_swizzle(read, ins->src[1].swizzle, ins->dst[0].write_mask);
|
2025-07-27 15:39:33 +02:00
|
|
|
vkd3d_string_buffer_printf(read, ")");
|
2024-12-12 15:02:51 +08:00
|
|
|
|
|
|
|
msl_print_assignment(gen, &dst, "%s", read->buffer);
|
|
|
|
|
|
|
|
vkd3d_string_buffer_release(&gen->string_buffers, read);
|
|
|
|
msl_dst_cleanup(&dst, &gen->string_buffers);
|
|
|
|
}
|
|
|
|
|
2025-05-24 19:46:59 +02:00
|
|
|
static void msl_sample(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins)
|
|
|
|
{
|
2025-05-27 23:56:53 +02:00
|
|
|
bool bias, compare, comparison_sampler, dynamic_offset, gather, grad, lod, lod_zero, offset;
|
2025-05-24 19:46:59 +02:00
|
|
|
const struct msl_resource_type_info *resource_type_info;
|
2025-05-27 23:42:48 +02:00
|
|
|
const struct vkd3d_shader_src_param *resource, *sampler;
|
2025-05-24 19:46:59 +02:00
|
|
|
unsigned int resource_id, resource_idx, resource_space;
|
|
|
|
const struct vkd3d_shader_descriptor_binding *binding;
|
|
|
|
unsigned int sampler_id, sampler_idx, sampler_space;
|
|
|
|
const struct vkd3d_shader_descriptor_info1 *d;
|
|
|
|
enum vkd3d_shader_resource_type resource_type;
|
|
|
|
unsigned int srv_binding, sampler_binding;
|
2025-07-27 15:39:33 +02:00
|
|
|
uint32_t coord_mask, write_mask_size;
|
2025-05-24 19:46:59 +02:00
|
|
|
struct vkd3d_string_buffer *sample;
|
2025-07-17 15:22:54 +02:00
|
|
|
enum vsir_data_type data_type;
|
2025-05-26 21:11:13 +02:00
|
|
|
unsigned int component_idx;
|
2025-05-24 19:46:59 +02:00
|
|
|
struct msl_dst dst;
|
2025-05-25 23:10:03 +02:00
|
|
|
|
2025-06-24 13:11:57 +02:00
|
|
|
bias = ins->opcode == VSIR_OP_SAMPLE_B;
|
|
|
|
compare = ins->opcode == VSIR_OP_GATHER4_C || ins->opcode == VSIR_OP_SAMPLE_C
|
|
|
|
|| ins->opcode == VSIR_OP_SAMPLE_C_LZ;
|
|
|
|
dynamic_offset = ins->opcode == VSIR_OP_GATHER4_PO;
|
|
|
|
gather = ins->opcode == VSIR_OP_GATHER4 || ins->opcode == VSIR_OP_GATHER4_C
|
|
|
|
|| ins->opcode == VSIR_OP_GATHER4_PO;
|
|
|
|
grad = ins->opcode == VSIR_OP_SAMPLE_GRAD;
|
|
|
|
lod = ins->opcode == VSIR_OP_SAMPLE_LOD;
|
|
|
|
lod_zero = ins->opcode == VSIR_OP_SAMPLE_C_LZ;
|
2025-05-27 23:56:53 +02:00
|
|
|
offset = dynamic_offset || vkd3d_shader_instruction_has_texel_offset(ins);
|
2025-05-27 23:42:48 +02:00
|
|
|
|
2025-05-27 23:56:53 +02:00
|
|
|
resource = &ins->src[1 + dynamic_offset];
|
|
|
|
sampler = &ins->src[2 + dynamic_offset];
|
2025-05-24 19:46:59 +02:00
|
|
|
|
2025-05-27 23:42:48 +02:00
|
|
|
if (resource->reg.idx[0].rel_addr || resource->reg.idx[1].rel_addr
|
|
|
|
|| sampler->reg.idx[0].rel_addr || sampler->reg.idx[1].rel_addr)
|
2025-05-24 19:46:59 +02:00
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_UNSUPPORTED,
|
|
|
|
"Descriptor indexing is not supported.");
|
|
|
|
|
2025-05-27 23:42:48 +02:00
|
|
|
resource_id = resource->reg.idx[0].offset;
|
|
|
|
resource_idx = resource->reg.idx[1].offset;
|
2025-05-24 19:46:59 +02:00
|
|
|
if ((d = vkd3d_shader_find_descriptor(&gen->program->descriptors,
|
|
|
|
VKD3D_SHADER_DESCRIPTOR_TYPE_SRV, resource_id)))
|
|
|
|
{
|
|
|
|
resource_space = d->register_space;
|
|
|
|
resource_type = d->resource_type;
|
|
|
|
data_type = d->resource_data_type;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Undeclared resource descriptor %u.", resource_id);
|
|
|
|
resource_space = 0;
|
|
|
|
resource_type = VKD3D_SHADER_RESOURCE_TEXTURE_2D;
|
2025-07-17 15:55:17 +02:00
|
|
|
data_type = VSIR_DATA_F32;
|
2025-05-24 19:46:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (resource_type == VKD3D_SHADER_RESOURCE_BUFFER
|
|
|
|
|| resource_type == VKD3D_SHADER_RESOURCE_TEXTURE_2DMS
|
|
|
|
|| resource_type == VKD3D_SHADER_RESOURCE_TEXTURE_2DMSARRAY)
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_UNSUPPORTED,
|
|
|
|
"Sampling resource type %#x is not supported.", resource_type);
|
|
|
|
|
2025-05-25 23:10:03 +02:00
|
|
|
if ((resource_type == VKD3D_SHADER_RESOURCE_TEXTURE_1D || resource_type == VKD3D_SHADER_RESOURCE_TEXTURE_1DARRAY)
|
2025-05-26 10:27:34 +02:00
|
|
|
&& (bias || grad || lod || lod_zero))
|
2025-05-25 23:10:03 +02:00
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_UNSUPPORTED,
|
|
|
|
"Resource type %#x does not support mipmapping.", resource_type);
|
|
|
|
|
2025-05-26 21:11:13 +02:00
|
|
|
if ((resource_type == VKD3D_SHADER_RESOURCE_TEXTURE_1D || resource_type == VKD3D_SHADER_RESOURCE_TEXTURE_1DARRAY
|
|
|
|
|| resource_type == VKD3D_SHADER_RESOURCE_TEXTURE_3D) && gather)
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_UNSUPPORTED,
|
|
|
|
"Resource type %#x does not support gather operations.", resource_type);
|
|
|
|
|
2025-05-24 19:46:59 +02:00
|
|
|
if (!(resource_type_info = msl_get_resource_type_info(resource_type)))
|
|
|
|
{
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled resource type %#x.", resource_type);
|
|
|
|
resource_type_info = msl_get_resource_type_info(VKD3D_SHADER_RESOURCE_TEXTURE_2D);
|
|
|
|
}
|
|
|
|
coord_mask = vkd3d_write_mask_from_component_count(resource_type_info->coord_size);
|
|
|
|
|
|
|
|
if ((binding = msl_get_srv_binding(gen, resource_space, resource_idx, resource_type)))
|
|
|
|
{
|
|
|
|
srv_binding = binding->binding;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_BINDING_NOT_FOUND,
|
|
|
|
"No descriptor binding specified for SRV %u (index %u, space %u).",
|
|
|
|
resource_id, resource_idx, resource_space);
|
|
|
|
srv_binding = 0;
|
|
|
|
}
|
|
|
|
|
2025-05-27 23:42:48 +02:00
|
|
|
sampler_id = sampler->reg.idx[0].offset;
|
|
|
|
sampler_idx = sampler->reg.idx[1].offset;
|
2025-05-24 19:46:59 +02:00
|
|
|
if ((d = vkd3d_shader_find_descriptor(&gen->program->descriptors,
|
|
|
|
VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER, sampler_id)))
|
|
|
|
{
|
|
|
|
sampler_space = d->register_space;
|
2025-05-26 00:18:05 +02:00
|
|
|
comparison_sampler = d->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_SAMPLER_COMPARISON_MODE;
|
|
|
|
|
|
|
|
if (compare)
|
|
|
|
{
|
|
|
|
if (!comparison_sampler)
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Sampler %u is not a comparison sampler.", sampler_id);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (comparison_sampler)
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Sampler %u is a comparison sampler.", sampler_id);
|
|
|
|
}
|
2025-05-24 19:46:59 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Undeclared sampler descriptor %u.", sampler_id);
|
|
|
|
sampler_space = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((binding = msl_get_sampler_binding(gen, sampler_space, sampler_idx)))
|
|
|
|
{
|
|
|
|
sampler_binding = binding->binding;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_BINDING_NOT_FOUND,
|
|
|
|
"No descriptor binding specified for sampler %u (index %u, space %u).",
|
|
|
|
sampler_id, sampler_idx, sampler_space);
|
|
|
|
sampler_binding = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
msl_dst_init(&dst, gen, ins, &ins->dst[0]);
|
|
|
|
sample = vkd3d_string_buffer_get(&gen->string_buffers);
|
|
|
|
|
2025-07-27 15:39:33 +02:00
|
|
|
vkd3d_string_buffer_printf(sample, "as_type<");
|
|
|
|
msl_print_resource_datatype(gen, sample, ins->dst[0].reg.data_type);
|
|
|
|
write_mask_size = vkd3d_popcount(ins->dst[0].write_mask);
|
|
|
|
if (write_mask_size != 1)
|
|
|
|
vkd3d_string_buffer_printf(sample, "%u", write_mask_size);
|
|
|
|
vkd3d_string_buffer_printf(sample, ">(");
|
2025-05-26 00:18:05 +02:00
|
|
|
msl_print_srv_name(sample, gen, srv_binding, resource_type_info, data_type, compare);
|
2025-05-27 23:18:09 +02:00
|
|
|
if (gather && compare)
|
|
|
|
vkd3d_string_buffer_printf(sample, ".gather_compare(");
|
|
|
|
else if (gather)
|
2025-05-26 21:11:13 +02:00
|
|
|
vkd3d_string_buffer_printf(sample, ".gather(");
|
|
|
|
else if (compare)
|
2025-05-26 00:18:05 +02:00
|
|
|
vkd3d_string_buffer_printf(sample, ".sample_compare(");
|
|
|
|
else
|
|
|
|
vkd3d_string_buffer_printf(sample, ".sample(");
|
2025-05-24 19:46:59 +02:00
|
|
|
msl_print_sampler_name(sample, sampler_binding);
|
|
|
|
vkd3d_string_buffer_printf(sample, ", ");
|
|
|
|
msl_print_src_with_type(sample, gen, &ins->src[0], coord_mask, ins->src[0].reg.data_type);
|
|
|
|
if (resource_type_info->array)
|
|
|
|
{
|
|
|
|
vkd3d_string_buffer_printf(sample, ", uint(");
|
|
|
|
msl_print_src_with_type(sample, gen, &ins->src[0], coord_mask + 1, ins->src[0].reg.data_type);
|
|
|
|
vkd3d_string_buffer_printf(sample, ")");
|
|
|
|
}
|
2025-05-26 00:18:05 +02:00
|
|
|
if (compare)
|
|
|
|
{
|
|
|
|
if (!resource_type_info->comparison)
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_UNSUPPORTED,
|
|
|
|
"Comparison samplers are not supported with resource type %#x.", resource_type);
|
|
|
|
vkd3d_string_buffer_printf(sample, ", ");
|
|
|
|
msl_print_src_with_type(sample, gen, &ins->src[3], VKD3DSP_WRITEMASK_0, ins->src[3].reg.data_type);
|
|
|
|
}
|
2025-05-26 10:12:51 +02:00
|
|
|
if (grad)
|
|
|
|
{
|
|
|
|
vkd3d_string_buffer_printf(sample, ", gradient%s(", resource_type_info->type_suffix);
|
|
|
|
msl_print_src_with_type(sample, gen, &ins->src[3], coord_mask, ins->src[3].reg.data_type);
|
|
|
|
vkd3d_string_buffer_printf(sample, ", ");
|
|
|
|
msl_print_src_with_type(sample, gen, &ins->src[4], coord_mask, ins->src[4].reg.data_type);
|
|
|
|
vkd3d_string_buffer_printf(sample, ")");
|
|
|
|
}
|
2025-05-26 00:30:36 +02:00
|
|
|
if (lod_zero)
|
|
|
|
{
|
|
|
|
vkd3d_string_buffer_printf(sample, ", level(0.0f)");
|
|
|
|
}
|
2025-05-26 10:27:34 +02:00
|
|
|
else if (lod)
|
|
|
|
{
|
|
|
|
vkd3d_string_buffer_printf(sample, ", level(");
|
|
|
|
msl_print_src_with_type(sample, gen, &ins->src[3], VKD3DSP_WRITEMASK_0, ins->src[3].reg.data_type);
|
|
|
|
vkd3d_string_buffer_printf(sample, ")");
|
|
|
|
}
|
2025-05-25 23:10:03 +02:00
|
|
|
if (bias)
|
|
|
|
{
|
|
|
|
vkd3d_string_buffer_printf(sample, ", bias(");
|
|
|
|
msl_print_src_with_type(sample, gen, &ins->src[3], VKD3DSP_WRITEMASK_0, ins->src[3].reg.data_type);
|
|
|
|
vkd3d_string_buffer_printf(sample, ")");
|
|
|
|
}
|
2025-05-27 23:42:48 +02:00
|
|
|
if (offset)
|
|
|
|
{
|
|
|
|
if (!resource_type_info->offset)
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_UNSUPPORTED,
|
|
|
|
"Texel sample offsets are not supported with resource type %#x.", resource_type);
|
|
|
|
vkd3d_string_buffer_printf(sample, ", ");
|
2025-05-27 23:56:53 +02:00
|
|
|
if (dynamic_offset)
|
|
|
|
msl_print_src_with_type(sample, gen, &ins->src[1], coord_mask, ins->src[1].reg.data_type);
|
|
|
|
else
|
|
|
|
msl_print_texel_offset(sample, gen, resource_type_info->coord_size, &ins->texel_offset);
|
2025-05-27 23:42:48 +02:00
|
|
|
}
|
|
|
|
if (gather && !compare && (component_idx = vsir_swizzle_get_component(sampler->swizzle, 0)))
|
2025-05-26 21:11:13 +02:00
|
|
|
{
|
2025-05-27 23:42:48 +02:00
|
|
|
if (!offset && resource_type_info->offset)
|
2025-05-26 21:11:13 +02:00
|
|
|
vkd3d_string_buffer_printf(sample, ", int2(0)");
|
|
|
|
vkd3d_string_buffer_printf(sample, ", component::%c", "xyzw"[component_idx]);
|
|
|
|
}
|
2025-05-26 00:18:05 +02:00
|
|
|
vkd3d_string_buffer_printf(sample, ")");
|
2025-05-27 23:18:09 +02:00
|
|
|
if (!compare || gather)
|
2025-05-27 23:42:48 +02:00
|
|
|
msl_print_swizzle(sample, resource->swizzle, ins->dst[0].write_mask);
|
2025-07-27 15:39:33 +02:00
|
|
|
vkd3d_string_buffer_printf(sample, ")");
|
2025-05-24 19:46:59 +02:00
|
|
|
|
|
|
|
msl_print_assignment(gen, &dst, "%s", sample->buffer);
|
|
|
|
|
|
|
|
vkd3d_string_buffer_release(&gen->string_buffers, sample);
|
|
|
|
msl_dst_cleanup(&dst, &gen->string_buffers);
|
|
|
|
}
|
|
|
|
|
2025-05-28 22:52:18 +02:00
|
|
|
static void msl_store_uav_typed(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins)
|
|
|
|
{
|
|
|
|
const struct msl_resource_type_info *resource_type_info;
|
|
|
|
const struct vkd3d_shader_descriptor_binding *binding;
|
|
|
|
const struct vkd3d_shader_descriptor_info1 *d;
|
|
|
|
enum vkd3d_shader_resource_type resource_type;
|
|
|
|
unsigned int uav_id, uav_idx, uav_space;
|
|
|
|
struct vkd3d_string_buffer *image_data;
|
2025-07-17 15:22:54 +02:00
|
|
|
enum vsir_data_type data_type;
|
2025-05-28 22:52:18 +02:00
|
|
|
unsigned int uav_binding;
|
|
|
|
uint32_t coord_mask;
|
|
|
|
|
|
|
|
if (ins->dst[0].reg.idx[0].rel_addr || ins->dst[0].reg.idx[1].rel_addr)
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_UNSUPPORTED,
|
|
|
|
"Descriptor indexing is not supported.");
|
|
|
|
|
|
|
|
uav_id = ins->dst[0].reg.idx[0].offset;
|
|
|
|
uav_idx = ins->dst[0].reg.idx[1].offset;
|
|
|
|
if ((d = vkd3d_shader_find_descriptor(&gen->program->descriptors,
|
|
|
|
VKD3D_SHADER_DESCRIPTOR_TYPE_UAV, uav_id)))
|
|
|
|
{
|
|
|
|
uav_space = d->register_space;
|
|
|
|
resource_type = d->resource_type;
|
|
|
|
data_type = d->resource_data_type;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Undeclared UAV descriptor %u.", uav_id);
|
|
|
|
uav_space = 0;
|
|
|
|
resource_type = VKD3D_SHADER_RESOURCE_TEXTURE_2D;
|
2025-07-17 15:55:17 +02:00
|
|
|
data_type = VSIR_DATA_F32;
|
2025-05-28 22:52:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!(resource_type_info = msl_get_resource_type_info(resource_type)))
|
|
|
|
{
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled resource type %#x.", resource_type);
|
|
|
|
resource_type_info = msl_get_resource_type_info(VKD3D_SHADER_RESOURCE_TEXTURE_2D);
|
|
|
|
}
|
|
|
|
coord_mask = vkd3d_write_mask_from_component_count(resource_type_info->coord_size);
|
|
|
|
|
|
|
|
if ((binding = msl_get_uav_binding(gen, uav_space, uav_idx, resource_type)))
|
|
|
|
{
|
|
|
|
uav_binding = binding->binding;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_BINDING_NOT_FOUND,
|
|
|
|
"No descriptor binding specified for UAV %u (index %u, space %u).",
|
|
|
|
uav_id, uav_idx, uav_space);
|
|
|
|
uav_binding = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
image_data = vkd3d_string_buffer_get(&gen->string_buffers);
|
|
|
|
|
|
|
|
if (ins->src[1].reg.dimension == VSIR_DIMENSION_SCALAR)
|
|
|
|
{
|
|
|
|
switch (data_type)
|
|
|
|
{
|
2025-07-17 16:47:43 +02:00
|
|
|
case VSIR_DATA_U32:
|
2025-05-28 22:52:18 +02:00
|
|
|
vkd3d_string_buffer_printf(image_data, "uint4(");
|
|
|
|
break;
|
2025-07-17 16:29:38 +02:00
|
|
|
case VSIR_DATA_I32:
|
2025-05-28 22:52:18 +02:00
|
|
|
vkd3d_string_buffer_printf(image_data, "int4(");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled data type %#x.", data_type);
|
|
|
|
/* fall through */
|
2025-07-17 15:55:17 +02:00
|
|
|
case VSIR_DATA_F32:
|
2025-07-21 15:09:30 +02:00
|
|
|
case VSIR_DATA_SNORM:
|
2025-07-21 15:05:46 +02:00
|
|
|
case VSIR_DATA_UNORM:
|
2025-05-28 22:52:18 +02:00
|
|
|
vkd3d_string_buffer_printf(image_data, "float4(");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
msl_print_src_with_type(image_data, gen, &ins->src[1], VKD3DSP_WRITEMASK_ALL, data_type);
|
|
|
|
if (ins->src[1].reg.dimension == VSIR_DIMENSION_SCALAR)
|
|
|
|
vkd3d_string_buffer_printf(image_data, ", 0, 0, 0)");
|
|
|
|
|
|
|
|
msl_print_indent(gen->buffer, gen->indent);
|
|
|
|
msl_print_uav_name(gen->buffer, gen, uav_binding, resource_type_info, data_type);
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, ".write(%s, ", image_data->buffer);
|
2025-07-17 16:47:43 +02:00
|
|
|
msl_print_src_with_type(gen->buffer, gen, &ins->src[0], coord_mask, VSIR_DATA_U32);
|
2025-05-28 22:52:18 +02:00
|
|
|
vkd3d_string_buffer_printf(gen->buffer, ");\n");
|
|
|
|
|
|
|
|
vkd3d_string_buffer_release(&gen->string_buffers, image_data);
|
|
|
|
}
|
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
|
2025-05-22 22:37:28 +02:00
|
|
|
static void msl_dcl_indexable_temp(struct msl_generator *gen, const struct vkd3d_shader_instruction *ins)
|
|
|
|
{
|
2025-07-15 17:56:31 +02:00
|
|
|
const char *type = ins->declaration.indexable_temp.component_count == 4 ? "vkd3d_vec4" : "vkd3d_scalar";
|
2025-05-22 22:37:28 +02:00
|
|
|
msl_print_indent(gen->buffer, gen->indent);
|
2025-07-15 17:56:31 +02:00
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "%s x%u[%u];\n", type,
|
2025-05-22 22:37:28 +02:00
|
|
|
ins->declaration.indexable_temp.register_idx,
|
|
|
|
ins->declaration.indexable_temp.register_size);
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
{
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_ADD:
|
|
|
|
case VSIR_OP_IADD:
|
2024-11-22 15:45:54 +08:00
|
|
|
msl_binop(gen, ins, "+");
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_AND:
|
2024-11-22 15:45:54 +08:00
|
|
|
msl_binop(gen, ins, "&");
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_BREAK:
|
2025-05-23 15:45:11 +02:00
|
|
|
msl_break(gen);
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_CASE:
|
2025-05-23 16:15:49 +02:00
|
|
|
msl_case(gen, ins);
|
|
|
|
break;
|
2025-05-28 10:14:33 +02:00
|
|
|
case VSIR_OP_CONTINUE:
|
|
|
|
msl_continue(gen);
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_DCL_INDEXABLE_TEMP:
|
2025-05-22 22:37:28 +02:00
|
|
|
msl_dcl_indexable_temp(gen, ins);
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_NOP:
|
2024-09-16 18:37:58 +08:00
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_DEFAULT:
|
2025-05-23 16:15:49 +02:00
|
|
|
msl_default(gen);
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_DISCARD:
|
2025-05-23 16:53:38 +02:00
|
|
|
msl_discard(gen, ins);
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_DIV:
|
2024-11-22 15:45:54 +08:00
|
|
|
msl_binop(gen, ins, "/");
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_DP2:
|
2024-11-22 15:45:54 +08:00
|
|
|
msl_dot(gen, ins, vkd3d_write_mask_from_component_count(2));
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_DP3:
|
2024-11-22 15:45:54 +08:00
|
|
|
msl_dot(gen, ins, vkd3d_write_mask_from_component_count(3));
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_DP4:
|
2024-11-22 15:45:54 +08:00
|
|
|
msl_dot(gen, ins, VKD3DSP_WRITEMASK_ALL);
|
|
|
|
break;
|
2025-05-28 10:28:52 +02:00
|
|
|
case VSIR_OP_DSX:
|
2025-05-28 15:06:38 +02:00
|
|
|
case VSIR_OP_DSX_COARSE:
|
2025-05-28 15:18:33 +02:00
|
|
|
case VSIR_OP_DSX_FINE:
|
2025-05-28 15:06:38 +02:00
|
|
|
/* dfdx() and dfdy() are specified to return "a high precision
|
|
|
|
* partial derivative", which would seem to correspond to
|
|
|
|
* DSX_FINE/DSY_FINE. As of MSL 3.2, coarse/fast variants don't
|
|
|
|
* appear to be available. */
|
2025-05-28 10:28:52 +02:00
|
|
|
msl_intrinsic(gen, ins, "dfdx");
|
|
|
|
break;
|
|
|
|
case VSIR_OP_DSY:
|
2025-05-28 15:06:38 +02:00
|
|
|
case VSIR_OP_DSY_COARSE:
|
2025-05-28 15:18:33 +02:00
|
|
|
case VSIR_OP_DSY_FINE:
|
2025-05-28 10:28:52 +02:00
|
|
|
msl_intrinsic(gen, ins, "dfdy");
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_ELSE:
|
2024-12-03 00:58:19 +08:00
|
|
|
msl_else(gen);
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_ENDIF:
|
|
|
|
case VSIR_OP_ENDLOOP:
|
|
|
|
case VSIR_OP_ENDSWITCH:
|
2024-12-03 00:58:19 +08:00
|
|
|
msl_end_block(gen);
|
2024-12-03 00:06:32 +08:00
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_EQO:
|
|
|
|
case VSIR_OP_IEQ:
|
2024-12-02 23:52:13 +08:00
|
|
|
msl_relop(gen, ins, "==");
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_EXP:
|
2024-12-02 23:53:45 +08:00
|
|
|
msl_intrinsic(gen, ins, "exp2");
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_FRC:
|
2024-11-22 15:45:54 +08:00
|
|
|
msl_intrinsic(gen, ins, "fract");
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_FTOI:
|
2024-11-22 15:45:54 +08:00
|
|
|
msl_cast(gen, ins, "int");
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_FTOU:
|
2024-11-22 15:45:54 +08:00
|
|
|
msl_cast(gen, ins, "uint");
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_GATHER4:
|
|
|
|
case VSIR_OP_GATHER4_C:
|
|
|
|
case VSIR_OP_GATHER4_PO:
|
|
|
|
case VSIR_OP_SAMPLE:
|
|
|
|
case VSIR_OP_SAMPLE_B:
|
|
|
|
case VSIR_OP_SAMPLE_C:
|
|
|
|
case VSIR_OP_SAMPLE_C_LZ:
|
|
|
|
case VSIR_OP_SAMPLE_GRAD:
|
|
|
|
case VSIR_OP_SAMPLE_LOD:
|
2025-05-24 19:46:59 +02:00
|
|
|
msl_sample(gen, ins);
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_GEO:
|
|
|
|
case VSIR_OP_IGE:
|
2024-11-22 15:45:54 +08:00
|
|
|
msl_relop(gen, ins, ">=");
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_IF:
|
2024-12-03 00:06:32 +08:00
|
|
|
msl_if(gen, ins);
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_ISHL:
|
2024-12-03 01:12:13 +08:00
|
|
|
msl_binop(gen, ins, "<<");
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_ISHR:
|
|
|
|
case VSIR_OP_USHR:
|
2024-12-03 01:13:10 +08:00
|
|
|
msl_binop(gen, ins, ">>");
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_ILT:
|
|
|
|
case VSIR_OP_LTO:
|
|
|
|
case VSIR_OP_ULT:
|
2024-12-02 23:55:28 +08:00
|
|
|
msl_relop(gen, ins, "<");
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_MAD:
|
2024-12-03 01:09:44 +08:00
|
|
|
msl_intrinsic(gen, ins, "fma");
|
|
|
|
break;
|
2025-05-28 15:28:02 +02:00
|
|
|
case VSIR_OP_IMAX:
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_MAX:
|
2025-05-28 15:43:39 +02:00
|
|
|
case VSIR_OP_UMAX:
|
2024-12-03 00:46:35 +08:00
|
|
|
msl_intrinsic(gen, ins, "max");
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_MIN:
|
2025-05-28 15:43:39 +02:00
|
|
|
case VSIR_OP_UMIN:
|
2024-12-03 00:49:05 +08:00
|
|
|
msl_intrinsic(gen, ins, "min");
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_IMUL_LOW:
|
2025-06-10 17:11:31 +02:00
|
|
|
msl_binop(gen, ins, "*");
|
2025-05-23 15:23:10 +02:00
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_INE:
|
|
|
|
case VSIR_OP_NEU:
|
2024-11-22 15:45:54 +08:00
|
|
|
msl_relop(gen, ins, "!=");
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_INEG:
|
2025-05-23 21:01:53 +02:00
|
|
|
msl_unary_op(gen, ins, "-");
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_ITOF:
|
|
|
|
case VSIR_OP_UTOF:
|
2024-11-22 15:45:54 +08:00
|
|
|
msl_cast(gen, ins, "float");
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_LD:
|
|
|
|
case VSIR_OP_LD2DMS:
|
2024-12-12 15:02:51 +08:00
|
|
|
msl_ld(gen, ins);
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_LOG:
|
2024-12-03 00:41:31 +08:00
|
|
|
msl_intrinsic(gen, ins, "log2");
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_LOOP:
|
2025-05-23 15:45:11 +02:00
|
|
|
msl_loop(gen);
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_MOV:
|
2024-09-17 20:50:44 +08:00
|
|
|
msl_mov(gen, ins);
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_MOVC:
|
2024-11-22 15:45:54 +08:00
|
|
|
msl_movc(gen, ins);
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_MUL:
|
2024-11-22 15:45:54 +08:00
|
|
|
msl_binop(gen, ins, "*");
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_NOT:
|
2024-12-03 00:55:22 +08:00
|
|
|
msl_unary_op(gen, ins, "~");
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_OR:
|
2024-11-22 15:45:54 +08:00
|
|
|
msl_binop(gen, ins, "|");
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_RET:
|
2024-09-16 19:15:39 +08:00
|
|
|
msl_ret(gen, ins);
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_ROUND_NE:
|
2024-12-03 00:09:01 +08:00
|
|
|
msl_intrinsic(gen, ins, "rint");
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_ROUND_NI:
|
2024-12-03 00:04:03 +08:00
|
|
|
msl_intrinsic(gen, ins, "floor");
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_ROUND_PI:
|
2024-11-22 15:45:54 +08:00
|
|
|
msl_intrinsic(gen, ins, "ceil");
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_ROUND_Z:
|
2024-11-22 15:45:54 +08:00
|
|
|
msl_intrinsic(gen, ins, "trunc");
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_RSQ:
|
2024-12-03 00:50:47 +08:00
|
|
|
msl_intrinsic(gen, ins, "rsqrt");
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_SQRT:
|
2024-11-22 15:45:54 +08:00
|
|
|
msl_intrinsic(gen, ins, "sqrt");
|
|
|
|
break;
|
2025-05-28 22:52:18 +02:00
|
|
|
case VSIR_OP_STORE_UAV_TYPED:
|
|
|
|
msl_store_uav_typed(gen, ins);
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_SWITCH:
|
2025-05-23 16:15:49 +02:00
|
|
|
msl_switch(gen, ins);
|
|
|
|
break;
|
2025-06-24 13:11:57 +02:00
|
|
|
case VSIR_OP_XOR:
|
2025-05-23 21:15:38 +02:00
|
|
|
msl_binop(gen, ins, "^");
|
|
|
|
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;
|
2025-07-27 15:06:06 +02:00
|
|
|
bool locations[MAX_IO_REG_COUNT] = {0};
|
2024-09-30 11:05:26 +08:00
|
|
|
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;
|
|
|
|
|
2025-07-27 15:06:06 +02:00
|
|
|
if (e->target_location >= ARRAY_SIZE(locations))
|
|
|
|
{
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled input target location %u.", e->target_location);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (locations[e->target_location])
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled duplicate input target location %u.", e->target_location);
|
|
|
|
locations[e->target_location] = true;
|
|
|
|
|
2025-05-19 00:19:02 +02:00
|
|
|
switch (e->sysval_semantic)
|
2024-09-30 11:05:26 +08:00
|
|
|
{
|
2025-05-19 00:19:02 +02:00
|
|
|
case VKD3D_SHADER_SV_NONE:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VKD3D_SHADER_SV_POSITION:
|
2024-12-03 00:31:48 +08:00
|
|
|
if (type != VKD3D_SHADER_TYPE_PIXEL)
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
2025-05-19 00:19:02 +02:00
|
|
|
"Internal compiler error: Unhandled SV_POSITION in shader type #%x.", type);
|
|
|
|
msl_print_indent(gen->buffer, 1);
|
|
|
|
vkd3d_string_buffer_printf(buffer, "float4 position [[position]];\n");
|
|
|
|
continue;
|
2024-12-03 00:31:48 +08:00
|
|
|
|
2025-05-19 00:40:37 +02:00
|
|
|
case VKD3D_SHADER_SV_VERTEX_ID:
|
|
|
|
if (type != VKD3D_SHADER_TYPE_VERTEX)
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled SV_VERTEX_ID in shader type #%x.", type);
|
|
|
|
gen->read_vertex_id = true;
|
|
|
|
continue;
|
|
|
|
|
2025-05-19 00:19:02 +02:00
|
|
|
case 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);
|
2024-12-03 00:31:48 +08:00
|
|
|
msl_print_indent(gen->buffer, 1);
|
|
|
|
vkd3d_string_buffer_printf(buffer, "bool is_front_face [[front_facing]];\n");
|
|
|
|
continue;
|
2025-05-19 00:19:02 +02:00
|
|
|
|
2025-05-22 10:11:39 +02:00
|
|
|
case VKD3D_SHADER_SV_SAMPLE_INDEX:
|
|
|
|
if (type != VKD3D_SHADER_TYPE_PIXEL)
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled SV_SAMPLE_INDEX in shader type #%x.", type);
|
|
|
|
msl_print_indent(gen->buffer, 1);
|
|
|
|
vkd3d_string_buffer_printf(buffer, "uint sample_index [[sample_id]];\n");
|
|
|
|
continue;
|
|
|
|
|
2025-05-19 00:19:02 +02:00
|
|
|
default:
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled system value %#x.", e->sysval_semantic);
|
2025-05-22 10:11:39 +02:00
|
|
|
msl_print_indent(gen->buffer, 1);
|
|
|
|
vkd3d_string_buffer_printf(buffer, "<unhandled sysval %#x>;\n", e->sysval_semantic);
|
2025-05-19 00:19:02 +02:00
|
|
|
continue;
|
2024-09-30 11:05:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2025-05-19 00:40:37 +02:00
|
|
|
vkd3d_string_buffer_printf(buffer, "shader_in_%u [[", i);
|
2024-09-30 11:05:26 +08:00
|
|
|
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case VKD3D_SHADER_TYPE_VERTEX:
|
2025-05-19 00:40:37 +02:00
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "attribute(%u)", e->target_location);
|
2024-09-30 11:05:26 +08:00
|
|
|
break;
|
|
|
|
case VKD3D_SHADER_TYPE_PIXEL:
|
2025-05-19 00:40:37 +02:00
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "user(locn%u)", e->target_location);
|
2024-09-30 11:05:26 +08:00
|
|
|
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;
|
2025-05-19 00:40:37 +02:00
|
|
|
case VKD3DSIM_CONSTANT:
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, ", flat");
|
|
|
|
break;
|
2024-11-22 15:45:54 +08:00
|
|
|
default:
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled interpolation mode %#x.", e->interpolation_mode);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2025-05-19 00:40:37 +02:00
|
|
|
vkd3d_string_buffer_printf(buffer, "]];\n");
|
2024-09-30 11:05:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2025-07-27 15:06:06 +02:00
|
|
|
bool locations[MAX_IO_REG_COUNT] = {0};
|
2024-09-30 10:58:02 +08:00
|
|
|
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];
|
|
|
|
|
2025-05-21 23:38:16 +02:00
|
|
|
if (e->target_location == SIGNATURE_TARGET_LOCATION_UNUSED
|
|
|
|
|| e->sysval_semantic == VKD3D_SHADER_SV_DEPTH)
|
2024-09-30 10:58:02 +08:00
|
|
|
continue;
|
|
|
|
|
2025-07-27 15:06:06 +02:00
|
|
|
if (e->target_location >= ARRAY_SIZE(locations))
|
|
|
|
{
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled input target location %u.", e->target_location);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (locations[e->target_location])
|
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled duplicate input target location %u.", e->target_location);
|
|
|
|
locations[e->target_location] = true;
|
|
|
|
|
2024-09-30 10:58:02 +08:00
|
|
|
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_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");
|
|
|
|
}
|
|
|
|
|
2025-05-21 23:38:16 +02:00
|
|
|
if (bitmap_is_set(gen->program->io_dcls, VKD3DSPR_DEPTHOUT))
|
|
|
|
{
|
|
|
|
msl_print_indent(gen->buffer, 1);
|
|
|
|
vkd3d_string_buffer_printf(buffer, "float shader_out_depth [[depth(any)]];\n");
|
|
|
|
}
|
|
|
|
|
2025-05-23 09:32:21 +02:00
|
|
|
if (bitmap_is_set(gen->program->io_dcls, VKD3DSPR_SAMPLEMASK))
|
|
|
|
{
|
|
|
|
msl_print_indent(gen->buffer, 1);
|
|
|
|
vkd3d_string_buffer_printf(buffer, "uint shader_out_mask [[sample_mask]];\n");
|
|
|
|
}
|
|
|
|
|
2024-09-30 10:58:02 +08:00
|
|
|
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);
|
2025-05-19 00:19:02 +02:00
|
|
|
switch (e->sysval_semantic)
|
2024-09-30 11:52:49 +08:00
|
|
|
{
|
2025-05-19 00:19:02 +02:00
|
|
|
case VKD3D_SHADER_SV_NONE:
|
2025-07-17 15:22:54 +02:00
|
|
|
msl_print_register_datatype(buffer, gen, vsir_data_type_from_component_type(e->component_type));
|
2025-05-19 00:19:02 +02:00
|
|
|
msl_print_write_mask(buffer, e->mask);
|
|
|
|
vkd3d_string_buffer_printf(buffer, " = input.shader_in_%u", i);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VKD3D_SHADER_SV_POSITION:
|
2025-07-17 15:55:17 +02:00
|
|
|
msl_print_register_datatype(buffer, gen, VSIR_DATA_F32);
|
2025-05-19 00:19:02 +02:00
|
|
|
msl_print_write_mask(buffer, e->mask);
|
|
|
|
vkd3d_string_buffer_printf(buffer, " = float4(input.position.xyz, 1.0f / input.position.w)");
|
|
|
|
break;
|
|
|
|
|
2025-05-19 00:40:37 +02:00
|
|
|
case VKD3D_SHADER_SV_VERTEX_ID:
|
2025-07-17 16:47:43 +02:00
|
|
|
msl_print_register_datatype(buffer, gen, VSIR_DATA_U32);
|
2025-05-19 00:40:37 +02:00
|
|
|
msl_print_write_mask(buffer, e->mask);
|
|
|
|
vkd3d_string_buffer_printf(buffer, " = uint4(vertex_id, 0u, 0u, 0u)");
|
|
|
|
break;
|
|
|
|
|
2025-05-19 00:19:02 +02:00
|
|
|
case VKD3D_SHADER_SV_IS_FRONT_FACE:
|
2025-07-17 16:47:43 +02:00
|
|
|
msl_print_register_datatype(buffer, gen, VSIR_DATA_U32);
|
2025-05-19 00:19:02 +02:00
|
|
|
msl_print_write_mask(buffer, e->mask);
|
|
|
|
vkd3d_string_buffer_printf(buffer, " = uint4(input.is_front_face ? 0xffffffffu : 0u, 0, 0, 0)");
|
|
|
|
break;
|
|
|
|
|
2025-05-22 10:11:39 +02:00
|
|
|
case VKD3D_SHADER_SV_SAMPLE_INDEX:
|
2025-07-17 16:47:43 +02:00
|
|
|
msl_print_register_datatype(buffer, gen, VSIR_DATA_U32);
|
2025-05-22 10:11:39 +02:00
|
|
|
msl_print_write_mask(buffer, e->mask);
|
|
|
|
vkd3d_string_buffer_printf(buffer, " = uint4(input.sample_index, 0u, 0u, 0u)");
|
|
|
|
break;
|
|
|
|
|
2025-05-19 00:19:02 +02:00
|
|
|
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);
|
|
|
|
break;
|
2024-09-30 11:52:49 +08:00
|
|
|
}
|
2025-05-19 00:19:02 +02:00
|
|
|
msl_print_write_mask(buffer, e->mask);
|
2024-09-30 11:52:49 +08:00
|
|
|
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];
|
|
|
|
|
|
|
|
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);
|
2025-07-17 15:22:54 +02:00
|
|
|
msl_print_register_datatype(buffer, gen, vsir_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;
|
2025-05-21 23:38:16 +02:00
|
|
|
case VKD3D_SHADER_SV_DEPTH:
|
|
|
|
continue;
|
2024-09-30 11:51:26 +08:00
|
|
|
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");
|
|
|
|
}
|
2025-05-23 09:32:21 +02:00
|
|
|
|
|
|
|
if (bitmap_is_set(gen->program->io_dcls, VKD3DSPR_SAMPLEMASK))
|
2025-07-15 20:59:34 +02:00
|
|
|
vkd3d_string_buffer_printf(gen->buffer, " output.shader_out_mask = o_mask.u;\n");
|
2024-09-30 11:51:26 +08:00
|
|
|
}
|
|
|
|
|
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:
|
2025-05-28 23:23:06 +02:00
|
|
|
if (gen->program->global_flags & VKD3DSGF_FORCE_EARLY_DEPTH_STENCIL)
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "[[early_fragment_tests]]\n");
|
2024-09-30 11:37:15 +08:00
|
|
|
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
|
|
|
|
2025-05-19 00:40:37 +02:00
|
|
|
if (gen->read_vertex_id)
|
|
|
|
{
|
|
|
|
msl_print_indent(gen->buffer, 2);
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "uint vertex_id [[vertex_id]],\n");
|
|
|
|
}
|
|
|
|
|
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 */
|
2025-07-27 15:06:06 +02:00
|
|
|
vkd3d_string_buffer_printf(gen->buffer, " vkd3d_vec4 %s_in[%u];\n", gen->prefix, MAX_IO_REG_COUNT);
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, " vkd3d_vec4 %s_out[%u];\n", gen->prefix, MAX_IO_REG_COUNT);
|
2024-09-30 11:37:15 +08:00
|
|
|
vkd3d_string_buffer_printf(gen->buffer, " vkd3d_%s_out output;\n", gen->prefix);
|
2025-05-23 09:32:21 +02:00
|
|
|
if (bitmap_is_set(gen->program->io_dcls, VKD3DSPR_SAMPLEMASK))
|
2025-07-15 20:59:34 +02:00
|
|
|
vkd3d_string_buffer_printf(gen->buffer, " vkd3d_scalar o_mask;\n");
|
2025-05-23 09:32:21 +02:00
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "\n");
|
2024-09-30 11:37:15 +08:00
|
|
|
|
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);
|
2025-05-19 00:40:37 +02:00
|
|
|
if (gen->read_vertex_id)
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, ", vertex_id");
|
2025-05-21 23:38:16 +02:00
|
|
|
if (bitmap_is_set(gen->program->io_dcls, VKD3DSPR_DEPTHOUT))
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, ", output.shader_out_depth");
|
2025-05-23 09:32:21 +02:00
|
|
|
if (bitmap_is_set(gen->program->io_dcls, VKD3DSPR_SAMPLEMASK))
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, ", o_mask");
|
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");
|
2025-05-23 09:32:21 +02:00
|
|
|
vkd3d_string_buffer_printf(gen->buffer, ");\n\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
|
|
|
{
|
2025-07-21 21:48:38 +02:00
|
|
|
struct vkd3d_shader_instruction *ins;
|
|
|
|
struct vsir_program_iterator it;
|
2024-08-29 01:21:22 +08:00
|
|
|
|
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
|
|
|
|
2025-05-28 23:23:06 +02:00
|
|
|
if (gen->program->global_flags & ~(VKD3DSGF_REFACTORING_ALLOWED | VKD3DSGF_FORCE_EARLY_DEPTH_STENCIL))
|
2024-10-18 22:38:45 +02:00
|
|
|
msl_compiler_error(gen, VKD3D_SHADER_ERROR_MSL_INTERNAL,
|
|
|
|
"Internal compiler error: Unhandled global flags %#"PRIx64".", (uint64_t)gen->program->global_flags);
|
|
|
|
|
2025-07-15 17:56:31 +02:00
|
|
|
vkd3d_string_buffer_printf(gen->buffer, "union vkd3d_scalar\n{\n");
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, " uint u;\n");
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, " int i;\n");
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, " float f;\n};\n\n");
|
|
|
|
|
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"
|
2025-05-24 19:46:59 +02:00
|
|
|
" constant T &as() constant\n"
|
2024-12-12 15:02:51 +08:00
|
|
|
" {\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,
|
2025-05-22 22:39:36 +02:00
|
|
|
"static 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);
|
2025-05-19 00:40:37 +02:00
|
|
|
|
|
|
|
if (gen->read_vertex_id)
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, ", uint vertex_id");
|
2025-05-21 23:38:16 +02:00
|
|
|
if (bitmap_is_set(gen->program->io_dcls, VKD3DSPR_DEPTHOUT))
|
|
|
|
vkd3d_string_buffer_printf(gen->buffer, ", thread float &o_depth");
|
2025-05-23 09:32:21 +02:00
|
|
|
if (bitmap_is_set(gen->program->io_dcls, VKD3DSPR_SAMPLEMASK))
|
2025-07-15 20:59:34 +02:00
|
|
|
vkd3d_string_buffer_printf(gen->buffer, ", thread vkd3d_scalar &o_mask");
|
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);
|
|
|
|
}
|
|
|
|
|
2025-07-21 21:48:38 +02:00
|
|
|
it = vsir_program_iterator(&gen->program->instructions);
|
|
|
|
for (ins = vsir_program_iterator_head(&it); ins; ins = vsir_program_iterator_next(&it))
|
2024-08-29 01:21:22 +08:00
|
|
|
{
|
2025-07-21 21:48:38 +02:00
|
|
|
msl_handle_instruction(gen, ins);
|
2024-08-29 01:21:22 +08:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
2025-07-27 14:01:54 +02:00
|
|
|
if ((ret = vsir_allocate_temp_registers(program, 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
|
|
|
}
|