pvr, pco: initial support for blend constants

Signed-off-by: Simon Perretta <simon.perretta@imgtec.com>
Acked-by: Erik Faye-Lund <erik.faye-lund@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36412>
This commit is contained in:
Simon Perretta 2025-02-20 15:45:10 +00:00 committed by Marge Bot
parent 2752a151bf
commit 992ade9e76
6 changed files with 158 additions and 108 deletions

View file

@ -15,6 +15,7 @@
#include "common/pvr_limits.h" #include "common/pvr_limits.h"
#include "compiler/shader_enums.h" #include "compiler/shader_enums.h"
#include "nir/nir_lower_blend.h"
#include "util/format/u_format.h" #include "util/format/u_format.h"
#include <stdbool.h> #include <stdbool.h>
@ -64,11 +65,17 @@ typedef struct _pco_fs_data {
/** Fragment output formats. */ /** Fragment output formats. */
enum pipe_format output_formats[FRAG_RESULT_MAX]; 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 { struct {
bool w; /** Whether the shader uses pos.w. */ bool w; /** Whether the shader uses pos.w. */
bool z; /** Whether the shader uses pos.z */ bool z; /** Whether the shader uses pos.z */
bool pntc; /** Whether the shader uses point coord. */ bool pntc; /** Whether the shader uses point coord. */
bool phase_change; /** Whether the shader does a phase change. */ bool phase_change; /** Whether the shader does a phase change. */
bool fbfetch; /** Whether the shader fetches from the framebuffer. */
} uses; } uses;
} pco_fs_data; } pco_fs_data;

View file

@ -11,6 +11,7 @@
*/ */
#include "nir/nir_builder.h" #include "nir/nir_builder.h"
#include "nir/nir_lower_blend.h"
#include "pco.h" #include "pco.h"
#include "pco_internal.h" #include "pco_internal.h"
#include "pvr_limits.h" #include "pvr_limits.h"
@ -185,10 +186,11 @@ static bool gather_fs_data_pass(UNUSED struct nir_builder *b,
nir_intrinsic_instr *intr, nir_intrinsic_instr *intr,
void *cb_data) void *cb_data)
{ {
/* Check whether the shader accesses z/w. */ pco_data *data = cb_data;
if (intr->intrinsic != nir_intrinsic_load_input)
return false;
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); struct nir_io_semantics io_semantics = nir_intrinsic_io_semantics(intr);
if (io_semantics.location != VARYING_SLOT_POS) if (io_semantics.location != VARYING_SLOT_POS)
return false; return false;
@ -197,10 +199,18 @@ static bool gather_fs_data_pass(UNUSED struct nir_builder *b,
unsigned chans = intr->def.num_components; unsigned chans = intr->def.num_components;
assert(component == 2 || chans == 1); assert(component == 2 || chans == 1);
pco_data *data = cb_data;
data->fs.uses.z |= (component == 2); data->fs.uses.z |= (component == 2);
data->fs.uses.w |= (component + chans > 3); 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; return false;
} }
@ -225,6 +235,8 @@ static void gather_fs_data(nir_shader *nir, pco_data *data)
break; 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); NIR_PASS(_, nir, pco_nir_lower_tex);
if (nir->info.stage == MESA_SHADER_FRAGMENT) { 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); NIR_PASS(_, nir, pco_nir_pfo, &data->fs);
} else if (nir->info.stage == MESA_SHADER_VERTEX) { } else if (nir->info.stage == MESA_SHADER_VERTEX) {
NIR_PASS(_, NIR_PASS(_,

View file

@ -1131,6 +1131,16 @@ static pco_instr *trans_intr(trans_ctx *tctx, nir_intrinsic_instr *intr)
&tctx->shader->data.common.push_consts.range); &tctx->shader->data.common.push_consts.range);
break; 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: case nir_intrinsic_load_shared:
assert(tctx->stage == MESA_SHADER_COMPUTE); assert(tctx->stage == MESA_SHADER_COMPUTE);
instr = trans_load_common_store(tctx, instr = trans_load_common_store(tctx,

View file

@ -1574,7 +1574,8 @@ void pvr_pds_generate_descriptor_upload_program(
bool halt = last_dma && !input_program->secondary_program_present; bool halt = last_dma && !input_program->secondary_program_present;
switch (buffer->type) { 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; struct pvr_const_map_entry_special_buffer *special_buffer_entry;
special_buffer_entry = special_buffer_entry =

View file

@ -3640,6 +3640,26 @@ static VkResult pvr_setup_descriptor_mappings(
break; 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: default:
UNREACHABLE("Unsupported special buffer type."); UNREACHABLE("Unsupported special buffer type.");
} }

View file

@ -33,6 +33,7 @@
#include "compiler/shader_enums.h" #include "compiler/shader_enums.h"
#include "hwdef/rogue_hw_utils.h" #include "hwdef/rogue_hw_utils.h"
#include "nir/nir.h" #include "nir/nir.h"
#include "nir/nir_lower_blend.h"
#include "pco/pco.h" #include "pco/pco.h"
#include "pco/pco_data.h" #include "pco/pco_data.h"
#include "pvr_bo.h" #include "pvr_bo.h"
@ -51,6 +52,7 @@
#include "util/u_dynarray.h" #include "util/u_dynarray.h"
#include "util/u_math.h" #include "util/u_math.h"
#include "vk_alloc.h" #include "vk_alloc.h"
#include "vk_blend.h"
#include "vk_format.h" #include "vk_format.h"
#include "vk_graphics_state.h" #include "vk_graphics_state.h"
#include "vk_log.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; pds_info->entries_size_in_bytes = const_entries_size_in_bytes;
pvr_pds_generate_descriptor_upload_program(&program, NULL, pds_info); 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); vk_object_base_finish(&pipeline->base);
} }
/* How many shared regs it takes to store a pvr_dev_addr_t. static void
* Each shared reg is 32 bits. pvr_preprocess_shader_data(pco_data *data,
*/
#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, nir_shader *nir,
const void *pCreateInfo, const void *pCreateInfo,
struct vk_pipeline_layout *layout); struct vk_pipeline_layout *layout,
const struct vk_graphics_pipeline_state *state);
static void pvr_postprocess_shader_data(pco_data *data, static void pvr_postprocess_shader_data(pco_data *data,
nir_shader *nir, nir_shader *nir,
@ -933,7 +939,7 @@ static VkResult pvr_compute_pipeline_compile(
goto err_free_build_context; goto err_free_build_context;
pco_preprocess_nir(pco_ctx, nir); 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_lower_nir(pco_ctx, nir, &shader_data);
pco_postprocess_nir(pco_ctx, nir, &shader_data); pco_postprocess_nir(pco_ctx, nir, &shader_data);
pvr_postprocess_shader_data(&shader_data, nir, pCreateInfo, layout); 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)); memcpy(&gfx_pipeline->fs_data, shader_data, sizeof(*shader_data));
/* TODO: add selection for other values of pass type and sample rate. */ /* TODO: add selection for other values of pass type and sample rate. */
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->pass_type = ROGUE_TA_PASSTYPE_OPAQUE;
fragment_state->sample_rate = ROGUE_PDSINST_DOUTU_SAMPLE_RATE_INSTANCE; fragment_state->sample_rate = ROGUE_PDSINST_DOUTU_SAMPLE_RATE_INSTANCE;
/* We can't initialize it yet since we still need to generate the PDS /* 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; 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( static void pvr_graphics_pipeline_setup_vertex_dma(
struct pvr_graphics_pipeline *gfx_pipeline, struct pvr_graphics_pipeline *gfx_pipeline,
const VkPipelineVertexInputStateCreateInfo *const vertex_input_state, const VkPipelineVertexInputStateCreateInfo *const vertex_input_state,
@ -1916,6 +1851,51 @@ static void pvr_init_fs_input_attachments(
pvr_finishme("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( static void pvr_setup_fs_input_attachments(
pco_data *data, pco_data *data,
nir_shader *nir, nir_shader *nir,
@ -1925,6 +1905,20 @@ static void pvr_setup_fs_input_attachments(
pvr_finishme("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) static void pvr_alloc_cs_sysvals(pco_data *data, nir_shader *nir)
{ {
BITSET_DECLARE(system_values_read, SYSTEM_VALUE_MAX); 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); assert(data->common.shareds < 256);
} }
static void pvr_preprocess_shader_data(pco_data *data, static void
pvr_preprocess_shader_data(pco_data *data,
nir_shader *nir, nir_shader *nir,
const void *pCreateInfo, const void *pCreateInfo,
struct vk_pipeline_layout *layout) struct vk_pipeline_layout *layout,
const struct vk_graphics_pipeline_state *state)
{ {
const VkGraphicsPipelineCreateInfo *pGraphicsCreateInfo = pCreateInfo; 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_outputs(data, pass, subpass, hw_subpass);
pvr_init_fs_input_attachments(data, 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; break;
} }
@ -2162,6 +2159,7 @@ static void pvr_postprocess_shader_data(pco_data *data,
pvr_alloc_fs_varyings(data, nir); pvr_alloc_fs_varyings(data, nir);
pvr_setup_fs_outputs(data, nir, subpass, hw_subpass); pvr_setup_fs_outputs(data, nir, subpass, hw_subpass);
pvr_setup_fs_input_attachments(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. */ /* TODO: push consts, blend consts, dynamic state, etc. */
break; break;
@ -2268,7 +2266,8 @@ pvr_graphics_pipeline_compile(struct pvr_device *const device,
pvr_preprocess_shader_data(&shader_data[stage], pvr_preprocess_shader_data(&shader_data[stage],
nir_shaders[stage], nir_shaders[stage],
pCreateInfo, pCreateInfo,
layout); layout,
state);
pco_lower_nir(pco_ctx, nir_shaders[stage], &shader_data[stage]); pco_lower_nir(pco_ctx, nir_shaders[stage], &shader_data[stage]);