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