00001 /************************************************************************** 00002 * 00003 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. 00004 * All Rights Reserved. 00005 * 00006 * Permission is hereby granted, free of charge, to any person obtaining a 00007 * copy of this software and associated documentation files (the 00008 * "Software"), to deal in the Software without restriction, including 00009 * without limitation the rights to use, copy, modify, merge, publish, 00010 * distribute, sub license, and/or sell copies of the Software, and to 00011 * permit persons to whom the Software is furnished to do so, subject to 00012 * the following conditions: 00013 * 00014 * The above copyright notice and this permission notice (including the 00015 * next paragraph) shall be included in all copies or substantial portions 00016 * of the Software. 00017 * 00018 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 00019 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00020 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 00021 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 00022 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 00023 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 00024 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00025 * 00026 **************************************************************************/ 00027 00032 #include "pipe/p_defines.h" 00033 #include "util/u_memory.h" 00034 #include "sp_context.h" 00035 #include "sp_headers.h" 00036 #include "sp_surface.h" 00037 #include "sp_quad.h" 00038 #include "sp_tile_cache.h" 00039 00040 00046 /* 00047 * To increase efficiency, we should probably have multiple versions 00048 * of this function that are specifically for Z16, Z32 and FP Z buffers. 00049 * Try to effectively do that with codegen... 00050 */ 00051 00052 void 00053 sp_depth_test_quad(struct quad_stage *qs, struct quad_header *quad) 00054 { 00055 struct softpipe_context *softpipe = qs->softpipe; 00056 struct pipe_surface *ps = softpipe->framebuffer.zsbuf; 00057 const enum pipe_format format = ps->format; 00058 unsigned bzzzz[QUAD_SIZE]; 00059 unsigned qzzzz[QUAD_SIZE]; 00060 unsigned zmask = 0; 00061 unsigned j; 00062 struct softpipe_cached_tile *tile 00063 = sp_get_cached_tile(softpipe, softpipe->zsbuf_cache, quad->input.x0, quad->input.y0); 00064 00065 assert(ps); /* shouldn't get here if there's no zbuffer */ 00066 00067 /* 00068 * Convert quad's float depth values to int depth values (qzzzz). 00069 * If the Z buffer stores integer values, we _have_ to do the depth 00070 * compares with integers (not floats). Otherwise, the float->int->float 00071 * conversion of Z values (which isn't an identity function) will cause 00072 * Z-fighting errors. 00073 * 00074 * Also, get the zbuffer values (bzzzz) from the cached tile. 00075 */ 00076 switch (format) { 00077 case PIPE_FORMAT_Z16_UNORM: 00078 { 00079 float scale = 65535.0; 00080 00081 for (j = 0; j < QUAD_SIZE; j++) { 00082 qzzzz[j] = (unsigned) (quad->output.depth[j] * scale); 00083 } 00084 00085 for (j = 0; j < QUAD_SIZE; j++) { 00086 int x = quad->input.x0 % TILE_SIZE + (j & 1); 00087 int y = quad->input.y0 % TILE_SIZE + (j >> 1); 00088 bzzzz[j] = tile->data.depth16[y][x]; 00089 } 00090 } 00091 break; 00092 case PIPE_FORMAT_Z32_UNORM: 00093 { 00094 double scale = (double) (uint) ~0UL; 00095 00096 for (j = 0; j < QUAD_SIZE; j++) { 00097 qzzzz[j] = (unsigned) (quad->output.depth[j] * scale); 00098 } 00099 00100 for (j = 0; j < QUAD_SIZE; j++) { 00101 int x = quad->input.x0 % TILE_SIZE + (j & 1); 00102 int y = quad->input.y0 % TILE_SIZE + (j >> 1); 00103 bzzzz[j] = tile->data.depth32[y][x]; 00104 } 00105 } 00106 break; 00107 case PIPE_FORMAT_X8Z24_UNORM: 00108 /* fall-through */ 00109 case PIPE_FORMAT_S8Z24_UNORM: 00110 { 00111 float scale = (float) ((1 << 24) - 1); 00112 00113 for (j = 0; j < QUAD_SIZE; j++) { 00114 qzzzz[j] = (unsigned) (quad->output.depth[j] * scale); 00115 } 00116 00117 for (j = 0; j < QUAD_SIZE; j++) { 00118 int x = quad->input.x0 % TILE_SIZE + (j & 1); 00119 int y = quad->input.y0 % TILE_SIZE + (j >> 1); 00120 bzzzz[j] = tile->data.depth32[y][x] & 0xffffff; 00121 } 00122 } 00123 break; 00124 case PIPE_FORMAT_Z24X8_UNORM: 00125 /* fall-through */ 00126 case PIPE_FORMAT_Z24S8_UNORM: 00127 { 00128 float scale = (float) ((1 << 24) - 1); 00129 00130 for (j = 0; j < QUAD_SIZE; j++) { 00131 qzzzz[j] = (unsigned) (quad->output.depth[j] * scale); 00132 } 00133 00134 for (j = 0; j < QUAD_SIZE; j++) { 00135 int x = quad->input.x0 % TILE_SIZE + (j & 1); 00136 int y = quad->input.y0 % TILE_SIZE + (j >> 1); 00137 bzzzz[j] = tile->data.depth32[y][x] >> 8; 00138 } 00139 } 00140 break; 00141 default: 00142 assert(0); 00143 } 00144 00145 switch (softpipe->depth_stencil->depth.func) { 00146 case PIPE_FUNC_NEVER: 00147 /* zmask = 0 */ 00148 break; 00149 case PIPE_FUNC_LESS: 00150 /* Note this is pretty much a single sse or cell instruction. 00151 * Like this: quad->mask &= (quad->outputs.depth < zzzz); 00152 */ 00153 for (j = 0; j < QUAD_SIZE; j++) { 00154 if (qzzzz[j] < bzzzz[j]) 00155 zmask |= 1 << j; 00156 } 00157 break; 00158 case PIPE_FUNC_EQUAL: 00159 for (j = 0; j < QUAD_SIZE; j++) { 00160 if (qzzzz[j] == bzzzz[j]) 00161 zmask |= 1 << j; 00162 } 00163 break; 00164 case PIPE_FUNC_LEQUAL: 00165 for (j = 0; j < QUAD_SIZE; j++) { 00166 if (qzzzz[j] <= bzzzz[j]) 00167 zmask |= (1 << j); 00168 } 00169 break; 00170 case PIPE_FUNC_GREATER: 00171 for (j = 0; j < QUAD_SIZE; j++) { 00172 if (qzzzz[j] > bzzzz[j]) 00173 zmask |= (1 << j); 00174 } 00175 break; 00176 case PIPE_FUNC_NOTEQUAL: 00177 for (j = 0; j < QUAD_SIZE; j++) { 00178 if (qzzzz[j] != bzzzz[j]) 00179 zmask |= (1 << j); 00180 } 00181 break; 00182 case PIPE_FUNC_GEQUAL: 00183 for (j = 0; j < QUAD_SIZE; j++) { 00184 if (qzzzz[j] >= bzzzz[j]) 00185 zmask |= (1 << j); 00186 } 00187 break; 00188 case PIPE_FUNC_ALWAYS: 00189 zmask = MASK_ALL; 00190 break; 00191 default: 00192 assert(0); 00193 } 00194 00195 quad->inout.mask &= zmask; 00196 00197 if (softpipe->depth_stencil->depth.writemask) { 00198 00199 /* This is also efficient with sse / spe instructions: 00200 */ 00201 for (j = 0; j < QUAD_SIZE; j++) { 00202 if (quad->inout.mask & (1 << j)) { 00203 bzzzz[j] = qzzzz[j]; 00204 } 00205 } 00206 00207 /* put updated Z values back into cached tile */ 00208 switch (format) { 00209 case PIPE_FORMAT_Z16_UNORM: 00210 for (j = 0; j < QUAD_SIZE; j++) { 00211 int x = quad->input.x0 % TILE_SIZE + (j & 1); 00212 int y = quad->input.y0 % TILE_SIZE + (j >> 1); 00213 tile->data.depth16[y][x] = (ushort) bzzzz[j]; 00214 } 00215 break; 00216 case PIPE_FORMAT_X8Z24_UNORM: 00217 /* fall-through */ 00218 /* (yes, this falls through to a different case than above) */ 00219 case PIPE_FORMAT_Z32_UNORM: 00220 for (j = 0; j < QUAD_SIZE; j++) { 00221 int x = quad->input.x0 % TILE_SIZE + (j & 1); 00222 int y = quad->input.y0 % TILE_SIZE + (j >> 1); 00223 tile->data.depth32[y][x] = bzzzz[j]; 00224 } 00225 break; 00226 case PIPE_FORMAT_S8Z24_UNORM: 00227 for (j = 0; j < QUAD_SIZE; j++) { 00228 int x = quad->input.x0 % TILE_SIZE + (j & 1); 00229 int y = quad->input.y0 % TILE_SIZE + (j >> 1); 00230 uint s8z24 = tile->data.depth32[y][x]; 00231 s8z24 = (s8z24 & 0xff000000) | bzzzz[j]; 00232 tile->data.depth32[y][x] = s8z24; 00233 } 00234 break; 00235 case PIPE_FORMAT_Z24S8_UNORM: 00236 for (j = 0; j < QUAD_SIZE; j++) { 00237 int x = quad->input.x0 % TILE_SIZE + (j & 1); 00238 int y = quad->input.y0 % TILE_SIZE + (j >> 1); 00239 uint z24s8 = tile->data.depth32[y][x]; 00240 z24s8 = (z24s8 & 0xff) | (bzzzz[j] << 8); 00241 tile->data.depth32[y][x] = z24s8; 00242 } 00243 break; 00244 case PIPE_FORMAT_Z24X8_UNORM: 00245 for (j = 0; j < QUAD_SIZE; j++) { 00246 int x = quad->input.x0 % TILE_SIZE + (j & 1); 00247 int y = quad->input.y0 % TILE_SIZE + (j >> 1); 00248 tile->data.depth32[y][x] = bzzzz[j] << 8; 00249 } 00250 break; 00251 default: 00252 assert(0); 00253 } 00254 } 00255 } 00256 00257 00258 static void 00259 depth_test_quad(struct quad_stage *qs, struct quad_header *quad) 00260 { 00261 sp_depth_test_quad(qs, quad); 00262 00263 if (quad->inout.mask) 00264 qs->next->run(qs->next, quad); 00265 } 00266 00267 00268 static void depth_test_begin(struct quad_stage *qs) 00269 { 00270 qs->next->begin(qs->next); 00271 } 00272 00273 00274 static void depth_test_destroy(struct quad_stage *qs) 00275 { 00276 FREE( qs ); 00277 } 00278 00279 00280 struct quad_stage *sp_quad_depth_test_stage( struct softpipe_context *softpipe ) 00281 { 00282 struct quad_stage *stage = CALLOC_STRUCT(quad_stage); 00283 00284 stage->softpipe = softpipe; 00285 stage->begin = depth_test_begin; 00286 stage->run = depth_test_quad; 00287 stage->destroy = depth_test_destroy; 00288 00289 return stage; 00290 }