xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/zink/zink_clear.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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