Correct test for attenuation.
[mesa.git] / src / mesa / swrast / s_drawpix.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.3
4 *
5 * Copyright (C) 1999-2004 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 #include "glheader.h"
27 #include "bufferobj.h"
28 #include "context.h"
29 #include "convolve.h"
30 #include "image.h"
31 #include "macros.h"
32 #include "imports.h"
33 #include "pixel.h"
34
35 #include "s_context.h"
36 #include "s_drawpix.h"
37 #include "s_pixeltex.h"
38 #include "s_span.h"
39 #include "s_stencil.h"
40 #include "s_zoom.h"
41
42
43 /*
44 * Try to do a fast and simple RGB(a) glDrawPixels.
45 * Return: GL_TRUE if success, GL_FALSE if slow path must be used instead
46 */
47 static GLboolean
48 fast_draw_pixels(GLcontext *ctx, GLint x, GLint y,
49 GLsizei width, GLsizei height,
50 GLenum format, GLenum type,
51 const struct gl_pixelstore_attrib *unpack,
52 const GLvoid *pixels)
53 {
54 #if NEW_RENDERBUFFER
55 struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0][0];
56 #endif
57 SWcontext *swrast = SWRAST_CONTEXT(ctx);
58 struct sw_span span;
59
60 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA);
61
62 if (!ctx->Current.RasterPosValid) {
63 return GL_TRUE; /* no-op */
64 }
65
66 if (swrast->_RasterMask & MULTI_DRAW_BIT)
67 return GL_FALSE;
68
69 if (ctx->Depth.Test)
70 _swrast_span_default_z(ctx, &span);
71 if (ctx->Fog.Enabled)
72 _swrast_span_default_fog(ctx, &span);
73 if (ctx->Texture._EnabledCoordUnits)
74 _swrast_span_default_texcoords(ctx, &span);
75
76 if ((SWRAST_CONTEXT(ctx)->_RasterMask & ~CLIP_BIT) == 0
77 && ctx->Texture._EnabledCoordUnits == 0
78 && unpack->Alignment == 1
79 && !unpack->SwapBytes
80 && !unpack->LsbFirst) {
81
82 GLint destX = x;
83 GLint destY = y;
84 GLint drawWidth = width; /* actual width drawn */
85 GLint drawHeight = height; /* actual height drawn */
86 GLint skipPixels = unpack->SkipPixels;
87 GLint skipRows = unpack->SkipRows;
88 GLint rowLength;
89 GLint zoomY0 = 0;
90
91 if (unpack->RowLength > 0)
92 rowLength = unpack->RowLength;
93 else
94 rowLength = width;
95
96 /* If we're not using pixel zoom then do all clipping calculations
97 * now. Otherwise, we'll let the _swrast_write_zoomed_*_span() functions
98 * handle the clipping.
99 */
100 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
101 /* horizontal clipping */
102 if (destX < ctx->DrawBuffer->_Xmin) {
103 skipPixels += (ctx->DrawBuffer->_Xmin - destX);
104 drawWidth -= (ctx->DrawBuffer->_Xmin - destX);
105 destX = ctx->DrawBuffer->_Xmin;
106 }
107 if (destX + drawWidth > ctx->DrawBuffer->_Xmax)
108 drawWidth -= (destX + drawWidth - ctx->DrawBuffer->_Xmax);
109 if (drawWidth <= 0)
110 return GL_TRUE;
111
112 /* vertical clipping */
113 if (destY < ctx->DrawBuffer->_Ymin) {
114 skipRows += (ctx->DrawBuffer->_Ymin - destY);
115 drawHeight -= (ctx->DrawBuffer->_Ymin - destY);
116 destY = ctx->DrawBuffer->_Ymin;
117 }
118 if (destY + drawHeight > ctx->DrawBuffer->_Ymax)
119 drawHeight -= (destY + drawHeight - ctx->DrawBuffer->_Ymax);
120 if (drawHeight <= 0)
121 return GL_TRUE;
122 }
123 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
124 /* upside-down image */
125 /* horizontal clipping */
126 if (destX < ctx->DrawBuffer->_Xmin) {
127 skipPixels += (ctx->DrawBuffer->_Xmin - destX);
128 drawWidth -= (ctx->DrawBuffer->_Xmin - destX);
129 destX = ctx->DrawBuffer->_Xmin;
130 }
131 if (destX + drawWidth > ctx->DrawBuffer->_Xmax)
132 drawWidth -= (destX + drawWidth - ctx->DrawBuffer->_Xmax);
133 if (drawWidth <= 0)
134 return GL_TRUE;
135
136 /* vertical clipping */
137 if (destY > ctx->DrawBuffer->_Ymax) {
138 skipRows += (destY - ctx->DrawBuffer->_Ymax);
139 drawHeight -= (destY - ctx->DrawBuffer->_Ymax);
140 destY = ctx->DrawBuffer->_Ymax;
141 }
142 if (destY - drawHeight < ctx->DrawBuffer->_Ymin)
143 drawHeight -= (ctx->DrawBuffer->_Ymin - (destY - drawHeight));
144 if (drawHeight <= 0)
145 return GL_TRUE;
146 }
147 else {
148 if (drawWidth > MAX_WIDTH)
149 return GL_FALSE; /* fall back to general case path */
150
151 /* save Y value of first row */
152 zoomY0 = IROUND(ctx->Current.RasterPos[1]);
153 }
154
155
156 /*
157 * Ready to draw!
158 * The window region at (destX, destY) of size (drawWidth, drawHeight)
159 * will be written to.
160 * We'll take pixel data from buffer pointed to by "pixels" but we'll
161 * skip "skipRows" rows and skip "skipPixels" pixels/row.
162 */
163
164 if (format == GL_RGBA && type == CHAN_TYPE
165 && ctx->_ImageTransferState==0) {
166 if (ctx->Visual.rgbMode) {
167 GLchan *src = (GLchan *) pixels
168 + (skipRows * rowLength + skipPixels) * 4;
169 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
170 /* no zooming */
171 GLint row;
172 for (row=0; row<drawHeight; row++) {
173 #if OLD_RENDERBUFFER
174 if (swrast->Driver.WriteRGBASpan)
175 swrast->Driver.WriteRGBASpan(ctx, rb, drawWidth,
176 destX, destY,
177 (CONST GLchan (*)[4]) src,
178 NULL);
179 else
180 #endif
181 rb->PutRow(ctx, rb, drawWidth, destX, destY, src, NULL);
182 src += rowLength * 4;
183 destY++;
184 }
185 }
186 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
187 /* upside-down */
188 GLint row;
189 for (row=0; row<drawHeight; row++) {
190 destY--;
191 #if OLD_RENDERBUFFER
192 if (swrast->Driver.WriteRGBASpan)
193 swrast->Driver.WriteRGBASpan(ctx, rb, drawWidth,
194 destX, destY,
195 (CONST GLchan (*)[4]) src,
196 NULL);
197 else
198 #endif
199 rb->PutRow(ctx, rb, drawWidth, destX, destY, src, NULL);
200 src += rowLength * 4;
201 }
202 }
203 else {
204 /* with zooming */
205 GLint row;
206 for (row=0; row<drawHeight; row++) {
207 span.x = destX;
208 span.y = destY;
209 span.end = drawWidth;
210 _swrast_write_zoomed_rgba_span(ctx, &span,
211 (CONST GLchan (*)[4]) src, zoomY0, 0);
212 src += rowLength * 4;
213 destY++;
214 }
215 }
216 }
217 return GL_TRUE;
218 }
219 else if (format == GL_RGB && type == CHAN_TYPE
220 && ctx->_ImageTransferState == 0) {
221 if (ctx->Visual.rgbMode) {
222 GLchan *src = (GLchan *) pixels
223 + (skipRows * rowLength + skipPixels) * 3;
224 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
225 GLint row;
226 for (row=0; row<drawHeight; row++) {
227 #if OLD_RENDERBUFFER
228 if (swrast->Driver.WriteRGBSpan)
229 (*swrast->Driver.WriteRGBSpan)(ctx, rb, drawWidth,
230 destX, destY,
231 (CONST GLchan (*)[3]) src,
232 NULL);
233 else
234 #endif
235 rb->PutRowRGB(ctx, rb, drawWidth, destX, destY, src, NULL);
236 src += rowLength * 3;
237 destY++;
238 }
239 }
240 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
241 /* upside-down */
242 GLint row;
243 for (row=0; row<drawHeight; row++) {
244 destY--;
245 #if OLD_RENDERBUFFER
246 if (swrast->Driver.WriteRGBASpan)
247 (*swrast->Driver.WriteRGBSpan)(ctx, rb, drawWidth,
248 destX, destY,
249 (CONST GLchan (*)[3]) src,
250 NULL);
251 else
252 #endif
253 rb->PutRowRGB(ctx, rb, drawWidth, destX, destY, src, NULL);
254 src += rowLength * 3;
255 }
256 }
257 else {
258 /* with zooming */
259 GLint row;
260 for (row=0; row<drawHeight; row++) {
261 span.x = destX;
262 span.y = destY;
263 span.end = drawWidth;
264 _swrast_write_zoomed_rgb_span(ctx, &span,
265 (CONST GLchan (*)[3]) src, zoomY0, 0);
266 src += rowLength * 3;
267 destY++;
268 }
269 }
270 }
271 return GL_TRUE;
272 }
273 else if (format == GL_LUMINANCE && type == CHAN_TYPE
274 && ctx->_ImageTransferState==0) {
275 if (ctx->Visual.rgbMode) {
276 GLchan *src = (GLchan *) pixels
277 + (skipRows * rowLength + skipPixels);
278 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
279 /* no zooming */
280 GLint row;
281 ASSERT(drawWidth <= MAX_WIDTH);
282 for (row=0; row<drawHeight; row++) {
283 GLint i;
284 for (i=0;i<drawWidth;i++) {
285 span.array->rgb[i][0] = src[i];
286 span.array->rgb[i][1] = src[i];
287 span.array->rgb[i][2] = src[i];
288 }
289 #if OLD_RENDERBUFFER
290 if (swrast->Driver.WriteRGBSpan)
291 (*swrast->Driver.WriteRGBSpan)(ctx, rb, drawWidth,
292 destX, destY,
293 (CONST GLchan (*)[3]) span.array->rgb, NULL);
294 else
295 #endif
296 rb->PutRowRGB(ctx, rb, drawWidth, destX, destY,
297 span.array->rgb, NULL);
298 src += rowLength;
299 destY++;
300 }
301 }
302 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
303 /* upside-down */
304 GLint row;
305 ASSERT(drawWidth <= MAX_WIDTH);
306 for (row=0; row<drawHeight; row++) {
307 GLint i;
308 for (i=0;i<drawWidth;i++) {
309 span.array->rgb[i][0] = src[i];
310 span.array->rgb[i][1] = src[i];
311 span.array->rgb[i][2] = src[i];
312 }
313 destY--;
314 #if OLD_RENDERBUFFER
315 if (swrast->Driver.WriteRGBSpan)
316 (*swrast->Driver.WriteRGBSpan)(ctx, rb, drawWidth,
317 destX, destY,
318 (CONST GLchan (*)[3]) span.array->rgb, NULL);
319 else
320 #endif
321 rb->PutRow(ctx, rb, drawWidth, destX, destY,
322 span.array->rgb, NULL);
323 src += rowLength;
324 }
325 }
326 else {
327 /* with zooming */
328 GLint row;
329 ASSERT(drawWidth <= MAX_WIDTH);
330 for (row=0; row<drawHeight; row++) {
331 GLint i;
332 for (i=0;i<drawWidth;i++) {
333 span.array->rgb[i][0] = src[i];
334 span.array->rgb[i][1] = src[i];
335 span.array->rgb[i][2] = src[i];
336 }
337 span.x = destX;
338 span.y = destY;
339 span.end = drawWidth;
340 _swrast_write_zoomed_rgb_span(ctx, &span,
341 (CONST GLchan (*)[3]) span.array->rgb, zoomY0, 0);
342 src += rowLength;
343 destY++;
344 }
345 }
346 }
347 return GL_TRUE;
348 }
349 else if (format == GL_LUMINANCE_ALPHA && type == CHAN_TYPE
350 && ctx->_ImageTransferState == 0) {
351 if (ctx->Visual.rgbMode) {
352 GLchan *src = (GLchan *) pixels
353 + (skipRows * rowLength + skipPixels)*2;
354 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
355 /* no zooming */
356 GLint row;
357 ASSERT(drawWidth <= MAX_WIDTH);
358 for (row=0; row<drawHeight; row++) {
359 GLint i;
360 GLchan *ptr = src;
361 for (i=0;i<drawWidth;i++) {
362 span.array->rgba[i][0] = *ptr;
363 span.array->rgba[i][1] = *ptr;
364 span.array->rgba[i][2] = *ptr++;
365 span.array->rgba[i][3] = *ptr++;
366 }
367 #if OLD_RENDERBUFFER
368 if (swrast->Driver.WriteRGBASpan)
369 swrast->Driver.WriteRGBASpan(ctx, rb, drawWidth, destX,destY,
370 (CONST GLchan (*)[4]) span.array->rgba, NULL);
371 else
372 #endif
373 rb->PutRow(ctx, rb, drawWidth, destX, destY,
374 span.array->rgba, NULL);
375 src += rowLength*2;
376 destY++;
377 }
378 }
379 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
380 /* upside-down */
381 GLint row;
382 ASSERT(drawWidth <= MAX_WIDTH);
383 for (row=0; row<drawHeight; row++) {
384 GLint i;
385 GLchan *ptr = src;
386 for (i=0;i<drawWidth;i++) {
387 span.array->rgba[i][0] = *ptr;
388 span.array->rgba[i][1] = *ptr;
389 span.array->rgba[i][2] = *ptr++;
390 span.array->rgba[i][3] = *ptr++;
391 }
392 destY--;
393 #if OLD_RENDERBUFFER
394 if (swrast->Driver.WriteRGBASpan)
395 swrast->Driver.WriteRGBASpan(ctx, rb, drawWidth, destX,destY,
396 (CONST GLchan (*)[4]) span.array->rgba, NULL);
397 else
398 #endif
399 rb->PutRow(ctx, rb, drawWidth, destX, destY,
400 span.array->rgba, NULL);
401 src += rowLength*2;
402 }
403 }
404 else {
405 /* with zooming */
406 GLint row;
407 ASSERT(drawWidth <= MAX_WIDTH);
408 for (row=0; row<drawHeight; row++) {
409 GLchan *ptr = src;
410 GLint i;
411 for (i=0;i<drawWidth;i++) {
412 span.array->rgba[i][0] = *ptr;
413 span.array->rgba[i][1] = *ptr;
414 span.array->rgba[i][2] = *ptr++;
415 span.array->rgba[i][3] = *ptr++;
416 }
417 span.x = destX;
418 span.y = destY;
419 span.end = drawWidth;
420 _swrast_write_zoomed_rgba_span(ctx, &span,
421 (CONST GLchan (*)[4]) span.array->rgba, zoomY0, 0);
422 src += rowLength*2;
423 destY++;
424 }
425 }
426 }
427 return GL_TRUE;
428 }
429 else if (format==GL_COLOR_INDEX && type==GL_UNSIGNED_BYTE) {
430 GLubyte *src = (GLubyte *) pixels + skipRows * rowLength + skipPixels;
431 if (ctx->Visual.rgbMode) {
432 /* convert CI data to RGBA */
433 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
434 /* no zooming */
435 GLint row;
436 for (row=0; row<drawHeight; row++) {
437 ASSERT(drawWidth <= MAX_WIDTH);
438 _mesa_map_ci8_to_rgba(ctx, drawWidth, src, span.array->rgba);
439 #if OLD_RENDERBUFFER
440 if (swrast->Driver.WriteRGBASpan)
441 swrast->Driver.WriteRGBASpan(ctx, rb, drawWidth, destX,destY,
442 (const GLchan (*)[4]) span.array->rgba, NULL);
443 else
444 #endif
445 rb->PutRow(ctx, rb, drawWidth, destX, destY,
446 span.array->rgba, NULL);
447
448 src += rowLength;
449 destY++;
450 }
451 return GL_TRUE;
452 }
453 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
454 /* upside-down */
455 GLint row;
456 for (row=0; row<drawHeight; row++) {
457 ASSERT(drawWidth <= MAX_WIDTH);
458 _mesa_map_ci8_to_rgba(ctx, drawWidth, src, span.array->rgba);
459 destY--;
460 #if OLD_RENDERBUFFER
461 if (swrast->Driver.WriteRGBASpan)
462 swrast->Driver.WriteRGBASpan(ctx, rb, drawWidth, destX,destY,
463 (CONST GLchan (*)[4]) span.array->rgba, NULL);
464 else
465 #endif
466 rb->PutRow(ctx, rb, drawWidth, destX, destY,
467 span.array->rgba, NULL);
468 src += rowLength;
469 }
470 return GL_TRUE;
471 }
472 else {
473 /* with zooming */
474 GLint row;
475 for (row=0; row<drawHeight; row++) {
476 ASSERT(drawWidth <= MAX_WIDTH);
477 _mesa_map_ci8_to_rgba(ctx, drawWidth, src, span.array->rgba);
478 span.x = destX;
479 span.y = destY;
480 span.end = drawWidth;
481 _swrast_write_zoomed_rgba_span(ctx, &span,
482 (CONST GLchan (*)[4]) span.array->rgba, zoomY0, 0);
483 src += rowLength;
484 destY++;
485 }
486 return GL_TRUE;
487 }
488 }
489 else if (ctx->_ImageTransferState==0) {
490 /* write CI data to CI frame buffer */
491 GLint row;
492 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
493 /* no zooming */
494 for (row=0; row<drawHeight; row++) {
495 GLuint index32[MAX_WIDTH];
496 GLint col;
497 for (col = 0; col < drawWidth; col++)
498 index32[col] = src[col];
499 rb->PutRow(ctx, rb, drawWidth, destX, destY, index32, NULL);
500 src += rowLength;
501 destY++;
502 }
503 return GL_TRUE;
504 }
505 else {
506 /* with zooming */
507 return GL_FALSE;
508 }
509 }
510 }
511 else {
512 /* can't handle this pixel format and/or data type here */
513 return GL_FALSE;
514 }
515 }
516
517 /* can't do a simple draw, have to use slow path */
518 return GL_FALSE;
519 }
520
521
522
523 /*
524 * Draw color index image.
525 */
526 static void
527 draw_index_pixels( GLcontext *ctx, GLint x, GLint y,
528 GLsizei width, GLsizei height,
529 GLenum type,
530 const struct gl_pixelstore_attrib *unpack,
531 const GLvoid *pixels )
532 {
533 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
534 GLint row, skipPixels;
535 struct sw_span span;
536
537 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_INDEX);
538
539 if (ctx->Depth.Test)
540 _swrast_span_default_z(ctx, &span);
541 if (ctx->Fog.Enabled)
542 _swrast_span_default_fog(ctx, &span);
543
544 /*
545 * General solution
546 */
547 skipPixels = 0;
548 while (skipPixels < width) {
549 const GLint spanX = x + (zoom ? 0 : skipPixels);
550 GLint spanY = y;
551 const GLint spanEnd = (width - skipPixels > MAX_WIDTH)
552 ? MAX_WIDTH : (width - skipPixels);
553 ASSERT(spanEnd <= MAX_WIDTH);
554 for (row = 0; row < height; row++, spanY++) {
555 const GLvoid *source = _mesa_image_address2d(unpack, pixels,
556 width, height,
557 GL_COLOR_INDEX, type,
558 row, skipPixels);
559 _mesa_unpack_index_span(ctx, spanEnd, GL_UNSIGNED_INT,
560 span.array->index, type, source, unpack,
561 ctx->_ImageTransferState);
562
563 /* These may get changed during writing/clipping */
564 span.x = spanX;
565 span.y = spanY;
566 span.end = spanEnd;
567
568 if (zoom)
569 _swrast_write_zoomed_index_span(ctx, &span, y, skipPixels);
570 else
571 _swrast_write_index_span(ctx, &span);
572 }
573 skipPixels += spanEnd;
574 }
575 }
576
577
578
579 /*
580 * Draw stencil image.
581 */
582 static void
583 draw_stencil_pixels( GLcontext *ctx, GLint x, GLint y,
584 GLsizei width, GLsizei height,
585 GLenum type,
586 const struct gl_pixelstore_attrib *unpack,
587 const GLvoid *pixels )
588 {
589 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
590 const GLint desty = y;
591 GLint row, skipPixels;
592
593 if (type != GL_BYTE &&
594 type != GL_UNSIGNED_BYTE &&
595 type != GL_SHORT &&
596 type != GL_UNSIGNED_SHORT &&
597 type != GL_INT &&
598 type != GL_UNSIGNED_INT &&
599 type != GL_FLOAT &&
600 type != GL_BITMAP) {
601 _mesa_error( ctx, GL_INVALID_ENUM, "glDrawPixels(stencil type)");
602 return;
603 }
604
605 if (ctx->Visual.stencilBits == 0) {
606 _mesa_error( ctx, GL_INVALID_OPERATION, "glDrawPixels(no stencil buffer)");
607 return;
608 }
609
610 /* if width > MAX_WIDTH, have to process image in chunks */
611 skipPixels = 0;
612 while (skipPixels < width) {
613 const GLint spanX = x;
614 GLint spanY = y;
615 const GLint spanWidth = (width - skipPixels > MAX_WIDTH)
616 ? MAX_WIDTH : (width - skipPixels);
617
618 for (row = 0; row < height; row++, spanY++) {
619 GLstencil values[MAX_WIDTH];
620 GLenum destType = (sizeof(GLstencil) == sizeof(GLubyte))
621 ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT;
622 const GLvoid *source = _mesa_image_address2d(unpack, pixels,
623 width, height,
624 GL_COLOR_INDEX, type,
625 row, skipPixels);
626 _mesa_unpack_index_span(ctx, spanWidth, destType, values,
627 type, source, unpack,
628 ctx->_ImageTransferState);
629 if (ctx->_ImageTransferState & IMAGE_SHIFT_OFFSET_BIT) {
630 _mesa_shift_and_offset_stencil(ctx, spanWidth, values);
631 }
632 if (ctx->Pixel.MapStencilFlag) {
633 _mesa_map_stencil(ctx, spanWidth, values);
634 }
635
636 if (zoom) {
637 _swrast_write_zoomed_stencil_span(ctx, (GLuint) spanWidth,
638 spanX, spanY, values, desty, 0);
639 }
640 else {
641 _swrast_write_stencil_span(ctx, (GLuint) spanWidth,
642 spanX, spanY, values);
643 }
644 }
645 skipPixels += spanWidth;
646 }
647 }
648
649
650 /*
651 * Draw depth image.
652 */
653 static void
654 draw_depth_pixels( GLcontext *ctx, GLint x, GLint y,
655 GLsizei width, GLsizei height,
656 GLenum type,
657 const struct gl_pixelstore_attrib *unpack,
658 const GLvoid *pixels )
659 {
660 const GLboolean bias_or_scale = ctx->Pixel.DepthBias!=0.0 || ctx->Pixel.DepthScale!=1.0;
661 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0;
662 const GLint desty = y;
663 struct sw_span span;
664
665 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_Z);
666
667 if (type != GL_BYTE
668 && type != GL_UNSIGNED_BYTE
669 && type != GL_SHORT
670 && type != GL_UNSIGNED_SHORT
671 && type != GL_INT
672 && type != GL_UNSIGNED_INT
673 && type != GL_FLOAT) {
674 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawPixels(type)");
675 return;
676 }
677
678 _swrast_span_default_color(ctx, &span);
679
680 if (ctx->Fog.Enabled)
681 _swrast_span_default_fog(ctx, &span);
682 if (ctx->Texture._EnabledCoordUnits)
683 _swrast_span_default_texcoords(ctx, &span);
684
685 if (type == GL_UNSIGNED_SHORT
686 && ctx->Visual.depthBits == 16
687 && !bias_or_scale
688 && !zoom
689 && ctx->Visual.rgbMode
690 && width <= MAX_WIDTH) {
691 /* Special case: directly write 16-bit depth values */
692 GLint row, spanY = y;
693 for (row = 0; row < height; row++, spanY++) {
694 const GLushort *zSrc = (const GLushort *)
695 _mesa_image_address2d(unpack, pixels, width, height,
696 GL_DEPTH_COMPONENT, type, row, 0);
697 GLint i;
698 for (i = 0; i < width; i++)
699 span.array->z[i] = zSrc[i];
700 span.x = x;
701 span.y = spanY;
702 span.end = width;
703 _swrast_write_rgba_span(ctx, &span);
704 }
705 }
706 else if (type == GL_UNSIGNED_INT
707 && sizeof(GLdepth) == 4
708 && !bias_or_scale
709 && !zoom
710 && ctx->Visual.rgbMode
711 && width <= MAX_WIDTH) {
712 /* Special case: shift 32-bit values down to ctx->Visual.depthBits */
713 const GLint shift = 32 - ctx->Visual.depthBits;
714 GLint row, spanY = y;
715 for (row = 0; row < height; row++, spanY++) {
716 const GLuint *zSrc = (const GLuint *)
717 _mesa_image_address2d(unpack, pixels, width, height,
718 GL_DEPTH_COMPONENT, type, row, 0);
719 if (shift == 0) {
720 MEMCPY(span.array->z, zSrc, width * sizeof(GLdepth));
721 }
722 else {
723 GLint col;
724 for (col = 0; col < width; col++)
725 span.array->z[col] = zSrc[col] >> shift;
726 }
727 span.x = x;
728 span.y = spanY;
729 span.end = width;
730 _swrast_write_rgba_span(ctx, &span);
731 }
732 }
733 else {
734 /* General case */
735 const GLfloat depthMax = ctx->DrawBuffer->_DepthMaxF;
736 GLint row, skipPixels = 0;
737
738 /* in case width > MAX_WIDTH do the copy in chunks */
739 while (skipPixels < width) {
740 const GLint spanX = x + (zoom ? 0 : skipPixels);
741 GLint spanY = y;
742 const GLint spanEnd = (width - skipPixels > MAX_WIDTH)
743 ? MAX_WIDTH : (width - skipPixels);
744 ASSERT(span.end <= MAX_WIDTH);
745 for (row = 0; row < height; row++, spanY++) {
746 GLfloat floatSpan[MAX_WIDTH];
747 const GLvoid *zSrc = _mesa_image_address2d(unpack,
748 pixels, width, height,
749 GL_DEPTH_COMPONENT, type,
750 row, skipPixels);
751
752 /* Set these for each row since the _swrast_write_* function may
753 * change them while clipping.
754 */
755 span.x = spanX;
756 span.y = spanY;
757 span.end = spanEnd;
758
759 _mesa_unpack_depth_span(ctx, span.end, floatSpan, type,
760 zSrc, unpack);
761 /* clamp depth values to [0,1] and convert from floats to ints */
762 {
763 GLuint i;
764 for (i = 0; i < span.end; i++) {
765 span.array->z[i] = (GLdepth) (floatSpan[i] * depthMax);
766 }
767 }
768 if (zoom) {
769 _swrast_write_zoomed_depth_span(ctx, &span, desty, skipPixels);
770 }
771 else if (ctx->Visual.rgbMode) {
772 _swrast_write_rgba_span(ctx, &span);
773 }
774 else {
775 _swrast_write_index_span(ctx, &span);
776 }
777 }
778 skipPixels += spanEnd;
779 }
780 }
781 }
782
783
784
785 /*
786 * Draw RGBA image.
787 */
788 static void
789 draw_rgba_pixels( GLcontext *ctx, GLint x, GLint y,
790 GLsizei width, GLsizei height,
791 GLenum format, GLenum type,
792 const struct gl_pixelstore_attrib *unpack,
793 const GLvoid *pixels )
794 {
795 struct gl_renderbuffer *rb = NULL; /* only used for quickDraw path */
796 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
797 const GLint desty = y;
798 GLboolean quickDraw;
799 GLfloat *convImage = NULL;
800 GLuint transferOps = ctx->_ImageTransferState;
801 struct sw_span span;
802
803 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA);
804
805 if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
806 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawPixels(format or type)");
807 return;
808 }
809
810 /* Try an optimized glDrawPixels first */
811 if (fast_draw_pixels(ctx, x, y, width, height, format, type, unpack, pixels))
812 return;
813
814 if (ctx->Depth.Test)
815 _swrast_span_default_z(ctx, &span);
816 if (ctx->Fog.Enabled)
817 _swrast_span_default_fog(ctx, &span);
818 if (ctx->Texture._EnabledCoordUnits)
819 _swrast_span_default_texcoords(ctx, &span);
820
821 if (SWRAST_CONTEXT(ctx)->_RasterMask == 0 && !zoom && x >= 0 && y >= 0
822 && x + width <= (GLint) ctx->DrawBuffer->Width
823 && y + height <= (GLint) ctx->DrawBuffer->Height
824 && ctx->DrawBuffer->_NumColorDrawBuffers[0] == 1) {
825 quickDraw = GL_TRUE;
826 rb = ctx->DrawBuffer->_ColorDrawBuffers[0][0];
827 }
828 else {
829 quickDraw = GL_FALSE;
830 rb = NULL;
831 }
832
833 if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
834 /* Convolution has to be handled specially. We'll create an
835 * intermediate image, applying all pixel transfer operations
836 * up to convolution. Then we'll convolve the image. Then
837 * we'll proceed with the rest of the transfer operations and
838 * rasterize the image.
839 */
840 GLint row;
841 GLfloat *dest, *tmpImage;
842
843 tmpImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
844 if (!tmpImage) {
845 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
846 return;
847 }
848 convImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
849 if (!convImage) {
850 _mesa_free(tmpImage);
851 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
852 return;
853 }
854
855 /* Unpack the image and apply transfer ops up to convolution */
856 dest = tmpImage;
857 for (row = 0; row < height; row++) {
858 const GLvoid *source = _mesa_image_address2d(unpack,
859 pixels, width, height, format, type, row, 0);
860 _mesa_unpack_color_span_float(ctx, width, GL_RGBA, (GLfloat *) dest,
861 format, type, source, unpack,
862 transferOps & IMAGE_PRE_CONVOLUTION_BITS);
863 dest += width * 4;
864 }
865
866 /* do convolution */
867 if (ctx->Pixel.Convolution2DEnabled) {
868 _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage);
869 }
870 else {
871 ASSERT(ctx->Pixel.Separable2DEnabled);
872 _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage);
873 }
874 _mesa_free(tmpImage);
875
876 /* continue transfer ops and draw the convolved image */
877 unpack = &ctx->DefaultPacking;
878 pixels = convImage;
879 format = GL_RGBA;
880 type = GL_FLOAT;
881 transferOps &= IMAGE_POST_CONVOLUTION_BITS;
882 }
883
884 /*
885 * General solution
886 */
887 {
888 const GLuint interpMask = span.interpMask;
889 const GLuint arrayMask = span.arrayMask;
890 GLint row, skipPixels = 0;
891
892 /* if the span is wider than MAX_WIDTH we have to do it in chunks */
893 while (skipPixels < width) {
894 const GLint spanX = x + (zoom ? 0 : skipPixels);
895 GLint spanY = y;
896 const GLint spanEnd = (width - skipPixels > MAX_WIDTH)
897 ? MAX_WIDTH : (width - skipPixels);
898 ASSERT(span.end <= MAX_WIDTH);
899
900 for (row = 0; row < height; row++, spanY++) {
901 const GLvoid *source = _mesa_image_address2d(unpack,
902 pixels, width, height, format, type, row, skipPixels);
903
904 /* Set these for each row since the _swrast_write_* function may
905 * change them while clipping.
906 */
907 span.x = spanX;
908 span.y = spanY;
909 span.end = spanEnd;
910 span.arrayMask = arrayMask;
911 span.interpMask = interpMask;
912
913 _mesa_unpack_color_span_chan(ctx, span.end, GL_RGBA,
914 (GLchan *) span.array->rgba,
915 format, type, source, unpack,
916 transferOps);
917
918 if ((ctx->Pixel.MinMaxEnabled && ctx->MinMax.Sink) ||
919 (ctx->Pixel.HistogramEnabled && ctx->Histogram.Sink))
920 continue;
921
922 if (ctx->Pixel.PixelTextureEnabled && ctx->Texture._EnabledUnits) {
923 _swrast_pixel_texture(ctx, &span);
924 }
925
926 /* draw the span */
927 if (quickDraw) {
928 rb->PutRow(ctx, rb, span.end, span.x, span.y,
929 span.array->rgba, NULL);
930 }
931 else if (zoom) {
932 _swrast_write_zoomed_rgba_span(ctx, &span,
933 (CONST GLchan (*)[4]) span.array->rgba, desty, skipPixels);
934 }
935 else {
936 _swrast_write_rgba_span(ctx, &span);
937 }
938 }
939
940 skipPixels += spanEnd;
941 }
942 }
943
944 if (convImage) {
945 _mesa_free(convImage);
946 }
947 }
948
949
950
951 /*
952 * Execute glDrawPixels
953 */
954 void
955 _swrast_DrawPixels( GLcontext *ctx,
956 GLint x, GLint y,
957 GLsizei width, GLsizei height,
958 GLenum format, GLenum type,
959 const struct gl_pixelstore_attrib *unpack,
960 const GLvoid *pixels )
961 {
962 SWcontext *swrast = SWRAST_CONTEXT(ctx);
963
964 if (swrast->NewState)
965 _swrast_validate_derived( ctx );
966
967 if (unpack->BufferObj->Name) {
968 /* unpack from PBO */
969 GLubyte *buf;
970 if (!_mesa_validate_pbo_access(2, unpack, width, height, 1,
971 format, type, pixels)) {
972 _mesa_error(ctx, GL_INVALID_OPERATION,
973 "glDrawPixels(invalid PBO access)");
974 return;
975 }
976 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
977 GL_READ_ONLY_ARB,
978 unpack->BufferObj);
979 if (!buf) {
980 /* buffer is already mapped - that's an error */
981 _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawPixels(PBO is mapped)");
982 return;
983 }
984 pixels = ADD_POINTERS(buf, pixels);
985 }
986
987 RENDER_START(swrast,ctx);
988
989 switch (format) {
990 case GL_STENCIL_INDEX:
991 draw_stencil_pixels( ctx, x, y, width, height, type, unpack, pixels );
992 break;
993 case GL_DEPTH_COMPONENT:
994 draw_depth_pixels( ctx, x, y, width, height, type, unpack, pixels );
995 break;
996 case GL_COLOR_INDEX:
997 if (ctx->Visual.rgbMode)
998 draw_rgba_pixels(ctx, x,y, width, height, format, type, unpack, pixels);
999 else
1000 draw_index_pixels(ctx, x, y, width, height, type, unpack, pixels);
1001 break;
1002 case GL_RED:
1003 case GL_GREEN:
1004 case GL_BLUE:
1005 case GL_ALPHA:
1006 case GL_LUMINANCE:
1007 case GL_LUMINANCE_ALPHA:
1008 case GL_RGB:
1009 case GL_BGR:
1010 case GL_RGBA:
1011 case GL_BGRA:
1012 case GL_ABGR_EXT:
1013 draw_rgba_pixels(ctx, x, y, width, height, format, type, unpack, pixels);
1014 break;
1015 default:
1016 _mesa_error( ctx, GL_INVALID_ENUM, "glDrawPixels(format)" );
1017 /* don't return yet, clean-up */
1018 }
1019
1020 RENDER_FINISH(swrast,ctx);
1021
1022 if (unpack->BufferObj->Name) {
1023 /* done with PBO so unmap it now */
1024 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
1025 unpack->BufferObj);
1026 }
1027 }
1028
1029
1030
1031 #if 0 /* experimental */
1032 /*
1033 * Execute glDrawDepthPixelsMESA().
1034 */
1035 void
1036 _swrast_DrawDepthPixelsMESA( GLcontext *ctx,
1037 GLint x, GLint y,
1038 GLsizei width, GLsizei height,
1039 GLenum colorFormat, GLenum colorType,
1040 const GLvoid *colors,
1041 GLenum depthType, const GLvoid *depths,
1042 const struct gl_pixelstore_attrib *unpack )
1043 {
1044 SWcontext *swrast = SWRAST_CONTEXT(ctx);
1045
1046 if (swrast->NewState)
1047 _swrast_validate_derived( ctx );
1048
1049 RENDER_START(swrast,ctx);
1050
1051 switch (colorFormat) {
1052 case GL_COLOR_INDEX:
1053 if (ctx->Visual.rgbMode)
1054 draw_rgba_pixels(ctx, x,y, width, height, colorFormat, colorType, unpack, colors);
1055 else
1056 draw_index_pixels(ctx, x, y, width, height, colorType, unpack, colors);
1057 break;
1058 case GL_RED:
1059 case GL_GREEN:
1060 case GL_BLUE:
1061 case GL_ALPHA:
1062 case GL_LUMINANCE:
1063 case GL_LUMINANCE_ALPHA:
1064 case GL_RGB:
1065 case GL_BGR:
1066 case GL_RGBA:
1067 case GL_BGRA:
1068 case GL_ABGR_EXT:
1069 draw_rgba_pixels(ctx, x, y, width, height, colorFormat, colorType, unpack, colors);
1070 break;
1071 default:
1072 _mesa_error( ctx, GL_INVALID_ENUM,
1073 "glDrawDepthPixelsMESA(colorFormat)" );
1074 }
1075
1076 RENDER_FINISH(swrast,ctx);
1077 }
1078 #endif