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_batch.h"
25 #include "zink_clear.h"
26 #include "zink_context.h"
27 #include "zink_format.h"
28 #include "zink_inlines.h"
29 #include "zink_query.h"
30
31 #include "util/u_blitter.h"
32 #include "util/format/u_format.h"
33 #include "util/format_srgb.h"
34 #include "util/helpers.h"
35 #include "util/u_framebuffer.h"
36 #include "util/u_inlines.h"
37 #include "util/u_rect.h"
38 #include "util/u_surface.h"
39 #include "util/u_helpers.h"
40
41 static inline bool
scissor_states_equal(const struct pipe_scissor_state * a,const struct pipe_scissor_state * b)42 scissor_states_equal(const struct pipe_scissor_state *a, const struct pipe_scissor_state *b)
43 {
44 return a->minx == b->minx && a->miny == b->miny && a->maxx == b->maxx && a->maxy == b->maxy;
45 }
46
47 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)48 clear_in_rp(struct pipe_context *pctx,
49 unsigned buffers,
50 const struct pipe_scissor_state *scissor_state,
51 const union pipe_color_union *pcolor,
52 double depth, unsigned stencil)
53 {
54 struct zink_context *ctx = zink_context(pctx);
55 struct pipe_framebuffer_state *fb = &ctx->fb_state;
56
57 VkClearAttachment attachments[1 + PIPE_MAX_COLOR_BUFS];
58 int num_attachments = 0;
59
60 if (buffers & PIPE_CLEAR_COLOR) {
61 VkClearColorValue color;
62 color.uint32[0] = pcolor->ui[0];
63 color.uint32[1] = pcolor->ui[1];
64 color.uint32[2] = pcolor->ui[2];
65 color.uint32[3] = pcolor->ui[3];
66
67 for (unsigned i = 0; i < fb->nr_cbufs; i++) {
68 if (!(buffers & (PIPE_CLEAR_COLOR0 << i)) || !fb->cbufs[i])
69 continue;
70
71 attachments[num_attachments].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
72 attachments[num_attachments].colorAttachment = i;
73 attachments[num_attachments].clearValue.color = color;
74 ++num_attachments;
75 }
76 }
77
78 if (buffers & PIPE_CLEAR_DEPTHSTENCIL && fb->zsbuf) {
79 VkImageAspectFlags aspect = 0;
80 if (buffers & PIPE_CLEAR_DEPTH)
81 aspect |= VK_IMAGE_ASPECT_DEPTH_BIT;
82 if (buffers & PIPE_CLEAR_STENCIL)
83 aspect |= VK_IMAGE_ASPECT_STENCIL_BIT;
84
85 assert(zink_is_zsbuf_used(ctx));
86
87 attachments[num_attachments].aspectMask = aspect;
88 attachments[num_attachments].clearValue.depthStencil.depth = depth;
89 attachments[num_attachments].clearValue.depthStencil.stencil = stencil;
90 ++num_attachments;
91 }
92
93 VkClearRect cr = {0};
94 if (scissor_state) {
95 /* invalid clear */
96 if (scissor_state->minx > ctx->fb_state.width || scissor_state->miny > ctx->fb_state.height)
97 return;
98 cr.rect.offset.x = scissor_state->minx;
99 cr.rect.offset.y = scissor_state->miny;
100 cr.rect.extent.width = MIN2(fb->width - cr.rect.offset.x, scissor_state->maxx - scissor_state->minx);
101 cr.rect.extent.height = MIN2(fb->height - cr.rect.offset.y, scissor_state->maxy - scissor_state->miny);
102 } else {
103 cr.rect.extent.width = fb->width;
104 cr.rect.extent.height = fb->height;
105 }
106 cr.baseArrayLayer = 0;
107 cr.layerCount = util_framebuffer_get_num_layers(fb);
108 assert(ctx->in_rp);
109 VKCTX(CmdClearAttachments)(ctx->bs->cmdbuf, num_attachments, attachments, 1, &cr);
110 ctx->bs->has_work = true;
111 /*
112 Rendering within a subpass containing a feedback loop creates a data race, except in the following
113 cases:
114 • If a memory dependency is inserted between when the attachment is written and when it is
115 subsequently read by later fragments. Pipeline barriers expressing a subpass self-dependency
116 are the only way to achieve this, and one must be inserted every time a fragment will read
117 values at a particular sample (x, y, layer, sample) coordinate, if those values have been written
118 since the most recent pipeline barrier
119
120 VK 1.3.211, Chapter 8: Render Pass
121 */
122 if (ctx->fbfetch_outputs)
123 ctx->base.texture_barrier(&ctx->base, PIPE_TEXTURE_BARRIER_FRAMEBUFFER);
124 }
125
126 static struct zink_framebuffer_clear_data *
add_new_clear(struct zink_framebuffer_clear * fb_clear)127 add_new_clear(struct zink_framebuffer_clear *fb_clear)
128 {
129 struct zink_framebuffer_clear_data cd = {0};
130 util_dynarray_append(&fb_clear->clears, struct zink_framebuffer_clear_data, cd);
131 return zink_fb_clear_element(fb_clear, zink_fb_clear_count(fb_clear) - 1);
132 }
133
134 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)135 get_clear_data(struct zink_context *ctx, struct zink_framebuffer_clear *fb_clear, const struct pipe_scissor_state *scissor_state)
136 {
137 unsigned num_clears = zink_fb_clear_count(fb_clear);
138 if (num_clears) {
139 struct zink_framebuffer_clear_data *last_clear = zink_fb_clear_element(fb_clear, num_clears - 1);
140 /* if we're completely overwriting the previous clear, merge this into the previous clear */
141 if (!scissor_state || (last_clear->has_scissor && scissor_states_equal(&last_clear->scissor, scissor_state)))
142 return last_clear;
143 }
144 return add_new_clear(fb_clear);
145 }
146
147 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)148 zink_clear(struct pipe_context *pctx,
149 unsigned buffers,
150 const struct pipe_scissor_state *scissor_state,
151 const union pipe_color_union *pcolor,
152 double depth, unsigned stencil)
153 {
154 struct zink_context *ctx = zink_context(pctx);
155 struct zink_screen *screen = zink_screen(pctx->screen);
156 struct pipe_framebuffer_state *fb = &ctx->fb_state;
157 bool needs_rp = false;
158
159 if (scissor_state) {
160 struct u_rect scissor = {scissor_state->minx, scissor_state->maxx, scissor_state->miny, scissor_state->maxy};
161 needs_rp = !zink_blit_region_fills(scissor, fb->width, fb->height);
162 }
163
164 if (unlikely(ctx->fb_layer_mismatch)) {
165 /* this is a terrible scenario:
166 * at least one attachment has a layerCount greater than the others,
167 * so iterate over all the mismatched attachments and pre-clear them separately,
168 * then continue to flag them as need (additional) clearing
169 * to avoid loadOp=LOAD
170 */
171 unsigned x = 0;
172 unsigned y = 0;
173 unsigned w = ctx->fb_state.width;
174 unsigned h = ctx->fb_state.height;
175 if (scissor_state) {
176 x = scissor_state->minx;
177 y = scissor_state->miny;
178 w = scissor_state->minx + scissor_state->maxx;
179 h = scissor_state->miny + scissor_state->maxy;
180 }
181 unsigned clear_buffers = buffers >> 2;
182 for (unsigned i = 0; i < ctx->fb_state.nr_cbufs; i++) {
183 if (ctx->fb_state.cbufs[i] &&
184 (ctx->fb_layer_mismatch & clear_buffers & BITFIELD_BIT(i))) {
185 if (ctx->void_clears & (PIPE_CLEAR_COLOR0 << i)) {
186 union pipe_color_union color;
187 color.f[0] = color.f[1] = color.f[2] = 0;
188 color.f[3] = 1.0;
189 pctx->clear_render_target(pctx, ctx->fb_state.cbufs[i], &color,
190 0, 0,
191 ctx->fb_state.cbufs[i]->width, ctx->fb_state.cbufs[i]->height,
192 ctx->render_condition_active);
193 }
194 pctx->clear_render_target(pctx, ctx->fb_state.cbufs[i], pcolor,
195 x, y, w, h, ctx->render_condition_active);
196 }
197 }
198 if (ctx->fb_state.zsbuf && (buffers & PIPE_CLEAR_DEPTHSTENCIL))
199 pctx->clear_depth_stencil(pctx, ctx->fb_state.zsbuf, buffers & PIPE_CLEAR_DEPTHSTENCIL, depth, stencil,
200 x, y, w, h, ctx->render_condition_active);
201 }
202
203 if (ctx->in_rp) {
204 if (buffers & PIPE_CLEAR_DEPTHSTENCIL && (ctx->zsbuf_unused || ctx->zsbuf_readonly)) {
205 /* this will need a layout change */
206 assert(!ctx->track_renderpasses);
207 zink_batch_no_rp(ctx);
208 } else {
209 clear_in_rp(pctx, buffers, scissor_state, pcolor, depth, stencil);
210 return;
211 }
212 }
213
214 unsigned rp_clears_enabled = ctx->rp_clears_enabled;
215
216 if (ctx->void_clears & buffers) {
217 unsigned void_clears = ctx->void_clears & buffers;
218 ctx->void_clears &= ~buffers;
219 union pipe_color_union color;
220 color.f[0] = color.f[1] = color.f[2] = 0;
221 color.f[3] = 1.0;
222 for (unsigned i = 0; i < fb->nr_cbufs; i++) {
223 if ((void_clears & (PIPE_CLEAR_COLOR0 << i)) && fb->cbufs[i]) {
224 struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[i];
225 unsigned num_clears = zink_fb_clear_count(fb_clear);
226 if (num_clears) {
227 if (zink_fb_clear_first_needs_explicit(fb_clear)) {
228 /* a scissored clear exists:
229 * - extend the clear array
230 * - shift existing clears back by one position
231 * - inject void clear base of array
232 */
233 add_new_clear(fb_clear);
234 struct zink_framebuffer_clear_data *clear = fb_clear->clears.data;
235 memmove(clear + 1, clear, num_clears);
236 memcpy(&clear->color, &color, sizeof(color));
237 } else {
238 /* no void clear needed */
239 }
240 void_clears &= ~(PIPE_CLEAR_COLOR0 << i);
241 }
242 }
243 }
244 if (void_clears)
245 pctx->clear(pctx, void_clears, NULL, &color, 0, 0);
246 }
247
248 if (buffers & PIPE_CLEAR_COLOR) {
249 for (unsigned i = 0; i < fb->nr_cbufs; i++) {
250 if ((buffers & (PIPE_CLEAR_COLOR0 << i)) && fb->cbufs[i]) {
251 struct pipe_surface *psurf = fb->cbufs[i];
252 struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[i];
253 struct zink_framebuffer_clear_data *clear = get_clear_data(ctx, fb_clear, needs_rp ? scissor_state : NULL);
254
255 ctx->clears_enabled |= PIPE_CLEAR_COLOR0 << i;
256 clear->conditional = ctx->render_condition_active;
257 clear->has_scissor = needs_rp;
258 memcpy(&clear->color, pcolor, sizeof(union pipe_color_union));
259 zink_convert_color(screen, psurf->format, &clear->color, pcolor);
260 if (scissor_state && needs_rp)
261 clear->scissor = *scissor_state;
262 if (zink_fb_clear_first_needs_explicit(fb_clear))
263 ctx->rp_clears_enabled &= ~(PIPE_CLEAR_COLOR0 << i);
264 else
265 ctx->rp_clears_enabled |= PIPE_CLEAR_COLOR0 << i;
266 }
267 }
268 }
269
270 if (buffers & PIPE_CLEAR_DEPTHSTENCIL && fb->zsbuf) {
271 struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[PIPE_MAX_COLOR_BUFS];
272 struct zink_framebuffer_clear_data *clear = get_clear_data(ctx, fb_clear, needs_rp ? scissor_state : NULL);
273 ctx->clears_enabled |= PIPE_CLEAR_DEPTHSTENCIL;
274 clear->conditional = ctx->render_condition_active;
275 clear->has_scissor = needs_rp;
276 if (scissor_state && needs_rp)
277 clear->scissor = *scissor_state;
278 if (buffers & PIPE_CLEAR_DEPTH)
279 clear->zs.depth = depth;
280 if (buffers & PIPE_CLEAR_STENCIL)
281 clear->zs.stencil = stencil;
282 clear->zs.bits |= (buffers & PIPE_CLEAR_DEPTHSTENCIL);
283 if (zink_fb_clear_first_needs_explicit(fb_clear)) {
284 ctx->rp_clears_enabled &= ~PIPE_CLEAR_DEPTHSTENCIL;
285 if (!ctx->track_renderpasses)
286 ctx->dynamic_fb.tc_info.zsbuf_clear_partial = true;
287 } else {
288 ctx->rp_clears_enabled |= (buffers & PIPE_CLEAR_DEPTHSTENCIL);
289 if (!ctx->track_renderpasses)
290 ctx->dynamic_fb.tc_info.zsbuf_clear = true;
291 }
292 }
293 assert(!ctx->in_rp);
294 ctx->rp_changed |= ctx->rp_clears_enabled != rp_clears_enabled;
295 }
296
297 static inline bool
colors_equal(union pipe_color_union * a,union pipe_color_union * b)298 colors_equal(union pipe_color_union *a, union pipe_color_union *b)
299 {
300 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];
301 }
302
303 void
zink_clear_framebuffer(struct zink_context * ctx,unsigned clear_buffers)304 zink_clear_framebuffer(struct zink_context *ctx, unsigned clear_buffers)
305 {
306 unsigned to_clear = 0;
307 struct pipe_framebuffer_state *fb_state = &ctx->fb_state;
308 #ifndef NDEBUG
309 assert(!(clear_buffers & PIPE_CLEAR_DEPTHSTENCIL) || zink_fb_clear_enabled(ctx, PIPE_MAX_COLOR_BUFS));
310 for (int i = 0; i < fb_state->nr_cbufs && clear_buffers >= PIPE_CLEAR_COLOR0; i++) {
311 assert(!(clear_buffers & (PIPE_CLEAR_COLOR0 << i)) || zink_fb_clear_enabled(ctx, i));
312 }
313 #endif
314 while (clear_buffers) {
315 struct zink_framebuffer_clear *color_clear = NULL;
316 struct zink_framebuffer_clear *zs_clear = NULL;
317 unsigned num_clears = 0;
318 for (int i = 0; i < fb_state->nr_cbufs && clear_buffers >= PIPE_CLEAR_COLOR0; i++) {
319 struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[i];
320 /* these need actual clear calls inside the rp */
321 if (!(clear_buffers & (PIPE_CLEAR_COLOR0 << i)))
322 continue;
323 if (color_clear) {
324 /* different number of clears -> do another clear */
325 //XXX: could potentially merge "some" of the clears into this one for a very, very small optimization
326 if (num_clears != zink_fb_clear_count(fb_clear))
327 goto out;
328 /* compare all the clears to determine if we can batch these buffers together */
329 for (int j = !zink_fb_clear_first_needs_explicit(fb_clear); j < num_clears; j++) {
330 struct zink_framebuffer_clear_data *a = zink_fb_clear_element(color_clear, j);
331 struct zink_framebuffer_clear_data *b = zink_fb_clear_element(fb_clear, j);
332 /* scissors don't match, fire this one off */
333 if (a->has_scissor != b->has_scissor || (a->has_scissor && !scissor_states_equal(&a->scissor, &b->scissor)))
334 goto out;
335
336 /* colors don't match, fire this one off */
337 if (!colors_equal(&a->color, &b->color))
338 goto out;
339 }
340 } else {
341 color_clear = fb_clear;
342 num_clears = zink_fb_clear_count(fb_clear);
343 }
344
345 clear_buffers &= ~(PIPE_CLEAR_COLOR0 << i);
346 to_clear |= (PIPE_CLEAR_COLOR0 << i);
347 }
348 clear_buffers &= ~PIPE_CLEAR_COLOR;
349 if (clear_buffers & PIPE_CLEAR_DEPTHSTENCIL) {
350 struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[PIPE_MAX_COLOR_BUFS];
351 if (color_clear) {
352 if (num_clears != zink_fb_clear_count(fb_clear))
353 goto out;
354 /* compare all the clears to determine if we can batch these buffers together */
355 for (int j = !zink_fb_clear_first_needs_explicit(fb_clear); j < zink_fb_clear_count(color_clear); j++) {
356 struct zink_framebuffer_clear_data *a = zink_fb_clear_element(color_clear, j);
357 struct zink_framebuffer_clear_data *b = zink_fb_clear_element(fb_clear, j);
358 /* scissors don't match, fire this one off */
359 if (a->has_scissor != b->has_scissor || (a->has_scissor && !scissor_states_equal(&a->scissor, &b->scissor)))
360 goto out;
361 }
362 }
363 zs_clear = fb_clear;
364 to_clear |= (clear_buffers & PIPE_CLEAR_DEPTHSTENCIL);
365 clear_buffers &= ~PIPE_CLEAR_DEPTHSTENCIL;
366 }
367 out:
368 if (to_clear) {
369 if (num_clears) {
370 for (int j = !zink_fb_clear_first_needs_explicit(color_clear); j < num_clears; j++) {
371 struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(color_clear, j);
372 struct zink_framebuffer_clear_data *zsclear = NULL;
373 /* zs bits are both set here if those aspects should be cleared at some point */
374 unsigned clear_bits = to_clear & ~PIPE_CLEAR_DEPTHSTENCIL;
375 if (zs_clear) {
376 zsclear = zink_fb_clear_element(zs_clear, j);
377 clear_bits |= zsclear->zs.bits;
378 }
379 zink_clear(&ctx->base, clear_bits,
380 clear->has_scissor ? &clear->scissor : NULL,
381 &clear->color,
382 zsclear ? zsclear->zs.depth : 0,
383 zsclear ? zsclear->zs.stencil : 0);
384 }
385 } else {
386 for (int j = !zink_fb_clear_first_needs_explicit(zs_clear); j < zink_fb_clear_count(zs_clear); j++) {
387 struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(zs_clear, j);
388 zink_clear(&ctx->base, clear->zs.bits,
389 clear->has_scissor ? &clear->scissor : NULL,
390 NULL,
391 clear->zs.depth,
392 clear->zs.stencil);
393 }
394 }
395 }
396 to_clear = 0;
397 }
398 if (ctx->clears_enabled & PIPE_CLEAR_DEPTHSTENCIL)
399 zink_fb_clear_reset(ctx, PIPE_MAX_COLOR_BUFS);
400 u_foreach_bit(i, ctx->clears_enabled >> 2)
401 zink_fb_clear_reset(ctx, i);
402 }
403
404 static struct pipe_surface *
create_clear_surface(struct pipe_context * pctx,struct pipe_resource * pres,unsigned level,const struct pipe_box * box)405 create_clear_surface(struct pipe_context *pctx, struct pipe_resource *pres, unsigned level, const struct pipe_box *box)
406 {
407 struct pipe_surface tmpl = {{0}};
408
409 tmpl.format = pres->format;
410 tmpl.u.tex.first_layer = box->z;
411 tmpl.u.tex.last_layer = box->z + box->depth - 1;
412 tmpl.u.tex.level = level;
413 return pctx->create_surface(pctx, pres, &tmpl);
414 }
415
416 static void
set_clear_fb(struct pipe_context * pctx,struct pipe_surface * psurf,struct pipe_surface * zsurf)417 set_clear_fb(struct pipe_context *pctx, struct pipe_surface *psurf, struct pipe_surface *zsurf)
418 {
419 struct pipe_framebuffer_state fb_state = {0};
420 fb_state.width = psurf ? psurf->width : zsurf->width;
421 fb_state.height = psurf ? psurf->height : zsurf->height;
422 fb_state.nr_cbufs = !!psurf;
423 fb_state.cbufs[0] = psurf;
424 fb_state.zsbuf = zsurf;
425 pctx->set_framebuffer_state(pctx, &fb_state);
426 }
427
428 void
zink_clear_texture_dynamic(struct pipe_context * pctx,struct pipe_resource * pres,unsigned level,const struct pipe_box * box,const void * data)429 zink_clear_texture_dynamic(struct pipe_context *pctx,
430 struct pipe_resource *pres,
431 unsigned level,
432 const struct pipe_box *box,
433 const void *data)
434 {
435 struct zink_context *ctx = zink_context(pctx);
436 struct zink_screen *screen = zink_screen(pctx->screen);
437 struct zink_resource *res = zink_resource(pres);
438
439 bool full_clear = 0 <= box->x && u_minify(pres->width0, level) >= box->x + box->width &&
440 0 <= box->y && u_minify(pres->height0, level) >= box->y + box->height &&
441 0 <= box->z && u_minify(pres->target == PIPE_TEXTURE_3D ? pres->depth0 : pres->array_size, level) >= box->z + box->depth;
442
443 struct pipe_surface *surf = create_clear_surface(pctx, pres, level, box);
444
445 VkRenderingAttachmentInfo att = {0};
446 att.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO;
447 att.imageView = zink_csurface(surf)->image_view;
448 att.imageLayout = res->aspect & VK_IMAGE_ASPECT_COLOR_BIT ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
449 att.loadOp = full_clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD;
450 att.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
451
452 VkRenderingInfo info = {0};
453 info.sType = VK_STRUCTURE_TYPE_RENDERING_INFO;
454 info.renderArea.offset.x = box->x;
455 info.renderArea.offset.y = box->y;
456 info.renderArea.extent.width = box->width;
457 info.renderArea.extent.height = box->height;
458 info.layerCount = MAX2(box->depth, 1);
459
460 union pipe_color_union color, tmp;
461 float depth = 0.0;
462 uint8_t stencil = 0;
463 if (res->aspect & VK_IMAGE_ASPECT_COLOR_BIT) {
464 util_format_unpack_rgba(pres->format, tmp.ui, data, 1);
465 zink_convert_color(screen, surf->format, &color, &tmp);
466 } else {
467 if (res->aspect & VK_IMAGE_ASPECT_DEPTH_BIT)
468 util_format_unpack_z_float(pres->format, &depth, data, 1);
469
470 if (res->aspect & VK_IMAGE_ASPECT_STENCIL_BIT)
471 util_format_unpack_s_8uint(pres->format, &stencil, data, 1);
472 }
473
474 zink_blit_barriers(ctx, NULL, res, full_clear);
475 VkCommandBuffer cmdbuf = zink_get_cmdbuf(ctx, NULL, res);
476 if (cmdbuf == ctx->bs->cmdbuf && ctx->in_rp)
477 zink_batch_no_rp(ctx);
478
479 if (res->aspect & VK_IMAGE_ASPECT_COLOR_BIT) {
480 memcpy(&att.clearValue, &color, sizeof(float) * 4);
481 info.colorAttachmentCount = 1;
482 info.pColorAttachments = &att;
483 } else {
484 att.clearValue.depthStencil.depth = depth;
485 att.clearValue.depthStencil.stencil = stencil;
486 if (res->aspect & VK_IMAGE_ASPECT_DEPTH_BIT)
487 info.pDepthAttachment = &att;
488 if (res->aspect & VK_IMAGE_ASPECT_STENCIL_BIT)
489 info.pStencilAttachment = &att;
490 }
491 VKCTX(CmdBeginRendering)(cmdbuf, &info);
492 if (!full_clear) {
493 VkClearRect rect;
494 rect.rect = info.renderArea;
495 rect.baseArrayLayer = box->z;
496 rect.layerCount = box->depth;
497
498 VkClearAttachment clear_att;
499 clear_att.aspectMask = res->aspect;
500 clear_att.colorAttachment = 0;
501 clear_att.clearValue = att.clearValue;
502
503 VKCTX(CmdClearAttachments)(cmdbuf, 1, &clear_att, 1, &rect);
504 }
505 VKCTX(CmdEndRendering)(cmdbuf);
506 zink_batch_reference_resource_rw(ctx, res, true);
507 /* this will never destroy the surface */
508 pipe_surface_reference(&surf, NULL);
509 }
510
511 void
zink_clear_texture(struct pipe_context * pctx,struct pipe_resource * pres,unsigned level,const struct pipe_box * box,const void * data)512 zink_clear_texture(struct pipe_context *pctx,
513 struct pipe_resource *pres,
514 unsigned level,
515 const struct pipe_box *box,
516 const void *data)
517 {
518 struct zink_context *ctx = zink_context(pctx);
519 struct zink_resource *res = zink_resource(pres);
520 struct pipe_surface *surf = NULL;
521 struct pipe_scissor_state scissor = {box->x, box->y, box->x + box->width, box->y + box->height};
522
523 if (res->aspect & VK_IMAGE_ASPECT_COLOR_BIT) {
524 union pipe_color_union color;
525
526 util_format_unpack_rgba(pres->format, color.ui, data, 1);
527
528 surf = create_clear_surface(pctx, pres, level, box);
529 util_blitter_save_framebuffer(ctx->blitter, &ctx->fb_state);
530 set_clear_fb(pctx, surf, NULL);
531 zink_blit_barriers(ctx, NULL, res, false);
532 ctx->blitting = true;
533 ctx->queries_disabled = true;
534 pctx->clear(pctx, PIPE_CLEAR_COLOR0, &scissor, &color, 0, 0);
535 util_blitter_restore_fb_state(ctx->blitter);
536 ctx->queries_disabled = false;
537 ctx->blitting = false;
538 } else {
539 float depth = 0.0;
540 uint8_t stencil = 0;
541
542 if (res->aspect & VK_IMAGE_ASPECT_DEPTH_BIT)
543 util_format_unpack_z_float(pres->format, &depth, data, 1);
544
545 if (res->aspect & VK_IMAGE_ASPECT_STENCIL_BIT)
546 util_format_unpack_s_8uint(pres->format, &stencil, data, 1);
547
548 unsigned flags = 0;
549 if (res->aspect & VK_IMAGE_ASPECT_DEPTH_BIT)
550 flags |= PIPE_CLEAR_DEPTH;
551 if (res->aspect & VK_IMAGE_ASPECT_STENCIL_BIT)
552 flags |= PIPE_CLEAR_STENCIL;
553 surf = create_clear_surface(pctx, pres, level, box);
554 util_blitter_save_framebuffer(ctx->blitter, &ctx->fb_state);
555 zink_blit_barriers(ctx, NULL, res, false);
556 ctx->blitting = true;
557 set_clear_fb(pctx, NULL, surf);
558 ctx->queries_disabled = true;
559 pctx->clear(pctx, flags, &scissor, NULL, depth, stencil);
560 util_blitter_restore_fb_state(ctx->blitter);
561 ctx->queries_disabled = false;
562 ctx->blitting = false;
563 }
564 /* this will never destroy the surface */
565 pipe_surface_reference(&surf, NULL);
566 }
567
568 void
zink_clear_buffer(struct pipe_context * pctx,struct pipe_resource * pres,unsigned offset,unsigned size,const void * clear_value,int clear_value_size)569 zink_clear_buffer(struct pipe_context *pctx,
570 struct pipe_resource *pres,
571 unsigned offset,
572 unsigned size,
573 const void *clear_value,
574 int clear_value_size)
575 {
576 struct zink_context *ctx = zink_context(pctx);
577 struct zink_resource *res = zink_resource(pres);
578
579 uint32_t clamped;
580 if (util_lower_clearsize_to_dword(clear_value, &clear_value_size, &clamped))
581 clear_value = &clamped;
582 if (offset % 4 == 0 && size % 4 == 0 && clear_value_size == sizeof(uint32_t)) {
583 /*
584 - dstOffset is the byte offset into the buffer at which to start filling,
585 and must be a multiple of 4.
586
587 - size is the number of bytes to fill, and must be either a multiple of 4,
588 or VK_WHOLE_SIZE to fill the range from offset to the end of the buffer
589 */
590 zink_resource_buffer_transfer_dst_barrier(ctx, res, offset, size);
591 VkCommandBuffer cmdbuf = zink_get_cmdbuf(ctx, NULL, res);
592 zink_batch_reference_resource_rw(ctx, res, true);
593 VKCTX(CmdFillBuffer)(cmdbuf, res->obj->buffer, offset, size, *(uint32_t*)clear_value);
594 return;
595 }
596 struct pipe_transfer *xfer;
597 uint8_t *map = pipe_buffer_map_range(pctx, pres, offset, size,
598 PIPE_MAP_WRITE | PIPE_MAP_ONCE | PIPE_MAP_DISCARD_RANGE, &xfer);
599 if (!map)
600 return;
601 unsigned rem = size % clear_value_size;
602 uint8_t *ptr = map;
603 for (unsigned i = 0; i < (size - rem) / clear_value_size; i++) {
604 memcpy(ptr, clear_value, clear_value_size);
605 ptr += clear_value_size;
606 }
607 if (rem)
608 memcpy(map + size - rem, clear_value, rem);
609 pipe_buffer_unmap(pctx, xfer);
610 }
611
612 void
zink_clear_render_target(struct pipe_context * pctx,struct pipe_surface * dst,const union pipe_color_union * color,unsigned dstx,unsigned dsty,unsigned width,unsigned height,bool render_condition_enabled)613 zink_clear_render_target(struct pipe_context *pctx, struct pipe_surface *dst,
614 const union pipe_color_union *color, unsigned dstx,
615 unsigned dsty, unsigned width, unsigned height,
616 bool render_condition_enabled)
617 {
618 struct zink_context *ctx = zink_context(pctx);
619 bool render_condition_active = ctx->render_condition_active;
620 if (!render_condition_enabled && render_condition_active) {
621 zink_stop_conditional_render(ctx);
622 ctx->render_condition_active = false;
623 }
624 util_blitter_save_framebuffer(ctx->blitter, &ctx->fb_state);
625 set_clear_fb(pctx, dst, NULL);
626 struct pipe_scissor_state scissor = {dstx, dsty, dstx + width, dsty + height};
627 zink_blit_barriers(ctx, NULL, zink_resource(dst->texture), false);
628 ctx->blitting = true;
629 pctx->clear(pctx, PIPE_CLEAR_COLOR0, &scissor, color, 0, 0);
630 util_blitter_restore_fb_state(ctx->blitter);
631 ctx->blitting = false;
632 if (!render_condition_enabled && render_condition_active)
633 zink_start_conditional_render(ctx);
634 ctx->render_condition_active = render_condition_active;
635 }
636
637 void
zink_clear_depth_stencil(struct pipe_context * pctx,struct pipe_surface * dst,unsigned clear_flags,double depth,unsigned stencil,unsigned dstx,unsigned dsty,unsigned width,unsigned height,bool render_condition_enabled)638 zink_clear_depth_stencil(struct pipe_context *pctx, struct pipe_surface *dst,
639 unsigned clear_flags, double depth, unsigned stencil,
640 unsigned dstx, unsigned dsty, unsigned width, unsigned height,
641 bool render_condition_enabled)
642 {
643 struct zink_context *ctx = zink_context(pctx);
644 /* check for stencil fallback */
645 bool blitting = ctx->blitting;
646 bool render_condition_active = ctx->render_condition_active;
647 if (!render_condition_enabled && render_condition_active) {
648 zink_stop_conditional_render(ctx);
649 ctx->render_condition_active = false;
650 }
651 bool cur_attachment = zink_csurface(ctx->fb_state.zsbuf) == zink_csurface(dst);
652 if (dstx > ctx->fb_state.width || dsty > ctx->fb_state.height ||
653 dstx + width > ctx->fb_state.width ||
654 dsty + height > ctx->fb_state.height)
655 cur_attachment = false;
656 if (!cur_attachment) {
657 if (!blitting) {
658 util_blitter_save_framebuffer(ctx->blitter, &ctx->fb_state);
659 set_clear_fb(pctx, NULL, dst);
660 zink_blit_barriers(ctx, NULL, zink_resource(dst->texture), false);
661 ctx->blitting = true;
662 }
663 }
664 struct pipe_scissor_state scissor = {dstx, dsty, dstx + width, dsty + height};
665 pctx->clear(pctx, clear_flags, &scissor, NULL, depth, stencil);
666 if (!cur_attachment && !blitting) {
667 util_blitter_restore_fb_state(ctx->blitter);
668 ctx->blitting = false;
669 }
670 if (!render_condition_enabled && render_condition_active)
671 zink_start_conditional_render(ctx);
672 ctx->render_condition_active = render_condition_active;
673 }
674
675 bool
zink_fb_clear_needs_explicit(struct zink_framebuffer_clear * fb_clear)676 zink_fb_clear_needs_explicit(struct zink_framebuffer_clear *fb_clear)
677 {
678 if (zink_fb_clear_count(fb_clear) != 1)
679 return true;
680 return zink_fb_clear_element_needs_explicit(zink_fb_clear_element(fb_clear, 0));
681 }
682
683 bool
zink_fb_clear_first_needs_explicit(struct zink_framebuffer_clear * fb_clear)684 zink_fb_clear_first_needs_explicit(struct zink_framebuffer_clear *fb_clear)
685 {
686 if (!zink_fb_clear_count(fb_clear))
687 return false;
688 return zink_fb_clear_element_needs_explicit(zink_fb_clear_element(fb_clear, 0));
689 }
690
691 static void
fb_clears_apply_internal(struct zink_context * ctx,struct pipe_resource * pres,int i)692 fb_clears_apply_internal(struct zink_context *ctx, struct pipe_resource *pres, int i)
693 {
694 if (!zink_fb_clear_enabled(ctx, i))
695 return;
696 if (ctx->in_rp)
697 zink_clear_framebuffer(ctx, BITFIELD_BIT(i));
698 else {
699 struct zink_resource *res = zink_resource(pres);
700 bool queries_disabled = ctx->queries_disabled;
701 VkCommandBuffer cmdbuf = ctx->bs->cmdbuf;
702 /* slightly different than the u_blitter handling:
703 * this can be called recursively while unordered_blitting=true
704 */
705 bool can_reorder = zink_screen(ctx->base.screen)->info.have_KHR_dynamic_rendering &&
706 !ctx->render_condition_active &&
707 !ctx->unordered_blitting &&
708 zink_get_cmdbuf(ctx, NULL, res) == ctx->bs->reordered_cmdbuf;
709 if (can_reorder) {
710 /* set unordered_blitting but NOT blitting:
711 * let begin_rendering handle layouts
712 */
713 ctx->unordered_blitting = true;
714 /* for unordered clears, swap the unordered cmdbuf for the main one for the whole op to avoid conditional hell */
715 ctx->bs->cmdbuf = ctx->bs->reordered_cmdbuf;
716 ctx->rp_changed = true;
717 ctx->queries_disabled = true;
718 }
719 /* this will automatically trigger all the clears */
720 zink_batch_rp(ctx);
721 if (can_reorder) {
722 zink_batch_no_rp(ctx);
723 ctx->unordered_blitting = false;
724 ctx->rp_changed = true;
725 ctx->queries_disabled = queries_disabled;
726 ctx->bs->cmdbuf = cmdbuf;
727 }
728 }
729 zink_fb_clear_reset(ctx, i);
730 }
731
732 void
zink_fb_clear_reset(struct zink_context * ctx,unsigned i)733 zink_fb_clear_reset(struct zink_context *ctx, unsigned i)
734 {
735 unsigned rp_clears_enabled = ctx->clears_enabled;
736 util_dynarray_clear(&ctx->fb_clears[i].clears);
737 if (i == PIPE_MAX_COLOR_BUFS) {
738 ctx->clears_enabled &= ~PIPE_CLEAR_DEPTHSTENCIL;
739 ctx->rp_clears_enabled &= ~PIPE_CLEAR_DEPTHSTENCIL;
740 } else {
741 ctx->clears_enabled &= ~(PIPE_CLEAR_COLOR0 << i);
742 ctx->rp_clears_enabled &= ~(PIPE_CLEAR_COLOR0 << i);
743 }
744 if (ctx->rp_clears_enabled != rp_clears_enabled)
745 ctx->rp_loadop_changed = true;
746 }
747
748 void
zink_fb_clears_apply(struct zink_context * ctx,struct pipe_resource * pres)749 zink_fb_clears_apply(struct zink_context *ctx, struct pipe_resource *pres)
750 {
751 if (zink_resource(pres)->aspect == VK_IMAGE_ASPECT_COLOR_BIT) {
752 for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) {
753 if (ctx->fb_state.cbufs[i] && ctx->fb_state.cbufs[i]->texture == pres) {
754 fb_clears_apply_internal(ctx, pres, i);
755 }
756 }
757 } else {
758 if (ctx->fb_state.zsbuf && ctx->fb_state.zsbuf->texture == pres) {
759 fb_clears_apply_internal(ctx, pres, PIPE_MAX_COLOR_BUFS);
760 }
761 }
762 }
763
764 void
zink_fb_clears_discard(struct zink_context * ctx,struct pipe_resource * pres)765 zink_fb_clears_discard(struct zink_context *ctx, struct pipe_resource *pres)
766 {
767 if (zink_resource(pres)->aspect == VK_IMAGE_ASPECT_COLOR_BIT) {
768 for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) {
769 if (ctx->fb_state.cbufs[i] && ctx->fb_state.cbufs[i]->texture == pres) {
770 if (zink_fb_clear_enabled(ctx, i)) {
771 zink_fb_clear_reset(ctx, i);
772 }
773 }
774 }
775 } else {
776 if (zink_fb_clear_enabled(ctx, PIPE_MAX_COLOR_BUFS) && ctx->fb_state.zsbuf && ctx->fb_state.zsbuf->texture == pres) {
777 int i = PIPE_MAX_COLOR_BUFS;
778 zink_fb_clear_reset(ctx, i);
779 }
780 }
781 }
782
783 void
zink_clear_apply_conditionals(struct zink_context * ctx)784 zink_clear_apply_conditionals(struct zink_context *ctx)
785 {
786 for (int i = 0; i < ARRAY_SIZE(ctx->fb_clears); i++) {
787 struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[i];
788 if (!zink_fb_clear_enabled(ctx, i))
789 continue;
790 for (int j = 0; j < zink_fb_clear_count(fb_clear); j++) {
791 struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(fb_clear, j);
792 if (clear->conditional) {
793 struct pipe_surface *surf;
794 if (i < PIPE_MAX_COLOR_BUFS)
795 surf = ctx->fb_state.cbufs[i];
796 else
797 surf = ctx->fb_state.zsbuf;
798 if (surf)
799 fb_clears_apply_internal(ctx, surf->texture, i);
800 else
801 zink_fb_clear_reset(ctx, i);
802 break;
803 }
804 }
805 }
806 }
807
808 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)809 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)
810 {
811 struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[i];
812 if (zink_fb_clear_enabled(ctx, i)) {
813 if (zink_blit_region_fills(region, pres->width0, pres->height0)) {
814 if (invert)
815 fb_clears_apply_internal(ctx, pres, i);
816 else
817 /* we know we can skip these */
818 zink_fb_clears_discard(ctx, pres);
819 return;
820 }
821 for (int j = 0; j < zink_fb_clear_count(fb_clear); j++) {
822 struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(fb_clear, j);
823 struct u_rect scissor = {clear->scissor.minx, clear->scissor.maxx,
824 clear->scissor.miny, clear->scissor.maxy};
825 if (!clear->has_scissor || zink_blit_region_covers(region, scissor)) {
826 /* this is a clear that isn't fully covered by our pending write */
827 if (!discard_only)
828 fb_clears_apply_internal(ctx, pres, i);
829 return;
830 }
831 }
832 if (!invert)
833 /* if we haven't already returned, then we know we can discard */
834 zink_fb_clears_discard(ctx, pres);
835 }
836 }
837
838 void
zink_fb_clears_apply_or_discard(struct zink_context * ctx,struct pipe_resource * pres,struct u_rect region,bool discard_only)839 zink_fb_clears_apply_or_discard(struct zink_context *ctx, struct pipe_resource *pres, struct u_rect region, bool discard_only)
840 {
841 if (zink_resource(pres)->aspect == VK_IMAGE_ASPECT_COLOR_BIT) {
842 for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) {
843 if (ctx->fb_state.cbufs[i] && ctx->fb_state.cbufs[i]->texture == pres) {
844 fb_clears_apply_or_discard_internal(ctx, pres, region, discard_only, false, i);
845 }
846 }
847 } else {
848 if (zink_fb_clear_enabled(ctx, PIPE_MAX_COLOR_BUFS) && ctx->fb_state.zsbuf && ctx->fb_state.zsbuf->texture == pres) {
849 fb_clears_apply_or_discard_internal(ctx, pres, region, discard_only, false, PIPE_MAX_COLOR_BUFS);
850 }
851 }
852 }
853
854 void
zink_fb_clears_apply_region(struct zink_context * ctx,struct pipe_resource * pres,struct u_rect region)855 zink_fb_clears_apply_region(struct zink_context *ctx, struct pipe_resource *pres, struct u_rect region)
856 {
857 if (zink_resource(pres)->aspect == VK_IMAGE_ASPECT_COLOR_BIT) {
858 for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) {
859 if (ctx->fb_state.cbufs[i] && ctx->fb_state.cbufs[i]->texture == pres) {
860 fb_clears_apply_or_discard_internal(ctx, pres, region, false, true, i);
861 }
862 }
863 } else {
864 if (ctx->fb_state.zsbuf && ctx->fb_state.zsbuf->texture == pres) {
865 fb_clears_apply_or_discard_internal(ctx, pres, region, false, true, PIPE_MAX_COLOR_BUFS);
866 }
867 }
868 }
869
870 void
zink_fb_clear_rewrite(struct zink_context * ctx,unsigned idx,enum pipe_format before,enum pipe_format after)871 zink_fb_clear_rewrite(struct zink_context *ctx, unsigned idx, enum pipe_format before, enum pipe_format after)
872 {
873 /* if the values for the clear color are incompatible, they must be rewritten;
874 * this occurs if:
875 * - the formats' srgb-ness does not match
876 * - the formats' signedness does not match
877 */
878 const struct util_format_description *bdesc = util_format_description(before);
879 const struct util_format_description *adesc = util_format_description(after);
880 int bfirst_non_void_chan = util_format_get_first_non_void_channel(before);
881 int afirst_non_void_chan = util_format_get_first_non_void_channel(after);
882 bool bsigned = false, asigned = false;
883 if (bfirst_non_void_chan > 0)
884 bsigned = bdesc->channel[bfirst_non_void_chan].type == UTIL_FORMAT_TYPE_SIGNED;
885 if (afirst_non_void_chan > 0)
886 asigned = adesc->channel[afirst_non_void_chan].type == UTIL_FORMAT_TYPE_SIGNED;
887 if (util_format_is_srgb(before) == util_format_is_srgb(after) &&
888 bsigned == asigned)
889 return;
890 struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[idx];
891 for (int j = 0; j < zink_fb_clear_count(fb_clear); j++) {
892 struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(fb_clear, j);
893 uint32_t data[4];
894 util_format_pack_rgba(before, data, clear->color.ui, 1);
895 util_format_unpack_rgba(after, clear->color.ui, data, 1);
896 }
897 }
898