llvmpipe: move all depth/stencil/alpha pixel processing into one stage

This commit is contained in:
Keith Whitwell 2009-07-27 08:17:45 +01:00 committed by José Fonseca
parent b8c437f20f
commit 05bfd93c3f
13 changed files with 586 additions and 963 deletions

View file

@ -19,13 +19,8 @@ C_SOURCES = \
lp_prim_vbuf.c \
lp_quad_pipe.c \
lp_quad_stipple.c \
lp_quad_earlyz.c \
lp_quad_depth_test.c \
lp_quad_stencil.c \
lp_quad_fs.c \
lp_quad_alpha_test.c \
lp_quad_occlusion.c \
lp_quad_coverage.c \
lp_quad_blend.c \
lp_screen.c \
lp_setup.c \

View file

@ -88,14 +88,8 @@ static void llvmpipe_destroy( struct pipe_context *pipe )
if (llvmpipe->draw)
draw_destroy( llvmpipe->draw );
llvmpipe->quad.polygon_stipple->destroy( llvmpipe->quad.polygon_stipple );
llvmpipe->quad.earlyz->destroy( llvmpipe->quad.earlyz );
llvmpipe->quad.shade->destroy( llvmpipe->quad.shade );
llvmpipe->quad.alpha_test->destroy( llvmpipe->quad.alpha_test );
llvmpipe->quad.depth_test->destroy( llvmpipe->quad.depth_test );
llvmpipe->quad.stencil_test->destroy( llvmpipe->quad.stencil_test );
llvmpipe->quad.occlusion->destroy( llvmpipe->quad.occlusion );
llvmpipe->quad.coverage->destroy( llvmpipe->quad.coverage );
llvmpipe->quad.blend->destroy( llvmpipe->quad.blend );
for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++)
@ -230,14 +224,8 @@ llvmpipe_create( struct pipe_screen *screen )
/* setup quad rendering stages */
llvmpipe->quad.polygon_stipple = lp_quad_polygon_stipple_stage(llvmpipe);
llvmpipe->quad.earlyz = lp_quad_earlyz_stage(llvmpipe);
llvmpipe->quad.shade = lp_quad_shade_stage(llvmpipe);
llvmpipe->quad.alpha_test = lp_quad_alpha_test_stage(llvmpipe);
llvmpipe->quad.depth_test = lp_quad_depth_test_stage(llvmpipe);
llvmpipe->quad.stencil_test = lp_quad_stencil_test_stage(llvmpipe);
llvmpipe->quad.occlusion = lp_quad_occlusion_stage(llvmpipe);
llvmpipe->quad.coverage = lp_quad_coverage_stage(llvmpipe);
llvmpipe->quad.blend = lp_quad_blend_stage(llvmpipe);
/* vertex shader samplers */

View file

@ -114,14 +114,8 @@ struct llvmpipe_context {
/** Software quad rendering pipeline */
struct {
struct quad_stage *polygon_stipple;
struct quad_stage *earlyz;
struct quad_stage *shade;
struct quad_stage *alpha_test;
struct quad_stage *stencil_test;
struct quad_stage *depth_test;
struct quad_stage *occlusion;
struct quad_stage *coverage;
struct quad_stage *blend;
struct quad_stage *first; /**< points to one of the above stages */

View file

@ -1,112 +0,0 @@
/**
* quad alpha test
*/
#include "lp_context.h"
#include "lp_quad.h"
#include "lp_quad_pipe.h"
#include "pipe/p_defines.h"
#include "util/u_memory.h"
#define ALPHATEST( FUNC, COMP ) \
static void \
alpha_test_quads_##FUNC( struct quad_stage *qs, \
struct quad_header *quads[], \
unsigned nr ) \
{ \
const float ref = qs->llvmpipe->depth_stencil->alpha.ref_value; \
const uint cbuf = 0; /* only output[0].alpha is tested */ \
unsigned pass_nr = 0; \
unsigned i; \
\
for (i = 0; i < nr; i++) { \
const float *aaaa = quads[i]->output.color[cbuf][3]; \
unsigned passMask = 0; \
\
if (aaaa[0] COMP ref) passMask |= (1 << 0); \
if (aaaa[1] COMP ref) passMask |= (1 << 1); \
if (aaaa[2] COMP ref) passMask |= (1 << 2); \
if (aaaa[3] COMP ref) passMask |= (1 << 3); \
\
quads[i]->inout.mask &= passMask; \
\
if (quads[i]->inout.mask) \
quads[pass_nr++] = quads[i]; \
} \
\
if (pass_nr) \
qs->next->run(qs->next, quads, pass_nr); \
}
ALPHATEST( LESS, < )
ALPHATEST( EQUAL, == )
ALPHATEST( LEQUAL, <= )
ALPHATEST( GREATER, > )
ALPHATEST( NOTEQUAL, != )
ALPHATEST( GEQUAL, >= )
/* XXX: Incorporate into shader using KILP.
*/
static void
alpha_test_quad(struct quad_stage *qs,
struct quad_header *quads[],
unsigned nr)
{
switch (qs->llvmpipe->depth_stencil->alpha.func) {
case PIPE_FUNC_LESS:
alpha_test_quads_LESS( qs, quads, nr );
break;
case PIPE_FUNC_EQUAL:
alpha_test_quads_EQUAL( qs, quads, nr );
break;
case PIPE_FUNC_LEQUAL:
alpha_test_quads_LEQUAL( qs, quads, nr );
break;
case PIPE_FUNC_GREATER:
alpha_test_quads_GREATER( qs, quads, nr );
break;
case PIPE_FUNC_NOTEQUAL:
alpha_test_quads_NOTEQUAL( qs, quads, nr );
break;
case PIPE_FUNC_GEQUAL:
alpha_test_quads_GEQUAL( qs, quads, nr );
break;
case PIPE_FUNC_ALWAYS:
assert(0); /* should be caught earlier */
qs->next->run(qs->next, quads, nr);
break;
case PIPE_FUNC_NEVER:
default:
assert(0); /* should be caught earlier */
return;
}
}
static void alpha_test_begin(struct quad_stage *qs)
{
qs->next->begin(qs->next);
}
static void alpha_test_destroy(struct quad_stage *qs)
{
FREE( qs );
}
struct quad_stage *
lp_quad_alpha_test_stage( struct llvmpipe_context *llvmpipe )
{
struct quad_stage *stage = CALLOC_STRUCT(quad_stage);
stage->llvmpipe = llvmpipe;
stage->begin = alpha_test_begin;
stage->run = alpha_test_quad;
stage->destroy = alpha_test_destroy;
return stage;
}

View file

@ -1,101 +0,0 @@
/**************************************************************************
*
* Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
/**
* \brief Apply AA coverage to quad alpha valus
* \author Brian Paul
*/
#include "pipe/p_defines.h"
#include "util/u_memory.h"
#include "lp_context.h"
#include "lp_quad.h"
#include "lp_quad_pipe.h"
/**
* Multiply quad's alpha values by the fragment coverage.
*/
static INLINE void
coverage_quad(struct quad_stage *qs, struct quad_header *quad)
{
struct llvmpipe_context *llvmpipe = qs->llvmpipe;
uint cbuf;
/* loop over colorbuffer outputs */
for (cbuf = 0; cbuf < llvmpipe->framebuffer.nr_cbufs; cbuf++) {
float (*quadColor)[4] = quad->output.color[cbuf];
unsigned j;
for (j = 0; j < QUAD_SIZE; j++) {
assert(quad->input.coverage[j] >= 0.0);
assert(quad->input.coverage[j] <= 1.0);
quadColor[3][j] *= quad->input.coverage[j];
}
}
}
/* XXX: Incorporate into shader after alpha_test.
*/
static void
coverage_run(struct quad_stage *qs,
struct quad_header *quads[],
unsigned nr)
{
unsigned i;
for (i = 0; i < nr; i++)
coverage_quad( qs, quads[i] );
qs->next->run(qs->next, quads, nr);
}
static void coverage_begin(struct quad_stage *qs)
{
qs->next->begin(qs->next);
}
static void coverage_destroy(struct quad_stage *qs)
{
FREE( qs );
}
struct quad_stage *lp_quad_coverage_stage( struct llvmpipe_context *llvmpipe )
{
struct quad_stage *stage = CALLOC_STRUCT(quad_stage);
stage->llvmpipe = llvmpipe;
stage->begin = coverage_begin;
stage->run = coverage_run;
stage->destroy = coverage_destroy;
return stage;
}

View file

@ -31,61 +31,109 @@
#include "pipe/p_defines.h"
#include "util/u_memory.h"
#include "tgsi/tgsi_scan.h"
#include "lp_context.h"
#include "lp_quad.h"
#include "lp_surface.h"
#include "lp_quad_pipe.h"
#include "lp_tile_cache.h"
#include "lp_state.h" /* for lp_fragment_shader */
/**
* Do depth testing for a quad.
* Not static since it's used by the stencil code.
*/
/*
* To increase efficiency, we should probably have multiple versions
* of this function that are specifically for Z16, Z32 and FP Z buffers.
* Try to effectively do that with codegen...
*/
boolean
lp_depth_test_quad(struct quad_stage *qs, struct quad_header *quad)
{
struct llvmpipe_context *llvmpipe = qs->llvmpipe;
struct pipe_surface *ps = llvmpipe->framebuffer.zsbuf;
const enum pipe_format format = ps->format;
struct depth_data {
struct pipe_surface *ps;
enum pipe_format format;
unsigned bzzzz[QUAD_SIZE]; /**< Z values fetched from depth buffer */
unsigned qzzzz[QUAD_SIZE]; /**< Z values from the quad */
unsigned zmask = 0;
ubyte stencilVals[QUAD_SIZE];
struct llvmpipe_cached_tile *tile;
};
static void
get_depth_stencil_values( struct depth_data *data,
const struct quad_header *quad )
{
unsigned j;
struct llvmpipe_cached_tile *tile
= lp_get_cached_tile(llvmpipe->zsbuf_cache, quad->input.x0, quad->input.y0);
const struct llvmpipe_cached_tile *tile = data->tile;
assert(ps); /* shouldn't get here if there's no zbuffer */
switch (data->format) {
case PIPE_FORMAT_Z16_UNORM:
for (j = 0; j < QUAD_SIZE; j++) {
int x = quad->input.x0 % TILE_SIZE + (j & 1);
int y = quad->input.y0 % TILE_SIZE + (j >> 1);
data->bzzzz[j] = tile->data.depth16[y][x];
}
break;
case PIPE_FORMAT_Z32_UNORM:
for (j = 0; j < QUAD_SIZE; j++) {
int x = quad->input.x0 % TILE_SIZE + (j & 1);
int y = quad->input.y0 % TILE_SIZE + (j >> 1);
data->bzzzz[j] = tile->data.depth32[y][x];
}
break;
case PIPE_FORMAT_X8Z24_UNORM:
case PIPE_FORMAT_S8Z24_UNORM:
for (j = 0; j < QUAD_SIZE; j++) {
int x = quad->input.x0 % TILE_SIZE + (j & 1);
int y = quad->input.y0 % TILE_SIZE + (j >> 1);
data->bzzzz[j] = tile->data.depth32[y][x] & 0xffffff;
data->stencilVals[j] = tile->data.depth32[y][x] >> 24;
}
break;
case PIPE_FORMAT_Z24X8_UNORM:
case PIPE_FORMAT_Z24S8_UNORM:
for (j = 0; j < QUAD_SIZE; j++) {
int x = quad->input.x0 % TILE_SIZE + (j & 1);
int y = quad->input.y0 % TILE_SIZE + (j >> 1);
data->bzzzz[j] = tile->data.depth32[y][x] >> 8;
data->stencilVals[j] = tile->data.depth32[y][x] & 0xff;
}
break;
default:
assert(0);
}
}
/*
* Convert quad's float depth values to int depth values (qzzzz).
/* If the shader has not been run, interpolate the depth values
* ourselves.
*/
static void
interpolate_quad_depth( struct quad_header *quad )
{
const float fx = (float) quad->input.x0;
const float fy = (float) quad->input.y0;
const float dzdx = quad->posCoef->dadx[2];
const float dzdy = quad->posCoef->dady[2];
const float z0 = quad->posCoef->a0[2] + dzdx * fx + dzdy * fy;
quad->output.depth[0] = z0;
quad->output.depth[1] = z0 + dzdx;
quad->output.depth[2] = z0 + dzdy;
quad->output.depth[3] = z0 + dzdx + dzdy;
}
static void
convert_quad_depth( struct depth_data *data,
const struct quad_header *quad )
{
unsigned j;
/* Convert quad's float depth values to int depth values (qzzzz).
* If the Z buffer stores integer values, we _have_ to do the depth
* compares with integers (not floats). Otherwise, the float->int->float
* conversion of Z values (which isn't an identity function) will cause
* Z-fighting errors.
*
* Also, get the zbuffer values (bzzzz) from the cached tile.
*/
switch (format) {
switch (data->format) {
case PIPE_FORMAT_Z16_UNORM:
{
float scale = 65535.0;
for (j = 0; j < QUAD_SIZE; j++) {
qzzzz[j] = (unsigned) (quad->output.depth[j] * scale);
}
for (j = 0; j < QUAD_SIZE; j++) {
int x = quad->input.x0 % TILE_SIZE + (j & 1);
int y = quad->input.y0 % TILE_SIZE + (j >> 1);
bzzzz[j] = tile->data.depth16[y][x];
data->qzzzz[j] = (unsigned) (quad->output.depth[j] * scale);
}
}
break;
@ -94,53 +142,286 @@ lp_depth_test_quad(struct quad_stage *qs, struct quad_header *quad)
double scale = (double) (uint) ~0UL;
for (j = 0; j < QUAD_SIZE; j++) {
qzzzz[j] = (unsigned) (quad->output.depth[j] * scale);
}
for (j = 0; j < QUAD_SIZE; j++) {
int x = quad->input.x0 % TILE_SIZE + (j & 1);
int y = quad->input.y0 % TILE_SIZE + (j >> 1);
bzzzz[j] = tile->data.depth32[y][x];
data->qzzzz[j] = (unsigned) (quad->output.depth[j] * scale);
}
}
break;
case PIPE_FORMAT_X8Z24_UNORM:
/* fall-through */
case PIPE_FORMAT_S8Z24_UNORM:
{
float scale = (float) ((1 << 24) - 1);
for (j = 0; j < QUAD_SIZE; j++) {
qzzzz[j] = (unsigned) (quad->output.depth[j] * scale);
}
for (j = 0; j < QUAD_SIZE; j++) {
int x = quad->input.x0 % TILE_SIZE + (j & 1);
int y = quad->input.y0 % TILE_SIZE + (j >> 1);
bzzzz[j] = tile->data.depth32[y][x] & 0xffffff;
data->qzzzz[j] = (unsigned) (quad->output.depth[j] * scale);
}
}
break;
case PIPE_FORMAT_Z24X8_UNORM:
/* fall-through */
case PIPE_FORMAT_Z24S8_UNORM:
{
float scale = (float) ((1 << 24) - 1);
for (j = 0; j < QUAD_SIZE; j++) {
qzzzz[j] = (unsigned) (quad->output.depth[j] * scale);
}
for (j = 0; j < QUAD_SIZE; j++) {
int x = quad->input.x0 % TILE_SIZE + (j & 1);
int y = quad->input.y0 % TILE_SIZE + (j >> 1);
bzzzz[j] = tile->data.depth32[y][x] >> 8;
data->qzzzz[j] = (unsigned) (quad->output.depth[j] * scale);
}
}
break;
default:
assert(0);
}
}
static void
write_depth_stencil_values( struct depth_data *data,
struct quad_header *quad )
{
struct llvmpipe_cached_tile *tile = data->tile;
unsigned j;
/* put updated Z values back into cached tile */
switch (data->format) {
case PIPE_FORMAT_Z16_UNORM:
for (j = 0; j < QUAD_SIZE; j++) {
int x = quad->input.x0 % TILE_SIZE + (j & 1);
int y = quad->input.y0 % TILE_SIZE + (j >> 1);
tile->data.depth16[y][x] = (ushort) data->bzzzz[j];
}
break;
case PIPE_FORMAT_X8Z24_UNORM:
case PIPE_FORMAT_Z32_UNORM:
for (j = 0; j < QUAD_SIZE; j++) {
int x = quad->input.x0 % TILE_SIZE + (j & 1);
int y = quad->input.y0 % TILE_SIZE + (j >> 1);
tile->data.depth32[y][x] = data->bzzzz[j];
}
break;
case PIPE_FORMAT_S8Z24_UNORM:
for (j = 0; j < QUAD_SIZE; j++) {
int x = quad->input.x0 % TILE_SIZE + (j & 1);
int y = quad->input.y0 % TILE_SIZE + (j >> 1);
tile->data.depth32[y][x] = (data->stencilVals[j] << 24) | data->bzzzz[j];
}
break;
case PIPE_FORMAT_Z24S8_UNORM:
for (j = 0; j < QUAD_SIZE; j++) {
int x = quad->input.x0 % TILE_SIZE + (j & 1);
int y = quad->input.y0 % TILE_SIZE + (j >> 1);
tile->data.depth32[y][x] = (data->bzzzz[j] << 8) | data->stencilVals[j];
}
break;
case PIPE_FORMAT_Z24X8_UNORM:
for (j = 0; j < QUAD_SIZE; j++) {
int x = quad->input.x0 % TILE_SIZE + (j & 1);
int y = quad->input.y0 % TILE_SIZE + (j >> 1);
tile->data.depth32[y][x] = data->bzzzz[j] << 8;
}
break;
default:
assert(0);
}
}
/** Only 8-bit stencil supported */
#define STENCIL_MAX 0xff
/**
* Do the basic stencil test (compare stencil buffer values against the
* reference value.
*
* \param data->stencilVals the stencil values from the stencil buffer
* \param func the stencil func (PIPE_FUNC_x)
* \param ref the stencil reference value
* \param valMask the stencil value mask indicating which bits of the stencil
* values and ref value are to be used.
* \return mask indicating which pixels passed the stencil test
*/
static unsigned
do_stencil_test(struct depth_data *data,
unsigned func,
unsigned ref, unsigned valMask)
{
unsigned passMask = 0x0;
unsigned j;
ref &= valMask;
switch (func) {
case PIPE_FUNC_NEVER:
/* passMask = 0x0 */
break;
case PIPE_FUNC_LESS:
for (j = 0; j < QUAD_SIZE; j++) {
if (ref < (data->stencilVals[j] & valMask)) {
passMask |= (1 << j);
}
}
break;
case PIPE_FUNC_EQUAL:
for (j = 0; j < QUAD_SIZE; j++) {
if (ref == (data->stencilVals[j] & valMask)) {
passMask |= (1 << j);
}
}
break;
case PIPE_FUNC_LEQUAL:
for (j = 0; j < QUAD_SIZE; j++) {
if (ref <= (data->stencilVals[j] & valMask)) {
passMask |= (1 << j);
}
}
break;
case PIPE_FUNC_GREATER:
for (j = 0; j < QUAD_SIZE; j++) {
if (ref > (data->stencilVals[j] & valMask)) {
passMask |= (1 << j);
}
}
break;
case PIPE_FUNC_NOTEQUAL:
for (j = 0; j < QUAD_SIZE; j++) {
if (ref != (data->stencilVals[j] & valMask)) {
passMask |= (1 << j);
}
}
break;
case PIPE_FUNC_GEQUAL:
for (j = 0; j < QUAD_SIZE; j++) {
if (ref >= (data->stencilVals[j] & valMask)) {
passMask |= (1 << j);
}
}
break;
case PIPE_FUNC_ALWAYS:
passMask = MASK_ALL;
break;
default:
assert(0);
}
return passMask;
}
/**
* Apply the stencil operator to stencil values.
*
* \param data->stencilVals the stencil buffer values (read and written)
* \param mask indicates which pixels to update
* \param op the stencil operator (PIPE_STENCIL_OP_x)
* \param ref the stencil reference value
* \param wrtMask writemask controlling which bits are changed in the
* stencil values
*/
static void
apply_stencil_op(struct depth_data *data,
unsigned mask, unsigned op, ubyte ref, ubyte wrtMask)
{
unsigned j;
ubyte newstencil[QUAD_SIZE];
for (j = 0; j < QUAD_SIZE; j++) {
newstencil[j] = data->stencilVals[j];
}
switch (op) {
case PIPE_STENCIL_OP_KEEP:
/* no-op */
break;
case PIPE_STENCIL_OP_ZERO:
for (j = 0; j < QUAD_SIZE; j++) {
if (mask & (1 << j)) {
newstencil[j] = 0;
}
}
break;
case PIPE_STENCIL_OP_REPLACE:
for (j = 0; j < QUAD_SIZE; j++) {
if (mask & (1 << j)) {
newstencil[j] = ref;
}
}
break;
case PIPE_STENCIL_OP_INCR:
for (j = 0; j < QUAD_SIZE; j++) {
if (mask & (1 << j)) {
if (data->stencilVals[j] < STENCIL_MAX) {
newstencil[j] = data->stencilVals[j] + 1;
}
}
}
break;
case PIPE_STENCIL_OP_DECR:
for (j = 0; j < QUAD_SIZE; j++) {
if (mask & (1 << j)) {
if (data->stencilVals[j] > 0) {
newstencil[j] = data->stencilVals[j] - 1;
}
}
}
break;
case PIPE_STENCIL_OP_INCR_WRAP:
for (j = 0; j < QUAD_SIZE; j++) {
if (mask & (1 << j)) {
newstencil[j] = data->stencilVals[j] + 1;
}
}
break;
case PIPE_STENCIL_OP_DECR_WRAP:
for (j = 0; j < QUAD_SIZE; j++) {
if (mask & (1 << j)) {
newstencil[j] = data->stencilVals[j] - 1;
}
}
break;
case PIPE_STENCIL_OP_INVERT:
for (j = 0; j < QUAD_SIZE; j++) {
if (mask & (1 << j)) {
newstencil[j] = ~data->stencilVals[j];
}
}
break;
default:
assert(0);
}
/*
* update the stencil values
*/
if (wrtMask != STENCIL_MAX) {
/* apply bit-wise stencil buffer writemask */
for (j = 0; j < QUAD_SIZE; j++) {
data->stencilVals[j] = (wrtMask & newstencil[j]) | (~wrtMask & data->stencilVals[j]);
}
}
else {
for (j = 0; j < QUAD_SIZE; j++) {
data->stencilVals[j] = newstencil[j];
}
}
}
/*
* To increase efficiency, we should probably have multiple versions
* of this function that are specifically for Z16, Z32 and FP Z buffers.
* Try to effectively do that with codegen...
*/
static boolean
depth_test_quad(struct quad_stage *qs,
struct depth_data *data,
struct quad_header *quad)
{
struct llvmpipe_context *llvmpipe = qs->llvmpipe;
unsigned zmask = 0;
unsigned j;
switch (llvmpipe->depth_stencil->depth.func) {
case PIPE_FUNC_NEVER:
@ -151,37 +432,37 @@ lp_depth_test_quad(struct quad_stage *qs, struct quad_header *quad)
* Like this: quad->mask &= (quad->outputs.depth < zzzz);
*/
for (j = 0; j < QUAD_SIZE; j++) {
if (qzzzz[j] < bzzzz[j])
if (data->qzzzz[j] < data->bzzzz[j])
zmask |= 1 << j;
}
break;
case PIPE_FUNC_EQUAL:
for (j = 0; j < QUAD_SIZE; j++) {
if (qzzzz[j] == bzzzz[j])
if (data->qzzzz[j] == data->bzzzz[j])
zmask |= 1 << j;
}
break;
case PIPE_FUNC_LEQUAL:
for (j = 0; j < QUAD_SIZE; j++) {
if (qzzzz[j] <= bzzzz[j])
if (data->qzzzz[j] <= data->bzzzz[j])
zmask |= (1 << j);
}
break;
case PIPE_FUNC_GREATER:
for (j = 0; j < QUAD_SIZE; j++) {
if (qzzzz[j] > bzzzz[j])
if (data->qzzzz[j] > data->bzzzz[j])
zmask |= (1 << j);
}
break;
case PIPE_FUNC_NOTEQUAL:
for (j = 0; j < QUAD_SIZE; j++) {
if (qzzzz[j] != bzzzz[j])
if (data->qzzzz[j] != data->bzzzz[j])
zmask |= (1 << j);
}
break;
case PIPE_FUNC_GEQUAL:
for (j = 0; j < QUAD_SIZE; j++) {
if (qzzzz[j] >= bzzzz[j])
if (data->qzzzz[j] >= data->bzzzz[j])
zmask |= (1 << j);
}
break;
@ -196,62 +477,15 @@ lp_depth_test_quad(struct quad_stage *qs, struct quad_header *quad)
if (quad->inout.mask == 0)
return FALSE;
/* Update our internal copy only if writemask set. Even if
* depth.writemask is FALSE, may still need to write out buffer
* data due to stencil changes.
*/
if (llvmpipe->depth_stencil->depth.writemask) {
/* This is also efficient with sse / spe instructions:
*/
for (j = 0; j < QUAD_SIZE; j++) {
if (quad->inout.mask & (1 << j)) {
bzzzz[j] = qzzzz[j];
}
}
/* put updated Z values back into cached tile */
switch (format) {
case PIPE_FORMAT_Z16_UNORM:
for (j = 0; j < QUAD_SIZE; j++) {
int x = quad->input.x0 % TILE_SIZE + (j & 1);
int y = quad->input.y0 % TILE_SIZE + (j >> 1);
tile->data.depth16[y][x] = (ushort) bzzzz[j];
if (quad->inout.mask & (1 << j)) {
data->bzzzz[j] = data->qzzzz[j];
}
break;
case PIPE_FORMAT_X8Z24_UNORM:
/* fall-through */
/* (yes, this falls through to a different case than above) */
case PIPE_FORMAT_Z32_UNORM:
for (j = 0; j < QUAD_SIZE; j++) {
int x = quad->input.x0 % TILE_SIZE + (j & 1);
int y = quad->input.y0 % TILE_SIZE + (j >> 1);
tile->data.depth32[y][x] = bzzzz[j];
}
break;
case PIPE_FORMAT_S8Z24_UNORM:
for (j = 0; j < QUAD_SIZE; j++) {
int x = quad->input.x0 % TILE_SIZE + (j & 1);
int y = quad->input.y0 % TILE_SIZE + (j >> 1);
uint s8z24 = tile->data.depth32[y][x];
s8z24 = (s8z24 & 0xff000000) | bzzzz[j];
tile->data.depth32[y][x] = s8z24;
}
break;
case PIPE_FORMAT_Z24S8_UNORM:
for (j = 0; j < QUAD_SIZE; j++) {
int x = quad->input.x0 % TILE_SIZE + (j & 1);
int y = quad->input.y0 % TILE_SIZE + (j >> 1);
uint z24s8 = tile->data.depth32[y][x];
z24s8 = (z24s8 & 0xff) | (bzzzz[j] << 8);
tile->data.depth32[y][x] = z24s8;
}
break;
case PIPE_FORMAT_Z24X8_UNORM:
for (j = 0; j < QUAD_SIZE; j++) {
int x = quad->input.x0 % TILE_SIZE + (j & 1);
int y = quad->input.y0 % TILE_SIZE + (j >> 1);
tile->data.depth32[y][x] = bzzzz[j] << 8;
}
break;
default:
assert(0);
}
}
@ -259,20 +493,215 @@ lp_depth_test_quad(struct quad_stage *qs, struct quad_header *quad)
}
/**
* Do stencil (and depth) testing. Stenciling depends on the outcome of
* depth testing.
*/
static boolean
depth_stencil_test_quad(struct quad_stage *qs,
struct depth_data *data,
struct quad_header *quad)
{
struct llvmpipe_context *llvmpipe = qs->llvmpipe;
unsigned func, zFailOp, zPassOp, failOp;
ubyte ref, wrtMask, valMask;
uint face = quad->input.facing;
if (!llvmpipe->depth_stencil->stencil[1].enabled) {
/* single-sided stencil test, use front (face=0) state */
face = 0;
}
/* choose front or back face function, operator, etc */
/* XXX we could do these initializations once per primitive */
func = llvmpipe->depth_stencil->stencil[face].func;
failOp = llvmpipe->depth_stencil->stencil[face].fail_op;
zFailOp = llvmpipe->depth_stencil->stencil[face].zfail_op;
zPassOp = llvmpipe->depth_stencil->stencil[face].zpass_op;
ref = llvmpipe->depth_stencil->stencil[face].ref_value;
wrtMask = llvmpipe->depth_stencil->stencil[face].writemask;
valMask = llvmpipe->depth_stencil->stencil[face].valuemask;
/* do the stencil test first */
{
unsigned passMask, failMask;
passMask = do_stencil_test(data, func, ref, valMask);
failMask = quad->inout.mask & ~passMask;
quad->inout.mask &= passMask;
if (failOp != PIPE_STENCIL_OP_KEEP) {
apply_stencil_op(data, failMask, failOp, ref, wrtMask);
}
}
if (quad->inout.mask) {
/* now the pixels that passed the stencil test are depth tested */
if (llvmpipe->depth_stencil->depth.enabled) {
const unsigned origMask = quad->inout.mask;
depth_test_quad(qs, data, quad); /* quad->mask is updated */
/* update stencil buffer values according to z pass/fail result */
if (zFailOp != PIPE_STENCIL_OP_KEEP) {
const unsigned failMask = origMask & ~quad->inout.mask;
apply_stencil_op(data, failMask, zFailOp, ref, wrtMask);
}
if (zPassOp != PIPE_STENCIL_OP_KEEP) {
const unsigned passMask = origMask & quad->inout.mask;
apply_stencil_op(data, passMask, zPassOp, ref, wrtMask);
}
}
else {
/* no depth test, apply Zpass operator to stencil buffer values */
apply_stencil_op(data, quad->inout.mask, zPassOp, ref, wrtMask);
}
}
return quad->inout.mask != 0;
}
#define ALPHATEST( FUNC, COMP ) \
static int \
alpha_test_quads_##FUNC( struct quad_stage *qs, \
struct quad_header *quads[], \
unsigned nr ) \
{ \
const float ref = qs->llvmpipe->depth_stencil->alpha.ref_value; \
const uint cbuf = 0; /* only output[0].alpha is tested */ \
unsigned pass_nr = 0; \
unsigned i; \
\
for (i = 0; i < nr; i++) { \
const float *aaaa = quads[i]->output.color[cbuf][3]; \
unsigned passMask = 0; \
\
if (aaaa[0] COMP ref) passMask |= (1 << 0); \
if (aaaa[1] COMP ref) passMask |= (1 << 1); \
if (aaaa[2] COMP ref) passMask |= (1 << 2); \
if (aaaa[3] COMP ref) passMask |= (1 << 3); \
\
quads[i]->inout.mask &= passMask; \
\
if (quads[i]->inout.mask) \
quads[pass_nr++] = quads[i]; \
} \
\
return pass_nr; \
}
ALPHATEST( LESS, < )
ALPHATEST( EQUAL, == )
ALPHATEST( LEQUAL, <= )
ALPHATEST( GREATER, > )
ALPHATEST( NOTEQUAL, != )
ALPHATEST( GEQUAL, >= )
/* XXX: Incorporate into shader using KILP.
*/
static int
alpha_test_quads(struct quad_stage *qs,
struct quad_header *quads[],
unsigned nr)
{
switch (qs->llvmpipe->depth_stencil->alpha.func) {
case PIPE_FUNC_LESS:
return alpha_test_quads_LESS( qs, quads, nr );
case PIPE_FUNC_EQUAL:
return alpha_test_quads_EQUAL( qs, quads, nr );
break;
case PIPE_FUNC_LEQUAL:
return alpha_test_quads_LEQUAL( qs, quads, nr );
case PIPE_FUNC_GREATER:
return alpha_test_quads_GREATER( qs, quads, nr );
case PIPE_FUNC_NOTEQUAL:
return alpha_test_quads_NOTEQUAL( qs, quads, nr );
case PIPE_FUNC_GEQUAL:
return alpha_test_quads_GEQUAL( qs, quads, nr );
case PIPE_FUNC_ALWAYS:
return nr;
case PIPE_FUNC_NEVER:
default:
return 0;
}
}
static unsigned mask_count[0x8] =
{
0, /* 0x0 */
1, /* 0x1 */
1, /* 0x2 */
2, /* 0x3 */
1, /* 0x4 */
2, /* 0x5 */
2, /* 0x6 */
3, /* 0x7 */
};
static void
depth_test_quads(struct quad_stage *qs,
struct quad_header *quads[],
unsigned nr)
{
unsigned i, pass = 0;
const struct lp_fragment_shader *fs = qs->llvmpipe->fs;
boolean interp_depth = !fs->info.writes_z;
struct depth_data data;
for (i = 0; i < nr; i++) {
if (lp_depth_test_quad(qs, quads[i]))
quads[pass++] = quads[i];
if (qs->llvmpipe->depth_stencil->alpha.enabled) {
nr = alpha_test_quads(qs, quads, nr);
}
if (pass)
qs->next->run(qs->next, quads, pass);
if (qs->llvmpipe->framebuffer.zsbuf &&
(qs->llvmpipe->depth_stencil->depth.enabled ||
qs->llvmpipe->depth_stencil->stencil[0].enabled)) {
data.ps = qs->llvmpipe->framebuffer.zsbuf;
data.format = data.ps->format;
data.tile = lp_get_cached_tile(qs->llvmpipe->zsbuf_cache,
quads[0]->input.x0,
quads[0]->input.y0);
for (i = 0; i < nr; i++) {
get_depth_stencil_values(&data, quads[i]);
if (qs->llvmpipe->depth_stencil->depth.enabled) {
if (interp_depth)
interpolate_quad_depth(quads[i]);
convert_quad_depth(&data, quads[i]);
}
if (qs->llvmpipe->depth_stencil->stencil[0].enabled) {
if (!depth_stencil_test_quad(qs, &data, quads[i]))
continue;
}
else {
if (!depth_test_quad(qs, &data, quads[i]))
continue;
}
if (qs->llvmpipe->depth_stencil->stencil[0].enabled ||
qs->llvmpipe->depth_stencil->depth.writemask)
write_depth_stencil_values(&data, quads[i]);
qs->llvmpipe->occlusion_count += mask_count[quads[i]->inout.mask];
quads[pass++] = quads[i];
}
nr = pass;
}
if (nr)
qs->next->run(qs->next, quads, nr);
}

View file

@ -1,94 +0,0 @@
/**************************************************************************
*
* Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
/**
* \brief Quad early-z testing
*/
#include "pipe/p_defines.h"
#include "util/u_memory.h"
#include "lp_quad.h"
#include "lp_quad_pipe.h"
/**
* All this stage does is compute the quad's Z values (which is normally
* done by the shading stage).
* The next stage will do the actual depth test.
*/
static void
earlyz_quad(
struct quad_stage *qs,
struct quad_header *quads[],
unsigned nr )
{
const float a0z = quads[0]->posCoef->a0[2];
const float dzdx = quads[0]->posCoef->dadx[2];
const float dzdy = quads[0]->posCoef->dady[2];
unsigned i;
for (i = 0; i < nr; i++) {
const float fx = (float) quads[i]->input.x0;
const float fy = (float) quads[i]->input.y0;
const float z0 = a0z + dzdx * fx + dzdy * fy;
quads[i]->output.depth[0] = z0;
quads[i]->output.depth[1] = z0 + dzdx;
quads[i]->output.depth[2] = z0 + dzdy;
quads[i]->output.depth[3] = z0 + dzdx + dzdy;
}
qs->next->run( qs->next, quads, nr );
}
static void
earlyz_begin(
struct quad_stage *qs )
{
qs->next->begin( qs->next );
}
static void
earlyz_destroy(
struct quad_stage *qs )
{
FREE( qs );
}
struct quad_stage *
lp_quad_earlyz_stage(
struct llvmpipe_context *llvmpipe )
{
struct quad_stage *stage = CALLOC_STRUCT( quad_stage );
stage->llvmpipe = llvmpipe;
stage->begin = earlyz_begin;
stage->run = earlyz_quad;
stage->destroy = earlyz_destroy;
return stage;
}

View file

@ -111,24 +111,31 @@ shade_quad(struct quad_stage *qs, struct quad_header *quad)
}
}
if (!z_written) {
/* compute Z values now, as in the quad earlyz stage */
/* XXX we should really only do this if the earlyz stage is not used */
const float fx = (float) quad->input.x0;
const float fy = (float) quad->input.y0;
const float dzdx = quad->posCoef->dadx[2];
const float dzdy = quad->posCoef->dady[2];
const float z0 = quad->posCoef->a0[2] + dzdx * fx + dzdy * fy;
quad->output.depth[0] = z0;
quad->output.depth[1] = z0 + dzdx;
quad->output.depth[2] = z0 + dzdy;
quad->output.depth[3] = z0 + dzdx + dzdy;
}
return TRUE;
}
static void
coverage_quad(struct quad_stage *qs, struct quad_header *quad)
{
struct llvmpipe_context *llvmpipe = qs->llvmpipe;
uint cbuf;
/* loop over colorbuffer outputs */
for (cbuf = 0; cbuf < llvmpipe->framebuffer.nr_cbufs; cbuf++) {
float (*quadColor)[4] = quad->output.color[cbuf];
unsigned j;
for (j = 0; j < QUAD_SIZE; j++) {
assert(quad->input.coverage[j] >= 0.0);
assert(quad->input.coverage[j] <= 1.0);
quadColor[3][j] *= quad->input.coverage[j];
}
}
}
static void
shade_quads(struct quad_stage *qs,
struct quad_header *quads[],
@ -144,8 +151,13 @@ shade_quads(struct quad_stage *qs,
machine->InterpCoefs = quads[0]->coef;
for (i = 0; i < nr; i++) {
if (shade_quad(qs, quads[i]))
quads[pass++] = quads[i];
if (!shade_quad(qs, quads[i]))
continue;
if (/*do_coverage*/ 0)
coverage_quad( qs, quads[i] );
quads[pass++] = quads[i];
}
if (pass)

View file

@ -1,87 +0,0 @@
/**************************************************************************
*
* Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
/**
* \brief Quad occlusion counter stage
* \author Brian Paul
*/
#include "pipe/p_defines.h"
#include "util/u_memory.h"
#include "lp_context.h"
#include "lp_quad.h"
#include "lp_surface.h"
#include "lp_quad_pipe.h"
static unsigned count_bits( unsigned val )
{
unsigned i;
for (i = 0; val ; val >>= 1)
i += (val & 1);
return i;
}
static void
occlusion_count_quads(struct quad_stage *qs, struct quad_header *quads[], unsigned nr)
{
struct llvmpipe_context *llvmpipe = qs->llvmpipe;
unsigned i;
for (i = 0; i < nr; i++)
llvmpipe->occlusion_count += count_bits(quads[i]->inout.mask);
qs->next->run(qs->next, quads, nr);
}
static void occlusion_begin(struct quad_stage *qs)
{
qs->next->begin(qs->next);
}
static void occlusion_destroy(struct quad_stage *qs)
{
FREE( qs );
}
struct quad_stage *lp_quad_occlusion_stage( struct llvmpipe_context *llvmpipe )
{
struct quad_stage *stage = CALLOC_STRUCT(quad_stage);
stage->llvmpipe = llvmpipe;
stage->begin = occlusion_begin;
stage->run = occlusion_count_quads;
stage->destroy = occlusion_destroy;
return stage;
}

View file

@ -38,18 +38,6 @@ lp_push_quad_first( struct llvmpipe_context *lp,
lp->quad.first = quad;
}
static void
lp_build_depth_stencil( struct llvmpipe_context *lp )
{
if (lp->depth_stencil->stencil[0].enabled ||
lp->depth_stencil->stencil[1].enabled) {
lp_push_quad_first( lp, lp->quad.stencil_test );
}
else if (lp->depth_stencil->depth.enabled &&
lp->framebuffer.zsbuf) {
lp_push_quad_first( lp, lp->quad.depth_test );
}
}
void
lp_build_quad_pipeline(struct llvmpipe_context *lp)
@ -61,37 +49,15 @@ lp_build_quad_pipeline(struct llvmpipe_context *lp)
!lp->fs->info.uses_kill &&
!lp->fs->info.writes_z;
/* build up the pipeline in reverse order... */
/* Color combine
*/
lp->quad.first = lp->quad.blend;
/* Shade/Depth/Stencil/Alpha
*/
if ((lp->rasterizer->poly_smooth && lp->reduced_prim == PIPE_PRIM_TRIANGLES) ||
(lp->rasterizer->line_smooth && lp->reduced_prim == PIPE_PRIM_LINES) ||
(lp->rasterizer->point_smooth && lp->reduced_prim == PIPE_PRIM_POINTS)) {
lp_push_quad_first( lp, lp->quad.coverage );
}
if (lp->active_query_count) {
lp_push_quad_first( lp, lp->quad.occlusion );
}
if (!early_depth_test) {
lp_build_depth_stencil( lp );
}
if (lp->depth_stencil->alpha.enabled) {
lp_push_quad_first( lp, lp->quad.alpha_test );
}
lp_push_quad_first( lp, lp->quad.shade );
if (early_depth_test) {
lp_build_depth_stencil( lp );
lp_push_quad_first( lp, lp->quad.earlyz );
lp_push_quad_first( lp, lp->quad.shade );
lp_push_quad_first( lp, lp->quad.depth_test );
}
else {
lp_push_quad_first( lp, lp->quad.depth_test );
lp_push_quad_first( lp, lp->quad.shade );
}
}

View file

@ -69,6 +69,4 @@ struct quad_stage *lp_quad_output_stage( struct llvmpipe_context *llvmpipe );
void lp_build_quad_pipeline(struct llvmpipe_context *lp);
boolean lp_depth_test_quad(struct quad_stage *qs, struct quad_header *quad);
#endif /* LP_QUAD_PIPE_H */

View file

@ -1,363 +0,0 @@
/**
* \brief Quad stencil testing
*/
#include "lp_context.h"
#include "lp_quad.h"
#include "lp_surface.h"
#include "lp_tile_cache.h"
#include "lp_quad_pipe.h"
#include "pipe/p_defines.h"
#include "util/u_memory.h"
/** Only 8-bit stencil supported */
#define STENCIL_MAX 0xff
/**
* Do the basic stencil test (compare stencil buffer values against the
* reference value.
*
* \param stencilVals the stencil values from the stencil buffer
* \param func the stencil func (PIPE_FUNC_x)
* \param ref the stencil reference value
* \param valMask the stencil value mask indicating which bits of the stencil
* values and ref value are to be used.
* \return mask indicating which pixels passed the stencil test
*/
static unsigned
do_stencil_test(const ubyte stencilVals[QUAD_SIZE], unsigned func,
unsigned ref, unsigned valMask)
{
unsigned passMask = 0x0;
unsigned j;
ref &= valMask;
switch (func) {
case PIPE_FUNC_NEVER:
/* passMask = 0x0 */
break;
case PIPE_FUNC_LESS:
for (j = 0; j < QUAD_SIZE; j++) {
if (ref < (stencilVals[j] & valMask)) {
passMask |= (1 << j);
}
}
break;
case PIPE_FUNC_EQUAL:
for (j = 0; j < QUAD_SIZE; j++) {
if (ref == (stencilVals[j] & valMask)) {
passMask |= (1 << j);
}
}
break;
case PIPE_FUNC_LEQUAL:
for (j = 0; j < QUAD_SIZE; j++) {
if (ref <= (stencilVals[j] & valMask)) {
passMask |= (1 << j);
}
}
break;
case PIPE_FUNC_GREATER:
for (j = 0; j < QUAD_SIZE; j++) {
if (ref > (stencilVals[j] & valMask)) {
passMask |= (1 << j);
}
}
break;
case PIPE_FUNC_NOTEQUAL:
for (j = 0; j < QUAD_SIZE; j++) {
if (ref != (stencilVals[j] & valMask)) {
passMask |= (1 << j);
}
}
break;
case PIPE_FUNC_GEQUAL:
for (j = 0; j < QUAD_SIZE; j++) {
if (ref >= (stencilVals[j] & valMask)) {
passMask |= (1 << j);
}
}
break;
case PIPE_FUNC_ALWAYS:
passMask = MASK_ALL;
break;
default:
assert(0);
}
return passMask;
}
/**
* Apply the stencil operator to stencil values.
*
* \param stencilVals the stencil buffer values (read and written)
* \param mask indicates which pixels to update
* \param op the stencil operator (PIPE_STENCIL_OP_x)
* \param ref the stencil reference value
* \param wrtMask writemask controlling which bits are changed in the
* stencil values
*/
static void
apply_stencil_op(ubyte stencilVals[QUAD_SIZE],
unsigned mask, unsigned op, ubyte ref, ubyte wrtMask)
{
unsigned j;
ubyte newstencil[QUAD_SIZE];
for (j = 0; j < QUAD_SIZE; j++) {
newstencil[j] = stencilVals[j];
}
switch (op) {
case PIPE_STENCIL_OP_KEEP:
/* no-op */
break;
case PIPE_STENCIL_OP_ZERO:
for (j = 0; j < QUAD_SIZE; j++) {
if (mask & (1 << j)) {
newstencil[j] = 0;
}
}
break;
case PIPE_STENCIL_OP_REPLACE:
for (j = 0; j < QUAD_SIZE; j++) {
if (mask & (1 << j)) {
newstencil[j] = ref;
}
}
break;
case PIPE_STENCIL_OP_INCR:
for (j = 0; j < QUAD_SIZE; j++) {
if (mask & (1 << j)) {
if (stencilVals[j] < STENCIL_MAX) {
newstencil[j] = stencilVals[j] + 1;
}
}
}
break;
case PIPE_STENCIL_OP_DECR:
for (j = 0; j < QUAD_SIZE; j++) {
if (mask & (1 << j)) {
if (stencilVals[j] > 0) {
newstencil[j] = stencilVals[j] - 1;
}
}
}
break;
case PIPE_STENCIL_OP_INCR_WRAP:
for (j = 0; j < QUAD_SIZE; j++) {
if (mask & (1 << j)) {
newstencil[j] = stencilVals[j] + 1;
}
}
break;
case PIPE_STENCIL_OP_DECR_WRAP:
for (j = 0; j < QUAD_SIZE; j++) {
if (mask & (1 << j)) {
newstencil[j] = stencilVals[j] - 1;
}
}
break;
case PIPE_STENCIL_OP_INVERT:
for (j = 0; j < QUAD_SIZE; j++) {
if (mask & (1 << j)) {
newstencil[j] = ~stencilVals[j];
}
}
break;
default:
assert(0);
}
/*
* update the stencil values
*/
if (wrtMask != STENCIL_MAX) {
/* apply bit-wise stencil buffer writemask */
for (j = 0; j < QUAD_SIZE; j++) {
stencilVals[j] = (wrtMask & newstencil[j]) | (~wrtMask & stencilVals[j]);
}
}
else {
for (j = 0; j < QUAD_SIZE; j++) {
stencilVals[j] = newstencil[j];
}
}
}
/**
* Do stencil (and depth) testing. Stenciling depends on the outcome of
* depth testing.
*/
static void
stencil_test_quad(struct quad_stage *qs, struct quad_header *quads[],
unsigned nr)
{
struct llvmpipe_context *llvmpipe = qs->llvmpipe;
struct pipe_surface *ps = llvmpipe->framebuffer.zsbuf;
unsigned func, zFailOp, zPassOp, failOp;
ubyte ref, wrtMask, valMask;
ubyte stencilVals[QUAD_SIZE];
struct llvmpipe_cached_tile *tile
= lp_get_cached_tile(llvmpipe->zsbuf_cache,
quads[0]->input.x0,
quads[0]->input.y0);
uint face = quads[0]->input.facing;
uint pass = 0;
uint j, q;
if (!llvmpipe->depth_stencil->stencil[1].enabled) {
/* single-sided stencil test, use front (face=0) state */
face = 0;
}
/* choose front or back face function, operator, etc */
/* XXX we could do these initializations once per primitive */
func = llvmpipe->depth_stencil->stencil[face].func;
failOp = llvmpipe->depth_stencil->stencil[face].fail_op;
zFailOp = llvmpipe->depth_stencil->stencil[face].zfail_op;
zPassOp = llvmpipe->depth_stencil->stencil[face].zpass_op;
ref = llvmpipe->depth_stencil->stencil[face].ref_value;
wrtMask = llvmpipe->depth_stencil->stencil[face].writemask;
valMask = llvmpipe->depth_stencil->stencil[face].valuemask;
assert(ps); /* shouldn't get here if there's no stencil buffer */
for (q = 0; q < nr; q++) {
struct quad_header *quad = quads[q];
/* get stencil values from cached tile */
switch (ps->format) {
case PIPE_FORMAT_S8Z24_UNORM:
for (j = 0; j < QUAD_SIZE; j++) {
int x = quad->input.x0 % TILE_SIZE + (j & 1);
int y = quad->input.y0 % TILE_SIZE + (j >> 1);
stencilVals[j] = tile->data.depth32[y][x] >> 24;
}
break;
case PIPE_FORMAT_Z24S8_UNORM:
for (j = 0; j < QUAD_SIZE; j++) {
int x = quad->input.x0 % TILE_SIZE + (j & 1);
int y = quad->input.y0 % TILE_SIZE + (j >> 1);
stencilVals[j] = tile->data.depth32[y][x] & 0xff;
}
break;
case PIPE_FORMAT_S8_UNORM:
for (j = 0; j < QUAD_SIZE; j++) {
int x = quad->input.x0 % TILE_SIZE + (j & 1);
int y = quad->input.y0 % TILE_SIZE + (j >> 1);
stencilVals[j] = tile->data.stencil8[y][x];
}
break;
default:
assert(0);
}
/* do the stencil test first */
{
unsigned passMask, failMask;
passMask = do_stencil_test(stencilVals, func, ref, valMask);
failMask = quad->inout.mask & ~passMask;
quad->inout.mask &= passMask;
if (failOp != PIPE_STENCIL_OP_KEEP) {
apply_stencil_op(stencilVals, failMask, failOp, ref, wrtMask);
}
}
if (quad->inout.mask) {
/* now the pixels that passed the stencil test are depth tested */
if (llvmpipe->depth_stencil->depth.enabled) {
const unsigned origMask = quad->inout.mask;
lp_depth_test_quad(qs, quad); /* quad->mask is updated */
/* update stencil buffer values according to z pass/fail result */
if (zFailOp != PIPE_STENCIL_OP_KEEP) {
const unsigned failMask = origMask & ~quad->inout.mask;
apply_stencil_op(stencilVals, failMask, zFailOp, ref, wrtMask);
}
if (zPassOp != PIPE_STENCIL_OP_KEEP) {
const unsigned passMask = origMask & quad->inout.mask;
apply_stencil_op(stencilVals, passMask, zPassOp, ref, wrtMask);
}
}
else {
/* no depth test, apply Zpass operator to stencil buffer values */
apply_stencil_op(stencilVals, quad->inout.mask, zPassOp, ref, wrtMask);
}
}
/* put new stencil values into cached tile */
switch (ps->format) {
case PIPE_FORMAT_S8Z24_UNORM:
for (j = 0; j < QUAD_SIZE; j++) {
int x = quad->input.x0 % TILE_SIZE + (j & 1);
int y = quad->input.y0 % TILE_SIZE + (j >> 1);
uint s8z24 = tile->data.depth32[y][x];
s8z24 = (stencilVals[j] << 24) | (s8z24 & 0xffffff);
tile->data.depth32[y][x] = s8z24;
}
break;
case PIPE_FORMAT_Z24S8_UNORM:
for (j = 0; j < QUAD_SIZE; j++) {
int x = quad->input.x0 % TILE_SIZE + (j & 1);
int y = quad->input.y0 % TILE_SIZE + (j >> 1);
uint z24s8 = tile->data.depth32[y][x];
z24s8 = (z24s8 & 0xffffff00) | stencilVals[j];
tile->data.depth32[y][x] = z24s8;
}
break;
case PIPE_FORMAT_S8_UNORM:
for (j = 0; j < QUAD_SIZE; j++) {
int x = quad->input.x0 % TILE_SIZE + (j & 1);
int y = quad->input.y0 % TILE_SIZE + (j >> 1);
tile->data.stencil8[y][x] = stencilVals[j];
}
break;
default:
assert(0);
}
if (quad->inout.mask)
quads[pass++] = quad;
}
if (pass)
qs->next->run(qs->next, quads, pass);
}
static void stencil_begin(struct quad_stage *qs)
{
qs->next->begin(qs->next);
}
static void stencil_destroy(struct quad_stage *qs)
{
FREE( qs );
}
struct quad_stage *lp_quad_stencil_test_stage( struct llvmpipe_context *llvmpipe )
{
struct quad_stage *stage = CALLOC_STRUCT(quad_stage);
stage->llvmpipe = llvmpipe;
stage->begin = stencil_begin;
stage->run = stencil_test_quad;
stage->destroy = stencil_destroy;
return stage;
}

View file

@ -246,9 +246,7 @@ void llvmpipe_update_derived( struct llvmpipe_context *llvmpipe )
if (llvmpipe->dirty & (LP_NEW_BLEND |
LP_NEW_DEPTH_STENCIL_ALPHA |
LP_NEW_FRAMEBUFFER |
LP_NEW_RASTERIZER |
LP_NEW_FS |
LP_NEW_QUERY))
LP_NEW_FS))
lp_build_quad_pipeline(llvmpipe);
llvmpipe->dirty = 0;