xref: /aosp_15_r20/external/mesa3d/src/mesa/state_tracker/st_cb_clear.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /**************************************************************************
2  *
3  * Copyright 2007 VMware, Inc.
4  * All Rights Reserved.
5  * Copyright 2009 VMware, Inc.  All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the
9  * "Software"), to deal in the Software without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sub license, and/or sell copies of the Software, and to
12  * permit persons to whom the Software is furnished to do so, subject to
13  * the following conditions:
14  *
15  * The above copyright notice and this permission notice (including the
16  * next paragraph) shall be included in all copies or substantial portions
17  * of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
23  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  *
27  **************************************************************************/
28 
29  /*
30   * Authors:
31   *   Keith Whitwell <[email protected]>
32   *   Brian Paul
33   *   Michel Dänzer
34   */
35 
36 #include "main/errors.h"
37 #include "util/glheader.h"
38 #include "main/accum.h"
39 #include "main/formats.h"
40 #include "main/framebuffer.h"
41 #include "main/macros.h"
42 #include "main/glformats.h"
43 #include "program/prog_instruction.h"
44 #include "st_context.h"
45 #include "st_atom.h"
46 #include "st_cb_bitmap.h"
47 #include "st_cb_clear.h"
48 #include "st_draw.h"
49 #include "st_format.h"
50 #include "st_nir.h"
51 #include "st_program.h"
52 #include "st_util.h"
53 
54 #include "pipe/p_context.h"
55 #include "pipe/p_shader_tokens.h"
56 #include "pipe/p_state.h"
57 #include "pipe/p_defines.h"
58 #include "util/format/u_format.h"
59 #include "util/u_inlines.h"
60 #include "util/u_simple_shaders.h"
61 
62 #include "cso_cache/cso_context.h"
63 
64 
65 /**
66  * Do per-context initialization for glClear.
67  */
68 void
st_init_clear(struct st_context * st)69 st_init_clear(struct st_context *st)
70 {
71    memset(&st->clear, 0, sizeof(st->clear));
72 
73    st->clear.raster.half_pixel_center = 1;
74    st->clear.raster.bottom_edge_rule = 1;
75    st->clear.raster.depth_clip_near = 1;
76    st->clear.raster.depth_clip_far = 1;
77 }
78 
79 
80 /**
81  * Free per-context state for glClear.
82  */
83 void
st_destroy_clear(struct st_context * st)84 st_destroy_clear(struct st_context *st)
85 {
86    if (st->clear.fs) {
87       st->pipe->delete_fs_state(st->pipe, st->clear.fs);
88       st->clear.fs = NULL;
89    }
90    if (st->clear.vs) {
91       st->pipe->delete_vs_state(st->pipe, st->clear.vs);
92       st->clear.vs = NULL;
93    }
94    if (st->clear.vs_layered) {
95       st->pipe->delete_vs_state(st->pipe, st->clear.vs_layered);
96       st->clear.vs_layered = NULL;
97    }
98    if (st->clear.gs_layered) {
99       st->pipe->delete_gs_state(st->pipe, st->clear.gs_layered);
100       st->clear.gs_layered = NULL;
101    }
102 }
103 
104 
105 /**
106  * Helper function to set the clear color fragment shader.
107  */
108 static void
set_clearcolor_fs(struct st_context * st,union pipe_color_union * color)109 set_clearcolor_fs(struct st_context *st, union pipe_color_union *color)
110 {
111    struct pipe_constant_buffer cb = {
112       .user_buffer = color->f,
113       .buffer_size = 4 * sizeof(float),
114    };
115    st->pipe->set_constant_buffer(st->pipe, PIPE_SHADER_FRAGMENT, 0,
116                                 false, &cb);
117 
118    if (!st->clear.fs) {
119       st->clear.fs = st_nir_make_clearcolor_shader(st);
120    }
121 
122    cso_set_fragment_shader_handle(st->cso_context, st->clear.fs);
123 }
124 
125 static void *
make_nir_clear_vertex_shader(struct st_context * st,bool layered)126 make_nir_clear_vertex_shader(struct st_context *st, bool layered)
127 {
128    const char *shader_name = layered ? "layered clear VS" : "clear VS";
129    unsigned inputs[] = {
130       VERT_ATTRIB_POS,
131       SYSTEM_VALUE_INSTANCE_ID,
132    };
133    gl_varying_slot outputs[] = {
134       VARYING_SLOT_POS,
135       VARYING_SLOT_LAYER
136    };
137 
138    return st_nir_make_passthrough_shader(st, shader_name, MESA_SHADER_VERTEX,
139                                          layered ? 2 : 1, inputs, outputs,
140                                          NULL, (1 << 1));
141 }
142 
143 
144 /**
145  * Helper function to set the vertex shader.
146  */
147 static inline void
set_vertex_shader(struct st_context * st)148 set_vertex_shader(struct st_context *st)
149 {
150    /* vertex shader - still required to provide the linkage between
151     * fragment shader input semantics and vertex_element/buffers.
152     */
153    if (!st->clear.vs)
154       st->clear.vs = make_nir_clear_vertex_shader(st, false);
155 
156    cso_set_vertex_shader_handle(st->cso_context, st->clear.vs);
157    cso_set_geometry_shader_handle(st->cso_context, NULL);
158 }
159 
160 
161 static void
set_vertex_shader_layered(struct st_context * st)162 set_vertex_shader_layered(struct st_context *st)
163 {
164    struct pipe_context *pipe = st->pipe;
165 
166    if (!st->screen->get_param(st->screen, PIPE_CAP_VS_INSTANCEID)) {
167       assert(!"Got layered clear, but VS instancing is unsupported");
168       set_vertex_shader(st);
169       return;
170    }
171 
172    if (!st->clear.vs_layered) {
173       bool vs_layer =
174          st->screen->get_param(st->screen, PIPE_CAP_VS_LAYER_VIEWPORT);
175       if (vs_layer) {
176          st->clear.vs_layered = make_nir_clear_vertex_shader(st, true);
177       } else {
178          st->clear.vs_layered = util_make_layered_clear_helper_vertex_shader(pipe);
179          st->clear.gs_layered = util_make_layered_clear_geometry_shader(pipe);
180       }
181    }
182 
183    cso_set_vertex_shader_handle(st->cso_context, st->clear.vs_layered);
184    cso_set_geometry_shader_handle(st->cso_context, st->clear.gs_layered);
185 }
186 
187 
188 /**
189  * Do glClear by drawing a quadrilateral.
190  * The vertices of the quad will be computed from the
191  * ctx->DrawBuffer->_X/Ymin/max fields.
192  */
193 static void
clear_with_quad(struct gl_context * ctx,unsigned clear_buffers)194 clear_with_quad(struct gl_context *ctx, unsigned clear_buffers)
195 {
196    struct st_context *st = st_context(ctx);
197    struct cso_context *cso = st->cso_context;
198    const struct gl_framebuffer *fb = ctx->DrawBuffer;
199    const GLfloat fb_width = (GLfloat) fb->Width;
200    const GLfloat fb_height = (GLfloat) fb->Height;
201 
202    _mesa_update_draw_buffer_bounds(ctx, ctx->DrawBuffer);
203 
204    const GLfloat x0 = (GLfloat) ctx->DrawBuffer->_Xmin / fb_width * 2.0f - 1.0f;
205    const GLfloat x1 = (GLfloat) ctx->DrawBuffer->_Xmax / fb_width * 2.0f - 1.0f;
206    const GLfloat y0 = (GLfloat) ctx->DrawBuffer->_Ymin / fb_height * 2.0f - 1.0f;
207    const GLfloat y1 = (GLfloat) ctx->DrawBuffer->_Ymax / fb_height * 2.0f - 1.0f;
208    unsigned num_layers = st->state.fb_num_layers;
209 
210    /*
211    printf("%s %s%s%s %f,%f %f,%f\n", __func__,
212 	  color ? "color, " : "",
213 	  depth ? "depth, " : "",
214 	  stencil ? "stencil" : "",
215 	  x0, y0,
216 	  x1, y1);
217    */
218 
219    cso_save_state(cso, (CSO_BIT_BLEND |
220                         CSO_BIT_STENCIL_REF |
221                         CSO_BIT_DEPTH_STENCIL_ALPHA |
222                         CSO_BIT_RASTERIZER |
223                         CSO_BIT_SAMPLE_MASK |
224                         CSO_BIT_MIN_SAMPLES |
225                         CSO_BIT_VIEWPORT |
226                         CSO_BIT_STREAM_OUTPUTS |
227                         CSO_BIT_VERTEX_ELEMENTS |
228                         (st->active_queries ? CSO_BIT_PAUSE_QUERIES : 0) |
229                         CSO_BITS_ALL_SHADERS));
230 
231    /* blend state: RGBA masking */
232    {
233       struct pipe_blend_state blend;
234       memset(&blend, 0, sizeof(blend));
235       if (clear_buffers & PIPE_CLEAR_COLOR) {
236          int num_buffers = ctx->Extensions.EXT_draw_buffers2 ?
237                            ctx->DrawBuffer->_NumColorDrawBuffers : 1;
238          int i;
239 
240          blend.independent_blend_enable = num_buffers > 1;
241          blend.max_rt = num_buffers - 1;
242 
243          for (i = 0; i < num_buffers; i++) {
244             if (!(clear_buffers & (PIPE_CLEAR_COLOR0 << i)))
245                continue;
246 
247             blend.rt[i].colormask = GET_COLORMASK(ctx->Color.ColorMask, i);
248          }
249 
250          if (ctx->Color.DitherFlag)
251             blend.dither = 1;
252       }
253       cso_set_blend(cso, &blend);
254    }
255 
256    /* depth_stencil state: always pass/set to ref value */
257    {
258       struct pipe_depth_stencil_alpha_state depth_stencil;
259       memset(&depth_stencil, 0, sizeof(depth_stencil));
260       if (clear_buffers & PIPE_CLEAR_DEPTH) {
261          depth_stencil.depth_enabled = 1;
262          depth_stencil.depth_writemask = 1;
263          depth_stencil.depth_func = PIPE_FUNC_ALWAYS;
264       }
265 
266       if (clear_buffers & PIPE_CLEAR_STENCIL) {
267          struct pipe_stencil_ref stencil_ref;
268          memset(&stencil_ref, 0, sizeof(stencil_ref));
269          depth_stencil.stencil[0].enabled = 1;
270          depth_stencil.stencil[0].func = PIPE_FUNC_ALWAYS;
271          depth_stencil.stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE;
272          depth_stencil.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE;
273          depth_stencil.stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE;
274          depth_stencil.stencil[0].valuemask = 0xff;
275          depth_stencil.stencil[0].writemask = ctx->Stencil.WriteMask[0] & 0xff;
276          stencil_ref.ref_value[0] = ctx->Stencil.Clear;
277          cso_set_stencil_ref(cso, stencil_ref);
278       }
279 
280       cso_set_depth_stencil_alpha(cso, &depth_stencil);
281    }
282 
283    st->util_velems.count = 1;
284    cso_set_vertex_elements(cso, &st->util_velems);
285 
286    cso_set_stream_outputs(cso, 0, NULL, NULL);
287    cso_set_sample_mask(cso, ~0);
288    cso_set_min_samples(cso, 1);
289    st->clear.raster.multisample = st->state.fb_num_samples > 1;
290    cso_set_rasterizer(cso, &st->clear.raster);
291 
292    /* viewport state: viewport matching window dims */
293    cso_set_viewport_dims(st->cso_context, fb_width, fb_height,
294                          _mesa_fb_orientation(fb) == Y_0_TOP);
295 
296    /* Set constant buffer */
297    set_clearcolor_fs(st, (union pipe_color_union*)&ctx->Color.ClearColor);
298    cso_set_tessctrl_shader_handle(cso, NULL);
299    cso_set_tesseval_shader_handle(cso, NULL);
300 
301    if (num_layers > 1)
302       set_vertex_shader_layered(st);
303    else
304       set_vertex_shader(st);
305 
306    /* draw quad matching scissor rect.
307     *
308     * Note: if we're only clearing depth/stencil we still setup vertices
309     * with color, but they'll be ignored.
310     *
311     * We can't translate the clear color to the colorbuffer format,
312     * because different colorbuffers may have different formats.
313     */
314    if (!st_draw_quad(st, x0, y0, x1, y1,
315                      ctx->Depth.Clear * 2.0f - 1.0f,
316                      0.0f, 0.0f, 0.0f, 0.0f,
317                      (const float *) &ctx->Color.ClearColor.f,
318                      num_layers)) {
319       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glClear");
320    }
321 
322    /* Restore pipe state */
323    cso_restore_state(cso, 0);
324    ctx->Array.NewVertexElements = true;
325    ctx->NewDriverState |= ST_NEW_VERTEX_ARRAYS |
326                           ST_NEW_FS_CONSTANTS;
327 }
328 
329 
330 /**
331  * Return if the scissor must be enabled during the clear.
332  */
333 static inline GLboolean
is_scissor_enabled(struct gl_context * ctx,struct gl_renderbuffer * rb)334 is_scissor_enabled(struct gl_context *ctx, struct gl_renderbuffer *rb)
335 {
336    const struct gl_scissor_rect *scissor = &ctx->Scissor.ScissorArray[0];
337 
338    return (ctx->Scissor.EnableFlags & 1) &&
339           (scissor->X > 0 ||
340            scissor->Y > 0 ||
341            scissor->X + scissor->Width < (int)rb->Width ||
342            scissor->Y + scissor->Height < (int)rb->Height);
343 }
344 
345 /**
346  * Return if window rectangles must be enabled during the clear.
347  */
348 static inline bool
is_window_rectangle_enabled(struct gl_context * ctx)349 is_window_rectangle_enabled(struct gl_context *ctx)
350 {
351    if (ctx->DrawBuffer == ctx->WinSysDrawBuffer)
352       return false;
353    return ctx->Scissor.NumWindowRects > 0 ||
354       ctx->Scissor.WindowRectMode == GL_INCLUSIVE_EXT;
355 }
356 
357 
358 /**
359  * Return if all of the stencil bits are masked.
360  */
361 static inline GLboolean
is_stencil_disabled(struct gl_context * ctx,struct gl_renderbuffer * rb)362 is_stencil_disabled(struct gl_context *ctx, struct gl_renderbuffer *rb)
363 {
364    const GLuint stencilMax = 0xff;
365 
366    assert(_mesa_get_format_bits(rb->Format, GL_STENCIL_BITS) > 0);
367    return (ctx->Stencil.WriteMask[0] & stencilMax) == 0;
368 }
369 
370 
371 /**
372  * Return if any of the stencil bits are masked.
373  */
374 static inline GLboolean
is_stencil_masked(struct gl_context * ctx,struct gl_renderbuffer * rb)375 is_stencil_masked(struct gl_context *ctx, struct gl_renderbuffer *rb)
376 {
377    const GLuint stencilMax = 0xff;
378 
379    assert(_mesa_get_format_bits(rb->Format, GL_STENCIL_BITS) > 0);
380    return (ctx->Stencil.WriteMask[0] & stencilMax) != stencilMax;
381 }
382 
383 void
st_Clear(struct gl_context * ctx,GLbitfield mask)384 st_Clear(struct gl_context *ctx, GLbitfield mask)
385 {
386    struct st_context *st = st_context(ctx);
387    struct gl_renderbuffer *depthRb
388       = ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
389    struct gl_renderbuffer *stencilRb
390       = ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
391    GLbitfield quad_buffers = 0x0;
392    GLbitfield clear_buffers = 0x0;
393    bool have_scissor_buffers = false;
394    GLuint i;
395 
396    st_flush_bitmap_cache(st);
397    st_invalidate_readpix_cache(st);
398 
399    /* This makes sure the pipe has the latest scissor, etc values */
400    st_validate_state(st, ST_PIPELINE_CLEAR_STATE_MASK);
401 
402    if (mask & BUFFER_BITS_COLOR) {
403       for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) {
404          gl_buffer_index b = ctx->DrawBuffer->_ColorDrawBufferIndexes[i];
405 
406          if (b != BUFFER_NONE && mask & (1 << b)) {
407             struct gl_renderbuffer *rb
408                = ctx->DrawBuffer->Attachment[b].Renderbuffer;
409             int colormask_index = ctx->Extensions.EXT_draw_buffers2 ? i : 0;
410 
411             if (!rb || !rb->surface)
412                continue;
413 
414             unsigned colormask =
415                GET_COLORMASK(ctx->Color.ColorMask, colormask_index);
416 
417             if (!colormask)
418                continue;
419 
420             unsigned surf_colormask =
421                util_format_colormask(util_format_description(rb->surface->format));
422 
423             bool scissor = is_scissor_enabled(ctx, rb);
424             if ((scissor && !st->can_scissor_clear) ||
425                 is_window_rectangle_enabled(ctx) ||
426                 ((colormask & surf_colormask) != surf_colormask))
427                quad_buffers |= PIPE_CLEAR_COLOR0 << i;
428             else
429                clear_buffers |= PIPE_CLEAR_COLOR0 << i;
430             have_scissor_buffers |= scissor && st->can_scissor_clear;
431          }
432       }
433    }
434 
435    if (mask & BUFFER_BIT_DEPTH) {
436       if (depthRb->surface && ctx->Depth.Mask) {
437          bool scissor = is_scissor_enabled(ctx, depthRb);
438          if ((scissor && !st->can_scissor_clear) ||
439              is_window_rectangle_enabled(ctx))
440             quad_buffers |= PIPE_CLEAR_DEPTH;
441          else
442             clear_buffers |= PIPE_CLEAR_DEPTH;
443          have_scissor_buffers |= scissor && st->can_scissor_clear;
444       }
445    }
446    if (mask & BUFFER_BIT_STENCIL) {
447       if (stencilRb->surface && !is_stencil_disabled(ctx, stencilRb)) {
448          bool scissor = is_scissor_enabled(ctx, stencilRb);
449          if ((scissor && !st->can_scissor_clear) ||
450              is_window_rectangle_enabled(ctx) ||
451              is_stencil_masked(ctx, stencilRb))
452             quad_buffers |= PIPE_CLEAR_STENCIL;
453          else
454             clear_buffers |= PIPE_CLEAR_STENCIL;
455          have_scissor_buffers |= scissor && st->can_scissor_clear;
456       }
457    }
458 
459    /* Always clear depth and stencil together.
460     * This can only happen when the stencil writemask is not a full mask.
461     */
462    if (quad_buffers & PIPE_CLEAR_DEPTHSTENCIL &&
463        clear_buffers & PIPE_CLEAR_DEPTHSTENCIL) {
464       quad_buffers |= clear_buffers & PIPE_CLEAR_DEPTHSTENCIL;
465       clear_buffers &= ~PIPE_CLEAR_DEPTHSTENCIL;
466    }
467 
468    /* Only use quad-based clearing for the renderbuffers which cannot
469     * use pipe->clear. We want to always use pipe->clear for the other
470     * renderbuffers, because it's likely to be faster.
471     */
472    if (clear_buffers) {
473       const struct gl_scissor_rect *scissor = &ctx->Scissor.ScissorArray[0];
474       struct pipe_scissor_state scissor_state = {
475          .minx = MAX2(scissor->X, 0),
476          .miny = MAX2(scissor->Y, 0),
477          .maxx = MAX2(scissor->X + scissor->Width, 0),
478          .maxy = MAX2(scissor->Y + scissor->Height, 0),
479 
480       };
481 
482       /* Now invert Y if needed.
483        * Gallium drivers use the convention Y=0=top for surfaces.
484        */
485       if (st->state.fb_orientation == Y_0_TOP) {
486          const struct gl_framebuffer *fb = ctx->DrawBuffer;
487          /* use intermediate variables to avoid uint underflow */
488          GLint miny, maxy;
489          miny = fb->Height - scissor_state.maxy;
490          maxy = fb->Height - scissor_state.miny;
491          scissor_state.miny = MAX2(miny, 0);
492          scissor_state.maxy = MAX2(maxy, 0);
493       }
494       if (have_scissor_buffers) {
495          const struct gl_framebuffer *fb = ctx->DrawBuffer;
496          scissor_state.maxx = MIN2(scissor_state.maxx, fb->Width);
497          scissor_state.maxy = MIN2(scissor_state.maxy, fb->Height);
498          if (scissor_state.minx >= scissor_state.maxx ||
499              scissor_state.miny >= scissor_state.maxy)
500             return;
501       }
502       /* We can't translate the clear color to the colorbuffer format,
503        * because different colorbuffers may have different formats.
504        */
505       st->pipe->clear(st->pipe, clear_buffers, have_scissor_buffers ? &scissor_state : NULL,
506                       (union pipe_color_union*)&ctx->Color.ClearColor,
507                       ctx->Depth.Clear, ctx->Stencil.Clear);
508    }
509    if (quad_buffers) {
510       clear_with_quad(ctx, quad_buffers);
511    }
512    if (mask & BUFFER_BIT_ACCUM)
513       _mesa_clear_accum_buffer(ctx);
514 }
515 
516