xref: /aosp_15_r20/external/mesa3d/src/freedreno/vulkan/tu_lrz.cc (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker  * Copyright © 2022 Igalia S.L.
3*61046927SAndroid Build Coastguard Worker  * SPDX-License-Identifier: MIT
4*61046927SAndroid Build Coastguard Worker  */
5*61046927SAndroid Build Coastguard Worker 
6*61046927SAndroid Build Coastguard Worker #include "tu_lrz.h"
7*61046927SAndroid Build Coastguard Worker 
8*61046927SAndroid Build Coastguard Worker #include "tu_clear_blit.h"
9*61046927SAndroid Build Coastguard Worker #include "tu_cmd_buffer.h"
10*61046927SAndroid Build Coastguard Worker #include "tu_cs.h"
11*61046927SAndroid Build Coastguard Worker #include "tu_image.h"
12*61046927SAndroid Build Coastguard Worker 
13*61046927SAndroid Build Coastguard Worker #include "common/freedreno_gpu_event.h"
14*61046927SAndroid Build Coastguard Worker #include "common/freedreno_lrz.h"
15*61046927SAndroid Build Coastguard Worker 
16*61046927SAndroid Build Coastguard Worker /* See lrz.rst for how HW works. Here are only the implementation notes.
17*61046927SAndroid Build Coastguard Worker  *
18*61046927SAndroid Build Coastguard Worker  * There are a number of limitations when LRZ cannot be used:
19*61046927SAndroid Build Coastguard Worker  * - Fragment shader side-effects (writing to SSBOs, atomic operations, etc);
20*61046927SAndroid Build Coastguard Worker  * - Writing to stencil buffer
21*61046927SAndroid Build Coastguard Worker  * - Writing depth while:
22*61046927SAndroid Build Coastguard Worker  *   - Changing direction of depth test (e.g. from OP_GREATER to OP_LESS);
23*61046927SAndroid Build Coastguard Worker  *   - Using OP_ALWAYS or OP_NOT_EQUAL;
24*61046927SAndroid Build Coastguard Worker  * - Clearing depth with vkCmdClearAttachments;
25*61046927SAndroid Build Coastguard Worker  * - (pre-a650) Not clearing depth attachment with LOAD_OP_CLEAR;
26*61046927SAndroid Build Coastguard Worker  * - (pre-a650) Using secondary command buffers;
27*61046927SAndroid Build Coastguard Worker  * - Sysmem rendering (with small caveat).
28*61046927SAndroid Build Coastguard Worker  *
29*61046927SAndroid Build Coastguard Worker  * A650+ (gen3+)
30*61046927SAndroid Build Coastguard Worker  * =============
31*61046927SAndroid Build Coastguard Worker  *
32*61046927SAndroid Build Coastguard Worker  * While LRZ could be reused between renderpasses LRZ, it is disabled when
33*61046927SAndroid Build Coastguard Worker  * underlying depth buffer is changed.
34*61046927SAndroid Build Coastguard Worker  * The following commands could change a depth image:
35*61046927SAndroid Build Coastguard Worker  * - vkCmdBlitImage*
36*61046927SAndroid Build Coastguard Worker  * - vkCmdCopyBufferToImage*
37*61046927SAndroid Build Coastguard Worker  * - vkCmdCopyImage*
38*61046927SAndroid Build Coastguard Worker  *
39*61046927SAndroid Build Coastguard Worker  * LRZ Fast-Clear
40*61046927SAndroid Build Coastguard Worker  * ==============
41*61046927SAndroid Build Coastguard Worker  *
42*61046927SAndroid Build Coastguard Worker  * It's always valid to fast-clear. On the other hand we disable
43*61046927SAndroid Build Coastguard Worker  * fast-clear if depth clear value is not 0.0 or 1.0 because it may be worse
44*61046927SAndroid Build Coastguard Worker  * for perf if some primitives are expected to fail depth test against the
45*61046927SAndroid Build Coastguard Worker  * actual depth clear value.
46*61046927SAndroid Build Coastguard Worker  *
47*61046927SAndroid Build Coastguard Worker  * LRZ Caches
48*61046927SAndroid Build Coastguard Worker  * ==========
49*61046927SAndroid Build Coastguard Worker  *
50*61046927SAndroid Build Coastguard Worker  * ! The policy here is to flush LRZ cache right after it is changed,
51*61046927SAndroid Build Coastguard Worker  * so if LRZ data is needed afterwards - there is no need to flush it
52*61046927SAndroid Build Coastguard Worker  * before using LRZ.
53*61046927SAndroid Build Coastguard Worker  */
54*61046927SAndroid Build Coastguard Worker 
55*61046927SAndroid Build Coastguard Worker static inline void
tu_lrz_disable_reason(struct tu_cmd_buffer * cmd,const char * reason)56*61046927SAndroid Build Coastguard Worker tu_lrz_disable_reason(struct tu_cmd_buffer *cmd, const char *reason) {
57*61046927SAndroid Build Coastguard Worker    cmd->state.rp.lrz_disable_reason = reason;
58*61046927SAndroid Build Coastguard Worker    perf_debug(cmd->device, "Disabling LRZ because '%s'", reason);
59*61046927SAndroid Build Coastguard Worker }
60*61046927SAndroid Build Coastguard Worker 
61*61046927SAndroid Build Coastguard Worker template <chip CHIP>
62*61046927SAndroid Build Coastguard Worker static void
tu6_emit_lrz_buffer(struct tu_cs * cs,struct tu_image * depth_image)63*61046927SAndroid Build Coastguard Worker tu6_emit_lrz_buffer(struct tu_cs *cs, struct tu_image *depth_image)
64*61046927SAndroid Build Coastguard Worker {
65*61046927SAndroid Build Coastguard Worker    if (!depth_image) {
66*61046927SAndroid Build Coastguard Worker       tu_cs_emit_regs(cs,
67*61046927SAndroid Build Coastguard Worker                       A6XX_GRAS_LRZ_BUFFER_BASE(0),
68*61046927SAndroid Build Coastguard Worker                       A6XX_GRAS_LRZ_BUFFER_PITCH(0),
69*61046927SAndroid Build Coastguard Worker                       A6XX_GRAS_LRZ_FAST_CLEAR_BUFFER_BASE(0));
70*61046927SAndroid Build Coastguard Worker 
71*61046927SAndroid Build Coastguard Worker       if (CHIP >= A7XX)
72*61046927SAndroid Build Coastguard Worker          tu_cs_emit_regs(cs, A7XX_GRAS_LRZ_DEPTH_BUFFER_INFO());
73*61046927SAndroid Build Coastguard Worker 
74*61046927SAndroid Build Coastguard Worker       return;
75*61046927SAndroid Build Coastguard Worker    }
76*61046927SAndroid Build Coastguard Worker 
77*61046927SAndroid Build Coastguard Worker    uint64_t lrz_iova = depth_image->iova + depth_image->lrz_offset;
78*61046927SAndroid Build Coastguard Worker    uint64_t lrz_fc_iova = depth_image->iova + depth_image->lrz_fc_offset;
79*61046927SAndroid Build Coastguard Worker    if (!depth_image->lrz_fc_offset)
80*61046927SAndroid Build Coastguard Worker       lrz_fc_iova = 0;
81*61046927SAndroid Build Coastguard Worker 
82*61046927SAndroid Build Coastguard Worker    tu_cs_emit_regs(cs,
83*61046927SAndroid Build Coastguard Worker                    A6XX_GRAS_LRZ_BUFFER_BASE(.qword = lrz_iova),
84*61046927SAndroid Build Coastguard Worker                    A6XX_GRAS_LRZ_BUFFER_PITCH(.pitch = depth_image->lrz_pitch),
85*61046927SAndroid Build Coastguard Worker                    A6XX_GRAS_LRZ_FAST_CLEAR_BUFFER_BASE(.qword = lrz_fc_iova));
86*61046927SAndroid Build Coastguard Worker 
87*61046927SAndroid Build Coastguard Worker    if (CHIP >= A7XX) {
88*61046927SAndroid Build Coastguard Worker       tu_cs_emit_regs(cs, A7XX_GRAS_LRZ_DEPTH_BUFFER_INFO(
89*61046927SAndroid Build Coastguard Worker          .depth_format = tu6_pipe2depth(depth_image->vk.format)
90*61046927SAndroid Build Coastguard Worker       ));
91*61046927SAndroid Build Coastguard Worker    }
92*61046927SAndroid Build Coastguard Worker }
93*61046927SAndroid Build Coastguard Worker 
94*61046927SAndroid Build Coastguard Worker static void
tu6_write_lrz_reg(struct tu_cmd_buffer * cmd,struct tu_cs * cs,struct tu_reg_value reg)95*61046927SAndroid Build Coastguard Worker tu6_write_lrz_reg(struct tu_cmd_buffer *cmd, struct tu_cs *cs,
96*61046927SAndroid Build Coastguard Worker                   struct tu_reg_value reg)
97*61046927SAndroid Build Coastguard Worker {
98*61046927SAndroid Build Coastguard Worker    if (cmd->device->physical_device->info->a6xx.lrz_track_quirk) {
99*61046927SAndroid Build Coastguard Worker       tu_cs_emit_pkt7(cs, CP_REG_WRITE, 3);
100*61046927SAndroid Build Coastguard Worker       tu_cs_emit(cs, CP_REG_WRITE_0_TRACKER(TRACK_LRZ));
101*61046927SAndroid Build Coastguard Worker       tu_cs_emit(cs, reg.reg);
102*61046927SAndroid Build Coastguard Worker       tu_cs_emit(cs, reg.value);
103*61046927SAndroid Build Coastguard Worker    } else {
104*61046927SAndroid Build Coastguard Worker       tu_cs_emit_pkt4(cs, reg.reg, 1);
105*61046927SAndroid Build Coastguard Worker       tu_cs_emit(cs, reg.value);
106*61046927SAndroid Build Coastguard Worker    }
107*61046927SAndroid Build Coastguard Worker }
108*61046927SAndroid Build Coastguard Worker 
109*61046927SAndroid Build Coastguard Worker template <chip CHIP>
110*61046927SAndroid Build Coastguard Worker static void
tu6_write_lrz_cntl(struct tu_cmd_buffer * cmd,struct tu_cs * cs,struct A6XX_GRAS_LRZ_CNTL cntl)111*61046927SAndroid Build Coastguard Worker tu6_write_lrz_cntl(struct tu_cmd_buffer *cmd, struct tu_cs *cs,
112*61046927SAndroid Build Coastguard Worker                    struct A6XX_GRAS_LRZ_CNTL cntl)
113*61046927SAndroid Build Coastguard Worker {
114*61046927SAndroid Build Coastguard Worker    if (CHIP >= A7XX) {
115*61046927SAndroid Build Coastguard Worker       // A7XX split LRZ_CNTL into two seperate registers.
116*61046927SAndroid Build Coastguard Worker       struct tu_reg_value cntl2 = A7XX_GRAS_LRZ_CNTL2(
117*61046927SAndroid Build Coastguard Worker          .disable_on_wrong_dir = cntl.disable_on_wrong_dir,
118*61046927SAndroid Build Coastguard Worker          .fc_enable = cntl.fc_enable,
119*61046927SAndroid Build Coastguard Worker       );
120*61046927SAndroid Build Coastguard Worker       cntl.disable_on_wrong_dir = false;
121*61046927SAndroid Build Coastguard Worker       cntl.fc_enable = false;
122*61046927SAndroid Build Coastguard Worker 
123*61046927SAndroid Build Coastguard Worker       tu6_write_lrz_reg(cmd, cs, A6XX_GRAS_LRZ_CNTL(cntl));
124*61046927SAndroid Build Coastguard Worker       tu6_write_lrz_reg(cmd, cs, cntl2);
125*61046927SAndroid Build Coastguard Worker    } else {
126*61046927SAndroid Build Coastguard Worker       tu6_write_lrz_reg(cmd, cs, A6XX_GRAS_LRZ_CNTL(cntl));
127*61046927SAndroid Build Coastguard Worker    }
128*61046927SAndroid Build Coastguard Worker }
129*61046927SAndroid Build Coastguard Worker 
130*61046927SAndroid Build Coastguard Worker template <chip CHIP>
131*61046927SAndroid Build Coastguard Worker static void
tu6_disable_lrz_via_depth_view(struct tu_cmd_buffer * cmd,struct tu_cs * cs)132*61046927SAndroid Build Coastguard Worker tu6_disable_lrz_via_depth_view(struct tu_cmd_buffer *cmd, struct tu_cs *cs)
133*61046927SAndroid Build Coastguard Worker {
134*61046927SAndroid Build Coastguard Worker    /* Disable direction by writing invalid depth view. */
135*61046927SAndroid Build Coastguard Worker    tu6_write_lrz_reg(cmd, cs, A6XX_GRAS_LRZ_DEPTH_VIEW(
136*61046927SAndroid Build Coastguard Worker       .base_layer = 0b11111111111,
137*61046927SAndroid Build Coastguard Worker       .layer_count = 0b11111111111,
138*61046927SAndroid Build Coastguard Worker       .base_mip_level = 0b1111,
139*61046927SAndroid Build Coastguard Worker    ));
140*61046927SAndroid Build Coastguard Worker 
141*61046927SAndroid Build Coastguard Worker    tu6_write_lrz_cntl<CHIP>(cmd, cs, {
142*61046927SAndroid Build Coastguard Worker       .enable = true,
143*61046927SAndroid Build Coastguard Worker       .disable_on_wrong_dir = true,
144*61046927SAndroid Build Coastguard Worker    });
145*61046927SAndroid Build Coastguard Worker 
146*61046927SAndroid Build Coastguard Worker    tu_emit_event_write<A6XX>(cmd, cs, FD_LRZ_CLEAR);
147*61046927SAndroid Build Coastguard Worker    tu_emit_event_write<A6XX>(cmd, cs, FD_LRZ_FLUSH);
148*61046927SAndroid Build Coastguard Worker }
149*61046927SAndroid Build Coastguard Worker 
150*61046927SAndroid Build Coastguard Worker static void
tu_lrz_init_state(struct tu_cmd_buffer * cmd,const struct tu_render_pass_attachment * att,const struct tu_image_view * view)151*61046927SAndroid Build Coastguard Worker tu_lrz_init_state(struct tu_cmd_buffer *cmd,
152*61046927SAndroid Build Coastguard Worker                   const struct tu_render_pass_attachment *att,
153*61046927SAndroid Build Coastguard Worker                   const struct tu_image_view *view)
154*61046927SAndroid Build Coastguard Worker {
155*61046927SAndroid Build Coastguard Worker    if (!view->image->lrz_height) {
156*61046927SAndroid Build Coastguard Worker       assert(!cmd->device->use_lrz || !vk_format_has_depth(att->format));
157*61046927SAndroid Build Coastguard Worker       return;
158*61046927SAndroid Build Coastguard Worker    }
159*61046927SAndroid Build Coastguard Worker 
160*61046927SAndroid Build Coastguard Worker    bool clears_depth = att->clear_mask &
161*61046927SAndroid Build Coastguard Worker       (VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT);
162*61046927SAndroid Build Coastguard Worker    bool has_gpu_tracking =
163*61046927SAndroid Build Coastguard Worker       cmd->device->physical_device->info->a6xx.has_lrz_dir_tracking;
164*61046927SAndroid Build Coastguard Worker 
165*61046927SAndroid Build Coastguard Worker    if (!has_gpu_tracking && !clears_depth)
166*61046927SAndroid Build Coastguard Worker       return;
167*61046927SAndroid Build Coastguard Worker 
168*61046927SAndroid Build Coastguard Worker    /* We need to always have an LRZ view just to disable it if there is a
169*61046927SAndroid Build Coastguard Worker     * depth attachment, there are any secondaries, and GPU tracking is
170*61046927SAndroid Build Coastguard Worker     * enabled, in order not to rely on loadOp state which doesn't exist with
171*61046927SAndroid Build Coastguard Worker     * dynamic rendering in secondaries. Otherwise the secondary will have LRZ
172*61046927SAndroid Build Coastguard Worker     * enabled and there will be a NULL/garbage LRZ buffer.
173*61046927SAndroid Build Coastguard Worker     */
174*61046927SAndroid Build Coastguard Worker    cmd->state.lrz.image_view = view;
175*61046927SAndroid Build Coastguard Worker 
176*61046927SAndroid Build Coastguard Worker    if (!clears_depth && !att->load)
177*61046927SAndroid Build Coastguard Worker       return;
178*61046927SAndroid Build Coastguard Worker 
179*61046927SAndroid Build Coastguard Worker    cmd->state.lrz.valid = true;
180*61046927SAndroid Build Coastguard Worker    cmd->state.lrz.prev_direction = TU_LRZ_UNKNOWN;
181*61046927SAndroid Build Coastguard Worker    /* Be optimistic and unconditionally enable fast-clear in
182*61046927SAndroid Build Coastguard Worker     * secondary cmdbufs and when reusing previous LRZ state.
183*61046927SAndroid Build Coastguard Worker     */
184*61046927SAndroid Build Coastguard Worker    cmd->state.lrz.fast_clear = view->image->has_lrz_fc;
185*61046927SAndroid Build Coastguard Worker 
186*61046927SAndroid Build Coastguard Worker    cmd->state.lrz.gpu_dir_tracking = has_gpu_tracking;
187*61046927SAndroid Build Coastguard Worker    cmd->state.lrz.reuse_previous_state = !clears_depth;
188*61046927SAndroid Build Coastguard Worker }
189*61046927SAndroid Build Coastguard Worker 
190*61046927SAndroid Build Coastguard Worker /* Note: if we enable LRZ here, then tu_lrz_init_state() must at least set
191*61046927SAndroid Build Coastguard Worker  * lrz.image_view, so that an LRZ buffer is present (even if LRZ is
192*61046927SAndroid Build Coastguard Worker  * dynamically disabled).
193*61046927SAndroid Build Coastguard Worker  */
194*61046927SAndroid Build Coastguard Worker 
195*61046927SAndroid Build Coastguard Worker static void
tu_lrz_init_secondary(struct tu_cmd_buffer * cmd,const struct tu_render_pass_attachment * att)196*61046927SAndroid Build Coastguard Worker tu_lrz_init_secondary(struct tu_cmd_buffer *cmd,
197*61046927SAndroid Build Coastguard Worker                       const struct tu_render_pass_attachment *att)
198*61046927SAndroid Build Coastguard Worker {
199*61046927SAndroid Build Coastguard Worker    bool has_gpu_tracking =
200*61046927SAndroid Build Coastguard Worker       cmd->device->physical_device->info->a6xx.has_lrz_dir_tracking;
201*61046927SAndroid Build Coastguard Worker 
202*61046927SAndroid Build Coastguard Worker    if (!has_gpu_tracking)
203*61046927SAndroid Build Coastguard Worker       return;
204*61046927SAndroid Build Coastguard Worker 
205*61046927SAndroid Build Coastguard Worker    if (!cmd->device->use_lrz)
206*61046927SAndroid Build Coastguard Worker       return;
207*61046927SAndroid Build Coastguard Worker 
208*61046927SAndroid Build Coastguard Worker    if (!vk_format_has_depth(att->format))
209*61046927SAndroid Build Coastguard Worker       return;
210*61046927SAndroid Build Coastguard Worker 
211*61046927SAndroid Build Coastguard Worker    cmd->state.lrz.valid = true;
212*61046927SAndroid Build Coastguard Worker    cmd->state.lrz.prev_direction = TU_LRZ_UNKNOWN;
213*61046927SAndroid Build Coastguard Worker    cmd->state.lrz.gpu_dir_tracking = has_gpu_tracking;
214*61046927SAndroid Build Coastguard Worker 
215*61046927SAndroid Build Coastguard Worker    /* We may not have the depth attachment when executing in a secondary
216*61046927SAndroid Build Coastguard Worker     * inside a render pass. This means we have to be even more optimistic than
217*61046927SAndroid Build Coastguard Worker     * the normal case and enable fast clear even if the depth image doesn't
218*61046927SAndroid Build Coastguard Worker     * support it.
219*61046927SAndroid Build Coastguard Worker     */
220*61046927SAndroid Build Coastguard Worker    cmd->state.lrz.fast_clear = true;
221*61046927SAndroid Build Coastguard Worker 
222*61046927SAndroid Build Coastguard Worker    /* These are not used inside secondaries */
223*61046927SAndroid Build Coastguard Worker    cmd->state.lrz.image_view = NULL;
224*61046927SAndroid Build Coastguard Worker    cmd->state.lrz.reuse_previous_state = false;
225*61046927SAndroid Build Coastguard Worker }
226*61046927SAndroid Build Coastguard Worker 
227*61046927SAndroid Build Coastguard Worker template <chip CHIP>
228*61046927SAndroid Build Coastguard Worker bool
tu_lrzfc_depth_supported(float depth)229*61046927SAndroid Build Coastguard Worker tu_lrzfc_depth_supported(float depth) {
230*61046927SAndroid Build Coastguard Worker    /* A7XX supports fast-clearing to any value, while A6XX only supports 0.0/1.0 */
231*61046927SAndroid Build Coastguard Worker    return CHIP >= A7XX || depth == 0.0f || depth == 1.0f;
232*61046927SAndroid Build Coastguard Worker }
233*61046927SAndroid Build Coastguard Worker 
234*61046927SAndroid Build Coastguard Worker /* This is generally the same as tu_lrz_begin_renderpass(), but we skip
235*61046927SAndroid Build Coastguard Worker  * actually emitting anything. The lrz state needs to be consistent between
236*61046927SAndroid Build Coastguard Worker  * renderpasses, but only the first should actually emit commands to disable
237*61046927SAndroid Build Coastguard Worker  * lrz etc.
238*61046927SAndroid Build Coastguard Worker  */
239*61046927SAndroid Build Coastguard Worker template <chip CHIP>
240*61046927SAndroid Build Coastguard Worker void
tu_lrz_begin_resumed_renderpass(struct tu_cmd_buffer * cmd)241*61046927SAndroid Build Coastguard Worker tu_lrz_begin_resumed_renderpass(struct tu_cmd_buffer *cmd)
242*61046927SAndroid Build Coastguard Worker {
243*61046927SAndroid Build Coastguard Worker     /* Track LRZ valid state */
244*61046927SAndroid Build Coastguard Worker    memset(&cmd->state.lrz, 0, sizeof(cmd->state.lrz));
245*61046927SAndroid Build Coastguard Worker 
246*61046927SAndroid Build Coastguard Worker    uint32_t a;
247*61046927SAndroid Build Coastguard Worker    for (a = 0; a < cmd->state.pass->attachment_count; a++) {
248*61046927SAndroid Build Coastguard Worker       if (cmd->state.attachments[a]->image->lrz_height)
249*61046927SAndroid Build Coastguard Worker          break;
250*61046927SAndroid Build Coastguard Worker    }
251*61046927SAndroid Build Coastguard Worker 
252*61046927SAndroid Build Coastguard Worker    if (a != cmd->state.pass->attachment_count) {
253*61046927SAndroid Build Coastguard Worker       const struct tu_render_pass_attachment *att = &cmd->state.pass->attachments[a];
254*61046927SAndroid Build Coastguard Worker       tu_lrz_init_state(cmd, att, cmd->state.attachments[a]);
255*61046927SAndroid Build Coastguard Worker       if (att->clear_mask & (VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT)) {
256*61046927SAndroid Build Coastguard Worker          VkClearValue clear = cmd->state.clear_values[a];
257*61046927SAndroid Build Coastguard Worker          cmd->state.lrz.depth_clear_value = clear;
258*61046927SAndroid Build Coastguard Worker          cmd->state.lrz.fast_clear = cmd->state.lrz.fast_clear &&
259*61046927SAndroid Build Coastguard Worker                                      tu_lrzfc_depth_supported<CHIP>(clear.depthStencil.depth);
260*61046927SAndroid Build Coastguard Worker       }
261*61046927SAndroid Build Coastguard Worker       cmd->state.dirty |= TU_CMD_DIRTY_LRZ;
262*61046927SAndroid Build Coastguard Worker    }
263*61046927SAndroid Build Coastguard Worker }
264*61046927SAndroid Build Coastguard Worker TU_GENX(tu_lrz_begin_resumed_renderpass);
265*61046927SAndroid Build Coastguard Worker 
266*61046927SAndroid Build Coastguard Worker template <chip CHIP>
267*61046927SAndroid Build Coastguard Worker void
tu_lrz_begin_renderpass(struct tu_cmd_buffer * cmd)268*61046927SAndroid Build Coastguard Worker tu_lrz_begin_renderpass(struct tu_cmd_buffer *cmd)
269*61046927SAndroid Build Coastguard Worker {
270*61046927SAndroid Build Coastguard Worker    const struct tu_render_pass *pass = cmd->state.pass;
271*61046927SAndroid Build Coastguard Worker 
272*61046927SAndroid Build Coastguard Worker    cmd->state.rp.lrz_disable_reason = "";
273*61046927SAndroid Build Coastguard Worker 
274*61046927SAndroid Build Coastguard Worker    int lrz_img_count = 0;
275*61046927SAndroid Build Coastguard Worker    for (unsigned i = 0; i < pass->attachment_count; i++) {
276*61046927SAndroid Build Coastguard Worker       if (cmd->state.attachments[i]->image->lrz_height)
277*61046927SAndroid Build Coastguard Worker          lrz_img_count++;
278*61046927SAndroid Build Coastguard Worker    }
279*61046927SAndroid Build Coastguard Worker 
280*61046927SAndroid Build Coastguard Worker    if (cmd->device->physical_device->info->a6xx.has_lrz_dir_tracking &&
281*61046927SAndroid Build Coastguard Worker        cmd->state.pass->subpass_count > 1 && lrz_img_count > 1) {
282*61046927SAndroid Build Coastguard Worker       /* Theoretically we could switch between LRZ buffers during the binning
283*61046927SAndroid Build Coastguard Worker        * and tiling passes, but it is untested and would add complexity for
284*61046927SAndroid Build Coastguard Worker        * presumably extremely rare case.
285*61046927SAndroid Build Coastguard Worker        */
286*61046927SAndroid Build Coastguard Worker       tu_lrz_disable_reason(cmd, "Several subpasses with different depth attachments");
287*61046927SAndroid Build Coastguard Worker 
288*61046927SAndroid Build Coastguard Worker       for (unsigned i = 0; i < pass->attachment_count; i++) {
289*61046927SAndroid Build Coastguard Worker          struct tu_image *image = cmd->state.attachments[i]->image;
290*61046927SAndroid Build Coastguard Worker          tu_disable_lrz<CHIP>(cmd, &cmd->cs, image);
291*61046927SAndroid Build Coastguard Worker       }
292*61046927SAndroid Build Coastguard Worker 
293*61046927SAndroid Build Coastguard Worker       /* We need a valid LRZ fast-clear base, in case the render pass contents
294*61046927SAndroid Build Coastguard Worker        * are in secondaries that enable LRZ, so that they can read that LRZ is
295*61046927SAndroid Build Coastguard Worker        * dynamically disabled. It doesn't matter which we use, so just leave
296*61046927SAndroid Build Coastguard Worker        * the last one as emitted in tu_disable_lrz().
297*61046927SAndroid Build Coastguard Worker        */
298*61046927SAndroid Build Coastguard Worker       memset(&cmd->state.lrz, 0, sizeof(cmd->state.lrz));
299*61046927SAndroid Build Coastguard Worker       return;
300*61046927SAndroid Build Coastguard Worker    }
301*61046927SAndroid Build Coastguard Worker 
302*61046927SAndroid Build Coastguard Worker     /* Track LRZ valid state */
303*61046927SAndroid Build Coastguard Worker    tu_lrz_begin_resumed_renderpass<CHIP>(cmd);
304*61046927SAndroid Build Coastguard Worker 
305*61046927SAndroid Build Coastguard Worker    if (!cmd->state.lrz.valid) {
306*61046927SAndroid Build Coastguard Worker       tu6_emit_lrz_buffer<CHIP>(&cmd->cs, NULL);
307*61046927SAndroid Build Coastguard Worker    }
308*61046927SAndroid Build Coastguard Worker }
309*61046927SAndroid Build Coastguard Worker TU_GENX(tu_lrz_begin_renderpass);
310*61046927SAndroid Build Coastguard Worker 
311*61046927SAndroid Build Coastguard Worker void
tu_lrz_begin_secondary_cmdbuf(struct tu_cmd_buffer * cmd)312*61046927SAndroid Build Coastguard Worker tu_lrz_begin_secondary_cmdbuf(struct tu_cmd_buffer *cmd)
313*61046927SAndroid Build Coastguard Worker {
314*61046927SAndroid Build Coastguard Worker    memset(&cmd->state.lrz, 0, sizeof(cmd->state.lrz));
315*61046927SAndroid Build Coastguard Worker    uint32_t a = cmd->state.subpass->depth_stencil_attachment.attachment;
316*61046927SAndroid Build Coastguard Worker    if (a != VK_ATTACHMENT_UNUSED) {
317*61046927SAndroid Build Coastguard Worker       const struct tu_render_pass_attachment *att = &cmd->state.pass->attachments[a];
318*61046927SAndroid Build Coastguard Worker       tu_lrz_init_secondary(cmd, att);
319*61046927SAndroid Build Coastguard Worker    }
320*61046927SAndroid Build Coastguard Worker }
321*61046927SAndroid Build Coastguard Worker 
322*61046927SAndroid Build Coastguard Worker template <chip CHIP>
323*61046927SAndroid Build Coastguard Worker void
tu_lrz_tiling_begin(struct tu_cmd_buffer * cmd,struct tu_cs * cs)324*61046927SAndroid Build Coastguard Worker tu_lrz_tiling_begin(struct tu_cmd_buffer *cmd, struct tu_cs *cs)
325*61046927SAndroid Build Coastguard Worker {
326*61046927SAndroid Build Coastguard Worker    /* TODO: If lrz was never valid for the entire renderpass, we could exit
327*61046927SAndroid Build Coastguard Worker     * early here. Sometimes we know this ahead of time and null out
328*61046927SAndroid Build Coastguard Worker     * image_view, but with LOAD_OP_DONT_CARE this only happens if there were
329*61046927SAndroid Build Coastguard Worker     * no secondaries.
330*61046927SAndroid Build Coastguard Worker     */
331*61046927SAndroid Build Coastguard Worker    if (!cmd->state.lrz.image_view)
332*61046927SAndroid Build Coastguard Worker       return;
333*61046927SAndroid Build Coastguard Worker 
334*61046927SAndroid Build Coastguard Worker    struct tu_lrz_state *lrz = &cmd->state.lrz;
335*61046927SAndroid Build Coastguard Worker 
336*61046927SAndroid Build Coastguard Worker    tu6_emit_lrz_buffer<CHIP>(cs, lrz->image_view->image);
337*61046927SAndroid Build Coastguard Worker 
338*61046927SAndroid Build Coastguard Worker    if (lrz->reuse_previous_state) {
339*61046927SAndroid Build Coastguard Worker       /* Reuse previous LRZ state, LRZ cache is assumed to be
340*61046927SAndroid Build Coastguard Worker        * already invalidated by previous renderpass.
341*61046927SAndroid Build Coastguard Worker        */
342*61046927SAndroid Build Coastguard Worker       assert(lrz->gpu_dir_tracking);
343*61046927SAndroid Build Coastguard Worker 
344*61046927SAndroid Build Coastguard Worker       tu6_write_lrz_reg(cmd, cs,
345*61046927SAndroid Build Coastguard Worker          A6XX_GRAS_LRZ_DEPTH_VIEW(.dword = lrz->image_view->view.GRAS_LRZ_DEPTH_VIEW));
346*61046927SAndroid Build Coastguard Worker       return;
347*61046927SAndroid Build Coastguard Worker    }
348*61046927SAndroid Build Coastguard Worker 
349*61046927SAndroid Build Coastguard Worker    bool invalidate_lrz = !lrz->valid && lrz->gpu_dir_tracking;
350*61046927SAndroid Build Coastguard Worker    if (invalidate_lrz) {
351*61046927SAndroid Build Coastguard Worker       /* Following the blob we elect to disable LRZ for the whole renderpass
352*61046927SAndroid Build Coastguard Worker        * if it is known that LRZ is disabled somewhere in the renderpass.
353*61046927SAndroid Build Coastguard Worker        *
354*61046927SAndroid Build Coastguard Worker        * This is accomplished by making later GRAS_LRZ_CNTL (in binning pass)
355*61046927SAndroid Build Coastguard Worker        * to fail the comparison of depth views.
356*61046927SAndroid Build Coastguard Worker        */
357*61046927SAndroid Build Coastguard Worker       tu6_disable_lrz_via_depth_view<CHIP>(cmd, cs);
358*61046927SAndroid Build Coastguard Worker       tu6_write_lrz_reg(cmd, cs, A6XX_GRAS_LRZ_DEPTH_VIEW(.dword = 0));
359*61046927SAndroid Build Coastguard Worker    } else if (lrz->fast_clear || lrz->gpu_dir_tracking) {
360*61046927SAndroid Build Coastguard Worker       if (lrz->gpu_dir_tracking) {
361*61046927SAndroid Build Coastguard Worker          tu6_write_lrz_reg(cmd, cs,
362*61046927SAndroid Build Coastguard Worker             A6XX_GRAS_LRZ_DEPTH_VIEW(.dword = lrz->image_view->view.GRAS_LRZ_DEPTH_VIEW));
363*61046927SAndroid Build Coastguard Worker       }
364*61046927SAndroid Build Coastguard Worker 
365*61046927SAndroid Build Coastguard Worker       tu6_write_lrz_cntl<CHIP>(cmd, cs, {
366*61046927SAndroid Build Coastguard Worker          .enable = true,
367*61046927SAndroid Build Coastguard Worker          .fc_enable = lrz->fast_clear,
368*61046927SAndroid Build Coastguard Worker          .disable_on_wrong_dir = lrz->gpu_dir_tracking,
369*61046927SAndroid Build Coastguard Worker       });
370*61046927SAndroid Build Coastguard Worker 
371*61046927SAndroid Build Coastguard Worker       /* LRZ_CLEAR.fc_enable + LRZ_CLEAR - clears fast-clear buffer;
372*61046927SAndroid Build Coastguard Worker        * LRZ_CLEAR.disable_on_wrong_dir + LRZ_CLEAR - sets direction to
373*61046927SAndroid Build Coastguard Worker        *  CUR_DIR_UNSET.
374*61046927SAndroid Build Coastguard Worker        */
375*61046927SAndroid Build Coastguard Worker       if (CHIP >= A7XX)
376*61046927SAndroid Build Coastguard Worker          tu_cs_emit_regs(cs, A7XX_GRAS_LRZ_CLEAR_DEPTH_F32(lrz->depth_clear_value.depthStencil.depth));
377*61046927SAndroid Build Coastguard Worker       tu_emit_event_write<CHIP>(cmd, cs, FD_LRZ_CLEAR);
378*61046927SAndroid Build Coastguard Worker    }
379*61046927SAndroid Build Coastguard Worker 
380*61046927SAndroid Build Coastguard Worker    if (!lrz->fast_clear && !invalidate_lrz) {
381*61046927SAndroid Build Coastguard Worker       tu6_clear_lrz<CHIP>(cmd, cs, lrz->image_view->image, &lrz->depth_clear_value);
382*61046927SAndroid Build Coastguard Worker       /* Even though we disable fast-clear we still have to dirty
383*61046927SAndroid Build Coastguard Worker        * fast-clear buffer because both secondary cmdbufs and following
384*61046927SAndroid Build Coastguard Worker        * renderpasses won't know that fast-clear is disabled.
385*61046927SAndroid Build Coastguard Worker        *
386*61046927SAndroid Build Coastguard Worker        * TODO: we could avoid this if we don't store depth and don't
387*61046927SAndroid Build Coastguard Worker        * expect secondary cmdbufs.
388*61046927SAndroid Build Coastguard Worker        */
389*61046927SAndroid Build Coastguard Worker       if (lrz->image_view->image->has_lrz_fc) {
390*61046927SAndroid Build Coastguard Worker          tu6_dirty_lrz_fc<CHIP>(cmd, cs, lrz->image_view->image);
391*61046927SAndroid Build Coastguard Worker       }
392*61046927SAndroid Build Coastguard Worker    }
393*61046927SAndroid Build Coastguard Worker }
394*61046927SAndroid Build Coastguard Worker TU_GENX(tu_lrz_tiling_begin);
395*61046927SAndroid Build Coastguard Worker 
396*61046927SAndroid Build Coastguard Worker template <chip CHIP>
397*61046927SAndroid Build Coastguard Worker void
tu_lrz_tiling_end(struct tu_cmd_buffer * cmd,struct tu_cs * cs)398*61046927SAndroid Build Coastguard Worker tu_lrz_tiling_end(struct tu_cmd_buffer *cmd, struct tu_cs *cs)
399*61046927SAndroid Build Coastguard Worker {
400*61046927SAndroid Build Coastguard Worker    if (cmd->state.lrz.fast_clear || cmd->state.lrz.gpu_dir_tracking) {
401*61046927SAndroid Build Coastguard Worker       tu6_emit_lrz_buffer<CHIP>(cs, cmd->state.lrz.image_view->image);
402*61046927SAndroid Build Coastguard Worker 
403*61046927SAndroid Build Coastguard Worker       if (cmd->state.lrz.gpu_dir_tracking) {
404*61046927SAndroid Build Coastguard Worker          tu6_write_lrz_reg(cmd, &cmd->cs,
405*61046927SAndroid Build Coastguard Worker             A6XX_GRAS_LRZ_DEPTH_VIEW(.dword = cmd->state.lrz.image_view->view.GRAS_LRZ_DEPTH_VIEW));
406*61046927SAndroid Build Coastguard Worker       }
407*61046927SAndroid Build Coastguard Worker 
408*61046927SAndroid Build Coastguard Worker       /* Enable flushing of LRZ fast-clear and of direction buffer */
409*61046927SAndroid Build Coastguard Worker       tu6_write_lrz_cntl<CHIP>(cmd, cs, {
410*61046927SAndroid Build Coastguard Worker          .enable = true,
411*61046927SAndroid Build Coastguard Worker          .fc_enable = cmd->state.lrz.fast_clear,
412*61046927SAndroid Build Coastguard Worker          .disable_on_wrong_dir = cmd->state.lrz.gpu_dir_tracking,
413*61046927SAndroid Build Coastguard Worker       });
414*61046927SAndroid Build Coastguard Worker    } else {
415*61046927SAndroid Build Coastguard Worker       tu6_write_lrz_cntl<CHIP>(cmd, cs, {.enable = false});
416*61046927SAndroid Build Coastguard Worker    }
417*61046927SAndroid Build Coastguard Worker 
418*61046927SAndroid Build Coastguard Worker    tu_emit_event_write<CHIP>(cmd, cs, FD_LRZ_FLUSH);
419*61046927SAndroid Build Coastguard Worker 
420*61046927SAndroid Build Coastguard Worker    /* If gpu_dir_tracking is enabled and lrz is not valid blob, at this point,
421*61046927SAndroid Build Coastguard Worker     * additionally clears direction buffer:
422*61046927SAndroid Build Coastguard Worker     *  GRAS_LRZ_DEPTH_VIEW(.dword = 0)
423*61046927SAndroid Build Coastguard Worker     *  GRAS_LRZ_DEPTH_VIEW(.dword = 0xffffffff)
424*61046927SAndroid Build Coastguard Worker     *  A6XX_GRAS_LRZ_CNTL(.enable = true, .disable_on_wrong_dir = true)
425*61046927SAndroid Build Coastguard Worker     *  LRZ_CLEAR
426*61046927SAndroid Build Coastguard Worker     *  LRZ_FLUSH
427*61046927SAndroid Build Coastguard Worker     * Since it happens after all of the rendering is done there is no known
428*61046927SAndroid Build Coastguard Worker     * reason to do such clear.
429*61046927SAndroid Build Coastguard Worker     */
430*61046927SAndroid Build Coastguard Worker }
431*61046927SAndroid Build Coastguard Worker TU_GENX(tu_lrz_tiling_end);
432*61046927SAndroid Build Coastguard Worker 
433*61046927SAndroid Build Coastguard Worker template <chip CHIP>
434*61046927SAndroid Build Coastguard Worker void
tu_lrz_sysmem_begin(struct tu_cmd_buffer * cmd,struct tu_cs * cs)435*61046927SAndroid Build Coastguard Worker tu_lrz_sysmem_begin(struct tu_cmd_buffer *cmd, struct tu_cs *cs)
436*61046927SAndroid Build Coastguard Worker {
437*61046927SAndroid Build Coastguard Worker    if (cmd->device->physical_device->info->a6xx.has_lrz_feedback) {
438*61046927SAndroid Build Coastguard Worker       tu_lrz_tiling_begin<CHIP>(cmd, cs);
439*61046927SAndroid Build Coastguard Worker       return;
440*61046927SAndroid Build Coastguard Worker    }
441*61046927SAndroid Build Coastguard Worker 
442*61046927SAndroid Build Coastguard Worker    if (!cmd->state.lrz.image_view)
443*61046927SAndroid Build Coastguard Worker       return;
444*61046927SAndroid Build Coastguard Worker 
445*61046927SAndroid Build Coastguard Worker    /* Actually, LRZ buffer could be filled in sysmem, in theory to
446*61046927SAndroid Build Coastguard Worker     * be used in another renderpass, but the benefit is rather dubious.
447*61046927SAndroid Build Coastguard Worker     */
448*61046927SAndroid Build Coastguard Worker 
449*61046927SAndroid Build Coastguard Worker    struct tu_lrz_state *lrz = &cmd->state.lrz;
450*61046927SAndroid Build Coastguard Worker 
451*61046927SAndroid Build Coastguard Worker    if (cmd->device->physical_device->info->a6xx.has_lrz_dir_tracking) {
452*61046927SAndroid Build Coastguard Worker       tu_disable_lrz<CHIP>(cmd, cs, lrz->image_view->image);
453*61046927SAndroid Build Coastguard Worker       /* Make sure depth view comparison will fail. */
454*61046927SAndroid Build Coastguard Worker       tu6_write_lrz_reg(cmd, cs,
455*61046927SAndroid Build Coastguard Worker          A6XX_GRAS_LRZ_DEPTH_VIEW(.dword = 0));
456*61046927SAndroid Build Coastguard Worker    } else {
457*61046927SAndroid Build Coastguard Worker       tu6_emit_lrz_buffer<CHIP>(cs, lrz->image_view->image);
458*61046927SAndroid Build Coastguard Worker       /* Even though we disable LRZ writes in sysmem mode - there is still
459*61046927SAndroid Build Coastguard Worker        * LRZ test, so LRZ should be cleared.
460*61046927SAndroid Build Coastguard Worker        */
461*61046927SAndroid Build Coastguard Worker       if (lrz->fast_clear) {
462*61046927SAndroid Build Coastguard Worker          tu6_write_lrz_cntl<CHIP>(cmd, &cmd->cs, {
463*61046927SAndroid Build Coastguard Worker             .enable = true,
464*61046927SAndroid Build Coastguard Worker             .fc_enable = true,
465*61046927SAndroid Build Coastguard Worker          });
466*61046927SAndroid Build Coastguard Worker 
467*61046927SAndroid Build Coastguard Worker          if (CHIP >= A7XX)
468*61046927SAndroid Build Coastguard Worker             tu_cs_emit_regs(cs, A7XX_GRAS_LRZ_CLEAR_DEPTH_F32(lrz->depth_clear_value.depthStencil.depth));
469*61046927SAndroid Build Coastguard Worker          tu_emit_event_write<CHIP>(cmd, &cmd->cs, FD_LRZ_CLEAR);
470*61046927SAndroid Build Coastguard Worker          tu_emit_event_write<CHIP>(cmd, &cmd->cs, FD_LRZ_FLUSH);
471*61046927SAndroid Build Coastguard Worker       } else {
472*61046927SAndroid Build Coastguard Worker          tu6_clear_lrz<CHIP>(cmd, cs, lrz->image_view->image, &lrz->depth_clear_value);
473*61046927SAndroid Build Coastguard Worker       }
474*61046927SAndroid Build Coastguard Worker    }
475*61046927SAndroid Build Coastguard Worker }
476*61046927SAndroid Build Coastguard Worker TU_GENX(tu_lrz_sysmem_begin);
477*61046927SAndroid Build Coastguard Worker 
478*61046927SAndroid Build Coastguard Worker template <chip CHIP>
479*61046927SAndroid Build Coastguard Worker void
tu_lrz_sysmem_end(struct tu_cmd_buffer * cmd,struct tu_cs * cs)480*61046927SAndroid Build Coastguard Worker tu_lrz_sysmem_end(struct tu_cmd_buffer *cmd, struct tu_cs *cs)
481*61046927SAndroid Build Coastguard Worker {
482*61046927SAndroid Build Coastguard Worker    if (cmd->device->physical_device->info->a6xx.has_lrz_feedback) {
483*61046927SAndroid Build Coastguard Worker       tu_lrz_tiling_end<CHIP>(cmd, cs);
484*61046927SAndroid Build Coastguard Worker       return;
485*61046927SAndroid Build Coastguard Worker    }
486*61046927SAndroid Build Coastguard Worker 
487*61046927SAndroid Build Coastguard Worker    tu_emit_event_write<CHIP>(cmd, &cmd->cs, FD_LRZ_FLUSH);
488*61046927SAndroid Build Coastguard Worker }
489*61046927SAndroid Build Coastguard Worker TU_GENX(tu_lrz_sysmem_end);
490*61046927SAndroid Build Coastguard Worker 
491*61046927SAndroid Build Coastguard Worker /* Disable LRZ outside of renderpass. */
492*61046927SAndroid Build Coastguard Worker template <chip CHIP>
493*61046927SAndroid Build Coastguard Worker void
tu_disable_lrz(struct tu_cmd_buffer * cmd,struct tu_cs * cs,struct tu_image * image)494*61046927SAndroid Build Coastguard Worker tu_disable_lrz(struct tu_cmd_buffer *cmd, struct tu_cs *cs,
495*61046927SAndroid Build Coastguard Worker                struct tu_image *image)
496*61046927SAndroid Build Coastguard Worker {
497*61046927SAndroid Build Coastguard Worker    if (!cmd->device->physical_device->info->a6xx.has_lrz_dir_tracking)
498*61046927SAndroid Build Coastguard Worker       return;
499*61046927SAndroid Build Coastguard Worker 
500*61046927SAndroid Build Coastguard Worker    if (!image->lrz_height)
501*61046927SAndroid Build Coastguard Worker       return;
502*61046927SAndroid Build Coastguard Worker 
503*61046927SAndroid Build Coastguard Worker    tu6_emit_lrz_buffer<CHIP>(cs, image);
504*61046927SAndroid Build Coastguard Worker    tu6_disable_lrz_via_depth_view<CHIP>(cmd, cs);
505*61046927SAndroid Build Coastguard Worker }
506*61046927SAndroid Build Coastguard Worker TU_GENX(tu_disable_lrz);
507*61046927SAndroid Build Coastguard Worker 
508*61046927SAndroid Build Coastguard Worker /* Clear LRZ, used for out of renderpass depth clears. */
509*61046927SAndroid Build Coastguard Worker template <chip CHIP>
510*61046927SAndroid Build Coastguard Worker void
tu_lrz_clear_depth_image(struct tu_cmd_buffer * cmd,struct tu_image * image,const VkClearDepthStencilValue * pDepthStencil,uint32_t rangeCount,const VkImageSubresourceRange * pRanges)511*61046927SAndroid Build Coastguard Worker tu_lrz_clear_depth_image(struct tu_cmd_buffer *cmd,
512*61046927SAndroid Build Coastguard Worker                          struct tu_image *image,
513*61046927SAndroid Build Coastguard Worker                          const VkClearDepthStencilValue *pDepthStencil,
514*61046927SAndroid Build Coastguard Worker                          uint32_t rangeCount,
515*61046927SAndroid Build Coastguard Worker                          const VkImageSubresourceRange *pRanges)
516*61046927SAndroid Build Coastguard Worker {
517*61046927SAndroid Build Coastguard Worker    if (!rangeCount || !image->lrz_height ||
518*61046927SAndroid Build Coastguard Worker        !cmd->device->physical_device->info->a6xx.has_lrz_dir_tracking)
519*61046927SAndroid Build Coastguard Worker       return;
520*61046927SAndroid Build Coastguard Worker 
521*61046927SAndroid Build Coastguard Worker    /* We cannot predict which depth subresource would be used later on,
522*61046927SAndroid Build Coastguard Worker     * so we just pick the first one with depth cleared and clear the LRZ.
523*61046927SAndroid Build Coastguard Worker     */
524*61046927SAndroid Build Coastguard Worker    const VkImageSubresourceRange *range = NULL;
525*61046927SAndroid Build Coastguard Worker    for (unsigned i = 0; i < rangeCount; i++) {
526*61046927SAndroid Build Coastguard Worker       if (pRanges[i].aspectMask &
527*61046927SAndroid Build Coastguard Worker             (VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT)) {
528*61046927SAndroid Build Coastguard Worker          range = &pRanges[i];
529*61046927SAndroid Build Coastguard Worker          break;
530*61046927SAndroid Build Coastguard Worker       }
531*61046927SAndroid Build Coastguard Worker    }
532*61046927SAndroid Build Coastguard Worker 
533*61046927SAndroid Build Coastguard Worker    if (!range)
534*61046927SAndroid Build Coastguard Worker       return;
535*61046927SAndroid Build Coastguard Worker 
536*61046927SAndroid Build Coastguard Worker    bool fast_clear = image->has_lrz_fc &&
537*61046927SAndroid Build Coastguard Worker                      tu_lrzfc_depth_supported<CHIP>(pDepthStencil->depth);
538*61046927SAndroid Build Coastguard Worker 
539*61046927SAndroid Build Coastguard Worker    tu6_emit_lrz_buffer<CHIP>(&cmd->cs, image);
540*61046927SAndroid Build Coastguard Worker 
541*61046927SAndroid Build Coastguard Worker    tu6_write_lrz_reg(cmd, &cmd->cs, A6XX_GRAS_LRZ_DEPTH_VIEW(
542*61046927SAndroid Build Coastguard Worker          .base_layer = range->baseArrayLayer,
543*61046927SAndroid Build Coastguard Worker          .layer_count = vk_image_subresource_layer_count(&image->vk, range),
544*61046927SAndroid Build Coastguard Worker          .base_mip_level = range->baseMipLevel,
545*61046927SAndroid Build Coastguard Worker    ));
546*61046927SAndroid Build Coastguard Worker 
547*61046927SAndroid Build Coastguard Worker    tu6_write_lrz_cntl<CHIP>(cmd, &cmd->cs, {
548*61046927SAndroid Build Coastguard Worker       .enable = true,
549*61046927SAndroid Build Coastguard Worker       .fc_enable = fast_clear,
550*61046927SAndroid Build Coastguard Worker       .disable_on_wrong_dir = true,
551*61046927SAndroid Build Coastguard Worker    });
552*61046927SAndroid Build Coastguard Worker 
553*61046927SAndroid Build Coastguard Worker    if (CHIP >= A7XX)
554*61046927SAndroid Build Coastguard Worker       tu_cs_emit_regs(&cmd->cs, A7XX_GRAS_LRZ_CLEAR_DEPTH_F32(pDepthStencil->depth));
555*61046927SAndroid Build Coastguard Worker    tu_emit_event_write<CHIP>(cmd, &cmd->cs, FD_LRZ_CLEAR);
556*61046927SAndroid Build Coastguard Worker    tu_emit_event_write<CHIP>(cmd, &cmd->cs, FD_LRZ_FLUSH);
557*61046927SAndroid Build Coastguard Worker 
558*61046927SAndroid Build Coastguard Worker    if (!fast_clear) {
559*61046927SAndroid Build Coastguard Worker       tu6_clear_lrz<CHIP>(cmd, &cmd->cs, image, (const VkClearValue*) pDepthStencil);
560*61046927SAndroid Build Coastguard Worker    }
561*61046927SAndroid Build Coastguard Worker }
562*61046927SAndroid Build Coastguard Worker TU_GENX(tu_lrz_clear_depth_image);
563*61046927SAndroid Build Coastguard Worker 
564*61046927SAndroid Build Coastguard Worker template <chip CHIP>
565*61046927SAndroid Build Coastguard Worker void
tu_lrz_disable_during_renderpass(struct tu_cmd_buffer * cmd)566*61046927SAndroid Build Coastguard Worker tu_lrz_disable_during_renderpass(struct tu_cmd_buffer *cmd)
567*61046927SAndroid Build Coastguard Worker {
568*61046927SAndroid Build Coastguard Worker    assert(cmd->state.pass);
569*61046927SAndroid Build Coastguard Worker 
570*61046927SAndroid Build Coastguard Worker    cmd->state.lrz.valid = false;
571*61046927SAndroid Build Coastguard Worker    cmd->state.dirty |= TU_CMD_DIRTY_LRZ;
572*61046927SAndroid Build Coastguard Worker 
573*61046927SAndroid Build Coastguard Worker    if (cmd->state.lrz.gpu_dir_tracking) {
574*61046927SAndroid Build Coastguard Worker       tu6_write_lrz_cntl<CHIP>(cmd, &cmd->cs, {
575*61046927SAndroid Build Coastguard Worker          .enable = true,
576*61046927SAndroid Build Coastguard Worker          .dir = LRZ_DIR_INVALID,
577*61046927SAndroid Build Coastguard Worker          .disable_on_wrong_dir = true,
578*61046927SAndroid Build Coastguard Worker       });
579*61046927SAndroid Build Coastguard Worker    }
580*61046927SAndroid Build Coastguard Worker }
581*61046927SAndroid Build Coastguard Worker TU_GENX(tu_lrz_disable_during_renderpass);
582*61046927SAndroid Build Coastguard Worker 
583*61046927SAndroid Build Coastguard Worker /* update lrz state based on stencil-test func:
584*61046927SAndroid Build Coastguard Worker  *
585*61046927SAndroid Build Coastguard Worker  * Conceptually the order of the pipeline is:
586*61046927SAndroid Build Coastguard Worker  *
587*61046927SAndroid Build Coastguard Worker  *
588*61046927SAndroid Build Coastguard Worker  *   FS -> Alpha-Test  ->  Stencil-Test  ->  Depth-Test
589*61046927SAndroid Build Coastguard Worker  *                              |                |
590*61046927SAndroid Build Coastguard Worker  *                       if wrmask != 0     if wrmask != 0
591*61046927SAndroid Build Coastguard Worker  *                              |                |
592*61046927SAndroid Build Coastguard Worker  *                              v                v
593*61046927SAndroid Build Coastguard Worker  *                        Stencil-Write      Depth-Write
594*61046927SAndroid Build Coastguard Worker  *
595*61046927SAndroid Build Coastguard Worker  * Because Stencil-Test can have side effects (Stencil-Write) prior
596*61046927SAndroid Build Coastguard Worker  * to depth test, in this case we potentially need to disable early
597*61046927SAndroid Build Coastguard Worker  * lrz-test. See:
598*61046927SAndroid Build Coastguard Worker  *
599*61046927SAndroid Build Coastguard Worker  * https://www.khronos.org/opengl/wiki/Per-Sample_Processing
600*61046927SAndroid Build Coastguard Worker  */
601*61046927SAndroid Build Coastguard Worker static bool
tu6_stencil_op_lrz_allowed(struct A6XX_GRAS_LRZ_CNTL * gras_lrz_cntl,VkCompareOp func,bool stencil_write)602*61046927SAndroid Build Coastguard Worker tu6_stencil_op_lrz_allowed(struct A6XX_GRAS_LRZ_CNTL *gras_lrz_cntl,
603*61046927SAndroid Build Coastguard Worker                            VkCompareOp func,
604*61046927SAndroid Build Coastguard Worker                            bool stencil_write)
605*61046927SAndroid Build Coastguard Worker {
606*61046927SAndroid Build Coastguard Worker    switch (func) {
607*61046927SAndroid Build Coastguard Worker    case VK_COMPARE_OP_ALWAYS:
608*61046927SAndroid Build Coastguard Worker       /* nothing to do for LRZ, but for stencil test when stencil-
609*61046927SAndroid Build Coastguard Worker        * write is enabled, we need to disable lrz-test, since
610*61046927SAndroid Build Coastguard Worker        * conceptually stencil test and write happens before depth-test.
611*61046927SAndroid Build Coastguard Worker        */
612*61046927SAndroid Build Coastguard Worker       if (stencil_write) {
613*61046927SAndroid Build Coastguard Worker          return false;
614*61046927SAndroid Build Coastguard Worker       }
615*61046927SAndroid Build Coastguard Worker       break;
616*61046927SAndroid Build Coastguard Worker    case VK_COMPARE_OP_NEVER:
617*61046927SAndroid Build Coastguard Worker       /* fragment never passes, disable lrz_write for this draw. */
618*61046927SAndroid Build Coastguard Worker       gras_lrz_cntl->lrz_write = false;
619*61046927SAndroid Build Coastguard Worker       break;
620*61046927SAndroid Build Coastguard Worker    default:
621*61046927SAndroid Build Coastguard Worker       /* whether the fragment passes or not depends on result
622*61046927SAndroid Build Coastguard Worker        * of stencil test, which we cannot know when doing binning
623*61046927SAndroid Build Coastguard Worker        * pass.
624*61046927SAndroid Build Coastguard Worker        */
625*61046927SAndroid Build Coastguard Worker       gras_lrz_cntl->lrz_write = false;
626*61046927SAndroid Build Coastguard Worker       /* similarly to the VK_COMPARE_OP_ALWAYS case, if there are side-
627*61046927SAndroid Build Coastguard Worker        * effects from stencil test we need to disable lrz-test.
628*61046927SAndroid Build Coastguard Worker        */
629*61046927SAndroid Build Coastguard Worker       if (stencil_write) {
630*61046927SAndroid Build Coastguard Worker          return false;
631*61046927SAndroid Build Coastguard Worker       }
632*61046927SAndroid Build Coastguard Worker       break;
633*61046927SAndroid Build Coastguard Worker    }
634*61046927SAndroid Build Coastguard Worker 
635*61046927SAndroid Build Coastguard Worker    return true;
636*61046927SAndroid Build Coastguard Worker }
637*61046927SAndroid Build Coastguard Worker 
638*61046927SAndroid Build Coastguard Worker template <chip CHIP>
639*61046927SAndroid Build Coastguard Worker static struct A6XX_GRAS_LRZ_CNTL
tu6_calculate_lrz_state(struct tu_cmd_buffer * cmd,const uint32_t a)640*61046927SAndroid Build Coastguard Worker tu6_calculate_lrz_state(struct tu_cmd_buffer *cmd,
641*61046927SAndroid Build Coastguard Worker                         const uint32_t a)
642*61046927SAndroid Build Coastguard Worker {
643*61046927SAndroid Build Coastguard Worker    const struct tu_shader *fs = cmd->state.shaders[MESA_SHADER_FRAGMENT];
644*61046927SAndroid Build Coastguard Worker    bool z_test_enable = cmd->vk.dynamic_graphics_state.ds.depth.test_enable;
645*61046927SAndroid Build Coastguard Worker    bool z_write_enable = cmd->vk.dynamic_graphics_state.ds.depth.write_enable;
646*61046927SAndroid Build Coastguard Worker    bool z_bounds_enable = cmd->vk.dynamic_graphics_state.ds.depth.bounds_test.enable;
647*61046927SAndroid Build Coastguard Worker    VkCompareOp depth_compare_op =
648*61046927SAndroid Build Coastguard Worker       cmd->vk.dynamic_graphics_state.ds.depth.compare_op;
649*61046927SAndroid Build Coastguard Worker 
650*61046927SAndroid Build Coastguard Worker    struct A6XX_GRAS_LRZ_CNTL gras_lrz_cntl = { 0 };
651*61046927SAndroid Build Coastguard Worker 
652*61046927SAndroid Build Coastguard Worker    if (!cmd->state.lrz.valid) {
653*61046927SAndroid Build Coastguard Worker       return gras_lrz_cntl;
654*61046927SAndroid Build Coastguard Worker    }
655*61046927SAndroid Build Coastguard Worker 
656*61046927SAndroid Build Coastguard Worker    /* If depth test is disabled we shouldn't touch LRZ.
657*61046927SAndroid Build Coastguard Worker     * Same if there is no depth attachment.
658*61046927SAndroid Build Coastguard Worker     */
659*61046927SAndroid Build Coastguard Worker    if (a == VK_ATTACHMENT_UNUSED || !z_test_enable || !cmd->device->use_lrz)
660*61046927SAndroid Build Coastguard Worker       return gras_lrz_cntl;
661*61046927SAndroid Build Coastguard Worker 
662*61046927SAndroid Build Coastguard Worker    if (!cmd->state.lrz.gpu_dir_tracking && !cmd->state.attachments) {
663*61046927SAndroid Build Coastguard Worker       /* Without on-gpu LRZ direction tracking - there is nothing we
664*61046927SAndroid Build Coastguard Worker        * can do to enable LRZ in secondary command buffers.
665*61046927SAndroid Build Coastguard Worker        */
666*61046927SAndroid Build Coastguard Worker       return gras_lrz_cntl;
667*61046927SAndroid Build Coastguard Worker    }
668*61046927SAndroid Build Coastguard Worker 
669*61046927SAndroid Build Coastguard Worker    /* See comment in tu_pipeline about disabling LRZ write for blending. */
670*61046927SAndroid Build Coastguard Worker    bool reads_dest = cmd->state.blend_reads_dest;
671*61046927SAndroid Build Coastguard Worker 
672*61046927SAndroid Build Coastguard Worker    gras_lrz_cntl.enable = true;
673*61046927SAndroid Build Coastguard Worker    gras_lrz_cntl.lrz_write =
674*61046927SAndroid Build Coastguard Worker       z_write_enable &&
675*61046927SAndroid Build Coastguard Worker       !reads_dest &&
676*61046927SAndroid Build Coastguard Worker       !(fs->fs.lrz.status & TU_LRZ_FORCE_DISABLE_WRITE);
677*61046927SAndroid Build Coastguard Worker    gras_lrz_cntl.z_test_enable = z_write_enable;
678*61046927SAndroid Build Coastguard Worker    gras_lrz_cntl.z_bounds_enable = z_bounds_enable;
679*61046927SAndroid Build Coastguard Worker    gras_lrz_cntl.fc_enable = cmd->state.lrz.fast_clear;
680*61046927SAndroid Build Coastguard Worker    gras_lrz_cntl.dir_write = cmd->state.lrz.gpu_dir_tracking;
681*61046927SAndroid Build Coastguard Worker    gras_lrz_cntl.disable_on_wrong_dir = cmd->state.lrz.gpu_dir_tracking;
682*61046927SAndroid Build Coastguard Worker 
683*61046927SAndroid Build Coastguard Worker    if (CHIP >= A7XX)
684*61046927SAndroid Build Coastguard Worker       gras_lrz_cntl.z_func = tu6_compare_func(depth_compare_op);
685*61046927SAndroid Build Coastguard Worker 
686*61046927SAndroid Build Coastguard Worker    /* LRZ is disabled until it is cleared, which means that one "wrong"
687*61046927SAndroid Build Coastguard Worker     * depth test or shader could disable LRZ until depth buffer is cleared.
688*61046927SAndroid Build Coastguard Worker     */
689*61046927SAndroid Build Coastguard Worker    bool disable_lrz = false;
690*61046927SAndroid Build Coastguard Worker    bool temporary_disable_lrz = false;
691*61046927SAndroid Build Coastguard Worker 
692*61046927SAndroid Build Coastguard Worker    /* What happens in FS could affect LRZ, e.g.: writes to gl_FragDepth or early
693*61046927SAndroid Build Coastguard Worker     * fragment tests.  We have to skip LRZ testing and updating, but as long as
694*61046927SAndroid Build Coastguard Worker     * the depth direction stayed the same we can continue with LRZ testing later.
695*61046927SAndroid Build Coastguard Worker     */
696*61046927SAndroid Build Coastguard Worker    if (fs->fs.lrz.status & TU_LRZ_FORCE_DISABLE_LRZ) {
697*61046927SAndroid Build Coastguard Worker       if (cmd->state.lrz.prev_direction != TU_LRZ_UNKNOWN || !cmd->state.lrz.gpu_dir_tracking) {
698*61046927SAndroid Build Coastguard Worker          perf_debug(cmd->device, "Skipping LRZ due to FS");
699*61046927SAndroid Build Coastguard Worker          temporary_disable_lrz = true;
700*61046927SAndroid Build Coastguard Worker       } else {
701*61046927SAndroid Build Coastguard Worker          tu_lrz_disable_reason(cmd, "FS writes depth or has side-effects (TODO: fix for gpu-direction-tracking case)");
702*61046927SAndroid Build Coastguard Worker          disable_lrz = true;
703*61046927SAndroid Build Coastguard Worker       }
704*61046927SAndroid Build Coastguard Worker    }
705*61046927SAndroid Build Coastguard Worker 
706*61046927SAndroid Build Coastguard Worker    /* If Z is not written - it doesn't affect LRZ buffer state.
707*61046927SAndroid Build Coastguard Worker     * Which means two things:
708*61046927SAndroid Build Coastguard Worker     * - Don't lock direction until Z is written for the first time;
709*61046927SAndroid Build Coastguard Worker     * - If Z isn't written and direction IS locked it's possible to just
710*61046927SAndroid Build Coastguard Worker     *   temporary disable LRZ instead of fully bailing out, when direction
711*61046927SAndroid Build Coastguard Worker     *   is changed.
712*61046927SAndroid Build Coastguard Worker     */
713*61046927SAndroid Build Coastguard Worker 
714*61046927SAndroid Build Coastguard Worker    enum tu_lrz_direction lrz_direction = TU_LRZ_UNKNOWN;
715*61046927SAndroid Build Coastguard Worker    switch (depth_compare_op) {
716*61046927SAndroid Build Coastguard Worker    case VK_COMPARE_OP_ALWAYS:
717*61046927SAndroid Build Coastguard Worker    case VK_COMPARE_OP_NOT_EQUAL:
718*61046927SAndroid Build Coastguard Worker       /* OP_ALWAYS and OP_NOT_EQUAL could have depth value of any direction,
719*61046927SAndroid Build Coastguard Worker        * so if there is a depth write - LRZ must be disabled.
720*61046927SAndroid Build Coastguard Worker        */
721*61046927SAndroid Build Coastguard Worker       if (z_write_enable) {
722*61046927SAndroid Build Coastguard Worker          tu_lrz_disable_reason(cmd, "Depth write + ALWAYS/NOT_EQUAL");
723*61046927SAndroid Build Coastguard Worker          disable_lrz = true;
724*61046927SAndroid Build Coastguard Worker          gras_lrz_cntl.dir = LRZ_DIR_INVALID;
725*61046927SAndroid Build Coastguard Worker       } else {
726*61046927SAndroid Build Coastguard Worker          perf_debug(cmd->device, "Skipping LRZ due to ALWAYS/NOT_EQUAL");
727*61046927SAndroid Build Coastguard Worker          temporary_disable_lrz = true;
728*61046927SAndroid Build Coastguard Worker       }
729*61046927SAndroid Build Coastguard Worker       break;
730*61046927SAndroid Build Coastguard Worker    case VK_COMPARE_OP_EQUAL:
731*61046927SAndroid Build Coastguard Worker    case VK_COMPARE_OP_NEVER:
732*61046927SAndroid Build Coastguard Worker       /* Blob disables LRZ for OP_EQUAL, and from our empirical
733*61046927SAndroid Build Coastguard Worker        * evidence it is a right thing to do.
734*61046927SAndroid Build Coastguard Worker        *
735*61046927SAndroid Build Coastguard Worker        * Both OP_EQUAL and OP_NEVER don't change LRZ buffer so
736*61046927SAndroid Build Coastguard Worker        * we could just temporary disable LRZ.
737*61046927SAndroid Build Coastguard Worker        */
738*61046927SAndroid Build Coastguard Worker       temporary_disable_lrz = true;
739*61046927SAndroid Build Coastguard Worker       break;
740*61046927SAndroid Build Coastguard Worker    case VK_COMPARE_OP_GREATER:
741*61046927SAndroid Build Coastguard Worker    case VK_COMPARE_OP_GREATER_OR_EQUAL:
742*61046927SAndroid Build Coastguard Worker       lrz_direction = TU_LRZ_GREATER;
743*61046927SAndroid Build Coastguard Worker       gras_lrz_cntl.greater = true;
744*61046927SAndroid Build Coastguard Worker       gras_lrz_cntl.dir = LRZ_DIR_GE;
745*61046927SAndroid Build Coastguard Worker       break;
746*61046927SAndroid Build Coastguard Worker    case VK_COMPARE_OP_LESS:
747*61046927SAndroid Build Coastguard Worker    case VK_COMPARE_OP_LESS_OR_EQUAL:
748*61046927SAndroid Build Coastguard Worker       lrz_direction = TU_LRZ_LESS;
749*61046927SAndroid Build Coastguard Worker       gras_lrz_cntl.greater = false;
750*61046927SAndroid Build Coastguard Worker       gras_lrz_cntl.dir = LRZ_DIR_LE;
751*61046927SAndroid Build Coastguard Worker       break;
752*61046927SAndroid Build Coastguard Worker    default:
753*61046927SAndroid Build Coastguard Worker       unreachable("bad VK_COMPARE_OP value or uninitialized");
754*61046927SAndroid Build Coastguard Worker       break;
755*61046927SAndroid Build Coastguard Worker    };
756*61046927SAndroid Build Coastguard Worker 
757*61046927SAndroid Build Coastguard Worker    /* If depthfunc direction is changed, bail out on using LRZ. The
758*61046927SAndroid Build Coastguard Worker     * LRZ buffer encodes a min/max depth value per block, but if
759*61046927SAndroid Build Coastguard Worker     * we switch from GT/GE <-> LT/LE, those values cannot be
760*61046927SAndroid Build Coastguard Worker     * interpreted properly.
761*61046927SAndroid Build Coastguard Worker     */
762*61046927SAndroid Build Coastguard Worker    if (cmd->state.lrz.prev_direction != TU_LRZ_UNKNOWN &&
763*61046927SAndroid Build Coastguard Worker        lrz_direction != TU_LRZ_UNKNOWN &&
764*61046927SAndroid Build Coastguard Worker        cmd->state.lrz.prev_direction != lrz_direction) {
765*61046927SAndroid Build Coastguard Worker       if (z_write_enable) {
766*61046927SAndroid Build Coastguard Worker          tu_lrz_disable_reason(cmd, "Depth write + compare-op direction change");
767*61046927SAndroid Build Coastguard Worker          disable_lrz = true;
768*61046927SAndroid Build Coastguard Worker       } else {
769*61046927SAndroid Build Coastguard Worker          perf_debug(cmd->device, "Skipping LRZ due to direction change");
770*61046927SAndroid Build Coastguard Worker          temporary_disable_lrz = true;
771*61046927SAndroid Build Coastguard Worker       }
772*61046927SAndroid Build Coastguard Worker    }
773*61046927SAndroid Build Coastguard Worker 
774*61046927SAndroid Build Coastguard Worker    /* Consider the following sequence of depthfunc changes:
775*61046927SAndroid Build Coastguard Worker     *
776*61046927SAndroid Build Coastguard Worker     * - COMPARE_OP_GREATER -> COMPARE_OP_EQUAL -> COMPARE_OP_GREATER
777*61046927SAndroid Build Coastguard Worker     * LRZ is disabled during COMPARE_OP_EQUAL but could be enabled
778*61046927SAndroid Build Coastguard Worker     * during second VK_COMPARE_OP_GREATER.
779*61046927SAndroid Build Coastguard Worker     *
780*61046927SAndroid Build Coastguard Worker     * - COMPARE_OP_GREATER -> COMPARE_OP_EQUAL -> COMPARE_OP_LESS
781*61046927SAndroid Build Coastguard Worker     * Here, LRZ is disabled during COMPARE_OP_EQUAL and should become
782*61046927SAndroid Build Coastguard Worker     * invalid during COMPARE_OP_LESS.
783*61046927SAndroid Build Coastguard Worker     *
784*61046927SAndroid Build Coastguard Worker     * This shows that we should keep last KNOWN direction.
785*61046927SAndroid Build Coastguard Worker     */
786*61046927SAndroid Build Coastguard Worker    if (z_write_enable && lrz_direction != TU_LRZ_UNKNOWN)
787*61046927SAndroid Build Coastguard Worker       cmd->state.lrz.prev_direction = lrz_direction;
788*61046927SAndroid Build Coastguard Worker 
789*61046927SAndroid Build Coastguard Worker    /* Invalidate LRZ and disable write if stencil test is enabled */
790*61046927SAndroid Build Coastguard Worker    bool stencil_test_enable = cmd->vk.dynamic_graphics_state.ds.stencil.test_enable;
791*61046927SAndroid Build Coastguard Worker    if (!disable_lrz && stencil_test_enable) {
792*61046927SAndroid Build Coastguard Worker       VkCompareOp stencil_front_compare_op = (VkCompareOp)
793*61046927SAndroid Build Coastguard Worker          cmd->vk.dynamic_graphics_state.ds.stencil.front.op.compare;
794*61046927SAndroid Build Coastguard Worker 
795*61046927SAndroid Build Coastguard Worker       VkCompareOp stencil_back_compare_op = (VkCompareOp)
796*61046927SAndroid Build Coastguard Worker          cmd->vk.dynamic_graphics_state.ds.stencil.back.op.compare;
797*61046927SAndroid Build Coastguard Worker 
798*61046927SAndroid Build Coastguard Worker       bool lrz_allowed = true;
799*61046927SAndroid Build Coastguard Worker       lrz_allowed = lrz_allowed && tu6_stencil_op_lrz_allowed(
800*61046927SAndroid Build Coastguard Worker                                       &gras_lrz_cntl, stencil_front_compare_op,
801*61046927SAndroid Build Coastguard Worker                                       cmd->state.stencil_front_write);
802*61046927SAndroid Build Coastguard Worker 
803*61046927SAndroid Build Coastguard Worker       lrz_allowed = lrz_allowed && tu6_stencil_op_lrz_allowed(
804*61046927SAndroid Build Coastguard Worker                                       &gras_lrz_cntl, stencil_back_compare_op,
805*61046927SAndroid Build Coastguard Worker                                       cmd->state.stencil_back_write);
806*61046927SAndroid Build Coastguard Worker 
807*61046927SAndroid Build Coastguard Worker       /* Without depth write it's enough to make sure that depth test
808*61046927SAndroid Build Coastguard Worker        * is executed after stencil test, so temporary disabling LRZ is enough.
809*61046927SAndroid Build Coastguard Worker        */
810*61046927SAndroid Build Coastguard Worker       if (!lrz_allowed) {
811*61046927SAndroid Build Coastguard Worker          if (z_write_enable) {
812*61046927SAndroid Build Coastguard Worker             tu_lrz_disable_reason(cmd, "Stencil write");
813*61046927SAndroid Build Coastguard Worker             disable_lrz = true;
814*61046927SAndroid Build Coastguard Worker          } else {
815*61046927SAndroid Build Coastguard Worker             perf_debug(cmd->device, "Skipping LRZ due to stencil write");
816*61046927SAndroid Build Coastguard Worker             temporary_disable_lrz = true;
817*61046927SAndroid Build Coastguard Worker          }
818*61046927SAndroid Build Coastguard Worker       }
819*61046927SAndroid Build Coastguard Worker    }
820*61046927SAndroid Build Coastguard Worker 
821*61046927SAndroid Build Coastguard Worker    /* Writing depth with blend enabled means we need to invalidate LRZ,
822*61046927SAndroid Build Coastguard Worker     * because the written depth value could mean that a later draw with
823*61046927SAndroid Build Coastguard Worker     * depth enabled (where we would otherwise write LRZ) could have
824*61046927SAndroid Build Coastguard Worker     * fragments which don't pass the depth test due to this draw.  For
825*61046927SAndroid Build Coastguard Worker     * example, consider this sequence of draws, with depth mode GREATER:
826*61046927SAndroid Build Coastguard Worker     *
827*61046927SAndroid Build Coastguard Worker     *   draw A:
828*61046927SAndroid Build Coastguard Worker     *     z=0.1, fragments pass
829*61046927SAndroid Build Coastguard Worker     *   draw B:
830*61046927SAndroid Build Coastguard Worker     *     z=0.4, fragments pass
831*61046927SAndroid Build Coastguard Worker     *     blend enabled (LRZ write disabled)
832*61046927SAndroid Build Coastguard Worker     *     depth write enabled
833*61046927SAndroid Build Coastguard Worker     *   draw C:
834*61046927SAndroid Build Coastguard Worker     *     z=0.2, fragments don't pass
835*61046927SAndroid Build Coastguard Worker     *     blend disabled
836*61046927SAndroid Build Coastguard Worker     *     depth write enabled
837*61046927SAndroid Build Coastguard Worker     *
838*61046927SAndroid Build Coastguard Worker     * Normally looking at the state in draw C, we'd assume we could
839*61046927SAndroid Build Coastguard Worker     * enable LRZ write.  But this would cause early-z/lrz to discard
840*61046927SAndroid Build Coastguard Worker     * fragments from draw A which should be visible due to draw B.
841*61046927SAndroid Build Coastguard Worker     */
842*61046927SAndroid Build Coastguard Worker    if (reads_dest && z_write_enable && cmd->device->instance->conservative_lrz) {
843*61046927SAndroid Build Coastguard Worker       tu_lrz_disable_reason(cmd, "Depth write + blending");
844*61046927SAndroid Build Coastguard Worker       disable_lrz = true;
845*61046927SAndroid Build Coastguard Worker    }
846*61046927SAndroid Build Coastguard Worker 
847*61046927SAndroid Build Coastguard Worker    if (disable_lrz)
848*61046927SAndroid Build Coastguard Worker       cmd->state.lrz.valid = false;
849*61046927SAndroid Build Coastguard Worker 
850*61046927SAndroid Build Coastguard Worker    if (disable_lrz && cmd->state.lrz.gpu_dir_tracking) {
851*61046927SAndroid Build Coastguard Worker       /* Direction byte on GPU should be set to CUR_DIR_DISABLED,
852*61046927SAndroid Build Coastguard Worker        * for this it's not enough to emit empty GRAS_LRZ_CNTL.
853*61046927SAndroid Build Coastguard Worker        */
854*61046927SAndroid Build Coastguard Worker       gras_lrz_cntl.enable = true;
855*61046927SAndroid Build Coastguard Worker       gras_lrz_cntl.dir = LRZ_DIR_INVALID;
856*61046927SAndroid Build Coastguard Worker 
857*61046927SAndroid Build Coastguard Worker       return gras_lrz_cntl;
858*61046927SAndroid Build Coastguard Worker    }
859*61046927SAndroid Build Coastguard Worker 
860*61046927SAndroid Build Coastguard Worker    if (temporary_disable_lrz)
861*61046927SAndroid Build Coastguard Worker       gras_lrz_cntl.enable = false;
862*61046927SAndroid Build Coastguard Worker 
863*61046927SAndroid Build Coastguard Worker    cmd->state.lrz.enabled = cmd->state.lrz.valid && gras_lrz_cntl.enable;
864*61046927SAndroid Build Coastguard Worker    if (!cmd->state.lrz.enabled)
865*61046927SAndroid Build Coastguard Worker       memset(&gras_lrz_cntl, 0, sizeof(gras_lrz_cntl));
866*61046927SAndroid Build Coastguard Worker 
867*61046927SAndroid Build Coastguard Worker    return gras_lrz_cntl;
868*61046927SAndroid Build Coastguard Worker }
869*61046927SAndroid Build Coastguard Worker 
870*61046927SAndroid Build Coastguard Worker template <chip CHIP>
871*61046927SAndroid Build Coastguard Worker void
tu6_emit_lrz(struct tu_cmd_buffer * cmd,struct tu_cs * cs)872*61046927SAndroid Build Coastguard Worker tu6_emit_lrz(struct tu_cmd_buffer *cmd, struct tu_cs *cs)
873*61046927SAndroid Build Coastguard Worker {
874*61046927SAndroid Build Coastguard Worker    const uint32_t a = cmd->state.subpass->depth_stencil_attachment.attachment;
875*61046927SAndroid Build Coastguard Worker    struct A6XX_GRAS_LRZ_CNTL gras_lrz_cntl = tu6_calculate_lrz_state<CHIP>(cmd, a);
876*61046927SAndroid Build Coastguard Worker 
877*61046927SAndroid Build Coastguard Worker    tu6_write_lrz_cntl<CHIP>(cmd, cs, gras_lrz_cntl);
878*61046927SAndroid Build Coastguard Worker    tu_cs_emit_regs(cs, A6XX_RB_LRZ_CNTL(.enable = gras_lrz_cntl.enable));
879*61046927SAndroid Build Coastguard Worker }
880*61046927SAndroid Build Coastguard Worker TU_GENX(tu6_emit_lrz);
881