remove stray tab
[mesa.git] / src / mesa / swrast / s_drawpix.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5.2
4 *
5 * Copyright (C) 1999-2006 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 #include "state.h"
35
36 #include "s_context.h"
37 #include "s_drawpix.h"
38 #include "s_span.h"
39 #include "s_stencil.h"
40 #include "s_zoom.h"
41
42
43
44 /**
45 * Try to do a fast and simple RGB(a) glDrawPixels.
46 * Return: GL_TRUE if success, GL_FALSE if slow path must be used instead
47 */
48 static GLboolean
49 fast_draw_rgba_pixels(GLcontext *ctx, GLint x, GLint y,
50 GLsizei width, GLsizei height,
51 GLenum format, GLenum type,
52 const struct gl_pixelstore_attrib *userUnpack,
53 const GLvoid *pixels)
54 {
55 const GLint imgX = x, imgY = y;
56 struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0][0];
57 const GLenum rbType = rb->DataType;
58 SWcontext *swrast = SWRAST_CONTEXT(ctx);
59 SWspan span;
60 GLboolean simpleZoom;
61 GLint yStep; /* +1 or -1 */
62 struct gl_pixelstore_attrib unpack;
63 GLint destX, destY, drawWidth, drawHeight; /* post clipping */
64
65 if ((swrast->_RasterMask & ~CLIP_BIT) ||
66 ctx->Texture._EnabledCoordUnits ||
67 userUnpack->SwapBytes ||
68 ctx->_ImageTransferState) {
69 /* can't handle any of those conditions */
70 return GL_FALSE;
71 }
72
73 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA);
74 if (ctx->Depth.Test)
75 _swrast_span_default_z(ctx, &span);
76 if (swrast->_FogEnabled)
77 _swrast_span_default_fog(ctx, &span);
78 if (ctx->Texture._EnabledCoordUnits)
79 _swrast_span_default_texcoords(ctx, &span);
80
81 /* copy input params since clipping may change them */
82 unpack = *userUnpack;
83 destX = x;
84 destY = y;
85 drawWidth = width;
86 drawHeight = height;
87
88 /* check for simple zooming and clipping */
89 if (ctx->Pixel.ZoomX == 1.0F &&
90 (ctx->Pixel.ZoomY == 1.0F || ctx->Pixel.ZoomY == -1.0F)) {
91 if (!_mesa_clip_drawpixels(ctx, &destX, &destY,
92 &drawWidth, &drawHeight, &unpack)) {
93 /* image was completely clipped: no-op, all done */
94 return GL_TRUE;
95 }
96 simpleZoom = GL_TRUE;
97 yStep = (GLint) ctx->Pixel.ZoomY;
98 ASSERT(yStep == 1 || yStep == -1);
99 }
100 else {
101 /* non-simple zooming */
102 simpleZoom = GL_FALSE;
103 yStep = 1;
104 if (unpack.RowLength == 0)
105 unpack.RowLength = width;
106 }
107
108 /*
109 * Ready to draw!
110 */
111
112 if (format == GL_RGBA && type == rbType) {
113 const GLubyte *src = _mesa_image_address2d(&unpack, pixels, width,
114 height, format, type, 0, 0);
115 const GLint srcStride = _mesa_image_row_stride(&unpack, width,
116 format, type);
117 if (simpleZoom) {
118 GLint row;
119 for (row = 0; row < drawHeight; row++) {
120 rb->PutRow(ctx, rb, drawWidth, destX, destY, src, NULL);
121 src += srcStride;
122 destY += yStep;
123 }
124 }
125 else {
126 /* with zooming */
127 GLint row;
128 for (row = 0; row < drawHeight; row++) {
129 span.x = destX;
130 span.y = destY + row;
131 span.end = drawWidth;
132 span.array->ChanType = rbType;
133 _swrast_write_zoomed_rgba_span(ctx, imgX, imgY, &span, src);
134 src += srcStride;
135 }
136 span.array->ChanType = CHAN_TYPE;
137 }
138 return GL_TRUE;
139 }
140
141 if (format == GL_RGB && type == rbType) {
142 const GLubyte *src = _mesa_image_address2d(&unpack, pixels, width,
143 height, format, type, 0, 0);
144 const GLint srcStride = _mesa_image_row_stride(&unpack, width,
145 format, type);
146 if (simpleZoom) {
147 GLint row;
148 for (row = 0; row < drawHeight; row++) {
149 rb->PutRowRGB(ctx, rb, drawWidth, destX, destY, src, NULL);
150 src += srcStride;
151 destY += yStep;
152 }
153 }
154 else {
155 /* with zooming */
156 GLint row;
157 for (row = 0; row < drawHeight; row++) {
158 span.x = destX;
159 span.y = destY;
160 span.end = drawWidth;
161 span.array->ChanType = rbType;
162 _swrast_write_zoomed_rgb_span(ctx, imgX, imgY, &span, src);
163 src += srcStride;
164 destY++;
165 }
166 span.array->ChanType = CHAN_TYPE;
167 }
168 return GL_TRUE;
169 }
170
171 /* Remaining cases haven't been tested with alignment != 1 */
172 if (userUnpack->Alignment != 1)
173 return GL_FALSE;
174
175 if (format == GL_LUMINANCE && type == CHAN_TYPE && rbType == CHAN_TYPE) {
176 const GLchan *src = (const GLchan *) pixels
177 + (unpack.SkipRows * unpack.RowLength + unpack.SkipPixels);
178 if (simpleZoom) {
179 /* no zooming */
180 GLint row;
181 ASSERT(drawWidth <= MAX_WIDTH);
182 for (row = 0; row < drawHeight; row++) {
183 GLchan rgb[MAX_WIDTH][3];
184 GLint i;
185 for (i = 0;i<drawWidth;i++) {
186 rgb[i][0] = src[i];
187 rgb[i][1] = src[i];
188 rgb[i][2] = src[i];
189 }
190 rb->PutRowRGB(ctx, rb, drawWidth, destX, destY, rgb, NULL);
191 src += unpack.RowLength;
192 destY += yStep;
193 }
194 }
195 else {
196 /* with zooming */
197 GLint row;
198 ASSERT(drawWidth <= MAX_WIDTH);
199 for (row = 0; row < drawHeight; row++) {
200 GLchan rgb[MAX_WIDTH][3];
201 GLint i;
202 for (i = 0;i<drawWidth;i++) {
203 rgb[i][0] = src[i];
204 rgb[i][1] = src[i];
205 rgb[i][2] = src[i];
206 }
207 span.x = destX;
208 span.y = destY;
209 span.end = drawWidth;
210 _swrast_write_zoomed_rgb_span(ctx, imgX, imgY, &span, rgb);
211 src += unpack.RowLength;
212 destY++;
213 }
214 }
215 return GL_TRUE;
216 }
217
218 if (format == GL_LUMINANCE_ALPHA && type == CHAN_TYPE && rbType == CHAN_TYPE) {
219 const GLchan *src = (const GLchan *) pixels
220 + (unpack.SkipRows * unpack.RowLength + unpack.SkipPixels)*2;
221 if (simpleZoom) {
222 GLint row;
223 ASSERT(drawWidth <= MAX_WIDTH);
224 for (row = 0; row < drawHeight; row++) {
225 GLint i;
226 const GLchan *ptr = src;
227 for (i = 0;i<drawWidth;i++) {
228 span.array->rgba[i][0] = *ptr;
229 span.array->rgba[i][1] = *ptr;
230 span.array->rgba[i][2] = *ptr++;
231 span.array->rgba[i][3] = *ptr++;
232 }
233 rb->PutRow(ctx, rb, drawWidth, destX, destY,
234 span.array->rgba, NULL);
235 src += unpack.RowLength*2;
236 destY += yStep;
237 }
238 }
239 else {
240 /* with zooming */
241 GLint row;
242 ASSERT(drawWidth <= MAX_WIDTH);
243 for (row = 0; row < drawHeight; row++) {
244 const GLchan *ptr = src;
245 GLint i;
246 for (i = 0;i<drawWidth;i++) {
247 span.array->rgba[i][0] = *ptr;
248 span.array->rgba[i][1] = *ptr;
249 span.array->rgba[i][2] = *ptr++;
250 span.array->rgba[i][3] = *ptr++;
251 }
252 span.x = destX;
253 span.y = destY;
254 span.end = drawWidth;
255 _swrast_write_zoomed_rgba_span(ctx, imgX, imgY, &span,
256 span.array->rgba);
257 src += unpack.RowLength*2;
258 destY++;
259 }
260 }
261 return GL_TRUE;
262 }
263
264 if (format == GL_COLOR_INDEX && type == GL_UNSIGNED_BYTE) {
265 const GLubyte *src = (const GLubyte *) pixels
266 + unpack.SkipRows * unpack.RowLength + unpack.SkipPixels;
267 if (ctx->Visual.rgbMode && rbType == GL_UNSIGNED_BYTE) {
268 /* convert ubyte/CI data to ubyte/RGBA */
269 if (simpleZoom) {
270 GLint row;
271 for (row = 0; row < drawHeight; row++) {
272 ASSERT(drawWidth <= MAX_WIDTH);
273 _mesa_map_ci8_to_rgba8(ctx, drawWidth, src,
274 span.array->color.sz1.rgba);
275 rb->PutRow(ctx, rb, drawWidth, destX, destY,
276 span.array->color.sz1.rgba, NULL);
277 src += unpack.RowLength;
278 destY += yStep;
279 }
280 }
281 else {
282 /* ubyte/CI to ubyte/RGBA with zooming */
283 GLint row;
284 for (row = 0; row < drawHeight; row++) {
285 ASSERT(drawWidth <= MAX_WIDTH);
286 _mesa_map_ci8_to_rgba8(ctx, drawWidth, src,
287 span.array->color.sz1.rgba);
288 span.x = destX;
289 span.y = destY;
290 span.end = drawWidth;
291 _swrast_write_zoomed_rgba_span(ctx, imgX, imgY, &span,
292 span.array->color.sz1.rgba);
293 src += unpack.RowLength;
294 destY++;
295 }
296 }
297 return GL_TRUE;
298 }
299 else if (!ctx->Visual.rgbMode && rbType == GL_UNSIGNED_INT) {
300 /* write CI data to CI frame buffer */
301 GLint row;
302 if (simpleZoom) {
303 for (row = 0; row < drawHeight; row++) {
304 GLuint index32[MAX_WIDTH];
305 GLint col;
306 for (col = 0; col < drawWidth; col++)
307 index32[col] = src[col];
308 rb->PutRow(ctx, rb, drawWidth, destX, destY, index32, NULL);
309 src += unpack.RowLength;
310 destY += yStep;
311 }
312 return GL_TRUE;
313 }
314 }
315 }
316
317 /* can't handle this pixel format and/or data type */
318 return GL_FALSE;
319 }
320
321
322
323 /*
324 * Draw color index image.
325 */
326 static void
327 draw_index_pixels( GLcontext *ctx, GLint x, GLint y,
328 GLsizei width, GLsizei height,
329 GLenum type,
330 const struct gl_pixelstore_attrib *unpack,
331 const GLvoid *pixels )
332 {
333 SWcontext *swrast = SWRAST_CONTEXT(ctx);
334 const GLint imgX = x, imgY = y;
335 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
336 GLint row, skipPixels;
337 SWspan span;
338
339 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_INDEX);
340
341 if (ctx->Depth.Test)
342 _swrast_span_default_z(ctx, &span);
343 if (swrast->_FogEnabled)
344 _swrast_span_default_fog(ctx, &span);
345
346 /*
347 * General solution
348 */
349 skipPixels = 0;
350 while (skipPixels < width) {
351 const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH);
352 ASSERT(spanWidth <= MAX_WIDTH);
353 for (row = 0; row < height; row++) {
354 const GLvoid *source = _mesa_image_address2d(unpack, pixels,
355 width, height,
356 GL_COLOR_INDEX, type,
357 row, skipPixels);
358 _mesa_unpack_index_span(ctx, spanWidth, GL_UNSIGNED_INT,
359 span.array->index, type, source, unpack,
360 ctx->_ImageTransferState);
361
362 /* These may get changed during writing/clipping */
363 span.x = x + skipPixels;
364 span.y = y + row;
365 span.end = spanWidth;
366
367 if (zoom)
368 _swrast_write_zoomed_index_span(ctx, imgX, imgY, &span);
369 else
370 _swrast_write_index_span(ctx, &span);
371 }
372 skipPixels += spanWidth;
373 }
374 }
375
376
377
378 /*
379 * Draw stencil image.
380 */
381 static void
382 draw_stencil_pixels( GLcontext *ctx, GLint x, GLint y,
383 GLsizei width, GLsizei height,
384 GLenum type,
385 const struct gl_pixelstore_attrib *unpack,
386 const GLvoid *pixels )
387 {
388 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0;
389 GLint skipPixels;
390
391 /* if width > MAX_WIDTH, have to process image in chunks */
392 skipPixels = 0;
393 while (skipPixels < width) {
394 const GLint spanX = x + skipPixels;
395 const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH);
396 GLint row;
397 for (row = 0; row < height; row++) {
398 const GLint spanY = y + row;
399 GLstencil values[MAX_WIDTH];
400 GLenum destType = (sizeof(GLstencil) == sizeof(GLubyte))
401 ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT;
402 const GLvoid *source = _mesa_image_address2d(unpack, pixels,
403 width, height,
404 GL_COLOR_INDEX, type,
405 row, skipPixels);
406 _mesa_unpack_index_span(ctx, spanWidth, destType, values,
407 type, source, unpack,
408 ctx->_ImageTransferState);
409 _mesa_apply_stencil_transfer_ops(ctx, spanWidth, values);
410 if (zoom) {
411 _swrast_write_zoomed_stencil_span(ctx, x, y, spanWidth,
412 spanX, spanY, values);
413 }
414 else {
415 _swrast_write_stencil_span(ctx, spanWidth, spanX, spanY, values);
416 }
417 }
418 skipPixels += spanWidth;
419 }
420 }
421
422
423 /*
424 * Draw depth image.
425 */
426 static void
427 draw_depth_pixels( GLcontext *ctx, GLint x, GLint y,
428 GLsizei width, GLsizei height,
429 GLenum type,
430 const struct gl_pixelstore_attrib *unpack,
431 const GLvoid *pixels )
432 {
433 SWcontext *swrast = SWRAST_CONTEXT(ctx);
434 const GLboolean scaleOrBias
435 = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0;
436 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0;
437 SWspan span;
438
439 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_Z);
440
441 _swrast_span_default_color(ctx, &span);
442
443 if (swrast->_FogEnabled)
444 _swrast_span_default_fog(ctx, &span);
445 if (ctx->Texture._EnabledCoordUnits)
446 _swrast_span_default_texcoords(ctx, &span);
447
448 if (type == GL_UNSIGNED_SHORT
449 && ctx->DrawBuffer->Visual.depthBits == 16
450 && !scaleOrBias
451 && !zoom
452 && ctx->Visual.rgbMode
453 && width <= MAX_WIDTH) {
454 /* Special case: directly write 16-bit depth values */
455 GLint row;
456 for (row = 0; row < height; row++) {
457 const GLushort *zSrc = (const GLushort *)
458 _mesa_image_address2d(unpack, pixels, width, height,
459 GL_DEPTH_COMPONENT, type, row, 0);
460 GLint i;
461 for (i = 0; i < width; i++)
462 span.array->z[i] = zSrc[i];
463 span.x = x;
464 span.y = y + row;
465 span.end = width;
466 _swrast_write_rgba_span(ctx, &span);
467 }
468 }
469 else if (type == GL_UNSIGNED_INT
470 && !scaleOrBias
471 && !zoom
472 && ctx->Visual.rgbMode
473 && width <= MAX_WIDTH) {
474 /* Special case: shift 32-bit values down to Visual.depthBits */
475 const GLint shift = 32 - ctx->DrawBuffer->Visual.depthBits;
476 GLint row;
477 for (row = 0; row < height; row++) {
478 const GLuint *zSrc = (const GLuint *)
479 _mesa_image_address2d(unpack, pixels, width, height,
480 GL_DEPTH_COMPONENT, type, row, 0);
481 if (shift == 0) {
482 _mesa_memcpy(span.array->z, zSrc, width * sizeof(GLuint));
483 }
484 else {
485 GLint col;
486 for (col = 0; col < width; col++)
487 span.array->z[col] = zSrc[col] >> shift;
488 }
489 span.x = x;
490 span.y = y + row;
491 span.end = width;
492 _swrast_write_rgba_span(ctx, &span);
493 }
494 }
495 else {
496 /* General case */
497 const GLfloat depthMax = ctx->DrawBuffer->_DepthMaxF;
498 GLint skipPixels = 0;
499
500 /* in case width > MAX_WIDTH do the copy in chunks */
501 while (skipPixels < width) {
502 const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH);
503 GLint row;
504 ASSERT(span.end <= MAX_WIDTH);
505 for (row = 0; row < height; row++) {
506 const GLvoid *zSrc = _mesa_image_address2d(unpack,
507 pixels, width, height,
508 GL_DEPTH_COMPONENT, type,
509 row, skipPixels);
510
511 /* Set these for each row since the _swrast_write_* function may
512 * change them while clipping.
513 */
514 span.x = x + skipPixels;
515 span.y = y + row;
516 span.end = spanWidth;
517
518 _mesa_unpack_depth_span(ctx, spanWidth,
519 GL_UNSIGNED_INT, span.array->z, depthMax,
520 type, zSrc, unpack);
521 if (zoom) {
522 _swrast_write_zoomed_depth_span(ctx, x, y, &span);
523 }
524 else if (ctx->Visual.rgbMode) {
525 _swrast_write_rgba_span(ctx, &span);
526 }
527 else {
528 _swrast_write_index_span(ctx, &span);
529 }
530 }
531 skipPixels += spanWidth;
532 }
533 }
534 }
535
536
537
538 /**
539 * Draw RGBA image.
540 */
541 static void
542 draw_rgba_pixels( GLcontext *ctx, GLint x, GLint y,
543 GLsizei width, GLsizei height,
544 GLenum format, GLenum type,
545 const struct gl_pixelstore_attrib *unpack,
546 const GLvoid *pixels )
547 {
548 SWcontext *swrast = SWRAST_CONTEXT(ctx);
549 const GLint imgX = x, imgY = y;
550 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
551 GLfloat *convImage = NULL;
552 GLbitfield transferOps = ctx->_ImageTransferState;
553 SWspan span;
554
555 /* Try an optimized glDrawPixels first */
556 if (fast_draw_rgba_pixels(ctx, x, y, width, height, format, type,
557 unpack, pixels))
558 return;
559
560 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA);
561 if (ctx->Depth.Test)
562 _swrast_span_default_z(ctx, &span);
563 if (swrast->_FogEnabled)
564 _swrast_span_default_fog(ctx, &span);
565 if (ctx->Texture._EnabledCoordUnits)
566 _swrast_span_default_texcoords(ctx, &span);
567
568 if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
569 /* Convolution has to be handled specially. We'll create an
570 * intermediate image, applying all pixel transfer operations
571 * up to convolution. Then we'll convolve the image. Then
572 * we'll proceed with the rest of the transfer operations and
573 * rasterize the image.
574 */
575 GLint row;
576 GLfloat *dest, *tmpImage;
577
578 tmpImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
579 if (!tmpImage) {
580 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
581 return;
582 }
583 convImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
584 if (!convImage) {
585 _mesa_free(tmpImage);
586 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
587 return;
588 }
589
590 /* Unpack the image and apply transfer ops up to convolution */
591 dest = tmpImage;
592 for (row = 0; row < height; row++) {
593 const GLvoid *source = _mesa_image_address2d(unpack,
594 pixels, width, height, format, type, row, 0);
595 _mesa_unpack_color_span_float(ctx, width, GL_RGBA, (GLfloat *) dest,
596 format, type, source, unpack,
597 transferOps & IMAGE_PRE_CONVOLUTION_BITS);
598 dest += width * 4;
599 }
600
601 /* do convolution */
602 if (ctx->Pixel.Convolution2DEnabled) {
603 _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage);
604 }
605 else {
606 ASSERT(ctx->Pixel.Separable2DEnabled);
607 _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage);
608 }
609 _mesa_free(tmpImage);
610
611 /* continue transfer ops and draw the convolved image */
612 unpack = &ctx->DefaultPacking;
613 pixels = convImage;
614 format = GL_RGBA;
615 type = GL_FLOAT;
616 transferOps &= IMAGE_POST_CONVOLUTION_BITS;
617 }
618
619 if (ctx->DrawBuffer->_NumColorDrawBuffers[0] > 0 &&
620 ctx->DrawBuffer->_ColorDrawBuffers[0][0]->DataType != GL_FLOAT &&
621 ctx->Color.ClampFragmentColor != GL_FALSE) {
622 /* need to clamp colors before applying fragment ops */
623 transferOps |= IMAGE_CLAMP_BIT;
624 }
625
626 /*
627 * General solution
628 */
629 {
630 const GLboolean sink = (ctx->Pixel.MinMaxEnabled && ctx->MinMax.Sink)
631 || (ctx->Pixel.HistogramEnabled && ctx->Histogram.Sink);
632 const GLbitfield interpMask = span.interpMask;
633 const GLbitfield arrayMask = span.arrayMask;
634 const GLint srcStride
635 = _mesa_image_row_stride(unpack, width, format, type);
636 GLint skipPixels = 0;
637 /* use span array for temp color storage */
638 GLfloat *rgba = (GLfloat *) span.array->color.sz4.rgba;
639
640 /* if the span is wider than MAX_WIDTH we have to do it in chunks */
641 while (skipPixels < width) {
642 const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH);
643 const GLubyte *source = _mesa_image_address2d(unpack, pixels,
644 width, height, format, type, 0, skipPixels);
645 GLint row;
646
647 for (row = 0; row < height; row++) {
648 /* get image row as float/RGBA */
649 _mesa_unpack_color_span_float(ctx, spanWidth, GL_RGBA, rgba,
650 format, type, source, unpack,
651 transferOps);
652 /* draw the span */
653 if (!sink) {
654 /* Set these for each row since the _swrast_write_* functions
655 * may change them while clipping/rendering.
656 */
657 span.array->ChanType = GL_FLOAT;
658 span.x = x + skipPixels;
659 span.y = y + row;
660 span.end = spanWidth;
661 span.arrayMask = arrayMask;
662 span.interpMask = interpMask;
663 if (zoom) {
664 _swrast_write_zoomed_rgba_span(ctx, imgX, imgY, &span, rgba);
665 }
666 else {
667 _swrast_write_rgba_span(ctx, &span);
668 }
669 }
670
671 source += srcStride;
672 } /* for row */
673
674 skipPixels += spanWidth;
675 } /* while skipPixels < width */
676
677 /* XXX this is ugly/temporary, to undo above change */
678 span.array->ChanType = CHAN_TYPE;
679 }
680
681 if (convImage) {
682 _mesa_free(convImage);
683 }
684 }
685
686
687 /**
688 * This is a bit different from drawing GL_DEPTH_COMPONENT pixels.
689 * The only per-pixel operations that apply are depth scale/bias,
690 * stencil offset/shift, GL_DEPTH_WRITEMASK and GL_STENCIL_WRITEMASK,
691 * and pixel zoom.
692 * Also, only the depth buffer and stencil buffers are touched, not the
693 * color buffer(s).
694 */
695 static void
696 draw_depth_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
697 GLsizei width, GLsizei height, GLenum type,
698 const struct gl_pixelstore_attrib *unpack,
699 const GLvoid *pixels)
700 {
701 const GLint imgX = x, imgY = y;
702 const GLboolean scaleOrBias
703 = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0;
704 const GLfloat depthScale = ctx->DrawBuffer->_DepthMaxF;
705 const GLuint stencilMask = ctx->Stencil.WriteMask[0];
706 const GLuint stencilType = (STENCIL_BITS == 8) ?
707 GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT;
708 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0;
709 struct gl_renderbuffer *depthRb, *stencilRb;
710 struct gl_pixelstore_attrib clippedUnpack = *unpack;
711
712 if (!zoom) {
713 if (!_mesa_clip_drawpixels(ctx, &x, &y, &width, &height,
714 &clippedUnpack)) {
715 /* totally clipped */
716 return;
717 }
718 }
719
720 depthRb = ctx->ReadBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
721 stencilRb = ctx->ReadBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
722 ASSERT(depthRb);
723 ASSERT(stencilRb);
724
725 if (depthRb->_BaseFormat == GL_DEPTH_STENCIL_EXT &&
726 stencilRb->_BaseFormat == GL_DEPTH_STENCIL_EXT &&
727 depthRb == stencilRb &&
728 !scaleOrBias &&
729 !zoom &&
730 ctx->Depth.Mask &&
731 (stencilMask & 0xff) == 0xff) {
732 /* This is the ideal case.
733 * Drawing GL_DEPTH_STENCIL pixels into a combined depth/stencil buffer.
734 * Plus, no pixel transfer ops, zooming, or masking needed.
735 */
736 GLint i;
737 for (i = 0; i < height; i++) {
738 const GLuint *src = (const GLuint *)
739 _mesa_image_address2d(&clippedUnpack, pixels, width, height,
740 GL_DEPTH_STENCIL_EXT, type, i, 0);
741 depthRb->PutRow(ctx, depthRb, width, x, y + i, src, NULL);
742 }
743 }
744 else {
745 /* sub-optimal cases:
746 * Separate depth/stencil buffers, or pixel transfer ops required.
747 */
748 /* XXX need to handle very wide images (skippixels) */
749 GLint i;
750
751 depthRb = ctx->DrawBuffer->_DepthBuffer;
752 stencilRb = ctx->DrawBuffer->_StencilBuffer;
753
754 for (i = 0; i < height; i++) {
755 const GLuint *depthStencilSrc = (const GLuint *)
756 _mesa_image_address2d(&clippedUnpack, pixels, width, height,
757 GL_DEPTH_STENCIL_EXT, type, i, 0);
758
759 if (ctx->Depth.Mask) {
760 if (!scaleOrBias && ctx->DrawBuffer->Visual.depthBits == 24) {
761 /* fast path 24-bit zbuffer */
762 GLuint zValues[MAX_WIDTH];
763 GLint j;
764 ASSERT(depthRb->DataType == GL_UNSIGNED_INT);
765 for (j = 0; j < width; j++) {
766 zValues[j] = depthStencilSrc[j] >> 8;
767 }
768 if (zoom)
769 _swrast_write_zoomed_z_span(ctx, imgX, imgY, width,
770 x, y + i, zValues);
771 else
772 depthRb->PutRow(ctx, depthRb, width, x, y + i, zValues,NULL);
773 }
774 else if (!scaleOrBias && ctx->DrawBuffer->Visual.depthBits == 16) {
775 /* fast path 16-bit zbuffer */
776 GLushort zValues[MAX_WIDTH];
777 GLint j;
778 ASSERT(depthRb->DataType == GL_UNSIGNED_SHORT);
779 for (j = 0; j < width; j++) {
780 zValues[j] = depthStencilSrc[j] >> 16;
781 }
782 if (zoom)
783 _swrast_write_zoomed_z_span(ctx, imgX, imgY, width,
784 x, y + i, zValues);
785 else
786 depthRb->PutRow(ctx, depthRb, width, x, y + i, zValues,NULL);
787 }
788 else {
789 /* general case */
790 GLuint zValues[MAX_WIDTH]; /* 16 or 32-bit Z value storage */
791 _mesa_unpack_depth_span(ctx, width,
792 depthRb->DataType, zValues, depthScale,
793 type, depthStencilSrc, &clippedUnpack);
794 if (zoom) {
795 _swrast_write_zoomed_z_span(ctx, imgX, imgY, width, x,
796 y + i, zValues);
797 }
798 else {
799 depthRb->PutRow(ctx, depthRb, width, x, y + i, zValues,NULL);
800 }
801 }
802 }
803
804 if (stencilMask != 0x0) {
805 GLstencil stencilValues[MAX_WIDTH];
806 /* get stencil values, with shift/offset/mapping */
807 _mesa_unpack_stencil_span(ctx, width, stencilType, stencilValues,
808 type, depthStencilSrc, &clippedUnpack,
809 ctx->_ImageTransferState);
810 if (zoom)
811 _swrast_write_zoomed_stencil_span(ctx, imgX, imgY, width,
812 x, y + i, stencilValues);
813 else
814 _swrast_write_stencil_span(ctx, width, x, y + i, stencilValues);
815 }
816 }
817 }
818 }
819
820
821
822 /**
823 * Execute software-based glDrawPixels.
824 * By time we get here, all error checking will have been done.
825 */
826 void
827 _swrast_DrawPixels( GLcontext *ctx,
828 GLint x, GLint y,
829 GLsizei width, GLsizei height,
830 GLenum format, GLenum type,
831 const struct gl_pixelstore_attrib *unpack,
832 const GLvoid *pixels )
833 {
834 SWcontext *swrast = SWRAST_CONTEXT(ctx);
835
836 RENDER_START(swrast,ctx);
837
838 if (ctx->NewState)
839 _mesa_update_state(ctx);
840
841 if (swrast->NewState)
842 _swrast_validate_derived( ctx );
843
844 if (unpack->BufferObj->Name) {
845 /* unpack from PBO */
846 GLubyte *buf;
847 if (!_mesa_validate_pbo_access(2, unpack, width, height, 1,
848 format, type, pixels)) {
849 _mesa_error(ctx, GL_INVALID_OPERATION,
850 "glDrawPixels(invalid PBO access)");
851 goto end;
852 }
853 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
854 GL_READ_ONLY_ARB,
855 unpack->BufferObj);
856 if (!buf) {
857 /* buffer is already mapped - that's an error */
858 _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawPixels(PBO is mapped)");
859 goto end;
860 }
861 pixels = ADD_POINTERS(buf, pixels);
862 }
863
864 switch (format) {
865 case GL_STENCIL_INDEX:
866 draw_stencil_pixels( ctx, x, y, width, height, type, unpack, pixels );
867 break;
868 case GL_DEPTH_COMPONENT:
869 draw_depth_pixels( ctx, x, y, width, height, type, unpack, pixels );
870 break;
871 case GL_COLOR_INDEX:
872 if (ctx->Visual.rgbMode)
873 draw_rgba_pixels(ctx, x,y, width, height, format, type, unpack, pixels);
874 else
875 draw_index_pixels(ctx, x, y, width, height, type, unpack, pixels);
876 break;
877 case GL_RED:
878 case GL_GREEN:
879 case GL_BLUE:
880 case GL_ALPHA:
881 case GL_LUMINANCE:
882 case GL_LUMINANCE_ALPHA:
883 case GL_RGB:
884 case GL_BGR:
885 case GL_RGBA:
886 case GL_BGRA:
887 case GL_ABGR_EXT:
888 draw_rgba_pixels(ctx, x, y, width, height, format, type, unpack, pixels);
889 break;
890 case GL_DEPTH_STENCIL_EXT:
891 draw_depth_stencil_pixels(ctx, x, y, width, height,
892 type, unpack, pixels);
893 break;
894 default:
895 _mesa_problem(ctx, "unexpected format in _swrast_DrawPixels");
896 /* don't return yet, clean-up */
897 }
898
899 end:
900
901 RENDER_FINISH(swrast,ctx);
902
903 if (unpack->BufferObj->Name) {
904 /* done with PBO so unmap it now */
905 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
906 unpack->BufferObj);
907 }
908 }
909
910
911
912 #if 0 /* experimental */
913 /*
914 * Execute glDrawDepthPixelsMESA().
915 */
916 void
917 _swrast_DrawDepthPixelsMESA( GLcontext *ctx,
918 GLint x, GLint y,
919 GLsizei width, GLsizei height,
920 GLenum colorFormat, GLenum colorType,
921 const GLvoid *colors,
922 GLenum depthType, const GLvoid *depths,
923 const struct gl_pixelstore_attrib *unpack )
924 {
925 SWcontext *swrast = SWRAST_CONTEXT(ctx);
926
927 if (swrast->NewState)
928 _swrast_validate_derived( ctx );
929
930 RENDER_START(swrast,ctx);
931
932 switch (colorFormat) {
933 case GL_COLOR_INDEX:
934 if (ctx->Visual.rgbMode)
935 draw_rgba_pixels(ctx, x,y, width, height, colorFormat, colorType,
936 unpack, colors);
937 else
938 draw_index_pixels(ctx, x, y, width, height, colorType,
939 unpack, colors);
940 break;
941 case GL_RED:
942 case GL_GREEN:
943 case GL_BLUE:
944 case GL_ALPHA:
945 case GL_LUMINANCE:
946 case GL_LUMINANCE_ALPHA:
947 case GL_RGB:
948 case GL_BGR:
949 case GL_RGBA:
950 case GL_BGRA:
951 case GL_ABGR_EXT:
952 draw_rgba_pixels(ctx, x, y, width, height, colorFormat, colorType,
953 unpack, colors);
954 break;
955 default:
956 _mesa_problem(ctx, "unexpected format in glDrawDepthPixelsMESA");
957 }
958
959 RENDER_FINISH(swrast,ctx);
960 }
961 #endif