diff --git a/src/gallium/drivers/v3d/v3d_blit.c b/src/gallium/drivers/v3d/v3d_blit.c index 8ebc42b7d3c..192e8d75bb0 100644 --- a/src/gallium/drivers/v3d/v3d_blit.c +++ b/src/gallium/drivers/v3d/v3d_blit.c @@ -521,6 +521,8 @@ v3d_tlb_blit(struct pipe_context *pctx, struct pipe_blit_info *info) job->draw_min_y = info->dst.box.y; job->draw_max_x = info->dst.box.x + info->dst.box.width; job->draw_max_y = info->dst.box.y + info->dst.box.height; + job->scissor.disabled = false; + /* The simulator complains if we do a TLB load from a source with a * stride that is smaller than the destination's, so we program the * 'frame region' to match the smallest dimensions of the two surfaces. diff --git a/src/gallium/drivers/v3d/v3d_context.h b/src/gallium/drivers/v3d/v3d_context.h index cd13c50b177..04ff23e859d 100644 --- a/src/gallium/drivers/v3d/v3d_context.h +++ b/src/gallium/drivers/v3d/v3d_context.h @@ -99,6 +99,8 @@ void v3d_job_add_bo(struct v3d_job *job, struct v3d_bo *bo); #define V3D_MAX_FS_INPUTS 64 +#define MAX_JOB_SCISSORS 16 + enum v3d_sampler_state_variant { V3D_SAMPLER_STATE_BORDER_0, V3D_SAMPLER_STATE_F16, @@ -356,11 +358,31 @@ struct v3d_job { uint32_t draw_min_y; uint32_t draw_max_x; uint32_t draw_max_y; + + /** @} */ + /** @{ + * List of scissor rects used for all queued drawing. All scissor + * rects will be contained in the draw_{min/max}_{x/y} bounding box. + * + * This is used as an optimization when all drawing is scissored to + * limit tile flushing only to tiles that intersect a scissor rect. + * If scissor is used together with non-scissored drawing, then + * the optimization is disabled. + */ + struct { + bool disabled; + uint32_t count; + struct { + uint32_t min_x, min_y; + uint32_t max_x, max_y; + } rects[MAX_JOB_SCISSORS]; + } scissor; + /** @} */ /** @{ * Width/height of the color framebuffer being rendered to, * for V3D_TILE_RENDERING_MODE_CONFIG. - */ + */ uint32_t draw_width; uint32_t draw_height; uint32_t num_layers; diff --git a/src/gallium/drivers/v3d/v3dx_draw.c b/src/gallium/drivers/v3d/v3dx_draw.c index b9b5254c9f8..0cf4b65d78d 100644 --- a/src/gallium/drivers/v3d/v3dx_draw.c +++ b/src/gallium/drivers/v3d/v3dx_draw.c @@ -1613,6 +1613,7 @@ v3d_tlb_clear(struct v3d_job *job, unsigned buffers, job->draw_max_y = v3d->framebuffer.height; job->clear |= buffers; job->store |= buffers; + job->scissor.disabled = true; v3d_start_draw(v3d); diff --git a/src/gallium/drivers/v3d/v3dx_emit.c b/src/gallium/drivers/v3d/v3dx_emit.c index 04eb27618e7..21c35561b8c 100644 --- a/src/gallium/drivers/v3d/v3dx_emit.c +++ b/src/gallium/drivers/v3d/v3dx_emit.c @@ -469,6 +469,26 @@ v3dX(emit_state)(struct pipe_context *pctx) job->draw_min_y = MIN2(job->draw_min_y, miny); job->draw_max_x = MAX2(job->draw_max_x, maxx); job->draw_max_y = MAX2(job->draw_max_y, maxy); + + if (!v3d->rasterizer->base.scissor) { + job->scissor.disabled = true; + } else if (!job->scissor.disabled && + (v3d->dirty & V3D_DIRTY_SCISSOR)) { + if (job->scissor.count < MAX_JOB_SCISSORS) { + job->scissor.rects[job->scissor.count].min_x = + v3d->scissor.minx; + job->scissor.rects[job->scissor.count].min_y = + v3d->scissor.miny; + job->scissor.rects[job->scissor.count].max_x = + v3d->scissor.maxx - 1; + job->scissor.rects[job->scissor.count].max_y = + v3d->scissor.maxy - 1; + job->scissor.count++; + } else { + job->scissor.disabled = true; + perf_debug("Too many scissor rects."); + } + } } if (v3d->dirty & (V3D_DIRTY_RASTERIZER | diff --git a/src/gallium/drivers/v3d/v3dx_rcl.c b/src/gallium/drivers/v3d/v3dx_rcl.c index 3acd56e7096..92e7c06cd60 100644 --- a/src/gallium/drivers/v3d/v3dx_rcl.c +++ b/src/gallium/drivers/v3d/v3dx_rcl.c @@ -532,6 +532,35 @@ v3d_emit_z_stencil_config(struct v3d_job *job, struct v3d_surface *surf, #define div_round_up(a, b) (((a) + (b) - 1) / b) +static bool +supertile_in_job_scissors(struct v3d_job *job, + uint32_t x, uint32_t y, uint32_t w, uint32_t h) +{ + if (job->scissor.disabled || job->scissor.count == 0) + return true; + + const uint32_t min_x = x * w; + const uint32_t min_y = y * h; + const uint32_t max_x = min_x + w - 1; + const uint32_t max_y = min_y + h - 1; + + for (uint32_t i = 0; i < job->scissor.count; i++) { + const uint32_t min_s_x = job->scissor.rects[i].min_x; + const uint32_t min_s_y = job->scissor.rects[i].min_y; + const uint32_t max_s_x = job->scissor.rects[i].max_x; + const uint32_t max_s_y = job->scissor.rects[i].max_y; + + if (max_x < min_s_x || min_x > max_s_x || + max_y < min_s_y || min_y > max_s_y) { + continue; + } + + return true; + } + + return false; +} + static void emit_render_layer(struct v3d_job *job, uint32_t layer) { @@ -641,9 +670,13 @@ emit_render_layer(struct v3d_job *job, uint32_t layer) for (int y = min_y_supertile; y <= max_y_supertile; y++) { for (int x = min_x_supertile; x <= max_x_supertile; x++) { - cl_emit(&job->rcl, SUPERTILE_COORDINATES, coords) { - coords.column_number_in_supertiles = x; - coords.row_number_in_supertiles = y; + if (supertile_in_job_scissors(job, x, y, + supertile_w_in_pixels, + supertile_h_in_pixels)) { + cl_emit(&job->rcl, SUPERTILE_COORDINATES, coords) { + coords.column_number_in_supertiles = x; + coords.row_number_in_supertiles = y; + } } } }