[MESA]
[reactos.git] / reactos / dll / opengl / mesa / swrast / s_span.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.5
4 *
5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
6 * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26
27 /**
28 * \file swrast/s_span.c
29 * \brief Span processing functions used by all rasterization functions.
30 * This is where all the per-fragment tests are performed
31 * \author Brian Paul
32 */
33
34 #include "main/glheader.h"
35 #include "main/colormac.h"
36 #include "main/format_pack.h"
37 #include "main/format_unpack.h"
38 #include "main/macros.h"
39 #include "main/imports.h"
40 #include "main/image.h"
41
42 #include "s_alpha.h"
43 #include "s_blend.h"
44 #include "s_context.h"
45 #include "s_depth.h"
46 #include "s_fog.h"
47 #include "s_logic.h"
48 #include "s_masking.h"
49 #include "s_span.h"
50 #include "s_stencil.h"
51 #include "s_texcombine.h"
52
53 /**
54 * Set default fragment attributes for the span using the
55 * current raster values. Used prior to glDraw/CopyPixels
56 * and glBitmap.
57 */
58 void
59 _swrast_span_default_attribs(struct gl_context *ctx, SWspan *span)
60 {
61 GLchan r, g, b, a;
62 /* Z*/
63 {
64 const GLfloat depthMax = ctx->DrawBuffer->_DepthMaxF;
65 if (ctx->DrawBuffer->Visual.depthBits <= 16)
66 span->z = FloatToFixed(ctx->Current.RasterPos[2] * depthMax + 0.5F);
67 else {
68 GLfloat tmpf = ctx->Current.RasterPos[2] * depthMax;
69 tmpf = MIN2(tmpf, depthMax);
70 span->z = (GLint)tmpf;
71 }
72 span->zStep = 0;
73 span->interpMask |= SPAN_Z;
74 }
75
76 /* W (for perspective correction) */
77 span->attrStart[FRAG_ATTRIB_WPOS][3] = 1.0;
78 span->attrStepX[FRAG_ATTRIB_WPOS][3] = 0.0;
79 span->attrStepY[FRAG_ATTRIB_WPOS][3] = 0.0;
80
81 /* primary color, or color index */
82 UNCLAMPED_FLOAT_TO_CHAN(r, ctx->Current.RasterColor[0]);
83 UNCLAMPED_FLOAT_TO_CHAN(g, ctx->Current.RasterColor[1]);
84 UNCLAMPED_FLOAT_TO_CHAN(b, ctx->Current.RasterColor[2]);
85 UNCLAMPED_FLOAT_TO_CHAN(a, ctx->Current.RasterColor[3]);
86 #if CHAN_TYPE == GL_FLOAT
87 span->red = r;
88 span->green = g;
89 span->blue = b;
90 span->alpha = a;
91 #else
92 span->red = IntToFixed(r);
93 span->green = IntToFixed(g);
94 span->blue = IntToFixed(b);
95 span->alpha = IntToFixed(a);
96 #endif
97 span->redStep = 0;
98 span->greenStep = 0;
99 span->blueStep = 0;
100 span->alphaStep = 0;
101 span->interpMask |= SPAN_RGBA;
102
103 COPY_4V(span->attrStart[FRAG_ATTRIB_COL0], ctx->Current.RasterColor);
104 ASSIGN_4V(span->attrStepX[FRAG_ATTRIB_COL0], 0.0, 0.0, 0.0, 0.0);
105 ASSIGN_4V(span->attrStepY[FRAG_ATTRIB_COL0], 0.0, 0.0, 0.0, 0.0);
106
107 /* Secondary color */
108 if (ctx->Light.Enabled || ctx->Fog.ColorSumEnabled)
109 {
110 COPY_4V(span->attrStart[FRAG_ATTRIB_COL1], ctx->Current.RasterSecondaryColor);
111 ASSIGN_4V(span->attrStepX[FRAG_ATTRIB_COL1], 0.0, 0.0, 0.0, 0.0);
112 ASSIGN_4V(span->attrStepY[FRAG_ATTRIB_COL1], 0.0, 0.0, 0.0, 0.0);
113 }
114
115 /* fog */
116 {
117 const SWcontext *swrast = SWRAST_CONTEXT(ctx);
118 GLfloat fogVal; /* a coord or a blend factor */
119 if (swrast->_PreferPixelFog) {
120 /* fog blend factors will be computed from fog coordinates per pixel */
121 fogVal = ctx->Current.RasterDistance;
122 }
123 else {
124 /* fog blend factor should be computed from fogcoord now */
125 fogVal = _swrast_z_to_fogfactor(ctx, ctx->Current.RasterDistance);
126 }
127 span->attrStart[FRAG_ATTRIB_FOGC][0] = fogVal;
128 span->attrStepX[FRAG_ATTRIB_FOGC][0] = 0.0;
129 span->attrStepY[FRAG_ATTRIB_FOGC][0] = 0.0;
130 }
131
132 /* texcoords */
133 {
134 const GLuint attr = FRAG_ATTRIB_TEX;
135 const GLfloat *tc = ctx->Current.RasterTexCoords;
136 if (tc[3] > 0.0F) {
137 /* use (s/q, t/q, r/q, 1) */
138 span->attrStart[attr][0] = tc[0] / tc[3];
139 span->attrStart[attr][1] = tc[1] / tc[3];
140 span->attrStart[attr][2] = tc[2] / tc[3];
141 span->attrStart[attr][3] = 1.0;
142 }
143 else {
144 ASSIGN_4V(span->attrStart[attr], 0.0F, 0.0F, 0.0F, 1.0F);
145 }
146 ASSIGN_4V(span->attrStepX[attr], 0.0F, 0.0F, 0.0F, 0.0F);
147 ASSIGN_4V(span->attrStepY[attr], 0.0F, 0.0F, 0.0F, 0.0F);
148 }
149 }
150
151
152 /**
153 * Interpolate the active attributes (and'd with attrMask) to
154 * fill in span->array->attribs[].
155 * Perspective correction will be done. The point/line/triangle function
156 * should have computed attrStart/Step values for FRAG_ATTRIB_WPOS[3]!
157 */
158 static inline void
159 interpolate_active_attribs(struct gl_context *ctx, SWspan *span,
160 GLbitfield64 attrMask)
161 {
162 const SWcontext *swrast = SWRAST_CONTEXT(ctx);
163
164 /*
165 * Don't overwrite existing array values, such as colors that may have
166 * been produced by glDraw/CopyPixels.
167 */
168 attrMask &= ~span->arrayAttribs;
169
170 ATTRIB_LOOP_BEGIN
171 if (attrMask & BITFIELD64_BIT(attr)) {
172 const GLfloat dwdx = span->attrStepX[FRAG_ATTRIB_WPOS][3];
173 GLfloat w = span->attrStart[FRAG_ATTRIB_WPOS][3];
174 const GLfloat dv0dx = span->attrStepX[attr][0];
175 const GLfloat dv1dx = span->attrStepX[attr][1];
176 const GLfloat dv2dx = span->attrStepX[attr][2];
177 const GLfloat dv3dx = span->attrStepX[attr][3];
178 GLfloat v0 = span->attrStart[attr][0] + span->leftClip * dv0dx;
179 GLfloat v1 = span->attrStart[attr][1] + span->leftClip * dv1dx;
180 GLfloat v2 = span->attrStart[attr][2] + span->leftClip * dv2dx;
181 GLfloat v3 = span->attrStart[attr][3] + span->leftClip * dv3dx;
182 GLuint k;
183 for (k = 0; k < span->end; k++) {
184 const GLfloat invW = 1.0f / w;
185 span->array->attribs[attr][k][0] = v0 * invW;
186 span->array->attribs[attr][k][1] = v1 * invW;
187 span->array->attribs[attr][k][2] = v2 * invW;
188 span->array->attribs[attr][k][3] = v3 * invW;
189 v0 += dv0dx;
190 v1 += dv1dx;
191 v2 += dv2dx;
192 v3 += dv3dx;
193 w += dwdx;
194 }
195 ASSERT((span->arrayAttribs & BITFIELD64_BIT(attr)) == 0);
196 span->arrayAttribs |= BITFIELD64_BIT(attr);
197 }
198 ATTRIB_LOOP_END
199 }
200
201
202 /**
203 * Interpolate primary colors to fill in the span->array->rgba8 (or rgb16)
204 * color array.
205 */
206 static inline void
207 interpolate_int_colors(struct gl_context *ctx, SWspan *span)
208 {
209 #if CHAN_BITS != 32
210 const GLuint n = span->end;
211 GLuint i;
212
213 ASSERT(!(span->arrayMask & SPAN_RGBA));
214 #endif
215
216 switch (span->array->ChanType) {
217 #if CHAN_BITS != 32
218 case GL_UNSIGNED_BYTE:
219 {
220 GLubyte (*rgba)[4] = span->array->rgba8;
221 if (span->interpMask & SPAN_FLAT) {
222 GLubyte color[4];
223 color[RCOMP] = FixedToInt(span->red);
224 color[GCOMP] = FixedToInt(span->green);
225 color[BCOMP] = FixedToInt(span->blue);
226 color[ACOMP] = FixedToInt(span->alpha);
227 for (i = 0; i < n; i++) {
228 COPY_4UBV(rgba[i], color);
229 }
230 }
231 else {
232 GLfixed r = span->red;
233 GLfixed g = span->green;
234 GLfixed b = span->blue;
235 GLfixed a = span->alpha;
236 GLint dr = span->redStep;
237 GLint dg = span->greenStep;
238 GLint db = span->blueStep;
239 GLint da = span->alphaStep;
240 for (i = 0; i < n; i++) {
241 rgba[i][RCOMP] = FixedToChan(r);
242 rgba[i][GCOMP] = FixedToChan(g);
243 rgba[i][BCOMP] = FixedToChan(b);
244 rgba[i][ACOMP] = FixedToChan(a);
245 r += dr;
246 g += dg;
247 b += db;
248 a += da;
249 }
250 }
251 }
252 break;
253 case GL_UNSIGNED_SHORT:
254 {
255 GLushort (*rgba)[4] = span->array->rgba16;
256 if (span->interpMask & SPAN_FLAT) {
257 GLushort color[4];
258 color[RCOMP] = FixedToInt(span->red);
259 color[GCOMP] = FixedToInt(span->green);
260 color[BCOMP] = FixedToInt(span->blue);
261 color[ACOMP] = FixedToInt(span->alpha);
262 for (i = 0; i < n; i++) {
263 COPY_4V(rgba[i], color);
264 }
265 }
266 else {
267 GLushort (*rgba)[4] = span->array->rgba16;
268 GLfixed r, g, b, a;
269 GLint dr, dg, db, da;
270 r = span->red;
271 g = span->green;
272 b = span->blue;
273 a = span->alpha;
274 dr = span->redStep;
275 dg = span->greenStep;
276 db = span->blueStep;
277 da = span->alphaStep;
278 for (i = 0; i < n; i++) {
279 rgba[i][RCOMP] = FixedToChan(r);
280 rgba[i][GCOMP] = FixedToChan(g);
281 rgba[i][BCOMP] = FixedToChan(b);
282 rgba[i][ACOMP] = FixedToChan(a);
283 r += dr;
284 g += dg;
285 b += db;
286 a += da;
287 }
288 }
289 }
290 break;
291 #endif
292 case GL_FLOAT:
293 interpolate_active_attribs(ctx, span, FRAG_BIT_COL0);
294 break;
295 default:
296 _mesa_problem(ctx, "bad datatype 0x%x in interpolate_int_colors",
297 span->array->ChanType);
298 }
299 span->arrayMask |= SPAN_RGBA;
300 }
301
302
303 /**
304 * Populate the FRAG_ATTRIB_COL0 array.
305 */
306 static inline void
307 interpolate_float_colors(SWspan *span)
308 {
309 GLfloat (*col0)[4] = span->array->attribs[FRAG_ATTRIB_COL0];
310 const GLuint n = span->end;
311 GLuint i;
312
313 assert(!(span->arrayAttribs & FRAG_BIT_COL0));
314
315 if (span->arrayMask & SPAN_RGBA) {
316 /* convert array of int colors */
317 for (i = 0; i < n; i++) {
318 col0[i][0] = UBYTE_TO_FLOAT(span->array->rgba8[i][0]);
319 col0[i][1] = UBYTE_TO_FLOAT(span->array->rgba8[i][1]);
320 col0[i][2] = UBYTE_TO_FLOAT(span->array->rgba8[i][2]);
321 col0[i][3] = UBYTE_TO_FLOAT(span->array->rgba8[i][3]);
322 }
323 }
324 else {
325 /* interpolate red/green/blue/alpha to get float colors */
326 ASSERT(span->interpMask & SPAN_RGBA);
327 if (span->interpMask & SPAN_FLAT) {
328 GLfloat r = FixedToFloat(span->red);
329 GLfloat g = FixedToFloat(span->green);
330 GLfloat b = FixedToFloat(span->blue);
331 GLfloat a = FixedToFloat(span->alpha);
332 for (i = 0; i < n; i++) {
333 ASSIGN_4V(col0[i], r, g, b, a);
334 }
335 }
336 else {
337 GLfloat r = FixedToFloat(span->red);
338 GLfloat g = FixedToFloat(span->green);
339 GLfloat b = FixedToFloat(span->blue);
340 GLfloat a = FixedToFloat(span->alpha);
341 GLfloat dr = FixedToFloat(span->redStep);
342 GLfloat dg = FixedToFloat(span->greenStep);
343 GLfloat db = FixedToFloat(span->blueStep);
344 GLfloat da = FixedToFloat(span->alphaStep);
345 for (i = 0; i < n; i++) {
346 col0[i][0] = r;
347 col0[i][1] = g;
348 col0[i][2] = b;
349 col0[i][3] = a;
350 r += dr;
351 g += dg;
352 b += db;
353 a += da;
354 }
355 }
356 }
357
358 span->arrayAttribs |= FRAG_BIT_COL0;
359 span->array->ChanType = GL_FLOAT;
360 }
361
362
363
364 /**
365 * Fill in the span.zArray array from the span->z, zStep values.
366 */
367 void
368 _swrast_span_interpolate_z( const struct gl_context *ctx, SWspan *span )
369 {
370 const GLuint n = span->end;
371 GLuint i;
372
373 ASSERT(!(span->arrayMask & SPAN_Z));
374
375 if (ctx->DrawBuffer->Visual.depthBits <= 16) {
376 GLfixed zval = span->z;
377 GLuint *z = span->array->z;
378 for (i = 0; i < n; i++) {
379 z[i] = FixedToInt(zval);
380 zval += span->zStep;
381 }
382 }
383 else {
384 /* Deep Z buffer, no fixed->int shift */
385 GLuint zval = span->z;
386 GLuint *z = span->array->z;
387 for (i = 0; i < n; i++) {
388 z[i] = zval;
389 zval += span->zStep;
390 }
391 }
392 span->interpMask &= ~SPAN_Z;
393 span->arrayMask |= SPAN_Z;
394 }
395
396
397 /**
398 * Compute mipmap LOD from partial derivatives.
399 * This the ideal solution, as given in the OpenGL spec.
400 */
401 GLfloat
402 _swrast_compute_lambda(GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy,
403 GLfloat dqdx, GLfloat dqdy, GLfloat texW, GLfloat texH,
404 GLfloat s, GLfloat t, GLfloat q, GLfloat invQ)
405 {
406 GLfloat dudx = texW * ((s + dsdx) / (q + dqdx) - s * invQ);
407 GLfloat dvdx = texH * ((t + dtdx) / (q + dqdx) - t * invQ);
408 GLfloat dudy = texW * ((s + dsdy) / (q + dqdy) - s * invQ);
409 GLfloat dvdy = texH * ((t + dtdy) / (q + dqdy) - t * invQ);
410 GLfloat x = SQRTF(dudx * dudx + dvdx * dvdx);
411 GLfloat y = SQRTF(dudy * dudy + dvdy * dvdy);
412 GLfloat rho = MAX2(x, y);
413 GLfloat lambda = LOG2(rho);
414 return lambda;
415 }
416
417
418 /**
419 * Compute mipmap LOD from partial derivatives.
420 * This is a faster approximation than above function.
421 */
422 #if 0
423 GLfloat
424 _swrast_compute_lambda(GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy,
425 GLfloat dqdx, GLfloat dqdy, GLfloat texW, GLfloat texH,
426 GLfloat s, GLfloat t, GLfloat q, GLfloat invQ)
427 {
428 GLfloat dsdx2 = (s + dsdx) / (q + dqdx) - s * invQ;
429 GLfloat dtdx2 = (t + dtdx) / (q + dqdx) - t * invQ;
430 GLfloat dsdy2 = (s + dsdy) / (q + dqdy) - s * invQ;
431 GLfloat dtdy2 = (t + dtdy) / (q + dqdy) - t * invQ;
432 GLfloat maxU, maxV, rho, lambda;
433 dsdx2 = FABSF(dsdx2);
434 dsdy2 = FABSF(dsdy2);
435 dtdx2 = FABSF(dtdx2);
436 dtdy2 = FABSF(dtdy2);
437 maxU = MAX2(dsdx2, dsdy2) * texW;
438 maxV = MAX2(dtdx2, dtdy2) * texH;
439 rho = MAX2(maxU, maxV);
440 lambda = LOG2(rho);
441 return lambda;
442 }
443 #endif
444
445
446 /**
447 * Fill in the span.array->attrib[FRAG_ATTRIB_TEXn] arrays from the
448 * using the attrStart/Step values.
449 *
450 * This function only used during fixed-function fragment processing.
451 *
452 * Note: in the places where we divide by Q (or mult by invQ) we're
453 * really doing two things: perspective correction and texcoord
454 * projection. Remember, for texcoord (s,t,r,q) we need to index
455 * texels with (s/q, t/q, r/q).
456 */
457 static void
458 interpolate_texcoords(struct gl_context *ctx, SWspan *span)
459 {
460 if (ctx->Texture._EnabledCoord) {
461 const GLuint attr = FRAG_ATTRIB_TEX;
462 const struct gl_texture_object *obj = ctx->Texture.Unit._Current;
463 GLfloat texW, texH;
464 GLboolean needLambda;
465 GLfloat (*texcoord)[4] = span->array->attribs[attr];
466 GLfloat *lambda = span->array->lambda;
467 const GLfloat dsdx = span->attrStepX[attr][0];
468 const GLfloat dsdy = span->attrStepY[attr][0];
469 const GLfloat dtdx = span->attrStepX[attr][1];
470 const GLfloat dtdy = span->attrStepY[attr][1];
471 const GLfloat drdx = span->attrStepX[attr][2];
472 const GLfloat dqdx = span->attrStepX[attr][3];
473 const GLfloat dqdy = span->attrStepY[attr][3];
474 GLfloat s = span->attrStart[attr][0] + span->leftClip * dsdx;
475 GLfloat t = span->attrStart[attr][1] + span->leftClip * dtdx;
476 GLfloat r = span->attrStart[attr][2] + span->leftClip * drdx;
477 GLfloat q = span->attrStart[attr][3] + span->leftClip * dqdx;
478
479 if (obj) {
480 const struct gl_texture_image *img = obj->Image[0][obj->BaseLevel];
481 const struct swrast_texture_image *swImg =
482 swrast_texture_image_const(img);
483
484 needLambda = (obj->Sampler.MinFilter != obj->Sampler.MagFilter);
485 /* LOD is calculated directly in the ansiotropic filter, we can
486 * skip the normal lambda function as the result is ignored.
487 */
488 if (obj->Sampler.MaxAnisotropy > 1.0 &&
489 obj->Sampler.MinFilter == GL_LINEAR_MIPMAP_LINEAR) {
490 needLambda = GL_FALSE;
491 }
492 texW = swImg->WidthScale;
493 texH = swImg->HeightScale;
494 }
495 else {
496 /* using a fragment program */
497 texW = 1.0;
498 texH = 1.0;
499 needLambda = GL_FALSE;
500 }
501
502 if (needLambda) {
503 GLuint i;
504 for (i = 0; i < span->end; i++) {
505 const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
506 texcoord[i][0] = s * invQ;
507 texcoord[i][1] = t * invQ;
508 texcoord[i][2] = r * invQ;
509 texcoord[i][3] = q;
510 lambda[i] = _swrast_compute_lambda(dsdx, dsdy, dtdx, dtdy,
511 dqdx, dqdy, texW, texH,
512 s, t, q, invQ);
513 s += dsdx;
514 t += dtdx;
515 r += drdx;
516 q += dqdx;
517 }
518 span->arrayMask |= SPAN_LAMBDA;
519 }
520 else {
521 GLuint i;
522 if (dqdx == 0.0F) {
523 /* Ortho projection or polygon's parallel to window X axis */
524 const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
525 for (i = 0; i < span->end; i++) {
526 texcoord[i][0] = s * invQ;
527 texcoord[i][1] = t * invQ;
528 texcoord[i][2] = r * invQ;
529 texcoord[i][3] = q;
530 lambda[i] = 0.0;
531 s += dsdx;
532 t += dtdx;
533 r += drdx;
534 }
535 }
536 else {
537 for (i = 0; i < span->end; i++) {
538 const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
539 texcoord[i][0] = s * invQ;
540 texcoord[i][1] = t * invQ;
541 texcoord[i][2] = r * invQ;
542 texcoord[i][3] = q;
543 lambda[i] = 0.0;
544 s += dsdx;
545 t += dtdx;
546 r += drdx;
547 q += dqdx;
548 }
549 }
550 } /* lambda */
551 } /* if */
552 }
553
554
555 /**
556 * Fill in the arrays->attribs[FRAG_ATTRIB_WPOS] array.
557 */
558 static inline void
559 interpolate_wpos(struct gl_context *ctx, SWspan *span)
560 {
561 GLfloat (*wpos)[4] = span->array->attribs[FRAG_ATTRIB_WPOS];
562 GLuint i;
563 const GLfloat zScale = 1.0F / ctx->DrawBuffer->_DepthMaxF;
564 GLfloat w, dw;
565
566 if (span->arrayMask & SPAN_XY) {
567 for (i = 0; i < span->end; i++) {
568 wpos[i][0] = (GLfloat) span->array->x[i];
569 wpos[i][1] = (GLfloat) span->array->y[i];
570 }
571 }
572 else {
573 for (i = 0; i < span->end; i++) {
574 wpos[i][0] = (GLfloat) span->x + i;
575 wpos[i][1] = (GLfloat) span->y;
576 }
577 }
578
579 dw = span->attrStepX[FRAG_ATTRIB_WPOS][3];
580 w = span->attrStart[FRAG_ATTRIB_WPOS][3] + span->leftClip * dw;
581 for (i = 0; i < span->end; i++) {
582 wpos[i][2] = (GLfloat) span->array->z[i] * zScale;
583 wpos[i][3] = w;
584 w += dw;
585 }
586 }
587
588
589 /**
590 * Apply the current polygon stipple pattern to a span of pixels.
591 */
592 static inline void
593 stipple_polygon_span(struct gl_context *ctx, SWspan *span)
594 {
595 GLubyte *mask = span->array->mask;
596
597 ASSERT(ctx->Polygon.StippleFlag);
598
599 if (span->arrayMask & SPAN_XY) {
600 /* arrays of x/y pixel coords */
601 GLuint i;
602 for (i = 0; i < span->end; i++) {
603 const GLint col = span->array->x[i] % 32;
604 const GLint row = span->array->y[i] % 32;
605 const GLuint stipple = ctx->PolygonStipple[row];
606 if (((1 << col) & stipple) == 0) {
607 mask[i] = 0;
608 }
609 }
610 }
611 else {
612 /* horizontal span of pixels */
613 const GLuint highBit = 1 << 31;
614 const GLuint stipple = ctx->PolygonStipple[span->y % 32];
615 GLuint i, m = highBit >> (GLuint) (span->x % 32);
616 for (i = 0; i < span->end; i++) {
617 if ((m & stipple) == 0) {
618 mask[i] = 0;
619 }
620 m = m >> 1;
621 if (m == 0) {
622 m = highBit;
623 }
624 }
625 }
626 span->writeAll = GL_FALSE;
627 }
628
629
630 /**
631 * Clip a pixel span to the current buffer/window boundaries:
632 * DrawBuffer->_Xmin, _Xmax, _Ymin, _Ymax. This will accomplish
633 * window clipping and scissoring.
634 * Return: GL_TRUE some pixels still visible
635 * GL_FALSE nothing visible
636 */
637 static inline GLuint
638 clip_span( struct gl_context *ctx, SWspan *span )
639 {
640 const GLint xmin = ctx->DrawBuffer->_Xmin;
641 const GLint xmax = ctx->DrawBuffer->_Xmax;
642 const GLint ymin = ctx->DrawBuffer->_Ymin;
643 const GLint ymax = ctx->DrawBuffer->_Ymax;
644
645 span->leftClip = 0;
646
647 if (span->arrayMask & SPAN_XY) {
648 /* arrays of x/y pixel coords */
649 const GLint *x = span->array->x;
650 const GLint *y = span->array->y;
651 const GLint n = span->end;
652 GLubyte *mask = span->array->mask;
653 GLint i;
654 GLuint passed = 0;
655 if (span->arrayMask & SPAN_MASK) {
656 /* note: using & intead of && to reduce branches */
657 for (i = 0; i < n; i++) {
658 mask[i] &= (x[i] >= xmin) & (x[i] < xmax)
659 & (y[i] >= ymin) & (y[i] < ymax);
660 passed += mask[i];
661 }
662 }
663 else {
664 /* note: using & intead of && to reduce branches */
665 for (i = 0; i < n; i++) {
666 mask[i] = (x[i] >= xmin) & (x[i] < xmax)
667 & (y[i] >= ymin) & (y[i] < ymax);
668 passed += mask[i];
669 }
670 }
671 return passed > 0;
672 }
673 else {
674 /* horizontal span of pixels */
675 const GLint x = span->x;
676 const GLint y = span->y;
677 GLint n = span->end;
678
679 /* Trivial rejection tests */
680 if (y < ymin || y >= ymax || x + n <= xmin || x >= xmax) {
681 span->end = 0;
682 return GL_FALSE; /* all pixels clipped */
683 }
684
685 /* Clip to right */
686 if (x + n > xmax) {
687 ASSERT(x < xmax);
688 n = span->end = xmax - x;
689 }
690
691 /* Clip to the left */
692 if (x < xmin) {
693 const GLint leftClip = xmin - x;
694 GLuint i;
695
696 ASSERT(leftClip > 0);
697 ASSERT(x + n > xmin);
698
699 /* Clip 'leftClip' pixels from the left side.
700 * The span->leftClip field will be applied when we interpolate
701 * fragment attributes.
702 * For arrays of values, shift them left.
703 */
704 for (i = 0; i < FRAG_ATTRIB_MAX; i++) {
705 if (span->interpMask & (1 << i)) {
706 GLuint j;
707 for (j = 0; j < 4; j++) {
708 span->attrStart[i][j] += leftClip * span->attrStepX[i][j];
709 }
710 }
711 }
712
713 span->red += leftClip * span->redStep;
714 span->green += leftClip * span->greenStep;
715 span->blue += leftClip * span->blueStep;
716 span->alpha += leftClip * span->alphaStep;
717 span->index += leftClip * span->indexStep;
718 span->z += leftClip * span->zStep;
719 span->intTex[0] += leftClip * span->intTexStep[0];
720 span->intTex[1] += leftClip * span->intTexStep[1];
721
722 #define SHIFT_ARRAY(ARRAY, SHIFT, LEN) \
723 memmove(ARRAY, ARRAY + (SHIFT), (LEN) * sizeof(ARRAY[0]))
724
725 for (i = 0; i < FRAG_ATTRIB_MAX; i++) {
726 if (span->arrayAttribs & (1 << i)) {
727 /* shift array elements left by 'leftClip' */
728 SHIFT_ARRAY(span->array->attribs[i], leftClip, n - leftClip);
729 }
730 }
731
732 SHIFT_ARRAY(span->array->mask, leftClip, n - leftClip);
733 SHIFT_ARRAY(span->array->rgba8, leftClip, n - leftClip);
734 SHIFT_ARRAY(span->array->rgba16, leftClip, n - leftClip);
735 SHIFT_ARRAY(span->array->x, leftClip, n - leftClip);
736 SHIFT_ARRAY(span->array->y, leftClip, n - leftClip);
737 SHIFT_ARRAY(span->array->z, leftClip, n - leftClip);
738 SHIFT_ARRAY(span->array->index, leftClip, n - leftClip);
739 SHIFT_ARRAY(span->array->lambda, leftClip, n - leftClip);
740 SHIFT_ARRAY(span->array->coverage, leftClip, n - leftClip);
741
742 #undef SHIFT_ARRAY
743
744 span->leftClip = leftClip;
745 span->x = xmin;
746 span->end -= leftClip;
747 span->writeAll = GL_FALSE;
748 }
749
750 ASSERT(span->x >= xmin);
751 ASSERT(span->x + span->end <= xmax);
752 ASSERT(span->y >= ymin);
753 ASSERT(span->y < ymax);
754
755 return GL_TRUE; /* some pixels visible */
756 }
757 }
758
759
760 /**
761 * Add specular colors to primary colors.
762 * Only called during fixed-function operation.
763 * Result is float color array (FRAG_ATTRIB_COL0).
764 */
765 static inline void
766 add_specular(struct gl_context *ctx, SWspan *span)
767 {
768 const SWcontext *swrast = SWRAST_CONTEXT(ctx);
769 const GLubyte *mask = span->array->mask;
770 GLfloat (*col0)[4] = span->array->attribs[FRAG_ATTRIB_COL0];
771 GLfloat (*col1)[4] = span->array->attribs[FRAG_ATTRIB_COL1];
772 GLuint i;
773
774 ASSERT(!_swrast_use_fragment_program(ctx));
775 ASSERT(span->arrayMask & SPAN_RGBA);
776 ASSERT(swrast->_ActiveAttribMask & FRAG_BIT_COL1);
777 (void) swrast; /* silence warning */
778
779 if (span->array->ChanType == GL_FLOAT) {
780 if ((span->arrayAttribs & FRAG_BIT_COL0) == 0) {
781 interpolate_active_attribs(ctx, span, FRAG_BIT_COL0);
782 }
783 }
784 else {
785 /* need float colors */
786 if ((span->arrayAttribs & FRAG_BIT_COL0) == 0) {
787 interpolate_float_colors(span);
788 }
789 }
790
791 if ((span->arrayAttribs & FRAG_BIT_COL1) == 0) {
792 /* XXX could avoid this and interpolate COL1 in the loop below */
793 interpolate_active_attribs(ctx, span, FRAG_BIT_COL1);
794 }
795
796 ASSERT(span->arrayAttribs & FRAG_BIT_COL0);
797 ASSERT(span->arrayAttribs & FRAG_BIT_COL1);
798
799 for (i = 0; i < span->end; i++) {
800 if (mask[i]) {
801 col0[i][0] += col1[i][0];
802 col0[i][1] += col1[i][1];
803 col0[i][2] += col1[i][2];
804 }
805 }
806
807 span->array->ChanType = GL_FLOAT;
808 }
809
810
811 /**
812 * Apply antialiasing coverage value to alpha values.
813 */
814 static inline void
815 apply_aa_coverage(SWspan *span)
816 {
817 const GLfloat *coverage = span->array->coverage;
818 GLuint i;
819 if (span->array->ChanType == GL_UNSIGNED_BYTE) {
820 GLubyte (*rgba)[4] = span->array->rgba8;
821 for (i = 0; i < span->end; i++) {
822 const GLfloat a = rgba[i][ACOMP] * coverage[i];
823 rgba[i][ACOMP] = (GLubyte) CLAMP(a, 0.0, 255.0);
824 ASSERT(coverage[i] >= 0.0);
825 ASSERT(coverage[i] <= 1.0);
826 }
827 }
828 else if (span->array->ChanType == GL_UNSIGNED_SHORT) {
829 GLushort (*rgba)[4] = span->array->rgba16;
830 for (i = 0; i < span->end; i++) {
831 const GLfloat a = rgba[i][ACOMP] * coverage[i];
832 rgba[i][ACOMP] = (GLushort) CLAMP(a, 0.0, 65535.0);
833 }
834 }
835 else {
836 GLfloat (*rgba)[4] = span->array->attribs[FRAG_ATTRIB_COL0];
837 for (i = 0; i < span->end; i++) {
838 rgba[i][ACOMP] = rgba[i][ACOMP] * coverage[i];
839 /* clamp later */
840 }
841 }
842 }
843
844
845 /**
846 * Clamp span's float colors to [0,1]
847 */
848 static inline void
849 clamp_colors(SWspan *span)
850 {
851 GLfloat (*rgba)[4] = span->array->attribs[FRAG_ATTRIB_COL0];
852 GLuint i;
853 ASSERT(span->array->ChanType == GL_FLOAT);
854 for (i = 0; i < span->end; i++) {
855 rgba[i][RCOMP] = CLAMP(rgba[i][RCOMP], 0.0F, 1.0F);
856 rgba[i][GCOMP] = CLAMP(rgba[i][GCOMP], 0.0F, 1.0F);
857 rgba[i][BCOMP] = CLAMP(rgba[i][BCOMP], 0.0F, 1.0F);
858 rgba[i][ACOMP] = CLAMP(rgba[i][ACOMP], 0.0F, 1.0F);
859 }
860 }
861
862
863 /**
864 * Convert the span's color arrays to the given type.
865 * The only way 'output' can be greater than zero is when we have a fragment
866 * program that writes to gl_FragData[1] or higher.
867 * \param output which fragment program color output is being processed
868 */
869 static inline void
870 convert_color_type(SWspan *span, GLenum newType, GLuint output)
871 {
872 GLvoid *src, *dst;
873
874 if (output > 0 || span->array->ChanType == GL_FLOAT) {
875 src = span->array->attribs[FRAG_ATTRIB_COL0 + output];
876 span->array->ChanType = GL_FLOAT;
877 }
878 else if (span->array->ChanType == GL_UNSIGNED_BYTE) {
879 src = span->array->rgba8;
880 }
881 else {
882 ASSERT(span->array->ChanType == GL_UNSIGNED_SHORT);
883 src = span->array->rgba16;
884 }
885
886 if (newType == GL_UNSIGNED_BYTE) {
887 dst = span->array->rgba8;
888 }
889 else if (newType == GL_UNSIGNED_SHORT) {
890 dst = span->array->rgba16;
891 }
892 else {
893 dst = span->array->attribs[FRAG_ATTRIB_COL0];
894 }
895
896 _mesa_convert_colors(span->array->ChanType, src,
897 newType, dst,
898 span->end, span->array->mask);
899
900 span->array->ChanType = newType;
901 span->array->rgba = dst;
902 }
903
904
905
906 /**
907 * Apply fragment shader, fragment program or normal texturing to span.
908 */
909 static inline void
910 shade_texture_span(struct gl_context *ctx, SWspan *span)
911 {
912 if (ctx->Texture._EnabledCoord) {
913 /* conventional texturing */
914
915 #if CHAN_BITS == 32
916 if ((span->arrayAttribs & FRAG_BIT_COL0) == 0) {
917 interpolate_int_colors(ctx, span);
918 }
919 #else
920 if (!(span->arrayMask & SPAN_RGBA))
921 interpolate_int_colors(ctx, span);
922 #endif
923 if (!(span->arrayAttribs & FRAG_BIT_TEX))
924 interpolate_texcoords(ctx, span);
925
926 _swrast_texture_span(ctx, span);
927 }
928 }
929
930
931 /** Put colors at x/y locations into a renderbuffer */
932 static void
933 put_values(struct gl_context *ctx, struct gl_renderbuffer *rb,
934 GLenum datatype,
935 GLuint count, const GLint x[], const GLint y[],
936 const void *values, const GLubyte *mask)
937 {
938 gl_pack_ubyte_rgba_func pack_ubyte;
939 gl_pack_float_rgba_func pack_float;
940 GLuint i;
941
942 if (datatype == GL_UNSIGNED_BYTE)
943 pack_ubyte = _mesa_get_pack_ubyte_rgba_function(rb->Format);
944 else
945 pack_float = _mesa_get_pack_float_rgba_function(rb->Format);
946
947 for (i = 0; i < count; i++) {
948 if (mask[i]) {
949 GLubyte *dst = _swrast_pixel_address(rb, x[i], y[i]);
950
951 if (datatype == GL_UNSIGNED_BYTE) {
952 pack_ubyte((const GLubyte *) values + 4 * i, dst);
953 }
954 else {
955 assert(datatype == GL_FLOAT);
956 pack_float((const GLfloat *) values + 4 * i, dst);
957 }
958 }
959 }
960 }
961
962
963 /** Put row of colors into renderbuffer */
964 void
965 _swrast_put_row(struct gl_context *ctx, struct gl_renderbuffer *rb,
966 GLenum datatype,
967 GLuint count, GLint x, GLint y,
968 const void *values, const GLubyte *mask)
969 {
970 GLubyte *dst = _swrast_pixel_address(rb, x, y);
971
972 if (!mask) {
973 if (datatype == GL_UNSIGNED_BYTE) {
974 _mesa_pack_ubyte_rgba_row(rb->Format, count,
975 (const GLubyte (*)[4]) values, dst);
976 }
977 else {
978 assert(datatype == GL_FLOAT);
979 _mesa_pack_float_rgba_row(rb->Format, count,
980 (const GLfloat (*)[4]) values, dst);
981 }
982 }
983 else {
984 const GLuint bpp = _mesa_get_format_bytes(rb->Format);
985 GLuint i, runLen, runStart;
986 /* We can't pass a 'mask' array to the _mesa_pack_rgba_row() functions
987 * so look for runs where mask=1...
988 */
989 runLen = runStart = 0;
990 for (i = 0; i < count; i++) {
991 if (mask[i]) {
992 if (runLen == 0)
993 runStart = i;
994 runLen++;
995 }
996
997 if (!mask[i] || i == count - 1) {
998 /* might be the end of a run of pixels */
999 if (runLen > 0) {
1000 if (datatype == GL_UNSIGNED_BYTE) {
1001 _mesa_pack_ubyte_rgba_row(rb->Format, runLen,
1002 (const GLubyte (*)[4]) values + runStart,
1003 dst + runStart * bpp);
1004 }
1005 else {
1006 assert(datatype == GL_FLOAT);
1007 _mesa_pack_float_rgba_row(rb->Format, runLen,
1008 (const GLfloat (*)[4]) values + runStart,
1009 dst + runStart * bpp);
1010 }
1011 runLen = 0;
1012 }
1013 }
1014 }
1015 }
1016 }
1017
1018
1019
1020 /**
1021 * Apply all the per-fragment operations to a span.
1022 * This now includes texturing (_swrast_write_texture_span() is history).
1023 * This function may modify any of the array values in the span.
1024 * span->interpMask and span->arrayMask may be changed but will be restored
1025 * to their original values before returning.
1026 */
1027 void
1028 _swrast_write_rgba_span( struct gl_context *ctx, SWspan *span)
1029 {
1030 const SWcontext *swrast = SWRAST_CONTEXT(ctx);
1031 const GLuint colorMask = *((GLuint *)ctx->Color.ColorMask);
1032 const GLbitfield origInterpMask = span->interpMask;
1033 const GLbitfield origArrayMask = span->arrayMask;
1034 const GLbitfield64 origArrayAttribs = span->arrayAttribs;
1035 const GLenum origChanType = span->array->ChanType;
1036 void * const origRgba = span->array->rgba;
1037 const GLboolean texture = ctx->Texture._EnabledCoord;
1038 struct gl_framebuffer *fb = ctx->DrawBuffer;
1039
1040 /*
1041 printf("%s() interp 0x%x array 0x%x\n", __FUNCTION__,
1042 span->interpMask, span->arrayMask);
1043 */
1044
1045 ASSERT(span->primitive == GL_POINT ||
1046 span->primitive == GL_LINE ||
1047 span->primitive == GL_POLYGON ||
1048 span->primitive == GL_BITMAP);
1049
1050 /* Fragment write masks */
1051 if (span->arrayMask & SPAN_MASK) {
1052 /* mask was initialized by caller, probably glBitmap */
1053 span->writeAll = GL_FALSE;
1054 }
1055 else {
1056 memset(span->array->mask, 1, span->end);
1057 span->writeAll = GL_TRUE;
1058 }
1059
1060 /* Clip to window/scissor box */
1061 if (!clip_span(ctx, span)) {
1062 return;
1063 }
1064
1065 ASSERT(span->end <= MAX_WIDTH);
1066
1067 /* Depth bounds test */
1068 if (ctx->Depth.BoundsTest && fb->Visual.depthBits > 0) {
1069 if (!_swrast_depth_bounds_test(ctx, span)) {
1070 return;
1071 }
1072 }
1073
1074 #ifdef DEBUG
1075 /* Make sure all fragments are within window bounds */
1076 if (span->arrayMask & SPAN_XY) {
1077 /* array of pixel locations */
1078 GLuint i;
1079 for (i = 0; i < span->end; i++) {
1080 if (span->array->mask[i]) {
1081 assert(span->array->x[i] >= fb->_Xmin);
1082 assert(span->array->x[i] < fb->_Xmax);
1083 assert(span->array->y[i] >= fb->_Ymin);
1084 assert(span->array->y[i] < fb->_Ymax);
1085 }
1086 }
1087 }
1088 #endif
1089
1090 /* Polygon Stippling */
1091 if (ctx->Polygon.StippleFlag && span->primitive == GL_POLYGON) {
1092 stipple_polygon_span(ctx, span);
1093 }
1094
1095 /* This is the normal place to compute the fragment color/Z
1096 * from texturing or shading.
1097 */
1098 if (texture && !swrast->_DeferredTexture) {
1099 shade_texture_span(ctx, span);
1100 }
1101
1102 /* Do the alpha test */
1103 if (ctx->Color.AlphaEnabled) {
1104 if (!_swrast_alpha_test(ctx, span)) {
1105 /* all fragments failed test */
1106 goto end;
1107 }
1108 }
1109
1110 /* Stencil and Z testing */
1111 if (ctx->Stencil._Enabled || ctx->Depth.Test) {
1112 if (!(span->arrayMask & SPAN_Z))
1113 _swrast_span_interpolate_z(ctx, span);
1114
1115 if (ctx->Stencil._Enabled) {
1116 /* Combined Z/stencil tests */
1117 if (!_swrast_stencil_and_ztest_span(ctx, span)) {
1118 /* all fragments failed test */
1119 goto end;
1120 }
1121 }
1122 else if (fb->Visual.depthBits > 0) {
1123 /* Just regular depth testing */
1124 ASSERT(ctx->Depth.Test);
1125 ASSERT(span->arrayMask & SPAN_Z);
1126 if (!_swrast_depth_test_span(ctx, span)) {
1127 /* all fragments failed test */
1128 goto end;
1129 }
1130 }
1131 }
1132
1133 /* We had to wait until now to check for glColorMask(0,0,0,0) because of
1134 * the occlusion test.
1135 */
1136 if (colorMask == 0) {
1137 /* no colors to write */
1138 goto end;
1139 }
1140
1141 /* If we were able to defer fragment color computation to now, there's
1142 * a good chance that many fragments will have already been killed by
1143 * Z/stencil testing.
1144 */
1145 if (texture && swrast->_DeferredTexture) {
1146 shade_texture_span(ctx, span);
1147 }
1148
1149 #if CHAN_BITS == 32
1150 if ((span->arrayAttribs & FRAG_BIT_COL0) == 0) {
1151 interpolate_active_attribs(ctx, span, FRAG_BIT_COL0);
1152 }
1153 #else
1154 if ((span->arrayMask & SPAN_RGBA) == 0) {
1155 interpolate_int_colors(ctx, span);
1156 }
1157 #endif
1158
1159 ASSERT(span->arrayMask & SPAN_RGBA);
1160
1161 if (span->primitive == GL_BITMAP || !swrast->SpecularVertexAdd) {
1162 /* Add primary and specular (diffuse + specular) colors */
1163 if (ctx->Fog.ColorSumEnabled ||
1164 (ctx->Light.Enabled &&
1165 ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)) {
1166 add_specular(ctx, span);
1167 }
1168 }
1169
1170 /* Fog */
1171 if (swrast->_FogEnabled) {
1172 _swrast_fog_rgba_span(ctx, span);
1173 }
1174
1175 /* Antialias coverage application */
1176 if (span->arrayMask & SPAN_COVERAGE) {
1177 apply_aa_coverage(span);
1178 }
1179
1180 /*
1181 * Write to renderbuffers.
1182 * Depending on glDrawBuffer() state and the which color outputs are
1183 * written by the fragment shader, we may either replicate one color to
1184 * all renderbuffers or write a different color to each renderbuffer.
1185 * multiFragOutputs=TRUE for the later case.
1186 */
1187 {
1188 struct gl_renderbuffer *rb = fb->_ColorDrawBuffer;
1189
1190 /* color[fragOutput] will be written to buffer */
1191
1192 if (rb) {
1193 struct swrast_renderbuffer *srb = swrast_renderbuffer(rb);
1194 GLenum colorType = srb->ColorType;
1195
1196 assert(colorType == GL_UNSIGNED_BYTE ||
1197 colorType == GL_FLOAT);
1198
1199 /* set span->array->rgba to colors for renderbuffer's datatype */
1200 if (span->array->ChanType != colorType) {
1201 convert_color_type(span, colorType, 0);
1202 }
1203 else {
1204 if (span->array->ChanType == GL_UNSIGNED_BYTE) {
1205 span->array->rgba = span->array->rgba8;
1206 }
1207 else {
1208 span->array->rgba = (void *)span->array->attribs[FRAG_ATTRIB_COL0];
1209 }
1210 }
1211
1212
1213 ASSERT(rb->_BaseFormat == GL_RGBA ||
1214 rb->_BaseFormat == GL_RGB ||
1215 rb->_BaseFormat == GL_RED ||
1216 rb->_BaseFormat == GL_RG ||
1217 rb->_BaseFormat == GL_ALPHA);
1218
1219 if (ctx->Color.ColorLogicOpEnabled) {
1220 _swrast_logicop_rgba_span(ctx, rb, span);
1221 }
1222 else if (ctx->Color.BlendEnabled) {
1223 _swrast_blend_span(ctx, rb, span);
1224 }
1225
1226 if (colorMask != 0xffffffff) {
1227 _swrast_mask_rgba_span(ctx, rb, span);
1228 }
1229
1230 if (span->arrayMask & SPAN_XY) {
1231 /* array of pixel coords */
1232 put_values(ctx, rb,
1233 span->array->ChanType, span->end,
1234 span->array->x, span->array->y,
1235 span->array->rgba, span->array->mask);
1236 }
1237 else {
1238 /* horizontal run of pixels */
1239 _swrast_put_row(ctx, rb,
1240 span->array->ChanType,
1241 span->end, span->x, span->y,
1242 span->array->rgba,
1243 span->writeAll ? NULL: span->array->mask);
1244 }
1245
1246 } /* if rb */
1247 }
1248
1249 end:
1250 /* restore these values before returning */
1251 span->interpMask = origInterpMask;
1252 span->arrayMask = origArrayMask;
1253 span->arrayAttribs = origArrayAttribs;
1254 span->array->ChanType = origChanType;
1255 span->array->rgba = origRgba;
1256 }
1257
1258
1259 /**
1260 * Read float RGBA pixels from a renderbuffer. Clipping will be done to
1261 * prevent reading ouside the buffer's boundaries.
1262 * \param rgba the returned colors
1263 */
1264 void
1265 _swrast_read_rgba_span( struct gl_context *ctx, struct gl_renderbuffer *rb,
1266 GLuint n, GLint x, GLint y,
1267 GLvoid *rgba)
1268 {
1269 struct swrast_renderbuffer *srb = swrast_renderbuffer(rb);
1270 GLenum dstType = GL_FLOAT;
1271 const GLint bufWidth = (GLint) rb->Width;
1272 const GLint bufHeight = (GLint) rb->Height;
1273
1274 if (y < 0 || y >= bufHeight || x + (GLint) n < 0 || x >= bufWidth) {
1275 /* completely above, below, or right */
1276 /* XXX maybe leave rgba values undefined? */
1277 memset(rgba, 0, 4 * n * sizeof(GLchan));
1278 }
1279 else {
1280 GLint skip, length;
1281 GLubyte *src;
1282
1283 if (x < 0) {
1284 /* left edge clipping */
1285 skip = -x;
1286 length = (GLint) n - skip;
1287 if (length < 0) {
1288 /* completely left of window */
1289 return;
1290 }
1291 if (length > bufWidth) {
1292 length = bufWidth;
1293 }
1294 }
1295 else if ((GLint) (x + n) > bufWidth) {
1296 /* right edge clipping */
1297 skip = 0;
1298 length = bufWidth - x;
1299 if (length < 0) {
1300 /* completely to right of window */
1301 return;
1302 }
1303 }
1304 else {
1305 /* no clipping */
1306 skip = 0;
1307 length = (GLint) n;
1308 }
1309
1310 ASSERT(rb);
1311 ASSERT(rb->_BaseFormat == GL_RGBA ||
1312 rb->_BaseFormat == GL_RGB ||
1313 rb->_BaseFormat == GL_RG ||
1314 rb->_BaseFormat == GL_RED ||
1315 rb->_BaseFormat == GL_LUMINANCE ||
1316 rb->_BaseFormat == GL_INTENSITY ||
1317 rb->_BaseFormat == GL_LUMINANCE_ALPHA ||
1318 rb->_BaseFormat == GL_ALPHA);
1319
1320 assert(srb->Map);
1321
1322 src = _swrast_pixel_address(rb, x + skip, y);
1323
1324 if (dstType == GL_UNSIGNED_BYTE) {
1325 _mesa_unpack_ubyte_rgba_row(rb->Format, length, src,
1326 (GLubyte (*)[4]) rgba + skip);
1327 }
1328 else if (dstType == GL_FLOAT) {
1329 _mesa_unpack_rgba_row(rb->Format, length, src,
1330 (GLfloat (*)[4]) rgba + skip);
1331 }
1332 else {
1333 _mesa_problem(ctx, "unexpected type in _swrast_read_rgba_span()");
1334 }
1335 }
1336 }
1337
1338
1339 /**
1340 * Get colors at x/y positions with clipping.
1341 * \param type type of values to return
1342 */
1343 static void
1344 get_values(struct gl_context *ctx, struct gl_renderbuffer *rb,
1345 GLuint count, const GLint x[], const GLint y[],
1346 void *values, GLenum type)
1347 {
1348 GLuint i;
1349
1350 for (i = 0; i < count; i++) {
1351 if (x[i] >= 0 && y[i] >= 0 &&
1352 x[i] < (GLint) rb->Width && y[i] < (GLint) rb->Height) {
1353 /* inside */
1354 const GLubyte *src = _swrast_pixel_address(rb, x[i], y[i]);
1355
1356 if (type == GL_UNSIGNED_BYTE) {
1357 _mesa_unpack_ubyte_rgba_row(rb->Format, 1, src,
1358 (GLubyte (*)[4]) values + i);
1359 }
1360 else if (type == GL_FLOAT) {
1361 _mesa_unpack_rgba_row(rb->Format, 1, src,
1362 (GLfloat (*)[4]) values + i);
1363 }
1364 else {
1365 _mesa_problem(ctx, "unexpected type in get_values()");
1366 }
1367 }
1368 }
1369 }
1370
1371
1372 /**
1373 * Get row of colors with clipping.
1374 * \param type type of values to return
1375 */
1376 static void
1377 get_row(struct gl_context *ctx, struct gl_renderbuffer *rb,
1378 GLuint count, GLint x, GLint y,
1379 GLvoid *values, GLenum type)
1380 {
1381 GLint skip = 0;
1382 GLubyte *src;
1383
1384 if (y < 0 || y >= (GLint) rb->Height)
1385 return; /* above or below */
1386
1387 if (x + (GLint) count <= 0 || x >= (GLint) rb->Width)
1388 return; /* entirely left or right */
1389
1390 if (x + count > rb->Width) {
1391 /* right clip */
1392 GLint clip = x + count - rb->Width;
1393 count -= clip;
1394 }
1395
1396 if (x < 0) {
1397 /* left clip */
1398 skip = -x;
1399 x = 0;
1400 count -= skip;
1401 }
1402
1403 src = _swrast_pixel_address(rb, x, y);
1404
1405 if (type == GL_UNSIGNED_BYTE) {
1406 _mesa_unpack_ubyte_rgba_row(rb->Format, count, src,
1407 (GLubyte (*)[4]) values + skip);
1408 }
1409 else if (type == GL_FLOAT) {
1410 _mesa_unpack_rgba_row(rb->Format, count, src,
1411 (GLfloat (*)[4]) values + skip);
1412 }
1413 else {
1414 _mesa_problem(ctx, "unexpected type in get_row()");
1415 }
1416 }
1417
1418
1419 /**
1420 * Get RGBA pixels from the given renderbuffer.
1421 * Used by blending, logicop and masking functions.
1422 * \return pointer to the colors we read.
1423 */
1424 void *
1425 _swrast_get_dest_rgba(struct gl_context *ctx, struct gl_renderbuffer *rb,
1426 SWspan *span)
1427 {
1428 void *rbPixels;
1429
1430 /* Point rbPixels to a temporary space */
1431 rbPixels = span->array->attribs[FRAG_ATTRIB_MAX - 1];
1432
1433 /* Get destination values from renderbuffer */
1434 if (span->arrayMask & SPAN_XY) {
1435 get_values(ctx, rb, span->end, span->array->x, span->array->y,
1436 rbPixels, span->array->ChanType);
1437 }
1438 else {
1439 get_row(ctx, rb, span->end, span->x, span->y,
1440 rbPixels, span->array->ChanType);
1441 }
1442
1443 return rbPixels;
1444 }