1/* 2 * Copyright 2018 Collabora Ltd. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * on the rights to use, copy, modify, merge, publish, distribute, sub 8 * license, and/or sell copies of the Software, and to permit persons to whom 9 * the Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21 * USE OR OTHER DEALINGS IN THE SOFTWARE. 22 */ 23 24#include "zink_context.h" 25#include "zink_query.h" 26#include "zink_resource.h" 27#include "zink_screen.h" 28 29#include "util/u_blitter.h" 30#include "util/u_dynarray.h" 31#include "util/format/u_format.h" 32#include "util/format_srgb.h" 33#include "util/u_framebuffer.h" 34#include "util/u_inlines.h" 35#include "util/u_rect.h" 36#include "util/u_surface.h" 37#include "util/u_helpers.h" 38 39static inline bool 40check_3d_layers(struct pipe_surface *psurf) 41{ 42 if (psurf->texture->target != PIPE_TEXTURE_3D) 43 return true; 44 /* SPEC PROBLEM: 45 * though the vk spec doesn't seem to explicitly address this, currently drivers 46 * are claiming that all 3D images have a single "3D" layer regardless of layercount, 47 * so we can never clear them if we aren't trying to clear only layer 0 48 */ 49 if (psurf->u.tex.first_layer) 50 return false; 51 52 if (psurf->u.tex.last_layer - psurf->u.tex.first_layer > 0) 53 return false; 54 return true; 55} 56 57static inline bool 58scissor_states_equal(const struct pipe_scissor_state *a, const struct pipe_scissor_state *b) 59{ 60 return a->minx == b->minx && a->miny == b->miny && a->maxx == b->maxx && a->maxy == b->maxy; 61} 62 63static void 64clear_in_rp(struct pipe_context *pctx, 65 unsigned buffers, 66 const struct pipe_scissor_state *scissor_state, 67 const union pipe_color_union *pcolor, 68 double depth, unsigned stencil) 69{ 70 struct zink_context *ctx = zink_context(pctx); 71 struct pipe_framebuffer_state *fb = &ctx->fb_state; 72 73 VkClearAttachment attachments[1 + PIPE_MAX_COLOR_BUFS]; 74 int num_attachments = 0; 75 76 if (buffers & PIPE_CLEAR_COLOR) { 77 VkClearColorValue color; 78 color.float32[0] = pcolor->f[0]; 79 color.float32[1] = pcolor->f[1]; 80 color.float32[2] = pcolor->f[2]; 81 color.float32[3] = pcolor->f[3]; 82 83 for (unsigned i = 0; i < fb->nr_cbufs; i++) { 84 if (!(buffers & (PIPE_CLEAR_COLOR0 << i)) || !fb->cbufs[i]) 85 continue; 86 87 attachments[num_attachments].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 88 attachments[num_attachments].colorAttachment = i; 89 attachments[num_attachments].clearValue.color = color; 90 ++num_attachments; 91 } 92 } 93 94 if (buffers & PIPE_CLEAR_DEPTHSTENCIL && fb->zsbuf) { 95 VkImageAspectFlags aspect = 0; 96 if (buffers & PIPE_CLEAR_DEPTH) 97 aspect |= VK_IMAGE_ASPECT_DEPTH_BIT; 98 if (buffers & PIPE_CLEAR_STENCIL) 99 aspect |= VK_IMAGE_ASPECT_STENCIL_BIT; 100 101 attachments[num_attachments].aspectMask = aspect; 102 attachments[num_attachments].clearValue.depthStencil.depth = depth; 103 attachments[num_attachments].clearValue.depthStencil.stencil = stencil; 104 ++num_attachments; 105 } 106 107 VkClearRect cr = {0}; 108 if (scissor_state) { 109 cr.rect.offset.x = scissor_state->minx; 110 cr.rect.offset.y = scissor_state->miny; 111 cr.rect.extent.width = MIN2(fb->width, scissor_state->maxx - scissor_state->minx); 112 cr.rect.extent.height = MIN2(fb->height, scissor_state->maxy - scissor_state->miny); 113 } else { 114 cr.rect.extent.width = fb->width; 115 cr.rect.extent.height = fb->height; 116 } 117 cr.baseArrayLayer = 0; 118 cr.layerCount = util_framebuffer_get_num_layers(fb); 119 struct zink_batch *batch = &ctx->batch; 120 zink_batch_rp(ctx); 121 VKCTX(CmdClearAttachments)(batch->state->cmdbuf, num_attachments, attachments, 1, &cr); 122} 123 124static void 125clear_color_no_rp(struct zink_context *ctx, struct zink_resource *res, const union pipe_color_union *pcolor, unsigned level, unsigned layer, unsigned layerCount) 126{ 127 struct zink_batch *batch = &ctx->batch; 128 zink_batch_no_rp(ctx); 129 VkImageSubresourceRange range = {0}; 130 range.baseMipLevel = level; 131 range.levelCount = 1; 132 range.baseArrayLayer = layer; 133 range.layerCount = layerCount; 134 range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 135 136 VkClearColorValue color; 137 color.float32[0] = pcolor->f[0]; 138 color.float32[1] = pcolor->f[1]; 139 color.float32[2] = pcolor->f[2]; 140 color.float32[3] = pcolor->f[3]; 141 142 if (zink_resource_image_needs_barrier(res, VK_IMAGE_LAYOUT_GENERAL, 0, 0) && 143 zink_resource_image_needs_barrier(res, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, 0)) 144 zink_resource_image_barrier(ctx, res, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, 0); 145 zink_batch_reference_resource_rw(batch, res, true); 146 VKCTX(CmdClearColorImage)(batch->state->cmdbuf, res->obj->image, res->layout, &color, 1, &range); 147} 148 149static void 150clear_zs_no_rp(struct zink_context *ctx, struct zink_resource *res, VkImageAspectFlags aspects, double depth, unsigned stencil, unsigned level, unsigned layer, unsigned layerCount) 151{ 152 struct zink_batch *batch = &ctx->batch; 153 zink_batch_no_rp(ctx); 154 VkImageSubresourceRange range = {0}; 155 range.baseMipLevel = level; 156 range.levelCount = 1; 157 range.baseArrayLayer = layer; 158 range.layerCount = layerCount; 159 range.aspectMask = aspects; 160 161 VkClearDepthStencilValue zs_value = {depth, stencil}; 162 163 if (zink_resource_image_needs_barrier(res, VK_IMAGE_LAYOUT_GENERAL, 0, 0) && 164 zink_resource_image_needs_barrier(res, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, 0)) 165 zink_resource_image_barrier(ctx, res, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, 0); 166 zink_batch_reference_resource_rw(batch, res, true); 167 VKCTX(CmdClearDepthStencilImage)(batch->state->cmdbuf, res->obj->image, res->layout, &zs_value, 1, &range); 168} 169 170 171 172static struct zink_framebuffer_clear_data * 173get_clear_data(struct zink_context *ctx, struct zink_framebuffer_clear *fb_clear, const struct pipe_scissor_state *scissor_state) 174{ 175 struct zink_framebuffer_clear_data *clear = NULL; 176 unsigned num_clears = zink_fb_clear_count(fb_clear); 177 if (num_clears) { 178 struct zink_framebuffer_clear_data *last_clear = zink_fb_clear_element(fb_clear, num_clears - 1); 179 /* if we're completely overwriting the previous clear, merge this into the previous clear */ 180 if (!scissor_state || (last_clear->has_scissor && scissor_states_equal(&last_clear->scissor, scissor_state))) 181 clear = last_clear; 182 } 183 if (!clear) { 184 struct zink_framebuffer_clear_data cd = {0}; 185 util_dynarray_append(&fb_clear->clears, struct zink_framebuffer_clear_data, cd); 186 clear = zink_fb_clear_element(fb_clear, zink_fb_clear_count(fb_clear) - 1); 187 } 188 return clear; 189} 190 191void 192zink_clear(struct pipe_context *pctx, 193 unsigned buffers, 194 const struct pipe_scissor_state *scissor_state, 195 const union pipe_color_union *pcolor, 196 double depth, unsigned stencil) 197{ 198 struct zink_context *ctx = zink_context(pctx); 199 struct pipe_framebuffer_state *fb = &ctx->fb_state; 200 struct zink_batch *batch = &ctx->batch; 201 bool needs_rp = false; 202 203 if (unlikely(!zink_screen(pctx->screen)->info.have_EXT_conditional_rendering && !zink_check_conditional_render(ctx))) 204 return; 205 206 if (scissor_state) { 207 struct u_rect scissor = {scissor_state->minx, scissor_state->maxx, scissor_state->miny, scissor_state->maxy}; 208 needs_rp = !zink_blit_region_fills(scissor, fb->width, fb->height); 209 } 210 211 212 if (batch->in_rp) { 213 clear_in_rp(pctx, buffers, scissor_state, pcolor, depth, stencil); 214 return; 215 } 216 217 if (buffers & PIPE_CLEAR_COLOR) { 218 for (unsigned i = 0; i < fb->nr_cbufs; i++) { 219 if ((buffers & (PIPE_CLEAR_COLOR0 << i)) && fb->cbufs[i]) { 220 struct pipe_surface *psurf = fb->cbufs[i]; 221 struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[i]; 222 struct zink_framebuffer_clear_data *clear = get_clear_data(ctx, fb_clear, needs_rp ? scissor_state : NULL); 223 224 ctx->clears_enabled |= PIPE_CLEAR_COLOR0 << i; 225 clear->conditional = ctx->render_condition_active; 226 clear->has_scissor = needs_rp; 227 if (scissor_state && needs_rp) 228 clear->scissor = *scissor_state; 229 clear->color.color = *pcolor; 230 clear->color.srgb = psurf->format != psurf->texture->format && 231 !util_format_is_srgb(psurf->format) && util_format_is_srgb(psurf->texture->format); 232 if (zink_fb_clear_first_needs_explicit(fb_clear)) 233 ctx->rp_clears_enabled &= ~(PIPE_CLEAR_COLOR0 << i); 234 else 235 ctx->rp_clears_enabled |= PIPE_CLEAR_COLOR0 << i; 236 } 237 } 238 } 239 240 if (buffers & PIPE_CLEAR_DEPTHSTENCIL && fb->zsbuf) { 241 struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[PIPE_MAX_COLOR_BUFS]; 242 struct zink_framebuffer_clear_data *clear = get_clear_data(ctx, fb_clear, needs_rp ? scissor_state : NULL); 243 ctx->clears_enabled |= PIPE_CLEAR_DEPTHSTENCIL; 244 clear->conditional = ctx->render_condition_active; 245 clear->has_scissor = needs_rp; 246 if (scissor_state && needs_rp) 247 clear->scissor = *scissor_state; 248 if (buffers & PIPE_CLEAR_DEPTH) 249 clear->zs.depth = depth; 250 if (buffers & PIPE_CLEAR_STENCIL) 251 clear->zs.stencil = stencil; 252 clear->zs.bits |= (buffers & PIPE_CLEAR_DEPTHSTENCIL); 253 if (zink_fb_clear_first_needs_explicit(fb_clear)) 254 ctx->rp_clears_enabled &= ~PIPE_CLEAR_DEPTHSTENCIL; 255 else 256 ctx->rp_clears_enabled |= (buffers & PIPE_CLEAR_DEPTHSTENCIL); 257 } 258} 259 260static inline bool 261colors_equal(union pipe_color_union *a, union pipe_color_union *b) 262{ 263 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]; 264} 265 266void 267zink_clear_framebuffer(struct zink_context *ctx, unsigned clear_buffers) 268{ 269 unsigned to_clear = 0; 270 struct pipe_framebuffer_state *fb_state = &ctx->fb_state; 271#ifndef NDEBUG 272 assert(!(clear_buffers & PIPE_CLEAR_DEPTHSTENCIL) || zink_fb_clear_enabled(ctx, PIPE_MAX_COLOR_BUFS)); 273 for (int i = 0; i < fb_state->nr_cbufs && clear_buffers >= PIPE_CLEAR_COLOR0; i++) { 274 assert(!(clear_buffers & (PIPE_CLEAR_COLOR0 << i)) || zink_fb_clear_enabled(ctx, i)); 275 } 276#endif 277 while (clear_buffers) { 278 struct zink_framebuffer_clear *color_clear = NULL; 279 struct zink_framebuffer_clear *zs_clear = NULL; 280 unsigned num_clears = 0; 281 for (int i = 0; i < fb_state->nr_cbufs && clear_buffers >= PIPE_CLEAR_COLOR0; i++) { 282 struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[i]; 283 /* these need actual clear calls inside the rp */ 284 if (!(clear_buffers & (PIPE_CLEAR_COLOR0 << i))) 285 continue; 286 if (color_clear) { 287 /* different number of clears -> do another clear */ 288 //XXX: could potentially merge "some" of the clears into this one for a very, very small optimization 289 if (num_clears != zink_fb_clear_count(fb_clear)) 290 goto out; 291 /* compare all the clears to determine if we can batch these buffers together */ 292 for (int j = !zink_fb_clear_first_needs_explicit(fb_clear); j < num_clears; j++) { 293 struct zink_framebuffer_clear_data *a = zink_fb_clear_element(color_clear, j); 294 struct zink_framebuffer_clear_data *b = zink_fb_clear_element(fb_clear, j); 295 /* scissors don't match, fire this one off */ 296 if (a->has_scissor != b->has_scissor || (a->has_scissor && !scissor_states_equal(&a->scissor, &b->scissor))) 297 goto out; 298 299 /* colors don't match, fire this one off */ 300 if (!colors_equal(&a->color.color, &b->color.color)) 301 goto out; 302 } 303 } else { 304 color_clear = fb_clear; 305 num_clears = zink_fb_clear_count(fb_clear); 306 } 307 308 clear_buffers &= ~(PIPE_CLEAR_COLOR0 << i); 309 to_clear |= (PIPE_CLEAR_COLOR0 << i); 310 } 311 clear_buffers &= ~PIPE_CLEAR_COLOR; 312 if (clear_buffers & PIPE_CLEAR_DEPTHSTENCIL) { 313 struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[PIPE_MAX_COLOR_BUFS]; 314 if (color_clear) { 315 if (num_clears != zink_fb_clear_count(fb_clear)) 316 goto out; 317 /* compare all the clears to determine if we can batch these buffers together */ 318 for (int j = !zink_fb_clear_first_needs_explicit(fb_clear); j < zink_fb_clear_count(color_clear); j++) { 319 struct zink_framebuffer_clear_data *a = zink_fb_clear_element(color_clear, j); 320 struct zink_framebuffer_clear_data *b = zink_fb_clear_element(fb_clear, j); 321 /* scissors don't match, fire this one off */ 322 if (a->has_scissor != b->has_scissor || (a->has_scissor && !scissor_states_equal(&a->scissor, &b->scissor))) 323 goto out; 324 } 325 } 326 zs_clear = fb_clear; 327 to_clear |= (clear_buffers & PIPE_CLEAR_DEPTHSTENCIL); 328 clear_buffers &= ~PIPE_CLEAR_DEPTHSTENCIL; 329 } 330out: 331 if (to_clear) { 332 if (num_clears) { 333 for (int j = !zink_fb_clear_first_needs_explicit(color_clear); j < num_clears; j++) { 334 struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(color_clear, j); 335 struct zink_framebuffer_clear_data *zsclear = NULL; 336 /* zs bits are both set here if those aspects should be cleared at some point */ 337 unsigned clear_bits = to_clear & ~PIPE_CLEAR_DEPTHSTENCIL; 338 if (zs_clear) { 339 zsclear = zink_fb_clear_element(zs_clear, j); 340 clear_bits |= zsclear->zs.bits; 341 } 342 zink_clear(&ctx->base, clear_bits, 343 clear->has_scissor ? &clear->scissor : NULL, 344 &clear->color.color, 345 zsclear ? zsclear->zs.depth : 0, 346 zsclear ? zsclear->zs.stencil : 0); 347 } 348 } else { 349 for (int j = !zink_fb_clear_first_needs_explicit(zs_clear); j < zink_fb_clear_count(zs_clear); j++) { 350 struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(zs_clear, j); 351 zink_clear(&ctx->base, clear->zs.bits, 352 clear->has_scissor ? &clear->scissor : NULL, 353 NULL, 354 clear->zs.depth, 355 clear->zs.stencil); 356 } 357 } 358 } 359 to_clear = 0; 360 } 361 for (int i = 0; i < ARRAY_SIZE(ctx->fb_clears); i++) 362 zink_fb_clear_reset(ctx, i); 363} 364 365static struct pipe_surface * 366create_clear_surface(struct pipe_context *pctx, struct pipe_resource *pres, unsigned level, const struct pipe_box *box) 367{ 368 struct pipe_surface tmpl = {{0}}; 369 370 tmpl.format = pres->format; 371 tmpl.u.tex.first_layer = box->z; 372 tmpl.u.tex.last_layer = box->z + box->depth - 1; 373 tmpl.u.tex.level = level; 374 return pctx->create_surface(pctx, pres, &tmpl); 375} 376 377void 378zink_clear_texture(struct pipe_context *pctx, 379 struct pipe_resource *pres, 380 unsigned level, 381 const struct pipe_box *box, 382 const void *data) 383{ 384 struct zink_context *ctx = zink_context(pctx); 385 struct zink_resource *res = zink_resource(pres); 386 struct pipe_screen *pscreen = pctx->screen; 387 struct u_rect region = zink_rect_from_box(box); 388 bool needs_rp = !zink_blit_region_fills(region, pres->width0, pres->height0) || ctx->render_condition_active; 389 struct pipe_surface *surf = NULL; 390 391 if (res->aspect & VK_IMAGE_ASPECT_COLOR_BIT) { 392 union pipe_color_union color; 393 394 util_format_unpack_rgba(pres->format, color.ui, data, 1); 395 396 if (pscreen->is_format_supported(pscreen, pres->format, pres->target, 0, 0, 397 PIPE_BIND_RENDER_TARGET) && !needs_rp) { 398 zink_batch_no_rp(ctx); 399 clear_color_no_rp(ctx, res, &color, level, box->z, box->depth); 400 } else { 401 surf = create_clear_surface(pctx, pres, level, box); 402 zink_blit_begin(ctx, ZINK_BLIT_SAVE_FB | ZINK_BLIT_SAVE_FS); 403 util_blitter_clear_render_target(ctx->blitter, surf, &color, box->x, box->y, box->width, box->height); 404 } 405 if (res->base.b.target == PIPE_BUFFER) 406 util_range_add(&res->base.b, &res->valid_buffer_range, box->x, box->x + box->width); 407 } else { 408 float depth = 0.0; 409 uint8_t stencil = 0; 410 411 if (res->aspect & VK_IMAGE_ASPECT_DEPTH_BIT) 412 util_format_unpack_z_float(pres->format, &depth, data, 1); 413 414 if (res->aspect & VK_IMAGE_ASPECT_STENCIL_BIT) 415 util_format_unpack_s_8uint(pres->format, &stencil, data, 1); 416 417 if (!needs_rp) { 418 zink_batch_no_rp(ctx); 419 clear_zs_no_rp(ctx, res, res->aspect, depth, stencil, level, box->z, box->depth); 420 } else { 421 unsigned flags = 0; 422 if (res->aspect & VK_IMAGE_ASPECT_DEPTH_BIT) 423 flags |= PIPE_CLEAR_DEPTH; 424 if (res->aspect & VK_IMAGE_ASPECT_STENCIL_BIT) 425 flags |= PIPE_CLEAR_STENCIL; 426 surf = create_clear_surface(pctx, pres, level, box); 427 zink_blit_begin(ctx, ZINK_BLIT_SAVE_FB | ZINK_BLIT_SAVE_FS); 428 util_blitter_clear_depth_stencil(ctx->blitter, surf, flags, depth, stencil, box->x, box->y, box->width, box->height); 429 } 430 } 431 /* this will never destroy the surface */ 432 pipe_surface_reference(&surf, NULL); 433} 434 435void 436zink_clear_buffer(struct pipe_context *pctx, 437 struct pipe_resource *pres, 438 unsigned offset, 439 unsigned size, 440 const void *clear_value, 441 int clear_value_size) 442{ 443 struct zink_context *ctx = zink_context(pctx); 444 struct zink_resource *res = zink_resource(pres); 445 446 uint32_t clamped; 447 if (util_lower_clearsize_to_dword(clear_value, &clear_value_size, &clamped)) 448 clear_value = &clamped; 449 if (offset % 4 == 0 && size % 4 == 0 && clear_value_size == sizeof(uint32_t)) { 450 /* 451 - dstOffset is the byte offset into the buffer at which to start filling, 452 and must be a multiple of 4. 453 454 - size is the number of bytes to fill, and must be either a multiple of 4, 455 or VK_WHOLE_SIZE to fill the range from offset to the end of the buffer 456 */ 457 struct zink_batch *batch = &ctx->batch; 458 zink_batch_no_rp(ctx); 459 zink_batch_reference_resource_rw(batch, res, true); 460 util_range_add(&res->base.b, &res->valid_buffer_range, offset, offset + size); 461 VKCTX(CmdFillBuffer)(batch->state->cmdbuf, res->obj->buffer, offset, size, *(uint32_t*)clear_value); 462 return; 463 } 464 struct pipe_transfer *xfer; 465 uint8_t *map = pipe_buffer_map_range(pctx, pres, offset, size, 466 PIPE_MAP_WRITE | PIPE_MAP_ONCE | PIPE_MAP_DISCARD_RANGE, &xfer); 467 if (!map) 468 return; 469 unsigned rem = size % clear_value_size; 470 uint8_t *ptr = map; 471 for (unsigned i = 0; i < (size - rem) / clear_value_size; i++) { 472 memcpy(ptr, clear_value, clear_value_size); 473 ptr += clear_value_size; 474 } 475 if (rem) 476 memcpy(map + size - rem, clear_value, rem); 477 pipe_buffer_unmap(pctx, xfer); 478} 479 480void 481zink_clear_render_target(struct pipe_context *pctx, struct pipe_surface *dst, 482 const union pipe_color_union *color, unsigned dstx, 483 unsigned dsty, unsigned width, unsigned height, 484 bool render_condition_enabled) 485{ 486 struct zink_context *ctx = zink_context(pctx); 487 zink_blit_begin(ctx, ZINK_BLIT_SAVE_FB | ZINK_BLIT_SAVE_FS | (render_condition_enabled ? 0 : ZINK_BLIT_NO_COND_RENDER)); 488 util_blitter_clear_render_target(ctx->blitter, dst, color, dstx, dsty, width, height); 489 if (!render_condition_enabled && ctx->render_condition_active) 490 zink_start_conditional_render(ctx); 491} 492 493void 494zink_clear_depth_stencil(struct pipe_context *pctx, struct pipe_surface *dst, 495 unsigned clear_flags, double depth, unsigned stencil, 496 unsigned dstx, unsigned dsty, unsigned width, unsigned height, 497 bool render_condition_enabled) 498{ 499 struct zink_context *ctx = zink_context(pctx); 500 zink_blit_begin(ctx, ZINK_BLIT_SAVE_FB | ZINK_BLIT_SAVE_FS | (render_condition_enabled ? 0 : ZINK_BLIT_NO_COND_RENDER)); 501 util_blitter_clear_depth_stencil(ctx->blitter, dst, clear_flags, depth, stencil, dstx, dsty, width, height); 502 if (!render_condition_enabled && ctx->render_condition_active) 503 zink_start_conditional_render(ctx); 504} 505 506bool 507zink_fb_clear_needs_explicit(struct zink_framebuffer_clear *fb_clear) 508{ 509 if (zink_fb_clear_count(fb_clear) != 1) 510 return true; 511 return zink_fb_clear_element_needs_explicit(zink_fb_clear_element(fb_clear, 0)); 512} 513 514bool 515zink_fb_clear_first_needs_explicit(struct zink_framebuffer_clear *fb_clear) 516{ 517 if (!zink_fb_clear_count(fb_clear)) 518 return false; 519 return zink_fb_clear_element_needs_explicit(zink_fb_clear_element(fb_clear, 0)); 520} 521 522void 523zink_fb_clear_util_unpack_clear_color(struct zink_framebuffer_clear_data *clear, enum pipe_format format, union pipe_color_union *color) 524{ 525 const struct util_format_description *desc = util_format_description(format); 526 if (clear->color.srgb) { 527 /* if SRGB mode is disabled for the fb with a backing srgb image then we have to 528 * convert this to srgb color 529 */ 530 for (unsigned j = 0; j < MIN2(3, desc->nr_channels); j++) { 531 assert(desc->channel[j].normalized); 532 color->f[j] = util_format_srgb_to_linear_float(clear->color.color.f[j]); 533 } 534 color->f[3] = clear->color.color.f[3]; 535 } else { 536 for (unsigned i = 0; i < 4; i++) 537 color->f[i] = clear->color.color.f[i]; 538 } 539} 540 541static void 542fb_clears_apply_internal(struct zink_context *ctx, struct pipe_resource *pres, int i) 543{ 544 struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[i]; 545 struct zink_resource *res = zink_resource(pres); 546 547 if (!zink_fb_clear_enabled(ctx, i)) 548 return; 549 if (ctx->batch.in_rp) 550 zink_clear_framebuffer(ctx, BITFIELD_BIT(i)); 551 else if (res->aspect == VK_IMAGE_ASPECT_COLOR_BIT) { 552 if (zink_fb_clear_needs_explicit(fb_clear) || !check_3d_layers(ctx->fb_state.cbufs[i])) 553 /* this will automatically trigger all the clears */ 554 zink_batch_rp(ctx); 555 else { 556 struct pipe_surface *psurf = ctx->fb_state.cbufs[i]; 557 struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(fb_clear, 0); 558 union pipe_color_union color; 559 zink_fb_clear_util_unpack_clear_color(clear, psurf->format, &color); 560 561 clear_color_no_rp(ctx, res, &color, 562 psurf->u.tex.level, psurf->u.tex.first_layer, 563 psurf->u.tex.last_layer - psurf->u.tex.first_layer + 1); 564 } 565 zink_fb_clear_reset(ctx, i); 566 return; 567 } else { 568 if (zink_fb_clear_needs_explicit(fb_clear) || !check_3d_layers(ctx->fb_state.zsbuf)) 569 /* this will automatically trigger all the clears */ 570 zink_batch_rp(ctx); 571 else { 572 struct pipe_surface *psurf = ctx->fb_state.zsbuf; 573 struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(fb_clear, 0); 574 VkImageAspectFlags aspects = 0; 575 if (clear->zs.bits & PIPE_CLEAR_DEPTH) 576 aspects |= VK_IMAGE_ASPECT_DEPTH_BIT; 577 if (clear->zs.bits & PIPE_CLEAR_STENCIL) 578 aspects |= VK_IMAGE_ASPECT_STENCIL_BIT; 579 clear_zs_no_rp(ctx, res, aspects, clear->zs.depth, clear->zs.stencil, 580 psurf->u.tex.level, psurf->u.tex.first_layer, 581 psurf->u.tex.last_layer - psurf->u.tex.first_layer + 1); 582 } 583 } 584 zink_fb_clear_reset(ctx, i); 585} 586 587void 588zink_fb_clear_reset(struct zink_context *ctx, unsigned i) 589{ 590 util_dynarray_clear(&ctx->fb_clears[i].clears); 591 if (i == PIPE_MAX_COLOR_BUFS) { 592 ctx->clears_enabled &= ~PIPE_CLEAR_DEPTHSTENCIL; 593 ctx->rp_clears_enabled &= ~PIPE_CLEAR_DEPTHSTENCIL; 594 } else { 595 ctx->clears_enabled &= ~(PIPE_CLEAR_COLOR0 << i); 596 ctx->rp_clears_enabled &= ~(PIPE_CLEAR_COLOR0 << i); 597 } 598} 599 600void 601zink_fb_clears_apply(struct zink_context *ctx, struct pipe_resource *pres) 602{ 603 if (zink_resource(pres)->aspect == VK_IMAGE_ASPECT_COLOR_BIT) { 604 for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) { 605 if (ctx->fb_state.cbufs[i] && ctx->fb_state.cbufs[i]->texture == pres) { 606 fb_clears_apply_internal(ctx, pres, i); 607 } 608 } 609 } else { 610 if (ctx->fb_state.zsbuf && ctx->fb_state.zsbuf->texture == pres) { 611 fb_clears_apply_internal(ctx, pres, PIPE_MAX_COLOR_BUFS); 612 } 613 } 614} 615 616void 617zink_fb_clears_discard(struct zink_context *ctx, struct pipe_resource *pres) 618{ 619 if (zink_resource(pres)->aspect == VK_IMAGE_ASPECT_COLOR_BIT) { 620 for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) { 621 if (ctx->fb_state.cbufs[i] && ctx->fb_state.cbufs[i]->texture == pres) { 622 if (zink_fb_clear_enabled(ctx, i)) { 623 zink_fb_clear_reset(ctx, i); 624 } 625 } 626 } 627 } else { 628 if (zink_fb_clear_enabled(ctx, PIPE_MAX_COLOR_BUFS) && ctx->fb_state.zsbuf && ctx->fb_state.zsbuf->texture == pres) { 629 int i = PIPE_MAX_COLOR_BUFS; 630 zink_fb_clear_reset(ctx, i); 631 } 632 } 633} 634 635void 636zink_clear_apply_conditionals(struct zink_context *ctx) 637{ 638 for (int i = 0; i < ARRAY_SIZE(ctx->fb_clears); i++) { 639 struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[i]; 640 if (!zink_fb_clear_enabled(ctx, i)) 641 continue; 642 for (int j = 0; j < zink_fb_clear_count(fb_clear); j++) { 643 struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(fb_clear, j); 644 if (clear->conditional) { 645 struct pipe_surface *surf; 646 if (i < PIPE_MAX_COLOR_BUFS) 647 surf = ctx->fb_state.cbufs[i]; 648 else 649 surf = ctx->fb_state.zsbuf; 650 if (surf) 651 fb_clears_apply_internal(ctx, surf->texture, i); 652 else 653 zink_fb_clear_reset(ctx, i); 654 break; 655 } 656 } 657 } 658} 659 660static void 661fb_clears_apply_or_discard_internal(struct zink_context *ctx, struct pipe_resource *pres, struct u_rect region, bool discard_only, bool invert, int i) 662{ 663 struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[i]; 664 if (zink_fb_clear_enabled(ctx, i)) { 665 if (zink_blit_region_fills(region, pres->width0, pres->height0)) { 666 if (invert) 667 fb_clears_apply_internal(ctx, pres, i); 668 else 669 /* we know we can skip these */ 670 zink_fb_clears_discard(ctx, pres); 671 return; 672 } 673 for (int j = 0; j < zink_fb_clear_count(fb_clear); j++) { 674 struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(fb_clear, j); 675 struct u_rect scissor = {clear->scissor.minx, clear->scissor.maxx, 676 clear->scissor.miny, clear->scissor.maxy}; 677 if (!clear->has_scissor || zink_blit_region_covers(region, scissor)) { 678 /* this is a clear that isn't fully covered by our pending write */ 679 if (!discard_only) 680 fb_clears_apply_internal(ctx, pres, i); 681 return; 682 } 683 } 684 if (!invert) 685 /* if we haven't already returned, then we know we can discard */ 686 zink_fb_clears_discard(ctx, pres); 687 } 688} 689 690void 691zink_fb_clears_apply_or_discard(struct zink_context *ctx, struct pipe_resource *pres, struct u_rect region, bool discard_only) 692{ 693 if (zink_resource(pres)->aspect == VK_IMAGE_ASPECT_COLOR_BIT) { 694 for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) { 695 if (ctx->fb_state.cbufs[i] && ctx->fb_state.cbufs[i]->texture == pres) { 696 fb_clears_apply_or_discard_internal(ctx, pres, region, discard_only, false, i); 697 } 698 } 699 } else { 700 if (zink_fb_clear_enabled(ctx, PIPE_MAX_COLOR_BUFS) && ctx->fb_state.zsbuf && ctx->fb_state.zsbuf->texture == pres) { 701 fb_clears_apply_or_discard_internal(ctx, pres, region, discard_only, false, PIPE_MAX_COLOR_BUFS); 702 } 703 } 704} 705 706void 707zink_fb_clears_apply_region(struct zink_context *ctx, struct pipe_resource *pres, struct u_rect region) 708{ 709 if (zink_resource(pres)->aspect == VK_IMAGE_ASPECT_COLOR_BIT) { 710 for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) { 711 if (ctx->fb_state.cbufs[i] && ctx->fb_state.cbufs[i]->texture == pres) { 712 fb_clears_apply_or_discard_internal(ctx, pres, region, false, true, i); 713 } 714 } 715 } else { 716 if (ctx->fb_state.zsbuf && ctx->fb_state.zsbuf->texture == pres) { 717 fb_clears_apply_or_discard_internal(ctx, pres, region, false, true, PIPE_MAX_COLOR_BUFS); 718 } 719 } 720} 721