Files
vkd3d/libs/vkd3d-shader/glsl.c
Henri Verbeet cab0bd07e5 vkd3d-shader/glsl: Resolve SSA values.
Since commit eaebef4265 we may receive
vsir generated from HLSL sources, which typically contains SSA values.
We could previously receive vsir with SSA values as well, but HLSL
sources would go through d3dbc/tpf as an intermediate step, making the
resulting vsir much less likely to contain SSA values.
2025-08-13 15:56:06 +02:00

2460 lines
93 KiB
C

/*
* Copyright 2021 Atharva Nimbalkar
*
* 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"
struct glsl_resource_type_info
{
/* The number of coordinates needed to sample the resource type. */
size_t coord_size;
/* Whether the resource type is an array type. */
bool array;
/* Whether the resource type has a shadow/comparison variant. */
bool shadow;
/* The type suffix for resource type. I.e., the "2D" part of "usampler2D"
* or "iimage2D". */
const char *type_suffix;
};
struct glsl_src
{
struct vkd3d_string_buffer *str;
};
struct glsl_dst
{
const struct vkd3d_shader_dst_param *vsir;
struct vkd3d_string_buffer *register_name;
struct vkd3d_string_buffer *mask;
};
struct vkd3d_glsl_generator
{
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;
unsigned int indent;
const char *prefix;
bool failed;
struct shader_limits
{
unsigned int input_count;
unsigned int output_count;
} limits;
bool interstage_input;
bool interstage_output;
const struct vkd3d_shader_interface_info *interface_info;
const struct vkd3d_shader_descriptor_offset_info *offset_info;
const struct vkd3d_shader_scan_combined_resource_sampler_info *combined_sampler_info;
};
static void shader_glsl_print_subscript(struct vkd3d_string_buffer *buffer, struct vkd3d_glsl_generator *gen,
const struct vkd3d_shader_src_param *rel_addr, unsigned int offset);
static void VKD3D_PRINTF_FUNC(3, 4) vkd3d_glsl_compiler_error(
struct vkd3d_glsl_generator *generator,
enum vkd3d_shader_error error, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vkd3d_shader_verror(generator->message_context, &generator->location, error, fmt, args);
va_end(args);
generator->failed = true;
}
static const char *shader_glsl_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;
}
}
static const struct glsl_resource_type_info *shader_glsl_get_resource_type_info(enum vkd3d_shader_resource_type t)
{
static const struct glsl_resource_type_info info[] =
{
{0, 0, 0, "None"}, /* VKD3D_SHADER_RESOURCE_NONE */
{1, 0, 0, "Buffer"}, /* VKD3D_SHADER_RESOURCE_BUFFER */
{1, 0, 1, "1D"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_1D */
{2, 0, 1, "2D"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_2D */
{2, 0, 0, "2DMS"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_2DMS */
{3, 0, 0, "3D"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_3D */
{3, 0, 1, "Cube"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_CUBE */
{2, 1, 1, "1DArray"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_1DARRAY */
{3, 1, 1, "2DArray"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_2DARRAY */
{3, 1, 0, "2DMSArray"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_2DMSARRAY */
{4, 1, 1, "CubeArray"}, /* VKD3D_SHADER_RESOURCE_TEXTURE_CUBEARRAY */
};
if (!t || t >= ARRAY_SIZE(info))
return NULL;
return &info[t];
}
static const struct vkd3d_shader_descriptor_info1 *shader_glsl_get_descriptor(struct vkd3d_glsl_generator *gen,
enum vkd3d_shader_descriptor_type type, unsigned int idx, unsigned int space)
{
const struct vkd3d_shader_scan_descriptor_info1 *info = &gen->program->descriptors;
for (unsigned int i = 0; i < info->descriptor_count; ++i)
{
const struct vkd3d_shader_descriptor_info1 *d = &info->descriptors[i];
if (d->type == type && d->register_space == space && d->register_index == idx)
return d;
}
return NULL;
}
static const struct vkd3d_shader_descriptor_info1 *shader_glsl_get_descriptor_by_id(
struct vkd3d_glsl_generator *gen, enum vkd3d_shader_descriptor_type type, unsigned int id)
{
const struct vkd3d_shader_scan_descriptor_info1 *info = &gen->program->descriptors;
for (unsigned int i = 0; i < info->descriptor_count; ++i)
{
const struct vkd3d_shader_descriptor_info1 *d = &info->descriptors[i];
if (d->type == type && d->register_id == id)
return d;
}
return NULL;
}
static void shader_glsl_print_indent(struct vkd3d_string_buffer *buffer, unsigned int indent)
{
vkd3d_string_buffer_printf(buffer, "%*s", 4 * indent, "");
}
static void shader_glsl_print_combined_sampler_name(struct vkd3d_string_buffer *buffer,
struct vkd3d_glsl_generator *gen, unsigned int resource_index,
unsigned int resource_space, unsigned int sampler_index, unsigned int sampler_space)
{
vkd3d_string_buffer_printf(buffer, "%s_t_%u", gen->prefix, resource_index);
if (resource_space)
vkd3d_string_buffer_printf(buffer, "_%u", resource_space);
if (sampler_index != VKD3D_SHADER_DUMMY_SAMPLER_INDEX)
{
vkd3d_string_buffer_printf(buffer, "_s_%u", sampler_index);
if (sampler_space)
vkd3d_string_buffer_printf(buffer, "_%u", sampler_space);
}
}
static void shader_glsl_print_image_name(struct vkd3d_string_buffer *buffer,
struct vkd3d_glsl_generator *gen, unsigned int idx, unsigned int space)
{
vkd3d_string_buffer_printf(buffer, "%s_image_%u", gen->prefix, idx);
if (space)
vkd3d_string_buffer_printf(buffer, "_%u", space);
}
static void shader_glsl_print_register_name(struct vkd3d_string_buffer *buffer,
struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_register *reg)
{
switch (reg->type)
{
case VKD3DSPR_TEMP:
vkd3d_string_buffer_printf(buffer, "r[%u]", reg->idx[0].offset);
break;
case VKD3DSPR_INPUT:
if (reg->idx_count != 1)
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled input register index count %u.", reg->idx_count);
vkd3d_string_buffer_printf(buffer, "<unhandled register %#x>", reg->type);
break;
}
if (reg->idx[0].rel_addr)
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled input register indirect addressing.");
vkd3d_string_buffer_printf(buffer, "<unhandled register %#x>", reg->type);
break;
}
vkd3d_string_buffer_printf(buffer, "%s_in[%u]", gen->prefix, reg->idx[0].offset);
break;
case VKD3DSPR_OUTPUT:
if (reg->idx_count != 1)
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled output register index count %u.", reg->idx_count);
vkd3d_string_buffer_printf(buffer, "<unhandled register %#x>", reg->type);
break;
}
if (reg->idx[0].rel_addr)
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled output register indirect addressing.");
vkd3d_string_buffer_printf(buffer, "<unhandled register %#x>", reg->type);
break;
}
vkd3d_string_buffer_printf(buffer, "%s_out[%u]", gen->prefix, reg->idx[0].offset);
break;
case VKD3DSPR_DEPTHOUT:
if (gen->program->shader_version.type != VKD3D_SHADER_TYPE_PIXEL)
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled depth output in shader type #%x.",
gen->program->shader_version.type);
vkd3d_string_buffer_printf(buffer, "gl_FragDepth");
break;
case VKD3DSPR_IMMCONST:
switch (reg->dimension)
{
case VSIR_DIMENSION_SCALAR:
vkd3d_string_buffer_printf(buffer, "%#xu", reg->u.immconst_u32[0]);
break;
case VSIR_DIMENSION_VEC4:
vkd3d_string_buffer_printf(buffer, "uvec4(%#xu, %#xu, %#xu, %#xu)",
reg->u.immconst_u32[0], reg->u.immconst_u32[1],
reg->u.immconst_u32[2], reg->u.immconst_u32[3]);
break;
default:
vkd3d_string_buffer_printf(buffer, "<unhandled_dimension %#x>", reg->dimension);
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled dimension %#x.", reg->dimension);
break;
}
break;
case VKD3DSPR_CONSTBUFFER:
if (reg->idx_count != 3)
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled constant buffer register index count %u.", reg->idx_count);
vkd3d_string_buffer_printf(buffer, "<unhandled register %#x>", reg->type);
break;
}
if (reg->idx[0].rel_addr)
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled constant buffer register indirect addressing.");
vkd3d_string_buffer_printf(buffer, "<unhandled register %#x>", reg->type);
break;
}
vkd3d_string_buffer_printf(buffer, "%s_cb_%u", gen->prefix, reg->idx[0].offset);
shader_glsl_print_subscript(buffer, gen, reg->idx[2].rel_addr, reg->idx[2].offset);
break;
case VKD3DSPR_THREADID:
vkd3d_string_buffer_printf(buffer, "gl_GlobalInvocationID");
break;
case VKD3DSPR_IDXTEMP:
vkd3d_string_buffer_printf(buffer, "x%u", reg->idx[0].offset);
shader_glsl_print_subscript(buffer, gen, reg->idx[1].rel_addr, reg->idx[1].offset);
break;
default:
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled register type %#x.", reg->type);
vkd3d_string_buffer_printf(buffer, "<unrecognised register %#x>", reg->type);
break;
}
}
static void shader_glsl_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 shader_glsl_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 glsl_src_cleanup(struct glsl_src *src, struct vkd3d_string_buffer_cache *cache)
{
vkd3d_string_buffer_release(cache, src->str);
}
static void shader_glsl_print_bitcast(struct vkd3d_string_buffer *dst, struct vkd3d_glsl_generator *gen,
const char *src, enum vsir_data_type dst_data_type, enum vsir_data_type src_data_type, unsigned int size)
{
if (dst_data_type == VSIR_DATA_UNORM || dst_data_type == VSIR_DATA_SNORM)
dst_data_type = VSIR_DATA_F32;
if (src_data_type == VSIR_DATA_UNORM || src_data_type == VSIR_DATA_SNORM)
src_data_type = VSIR_DATA_F32;
if (dst_data_type == src_data_type)
{
vkd3d_string_buffer_printf(dst, "%s", src);
return;
}
if (src_data_type == VSIR_DATA_F32)
{
switch (dst_data_type)
{
case VSIR_DATA_I32:
vkd3d_string_buffer_printf(dst, "floatBitsToInt(%s)", src);
return;
case VSIR_DATA_U32:
vkd3d_string_buffer_printf(dst, "floatBitsToUint(%s)", src);
return;
default:
break;
}
}
if (src_data_type == VSIR_DATA_U32)
{
switch (dst_data_type)
{
case VSIR_DATA_F32:
vkd3d_string_buffer_printf(dst, "uintBitsToFloat(%s)", src);
return;
case VSIR_DATA_I32:
if (size == 1)
vkd3d_string_buffer_printf(dst, "int(%s)", src);
else
vkd3d_string_buffer_printf(dst, "ivec%u(%s)", size, src);
return;
default:
break;
}
}
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled bitcast from %#x to %#x.",
src_data_type, dst_data_type);
vkd3d_string_buffer_printf(dst, "%s", src);
}
static void shader_glsl_print_src(struct vkd3d_string_buffer *buffer, struct vkd3d_glsl_generator *gen,
const struct vkd3d_shader_src_param *vsir_src, uint32_t mask, enum vsir_data_type data_type)
{
const struct vkd3d_shader_register *reg = &vsir_src->reg;
struct vkd3d_string_buffer *register_name, *str;
enum vsir_data_type src_data_type;
unsigned int size;
register_name = vkd3d_string_buffer_get(&gen->string_buffers);
if (reg->non_uniform)
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled 'non-uniform' modifier.");
if (reg->type == VKD3DSPR_IMMCONST || reg->type == VKD3DSPR_THREADID)
src_data_type = VSIR_DATA_U32;
else
src_data_type = VSIR_DATA_F32;
shader_glsl_print_register_name(register_name, gen, reg);
if (!vsir_src->modifiers)
str = buffer;
else
str = vkd3d_string_buffer_get(&gen->string_buffers);
size = reg->dimension == VSIR_DIMENSION_VEC4 ? 4 : 1;
shader_glsl_print_bitcast(str, gen, register_name->buffer, data_type, src_data_type, size);
if (reg->dimension == VSIR_DIMENSION_VEC4)
shader_glsl_print_swizzle(str, vsir_src->swizzle, mask);
switch (vsir_src->modifiers)
{
case VKD3DSPSM_NONE:
break;
case VKD3DSPSM_NEG:
vkd3d_string_buffer_printf(buffer, "-%s", str->buffer);
break;
case VKD3DSPSM_ABS:
vkd3d_string_buffer_printf(buffer, "abs(%s)", str->buffer);
break;
case VKD3DSPSM_ABSNEG:
vkd3d_string_buffer_printf(buffer, "-abs(%s)", str->buffer);
break;
default:
vkd3d_string_buffer_printf(buffer, "<unhandled modifier %#x>(%s)",
vsir_src->modifiers, str->buffer);
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled source modifier(s) %#x.", vsir_src->modifiers);
break;
}
if (str != buffer)
vkd3d_string_buffer_release(&gen->string_buffers, str);
vkd3d_string_buffer_release(&gen->string_buffers, register_name);
}
static void glsl_src_init(struct glsl_src *glsl_src, struct vkd3d_glsl_generator *gen,
const struct vkd3d_shader_src_param *vsir_src, uint32_t mask)
{
glsl_src->str = vkd3d_string_buffer_get(&gen->string_buffers);
shader_glsl_print_src(glsl_src->str, gen, vsir_src, mask, vsir_src->reg.data_type);
}
static void glsl_dst_cleanup(struct glsl_dst *dst, struct vkd3d_string_buffer_cache *cache)
{
vkd3d_string_buffer_release(cache, dst->mask);
vkd3d_string_buffer_release(cache, dst->register_name);
}
static uint32_t glsl_dst_init(struct glsl_dst *glsl_dst, struct vkd3d_glsl_generator *gen,
const struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_dst_param *vsir_dst)
{
uint32_t write_mask = vsir_dst->write_mask;
if (ins->flags & VKD3DSI_PRECISE_XYZW)
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled 'precise' modifier.");
if (vsir_dst->reg.non_uniform)
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled 'non-uniform' modifier.");
glsl_dst->vsir = vsir_dst;
glsl_dst->register_name = vkd3d_string_buffer_get(&gen->string_buffers);
glsl_dst->mask = vkd3d_string_buffer_get(&gen->string_buffers);
shader_glsl_print_register_name(glsl_dst->register_name, gen, &vsir_dst->reg);
shader_glsl_print_write_mask(glsl_dst->mask, write_mask);
return write_mask;
}
static void shader_glsl_print_subscript(struct vkd3d_string_buffer *buffer, struct vkd3d_glsl_generator *gen,
const struct vkd3d_shader_src_param *rel_addr, unsigned int offset)
{
struct glsl_src r;
if (!rel_addr)
{
vkd3d_string_buffer_printf(buffer, "[%u]", offset);
return;
}
glsl_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, "]");
glsl_src_cleanup(&r, &gen->string_buffers);
}
static void VKD3D_PRINTF_FUNC(4, 0) shader_glsl_vprint_assignment(struct vkd3d_glsl_generator *gen,
struct glsl_dst *dst, enum vsir_data_type data_type, const char *format, va_list args)
{
struct vkd3d_string_buffer *buffer = gen->buffer;
uint32_t modifiers = dst->vsir->modifiers;
bool close = true;
/* It is always legitimate to ignore _pp. */
modifiers &= ~VKD3DSPDM_PARTIALPRECISION;
if (dst->vsir->shift)
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled destination shift %#x.", dst->vsir->shift);
if (modifiers & ~VKD3DSPDM_SATURATE)
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled destination modifier(s) %#x.", modifiers);
shader_glsl_print_indent(buffer, gen->indent);
vkd3d_string_buffer_printf(buffer, "%s%s = ", dst->register_name->buffer, dst->mask->buffer);
if (modifiers & VKD3DSPDM_SATURATE)
vkd3d_string_buffer_printf(buffer, "clamp(");
switch (data_type)
{
default:
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled destination register data type %#x.", data_type);
/* fall through */
case VSIR_DATA_F32:
close = false;
break;
case VSIR_DATA_I32:
vkd3d_string_buffer_printf(buffer, "intBitsToFloat(");
break;
case VSIR_DATA_U32:
vkd3d_string_buffer_printf(buffer, "uintBitsToFloat(");
break;
}
vkd3d_string_buffer_vprintf(buffer, format, args);
if (close)
vkd3d_string_buffer_printf(buffer, ")");
if (modifiers & VKD3DSPDM_SATURATE)
vkd3d_string_buffer_printf(buffer, ", 0.0, 1.0)");
vkd3d_string_buffer_printf(buffer, ";\n");
}
static void VKD3D_PRINTF_FUNC(3, 4) shader_glsl_print_assignment(
struct vkd3d_glsl_generator *gen, struct glsl_dst *dst, const char *format, ...)
{
va_list args;
va_start(args, format);
shader_glsl_vprint_assignment(gen, dst, dst->vsir->reg.data_type, format, args);
va_end(args);
}
static void VKD3D_PRINTF_FUNC(4, 5) shader_glsl_print_assignment_ext(struct vkd3d_glsl_generator *gen,
struct glsl_dst *dst, enum vsir_data_type data_type, const char *format, ...)
{
va_list args;
va_start(args, format);
shader_glsl_vprint_assignment(gen, dst, data_type, format, args);
va_end(args);
}
static void shader_glsl_unhandled(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins)
{
const char *name = vsir_opcode_get_name(ins->opcode, "<unknown>");
shader_glsl_print_indent(gen->buffer, gen->indent);
vkd3d_string_buffer_printf(gen->buffer, "/* <unhandled instruction \"%s\" (%#x)> */\n", name, ins->opcode);
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled instruction \"%s\" (%#x).", name, ins->opcode);
}
static void shader_glsl_binop(struct vkd3d_glsl_generator *gen,
const struct vkd3d_shader_instruction *ins, const char *op)
{
struct glsl_src src[2];
struct glsl_dst dst;
uint32_t mask;
mask = glsl_dst_init(&dst, gen, ins, &ins->dst[0]);
glsl_src_init(&src[0], gen, &ins->src[0], mask);
glsl_src_init(&src[1], gen, &ins->src[1], mask);
shader_glsl_print_assignment(gen, &dst, "%s %s %s", src[0].str->buffer, op, src[1].str->buffer);
glsl_src_cleanup(&src[1], &gen->string_buffers);
glsl_src_cleanup(&src[0], &gen->string_buffers);
glsl_dst_cleanup(&dst, &gen->string_buffers);
}
static void shader_glsl_dot(struct vkd3d_glsl_generator *gen,
const struct vkd3d_shader_instruction *ins, uint32_t src_mask)
{
unsigned int component_count;
struct glsl_src src[2];
struct glsl_dst dst;
uint32_t dst_mask;
dst_mask = glsl_dst_init(&dst, gen, ins, &ins->dst[0]);
glsl_src_init(&src[0], gen, &ins->src[0], src_mask);
glsl_src_init(&src[1], gen, &ins->src[1], src_mask);
if ((component_count = vsir_write_mask_component_count(dst_mask)) > 1)
shader_glsl_print_assignment(gen, &dst, "vec%d(dot(%s, %s))",
component_count, src[0].str->buffer, src[1].str->buffer);
else
shader_glsl_print_assignment(gen, &dst, "dot(%s, %s)",
src[0].str->buffer, src[1].str->buffer);
glsl_src_cleanup(&src[1], &gen->string_buffers);
glsl_src_cleanup(&src[0], &gen->string_buffers);
glsl_dst_cleanup(&dst, &gen->string_buffers);
}
static void shader_glsl_intrinsic(struct vkd3d_glsl_generator *gen,
const struct vkd3d_shader_instruction *ins, const char *op)
{
struct vkd3d_string_buffer *args;
struct glsl_src src;
struct glsl_dst dst;
unsigned int i;
uint32_t mask;
mask = glsl_dst_init(&dst, gen, ins, &ins->dst[0]);
args = vkd3d_string_buffer_get(&gen->string_buffers);
for (i = 0; i < ins->src_count; ++i)
{
glsl_src_init(&src, gen, &ins->src[i], mask);
vkd3d_string_buffer_printf(args, "%s%s", i ? ", " : "", src.str->buffer);
glsl_src_cleanup(&src, &gen->string_buffers);
}
shader_glsl_print_assignment(gen, &dst, "%s(%s)", op, args->buffer);
vkd3d_string_buffer_release(&gen->string_buffers, args);
glsl_dst_cleanup(&dst, &gen->string_buffers);
}
static void shader_glsl_relop(struct vkd3d_glsl_generator *gen,
const struct vkd3d_shader_instruction *ins, const char *scalar_op, const char *vector_op)
{
unsigned int mask_size;
struct glsl_src src[2];
struct glsl_dst dst;
uint32_t mask;
mask = glsl_dst_init(&dst, gen, ins, &ins->dst[0]);
glsl_src_init(&src[0], gen, &ins->src[0], mask);
glsl_src_init(&src[1], gen, &ins->src[1], mask);
if ((mask_size = vsir_write_mask_component_count(mask)) > 1)
shader_glsl_print_assignment(gen, &dst, "uvec%u(%s(%s, %s)) * 0xffffffffu",
mask_size, vector_op, src[0].str->buffer, src[1].str->buffer);
else
shader_glsl_print_assignment(gen, &dst, "%s %s %s ? 0xffffffffu : 0u",
src[0].str->buffer, scalar_op, src[1].str->buffer);
glsl_src_cleanup(&src[1], &gen->string_buffers);
glsl_src_cleanup(&src[0], &gen->string_buffers);
glsl_dst_cleanup(&dst, &gen->string_buffers);
}
static void shader_glsl_cast(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins,
const char *scalar_constructor, const char *vector_constructor)
{
unsigned int component_count;
struct glsl_src src;
struct glsl_dst dst;
uint32_t mask;
mask = glsl_dst_init(&dst, gen, ins, &ins->dst[0]);
glsl_src_init(&src, gen, &ins->src[0], mask);
if ((component_count = vsir_write_mask_component_count(mask)) > 1)
shader_glsl_print_assignment(gen, &dst, "%s%u(%s)",
vector_constructor, component_count, src.str->buffer);
else
shader_glsl_print_assignment(gen, &dst, "%s(%s)",
scalar_constructor, src.str->buffer);
glsl_src_cleanup(&src, &gen->string_buffers);
glsl_dst_cleanup(&dst, &gen->string_buffers);
}
static void shader_glsl_end_block(struct vkd3d_glsl_generator *gen)
{
--gen->indent;
shader_glsl_print_indent(gen->buffer, gen->indent);
vkd3d_string_buffer_printf(gen->buffer, "}\n");
}
static void shader_glsl_begin_block(struct vkd3d_glsl_generator *gen)
{
shader_glsl_print_indent(gen->buffer, gen->indent);
vkd3d_string_buffer_printf(gen->buffer, "{\n");
++gen->indent;
}
static void shader_glsl_if(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins)
{
const char *condition;
struct glsl_src src;
glsl_src_init(&src, gen, &ins->src[0], VKD3DSP_WRITEMASK_0);
shader_glsl_print_indent(gen->buffer, gen->indent);
condition = ins->flags == VKD3D_SHADER_CONDITIONAL_OP_NZ ? "bool" : "!bool";
vkd3d_string_buffer_printf(gen->buffer, "if (%s(%s))\n", condition, src.str->buffer);
glsl_src_cleanup(&src, &gen->string_buffers);
shader_glsl_begin_block(gen);
}
static void shader_glsl_else(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins)
{
shader_glsl_end_block(gen);
shader_glsl_print_indent(gen->buffer, gen->indent);
vkd3d_string_buffer_printf(gen->buffer, "else\n");
shader_glsl_begin_block(gen);
}
static void shader_glsl_loop(struct vkd3d_glsl_generator *gen)
{
shader_glsl_print_indent(gen->buffer, gen->indent);
vkd3d_string_buffer_printf(gen->buffer, "for (;;)\n");
shader_glsl_begin_block(gen);
}
static void shader_glsl_break(struct vkd3d_glsl_generator *gen)
{
shader_glsl_print_indent(gen->buffer, gen->indent);
vkd3d_string_buffer_printf(gen->buffer, "break;\n");
}
static void shader_glsl_continue(struct vkd3d_glsl_generator *gen)
{
shader_glsl_print_indent(gen->buffer, gen->indent);
vkd3d_string_buffer_printf(gen->buffer, "continue;\n");
}
static void shader_glsl_switch(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins)
{
struct glsl_src src;
glsl_src_init(&src, gen, &ins->src[0], VKD3DSP_WRITEMASK_0);
shader_glsl_print_indent(gen->buffer, gen->indent);
vkd3d_string_buffer_printf(gen->buffer, "switch (%s)\n", src.str->buffer);
shader_glsl_begin_block(gen);
glsl_src_cleanup(&src, &gen->string_buffers);
}
static void shader_glsl_case(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins)
{
struct glsl_src src;
glsl_src_init(&src, gen, &ins->src[0], VKD3DSP_WRITEMASK_0);
shader_glsl_print_indent(gen->buffer, gen->indent);
vkd3d_string_buffer_printf(gen->buffer, "case %s:\n", src.str->buffer);
glsl_src_cleanup(&src, &gen->string_buffers);
}
static void shader_glsl_default(struct vkd3d_glsl_generator *gen)
{
shader_glsl_print_indent(gen->buffer, gen->indent);
vkd3d_string_buffer_printf(gen->buffer, "default:\n");
}
static void shader_glsl_print_texel_offset(struct vkd3d_string_buffer *buffer, struct vkd3d_glsl_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, "ivec2(%d, %d)", offset->u, offset->v);
break;
default:
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Invalid texel offset size %u.", offset_size);
/* fall through */
case 3:
vkd3d_string_buffer_printf(buffer, "ivec3(%d, %d, %d)", offset->u, offset->v, offset->w);
break;
}
}
static void shader_glsl_ld(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins)
{
unsigned int resource_id, resource_idx, resource_space, sample_count;
const struct glsl_resource_type_info *resource_type_info;
const struct vkd3d_shader_descriptor_info1 *d;
enum vkd3d_shader_resource_type resource_type;
struct vkd3d_string_buffer *fetch;
enum vsir_data_type data_type;
struct glsl_src coord;
struct glsl_dst dst;
uint32_t coord_mask;
if (vkd3d_shader_instruction_has_texel_offset(ins))
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_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)
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_UNSUPPORTED,
"Descriptor indexing is not supported.");
resource_id = ins->src[1].reg.idx[0].offset;
resource_idx = ins->src[1].reg.idx[1].offset;
if ((d = shader_glsl_get_descriptor_by_id(gen, VKD3D_SHADER_DESCRIPTOR_TYPE_SRV, resource_id)))
{
resource_type = d->resource_type;
resource_space = d->register_space;
sample_count = d->sample_count;
data_type = d->resource_data_type;
}
else
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Undeclared resource descriptor %u.", resource_id);
resource_space = 0;
resource_type = VKD3D_SHADER_RESOURCE_TEXTURE_2D;
sample_count = 1;
data_type = VSIR_DATA_F32;
}
if ((resource_type_info = shader_glsl_get_resource_type_info(resource_type)))
{
coord_mask = vkd3d_write_mask_from_component_count(resource_type_info->coord_size);
}
else
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled resource type %#x.", resource_type);
coord_mask = vkd3d_write_mask_from_component_count(2);
}
glsl_dst_init(&dst, gen, ins, &ins->dst[0]);
glsl_src_init(&coord, gen, &ins->src[0], coord_mask);
fetch = vkd3d_string_buffer_get(&gen->string_buffers);
vkd3d_string_buffer_printf(fetch, "texelFetch(");
shader_glsl_print_combined_sampler_name(fetch, gen, resource_idx,
resource_space, VKD3D_SHADER_DUMMY_SAMPLER_INDEX, 0);
vkd3d_string_buffer_printf(fetch, ", %s", coord.str->buffer);
if (resource_type != VKD3D_SHADER_RESOURCE_BUFFER)
{
vkd3d_string_buffer_printf(fetch, ", ");
if (ins->opcode != VSIR_OP_LD2DMS)
shader_glsl_print_src(fetch, gen, &ins->src[0], VKD3DSP_WRITEMASK_3, ins->src[0].reg.data_type);
else if (sample_count == 1)
/* If the resource isn't a true multisample resource, this is the
* "lod" parameter instead of the "sample" parameter. */
vkd3d_string_buffer_printf(fetch, "0");
else
shader_glsl_print_src(fetch, gen, &ins->src[2], VKD3DSP_WRITEMASK_0, ins->src[2].reg.data_type);
}
vkd3d_string_buffer_printf(fetch, ")");
shader_glsl_print_swizzle(fetch, ins->src[1].swizzle, ins->dst[0].write_mask);
shader_glsl_print_assignment_ext(gen, &dst, data_type, "%s", fetch->buffer);
vkd3d_string_buffer_release(&gen->string_buffers, fetch);
glsl_src_cleanup(&coord, &gen->string_buffers);
glsl_dst_cleanup(&dst, &gen->string_buffers);
}
static void shader_glsl_print_shadow_coord(struct vkd3d_string_buffer *buffer, struct vkd3d_glsl_generator *gen,
const struct vkd3d_shader_src_param *coord, const struct vkd3d_shader_src_param *ref, unsigned int coord_size)
{
uint32_t coord_mask = vkd3d_write_mask_from_component_count(coord_size);
switch (coord_size)
{
case 1:
vkd3d_string_buffer_printf(buffer, "vec3(");
shader_glsl_print_src(buffer, gen, coord, coord_mask, coord->reg.data_type);
vkd3d_string_buffer_printf(buffer, ", 0.0, ");
shader_glsl_print_src(buffer, gen, ref, VKD3DSP_WRITEMASK_0, ref->reg.data_type);
vkd3d_string_buffer_printf(buffer, ")");
break;
case 4:
shader_glsl_print_src(buffer, gen, coord, coord_mask, coord->reg.data_type);
vkd3d_string_buffer_printf(buffer, ", ");
shader_glsl_print_src(buffer, gen, ref, VKD3DSP_WRITEMASK_0, ref->reg.data_type);
break;
default:
vkd3d_string_buffer_printf(buffer, "vec%u(", coord_size + 1);
shader_glsl_print_src(buffer, gen, coord, coord_mask, coord->reg.data_type);
vkd3d_string_buffer_printf(buffer, ", ");
shader_glsl_print_src(buffer, gen, ref, VKD3DSP_WRITEMASK_0, ref->reg.data_type);
vkd3d_string_buffer_printf(buffer, ")");
break;
}
}
static void shader_glsl_sample(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins)
{
bool shadow_sampler, array, bias, dynamic_offset, gather, grad, lod, lod_zero, offset, shadow;
const struct glsl_resource_type_info *resource_type_info;
const struct vkd3d_shader_src_param *resource, *sampler;
unsigned int resource_id, resource_idx, resource_space;
unsigned int sampler_id, sampler_idx, sampler_space;
const struct vkd3d_shader_descriptor_info1 *d;
enum vkd3d_shader_resource_type resource_type;
unsigned int component_idx, coord_size;
struct vkd3d_string_buffer *sample;
enum vsir_data_type data_type;
struct glsl_dst dst;
bias = ins->opcode == VSIR_OP_SAMPLE_B;
dynamic_offset = ins->opcode == VSIR_OP_GATHER4_PO;
gather = ins->opcode == VSIR_OP_GATHER4 || ins->opcode == VSIR_OP_GATHER4_PO;
grad = ins->opcode == VSIR_OP_SAMPLE_GRAD;
lod = ins->opcode == VSIR_OP_SAMPLE_LOD || ins->opcode == VSIR_OP_SAMPLE_C_LZ;
lod_zero = ins->opcode == VSIR_OP_SAMPLE_C_LZ;
offset = dynamic_offset || vkd3d_shader_instruction_has_texel_offset(ins);
shadow = ins->opcode == VSIR_OP_SAMPLE_C || ins->opcode == VSIR_OP_SAMPLE_C_LZ;
resource = &ins->src[1 + dynamic_offset];
sampler = &ins->src[2 + dynamic_offset];
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)
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_UNSUPPORTED,
"Descriptor indexing is not supported.");
resource_id = resource->reg.idx[0].offset;
resource_idx = resource->reg.idx[1].offset;
if ((d = shader_glsl_get_descriptor_by_id(gen, VKD3D_SHADER_DESCRIPTOR_TYPE_SRV, resource_id)))
{
resource_type = d->resource_type;
resource_space = d->register_space;
data_type = d->resource_data_type;
}
else
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Undeclared resource descriptor %u.", resource_id);
resource_space = 0;
resource_type = VKD3D_SHADER_RESOURCE_TEXTURE_2D;
data_type = VSIR_DATA_F32;
}
if ((resource_type_info = shader_glsl_get_resource_type_info(resource_type)))
{
coord_size = resource_type_info->coord_size;
array = resource_type_info->array;
}
else
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled resource type %#x.", resource_type);
coord_size = 2;
array = false;
}
sampler_id = sampler->reg.idx[0].offset;
sampler_idx = sampler->reg.idx[1].offset;
if ((d = shader_glsl_get_descriptor_by_id(gen, VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER, sampler_id)))
{
sampler_space = d->register_space;
shadow_sampler = d->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_SAMPLER_COMPARISON_MODE;
if (shadow)
{
if (!shadow_sampler)
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Sampler %u is not a comparison sampler.", sampler_id);
}
else
{
if (shadow_sampler)
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Sampler %u is a comparison sampler.", sampler_id);
}
}
else
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Undeclared sampler descriptor %u.", sampler_id);
sampler_space = 0;
}
glsl_dst_init(&dst, gen, ins, &ins->dst[0]);
sample = vkd3d_string_buffer_get(&gen->string_buffers);
if (gather)
vkd3d_string_buffer_printf(sample, "textureGather");
else if (grad)
vkd3d_string_buffer_printf(sample, "textureGrad");
else if (lod)
vkd3d_string_buffer_printf(sample, "textureLod");
else
vkd3d_string_buffer_printf(sample, "texture");
vkd3d_string_buffer_printf(sample, "%s(", offset ? "Offset" : "");
shader_glsl_print_combined_sampler_name(sample, gen, resource_idx, resource_space, sampler_idx, sampler_space);
vkd3d_string_buffer_printf(sample, ", ");
if (shadow)
shader_glsl_print_shadow_coord(sample, gen, &ins->src[0], &ins->src[3], coord_size);
else
shader_glsl_print_src(sample, gen, &ins->src[0],
vkd3d_write_mask_from_component_count(coord_size), ins->src[0].reg.data_type);
if (grad)
{
vkd3d_string_buffer_printf(sample, ", ");
shader_glsl_print_src(sample, gen, &ins->src[3],
vkd3d_write_mask_from_component_count(coord_size - array), ins->src[3].reg.data_type);
vkd3d_string_buffer_printf(sample, ", ");
shader_glsl_print_src(sample, gen, &ins->src[4],
vkd3d_write_mask_from_component_count(coord_size - array), ins->src[4].reg.data_type);
}
else if (lod_zero)
{
vkd3d_string_buffer_printf(sample, ", 0.0");
}
else if (lod)
{
vkd3d_string_buffer_printf(sample, ", ");
shader_glsl_print_src(sample, gen, &ins->src[3], VKD3DSP_WRITEMASK_0, ins->src[3].reg.data_type);
}
if (offset)
{
vkd3d_string_buffer_printf(sample, ", ");
if (dynamic_offset)
shader_glsl_print_src(sample, gen, &ins->src[1],
vkd3d_write_mask_from_component_count(coord_size - array), ins->src[1].reg.data_type);
else
shader_glsl_print_texel_offset(sample, gen, coord_size - array, &ins->texel_offset);
}
if (bias)
{
vkd3d_string_buffer_printf(sample, ", ");
shader_glsl_print_src(sample, gen, &ins->src[3], VKD3DSP_WRITEMASK_0, ins->src[3].reg.data_type);
}
else if (gather)
{
if ((component_idx = vsir_swizzle_get_component(sampler->swizzle, 0)))
vkd3d_string_buffer_printf(sample, ", %d", component_idx);
}
vkd3d_string_buffer_printf(sample, ")");
shader_glsl_print_swizzle(sample, resource->swizzle, ins->dst[0].write_mask);
shader_glsl_print_assignment_ext(gen, &dst, data_type, "%s", sample->buffer);
vkd3d_string_buffer_release(&gen->string_buffers, sample);
glsl_dst_cleanup(&dst, &gen->string_buffers);
}
static void shader_glsl_load_uav_typed(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins)
{
const struct glsl_resource_type_info *resource_type_info;
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 *load;
enum vsir_data_type data_type;
struct glsl_src coord;
struct glsl_dst dst;
uint32_t coord_mask;
if (ins->src[1].reg.idx[0].rel_addr || ins->src[1].reg.idx[1].rel_addr)
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_UNSUPPORTED,
"Descriptor indexing is not supported.");
uav_id = ins->src[1].reg.idx[0].offset;
uav_idx = ins->src[1].reg.idx[1].offset;
if ((d = shader_glsl_get_descriptor_by_id(gen, VKD3D_SHADER_DESCRIPTOR_TYPE_UAV, uav_id)))
{
resource_type = d->resource_type;
uav_space = d->register_space;
data_type = d->resource_data_type;
}
else
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Undeclared UAV descriptor %u.", uav_id);
uav_space = 0;
resource_type = VKD3D_SHADER_RESOURCE_TEXTURE_2D;
data_type = VSIR_DATA_F32;
}
if ((resource_type_info = shader_glsl_get_resource_type_info(resource_type)))
{
coord_mask = vkd3d_write_mask_from_component_count(resource_type_info->coord_size);
}
else
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled UAV type %#x.", resource_type);
coord_mask = vkd3d_write_mask_from_component_count(2);
}
glsl_dst_init(&dst, gen, ins, &ins->dst[0]);
glsl_src_init(&coord, gen, &ins->src[0], coord_mask);
load = vkd3d_string_buffer_get(&gen->string_buffers);
vkd3d_string_buffer_printf(load, "imageLoad(");
shader_glsl_print_image_name(load, gen, uav_idx, uav_space);
vkd3d_string_buffer_printf(load, ", %s)", coord.str->buffer);
shader_glsl_print_swizzle(load, ins->src[1].swizzle, ins->dst[0].write_mask);
shader_glsl_print_assignment_ext(gen, &dst, data_type, "%s", load->buffer);
vkd3d_string_buffer_release(&gen->string_buffers, load);
glsl_src_cleanup(&coord, &gen->string_buffers);
glsl_dst_cleanup(&dst, &gen->string_buffers);
}
static void shader_glsl_store_uav_typed(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins)
{
const struct glsl_resource_type_info *resource_type_info;
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;
enum vsir_data_type data_type;
struct glsl_src image_coord;
uint32_t coord_mask;
if (ins->dst[0].reg.idx[0].rel_addr || ins->dst[0].reg.idx[1].rel_addr)
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_UNSUPPORTED,
"Descriptor indexing is not supported.");
uav_id = ins->dst[0].reg.idx[0].offset;
uav_idx = ins->dst[0].reg.idx[1].offset;
if ((d = shader_glsl_get_descriptor_by_id(gen, VKD3D_SHADER_DESCRIPTOR_TYPE_UAV, uav_id)))
{
resource_type = d->resource_type;
uav_space = d->register_space;
data_type = d->resource_data_type;
}
else
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Undeclared UAV descriptor %u.", uav_id);
uav_space = 0;
resource_type = VKD3D_SHADER_RESOURCE_TEXTURE_2D;
data_type = VSIR_DATA_F32;
}
if ((resource_type_info = shader_glsl_get_resource_type_info(resource_type)))
{
coord_mask = vkd3d_write_mask_from_component_count(resource_type_info->coord_size);
}
else
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled UAV type %#x.", resource_type);
coord_mask = vkd3d_write_mask_from_component_count(2);
}
glsl_src_init(&image_coord, gen, &ins->src[0], coord_mask);
image_data = vkd3d_string_buffer_get(&gen->string_buffers);
if (ins->src[1].reg.dimension == VSIR_DIMENSION_SCALAR)
{
switch (data_type)
{
case VSIR_DATA_I32:
vkd3d_string_buffer_printf(image_data, "ivec4(");
break;
case VSIR_DATA_U32:
vkd3d_string_buffer_printf(image_data, "uvec4(");
break;
default:
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled data type %#x.", data_type);
/* fall through */
case VSIR_DATA_F32:
case VSIR_DATA_SNORM:
case VSIR_DATA_UNORM:
vkd3d_string_buffer_printf(image_data, "vec4(");
break;
}
}
shader_glsl_print_src(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)");
shader_glsl_print_indent(gen->buffer, gen->indent);
vkd3d_string_buffer_printf(gen->buffer, "imageStore(");
shader_glsl_print_image_name(gen->buffer, gen, uav_idx, uav_space);
vkd3d_string_buffer_printf(gen->buffer, ", %s, %s);\n", image_coord.str->buffer, image_data->buffer);
vkd3d_string_buffer_release(&gen->string_buffers, image_data);
glsl_src_cleanup(&image_coord, &gen->string_buffers);
}
static void shader_glsl_unary_op(struct vkd3d_glsl_generator *gen,
const struct vkd3d_shader_instruction *ins, const char *op)
{
struct glsl_src src;
struct glsl_dst dst;
uint32_t mask;
mask = glsl_dst_init(&dst, gen, ins, &ins->dst[0]);
glsl_src_init(&src, gen, &ins->src[0], mask);
shader_glsl_print_assignment(gen, &dst, "%s%s", op, src.str->buffer);
glsl_src_cleanup(&src, &gen->string_buffers);
glsl_dst_cleanup(&dst, &gen->string_buffers);
}
static void shader_glsl_mov(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins)
{
struct glsl_src src;
struct glsl_dst dst;
uint32_t mask;
mask = glsl_dst_init(&dst, gen, ins, &ins->dst[0]);
glsl_src_init(&src, gen, &ins->src[0], mask);
shader_glsl_print_assignment(gen, &dst, "%s", src.str->buffer);
glsl_src_cleanup(&src, &gen->string_buffers);
glsl_dst_cleanup(&dst, &gen->string_buffers);
}
static void shader_glsl_movc(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins)
{
unsigned int component_count;
struct glsl_src src[3];
struct glsl_dst dst;
uint32_t mask;
mask = glsl_dst_init(&dst, gen, ins, &ins->dst[0]);
glsl_src_init(&src[0], gen, &ins->src[0], mask);
glsl_src_init(&src[1], gen, &ins->src[1], mask);
glsl_src_init(&src[2], gen, &ins->src[2], mask);
if ((component_count = vsir_write_mask_component_count(mask)) > 1)
shader_glsl_print_assignment(gen, &dst, "mix(%s, %s, bvec%u(%s))",
src[2].str->buffer, src[1].str->buffer, component_count, src[0].str->buffer);
else
shader_glsl_print_assignment(gen, &dst, "mix(%s, %s, bool(%s))",
src[2].str->buffer, src[1].str->buffer, src[0].str->buffer);
glsl_src_cleanup(&src[2], &gen->string_buffers);
glsl_src_cleanup(&src[1], &gen->string_buffers);
glsl_src_cleanup(&src[0], &gen->string_buffers);
glsl_dst_cleanup(&dst, &gen->string_buffers);
}
static void shader_glsl_print_sysval_name(struct vkd3d_string_buffer *buffer, struct vkd3d_glsl_generator *gen,
enum vkd3d_shader_sysval_semantic sysval, unsigned int idx)
{
const struct vkd3d_shader_version *version = &gen->program->shader_version;
switch (sysval)
{
case VKD3D_SHADER_SV_POSITION:
if (version->type == VKD3D_SHADER_TYPE_COMPUTE)
{
vkd3d_string_buffer_printf(buffer, "<unhandled sysval %#x>", sysval);
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled SV_POSITION in shader type #%x.", version->type);
break;
}
if (idx)
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled SV_POSITION index %u.", idx);
if (version->type == VKD3D_SHADER_TYPE_PIXEL)
vkd3d_string_buffer_printf(buffer, "vec4(gl_FragCoord.xyz, 1.0 / gl_FragCoord.w)");
else
vkd3d_string_buffer_printf(buffer, "gl_Position");
break;
case VKD3D_SHADER_SV_VERTEX_ID:
if (version->type != VKD3D_SHADER_TYPE_VERTEX)
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled SV_VERTEX_ID in shader type #%x.", version->type);
vkd3d_string_buffer_printf(buffer, "intBitsToFloat(ivec4(gl_VertexID, 0, 0, 0))");
break;
case VKD3D_SHADER_SV_IS_FRONT_FACE:
if (version->type != VKD3D_SHADER_TYPE_PIXEL)
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled SV_IS_FRONT_FACE in shader type #%x.", version->type);
vkd3d_string_buffer_printf(buffer,
"uintBitsToFloat(uvec4(gl_FrontFacing ? 0xffffffffu : 0u, 0u, 0u, 0u))");
break;
case VKD3D_SHADER_SV_SAMPLE_INDEX:
if (version->type != VKD3D_SHADER_TYPE_PIXEL)
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled SV_SAMPLE_INDEX in shader type #%x.", version->type);
vkd3d_string_buffer_printf(buffer, "intBitsToFloat(ivec4(gl_SampleID, 0, 0, 0))");
break;
case VKD3D_SHADER_SV_TARGET:
if (version->type != VKD3D_SHADER_TYPE_PIXEL)
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled SV_TARGET in shader type #%x.", version->type);
vkd3d_string_buffer_printf(buffer, "shader_out_%u", idx);
break;
default:
vkd3d_string_buffer_printf(buffer, "<unhandled sysval %#x>", sysval);
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled system value %#x.", sysval);
break;
}
}
static void shader_glsl_shader_prologue(struct vkd3d_glsl_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;
shader_glsl_print_indent(buffer, gen->indent);
vkd3d_string_buffer_printf(buffer, "%s_in[%u]", gen->prefix, e->register_index);
shader_glsl_print_write_mask(buffer, e->mask);
if (e->sysval_semantic == VKD3D_SHADER_SV_NONE)
{
if (gen->interstage_input)
{
vkd3d_string_buffer_printf(buffer, " = shader_in.reg_%u", e->target_location);
if (e->target_location >= gen->limits.input_count)
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Input element %u specifies target location %u, "
"but only %u inputs are supported.",
i, e->target_location, gen->limits.input_count);
}
else
{
switch (e->component_type)
{
case VKD3D_SHADER_COMPONENT_UINT:
vkd3d_string_buffer_printf(buffer, " = uintBitsToFloat(shader_in_%u)", i);
break;
case VKD3D_SHADER_COMPONENT_INT:
vkd3d_string_buffer_printf(buffer, " = intBitsToFloat(shader_in_%u)", i);
break;
default:
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled input component type %#x.", e->component_type);
/* fall through */
case VKD3D_SHADER_COMPONENT_FLOAT:
vkd3d_string_buffer_printf(buffer, " = shader_in_%u", i);
break;
}
}
}
else
{
vkd3d_string_buffer_printf(buffer, " = ");
shader_glsl_print_sysval_name(buffer, gen, e->sysval_semantic, e->semantic_index);
}
shader_glsl_print_write_mask(buffer, e->mask);
vkd3d_string_buffer_printf(buffer, ";\n");
}
}
static void shader_glsl_shader_epilogue(struct vkd3d_glsl_generator *gen)
{
const struct shader_signature *signature = &gen->program->output_signature;
struct vkd3d_string_buffer *buffer = gen->buffer;
enum vkd3d_shader_component_type type;
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;
type = e->component_type;
shader_glsl_print_indent(buffer, gen->indent);
if (e->sysval_semantic == VKD3D_SHADER_SV_NONE)
{
if (gen->interstage_output)
{
type = VKD3D_SHADER_COMPONENT_FLOAT;
vkd3d_string_buffer_printf(buffer, "shader_out.reg_%u", e->target_location);
if (e->target_location >= gen->limits.output_count)
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Output element %u specifies target location %u, "
"but only %u outputs are supported.",
i, e->target_location, gen->limits.output_count);
}
else
{
vkd3d_string_buffer_printf(buffer, "<unhandled output %u>", e->target_location);
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled output.");
}
}
else
{
shader_glsl_print_sysval_name(buffer, gen, e->sysval_semantic, e->semantic_index);
}
shader_glsl_print_write_mask(buffer, e->mask);
switch (type)
{
case VKD3D_SHADER_COMPONENT_UINT:
vkd3d_string_buffer_printf(buffer, " = floatBitsToUint(%s_out[%u])", gen->prefix, e->register_index);
break;
case VKD3D_SHADER_COMPONENT_INT:
vkd3d_string_buffer_printf(buffer, " = floatBitsToInt(%s_out[%u])", gen->prefix, e->register_index);
break;
default:
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled output component type %#x.", e->component_type);
/* fall through */
case VKD3D_SHADER_COMPONENT_FLOAT:
vkd3d_string_buffer_printf(buffer, " = %s_out[%u]", gen->prefix, e->register_index);
break;
}
shader_glsl_print_write_mask(buffer, e->mask);
vkd3d_string_buffer_printf(buffer, ";\n");
}
}
static void shader_glsl_ret(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_instruction *ins)
{
const struct vkd3d_shader_version *version = &gen->program->shader_version;
if (version->major >= 4)
{
shader_glsl_shader_epilogue(gen);
shader_glsl_print_indent(gen->buffer, gen->indent);
vkd3d_string_buffer_printf(gen->buffer, "return;\n");
}
}
static void shader_glsl_dcl_indexable_temp(struct vkd3d_glsl_generator *gen,
const struct vkd3d_shader_instruction *ins)
{
shader_glsl_print_indent(gen->buffer, gen->indent);
vkd3d_string_buffer_printf(gen->buffer, "vec4 x%u[%u];\n",
ins->declaration.indexable_temp.register_idx,
ins->declaration.indexable_temp.register_size);
}
static void vkd3d_glsl_handle_instruction(struct vkd3d_glsl_generator *gen,
const struct vkd3d_shader_instruction *ins)
{
gen->location = ins->location;
switch (ins->opcode)
{
case VSIR_OP_ADD:
case VSIR_OP_IADD:
shader_glsl_binop(gen, ins, "+");
break;
case VSIR_OP_AND:
shader_glsl_binop(gen, ins, "&");
break;
case VSIR_OP_BREAK:
shader_glsl_break(gen);
break;
case VSIR_OP_CASE:
shader_glsl_case(gen, ins);
break;
case VSIR_OP_CONTINUE:
shader_glsl_continue(gen);
break;
case VSIR_OP_DCL_INDEXABLE_TEMP:
shader_glsl_dcl_indexable_temp(gen, ins);
break;
case VSIR_OP_NOP:
break;
case VSIR_OP_DEFAULT:
shader_glsl_default(gen);
break;
case VSIR_OP_DIV:
shader_glsl_binop(gen, ins, "/");
break;
case VSIR_OP_DP2:
shader_glsl_dot(gen, ins, vkd3d_write_mask_from_component_count(2));
break;
case VSIR_OP_DP3:
shader_glsl_dot(gen, ins, vkd3d_write_mask_from_component_count(3));
break;
case VSIR_OP_DP4:
shader_glsl_dot(gen, ins, VKD3DSP_WRITEMASK_ALL);
break;
case VSIR_OP_ELSE:
shader_glsl_else(gen, ins);
break;
case VSIR_OP_ENDIF:
case VSIR_OP_ENDLOOP:
case VSIR_OP_ENDSWITCH:
shader_glsl_end_block(gen);
break;
case VSIR_OP_EQO:
case VSIR_OP_IEQ:
shader_glsl_relop(gen, ins, "==", "equal");
break;
case VSIR_OP_EXP:
shader_glsl_intrinsic(gen, ins, "exp2");
break;
case VSIR_OP_FRC:
shader_glsl_intrinsic(gen, ins, "fract");
break;
case VSIR_OP_FTOI:
shader_glsl_cast(gen, ins, "int", "ivec");
break;
case VSIR_OP_FTOU:
shader_glsl_cast(gen, ins, "uint", "uvec");
break;
case VSIR_OP_GATHER4:
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:
shader_glsl_sample(gen, ins);
break;
case VSIR_OP_GEO:
case VSIR_OP_IGE:
shader_glsl_relop(gen, ins, ">=", "greaterThanEqual");
break;
case VSIR_OP_IF:
shader_glsl_if(gen, ins);
break;
case VSIR_OP_MAD:
shader_glsl_intrinsic(gen, ins, "fma");
break;
case VSIR_OP_ILT:
case VSIR_OP_LTO:
case VSIR_OP_ULT:
shader_glsl_relop(gen, ins, "<", "lessThan");
break;
case VSIR_OP_IMAX:
case VSIR_OP_MAX:
case VSIR_OP_UMAX:
shader_glsl_intrinsic(gen, ins, "max");
break;
case VSIR_OP_MIN:
case VSIR_OP_UMIN:
shader_glsl_intrinsic(gen, ins, "min");
break;
case VSIR_OP_IMUL_LOW:
shader_glsl_binop(gen, ins, "*");
break;
case VSIR_OP_INE:
case VSIR_OP_NEU:
shader_glsl_relop(gen, ins, "!=", "notEqual");
break;
case VSIR_OP_INEG:
shader_glsl_unary_op(gen, ins, "-");
break;
case VSIR_OP_ISHL:
shader_glsl_binop(gen, ins, "<<");
break;
case VSIR_OP_ISHR:
case VSIR_OP_USHR:
shader_glsl_binop(gen, ins, ">>");
break;
case VSIR_OP_ITOF:
case VSIR_OP_UTOF:
shader_glsl_cast(gen, ins, "float", "vec");
break;
case VSIR_OP_LD:
case VSIR_OP_LD2DMS:
shader_glsl_ld(gen, ins);
break;
case VSIR_OP_LD_UAV_TYPED:
shader_glsl_load_uav_typed(gen, ins);
break;
case VSIR_OP_LOG:
shader_glsl_intrinsic(gen, ins, "log2");
break;
case VSIR_OP_LOOP:
shader_glsl_loop(gen);
break;
case VSIR_OP_MOV:
shader_glsl_mov(gen, ins);
break;
case VSIR_OP_MOVC:
shader_glsl_movc(gen, ins);
break;
case VSIR_OP_MUL:
shader_glsl_binop(gen, ins, "*");
break;
case VSIR_OP_NOT:
shader_glsl_unary_op(gen, ins, "~");
break;
case VSIR_OP_OR:
shader_glsl_binop(gen, ins, "|");
break;
case VSIR_OP_RET:
shader_glsl_ret(gen, ins);
break;
case VSIR_OP_ROUND_NE:
shader_glsl_intrinsic(gen, ins, "roundEven");
break;
case VSIR_OP_ROUND_NI:
shader_glsl_intrinsic(gen, ins, "floor");
break;
case VSIR_OP_ROUND_PI:
shader_glsl_intrinsic(gen, ins, "ceil");
break;
case VSIR_OP_ROUND_Z:
shader_glsl_intrinsic(gen, ins, "trunc");
break;
case VSIR_OP_RSQ:
shader_glsl_intrinsic(gen, ins, "inversesqrt");
break;
case VSIR_OP_SQRT:
shader_glsl_intrinsic(gen, ins, "sqrt");
break;
case VSIR_OP_STORE_UAV_TYPED:
shader_glsl_store_uav_typed(gen, ins);
break;
case VSIR_OP_SWITCH:
shader_glsl_switch(gen, ins);
break;
case VSIR_OP_XOR:
shader_glsl_binop(gen, ins, "^");
break;
default:
shader_glsl_unhandled(gen, ins);
break;
}
}
static bool shader_glsl_check_shader_visibility(const struct vkd3d_glsl_generator *gen,
enum vkd3d_shader_visibility visibility)
{
enum vkd3d_shader_type t = gen->program->shader_version.type;
switch (visibility)
{
case VKD3D_SHADER_VISIBILITY_ALL:
return true;
case VKD3D_SHADER_VISIBILITY_VERTEX:
return t == VKD3D_SHADER_TYPE_VERTEX;
case VKD3D_SHADER_VISIBILITY_HULL:
return t == VKD3D_SHADER_TYPE_HULL;
case VKD3D_SHADER_VISIBILITY_DOMAIN:
return t == VKD3D_SHADER_TYPE_DOMAIN;
case VKD3D_SHADER_VISIBILITY_GEOMETRY:
return t == VKD3D_SHADER_TYPE_GEOMETRY;
case VKD3D_SHADER_VISIBILITY_PIXEL:
return t == VKD3D_SHADER_TYPE_PIXEL;
case VKD3D_SHADER_VISIBILITY_COMPUTE:
return t == VKD3D_SHADER_TYPE_COMPUTE;
default:
WARN("Invalid shader visibility %#x.\n", visibility);
return false;
}
}
static bool shader_glsl_get_uav_binding(const struct vkd3d_glsl_generator *gen, unsigned int register_space,
unsigned int register_idx, enum vkd3d_shader_resource_type resource_type, unsigned int *binding_idx)
{
const struct vkd3d_shader_interface_info *interface_info = gen->interface_info;
const struct vkd3d_shader_resource_binding *binding;
enum vkd3d_shader_binding_flag resource_type_flag;
unsigned int i;
if (!interface_info)
return false;
resource_type_flag = resource_type == VKD3D_SHADER_RESOURCE_BUFFER
? VKD3D_SHADER_BINDING_FLAG_BUFFER : VKD3D_SHADER_BINDING_FLAG_IMAGE;
for (i = 0; i < interface_info->binding_count; ++i)
{
binding = &interface_info->bindings[i];
if (binding->type != VKD3D_SHADER_DESCRIPTOR_TYPE_UAV)
continue;
if (binding->register_space != register_space)
continue;
if (binding->register_index != register_idx)
continue;
if (!shader_glsl_check_shader_visibility(gen, binding->shader_visibility))
continue;
if (!(binding->flags & resource_type_flag))
continue;
*binding_idx = i;
return true;
}
return false;
}
static void shader_glsl_generate_uav_declaration(struct vkd3d_glsl_generator *gen,
const struct vkd3d_shader_descriptor_info1 *uav)
{
const struct glsl_resource_type_info *resource_type_info;
const char *image_type_prefix, *image_type, *read_format;
const struct vkd3d_shader_descriptor_binding *binding;
const struct vkd3d_shader_descriptor_offset *offset;
struct vkd3d_string_buffer *buffer = gen->buffer;
unsigned int binding_idx;
if (uav->count != 1)
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_UNSUPPORTED,
"UAV %u has unsupported descriptor array size %u.", uav->register_id, uav->count);
return;
}
if (!shader_glsl_get_uav_binding(gen, uav->register_space,
uav->register_index, uav->resource_type, &binding_idx))
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_BINDING_NOT_FOUND,
"No descriptor binding specified for UAV %u.", uav->register_id);
return;
}
binding = &gen->interface_info->bindings[binding_idx].binding;
if (binding->set != 0)
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_BINDING_NOT_FOUND,
"Unsupported binding set %u specified for UAV %u.", binding->set, uav->register_id);
return;
}
if (binding->count != 1)
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_BINDING_NOT_FOUND,
"Unsupported binding count %u specified for UAV %u.", binding->count, uav->register_id);
return;
}
if (gen->offset_info && gen->offset_info->binding_offsets)
{
offset = &gen->offset_info->binding_offsets[binding_idx];
if (offset->static_offset || offset->dynamic_offset_index != ~0u)
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled descriptor offset specified for UAV %u.",
uav->register_id);
return;
}
}
if ((resource_type_info = shader_glsl_get_resource_type_info(uav->resource_type)))
{
image_type = resource_type_info->type_suffix;
}
else
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled UAV type %#x.", uav->resource_type);
image_type = "<unhandled image type>";
}
switch (uav->resource_data_type)
{
case VSIR_DATA_I32:
image_type_prefix = "i";
read_format = "r32i";
break;
case VSIR_DATA_U32:
image_type_prefix = "u";
read_format = "r32ui";
break;
default:
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled data type %#x for UAV %u.",
uav->resource_data_type, uav->register_id);
/* fall through */
case VSIR_DATA_F32:
case VSIR_DATA_SNORM:
case VSIR_DATA_UNORM:
image_type_prefix = "";
read_format = "r32f";
break;
}
vkd3d_string_buffer_printf(buffer, "layout(binding = %u", binding->binding);
if (uav->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_UAV_READ)
vkd3d_string_buffer_printf(buffer, ", %s) ", read_format);
else
vkd3d_string_buffer_printf(buffer, ") writeonly ");
vkd3d_string_buffer_printf(buffer, "uniform %simage%s ", image_type_prefix, image_type);
shader_glsl_print_image_name(buffer, gen, uav->register_index, uav->register_space);
vkd3d_string_buffer_printf(buffer, ";\n");
}
static bool shader_glsl_get_cbv_binding(const struct vkd3d_glsl_generator *gen,
unsigned int register_space, unsigned int register_idx, unsigned int *binding_idx)
{
const struct vkd3d_shader_interface_info *interface_info = gen->interface_info;
const struct vkd3d_shader_resource_binding *binding;
unsigned int i;
if (!interface_info)
return false;
for (i = 0; i < interface_info->binding_count; ++i)
{
binding = &interface_info->bindings[i];
if (binding->type != VKD3D_SHADER_DESCRIPTOR_TYPE_CBV)
continue;
if (binding->register_space != register_space)
continue;
if (binding->register_index != register_idx)
continue;
if (!shader_glsl_check_shader_visibility(gen, binding->shader_visibility))
continue;
if (!(binding->flags & VKD3D_SHADER_BINDING_FLAG_BUFFER))
continue;
*binding_idx = i;
return true;
}
return false;
}
static void shader_glsl_generate_cbv_declaration(struct vkd3d_glsl_generator *gen,
const struct vkd3d_shader_descriptor_info1 *cbv)
{
const struct vkd3d_shader_descriptor_binding *binding;
const struct vkd3d_shader_descriptor_offset *offset;
struct vkd3d_string_buffer *buffer = gen->buffer;
const char *prefix = gen->prefix;
unsigned int binding_idx;
size_t size;
if (cbv->count != 1)
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_UNSUPPORTED,
"Constant buffer %u has unsupported descriptor array size %u.", cbv->register_id, cbv->count);
return;
}
if (!shader_glsl_get_cbv_binding(gen, cbv->register_space, cbv->register_index, &binding_idx))
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_BINDING_NOT_FOUND,
"No descriptor binding specified for constant buffer %u.", cbv->register_id);
return;
}
binding = &gen->interface_info->bindings[binding_idx].binding;
if (binding->set != 0)
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_BINDING_NOT_FOUND,
"Unsupported binding set %u specified for constant buffer %u.", binding->set, cbv->register_id);
return;
}
if (binding->count != 1)
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_BINDING_NOT_FOUND,
"Unsupported binding count %u specified for constant buffer %u.", binding->count, cbv->register_id);
return;
}
if (gen->offset_info && gen->offset_info->binding_offsets)
{
offset = &gen->offset_info->binding_offsets[binding_idx];
if (offset->static_offset || offset->dynamic_offset_index != ~0u)
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled descriptor offset specified for constant buffer %u.",
cbv->register_id);
return;
}
}
size = align(cbv->buffer_size, VKD3D_VEC4_SIZE * sizeof(uint32_t));
size /= VKD3D_VEC4_SIZE * sizeof(uint32_t);
vkd3d_string_buffer_printf(buffer,
"layout(std140, binding = %u) uniform block_%s_cb_%u { vec4 %s_cb_%u[%zu]; };\n",
binding->binding, prefix, cbv->register_id, prefix, cbv->register_id, size);
}
static bool shader_glsl_get_combined_sampler_binding(const struct vkd3d_glsl_generator *gen,
const struct vkd3d_shader_combined_resource_sampler_info *crs,
enum vkd3d_shader_resource_type resource_type, unsigned int *binding_idx)
{
const struct vkd3d_shader_interface_info *interface_info = gen->interface_info;
const struct vkd3d_shader_combined_resource_sampler *s;
enum vkd3d_shader_binding_flag resource_type_flag;
unsigned int i;
if (!interface_info)
return false;
resource_type_flag = resource_type == VKD3D_SHADER_RESOURCE_BUFFER
? VKD3D_SHADER_BINDING_FLAG_BUFFER : VKD3D_SHADER_BINDING_FLAG_IMAGE;
for (i = 0; i < interface_info->combined_sampler_count; ++i)
{
s = &interface_info->combined_samplers[i];
if (s->resource_space != crs->resource_space)
continue;
if (s->resource_index != crs->resource_index)
continue;
if (crs->sampler_index != VKD3D_SHADER_DUMMY_SAMPLER_INDEX)
{
if (s->sampler_space != crs->sampler_space)
continue;
if (s->sampler_index != crs->sampler_index)
continue;
}
if (!shader_glsl_check_shader_visibility(gen, s->shader_visibility))
continue;
if (!(s->flags & resource_type_flag))
continue;
*binding_idx = i;
return true;
}
return false;
}
static void shader_glsl_generate_sampler_declaration(struct vkd3d_glsl_generator *gen,
const struct vkd3d_shader_combined_resource_sampler_info *crs)
{
const struct vkd3d_shader_descriptor_info1 *sampler, *srv;
const struct glsl_resource_type_info *resource_type_info;
const struct vkd3d_shader_descriptor_binding *binding;
struct vkd3d_string_buffer *buffer = gen->buffer;
const char *sampler_type, *sampler_type_prefix;
enum vkd3d_shader_resource_type resource_type;
unsigned int binding_idx;
bool shadow = false;
if (crs->sampler_index != VKD3D_SHADER_DUMMY_SAMPLER_INDEX)
{
if (!(sampler = shader_glsl_get_descriptor(gen, VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER,
crs->sampler_index, crs->sampler_space)))
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: No descriptor found for sampler %u, space %u.",
crs->sampler_index, crs->sampler_space);
return;
}
shadow = sampler->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_SAMPLER_COMPARISON_MODE;
}
if (!(srv = shader_glsl_get_descriptor(gen, VKD3D_SHADER_DESCRIPTOR_TYPE_SRV,
crs->resource_index, crs->resource_space)))
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: No descriptor found for resource %u, space %u.",
crs->resource_index, crs->resource_space);
return;
}
resource_type = srv->resource_type;
if (srv->sample_count == 1)
{
/* The OpenGL API distinguishes between multi-sample textures with
* sample count 1 and single-sample textures. Direct3D and Vulkan
* don't make this distinction at the API level, but Direct3D shaders
* are capable of expressing both. We therefore map such multi-sample
* textures to their single-sample equivalents here. */
if (resource_type == VKD3D_SHADER_RESOURCE_TEXTURE_2DMS)
resource_type = VKD3D_SHADER_RESOURCE_TEXTURE_2D;
else if (resource_type == VKD3D_SHADER_RESOURCE_TEXTURE_2DMSARRAY)
resource_type = VKD3D_SHADER_RESOURCE_TEXTURE_2DARRAY;
}
if ((resource_type_info = shader_glsl_get_resource_type_info(resource_type)))
{
sampler_type = resource_type_info->type_suffix;
if (shadow && !resource_type_info->shadow)
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_UNSUPPORTED,
"Comparison samplers are not supported with resource type %#x.", resource_type);
}
else
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled resource type %#x for combined resource/sampler "
"for resource %u, space %u and sampler %u, space %u.", resource_type,
crs->resource_index, crs->resource_space, crs->sampler_index, crs->sampler_space);
sampler_type = "<unhandled sampler type>";
}
switch (srv->resource_data_type)
{
case VSIR_DATA_F32:
case VSIR_DATA_SNORM:
case VSIR_DATA_UNORM:
sampler_type_prefix = "";
break;
case VSIR_DATA_I32:
sampler_type_prefix = "i";
break;
case VSIR_DATA_U32:
sampler_type_prefix = "u";
break;
default:
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled data type %#x for combined resource/sampler "
"for resource %u, space %u and sampler %u, space %u.", srv->resource_data_type,
crs->resource_index, crs->resource_space, crs->sampler_index, crs->sampler_space);
sampler_type_prefix = "";
break;
}
if (!shader_glsl_get_combined_sampler_binding(gen, crs, resource_type, &binding_idx))
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_BINDING_NOT_FOUND,
"No descriptor binding specified for combined resource/sampler "
"for resource %u, space %u and sampler %u, space %u.",
crs->resource_index, crs->resource_space, crs->sampler_index, crs->sampler_space);
return;
}
binding = &gen->interface_info->combined_samplers[binding_idx].binding;
if (binding->set != 0)
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_BINDING_NOT_FOUND,
"Unsupported binding set %u specified for combined resource/sampler "
"for resource %u, space %u and sampler %u, space %u.", binding->set,
crs->resource_index, crs->resource_space, crs->sampler_index, crs->sampler_space);
return;
}
if (binding->count != 1)
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_BINDING_NOT_FOUND,
"Unsupported binding count %u specified for combined resource/sampler "
"for resource %u, space %u and sampler %u, space %u.", binding->count,
crs->resource_index, crs->resource_space, crs->sampler_index, crs->sampler_space);
return;
}
vkd3d_string_buffer_printf(buffer, "layout(binding = %u) uniform %ssampler%s%s ",
binding->binding, sampler_type_prefix, sampler_type, shadow ? "Shadow" : "");
shader_glsl_print_combined_sampler_name(buffer, gen, crs->resource_index,
crs->resource_space, crs->sampler_index, crs->sampler_space);
vkd3d_string_buffer_printf(buffer, ";\n");
}
static void shader_glsl_generate_descriptor_declarations(struct vkd3d_glsl_generator *gen)
{
const struct vkd3d_shader_scan_combined_resource_sampler_info *sampler_info = gen->combined_sampler_info;
const struct vkd3d_shader_scan_descriptor_info1 *info = &gen->program->descriptors;
const struct vkd3d_shader_descriptor_info1 *descriptor;
unsigned int i;
for (i = 0; i < info->descriptor_count; ++i)
{
descriptor = &info->descriptors[i];
switch (descriptor->type)
{
case VKD3D_SHADER_DESCRIPTOR_TYPE_SRV:
case VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER:
/* GLSL uses combined resource/sampler descriptors.*/
break;
case VKD3D_SHADER_DESCRIPTOR_TYPE_UAV:
shader_glsl_generate_uav_declaration(gen, descriptor);
break;
case VKD3D_SHADER_DESCRIPTOR_TYPE_CBV:
shader_glsl_generate_cbv_declaration(gen, descriptor);
break;
default:
vkd3d_string_buffer_printf(gen->buffer, "/* <unhandled descriptor type %#x> */\n", descriptor->type);
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled descriptor type %#x.", descriptor->type);
break;
}
}
for (i = 0; i < sampler_info->combined_sampler_count; ++i)
{
shader_glsl_generate_sampler_declaration(gen, &sampler_info->combined_samplers[i]);
}
if (info->descriptor_count)
vkd3d_string_buffer_printf(gen->buffer, "\n");
}
static const struct signature_element *signature_get_element_by_location(
const struct shader_signature *signature, unsigned int location)
{
const struct signature_element *e;
unsigned int i;
for (i = 0; i < signature->element_count; ++i)
{
e = &signature->elements[i];
if (e->target_location != location)
continue;
return e;
}
return NULL;
}
static const char *shader_glsl_get_interpolation(struct vkd3d_glsl_generator *gen,
const struct shader_signature *signature, const char *type, unsigned int location)
{
enum vkd3d_shader_interpolation_mode m;
const struct signature_element *e;
if ((e = signature_get_element_by_location(signature, location)))
m = e->interpolation_mode;
else
m = VKD3DSIM_NONE;
switch (m)
{
case VKD3DSIM_NONE:
case VKD3DSIM_LINEAR:
return "";
case VKD3DSIM_CONSTANT:
return "flat ";
default:
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled interpolation mode %#x for %s location %u.", m, type, location);
return "";
}
}
static void shader_glsl_generate_interface_block(struct vkd3d_glsl_generator *gen,
const struct shader_signature *signature, const char *type, unsigned int count)
{
struct vkd3d_string_buffer *buffer = gen->buffer;
const char *interpolation;
unsigned int i;
vkd3d_string_buffer_printf(buffer, "%s shader_in_out\n{\n", type);
for (i = 0; i < count; ++i)
{
interpolation = shader_glsl_get_interpolation(gen, signature, type, i);
vkd3d_string_buffer_printf(buffer, " %svec4 reg_%u;\n", interpolation, i);
}
vkd3d_string_buffer_printf(buffer, "} shader_%s;\n", type);
}
static void shader_glsl_generate_input_declarations(struct vkd3d_glsl_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, count;
if (!gen->interstage_input)
{
for (i = 0, count = 0; i < signature->element_count; ++i)
{
e = &signature->elements[i];
if (e->target_location == SIGNATURE_TARGET_LOCATION_UNUSED || e->sysval_semantic)
continue;
if (e->min_precision != VKD3D_SHADER_MINIMUM_PRECISION_NONE)
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled minimum precision %#x.", e->min_precision);
continue;
}
if (e->interpolation_mode != VKD3DSIM_NONE)
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled interpolation mode %#x.", e->interpolation_mode);
continue;
}
vkd3d_string_buffer_printf(buffer, "layout(location = %u) in ", e->target_location);
switch (e->component_type)
{
case VKD3D_SHADER_COMPONENT_UINT:
vkd3d_string_buffer_printf(buffer, "uvec4");
break;
case VKD3D_SHADER_COMPONENT_INT:
vkd3d_string_buffer_printf(buffer, "ivec4");
break;
case VKD3D_SHADER_COMPONENT_FLOAT:
vkd3d_string_buffer_printf(buffer, "vec4");
break;
default:
vkd3d_string_buffer_printf(buffer, "<unhandled type %#x>", e->component_type);
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled input component type %#x.", e->component_type);
break;
}
vkd3d_string_buffer_printf(buffer, " shader_in_%u;\n", i);
++count;
}
if (count)
vkd3d_string_buffer_printf(buffer, "\n");
}
else if (gen->limits.input_count)
{
shader_glsl_generate_interface_block(gen, signature, "in", gen->limits.input_count);
vkd3d_string_buffer_printf(buffer, "\n");
}
}
static void shader_glsl_generate_output_declarations(struct vkd3d_glsl_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, count;
if (!gen->interstage_output)
{
for (i = 0, count = 0; i < signature->element_count; ++i)
{
e = &signature->elements[i];
if (e->target_location == SIGNATURE_TARGET_LOCATION_UNUSED)
continue;
if (e->sysval_semantic != VKD3D_SHADER_SV_TARGET)
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled system value %#x.", e->sysval_semantic);
continue;
}
if (e->min_precision != VKD3D_SHADER_MINIMUM_PRECISION_NONE)
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled minimum precision %#x.", e->min_precision);
continue;
}
if (e->interpolation_mode != VKD3DSIM_NONE)
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled interpolation mode %#x.", e->interpolation_mode);
continue;
}
vkd3d_string_buffer_printf(buffer, "layout(location = %u) out ", e->target_location);
switch (e->component_type)
{
case VKD3D_SHADER_COMPONENT_UINT:
vkd3d_string_buffer_printf(buffer, "uvec4");
break;
case VKD3D_SHADER_COMPONENT_INT:
vkd3d_string_buffer_printf(buffer, "ivec4");
break;
case VKD3D_SHADER_COMPONENT_FLOAT:
vkd3d_string_buffer_printf(buffer, "vec4");
break;
default:
vkd3d_string_buffer_printf(buffer, "<unhandled type %#x>", e->component_type);
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled output component type %#x.", e->component_type);
break;
}
vkd3d_string_buffer_printf(buffer, " shader_out_%u;\n", e->semantic_index);
++count;
}
if (count)
vkd3d_string_buffer_printf(buffer, "\n");
}
else if (gen->limits.output_count)
{
shader_glsl_generate_interface_block(gen, signature, "out", gen->limits.output_count);
vkd3d_string_buffer_printf(buffer, "\n");
}
}
static void shader_glsl_handle_global_flags(struct vkd3d_string_buffer *buffer,
struct vkd3d_glsl_generator *gen, enum vsir_global_flags flags)
{
if (flags & VKD3DSGF_FORCE_EARLY_DEPTH_STENCIL)
{
vkd3d_string_buffer_printf(buffer, "layout(early_fragment_tests) in;\n");
flags &= ~VKD3DSGF_FORCE_EARLY_DEPTH_STENCIL;
}
if (flags & ~VKD3DSGF_REFACTORING_ALLOWED)
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled global flags %#"PRIx64".", (uint64_t)flags);
}
static void shader_glsl_generate_declarations(struct vkd3d_glsl_generator *gen)
{
const struct vsir_program *program = gen->program;
struct vkd3d_string_buffer *buffer = gen->buffer;
const struct vsir_thread_group_size *group_size;
if (program->shader_version.type == VKD3D_SHADER_TYPE_COMPUTE)
{
group_size = &program->thread_group_size;
vkd3d_string_buffer_printf(buffer, "layout(local_size_x = %u, local_size_y = %u, local_size_z = %u) in;\n\n",
group_size->x, group_size->y, group_size->z);
}
shader_glsl_handle_global_flags(buffer, gen, program->global_flags);
shader_glsl_generate_descriptor_declarations(gen);
shader_glsl_generate_input_declarations(gen);
shader_glsl_generate_output_declarations(gen);
if (gen->limits.input_count)
vkd3d_string_buffer_printf(buffer, "vec4 %s_in[%u];\n", gen->prefix, gen->limits.input_count);
if (gen->limits.output_count)
vkd3d_string_buffer_printf(buffer, "vec4 %s_out[%u];\n", gen->prefix, gen->limits.output_count);
if (program->temp_count)
vkd3d_string_buffer_printf(buffer, "vec4 r[%u];\n", program->temp_count);
vkd3d_string_buffer_printf(buffer, "\n");
}
static int vkd3d_glsl_generator_generate(struct vkd3d_glsl_generator *gen, struct vkd3d_shader_code *out)
{
struct vkd3d_string_buffer *buffer = gen->buffer;
struct vkd3d_shader_instruction *ins;
struct vsir_program_iterator it;
void *code;
MESSAGE("Generating a GLSL shader. This is unsupported; you get to keep all the pieces if it breaks.\n");
vkd3d_string_buffer_printf(buffer, "#version 440\n\n");
vkd3d_string_buffer_printf(buffer, "/* Generated by %s. */\n\n", vkd3d_shader_get_version(NULL, NULL));
shader_glsl_generate_declarations(gen);
vkd3d_string_buffer_printf(buffer, "void main()\n{\n");
++gen->indent;
shader_glsl_shader_prologue(gen);
it = vsir_program_iterator(&gen->program->instructions);
for (ins = vsir_program_iterator_head(&it); ins; ins = vsir_program_iterator_next(&it))
{
vkd3d_glsl_handle_instruction(gen, ins);
}
vkd3d_string_buffer_printf(buffer, "}\n");
if (TRACE_ON())
vkd3d_string_buffer_trace(buffer);
if (gen->failed)
return VKD3D_ERROR_INVALID_SHADER;
if ((code = vkd3d_malloc(buffer->buffer_size)))
{
memcpy(code, buffer->buffer, buffer->content_size);
out->size = buffer->content_size;
out->code = code;
}
else return VKD3D_ERROR_OUT_OF_MEMORY;
return VKD3D_OK;
}
static void vkd3d_glsl_generator_cleanup(struct vkd3d_glsl_generator *gen)
{
vkd3d_string_buffer_release(&gen->string_buffers, gen->buffer);
vkd3d_string_buffer_cache_cleanup(&gen->string_buffers);
}
static void shader_glsl_init_limits(struct vkd3d_glsl_generator *gen, const struct vkd3d_shader_version *version)
{
struct shader_limits *limits = &gen->limits;
if (version->major < 4 || version->major >= 6)
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled shader version %u.%u.", version->major, version->minor);
switch (version->type)
{
case VKD3D_SHADER_TYPE_VERTEX:
limits->input_count = 32;
limits->output_count = 32;
break;
case VKD3D_SHADER_TYPE_PIXEL:
limits->input_count = 32;
limits->output_count = 8;
break;
case VKD3D_SHADER_TYPE_COMPUTE:
limits->input_count = 0;
limits->output_count = 0;
break;
default:
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled shader type %#x.", version->type);
limits->input_count = 0;
limits->output_count = 0;
break;
}
}
static void vkd3d_glsl_generator_init(struct vkd3d_glsl_generator *gen,
struct vsir_program *program, const struct vkd3d_shader_compile_info *compile_info,
const struct vkd3d_shader_scan_combined_resource_sampler_info *combined_sampler_info,
struct vkd3d_shader_message_context *message_context)
{
enum vkd3d_shader_type type = program->shader_version.type;
memset(gen, 0, sizeof(*gen));
gen->program = program;
vkd3d_string_buffer_cache_init(&gen->string_buffers);
gen->buffer = vkd3d_string_buffer_get(&gen->string_buffers);
gen->location.source_name = compile_info->source_name;
gen->message_context = message_context;
if (!(gen->prefix = shader_glsl_get_prefix(type)))
{
vkd3d_glsl_compiler_error(gen, VKD3D_SHADER_ERROR_GLSL_INTERNAL,
"Internal compiler error: Unhandled shader type %#x.", type);
gen->prefix = "unknown";
}
shader_glsl_init_limits(gen, &program->shader_version);
gen->interstage_input = type != VKD3D_SHADER_TYPE_VERTEX && type != VKD3D_SHADER_TYPE_COMPUTE;
gen->interstage_output = type != VKD3D_SHADER_TYPE_PIXEL && type != VKD3D_SHADER_TYPE_COMPUTE;
gen->interface_info = vkd3d_find_struct(compile_info->next, INTERFACE_INFO);
gen->offset_info = vkd3d_find_struct(compile_info->next, DESCRIPTOR_OFFSET_INFO);
gen->combined_sampler_info = combined_sampler_info;
}
int glsl_compile(struct vsir_program *program, uint64_t config_flags,
const struct vkd3d_shader_scan_combined_resource_sampler_info *combined_sampler_info,
const struct vkd3d_shader_compile_info *compile_info,
struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context)
{
struct vkd3d_glsl_generator generator;
int ret;
if ((ret = vsir_program_transform(program, config_flags, compile_info, message_context)) < 0)
return ret;
if ((ret = vsir_allocate_temp_registers(program, message_context)) < 0)
return ret;
VKD3D_ASSERT(program->normalisation_level == VSIR_NORMALISED_SM6);
VKD3D_ASSERT(program->has_descriptor_info);
vkd3d_glsl_generator_init(&generator, program, compile_info,
combined_sampler_info, message_context);
ret = vkd3d_glsl_generator_generate(&generator, out);
vkd3d_glsl_generator_cleanup(&generator);
return ret;
}