• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_kopper.h"
26 #include "zink_framebuffer.h"
27 #include "zink_query.h"
28 #include "zink_resource.h"
29 #include "zink_screen.h"
30 
31 #include "util/u_blitter.h"
32 #include "util/u_dynarray.h"
33 #include "util/format/u_format.h"
34 #include "util/format_srgb.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       attachments[num_attachments].aspectMask = aspect;
86       attachments[num_attachments].clearValue.depthStencil.depth = depth;
87       attachments[num_attachments].clearValue.depthStencil.stencil = stencil;
88       ++num_attachments;
89    }
90 
91    VkClearRect cr = {0};
92    if (scissor_state) {
93       cr.rect.offset.x = scissor_state->minx;
94       cr.rect.offset.y = scissor_state->miny;
95       cr.rect.extent.width = MIN2(fb->width, scissor_state->maxx - scissor_state->minx);
96       cr.rect.extent.height = MIN2(fb->height, scissor_state->maxy - scissor_state->miny);
97    } else {
98       cr.rect.extent.width = fb->width;
99       cr.rect.extent.height = fb->height;
100    }
101    cr.baseArrayLayer = 0;
102    cr.layerCount = util_framebuffer_get_num_layers(fb);
103    struct zink_batch *batch = &ctx->batch;
104    assert(batch->in_rp);
105    VKCTX(CmdClearAttachments)(batch->state->cmdbuf, num_attachments, attachments, 1, &cr);
106    /*
107        Rendering within a subpass containing a feedback loop creates a data race, except in the following
108        cases:
109        • If a memory dependency is inserted between when the attachment is written and when it is
110        subsequently read by later fragments. Pipeline barriers expressing a subpass self-dependency
111        are the only way to achieve this, and one must be inserted every time a fragment will read
112        values at a particular sample (x, y, layer, sample) coordinate, if those values have been written
113        since the most recent pipeline barrier
114 
115        VK 1.3.211, Chapter 8: Render Pass
116     */
117    if (ctx->fbfetch_outputs)
118       ctx->base.texture_barrier(&ctx->base, PIPE_TEXTURE_BARRIER_FRAMEBUFFER);
119 }
120 
121 static struct zink_framebuffer_clear_data *
add_new_clear(struct zink_framebuffer_clear * fb_clear)122 add_new_clear(struct zink_framebuffer_clear *fb_clear)
123 {
124    struct zink_framebuffer_clear_data cd = {0};
125    util_dynarray_append(&fb_clear->clears, struct zink_framebuffer_clear_data, cd);
126    return zink_fb_clear_element(fb_clear, zink_fb_clear_count(fb_clear) - 1);
127 }
128 
129 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)130 get_clear_data(struct zink_context *ctx, struct zink_framebuffer_clear *fb_clear, const struct pipe_scissor_state *scissor_state)
131 {
132    unsigned num_clears = zink_fb_clear_count(fb_clear);
133    if (num_clears) {
134       struct zink_framebuffer_clear_data *last_clear = zink_fb_clear_element(fb_clear, num_clears - 1);
135       /* if we're completely overwriting the previous clear, merge this into the previous clear */
136       if (!scissor_state || (last_clear->has_scissor && scissor_states_equal(&last_clear->scissor, scissor_state)))
137          return last_clear;
138    }
139    return add_new_clear(fb_clear);
140 }
141 
142 static void
clamp_color(const struct util_format_description * desc,union pipe_color_union * dst,const union pipe_color_union * src,unsigned i)143 clamp_color(const struct util_format_description *desc, union pipe_color_union *dst, const union pipe_color_union *src, unsigned i)
144 {
145    int non_void = util_format_get_first_non_void_channel(desc->format);
146    switch (desc->channel[i].type) {
147    case UTIL_FORMAT_TYPE_VOID:
148       if (desc->channel[non_void].type == UTIL_FORMAT_TYPE_FLOAT) {
149          dst->f[i] = uif(UINT32_MAX);
150       } else {
151          if (desc->channel[non_void].normalized)
152             dst->f[i] = 1.0;
153          else if (desc->channel[non_void].type == UTIL_FORMAT_TYPE_SIGNED)
154             dst->i[i] = INT32_MAX;
155          else
156             dst->ui[i] = UINT32_MAX;
157       }
158       break;
159    case UTIL_FORMAT_TYPE_SIGNED:
160       if (desc->channel[i].normalized)
161          dst->i[i] = src->i[i];
162       else {
163          dst->i[i] = MAX2(src->i[i], -(1<<(desc->channel[i].size - 1)));
164          dst->i[i] = MIN2(dst->i[i], (1 << (desc->channel[i].size - 1)) - 1);
165       }
166       break;
167    case UTIL_FORMAT_TYPE_UNSIGNED:
168       if (desc->channel[i].normalized)
169          dst->ui[i] = src->ui[i];
170       else
171          dst->ui[i] = MIN2(src->ui[i], BITFIELD_MASK(desc->channel[i].size));
172       break;
173    case UTIL_FORMAT_TYPE_FIXED:
174    case UTIL_FORMAT_TYPE_FLOAT:
175       dst->ui[i] = src->ui[i];
176       break;
177    }
178 }
179 
180 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)181 zink_clear(struct pipe_context *pctx,
182            unsigned buffers,
183            const struct pipe_scissor_state *scissor_state,
184            const union pipe_color_union *pcolor,
185            double depth, unsigned stencil)
186 {
187    struct zink_context *ctx = zink_context(pctx);
188    struct pipe_framebuffer_state *fb = &ctx->fb_state;
189    struct zink_batch *batch = &ctx->batch;
190    bool needs_rp = false;
191 
192    if (unlikely(!zink_screen(pctx->screen)->info.have_EXT_conditional_rendering && !zink_check_conditional_render(ctx)))
193       return;
194 
195    if (scissor_state) {
196       struct u_rect scissor = {scissor_state->minx, scissor_state->maxx, scissor_state->miny, scissor_state->maxy};
197       needs_rp = !zink_blit_region_fills(scissor, fb->width, fb->height);
198    }
199 
200    if (unlikely(ctx->fb_layer_mismatch)) {
201       /* this is a terrible scenario:
202        * at least one attachment has a layerCount greater than the others,
203        * so iterate over all the mismatched attachments and pre-clear them separately,
204        * then continue to flag them as need (additional) clearing
205        * to avoid loadOp=LOAD
206        */
207       unsigned x = 0;
208       unsigned y = 0;
209       unsigned w = ctx->fb_state.width;
210       unsigned h = ctx->fb_state.height;
211       if (scissor_state) {
212          x = scissor_state->minx;
213          y = scissor_state->miny;
214          w = scissor_state->minx + scissor_state->maxx;
215          h = scissor_state->miny + scissor_state->maxy;
216       }
217       unsigned clear_buffers = buffers >> 2;
218       for (unsigned i = 0; i < ctx->fb_state.nr_cbufs; i++) {
219          if (ctx->fb_state.cbufs[i] &&
220              (ctx->fb_layer_mismatch & clear_buffers & BITFIELD_BIT(i))) {
221             if (ctx->void_clears & (PIPE_CLEAR_COLOR0 << i)) {
222                union pipe_color_union color;
223                color.f[0] = color.f[1] = color.f[2] = 0;
224                color.f[3] = 1.0;
225                pctx->clear_render_target(pctx, ctx->fb_state.cbufs[i], &color,
226                                          0, 0,
227                                          ctx->fb_state.cbufs[i]->width, ctx->fb_state.cbufs[i]->height,
228                                          ctx->render_condition_active);
229             }
230             pctx->clear_render_target(pctx, ctx->fb_state.cbufs[i], pcolor,
231                                       x, y, w, h, ctx->render_condition_active);
232          }
233       }
234       if (ctx->fb_state.zsbuf && (buffers & PIPE_CLEAR_DEPTHSTENCIL))
235          pctx->clear_depth_stencil(pctx, ctx->fb_state.zsbuf, buffers & PIPE_CLEAR_DEPTHSTENCIL, depth, stencil,
236                                    x, y, w, h, ctx->render_condition_active);
237    }
238 
239    if (batch->in_rp) {
240       clear_in_rp(pctx, buffers, scissor_state, pcolor, depth, stencil);
241       return;
242    }
243 
244    unsigned rp_clears_enabled = ctx->rp_clears_enabled;
245 
246    if (ctx->void_clears & buffers) {
247       unsigned void_clears = ctx->void_clears & buffers;
248       ctx->void_clears &= ~buffers;
249       union pipe_color_union color;
250       color.f[0] = color.f[1] = color.f[2] = 0;
251       color.f[3] = 1.0;
252       for (unsigned i = 0; i < fb->nr_cbufs; i++) {
253          if ((void_clears & (PIPE_CLEAR_COLOR0 << i)) && fb->cbufs[i]) {
254             struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[i];
255             unsigned num_clears = zink_fb_clear_count(fb_clear);
256             if (num_clears) {
257                if (zink_fb_clear_first_needs_explicit(fb_clear)) {
258                   /* a scissored clear exists:
259                    * - extend the clear array
260                    * - shift existing clears back by one position
261                    * - inject void clear base of array
262                    */
263                   add_new_clear(fb_clear);
264                   struct zink_framebuffer_clear_data *clear = fb_clear->clears.data;
265                   memcpy(clear + 1, clear, num_clears);
266                   memcpy(&clear->color, &color, sizeof(color));
267                } else {
268                   /* no void clear needed */
269                }
270                void_clears &= ~(PIPE_CLEAR_COLOR0 << i);
271             }
272          }
273       }
274       if (void_clears)
275          pctx->clear(pctx, void_clears, NULL, &color, 0, 0);
276    }
277 
278    if (buffers & PIPE_CLEAR_COLOR) {
279       for (unsigned i = 0; i < fb->nr_cbufs; i++) {
280          if ((buffers & (PIPE_CLEAR_COLOR0 << i)) && fb->cbufs[i]) {
281             struct pipe_surface *psurf = fb->cbufs[i];
282             const struct util_format_description *desc = util_format_description(psurf->format);
283             struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[i];
284             struct zink_framebuffer_clear_data *clear = get_clear_data(ctx, fb_clear, needs_rp ? scissor_state : NULL);
285 
286             ctx->clears_enabled |= PIPE_CLEAR_COLOR0 << i;
287             clear->conditional = ctx->render_condition_active;
288             clear->has_scissor = needs_rp;
289             if (scissor_state && needs_rp)
290                clear->scissor = *scissor_state;
291             for (unsigned i = 0; i < 4; i++)
292                clamp_color(desc, &clear->color, pcolor, i);
293             if (zink_fb_clear_first_needs_explicit(fb_clear))
294                ctx->rp_clears_enabled &= ~(PIPE_CLEAR_COLOR0 << i);
295             else
296                ctx->rp_clears_enabled |= PIPE_CLEAR_COLOR0 << i;
297          }
298       }
299    }
300 
301    if (buffers & PIPE_CLEAR_DEPTHSTENCIL && fb->zsbuf) {
302       struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[PIPE_MAX_COLOR_BUFS];
303       struct zink_framebuffer_clear_data *clear = get_clear_data(ctx, fb_clear, needs_rp ? scissor_state : NULL);
304       ctx->clears_enabled |= PIPE_CLEAR_DEPTHSTENCIL;
305       clear->conditional = ctx->render_condition_active;
306       clear->has_scissor = needs_rp;
307       if (scissor_state && needs_rp)
308          clear->scissor = *scissor_state;
309       if (buffers & PIPE_CLEAR_DEPTH)
310          clear->zs.depth = depth;
311       if (buffers & PIPE_CLEAR_STENCIL)
312          clear->zs.stencil = stencil;
313       clear->zs.bits |= (buffers & PIPE_CLEAR_DEPTHSTENCIL);
314       if (zink_fb_clear_first_needs_explicit(fb_clear))
315          ctx->rp_clears_enabled &= ~PIPE_CLEAR_DEPTHSTENCIL;
316       else
317          ctx->rp_clears_enabled |= (buffers & PIPE_CLEAR_DEPTHSTENCIL);
318    }
319    assert(!ctx->batch.in_rp);
320    ctx->rp_changed |= ctx->rp_clears_enabled != rp_clears_enabled;
321 }
322 
323 static inline bool
colors_equal(union pipe_color_union * a,union pipe_color_union * b)324 colors_equal(union pipe_color_union *a, union pipe_color_union *b)
325 {
326    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];
327 }
328 
329 void
zink_clear_framebuffer(struct zink_context * ctx,unsigned clear_buffers)330 zink_clear_framebuffer(struct zink_context *ctx, unsigned clear_buffers)
331 {
332    unsigned to_clear = 0;
333    struct pipe_framebuffer_state *fb_state = &ctx->fb_state;
334 #ifndef NDEBUG
335    assert(!(clear_buffers & PIPE_CLEAR_DEPTHSTENCIL) || zink_fb_clear_enabled(ctx, PIPE_MAX_COLOR_BUFS));
336    for (int i = 0; i < fb_state->nr_cbufs && clear_buffers >= PIPE_CLEAR_COLOR0; i++) {
337       assert(!(clear_buffers & (PIPE_CLEAR_COLOR0 << i)) || zink_fb_clear_enabled(ctx, i));
338    }
339 #endif
340    while (clear_buffers) {
341       struct zink_framebuffer_clear *color_clear = NULL;
342       struct zink_framebuffer_clear *zs_clear = NULL;
343       unsigned num_clears = 0;
344       for (int i = 0; i < fb_state->nr_cbufs && clear_buffers >= PIPE_CLEAR_COLOR0; i++) {
345          struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[i];
346          /* these need actual clear calls inside the rp */
347          if (!(clear_buffers & (PIPE_CLEAR_COLOR0 << i)))
348             continue;
349          if (color_clear) {
350             /* different number of clears -> do another clear */
351             //XXX: could potentially merge "some" of the clears into this one for a very, very small optimization
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 < num_clears; 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                /* colors don't match, fire this one off */
363                if (!colors_equal(&a->color, &b->color))
364                   goto out;
365             }
366          } else {
367             color_clear = fb_clear;
368             num_clears = zink_fb_clear_count(fb_clear);
369          }
370 
371          clear_buffers &= ~(PIPE_CLEAR_COLOR0 << i);
372          to_clear |= (PIPE_CLEAR_COLOR0 << i);
373       }
374       clear_buffers &= ~PIPE_CLEAR_COLOR;
375       if (clear_buffers & PIPE_CLEAR_DEPTHSTENCIL) {
376          struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[PIPE_MAX_COLOR_BUFS];
377          if (color_clear) {
378             if (num_clears != zink_fb_clear_count(fb_clear))
379                goto out;
380             /* compare all the clears to determine if we can batch these buffers together */
381             for (int j = !zink_fb_clear_first_needs_explicit(fb_clear); j < zink_fb_clear_count(color_clear); j++) {
382                struct zink_framebuffer_clear_data *a = zink_fb_clear_element(color_clear, j);
383                struct zink_framebuffer_clear_data *b = zink_fb_clear_element(fb_clear, j);
384                /* scissors don't match, fire this one off */
385                if (a->has_scissor != b->has_scissor || (a->has_scissor && !scissor_states_equal(&a->scissor, &b->scissor)))
386                   goto out;
387             }
388          }
389          zs_clear = fb_clear;
390          to_clear |= (clear_buffers & PIPE_CLEAR_DEPTHSTENCIL);
391          clear_buffers &= ~PIPE_CLEAR_DEPTHSTENCIL;
392       }
393 out:
394       if (to_clear) {
395          if (num_clears) {
396             for (int j = !zink_fb_clear_first_needs_explicit(color_clear); j < num_clears; j++) {
397                struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(color_clear, j);
398                struct zink_framebuffer_clear_data *zsclear = NULL;
399                /* zs bits are both set here if those aspects should be cleared at some point */
400                unsigned clear_bits = to_clear & ~PIPE_CLEAR_DEPTHSTENCIL;
401                if (zs_clear) {
402                   zsclear = zink_fb_clear_element(zs_clear, j);
403                   clear_bits |= zsclear->zs.bits;
404                }
405                zink_clear(&ctx->base, clear_bits,
406                           clear->has_scissor ? &clear->scissor : NULL,
407                           &clear->color,
408                           zsclear ? zsclear->zs.depth : 0,
409                           zsclear ? zsclear->zs.stencil : 0);
410             }
411          } else {
412             for (int j = !zink_fb_clear_first_needs_explicit(zs_clear); j < zink_fb_clear_count(zs_clear); j++) {
413                struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(zs_clear, j);
414                zink_clear(&ctx->base, clear->zs.bits,
415                           clear->has_scissor ? &clear->scissor : NULL,
416                           NULL,
417                           clear->zs.depth,
418                           clear->zs.stencil);
419             }
420          }
421       }
422       to_clear = 0;
423    }
424    for (int i = 0; i < ARRAY_SIZE(ctx->fb_clears); i++)
425        zink_fb_clear_reset(ctx, i);
426 }
427 
428 static struct pipe_surface *
create_clear_surface(struct pipe_context * pctx,struct pipe_resource * pres,unsigned level,const struct pipe_box * box)429 create_clear_surface(struct pipe_context *pctx, struct pipe_resource *pres, unsigned level, const struct pipe_box *box)
430 {
431    struct pipe_surface tmpl = {{0}};
432 
433    tmpl.format = pres->format;
434    tmpl.u.tex.first_layer = box->z;
435    tmpl.u.tex.last_layer = box->z + box->depth - 1;
436    tmpl.u.tex.level = level;
437    return pctx->create_surface(pctx, pres, &tmpl);
438 }
439 
440 static void
set_clear_fb(struct pipe_context * pctx,struct pipe_surface * psurf,struct pipe_surface * zsurf)441 set_clear_fb(struct pipe_context *pctx, struct pipe_surface *psurf, struct pipe_surface *zsurf)
442 {
443    struct pipe_framebuffer_state fb_state;
444    fb_state.width = psurf ? psurf->width : zsurf->width;
445    fb_state.height = psurf ? psurf->height : zsurf->height;
446    fb_state.nr_cbufs = !!psurf;
447    fb_state.cbufs[0] = psurf;
448    fb_state.zsbuf = zsurf;
449    pctx->set_framebuffer_state(pctx, &fb_state);
450 }
451 
452 void
zink_clear_texture(struct pipe_context * pctx,struct pipe_resource * pres,unsigned level,const struct pipe_box * box,const void * data)453 zink_clear_texture(struct pipe_context *pctx,
454                    struct pipe_resource *pres,
455                    unsigned level,
456                    const struct pipe_box *box,
457                    const void *data)
458 {
459    struct zink_context *ctx = zink_context(pctx);
460    struct zink_resource *res = zink_resource(pres);
461    struct pipe_surface *surf = NULL;
462    struct pipe_scissor_state scissor = {box->x, box->y, box->x + box->width, box->y + box->height};
463 
464    if (res->aspect & VK_IMAGE_ASPECT_COLOR_BIT) {
465       union pipe_color_union color;
466 
467       util_format_unpack_rgba(pres->format, color.ui, data, 1);
468 
469       surf = create_clear_surface(pctx, pres, level, box);
470       util_blitter_save_framebuffer(ctx->blitter, &ctx->fb_state);
471       set_clear_fb(pctx, surf, NULL);
472       pctx->clear(pctx, PIPE_CLEAR_COLOR0, &scissor, &color, 0, 0);
473       util_blitter_restore_fb_state(ctx->blitter);
474    } else {
475       float depth = 0.0;
476       uint8_t stencil = 0;
477 
478       if (res->aspect & VK_IMAGE_ASPECT_DEPTH_BIT)
479          util_format_unpack_z_float(pres->format, &depth, data, 1);
480 
481       if (res->aspect & VK_IMAGE_ASPECT_STENCIL_BIT)
482          util_format_unpack_s_8uint(pres->format, &stencil, data, 1);
483 
484       unsigned flags = 0;
485       if (res->aspect & VK_IMAGE_ASPECT_DEPTH_BIT)
486          flags |= PIPE_CLEAR_DEPTH;
487       if (res->aspect & VK_IMAGE_ASPECT_STENCIL_BIT)
488          flags |= PIPE_CLEAR_STENCIL;
489       surf = create_clear_surface(pctx, pres, level, box);
490       util_blitter_save_framebuffer(ctx->blitter, &ctx->fb_state);
491       set_clear_fb(pctx, NULL, surf);
492       pctx->clear(pctx, flags, &scissor, NULL, depth, stencil);
493       util_blitter_restore_fb_state(ctx->blitter);
494    }
495    /* this will never destroy the surface */
496    pipe_surface_reference(&surf, NULL);
497 }
498 
499 void
zink_clear_buffer(struct pipe_context * pctx,struct pipe_resource * pres,unsigned offset,unsigned size,const void * clear_value,int clear_value_size)500 zink_clear_buffer(struct pipe_context *pctx,
501                   struct pipe_resource *pres,
502                   unsigned offset,
503                   unsigned size,
504                   const void *clear_value,
505                   int clear_value_size)
506 {
507    struct zink_context *ctx = zink_context(pctx);
508    struct zink_resource *res = zink_resource(pres);
509 
510    uint32_t clamped;
511    if (util_lower_clearsize_to_dword(clear_value, &clear_value_size, &clamped))
512       clear_value = &clamped;
513    if (offset % 4 == 0 && size % 4 == 0 && clear_value_size == sizeof(uint32_t)) {
514       /*
515          - dstOffset is the byte offset into the buffer at which to start filling,
516            and must be a multiple of 4.
517 
518          - size is the number of bytes to fill, and must be either a multiple of 4,
519            or VK_WHOLE_SIZE to fill the range from offset to the end of the buffer
520        */
521       struct zink_batch *batch = &ctx->batch;
522       zink_batch_no_rp(ctx);
523       zink_batch_reference_resource_rw(batch, res, true);
524       util_range_add(&res->base.b, &res->valid_buffer_range, offset, offset + size);
525       zink_resource_buffer_barrier(ctx, res, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
526       res->obj->unordered_read = res->obj->unordered_write = false;
527       VKCTX(CmdFillBuffer)(batch->state->cmdbuf, res->obj->buffer, offset, size, *(uint32_t*)clear_value);
528       return;
529    }
530    struct pipe_transfer *xfer;
531    uint8_t *map = pipe_buffer_map_range(pctx, pres, offset, size,
532                                         PIPE_MAP_WRITE | PIPE_MAP_ONCE | PIPE_MAP_DISCARD_RANGE, &xfer);
533    if (!map)
534       return;
535    unsigned rem = size % clear_value_size;
536    uint8_t *ptr = map;
537    for (unsigned i = 0; i < (size - rem) / clear_value_size; i++) {
538       memcpy(ptr, clear_value, clear_value_size);
539       ptr += clear_value_size;
540    }
541    if (rem)
542       memcpy(map + size - rem, clear_value, rem);
543    pipe_buffer_unmap(pctx, xfer);
544 }
545 
546 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)547 zink_clear_render_target(struct pipe_context *pctx, struct pipe_surface *dst,
548                          const union pipe_color_union *color, unsigned dstx,
549                          unsigned dsty, unsigned width, unsigned height,
550                          bool render_condition_enabled)
551 {
552    struct zink_context *ctx = zink_context(pctx);
553    bool render_condition_active = ctx->render_condition_active;
554    if (!render_condition_enabled && render_condition_active) {
555       zink_stop_conditional_render(ctx);
556       ctx->render_condition_active = false;
557    }
558    util_blitter_save_framebuffer(ctx->blitter, &ctx->fb_state);
559    set_clear_fb(pctx, dst, NULL);
560    struct pipe_scissor_state scissor = {dstx, dsty, dstx + width, dsty + height};
561    pctx->clear(pctx, PIPE_CLEAR_COLOR0, &scissor, color, 0, 0);
562    util_blitter_restore_fb_state(ctx->blitter);
563    if (!render_condition_enabled && render_condition_active)
564       zink_start_conditional_render(ctx);
565    ctx->render_condition_active = render_condition_active;
566 }
567 
568 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)569 zink_clear_depth_stencil(struct pipe_context *pctx, struct pipe_surface *dst,
570                          unsigned clear_flags, double depth, unsigned stencil,
571                          unsigned dstx, unsigned dsty, unsigned width, unsigned height,
572                          bool render_condition_enabled)
573 {
574    struct zink_context *ctx = zink_context(pctx);
575    bool render_condition_active = ctx->render_condition_active;
576    if (!render_condition_enabled && render_condition_active) {
577       zink_stop_conditional_render(ctx);
578       ctx->render_condition_active = false;
579    }
580    bool cur_attachment = zink_csurface(ctx->fb_state.zsbuf) == zink_csurface(dst);
581    if (dstx > ctx->fb_state.width || dsty > ctx->fb_state.height ||
582        dstx + width > ctx->fb_state.width ||
583        dsty + height > ctx->fb_state.height)
584       cur_attachment = false;
585    if (!cur_attachment) {
586       util_blitter_save_framebuffer(ctx->blitter, &ctx->fb_state);
587       set_clear_fb(pctx, NULL, dst);
588    }
589    struct pipe_scissor_state scissor = {dstx, dsty, dstx + width, dsty + height};
590    pctx->clear(pctx, clear_flags, &scissor, NULL, depth, stencil);
591    if (!cur_attachment)
592       util_blitter_restore_fb_state(ctx->blitter);
593    if (!render_condition_enabled && render_condition_active)
594       zink_start_conditional_render(ctx);
595    ctx->render_condition_active = render_condition_active;
596 }
597 
598 bool
zink_fb_clear_needs_explicit(struct zink_framebuffer_clear * fb_clear)599 zink_fb_clear_needs_explicit(struct zink_framebuffer_clear *fb_clear)
600 {
601    if (zink_fb_clear_count(fb_clear) != 1)
602       return true;
603    return zink_fb_clear_element_needs_explicit(zink_fb_clear_element(fb_clear, 0));
604 }
605 
606 bool
zink_fb_clear_first_needs_explicit(struct zink_framebuffer_clear * fb_clear)607 zink_fb_clear_first_needs_explicit(struct zink_framebuffer_clear *fb_clear)
608 {
609    if (!zink_fb_clear_count(fb_clear))
610       return false;
611    return zink_fb_clear_element_needs_explicit(zink_fb_clear_element(fb_clear, 0));
612 }
613 
614 static void
fb_clears_apply_internal(struct zink_context * ctx,struct pipe_resource * pres,int i)615 fb_clears_apply_internal(struct zink_context *ctx, struct pipe_resource *pres, int i)
616 {
617    if (!zink_fb_clear_enabled(ctx, i))
618       return;
619    if (ctx->batch.in_rp)
620       zink_clear_framebuffer(ctx, BITFIELD_BIT(i));
621    else
622       /* this will automatically trigger all the clears */
623       zink_batch_rp(ctx);
624    zink_fb_clear_reset(ctx, i);
625 }
626 
627 void
zink_fb_clear_reset(struct zink_context * ctx,unsigned i)628 zink_fb_clear_reset(struct zink_context *ctx, unsigned i)
629 {
630    unsigned rp_clears_enabled = ctx->clears_enabled;
631    util_dynarray_clear(&ctx->fb_clears[i].clears);
632    if (i == PIPE_MAX_COLOR_BUFS) {
633       ctx->clears_enabled &= ~PIPE_CLEAR_DEPTHSTENCIL;
634       ctx->rp_clears_enabled &= ~PIPE_CLEAR_DEPTHSTENCIL;
635    } else {
636       ctx->clears_enabled &= ~(PIPE_CLEAR_COLOR0 << i);
637       ctx->rp_clears_enabled &= ~(PIPE_CLEAR_COLOR0 << i);
638    }
639    if (ctx->rp_clears_enabled != rp_clears_enabled)
640       ctx->rp_loadop_changed = true;
641 }
642 
643 void
zink_fb_clears_apply(struct zink_context * ctx,struct pipe_resource * pres)644 zink_fb_clears_apply(struct zink_context *ctx, struct pipe_resource *pres)
645 {
646    if (zink_resource(pres)->aspect == VK_IMAGE_ASPECT_COLOR_BIT) {
647       for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) {
648          if (ctx->fb_state.cbufs[i] && ctx->fb_state.cbufs[i]->texture == pres) {
649             fb_clears_apply_internal(ctx, pres, i);
650          }
651       }
652    } else {
653       if (ctx->fb_state.zsbuf && ctx->fb_state.zsbuf->texture == pres) {
654          fb_clears_apply_internal(ctx, pres, PIPE_MAX_COLOR_BUFS);
655       }
656    }
657 }
658 
659 void
zink_fb_clears_discard(struct zink_context * ctx,struct pipe_resource * pres)660 zink_fb_clears_discard(struct zink_context *ctx, struct pipe_resource *pres)
661 {
662    if (zink_resource(pres)->aspect == VK_IMAGE_ASPECT_COLOR_BIT) {
663       for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) {
664          if (ctx->fb_state.cbufs[i] && ctx->fb_state.cbufs[i]->texture == pres) {
665             if (zink_fb_clear_enabled(ctx, i)) {
666                zink_fb_clear_reset(ctx, i);
667             }
668          }
669       }
670    } else {
671       if (zink_fb_clear_enabled(ctx, PIPE_MAX_COLOR_BUFS) && ctx->fb_state.zsbuf && ctx->fb_state.zsbuf->texture == pres) {
672          int i = PIPE_MAX_COLOR_BUFS;
673          zink_fb_clear_reset(ctx, i);
674       }
675    }
676 }
677 
678 void
zink_clear_apply_conditionals(struct zink_context * ctx)679 zink_clear_apply_conditionals(struct zink_context *ctx)
680 {
681    for (int i = 0; i < ARRAY_SIZE(ctx->fb_clears); i++) {
682       struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[i];
683       if (!zink_fb_clear_enabled(ctx, i))
684          continue;
685       for (int j = 0; j < zink_fb_clear_count(fb_clear); j++) {
686          struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(fb_clear, j);
687          if (clear->conditional) {
688             struct pipe_surface *surf;
689             if (i < PIPE_MAX_COLOR_BUFS)
690                surf = ctx->fb_state.cbufs[i];
691             else
692                surf = ctx->fb_state.zsbuf;
693             if (surf)
694                fb_clears_apply_internal(ctx, surf->texture, i);
695             else
696                zink_fb_clear_reset(ctx, i);
697             break;
698          }
699       }
700    }
701 }
702 
703 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)704 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)
705 {
706    struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[i];
707    if (zink_fb_clear_enabled(ctx, i)) {
708       if (zink_blit_region_fills(region, pres->width0, pres->height0)) {
709          if (invert)
710             fb_clears_apply_internal(ctx, pres, i);
711          else
712             /* we know we can skip these */
713             zink_fb_clears_discard(ctx, pres);
714          return;
715       }
716       for (int j = 0; j < zink_fb_clear_count(fb_clear); j++) {
717          struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(fb_clear, j);
718          struct u_rect scissor = {clear->scissor.minx, clear->scissor.maxx,
719                                   clear->scissor.miny, clear->scissor.maxy};
720          if (!clear->has_scissor || zink_blit_region_covers(region, scissor)) {
721             /* this is a clear that isn't fully covered by our pending write */
722             if (!discard_only)
723                fb_clears_apply_internal(ctx, pres, i);
724             return;
725          }
726       }
727       if (!invert)
728          /* if we haven't already returned, then we know we can discard */
729          zink_fb_clears_discard(ctx, pres);
730    }
731 }
732 
733 void
zink_fb_clears_apply_or_discard(struct zink_context * ctx,struct pipe_resource * pres,struct u_rect region,bool discard_only)734 zink_fb_clears_apply_or_discard(struct zink_context *ctx, struct pipe_resource *pres, struct u_rect region, bool discard_only)
735 {
736    if (zink_resource(pres)->aspect == VK_IMAGE_ASPECT_COLOR_BIT) {
737       for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) {
738          if (ctx->fb_state.cbufs[i] && ctx->fb_state.cbufs[i]->texture == pres) {
739             fb_clears_apply_or_discard_internal(ctx, pres, region, discard_only, false, i);
740          }
741       }
742    }  else {
743       if (zink_fb_clear_enabled(ctx, PIPE_MAX_COLOR_BUFS) && ctx->fb_state.zsbuf && ctx->fb_state.zsbuf->texture == pres) {
744          fb_clears_apply_or_discard_internal(ctx, pres, region, discard_only, false, PIPE_MAX_COLOR_BUFS);
745       }
746    }
747 }
748 
749 void
zink_fb_clears_apply_region(struct zink_context * ctx,struct pipe_resource * pres,struct u_rect region)750 zink_fb_clears_apply_region(struct zink_context *ctx, struct pipe_resource *pres, struct u_rect region)
751 {
752    if (zink_resource(pres)->aspect == VK_IMAGE_ASPECT_COLOR_BIT) {
753       for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) {
754          if (ctx->fb_state.cbufs[i] && ctx->fb_state.cbufs[i]->texture == pres) {
755             fb_clears_apply_or_discard_internal(ctx, pres, region, false, true, i);
756          }
757       }
758    }  else {
759       if (ctx->fb_state.zsbuf && ctx->fb_state.zsbuf->texture == pres) {
760          fb_clears_apply_or_discard_internal(ctx, pres, region, false, true, PIPE_MAX_COLOR_BUFS);
761       }
762    }
763 }
764