Skip to content
Snippets Groups Projects
spirv.c 390 KiB
Newer Older
        {-1.0 / 16.0, -3.0 / 16.0},
        {-3.0 / 16.0,  2.0 / 16.0},
        { 4.0 / 16.0, -1.0 / 16.0},
        {-5.0 / 16.0, -2.0 / 16.0},
        { 2.0 / 16.0,  5.0 / 16.0},
        { 5.0 / 16.0,  3.0 / 16.0},
        { 3.0 / 16.0, -5.0 / 16.0},
        {-2.0 / 16.0,  6.0 / 16.0},
        { 0.0 / 16.0, -7.0 / 16.0},
        {-4.0 / 16.0, -6.0 / 16.0},
        {-6.0 / 16.0,  4.0 / 16.0},
        {-8.0 / 16.0,  0.0 / 16.0},
        { 7.0 / 16.0, -4.0 / 16.0},
        { 6.0 / 16.0,  7.0 / 16.0},
        {-7.0 / 16.0, -8.0 / 16.0},
    };
    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
    uint32_t constituents[ARRAY_SIZE(standard_sample_positions)];
    const struct vkd3d_shader_dst_param *dst = instruction->dst;
    uint32_t array_type_id, length_id, index_id, id;
    uint32_t sample_count_id, sample_index_id;
    uint32_t type_id, bool_id, ptr_type_id;
    unsigned int i;

    sample_count_id = spirv_compiler_emit_query_sample_count(compiler, &instruction->src[0]);
    sample_index_id = spirv_compiler_emit_load_src(compiler, &instruction->src[1], VKD3DSP_WRITEMASK_0);
    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, 1);
    index_id = vkd3d_spirv_build_op_iadd(builder, type_id, sample_count_id, sample_index_id);
    index_id = vkd3d_spirv_build_op_isub(builder,
            type_id, index_id, spirv_compiler_get_constant_uint(compiler, 1));

    /* Validate sample index. */
    bool_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_BOOL, 1);
    id = vkd3d_spirv_build_op_logical_and(builder, bool_id,
            vkd3d_spirv_build_op_uless_than(builder, bool_id, sample_index_id, sample_count_id),
            vkd3d_spirv_build_op_uless_than_equal(builder,
                    bool_id, sample_index_id, spirv_compiler_get_constant_uint(compiler, 16)));
    index_id = vkd3d_spirv_build_op_select(builder, type_id,
            id, index_id, spirv_compiler_get_constant_uint(compiler, 0));
    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT, 2);
    if (!(id = compiler->sample_positions_id))
    {
        length_id = spirv_compiler_get_constant_uint(compiler, ARRAY_SIZE(standard_sample_positions));
        array_type_id = vkd3d_spirv_get_op_type_array(builder, type_id, length_id);

        for (i = 0; i < ARRAY_SIZE(standard_sample_positions); ++ i)
        {
            constituents[i] = spirv_compiler_get_constant(compiler,
                    VKD3D_SHADER_COMPONENT_FLOAT, 2, (const uint32_t *)standard_sample_positions[i]);
        }

        id = vkd3d_spirv_build_op_constant_composite(builder, array_type_id, constituents, ARRAY_SIZE(constituents));
        ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassPrivate, array_type_id);
        id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream, ptr_type_id, SpvStorageClassPrivate, id);
        vkd3d_spirv_build_op_name(builder, id, "sample_pos");
        compiler->sample_positions_id = id;
    }

    ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassPrivate, type_id);
    id = vkd3d_spirv_build_op_in_bounds_access_chain1(builder, ptr_type_id, id, index_id);
    id = vkd3d_spirv_build_op_load(builder, type_id, id, SpvMemoryAccessMaskNone);

    id = spirv_compiler_emit_swizzle(compiler, id, VKD3DSP_WRITEMASK_0 | VKD3DSP_WRITEMASK_1,
            VKD3D_SHADER_COMPONENT_FLOAT, instruction->src[0].swizzle, dst->write_mask);
    spirv_compiler_emit_store_dst(compiler, dst, id);
static void spirv_compiler_emit_eval_attrib(struct spirv_compiler *compiler,
        const struct vkd3d_shader_instruction *instruction)
{
    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
    const struct vkd3d_shader_dst_param *dst = instruction->dst;
    const struct vkd3d_shader_src_param *src = instruction->src;
    const struct vkd3d_shader_register *input = &src[0].reg;
    uint32_t instr_set_id, type_id, val_id, src_ids[2];
    struct vkd3d_shader_register_info register_info;
    unsigned int src_count = 0;
    enum GLSLstd450 op;
    if (!spirv_compiler_get_register_info(compiler, input, &register_info))
        return;

    if (register_info.storage_class != SpvStorageClassInput)
    {
        FIXME("Not supported for storage class %#x.\n", register_info.storage_class);
        return;
    }

    vkd3d_spirv_enable_capability(builder, SpvCapabilityInterpolationFunction);

    src_ids[src_count++] = register_info.id;

    if (instruction->handler_idx == VKD3DSIH_EVAL_CENTROID)
    {
        op = GLSLstd450InterpolateAtCentroid;
    }
    else
    {
        assert(instruction->handler_idx == VKD3DSIH_EVAL_SAMPLE_INDEX);
        op = GLSLstd450InterpolateAtSample;
        src_ids[src_count++] = spirv_compiler_emit_load_src(compiler, &src[1], VKD3DSP_WRITEMASK_0);
    type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_FLOAT,
            vsir_write_mask_component_count(register_info.write_mask));

    instr_set_id = vkd3d_spirv_get_glsl_std450_instr_set(builder);
    val_id = vkd3d_spirv_build_op_ext_inst(builder, type_id, instr_set_id, op, src_ids, src_count);
    val_id = spirv_compiler_emit_swizzle(compiler, val_id, register_info.write_mask,
            VKD3D_SHADER_COMPONENT_FLOAT, src[0].swizzle, dst->write_mask);
    spirv_compiler_emit_store_dst(compiler, dst, val_id);
/* From the Vulkan spec:
 *
 *   "Scope for execution must be limited to: * Workgroup * Subgroup"
 *
 *   "Scope for memory must be limited to: * Device * Workgroup * Invocation"
 */
static void spirv_compiler_emit_sync(struct spirv_compiler *compiler,
        const struct vkd3d_shader_instruction *instruction)
{
    unsigned int memory_semantics = SpvMemorySemanticsAcquireReleaseMask;
    SpvScope execution_scope = SpvScopeMax;
    SpvScope memory_scope = SpvScopeDevice;
    uint32_t flags = instruction->flags;

    if (flags & VKD3DSSF_GROUP_SHARED_MEMORY)
    {
        memory_scope = SpvScopeWorkgroup;
        memory_semantics |= SpvMemorySemanticsWorkgroupMemoryMask;
        flags &= ~VKD3DSSF_GROUP_SHARED_MEMORY;
    }

    if (flags & VKD3DSSF_THREAD_GROUP)
    {
        execution_scope = SpvScopeWorkgroup;
        flags &= ~VKD3DSSF_THREAD_GROUP;
    }

    if (flags & VKD3DSSF_GLOBAL_UAV)
    {
        memory_scope = SpvScopeDevice;
        memory_semantics |= SpvMemorySemanticsImageMemoryMask;
        flags &= ~VKD3DSSF_GLOBAL_UAV;
    }

    if (flags)
    {
        FIXME("Unhandled sync flags %#x.\n", flags);
        memory_scope = SpvScopeDevice;
        execution_scope = SpvScopeWorkgroup;
        memory_semantics |= SpvMemorySemanticsUniformMemoryMask
                | SpvMemorySemanticsSubgroupMemoryMask
                | SpvMemorySemanticsWorkgroupMemoryMask
                | SpvMemorySemanticsCrossWorkgroupMemoryMask
                | SpvMemorySemanticsAtomicCounterMemoryMask
                | SpvMemorySemanticsImageMemoryMask;
    }

    spirv_compiler_emit_barrier(compiler, execution_scope, memory_scope, memory_semantics);
static void spirv_compiler_emit_emit_stream(struct spirv_compiler *compiler,
        const struct vkd3d_shader_instruction *instruction)
{
    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
    unsigned int stream_idx;

    if (instruction->handler_idx == VKD3DSIH_EMIT_STREAM)
        stream_idx = instruction->src[0].reg.idx[0].offset;
    else
        stream_idx = 0;

    if (stream_idx)
    {
        FIXME("Multiple streams are not supported yet.\n");
        return;
    }

    spirv_compiler_emit_shader_epilogue_invocation(compiler);
    vkd3d_spirv_build_op_emit_vertex(builder);
}

static void spirv_compiler_emit_cut_stream(struct spirv_compiler *compiler,
        const struct vkd3d_shader_instruction *instruction)
{
    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
    unsigned int stream_idx;

    if (instruction->handler_idx == VKD3DSIH_CUT_STREAM)
        stream_idx = instruction->src[0].reg.idx[0].offset;
    else
        stream_idx = 0;

    if (stream_idx)
    {
        FIXME("Multiple streams are not supported yet.\n");
        return;
    }

    vkd3d_spirv_build_op_end_primitive(builder);
}

/* This function is called after declarations are processed. */
static void spirv_compiler_emit_main_prolog(struct spirv_compiler *compiler)
    spirv_compiler_emit_push_constant_buffers(compiler);

    if (compiler->xfb_info && compiler->xfb_info->element_count
            && compiler->shader_type != VKD3D_SHADER_TYPE_GEOMETRY)
static bool is_dcl_instruction(enum vkd3d_shader_opcode handler_idx)
    return (VKD3DSIH_DCL <= handler_idx && handler_idx <= VKD3DSIH_DCL_VERTICES_OUT)
            || handler_idx == VKD3DSIH_HS_DECLS;
static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler,
        const struct vkd3d_shader_instruction *instruction)
{
    if (!is_dcl_instruction(instruction->handler_idx) && !compiler->after_declarations_section)
    {
        compiler->after_declarations_section = true;
    switch (instruction->handler_idx)
    {
        case VKD3DSIH_DCL_GLOBAL_FLAGS:
            spirv_compiler_emit_dcl_global_flags(compiler, instruction);
        case VKD3DSIH_DCL_INDEXABLE_TEMP:
            spirv_compiler_emit_dcl_indexable_temp(compiler, instruction);
        case VKD3DSIH_DCL_IMMEDIATE_CONSTANT_BUFFER:
            spirv_compiler_emit_dcl_immediate_constant_buffer(compiler, instruction);
        case VKD3DSIH_DCL_TGSM_RAW:
            spirv_compiler_emit_dcl_tgsm_raw(compiler, instruction);
        case VKD3DSIH_DCL_TGSM_STRUCTURED:
            spirv_compiler_emit_dcl_tgsm_structured(compiler, instruction);
        case VKD3DSIH_DCL_INPUT:
            spirv_compiler_emit_dcl_input(compiler, instruction);
        case VKD3DSIH_DCL_OUTPUT:
            spirv_compiler_emit_dcl_output(compiler, instruction);
            spirv_compiler_emit_dcl_stream(compiler, instruction);
        case VKD3DSIH_DCL_VERTICES_OUT:
            spirv_compiler_emit_output_vertex_count(compiler, instruction);
        case VKD3DSIH_DCL_INPUT_PRIMITIVE:
            spirv_compiler_emit_dcl_input_primitive(compiler, instruction);
        case VKD3DSIH_DCL_OUTPUT_TOPOLOGY:
            spirv_compiler_emit_dcl_output_topology(compiler, instruction);
        case VKD3DSIH_DCL_GS_INSTANCES:
            spirv_compiler_emit_dcl_gs_instances(compiler, instruction);
        case VKD3DSIH_DCL_OUTPUT_CONTROL_POINT_COUNT:
            spirv_compiler_emit_output_vertex_count(compiler, instruction);
        case VKD3DSIH_DCL_TESSELLATOR_DOMAIN:
            spirv_compiler_emit_dcl_tessellator_domain(compiler, instruction);
        case VKD3DSIH_DCL_TESSELLATOR_OUTPUT_PRIMITIVE:
            spirv_compiler_emit_tessellator_output_primitive(compiler,
                    instruction->declaration.tessellator_output_primitive);
        case VKD3DSIH_DCL_TESSELLATOR_PARTITIONING:
            spirv_compiler_emit_tessellator_partitioning(compiler,
                    instruction->declaration.tessellator_partitioning);
        case VKD3DSIH_DCL_THREAD_GROUP:
            spirv_compiler_emit_dcl_thread_group(compiler, instruction);
        case VKD3DSIH_HS_CONTROL_POINT_PHASE:
        case VKD3DSIH_HS_FORK_PHASE:
        case VKD3DSIH_HS_JOIN_PHASE:
            spirv_compiler_enter_shader_phase(compiler, instruction);
        case VKD3DSIH_DMOV:
        case VKD3DSIH_MOV:
            spirv_compiler_emit_mov(compiler, instruction);
        case VKD3DSIH_DMOVC:
        case VKD3DSIH_MOVC:
            spirv_compiler_emit_movc(compiler, instruction);
        case VKD3DSIH_SWAPC:
            spirv_compiler_emit_swapc(compiler, instruction);
        case VKD3DSIH_ADD:
        case VKD3DSIH_AND:
        case VKD3DSIH_COUNTBITS:
        case VKD3DSIH_DADD:
        case VKD3DSIH_DDIV:
        case VKD3DSIH_DMUL:
        case VKD3DSIH_DTOF:
        case VKD3DSIH_FTOD:
        case VKD3DSIH_IADD:
        case VKD3DSIH_INEG:
        case VKD3DSIH_ISHL:
        case VKD3DSIH_ISHR:
        case VKD3DSIH_ITOD:
        case VKD3DSIH_NOT:
        case VKD3DSIH_OR:
        case VKD3DSIH_USHR:
        case VKD3DSIH_UTOD:
            ret = spirv_compiler_emit_alu_instruction(compiler, instruction);
        case VKD3DSIH_DFMA:
        case VKD3DSIH_DMAX:
        case VKD3DSIH_DMIN:
        case VKD3DSIH_EXP:
        case VKD3DSIH_FIRSTBIT_HI:
        case VKD3DSIH_FIRSTBIT_LO:
        case VKD3DSIH_FIRSTBIT_SHI:
        case VKD3DSIH_FRC:
        case VKD3DSIH_IMAX:
        case VKD3DSIH_IMIN:
        case VKD3DSIH_LOG:
        case VKD3DSIH_MAX:
        case VKD3DSIH_MIN:
        case VKD3DSIH_ROUND_NE:
        case VKD3DSIH_ROUND_NI:
        case VKD3DSIH_ROUND_PI:
        case VKD3DSIH_ROUND_Z:
        case VKD3DSIH_SQRT:
        case VKD3DSIH_UMAX:
        case VKD3DSIH_UMIN:
            spirv_compiler_emit_ext_glsl_instruction(compiler, instruction);
        case VKD3DSIH_DP4:
        case VKD3DSIH_DP3:
        case VKD3DSIH_DP2:
            spirv_compiler_emit_dot(compiler, instruction);
        case VKD3DSIH_DRCP:
        case VKD3DSIH_RCP:
            spirv_compiler_emit_rcp(compiler, instruction);
        case VKD3DSIH_SINCOS:
            spirv_compiler_emit_sincos(compiler, instruction);
        case VKD3DSIH_IMUL:
            spirv_compiler_emit_imul(compiler, instruction);
        case VKD3DSIH_IMAD:
            spirv_compiler_emit_imad(compiler, instruction);
        case VKD3DSIH_UDIV:
            spirv_compiler_emit_int_div(compiler, instruction);
        case VKD3DSIH_FTOI:
            spirv_compiler_emit_ftoi(compiler, instruction);
            break;
        case VKD3DSIH_FTOU:
            spirv_compiler_emit_ftou(compiler, instruction);
            break;
        case VKD3DSIH_DLT:
        case VKD3DSIH_DNE:
        case VKD3DSIH_EQO:
        case VKD3DSIH_EQU:
        case VKD3DSIH_GEO:
        case VKD3DSIH_GEU:
        case VKD3DSIH_IEQ:
        case VKD3DSIH_IGE:
        case VKD3DSIH_ILT:
        case VKD3DSIH_INE:
        case VKD3DSIH_LTO:
        case VKD3DSIH_LTU:
        case VKD3DSIH_NEO:
        case VKD3DSIH_NEU:
        case VKD3DSIH_UGE:
        case VKD3DSIH_ULT:
            spirv_compiler_emit_comparison_instruction(compiler, instruction);
        case VKD3DSIH_BFI:
        case VKD3DSIH_IBFE:
        case VKD3DSIH_UBFE:
            spirv_compiler_emit_bitfield_instruction(compiler, instruction);
        case VKD3DSIH_F16TOF32:
            spirv_compiler_emit_f16tof32(compiler, instruction);
        case VKD3DSIH_F32TOF16:
            spirv_compiler_emit_f32tof16(compiler, instruction);
        case VKD3DSIH_RET:
            spirv_compiler_emit_return(compiler, instruction);
        case VKD3DSIH_RETP:
            spirv_compiler_emit_retc(compiler, instruction);
            break;
        case VKD3DSIH_DISCARD:
        case VKD3DSIH_TEXKILL:
            spirv_compiler_emit_kill(compiler, instruction);
            break;
        case VKD3DSIH_LABEL:
            spirv_compiler_emit_label(compiler, instruction);
            break;
        case VKD3DSIH_BRANCH:
            spirv_compiler_emit_branch(compiler, instruction);
            break;
        case VKD3DSIH_SWITCH_MONOLITHIC:
            spirv_compiler_emit_switch(compiler, instruction);
            break;
        case VKD3DSIH_DSX:
        case VKD3DSIH_DSX_COARSE:
        case VKD3DSIH_DSX_FINE:
        case VKD3DSIH_DSY:
        case VKD3DSIH_DSY_COARSE:
        case VKD3DSIH_DSY_FINE:
            spirv_compiler_emit_deriv_instruction(compiler, instruction);
        case VKD3DSIH_LD2DMS:
            spirv_compiler_emit_ld(compiler, instruction);
            spirv_compiler_emit_lod(compiler, instruction);
        case VKD3DSIH_SAMPLE:
        case VKD3DSIH_SAMPLE_B:
        case VKD3DSIH_SAMPLE_GRAD:
        case VKD3DSIH_SAMPLE_LOD:
            spirv_compiler_emit_sample(compiler, instruction);
        case VKD3DSIH_SAMPLE_C:
        case VKD3DSIH_SAMPLE_C_LZ:
            spirv_compiler_emit_sample_c(compiler, instruction);
        case VKD3DSIH_GATHER4:
        case VKD3DSIH_GATHER4_C:
        case VKD3DSIH_GATHER4_PO:
        case VKD3DSIH_GATHER4_PO_C:
            spirv_compiler_emit_gather4(compiler, instruction);
        case VKD3DSIH_LD_RAW:
        case VKD3DSIH_LD_STRUCTURED:
            spirv_compiler_emit_ld_raw_structured(compiler, instruction);
        case VKD3DSIH_STORE_RAW:
        case VKD3DSIH_STORE_STRUCTURED:
            spirv_compiler_emit_store_raw_structured(compiler, instruction);
            break;
        case VKD3DSIH_LD_UAV_TYPED:
            spirv_compiler_emit_ld_uav_typed(compiler, instruction);
        case VKD3DSIH_STORE_UAV_TYPED:
            spirv_compiler_emit_store_uav_typed(compiler, instruction);
        case VKD3DSIH_IMM_ATOMIC_ALLOC:
        case VKD3DSIH_IMM_ATOMIC_CONSUME:
            spirv_compiler_emit_uav_counter_instruction(compiler, instruction);
        case VKD3DSIH_ATOMIC_IADD:
        case VKD3DSIH_ATOMIC_IMAX:
        case VKD3DSIH_ATOMIC_IMIN:
        case VKD3DSIH_ATOMIC_OR:
        case VKD3DSIH_ATOMIC_UMAX:
        case VKD3DSIH_ATOMIC_UMIN:
        case VKD3DSIH_ATOMIC_XOR:
        case VKD3DSIH_IMM_ATOMIC_AND:
        case VKD3DSIH_IMM_ATOMIC_CMP_EXCH:
        case VKD3DSIH_IMM_ATOMIC_EXCH:
        case VKD3DSIH_IMM_ATOMIC_IADD:
        case VKD3DSIH_IMM_ATOMIC_IMAX:
        case VKD3DSIH_IMM_ATOMIC_IMIN:
        case VKD3DSIH_IMM_ATOMIC_OR:
        case VKD3DSIH_IMM_ATOMIC_UMAX:
        case VKD3DSIH_IMM_ATOMIC_UMIN:
        case VKD3DSIH_IMM_ATOMIC_XOR:
            spirv_compiler_emit_atomic_instruction(compiler, instruction);
        case VKD3DSIH_BUFINFO:
            spirv_compiler_emit_bufinfo(compiler, instruction);
        case VKD3DSIH_RESINFO:
            spirv_compiler_emit_resinfo(compiler, instruction);
        case VKD3DSIH_SAMPLE_INFO:
            spirv_compiler_emit_sample_info(compiler, instruction);
        case VKD3DSIH_SAMPLE_POS:
            spirv_compiler_emit_sample_position(compiler, instruction);
        case VKD3DSIH_EVAL_CENTROID:
        case VKD3DSIH_EVAL_SAMPLE_INDEX:
            spirv_compiler_emit_eval_attrib(compiler, instruction);
        case VKD3DSIH_SYNC:
            spirv_compiler_emit_sync(compiler, instruction);
        case VKD3DSIH_EMIT:
        case VKD3DSIH_EMIT_STREAM:
            spirv_compiler_emit_emit_stream(compiler, instruction);
        case VKD3DSIH_CUT:
        case VKD3DSIH_CUT_STREAM:
            spirv_compiler_emit_cut_stream(compiler, instruction);
        case VKD3DSIH_DCL_HS_MAX_TESSFACTOR:
        case VKD3DSIH_DCL_INPUT_CONTROL_POINT_COUNT:
        case VKD3DSIH_DCL_INPUT_SGV:
        case VKD3DSIH_DCL_INPUT_SIV:
        case VKD3DSIH_DCL_INPUT_PS_SGV:
        case VKD3DSIH_DCL_INPUT_PS_SIV:
        case VKD3DSIH_DCL_OUTPUT_SIV:
        case VKD3DSIH_DCL_RESOURCE_RAW:
        case VKD3DSIH_DCL_RESOURCE_STRUCTURED:
        case VKD3DSIH_DCL_UAV_RAW:
        case VKD3DSIH_DCL_UAV_STRUCTURED:
        case VKD3DSIH_DCL_UAV_TYPED:
        case VKD3DSIH_NOP:
        default:
            FIXME("Unhandled instruction %#x.\n", instruction->handler_idx);
            spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_INVALID_HANDLER,
                    "Encountered invalid/unhandled instruction handler %#x.", instruction->handler_idx);
            break;
static void spirv_compiler_emit_io_declarations(struct spirv_compiler *compiler)
{
    for (unsigned int i = 0; i < compiler->input_signature.element_count; ++i)
        spirv_compiler_emit_input(compiler, VKD3DSPR_INPUT, i);

    for (unsigned int i = 0; i < compiler->output_signature.element_count; ++i)
    {
        /* PS outputs other than TARGET have dedicated registers and therefore
         * go through spirv_compiler_emit_dcl_output() for now. */
        if (compiler->shader_type == VKD3D_SHADER_TYPE_PIXEL
                && compiler->output_signature.elements[i].sysval_semantic != VKD3D_SHADER_SV_TARGET)
            continue;
        spirv_compiler_emit_output(compiler, VKD3DSPR_OUTPUT, i);
    }

    for (unsigned int i = 0; i < compiler->patch_constant_signature.element_count; ++i)
    {
        if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL)
            spirv_compiler_emit_output(compiler, VKD3DSPR_PATCHCONST, i);
        else
            spirv_compiler_emit_input(compiler, VKD3DSPR_PATCHCONST, i);
    }
}

static void spirv_compiler_emit_descriptor_declarations(struct spirv_compiler *compiler)
{
    unsigned int i;

    for (i = 0; i < compiler->scan_descriptor_info->descriptor_count; ++i)
    {
        const struct vkd3d_shader_descriptor_info1 *descriptor = &compiler->scan_descriptor_info->descriptors[i];
        struct vkd3d_shader_register_range range;

        range.first = descriptor->register_index;
        if (descriptor->count == ~0u)
            range.last = ~0u;
        else
            range.last = descriptor->register_index + descriptor->count - 1;
        range.space = descriptor->register_space;

        switch (descriptor->type)
        {
            case VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER:
                spirv_compiler_emit_sampler_declaration(compiler, &range, descriptor->register_id);
                break;

            case VKD3D_SHADER_DESCRIPTOR_TYPE_CBV:
                spirv_compiler_emit_cbv_declaration(compiler, &range, descriptor->register_id, descriptor->buffer_size);
                break;

            case VKD3D_SHADER_DESCRIPTOR_TYPE_SRV:
                spirv_compiler_emit_resource_declaration(compiler, &range, descriptor->register_id,
                        descriptor->sample_count, false, descriptor->resource_type, descriptor->resource_data_type,
                        descriptor->structure_stride / 4, descriptor->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_RAW_BUFFER);
                break;

            case VKD3D_SHADER_DESCRIPTOR_TYPE_UAV:
                spirv_compiler_emit_resource_declaration(compiler, &range, descriptor->register_id,
                        descriptor->sample_count, true, descriptor->resource_type, descriptor->resource_data_type,
                        descriptor->structure_stride / 4, descriptor->flags & VKD3D_SHADER_DESCRIPTOR_INFO_FLAG_RAW_BUFFER);
static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler,
        const struct vkd3d_shader_compile_info *compile_info, struct vkd3d_shader_parser *parser,
        struct vkd3d_shader_code *spirv)
    const struct vkd3d_shader_spirv_target_info *info = compiler->spirv_target_info;
    const struct vkd3d_shader_spirv_domain_shader_target_info *ds_info;
    struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
    struct vkd3d_shader_desc *shader_desc = &parser->shader_desc;
    enum vkd3d_result result = VKD3D_OK;
    unsigned int i;

    if (parser->shader_desc.temp_count)
        spirv_compiler_emit_temps(compiler, parser->shader_desc.temp_count);
    if (parser->shader_desc.ssa_count)
        spirv_compiler_allocate_ssa_register_ids(compiler, parser->shader_desc.ssa_count);
    spirv_compiler_emit_descriptor_declarations(compiler);

    if ((result = vkd3d_shader_normalise(parser, compile_info)) < 0)
    if (parser->shader_desc.block_count && !spirv_compiler_init_blocks(compiler, parser->shader_desc.block_count))
        return VKD3D_ERROR_OUT_OF_MEMORY;

    instructions = parser->instructions;
    memset(&parser->instructions, 0, sizeof(parser->instructions));
    compiler->input_signature = shader_desc->input_signature;
    compiler->output_signature = shader_desc->output_signature;
    compiler->patch_constant_signature = shader_desc->patch_constant_signature;
    memset(&shader_desc->input_signature, 0, sizeof(shader_desc->input_signature));
    memset(&shader_desc->output_signature, 0, sizeof(shader_desc->output_signature));
    memset(&shader_desc->patch_constant_signature, 0, sizeof(shader_desc->patch_constant_signature));
    compiler->use_vocp = parser->shader_desc.use_vocp;
    compiler->input_control_point_count = shader_desc->input_control_point_count;
    compiler->output_control_point_count = shader_desc->output_control_point_count;

    if (compiler->shader_type != VKD3D_SHADER_TYPE_HULL)
        spirv_compiler_emit_shader_signature_outputs(compiler);
    spirv_compiler_emit_io_declarations(compiler);

    for (i = 0; i < instructions.count && result >= 0; ++i)
        result = spirv_compiler_handle_instruction(compiler, &instructions.elements[i]);
    if (!is_in_default_phase(compiler))
        spirv_compiler_leave_shader_phase(compiler);
    else
        vkd3d_spirv_build_op_function_end(builder);
    if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL)
        spirv_compiler_emit_hull_shader_main(compiler);
    if (compiler->shader_type == VKD3D_SHADER_TYPE_DOMAIN)
    {
        if (info && (ds_info = vkd3d_find_struct(compile_info->next, SPIRV_DOMAIN_SHADER_TARGET_INFO)))
            spirv_compiler_emit_tessellator_output_primitive(compiler, ds_info->output_primitive);
            spirv_compiler_emit_tessellator_partitioning(compiler, ds_info->partitioning);
        else if (spirv_compiler_is_opengl_target(compiler))
            ERR("vkd3d_shader_spirv_domain_shader_target_info is required for "
                    "OpenGL tessellation evaluation shader.\n");
        }
    }

    if (compiler->epilogue_function_id)
    {
        vkd3d_spirv_build_op_name(builder, compiler->epilogue_function_id, "epilogue");
        spirv_compiler_emit_shader_epilogue_function(compiler);
        vkd3d_spirv_stream_clear(&builder->debug_stream);

    if (!vkd3d_spirv_compile_module(builder, spirv, spirv_compiler_get_entry_point_name(compiler)))
    if (TRACE_ON() || parser->config_flags & VKD3D_SHADER_CONFIG_FLAG_FORCE_VALIDATION)
        enum vkd3d_shader_spirv_environment environment = spirv_compiler_get_target_environment(compiler);
        struct vkd3d_string_buffer buffer;

        if (TRACE_ON())
            vkd3d_spirv_dump(spirv, environment);

        vkd3d_string_buffer_init(&buffer);
        if (!vkd3d_spirv_validate(&buffer, spirv, environment))
        {
            FIXME("Failed to validate SPIR-V binary.\n");
            vkd3d_shader_trace_text(buffer.buffer, buffer.content_size);

            if (compiler->config_flags & VKD3D_SHADER_CONFIG_FLAG_FORCE_VALIDATION)
            {
                spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_INVALID_SHADER,
                        "Execution generated an invalid shader, failing compilation:\n%s",
                        buffer.buffer);
            }
        }
        vkd3d_string_buffer_cleanup(&buffer);
    if (compiler->failed)
        return VKD3D_ERROR_INVALID_SHADER;

    if (compile_info->target_type == VKD3D_SHADER_TARGET_SPIRV_TEXT)
    {
        struct vkd3d_shader_code text;
        enum vkd3d_shader_spirv_environment environment = spirv_compiler_get_target_environment(compiler);
        if (vkd3d_spirv_binary_to_text(spirv, environment, compiler->formatting, &text) != VKD3D_OK)
int spirv_compile(struct vkd3d_shader_parser *parser,
        const struct vkd3d_shader_scan_descriptor_info1 *scan_descriptor_info,
        const struct vkd3d_shader_compile_info *compile_info,
        struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context)
{
    struct spirv_compiler *spirv_compiler;
    int ret;

    if (!(spirv_compiler = spirv_compiler_create(&parser->shader_version, &parser->shader_desc,
            compile_info, scan_descriptor_info, message_context, &parser->location, parser->config_flags)))
    {
        ERR("Failed to create SPIR-V compiler.\n");
        return VKD3D_ERROR;
    }

    ret = spirv_compiler_generate_spirv(spirv_compiler, compile_info, parser, out);

    spirv_compiler_destroy(spirv_compiler);
    return ret;
}