vkd3d-shader/hlsl: Move RDEF generation to hlsl_codegen.c.

This commit is contained in:
Henri Verbeet 2024-12-19 22:33:15 +01:00
parent 9b3b47b1b8
commit 4227858cfe
Notes: Henri Verbeet 2025-01-10 20:15:36 +01:00
Approved-by: Elizabeth Figura (@zfigura)
Approved-by: Henri Verbeet (@hverbeet)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/1334
3 changed files with 510 additions and 508 deletions

View File

@ -1678,10 +1678,6 @@ struct extern_resource
struct vkd3d_shader_location loc;
};
struct extern_resource *sm4_get_extern_resources(struct hlsl_ctx *ctx, unsigned int *count);
void sm4_free_extern_resources(struct extern_resource *extern_resources, unsigned int count);
void sm4_generate_rdef(struct hlsl_ctx *ctx, struct vkd3d_shader_code *rdef);
struct hlsl_ir_function_decl *hlsl_compile_internal_function(struct hlsl_ctx *ctx, const char *name, const char *hlsl);
int hlsl_lexer_compile(struct hlsl_ctx *ctx, const struct vkd3d_shader_code *hlsl);

View File

@ -20,9 +20,13 @@
#include "hlsl.h"
#include "vkd3d_shader_private.h"
#include "vkd3d_d3dcommon.h"
#include <stdio.h>
#include <math.h>
/* The shift that corresponds to the D3D_SIF_TEXTURE_COMPONENTS mask. */
#define VKD3D_SM4_SIF_TEXTURE_COMPONENTS_SHIFT 2
/* TODO: remove when no longer needed, only used for new_offset_instr_from_deref() */
static struct hlsl_ir_node *new_offset_from_path_index(struct hlsl_ctx *ctx, struct hlsl_block *block,
struct hlsl_type *type, struct hlsl_ir_node *base_offset, struct hlsl_ir_node *idx,
@ -10106,7 +10110,7 @@ static const char *string_skip_tag(const char *string)
return string;
}
void sm4_free_extern_resources(struct extern_resource *extern_resources, unsigned int count)
static void sm4_free_extern_resources(struct extern_resource *extern_resources, unsigned int count)
{
unsigned int i;
@ -10117,7 +10121,7 @@ void sm4_free_extern_resources(struct extern_resource *extern_resources, unsigne
vkd3d_free(extern_resources);
}
struct extern_resource *sm4_get_extern_resources(struct hlsl_ctx *ctx, unsigned int *count)
static struct extern_resource *sm4_get_extern_resources(struct hlsl_ctx *ctx, unsigned int *count)
{
bool separate_components = ctx->profile->major_version == 5 && ctx->profile->minor_version == 0;
struct extern_resource *extern_resources = NULL;
@ -10650,6 +10654,510 @@ static void sm4_generate_vsir(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl
generate_vsir_scan_global_flags(ctx, program, func);
}
/* For some reason, for matrices, values from default value initializers end
* up in different components than from regular initializers. Default value
* initializers fill the matrix in vertical reading order
* (left-to-right top-to-bottom) instead of regular reading order
* (top-to-bottom left-to-right), so they have to be adjusted. An exception is
* that the order of matrix initializers for function parameters are row-major
* (top-to-bottom left-to-right). */
static unsigned int get_component_index_from_default_initializer_index(struct hlsl_type *type, unsigned int index)
{
unsigned int element_comp_count, element, x, y, i;
unsigned int base = 0;
switch (type->class)
{
case HLSL_CLASS_MATRIX:
x = index / type->e.numeric.dimy;
y = index % type->e.numeric.dimy;
return y * type->e.numeric.dimx + x;
case HLSL_CLASS_ARRAY:
element_comp_count = hlsl_type_component_count(type->e.array.type);
element = index / element_comp_count;
base = element * element_comp_count;
return base + get_component_index_from_default_initializer_index(type->e.array.type, index - base);
case HLSL_CLASS_STRUCT:
for (i = 0; i < type->e.record.field_count; ++i)
{
struct hlsl_type *field_type = type->e.record.fields[i].type;
element_comp_count = hlsl_type_component_count(field_type);
if (index - base < element_comp_count)
return base + get_component_index_from_default_initializer_index(field_type, index - base);
base += element_comp_count;
}
break;
default:
return index;
}
vkd3d_unreachable();
}
static D3D_SRV_DIMENSION sm4_rdef_resource_dimension(const struct hlsl_type *type)
{
switch (type->sampler_dim)
{
case HLSL_SAMPLER_DIM_1D:
return D3D_SRV_DIMENSION_TEXTURE1D;
case HLSL_SAMPLER_DIM_2D:
return D3D_SRV_DIMENSION_TEXTURE2D;
case HLSL_SAMPLER_DIM_3D:
return D3D_SRV_DIMENSION_TEXTURE3D;
case HLSL_SAMPLER_DIM_CUBE:
return D3D_SRV_DIMENSION_TEXTURECUBE;
case HLSL_SAMPLER_DIM_1DARRAY:
return D3D_SRV_DIMENSION_TEXTURE1DARRAY;
case HLSL_SAMPLER_DIM_2DARRAY:
return D3D_SRV_DIMENSION_TEXTURE2DARRAY;
case HLSL_SAMPLER_DIM_2DMS:
return D3D_SRV_DIMENSION_TEXTURE2DMS;
case HLSL_SAMPLER_DIM_2DMSARRAY:
return D3D_SRV_DIMENSION_TEXTURE2DMSARRAY;
case HLSL_SAMPLER_DIM_CUBEARRAY:
return D3D_SRV_DIMENSION_TEXTURECUBEARRAY;
case HLSL_SAMPLER_DIM_BUFFER:
case HLSL_SAMPLER_DIM_RAW_BUFFER:
case HLSL_SAMPLER_DIM_STRUCTURED_BUFFER:
return D3D_SRV_DIMENSION_BUFFER;
default:
break;
}
vkd3d_unreachable();
}
static enum D3D_RESOURCE_RETURN_TYPE sm4_data_type(const struct hlsl_type *type)
{
const struct hlsl_type *format = type->e.resource.format;
switch (format->e.numeric.type)
{
case HLSL_TYPE_DOUBLE:
return D3D_RETURN_TYPE_DOUBLE;
case HLSL_TYPE_FLOAT:
case HLSL_TYPE_HALF:
if (format->modifiers & HLSL_MODIFIER_UNORM)
return D3D_RETURN_TYPE_UNORM;
if (format->modifiers & HLSL_MODIFIER_SNORM)
return D3D_RETURN_TYPE_SNORM;
return D3D_RETURN_TYPE_FLOAT;
case HLSL_TYPE_INT:
return D3D_RETURN_TYPE_SINT;
break;
case HLSL_TYPE_BOOL:
case HLSL_TYPE_UINT:
return D3D_RETURN_TYPE_UINT;
}
vkd3d_unreachable();
}
static D3D_SHADER_INPUT_TYPE sm4_resource_type(const struct hlsl_type *type)
{
switch (type->class)
{
case HLSL_CLASS_SAMPLER:
return D3D_SIT_SAMPLER;
case HLSL_CLASS_TEXTURE:
return D3D_SIT_TEXTURE;
case HLSL_CLASS_UAV:
return D3D_SIT_UAV_RWTYPED;
default:
break;
}
vkd3d_unreachable();
}
static D3D_SHADER_VARIABLE_CLASS sm4_class(const struct hlsl_type *type)
{
switch (type->class)
{
case HLSL_CLASS_MATRIX:
VKD3D_ASSERT(type->modifiers & HLSL_MODIFIERS_MAJORITY_MASK);
if (type->modifiers & HLSL_MODIFIER_COLUMN_MAJOR)
return D3D_SVC_MATRIX_COLUMNS;
else
return D3D_SVC_MATRIX_ROWS;
case HLSL_CLASS_SCALAR:
return D3D_SVC_SCALAR;
case HLSL_CLASS_VECTOR:
return D3D_SVC_VECTOR;
case HLSL_CLASS_ARRAY:
case HLSL_CLASS_DEPTH_STENCIL_STATE:
case HLSL_CLASS_DEPTH_STENCIL_VIEW:
case HLSL_CLASS_EFFECT_GROUP:
case HLSL_CLASS_ERROR:
case HLSL_CLASS_STRUCT:
case HLSL_CLASS_PASS:
case HLSL_CLASS_PIXEL_SHADER:
case HLSL_CLASS_RASTERIZER_STATE:
case HLSL_CLASS_RENDER_TARGET_VIEW:
case HLSL_CLASS_SAMPLER:
case HLSL_CLASS_STRING:
case HLSL_CLASS_TECHNIQUE:
case HLSL_CLASS_TEXTURE:
case HLSL_CLASS_UAV:
case HLSL_CLASS_VERTEX_SHADER:
case HLSL_CLASS_VOID:
case HLSL_CLASS_CONSTANT_BUFFER:
case HLSL_CLASS_COMPUTE_SHADER:
case HLSL_CLASS_DOMAIN_SHADER:
case HLSL_CLASS_HULL_SHADER:
case HLSL_CLASS_GEOMETRY_SHADER:
case HLSL_CLASS_BLEND_STATE:
case HLSL_CLASS_STREAM_OUTPUT:
case HLSL_CLASS_NULL:
break;
}
vkd3d_unreachable();
}
static D3D_SHADER_VARIABLE_TYPE sm4_base_type(const struct hlsl_type *type)
{
switch (type->e.numeric.type)
{
case HLSL_TYPE_BOOL:
return D3D_SVT_BOOL;
case HLSL_TYPE_DOUBLE:
return D3D_SVT_DOUBLE;
case HLSL_TYPE_FLOAT:
case HLSL_TYPE_HALF:
return D3D_SVT_FLOAT;
case HLSL_TYPE_INT:
return D3D_SVT_INT;
case HLSL_TYPE_UINT:
return D3D_SVT_UINT;
}
vkd3d_unreachable();
}
static void write_sm4_type(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer, struct hlsl_type *type)
{
const struct hlsl_type *array_type = hlsl_get_multiarray_element_type(type);
const char *name = array_type->name ? array_type->name : "<unnamed>";
const struct hlsl_profile_info *profile = ctx->profile;
unsigned int array_size = 0;
size_t name_offset = 0;
size_t i;
if (type->bytecode_offset)
return;
if (profile->major_version >= 5)
name_offset = put_string(buffer, name);
if (type->class == HLSL_CLASS_ARRAY)
array_size = hlsl_get_multiarray_size(type);
if (array_type->class == HLSL_CLASS_STRUCT)
{
unsigned int field_count = 0;
size_t fields_offset = 0;
for (i = 0; i < array_type->e.record.field_count; ++i)
{
struct hlsl_struct_field *field = &array_type->e.record.fields[i];
if (!field->type->reg_size[HLSL_REGSET_NUMERIC])
continue;
field->name_bytecode_offset = put_string(buffer, field->name);
write_sm4_type(ctx, buffer, field->type);
++field_count;
}
fields_offset = bytecode_align(buffer);
for (i = 0; i < array_type->e.record.field_count; ++i)
{
struct hlsl_struct_field *field = &array_type->e.record.fields[i];
if (!field->type->reg_size[HLSL_REGSET_NUMERIC])
continue;
put_u32(buffer, field->name_bytecode_offset);
put_u32(buffer, field->type->bytecode_offset);
put_u32(buffer, field->reg_offset[HLSL_REGSET_NUMERIC] * sizeof(float));
}
type->bytecode_offset = put_u32(buffer, vkd3d_make_u32(D3D_SVC_STRUCT, D3D_SVT_VOID));
put_u32(buffer, vkd3d_make_u32(1, hlsl_type_component_count(array_type)));
put_u32(buffer, vkd3d_make_u32(array_size, field_count));
put_u32(buffer, fields_offset);
}
else
{
VKD3D_ASSERT(array_type->class <= HLSL_CLASS_LAST_NUMERIC);
type->bytecode_offset = put_u32(buffer, vkd3d_make_u32(sm4_class(array_type), sm4_base_type(array_type)));
put_u32(buffer, vkd3d_make_u32(array_type->e.numeric.dimy, array_type->e.numeric.dimx));
put_u32(buffer, vkd3d_make_u32(array_size, 0));
put_u32(buffer, 1);
}
if (profile->major_version >= 5)
{
put_u32(buffer, 0); /* FIXME: unknown */
put_u32(buffer, 0); /* FIXME: unknown */
put_u32(buffer, 0); /* FIXME: unknown */
put_u32(buffer, 0); /* FIXME: unknown */
put_u32(buffer, name_offset);
}
}
static void sm4_generate_rdef(struct hlsl_ctx *ctx, struct vkd3d_shader_code *rdef)
{
uint32_t binding_desc_size = (hlsl_version_ge(ctx, 5, 1) ? 10 : 8) * sizeof(uint32_t);
size_t cbuffers_offset, resources_offset, creator_offset, string_offset;
unsigned int cbuffer_count = 0, extern_resources_count, i, j;
size_t cbuffer_position, resource_position, creator_position;
const struct hlsl_profile_info *profile = ctx->profile;
struct vkd3d_bytecode_buffer buffer = {0};
struct extern_resource *extern_resources;
const struct hlsl_buffer *cbuffer;
const struct hlsl_ir_var *var;
static const uint16_t target_types[] =
{
0xffff, /* PIXEL */
0xfffe, /* VERTEX */
0x4753, /* GEOMETRY */
0x4853, /* HULL */
0x4453, /* DOMAIN */
0x4353, /* COMPUTE */
};
extern_resources = sm4_get_extern_resources(ctx, &extern_resources_count);
LIST_FOR_EACH_ENTRY(cbuffer, &ctx->buffers, struct hlsl_buffer, entry)
{
if (cbuffer->reg.allocated)
++cbuffer_count;
}
put_u32(&buffer, cbuffer_count);
cbuffer_position = put_u32(&buffer, 0);
put_u32(&buffer, extern_resources_count);
resource_position = put_u32(&buffer, 0);
put_u32(&buffer, vkd3d_make_u32(vkd3d_make_u16(profile->minor_version, profile->major_version),
target_types[profile->type]));
put_u32(&buffer, 0); /* FIXME: compilation flags */
creator_position = put_u32(&buffer, 0);
if (profile->major_version >= 5)
{
put_u32(&buffer, hlsl_version_ge(ctx, 5, 1) ? TAG_RD11_REVERSE : TAG_RD11);
put_u32(&buffer, 15 * sizeof(uint32_t)); /* size of RDEF header including this header */
put_u32(&buffer, 6 * sizeof(uint32_t)); /* size of buffer desc */
put_u32(&buffer, binding_desc_size); /* size of binding desc */
put_u32(&buffer, 10 * sizeof(uint32_t)); /* size of variable desc */
put_u32(&buffer, 9 * sizeof(uint32_t)); /* size of type desc */
put_u32(&buffer, 3 * sizeof(uint32_t)); /* size of member desc */
put_u32(&buffer, 0); /* unknown; possibly a null terminator */
}
/* Bound resources. */
resources_offset = bytecode_align(&buffer);
set_u32(&buffer, resource_position, resources_offset);
for (i = 0; i < extern_resources_count; ++i)
{
const struct extern_resource *resource = &extern_resources[i];
uint32_t flags = 0;
if (resource->is_user_packed)
flags |= D3D_SIF_USERPACKED;
put_u32(&buffer, 0); /* name */
if (resource->buffer)
put_u32(&buffer, resource->buffer->type == HLSL_BUFFER_CONSTANT ? D3D_SIT_CBUFFER : D3D_SIT_TBUFFER);
else
put_u32(&buffer, sm4_resource_type(resource->component_type));
if (resource->regset == HLSL_REGSET_TEXTURES || resource->regset == HLSL_REGSET_UAVS)
{
unsigned int dimx = resource->component_type->e.resource.format->e.numeric.dimx;
put_u32(&buffer, sm4_data_type(resource->component_type));
put_u32(&buffer, sm4_rdef_resource_dimension(resource->component_type));
put_u32(&buffer, ~0u); /* FIXME: multisample count */
flags |= (dimx - 1) << VKD3D_SM4_SIF_TEXTURE_COMPONENTS_SHIFT;
}
else
{
put_u32(&buffer, 0);
put_u32(&buffer, 0);
put_u32(&buffer, 0);
}
put_u32(&buffer, resource->index);
put_u32(&buffer, resource->bind_count);
put_u32(&buffer, flags);
if (hlsl_version_ge(ctx, 5, 1))
{
put_u32(&buffer, resource->space);
put_u32(&buffer, resource->id);
}
}
for (i = 0; i < extern_resources_count; ++i)
{
const struct extern_resource *resource = &extern_resources[i];
string_offset = put_string(&buffer, resource->name);
set_u32(&buffer, resources_offset + i * binding_desc_size, string_offset);
}
/* Buffers. */
cbuffers_offset = bytecode_align(&buffer);
set_u32(&buffer, cbuffer_position, cbuffers_offset);
LIST_FOR_EACH_ENTRY(cbuffer, &ctx->buffers, struct hlsl_buffer, entry)
{
unsigned int var_count = 0;
if (!cbuffer->reg.allocated)
continue;
LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry)
{
if (var->is_uniform && var->buffer == cbuffer && var->data_type->reg_size[HLSL_REGSET_NUMERIC])
++var_count;
}
put_u32(&buffer, 0); /* name */
put_u32(&buffer, var_count);
put_u32(&buffer, 0); /* variable offset */
put_u32(&buffer, align(cbuffer->size, 4) * sizeof(float));
put_u32(&buffer, 0); /* FIXME: flags */
put_u32(&buffer, cbuffer->type == HLSL_BUFFER_CONSTANT ? D3D_CT_CBUFFER : D3D_CT_TBUFFER);
}
i = 0;
LIST_FOR_EACH_ENTRY(cbuffer, &ctx->buffers, struct hlsl_buffer, entry)
{
if (!cbuffer->reg.allocated)
continue;
string_offset = put_string(&buffer, cbuffer->name);
set_u32(&buffer, cbuffers_offset + i++ * 6 * sizeof(uint32_t), string_offset);
}
i = 0;
LIST_FOR_EACH_ENTRY(cbuffer, &ctx->buffers, struct hlsl_buffer, entry)
{
size_t vars_start = bytecode_align(&buffer);
if (!cbuffer->reg.allocated)
continue;
set_u32(&buffer, cbuffers_offset + (i++ * 6 + 2) * sizeof(uint32_t), vars_start);
LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry)
{
uint32_t flags = 0;
if (!var->is_uniform || var->buffer != cbuffer || !var->data_type->reg_size[HLSL_REGSET_NUMERIC])
continue;
if (var->is_read)
flags |= D3D_SVF_USED;
put_u32(&buffer, 0); /* name */
put_u32(&buffer, var->buffer_offset * sizeof(float));
put_u32(&buffer, var->data_type->reg_size[HLSL_REGSET_NUMERIC] * sizeof(float));
put_u32(&buffer, flags);
put_u32(&buffer, 0); /* type */
put_u32(&buffer, 0); /* default value */
if (profile->major_version >= 5)
{
put_u32(&buffer, 0); /* texture start */
put_u32(&buffer, 0); /* texture count */
put_u32(&buffer, 0); /* sampler start */
put_u32(&buffer, 0); /* sampler count */
}
}
j = 0;
LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry)
{
const unsigned int var_size = (profile->major_version >= 5 ? 10 : 6);
size_t var_offset = vars_start + j * var_size * sizeof(uint32_t);
if (!var->is_uniform || var->buffer != cbuffer || !var->data_type->reg_size[HLSL_REGSET_NUMERIC])
continue;
string_offset = put_string(&buffer, var->name);
set_u32(&buffer, var_offset, string_offset);
write_sm4_type(ctx, &buffer, var->data_type);
set_u32(&buffer, var_offset + 4 * sizeof(uint32_t), var->data_type->bytecode_offset);
if (var->default_values)
{
unsigned int reg_size = var->data_type->reg_size[HLSL_REGSET_NUMERIC];
unsigned int comp_count = hlsl_type_component_count(var->data_type);
unsigned int default_value_offset;
unsigned int k;
default_value_offset = bytecode_reserve_bytes(&buffer, reg_size * sizeof(uint32_t));
set_u32(&buffer, var_offset + 5 * sizeof(uint32_t), default_value_offset);
for (k = 0; k < comp_count; ++k)
{
struct hlsl_type *comp_type = hlsl_type_get_component_type(ctx, var->data_type, k);
unsigned int comp_offset, comp_index;
enum hlsl_regset regset;
if (comp_type->class == HLSL_CLASS_STRING)
{
hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE,
"Cannot write string default value.");
continue;
}
comp_index = get_component_index_from_default_initializer_index(var->data_type, k);
comp_offset = hlsl_type_get_component_offset(ctx, var->data_type, comp_index, &regset);
if (regset == HLSL_REGSET_NUMERIC)
{
if (comp_type->e.numeric.type == HLSL_TYPE_DOUBLE)
hlsl_fixme(ctx, &var->loc, "Write double default values.");
set_u32(&buffer, default_value_offset + comp_offset * sizeof(uint32_t),
var->default_values[k].number.u);
}
}
}
++j;
}
}
creator_offset = put_string(&buffer, vkd3d_shader_get_version(NULL, NULL));
set_u32(&buffer, creator_position, creator_offset);
sm4_free_extern_resources(extern_resources, extern_resources_count);
if (buffer.status)
{
vkd3d_free(buffer.data);
ctx->result = buffer.status;
return;
}
rdef->code = buffer.data;
rdef->size = buffer.size;
}
static bool loop_unrolling_generate_const_bool_store(struct hlsl_ctx *ctx, struct hlsl_ir_var *var,
bool val, struct hlsl_block *block, struct vkd3d_shader_location *loc)
{

View File

@ -21,9 +21,7 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "hlsl.h"
#include "vkd3d_shader_private.h"
#include "vkd3d_d3dcommon.h"
#define SM4_MAX_SRC_COUNT 6
#define SM4_MAX_DST_COUNT 2
@ -163,9 +161,6 @@ STATIC_ASSERT(SM4_MAX_SRC_COUNT <= SPIRV_MAX_SRC_COUNT);
#define VKD3D_SM4_TYPE_COMPONENT(com, i) (((com) >> (4 * (i))) & 0xfu)
/* The shift that corresponds to the D3D_SIF_TEXTURE_COMPONENTS mask. */
#define VKD3D_SM4_SIF_TEXTURE_COMPONENTS_SHIFT 2
enum vkd3d_sm4_opcode
{
VKD3D_SM4_OP_ADD = 0x00,
@ -3268,503 +3263,6 @@ static void tpf_write_signature(struct tpf_compiler *tpf, const struct shader_si
vkd3d_free(sorted_elements);
}
static D3D_SHADER_VARIABLE_CLASS sm4_class(const struct hlsl_type *type)
{
switch (type->class)
{
case HLSL_CLASS_MATRIX:
VKD3D_ASSERT(type->modifiers & HLSL_MODIFIERS_MAJORITY_MASK);
if (type->modifiers & HLSL_MODIFIER_COLUMN_MAJOR)
return D3D_SVC_MATRIX_COLUMNS;
else
return D3D_SVC_MATRIX_ROWS;
case HLSL_CLASS_SCALAR:
return D3D_SVC_SCALAR;
case HLSL_CLASS_VECTOR:
return D3D_SVC_VECTOR;
case HLSL_CLASS_ARRAY:
case HLSL_CLASS_DEPTH_STENCIL_STATE:
case HLSL_CLASS_DEPTH_STENCIL_VIEW:
case HLSL_CLASS_EFFECT_GROUP:
case HLSL_CLASS_ERROR:
case HLSL_CLASS_STRUCT:
case HLSL_CLASS_PASS:
case HLSL_CLASS_PIXEL_SHADER:
case HLSL_CLASS_RASTERIZER_STATE:
case HLSL_CLASS_RENDER_TARGET_VIEW:
case HLSL_CLASS_SAMPLER:
case HLSL_CLASS_STRING:
case HLSL_CLASS_TECHNIQUE:
case HLSL_CLASS_TEXTURE:
case HLSL_CLASS_UAV:
case HLSL_CLASS_VERTEX_SHADER:
case HLSL_CLASS_VOID:
case HLSL_CLASS_CONSTANT_BUFFER:
case HLSL_CLASS_COMPUTE_SHADER:
case HLSL_CLASS_DOMAIN_SHADER:
case HLSL_CLASS_HULL_SHADER:
case HLSL_CLASS_GEOMETRY_SHADER:
case HLSL_CLASS_BLEND_STATE:
case HLSL_CLASS_STREAM_OUTPUT:
case HLSL_CLASS_NULL:
break;
}
vkd3d_unreachable();
}
static D3D_SHADER_VARIABLE_TYPE sm4_base_type(const struct hlsl_type *type)
{
switch (type->e.numeric.type)
{
case HLSL_TYPE_BOOL:
return D3D_SVT_BOOL;
case HLSL_TYPE_DOUBLE:
return D3D_SVT_DOUBLE;
case HLSL_TYPE_FLOAT:
case HLSL_TYPE_HALF:
return D3D_SVT_FLOAT;
case HLSL_TYPE_INT:
return D3D_SVT_INT;
case HLSL_TYPE_UINT:
return D3D_SVT_UINT;
}
vkd3d_unreachable();
}
static void write_sm4_type(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer, struct hlsl_type *type)
{
const struct hlsl_type *array_type = hlsl_get_multiarray_element_type(type);
const char *name = array_type->name ? array_type->name : "<unnamed>";
const struct hlsl_profile_info *profile = ctx->profile;
unsigned int array_size = 0;
size_t name_offset = 0;
size_t i;
if (type->bytecode_offset)
return;
if (profile->major_version >= 5)
name_offset = put_string(buffer, name);
if (type->class == HLSL_CLASS_ARRAY)
array_size = hlsl_get_multiarray_size(type);
if (array_type->class == HLSL_CLASS_STRUCT)
{
unsigned int field_count = 0;
size_t fields_offset = 0;
for (i = 0; i < array_type->e.record.field_count; ++i)
{
struct hlsl_struct_field *field = &array_type->e.record.fields[i];
if (!field->type->reg_size[HLSL_REGSET_NUMERIC])
continue;
field->name_bytecode_offset = put_string(buffer, field->name);
write_sm4_type(ctx, buffer, field->type);
++field_count;
}
fields_offset = bytecode_align(buffer);
for (i = 0; i < array_type->e.record.field_count; ++i)
{
struct hlsl_struct_field *field = &array_type->e.record.fields[i];
if (!field->type->reg_size[HLSL_REGSET_NUMERIC])
continue;
put_u32(buffer, field->name_bytecode_offset);
put_u32(buffer, field->type->bytecode_offset);
put_u32(buffer, field->reg_offset[HLSL_REGSET_NUMERIC] * sizeof(float));
}
type->bytecode_offset = put_u32(buffer, vkd3d_make_u32(D3D_SVC_STRUCT, D3D_SVT_VOID));
put_u32(buffer, vkd3d_make_u32(1, hlsl_type_component_count(array_type)));
put_u32(buffer, vkd3d_make_u32(array_size, field_count));
put_u32(buffer, fields_offset);
}
else
{
VKD3D_ASSERT(array_type->class <= HLSL_CLASS_LAST_NUMERIC);
type->bytecode_offset = put_u32(buffer, vkd3d_make_u32(sm4_class(array_type), sm4_base_type(array_type)));
put_u32(buffer, vkd3d_make_u32(array_type->e.numeric.dimy, array_type->e.numeric.dimx));
put_u32(buffer, vkd3d_make_u32(array_size, 0));
put_u32(buffer, 1);
}
if (profile->major_version >= 5)
{
put_u32(buffer, 0); /* FIXME: unknown */
put_u32(buffer, 0); /* FIXME: unknown */
put_u32(buffer, 0); /* FIXME: unknown */
put_u32(buffer, 0); /* FIXME: unknown */
put_u32(buffer, name_offset);
}
}
static D3D_SHADER_INPUT_TYPE sm4_resource_type(const struct hlsl_type *type)
{
switch (type->class)
{
case HLSL_CLASS_SAMPLER:
return D3D_SIT_SAMPLER;
case HLSL_CLASS_TEXTURE:
return D3D_SIT_TEXTURE;
case HLSL_CLASS_UAV:
return D3D_SIT_UAV_RWTYPED;
default:
break;
}
vkd3d_unreachable();
}
static enum vkd3d_sm4_data_type sm4_data_type(const struct hlsl_type *type)
{
const struct hlsl_type *format = type->e.resource.format;
switch (format->e.numeric.type)
{
case HLSL_TYPE_DOUBLE:
return VKD3D_SM4_DATA_DOUBLE;
case HLSL_TYPE_FLOAT:
case HLSL_TYPE_HALF:
if (format->modifiers & HLSL_MODIFIER_UNORM)
return VKD3D_SM4_DATA_UNORM;
if (format->modifiers & HLSL_MODIFIER_SNORM)
return VKD3D_SM4_DATA_SNORM;
return VKD3D_SM4_DATA_FLOAT;
case HLSL_TYPE_INT:
return VKD3D_SM4_DATA_INT;
break;
case HLSL_TYPE_BOOL:
case HLSL_TYPE_UINT:
return VKD3D_SM4_DATA_UINT;
}
vkd3d_unreachable();
}
static D3D_SRV_DIMENSION sm4_rdef_resource_dimension(const struct hlsl_type *type)
{
switch (type->sampler_dim)
{
case HLSL_SAMPLER_DIM_1D:
return D3D_SRV_DIMENSION_TEXTURE1D;
case HLSL_SAMPLER_DIM_2D:
return D3D_SRV_DIMENSION_TEXTURE2D;
case HLSL_SAMPLER_DIM_3D:
return D3D_SRV_DIMENSION_TEXTURE3D;
case HLSL_SAMPLER_DIM_CUBE:
return D3D_SRV_DIMENSION_TEXTURECUBE;
case HLSL_SAMPLER_DIM_1DARRAY:
return D3D_SRV_DIMENSION_TEXTURE1DARRAY;
case HLSL_SAMPLER_DIM_2DARRAY:
return D3D_SRV_DIMENSION_TEXTURE2DARRAY;
case HLSL_SAMPLER_DIM_2DMS:
return D3D_SRV_DIMENSION_TEXTURE2DMS;
case HLSL_SAMPLER_DIM_2DMSARRAY:
return D3D_SRV_DIMENSION_TEXTURE2DMSARRAY;
case HLSL_SAMPLER_DIM_CUBEARRAY:
return D3D_SRV_DIMENSION_TEXTURECUBEARRAY;
case HLSL_SAMPLER_DIM_BUFFER:
case HLSL_SAMPLER_DIM_RAW_BUFFER:
case HLSL_SAMPLER_DIM_STRUCTURED_BUFFER:
return D3D_SRV_DIMENSION_BUFFER;
default:
vkd3d_unreachable();
}
}
/* For some reason, for matrices, values from default value initializers end up in different
* components than from regular initializers. Default value initializers fill the matrix in
* vertical reading order (left-to-right top-to-bottom) instead of regular reading order
* (top-to-bottom left-to-right), so they have to be adjusted.
* An exception is that the order of matrix initializers for function parameters are row-major
* (top-to-bottom left-to-right). */
static unsigned int get_component_index_from_default_initializer_index(struct hlsl_type *type, unsigned int index)
{
unsigned int element_comp_count, element, x, y, i;
unsigned int base = 0;
switch (type->class)
{
case HLSL_CLASS_MATRIX:
x = index / type->e.numeric.dimy;
y = index % type->e.numeric.dimy;
return y * type->e.numeric.dimx + x;
case HLSL_CLASS_ARRAY:
element_comp_count = hlsl_type_component_count(type->e.array.type);
element = index / element_comp_count;
base = element * element_comp_count;
return base + get_component_index_from_default_initializer_index(type->e.array.type, index - base);
case HLSL_CLASS_STRUCT:
for (i = 0; i < type->e.record.field_count; ++i)
{
struct hlsl_type *field_type = type->e.record.fields[i].type;
element_comp_count = hlsl_type_component_count(field_type);
if (index - base < element_comp_count)
return base + get_component_index_from_default_initializer_index(field_type, index - base);
base += element_comp_count;
}
break;
default:
return index;
}
vkd3d_unreachable();
}
void sm4_generate_rdef(struct hlsl_ctx *ctx, struct vkd3d_shader_code *rdef)
{
uint32_t binding_desc_size = (hlsl_version_ge(ctx, 5, 1) ? 10 : 8) * sizeof(uint32_t);
size_t cbuffers_offset, resources_offset, creator_offset, string_offset;
unsigned int cbuffer_count = 0, extern_resources_count, i, j;
size_t cbuffer_position, resource_position, creator_position;
const struct hlsl_profile_info *profile = ctx->profile;
struct vkd3d_bytecode_buffer buffer = {0};
struct extern_resource *extern_resources;
const struct hlsl_buffer *cbuffer;
const struct hlsl_ir_var *var;
static const uint16_t target_types[] =
{
0xffff, /* PIXEL */
0xfffe, /* VERTEX */
0x4753, /* GEOMETRY */
0x4853, /* HULL */
0x4453, /* DOMAIN */
0x4353, /* COMPUTE */
};
extern_resources = sm4_get_extern_resources(ctx, &extern_resources_count);
LIST_FOR_EACH_ENTRY(cbuffer, &ctx->buffers, struct hlsl_buffer, entry)
{
if (cbuffer->reg.allocated)
++cbuffer_count;
}
put_u32(&buffer, cbuffer_count);
cbuffer_position = put_u32(&buffer, 0);
put_u32(&buffer, extern_resources_count);
resource_position = put_u32(&buffer, 0);
put_u32(&buffer, vkd3d_make_u32(vkd3d_make_u16(profile->minor_version, profile->major_version),
target_types[profile->type]));
put_u32(&buffer, 0); /* FIXME: compilation flags */
creator_position = put_u32(&buffer, 0);
if (profile->major_version >= 5)
{
put_u32(&buffer, hlsl_version_ge(ctx, 5, 1) ? TAG_RD11_REVERSE : TAG_RD11);
put_u32(&buffer, 15 * sizeof(uint32_t)); /* size of RDEF header including this header */
put_u32(&buffer, 6 * sizeof(uint32_t)); /* size of buffer desc */
put_u32(&buffer, binding_desc_size); /* size of binding desc */
put_u32(&buffer, 10 * sizeof(uint32_t)); /* size of variable desc */
put_u32(&buffer, 9 * sizeof(uint32_t)); /* size of type desc */
put_u32(&buffer, 3 * sizeof(uint32_t)); /* size of member desc */
put_u32(&buffer, 0); /* unknown; possibly a null terminator */
}
/* Bound resources. */
resources_offset = bytecode_align(&buffer);
set_u32(&buffer, resource_position, resources_offset);
for (i = 0; i < extern_resources_count; ++i)
{
const struct extern_resource *resource = &extern_resources[i];
uint32_t flags = 0;
if (resource->is_user_packed)
flags |= D3D_SIF_USERPACKED;
put_u32(&buffer, 0); /* name */
if (resource->buffer)
put_u32(&buffer, resource->buffer->type == HLSL_BUFFER_CONSTANT ? D3D_SIT_CBUFFER : D3D_SIT_TBUFFER);
else
put_u32(&buffer, sm4_resource_type(resource->component_type));
if (resource->regset == HLSL_REGSET_TEXTURES || resource->regset == HLSL_REGSET_UAVS)
{
unsigned int dimx = resource->component_type->e.resource.format->e.numeric.dimx;
put_u32(&buffer, sm4_data_type(resource->component_type));
put_u32(&buffer, sm4_rdef_resource_dimension(resource->component_type));
put_u32(&buffer, ~0u); /* FIXME: multisample count */
flags |= (dimx - 1) << VKD3D_SM4_SIF_TEXTURE_COMPONENTS_SHIFT;
}
else
{
put_u32(&buffer, 0);
put_u32(&buffer, 0);
put_u32(&buffer, 0);
}
put_u32(&buffer, resource->index);
put_u32(&buffer, resource->bind_count);
put_u32(&buffer, flags);
if (hlsl_version_ge(ctx, 5, 1))
{
put_u32(&buffer, resource->space);
put_u32(&buffer, resource->id);
}
}
for (i = 0; i < extern_resources_count; ++i)
{
const struct extern_resource *resource = &extern_resources[i];
string_offset = put_string(&buffer, resource->name);
set_u32(&buffer, resources_offset + i * binding_desc_size, string_offset);
}
/* Buffers. */
cbuffers_offset = bytecode_align(&buffer);
set_u32(&buffer, cbuffer_position, cbuffers_offset);
LIST_FOR_EACH_ENTRY(cbuffer, &ctx->buffers, struct hlsl_buffer, entry)
{
unsigned int var_count = 0;
if (!cbuffer->reg.allocated)
continue;
LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry)
{
if (var->is_uniform && var->buffer == cbuffer && var->data_type->reg_size[HLSL_REGSET_NUMERIC])
++var_count;
}
put_u32(&buffer, 0); /* name */
put_u32(&buffer, var_count);
put_u32(&buffer, 0); /* variable offset */
put_u32(&buffer, align(cbuffer->size, 4) * sizeof(float));
put_u32(&buffer, 0); /* FIXME: flags */
put_u32(&buffer, cbuffer->type == HLSL_BUFFER_CONSTANT ? D3D_CT_CBUFFER : D3D_CT_TBUFFER);
}
i = 0;
LIST_FOR_EACH_ENTRY(cbuffer, &ctx->buffers, struct hlsl_buffer, entry)
{
if (!cbuffer->reg.allocated)
continue;
string_offset = put_string(&buffer, cbuffer->name);
set_u32(&buffer, cbuffers_offset + i++ * 6 * sizeof(uint32_t), string_offset);
}
i = 0;
LIST_FOR_EACH_ENTRY(cbuffer, &ctx->buffers, struct hlsl_buffer, entry)
{
size_t vars_start = bytecode_align(&buffer);
if (!cbuffer->reg.allocated)
continue;
set_u32(&buffer, cbuffers_offset + (i++ * 6 + 2) * sizeof(uint32_t), vars_start);
LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry)
{
if (var->is_uniform && var->buffer == cbuffer && var->data_type->reg_size[HLSL_REGSET_NUMERIC])
{
uint32_t flags = 0;
if (var->is_read)
flags |= D3D_SVF_USED;
put_u32(&buffer, 0); /* name */
put_u32(&buffer, var->buffer_offset * sizeof(float));
put_u32(&buffer, var->data_type->reg_size[HLSL_REGSET_NUMERIC] * sizeof(float));
put_u32(&buffer, flags);
put_u32(&buffer, 0); /* type */
put_u32(&buffer, 0); /* default value */
if (profile->major_version >= 5)
{
put_u32(&buffer, 0); /* texture start */
put_u32(&buffer, 0); /* texture count */
put_u32(&buffer, 0); /* sampler start */
put_u32(&buffer, 0); /* sampler count */
}
}
}
j = 0;
LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry)
{
if (var->is_uniform && var->buffer == cbuffer && var->data_type->reg_size[HLSL_REGSET_NUMERIC])
{
const unsigned int var_size = (profile->major_version >= 5 ? 10 : 6);
size_t var_offset = vars_start + j * var_size * sizeof(uint32_t);
string_offset = put_string(&buffer, var->name);
set_u32(&buffer, var_offset, string_offset);
write_sm4_type(ctx, &buffer, var->data_type);
set_u32(&buffer, var_offset + 4 * sizeof(uint32_t), var->data_type->bytecode_offset);
if (var->default_values)
{
unsigned int reg_size = var->data_type->reg_size[HLSL_REGSET_NUMERIC];
unsigned int comp_count = hlsl_type_component_count(var->data_type);
unsigned int default_value_offset;
unsigned int k;
default_value_offset = bytecode_reserve_bytes(&buffer, reg_size * sizeof(uint32_t));
set_u32(&buffer, var_offset + 5 * sizeof(uint32_t), default_value_offset);
for (k = 0; k < comp_count; ++k)
{
struct hlsl_type *comp_type = hlsl_type_get_component_type(ctx, var->data_type, k);
unsigned int comp_offset, comp_index;
enum hlsl_regset regset;
if (comp_type->class == HLSL_CLASS_STRING)
{
hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE,
"Cannot write string default value.");
continue;
}
comp_index = get_component_index_from_default_initializer_index(var->data_type, k);
comp_offset = hlsl_type_get_component_offset(ctx, var->data_type, comp_index, &regset);
if (regset == HLSL_REGSET_NUMERIC)
{
if (comp_type->e.numeric.type == HLSL_TYPE_DOUBLE)
hlsl_fixme(ctx, &var->loc, "Write double default values.");
set_u32(&buffer, default_value_offset + comp_offset * sizeof(uint32_t),
var->default_values[k].number.u);
}
}
}
++j;
}
}
}
creator_offset = put_string(&buffer, vkd3d_shader_get_version(NULL, NULL));
set_u32(&buffer, creator_position, creator_offset);
sm4_free_extern_resources(extern_resources, extern_resources_count);
if (buffer.status)
{
vkd3d_free(buffer.data);
ctx->result = buffer.status;
return;
}
rdef->code = buffer.data;
rdef->size = buffer.size;
}
static enum vkd3d_sm4_resource_type sm4_resource_dimension(enum vkd3d_shader_resource_type resource_type)
{
switch (resource_type)