s_triangle.c revision f9995b30756140724f41daf963fa06167912be7f
1/* 2 * Mesa 3-D graphics library 3 * Version: 7.3 4 * 5 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 26/* 27 * When the device driver doesn't implement triangle rasterization it 28 * can hook in _swrast_Triangle, which eventually calls one of these 29 * functions to draw triangles. 30 */ 31 32#include "main/glheader.h" 33#include "main/context.h" 34#include "main/colormac.h" 35#include "main/imports.h" 36#include "main/macros.h" 37#include "main/texformat.h" 38#include "program/prog_instruction.h" 39 40#include "s_aatriangle.h" 41#include "s_context.h" 42#include "s_feedback.h" 43#include "s_span.h" 44#include "s_triangle.h" 45 46 47/** 48 * Test if a triangle should be culled. Used for feedback and selection mode. 49 * \return GL_TRUE if the triangle is to be culled, GL_FALSE otherwise. 50 */ 51GLboolean 52_swrast_culltriangle( struct gl_context *ctx, 53 const SWvertex *v0, 54 const SWvertex *v1, 55 const SWvertex *v2 ) 56{ 57 SWcontext *swrast = SWRAST_CONTEXT(ctx); 58 GLfloat ex = v1->attrib[FRAG_ATTRIB_WPOS][0] - v0->attrib[FRAG_ATTRIB_WPOS][0]; 59 GLfloat ey = v1->attrib[FRAG_ATTRIB_WPOS][1] - v0->attrib[FRAG_ATTRIB_WPOS][1]; 60 GLfloat fx = v2->attrib[FRAG_ATTRIB_WPOS][0] - v0->attrib[FRAG_ATTRIB_WPOS][0]; 61 GLfloat fy = v2->attrib[FRAG_ATTRIB_WPOS][1] - v0->attrib[FRAG_ATTRIB_WPOS][1]; 62 GLfloat c = ex*fy-ey*fx; 63 64 if (c * swrast->_BackfaceSign * swrast->_BackfaceCullSign <= 0.0F) 65 return GL_FALSE; 66 67 return GL_TRUE; 68} 69 70 71 72/* 73 * Render a flat-shaded RGBA triangle. 74 */ 75#define NAME flat_rgba_triangle 76#define INTERP_Z 1 77#define SETUP_CODE \ 78 ASSERT(ctx->Texture._EnabledCoordUnits == 0);\ 79 ASSERT(ctx->Light.ShadeModel==GL_FLAT); \ 80 span.interpMask |= SPAN_RGBA; \ 81 span.red = ChanToFixed(v2->color[0]); \ 82 span.green = ChanToFixed(v2->color[1]); \ 83 span.blue = ChanToFixed(v2->color[2]); \ 84 span.alpha = ChanToFixed(v2->color[3]); \ 85 span.redStep = 0; \ 86 span.greenStep = 0; \ 87 span.blueStep = 0; \ 88 span.alphaStep = 0; 89#define RENDER_SPAN( span ) _swrast_write_rgba_span(ctx, &span); 90#include "s_tritemp.h" 91 92 93 94/* 95 * Render a smooth-shaded RGBA triangle. 96 */ 97#define NAME smooth_rgba_triangle 98#define INTERP_Z 1 99#define INTERP_RGB 1 100#define INTERP_ALPHA 1 101#define SETUP_CODE \ 102 { \ 103 /* texturing must be off */ \ 104 ASSERT(ctx->Texture._EnabledCoordUnits == 0); \ 105 ASSERT(ctx->Light.ShadeModel==GL_SMOOTH); \ 106 } 107#define RENDER_SPAN( span ) _swrast_write_rgba_span(ctx, &span); 108#include "s_tritemp.h" 109 110 111 112/* 113 * Render an RGB, GL_DECAL, textured triangle. 114 * Interpolate S,T only w/out mipmapping or perspective correction. 115 * 116 * No fog. No depth testing. 117 */ 118#define NAME simple_textured_triangle 119#define INTERP_INT_TEX 1 120#define S_SCALE twidth 121#define T_SCALE theight 122 123#define SETUP_CODE \ 124 struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0]; \ 125 const struct gl_texture_object *obj = \ 126 ctx->Texture.Unit[0].CurrentTex[TEXTURE_2D_INDEX]; \ 127 const struct gl_texture_image *texImg = \ 128 obj->Image[0][obj->BaseLevel]; \ 129 const GLfloat twidth = (GLfloat) texImg->Width; \ 130 const GLfloat theight = (GLfloat) texImg->Height; \ 131 const GLint twidth_log2 = texImg->WidthLog2; \ 132 const GLubyte *texture = (const GLubyte *) texImg->Data; \ 133 const GLint smask = texImg->Width - 1; \ 134 const GLint tmask = texImg->Height - 1; \ 135 ASSERT(texImg->TexFormat == MESA_FORMAT_RGB888); \ 136 if (!rb || !texture) { \ 137 return; \ 138 } 139 140#define RENDER_SPAN( span ) \ 141 GLuint i; \ 142 GLubyte rgb[MAX_WIDTH][3]; \ 143 span.intTex[0] -= FIXED_HALF; /* off-by-one error? */ \ 144 span.intTex[1] -= FIXED_HALF; \ 145 for (i = 0; i < span.end; i++) { \ 146 GLint s = FixedToInt(span.intTex[0]) & smask; \ 147 GLint t = FixedToInt(span.intTex[1]) & tmask; \ 148 GLint pos = (t << twidth_log2) + s; \ 149 pos = pos + pos + pos; /* multiply by 3 */ \ 150 rgb[i][RCOMP] = texture[pos+2]; \ 151 rgb[i][GCOMP] = texture[pos+1]; \ 152 rgb[i][BCOMP] = texture[pos+0]; \ 153 span.intTex[0] += span.intTexStep[0]; \ 154 span.intTex[1] += span.intTexStep[1]; \ 155 } \ 156 rb->PutRowRGB(ctx, rb, span.end, span.x, span.y, rgb, NULL); 157 158#include "s_tritemp.h" 159 160 161 162/* 163 * Render an RGB, GL_DECAL, textured triangle. 164 * Interpolate S,T, GL_LESS depth test, w/out mipmapping or 165 * perspective correction. 166 * Depth buffer bits must be <= sizeof(DEFAULT_SOFTWARE_DEPTH_TYPE) 167 * 168 * No fog. 169 */ 170#define NAME simple_z_textured_triangle 171#define INTERP_Z 1 172#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE 173#define INTERP_INT_TEX 1 174#define S_SCALE twidth 175#define T_SCALE theight 176 177#define SETUP_CODE \ 178 struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0]; \ 179 const struct gl_texture_object *obj = \ 180 ctx->Texture.Unit[0].CurrentTex[TEXTURE_2D_INDEX]; \ 181 const struct gl_texture_image *texImg = \ 182 obj->Image[0][obj->BaseLevel]; \ 183 const GLfloat twidth = (GLfloat) texImg->Width; \ 184 const GLfloat theight = (GLfloat) texImg->Height; \ 185 const GLint twidth_log2 = texImg->WidthLog2; \ 186 const GLubyte *texture = (const GLubyte *) texImg->Data; \ 187 const GLint smask = texImg->Width - 1; \ 188 const GLint tmask = texImg->Height - 1; \ 189 ASSERT(texImg->TexFormat == MESA_FORMAT_RGB888); \ 190 if (!rb || !texture) { \ 191 return; \ 192 } 193 194#define RENDER_SPAN( span ) \ 195 GLuint i; \ 196 GLubyte rgb[MAX_WIDTH][3]; \ 197 span.intTex[0] -= FIXED_HALF; /* off-by-one error? */ \ 198 span.intTex[1] -= FIXED_HALF; \ 199 for (i = 0; i < span.end; i++) { \ 200 const GLuint z = FixedToDepth(span.z); \ 201 if (z < zRow[i]) { \ 202 GLint s = FixedToInt(span.intTex[0]) & smask; \ 203 GLint t = FixedToInt(span.intTex[1]) & tmask; \ 204 GLint pos = (t << twidth_log2) + s; \ 205 pos = pos + pos + pos; /* multiply by 3 */ \ 206 rgb[i][RCOMP] = texture[pos+2]; \ 207 rgb[i][GCOMP] = texture[pos+1]; \ 208 rgb[i][BCOMP] = texture[pos+0]; \ 209 zRow[i] = z; \ 210 span.array->mask[i] = 1; \ 211 } \ 212 else { \ 213 span.array->mask[i] = 0; \ 214 } \ 215 span.intTex[0] += span.intTexStep[0]; \ 216 span.intTex[1] += span.intTexStep[1]; \ 217 span.z += span.zStep; \ 218 } \ 219 rb->PutRowRGB(ctx, rb, span.end, span.x, span.y, rgb, span.array->mask); 220 221#include "s_tritemp.h" 222 223 224#if CHAN_TYPE != GL_FLOAT 225 226struct affine_info 227{ 228 GLenum filter; 229 GLenum format; 230 GLenum envmode; 231 GLint smask, tmask; 232 GLint twidth_log2; 233 const GLchan *texture; 234 GLfixed er, eg, eb, ea; 235 GLint tbytesline, tsize; 236}; 237 238 239static INLINE GLint 240ilerp(GLint t, GLint a, GLint b) 241{ 242 return a + ((t * (b - a)) >> FIXED_SHIFT); 243} 244 245static INLINE GLint 246ilerp_2d(GLint ia, GLint ib, GLint v00, GLint v10, GLint v01, GLint v11) 247{ 248 const GLint temp0 = ilerp(ia, v00, v10); 249 const GLint temp1 = ilerp(ia, v01, v11); 250 return ilerp(ib, temp0, temp1); 251} 252 253 254/* This function can handle GL_NEAREST or GL_LINEAR sampling of 2D RGB or RGBA 255 * textures with GL_REPLACE, GL_MODULATE, GL_BLEND, GL_DECAL or GL_ADD 256 * texture env modes. 257 */ 258static INLINE void 259affine_span(struct gl_context *ctx, SWspan *span, 260 struct affine_info *info) 261{ 262 GLchan sample[4]; /* the filtered texture sample */ 263 const GLuint texEnableSave = ctx->Texture._EnabledCoordUnits; 264 265 /* Instead of defining a function for each mode, a test is done 266 * between the outer and inner loops. This is to reduce code size 267 * and complexity. Observe that an optimizing compiler kills 268 * unused variables (for instance tf,sf,ti,si in case of GL_NEAREST). 269 */ 270 271#define NEAREST_RGB \ 272 sample[RCOMP] = tex00[2]; \ 273 sample[GCOMP] = tex00[1]; \ 274 sample[BCOMP] = tex00[0]; \ 275 sample[ACOMP] = CHAN_MAX; 276 277#define LINEAR_RGB \ 278 sample[RCOMP] = ilerp_2d(sf, tf, tex00[2], tex01[2], tex10[2], tex11[2]);\ 279 sample[GCOMP] = ilerp_2d(sf, tf, tex00[1], tex01[1], tex10[1], tex11[1]);\ 280 sample[BCOMP] = ilerp_2d(sf, tf, tex00[0], tex01[0], tex10[0], tex11[0]);\ 281 sample[ACOMP] = CHAN_MAX; 282 283#define NEAREST_RGBA \ 284 sample[RCOMP] = tex00[3]; \ 285 sample[GCOMP] = tex00[2]; \ 286 sample[BCOMP] = tex00[1]; \ 287 sample[ACOMP] = tex00[0]; 288 289#define LINEAR_RGBA \ 290 sample[RCOMP] = ilerp_2d(sf, tf, tex00[3], tex01[3], tex10[3], tex11[3]);\ 291 sample[GCOMP] = ilerp_2d(sf, tf, tex00[2], tex01[2], tex10[2], tex11[2]);\ 292 sample[BCOMP] = ilerp_2d(sf, tf, tex00[1], tex01[1], tex10[1], tex11[1]);\ 293 sample[ACOMP] = ilerp_2d(sf, tf, tex00[0], tex01[0], tex10[0], tex11[0]) 294 295#define MODULATE \ 296 dest[RCOMP] = span->red * (sample[RCOMP] + 1u) >> (FIXED_SHIFT + 8); \ 297 dest[GCOMP] = span->green * (sample[GCOMP] + 1u) >> (FIXED_SHIFT + 8); \ 298 dest[BCOMP] = span->blue * (sample[BCOMP] + 1u) >> (FIXED_SHIFT + 8); \ 299 dest[ACOMP] = span->alpha * (sample[ACOMP] + 1u) >> (FIXED_SHIFT + 8) 300 301#define DECAL \ 302 dest[RCOMP] = ((CHAN_MAX - sample[ACOMP]) * span->red + \ 303 ((sample[ACOMP] + 1) * sample[RCOMP] << FIXED_SHIFT)) \ 304 >> (FIXED_SHIFT + 8); \ 305 dest[GCOMP] = ((CHAN_MAX - sample[ACOMP]) * span->green + \ 306 ((sample[ACOMP] + 1) * sample[GCOMP] << FIXED_SHIFT)) \ 307 >> (FIXED_SHIFT + 8); \ 308 dest[BCOMP] = ((CHAN_MAX - sample[ACOMP]) * span->blue + \ 309 ((sample[ACOMP] + 1) * sample[BCOMP] << FIXED_SHIFT)) \ 310 >> (FIXED_SHIFT + 8); \ 311 dest[ACOMP] = FixedToInt(span->alpha) 312 313#define BLEND \ 314 dest[RCOMP] = ((CHAN_MAX - sample[RCOMP]) * span->red \ 315 + (sample[RCOMP] + 1) * info->er) >> (FIXED_SHIFT + 8); \ 316 dest[GCOMP] = ((CHAN_MAX - sample[GCOMP]) * span->green \ 317 + (sample[GCOMP] + 1) * info->eg) >> (FIXED_SHIFT + 8); \ 318 dest[BCOMP] = ((CHAN_MAX - sample[BCOMP]) * span->blue \ 319 + (sample[BCOMP] + 1) * info->eb) >> (FIXED_SHIFT + 8); \ 320 dest[ACOMP] = span->alpha * (sample[ACOMP] + 1) >> (FIXED_SHIFT + 8) 321 322#define REPLACE COPY_CHAN4(dest, sample) 323 324#define ADD \ 325 { \ 326 GLint rSum = FixedToInt(span->red) + (GLint) sample[RCOMP]; \ 327 GLint gSum = FixedToInt(span->green) + (GLint) sample[GCOMP]; \ 328 GLint bSum = FixedToInt(span->blue) + (GLint) sample[BCOMP]; \ 329 dest[RCOMP] = MIN2(rSum, CHAN_MAX); \ 330 dest[GCOMP] = MIN2(gSum, CHAN_MAX); \ 331 dest[BCOMP] = MIN2(bSum, CHAN_MAX); \ 332 dest[ACOMP] = span->alpha * (sample[ACOMP] + 1) >> (FIXED_SHIFT + 8); \ 333 } 334 335/* shortcuts */ 336 337#define NEAREST_RGB_REPLACE \ 338 NEAREST_RGB; \ 339 dest[0] = sample[0]; \ 340 dest[1] = sample[1]; \ 341 dest[2] = sample[2]; \ 342 dest[3] = FixedToInt(span->alpha); 343 344#define NEAREST_RGBA_REPLACE \ 345 dest[RCOMP] = tex00[3]; \ 346 dest[GCOMP] = tex00[2]; \ 347 dest[BCOMP] = tex00[1]; \ 348 dest[ACOMP] = tex00[0] 349 350#define SPAN_NEAREST(DO_TEX, COMPS) \ 351 for (i = 0; i < span->end; i++) { \ 352 /* Isn't it necessary to use FixedFloor below?? */ \ 353 GLint s = FixedToInt(span->intTex[0]) & info->smask; \ 354 GLint t = FixedToInt(span->intTex[1]) & info->tmask; \ 355 GLint pos = (t << info->twidth_log2) + s; \ 356 const GLchan *tex00 = info->texture + COMPS * pos; \ 357 DO_TEX; \ 358 span->red += span->redStep; \ 359 span->green += span->greenStep; \ 360 span->blue += span->blueStep; \ 361 span->alpha += span->alphaStep; \ 362 span->intTex[0] += span->intTexStep[0]; \ 363 span->intTex[1] += span->intTexStep[1]; \ 364 dest += 4; \ 365 } 366 367#define SPAN_LINEAR(DO_TEX, COMPS) \ 368 for (i = 0; i < span->end; i++) { \ 369 /* Isn't it necessary to use FixedFloor below?? */ \ 370 const GLint s = FixedToInt(span->intTex[0]) & info->smask; \ 371 const GLint t = FixedToInt(span->intTex[1]) & info->tmask; \ 372 const GLfixed sf = span->intTex[0] & FIXED_FRAC_MASK; \ 373 const GLfixed tf = span->intTex[1] & FIXED_FRAC_MASK; \ 374 const GLint pos = (t << info->twidth_log2) + s; \ 375 const GLchan *tex00 = info->texture + COMPS * pos; \ 376 const GLchan *tex10 = tex00 + info->tbytesline; \ 377 const GLchan *tex01 = tex00 + COMPS; \ 378 const GLchan *tex11 = tex10 + COMPS; \ 379 if (t == info->tmask) { \ 380 tex10 -= info->tsize; \ 381 tex11 -= info->tsize; \ 382 } \ 383 if (s == info->smask) { \ 384 tex01 -= info->tbytesline; \ 385 tex11 -= info->tbytesline; \ 386 } \ 387 DO_TEX; \ 388 span->red += span->redStep; \ 389 span->green += span->greenStep; \ 390 span->blue += span->blueStep; \ 391 span->alpha += span->alphaStep; \ 392 span->intTex[0] += span->intTexStep[0]; \ 393 span->intTex[1] += span->intTexStep[1]; \ 394 dest += 4; \ 395 } 396 397 398 GLuint i; 399 GLchan *dest = span->array->rgba[0]; 400 401 /* Disable tex units so they're not re-applied in swrast_write_rgba_span */ 402 ctx->Texture._EnabledCoordUnits = 0x0; 403 404 span->intTex[0] -= FIXED_HALF; 405 span->intTex[1] -= FIXED_HALF; 406 switch (info->filter) { 407 case GL_NEAREST: 408 switch (info->format) { 409 case MESA_FORMAT_RGB888: 410 switch (info->envmode) { 411 case GL_MODULATE: 412 SPAN_NEAREST(NEAREST_RGB;MODULATE,3); 413 break; 414 case GL_DECAL: 415 case GL_REPLACE: 416 SPAN_NEAREST(NEAREST_RGB_REPLACE,3); 417 break; 418 case GL_BLEND: 419 SPAN_NEAREST(NEAREST_RGB;BLEND,3); 420 break; 421 case GL_ADD: 422 SPAN_NEAREST(NEAREST_RGB;ADD,3); 423 break; 424 default: 425 _mesa_problem(ctx, "bad tex env mode in SPAN_LINEAR"); 426 return; 427 } 428 break; 429 case MESA_FORMAT_RGBA8888: 430 switch(info->envmode) { 431 case GL_MODULATE: 432 SPAN_NEAREST(NEAREST_RGBA;MODULATE,4); 433 break; 434 case GL_DECAL: 435 SPAN_NEAREST(NEAREST_RGBA;DECAL,4); 436 break; 437 case GL_BLEND: 438 SPAN_NEAREST(NEAREST_RGBA;BLEND,4); 439 break; 440 case GL_ADD: 441 SPAN_NEAREST(NEAREST_RGBA;ADD,4); 442 break; 443 case GL_REPLACE: 444 SPAN_NEAREST(NEAREST_RGBA_REPLACE,4); 445 break; 446 default: 447 _mesa_problem(ctx, "bad tex env mode (2) in SPAN_LINEAR"); 448 return; 449 } 450 break; 451 } 452 break; 453 454 case GL_LINEAR: 455 span->intTex[0] -= FIXED_HALF; 456 span->intTex[1] -= FIXED_HALF; 457 switch (info->format) { 458 case MESA_FORMAT_RGB888: 459 switch (info->envmode) { 460 case GL_MODULATE: 461 SPAN_LINEAR(LINEAR_RGB;MODULATE,3); 462 break; 463 case GL_DECAL: 464 case GL_REPLACE: 465 SPAN_LINEAR(LINEAR_RGB;REPLACE,3); 466 break; 467 case GL_BLEND: 468 SPAN_LINEAR(LINEAR_RGB;BLEND,3); 469 break; 470 case GL_ADD: 471 SPAN_LINEAR(LINEAR_RGB;ADD,3); 472 break; 473 default: 474 _mesa_problem(ctx, "bad tex env mode (3) in SPAN_LINEAR"); 475 return; 476 } 477 break; 478 case MESA_FORMAT_RGBA8888: 479 switch (info->envmode) { 480 case GL_MODULATE: 481 SPAN_LINEAR(LINEAR_RGBA;MODULATE,4); 482 break; 483 case GL_DECAL: 484 SPAN_LINEAR(LINEAR_RGBA;DECAL,4); 485 break; 486 case GL_BLEND: 487 SPAN_LINEAR(LINEAR_RGBA;BLEND,4); 488 break; 489 case GL_ADD: 490 SPAN_LINEAR(LINEAR_RGBA;ADD,4); 491 break; 492 case GL_REPLACE: 493 SPAN_LINEAR(LINEAR_RGBA;REPLACE,4); 494 break; 495 default: 496 _mesa_problem(ctx, "bad tex env mode (4) in SPAN_LINEAR"); 497 return; 498 } 499 break; 500 } 501 break; 502 } 503 span->interpMask &= ~SPAN_RGBA; 504 ASSERT(span->arrayMask & SPAN_RGBA); 505 506 _swrast_write_rgba_span(ctx, span); 507 508 /* re-enable texture units */ 509 ctx->Texture._EnabledCoordUnits = texEnableSave; 510 511#undef SPAN_NEAREST 512#undef SPAN_LINEAR 513} 514 515 516 517/* 518 * Render an RGB/RGBA textured triangle without perspective correction. 519 */ 520#define NAME affine_textured_triangle 521#define INTERP_Z 1 522#define INTERP_RGB 1 523#define INTERP_ALPHA 1 524#define INTERP_INT_TEX 1 525#define S_SCALE twidth 526#define T_SCALE theight 527 528#define SETUP_CODE \ 529 struct affine_info info; \ 530 struct gl_texture_unit *unit = ctx->Texture.Unit+0; \ 531 const struct gl_texture_object *obj = \ 532 ctx->Texture.Unit[0].CurrentTex[TEXTURE_2D_INDEX]; \ 533 const struct gl_texture_image *texImg = \ 534 obj->Image[0][obj->BaseLevel]; \ 535 const GLfloat twidth = (GLfloat) texImg->Width; \ 536 const GLfloat theight = (GLfloat) texImg->Height; \ 537 info.texture = (const GLchan *) texImg->Data; \ 538 info.twidth_log2 = texImg->WidthLog2; \ 539 info.smask = texImg->Width - 1; \ 540 info.tmask = texImg->Height - 1; \ 541 info.format = texImg->TexFormat; \ 542 info.filter = obj->MinFilter; \ 543 info.envmode = unit->EnvMode; \ 544 info.er = 0; \ 545 info.eg = 0; \ 546 info.eb = 0; \ 547 span.arrayMask |= SPAN_RGBA; \ 548 \ 549 if (info.envmode == GL_BLEND) { \ 550 /* potential off-by-one error here? (1.0f -> 2048 -> 0) */ \ 551 info.er = FloatToFixed(unit->EnvColor[RCOMP] * CHAN_MAXF); \ 552 info.eg = FloatToFixed(unit->EnvColor[GCOMP] * CHAN_MAXF); \ 553 info.eb = FloatToFixed(unit->EnvColor[BCOMP] * CHAN_MAXF); \ 554 info.ea = FloatToFixed(unit->EnvColor[ACOMP] * CHAN_MAXF); \ 555 } \ 556 if (!info.texture) { \ 557 /* this shouldn't happen */ \ 558 return; \ 559 } \ 560 \ 561 switch (info.format) { \ 562 case MESA_FORMAT_RGB888: \ 563 info.tbytesline = texImg->Width * 3; \ 564 break; \ 565 case MESA_FORMAT_RGBA8888: \ 566 info.tbytesline = texImg->Width * 4; \ 567 break; \ 568 default: \ 569 _mesa_problem(NULL, "Bad texture format in affine_texture_triangle");\ 570 return; \ 571 } \ 572 info.tsize = texImg->Height * info.tbytesline; 573 574#define RENDER_SPAN( span ) affine_span(ctx, &span, &info); 575 576#include "s_tritemp.h" 577 578 579 580struct persp_info 581{ 582 GLenum filter; 583 GLenum format; 584 GLenum envmode; 585 GLint smask, tmask; 586 GLint twidth_log2; 587 const GLchan *texture; 588 GLfixed er, eg, eb, ea; /* texture env color */ 589 GLint tbytesline, tsize; 590}; 591 592 593static INLINE void 594fast_persp_span(struct gl_context *ctx, SWspan *span, 595 struct persp_info *info) 596{ 597 GLchan sample[4]; /* the filtered texture sample */ 598 599 /* Instead of defining a function for each mode, a test is done 600 * between the outer and inner loops. This is to reduce code size 601 * and complexity. Observe that an optimizing compiler kills 602 * unused variables (for instance tf,sf,ti,si in case of GL_NEAREST). 603 */ 604#define SPAN_NEAREST(DO_TEX,COMP) \ 605 for (i = 0; i < span->end; i++) { \ 606 GLdouble invQ = tex_coord[2] ? \ 607 (1.0 / tex_coord[2]) : 1.0; \ 608 GLfloat s_tmp = (GLfloat) (tex_coord[0] * invQ); \ 609 GLfloat t_tmp = (GLfloat) (tex_coord[1] * invQ); \ 610 GLint s = IFLOOR(s_tmp) & info->smask; \ 611 GLint t = IFLOOR(t_tmp) & info->tmask; \ 612 GLint pos = (t << info->twidth_log2) + s; \ 613 const GLchan *tex00 = info->texture + COMP * pos; \ 614 DO_TEX; \ 615 span->red += span->redStep; \ 616 span->green += span->greenStep; \ 617 span->blue += span->blueStep; \ 618 span->alpha += span->alphaStep; \ 619 tex_coord[0] += tex_step[0]; \ 620 tex_coord[1] += tex_step[1]; \ 621 tex_coord[2] += tex_step[2]; \ 622 dest += 4; \ 623 } 624 625#define SPAN_LINEAR(DO_TEX,COMP) \ 626 for (i = 0; i < span->end; i++) { \ 627 GLdouble invQ = tex_coord[2] ? \ 628 (1.0 / tex_coord[2]) : 1.0; \ 629 const GLfloat s_tmp = (GLfloat) (tex_coord[0] * invQ); \ 630 const GLfloat t_tmp = (GLfloat) (tex_coord[1] * invQ); \ 631 const GLfixed s_fix = FloatToFixed(s_tmp) - FIXED_HALF; \ 632 const GLfixed t_fix = FloatToFixed(t_tmp) - FIXED_HALF; \ 633 const GLint s = FixedToInt(FixedFloor(s_fix)) & info->smask; \ 634 const GLint t = FixedToInt(FixedFloor(t_fix)) & info->tmask; \ 635 const GLfixed sf = s_fix & FIXED_FRAC_MASK; \ 636 const GLfixed tf = t_fix & FIXED_FRAC_MASK; \ 637 const GLint pos = (t << info->twidth_log2) + s; \ 638 const GLchan *tex00 = info->texture + COMP * pos; \ 639 const GLchan *tex10 = tex00 + info->tbytesline; \ 640 const GLchan *tex01 = tex00 + COMP; \ 641 const GLchan *tex11 = tex10 + COMP; \ 642 if (t == info->tmask) { \ 643 tex10 -= info->tsize; \ 644 tex11 -= info->tsize; \ 645 } \ 646 if (s == info->smask) { \ 647 tex01 -= info->tbytesline; \ 648 tex11 -= info->tbytesline; \ 649 } \ 650 DO_TEX; \ 651 span->red += span->redStep; \ 652 span->green += span->greenStep; \ 653 span->blue += span->blueStep; \ 654 span->alpha += span->alphaStep; \ 655 tex_coord[0] += tex_step[0]; \ 656 tex_coord[1] += tex_step[1]; \ 657 tex_coord[2] += tex_step[2]; \ 658 dest += 4; \ 659 } 660 661 GLuint i; 662 GLfloat tex_coord[3], tex_step[3]; 663 GLchan *dest = span->array->rgba[0]; 664 665 const GLuint texEnableSave = ctx->Texture._EnabledCoordUnits; 666 ctx->Texture._EnabledCoordUnits = 0; 667 668 tex_coord[0] = span->attrStart[FRAG_ATTRIB_TEX0][0] * (info->smask + 1); 669 tex_step[0] = span->attrStepX[FRAG_ATTRIB_TEX0][0] * (info->smask + 1); 670 tex_coord[1] = span->attrStart[FRAG_ATTRIB_TEX0][1] * (info->tmask + 1); 671 tex_step[1] = span->attrStepX[FRAG_ATTRIB_TEX0][1] * (info->tmask + 1); 672 /* span->attrStart[FRAG_ATTRIB_TEX0][2] only if 3D-texturing, here only 2D */ 673 tex_coord[2] = span->attrStart[FRAG_ATTRIB_TEX0][3]; 674 tex_step[2] = span->attrStepX[FRAG_ATTRIB_TEX0][3]; 675 676 switch (info->filter) { 677 case GL_NEAREST: 678 switch (info->format) { 679 case MESA_FORMAT_RGB888: 680 switch (info->envmode) { 681 case GL_MODULATE: 682 SPAN_NEAREST(NEAREST_RGB;MODULATE,3); 683 break; 684 case GL_DECAL: 685 case GL_REPLACE: 686 SPAN_NEAREST(NEAREST_RGB_REPLACE,3); 687 break; 688 case GL_BLEND: 689 SPAN_NEAREST(NEAREST_RGB;BLEND,3); 690 break; 691 case GL_ADD: 692 SPAN_NEAREST(NEAREST_RGB;ADD,3); 693 break; 694 default: 695 _mesa_problem(ctx, "bad tex env mode (5) in SPAN_LINEAR"); 696 return; 697 } 698 break; 699 case MESA_FORMAT_RGBA8888: 700 switch(info->envmode) { 701 case GL_MODULATE: 702 SPAN_NEAREST(NEAREST_RGBA;MODULATE,4); 703 break; 704 case GL_DECAL: 705 SPAN_NEAREST(NEAREST_RGBA;DECAL,4); 706 break; 707 case GL_BLEND: 708 SPAN_NEAREST(NEAREST_RGBA;BLEND,4); 709 break; 710 case GL_ADD: 711 SPAN_NEAREST(NEAREST_RGBA;ADD,4); 712 break; 713 case GL_REPLACE: 714 SPAN_NEAREST(NEAREST_RGBA_REPLACE,4); 715 break; 716 default: 717 _mesa_problem(ctx, "bad tex env mode (6) in SPAN_LINEAR"); 718 return; 719 } 720 break; 721 } 722 break; 723 724 case GL_LINEAR: 725 switch (info->format) { 726 case MESA_FORMAT_RGB888: 727 switch (info->envmode) { 728 case GL_MODULATE: 729 SPAN_LINEAR(LINEAR_RGB;MODULATE,3); 730 break; 731 case GL_DECAL: 732 case GL_REPLACE: 733 SPAN_LINEAR(LINEAR_RGB;REPLACE,3); 734 break; 735 case GL_BLEND: 736 SPAN_LINEAR(LINEAR_RGB;BLEND,3); 737 break; 738 case GL_ADD: 739 SPAN_LINEAR(LINEAR_RGB;ADD,3); 740 break; 741 default: 742 _mesa_problem(ctx, "bad tex env mode (7) in SPAN_LINEAR"); 743 return; 744 } 745 break; 746 case MESA_FORMAT_RGBA8888: 747 switch (info->envmode) { 748 case GL_MODULATE: 749 SPAN_LINEAR(LINEAR_RGBA;MODULATE,4); 750 break; 751 case GL_DECAL: 752 SPAN_LINEAR(LINEAR_RGBA;DECAL,4); 753 break; 754 case GL_BLEND: 755 SPAN_LINEAR(LINEAR_RGBA;BLEND,4); 756 break; 757 case GL_ADD: 758 SPAN_LINEAR(LINEAR_RGBA;ADD,4); 759 break; 760 case GL_REPLACE: 761 SPAN_LINEAR(LINEAR_RGBA;REPLACE,4); 762 break; 763 default: 764 _mesa_problem(ctx, "bad tex env mode (8) in SPAN_LINEAR"); 765 return; 766 } 767 break; 768 } 769 break; 770 } 771 772 ASSERT(span->arrayMask & SPAN_RGBA); 773 _swrast_write_rgba_span(ctx, span); 774 775#undef SPAN_NEAREST 776#undef SPAN_LINEAR 777 778 /* restore state */ 779 ctx->Texture._EnabledCoordUnits = texEnableSave; 780} 781 782 783/* 784 * Render an perspective corrected RGB/RGBA textured triangle. 785 * The Q (aka V in Mesa) coordinate must be zero such that the divide 786 * by interpolated Q/W comes out right. 787 * 788 */ 789#define NAME persp_textured_triangle 790#define INTERP_Z 1 791#define INTERP_RGB 1 792#define INTERP_ALPHA 1 793#define INTERP_ATTRIBS 1 794 795#define SETUP_CODE \ 796 struct persp_info info; \ 797 const struct gl_texture_unit *unit = ctx->Texture.Unit+0; \ 798 const struct gl_texture_object *obj = \ 799 ctx->Texture.Unit[0].CurrentTex[TEXTURE_2D_INDEX]; \ 800 const struct gl_texture_image *texImg = \ 801 obj->Image[0][obj->BaseLevel]; \ 802 info.texture = (const GLchan *) texImg->Data; \ 803 info.twidth_log2 = texImg->WidthLog2; \ 804 info.smask = texImg->Width - 1; \ 805 info.tmask = texImg->Height - 1; \ 806 info.format = texImg->TexFormat; \ 807 info.filter = obj->MinFilter; \ 808 info.envmode = unit->EnvMode; \ 809 info.er = 0; \ 810 info.eg = 0; \ 811 info.eb = 0; \ 812 \ 813 if (info.envmode == GL_BLEND) { \ 814 /* potential off-by-one error here? (1.0f -> 2048 -> 0) */ \ 815 info.er = FloatToFixed(unit->EnvColor[RCOMP] * CHAN_MAXF); \ 816 info.eg = FloatToFixed(unit->EnvColor[GCOMP] * CHAN_MAXF); \ 817 info.eb = FloatToFixed(unit->EnvColor[BCOMP] * CHAN_MAXF); \ 818 info.ea = FloatToFixed(unit->EnvColor[ACOMP] * CHAN_MAXF); \ 819 } \ 820 if (!info.texture) { \ 821 /* this shouldn't happen */ \ 822 return; \ 823 } \ 824 \ 825 switch (info.format) { \ 826 case MESA_FORMAT_RGB888: \ 827 info.tbytesline = texImg->Width * 3; \ 828 break; \ 829 case MESA_FORMAT_RGBA8888: \ 830 info.tbytesline = texImg->Width * 4; \ 831 break; \ 832 default: \ 833 _mesa_problem(NULL, "Bad texture format in persp_textured_triangle");\ 834 return; \ 835 } \ 836 info.tsize = texImg->Height * info.tbytesline; 837 838#define RENDER_SPAN( span ) \ 839 span.interpMask &= ~SPAN_RGBA; \ 840 span.arrayMask |= SPAN_RGBA; \ 841 fast_persp_span(ctx, &span, &info); 842 843#include "s_tritemp.h" 844 845#endif /*CHAN_TYPE != GL_FLOAT*/ 846 847 848 849/* 850 * Render an RGBA triangle with arbitrary attributes. 851 */ 852#define NAME general_triangle 853#define INTERP_Z 1 854#define INTERP_RGB 1 855#define INTERP_ALPHA 1 856#define INTERP_ATTRIBS 1 857#define RENDER_SPAN( span ) _swrast_write_rgba_span(ctx, &span); 858#include "s_tritemp.h" 859 860 861 862 863/* 864 * Special tri function for occlusion testing 865 */ 866#define NAME occlusion_zless_triangle 867#define INTERP_Z 1 868#define SETUP_CODE \ 869 struct gl_renderbuffer *rb = ctx->DrawBuffer->_DepthBuffer; \ 870 struct gl_query_object *q = ctx->Query.CurrentOcclusionObject; \ 871 ASSERT(ctx->Depth.Test); \ 872 ASSERT(!ctx->Depth.Mask); \ 873 ASSERT(ctx->Depth.Func == GL_LESS); \ 874 if (!q) { \ 875 return; \ 876 } 877#define RENDER_SPAN( span ) \ 878 if (rb->Format == MESA_FORMAT_Z16) { \ 879 GLuint i; \ 880 const GLushort *zRow = (const GLushort *) \ 881 rb->GetPointer(ctx, rb, span.x, span.y); \ 882 for (i = 0; i < span.end; i++) { \ 883 GLuint z = FixedToDepth(span.z); \ 884 if (z < zRow[i]) { \ 885 q->Result++; \ 886 } \ 887 span.z += span.zStep; \ 888 } \ 889 } \ 890 else { \ 891 GLuint i; \ 892 const GLuint *zRow = (const GLuint *) \ 893 rb->GetPointer(ctx, rb, span.x, span.y); \ 894 for (i = 0; i < span.end; i++) { \ 895 if ((GLuint)span.z < zRow[i]) { \ 896 q->Result++; \ 897 } \ 898 span.z += span.zStep; \ 899 } \ 900 } 901#include "s_tritemp.h" 902 903 904 905static void 906nodraw_triangle( struct gl_context *ctx, 907 const SWvertex *v0, 908 const SWvertex *v1, 909 const SWvertex *v2 ) 910{ 911 (void) (ctx && v0 && v1 && v2); 912} 913 914 915/* 916 * This is used when separate specular color is enabled, but not 917 * texturing. We add the specular color to the primary color, 918 * draw the triangle, then restore the original primary color. 919 * Inefficient, but seldom needed. 920 */ 921void 922_swrast_add_spec_terms_triangle(struct gl_context *ctx, const SWvertex *v0, 923 const SWvertex *v1, const SWvertex *v2) 924{ 925 SWvertex *ncv0 = (SWvertex *)v0; /* drop const qualifier */ 926 SWvertex *ncv1 = (SWvertex *)v1; 927 SWvertex *ncv2 = (SWvertex *)v2; 928 GLfloat rSum, gSum, bSum; 929 GLchan cSave[3][4]; 930 931 /* save original colors */ 932 COPY_CHAN4( cSave[0], ncv0->color ); 933 COPY_CHAN4( cSave[1], ncv1->color ); 934 COPY_CHAN4( cSave[2], ncv2->color ); 935 /* sum v0 */ 936 rSum = CHAN_TO_FLOAT(ncv0->color[0]) + ncv0->attrib[FRAG_ATTRIB_COL1][0]; 937 gSum = CHAN_TO_FLOAT(ncv0->color[1]) + ncv0->attrib[FRAG_ATTRIB_COL1][1]; 938 bSum = CHAN_TO_FLOAT(ncv0->color[2]) + ncv0->attrib[FRAG_ATTRIB_COL1][2]; 939 UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[0], rSum); 940 UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[1], gSum); 941 UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[2], bSum); 942 /* sum v1 */ 943 rSum = CHAN_TO_FLOAT(ncv1->color[0]) + ncv1->attrib[FRAG_ATTRIB_COL1][0]; 944 gSum = CHAN_TO_FLOAT(ncv1->color[1]) + ncv1->attrib[FRAG_ATTRIB_COL1][1]; 945 bSum = CHAN_TO_FLOAT(ncv1->color[2]) + ncv1->attrib[FRAG_ATTRIB_COL1][2]; 946 UNCLAMPED_FLOAT_TO_CHAN(ncv1->color[0], rSum); 947 UNCLAMPED_FLOAT_TO_CHAN(ncv1->color[1], gSum); 948 UNCLAMPED_FLOAT_TO_CHAN(ncv1->color[2], bSum); 949 /* sum v2 */ 950 rSum = CHAN_TO_FLOAT(ncv2->color[0]) + ncv2->attrib[FRAG_ATTRIB_COL1][0]; 951 gSum = CHAN_TO_FLOAT(ncv2->color[1]) + ncv2->attrib[FRAG_ATTRIB_COL1][1]; 952 bSum = CHAN_TO_FLOAT(ncv2->color[2]) + ncv2->attrib[FRAG_ATTRIB_COL1][2]; 953 UNCLAMPED_FLOAT_TO_CHAN(ncv2->color[0], rSum); 954 UNCLAMPED_FLOAT_TO_CHAN(ncv2->color[1], gSum); 955 UNCLAMPED_FLOAT_TO_CHAN(ncv2->color[2], bSum); 956 /* draw */ 957 SWRAST_CONTEXT(ctx)->SpecTriangle( ctx, ncv0, ncv1, ncv2 ); 958 /* restore original colors */ 959 COPY_CHAN4( ncv0->color, cSave[0] ); 960 COPY_CHAN4( ncv1->color, cSave[1] ); 961 COPY_CHAN4( ncv2->color, cSave[2] ); 962} 963 964 965 966#ifdef DEBUG 967 968/* record the current triangle function name */ 969const char *_mesa_triFuncName = NULL; 970 971#define USE(triFunc) \ 972do { \ 973 _mesa_triFuncName = #triFunc; \ 974 /*printf("%s\n", _mesa_triFuncName);*/ \ 975 swrast->Triangle = triFunc; \ 976} while (0) 977 978#else 979 980#define USE(triFunc) swrast->Triangle = triFunc; 981 982#endif 983 984 985 986 987/* 988 * Determine which triangle rendering function to use given the current 989 * rendering context. 990 * 991 * Please update the summary flag _SWRAST_NEW_TRIANGLE if you add or 992 * remove tests to this code. 993 */ 994void 995_swrast_choose_triangle( struct gl_context *ctx ) 996{ 997 SWcontext *swrast = SWRAST_CONTEXT(ctx); 998 999 if (ctx->Polygon.CullFlag && 1000 ctx->Polygon.CullFaceMode == GL_FRONT_AND_BACK) { 1001 USE(nodraw_triangle); 1002 return; 1003 } 1004 1005 if (ctx->RenderMode==GL_RENDER) { 1006 1007 if (ctx->Polygon.SmoothFlag) { 1008 _swrast_set_aa_triangle_function(ctx); 1009 ASSERT(swrast->Triangle); 1010 return; 1011 } 1012 1013 /* special case for occlusion testing */ 1014 if (ctx->Query.CurrentOcclusionObject && 1015 ctx->Depth.Test && 1016 ctx->Depth.Mask == GL_FALSE && 1017 ctx->Depth.Func == GL_LESS && 1018 !ctx->Stencil._Enabled) { 1019 if (ctx->Color.ColorMask[0][0] == 0 && 1020 ctx->Color.ColorMask[0][1] == 0 && 1021 ctx->Color.ColorMask[0][2] == 0 && 1022 ctx->Color.ColorMask[0][3] == 0) { 1023 USE(occlusion_zless_triangle); 1024 return; 1025 } 1026 } 1027 1028 /* 1029 * XXX should examine swrast->_ActiveAttribMask to determine what 1030 * needs to be interpolated. 1031 */ 1032 if (ctx->Texture._EnabledCoordUnits || 1033 ctx->FragmentProgram._Current || 1034 ctx->ATIFragmentShader._Enabled || 1035 NEED_SECONDARY_COLOR(ctx) || 1036 swrast->_FogEnabled) { 1037 /* Ugh, we do a _lot_ of tests to pick the best textured tri func */ 1038 const struct gl_texture_object *texObj2D; 1039 const struct gl_texture_image *texImg; 1040 GLenum minFilter, magFilter, envMode; 1041 gl_format format; 1042 texObj2D = ctx->Texture.Unit[0].CurrentTex[TEXTURE_2D_INDEX]; 1043 1044 texImg = texObj2D ? texObj2D->Image[0][texObj2D->BaseLevel] : NULL; 1045 format = texImg ? texImg->TexFormat : MESA_FORMAT_NONE; 1046 minFilter = texObj2D ? texObj2D->MinFilter : GL_NONE; 1047 magFilter = texObj2D ? texObj2D->MagFilter : GL_NONE; 1048 envMode = ctx->Texture.Unit[0].EnvMode; 1049 1050 /* First see if we can use an optimized 2-D texture function */ 1051 if (ctx->Texture._EnabledCoordUnits == 0x1 1052 && !ctx->FragmentProgram._Current 1053 && !ctx->ATIFragmentShader._Enabled 1054 && ctx->Texture._EnabledUnits == 0x1 1055 && ctx->Texture.Unit[0]._ReallyEnabled == TEXTURE_2D_BIT 1056 && texObj2D->WrapS == GL_REPEAT 1057 && texObj2D->WrapT == GL_REPEAT 1058 && texObj2D->_Swizzle == SWIZZLE_NOOP 1059 && texImg->_IsPowerOfTwo 1060 && texImg->Border == 0 1061 && texImg->Width == texImg->RowStride 1062 && (format == MESA_FORMAT_RGB888 || format == MESA_FORMAT_RGBA8888) 1063 && minFilter == magFilter 1064 && ctx->Light.Model.ColorControl == GL_SINGLE_COLOR 1065 && !swrast->_FogEnabled 1066 && ctx->Texture.Unit[0].EnvMode != GL_COMBINE_EXT 1067 && ctx->Texture.Unit[0].EnvMode != GL_COMBINE4_NV) { 1068 if (ctx->Hint.PerspectiveCorrection==GL_FASTEST) { 1069 if (minFilter == GL_NEAREST 1070 && format == MESA_FORMAT_RGB888 1071 && (envMode == GL_REPLACE || envMode == GL_DECAL) 1072 && ((swrast->_RasterMask == (DEPTH_BIT | TEXTURE_BIT) 1073 && ctx->Depth.Func == GL_LESS 1074 && ctx->Depth.Mask == GL_TRUE) 1075 || swrast->_RasterMask == TEXTURE_BIT) 1076 && ctx->Polygon.StippleFlag == GL_FALSE 1077 && ctx->DrawBuffer->Visual.depthBits <= 16) { 1078 if (swrast->_RasterMask == (DEPTH_BIT | TEXTURE_BIT)) { 1079 USE(simple_z_textured_triangle); 1080 } 1081 else { 1082 USE(simple_textured_triangle); 1083 } 1084 } 1085 else { 1086#if CHAN_BITS != 8 1087 USE(general_triangle); 1088#else 1089 if (format == MESA_FORMAT_RGBA8888 && !_mesa_little_endian()) { 1090 /* We only handle RGBA8888 correctly on little endian 1091 * in the optimized code above. 1092 */ 1093 USE(general_triangle); 1094 } 1095 else { 1096 USE(affine_textured_triangle); 1097 } 1098#endif 1099 } 1100 } 1101 else { 1102#if CHAN_BITS != 8 1103 USE(general_triangle); 1104#else 1105 USE(persp_textured_triangle); 1106#endif 1107 } 1108 } 1109 else { 1110 /* general case textured triangles */ 1111 USE(general_triangle); 1112 } 1113 } 1114 else { 1115 ASSERT(!swrast->_FogEnabled); 1116 ASSERT(!NEED_SECONDARY_COLOR(ctx)); 1117 if (ctx->Light.ShadeModel==GL_SMOOTH) { 1118 /* smooth shaded, no texturing, stippled or some raster ops */ 1119#if CHAN_BITS != 8 1120 USE(general_triangle); 1121#else 1122 USE(smooth_rgba_triangle); 1123#endif 1124 } 1125 else { 1126 /* flat shaded, no texturing, stippled or some raster ops */ 1127#if CHAN_BITS != 8 1128 USE(general_triangle); 1129#else 1130 USE(flat_rgba_triangle); 1131#endif 1132 } 1133 } 1134 } 1135 else if (ctx->RenderMode==GL_FEEDBACK) { 1136 USE(_swrast_feedback_triangle); 1137 } 1138 else { 1139 /* GL_SELECT mode */ 1140 USE(_swrast_select_triangle); 1141 } 1142} 1143