mirror of
https://gitlab.winehq.org/wine/vkd3d.git
synced 2025-04-13 05:43:18 -07:00
vkd3d-shader/ir: Merge all shader IR fork and join phases into a single phase.
Normalise the incoming vkd3d_shader_instruction IR to the shader model 6 pattern. This allows generation of a single patch constant function in SPIR-V.
This commit is contained in:
committed by
Alexandre Julliard
parent
57d92a15cf
commit
eabdccb117
Notes:
Alexandre Julliard
2023-04-03 22:08:13 +02:00
Approved-by: Henri Verbeet (@hverbeet) Approved-by: Alexandre Julliard (@julliard) Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/84
@ -251,6 +251,7 @@ libvkd3d_shader_la_SOURCES = \
|
|||||||
libs/vkd3d-shader/hlsl_constant_ops.c \
|
libs/vkd3d-shader/hlsl_constant_ops.c \
|
||||||
libs/vkd3d-shader/hlsl_sm1.c \
|
libs/vkd3d-shader/hlsl_sm1.c \
|
||||||
libs/vkd3d-shader/hlsl_sm4.c \
|
libs/vkd3d-shader/hlsl_sm4.c \
|
||||||
|
libs/vkd3d-shader/ir.c \
|
||||||
libs/vkd3d-shader/preproc.h \
|
libs/vkd3d-shader/preproc.h \
|
||||||
libs/vkd3d-shader/sm4.h \
|
libs/vkd3d-shader/sm4.h \
|
||||||
libs/vkd3d-shader/spirv.c \
|
libs/vkd3d-shader/spirv.c \
|
||||||
|
264
libs/vkd3d-shader/ir.c
Normal file
264
libs/vkd3d-shader/ir.c
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 Conor McCarthy for CodeWeavers
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "vkd3d_shader_private.h"
|
||||||
|
|
||||||
|
static inline bool shader_register_is_phase_instance_id(const struct vkd3d_shader_register *reg)
|
||||||
|
{
|
||||||
|
return reg->type == VKD3DSPR_FORKINSTID || reg->type == VKD3DSPR_JOININSTID;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool shader_instruction_is_dcl(const struct vkd3d_shader_instruction *ins)
|
||||||
|
{
|
||||||
|
return (VKD3DSIH_DCL <= ins->handler_idx && ins->handler_idx <= VKD3DSIH_DCL_VERTICES_OUT)
|
||||||
|
|| ins->handler_idx == VKD3DSIH_HS_DECLS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vkd3d_shader_instruction_make_nop(struct vkd3d_shader_instruction *ins)
|
||||||
|
{
|
||||||
|
ins->handler_idx = VKD3DSIH_NOP;
|
||||||
|
ins->dst_count = 0;
|
||||||
|
ins->src_count = 0;
|
||||||
|
ins->dst = NULL;
|
||||||
|
ins->src = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void shader_register_eliminate_phase_addressing(struct vkd3d_shader_register *reg,
|
||||||
|
unsigned int instance_id)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(reg->idx) && reg->idx[i].offset != ~0u; ++i)
|
||||||
|
{
|
||||||
|
if (reg->idx[i].rel_addr && shader_register_is_phase_instance_id(®->idx[i].rel_addr->reg))
|
||||||
|
{
|
||||||
|
reg->idx[i].rel_addr = NULL;
|
||||||
|
reg->idx[i].offset += instance_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void shader_instruction_eliminate_phase_instance_id(struct vkd3d_shader_instruction *ins,
|
||||||
|
unsigned int instance_id)
|
||||||
|
{
|
||||||
|
struct vkd3d_shader_register *reg;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ins->src_count; ++i)
|
||||||
|
{
|
||||||
|
reg = (struct vkd3d_shader_register *)&ins->src[i].reg;
|
||||||
|
if (shader_register_is_phase_instance_id(reg))
|
||||||
|
{
|
||||||
|
reg->type = VKD3DSPR_IMMCONST;
|
||||||
|
reg->precision = VKD3D_SHADER_REGISTER_PRECISION_DEFAULT;
|
||||||
|
reg->non_uniform = false;
|
||||||
|
reg->idx[0].offset = ~0u;
|
||||||
|
reg->idx[0].rel_addr = NULL;
|
||||||
|
reg->idx[1].offset = ~0u;
|
||||||
|
reg->idx[1].rel_addr = NULL;
|
||||||
|
reg->idx[2].offset = ~0u;
|
||||||
|
reg->idx[2].rel_addr = NULL;
|
||||||
|
reg->immconst_type = VKD3D_IMMCONST_SCALAR;
|
||||||
|
reg->u.immconst_uint[0] = instance_id;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
shader_register_eliminate_phase_addressing(reg, instance_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < ins->dst_count; ++i)
|
||||||
|
shader_register_eliminate_phase_addressing((struct vkd3d_shader_register *)&ins->dst[i].reg, instance_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool normaliser_is_in_fork_or_join_phase(const struct vkd3d_shader_normaliser *normaliser)
|
||||||
|
{
|
||||||
|
return normaliser->phase == VKD3DSIH_HS_FORK_PHASE || normaliser->phase == VKD3DSIH_HS_JOIN_PHASE;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct shader_phase_location
|
||||||
|
{
|
||||||
|
unsigned int index;
|
||||||
|
unsigned int instance_count;
|
||||||
|
unsigned int instruction_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct shader_phase_location_array
|
||||||
|
{
|
||||||
|
/* Unlikely worst case: one phase for each component of each output register. */
|
||||||
|
struct shader_phase_location locations[MAX_REG_OUTPUT * VKD3D_VEC4_SIZE];
|
||||||
|
unsigned int count;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void shader_normaliser_eliminate_phase_related_dcls(struct vkd3d_shader_normaliser *normaliser,
|
||||||
|
unsigned int index, struct shader_phase_location_array *locations)
|
||||||
|
{
|
||||||
|
struct vkd3d_shader_instruction *ins = &normaliser->instructions.elements[index];
|
||||||
|
struct shader_phase_location *loc;
|
||||||
|
bool b;
|
||||||
|
|
||||||
|
if (ins->handler_idx == VKD3DSIH_HS_FORK_PHASE || ins->handler_idx == VKD3DSIH_HS_JOIN_PHASE)
|
||||||
|
{
|
||||||
|
b = normaliser_is_in_fork_or_join_phase(normaliser);
|
||||||
|
/* Reset the phase info. */
|
||||||
|
normaliser->phase_body_idx = ~0u;
|
||||||
|
normaliser->phase = ins->handler_idx;
|
||||||
|
normaliser->instance_count = 1;
|
||||||
|
/* Leave the first occurrence and delete the rest. */
|
||||||
|
if (b)
|
||||||
|
vkd3d_shader_instruction_make_nop(ins);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (ins->handler_idx == VKD3DSIH_DCL_HS_FORK_PHASE_INSTANCE_COUNT
|
||||||
|
|| ins->handler_idx == VKD3DSIH_DCL_HS_JOIN_PHASE_INSTANCE_COUNT)
|
||||||
|
{
|
||||||
|
normaliser->instance_count = ins->declaration.count + !ins->declaration.count;
|
||||||
|
vkd3d_shader_instruction_make_nop(ins);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (ins->handler_idx == VKD3DSIH_DCL_INPUT && shader_register_is_phase_instance_id(
|
||||||
|
&ins->declaration.dst.reg))
|
||||||
|
{
|
||||||
|
vkd3d_shader_instruction_make_nop(ins);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (ins->handler_idx == VKD3DSIH_DCL_TEMPS && normaliser->phase != VKD3DSIH_INVALID)
|
||||||
|
{
|
||||||
|
/* Leave only the first temp declaration and set it to the max count later. */
|
||||||
|
if (!normaliser->max_temp_count)
|
||||||
|
normaliser->temp_dcl_idx = index;
|
||||||
|
else
|
||||||
|
vkd3d_shader_instruction_make_nop(ins);
|
||||||
|
normaliser->max_temp_count = max(normaliser->max_temp_count, ins->declaration.count);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (normaliser->phase == VKD3DSIH_INVALID || shader_instruction_is_dcl(ins))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (normaliser->phase_body_idx == ~0u)
|
||||||
|
normaliser->phase_body_idx = index;
|
||||||
|
|
||||||
|
if (ins->handler_idx == VKD3DSIH_RET)
|
||||||
|
{
|
||||||
|
vkd3d_shader_instruction_make_nop(ins);
|
||||||
|
if (locations->count >= ARRAY_SIZE(locations->locations))
|
||||||
|
{
|
||||||
|
FIXME("Insufficient space for phase location.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
loc = &locations->locations[locations->count++];
|
||||||
|
loc->index = normaliser->phase_body_idx;
|
||||||
|
loc->instance_count = normaliser->instance_count;
|
||||||
|
loc->instruction_count = index - normaliser->phase_body_idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum vkd3d_result shader_normaliser_flatten_phases(struct vkd3d_shader_normaliser *normaliser,
|
||||||
|
struct shader_phase_location_array *locations)
|
||||||
|
{
|
||||||
|
struct shader_phase_location *loc;
|
||||||
|
unsigned int i, j, k, end, count;
|
||||||
|
|
||||||
|
for (i = 0, count = 0; i < locations->count; ++i)
|
||||||
|
count += (locations->locations[i].instance_count - 1) * locations->locations[i].instruction_count;
|
||||||
|
|
||||||
|
if (!shader_instruction_array_reserve(&normaliser->instructions, normaliser->instructions.count + count))
|
||||||
|
return VKD3D_ERROR_OUT_OF_MEMORY;
|
||||||
|
end = normaliser->instructions.count;
|
||||||
|
normaliser->instructions.count += count;
|
||||||
|
|
||||||
|
for (i = locations->count; i > 0; --i)
|
||||||
|
{
|
||||||
|
loc = &locations->locations[i - 1];
|
||||||
|
j = loc->index + loc->instruction_count;
|
||||||
|
memmove(&normaliser->instructions.elements[j + count], &normaliser->instructions.elements[j],
|
||||||
|
(end - j) * sizeof(*normaliser->instructions.elements));
|
||||||
|
end = j;
|
||||||
|
count -= (loc->instance_count - 1) * loc->instruction_count;
|
||||||
|
loc->index += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0, count = 0; i < locations->count; ++i)
|
||||||
|
{
|
||||||
|
loc = &locations->locations[i];
|
||||||
|
/* Make a copy of the non-dcl instructions for each instance. */
|
||||||
|
for (j = 1; j < loc->instance_count; ++j)
|
||||||
|
{
|
||||||
|
for (k = 0; k < loc->instruction_count; ++k)
|
||||||
|
{
|
||||||
|
if (!shader_instruction_array_clone_instruction(&normaliser->instructions,
|
||||||
|
loc->index + loc->instruction_count * j + k, loc->index + k))
|
||||||
|
return VKD3D_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Replace each reference to the instance id with a constant instance id. */
|
||||||
|
for (j = 0; j < loc->instance_count; ++j)
|
||||||
|
{
|
||||||
|
for (k = 0; k < loc->instruction_count; ++k)
|
||||||
|
shader_instruction_eliminate_phase_instance_id(
|
||||||
|
&normaliser->instructions.elements[loc->index + loc->instruction_count * j + k], j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return VKD3D_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void shader_instruction_init(struct vkd3d_shader_instruction *ins, enum vkd3d_shader_opcode handler_idx)
|
||||||
|
{
|
||||||
|
memset(ins, 0, sizeof(*ins));
|
||||||
|
ins->handler_idx = handler_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void shader_normaliser_init(struct vkd3d_shader_normaliser *normaliser,
|
||||||
|
struct vkd3d_shader_instruction_array *instructions)
|
||||||
|
{
|
||||||
|
memset(normaliser, 0, sizeof(*normaliser));
|
||||||
|
normaliser->phase = VKD3DSIH_INVALID;
|
||||||
|
normaliser->instructions = *instructions;
|
||||||
|
memset(instructions, 0, sizeof(*instructions));
|
||||||
|
}
|
||||||
|
|
||||||
|
enum vkd3d_result shader_normaliser_flatten_hull_shader_phases(struct vkd3d_shader_normaliser *normaliser)
|
||||||
|
{
|
||||||
|
struct vkd3d_shader_instruction_array *instructions = &normaliser->instructions;
|
||||||
|
struct shader_phase_location_array locations;
|
||||||
|
enum vkd3d_result result = VKD3D_OK;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0, locations.count = 0; i < instructions->count; ++i)
|
||||||
|
shader_normaliser_eliminate_phase_related_dcls(normaliser, i, &locations);
|
||||||
|
|
||||||
|
if ((result = shader_normaliser_flatten_phases(normaliser, &locations)) < 0)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
if (normaliser->phase != VKD3DSIH_INVALID)
|
||||||
|
{
|
||||||
|
if (normaliser->temp_dcl_idx)
|
||||||
|
instructions->elements[normaliser->temp_dcl_idx].declaration.count = normaliser->max_temp_count;
|
||||||
|
|
||||||
|
if (!shader_instruction_array_reserve(&normaliser->instructions, normaliser->instructions.count + 1))
|
||||||
|
return VKD3D_ERROR_OUT_OF_MEMORY;
|
||||||
|
shader_instruction_init(&instructions->elements[instructions->count++], VKD3DSIH_RET);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void shader_normaliser_destroy(struct vkd3d_shader_normaliser *normaliser)
|
||||||
|
{
|
||||||
|
shader_instruction_array_destroy(&normaliser->instructions);
|
||||||
|
}
|
@ -2199,9 +2199,7 @@ struct vkd3d_shader_phase
|
|||||||
{
|
{
|
||||||
enum vkd3d_shader_opcode type;
|
enum vkd3d_shader_opcode type;
|
||||||
unsigned int idx;
|
unsigned int idx;
|
||||||
unsigned int instance_count;
|
|
||||||
uint32_t function_id;
|
uint32_t function_id;
|
||||||
uint32_t instance_id;
|
|
||||||
size_t function_location;
|
size_t function_location;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2887,12 +2885,6 @@ static bool spirv_compiler_get_register_name(char *buffer, unsigned int buffer_s
|
|||||||
case VKD3DSPR_DEPTHOUTLE:
|
case VKD3DSPR_DEPTHOUTLE:
|
||||||
snprintf(buffer, buffer_size, "oDepth");
|
snprintf(buffer, buffer_size, "oDepth");
|
||||||
break;
|
break;
|
||||||
case VKD3DSPR_FORKINSTID:
|
|
||||||
snprintf(buffer, buffer_size, "vForkInstanceId");
|
|
||||||
break;
|
|
||||||
case VKD3DSPR_JOININSTID:
|
|
||||||
snprintf(buffer, buffer_size, "vJoinInstanceId");
|
|
||||||
break;
|
|
||||||
case VKD3DSPR_GSINSTID:
|
case VKD3DSPR_GSINSTID:
|
||||||
snprintf(buffer, buffer_size, "vGSInstanceID");
|
snprintf(buffer, buffer_size, "vGSInstanceID");
|
||||||
break;
|
break;
|
||||||
@ -4333,29 +4325,15 @@ static void spirv_compiler_begin_shader_phase(struct spirv_compiler *compiler,
|
|||||||
{
|
{
|
||||||
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
|
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
|
||||||
uint32_t void_id, function_type_id;
|
uint32_t void_id, function_type_id;
|
||||||
unsigned int param_count;
|
|
||||||
uint32_t param_type_id;
|
uint32_t param_type_id;
|
||||||
|
|
||||||
if (phase->instance_count)
|
|
||||||
{
|
|
||||||
param_type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, 1);
|
|
||||||
param_count = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
param_count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
phase->function_id = vkd3d_spirv_alloc_id(builder);
|
phase->function_id = vkd3d_spirv_alloc_id(builder);
|
||||||
|
|
||||||
void_id = vkd3d_spirv_get_op_type_void(builder);
|
void_id = vkd3d_spirv_get_op_type_void(builder);
|
||||||
function_type_id = vkd3d_spirv_get_op_type_function(builder, void_id, ¶m_type_id, param_count);
|
function_type_id = vkd3d_spirv_get_op_type_function(builder, void_id, ¶m_type_id, 0);
|
||||||
vkd3d_spirv_build_op_function(builder, void_id, phase->function_id,
|
vkd3d_spirv_build_op_function(builder, void_id, phase->function_id,
|
||||||
SpvFunctionControlMaskNone, function_type_id);
|
SpvFunctionControlMaskNone, function_type_id);
|
||||||
|
|
||||||
if (phase->instance_count)
|
|
||||||
phase->instance_id = vkd3d_spirv_build_op_function_parameter(builder, param_type_id);
|
|
||||||
|
|
||||||
vkd3d_spirv_build_op_label(builder, vkd3d_spirv_alloc_id(builder));
|
vkd3d_spirv_build_op_label(builder, vkd3d_spirv_alloc_id(builder));
|
||||||
phase->function_location = vkd3d_spirv_stream_current_location(&builder->function_stream);
|
phase->function_location = vkd3d_spirv_stream_current_location(&builder->function_stream);
|
||||||
|
|
||||||
@ -4772,10 +4750,7 @@ static void spirv_compiler_emit_input_register(struct spirv_compiler *compiler,
|
|||||||
static void spirv_compiler_emit_shader_phase_input(struct spirv_compiler *compiler,
|
static void spirv_compiler_emit_shader_phase_input(struct spirv_compiler *compiler,
|
||||||
const struct vkd3d_shader_phase *phase, const struct vkd3d_shader_dst_param *dst)
|
const struct vkd3d_shader_phase *phase, const struct vkd3d_shader_dst_param *dst)
|
||||||
{
|
{
|
||||||
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
|
|
||||||
const struct vkd3d_shader_register *reg = &dst->reg;
|
const struct vkd3d_shader_register *reg = &dst->reg;
|
||||||
struct vkd3d_symbol reg_symbol;
|
|
||||||
uint32_t val_id;
|
|
||||||
|
|
||||||
switch (reg->type)
|
switch (reg->type)
|
||||||
{
|
{
|
||||||
@ -4787,10 +4762,6 @@ static void spirv_compiler_emit_shader_phase_input(struct spirv_compiler *compil
|
|||||||
case VKD3DSPR_PRIMID:
|
case VKD3DSPR_PRIMID:
|
||||||
spirv_compiler_emit_input_register(compiler, dst);
|
spirv_compiler_emit_input_register(compiler, dst);
|
||||||
return;
|
return;
|
||||||
case VKD3DSPR_FORKINSTID:
|
|
||||||
case VKD3DSPR_JOININSTID:
|
|
||||||
val_id = phase->instance_id;
|
|
||||||
break;
|
|
||||||
case VKD3DSPR_OUTPOINTID: /* Emitted in spirv_compiler_emit_initial_declarations(). */
|
case VKD3DSPR_OUTPOINTID: /* Emitted in spirv_compiler_emit_initial_declarations(). */
|
||||||
case VKD3DSPR_OUTCONTROLPOINT: /* See spirv_compiler_leave_shader_phase(). */
|
case VKD3DSPR_OUTCONTROLPOINT: /* See spirv_compiler_leave_shader_phase(). */
|
||||||
return;
|
return;
|
||||||
@ -4798,13 +4769,6 @@ static void spirv_compiler_emit_shader_phase_input(struct spirv_compiler *compil
|
|||||||
FIXME("Unhandled shader phase input register %#x.\n", reg->type);
|
FIXME("Unhandled shader phase input register %#x.\n", reg->type);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
vkd3d_symbol_make_register(®_symbol, reg);
|
|
||||||
vkd3d_symbol_set_register_info(®_symbol, val_id,
|
|
||||||
SpvStorageClassMax /* Intermediate value */,
|
|
||||||
VKD3D_SHADER_COMPONENT_UINT, VKD3DSP_WRITEMASK_0);
|
|
||||||
spirv_compiler_put_symbol(compiler, ®_symbol);
|
|
||||||
spirv_compiler_emit_register_debug_name(builder, val_id, reg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int spirv_compiler_get_output_variable_index(
|
static unsigned int spirv_compiler_get_output_variable_index(
|
||||||
@ -6560,20 +6524,6 @@ static void spirv_compiler_leave_shader_phase(struct spirv_compiler *compiler,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (phase->instance_count)
|
|
||||||
{
|
|
||||||
memset(®, 0, sizeof(reg));
|
|
||||||
reg.type = phase->type == VKD3DSIH_HS_FORK_PHASE ? VKD3DSPR_FORKINSTID : VKD3DSPR_JOININSTID;
|
|
||||||
reg.idx[0].offset = ~0u;
|
|
||||||
reg.idx[1].offset = ~0u;
|
|
||||||
vkd3d_symbol_make_register(®_symbol, ®);
|
|
||||||
if ((entry = rb_get(&compiler->symbol_table, ®_symbol)))
|
|
||||||
{
|
|
||||||
rb_remove(&compiler->symbol_table, entry);
|
|
||||||
vkd3d_symbol_free(entry, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void spirv_compiler_enter_shader_phase(struct spirv_compiler *compiler,
|
static void spirv_compiler_enter_shader_phase(struct spirv_compiler *compiler,
|
||||||
@ -6592,34 +6542,12 @@ static void spirv_compiler_enter_shader_phase(struct spirv_compiler *compiler,
|
|||||||
|
|
||||||
phase->type = instruction->handler_idx;
|
phase->type = instruction->handler_idx;
|
||||||
phase->idx = compiler->shader_phase_count;
|
phase->idx = compiler->shader_phase_count;
|
||||||
phase->instance_count = 0;
|
|
||||||
phase->function_id = 0;
|
phase->function_id = 0;
|
||||||
phase->instance_id = 0;
|
|
||||||
phase->function_location = 0;
|
phase->function_location = 0;
|
||||||
|
|
||||||
++compiler->shader_phase_count;
|
++compiler->shader_phase_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int spirv_compiler_emit_shader_phase_instance_count(struct spirv_compiler *compiler,
|
|
||||||
const struct vkd3d_shader_instruction *instruction)
|
|
||||||
{
|
|
||||||
struct vkd3d_shader_phase *phase = &compiler->shader_phases[compiler->shader_phase_count - 1];
|
|
||||||
|
|
||||||
if (!compiler->shader_phase_count
|
|
||||||
|| (phase->type != VKD3DSIH_HS_FORK_PHASE && phase->type != VKD3DSIH_HS_JOIN_PHASE)
|
|
||||||
|| phase->function_id)
|
|
||||||
{
|
|
||||||
WARN("Unexpected dcl_hs_{fork,join}_phase_instance_count instruction.\n");
|
|
||||||
return VKD3D_ERROR_INVALID_SHADER;
|
|
||||||
}
|
|
||||||
|
|
||||||
phase->instance_count = instruction->declaration.count;
|
|
||||||
|
|
||||||
spirv_compiler_begin_shader_phase(compiler, phase);
|
|
||||||
|
|
||||||
return VKD3D_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct vkd3d_shader_phase *spirv_compiler_get_control_point_phase(
|
static const struct vkd3d_shader_phase *spirv_compiler_get_control_point_phase(
|
||||||
struct spirv_compiler *compiler)
|
struct spirv_compiler *compiler)
|
||||||
{
|
{
|
||||||
@ -6851,12 +6779,27 @@ static void spirv_compiler_emit_shader_epilogue_invocation(struct spirv_compiler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct vkd3d_shader_phase *spirv_compiler_get_fork_or_join_phase(
|
||||||
|
struct spirv_compiler *compiler)
|
||||||
|
{
|
||||||
|
const struct vkd3d_shader_phase *phase;
|
||||||
|
|
||||||
|
assert(compiler->shader_phase_count);
|
||||||
|
|
||||||
|
phase = &compiler->shader_phases[0];
|
||||||
|
if (is_control_point_phase(phase))
|
||||||
|
{
|
||||||
|
assert(compiler->shader_phase_count > 1);
|
||||||
|
phase = &compiler->shader_phases[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return phase;
|
||||||
|
}
|
||||||
|
|
||||||
static void spirv_compiler_emit_hull_shader_main(struct spirv_compiler *compiler)
|
static void spirv_compiler_emit_hull_shader_main(struct spirv_compiler *compiler)
|
||||||
{
|
{
|
||||||
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
|
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
|
||||||
const struct vkd3d_shader_phase *control_point_phase, *phase;
|
const struct vkd3d_shader_phase *control_point_phase;
|
||||||
uint32_t phase_instance_id;
|
|
||||||
unsigned int i, j;
|
|
||||||
uint32_t void_id;
|
uint32_t void_id;
|
||||||
|
|
||||||
vkd3d_spirv_builder_begin_main_function(builder);
|
vkd3d_spirv_builder_begin_main_function(builder);
|
||||||
@ -6873,26 +6816,11 @@ static void spirv_compiler_emit_hull_shader_main(struct spirv_compiler *compiler
|
|||||||
if (compiler->use_vocp)
|
if (compiler->use_vocp)
|
||||||
spirv_compiler_emit_hull_shader_barrier(compiler);
|
spirv_compiler_emit_hull_shader_barrier(compiler);
|
||||||
|
|
||||||
for (i = 0; i < compiler->shader_phase_count; ++i)
|
/* TODO: only call the patch constant function for invocation 0. The simplest way
|
||||||
{
|
* is to avoid use of private variables there, otherwise we would need a separate
|
||||||
phase = &compiler->shader_phases[i];
|
* patch constant epilogue also only called from invocation 0. */
|
||||||
if (is_control_point_phase(phase))
|
vkd3d_spirv_build_op_function_call(builder, void_id, spirv_compiler_get_fork_or_join_phase(compiler)->function_id,
|
||||||
continue;
|
NULL, 0);
|
||||||
|
|
||||||
if (phase->instance_count)
|
|
||||||
{
|
|
||||||
for (j = 0; j < phase->instance_count; ++j)
|
|
||||||
{
|
|
||||||
phase_instance_id = spirv_compiler_get_constant_uint(compiler, j);
|
|
||||||
vkd3d_spirv_build_op_function_call(builder,
|
|
||||||
void_id, phase->function_id, &phase_instance_id, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
vkd3d_spirv_build_op_function_call(builder, void_id, phase->function_id, NULL, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spirv_compiler_emit_shader_epilogue_invocation(compiler);
|
spirv_compiler_emit_shader_epilogue_invocation(compiler);
|
||||||
vkd3d_spirv_build_op_return(builder);
|
vkd3d_spirv_build_op_return(builder);
|
||||||
@ -9699,10 +9627,6 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler,
|
|||||||
case VKD3DSIH_DCL_THREAD_GROUP:
|
case VKD3DSIH_DCL_THREAD_GROUP:
|
||||||
spirv_compiler_emit_dcl_thread_group(compiler, instruction);
|
spirv_compiler_emit_dcl_thread_group(compiler, instruction);
|
||||||
break;
|
break;
|
||||||
case VKD3DSIH_DCL_HS_FORK_PHASE_INSTANCE_COUNT:
|
|
||||||
case VKD3DSIH_DCL_HS_JOIN_PHASE_INSTANCE_COUNT:
|
|
||||||
ret = spirv_compiler_emit_shader_phase_instance_count(compiler, instruction);
|
|
||||||
break;
|
|
||||||
case VKD3DSIH_HS_CONTROL_POINT_PHASE:
|
case VKD3DSIH_HS_CONTROL_POINT_PHASE:
|
||||||
case VKD3DSIH_HS_FORK_PHASE:
|
case VKD3DSIH_HS_FORK_PHASE:
|
||||||
case VKD3DSIH_HS_JOIN_PHASE:
|
case VKD3DSIH_HS_JOIN_PHASE:
|
||||||
@ -9951,22 +9875,37 @@ int spirv_compiler_generate_spirv(struct spirv_compiler *compiler,
|
|||||||
const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_parser *parser,
|
const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_parser *parser,
|
||||||
struct vkd3d_shader_code *spirv)
|
struct vkd3d_shader_code *spirv)
|
||||||
{
|
{
|
||||||
const struct vkd3d_shader_instruction_array *instructions = &parser->instructions;
|
|
||||||
const struct vkd3d_shader_spirv_target_info *info = compiler->spirv_target_info;
|
const struct vkd3d_shader_spirv_target_info *info = compiler->spirv_target_info;
|
||||||
|
struct vkd3d_shader_instruction_array *instructions = &parser->instructions;
|
||||||
const struct vkd3d_shader_spirv_domain_shader_target_info *ds_info;
|
const struct vkd3d_shader_spirv_domain_shader_target_info *ds_info;
|
||||||
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
|
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
|
||||||
|
struct vkd3d_shader_normaliser normaliser;
|
||||||
const struct vkd3d_shader_phase *phase;
|
const struct vkd3d_shader_phase *phase;
|
||||||
enum vkd3d_result result = VKD3D_OK;
|
enum vkd3d_result result = VKD3D_OK;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
compiler->location.column = 0;
|
compiler->location.column = 0;
|
||||||
for (i = 0; i < instructions->count; ++i)
|
compiler->location.line = 1;
|
||||||
|
|
||||||
|
if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL)
|
||||||
|
{
|
||||||
|
shader_normaliser_init(&normaliser, instructions);
|
||||||
|
result = shader_normaliser_flatten_hull_shader_phases(&normaliser);
|
||||||
|
instructions = &normaliser.instructions;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < instructions->count && result >= 0; ++i)
|
||||||
{
|
{
|
||||||
compiler->location.line = i + 1;
|
compiler->location.line = i + 1;
|
||||||
if ((result = spirv_compiler_handle_instruction(compiler, &instructions->elements[i])) < 0)
|
result = spirv_compiler_handle_instruction(compiler, &instructions->elements[i]);
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (instructions == &normaliser.instructions)
|
||||||
|
shader_normaliser_destroy(&normaliser);
|
||||||
|
|
||||||
|
if (result < 0)
|
||||||
|
return result;
|
||||||
|
|
||||||
if ((phase = spirv_compiler_get_current_shader_phase(compiler)))
|
if ((phase = spirv_compiler_get_current_shader_phase(compiler)))
|
||||||
spirv_compiler_leave_shader_phase(compiler, phase);
|
spirv_compiler_leave_shader_phase(compiler, phase);
|
||||||
else
|
else
|
||||||
@ -10036,7 +9975,6 @@ void spirv_compiler_destroy(struct spirv_compiler *compiler)
|
|||||||
|
|
||||||
rb_destroy(&compiler->symbol_table, vkd3d_symbol_free, NULL);
|
rb_destroy(&compiler->symbol_table, vkd3d_symbol_free, NULL);
|
||||||
|
|
||||||
vkd3d_free(compiler->shader_phases);
|
|
||||||
vkd3d_free(compiler->spec_constants);
|
vkd3d_free(compiler->spec_constants);
|
||||||
|
|
||||||
vkd3d_string_buffer_cache_cleanup(&compiler->string_buffers);
|
vkd3d_string_buffer_cache_cleanup(&compiler->string_buffers);
|
||||||
|
@ -1644,6 +1644,84 @@ bool shader_instruction_array_add_icb(struct vkd3d_shader_instruction_array *ins
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct vkd3d_shader_src_param *shader_instruction_array_clone_src_params(
|
||||||
|
struct vkd3d_shader_instruction_array *instructions, const struct vkd3d_shader_src_param *params,
|
||||||
|
unsigned int count);
|
||||||
|
|
||||||
|
static bool shader_register_clone_relative_addresses(struct vkd3d_shader_register *reg,
|
||||||
|
struct vkd3d_shader_instruction_array *instructions)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(reg->idx) && reg->idx[i].offset != ~0u; ++i)
|
||||||
|
{
|
||||||
|
if (!reg->idx[i].rel_addr)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!(reg->idx[i].rel_addr = shader_instruction_array_clone_src_params(instructions, reg->idx[i].rel_addr, 1)))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct vkd3d_shader_dst_param *shader_instruction_array_clone_dst_params(
|
||||||
|
struct vkd3d_shader_instruction_array *instructions, const struct vkd3d_shader_dst_param *params,
|
||||||
|
unsigned int count)
|
||||||
|
{
|
||||||
|
struct vkd3d_shader_dst_param *dst_params;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
if (!(dst_params = shader_dst_param_allocator_get(&instructions->dst_params, count)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memcpy(dst_params, params, count * sizeof(*params));
|
||||||
|
for (i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
if (!shader_register_clone_relative_addresses(&dst_params[i].reg, instructions))
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst_params;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct vkd3d_shader_src_param *shader_instruction_array_clone_src_params(
|
||||||
|
struct vkd3d_shader_instruction_array *instructions, const struct vkd3d_shader_src_param *params,
|
||||||
|
unsigned int count)
|
||||||
|
{
|
||||||
|
struct vkd3d_shader_src_param *src_params;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
if (!(src_params = shader_src_param_allocator_get(&instructions->src_params, count)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memcpy(src_params, params, count * sizeof(*params));
|
||||||
|
for (i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
if (!shader_register_clone_relative_addresses(&src_params[i].reg, instructions))
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return src_params;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NOTE: Immediate constant buffers are not cloned, so the source must not be destroyed while the
|
||||||
|
* destination is in use. This seems like a reasonable requirement given how this is currently used. */
|
||||||
|
bool shader_instruction_array_clone_instruction(struct vkd3d_shader_instruction_array *instructions,
|
||||||
|
unsigned int dst, unsigned int src)
|
||||||
|
{
|
||||||
|
struct vkd3d_shader_instruction *ins = &instructions->elements[dst];
|
||||||
|
|
||||||
|
*ins = instructions->elements[src];
|
||||||
|
|
||||||
|
if (ins->dst_count && ins->dst && !(ins->dst = shader_instruction_array_clone_dst_params(instructions,
|
||||||
|
ins->dst, ins->dst_count)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return !ins->src_count || !!(ins->src = shader_instruction_array_clone_src_params(instructions,
|
||||||
|
ins->src, ins->src_count));
|
||||||
|
}
|
||||||
|
|
||||||
void shader_instruction_array_destroy(struct vkd3d_shader_instruction_array *instructions)
|
void shader_instruction_array_destroy(struct vkd3d_shader_instruction_array *instructions)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
@ -981,6 +981,8 @@ bool shader_instruction_array_init(struct vkd3d_shader_instruction_array *instru
|
|||||||
bool shader_instruction_array_reserve(struct vkd3d_shader_instruction_array *instructions, unsigned int reserve);
|
bool shader_instruction_array_reserve(struct vkd3d_shader_instruction_array *instructions, unsigned int reserve);
|
||||||
bool shader_instruction_array_add_icb(struct vkd3d_shader_instruction_array *instructions,
|
bool shader_instruction_array_add_icb(struct vkd3d_shader_instruction_array *instructions,
|
||||||
struct vkd3d_shader_immediate_constant_buffer *icb);
|
struct vkd3d_shader_immediate_constant_buffer *icb);
|
||||||
|
bool shader_instruction_array_clone_instruction(struct vkd3d_shader_instruction_array *instructions,
|
||||||
|
unsigned int dst, unsigned int src);
|
||||||
void shader_instruction_array_destroy(struct vkd3d_shader_instruction_array *instructions);
|
void shader_instruction_array_destroy(struct vkd3d_shader_instruction_array *instructions);
|
||||||
|
|
||||||
struct vkd3d_shader_parser
|
struct vkd3d_shader_parser
|
||||||
@ -1323,4 +1325,21 @@ void dxbc_writer_add_section(struct dxbc_writer *dxbc, uint32_t tag, const void
|
|||||||
void dxbc_writer_init(struct dxbc_writer *dxbc);
|
void dxbc_writer_init(struct dxbc_writer *dxbc);
|
||||||
int dxbc_writer_write(struct dxbc_writer *dxbc, struct vkd3d_shader_code *code);
|
int dxbc_writer_write(struct dxbc_writer *dxbc, struct vkd3d_shader_code *code);
|
||||||
|
|
||||||
|
struct vkd3d_shader_normaliser
|
||||||
|
{
|
||||||
|
struct vkd3d_shader_instruction_array instructions;
|
||||||
|
|
||||||
|
unsigned int max_temp_count;
|
||||||
|
unsigned int temp_dcl_idx;
|
||||||
|
|
||||||
|
unsigned int instance_count;
|
||||||
|
unsigned int phase_body_idx;
|
||||||
|
enum vkd3d_shader_opcode phase;
|
||||||
|
};
|
||||||
|
|
||||||
|
void shader_normaliser_init(struct vkd3d_shader_normaliser *normaliser,
|
||||||
|
struct vkd3d_shader_instruction_array *instructions);
|
||||||
|
enum vkd3d_result shader_normaliser_flatten_hull_shader_phases(struct vkd3d_shader_normaliser *normaliser);
|
||||||
|
void shader_normaliser_destroy(struct vkd3d_shader_normaliser *normaliser);
|
||||||
|
|
||||||
#endif /* __VKD3D_SHADER_PRIVATE_H */
|
#endif /* __VKD3D_SHADER_PRIVATE_H */
|
||||||
|
Reference in New Issue
Block a user