2023-11-05 13:07:01 -08:00
|
|
|
/*
|
|
|
|
* FX (Direct3D 9/10/11 effect) support
|
|
|
|
*
|
|
|
|
* Copyright 2023 Nikolay Sivov for CodeWeavers
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "hlsl.h"
|
|
|
|
|
2024-02-06 06:11:47 -08:00
|
|
|
static inline size_t put_u32_unaligned(struct vkd3d_bytecode_buffer *buffer, uint32_t value)
|
|
|
|
{
|
|
|
|
return bytecode_put_bytes_unaligned(buffer, &value, sizeof(value));
|
|
|
|
}
|
|
|
|
|
2024-01-12 05:33:05 -08:00
|
|
|
struct string_entry
|
|
|
|
{
|
|
|
|
struct rb_entry entry;
|
|
|
|
/* String points to original data, should not be freed. */
|
|
|
|
const char *string;
|
|
|
|
uint32_t offset;
|
|
|
|
};
|
|
|
|
|
2024-02-06 06:11:47 -08:00
|
|
|
struct type_entry
|
|
|
|
{
|
|
|
|
struct list entry;
|
|
|
|
const char *name;
|
|
|
|
uint32_t elements_count;
|
|
|
|
uint32_t offset;
|
|
|
|
};
|
|
|
|
|
2024-01-12 05:33:05 -08:00
|
|
|
static int string_storage_compare(const void *key, const struct rb_entry *entry)
|
|
|
|
{
|
|
|
|
struct string_entry *string_entry = RB_ENTRY_VALUE(entry, struct string_entry, entry);
|
|
|
|
const char *string = key;
|
|
|
|
|
|
|
|
return strcmp(string, string_entry->string);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void string_storage_destroy(struct rb_entry *entry, void *context)
|
|
|
|
{
|
|
|
|
struct string_entry *string_entry = RB_ENTRY_VALUE(entry, struct string_entry, entry);
|
|
|
|
|
|
|
|
vkd3d_free(string_entry);
|
|
|
|
}
|
|
|
|
|
2024-01-16 03:17:06 -08:00
|
|
|
struct fx_write_context;
|
|
|
|
|
|
|
|
struct fx_write_context_ops
|
|
|
|
{
|
|
|
|
uint32_t (*write_string)(const char *string, struct fx_write_context *fx);
|
2024-02-06 06:11:47 -08:00
|
|
|
uint32_t (*write_type)(const struct hlsl_type *type, struct fx_write_context *fx);
|
2024-01-16 03:17:06 -08:00
|
|
|
void (*write_technique)(struct hlsl_ir_var *var, struct fx_write_context *fx);
|
2023-11-15 14:31:01 -08:00
|
|
|
void (*write_pass)(struct hlsl_ir_var *var, struct fx_write_context *fx);
|
2024-01-16 03:17:06 -08:00
|
|
|
};
|
|
|
|
|
2023-11-05 13:07:01 -08:00
|
|
|
struct fx_write_context
|
|
|
|
{
|
2024-01-12 05:33:05 -08:00
|
|
|
struct hlsl_ctx *ctx;
|
|
|
|
|
2023-11-05 13:07:01 -08:00
|
|
|
struct vkd3d_bytecode_buffer unstructured;
|
|
|
|
struct vkd3d_bytecode_buffer structured;
|
|
|
|
|
2024-01-12 05:33:05 -08:00
|
|
|
struct rb_tree strings;
|
2024-02-06 06:11:47 -08:00
|
|
|
struct list types;
|
2024-01-12 05:33:05 -08:00
|
|
|
|
2024-01-12 05:26:39 -08:00
|
|
|
unsigned int min_technique_version;
|
|
|
|
unsigned int max_technique_version;
|
|
|
|
|
2023-11-05 13:07:01 -08:00
|
|
|
uint32_t technique_count;
|
2024-01-12 05:26:39 -08:00
|
|
|
uint32_t group_count;
|
2024-02-06 06:11:47 -08:00
|
|
|
uint32_t buffer_count;
|
|
|
|
uint32_t numeric_variable_count;
|
2023-11-05 13:07:01 -08:00
|
|
|
int status;
|
2024-01-16 03:17:06 -08:00
|
|
|
|
|
|
|
const struct fx_write_context_ops *ops;
|
2023-11-05 13:07:01 -08:00
|
|
|
};
|
|
|
|
|
2024-02-06 06:11:47 -08:00
|
|
|
static void set_status(struct fx_write_context *fx, int status)
|
|
|
|
{
|
|
|
|
if (fx->status < 0)
|
|
|
|
return;
|
|
|
|
if (status < 0)
|
|
|
|
fx->status = status;
|
|
|
|
}
|
|
|
|
|
2024-01-16 03:17:06 -08:00
|
|
|
static uint32_t write_string(const char *string, struct fx_write_context *fx)
|
|
|
|
{
|
|
|
|
return fx->ops->write_string(string, fx);
|
|
|
|
}
|
|
|
|
|
2023-11-15 14:31:01 -08:00
|
|
|
static void write_pass(struct hlsl_ir_var *var, struct fx_write_context *fx)
|
|
|
|
{
|
|
|
|
fx->ops->write_pass(var, fx);
|
|
|
|
}
|
|
|
|
|
2024-02-06 06:11:47 -08:00
|
|
|
static uint32_t write_type(const struct hlsl_type *type, struct fx_write_context *fx)
|
|
|
|
{
|
|
|
|
struct type_entry *type_entry;
|
|
|
|
unsigned int elements_count;
|
|
|
|
const char *name;
|
|
|
|
|
|
|
|
if (type->class == HLSL_CLASS_ARRAY)
|
|
|
|
{
|
|
|
|
name = hlsl_get_multiarray_element_type(type)->name;
|
|
|
|
elements_count = hlsl_get_multiarray_size(type);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
name = type->name;
|
|
|
|
elements_count = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY(type_entry, &fx->types, struct type_entry, entry)
|
|
|
|
{
|
|
|
|
if (strcmp(type_entry->name, name))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (type_entry->elements_count != elements_count)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
return type_entry->offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(type_entry = hlsl_alloc(fx->ctx, sizeof(*type_entry))))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
type_entry->offset = fx->ops->write_type(type, fx);
|
|
|
|
type_entry->name = name;
|
|
|
|
type_entry->elements_count = elements_count;
|
|
|
|
|
|
|
|
list_add_tail(&fx->types, &type_entry->entry);
|
|
|
|
|
|
|
|
return type_entry->offset;
|
|
|
|
}
|
|
|
|
|
2024-01-16 03:17:06 -08:00
|
|
|
static void fx_write_context_init(struct hlsl_ctx *ctx, const struct fx_write_context_ops *ops,
|
|
|
|
struct fx_write_context *fx)
|
2024-01-12 05:26:39 -08:00
|
|
|
{
|
|
|
|
unsigned int version = ctx->profile->major_version;
|
|
|
|
|
|
|
|
memset(fx, 0, sizeof(*fx));
|
|
|
|
|
2024-01-12 05:33:05 -08:00
|
|
|
fx->ctx = ctx;
|
2024-01-16 03:17:06 -08:00
|
|
|
fx->ops = ops;
|
2024-01-12 05:26:39 -08:00
|
|
|
if (version == 2)
|
|
|
|
{
|
|
|
|
fx->min_technique_version = 9;
|
|
|
|
fx->max_technique_version = 9;
|
|
|
|
}
|
|
|
|
else if (version == 4)
|
|
|
|
{
|
|
|
|
fx->min_technique_version = 10;
|
|
|
|
fx->max_technique_version = 10;
|
|
|
|
}
|
|
|
|
else if (version == 5)
|
|
|
|
{
|
|
|
|
fx->min_technique_version = 10;
|
|
|
|
fx->max_technique_version = 11;
|
|
|
|
}
|
2024-01-12 05:33:05 -08:00
|
|
|
|
|
|
|
rb_init(&fx->strings, string_storage_compare);
|
2024-02-06 06:11:47 -08:00
|
|
|
list_init(&fx->types);
|
2024-01-12 05:33:05 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int fx_write_context_cleanup(struct fx_write_context *fx)
|
|
|
|
{
|
2024-02-06 06:11:47 -08:00
|
|
|
struct type_entry *type, *next_type;
|
2024-01-12 05:33:05 -08:00
|
|
|
int status = fx->status;
|
2024-02-06 06:11:47 -08:00
|
|
|
|
2024-01-12 05:33:05 -08:00
|
|
|
rb_destroy(&fx->strings, string_storage_destroy, NULL);
|
|
|
|
|
2024-02-06 06:11:47 -08:00
|
|
|
LIST_FOR_EACH_ENTRY_SAFE(type, next_type, &fx->types, struct type_entry, entry)
|
|
|
|
{
|
|
|
|
list_remove(&type->entry);
|
|
|
|
vkd3d_free(type);
|
|
|
|
}
|
|
|
|
|
2024-01-12 05:33:05 -08:00
|
|
|
return status;
|
2024-01-12 05:26:39 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool technique_matches_version(const struct hlsl_ir_var *var, const struct fx_write_context *fx)
|
|
|
|
{
|
|
|
|
const struct hlsl_type *type = var->data_type;
|
|
|
|
|
|
|
|
if (type->base_type != HLSL_TYPE_TECHNIQUE)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return type->e.version >= fx->min_technique_version && type->e.version <= fx->max_technique_version;
|
|
|
|
}
|
|
|
|
|
2024-01-16 03:17:06 -08:00
|
|
|
static uint32_t write_fx_4_string(const char *string, struct fx_write_context *fx)
|
2023-11-05 13:07:01 -08:00
|
|
|
{
|
2024-01-12 05:33:05 -08:00
|
|
|
struct string_entry *string_entry;
|
|
|
|
struct rb_entry *entry;
|
|
|
|
|
2023-11-05 13:07:01 -08:00
|
|
|
/* NULLs are emitted as empty strings using the same 4 bytes at the start of the section. */
|
2024-01-12 05:33:05 -08:00
|
|
|
if (!string)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if ((entry = rb_get(&fx->strings, string)))
|
|
|
|
{
|
|
|
|
string_entry = RB_ENTRY_VALUE(entry, struct string_entry, entry);
|
|
|
|
return string_entry->offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(string_entry = hlsl_alloc(fx->ctx, sizeof(*string_entry))))
|
|
|
|
return 0;
|
|
|
|
|
2024-02-06 05:21:46 -08:00
|
|
|
string_entry->offset = bytecode_put_bytes_unaligned(&fx->unstructured, string, strlen(string) + 1);
|
2024-01-12 05:33:05 -08:00
|
|
|
string_entry->string = string;
|
|
|
|
|
|
|
|
rb_put(&fx->strings, string, &string_entry->entry);
|
|
|
|
|
|
|
|
return string_entry->offset;
|
2023-11-05 13:07:01 -08:00
|
|
|
}
|
|
|
|
|
2023-11-15 14:31:01 -08:00
|
|
|
static void write_fx_4_pass(struct hlsl_ir_var *var, struct fx_write_context *fx)
|
|
|
|
{
|
|
|
|
struct vkd3d_bytecode_buffer *buffer = &fx->structured;
|
|
|
|
uint32_t name_offset;
|
|
|
|
|
|
|
|
name_offset = write_string(var->name, fx);
|
|
|
|
put_u32(buffer, name_offset);
|
|
|
|
put_u32(buffer, 0); /* Assignment count. */
|
|
|
|
put_u32(buffer, 0); /* Annotation count. */
|
|
|
|
|
|
|
|
/* TODO: annotations */
|
|
|
|
/* TODO: assignments */
|
|
|
|
}
|
|
|
|
|
|
|
|
static void write_fx_2_pass(struct hlsl_ir_var *var, struct fx_write_context *fx)
|
2023-11-05 13:07:01 -08:00
|
|
|
{
|
|
|
|
struct vkd3d_bytecode_buffer *buffer = &fx->structured;
|
|
|
|
uint32_t name_offset;
|
|
|
|
|
2024-01-16 03:17:06 -08:00
|
|
|
name_offset = write_string(var->name, fx);
|
2023-11-05 13:07:01 -08:00
|
|
|
put_u32(buffer, name_offset);
|
|
|
|
put_u32(buffer, 0); /* Annotation count. */
|
2023-11-10 16:14:03 -08:00
|
|
|
put_u32(buffer, 0); /* Assignment count. */
|
2023-11-15 14:31:01 -08:00
|
|
|
|
|
|
|
/* TODO: annotations */
|
|
|
|
/* TODO: assignments */
|
2023-11-10 16:14:03 -08:00
|
|
|
}
|
|
|
|
|
2024-02-06 06:11:47 -08:00
|
|
|
static uint32_t get_fx_4_type_size(const struct hlsl_type *type)
|
|
|
|
{
|
|
|
|
uint32_t elements_count;
|
|
|
|
|
|
|
|
elements_count = hlsl_get_multiarray_size(type);
|
|
|
|
type = hlsl_get_multiarray_element_type(type);
|
|
|
|
|
|
|
|
return type->reg_size[HLSL_REGSET_NUMERIC] * sizeof(float) * elements_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t get_fx_4_numeric_type_description(const struct hlsl_type *type, struct fx_write_context *fx)
|
|
|
|
{
|
|
|
|
static const unsigned int NUMERIC_BASE_TYPE_SHIFT = 3;
|
|
|
|
static const unsigned int NUMERIC_ROWS_SHIFT = 8;
|
|
|
|
static const unsigned int NUMERIC_COLUMNS_SHIFT = 11;
|
|
|
|
static const unsigned int NUMERIC_COLUMN_MAJOR_MASK = 0x4000;
|
|
|
|
static const uint32_t numeric_type_class[] =
|
|
|
|
{
|
|
|
|
[HLSL_CLASS_SCALAR] = 1,
|
|
|
|
[HLSL_CLASS_VECTOR] = 2,
|
|
|
|
[HLSL_CLASS_MATRIX] = 3,
|
|
|
|
};
|
|
|
|
static const uint32_t numeric_base_type[] =
|
|
|
|
{
|
|
|
|
[HLSL_TYPE_FLOAT] = 1,
|
|
|
|
[HLSL_TYPE_INT ] = 2,
|
|
|
|
[HLSL_TYPE_UINT ] = 3,
|
|
|
|
[HLSL_TYPE_BOOL ] = 4,
|
|
|
|
};
|
|
|
|
uint32_t value = 0;
|
|
|
|
|
|
|
|
switch (type->class)
|
|
|
|
{
|
|
|
|
case HLSL_CLASS_SCALAR:
|
|
|
|
case HLSL_CLASS_VECTOR:
|
|
|
|
case HLSL_CLASS_MATRIX:
|
|
|
|
value |= numeric_type_class[type->class];
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
FIXME("Unexpected type class %u.\n", type->class);
|
|
|
|
set_status(fx, VKD3D_ERROR_NOT_IMPLEMENTED);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (type->base_type)
|
|
|
|
{
|
|
|
|
case HLSL_TYPE_FLOAT:
|
|
|
|
case HLSL_TYPE_INT:
|
|
|
|
case HLSL_TYPE_UINT:
|
|
|
|
case HLSL_TYPE_BOOL:
|
|
|
|
value |= (numeric_base_type[type->base_type] << NUMERIC_BASE_TYPE_SHIFT);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
FIXME("Unexpected base type %u.\n", type->base_type);
|
|
|
|
set_status(fx, VKD3D_ERROR_NOT_IMPLEMENTED);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
value |= (type->dimy & 0x7) << NUMERIC_ROWS_SHIFT;
|
|
|
|
value |= (type->dimx & 0x7) << NUMERIC_COLUMNS_SHIFT;
|
|
|
|
if (type->modifiers & HLSL_MODIFIER_COLUMN_MAJOR)
|
|
|
|
value |= NUMERIC_COLUMN_MAJOR_MASK;
|
|
|
|
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t write_fx_4_type(const struct hlsl_type *type, struct fx_write_context *fx)
|
|
|
|
{
|
|
|
|
struct vkd3d_bytecode_buffer *buffer = &fx->unstructured;
|
|
|
|
uint32_t name_offset, offset, size, stride, numeric_desc;
|
|
|
|
uint32_t elements_count = 0;
|
|
|
|
static const uint32_t variable_type[] =
|
|
|
|
{
|
|
|
|
[HLSL_CLASS_SCALAR] = 1,
|
|
|
|
[HLSL_CLASS_VECTOR] = 1,
|
|
|
|
[HLSL_CLASS_MATRIX] = 1,
|
|
|
|
[HLSL_CLASS_OBJECT] = 2,
|
|
|
|
[HLSL_CLASS_STRUCT] = 3,
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Resolve arrays to element type and number of elements. */
|
|
|
|
if (type->class == HLSL_CLASS_ARRAY)
|
|
|
|
{
|
|
|
|
elements_count = hlsl_get_multiarray_size(type);
|
|
|
|
type = hlsl_get_multiarray_element_type(type);
|
|
|
|
}
|
|
|
|
|
|
|
|
name_offset = write_string(type->name, fx);
|
|
|
|
offset = put_u32_unaligned(buffer, name_offset);
|
|
|
|
|
|
|
|
switch (type->class)
|
|
|
|
{
|
|
|
|
case HLSL_CLASS_SCALAR:
|
|
|
|
case HLSL_CLASS_VECTOR:
|
|
|
|
case HLSL_CLASS_MATRIX:
|
|
|
|
case HLSL_CLASS_OBJECT:
|
|
|
|
case HLSL_CLASS_STRUCT:
|
|
|
|
put_u32_unaligned(buffer, variable_type[type->class]);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
FIXME("Writing type class %u is not implemented.\n", type->class);
|
|
|
|
set_status(fx, VKD3D_ERROR_NOT_IMPLEMENTED);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
size = stride = type->reg_size[HLSL_REGSET_NUMERIC] * sizeof(float);
|
|
|
|
if (elements_count)
|
|
|
|
size *= elements_count;
|
|
|
|
stride = align(stride, 4 * sizeof(float));
|
|
|
|
|
|
|
|
put_u32_unaligned(buffer, elements_count);
|
|
|
|
put_u32_unaligned(buffer, size); /* Total size. */
|
|
|
|
put_u32_unaligned(buffer, stride); /* Stride. */
|
|
|
|
put_u32_unaligned(buffer, size);
|
|
|
|
|
|
|
|
if (type->class == HLSL_CLASS_STRUCT)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
put_u32_unaligned(buffer, type->e.record.field_count);
|
|
|
|
for (i = 0; i < type->e.record.field_count; ++i)
|
|
|
|
{
|
|
|
|
const struct hlsl_struct_field *field = &type->e.record.fields[i];
|
|
|
|
uint32_t semantic_offset, field_type_offset;
|
|
|
|
|
|
|
|
name_offset = write_string(field->name, fx);
|
|
|
|
semantic_offset = write_string(field->semantic.name, fx);
|
|
|
|
field_type_offset = write_type(field->type, fx);
|
|
|
|
|
|
|
|
put_u32_unaligned(buffer, name_offset);
|
|
|
|
put_u32_unaligned(buffer, semantic_offset);
|
|
|
|
put_u32_unaligned(buffer, field->reg_offset[HLSL_REGSET_NUMERIC]);
|
|
|
|
put_u32_unaligned(buffer, field_type_offset);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (type->class == HLSL_CLASS_OBJECT)
|
|
|
|
{
|
|
|
|
FIXME("Object types are not supported.\n");
|
|
|
|
set_status(fx, VKD3D_ERROR_NOT_IMPLEMENTED);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else /* Numeric type */
|
|
|
|
{
|
|
|
|
numeric_desc = get_fx_4_numeric_type_description(type, fx);
|
|
|
|
put_u32_unaligned(buffer, numeric_desc);
|
|
|
|
}
|
|
|
|
|
|
|
|
return offset;
|
|
|
|
}
|
|
|
|
|
2024-01-16 03:17:06 -08:00
|
|
|
static void write_fx_4_technique(struct hlsl_ir_var *var, struct fx_write_context *fx)
|
2023-11-10 16:14:03 -08:00
|
|
|
{
|
|
|
|
struct vkd3d_bytecode_buffer *buffer = &fx->structured;
|
|
|
|
uint32_t name_offset, count = 0;
|
|
|
|
struct hlsl_ir_var *pass;
|
|
|
|
uint32_t count_offset;
|
|
|
|
|
2024-01-16 03:17:06 -08:00
|
|
|
name_offset = write_string(var->name, fx);
|
2023-11-10 16:14:03 -08:00
|
|
|
put_u32(buffer, name_offset);
|
|
|
|
count_offset = put_u32(buffer, 0);
|
|
|
|
put_u32(buffer, 0); /* Annotation count. */
|
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY(pass, &var->scope->vars, struct hlsl_ir_var, scope_entry)
|
|
|
|
{
|
|
|
|
write_pass(pass, fx);
|
|
|
|
++count;
|
|
|
|
}
|
2023-11-05 13:07:01 -08:00
|
|
|
|
2023-11-10 16:14:03 -08:00
|
|
|
set_u32(buffer, count_offset, count);
|
2023-11-05 13:07:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void write_techniques(struct hlsl_scope *scope, struct fx_write_context *fx)
|
|
|
|
{
|
|
|
|
struct hlsl_ir_var *var;
|
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY(var, &scope->vars, struct hlsl_ir_var, scope_entry)
|
|
|
|
{
|
2024-01-16 03:09:41 -08:00
|
|
|
if (technique_matches_version(var, fx))
|
2023-11-05 13:07:01 -08:00
|
|
|
{
|
2024-01-16 03:17:06 -08:00
|
|
|
fx->ops->write_technique(var, fx);
|
2023-11-05 13:07:01 -08:00
|
|
|
++fx->technique_count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
set_status(fx, fx->unstructured.status);
|
|
|
|
set_status(fx, fx->structured.status);
|
|
|
|
}
|
|
|
|
|
2024-01-25 09:18:40 -08:00
|
|
|
static void write_group(struct hlsl_ir_var *var, struct fx_write_context *fx)
|
2024-01-12 05:26:39 -08:00
|
|
|
{
|
|
|
|
struct vkd3d_bytecode_buffer *buffer = &fx->structured;
|
2024-01-25 09:18:40 -08:00
|
|
|
uint32_t name_offset = write_string(var ? var->name : NULL, fx);
|
2024-01-12 05:26:39 -08:00
|
|
|
uint32_t count_offset, count;
|
|
|
|
|
|
|
|
put_u32(buffer, name_offset);
|
|
|
|
count_offset = put_u32(buffer, 0); /* Technique count */
|
|
|
|
put_u32(buffer, 0); /* Annotation count */
|
|
|
|
|
|
|
|
count = fx->technique_count;
|
2024-01-25 09:18:40 -08:00
|
|
|
write_techniques(var ? var->scope : fx->ctx->globals, fx);
|
2024-01-12 05:26:39 -08:00
|
|
|
set_u32(buffer, count_offset, fx->technique_count - count);
|
|
|
|
|
|
|
|
++fx->group_count;
|
|
|
|
}
|
|
|
|
|
2024-01-25 09:18:40 -08:00
|
|
|
static void write_groups(struct fx_write_context *fx)
|
2024-01-12 05:26:39 -08:00
|
|
|
{
|
2024-01-25 09:18:40 -08:00
|
|
|
struct hlsl_scope *scope = fx->ctx->globals;
|
2024-01-12 05:26:39 -08:00
|
|
|
bool needs_default_group = false;
|
|
|
|
struct hlsl_ir_var *var;
|
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY(var, &scope->vars, struct hlsl_ir_var, scope_entry)
|
|
|
|
{
|
|
|
|
if (technique_matches_version(var, fx))
|
|
|
|
{
|
|
|
|
needs_default_group = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (needs_default_group)
|
2024-01-25 09:18:40 -08:00
|
|
|
write_group(NULL, fx);
|
2024-01-12 05:26:39 -08:00
|
|
|
LIST_FOR_EACH_ENTRY(var, &scope->vars, struct hlsl_ir_var, scope_entry)
|
|
|
|
{
|
|
|
|
const struct hlsl_type *type = var->data_type;
|
|
|
|
|
|
|
|
if (type->base_type == HLSL_TYPE_EFFECT_GROUP)
|
2024-01-25 09:18:40 -08:00
|
|
|
write_group(var, fx);
|
2024-01-12 05:26:39 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-16 03:17:06 -08:00
|
|
|
static uint32_t write_fx_2_string(const char *string, struct fx_write_context *fx)
|
|
|
|
{
|
|
|
|
struct vkd3d_bytecode_buffer *buffer = &fx->unstructured;
|
|
|
|
const char *s = string ? string : "";
|
|
|
|
uint32_t size, offset;
|
|
|
|
|
|
|
|
size = strlen(s) + 1;
|
|
|
|
offset = put_u32(buffer, size);
|
|
|
|
bytecode_put_bytes(buffer, s, size);
|
|
|
|
return offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void write_fx_2_technique(struct hlsl_ir_var *var, struct fx_write_context *fx)
|
|
|
|
{
|
|
|
|
struct vkd3d_bytecode_buffer *buffer = &fx->structured;
|
2023-11-15 14:31:01 -08:00
|
|
|
uint32_t name_offset, count_offset, count = 0;
|
|
|
|
struct hlsl_ir_var *pass;
|
2024-01-16 03:17:06 -08:00
|
|
|
|
|
|
|
name_offset = write_string(var->name, fx);
|
|
|
|
put_u32(buffer, name_offset);
|
|
|
|
put_u32(buffer, 0); /* Annotation count. */
|
2023-11-15 14:31:01 -08:00
|
|
|
count_offset = put_u32(buffer, 0); /* Pass count. */
|
2024-01-16 03:17:06 -08:00
|
|
|
|
|
|
|
/* FIXME: annotations */
|
2023-11-15 14:31:01 -08:00
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY(pass, &var->scope->vars, struct hlsl_ir_var, scope_entry)
|
|
|
|
{
|
|
|
|
write_pass(pass, fx);
|
|
|
|
++count;
|
|
|
|
}
|
|
|
|
|
|
|
|
set_u32(buffer, count_offset, count);
|
2024-01-16 03:17:06 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static const struct fx_write_context_ops fx_2_ops =
|
|
|
|
{
|
|
|
|
.write_string = write_fx_2_string,
|
|
|
|
.write_technique = write_fx_2_technique,
|
2023-11-15 14:31:01 -08:00
|
|
|
.write_pass = write_fx_2_pass,
|
2024-01-16 03:17:06 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
static int hlsl_fx_2_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out)
|
|
|
|
{
|
|
|
|
struct vkd3d_bytecode_buffer buffer = { 0 };
|
|
|
|
struct vkd3d_bytecode_buffer *structured;
|
|
|
|
uint32_t offset, size, technique_count;
|
|
|
|
struct fx_write_context fx;
|
|
|
|
|
|
|
|
fx_write_context_init(ctx, &fx_2_ops, &fx);
|
|
|
|
structured = &fx.structured;
|
|
|
|
|
|
|
|
/* First entry is always zeroed and skipped. */
|
|
|
|
put_u32(&fx.unstructured, 0);
|
|
|
|
|
|
|
|
put_u32(&buffer, 0xfeff0901); /* Version. */
|
|
|
|
offset = put_u32(&buffer, 0);
|
|
|
|
|
|
|
|
put_u32(structured, 0); /* Parameter count */
|
|
|
|
technique_count = put_u32(structured, 0);
|
|
|
|
put_u32(structured, 0); /* Unknown */
|
|
|
|
put_u32(structured, 0); /* Object count */
|
|
|
|
|
|
|
|
/* TODO: parameters */
|
|
|
|
|
|
|
|
write_techniques(ctx->globals, &fx);
|
|
|
|
set_u32(structured, technique_count, fx.technique_count);
|
|
|
|
|
|
|
|
put_u32(structured, 0); /* String count */
|
|
|
|
put_u32(structured, 0); /* Resource count */
|
|
|
|
|
|
|
|
/* TODO: strings */
|
|
|
|
/* TODO: resources */
|
|
|
|
|
|
|
|
size = align(fx.unstructured.size, 4);
|
|
|
|
set_u32(&buffer, offset, size);
|
|
|
|
|
|
|
|
bytecode_put_bytes(&buffer, fx.unstructured.data, fx.unstructured.size);
|
|
|
|
bytecode_put_bytes(&buffer, fx.structured.data, fx.structured.size);
|
|
|
|
|
|
|
|
vkd3d_free(fx.unstructured.data);
|
|
|
|
vkd3d_free(fx.structured.data);
|
|
|
|
|
|
|
|
if (!fx.status)
|
|
|
|
{
|
|
|
|
out->code = buffer.data;
|
|
|
|
out->size = buffer.size;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fx.status < 0)
|
|
|
|
ctx->result = fx.status;
|
|
|
|
|
|
|
|
return fx_write_context_cleanup(&fx);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct fx_write_context_ops fx_4_ops =
|
|
|
|
{
|
|
|
|
.write_string = write_fx_4_string,
|
2024-02-06 06:11:47 -08:00
|
|
|
.write_type = write_fx_4_type,
|
2024-01-16 03:17:06 -08:00
|
|
|
.write_technique = write_fx_4_technique,
|
2023-11-15 14:31:01 -08:00
|
|
|
.write_pass = write_fx_4_pass,
|
2024-01-16 03:17:06 -08:00
|
|
|
};
|
|
|
|
|
2024-02-06 06:11:47 -08:00
|
|
|
static void write_fx_4_variable(struct hlsl_ir_var *var, struct fx_write_context *fx)
|
|
|
|
{
|
|
|
|
struct vkd3d_bytecode_buffer *buffer = &fx->structured;
|
|
|
|
uint32_t semantic_offset, flags = 0;
|
|
|
|
uint32_t name_offset, type_offset;
|
|
|
|
enum fx_4_variable_flags
|
|
|
|
{
|
|
|
|
HAS_EXPLICIT_BIND_POINT = 0x4,
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Explicit bind point. */
|
|
|
|
if (var->reg_reservation.reg_type)
|
|
|
|
flags |= HAS_EXPLICIT_BIND_POINT;
|
|
|
|
|
|
|
|
type_offset = write_type(var->data_type, fx);
|
|
|
|
name_offset = write_string(var->name, fx);
|
|
|
|
semantic_offset = write_string(var->semantic.name, fx);
|
|
|
|
|
|
|
|
put_u32(buffer, name_offset);
|
|
|
|
put_u32(buffer, type_offset);
|
|
|
|
|
|
|
|
semantic_offset = put_u32(buffer, semantic_offset); /* Semantic */
|
|
|
|
put_u32(buffer, var->buffer_offset); /* Offset in the constant buffer */
|
|
|
|
put_u32(buffer, 0); /* FIXME: default value offset */
|
|
|
|
put_u32(buffer, flags); /* Flags */
|
|
|
|
|
|
|
|
put_u32(buffer, 0); /* Annotations count */
|
|
|
|
/* FIXME: write annotations */
|
|
|
|
}
|
|
|
|
|
|
|
|
static void write_fx_4_buffer(struct hlsl_buffer *b, struct fx_write_context *fx)
|
|
|
|
{
|
|
|
|
enum fx_4_buffer_flags
|
|
|
|
{
|
|
|
|
IS_TBUFFER = 0x1,
|
|
|
|
IS_SINGLE = 0x2,
|
|
|
|
};
|
|
|
|
struct vkd3d_bytecode_buffer *buffer = &fx->structured;
|
|
|
|
uint32_t count = 0, bind_point = ~0u, flags = 0, size;
|
|
|
|
uint32_t name_offset, size_offset;
|
|
|
|
struct hlsl_ctx *ctx = fx->ctx;
|
|
|
|
struct hlsl_ir_var *var;
|
|
|
|
uint32_t count_offset;
|
|
|
|
|
|
|
|
if (b->reservation.reg_type)
|
|
|
|
bind_point = b->reservation.reg_index;
|
|
|
|
if (b->type == HLSL_BUFFER_TEXTURE)
|
|
|
|
flags |= IS_TBUFFER;
|
|
|
|
/* FIXME: set 'single' flag for fx_5_0 */
|
|
|
|
|
|
|
|
name_offset = write_string(b->name, fx);
|
|
|
|
|
|
|
|
put_u32(buffer, name_offset); /* Name */
|
|
|
|
size_offset = put_u32(buffer, 0); /* Data size */
|
|
|
|
put_u32(buffer, flags); /* Flags */
|
|
|
|
count_offset = put_u32(buffer, 0);
|
|
|
|
put_u32(buffer, bind_point); /* Bind point */
|
|
|
|
|
|
|
|
put_u32(buffer, 0); /* Annotations count */
|
|
|
|
/* FIXME: write annotations */
|
|
|
|
|
|
|
|
count = 0;
|
|
|
|
size = 0;
|
|
|
|
LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry)
|
|
|
|
{
|
|
|
|
if (var->buffer != b)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
write_fx_4_variable(var, fx);
|
|
|
|
size += get_fx_4_type_size(var->data_type);
|
|
|
|
++count;
|
|
|
|
}
|
|
|
|
|
|
|
|
set_u32(buffer, count_offset, count);
|
|
|
|
set_u32(buffer, size_offset, align(size, 16));
|
|
|
|
|
|
|
|
fx->numeric_variable_count += count;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void write_buffers(struct fx_write_context *fx)
|
|
|
|
{
|
|
|
|
struct hlsl_buffer *buffer;
|
|
|
|
struct hlsl_block block;
|
|
|
|
|
|
|
|
hlsl_block_init(&block);
|
|
|
|
hlsl_prepend_global_uniform_copy(fx->ctx, &block);
|
|
|
|
hlsl_block_init(&block);
|
|
|
|
hlsl_calculate_buffer_offsets(fx->ctx);
|
|
|
|
|
|
|
|
LIST_FOR_EACH_ENTRY(buffer, &fx->ctx->buffers, struct hlsl_buffer, entry)
|
|
|
|
{
|
|
|
|
if (!buffer->size)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
write_fx_4_buffer(buffer, fx);
|
|
|
|
++fx->buffer_count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-05 13:07:01 -08:00
|
|
|
static int hlsl_fx_4_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out)
|
|
|
|
{
|
|
|
|
struct vkd3d_bytecode_buffer buffer = { 0 };
|
2024-02-06 06:11:47 -08:00
|
|
|
struct fx_write_context fx;
|
2024-02-06 15:38:59 -08:00
|
|
|
uint32_t size_offset;
|
2023-11-05 13:07:01 -08:00
|
|
|
|
2024-01-16 03:17:06 -08:00
|
|
|
fx_write_context_init(ctx, &fx_4_ops, &fx);
|
2023-11-05 13:07:01 -08:00
|
|
|
|
|
|
|
put_u32(&fx.unstructured, 0); /* Empty string placeholder. */
|
|
|
|
|
2024-02-06 06:11:47 -08:00
|
|
|
write_buffers(&fx);
|
2023-11-05 13:07:01 -08:00
|
|
|
/* TODO: objects */
|
|
|
|
/* TODO: shared buffers */
|
|
|
|
/* TODO: shared objects */
|
|
|
|
|
|
|
|
write_techniques(ctx->globals, &fx);
|
|
|
|
|
|
|
|
put_u32(&buffer, ctx->profile->minor_version == 0 ? 0xfeff1001 : 0xfeff1011); /* Version. */
|
2024-02-06 06:11:47 -08:00
|
|
|
put_u32(&buffer, fx.buffer_count); /* Buffer count. */
|
|
|
|
put_u32(&buffer, fx.numeric_variable_count); /* Numeric variable count. */
|
|
|
|
put_u32(&buffer, 0); /* Object variable count. */
|
2023-11-05 13:07:01 -08:00
|
|
|
put_u32(&buffer, 0); /* Pool buffer count. */
|
|
|
|
put_u32(&buffer, 0); /* Pool variable count. */
|
|
|
|
put_u32(&buffer, 0); /* Pool object count. */
|
|
|
|
put_u32(&buffer, fx.technique_count);
|
|
|
|
size_offset = put_u32(&buffer, 0); /* Unstructured size. */
|
|
|
|
put_u32(&buffer, 0); /* String count. */
|
|
|
|
put_u32(&buffer, 0); /* Texture object count. */
|
|
|
|
put_u32(&buffer, 0); /* Depth stencil state count. */
|
|
|
|
put_u32(&buffer, 0); /* Blend state count. */
|
|
|
|
put_u32(&buffer, 0); /* Rasterizer state count. */
|
|
|
|
put_u32(&buffer, 0); /* Sampler state count. */
|
|
|
|
put_u32(&buffer, 0); /* Rendertarget view count. */
|
|
|
|
put_u32(&buffer, 0); /* Depth stencil view count. */
|
|
|
|
put_u32(&buffer, 0); /* Shader count. */
|
|
|
|
put_u32(&buffer, 0); /* Inline shader count. */
|
|
|
|
|
2024-02-06 15:38:59 -08:00
|
|
|
set_u32(&buffer, size_offset, fx.unstructured.size);
|
2023-11-05 13:07:01 -08:00
|
|
|
|
|
|
|
bytecode_put_bytes(&buffer, fx.unstructured.data, fx.unstructured.size);
|
2024-02-06 15:38:59 -08:00
|
|
|
bytecode_put_bytes_unaligned(&buffer, fx.structured.data, fx.structured.size);
|
2023-11-05 13:07:01 -08:00
|
|
|
|
|
|
|
vkd3d_free(fx.unstructured.data);
|
|
|
|
vkd3d_free(fx.structured.data);
|
|
|
|
|
|
|
|
set_status(&fx, buffer.status);
|
|
|
|
|
|
|
|
if (!fx.status)
|
|
|
|
{
|
|
|
|
out->code = buffer.data;
|
|
|
|
out->size = buffer.size;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fx.status < 0)
|
|
|
|
ctx->result = fx.status;
|
|
|
|
|
2024-01-12 05:33:05 -08:00
|
|
|
return fx_write_context_cleanup(&fx);
|
2023-11-05 13:07:01 -08:00
|
|
|
}
|
|
|
|
|
2024-01-12 05:26:39 -08:00
|
|
|
static int hlsl_fx_5_write(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out)
|
|
|
|
{
|
|
|
|
struct vkd3d_bytecode_buffer buffer = { 0 };
|
2024-02-06 06:11:47 -08:00
|
|
|
struct fx_write_context fx;
|
2024-02-06 15:38:59 -08:00
|
|
|
uint32_t size_offset;
|
2024-01-12 05:26:39 -08:00
|
|
|
|
2024-01-16 03:17:06 -08:00
|
|
|
fx_write_context_init(ctx, &fx_4_ops, &fx);
|
2024-01-12 05:26:39 -08:00
|
|
|
|
|
|
|
put_u32(&fx.unstructured, 0); /* Empty string placeholder. */
|
|
|
|
|
2024-02-06 06:11:47 -08:00
|
|
|
write_buffers(&fx);
|
2024-01-12 05:26:39 -08:00
|
|
|
/* TODO: objects */
|
|
|
|
/* TODO: interface variables */
|
|
|
|
|
2024-01-25 09:18:40 -08:00
|
|
|
write_groups(&fx);
|
2024-01-12 05:26:39 -08:00
|
|
|
|
|
|
|
put_u32(&buffer, 0xfeff2001); /* Version. */
|
2024-02-06 06:11:47 -08:00
|
|
|
put_u32(&buffer, fx.buffer_count); /* Buffer count. */
|
|
|
|
put_u32(&buffer, fx.numeric_variable_count); /* Numeric variable count. */
|
|
|
|
put_u32(&buffer, 0); /* Object variable count. */
|
2024-01-12 05:26:39 -08:00
|
|
|
put_u32(&buffer, 0); /* Pool buffer count. */
|
|
|
|
put_u32(&buffer, 0); /* Pool variable count. */
|
|
|
|
put_u32(&buffer, 0); /* Pool object count. */
|
|
|
|
put_u32(&buffer, fx.technique_count);
|
|
|
|
size_offset = put_u32(&buffer, 0); /* Unstructured size. */
|
|
|
|
put_u32(&buffer, 0); /* String count. */
|
|
|
|
put_u32(&buffer, 0); /* Texture object count. */
|
|
|
|
put_u32(&buffer, 0); /* Depth stencil state count. */
|
|
|
|
put_u32(&buffer, 0); /* Blend state count. */
|
|
|
|
put_u32(&buffer, 0); /* Rasterizer state count. */
|
|
|
|
put_u32(&buffer, 0); /* Sampler state count. */
|
|
|
|
put_u32(&buffer, 0); /* Rendertarget view count. */
|
|
|
|
put_u32(&buffer, 0); /* Depth stencil view count. */
|
|
|
|
put_u32(&buffer, 0); /* Shader count. */
|
|
|
|
put_u32(&buffer, 0); /* Inline shader count. */
|
|
|
|
put_u32(&buffer, fx.group_count); /* Group count. */
|
|
|
|
put_u32(&buffer, 0); /* UAV count. */
|
|
|
|
put_u32(&buffer, 0); /* Interface variables count. */
|
|
|
|
put_u32(&buffer, 0); /* Interface variable element count. */
|
|
|
|
put_u32(&buffer, 0); /* Class instance elements count. */
|
|
|
|
|
2024-02-06 15:38:59 -08:00
|
|
|
set_u32(&buffer, size_offset, fx.unstructured.size);
|
2024-01-12 05:26:39 -08:00
|
|
|
|
|
|
|
bytecode_put_bytes(&buffer, fx.unstructured.data, fx.unstructured.size);
|
2024-02-06 15:38:59 -08:00
|
|
|
bytecode_put_bytes_unaligned(&buffer, fx.structured.data, fx.structured.size);
|
2024-01-12 05:26:39 -08:00
|
|
|
|
|
|
|
vkd3d_free(fx.unstructured.data);
|
|
|
|
vkd3d_free(fx.structured.data);
|
|
|
|
|
|
|
|
set_status(&fx, buffer.status);
|
|
|
|
|
|
|
|
if (!fx.status)
|
|
|
|
{
|
|
|
|
out->code = buffer.data;
|
|
|
|
out->size = buffer.size;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fx.status < 0)
|
|
|
|
ctx->result = fx.status;
|
|
|
|
|
2024-01-12 05:33:05 -08:00
|
|
|
return fx_write_context_cleanup(&fx);
|
2024-01-12 05:26:39 -08:00
|
|
|
}
|
|
|
|
|
2023-11-05 13:07:01 -08:00
|
|
|
int hlsl_emit_effect_binary(struct hlsl_ctx *ctx, struct vkd3d_shader_code *out)
|
|
|
|
{
|
|
|
|
if (ctx->profile->major_version == 2)
|
|
|
|
{
|
2024-01-16 03:17:06 -08:00
|
|
|
return hlsl_fx_2_write(ctx, out);
|
2023-11-05 13:07:01 -08:00
|
|
|
}
|
|
|
|
else if (ctx->profile->major_version == 4)
|
|
|
|
{
|
|
|
|
return hlsl_fx_4_write(ctx, out);
|
|
|
|
}
|
|
|
|
else if (ctx->profile->major_version == 5)
|
|
|
|
{
|
2024-01-12 05:26:39 -08:00
|
|
|
return hlsl_fx_5_write(ctx, out);
|
2023-11-05 13:07:01 -08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
vkd3d_unreachable();
|
|
|
|
}
|
|
|
|
}
|