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