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