zink: defer pipe_context::clear calls when not currently in a renderpass

instead, we can attach the clear to the next renderpass start and even add it to
the renderpass cache for reuse

also add handling for flushing clears on map or fb switching to avoid brekaing behavior

this should save us a lot of time with potentially beginning/ending renderpasses as well
as allowing drivers to do better batching of clears by passing in all the buffers at
once

this doesn't handle deferring conditional renders yet in a futile attempt to try and keep
the size of the patch down

Reviewed-by: Dave Airlie <airlied@redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/9206>
This commit is contained in:
Mike Blumenkrantz 2020-09-16 17:47:17 -04:00 committed by Marge Bot
parent b37cba8271
commit 5c629e9ff2
7 changed files with 379 additions and 49 deletions

View file

@ -36,6 +36,9 @@ blit_resolve(struct zink_context *ctx, const struct pipe_blit_info *info)
if (info->dst.resource->target == PIPE_BUFFER) if (info->dst.resource->target == PIPE_BUFFER)
util_range_add(info->dst.resource, &dst->valid_buffer_range, util_range_add(info->dst.resource, &dst->valid_buffer_range,
info->dst.box.x, info->dst.box.x + info->dst.box.width); info->dst.box.x, info->dst.box.x + info->dst.box.width);
zink_fb_clears_apply(ctx, info->dst.resource);
zink_fb_clears_apply(ctx, info->src.resource);
struct zink_batch *batch = zink_batch_no_rp(ctx); struct zink_batch *batch = zink_batch_no_rp(ctx);
zink_batch_reference_resource_rw(batch, src, false); zink_batch_reference_resource_rw(batch, src, false);
@ -116,6 +119,8 @@ blit_native(struct zink_context *ctx, const struct pipe_blit_info *info)
dst->format != zink_get_format(screen, info->dst.format)) dst->format != zink_get_format(screen, info->dst.format))
return false; return false;
zink_fb_clears_apply(ctx, info->dst.resource);
zink_fb_clears_apply(ctx, info->src.resource);
struct zink_batch *batch = zink_batch_no_rp(ctx); struct zink_batch *batch = zink_batch_no_rp(ctx);
zink_batch_reference_resource_rw(batch, src, false); zink_batch_reference_resource_rw(batch, src, false);
zink_batch_reference_resource_rw(batch, dst, true); zink_batch_reference_resource_rw(batch, dst, true);

View file

@ -26,6 +26,7 @@
#include "zink_screen.h" #include "zink_screen.h"
#include "util/u_blitter.h" #include "util/u_blitter.h"
#include "util/u_dynarray.h"
#include "util/format/u_format.h" #include "util/format/u_format.h"
#include "util/format_srgb.h" #include "util/format_srgb.h"
#include "util/u_framebuffer.h" #include "util/u_framebuffer.h"
@ -36,6 +37,8 @@
static inline bool static inline bool
check_3d_layers(struct pipe_surface *psurf) check_3d_layers(struct pipe_surface *psurf)
{ {
if (psurf->texture->target != PIPE_TEXTURE_3D)
return true;
/* SPEC PROBLEM: /* SPEC PROBLEM:
* though the vk spec doesn't seem to explicitly address this, currently drivers * though the vk spec doesn't seem to explicitly address this, currently drivers
* are claiming that all 3D images have a single "3D" layer regardless of layercount, * are claiming that all 3D images have a single "3D" layer regardless of layercount,
@ -49,6 +52,12 @@ check_3d_layers(struct pipe_surface *psurf)
return true; return true;
} }
static inline bool
scissor_states_equal(const struct pipe_scissor_state *a, const struct pipe_scissor_state *b)
{
return a->minx == b->minx && a->miny == b->miny && a->maxx == b->maxx && a->maxy == b->maxy;
}
static void static void
clear_in_rp(struct pipe_context *pctx, clear_in_rp(struct pipe_context *pctx,
unsigned buffers, unsigned buffers,
@ -58,8 +67,6 @@ clear_in_rp(struct pipe_context *pctx,
{ {
struct zink_context *ctx = zink_context(pctx); struct zink_context *ctx = zink_context(pctx);
struct pipe_framebuffer_state *fb = &ctx->fb_state; struct pipe_framebuffer_state *fb = &ctx->fb_state;
struct zink_resource *resources[PIPE_MAX_COLOR_BUFS + 1] = {};
int res_count = 0;
VkClearAttachment attachments[1 + PIPE_MAX_COLOR_BUFS]; VkClearAttachment attachments[1 + PIPE_MAX_COLOR_BUFS];
int num_attachments = 0; int num_attachments = 0;
@ -79,9 +86,6 @@ clear_in_rp(struct pipe_context *pctx,
attachments[num_attachments].colorAttachment = i; attachments[num_attachments].colorAttachment = i;
attachments[num_attachments].clearValue.color = color; attachments[num_attachments].clearValue.color = color;
++num_attachments; ++num_attachments;
struct zink_resource *res = (struct zink_resource*)fb->cbufs[i]->texture;
zink_resource_image_barrier(ctx, NULL, res, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 0, 0);
resources[res_count++] = res;
} }
} }
@ -96,9 +100,6 @@ clear_in_rp(struct pipe_context *pctx,
attachments[num_attachments].clearValue.depthStencil.depth = depth; attachments[num_attachments].clearValue.depthStencil.depth = depth;
attachments[num_attachments].clearValue.depthStencil.stencil = stencil; attachments[num_attachments].clearValue.depthStencil.stencil = stencil;
++num_attachments; ++num_attachments;
struct zink_resource *res = (struct zink_resource*)fb->zsbuf->texture;
zink_resource_image_barrier(ctx, NULL, res, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 0, 0);
resources[res_count++] = res;
} }
VkClearRect cr = {}; VkClearRect cr = {};
@ -114,8 +115,6 @@ clear_in_rp(struct pipe_context *pctx,
cr.baseArrayLayer = 0; cr.baseArrayLayer = 0;
cr.layerCount = util_framebuffer_get_num_layers(fb); cr.layerCount = util_framebuffer_get_num_layers(fb);
struct zink_batch *batch = zink_batch_rp(ctx); struct zink_batch *batch = zink_batch_rp(ctx);
for (int i = 0; i < res_count; i++)
zink_batch_reference_resource_rw(batch, resources[i], true);
vkCmdClearAttachments(batch->cmdbuf, num_attachments, attachments, 1, &cr); vkCmdClearAttachments(batch->cmdbuf, num_attachments, attachments, 1, &cr);
} }
@ -168,11 +167,6 @@ clear_needs_rp(unsigned width, unsigned height, struct u_rect *region)
{ {
struct u_rect intersect = {0, width, 0, height}; struct u_rect intersect = {0, width, 0, height};
/* FIXME: this is very inefficient; if no renderpass has been started yet,
* we should record the clear if it's full-screen, and apply it as we
* start the render-pass. Otherwise we can do a partial out-of-renderpass
* clear.
*/
if (!u_rect_test_intersection(region, &intersect)) if (!u_rect_test_intersection(region, &intersect))
/* is this even a thing? */ /* is this even a thing? */
return true; return true;
@ -185,6 +179,25 @@ clear_needs_rp(unsigned width, unsigned height, struct u_rect *region)
return false; return false;
} }
static struct zink_framebuffer_clear_data *
get_clear_data(struct zink_context *ctx, struct zink_framebuffer_clear *fb_clear, const struct pipe_scissor_state *scissor_state)
{
struct zink_framebuffer_clear_data *clear = NULL;
unsigned num_clears = zink_fb_clear_count(fb_clear);
if (num_clears) {
struct zink_framebuffer_clear_data *last_clear = zink_fb_clear_element(fb_clear, num_clears - 1);
/* if we're completely overwriting the previous clear, merge this into the previous clear */
if (!scissor_state || (last_clear->has_scissor && scissor_states_equal(&last_clear->scissor, scissor_state)))
clear = last_clear;
}
if (!clear) {
struct zink_framebuffer_clear_data cd = {};
util_dynarray_append(&fb_clear->clears, struct zink_framebuffer_clear_data, cd);
clear = zink_fb_clear_element(fb_clear, zink_fb_clear_count(fb_clear) - 1);
}
return clear;
}
void void
zink_clear(struct pipe_context *pctx, zink_clear(struct pipe_context *pctx,
unsigned buffers, unsigned buffers,
@ -203,7 +216,7 @@ zink_clear(struct pipe_context *pctx,
} }
if (needs_rp || batch->in_rp || ctx->render_condition_active) { if (batch->in_rp || ctx->render_condition_active) {
clear_in_rp(pctx, buffers, scissor_state, pcolor, depth, stencil); clear_in_rp(pctx, buffers, scissor_state, pcolor, depth, stencil);
return; return;
} }
@ -212,45 +225,129 @@ zink_clear(struct pipe_context *pctx,
for (unsigned i = 0; i < fb->nr_cbufs; i++) { for (unsigned i = 0; i < fb->nr_cbufs; i++) {
if ((buffers & (PIPE_CLEAR_COLOR0 << i)) && fb->cbufs[i]) { if ((buffers & (PIPE_CLEAR_COLOR0 << i)) && fb->cbufs[i]) {
struct pipe_surface *psurf = fb->cbufs[i]; struct pipe_surface *psurf = fb->cbufs[i];
struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[i];
struct zink_framebuffer_clear_data *clear = get_clear_data(ctx, fb_clear, needs_rp ? scissor_state : NULL);
if (psurf->texture->target == PIPE_TEXTURE_3D && !check_3d_layers(psurf)) { fb_clear->enabled = true;
clear_in_rp(pctx, buffers, scissor_state, pcolor, depth, stencil); clear->has_scissor = needs_rp;
return; if (scissor_state && needs_rp)
} clear->scissor = *scissor_state;
struct zink_resource *res = zink_resource(psurf->texture); clear->color.color = *pcolor;
union pipe_color_union color = *pcolor; clear->color.srgb = psurf->format != psurf->texture->format &&
if (psurf->format != res->base.format && !util_format_is_srgb(psurf->format) && util_format_is_srgb(psurf->texture->format);
!util_format_is_srgb(psurf->format) && util_format_is_srgb(res->base.format)) {
/* if SRGB mode is disabled for the fb with a backing srgb image then we have to
* convert this to srgb color
*/
color.f[0] = util_format_srgb_to_linear_float(pcolor->f[0]);
color.f[1] = util_format_srgb_to_linear_float(pcolor->f[1]);
color.f[2] = util_format_srgb_to_linear_float(pcolor->f[2]);
}
clear_color_no_rp(ctx, zink_resource(fb->cbufs[i]->texture), &color,
psurf->u.tex.level, psurf->u.tex.first_layer,
psurf->u.tex.last_layer - psurf->u.tex.first_layer + 1);
} }
} }
} }
if (buffers & PIPE_CLEAR_DEPTHSTENCIL && fb->zsbuf) { if (buffers & PIPE_CLEAR_DEPTHSTENCIL && fb->zsbuf) {
if (fb->zsbuf->texture->target == PIPE_TEXTURE_3D && !check_3d_layers(fb->zsbuf)) { struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[PIPE_MAX_COLOR_BUFS];
clear_in_rp(pctx, buffers, scissor_state, pcolor, depth, stencil); struct zink_framebuffer_clear_data *clear = get_clear_data(ctx, fb_clear, needs_rp ? scissor_state : NULL);
return; fb_clear->enabled = true;
} clear->has_scissor = needs_rp;
VkImageAspectFlags aspects = 0; if (scissor_state && needs_rp)
clear->scissor = *scissor_state;
if (buffers & PIPE_CLEAR_DEPTH) if (buffers & PIPE_CLEAR_DEPTH)
aspects |= VK_IMAGE_ASPECT_DEPTH_BIT; clear->zs.depth = depth;
if (buffers & PIPE_CLEAR_STENCIL) if (buffers & PIPE_CLEAR_STENCIL)
aspects |= VK_IMAGE_ASPECT_STENCIL_BIT; clear->zs.stencil = stencil;
clear_zs_no_rp(ctx, zink_resource(fb->zsbuf->texture), aspects, clear->zs.bits |= (buffers & PIPE_CLEAR_DEPTHSTENCIL);
depth, stencil, fb->zsbuf->u.tex.level, fb->zsbuf->u.tex.first_layer,
fb->zsbuf->u.tex.last_layer - fb->zsbuf->u.tex.first_layer + 1);
} }
} }
static inline bool
colors_equal(union pipe_color_union *a, union pipe_color_union *b)
{
return a->ui[0] == b->ui[0] && a->ui[1] == b->ui[1] && a->ui[2] == b->ui[2] && a->ui[3] == b->ui[3];
}
void
zink_clear_framebuffer(struct zink_context *ctx, unsigned clear_buffers)
{
unsigned to_clear = 0;
struct pipe_framebuffer_state *fb_state = &ctx->fb_state;
while (clear_buffers) {
struct zink_framebuffer_clear *color_clear = NULL;
struct zink_framebuffer_clear *zs_clear = NULL;
unsigned num_clears = 0;
for (int i = 0; i < fb_state->nr_cbufs && clear_buffers >= PIPE_CLEAR_COLOR0; i++) {
struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[i];
/* these need actual clear calls inside the rp */
if (!(clear_buffers & (PIPE_CLEAR_COLOR0 << i)))
continue;
if (color_clear) {
/* different number of clears -> do another clear */
//XXX: could potentially merge "some" of the clears into this one for a very, very small optimization
if (num_clears != zink_fb_clear_count(fb_clear))
goto out;
/* compare all the clears to determine if we can batch these buffers together */
for (int j = 0; j < num_clears; j++) {
struct zink_framebuffer_clear_data *a = zink_fb_clear_element(color_clear, j);
struct zink_framebuffer_clear_data *b = zink_fb_clear_element(fb_clear, j);
/* scissors don't match, fire this one off */
if (a->has_scissor != b->has_scissor || (a->has_scissor && !scissor_states_equal(&a->scissor, &b->scissor)))
goto out;
/* colors don't match, fire this one off */
if (!colors_equal(&a->color.color, &b->color.color))
goto out;
}
} else {
color_clear = fb_clear;
num_clears = zink_fb_clear_count(fb_clear);
}
clear_buffers &= ~(PIPE_CLEAR_COLOR0 << i);
to_clear |= (PIPE_CLEAR_COLOR0 << i);
}
if (clear_buffers & PIPE_CLEAR_DEPTHSTENCIL) {
struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[PIPE_MAX_COLOR_BUFS];
if (color_clear) {
if (num_clears != zink_fb_clear_count(fb_clear))
goto out;
/* compare all the clears to determine if we can batch these buffers together */
for (int j = 0; j < zink_fb_clear_count(color_clear); j++) {
struct zink_framebuffer_clear_data *a = zink_fb_clear_element(color_clear, j);
struct zink_framebuffer_clear_data *b = zink_fb_clear_element(fb_clear, j);
/* scissors don't match, fire this one off */
if (a->has_scissor != b->has_scissor || (a->has_scissor && !scissor_states_equal(&a->scissor, &b->scissor)))
goto out;
}
}
zs_clear = fb_clear;
to_clear |= (clear_buffers & PIPE_CLEAR_DEPTHSTENCIL);
clear_buffers &= ~PIPE_CLEAR_DEPTHSTENCIL;
}
out:
if (to_clear) {
if (num_clears) {
for (int j = 0; j < num_clears; j++) {
struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(color_clear, j);
struct zink_framebuffer_clear_data *zsclear = NULL;
if (zs_clear)
zsclear = zink_fb_clear_element(zs_clear, j);
zink_clear(&ctx->base, to_clear,
clear->has_scissor ? &clear->scissor : NULL,
&clear->color.color,
zsclear ? zsclear->zs.depth : 0,
zsclear ? zsclear->zs.stencil : 0);
}
} else {
for (int j = 0; j < zink_fb_clear_count(zs_clear); j++) {
struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(zs_clear, j);
zink_clear(&ctx->base, to_clear,
clear->has_scissor ? &clear->scissor : NULL,
NULL,
clear->zs.depth,
clear->zs.stencil);
}
}
}
to_clear = 0;
}
for (int i = 0; i < ARRAY_SIZE(ctx->fb_clears); i++)
zink_fb_clear_reset(&ctx->fb_clears[i]);
}
static struct pipe_surface * static struct pipe_surface *
create_clear_surface(struct pipe_context *pctx, struct pipe_resource *pres, unsigned level, const struct pipe_box *box) create_clear_surface(struct pipe_context *pctx, struct pipe_resource *pres, unsigned level, const struct pipe_box *box)
{ {
@ -318,3 +415,91 @@ zink_clear_texture(struct pipe_context *pctx,
} }
pipe_surface_reference(&surf, NULL); pipe_surface_reference(&surf, NULL);
} }
bool
zink_fb_clear_needs_explicit(struct zink_framebuffer_clear *fb_clear)
{
if (zink_fb_clear_count(fb_clear) != 1)
return true;
struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(fb_clear, 0);
return clear->has_scissor;
}
void
zink_fb_clears_apply(struct zink_context *ctx, struct pipe_resource *pres)
{
if (zink_resource(pres)->aspect == VK_IMAGE_ASPECT_COLOR_BIT) {
for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) {
if (ctx->fb_state.cbufs[i] && ctx->fb_state.cbufs[i]->texture == pres) {
struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[i];
if (fb_clear->enabled) {
assert(!zink_curr_batch(ctx)->in_rp);
if (zink_fb_clear_needs_explicit(fb_clear) || !check_3d_layers(ctx->fb_state.cbufs[i]))
/* this will automatically trigger all the clears */
zink_batch_rp(ctx);
else {
struct pipe_surface *psurf = ctx->fb_state.cbufs[i];
struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(fb_clear, 0);
union pipe_color_union color = clear->color.color;
if (clear->color.srgb) {
/* if SRGB mode is disabled for the fb with a backing srgb image then we have to
* convert this to srgb color
*/
color.f[0] = util_format_srgb_to_linear_float(clear->color.color.f[0]);
color.f[1] = util_format_srgb_to_linear_float(clear->color.color.f[1]);
color.f[2] = util_format_srgb_to_linear_float(clear->color.color.f[2]);
}
clear_color_no_rp(ctx, zink_resource(pres), &color,
psurf->u.tex.level, psurf->u.tex.first_layer,
psurf->u.tex.last_layer - psurf->u.tex.first_layer + 1);
}
zink_fb_clear_reset(&ctx->fb_clears[i]);
}
return;
}
}
} else {
struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[PIPE_MAX_COLOR_BUFS];
if (fb_clear->enabled && ctx->fb_state.zsbuf && ctx->fb_state.zsbuf->texture == pres) {
assert(!zink_curr_batch(ctx)->in_rp);
if (zink_fb_clear_needs_explicit(fb_clear) || !check_3d_layers(ctx->fb_state.zsbuf))
/* this will automatically trigger all the clears */
zink_batch_rp(ctx);
else {
struct pipe_surface *psurf = ctx->fb_state.zsbuf;
struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(fb_clear, 0);
VkImageAspectFlags aspects = 0;
if (clear->zs.bits & PIPE_CLEAR_DEPTH)
aspects |= VK_IMAGE_ASPECT_DEPTH_BIT;
if (clear->zs.bits & PIPE_CLEAR_STENCIL)
aspects |= VK_IMAGE_ASPECT_STENCIL_BIT;
clear_zs_no_rp(ctx, zink_resource(pres), aspects, clear->zs.depth, clear->zs.stencil,
psurf->u.tex.level, psurf->u.tex.first_layer,
psurf->u.tex.last_layer - psurf->u.tex.first_layer + 1);
zink_fb_clear_reset(fb_clear);
}
}
}
}
void
zink_fb_clears_discard(struct zink_context *ctx, struct pipe_resource *pres)
{
if (zink_resource(pres)->aspect == VK_IMAGE_ASPECT_COLOR_BIT) {
for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) {
if (ctx->fb_state.cbufs[i] && ctx->fb_state.cbufs[i]->texture == pres) {
if (ctx->fb_clears[i].enabled) {
zink_fb_clear_reset(&ctx->fb_clears[i]);
return;
}
}
}
} else {
if (ctx->fb_clears[PIPE_MAX_COLOR_BUFS].enabled && ctx->fb_state.zsbuf && ctx->fb_state.zsbuf->texture == pres) {
int i = PIPE_MAX_COLOR_BUFS;
zink_fb_clear_reset(&ctx->fb_clears[i]);
}
}
}

View file

@ -40,6 +40,7 @@
#include "indices/u_primconvert.h" #include "indices/u_primconvert.h"
#include "util/u_blitter.h" #include "util/u_blitter.h"
#include "util/u_debug.h" #include "util/u_debug.h"
#include "util/format_srgb.h"
#include "util/format/u_format.h" #include "util/format/u_format.h"
#include "util/u_framebuffer.h" #include "util/u_framebuffer.h"
#include "util/u_helpers.h" #include "util/u_helpers.h"
@ -731,6 +732,7 @@ get_render_pass(struct zink_context *ctx)
struct zink_screen *screen = zink_screen(ctx->base.screen); struct zink_screen *screen = zink_screen(ctx->base.screen);
const struct pipe_framebuffer_state *fb = &ctx->fb_state; const struct pipe_framebuffer_state *fb = &ctx->fb_state;
struct zink_render_pass_state state = { 0 }; struct zink_render_pass_state state = { 0 };
uint32_t clears = 0;
for (int i = 0; i < fb->nr_cbufs; i++) { for (int i = 0; i < fb->nr_cbufs; i++) {
struct pipe_surface *surf = fb->cbufs[i]; struct pipe_surface *surf = fb->cbufs[i];
@ -738,6 +740,8 @@ get_render_pass(struct zink_context *ctx)
state.rts[i].format = zink_get_format(screen, surf->format); state.rts[i].format = zink_get_format(screen, surf->format);
state.rts[i].samples = surf->texture->nr_samples > 0 ? surf->texture->nr_samples : state.rts[i].samples = surf->texture->nr_samples > 0 ? surf->texture->nr_samples :
VK_SAMPLE_COUNT_1_BIT; VK_SAMPLE_COUNT_1_BIT;
state.rts[i].clear_color = ctx->fb_clears[i].enabled && !zink_fb_clear_needs_explicit(&ctx->fb_clears[i]);
clears |= !!state.rts[i].clear_color ? BITFIELD_BIT(i) : 0;
} else { } else {
state.rts[i].format = VK_FORMAT_R8_UINT; state.rts[i].format = VK_FORMAT_R8_UINT;
state.rts[i].samples = MAX2(fb->samples, 1); state.rts[i].samples = MAX2(fb->samples, 1);
@ -748,11 +752,22 @@ get_render_pass(struct zink_context *ctx)
if (fb->zsbuf) { if (fb->zsbuf) {
struct zink_resource *zsbuf = zink_resource(fb->zsbuf->texture); struct zink_resource *zsbuf = zink_resource(fb->zsbuf->texture);
struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[PIPE_MAX_COLOR_BUFS];
state.rts[fb->nr_cbufs].format = zsbuf->format; state.rts[fb->nr_cbufs].format = zsbuf->format;
state.rts[fb->nr_cbufs].samples = zsbuf->base.nr_samples > 0 ? zsbuf->base.nr_samples : VK_SAMPLE_COUNT_1_BIT; state.rts[fb->nr_cbufs].samples = zsbuf->base.nr_samples > 0 ? zsbuf->base.nr_samples : VK_SAMPLE_COUNT_1_BIT;
state.rts[fb->nr_cbufs].clear_color = fb_clear->enabled &&
!zink_fb_clear_needs_explicit(fb_clear) &&
(zink_fb_clear_element(fb_clear, 0)->zs.bits & PIPE_CLEAR_DEPTH);
state.rts[fb->nr_cbufs].clear_stencil = fb_clear->enabled &&
!zink_fb_clear_needs_explicit(fb_clear) &&
(zink_fb_clear_element(fb_clear, 0)->zs.bits & PIPE_CLEAR_STENCIL);
clears |= state.rts[fb->nr_cbufs].clear_color || state.rts[fb->nr_cbufs].clear_stencil ? BITFIELD_BIT(fb->nr_cbufs) : 0;;
state.num_rts++; state.num_rts++;
} }
state.have_zsbuf = fb->zsbuf != NULL; state.have_zsbuf = fb->zsbuf != NULL;
#ifndef NDEBUG
state.clears = clears;
#endif
uint32_t hash = hash_render_pass_state(&state); uint32_t hash = hash_render_pass_state(&state);
struct hash_entry *entry = _mesa_hash_table_search_pre_hashed(ctx->render_pass_cache, hash, struct hash_entry *entry = _mesa_hash_table_search_pre_hashed(ctx->render_pass_cache, hash,
@ -845,8 +860,51 @@ zink_begin_render_pass(struct zink_context *ctx, struct zink_batch *batch)
rpbi.renderArea.offset.y = 0; rpbi.renderArea.offset.y = 0;
rpbi.renderArea.extent.width = fb_state->width; rpbi.renderArea.extent.width = fb_state->width;
rpbi.renderArea.extent.height = fb_state->height; rpbi.renderArea.extent.height = fb_state->height;
rpbi.clearValueCount = 0;
rpbi.pClearValues = NULL; VkClearValue clears[PIPE_MAX_COLOR_BUFS + 1] = {};
unsigned clear_buffers = 0;
uint32_t clear_validate = 0;
for (int i = 0; i < fb_state->nr_cbufs; i++) {
/* these are no-ops */
if (!fb_state->cbufs[i] || !ctx->fb_clears[i].enabled)
continue;
/* these need actual clear calls inside the rp */
if (zink_fb_clear_needs_explicit(&ctx->fb_clears[i])) {
clear_buffers |= (PIPE_CLEAR_COLOR0 << i);
continue;
}
/* we now know there's only one clear */
struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(&ctx->fb_clears[i], 0);
if (clear->color.srgb) {
clears[i].color.float32[0] = util_format_srgb_to_linear_float(clear->color.color.f[0]);
clears[i].color.float32[1] = util_format_srgb_to_linear_float(clear->color.color.f[1]);
clears[i].color.float32[2] = util_format_srgb_to_linear_float(clear->color.color.f[2]);
} else {
clears[i].color.float32[0] = clear->color.color.f[0];
clears[i].color.float32[1] = clear->color.color.f[1];
clears[i].color.float32[2] = clear->color.color.f[2];
}
clears[i].color.float32[3] = clear->color.color.f[3];
rpbi.clearValueCount = i + 1;
clear_validate |= BITFIELD_BIT(i);
assert(ctx->framebuffer->rp->state.clears);
}
if (fb_state->zsbuf && ctx->fb_clears[PIPE_MAX_COLOR_BUFS].enabled) {
struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[PIPE_MAX_COLOR_BUFS];
if (zink_fb_clear_needs_explicit(fb_clear)) {
for (int j = 0; j < zink_fb_clear_count(fb_clear); j++)
clear_buffers |= zink_fb_clear_element(fb_clear, j)->zs.bits;
} else {
struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(fb_clear, 0);
clears[fb_state->nr_cbufs].depthStencil.depth = clear->zs.depth;
clears[fb_state->nr_cbufs].depthStencil.stencil = clear->zs.stencil;
rpbi.clearValueCount = fb_state->nr_cbufs + 1;
clear_validate |= BITFIELD_BIT(fb_state->nr_cbufs);
assert(ctx->framebuffer->rp->state.clears);
}
}
assert(clear_validate == ctx->framebuffer->rp->state.clears);
rpbi.pClearValues = &clears[0];
rpbi.framebuffer = ctx->framebuffer->fb; rpbi.framebuffer = ctx->framebuffer->fb;
assert(ctx->gfx_pipeline_state.render_pass && ctx->framebuffer); assert(ctx->gfx_pipeline_state.render_pass && ctx->framebuffer);
@ -859,6 +917,8 @@ zink_begin_render_pass(struct zink_context *ctx, struct zink_batch *batch)
vkCmdBeginRenderPass(batch->cmdbuf, &rpbi, VK_SUBPASS_CONTENTS_INLINE); vkCmdBeginRenderPass(batch->cmdbuf, &rpbi, VK_SUBPASS_CONTENTS_INLINE);
batch->in_rp = true; batch->in_rp = true;
zink_clear_framebuffer(ctx, clear_buffers);
} }
static void static void
@ -916,6 +976,22 @@ zink_set_framebuffer_state(struct pipe_context *pctx,
{ {
struct zink_context *ctx = zink_context(pctx); struct zink_context *ctx = zink_context(pctx);
for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) {
struct pipe_surface *surf = ctx->fb_state.cbufs[i];
if (surf &&
(!state->cbufs[i] || i >= state->nr_cbufs ||
surf->texture != state->cbufs[i]->texture ||
surf->format != state->cbufs[i]->format ||
memcmp(&surf->u, &state->cbufs[i]->u, sizeof(union pipe_surface_desc))))
zink_fb_clears_apply(ctx, surf->texture);
}
if (ctx->fb_state.zsbuf) {
struct pipe_surface *surf = ctx->fb_state.zsbuf;
if (!state->zsbuf || surf->texture != state->zsbuf->texture ||
memcmp(&surf->u, &state->zsbuf->u, sizeof(union pipe_surface_desc)))
zink_fb_clears_apply(ctx, ctx->fb_state.zsbuf->texture);
}
util_copy_framebuffer_state(&ctx->fb_state, state); util_copy_framebuffer_state(&ctx->fb_state, state);
uint8_t rast_samples = util_framebuffer_get_num_samples(state); uint8_t rast_samples = util_framebuffer_get_num_samples(state);
@ -1515,6 +1591,9 @@ zink_resource_copy_region(struct pipe_context *pctx,
} else } else
unreachable("planar formats not yet handled"); unreachable("planar formats not yet handled");
zink_fb_clears_apply(ctx, pdst);
zink_fb_clears_apply(ctx, psrc);
region.srcSubresource.aspectMask = src->aspect; region.srcSubresource.aspectMask = src->aspect;
region.srcSubresource.mipLevel = src_level; region.srcSubresource.mipLevel = src_level;
region.srcSubresource.layerCount = 1; region.srcSubresource.layerCount = 1;
@ -1767,6 +1846,8 @@ zink_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags)
ctx->base.stream_uploader = u_upload_create_default(&ctx->base); ctx->base.stream_uploader = u_upload_create_default(&ctx->base);
ctx->base.const_uploader = ctx->base.stream_uploader; ctx->base.const_uploader = ctx->base.stream_uploader;
for (int i = 0; i < ARRAY_SIZE(ctx->fb_clears); i++)
util_dynarray_init(&ctx->fb_clears[i].clears, ctx);
int prim_hwsupport = 1 << PIPE_PRIM_POINTS | int prim_hwsupport = 1 << PIPE_PRIM_POINTS |
1 << PIPE_PRIM_LINES | 1 << PIPE_PRIM_LINES |

View file

@ -96,6 +96,27 @@ struct zink_viewport_state {
uint8_t num_viewports; uint8_t num_viewports;
}; };
struct zink_framebuffer_clear_data {
union {
struct {
union pipe_color_union color;
bool srgb;
} color;
struct {
float depth;
unsigned stencil;
uint8_t bits : 2; // PIPE_CLEAR_DEPTH, PIPE_CLEAR_STENCIL
} zs;
};
struct pipe_scissor_state scissor;
bool has_scissor;
};
struct zink_framebuffer_clear {
struct util_dynarray clears;
bool enabled;
};
#define ZINK_SHADER_COUNT (PIPE_SHADER_TYPES - 1) #define ZINK_SHADER_COUNT (PIPE_SHADER_TYPES - 1)
#define ZINK_NUM_GFX_BATCHES 4 #define ZINK_NUM_GFX_BATCHES 4
#define ZINK_COMPUTE_BATCH_ID ZINK_NUM_GFX_BATCHES #define ZINK_COMPUTE_BATCH_ID ZINK_NUM_GFX_BATCHES
@ -145,6 +166,7 @@ struct zink_context {
struct primconvert_context *primconvert; struct primconvert_context *primconvert;
struct zink_framebuffer *framebuffer; struct zink_framebuffer *framebuffer;
struct zink_framebuffer_clear fb_clears[PIPE_MAX_COLOR_BUFS + 1];
struct pipe_vertex_buffer buffers[PIPE_MAX_ATTRIBS]; struct pipe_vertex_buffer buffers[PIPE_MAX_ATTRIBS];
uint32_t buffers_enabled_mask; uint32_t buffers_enabled_mask;
@ -270,6 +292,37 @@ zink_clear_texture(struct pipe_context *ctx,
const struct pipe_box *box, const struct pipe_box *box,
const void *data); const void *data);
bool
zink_fb_clear_needs_explicit(struct zink_framebuffer_clear *fb_clear);
void
zink_clear_framebuffer(struct zink_context *ctx, unsigned clear_buffers);
static inline struct zink_framebuffer_clear_data *
zink_fb_clear_element(struct zink_framebuffer_clear *fb_clear, int idx)
{
return util_dynarray_element(&fb_clear->clears, struct zink_framebuffer_clear_data, idx);
}
static inline unsigned
zink_fb_clear_count(struct zink_framebuffer_clear *fb_clear)
{
return util_dynarray_num_elements(&fb_clear->clears, struct zink_framebuffer_clear_data);
}
static inline void
zink_fb_clear_reset(struct zink_framebuffer_clear *fb_clear)
{
util_dynarray_fini(&fb_clear->clears);
fb_clear->enabled = false;
}
void
zink_fb_clears_apply(struct zink_context *ctx, struct pipe_resource *pres);
void
zink_fb_clears_discard(struct zink_context *ctx, struct pipe_resource *pres);
void void
zink_draw_vbo(struct pipe_context *pctx, zink_draw_vbo(struct pipe_context *pctx,
const struct pipe_draw_info *dinfo, const struct pipe_draw_info *dinfo,

View file

@ -40,7 +40,7 @@ create_render_pass(VkDevice dev, struct zink_render_pass_state *state)
attachments[i].flags = 0; attachments[i].flags = 0;
attachments[i].format = rt->format; attachments[i].format = rt->format;
attachments[i].samples = rt->samples; attachments[i].samples = rt->samples;
attachments[i].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; attachments[i].loadOp = rt->clear_color ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD;
attachments[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE; attachments[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; attachments[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; attachments[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
@ -56,9 +56,9 @@ create_render_pass(VkDevice dev, struct zink_render_pass_state *state)
attachments[num_attachments].flags = 0; attachments[num_attachments].flags = 0;
attachments[num_attachments].format = rt->format; attachments[num_attachments].format = rt->format;
attachments[num_attachments].samples = rt->samples; attachments[num_attachments].samples = rt->samples;
attachments[num_attachments].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; attachments[num_attachments].loadOp = rt->clear_color ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD;
attachments[num_attachments].storeOp = VK_ATTACHMENT_STORE_OP_STORE; attachments[num_attachments].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[num_attachments].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; attachments[num_attachments].stencilLoadOp = rt->clear_stencil ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD;
attachments[num_attachments].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; attachments[num_attachments].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[num_attachments].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; attachments[num_attachments].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
attachments[num_attachments].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; attachments[num_attachments].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;

View file

@ -34,6 +34,8 @@ struct zink_screen;
struct zink_rt_attrib { struct zink_rt_attrib {
VkFormat format; VkFormat format;
VkSampleCountFlagBits samples; VkSampleCountFlagBits samples;
bool clear_color;
bool clear_stencil;
}; };
struct zink_render_pass_state { struct zink_render_pass_state {
@ -41,6 +43,9 @@ struct zink_render_pass_state {
uint8_t have_zsbuf : 1; uint8_t have_zsbuf : 1;
struct zink_rt_attrib rts[PIPE_MAX_COLOR_BUFS + 1]; struct zink_rt_attrib rts[PIPE_MAX_COLOR_BUFS + 1];
unsigned num_rts; unsigned num_rts;
#ifndef NDEBUG
uint32_t clears; //for extra verification
#endif
}; };
struct zink_render_pass { struct zink_render_pass {

View file

@ -619,6 +619,7 @@ zink_transfer_map(struct pipe_context *pctx,
if (usage & PIPE_MAP_WRITE) if (usage & PIPE_MAP_WRITE)
util_range_add(&res->base, &res->valid_buffer_range, box->x, box->x + box->width); util_range_add(&res->base, &res->valid_buffer_range, box->x, box->x + box->width);
} else { } else {
zink_fb_clears_apply(ctx, pres);
if (res->optimal_tiling || !res->host_visible) { if (res->optimal_tiling || !res->host_visible) {
enum pipe_format format = pres->format; enum pipe_format format = pres->format;
if (usage & PIPE_MAP_DEPTH_ONLY) if (usage & PIPE_MAP_DEPTH_ONLY)