1/* 2 * Copyright (C) 2016 Rob Clark <robclark@freedesktop.org> 3 * Copyright © 2018 Google, Inc. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 * 24 * Authors: 25 * Rob Clark <robclark@freedesktop.org> 26 */ 27 28#include "pipe/p_state.h" 29#include "util/u_memory.h" 30#include "util/u_string.h" 31 32#include "fd6_context.h" 33#include "fd6_zsa.h" 34 35/* update lza state based on stencil-test func: 36 * 37 * Conceptually the order of the pipeline is: 38 * 39 * 40 * FS -> Alpha-Test -> Stencil-Test -> Depth-Test 41 * | | 42 * if wrmask != 0 if wrmask != 0 43 * | | 44 * v v 45 * Stencil-Write Depth-Write 46 * 47 * Because Stencil-Test can have side effects (Stencil-Write) prior 48 * to depth test, in this case we potentially need to disable early 49 * lrz-test. See: 50 * 51 * https://www.khronos.org/opengl/wiki/Per-Sample_Processing 52 */ 53static void 54update_lrz_stencil(struct fd6_zsa_stateobj *so, enum pipe_compare_func func, 55 bool stencil_write) 56{ 57 switch (func) { 58 case PIPE_FUNC_ALWAYS: 59 /* nothing to do for LRZ, but for stencil test when stencil- 60 * write is enabled, we need to disable lrz-test, since 61 * conceptually stencil test and write happens before depth- 62 * test: 63 */ 64 if (stencil_write) { 65 so->lrz.enable = false; 66 so->lrz.test = false; 67 } 68 break; 69 case PIPE_FUNC_NEVER: 70 /* fragment never passes, disable lrz_write for this draw: */ 71 so->lrz.write = false; 72 break; 73 default: 74 /* whether the fragment passes or not depends on result 75 * of stencil test, which we cannot know when doing binning 76 * pass: 77 */ 78 so->lrz.write = false; 79 /* similarly to the PIPE_FUNC_ALWAY case, if there are side- 80 * effects from stencil test we need to disable lrz-test. 81 */ 82 if (stencil_write) { 83 so->lrz.enable = false; 84 so->lrz.test = false; 85 } 86 break; 87 } 88} 89 90void * 91fd6_zsa_state_create(struct pipe_context *pctx, 92 const struct pipe_depth_stencil_alpha_state *cso) 93{ 94 struct fd_context *ctx = fd_context(pctx); 95 struct fd6_zsa_stateobj *so; 96 97 so = CALLOC_STRUCT(fd6_zsa_stateobj); 98 if (!so) 99 return NULL; 100 101 so->base = *cso; 102 103 so->writes_zs = util_writes_depth_stencil(cso); 104 105 so->rb_depth_cntl |= 106 A6XX_RB_DEPTH_CNTL_ZFUNC(cso->depth_func); /* maps 1:1 */ 107 108 if (cso->depth_enabled) { 109 so->rb_depth_cntl |= 110 A6XX_RB_DEPTH_CNTL_Z_TEST_ENABLE | A6XX_RB_DEPTH_CNTL_Z_READ_ENABLE; 111 112 so->lrz.test = true; 113 114 if (cso->depth_writemask) { 115 so->lrz.write = true; 116 } 117 118 switch (cso->depth_func) { 119 case PIPE_FUNC_LESS: 120 case PIPE_FUNC_LEQUAL: 121 so->lrz.enable = true; 122 so->lrz.direction = FD_LRZ_LESS; 123 break; 124 125 case PIPE_FUNC_GREATER: 126 case PIPE_FUNC_GEQUAL: 127 so->lrz.enable = true; 128 so->lrz.direction = FD_LRZ_GREATER; 129 break; 130 131 case PIPE_FUNC_NEVER: 132 so->lrz.enable = true; 133 so->lrz.write = false; 134 so->lrz.direction = FD_LRZ_LESS; 135 break; 136 137 /* TODO revisit these: */ 138 case PIPE_FUNC_EQUAL: 139 case PIPE_FUNC_NOTEQUAL: 140 case PIPE_FUNC_ALWAYS: 141 so->lrz.write = false; 142 so->invalidate_lrz = true; 143 break; 144 } 145 } 146 147 if (cso->depth_writemask) 148 so->rb_depth_cntl |= A6XX_RB_DEPTH_CNTL_Z_WRITE_ENABLE; 149 150 if (cso->stencil[0].enabled) { 151 const struct pipe_stencil_state *s = &cso->stencil[0]; 152 153 /* stencil test happens before depth test, so without performing 154 * stencil test we don't really know what the updates to the 155 * depth buffer will be. 156 */ 157 update_lrz_stencil(so, s->func, !!s->writemask); 158 159 so->rb_stencil_control |= 160 A6XX_RB_STENCIL_CONTROL_STENCIL_READ | 161 A6XX_RB_STENCIL_CONTROL_STENCIL_ENABLE | 162 A6XX_RB_STENCIL_CONTROL_FUNC(s->func) | /* maps 1:1 */ 163 A6XX_RB_STENCIL_CONTROL_FAIL(fd_stencil_op(s->fail_op)) | 164 A6XX_RB_STENCIL_CONTROL_ZPASS(fd_stencil_op(s->zpass_op)) | 165 A6XX_RB_STENCIL_CONTROL_ZFAIL(fd_stencil_op(s->zfail_op)); 166 167 so->rb_stencilmask = A6XX_RB_STENCILMASK_MASK(s->valuemask); 168 so->rb_stencilwrmask = A6XX_RB_STENCILWRMASK_WRMASK(s->writemask); 169 170 if (cso->stencil[1].enabled) { 171 const struct pipe_stencil_state *bs = &cso->stencil[1]; 172 173 update_lrz_stencil(so, bs->func, !!bs->writemask); 174 175 so->rb_stencil_control |= 176 A6XX_RB_STENCIL_CONTROL_STENCIL_ENABLE_BF | 177 A6XX_RB_STENCIL_CONTROL_FUNC_BF(bs->func) | /* maps 1:1 */ 178 A6XX_RB_STENCIL_CONTROL_FAIL_BF(fd_stencil_op(bs->fail_op)) | 179 A6XX_RB_STENCIL_CONTROL_ZPASS_BF(fd_stencil_op(bs->zpass_op)) | 180 A6XX_RB_STENCIL_CONTROL_ZFAIL_BF(fd_stencil_op(bs->zfail_op)); 181 182 so->rb_stencilmask |= A6XX_RB_STENCILMASK_BFMASK(bs->valuemask); 183 so->rb_stencilwrmask |= A6XX_RB_STENCILWRMASK_BFWRMASK(bs->writemask); 184 } 185 } 186 187 if (cso->alpha_enabled) { 188 /* Alpha test is functionally a conditional discard, so we can't 189 * write LRZ before seeing if we end up discarding or not 190 */ 191 if (cso->alpha_func != PIPE_FUNC_ALWAYS) { 192 so->lrz.write = false; 193 so->alpha_test = true; 194 } 195 196 uint32_t ref = cso->alpha_ref_value * 255.0f; 197 so->rb_alpha_control = 198 A6XX_RB_ALPHA_CONTROL_ALPHA_TEST | 199 A6XX_RB_ALPHA_CONTROL_ALPHA_REF(ref) | 200 A6XX_RB_ALPHA_CONTROL_ALPHA_TEST_FUNC(cso->alpha_func); 201 } 202 203 for (int i = 0; i < 4; i++) { 204 struct fd_ringbuffer *ring = fd_ringbuffer_new_object(ctx->pipe, 9 * 4); 205 206 OUT_PKT4(ring, REG_A6XX_RB_ALPHA_CONTROL, 1); 207 OUT_RING(ring, 208 (i & FD6_ZSA_NO_ALPHA) 209 ? so->rb_alpha_control & ~A6XX_RB_ALPHA_CONTROL_ALPHA_TEST 210 : so->rb_alpha_control); 211 212 OUT_PKT4(ring, REG_A6XX_RB_STENCIL_CONTROL, 1); 213 OUT_RING(ring, so->rb_stencil_control); 214 215 OUT_PKT4(ring, REG_A6XX_RB_DEPTH_CNTL, 1); 216 OUT_RING(ring, 217 so->rb_depth_cntl | COND(i & FD6_ZSA_DEPTH_CLIP_DISABLE, 218 A6XX_RB_DEPTH_CNTL_Z_CLIP_DISABLE)); 219 220 OUT_PKT4(ring, REG_A6XX_RB_STENCILMASK, 2); 221 OUT_RING(ring, so->rb_stencilmask); 222 OUT_RING(ring, so->rb_stencilwrmask); 223 224 so->stateobj[i] = ring; 225 } 226 227 return so; 228} 229 230void 231fd6_zsa_state_delete(struct pipe_context *pctx, void *hwcso) 232{ 233 struct fd6_zsa_stateobj *so = hwcso; 234 235 for (int i = 0; i < ARRAY_SIZE(so->stateobj); i++) 236 fd_ringbuffer_del(so->stateobj[i]); 237 FREE(hwcso); 238} 239