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