From 527b38d1fda8b15a564fea9e5608dd02229c5fc8 Mon Sep 17 00:00:00 2001 From: Simon Perretta Date: Thu, 14 Nov 2024 00:32:36 +0000 Subject: [PATCH] pvr, pco: rewrite compiler/driver interface for vs & fs I/O Basic vertex/fragment shader I/O and sysval allocation rewritten to use the new compiler/driver interface, with allocation moved entirely into the driver. RHW coeffs now only emitted when required. Boilerplate support for converting formats for vs inputs/fs outputs. Signed-off-by: Simon Perretta Acked-by: Frank Binns Part-of: --- src/imagination/include/hwdef/rogue_hw_defs.h | 2 + src/imagination/pco/pco.c | 6 +- src/imagination/pco/pco.h | 11 +- src/imagination/pco/pco_binary.c | 3 + src/imagination/pco/pco_data.h | 108 ++ src/imagination/pco/pco_internal.h | 7 +- src/imagination/pco/pco_nir.c | 191 ++- src/imagination/pco/pco_nir_pvfio.c | 96 +- src/imagination/pco/pco_ra.c | 2 + src/imagination/pco/pco_trans_nir.c | 229 +++- src/imagination/vulkan/pvr_cmd_buffer.c | 124 +- src/imagination/vulkan/pvr_csb_enum_helpers.h | 21 - src/imagination/vulkan/pvr_hardcode.c | 8 - src/imagination/vulkan/pvr_pass.c | 42 +- src/imagination/vulkan/pvr_pipeline.c | 1164 +++++++++++------ src/imagination/vulkan/pvr_private.h | 39 +- 16 files changed, 1405 insertions(+), 648 deletions(-) create mode 100644 src/imagination/pco/pco_data.h diff --git a/src/imagination/include/hwdef/rogue_hw_defs.h b/src/imagination/include/hwdef/rogue_hw_defs.h index 00c01e9f0d2..dfa47fef968 100644 --- a/src/imagination/include/hwdef/rogue_hw_defs.h +++ b/src/imagination/include/hwdef/rogue_hw_defs.h @@ -165,4 +165,6 @@ #define ROGUE_USRM_LINE_SIZE_PER_INSTANCE \ (ROGUE_PDS_US_TEMP_ALLOCATION_GRANULARITY * ROGUE_USRM_LINE_SIZE) +#define ROGUE_USC_COEFFICIENT_SET_SIZE 4U + #endif /* ROGUE_HW_DEFS_H */ diff --git a/src/imagination/pco/pco.c b/src/imagination/pco/pco.c index 81338f30709..3be3c27bbb5 100644 --- a/src/imagination/pco/pco.c +++ b/src/imagination/pco/pco.c @@ -288,11 +288,11 @@ void pco_instr_delete(pco_instr *instr) } /** - * \brief Returns the number of temps allocated to the entrypoint function. + * \brief Returns the shader data. * * \param[in] shader PCO shader. */ -unsigned pco_shader_temps(pco_shader *shader) +pco_data *pco_shader_data(pco_shader *shader) { - return pco_entrypoint(shader)->temps; + return &shader->data; } diff --git a/src/imagination/pco/pco.h b/src/imagination/pco/pco.h index 0ddce469be6..27027b62ebc 100644 --- a/src/imagination/pco/pco.h +++ b/src/imagination/pco/pco.h @@ -24,6 +24,7 @@ struct pvr_device_info; /* Compiler-specific forward-declarations. */ typedef struct _pco_shader pco_shader; typedef struct _pco_ctx pco_ctx; +typedef struct _pco_data pco_data; pco_ctx *pco_ctx_create(const struct pvr_device_info *dev_info, void *mem_ctx); const struct spirv_to_nir_options *pco_spirv_options(pco_ctx *ctx); @@ -31,16 +32,18 @@ const nir_shader_compiler_options *pco_nir_options(pco_ctx *ctx); void pco_preprocess_nir(pco_ctx *ctx, nir_shader *nir); void pco_link_nir(pco_ctx *ctx, nir_shader *producer, nir_shader *consumer); -void pco_lower_nir(pco_ctx *ctx, nir_shader *nir); -void pco_postprocess_nir(pco_ctx *ctx, nir_shader *nir); +void pco_rev_link_nir(pco_ctx *ctx, nir_shader *producer, nir_shader *consumer); +void pco_lower_nir(pco_ctx *ctx, nir_shader *nir, pco_data *data); +void pco_postprocess_nir(pco_ctx *ctx, nir_shader *nir, pco_data *data); -pco_shader *pco_trans_nir(pco_ctx *ctx, nir_shader *nir, void *mem_ctx); +pco_shader * +pco_trans_nir(pco_ctx *ctx, nir_shader *nir, pco_data *data, void *mem_ctx); void pco_process_ir(pco_ctx *ctx, pco_shader *shader); void pco_encode_ir(pco_ctx *ctx, pco_shader *shader); void pco_shader_finalize(pco_ctx *ctx, pco_shader *shader); -unsigned pco_shader_temps(pco_shader *shader); +pco_data *pco_shader_data(pco_shader *shader); unsigned pco_shader_binary_size(pco_shader *shader); const void *pco_shader_binary_data(pco_shader *shader); diff --git a/src/imagination/pco/pco_binary.c b/src/imagination/pco/pco_binary.c index 7c6ff23a3a6..d097ded836d 100644 --- a/src/imagination/pco/pco_binary.c +++ b/src/imagination/pco/pco_binary.c @@ -142,6 +142,9 @@ void pco_shader_finalize(pco_ctx *ctx, pco_shader *shader) { puts("finishme: pco_shader_finalize"); + pco_func *entry = pco_entrypoint(shader); + shader->data.common.entry_offset = entry->enc_offset; + if (pco_should_print_binary(shader)) pco_print_binary(shader, stdout, "after finalizing"); } diff --git a/src/imagination/pco/pco_data.h b/src/imagination/pco/pco_data.h new file mode 100644 index 00000000000..1f216091bd4 --- /dev/null +++ b/src/imagination/pco/pco_data.h @@ -0,0 +1,108 @@ +/* + * Copyright © 2024 Imagination Technologies Ltd. + * + * SPDX-License-Identifier: MIT + */ + +#ifndef PCO_DATA_H +#define PCO_DATA_H + +/** + * \file pco_data.h + * + * \brief PCO shader-specific data/compiler-driver interface. + */ + +#include "compiler/shader_enums.h" +#include "util/format/u_format.h" + +#include + +/** Generic range struct. */ +typedef struct _pco_range { + unsigned start; + unsigned count; +} pco_range; + +/** PCO vertex shader-specific data. */ +typedef struct _pco_vs_data { + /** Attributes/input mappings. */ + pco_range attribs[VERT_ATTRIB_MAX]; + + enum pipe_format attrib_formats[VERT_ATTRIB_MAX]; + + /** Varyings/output mappings. */ + pco_range varyings[VARYING_SLOT_MAX]; + + unsigned f32_smooth; /** Number of F32 linear varyings. */ + unsigned f32_flat; /** Number of F32 flat varyings. */ + unsigned f32_npc; /** Number of F32 NPC varyings. */ + + unsigned f16_smooth; /** Number of F16 linear varyings. */ + unsigned f16_flat; /** Number of F16 flat varyings. */ + unsigned f16_npc; /** Number of F16 NPC varyings. */ + + unsigned vtxouts; /** How many vertex outputs are written to. */ +} pco_vs_data; + +/** PCO fragment shader-specific data. */ +typedef struct _pco_fs_data { + /** Varyings/input mappings. */ + pco_range varyings[VARYING_SLOT_MAX]; + + /** Results/output mappings. */ + pco_range outputs[FRAG_RESULT_MAX]; + + /** If outputs are to be placed in pixout regs. */ + bool output_reg[FRAG_RESULT_MAX]; + + /** Fragment output formats. */ + enum pipe_format output_formats[FRAG_RESULT_MAX]; + + struct { + bool w; /** Whether the shader uses pos.w. */ + bool z; /** Whether the shader uses pos.z */ + bool pntc; /** Whether the shader uses point coord. */ + bool phase_change; /** Whether the shader does a phase change. */ + } uses; +} pco_fs_data; + +/** PCO compute shader-specific data. */ +typedef struct _pco_cs_data { + /**/ +} pco_cs_data; + +/** PCO common data. */ +typedef struct _pco_common_data { + /** System value mappings. */ + pco_range sys_vals[SYSTEM_VALUE_MAX]; + + unsigned temps; /** Number of allocated temp registers. */ + unsigned vtxins; /** Number of allocated vertex input registers. */ + unsigned interns; /** Number of allocated internal registers. */ + + unsigned coeffs; /** Number of allocated coefficient registers. */ + unsigned shareds; /** Number of allocated shared registers. */ + + unsigned entry_offset; /** Offset of the shader entrypoint. */ + + struct { + bool atomics; /** Whether the shader uses atomics. */ + bool barriers; /** Whether the shader uses barriers. */ + bool side_effects; /** Whether the shader has side effects. */ + bool empty; /** Whether the shader is empty. */ + } uses; +} pco_common_data; + +/** PCO shader data. */ +typedef struct _pco_data { + union { + pco_vs_data vs; + pco_fs_data fs; + pco_cs_data cs; + }; + + pco_common_data common; +} pco_data; + +#endif /* PCO_DATA_H */ diff --git a/src/imagination/pco/pco_internal.h b/src/imagination/pco/pco_internal.h index 6b03a5a2817..9290190d4a0 100644 --- a/src/imagination/pco/pco_internal.h +++ b/src/imagination/pco/pco_internal.h @@ -17,6 +17,7 @@ #include "hwdef/rogue_hw_utils.h" #include "pco.h" #include "pco_common.h" +#include "pco_data.h" #include "pco_ops.h" #include "spirv/nir_spirv.h" #include "util/compiler.h" @@ -340,6 +341,8 @@ typedef struct _pco_shader { struct list_head funcs; /** List of functions. */ unsigned next_func; /** Next function index. */ + pco_data data; /** Shader data. */ + struct { struct util_dynarray buf; /** Shader binary. */ @@ -1116,8 +1119,8 @@ bool pco_dce(pco_shader *shader); bool pco_end(pco_shader *shader); bool pco_group_instrs(pco_shader *shader); bool pco_index(pco_shader *shader, bool skip_ssa); -bool pco_nir_pfo(nir_shader *nir); -bool pco_nir_pvi(nir_shader *nir); +bool pco_nir_pfo(nir_shader *nir, pco_fs_data *fs); +bool pco_nir_pvi(nir_shader *nir, pco_vs_data *vs); bool pco_opt(pco_shader *shader); bool pco_ra(pco_shader *shader); bool pco_schedule(pco_shader *shader); diff --git a/src/imagination/pco/pco_nir.c b/src/imagination/pco/pco_nir.c index 59e4fe34f9b..dff529bfffa 100644 --- a/src/imagination/pco/pco_nir.c +++ b/src/imagination/pco/pco_nir.c @@ -10,6 +10,7 @@ * \brief NIR-specific functions. */ +#include "nir/nir_builder.h" #include "pco.h" #include "pco_internal.h" @@ -140,13 +141,32 @@ static uint8_t vectorize_filter(const nir_instr *instr, UNUSED const void *data) return 2; } +/** + * \brief Filters for a varying position load_input in frag shaders. + * + * \param[in] instr Instruction. + * \param[in] data User data. + * \return True if the instruction was found. + */ +static bool frag_pos_filter(const nir_instr *instr, UNUSED const void *data) +{ + assert(instr->type == nir_instr_type_intrinsic); + + nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr); + if (intr->intrinsic != nir_intrinsic_load_input) + return false; + + return nir_intrinsic_io_semantics(intr).location == VARYING_SLOT_POS; +} + /** * \brief Lowers a NIR shader. * * \param[in] ctx PCO compiler context. * \param[in,out] nir NIR shader. + * \param[in,out] data Shader data. */ -void pco_lower_nir(pco_ctx *ctx, nir_shader *nir) +void pco_lower_nir(pco_ctx *ctx, nir_shader *nir, pco_data *data) { NIR_PASS(_, nir, @@ -163,9 +183,9 @@ void pco_lower_nir(pco_ctx *ctx, nir_shader *nir) nir_var_shader_in | nir_var_shader_out); if (nir->info.stage == MESA_SHADER_FRAGMENT) { - NIR_PASS(_, nir, pco_nir_pfo); + NIR_PASS(_, nir, pco_nir_pfo, &data->fs); } else if (nir->info.stage == MESA_SHADER_VERTEX) { - NIR_PASS(_, nir, pco_nir_pvi); + NIR_PASS(_, nir, pco_nir_pvi, &data->vs); } /* TODO: this should happen in the linking stage to cull unused I/O. */ @@ -196,10 +216,26 @@ void pco_lower_nir(pco_ctx *ctx, nir_shader *nir) NIR_PASS(_, nir, nir_opt_cse); } while (progress); - NIR_PASS(_, - nir, - nir_opt_vectorize_io, - nir_var_shader_in | nir_var_shader_out); + nir_variable_mode vec_modes = nir_var_shader_in; + /* Fragment shader needs scalar writes after pfo. */ + if (nir->info.stage != MESA_SHADER_FRAGMENT) + vec_modes |= nir_var_shader_out; + + NIR_PASS(_, nir, nir_opt_vectorize_io, vec_modes); + + /* Special case for frag coords: + * - x,y come from (non-consecutive) special regs - always scalar. + * - z,w are iterated and driver will make sure they're consecutive. + * - TODO: keep scalar for now, but add pass to vectorize. + */ + if (nir->info.stage == MESA_SHADER_FRAGMENT) { + NIR_PASS(_, + nir, + nir_lower_io_to_scalar, + nir_var_shader_in, + frag_pos_filter, + NULL); + } NIR_PASS(_, nir, nir_lower_alu_to_scalar, NULL, NULL); @@ -219,13 +255,88 @@ void pco_lower_nir(pco_ctx *ctx, nir_shader *nir) } } +/** + * \brief Gather fragment shader data pass. + * + * \param[in] b NIR builder. + * \param[in] intr NIR intrinsic instruction. + * \param[in,out] cb_data Callback data. + * \return True if the shader was modified (always return false). + */ +static bool gather_fs_data_pass(UNUSED struct nir_builder *b, + nir_intrinsic_instr *intr, + void *cb_data) +{ + /* Check whether the shader accesses z/w. */ + if (intr->intrinsic != nir_intrinsic_load_input) + return false; + + struct nir_io_semantics io_semantics = nir_intrinsic_io_semantics(intr); + if (io_semantics.location != VARYING_SLOT_POS) + return false; + + unsigned component = nir_intrinsic_component(intr); + unsigned chans = intr->def.num_components; + + pco_data *data = cb_data; + + data->fs.uses.z |= (component + chans > 2); + data->fs.uses.w |= (component + chans > 3); + + return false; +} + +/** + * \brief Gathers fragment shader data. + * + * \param[in] nir NIR shader. + * \param[in,out] data Shader data. + */ +static void gather_fs_data(nir_shader *nir, pco_data *data) +{ + nir_shader_intrinsics_pass(nir, gather_fs_data_pass, nir_metadata_all, data); + + /* If any inputs use smooth shading, then w is needed. */ + if (!data->fs.uses.w) { + nir_foreach_shader_in_variable (var, nir) { + if (var->data.interpolation > INTERP_MODE_SMOOTH) + continue; + + data->fs.uses.w = true; + break; + } + } +} + +/** + * \brief Gathers shader data. + * + * \param[in] nir NIR shader. + * \param[in,out] data Shader data. + */ +static void gather_data(nir_shader *nir, pco_data *data) +{ + switch (nir->info.stage) { + case MESA_SHADER_FRAGMENT: + return gather_fs_data(nir, data); + + case MESA_SHADER_VERTEX: + /* TODO */ + break; + + default: + unreachable(); + } +} + /** * \brief Runs post-processing passes on a NIR shader. * * \param[in] ctx PCO compiler context. * \param[in,out] nir NIR shader. + * \param[in,out] data Shader data. */ -void pco_postprocess_nir(pco_ctx *ctx, nir_shader *nir) +void pco_postprocess_nir(pco_ctx *ctx, nir_shader *nir, pco_data *data) { NIR_PASS(_, nir, nir_move_vec_src_uses_to_dest, false); @@ -238,6 +349,8 @@ void pco_postprocess_nir(pco_ctx *ctx, nir_shader *nir) nir_shader_gather_info(nir, nir_shader_get_entrypoint(nir)); + gather_data(nir, data); + if (pco_should_print_nir(nir)) { puts("after pco_postprocess_nir:"); nir_print_shader(nir, stdout); @@ -253,6 +366,9 @@ void pco_postprocess_nir(pco_ctx *ctx, nir_shader *nir) */ void pco_link_nir(pco_ctx *ctx, nir_shader *producer, nir_shader *consumer) { + /* TODO */ + puts("finishme: pco_link_nir"); + if (pco_should_print_nir(producer)) { puts("producer after pco_link_nir:"); nir_print_shader(producer, stdout); @@ -262,6 +378,61 @@ void pco_link_nir(pco_ctx *ctx, nir_shader *producer, nir_shader *consumer) puts("consumer after pco_link_nir:"); nir_print_shader(consumer, stdout); } - - puts("finishme: pco_link_nir"); +} + +/** + * \brief Checks whether two varying variables are the same. + * + * \param[in] out_var The first varying being compared. + * \param[in] in_var The second varying being compared. + * \return True if the varyings match. + */ +static bool varyings_match(nir_variable *out_var, nir_variable *in_var) +{ + return in_var->data.location == out_var->data.location && + in_var->data.location_frac == out_var->data.location_frac && + in_var->type == out_var->type; +} + +/** + * \brief Performs reverse linking optimizations on consecutive NIR shader + * stages. + * + * \param[in] ctx PCO compiler context. + * \param[in,out] producer NIR producer shader. + * \param[in,out] consumer NIR consumer shader. + */ +PUBLIC +void pco_rev_link_nir(pco_ctx *ctx, nir_shader *producer, nir_shader *consumer) +{ + /* TODO */ + puts("finishme: pco_rev_link_nir"); + + /* Propagate back/adjust the interpolation qualifiers. */ + nir_foreach_shader_in_variable (in_var, consumer) { + if (in_var->data.location == VARYING_SLOT_POS || + in_var->data.location == VARYING_SLOT_PNTC) { + in_var->data.interpolation = INTERP_MODE_NOPERSPECTIVE; + } else if (in_var->data.interpolation == INTERP_MODE_NONE) { + in_var->data.interpolation = INTERP_MODE_SMOOTH; + } + + nir_foreach_shader_out_variable (out_var, producer) { + if (!varyings_match(out_var, in_var)) + continue; + + out_var->data.interpolation = in_var->data.interpolation; + break; + } + } + + if (pco_should_print_nir(producer)) { + puts("producer after pco_rev_link_nir:"); + nir_print_shader(producer, stdout); + } + + if (pco_should_print_nir(consumer)) { + puts("consumer after pco_rev_link_nir:"); + nir_print_shader(consumer, stdout); + } } diff --git a/src/imagination/pco/pco_nir_pvfio.c b/src/imagination/pco/pco_nir_pvfio.c index 7daca7d10c3..606fad72278 100644 --- a/src/imagination/pco/pco_nir_pvfio.c +++ b/src/imagination/pco/pco_nir_pvfio.c @@ -10,6 +10,8 @@ * \brief PCO NIR per-vertex/fragment input/output passes. */ +#include "compiler/glsl_types.h" +#include "compiler/shader_enums.h" #include "nir.h" #include "nir_builder.h" #include "pco.h" @@ -25,6 +27,7 @@ /** Per-fragment output pass state. */ struct pfo_state { struct util_dynarray stores; /** List of fragment stores. */ + pco_fs_data *fs; /** Fragment-specific data. */ }; /** @@ -51,6 +54,36 @@ static inline nir_intrinsic_instr *is_intr(nir_instr *instr, return intr; } +/** + * \brief Returns the GLSL base type equivalent of a pipe format. + * + * \param[in] format Pipe format. + * \return The GLSL base type, or GLSL_TYPE_ERROR if unsupported/invalid. + */ +static inline enum glsl_base_type base_type_from_fmt(enum pipe_format format) +{ + const struct util_format_description *desc = util_format_description(format); + int chan = util_format_get_first_non_void_channel(format); + if (chan < 0) + return GLSL_TYPE_ERROR; + + switch (desc->channel[chan].type) { + case UTIL_FORMAT_TYPE_UNSIGNED: + return GLSL_TYPE_UINT; + + case UTIL_FORMAT_TYPE_SIGNED: + return GLSL_TYPE_INT; + + case UTIL_FORMAT_TYPE_FLOAT: + return GLSL_TYPE_FLOAT; + + default: + break; + } + + return GLSL_TYPE_ERROR; +} + /** * \brief Lowers a PFO-related instruction. * @@ -89,31 +122,48 @@ static bool lower_pfo(nir_builder *b, nir_instr *instr, void *cb_data) assert(nir_src_num_components(*value) == 4); assert(nir_src_bit_size(*value) == 32); - /* Update the type of the stored variable. */ - nir_variable *var = nir_find_variable_with_location( - b->shader, - nir_var_shader_out, - nir_intrinsic_io_semantics(intr).location); + struct nir_io_semantics io_semantics = nir_intrinsic_io_semantics(intr); + gl_frag_result location = io_semantics.location; - var->type = glsl_uint_type(); + enum pipe_format format = state->fs->output_formats[location]; + + unsigned format_bits = util_format_get_blocksizebits(format); + assert(!(format_bits % 32)); + + /* Update the type of the stored variable. */ + nir_variable *var = nir_find_variable_with_location(b->shader, + nir_var_shader_out, + location); + assert(var); + + var->type = glsl_simple_explicit_type(base_type_from_fmt(format), + format_bits / 32, + 1, + 0, + false, + 0); b->cursor = nir_after_block( nir_impl_last_block(nir_shader_get_entrypoint(b->shader))); /* Emit and track the new store. */ - /* TODO NEXT: base is calculated to be the register offset. */ - nir_intrinsic_instr *store = - nir_store_output(b, - nir_pack_unorm_4x8(b, value->ssa), - offset->ssa, - .base = nir_intrinsic_base(intr), - .write_mask = 1, - .component = 0, - .src_type = nir_type_uint32, - .io_semantics = nir_intrinsic_io_semantics(intr), - .io_xfb = nir_intrinsic_io_xfb(intr), - .io_xfb2 = nir_intrinsic_io_xfb2(intr)); - util_dynarray_append(&state->stores, nir_intrinsic_instr *, store); + /* TODO: support other formats. */ + if (format == PIPE_FORMAT_R8G8B8A8_UNORM) { + nir_intrinsic_instr *store = + nir_store_output(b, + nir_pack_unorm_4x8(b, value->ssa), + offset->ssa, + .base = nir_intrinsic_base(intr), + .write_mask = 1, + .component = 0, + .src_type = nir_type_uint32, + .io_semantics = io_semantics, + .io_xfb = nir_intrinsic_io_xfb(intr), + .io_xfb2 = nir_intrinsic_io_xfb2(intr)); + util_dynarray_append(&state->stores, nir_intrinsic_instr *, store); + } else { + unreachable(); + } /* Remove the old store. */ b->cursor = nir_instr_remove(instr); @@ -128,13 +178,14 @@ static bool lower_pfo(nir_builder *b, nir_instr *instr, void *cb_data) * \brief Per-fragment output pass. * * \param[in,out] nir NIR shader. + * \param[in,out] fs Fragment shader-specific data. * \return True if the pass made progress. */ -bool pco_nir_pfo(nir_shader *nir) +bool pco_nir_pfo(nir_shader *nir, pco_fs_data *fs) { assert(nir->info.stage == MESA_SHADER_FRAGMENT); - struct pfo_state state = {}; + struct pfo_state state = { .fs = fs }; util_dynarray_init(&state.stores, NULL); bool progress = @@ -149,9 +200,10 @@ bool pco_nir_pfo(nir_shader *nir) * \brief Per-vertex input pass. * * \param[in,out] nir NIR shader. + * \param[in,out] vs Vertex shader-specific data. * \return True if the pass made progress. */ -bool pco_nir_pvi(nir_shader *nir) +bool pco_nir_pvi(nir_shader *nir, pco_vs_data *vs) { assert(nir->info.stage == MESA_SHADER_VERTEX); diff --git a/src/imagination/pco/pco_ra.c b/src/imagination/pco/pco_ra.c index 412ac2f3c09..c5c957f4277 100644 --- a/src/imagination/pco/pco_ra.c +++ b/src/imagination/pco/pco_ra.c @@ -377,6 +377,8 @@ bool pco_ra(pco_shader *shader) allocable_temps, allocable_vtxins, allocable_interns); + + shader->data.common.temps = MAX2(shader->data.common.temps, func->temps); } return progress; diff --git a/src/imagination/pco/pco_trans_nir.c b/src/imagination/pco/pco_trans_nir.c index d543b04c649..c2a7d57b0e0 100644 --- a/src/imagination/pco/pco_trans_nir.c +++ b/src/imagination/pco/pco_trans_nir.c @@ -12,6 +12,7 @@ #include "compiler/glsl/list.h" #include "compiler/shader_enums.h" +#include "hwdef/rogue_hw_defs.h" #include "pco.h" #include "pco_builder.h" #include "pco_internal.h" @@ -182,21 +183,25 @@ pco_ref_nir_alu_src_t(const nir_alu_instr *alu, unsigned src, trans_ctx *tctx) static pco_instr * trans_load_input_vs(trans_ctx *tctx, nir_intrinsic_instr *intr, pco_ref dest) { - puts("finishme: trans_load_input_vs"); + ASSERTED unsigned base = nir_intrinsic_base(intr); + assert(!base); - /* unsigned base = nir_intrinsic_base(intr); */ - unsigned base = - nir_intrinsic_io_semantics(intr).location - VERT_ATTRIB_GENERIC0; + ASSERTED nir_alu_type type = nir_intrinsic_dest_type(intr); + assert(type == nir_type_float32); + /* TODO: f16 support. */ + + ASSERTED const nir_src offset = intr->src[0]; + assert(nir_src_as_uint(offset) == 0); + + gl_vert_attrib location = nir_intrinsic_io_semantics(intr).location; unsigned component = nir_intrinsic_component(intr); unsigned chans = pco_ref_get_chans(dest); - const nir_src offset = intr->src[0]; - assert(nir_src_as_uint(offset) == 0); - - /* TODO NEXT: Wrong! Do properly! */ - unsigned vtxin_offset = (4 * base) + component; - pco_ref src = pco_ref_hwreg_vec(vtxin_offset, PCO_REG_CLASS_VTXIN, chans); + const pco_range *range = &tctx->shader->data.vs.attribs[location]; + assert(component + chans <= range->count); + pco_ref src = + pco_ref_hwreg_vec(range->start + component, PCO_REG_CLASS_VTXIN, chans); return pco_mov(&tctx->b, dest, src, .rpt = chans); } @@ -211,34 +216,28 @@ trans_load_input_vs(trans_ctx *tctx, nir_intrinsic_instr *intr, pco_ref dest) static pco_instr * trans_store_output_vs(trans_ctx *tctx, nir_intrinsic_instr *intr, pco_ref src) { - puts("finishme: trans_store_output_vs"); + ASSERTED unsigned base = nir_intrinsic_base(intr); + assert(!base); - /* unsigned base = nir_intrinsic_base(intr); */ + ASSERTED nir_alu_type type = nir_intrinsic_src_type(intr); + assert(type == nir_type_float32); + /* TODO: f16 support. */ - unsigned location = nir_intrinsic_io_semantics(intr).location; - unsigned base; - switch (location) { - case VARYING_SLOT_POS: - base = 0; - break; - - case VARYING_SLOT_VAR0 ... VARYING_SLOT_VAR31: - base = location - VARYING_SLOT_VAR0 + 1; - break; - - default: - unreachable(); - } + ASSERTED const nir_src offset = intr->src[1]; + assert(nir_src_as_uint(offset) == 0); + gl_varying_slot location = nir_intrinsic_io_semantics(intr).location; unsigned component = nir_intrinsic_component(intr); unsigned chans = pco_ref_get_chans(src); - const nir_src offset = intr->src[1]; - assert(nir_src_as_uint(offset) == 0); + /* Only contiguous write masks supported. */ + ASSERTED unsigned write_mask = nir_intrinsic_write_mask(intr); + assert(write_mask == BITFIELD_MASK(chans)); - /* TODO NEXT: Wrong! Do properly! */ - pco_ref vtxout_addr = pco_ref_val8((4 * base) + component); + const pco_range *range = &tctx->shader->data.vs.varyings[location]; + assert(component + chans <= range->count); + pco_ref vtxout_addr = pco_ref_val8(range->start + component); return pco_uvsw_write(&tctx->b, src, vtxout_addr, .rpt = chans); } @@ -253,8 +252,7 @@ trans_store_output_vs(trans_ctx *tctx, nir_intrinsic_instr *intr, pco_ref src) static pco_instr * trans_load_input_fs(trans_ctx *tctx, nir_intrinsic_instr *intr, pco_ref dest) { - puts("finishme: trans_load_input_fs"); - + pco_fs_data *fs_data = &tctx->shader->data.fs; ASSERTED unsigned base = nir_intrinsic_base(intr); assert(!base); @@ -264,34 +262,116 @@ trans_load_input_fs(trans_ctx *tctx, nir_intrinsic_instr *intr, pco_ref dest) const nir_src offset = intr->src[0]; assert(nir_src_as_uint(offset) == 0); - /* TODO NEXT: Wrong! Do properly! */ - unsigned loc_offset = - nir_intrinsic_io_semantics(intr).location - VARYING_SLOT_VAR0; - /* TEMP: +1 to skip over wcoeffs */ - unsigned coeffs_index = 4 * (loc_offset + component + 1); - unsigned wcoeffs_index = 0; + struct nir_io_semantics io_semantics = nir_intrinsic_io_semantics(intr); + gl_varying_slot location = io_semantics.location; - pco_ref coeffs = - pco_ref_hwreg_vec(coeffs_index, PCO_REG_CLASS_COEFF, 4 * chans); - pco_ref wcoeffs = pco_ref_hwreg_vec(wcoeffs_index, PCO_REG_CLASS_COEFF, 4); + nir_variable *var = nir_find_variable_with_location(tctx->shader->nir, + nir_var_shader_in, + location); + + enum pco_itr_mode itr_mode = PCO_ITR_MODE_PIXEL; + assert(!(var->data.sample && var->data.centroid)); + if (var->data.sample) + itr_mode = PCO_ITR_MODE_SAMPLE; + else if (var->data.centroid) + itr_mode = PCO_ITR_MODE_CENTROID; + + if (location == VARYING_SLOT_POS) { + /* Only scalar supported for now. */ + /* TODO: support vector for zw. */ + assert(chans == 1); + + /* TODO: support packing/partial vars. */ + assert(!var->data.location_frac); + + assert(var->data.interpolation == INTERP_MODE_NOPERSPECTIVE); + + /* Special case: x and y are loaded from special registers. */ + /* TODO: select appropriate regs if sample rate shading. */ + switch (component) { + case 0: /* x */ + return pco_mov(&tctx->b, + dest, + pco_ref_hwreg(PCO_SR_X_P, PCO_REG_CLASS_SPEC)); + + case 1: /* y */ + return pco_mov(&tctx->b, + dest, + pco_ref_hwreg(PCO_SR_Y_P, PCO_REG_CLASS_SPEC)); + + case 2: + assert(fs_data->uses.z); + component = 0; + break; + + case 3: + assert(fs_data->uses.w); + component = fs_data->uses.z ? 1 : 0; + break; + + default: + unreachable(); + } + } + + const pco_range *range = &fs_data->varyings[location]; + assert(component + (ROGUE_USC_COEFFICIENT_SET_SIZE * chans) <= range->count); + + unsigned coeffs_index = + range->start + (ROGUE_USC_COEFFICIENT_SET_SIZE * component); + + pco_ref coeffs = pco_ref_hwreg_vec(coeffs_index, + PCO_REG_CLASS_COEFF, + ROGUE_USC_COEFFICIENT_SET_SIZE * chans); pco_ref itr_count = pco_ref_val16(chans); - if (PVR_HAS_FEATURE(tctx->pco_ctx->dev_info, usc_itrsmp_enhanced)) { - return pco_ditrp(&tctx->b, - dest, - pco_ref_drc(PCO_DRC_0), - coeffs, - wcoeffs, - itr_count, - .itr_mode = PCO_ITR_MODE_PIXEL); - } else { - return pco_fitrp(&tctx->b, - dest, - pco_ref_drc(PCO_DRC_0), - coeffs, - wcoeffs, - itr_count, - .itr_mode = PCO_ITR_MODE_PIXEL); + bool usc_itrsmp_enhanced = + PVR_HAS_FEATURE(tctx->pco_ctx->dev_info, usc_itrsmp_enhanced); + + switch (var->data.interpolation) { + case INTERP_MODE_SMOOTH: { + assert(fs_data->uses.w); + + unsigned wcoeffs_index = fs_data->uses.z ? ROGUE_USC_COEFFICIENT_SET_SIZE + : 0; + + pco_ref wcoeffs = pco_ref_hwreg_vec(wcoeffs_index, + PCO_REG_CLASS_COEFF, + ROGUE_USC_COEFFICIENT_SET_SIZE); + + return usc_itrsmp_enhanced ? pco_ditrp(&tctx->b, + dest, + pco_ref_drc(PCO_DRC_0), + coeffs, + wcoeffs, + itr_count, + .itr_mode = itr_mode) + : pco_fitrp(&tctx->b, + dest, + pco_ref_drc(PCO_DRC_0), + coeffs, + wcoeffs, + itr_count, + .itr_mode = itr_mode); + } + + case INTERP_MODE_NOPERSPECTIVE: + return usc_itrsmp_enhanced ? pco_ditr(&tctx->b, + dest, + pco_ref_drc(PCO_DRC_0), + coeffs, + itr_count, + .itr_mode = itr_mode) + : pco_fitr(&tctx->b, + dest, + pco_ref_drc(PCO_DRC_0), + coeffs, + itr_count, + .itr_mode = itr_mode); + + default: + /* Should have been previously lowered. */ + unreachable(); } } @@ -306,21 +386,26 @@ trans_load_input_fs(trans_ctx *tctx, nir_intrinsic_instr *intr, pco_ref dest) static pco_instr * trans_store_output_fs(trans_ctx *tctx, nir_intrinsic_instr *intr, pco_ref src) { + ASSERTED unsigned base = nir_intrinsic_base(intr); + assert(!base); + assert(pco_ref_is_scalar(src)); - puts("finishme: trans_store_output_fs"); + unsigned component = nir_intrinsic_component(intr); - bool is_reg_store = nir_src_is_const(intr->src[1]); - unsigned base = nir_intrinsic_base(intr); + ASSERTED const nir_src offset = intr->src[1]; + assert(nir_src_as_uint(offset) == 0); - if (is_reg_store) { - /* TODO NEXT: Wrong! Do properly! */ - pco_ref dest = pco_ref_hwreg(base, PCO_REG_CLASS_PIXOUT); - /* TODO NEXT: optimize this to be propagated (backwards?) */ - /* return pco_mbyp0(&tctx->b, dest, src, .olchk = true); */ - return pco_mov(&tctx->b, dest, src, .olchk = true); - } + gl_varying_slot location = nir_intrinsic_io_semantics(intr).location; - unreachable(); + const pco_range *range = &tctx->shader->data.fs.outputs[location]; + assert(component < range->count); + + ASSERTED bool output_reg = tctx->shader->data.fs.output_reg[location]; + assert(output_reg); + /* TODO: tile buffer support. */ + + pco_ref dest = pco_ref_hwreg(range->start + component, PCO_REG_CLASS_PIXOUT); + return pco_mov(&tctx->b, dest, src, .olchk = true); } /** @@ -804,12 +889,18 @@ static pco_block *trans_cf_nodes(trans_ctx *tctx, * * \param[in] ctx PCO compiler context. * \param[in] nir NIR shader. + * \param[in] data Shader-specific data. * \param[in] mem_ctx Ralloc memory allocation context. * \return The PCO shader. */ -pco_shader *pco_trans_nir(pco_ctx *ctx, nir_shader *nir, void *mem_ctx) +pco_shader * +pco_trans_nir(pco_ctx *ctx, nir_shader *nir, pco_data *data, void *mem_ctx) { pco_shader *shader = pco_shader_create(ctx, nir, mem_ctx); + + if (data) + memcpy(&shader->data, data, sizeof(*data)); + trans_ctx tctx = { .pco_ctx = ctx, .shader = shader, diff --git a/src/imagination/vulkan/pvr_cmd_buffer.c b/src/imagination/vulkan/pvr_cmd_buffer.c index b5b61fbbf7d..ccee41835ba 100644 --- a/src/imagination/vulkan/pvr_cmd_buffer.c +++ b/src/imagination/vulkan/pvr_cmd_buffer.c @@ -3366,9 +3366,11 @@ pvr_setup_vertex_buffers(struct pvr_cmd_buffer *cmd_buffer, case PVR_PDS_CONST_MAP_ENTRY_TYPE_DOUTU_ADDRESS: { const struct pvr_const_map_entry_doutu_address *const doutu_addr = (struct pvr_const_map_entry_doutu_address *)entries; + + const pco_data *const vs_data = &state->gfx_pipeline->vs_data; const pvr_dev_addr_t exec_addr = PVR_DEV_ADDR_OFFSET(vertex_state->bo->dev_addr, - vertex_state->entry_offset); + vs_data->common.entry_offset); uint64_t addr = 0ULL; pvr_set_usc_execution_address64(&addr, exec_addr.addr); @@ -4769,19 +4771,10 @@ pvr_update_draw_state(struct pvr_cmd_buffer_state *const state, static uint32_t pvr_calc_shared_regs_count( const struct pvr_graphics_pipeline *const gfx_pipeline) { - const struct pvr_pipeline_stage_state *const vertex_state = - &gfx_pipeline->shader_state.vertex.stage_state; - - uint32_t shared_regs = vertex_state->const_shared_reg_count + - vertex_state->const_shared_reg_offset; + uint32_t shared_regs = gfx_pipeline->vs_data.common.shareds; if (gfx_pipeline->shader_state.fragment.bo) { - const struct pvr_pipeline_stage_state *const fragment_state = - &gfx_pipeline->shader_state.fragment.stage_state; - - uint32_t fragment_regs = fragment_state->const_shared_reg_count + - fragment_state->const_shared_reg_offset; - + uint32_t fragment_regs = gfx_pipeline->fs_data.common.shareds; shared_regs = MAX2(shared_regs, fragment_regs); } @@ -4797,8 +4790,7 @@ pvr_emit_dirty_pds_state(const struct pvr_cmd_buffer *const cmd_buffer, const struct pvr_stage_allocation_descriptor_state *const vertex_descriptor_state = &state->gfx_pipeline->shader_state.vertex.descriptor_state; - const struct pvr_pipeline_stage_state *const vertex_stage_state = - &state->gfx_pipeline->shader_state.vertex.stage_state; + const pco_data *const vs_data = &state->gfx_pipeline->vs_data; struct pvr_csb *const csb = &sub_cmd->control_stream; if (!vertex_descriptor_state->pds_info.code_size_in_dwords) @@ -4810,7 +4802,7 @@ pvr_emit_dirty_pds_state(const struct pvr_cmd_buffer *const cmd_buffer, state0.usc_target = ROGUE_VDMCTRL_USC_TARGET_ALL; state0.usc_common_size = - DIV_ROUND_UP(vertex_stage_state->const_shared_reg_count << 2, + DIV_ROUND_UP(vs_data->common.shareds, ROGUE_VDMCTRL_PDS_STATE0_USC_COMMON_SIZE_UNIT_SIZE); state0.pds_data_size = DIV_ROUND_UP( @@ -4835,21 +4827,33 @@ static void pvr_setup_output_select(struct pvr_cmd_buffer *const cmd_buffer) { const struct pvr_graphics_pipeline *const gfx_pipeline = cmd_buffer->state.gfx_pipeline; - const struct pvr_vertex_shader_state *const vertex_state = - &gfx_pipeline->shader_state.vertex; struct vk_dynamic_graphics_state *const dynamic_state = &cmd_buffer->vk.dynamic_graphics_state; struct ROGUE_TA_STATE_HEADER *const header = &cmd_buffer->state.emit_header; struct pvr_ppp_state *const ppp_state = &cmd_buffer->state.ppp_state; + const pco_data *const vs_data = &gfx_pipeline->vs_data; + const pco_data *const fs_data = &gfx_pipeline->fs_data; uint32_t output_selects; + uint32_t varying[2]; - /* TODO: Handle vertex and fragment shader state flags. */ + const pco_range *varyings = vs_data->vs.varyings; + + const bool has_point_size = dynamic_state->ia.primitive_topology == + VK_PRIMITIVE_TOPOLOGY_POINT_LIST && + varyings[VARYING_SLOT_PSIZ].count > 0; + + const bool has_viewport = varyings[VARYING_SLOT_VIEWPORT].count > 0; + + const bool has_layer = varyings[VARYING_SLOT_LAYER].count > 0; pvr_csb_pack (&output_selects, TA_OUTPUT_SEL, state) { - state.rhw_pres = true; - state.vtxsize = DIV_ROUND_UP(vertex_state->vertex_output_size, 4U); - state.psprite_size_pres = (dynamic_state->ia.primitive_topology == - VK_PRIMITIVE_TOPOLOGY_POINT_LIST); + state.rhw_pres = fs_data->fs.uses.w; + state.tsp_unclamped_z_pres = fs_data->fs.uses.z; + + state.vtxsize = vs_data->vs.vtxouts; + state.psprite_size_pres = has_point_size; + state.vpt_tgt_pres = has_viewport; + state.render_tgt_pres = has_layer; } if (ppp_state->output_selects != output_selects) { @@ -4857,13 +4861,25 @@ static void pvr_setup_output_select(struct pvr_cmd_buffer *const cmd_buffer) header->pres_outselects = true; } - if (ppp_state->varying_word[0] != vertex_state->varying[0]) { - ppp_state->varying_word[0] = vertex_state->varying[0]; + pvr_csb_pack (&varying[0], TA_STATE_VARYING0, varying0) { + varying0.f32_linear = vs_data->vs.f32_smooth; + varying0.f32_flat = vs_data->vs.f32_flat; + varying0.f32_npc = vs_data->vs.f32_npc; + } + + if (ppp_state->varying_word[0] != varying[0]) { + ppp_state->varying_word[0] = varying[0]; header->pres_varying_word0 = true; } - if (ppp_state->varying_word[1] != vertex_state->varying[1]) { - ppp_state->varying_word[1] = vertex_state->varying[1]; + pvr_csb_pack (&varying[1], TA_STATE_VARYING1, varying1) { + varying1.f16_linear = vs_data->vs.f16_smooth; + varying1.f16_flat = vs_data->vs.f16_flat; + varying1.f16_npc = vs_data->vs.f16_npc; + } + + if (ppp_state->varying_word[1] != varying[1]) { + ppp_state->varying_word[1] = varying[1]; header->pres_varying_word1 = true; } } @@ -5402,15 +5418,16 @@ pvr_setup_fragment_state_pointers(struct pvr_cmd_buffer *const cmd_buffer, struct pvr_sub_cmd_gfx *const sub_cmd) { struct pvr_cmd_buffer_state *const state = &cmd_buffer->state; + const pco_data *const fs_data = &state->gfx_pipeline->fs_data; - const struct pvr_fragment_shader_state *const fragment = + const struct pvr_fragment_shader_state *const fragment_shader_state = &state->gfx_pipeline->shader_state.fragment; const struct pvr_stage_allocation_descriptor_state *descriptor_shader_state = - &fragment->descriptor_state; + &fragment_shader_state->descriptor_state; const struct pvr_pipeline_stage_state *fragment_state = - &fragment->stage_state; + &fragment_shader_state->stage_state; const struct pvr_pds_upload *pds_coeff_program = - &fragment->pds_coeff_program; + &fragment_shader_state->pds_coeff_program; const struct pvr_physical_device *pdevice = cmd_buffer->device->pdevice; struct ROGUE_TA_STATE_HEADER *const header = &state->emit_header; @@ -5425,7 +5442,7 @@ pvr_setup_fragment_state_pointers(struct pvr_cmd_buffer *const cmd_buffer, ROGUE_TA_STATE_PDS_SIZEINFO1_PDS_VARYINGSIZE_UNIT_SIZE); const uint32_t usc_varying_size = - DIV_ROUND_UP(fragment_state->coefficient_size, + DIV_ROUND_UP(fs_data->common.coeffs, ROGUE_TA_STATE_PDS_SIZEINFO1_USC_VARYINGSIZE_UNIT_SIZE); const uint32_t pds_temp_size = @@ -5433,7 +5450,7 @@ pvr_setup_fragment_state_pointers(struct pvr_cmd_buffer *const cmd_buffer, ROGUE_TA_STATE_PDS_SIZEINFO1_PDS_TEMPSIZE_UNIT_SIZE); const uint32_t usc_shared_size = - DIV_ROUND_UP(fragment_state->const_shared_reg_count, + DIV_ROUND_UP(fs_data->common.shareds, ROGUE_TA_STATE_PDS_SIZEINFO2_USC_SHAREDSIZE_UNIT_SIZE); const uint32_t max_tiles_in_flight = @@ -5453,7 +5470,7 @@ pvr_setup_fragment_state_pointers(struct pvr_cmd_buffer *const cmd_buffer, TA_STATE_PDS_SHADERBASE, shader_base) { const struct pvr_pds_upload *const pds_upload = - &fragment->pds_fragment_program; + &fragment_shader_state->pds_fragment_program; shader_base.addr = PVR_DEV_ADDR(pds_upload->data_offset); } @@ -6010,7 +6027,7 @@ pvr_emit_dirty_ppp_state(struct pvr_cmd_buffer *const cmd_buffer, if (!dynamic_state->rs.rasterizer_discard_enable && state->dirty.fragment_descriptors && state->gfx_pipeline->shader_state.fragment.bo && - !state->gfx_pipeline->shader_state.fragment.stage_state.empty_program) { + !state->gfx_pipeline->fs_data.common.uses.empty) { pvr_setup_fragment_state_pointers(cmd_buffer, sub_cmd); } @@ -6127,22 +6144,16 @@ static void pvr_emit_dirty_vdm_state(struct pvr_cmd_buffer *const cmd_buffer, struct vk_dynamic_graphics_state *const dynamic_state = &cmd_buffer->vk.dynamic_graphics_state; const struct pvr_cmd_buffer_state *const state = &cmd_buffer->state; - const struct pvr_vertex_shader_state *const vertex_shader_state = - &state->gfx_pipeline->shader_state.vertex; + const pco_data *const vs_data = &state->gfx_pipeline->vs_data; struct pvr_csb *const csb = &sub_cmd->control_stream; - uint32_t vs_output_size; uint32_t max_instances; uint32_t cam_size; /* CAM Calculations and HW state take vertex size aligned to DWORDS. */ - vs_output_size = - DIV_ROUND_UP(vertex_shader_state->vertex_output_size, - ROGUE_VDMCTRL_VDM_STATE4_VS_OUTPUT_SIZE_UNIT_SIZE); - - assert(vs_output_size <= max_user_vertex_output_components); + assert(vs_data->vs.vtxouts <= max_user_vertex_output_components); pvr_calculate_vertex_cam_size(dev_info, - vs_output_size, + vs_data->vs.vtxouts, true, &cam_size, &max_instances); @@ -6210,8 +6221,8 @@ static void pvr_emit_dirty_vdm_state(struct pvr_cmd_buffer *const cmd_buffer, } if (header.vs_other_present) { - const uint32_t usc_unified_store_size_in_bytes = - vertex_shader_state->vertex_input_size << 2; + const uint32_t usc_unified_store_size_in_bytes = vs_data->common.vtxins + << 2; pvr_csb_emit (csb, VDMCTRL_VDM_STATE3, state3) { state3.vs_pds_code_base_addr = @@ -6219,7 +6230,7 @@ static void pvr_emit_dirty_vdm_state(struct pvr_cmd_buffer *const cmd_buffer, } pvr_csb_emit (csb, VDMCTRL_VDM_STATE4, state4) { - state4.vs_output_size = vs_output_size; + state4.vs_output_size = vs_data->vs.vtxouts; } pvr_csb_emit (csb, VDMCTRL_VDM_STATE5, state5) { @@ -6246,10 +6257,7 @@ static VkResult pvr_validate_draw_state(struct pvr_cmd_buffer *cmd_buffer) struct vk_dynamic_graphics_state *const dynamic_state = &cmd_buffer->vk.dynamic_graphics_state; const struct pvr_graphics_pipeline *const gfx_pipeline = state->gfx_pipeline; - const struct pvr_pipeline_stage_state *const fragment_state = - &gfx_pipeline->shader_state.fragment.stage_state; - const struct pvr_pipeline_stage_state *const vertex_state = - &gfx_pipeline->shader_state.vertex.stage_state; + const pco_data *const fs_data = &gfx_pipeline->fs_data; struct pvr_sub_cmd_gfx *sub_cmd; bool fstencil_writemask_zero; bool bstencil_writemask_zero; @@ -6282,7 +6290,7 @@ static VkResult pvr_validate_draw_state(struct pvr_cmd_buffer *cmd_buffer) if (PVR_HAS_FEATURE(&cmd_buffer->device->pdevice->dev_info, compute_overlap)) { uint32_t coefficient_size = - DIV_ROUND_UP(fragment_state->coefficient_size, + DIV_ROUND_UP(fs_data->common.coeffs, ROGUE_TA_STATE_PDS_SIZEINFO1_USC_VARYINGSIZE_UNIT_SIZE); if (coefficient_size > @@ -6290,10 +6298,10 @@ static VkResult pvr_validate_draw_state(struct pvr_cmd_buffer *cmd_buffer) sub_cmd->disable_compute_overlap = true; } - sub_cmd->frag_uses_atomic_ops |= fragment_state->uses_atomic_ops; - sub_cmd->frag_has_side_effects |= fragment_state->has_side_effects; - sub_cmd->frag_uses_texture_rw |= fragment_state->uses_texture_rw; - sub_cmd->vertex_uses_texture_rw |= vertex_state->uses_texture_rw; + sub_cmd->frag_uses_atomic_ops |= fs_data->common.uses.atomics; + sub_cmd->frag_has_side_effects |= fs_data->common.uses.side_effects; + sub_cmd->frag_uses_texture_rw |= false; + sub_cmd->vertex_uses_texture_rw |= false; sub_cmd->job.get_vis_results = state->vis_test_enabled; @@ -6656,8 +6664,8 @@ static void pvr_emit_vdm_index_list(struct pvr_cmd_buffer *cmd_buffer, uint32_t stride) { struct pvr_cmd_buffer_state *state = &cmd_buffer->state; - const bool vertex_shader_has_side_effects = - state->gfx_pipeline->shader_state.vertex.stage_state.has_side_effects; + + const pco_data *const vs_data = &state->gfx_pipeline->vs_data; struct ROGUE_VDMCTRL_INDEX_LIST0 list_hdr = { pvr_cmd_header( VDMCTRL_INDEX_LIST0) }; pvr_dev_addr_t index_buffer_addr = PVR_DEV_ADDR_INVALID; @@ -6695,7 +6703,7 @@ static void pvr_emit_vdm_index_list(struct pvr_cmd_buffer *cmd_buffer, list_hdr.degen_cull_enable = PVR_HAS_FEATURE(&cmd_buffer->device->pdevice->dev_info, vdm_degenerate_culling) && - !vertex_shader_has_side_effects; + !vs_data->common.uses.side_effects; if (state->draw_state.draw_indirect) { assert(buffer); diff --git a/src/imagination/vulkan/pvr_csb_enum_helpers.h b/src/imagination/vulkan/pvr_csb_enum_helpers.h index eff094471d4..893811cfb8b 100644 --- a/src/imagination/vulkan/pvr_csb_enum_helpers.h +++ b/src/imagination/vulkan/pvr_csb_enum_helpers.h @@ -108,27 +108,6 @@ pvr_zls_format_type_is_int(enum ROGUE_CR_ZLS_FORMAT_TYPE type) } } -/****************************************************************************** - PDS - ******************************************************************************/ - -/* clang-format off */ -static inline enum ROGUE_PDSINST_DOUTU_SAMPLE_RATE -pvr_pdsinst_doutu_sample_rate(enum pvr_msaa_mode msaa_mode) -/* clang-format on */ -{ - switch (msaa_mode) { - case PVR_MSAA_MODE_PIXEL: - return ROGUE_PDSINST_DOUTU_SAMPLE_RATE_INSTANCE; - case PVR_MSAA_MODE_SELECTIVE: - return ROGUE_PDSINST_DOUTU_SAMPLE_RATE_SELECTIVE; - case PVR_MSAA_MODE_FULL: - return ROGUE_PDSINST_DOUTU_SAMPLE_RATE_FULL; - default: - unreachable("Undefined MSAA mode."); - } -} - /****************************************************************************** PBESTATE ******************************************************************************/ diff --git a/src/imagination/vulkan/pvr_hardcode.c b/src/imagination/vulkan/pvr_hardcode.c index 974f5157da7..ce62124141e 100644 --- a/src/imagination/vulkan/pvr_hardcode.c +++ b/src/imagination/vulkan/pvr_hardcode.c @@ -294,10 +294,6 @@ void pvr_hard_code_graphics_get_build_info( data->graphics.vert_shader_states[pipeline_n] ->stage_state.pds_temps_count); - assert(data->graphics.build_infos[pipeline_n]->vert_common_data.coeffs == - data->graphics.vert_shader_states[pipeline_n] - ->stage_state.coefficient_size); - build_data->vs = data->graphics.build_infos[pipeline_n]->stage_data.vs; *common_build_data = data->graphics.build_infos[pipeline_n]->vert_common_data; @@ -311,10 +307,6 @@ void pvr_hard_code_graphics_get_build_info( data->graphics.frag_shader_states[pipeline_n] ->stage_state.pds_temps_count); - assert(data->graphics.build_infos[pipeline_n]->frag_common_data.coeffs == - data->graphics.frag_shader_states[pipeline_n] - ->stage_state.coefficient_size); - build_data->fs = data->graphics.build_infos[pipeline_n]->stage_data.fs; *common_build_data = data->graphics.build_infos[pipeline_n]->frag_common_data; diff --git a/src/imagination/vulkan/pvr_pass.c b/src/imagination/vulkan/pvr_pass.c index 4ee740dfce2..ee654548dfc 100644 --- a/src/imagination/vulkan/pvr_pass.c +++ b/src/imagination/vulkan/pvr_pass.c @@ -40,26 +40,6 @@ #include "vk_log.h" #include "vk_render_pass.h" -/***************************************************************************** - PDS pre-baked program generation parameters and variables. -*****************************************************************************/ -/* These would normally be produced by the compiler or other code. We're using - * them for now just to speed up things. All of these should eventually be - * removed. - */ - -static const struct { - /* Indicates the amount of temporaries for the shader. */ - uint32_t temp_count; - enum pvr_msaa_mode msaa_mode; - /* Indicates the presence of PHAS instruction. */ - bool has_phase_rate_change; -} pvr_pds_fragment_program_params = { - .temp_count = 0, - .msaa_mode = PVR_MSAA_MODE_PIXEL, - .has_phase_rate_change = false, -}; - static inline bool pvr_subpass_has_msaa_input_attachment( struct pvr_render_subpass *subpass, const VkRenderPassCreateInfo2 *pCreateInfo) @@ -330,14 +310,20 @@ pvr_generate_load_op_shader(struct pvr_device *device, if (result != VK_SUCCESS) return result; - result = pvr_pds_fragment_program_create_and_upload( - device, - allocator, - load_op->usc_frag_prog_bo, - pvr_pds_fragment_program_params.temp_count, - pvr_pds_fragment_program_params.msaa_mode, - pvr_pds_fragment_program_params.has_phase_rate_change, - &load_op->pds_frag_prog); + /* TODO: amend this once the hardcoded shaders have been removed. */ + struct pvr_fragment_shader_state fragment_state = { + .bo = load_op->usc_frag_prog_bo, + .sample_rate = ROGUE_PDSINST_DOUTU_SAMPLE_RATE_INSTANCE, + .pds_fragment_program = load_op->pds_frag_prog, + }; + + result = pvr_pds_fragment_program_create_and_upload(device, + allocator, + NULL, + &fragment_state); + load_op->usc_frag_prog_bo = fragment_state.bo; + load_op->pds_frag_prog = fragment_state.pds_fragment_program; + if (result != VK_SUCCESS) goto err_free_usc_frag_prog_bo; diff --git a/src/imagination/vulkan/pvr_pipeline.c b/src/imagination/vulkan/pvr_pipeline.c index eff9aa20fa6..174ac214a97 100644 --- a/src/imagination/vulkan/pvr_pipeline.c +++ b/src/imagination/vulkan/pvr_pipeline.c @@ -34,6 +34,7 @@ #include "hwdef/rogue_hw_utils.h" #include "nir/nir.h" #include "pco/pco.h" +#include "pco/pco_data.h" #include "pvr_bo.h" #include "pvr_csb.h" #include "pvr_csb_enum_helpers.h" @@ -68,34 +69,29 @@ static VkResult pvr_pds_coeff_program_create_and_upload( struct pvr_device *device, const VkAllocationCallbacks *allocator, - const uint32_t *fpu_iterators, - uint32_t fpu_iterators_count, - const uint32_t *destinations, - struct pvr_pds_upload *const pds_upload_out, - uint32_t *const pds_temps_count_out) + struct pvr_pds_coeff_loading_program *program, + struct pvr_fragment_shader_state *fragment_state) { - struct pvr_pds_coeff_loading_program program = { - .num_fpu_iterators = fpu_iterators_count, - }; uint32_t staging_buffer_size; uint32_t *staging_buffer; VkResult result; - assert(fpu_iterators_count < PVR_MAXIMUM_ITERATIONS); + assert(program->num_fpu_iterators < PVR_MAXIMUM_ITERATIONS); /* Get the size of the program and then allocate that much memory. */ - pvr_pds_coefficient_loading(&program, NULL, PDS_GENERATE_SIZES); + pvr_pds_coefficient_loading(program, NULL, PDS_GENERATE_SIZES); - if (!program.code_size) { - pds_upload_out->pvr_bo = NULL; - pds_upload_out->code_size = 0; - pds_upload_out->data_size = 0; - *pds_temps_count_out = 0; + if (!program->code_size) { + fragment_state->pds_coeff_program.pvr_bo = NULL; + fragment_state->pds_coeff_program.code_size = 0; + fragment_state->pds_coeff_program.data_size = 0; + fragment_state->stage_state.pds_temps_count = 0; return VK_SUCCESS; } - staging_buffer_size = PVR_DW_TO_BYTES(program.code_size + program.data_size); + staging_buffer_size = + PVR_DW_TO_BYTES(program->code_size + program->data_size); staging_buffer = vk_alloc2(&device->vk.alloc, allocator, @@ -105,28 +101,21 @@ static VkResult pvr_pds_coeff_program_create_and_upload( if (!staging_buffer) return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); - /* FIXME: Should we save pointers when we redesign the pds gen api ? */ - typed_memcpy(program.FPU_iterators, - fpu_iterators, - program.num_fpu_iterators); - - typed_memcpy(program.destination, destinations, program.num_fpu_iterators); - /* Generate the program into is the staging_buffer. */ - pvr_pds_coefficient_loading(&program, + pvr_pds_coefficient_loading(program, staging_buffer, PDS_GENERATE_CODEDATA_SEGMENTS); /* FIXME: Figure out the define for alignment of 16. */ result = pvr_gpu_upload_pds(device, &staging_buffer[0], - program.data_size, + program->data_size, 16, - &staging_buffer[program.data_size], - program.code_size, + &staging_buffer[program->data_size], + program->code_size, 16, 16, - pds_upload_out); + &fragment_state->pds_coeff_program); if (result != VK_SUCCESS) { vk_free2(&device->vk.alloc, allocator, staging_buffer); return result; @@ -134,7 +123,7 @@ static VkResult pvr_pds_coeff_program_create_and_upload( vk_free2(&device->vk.alloc, allocator, staging_buffer); - *pds_temps_count_out = program.temps_used; + fragment_state->stage_state.pds_temps_count = program->temps_used; return VK_SUCCESS; } @@ -144,30 +133,44 @@ static VkResult pvr_pds_coeff_program_create_and_upload( VkResult pvr_pds_fragment_program_create_and_upload( struct pvr_device *device, const VkAllocationCallbacks *allocator, - const struct pvr_suballoc_bo *fragment_shader_bo, - uint32_t fragment_temp_count, - enum pvr_msaa_mode msaa_mode, - bool has_phase_rate_change, - struct pvr_pds_upload *const pds_upload_out) + pco_shader *fs, + struct pvr_fragment_shader_state *fragment_state) { - const enum ROGUE_PDSINST_DOUTU_SAMPLE_RATE sample_rate = - pvr_pdsinst_doutu_sample_rate(msaa_mode); + /* TODO: remove the below + revert the pvr_pds_setup_doutu + * args and make sure fs isn't NULL instead; + * temporarily in place for hardcoded load ops in + * pvr_pass.c:pvr_generate_load_op_shader() + */ + unsigned temps = 0; + bool has_phase_rate_change = false; + unsigned entry_offset = 0; + + if (fs) { + pco_data *fs_data = pco_shader_data(fs); + temps = fs_data->common.temps; + has_phase_rate_change = fs_data->fs.uses.phase_change; + entry_offset = fs_data->common.entry_offset; + } + struct pvr_pds_kickusc_program program = { 0 }; uint32_t staging_buffer_size; uint32_t *staging_buffer; VkResult result; - /* FIXME: Should it be passing in the USC offset rather than address here? - */ + const pvr_dev_addr_t exec_addr = + PVR_DEV_ADDR_OFFSET(fragment_state->bo->dev_addr, + /* fs_data->common.entry_offset */ entry_offset); + /* Note this is not strictly required to be done before calculating the * staging_buffer_size in this particular case. It can also be done after * allocating the buffer. The size from pvr_pds_kick_usc() is constant. */ - pvr_pds_setup_doutu(&program.usc_task_control, - fragment_shader_bo->dev_addr.addr, - fragment_temp_count, - sample_rate, - has_phase_rate_change); + pvr_pds_setup_doutu( + &program.usc_task_control, + exec_addr.addr, + /* fs_data->common.temps */ temps, + fragment_state->sample_rate, + /* fs_data->fs.uses.phase_change */ has_phase_rate_change); pvr_pds_kick_usc(&program, NULL, 0, false, PDS_GENERATE_SIZES); @@ -196,7 +199,7 @@ VkResult pvr_pds_fragment_program_create_and_upload( program.code_size, 16, 16, - pds_upload_out); + &fragment_state->pds_fragment_program); if (result != VK_SUCCESS) { vk_free2(&device->vk.alloc, allocator, staging_buffer); return result; @@ -384,19 +387,6 @@ static inline void pvr_pds_vertex_attrib_program_destroy( typedef struct pvr_pds_attrib_program (*const pvr_pds_attrib_programs_array_ptr) [PVR_PDS_VERTEX_ATTRIB_PROGRAM_COUNT]; -/* Indicates that the special variable is unused and has not been allocated a - * register. - */ -#define PVR_VERTEX_SPECIAL_VAR_UNUSED (-1) - -/* Each special variable gets allocated its own vtxin reg if used. */ -struct pvr_vertex_special_vars { - /* VertexIndex built-in. */ - int16_t vertex_id_offset; - /* InstanceIndex built-in. */ - int16_t instance_id_offset; -}; - /* Generate and uploads a PDS program for DMAing vertex attribs into USC vertex * inputs. This will bake the code segment and create a template of the data * segment for the command buffer to fill in. @@ -408,37 +398,44 @@ struct pvr_vertex_special_vars { static VkResult pvr_pds_vertex_attrib_programs_create_and_upload( struct pvr_device *device, const VkAllocationCallbacks *const allocator, - const VkPipelineVertexInputStateCreateInfo *const vertex_input_state, - uint32_t usc_temp_count, - const struct rogue_vs_build_data *vs_data, - - /* Needed for the new path. */ - /* TODO: Remove some of the above once the compiler is hooked up. */ + pco_data *shader_data, const struct pvr_pds_vertex_dma dma_descriptions[static const PVR_MAX_VERTEX_ATTRIB_DMAS], uint32_t dma_count, - const struct pvr_vertex_special_vars *special_vars_layout, - pvr_pds_attrib_programs_array_ptr programs_out_ptr) { struct pvr_pds_vertex_primary_program_input input = { .dma_list = dma_descriptions, .dma_count = dma_count, }; + uint32_t usc_temp_count = shader_data->common.temps; struct pvr_pds_attrib_program *const programs_out = *programs_out_ptr; VkResult result; - if (special_vars_layout->vertex_id_offset != PVR_VERTEX_SPECIAL_VAR_UNUSED) { - /* Gets filled by the HW and copied into the appropriate reg. */ + pco_range *sys_vals = shader_data->common.sys_vals; + if (sys_vals[SYSTEM_VALUE_VERTEX_ID].count > 0) { input.flags |= PVR_PDS_VERTEX_FLAGS_VERTEX_ID_REQUIRED; - input.vertex_id_register = special_vars_layout->vertex_id_offset; + input.vertex_id_register = sys_vals[SYSTEM_VALUE_VERTEX_ID].start; } - if (special_vars_layout->instance_id_offset != - PVR_VERTEX_SPECIAL_VAR_UNUSED) { - /* Gets filled by the HW and copied into the appropriate reg. */ + if (sys_vals[SYSTEM_VALUE_INSTANCE_ID].count > 0) { input.flags |= PVR_PDS_VERTEX_FLAGS_INSTANCE_ID_REQUIRED; - input.instance_id_register = special_vars_layout->instance_id_offset; + input.instance_id_register = sys_vals[SYSTEM_VALUE_INSTANCE_ID].start; + } + + if (sys_vals[SYSTEM_VALUE_BASE_INSTANCE].count > 0) { + input.flags |= PVR_PDS_VERTEX_FLAGS_BASE_INSTANCE_REQUIRED; + input.base_instance_register = sys_vals[SYSTEM_VALUE_BASE_INSTANCE].start; + } + + if (sys_vals[SYSTEM_VALUE_BASE_VERTEX].count > 0) { + input.flags |= PVR_PDS_VERTEX_FLAGS_BASE_VERTEX_REQUIRED; + input.base_vertex_register = sys_vals[SYSTEM_VALUE_BASE_VERTEX].start; + } + + if (sys_vals[SYSTEM_VALUE_DRAW_ID].count > 0) { + input.flags |= PVR_PDS_VERTEX_FLAGS_DRAW_INDEX_REQUIRED; + input.draw_index_register = sys_vals[SYSTEM_VALUE_DRAW_ID].start; } pvr_pds_setup_doutu(&input.usc_task_control, @@ -1229,81 +1226,34 @@ pvr_graphics_pipeline_destroy(struct pvr_device *const device, vk_free2(&device->vk.alloc, allocator, gfx_pipeline); } -static void -pvr_vertex_state_init(struct pvr_graphics_pipeline *gfx_pipeline, - const struct rogue_common_build_data *common_data, - uint32_t vtxin_regs_used, - const struct rogue_vs_build_data *vs_data) +static void pvr_vertex_state_save(struct pvr_graphics_pipeline *gfx_pipeline, + pco_shader *vs) { struct pvr_vertex_shader_state *vertex_state = &gfx_pipeline->shader_state.vertex; - /* TODO: Hard coding these for now. These should be populated based on the - * information returned by the compiler. - */ - vertex_state->stage_state.const_shared_reg_count = common_data->shareds; - vertex_state->stage_state.const_shared_reg_offset = 0; - vertex_state->stage_state.coefficient_size = common_data->coeffs; - vertex_state->stage_state.uses_atomic_ops = false; - vertex_state->stage_state.uses_texture_rw = false; - vertex_state->stage_state.uses_barrier = false; - vertex_state->stage_state.has_side_effects = false; - vertex_state->stage_state.empty_program = false; + const pco_data *shader_data = pco_shader_data(vs); + memcpy(&gfx_pipeline->vs_data, shader_data, sizeof(*shader_data)); /* This ends up unused since we'll use the temp_usage for the PDS program we * end up selecting, and the descriptor PDS program doesn't use any temps. * Let's set it to ~0 in case it ever gets used. */ vertex_state->stage_state.pds_temps_count = ~0; - - vertex_state->vertex_input_size = vtxin_regs_used; - vertex_state->vertex_output_size = - vs_data->num_vertex_outputs * ROGUE_REG_SIZE_BYTES; - vertex_state->user_clip_planes_mask = 0; - vertex_state->entry_offset = 0; - - /* TODO: The number of varyings should be checked against the fragment - * shader inputs and assigned in the place where that happens. - * There will also be an opportunity to cull unused fs inputs/vs outputs. - */ - pvr_csb_pack (&gfx_pipeline->shader_state.vertex.varying[0], - TA_STATE_VARYING0, - varying0) { - varying0.f32_linear = vs_data->num_varyings; - varying0.f32_flat = 0; - varying0.f32_npc = 0; - } - - pvr_csb_pack (&gfx_pipeline->shader_state.vertex.varying[1], - TA_STATE_VARYING1, - varying1) { - varying1.f16_linear = 0; - varying1.f16_flat = 0; - varying1.f16_npc = 0; - } } -static void -pvr_fragment_state_init(struct pvr_graphics_pipeline *gfx_pipeline, - const struct rogue_common_build_data *common_data) +static void pvr_fragment_state_save(struct pvr_graphics_pipeline *gfx_pipeline, + pco_shader *fs) { struct pvr_fragment_shader_state *fragment_state = &gfx_pipeline->shader_state.fragment; - /* TODO: Hard coding these for now. These should be populated based on the - * information returned by the compiler. - */ - fragment_state->stage_state.const_shared_reg_count = 0; - fragment_state->stage_state.const_shared_reg_offset = 0; - fragment_state->stage_state.coefficient_size = common_data->coeffs; - fragment_state->stage_state.uses_atomic_ops = false; - fragment_state->stage_state.uses_texture_rw = false; - fragment_state->stage_state.uses_barrier = false; - fragment_state->stage_state.has_side_effects = false; - fragment_state->stage_state.empty_program = false; + const pco_data *shader_data = pco_shader_data(fs); + memcpy(&gfx_pipeline->fs_data, shader_data, sizeof(*shader_data)); + /* TODO: add selection for other values of pass type and sample rate. */ fragment_state->pass_type = ROGUE_TA_PASSTYPE_OPAQUE; - fragment_state->entry_offset = 0; + fragment_state->sample_rate = ROGUE_PDSINST_DOUTU_SAMPLE_RATE_INSTANCE; /* We can't initialize it yet since we still need to generate the PDS * programs so set it to `~0` to make sure that we set this up later on. @@ -1422,34 +1372,19 @@ static uint32_t pvr_graphics_pipeline_alloc_shareds( #undef PVR_DEV_ADDR_SIZE_IN_SH_REGS -/* This is a const pointer to an array of pvr_pds_vertex_dma structs. - * The array being pointed to is of PVR_MAX_VERTEX_ATTRIB_DMAS size. - */ -typedef struct pvr_pds_vertex_dma ( - *const - pvr_pds_attrib_dma_descriptions_array_ptr)[PVR_MAX_VERTEX_ATTRIB_DMAS]; - -static void pvr_graphics_pipeline_alloc_vertex_inputs( - const VkPipelineVertexInputStateCreateInfo *const vs_data, - rogue_vertex_inputs *const vertex_input_layout_out, - unsigned *num_vertex_input_regs_out, - pvr_pds_attrib_dma_descriptions_array_ptr dma_descriptions_out_ptr, - uint32_t *const dma_count_out) +static void pvr_graphics_pipeline_setup_vertex_dma( + pco_shader *vs, + const VkPipelineVertexInputStateCreateInfo *const vertex_input_state, + struct pvr_pds_vertex_dma *const dma_descriptions, + uint32_t *const dma_count) { + pco_vs_data *vs_data = &pco_shader_data(vs)->vs; + const VkVertexInputBindingDescription *sorted_bindings[PVR_MAX_VERTEX_INPUT_BINDINGS] = { 0 }; const VkVertexInputAttributeDescription *sorted_attributes[PVR_MAX_VERTEX_INPUT_BINDINGS] = { 0 }; - rogue_vertex_inputs build_data = { - .num_input_vars = vs_data->vertexAttributeDescriptionCount, - }; - uint32_t next_reg_offset = 0; - - struct pvr_pds_vertex_dma *const dma_descriptions = - *dma_descriptions_out_ptr; - uint32_t dma_count = 0; - /* Vertex attributes map to the `layout(location = x)` annotation in the * shader where `x` is the attribute's location. * Vertex bindings have NO relation to the shader. They have nothing to do @@ -1460,60 +1395,40 @@ static void pvr_graphics_pipeline_alloc_vertex_inputs( * from, to fill in the collection of vertex attributes. */ - for (uint32_t i = 0; i < vs_data->vertexBindingDescriptionCount; i++) { + for (uint32_t i = 0; i < vertex_input_state->vertexBindingDescriptionCount; + i++) { const VkVertexInputBindingDescription *binding_desc = - &vs_data->pVertexBindingDescriptions[i]; + &vertex_input_state->pVertexBindingDescriptions[i]; sorted_bindings[binding_desc->binding] = binding_desc; } - for (uint32_t i = 0; i < vs_data->vertexAttributeDescriptionCount; i++) { + for (uint32_t i = 0; i < vertex_input_state->vertexAttributeDescriptionCount; + i++) { const VkVertexInputAttributeDescription *attribute_desc = - &vs_data->pVertexAttributeDescriptions[i]; + &vertex_input_state->pVertexAttributeDescriptions[i]; sorted_attributes[attribute_desc->location] = attribute_desc; } - for (uint32_t i = 0, j = 0; i < ARRAY_SIZE(sorted_attributes); i++) { - if (sorted_attributes[i]) - sorted_attributes[j++] = sorted_attributes[i]; - } - - for (uint32_t i = 0; i < vs_data->vertexAttributeDescriptionCount; i++) { + for (uint32_t i = 0; i < vertex_input_state->vertexAttributeDescriptionCount; + i++) { const VkVertexInputAttributeDescription *attribute = sorted_attributes[i]; + if (!attribute) + continue; + + gl_vert_attrib location = attribute->location + VERT_ATTRIB_GENERIC0; const VkVertexInputBindingDescription *binding = sorted_bindings[attribute->binding]; + struct pvr_pds_vertex_dma *dma_desc = &dma_descriptions[*dma_count]; const struct util_format_description *fmt_description = vk_format_description(attribute->format); - struct pvr_pds_vertex_dma *dma_desc = &dma_descriptions[dma_count]; - unsigned vtxin_reg_offset; - /* Reg allocation. */ + const pco_range *attrib_range = &vs_data->attribs[location]; - vtxin_reg_offset = next_reg_offset; - build_data.base[i] = vtxin_reg_offset; - - if (fmt_description->colorspace != UTIL_FORMAT_COLORSPACE_RGB || - fmt_description->layout != UTIL_FORMAT_LAYOUT_PLAIN || - fmt_description->block.bits % 32 != 0 || !fmt_description->is_array) { - /* For now we only support formats with 32 bit components since we - * don't need to pack/unpack them. - */ - /* TODO: Support any other format with VERTEX_BUFFER_BIT set that - * doesn't have 32 bit components if we're advertising any. - */ - assert(false); - } - - /* TODO: Check if this is fine with the compiler. Does it want the amount - * of components or does it want a size in dwords to figure out how many - * vtxin regs are covered. For formats with 32 bit components the - * distinction doesn't change anything. - */ - build_data.components[i] = - util_format_get_nr_components(fmt_description->format); - - next_reg_offset += build_data.components[i]; + /* Skip unused attributes. */ + if (!attrib_range->count) + continue; /* DMA setup. */ @@ -1559,11 +1474,12 @@ static void pvr_graphics_pipeline_alloc_vertex_inputs( dma_desc->flags = 0; /* Size to DMA per vertex attribute. Used to setup src3 in the DDMAD. */ - assert(fmt_description->block.bits != 0); /* Likely an unsupported fmt. */ - dma_desc->size_in_dwords = fmt_description->block.bits / 32; + /* TODO: what if not all components are used */ + assert(attrib_range->count == fmt_description->block.bits / 32); + dma_desc->size_in_dwords = attrib_range->count; /* Vtxin reg offset to start DMAing into. */ - dma_desc->destination = vtxin_reg_offset; + dma_desc->destination = attrib_range->start; /* Will be used by the driver to figure out buffer address to patch in the * data section. I.e. which binding we should DMA from. @@ -1574,6 +1490,7 @@ static void pvr_graphics_pipeline_alloc_vertex_inputs( * repeating of instance-rate vertex attributes needed. We should always * move on to the next vertex attribute. */ + assert(binding->inputRate != VK_VERTEX_INPUT_RATE_INSTANCE); dma_desc->divisor = 1; /* Will be used to generate PDS code that takes care of robust buffer @@ -1589,39 +1506,577 @@ static void pvr_graphics_pipeline_alloc_vertex_inputs( dma_desc->component_size_in_bytes = fmt_description->block.bits / fmt_description->nr_channels / 8; - dma_count++; - }; - - *vertex_input_layout_out = build_data; - *num_vertex_input_regs_out = next_reg_offset; - *dma_count_out = dma_count; + ++*dma_count; + } } -static void pvr_graphics_pipeline_alloc_vertex_special_vars( - unsigned *num_vertex_input_regs, - struct pvr_vertex_special_vars *special_vars_layout_out) +static void pvr_graphics_pipeline_setup_fragment_coeff_program( + pco_fs_data *fs_data, + pco_vs_data *vs_data, + nir_shader *fs, + struct pvr_pds_coeff_loading_program *frag_coeff_program) { - unsigned next_free_reg = *num_vertex_input_regs; - struct pvr_vertex_special_vars layout; + uint64_t varyings_used = fs->info.inputs_read & + BITFIELD64_RANGE(VARYING_SLOT_VAR0, MAX_VARYING); - /* We don't support VK_KHR_shader_draw_parameters or Vulkan 1.1 so no - * BaseInstance, BaseVertex, DrawIndex. - */ + unsigned fpu = 0; + unsigned dest = 0; - /* TODO: The shader might not necessarily be using this so we'd just be - * wasting regs. Get the info from the compiler about whether or not the - * shader uses them and allocate them accordingly. For now we'll set them up - * regardless. - */ + if (fs_data->uses.z) { + pvr_csb_pack (&frag_coeff_program->FPU_iterators[fpu], + PDSINST_DOUT_FIELDS_DOUTI_SRC, + douti_src) { + /* TODO: define instead of sizeof(uint16_t). */ + douti_src.f32_offset = fs_data->uses.w ? 1 * sizeof(uint16_t) : 0; + douti_src.f16_offset = douti_src.f32_offset; + douti_src.shademodel = ROGUE_PDSINST_DOUTI_SHADEMODEL_GOURUAD; + douti_src.size = ROGUE_PDSINST_DOUTI_SIZE_1D; + } - layout.vertex_id_offset = (int16_t)next_free_reg; - next_free_reg++; + frag_coeff_program->destination[fpu++] = dest++; + } - layout.instance_id_offset = (int16_t)next_free_reg; - next_free_reg++; + if (fs_data->uses.w) { + pvr_csb_pack (&frag_coeff_program->FPU_iterators[fpu], + PDSINST_DOUT_FIELDS_DOUTI_SRC, + douti_src) { + douti_src.f32_offset = 0; + douti_src.f16_offset = douti_src.f32_offset; + douti_src.shademodel = ROGUE_PDSINST_DOUTI_SHADEMODEL_GOURUAD; + douti_src.size = ROGUE_PDSINST_DOUTI_SIZE_1D; + } - *num_vertex_input_regs = next_free_reg; - *special_vars_layout_out = layout; + frag_coeff_program->destination[fpu++] = dest++; + } + + if (fs_data->uses.pntc) { + pvr_csb_pack (&frag_coeff_program->FPU_iterators[fpu], + PDSINST_DOUT_FIELDS_DOUTI_SRC, + douti_src) { + douti_src.shademodel = ROGUE_PDSINST_DOUTI_SHADEMODEL_GOURUAD; + douti_src.size = ROGUE_PDSINST_DOUTI_SIZE_2D; + douti_src.pointsprite = true; + } + + frag_coeff_program->destination[fpu++] = dest; + dest += 2; + } + + u_foreach_bit64 (varying, varyings_used) { + nir_variable *var = + nir_find_variable_with_location(fs, nir_var_shader_in, varying); + assert(var); + + pco_range *cf_range = &fs_data->varyings[varying]; + assert(cf_range->count > 0); + assert(!(cf_range->start % ROGUE_USC_COEFFICIENT_SET_SIZE)); + assert(!(cf_range->count % ROGUE_USC_COEFFICIENT_SET_SIZE)); + + pco_range *vtxout_range = &vs_data->varyings[varying]; + assert(vtxout_range->count > 0); + assert(vtxout_range->start >= 4); + + assert(vtxout_range->count == + cf_range->count / ROGUE_USC_COEFFICIENT_SET_SIZE); + + unsigned count = vtxout_range->count; + + unsigned vtxout = vtxout_range->start; + + /* pos.x, pos.y unused. */ + vtxout -= 2; + + /* pos.z unused. */ + if (!fs_data->uses.z) + vtxout -= 1; + + /* pos.w unused. */ + if (!fs_data->uses.w) + vtxout -= 1; + + pvr_csb_pack (&frag_coeff_program->FPU_iterators[fpu], + PDSINST_DOUT_FIELDS_DOUTI_SRC, + douti_src) { + /* TODO: define instead of sizeof(uint16_t). */ + douti_src.f32_offset = vtxout * sizeof(uint16_t); + /* TODO: f16 support. */ + douti_src.f16 = false; + douti_src.f16_offset = douti_src.f32_offset; + + switch (var->data.interpolation) { + case INTERP_MODE_SMOOTH: + douti_src.shademodel = ROGUE_PDSINST_DOUTI_SHADEMODEL_GOURUAD; + douti_src.perspective = true; + break; + + case INTERP_MODE_NOPERSPECTIVE: + douti_src.shademodel = ROGUE_PDSINST_DOUTI_SHADEMODEL_GOURUAD; + break; + + case INTERP_MODE_FLAT: + /* TODO: triangle fan, provoking vertex last. */ + douti_src.shademodel = ROGUE_PDSINST_DOUTI_SHADEMODEL_FLAT_VERTEX0; + break; + + default: + unreachable("Unimplemented interpolation type."); + } + + douti_src.size = ROGUE_PDSINST_DOUTI_SIZE_1D + count - 1; + } + + frag_coeff_program->destination[fpu++] = + cf_range->start / ROGUE_USC_COEFFICIENT_SET_SIZE; + } + + frag_coeff_program->num_fpu_iterators = fpu; +} + +static void set_var(pco_range *allocation_list, + unsigned to, + nir_variable *var, + unsigned dwords_each) +{ + unsigned slots = glsl_count_dword_slots(var->type, false); + + allocation_list[var->data.location] = (pco_range){ + .start = to, + .count = slots * dwords_each, + }; +} + +static void allocate_var(pco_range *allocation_list, + unsigned *counter, + nir_variable *var, + unsigned dwords_each) +{ + unsigned slots = glsl_count_dword_slots(var->type, false); + + allocation_list[var->data.location] = (pco_range){ + .start = *counter, + .count = slots * dwords_each, + }; + + *counter += slots * dwords_each; +} + +static void try_allocate_var(pco_range *allocation_list, + unsigned *counter, + nir_shader *nir, + uint64_t bitset, + nir_variable_mode mode, + int location, + unsigned dwords_each) +{ + nir_variable *var = nir_find_variable_with_location(nir, mode, location); + + if (!(bitset & BITFIELD64_BIT(location))) + return; + + assert(var); + + allocate_var(allocation_list, counter, var, dwords_each); +} + +static void try_allocate_vars(pco_range *allocation_list, + unsigned *counter, + nir_shader *nir, + uint64_t *bitset, + nir_variable_mode mode, + bool f16, + enum glsl_interp_mode interp_mode, + unsigned dwords_each) +{ + uint64_t skipped = 0; + + while (*bitset) { + int location = u_bit_scan64(bitset); + + nir_variable *var = nir_find_variable_with_location(nir, mode, location); + assert(var); + + if (glsl_type_is_16bit(glsl_without_array_or_matrix(var->type)) != f16 || + var->data.interpolation != interp_mode) { + skipped |= BITFIELD64_BIT(location); + continue; + } + + allocate_var(allocation_list, counter, var, dwords_each); + } + + *bitset |= skipped; +} + +static void allocate_val(pco_range *allocation_list, + unsigned *counter, + unsigned location, + unsigned dwords_each) +{ + allocation_list[location] = (pco_range){ + .start = *counter, + .count = dwords_each, + }; + + *counter += dwords_each; +} + +static void pvr_alloc_vs_sysvals(pco_data *data, nir_shader *nir) +{ + BITSET_DECLARE(system_values_read, SYSTEM_VALUE_MAX); + BITSET_COPY(system_values_read, nir->info.system_values_read); + + gl_system_value sys_vals[] = { + SYSTEM_VALUE_VERTEX_ID, SYSTEM_VALUE_INSTANCE_ID, + SYSTEM_VALUE_BASE_INSTANCE, SYSTEM_VALUE_BASE_VERTEX, + SYSTEM_VALUE_DRAW_ID, + }; + + for (unsigned u = 0; u < ARRAY_SIZE(sys_vals); ++u) { + if (BITSET_TEST(system_values_read, sys_vals[u])) { + allocate_val(data->common.sys_vals, + &data->common.vtxins, + sys_vals[u], + 1); + + BITSET_CLEAR(system_values_read, sys_vals[u]); + } + } + + assert(BITSET_IS_EMPTY(system_values_read)); +} + +static void pvr_init_vs_attribs( + pco_data *data, + const VkPipelineVertexInputStateCreateInfo *const vertex_input_state) +{ + for (unsigned u = 0; u < vertex_input_state->vertexAttributeDescriptionCount; + ++u) { + const VkVertexInputAttributeDescription *attrib = + &vertex_input_state->pVertexAttributeDescriptions[u]; + + gl_vert_attrib location = attrib->location + VERT_ATTRIB_GENERIC0; + + data->vs.attrib_formats[location] = + vk_format_to_pipe_format(attrib->format); + } +} + +static void pvr_alloc_vs_attribs(pco_data *data, nir_shader *nir) +{ + /* TODO NEXT: this should be based on the format size. */ + nir_foreach_shader_in_variable (var, nir) { + allocate_var(data->vs.attribs, &data->common.vtxins, var, 1); + } +} + +static void pvr_alloc_vs_varyings(pco_data *data, nir_shader *nir) +{ + uint64_t vars_mask = nir->info.outputs_written & + BITFIELD64_RANGE(VARYING_SLOT_VAR0, MAX_VARYING); + + /* Output position must be present. */ + assert(nir_find_variable_with_location(nir, + nir_var_shader_out, + VARYING_SLOT_POS)); + + /* Varying ordering is specific. */ + try_allocate_var(data->vs.varyings, + &data->vs.vtxouts, + nir, + nir->info.outputs_written, + nir_var_shader_out, + VARYING_SLOT_POS, + 1); + + /* Save varying counts. */ + u_foreach_bit64 (location, vars_mask) { + nir_variable *var = + nir_find_variable_with_location(nir, nir_var_shader_out, location); + assert(var); + + /* TODO: f16 support. */ + bool f16 = glsl_type_is_16bit(glsl_without_array_or_matrix(var->type)); + assert(!f16); + unsigned components = glsl_get_components(var->type); + + switch (var->data.interpolation) { + case INTERP_MODE_SMOOTH: + if (f16) + data->vs.f16_smooth += components; + else + data->vs.f32_smooth += components; + + break; + + case INTERP_MODE_FLAT: + if (f16) + data->vs.f16_flat += components; + else + data->vs.f32_flat += components; + + break; + + case INTERP_MODE_NOPERSPECTIVE: + if (f16) + data->vs.f16_npc += components; + else + data->vs.f32_npc += components; + + break; + + default: + unreachable(); + } + } + + for (unsigned f16 = 0; f16 <= 1; ++f16) { + for (enum glsl_interp_mode interp_mode = INTERP_MODE_SMOOTH; + interp_mode <= INTERP_MODE_NOPERSPECTIVE; + ++interp_mode) { + try_allocate_vars(data->vs.varyings, + &data->vs.vtxouts, + nir, + &vars_mask, + nir_var_shader_out, + f16, + interp_mode, + 1); + } + } + + assert(!vars_mask); + + const gl_varying_slot last_slots[] = { + VARYING_SLOT_PSIZ, + VARYING_SLOT_VIEWPORT, + VARYING_SLOT_LAYER, + }; + + for (unsigned u = 0; u < ARRAY_SIZE(last_slots); ++u) { + try_allocate_var(data->vs.varyings, + &data->vs.vtxouts, + nir, + nir->info.outputs_written, + nir_var_shader_out, + last_slots[u], + 1); + } +} + +static void pvr_alloc_fs_sysvals(pco_data *data, nir_shader *nir) +{ + /* TODO */ +} + +static void pvr_alloc_fs_varyings(pco_data *data, nir_shader *nir) +{ + assert(!data->common.coeffs); + + /* Save the z/w locations. */ + unsigned zw_count = !!data->fs.uses.z + !!data->fs.uses.w; + allocate_val(data->fs.varyings, + &data->common.coeffs, + VARYING_SLOT_POS, + zw_count * ROGUE_USC_COEFFICIENT_SET_SIZE); + + /* If point coords are used, they come after z/w (if present). */ + nir_variable *var = nir_find_variable_with_location(nir, + nir_var_shader_in, + VARYING_SLOT_PNTC); + if (var) { + assert(!var->data.location_frac); + unsigned count = glsl_get_components(var->type); + assert(count == 2); + + allocate_var(data->fs.varyings, + &data->common.coeffs, + var, + ROGUE_USC_COEFFICIENT_SET_SIZE); + + data->fs.uses.pntc = true; + } + + /* Allocate the rest of the input varyings. */ + nir_foreach_shader_in_variable (var, nir) { + /* Already handled. */ + if (var->data.location == VARYING_SLOT_POS || + var->data.location == VARYING_SLOT_PNTC) + continue; + + allocate_var(data->fs.varyings, + &data->common.coeffs, + var, + ROGUE_USC_COEFFICIENT_SET_SIZE); + } +} + +static void +pvr_init_fs_outputs(pco_data *data, + const struct pvr_render_pass *pass, + const struct pvr_render_subpass *const subpass, + const struct pvr_renderpass_hwsetup_subpass *hw_subpass) +{ + for (unsigned u = 0; u < subpass->color_count; ++u) { + unsigned idx = subpass->color_attachments[u]; + if (idx == VK_ATTACHMENT_UNUSED) + continue; + + gl_frag_result location = FRAG_RESULT_DATA0 + u; + VkFormat vk_format = pass->attachments[idx].vk_format; + data->fs.output_formats[location] = vk_format_to_pipe_format(vk_format); + } + + /* TODO: z-replicate. */ +} + +static void +pvr_setup_fs_outputs(pco_data *data, + nir_shader *nir, + const struct pvr_render_subpass *const subpass, + const struct pvr_renderpass_hwsetup_subpass *hw_subpass) +{ + ASSERTED unsigned num_outputs = hw_subpass->setup.num_render_targets; + assert(num_outputs == subpass->color_count); + + uint64_t outputs_written = nir->info.outputs_written; + assert(util_bitcount64(outputs_written) == num_outputs); + + for (unsigned u = 0; u < subpass->color_count; ++u) { + gl_frag_result location = FRAG_RESULT_DATA0 + u; + unsigned idx = subpass->color_attachments[u]; + const struct usc_mrt_resource *mrt_resource; + ASSERTED bool output_reg; + enum pipe_format format; + unsigned format_bits; + nir_variable *var; + + if (idx == VK_ATTACHMENT_UNUSED) + continue; + + assert(u == idx); /* TODO: not sure if this is true or not... */ + + mrt_resource = &hw_subpass->setup.mrt_resources[u]; + output_reg = mrt_resource->type == USC_MRT_RESOURCE_TYPE_OUTPUT_REG; + + assert(output_reg); + /* TODO: tile buffer support. */ + + var = nir_find_variable_with_location(nir, nir_var_shader_out, location); + assert(var); + + format = data->fs.output_formats[location]; + format_bits = util_format_get_blocksizebits(format); + /* TODO: other sized formats. */ + assert(!(format_bits % 32)); + + assert(mrt_resource->intermediate_size == format_bits / 8); + + set_var(data->fs.outputs, + mrt_resource->reg.output_reg, + var, + format_bits / 32); + data->fs.output_reg[location] = output_reg; + + outputs_written &= ~BITFIELD64_BIT(location); + } + + /* TODO: z-replicate. */ + + assert(!outputs_written); +} + +static void pvr_init_fs_input_attachments( + pco_data *data, + const struct pvr_render_subpass *const subpass, + const struct pvr_renderpass_hwsetup_subpass *hw_subpass) +{ + pvr_finishme("pvr_init_fs_input_attachments"); +} + +static void pvr_setup_fs_input_attachments( + pco_data *data, + nir_shader *nir, + const struct pvr_render_subpass *const subpass, + const struct pvr_renderpass_hwsetup_subpass *hw_subpass) +{ + pvr_finishme("pvr_setup_fs_input_attachments"); +} + +static void +pvr_preprocess_shader_data(pco_data *data, + nir_shader *nir, + const VkGraphicsPipelineCreateInfo *pCreateInfo) +{ + switch (nir->info.stage) { + case MESA_SHADER_VERTEX: { + const VkPipelineVertexInputStateCreateInfo *const vertex_input_state = + pCreateInfo->pVertexInputState; + + pvr_init_vs_attribs(data, vertex_input_state); + break; + } + + case MESA_SHADER_FRAGMENT: { + PVR_FROM_HANDLE(pvr_render_pass, pass, pCreateInfo->renderPass); + const struct pvr_render_subpass *const subpass = + &pass->subpasses[pCreateInfo->subpass]; + const struct pvr_renderpass_hw_map *subpass_map = + &pass->hw_setup->subpass_map[pCreateInfo->subpass]; + const struct pvr_renderpass_hwsetup_subpass *hw_subpass = + &pass->hw_setup->renders[subpass_map->render] + .subpasses[subpass_map->subpass]; + + pvr_init_fs_outputs(data, pass, subpass, hw_subpass); + pvr_init_fs_input_attachments(data, subpass, hw_subpass); + + /* TODO: push consts, blend consts, dynamic state, etc. */ + break; + } + + default: + unreachable(); + } + + /* TODO: common things, like large constants being put into shareds. */ +} + +static void +pvr_postprocess_shader_data(pco_data *data, + nir_shader *nir, + const VkGraphicsPipelineCreateInfo *pCreateInfo) +{ + switch (nir->info.stage) { + case MESA_SHADER_VERTEX: { + pvr_alloc_vs_sysvals(data, nir); + pvr_alloc_vs_attribs(data, nir); + pvr_alloc_vs_varyings(data, nir); + break; + } + + case MESA_SHADER_FRAGMENT: { + PVR_FROM_HANDLE(pvr_render_pass, pass, pCreateInfo->renderPass); + const struct pvr_render_subpass *const subpass = + &pass->subpasses[pCreateInfo->subpass]; + const struct pvr_renderpass_hw_map *subpass_map = + &pass->hw_setup->subpass_map[pCreateInfo->subpass]; + const struct pvr_renderpass_hwsetup_subpass *hw_subpass = + &pass->hw_setup->renders[subpass_map->render] + .subpasses[subpass_map->subpass]; + + pvr_alloc_fs_sysvals(data, nir); + pvr_alloc_fs_varyings(data, nir); + pvr_setup_fs_outputs(data, nir, subpass, hw_subpass); + pvr_setup_fs_input_attachments(data, nir, subpass, hw_subpass); + + /* TODO: push consts, blend consts, dynamic state, etc. */ + break; + } + + default: + unreachable(); + } + + /* TODO: common things, like large constants being put into shareds. */ } /* Compiles and uploads shaders and PDS programs. */ @@ -1637,42 +2092,36 @@ pvr_graphics_pipeline_compile(struct pvr_device *const device, &layout->sh_reg_layout_per_stage[PVR_STAGE_ALLOCATION_VERTEX_GEOMETRY]; struct pvr_sh_reg_layout *sh_reg_layout_frag = &layout->sh_reg_layout_per_stage[PVR_STAGE_ALLOCATION_FRAGMENT]; - const VkPipelineVertexInputStateCreateInfo *const vertex_input_state = - pCreateInfo->pVertexInputState; const uint32_t cache_line_size = rogue_get_slc_cache_line_size(&device->pdevice->dev_info); - struct rogue_compiler *compiler = device->pdevice->compiler; - struct rogue_build_ctx *ctx = NULL; VkResult result; + struct pvr_vertex_shader_state *vertex_state = + &gfx_pipeline->shader_state.vertex; + struct pvr_fragment_shader_state *fragment_state = + &gfx_pipeline->shader_state.fragment; + pco_ctx *pco_ctx = device->pdevice->pco_ctx; const struct spirv_to_nir_options *spirv_options = pco_spirv_options(pco_ctx); const nir_shader_compiler_options *nir_options = pco_nir_options(pco_ctx); nir_shader *producer = NULL; + nir_shader *consumer = NULL; + pco_data shader_data[MESA_SHADER_STAGES] = { 0 }; nir_shader *nir_shaders[MESA_SHADER_STAGES] = { 0 }; pco_shader *pco_shaders[MESA_SHADER_STAGES] = { 0 }; + pco_shader **vs = &pco_shaders[MESA_SHADER_VERTEX]; + pco_shader **fs = &pco_shaders[MESA_SHADER_FRAGMENT]; void *shader_mem_ctx = ralloc_context(NULL); - /* Vars needed for the new path. */ struct pvr_pds_vertex_dma vtx_dma_descriptions[PVR_MAX_VERTEX_ATTRIB_DMAS]; uint32_t vtx_dma_count = 0; - rogue_vertex_inputs *vertex_input_layout; - unsigned *vertex_input_reg_count; - /* TODO: The compiler should be making use of this to determine where - * specific special variables are located in the vtxin reg set. - */ - struct pvr_vertex_special_vars special_vars_layout = { 0 }; - - uint32_t sh_count[PVR_STAGE_ALLOCATION_COUNT] = { 0 }; + struct pvr_pds_coeff_loading_program frag_coeff_program = { 0 }; for (gl_shader_stage stage = 0; stage < MESA_SHADER_STAGES; ++stage) { - nir_shader **nir = &nir_shaders[stage]; size_t stage_index = gfx_pipeline->stage_indices[stage]; - const VkPipelineShaderStageCreateInfo *create_info = - &pCreateInfo->pStages[stage_index]; /* Skip unused/inactive stages. */ if (stage_index == ~0) @@ -1681,26 +2130,61 @@ pvr_graphics_pipeline_compile(struct pvr_device *const device, result = vk_pipeline_shader_stage_to_nir(&device->vk, gfx_pipeline->base.pipeline_flags, - create_info, + &pCreateInfo->pStages[stage_index], spirv_options, nir_options, shader_mem_ctx, - nir); + &nir_shaders[stage]); if (result != VK_SUCCESS) goto err_free_build_context; - pco_preprocess_nir(pco_ctx, *nir); - if (producer) - pco_link_nir(pco_ctx, producer, *nir); - - pco_lower_nir(pco_ctx, *nir); - pvr_lower_nir(pco_ctx, layout, *nir); - - pco_postprocess_nir(pco_ctx, *nir); - - producer = *nir; + pco_preprocess_nir(pco_ctx, nir_shaders[stage]); } + for (gl_shader_stage stage = 0; stage < MESA_SHADER_STAGES; ++stage) { + if (!nir_shaders[stage]) + continue; + + if (producer) + pco_link_nir(pco_ctx, producer, nir_shaders[stage]); + + producer = nir_shaders[stage]; + } + + for (gl_shader_stage stage = MESA_SHADER_STAGES; stage-- > 0;) { + if (!nir_shaders[stage]) + continue; + + if (consumer) + pco_rev_link_nir(pco_ctx, nir_shaders[stage], consumer); + + consumer = nir_shaders[stage]; + } + + for (gl_shader_stage stage = 0; stage < MESA_SHADER_STAGES; ++stage) { + if (!nir_shaders[stage]) + continue; + + pvr_preprocess_shader_data(&shader_data[stage], + nir_shaders[stage], + pCreateInfo); + + pco_lower_nir(pco_ctx, nir_shaders[stage], &shader_data[stage]); + pvr_lower_nir(pco_ctx, layout, nir_shaders[stage]); + + pco_postprocess_nir(pco_ctx, nir_shaders[stage], &shader_data[stage]); + + pvr_postprocess_shader_data(&shader_data[stage], + nir_shaders[stage], + pCreateInfo); + } + + /* TODO NEXT: setup shareds/for descriptors, here or in + * pvr_{pre,post}process_shader_data. + */ + memset(sh_reg_layout_vert, 0, sizeof(*sh_reg_layout_vert)); + memset(sh_reg_layout_frag, 0, sizeof(*sh_reg_layout_frag)); + for (gl_shader_stage stage = 0; stage < MESA_SHADER_STAGES; ++stage) { pco_shader **pco = &pco_shaders[stage]; @@ -1708,7 +2192,10 @@ pvr_graphics_pipeline_compile(struct pvr_device *const device, if (!nir_shaders[stage]) continue; - *pco = pco_trans_nir(pco_ctx, nir_shaders[stage], shader_mem_ctx); + *pco = pco_trans_nir(pco_ctx, + nir_shaders[stage], + &shader_data[stage], + shader_mem_ctx); if (!*pco) { result = VK_ERROR_INITIALIZATION_FAILED; goto err_free_build_context; @@ -1719,125 +2206,37 @@ pvr_graphics_pipeline_compile(struct pvr_device *const device, pco_shader_finalize(pco_ctx, *pco); } - /* Setup shared build context. */ - ctx = rogue_build_context_create(compiler, layout); - if (!ctx) - return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); + pvr_graphics_pipeline_setup_vertex_dma(*vs, + pCreateInfo->pVertexInputState, + vtx_dma_descriptions, + &vtx_dma_count); - vertex_input_layout = &ctx->stage_data.vs.inputs; - vertex_input_reg_count = &ctx->stage_data.vs.num_vertex_input_regs; + pvr_vertex_state_save(gfx_pipeline, *vs); - pvr_graphics_pipeline_alloc_vertex_inputs(vertex_input_state, - vertex_input_layout, - vertex_input_reg_count, - &vtx_dma_descriptions, - &vtx_dma_count); - - pvr_graphics_pipeline_alloc_vertex_special_vars(vertex_input_reg_count, - &special_vars_layout); - - for (enum pvr_stage_allocation pvr_stage = - PVR_STAGE_ALLOCATION_VERTEX_GEOMETRY; - pvr_stage < PVR_STAGE_ALLOCATION_COMPUTE; - ++pvr_stage) - sh_count[pvr_stage] = pvr_pipeline_alloc_shareds( - device, - layout, - pvr_stage, - &layout->sh_reg_layout_per_stage[pvr_stage]); - - /* NIR middle-end translation. */ - for (gl_shader_stage stage = MESA_SHADER_FRAGMENT; stage > MESA_SHADER_NONE; - stage--) { - const VkPipelineShaderStageCreateInfo *create_info; - size_t stage_index = gfx_pipeline->stage_indices[stage]; - - /* Skip unused/inactive stages. */ - if (stage_index == ~0) - continue; - - create_info = &pCreateInfo->pStages[stage_index]; - - /* SPIR-V to NIR. */ - ctx->nir[stage] = pvr_spirv_to_nir(ctx, stage, create_info); - if (!ctx->nir[stage]) { - ralloc_free(ctx); - return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); - } - } - - /* Pre-back-end analysis and optimization, driver data extraction. */ - /* TODO: Analyze and cull unused I/O between stages. */ - /* TODO: Allocate UBOs between stages; - * pipeline->layout->set_{count,layout}. - */ - - /* Back-end translation. */ - for (gl_shader_stage stage = MESA_SHADER_FRAGMENT; stage > MESA_SHADER_NONE; - stage--) { - if (!ctx->nir[stage]) - continue; - - ctx->rogue[stage] = pvr_nir_to_rogue(ctx, ctx->nir[stage]); - if (!ctx->rogue[stage]) { - ralloc_free(ctx); - return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); - } - - pvr_rogue_to_binary(ctx, ctx->rogue[stage], &ctx->binary[stage]); - if (!ctx->binary[stage].size) { - ralloc_free(ctx); - return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); - } - } - - pvr_vertex_state_init(gfx_pipeline, - &ctx->common_data[MESA_SHADER_VERTEX], - *vertex_input_reg_count, - &ctx->stage_data.vs); - - struct pvr_vertex_shader_state *vertex_state = - &gfx_pipeline->shader_state.vertex; - - /* FIXME: For now we just overwrite it but the compiler shouldn't be - * returning the sh count since the driver is in charge of - * allocating them. - */ - vertex_state->stage_state.const_shared_reg_count = - sh_count[PVR_STAGE_ALLOCATION_VERTEX_GEOMETRY]; - - gfx_pipeline->shader_state.vertex.vertex_input_size = - ctx->stage_data.vs.num_vertex_input_regs; - - result = - pvr_gpu_upload_usc(device, - util_dynarray_begin(&ctx->binary[MESA_SHADER_VERTEX]), - ctx->binary[MESA_SHADER_VERTEX].size, - cache_line_size, - &gfx_pipeline->shader_state.vertex.bo); + result = pvr_gpu_upload_usc( + device, + pco_shader_binary_data(pco_shaders[MESA_SHADER_VERTEX]), + pco_shader_binary_size(pco_shaders[MESA_SHADER_VERTEX]), + cache_line_size, + &vertex_state->bo); if (result != VK_SUCCESS) goto err_free_build_context; - if (ctx->nir[MESA_SHADER_FRAGMENT]) { - struct pvr_fragment_shader_state *fragment_state = - &gfx_pipeline->shader_state.fragment; + if (pco_shaders[MESA_SHADER_FRAGMENT]) { + pvr_graphics_pipeline_setup_fragment_coeff_program( + &pco_shader_data(pco_shaders[MESA_SHADER_FRAGMENT])->fs, + &pco_shader_data(pco_shaders[MESA_SHADER_VERTEX])->vs, + nir_shaders[MESA_SHADER_FRAGMENT], + &frag_coeff_program); - pvr_fragment_state_init(gfx_pipeline, - &ctx->common_data[MESA_SHADER_FRAGMENT]); - - /* FIXME: For now we just overwrite it but the compiler shouldn't - * be returning the sh count since the driver is in charge of - * allocating them. - */ - fragment_state->stage_state.const_shared_reg_count = - sh_count[PVR_STAGE_ALLOCATION_FRAGMENT]; + pvr_fragment_state_save(gfx_pipeline, *fs); result = pvr_gpu_upload_usc( device, - util_dynarray_begin(&ctx->binary[MESA_SHADER_FRAGMENT]), - ctx->binary[MESA_SHADER_FRAGMENT].size, + pco_shader_binary_data(pco_shaders[MESA_SHADER_FRAGMENT]), + pco_shader_binary_size(pco_shaders[MESA_SHADER_FRAGMENT]), cache_line_size, - &gfx_pipeline->shader_state.fragment.bo); + &fragment_state->bo); if (result != VK_SUCCESS) goto err_free_vertex_bo; @@ -1846,25 +2245,17 @@ pvr_graphics_pipeline_compile(struct pvr_device *const device, * since in our case the optimization doesn't happen. */ - result = pvr_pds_coeff_program_create_and_upload( - device, - allocator, - ctx->stage_data.fs.iterator_args.fpu_iterators, - ctx->stage_data.fs.iterator_args.num_fpu_iterators, - ctx->stage_data.fs.iterator_args.destination, - &fragment_state->pds_coeff_program, - &fragment_state->stage_state.pds_temps_count); + result = pvr_pds_coeff_program_create_and_upload(device, + allocator, + &frag_coeff_program, + fragment_state); if (result != VK_SUCCESS) goto err_free_fragment_bo; - result = pvr_pds_fragment_program_create_and_upload( - device, - allocator, - gfx_pipeline->shader_state.fragment.bo, - ctx->common_data[MESA_SHADER_FRAGMENT].temps, - ctx->stage_data.fs.msaa_mode, - ctx->stage_data.fs.phas, - &fragment_state->pds_fragment_program); + result = pvr_pds_fragment_program_create_and_upload(device, + allocator, + *fs, + fragment_state); if (result != VK_SUCCESS) goto err_free_coeff_program; @@ -1887,13 +2278,10 @@ pvr_graphics_pipeline_compile(struct pvr_device *const device, result = pvr_pds_vertex_attrib_programs_create_and_upload( device, allocator, - vertex_input_state, - ctx->common_data[MESA_SHADER_VERTEX].temps, - &ctx->stage_data.vs, + pco_shader_data(pco_shaders[MESA_SHADER_VERTEX]), vtx_dma_descriptions, vtx_dma_count, - &special_vars_layout, - &gfx_pipeline->shader_state.vertex.pds_attrib_programs); + &vertex_state->pds_attrib_programs); if (result != VK_SUCCESS) goto err_free_frag_descriptor_program; @@ -1903,7 +2291,7 @@ pvr_graphics_pipeline_compile(struct pvr_device *const device, layout, PVR_STAGE_ALLOCATION_VERTEX_GEOMETRY, sh_reg_layout_vert, - &gfx_pipeline->shader_state.vertex.descriptor_state); + &vertex_state->descriptor_state); if (result != VK_SUCCESS) goto err_free_vertex_attrib_program; @@ -1915,36 +2303,30 @@ pvr_graphics_pipeline_compile(struct pvr_device *const device, /* TODO: Implement spilling with the above. */ ralloc_free(shader_mem_ctx); - ralloc_free(ctx); return VK_SUCCESS; err_free_vertex_attrib_program: - for (uint32_t i = 0; - i < ARRAY_SIZE(gfx_pipeline->shader_state.vertex.pds_attrib_programs); + for (uint32_t i = 0; i < ARRAY_SIZE(vertex_state->pds_attrib_programs); i++) { struct pvr_pds_attrib_program *const attrib_program = - &gfx_pipeline->shader_state.vertex.pds_attrib_programs[i]; + &vertex_state->pds_attrib_programs[i]; pvr_pds_vertex_attrib_program_destroy(device, allocator, attrib_program); } err_free_frag_descriptor_program: - pvr_pds_descriptor_program_destroy( - device, - allocator, - &gfx_pipeline->shader_state.fragment.descriptor_state); + pvr_pds_descriptor_program_destroy(device, + allocator, + &fragment_state->descriptor_state); err_free_frag_program: - pvr_bo_suballoc_free( - gfx_pipeline->shader_state.fragment.pds_fragment_program.pvr_bo); + pvr_bo_suballoc_free(fragment_state->pds_fragment_program.pvr_bo); err_free_coeff_program: - pvr_bo_suballoc_free( - gfx_pipeline->shader_state.fragment.pds_coeff_program.pvr_bo); + pvr_bo_suballoc_free(fragment_state->pds_coeff_program.pvr_bo); err_free_fragment_bo: - pvr_bo_suballoc_free(gfx_pipeline->shader_state.fragment.bo); + pvr_bo_suballoc_free(fragment_state->bo); err_free_vertex_bo: - pvr_bo_suballoc_free(gfx_pipeline->shader_state.vertex.bo); + pvr_bo_suballoc_free(vertex_state->bo); err_free_build_context: - ralloc_free(ctx); ralloc_free(shader_mem_ctx); return result; } diff --git a/src/imagination/vulkan/pvr_private.h b/src/imagination/vulkan/pvr_private.h index 255e1fd9a8f..94389a7309c 100644 --- a/src/imagination/vulkan/pvr_private.h +++ b/src/imagination/vulkan/pvr_private.h @@ -39,6 +39,7 @@ #include "compiler/shader_enums.h" #include "hwdef/rogue_hw_defs.h" #include "pco/pco.h" +#include "pco/pco_data.h" #include "pvr_border.h" #include "pvr_clear.h" #include "pvr_common.h" @@ -851,26 +852,7 @@ struct pvr_pds_attrib_program { }; struct pvr_pipeline_stage_state { - uint32_t const_shared_reg_count; - uint32_t const_shared_reg_offset; uint32_t pds_temps_count; - - uint32_t coefficient_size; - - /* True if this shader uses any atomic operations. */ - bool uses_atomic_ops; - - /* True if this shader uses both texture reads and texture writes. */ - bool uses_texture_rw; - - /* Only used for compute stage. */ - bool uses_barrier; - - /* True if this shader has side effects */ - bool has_side_effects; - - /* True if this shader is simply a nop.end. */ - bool empty_program; }; struct pvr_compute_shader_state { @@ -891,10 +873,6 @@ struct pvr_compute_shader_state { struct pvr_vertex_shader_state { /* Pointer to a buffer object that contains the shader binary. */ struct pvr_suballoc_bo *bo; - uint32_t entry_offset; - - /* 2 since we only need STATE_VARYING{0,1} state words. */ - uint32_t varying[2]; struct pvr_pds_attrib_program pds_attrib_programs[PVR_PDS_VERTEX_ATTRIB_PROGRAM_COUNT]; @@ -902,20 +880,17 @@ struct pvr_vertex_shader_state { struct pvr_pipeline_stage_state stage_state; /* FIXME: Move this into stage_state? */ struct pvr_stage_allocation_descriptor_state descriptor_state; - uint32_t vertex_input_size; - uint32_t vertex_output_size; - uint32_t user_clip_planes_mask; }; struct pvr_fragment_shader_state { /* Pointer to a buffer object that contains the shader binary. */ struct pvr_suballoc_bo *bo; - uint32_t entry_offset; struct pvr_pipeline_stage_state stage_state; /* FIXME: Move this into stage_state? */ struct pvr_stage_allocation_descriptor_state descriptor_state; enum ROGUE_TA_PASSTYPE pass_type; + enum ROGUE_PDSINST_DOUTU_SAMPLE_RATE sample_rate; struct pvr_pds_upload pds_coeff_program; struct pvr_pds_upload pds_fragment_program; @@ -967,6 +942,9 @@ struct pvr_graphics_pipeline { /* Derived and other state */ size_t stage_indices[MESA_SHADER_STAGES]; + pco_data vs_data; + pco_data fs_data; + struct { struct pvr_vertex_shader_state vertex; struct pvr_fragment_shader_state fragment; @@ -1390,11 +1368,8 @@ enum pvr_msaa_mode { VkResult pvr_pds_fragment_program_create_and_upload( struct pvr_device *device, const VkAllocationCallbacks *allocator, - const struct pvr_suballoc_bo *fragment_shader_bo, - uint32_t fragment_temp_count, - enum pvr_msaa_mode msaa_mode, - bool has_phase_rate_change, - struct pvr_pds_upload *const pds_upload_out); + pco_shader *fs, + struct pvr_fragment_shader_state *fragment_state); VkResult pvr_pds_unitex_state_program_create_and_upload( struct pvr_device *device,