
both bits will have been flagged at this point in order to indicate
that the aspects will be cleared "at some point" during the loop, but
when actually iterating through the pending clears, only the bits set
in the clear call should be applied
Fixes: 5c629e9ff2
("zink: defer pipe_context::clear calls when not currently in a renderpass")
Reviewed-by: Dave Airlie <airlied@redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/9366>
603 lines
24 KiB
C
603 lines
24 KiB
C
/*
|
|
* Copyright 2018 Collabora Ltd.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* on the rights to use, copy, modify, merge, publish, distribute, sub
|
|
* license, and/or sell copies of the Software, and to permit persons to whom
|
|
* the Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice (including the next
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
* Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
|
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
#include "zink_context.h"
|
|
#include "zink_resource.h"
|
|
#include "zink_screen.h"
|
|
|
|
#include "util/u_blitter.h"
|
|
#include "util/u_dynarray.h"
|
|
#include "util/format/u_format.h"
|
|
#include "util/format_srgb.h"
|
|
#include "util/u_framebuffer.h"
|
|
#include "util/u_inlines.h"
|
|
#include "util/u_rect.h"
|
|
#include "util/u_surface.h"
|
|
|
|
static inline bool
|
|
check_3d_layers(struct pipe_surface *psurf)
|
|
{
|
|
if (psurf->texture->target != PIPE_TEXTURE_3D)
|
|
return true;
|
|
/* SPEC PROBLEM:
|
|
* 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,
|
|
* so we can never clear them if we aren't trying to clear only layer 0
|
|
*/
|
|
if (psurf->u.tex.first_layer)
|
|
return false;
|
|
|
|
if (psurf->u.tex.last_layer - psurf->u.tex.first_layer > 0)
|
|
return false;
|
|
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
|
|
clear_in_rp(struct pipe_context *pctx,
|
|
unsigned buffers,
|
|
const struct pipe_scissor_state *scissor_state,
|
|
const union pipe_color_union *pcolor,
|
|
double depth, unsigned stencil)
|
|
{
|
|
struct zink_context *ctx = zink_context(pctx);
|
|
struct pipe_framebuffer_state *fb = &ctx->fb_state;
|
|
|
|
VkClearAttachment attachments[1 + PIPE_MAX_COLOR_BUFS];
|
|
int num_attachments = 0;
|
|
|
|
if (buffers & PIPE_CLEAR_COLOR) {
|
|
VkClearColorValue color;
|
|
color.float32[0] = pcolor->f[0];
|
|
color.float32[1] = pcolor->f[1];
|
|
color.float32[2] = pcolor->f[2];
|
|
color.float32[3] = pcolor->f[3];
|
|
|
|
for (unsigned i = 0; i < fb->nr_cbufs; i++) {
|
|
if (!(buffers & (PIPE_CLEAR_COLOR0 << i)) || !fb->cbufs[i])
|
|
continue;
|
|
|
|
attachments[num_attachments].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
attachments[num_attachments].colorAttachment = i;
|
|
attachments[num_attachments].clearValue.color = color;
|
|
++num_attachments;
|
|
}
|
|
}
|
|
|
|
if (buffers & PIPE_CLEAR_DEPTHSTENCIL && fb->zsbuf) {
|
|
VkImageAspectFlags aspect = 0;
|
|
if (buffers & PIPE_CLEAR_DEPTH)
|
|
aspect |= VK_IMAGE_ASPECT_DEPTH_BIT;
|
|
if (buffers & PIPE_CLEAR_STENCIL)
|
|
aspect |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
|
|
|
attachments[num_attachments].aspectMask = aspect;
|
|
attachments[num_attachments].clearValue.depthStencil.depth = depth;
|
|
attachments[num_attachments].clearValue.depthStencil.stencil = stencil;
|
|
++num_attachments;
|
|
}
|
|
|
|
VkClearRect cr = {};
|
|
if (scissor_state) {
|
|
cr.rect.offset.x = scissor_state->minx;
|
|
cr.rect.offset.y = scissor_state->miny;
|
|
cr.rect.extent.width = MIN2(fb->width, scissor_state->maxx - scissor_state->minx);
|
|
cr.rect.extent.height = MIN2(fb->height, scissor_state->maxy - scissor_state->miny);
|
|
} else {
|
|
cr.rect.extent.width = fb->width;
|
|
cr.rect.extent.height = fb->height;
|
|
}
|
|
cr.baseArrayLayer = 0;
|
|
cr.layerCount = util_framebuffer_get_num_layers(fb);
|
|
struct zink_batch *batch = zink_batch_rp(ctx);
|
|
vkCmdClearAttachments(batch->cmdbuf, num_attachments, attachments, 1, &cr);
|
|
}
|
|
|
|
static void
|
|
clear_color_no_rp(struct zink_context *ctx, struct zink_resource *res, const union pipe_color_union *pcolor, unsigned level, unsigned layer, unsigned layerCount)
|
|
{
|
|
struct zink_batch *batch = zink_batch_no_rp(ctx);
|
|
VkImageSubresourceRange range = {};
|
|
range.baseMipLevel = level;
|
|
range.levelCount = 1;
|
|
range.baseArrayLayer = layer;
|
|
range.layerCount = layerCount;
|
|
range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
|
|
VkClearColorValue color;
|
|
color.float32[0] = pcolor->f[0];
|
|
color.float32[1] = pcolor->f[1];
|
|
color.float32[2] = pcolor->f[2];
|
|
color.float32[3] = pcolor->f[3];
|
|
|
|
if (zink_resource_image_needs_barrier(res, VK_IMAGE_LAYOUT_GENERAL, 0, 0) &&
|
|
zink_resource_image_needs_barrier(res, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, 0))
|
|
zink_resource_image_barrier(ctx, NULL, res, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, 0);
|
|
zink_batch_reference_resource_rw(batch, res, true);
|
|
vkCmdClearColorImage(batch->cmdbuf, res->image, res->layout, &color, 1, &range);
|
|
}
|
|
|
|
static void
|
|
clear_zs_no_rp(struct zink_context *ctx, struct zink_resource *res, VkImageAspectFlags aspects, double depth, unsigned stencil, unsigned level, unsigned layer, unsigned layerCount)
|
|
{
|
|
struct zink_batch *batch = zink_batch_no_rp(ctx);
|
|
VkImageSubresourceRange range = {};
|
|
range.baseMipLevel = level;
|
|
range.levelCount = 1;
|
|
range.baseArrayLayer = layer;
|
|
range.layerCount = layerCount;
|
|
range.aspectMask = aspects;
|
|
|
|
VkClearDepthStencilValue zs_value = {depth, stencil};
|
|
|
|
if (zink_resource_image_needs_barrier(res, VK_IMAGE_LAYOUT_GENERAL, 0, 0) &&
|
|
zink_resource_image_needs_barrier(res, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, 0))
|
|
zink_resource_image_barrier(ctx, NULL, res, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, 0);
|
|
zink_batch_reference_resource_rw(batch, res, true);
|
|
vkCmdClearDepthStencilImage(batch->cmdbuf, res->image, res->layout, &zs_value, 1, &range);
|
|
}
|
|
|
|
|
|
|
|
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
|
|
zink_clear(struct pipe_context *pctx,
|
|
unsigned buffers,
|
|
const struct pipe_scissor_state *scissor_state,
|
|
const union pipe_color_union *pcolor,
|
|
double depth, unsigned stencil)
|
|
{
|
|
struct zink_context *ctx = zink_context(pctx);
|
|
struct pipe_framebuffer_state *fb = &ctx->fb_state;
|
|
struct zink_batch *batch = zink_curr_batch(ctx);
|
|
bool needs_rp = false;
|
|
|
|
if (scissor_state) {
|
|
struct u_rect scissor = {scissor_state->minx, scissor_state->maxx, scissor_state->miny, scissor_state->maxy};
|
|
needs_rp = !zink_blit_region_fills(scissor, fb->width, fb->height);
|
|
}
|
|
|
|
|
|
if (batch->in_rp) {
|
|
clear_in_rp(pctx, buffers, scissor_state, pcolor, depth, stencil);
|
|
return;
|
|
}
|
|
|
|
if (buffers & PIPE_CLEAR_COLOR) {
|
|
for (unsigned i = 0; i < fb->nr_cbufs; i++) {
|
|
if ((buffers & (PIPE_CLEAR_COLOR0 << i)) && 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);
|
|
|
|
fb_clear->enabled = true;
|
|
clear->conditional = ctx->render_condition_active;
|
|
clear->has_scissor = needs_rp;
|
|
if (scissor_state && needs_rp)
|
|
clear->scissor = *scissor_state;
|
|
clear->color.color = *pcolor;
|
|
clear->color.srgb = psurf->format != psurf->texture->format &&
|
|
!util_format_is_srgb(psurf->format) && util_format_is_srgb(psurf->texture->format);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (buffers & PIPE_CLEAR_DEPTHSTENCIL && fb->zsbuf) {
|
|
struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[PIPE_MAX_COLOR_BUFS];
|
|
struct zink_framebuffer_clear_data *clear = get_clear_data(ctx, fb_clear, needs_rp ? scissor_state : NULL);
|
|
fb_clear->enabled = true;
|
|
clear->conditional = ctx->render_condition_active;
|
|
clear->has_scissor = needs_rp;
|
|
if (scissor_state && needs_rp)
|
|
clear->scissor = *scissor_state;
|
|
if (buffers & PIPE_CLEAR_DEPTH)
|
|
clear->zs.depth = depth;
|
|
if (buffers & PIPE_CLEAR_STENCIL)
|
|
clear->zs.stencil = stencil;
|
|
clear->zs.bits |= (buffers & PIPE_CLEAR_DEPTHSTENCIL);
|
|
}
|
|
}
|
|
|
|
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 = !zink_fb_clear_first_needs_explicit(fb_clear); 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 = !zink_fb_clear_first_needs_explicit(fb_clear); 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 = !zink_fb_clear_first_needs_explicit(color_clear); j < num_clears; j++) {
|
|
struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(color_clear, j);
|
|
struct zink_framebuffer_clear_data *zsclear = NULL;
|
|
/* zs bits are both set here if those aspects should be cleared at some point */
|
|
unsigned clear_bits = to_clear & ~PIPE_CLEAR_DEPTHSTENCIL;
|
|
if (zs_clear) {
|
|
zsclear = zink_fb_clear_element(zs_clear, j);
|
|
clear_bits |= zsclear->zs.bits;
|
|
}
|
|
zink_clear(&ctx->base, clear_bits,
|
|
clear->has_scissor ? &clear->scissor : NULL,
|
|
&clear->color.color,
|
|
zsclear ? zsclear->zs.depth : 0,
|
|
zsclear ? zsclear->zs.stencil : 0);
|
|
}
|
|
} else {
|
|
for (int j = !zink_fb_clear_first_needs_explicit(zs_clear); 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, clear->zs.bits,
|
|
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 *
|
|
create_clear_surface(struct pipe_context *pctx, struct pipe_resource *pres, unsigned level, const struct pipe_box *box)
|
|
{
|
|
struct pipe_surface tmpl = {{0}};
|
|
|
|
tmpl.format = pres->format;
|
|
tmpl.u.tex.first_layer = box->z;
|
|
tmpl.u.tex.last_layer = box->z + box->depth - 1;
|
|
tmpl.u.tex.level = level;
|
|
return pctx->create_surface(pctx, pres, &tmpl);
|
|
}
|
|
|
|
void
|
|
zink_clear_texture(struct pipe_context *pctx,
|
|
struct pipe_resource *pres,
|
|
unsigned level,
|
|
const struct pipe_box *box,
|
|
const void *data)
|
|
{
|
|
struct zink_context *ctx = zink_context(pctx);
|
|
struct zink_resource *res = zink_resource(pres);
|
|
struct pipe_screen *pscreen = pctx->screen;
|
|
struct u_rect region = zink_rect_from_box(box);
|
|
bool needs_rp = !zink_blit_region_fills(region, pres->width0, pres->height0) || ctx->render_condition_active;
|
|
struct zink_batch *batch = zink_curr_batch(ctx);
|
|
struct pipe_surface *surf = NULL;
|
|
|
|
if (res->aspect & VK_IMAGE_ASPECT_COLOR_BIT) {
|
|
union pipe_color_union color;
|
|
|
|
util_format_unpack_rgba(pres->format, color.ui, data, 1);
|
|
|
|
if (pscreen->is_format_supported(pscreen, pres->format, pres->target, 0, 0,
|
|
PIPE_BIND_RENDER_TARGET) && !needs_rp && !batch->in_rp) {
|
|
clear_color_no_rp(ctx, res, &color, level, box->z, box->depth);
|
|
} else {
|
|
surf = create_clear_surface(pctx, pres, level, box);
|
|
zink_blit_begin(ctx, ZINK_BLIT_SAVE_FB | ZINK_BLIT_SAVE_FS);
|
|
util_clear_render_target(pctx, surf, &color, box->x, box->y, box->width, box->height);
|
|
}
|
|
if (res->base.target == PIPE_BUFFER)
|
|
util_range_add(&res->base, &res->valid_buffer_range, box->x, box->x + box->width);
|
|
} else {
|
|
float depth = 0.0;
|
|
uint8_t stencil = 0;
|
|
|
|
if (res->aspect & VK_IMAGE_ASPECT_DEPTH_BIT)
|
|
util_format_unpack_z_float(pres->format, &depth, data, 1);
|
|
|
|
if (res->aspect & VK_IMAGE_ASPECT_STENCIL_BIT)
|
|
util_format_unpack_s_8uint(pres->format, &stencil, data, 1);
|
|
|
|
if (!needs_rp && !batch->in_rp)
|
|
clear_zs_no_rp(ctx, res, res->aspect, depth, stencil, level, box->z, box->depth);
|
|
else {
|
|
unsigned flags = 0;
|
|
if (res->aspect & VK_IMAGE_ASPECT_DEPTH_BIT)
|
|
flags |= PIPE_CLEAR_DEPTH;
|
|
if (res->aspect & VK_IMAGE_ASPECT_STENCIL_BIT)
|
|
flags |= PIPE_CLEAR_STENCIL;
|
|
surf = create_clear_surface(pctx, pres, level, box);
|
|
zink_blit_begin(ctx, ZINK_BLIT_SAVE_FB | ZINK_BLIT_SAVE_FS);
|
|
util_blitter_clear_depth_stencil(ctx->blitter, surf, flags, depth, stencil, box->x, box->y, box->width, box->height);
|
|
}
|
|
}
|
|
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;
|
|
return zink_fb_clear_element_needs_explicit(zink_fb_clear_element(fb_clear, 0));
|
|
}
|
|
|
|
bool
|
|
zink_fb_clear_first_needs_explicit(struct zink_framebuffer_clear *fb_clear)
|
|
{
|
|
if (!zink_fb_clear_count(fb_clear))
|
|
return false;
|
|
return zink_fb_clear_element_needs_explicit(zink_fb_clear_element(fb_clear, 0));
|
|
}
|
|
|
|
static void
|
|
fb_clears_apply_internal(struct zink_context *ctx, struct pipe_resource *pres, int i)
|
|
{
|
|
struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[i];
|
|
|
|
if (!fb_clear->enabled)
|
|
return;
|
|
if (zink_resource(pres)->aspect == VK_IMAGE_ASPECT_COLOR_BIT) {
|
|
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 {
|
|
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_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) {
|
|
fb_clears_apply_internal(ctx, pres, i);
|
|
return;
|
|
}
|
|
}
|
|
} else {
|
|
if (ctx->fb_state.zsbuf && ctx->fb_state.zsbuf->texture == pres) {
|
|
fb_clears_apply_internal(ctx, pres, PIPE_MAX_COLOR_BUFS);
|
|
}
|
|
}
|
|
}
|
|
|
|
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]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
zink_clear_apply_conditionals(struct zink_context *ctx)
|
|
{
|
|
for (int i = 0; i < ARRAY_SIZE(ctx->fb_clears); i++) {
|
|
struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[i];
|
|
if (!fb_clear->enabled)
|
|
continue;
|
|
for (int j = 0; j < zink_fb_clear_count(fb_clear); j++) {
|
|
struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(fb_clear, j);
|
|
if (clear->conditional) {
|
|
struct pipe_surface *surf;
|
|
if (i < PIPE_MAX_COLOR_BUFS)
|
|
surf = ctx->fb_state.cbufs[i];
|
|
else
|
|
surf = ctx->fb_state.zsbuf;
|
|
if (surf)
|
|
fb_clears_apply_internal(ctx, surf->texture, i);
|
|
else
|
|
zink_fb_clear_reset(&ctx->fb_clears[i]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
fb_clears_apply_or_discard_internal(struct zink_context *ctx, struct pipe_resource *pres, struct u_rect region, bool discard_only, bool invert, int i)
|
|
{
|
|
struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[i];
|
|
if (fb_clear->enabled) {
|
|
if (zink_blit_region_fills(region, pres->width0, pres->height0)) {
|
|
if (invert)
|
|
fb_clears_apply_internal(ctx, pres, i);
|
|
else
|
|
/* we know we can skip these */
|
|
zink_fb_clears_discard(ctx, pres);
|
|
return;
|
|
}
|
|
for (int j = 0; j < zink_fb_clear_count(fb_clear); j++) {
|
|
struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(fb_clear, j);
|
|
struct u_rect scissor = {clear->scissor.minx, clear->scissor.maxx,
|
|
clear->scissor.miny, clear->scissor.maxy};
|
|
if (!clear->has_scissor || zink_blit_region_covers(region, scissor)) {
|
|
/* this is a clear that isn't fully covered by our pending write */
|
|
if (!discard_only)
|
|
fb_clears_apply_internal(ctx, pres, i);
|
|
return;
|
|
}
|
|
}
|
|
if (!invert)
|
|
/* if we haven't already returned, then we know we can discard */
|
|
zink_fb_clears_discard(ctx, pres);
|
|
}
|
|
}
|
|
|
|
void
|
|
zink_fb_clears_apply_or_discard(struct zink_context *ctx, struct pipe_resource *pres, struct u_rect region, bool discard_only)
|
|
{
|
|
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) {
|
|
fb_clears_apply_or_discard_internal(ctx, pres, region, discard_only, false, i);
|
|
return;
|
|
}
|
|
}
|
|
} else {
|
|
if (ctx->fb_clears[PIPE_MAX_COLOR_BUFS].enabled && ctx->fb_state.zsbuf && ctx->fb_state.zsbuf->texture == pres) {
|
|
fb_clears_apply_or_discard_internal(ctx, pres, region, discard_only, false, PIPE_MAX_COLOR_BUFS);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
zink_fb_clears_apply_region(struct zink_context *ctx, struct pipe_resource *pres, struct u_rect region)
|
|
{
|
|
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) {
|
|
fb_clears_apply_or_discard_internal(ctx, pres, region, false, true, i);
|
|
return;
|
|
}
|
|
}
|
|
} else {
|
|
if (ctx->fb_state.zsbuf && ctx->fb_state.zsbuf->texture == pres) {
|
|
fb_clears_apply_or_discard_internal(ctx, pres, region, false, true, PIPE_MAX_COLOR_BUFS);
|
|
}
|
|
}
|
|
}
|