/* VC4_CONFIGURATION_BITS */
uint8_t config_bits[3];
+
+ /** Uniforms for stencil state.
+ *
+ * Index 0 is either the front config, or the front-and-back config.
+ * Index 1 is the back config if doing separate back stencil.
+ * Index 2 is the writemask config if it's not a common mask value.
+ */
+ uint32_t stencil_uniforms[3];
};
static inline struct vc4_context *
if (vc4->zsa && vc4->zsa->base.depth.enabled) {
vc4->resolve |= PIPE_CLEAR_DEPTH;
}
+ if (vc4->zsa && vc4->zsa->base.stencil[0].enabled)
+ vc4->resolve |= PIPE_CLEAR_STENCIL;
vc4->resolve |= PIPE_CLEAR_COLOR0;
vc4->shader_rec_count++;
struct vc4_key base;
enum pipe_format color_format;
bool depth_enabled;
+ bool stencil_enabled;
+ bool stencil_twoside;
+ bool stencil_full_writemasks;
bool is_points;
bool is_lines;
if (c->discard.file != QFILE_NULL)
qir_TLB_DISCARD_SETUP(c, c->discard);
+ if (c->fs_key->stencil_enabled) {
+ qir_TLB_STENCIL_SETUP(c, add_uniform(c, QUNIFORM_STENCIL, 0));
+ if (c->fs_key->stencil_twoside) {
+ qir_TLB_STENCIL_SETUP(c, add_uniform(c, QUNIFORM_STENCIL, 1));
+ }
+ if (c->fs_key->stencil_full_writemasks) {
+ qir_TLB_STENCIL_SETUP(c, add_uniform(c, QUNIFORM_STENCIL, 2));
+ }
+ }
+
if (c->fs_key->depth_enabled) {
struct qreg z;
if (c->output_position_index != -1) {
if (vc4->framebuffer.cbufs[0])
key->color_format = vc4->framebuffer.cbufs[0]->format;
- key->depth_enabled = vc4->zsa->base.depth.enabled;
+ key->stencil_enabled = vc4->zsa->stencil_uniforms[0] != 0;
+ key->stencil_twoside = vc4->zsa->stencil_uniforms[1] != 0;
+ key->stencil_full_writemasks = vc4->zsa->stencil_uniforms[2] != 0;
+ key->depth_enabled = (vc4->zsa->base.depth.enabled ||
+ key->stencil_enabled);
vc4->prog.fs = util_hash_table_get(vc4->fs_cache, key);
if (vc4->prog.fs)
cl_f(&vc4->uniforms,
vc4->blend_color.color[uinfo->data[i]]);
break;
+
+ case QUNIFORM_STENCIL:
+ cl_u32(&vc4->uniforms,
+ vc4->zsa->stencil_uniforms[uinfo->data[i]] |
+ (uinfo->data[i] <= 1 ?
+ (vc4->stencil_ref.ref_value[uinfo->data[i]] << 8) :
+ 0));
+ break;
}
#if 0
uint32_t written_val = *(uint32_t *)(vc4->uniforms.next - 4);
[QOP_VPM_WRITE] = { "vpm_write", 0, 1, true },
[QOP_VPM_READ] = { "vpm_read", 0, 1, true },
[QOP_TLB_DISCARD_SETUP] = { "discard", 0, 1, true },
+ [QOP_TLB_STENCIL_SETUP] = { "tlb_stencil_setup", 0, 1, true },
[QOP_TLB_Z_WRITE] = { "tlb_z", 0, 1, true },
[QOP_TLB_COLOR_WRITE] = { "tlb_color", 0, 1, true },
[QOP_TLB_COLOR_READ] = { "tlb_color_read", 1, 0, true },
QOP_VPM_WRITE,
QOP_VPM_READ,
QOP_TLB_DISCARD_SETUP,
+ QOP_TLB_STENCIL_SETUP,
QOP_TLB_Z_WRITE,
QOP_TLB_COLOR_WRITE,
QOP_TLB_COLOR_READ,
QUNIFORM_TEXRECT_SCALE_Y,
QUNIFORM_BLEND_CONST_COLOR,
+ QUNIFORM_STENCIL,
};
struct vc4_compile {
QIR_ALU0(TLB_COLOR_READ)
QIR_NODST_1(TLB_Z_WRITE)
QIR_NODST_1(TLB_DISCARD_SETUP)
+QIR_NODST_1(TLB_STENCIL_SETUP)
static inline struct qreg
qir_R4_UNPACK(struct vc4_compile *c, struct qreg r4, int i)
*last_inst(c) |= QPU_SF;
break;
+ case QOP_TLB_STENCIL_SETUP:
+ queue(c, qpu_a_MOV(qpu_ra(QPU_W_TLB_STENCIL_SETUP), src[0]));
+ break;
+
case QOP_TLB_Z_WRITE:
queue(c, qpu_a_MOV(qpu_ra(QPU_W_TLB_Z), src[0]));
if (discard) {
case QPU_W_HOST_INT:
case QPU_W_TMU_NOSWAP:
- case QPU_W_TLB_STENCIL_SETUP:
case QPU_W_TLB_ALPHA_MASK:
case QPU_W_MUTEX_RELEASE:
/* XXX: I haven't thought about these, so don't support them
* triggered by QPU_W_VPM_ADDR writes.
*/
return true;
+
+ case QPU_W_TLB_STENCIL_SETUP:
+ return true;
}
return true;
return vc4_generic_cso_state_create(cso, sizeof(*cso));
}
+/**
+ * The TLB_STENCIL_SETUP data has a little bitfield for common writemask
+ * values, so you don't have to do a separate writemask setup.
+ */
+static uint8_t
+tlb_stencil_setup_writemask(uint8_t mask)
+{
+ switch (mask) {
+ case 0x1: return 0;
+ case 0x3: return 1;
+ case 0xf: return 2;
+ case 0xff: return 3;
+ default: return 0xff;
+ }
+}
+
+static uint32_t
+tlb_stencil_setup_bits(const struct pipe_stencil_state *state,
+ uint8_t writemask_bits)
+{
+ static const uint8_t op_map[] = {
+ [PIPE_STENCIL_OP_ZERO] = 0,
+ [PIPE_STENCIL_OP_KEEP] = 1,
+ [PIPE_STENCIL_OP_REPLACE] = 2,
+ [PIPE_STENCIL_OP_INCR] = 3,
+ [PIPE_STENCIL_OP_DECR] = 4,
+ [PIPE_STENCIL_OP_INVERT] = 5,
+ [PIPE_STENCIL_OP_INCR_WRAP] = 6,
+ [PIPE_STENCIL_OP_DECR_WRAP] = 7,
+ };
+ uint32_t bits = 0;
+
+ if (writemask_bits != 0xff)
+ bits |= writemask_bits << 28;
+ bits |= op_map[state->zfail_op] << 25;
+ bits |= op_map[state->zpass_op] << 22;
+ bits |= op_map[state->fail_op] << 19;
+ bits |= state->func << 16;
+ /* Ref is filled in at uniform upload time */
+ bits |= state->valuemask << 0;
+
+ return bits;
+}
+
static void *
vc4_create_depth_stencil_alpha_state(struct pipe_context *pctx,
const struct pipe_depth_stencil_alpha_state *cso)
VC4_CONFIG_BITS_DEPTH_FUNC_SHIFT);
}
+ if (cso->stencil[0].enabled) {
+ const struct pipe_stencil_state *front = &cso->stencil[0];
+ const struct pipe_stencil_state *back = &cso->stencil[1];
+
+ uint8_t front_writemask_bits =
+ tlb_stencil_setup_writemask(front->writemask);
+ uint8_t back_writemask_bits =
+ tlb_stencil_setup_writemask(back->writemask);
+
+ so->stencil_uniforms[0] =
+ tlb_stencil_setup_bits(front, front_writemask_bits);
+ if (back->enabled) {
+ so->stencil_uniforms[0] |= (1 << 30);
+ so->stencil_uniforms[1] =
+ tlb_stencil_setup_bits(back, back_writemask_bits);
+ so->stencil_uniforms[1] |= (2 << 30);
+ } else {
+ so->stencil_uniforms[0] |= (3 << 30);
+ }
+
+ if (front_writemask_bits == 0xff ||
+ back_writemask_bits == 0xff) {
+ so->stencil_uniforms[2] = (front_writemask_bits |
+ (back_writemask_bits << 8));
+ }
+ }
+
return so;
}