diff --git a/src/imagination/pco/pco_data.h b/src/imagination/pco/pco_data.h index b93ae30001b..22f59aac253 100644 --- a/src/imagination/pco/pco_data.h +++ b/src/imagination/pco/pco_data.h @@ -15,6 +15,7 @@ #include "common/pvr_limits.h" #include "compiler/shader_enums.h" +#include "nir/nir_lower_blend.h" #include "util/format/u_format.h" #include @@ -64,11 +65,17 @@ typedef struct _pco_fs_data { /** Fragment output formats. */ enum pipe_format output_formats[FRAG_RESULT_MAX]; + /* Blend options. */ + nir_lower_blend_options blend_opts; + pco_range blend_consts; + uint8_t blend_consts_needed; + 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. */ + bool fbfetch; /** Whether the shader fetches from the framebuffer. */ } uses; } pco_fs_data; diff --git a/src/imagination/pco/pco_nir.c b/src/imagination/pco/pco_nir.c index 12dcb995ae6..7a4c8a0c03e 100644 --- a/src/imagination/pco/pco_nir.c +++ b/src/imagination/pco/pco_nir.c @@ -11,6 +11,7 @@ */ #include "nir/nir_builder.h" +#include "nir/nir_lower_blend.h" #include "pco.h" #include "pco_internal.h" #include "pvr_limits.h" @@ -185,22 +186,31 @@ 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; - assert(component == 2 || chans == 1); - pco_data *data = cb_data; - data->fs.uses.z |= (component == 2); - data->fs.uses.w |= (component + chans > 3); + switch (intr->intrinsic) { + /* Check whether the shader accesses z/w. */ + case nir_intrinsic_load_input: { + 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; + assert(component == 2 || chans == 1); + + data->fs.uses.z |= (component == 2); + data->fs.uses.w |= (component + chans > 3); + break; + } + + case nir_intrinsic_load_blend_const_color_rgba: + data->fs.blend_consts_needed |= PIPE_MASK_RGBA; + break; + + default: + break; + } return false; } @@ -225,6 +235,8 @@ static void gather_fs_data(nir_shader *nir, pco_data *data) break; } } + + data->fs.uses.fbfetch = nir->info.fs.uses_fbfetch_output; } /** @@ -704,6 +716,7 @@ void pco_lower_nir(pco_ctx *ctx, nir_shader *nir, pco_data *data) NIR_PASS(_, nir, pco_nir_lower_tex); if (nir->info.stage == MESA_SHADER_FRAGMENT) { + NIR_PASS(_, nir, nir_lower_blend, &data->fs.blend_opts); NIR_PASS(_, nir, pco_nir_pfo, &data->fs); } else if (nir->info.stage == MESA_SHADER_VERTEX) { NIR_PASS(_, diff --git a/src/imagination/pco/pco_trans_nir.c b/src/imagination/pco/pco_trans_nir.c index bc873ea2313..46772c584dd 100644 --- a/src/imagination/pco/pco_trans_nir.c +++ b/src/imagination/pco/pco_trans_nir.c @@ -1131,6 +1131,16 @@ static pco_instr *trans_intr(trans_ctx *tctx, nir_intrinsic_instr *intr) &tctx->shader->data.common.push_consts.range); break; + case nir_intrinsic_load_blend_const_color_rgba: + assert(tctx->stage == MESA_SHADER_FRAGMENT); + instr = trans_load_common_store(tctx, + intr, + dest, + pco_ref_null(), + false, + &tctx->shader->data.fs.blend_consts); + break; + case nir_intrinsic_load_shared: assert(tctx->stage == MESA_SHADER_COMPUTE); instr = trans_load_common_store(tctx, diff --git a/src/imagination/vulkan/pds/pvr_pipeline_pds.c b/src/imagination/vulkan/pds/pvr_pipeline_pds.c index 155c37097be..eb7fefb6af3 100644 --- a/src/imagination/vulkan/pds/pvr_pipeline_pds.c +++ b/src/imagination/vulkan/pds/pvr_pipeline_pds.c @@ -1574,7 +1574,8 @@ void pvr_pds_generate_descriptor_upload_program( bool halt = last_dma && !input_program->secondary_program_present; switch (buffer->type) { - case PVR_BUFFER_TYPE_PUSH_CONSTS: { + case PVR_BUFFER_TYPE_PUSH_CONSTS: + case PVR_BUFFER_TYPE_BLEND_CONSTS: { struct pvr_const_map_entry_special_buffer *special_buffer_entry; special_buffer_entry = diff --git a/src/imagination/vulkan/pvr_cmd_buffer.c b/src/imagination/vulkan/pvr_cmd_buffer.c index 618e27f9078..3254bee883c 100644 --- a/src/imagination/vulkan/pvr_cmd_buffer.c +++ b/src/imagination/vulkan/pvr_cmd_buffer.c @@ -3640,6 +3640,26 @@ static VkResult pvr_setup_descriptor_mappings( break; } + case PVR_BUFFER_TYPE_BLEND_CONSTS: { + const struct vk_color_blend_state *cb = + &cmd_buffer->vk.dynamic_graphics_state.cb; + + struct pvr_suballoc_bo *blend_consts_bo; + result = pvr_cmd_buffer_upload_general(cmd_buffer, + cb->blend_constants, + sizeof(cb->blend_constants), + &blend_consts_bo); + + if (result != VK_SUCCESS) + return result; + + PVR_WRITE(qword_buffer, + blend_consts_bo->dev_addr.addr, + special_buff_entry->const_offset, + pds_info->data_size_in_dwords); + break; + } + default: UNREACHABLE("Unsupported special buffer type."); } diff --git a/src/imagination/vulkan/pvr_pipeline.c b/src/imagination/vulkan/pvr_pipeline.c index 72716abe39c..886c9756275 100644 --- a/src/imagination/vulkan/pvr_pipeline.c +++ b/src/imagination/vulkan/pvr_pipeline.c @@ -33,6 +33,7 @@ #include "compiler/shader_enums.h" #include "hwdef/rogue_hw_utils.h" #include "nir/nir.h" +#include "nir/nir_lower_blend.h" #include "pco/pco.h" #include "pco/pco_data.h" #include "pvr_bo.h" @@ -51,6 +52,7 @@ #include "util/u_dynarray.h" #include "util/u_math.h" #include "vk_alloc.h" +#include "vk_blend.h" #include "vk_format.h" #include "vk_graphics_state.h" #include "vk_log.h" @@ -588,6 +590,14 @@ static VkResult pvr_pds_descriptor_program_create_and_upload( }; } + if (stage == MESA_SHADER_FRAGMENT && data->fs.blend_consts.count > 0) { + program.buffers[program.buffer_count++] = (struct pvr_pds_buffer){ + .type = PVR_BUFFER_TYPE_BLEND_CONSTS, + .size_in_dwords = data->fs.blend_consts.count, + .destination = data->fs.blend_consts.start, + }; + } + pds_info->entries_size_in_bytes = const_entries_size_in_bytes; pvr_pds_generate_descriptor_upload_program(&program, NULL, pds_info); @@ -871,16 +881,12 @@ static void pvr_pipeline_finish(struct pvr_device *device, vk_object_base_finish(&pipeline->base); } -/* How many shared regs it takes to store a pvr_dev_addr_t. - * Each shared reg is 32 bits. - */ -#define PVR_DEV_ADDR_SIZE_IN_SH_REGS \ - DIV_ROUND_UP(sizeof(pvr_dev_addr_t), sizeof(uint32_t)) - -static void pvr_preprocess_shader_data(pco_data *data, - nir_shader *nir, - const void *pCreateInfo, - struct vk_pipeline_layout *layout); +static void +pvr_preprocess_shader_data(pco_data *data, + nir_shader *nir, + const void *pCreateInfo, + struct vk_pipeline_layout *layout, + const struct vk_graphics_pipeline_state *state); static void pvr_postprocess_shader_data(pco_data *data, nir_shader *nir, @@ -933,7 +939,7 @@ static VkResult pvr_compute_pipeline_compile( goto err_free_build_context; pco_preprocess_nir(pco_ctx, nir); - pvr_preprocess_shader_data(&shader_data, nir, pCreateInfo, layout); + pvr_preprocess_shader_data(&shader_data, nir, pCreateInfo, layout, NULL); pco_lower_nir(pco_ctx, nir, &shader_data); pco_postprocess_nir(pco_ctx, nir, &shader_data); pvr_postprocess_shader_data(&shader_data, nir, pCreateInfo, layout); @@ -1209,7 +1215,11 @@ static void pvr_fragment_state_save(struct pvr_graphics_pipeline *gfx_pipeline, 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; + if (shader_data->fs.uses.fbfetch) + fragment_state->pass_type = ROGUE_TA_PASSTYPE_TRANSLUCENT; + else + fragment_state->pass_type = ROGUE_TA_PASSTYPE_OPAQUE; + fragment_state->sample_rate = ROGUE_PDSINST_DOUTU_SAMPLE_RATE_INSTANCE; /* We can't initialize it yet since we still need to generate the PDS @@ -1218,81 +1228,6 @@ static void pvr_fragment_state_save(struct pvr_graphics_pipeline *gfx_pipeline, fragment_state->stage_state.pds_temps_count = ~0; } -static bool pvr_blend_factor_requires_consts(VkBlendFactor factor) -{ - switch (factor) { - case VK_BLEND_FACTOR_CONSTANT_COLOR: - case VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR: - case VK_BLEND_FACTOR_CONSTANT_ALPHA: - case VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA: - return true; - - default: - return false; - } -} - -/** - * \brief Indicates whether dynamic blend constants are needed. - * - * If the user has specified the blend constants to be dynamic, they might not - * necessarily be using them. This function makes sure that they are being used - * in order to determine whether we need to upload them later on for the shader - * to access them. - */ -static bool pvr_graphics_pipeline_requires_dynamic_blend_consts( - const struct pvr_graphics_pipeline *gfx_pipeline) -{ - const struct vk_dynamic_graphics_state *const state = - &gfx_pipeline->dynamic_state; - - if (BITSET_TEST(state->set, MESA_VK_DYNAMIC_CB_BLEND_CONSTANTS)) - return false; - - for (uint32_t i = 0; i < state->cb.attachment_count; i++) { - const struct vk_color_blend_attachment_state *attachment = - &state->cb.attachments[i]; - - const bool has_color_write = - attachment->write_mask & - (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | - VK_COLOR_COMPONENT_B_BIT); - const bool has_alpha_write = attachment->write_mask & - VK_COLOR_COMPONENT_A_BIT; - - if (!attachment->blend_enable || attachment->write_mask == 0) - continue; - - if (has_color_write) { - const uint8_t src_color_blend_factor = - attachment->src_color_blend_factor; - const uint8_t dst_color_blend_factor = - attachment->dst_color_blend_factor; - - if (pvr_blend_factor_requires_consts(src_color_blend_factor) || - pvr_blend_factor_requires_consts(dst_color_blend_factor)) { - return true; - } - } - - if (has_alpha_write) { - const uint8_t src_alpha_blend_factor = - attachment->src_alpha_blend_factor; - const uint8_t dst_alpha_blend_factor = - attachment->dst_alpha_blend_factor; - - if (pvr_blend_factor_requires_consts(src_alpha_blend_factor) || - pvr_blend_factor_requires_consts(dst_alpha_blend_factor)) { - return true; - } - } - } - - return false; -} - -#undef PVR_DEV_ADDR_SIZE_IN_SH_REGS - static void pvr_graphics_pipeline_setup_vertex_dma( struct pvr_graphics_pipeline *gfx_pipeline, const VkPipelineVertexInputStateCreateInfo *const vertex_input_state, @@ -1916,6 +1851,51 @@ static void pvr_init_fs_input_attachments( pvr_finishme("pvr_init_fs_input_attachments"); } +static void pvr_init_fs_blend(pco_data *data, + const struct vk_color_blend_state *cb) +{ + nir_lower_blend_options *blend_opts = &data->fs.blend_opts; + if (!cb) + return; + + blend_opts->logicop_enable = cb->logic_op_enable; + blend_opts->logicop_func = vk_logic_op_to_pipe(cb->logic_op); + + unsigned count = cb->attachment_count; + for (unsigned u = 0; u < count; ++u) { + const struct vk_color_blend_attachment_state *rt = &cb->attachments[u]; + gl_frag_result location = FRAG_RESULT_DATA0 + u; + blend_opts->format[u] = data->fs.output_formats[location]; + + if (cb->logic_op_enable) { + /* No blending, but we get the colour mask below */ + } else if (!rt->blend_enable) { + const nir_lower_blend_channel replace = { + .func = PIPE_BLEND_ADD, + .src_factor = PIPE_BLENDFACTOR_ONE, + .dst_factor = PIPE_BLENDFACTOR_ZERO, + }; + + blend_opts->rt[u].rgb = replace; + blend_opts->rt[u].alpha = replace; + } else { + blend_opts->rt[u].rgb.func = vk_blend_op_to_pipe(rt->color_blend_op); + blend_opts->rt[u].rgb.src_factor = + vk_blend_factor_to_pipe(rt->src_color_blend_factor); + blend_opts->rt[u].rgb.dst_factor = + vk_blend_factor_to_pipe(rt->dst_color_blend_factor); + + blend_opts->rt[u].alpha.func = vk_blend_op_to_pipe(rt->alpha_blend_op); + blend_opts->rt[u].alpha.src_factor = + vk_blend_factor_to_pipe(rt->src_alpha_blend_factor); + blend_opts->rt[u].alpha.dst_factor = + vk_blend_factor_to_pipe(rt->dst_alpha_blend_factor); + } + + blend_opts->rt[u].colormask = rt->write_mask; + } +} + static void pvr_setup_fs_input_attachments( pco_data *data, nir_shader *nir, @@ -1925,6 +1905,20 @@ static void pvr_setup_fs_input_attachments( pvr_finishme("pvr_setup_fs_input_attachments"); } +static void pvr_setup_fs_blend(pco_data *data) +{ + unsigned num_blend_consts = util_bitcount(data->fs.blend_consts_needed); + if (!num_blend_consts) + return; + + data->fs.blend_consts = (pco_range){ + .start = data->common.shareds, + .count = num_blend_consts, + }; + + data->common.shareds += num_blend_consts; +} + static void pvr_alloc_cs_sysvals(pco_data *data, nir_shader *nir) { BITSET_DECLARE(system_values_read, SYSTEM_VALUE_MAX); @@ -2087,10 +2081,12 @@ static void pvr_setup_descriptors(pco_data *data, assert(data->common.shareds < 256); } -static void pvr_preprocess_shader_data(pco_data *data, - nir_shader *nir, - const void *pCreateInfo, - struct vk_pipeline_layout *layout) +static void +pvr_preprocess_shader_data(pco_data *data, + nir_shader *nir, + const void *pCreateInfo, + struct vk_pipeline_layout *layout, + const struct vk_graphics_pipeline_state *state) { const VkGraphicsPipelineCreateInfo *pGraphicsCreateInfo = pCreateInfo; @@ -2115,8 +2111,9 @@ static void pvr_preprocess_shader_data(pco_data *data, pvr_init_fs_outputs(data, pass, subpass, hw_subpass); pvr_init_fs_input_attachments(data, subpass, hw_subpass); + pvr_init_fs_blend(data, state->cb); - /* TODO: push consts, blend consts, dynamic state, etc. */ + /* TODO: push consts, dynamic state, etc. */ break; } @@ -2162,6 +2159,7 @@ static void pvr_postprocess_shader_data(pco_data *data, 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); + pvr_setup_fs_blend(data); /* TODO: push consts, blend consts, dynamic state, etc. */ break; @@ -2268,7 +2266,8 @@ pvr_graphics_pipeline_compile(struct pvr_device *const device, pvr_preprocess_shader_data(&shader_data[stage], nir_shaders[stage], pCreateInfo, - layout); + layout, + state); pco_lower_nir(pco_ctx, nir_shaders[stage], &shader_data[stage]);