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