v3d: implement double-buffer mode

As with Vulkan, we are not enabling this by default since it may
improve of hurt performance depending on the case. Instead, we
can selectively enable it by using the V3D_DEBUG environment
variable.

Reviewed-by: Juan A. Suarez <jasuarez@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/14551>
This commit is contained in:
Iago Toral Quiroga
2022-01-07 08:08:00 +01:00
committed by Marge Bot
parent b9f9474577
commit b0f7f1afac
6 changed files with 46 additions and 9 deletions
+7 -1
View File
@@ -467,8 +467,13 @@ v3d_tlb_blit(struct pipe_context *pctx, struct pipe_blit_info *info)
if (is_color_blit)
surfaces[0] = dst_surf;
bool double_buffer =
unlikely(V3D_DEBUG & V3D_DEBUG_DOUBLE_BUFFER) && !msaa;
uint32_t tile_width, tile_height, max_bpp;
v3d_get_tile_buffer_size(msaa, is_color_blit ? 1 : 0, surfaces, src_surf, &tile_width, &tile_height, &max_bpp);
v3d_get_tile_buffer_size(msaa, double_buffer,
is_color_blit ? 1 : 0, surfaces, src_surf,
&tile_width, &tile_height, &max_bpp);
int dst_surface_width = u_minify(info->dst.resource->width0,
info->dst.level);
@@ -491,6 +496,7 @@ v3d_tlb_blit(struct pipe_context *pctx, struct pipe_blit_info *info)
is_color_blit ? NULL : dst_surf,
src_surf);
job->msaa = msaa;
job->double_buffer = double_buffer;
job->tile_width = tile_width;
job->tile_height = tile_height;
job->internal_bpp = max_bpp;
+5 -2
View File
@@ -242,6 +242,7 @@ v3d_create_texture_shader_state_bo(struct v3d_context *v3d,
void
v3d_get_tile_buffer_size(bool is_msaa,
bool double_buffer,
uint32_t nr_cbufs,
struct pipe_surface **cbufs,
struct pipe_surface *bbuf,
@@ -249,6 +250,8 @@ v3d_get_tile_buffer_size(bool is_msaa,
uint32_t *tile_height,
uint32_t *max_bpp)
{
assert(!is_msaa || !double_buffer);
uint32_t max_cbuf_idx = 0;
*max_bpp = 0;
for (int i = 0; i < nr_cbufs; i++) {
@@ -265,8 +268,8 @@ v3d_get_tile_buffer_size(bool is_msaa,
*max_bpp = MAX2(*max_bpp, bsurf->internal_bpp);
}
v3d_choose_tile_size(max_cbuf_idx + 1, *max_bpp, is_msaa,
false /* double-buffer */,
v3d_choose_tile_size(max_cbuf_idx + 1, *max_bpp,
is_msaa, double_buffer,
tile_width, tile_height);
}
+4
View File
@@ -430,6 +430,9 @@ struct v3d_job {
float clear_z;
uint8_t clear_s;
/* If TLB double-buffering is enabled for this job */
bool double_buffer;
/**
* Set if some drawing (triangles, blits, or just a glClear()) has
* been done to the FBO, meaning that we need to
@@ -777,6 +780,7 @@ void v3d_create_texture_shader_state_bo(struct v3d_context *v3d,
struct v3d_sampler_view *so);
void v3d_get_tile_buffer_size(bool is_msaa,
bool double_buffer,
uint32_t nr_cbufs,
struct pipe_surface **cbufs,
struct pipe_surface *bbuf,
+9 -5
View File
@@ -358,6 +358,9 @@ v3d_get_job(struct v3d_context *v3d,
}
}
job->double_buffer =
unlikely(V3D_DEBUG & V3D_DEBUG_DOUBLE_BUFFER) && !job->msaa;
memcpy(&job->key, &local_key, sizeof(local_key));
_mesa_hash_table_insert(v3d->jobs, &job->key, job);
@@ -375,13 +378,14 @@ v3d_get_job_for_fbo(struct v3d_context *v3d)
struct pipe_surface *zsbuf = v3d->framebuffer.zsbuf;
struct v3d_job *job = v3d_get_job(v3d, nr_cbufs, cbufs, zsbuf, NULL);
if (v3d->framebuffer.samples >= 1)
if (v3d->framebuffer.samples >= 1) {
job->msaa = true;
job->double_buffer = false;
}
v3d_get_tile_buffer_size(job->msaa, job->nr_cbufs,
job->cbufs, job->bbuf,
&job->tile_width,
&job->tile_height,
v3d_get_tile_buffer_size(job->msaa, job->double_buffer,
job->nr_cbufs, job->cbufs, job->bbuf,
&job->tile_width, &job->tile_height,
&job->internal_bpp);
/* The dirty flags are tracking what's been updated while v3d->job has
+3
View File
@@ -94,6 +94,7 @@ v3dX(start_binning)(struct v3d_context *v3d, struct v3d_job *job)
}
#endif
assert(!job->msaa || !job->double_buffer);
#if V3D_VERSION >= 40
cl_emit(&job->bcl, TILE_BINNING_MODE_CFG, config) {
config.width_in_pixels = job->draw_width;
@@ -102,6 +103,7 @@ v3dX(start_binning)(struct v3d_context *v3d, struct v3d_job *job)
MAX2(job->nr_cbufs, 1);
config.multisample_mode_4x = job->msaa;
config.double_buffer_in_non_ms_mode = job->double_buffer;
config.maximum_bpp_of_all_render_targets = job->internal_bpp;
}
@@ -128,6 +130,7 @@ v3dX(start_binning)(struct v3d_context *v3d, struct v3d_job *job)
MAX2(job->nr_cbufs, 1);
config.multisample_mode_4x = job->msaa;
config.double_buffer_in_non_ms_mode = job->double_buffer;
config.maximum_bpp_of_all_render_targets = job->internal_bpp;
}
+18 -1
View File
@@ -561,6 +561,21 @@ supertile_in_job_scissors(struct v3d_job *job,
return false;
}
static inline bool
do_double_initial_tile_clear(const struct v3d_job *job)
{
/* Our rendering code emits an initial clear per layer, unlike the
* Vulkan driver, which only executes a single initial clear for all
* layers. This is because in GL we don't use the
* 'clear_buffer_being_stored' bit when storing tiles, so each layer
* needs the iniital clear. This is also why this helper, unlike the
* Vulkan version, doesn't check the layer count to decide if double
* clear for double buffer mode is required.
*/
return job->double_buffer &&
(job->draw_tiles_x > 1 || job->draw_tiles_y > 1);
}
static void
emit_render_layer(struct v3d_job *job, uint32_t layer)
{
@@ -638,7 +653,7 @@ emit_render_layer(struct v3d_job *job, uint32_t layer)
cl_emit(&job->rcl, STORE_TILE_BUFFER_GENERAL, store) {
store.buffer_to_store = NONE;
}
if (i == 0) {
if (i == 0 || do_double_initial_tile_clear(job)) {
cl_emit(&job->rcl, CLEAR_TILE_BUFFERS, clear) {
clear.clear_z_stencil_buffer = true;
clear.clear_all_render_targets = true;
@@ -732,7 +747,9 @@ v3dX(emit_rcl)(struct v3d_job *job)
config.number_of_render_targets = MAX2(job->nr_cbufs, 1);
assert(!job->msaa || !job->double_buffer);
config.multisample_mode_4x = job->msaa;
config.double_buffer_in_non_ms_mode = job->double_buffer;
config.maximum_bpp_of_all_render_targets = job->internal_bpp;
}