2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2004 Brian Paul All Rights Reserved.
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:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
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.
27 #include "bufferobj.h"
35 #include "s_context.h"
36 #include "s_drawpix.h"
37 #include "s_pixeltex.h"
39 #include "s_stencil.h"
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
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
,
54 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
57 INIT_SPAN(span
, GL_BITMAP
, 0, 0, SPAN_RGBA
);
59 if (!ctx
->Current
.RasterPosValid
) {
60 return GL_TRUE
; /* no-op */
64 _swrast_span_default_z(ctx
, &span
);
66 _swrast_span_default_fog(ctx
, &span
);
67 if (ctx
->Texture
._EnabledCoordUnits
)
68 _swrast_span_default_texcoords(ctx
, &span
);
70 if ((SWRAST_CONTEXT(ctx
)->_RasterMask
& ~CLIP_BIT
) == 0
71 && ctx
->Texture
._EnabledCoordUnits
== 0
72 && unpack
->Alignment
== 1
74 && !unpack
->LsbFirst
) {
78 GLint drawWidth
= width
; /* actual width drawn */
79 GLint drawHeight
= height
; /* actual height drawn */
80 GLint skipPixels
= unpack
->SkipPixels
;
81 GLint skipRows
= unpack
->SkipRows
;
85 if (unpack
->RowLength
> 0)
86 rowLength
= unpack
->RowLength
;
90 /* If we're not using pixel zoom then do all clipping calculations
91 * now. Otherwise, we'll let the _swrast_write_zoomed_*_span() functions
92 * handle the clipping.
94 if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==1.0F
) {
95 /* horizontal clipping */
96 if (destX
< ctx
->DrawBuffer
->_Xmin
) {
97 skipPixels
+= (ctx
->DrawBuffer
->_Xmin
- destX
);
98 drawWidth
-= (ctx
->DrawBuffer
->_Xmin
- destX
);
99 destX
= ctx
->DrawBuffer
->_Xmin
;
101 if (destX
+ drawWidth
> ctx
->DrawBuffer
->_Xmax
)
102 drawWidth
-= (destX
+ drawWidth
- ctx
->DrawBuffer
->_Xmax
);
106 /* vertical clipping */
107 if (destY
< ctx
->DrawBuffer
->_Ymin
) {
108 skipRows
+= (ctx
->DrawBuffer
->_Ymin
- destY
);
109 drawHeight
-= (ctx
->DrawBuffer
->_Ymin
- destY
);
110 destY
= ctx
->DrawBuffer
->_Ymin
;
112 if (destY
+ drawHeight
> ctx
->DrawBuffer
->_Ymax
)
113 drawHeight
-= (destY
+ drawHeight
- ctx
->DrawBuffer
->_Ymax
);
117 else if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==-1.0F
) {
118 /* upside-down image */
119 /* horizontal clipping */
120 if (destX
< ctx
->DrawBuffer
->_Xmin
) {
121 skipPixels
+= (ctx
->DrawBuffer
->_Xmin
- destX
);
122 drawWidth
-= (ctx
->DrawBuffer
->_Xmin
- destX
);
123 destX
= ctx
->DrawBuffer
->_Xmin
;
125 if (destX
+ drawWidth
> ctx
->DrawBuffer
->_Xmax
)
126 drawWidth
-= (destX
+ drawWidth
- ctx
->DrawBuffer
->_Xmax
);
130 /* vertical clipping */
131 if (destY
> ctx
->DrawBuffer
->_Ymax
) {
132 skipRows
+= (destY
- ctx
->DrawBuffer
->_Ymax
);
133 drawHeight
-= (destY
- ctx
->DrawBuffer
->_Ymax
);
134 destY
= ctx
->DrawBuffer
->_Ymax
;
136 if (destY
- drawHeight
< ctx
->DrawBuffer
->_Ymin
)
137 drawHeight
-= (ctx
->DrawBuffer
->_Ymin
- (destY
- drawHeight
));
142 if (drawWidth
> MAX_WIDTH
)
143 return GL_FALSE
; /* fall back to general case path */
145 /* save Y value of first row */
146 zoomY0
= IROUND(ctx
->Current
.RasterPos
[1]);
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.
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
) {
166 for (row
=0; row
<drawHeight
; row
++) {
167 (*swrast
->Driver
.WriteRGBASpan
)(ctx
, drawWidth
, destX
, destY
,
168 (CONST
GLchan (*)[4]) src
, NULL
);
169 src
+= rowLength
* 4;
173 else if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==-1.0F
) {
176 for (row
=0; row
<drawHeight
; row
++) {
178 (*swrast
->Driver
.WriteRGBASpan
)(ctx
, drawWidth
, destX
, destY
,
179 (CONST
GLchan (*)[4]) src
, NULL
);
180 src
+= rowLength
* 4;
186 for (row
=0; row
<drawHeight
; row
++) {
189 span
.end
= drawWidth
;
190 _swrast_write_zoomed_rgba_span(ctx
, &span
,
191 (CONST
GLchan (*)[4]) src
, zoomY0
, 0);
192 src
+= rowLength
* 4;
199 else if (format
== GL_RGB
&& type
== CHAN_TYPE
200 && ctx
->_ImageTransferState
== 0) {
201 if (ctx
->Visual
.rgbMode
) {
202 GLchan
*src
= (GLchan
*) pixels
203 + (skipRows
* rowLength
+ skipPixels
) * 3;
204 if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==1.0F
) {
206 for (row
=0; row
<drawHeight
; row
++) {
207 (*swrast
->Driver
.WriteRGBSpan
)(ctx
, drawWidth
, destX
, destY
,
208 (CONST
GLchan (*)[3]) src
, NULL
);
209 src
+= rowLength
* 3;
213 else if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==-1.0F
) {
216 for (row
=0; row
<drawHeight
; row
++) {
218 (*swrast
->Driver
.WriteRGBSpan
)(ctx
, drawWidth
, destX
, destY
,
219 (CONST
GLchan (*)[3]) src
, NULL
);
220 src
+= rowLength
* 3;
226 for (row
=0; row
<drawHeight
; row
++) {
229 span
.end
= drawWidth
;
230 _swrast_write_zoomed_rgb_span(ctx
, &span
,
231 (CONST
GLchan (*)[3]) src
, zoomY0
, 0);
232 src
+= rowLength
* 3;
239 else if (format
== GL_LUMINANCE
&& type
== CHAN_TYPE
240 && ctx
->_ImageTransferState
==0) {
241 if (ctx
->Visual
.rgbMode
) {
242 GLchan
*src
= (GLchan
*) pixels
243 + (skipRows
* rowLength
+ skipPixels
);
244 if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==1.0F
) {
247 ASSERT(drawWidth
<= MAX_WIDTH
);
248 for (row
=0; row
<drawHeight
; row
++) {
250 for (i
=0;i
<drawWidth
;i
++) {
251 span
.array
->rgb
[i
][0] = src
[i
];
252 span
.array
->rgb
[i
][1] = src
[i
];
253 span
.array
->rgb
[i
][2] = src
[i
];
255 (*swrast
->Driver
.WriteRGBSpan
)(ctx
, drawWidth
, destX
, destY
,
256 (CONST
GLchan (*)[3]) span
.array
->rgb
, NULL
);
261 else if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==-1.0F
) {
264 ASSERT(drawWidth
<= MAX_WIDTH
);
265 for (row
=0; row
<drawHeight
; row
++) {
267 for (i
=0;i
<drawWidth
;i
++) {
268 span
.array
->rgb
[i
][0] = src
[i
];
269 span
.array
->rgb
[i
][1] = src
[i
];
270 span
.array
->rgb
[i
][2] = src
[i
];
273 (*swrast
->Driver
.WriteRGBSpan
)(ctx
, drawWidth
, destX
, destY
,
274 (CONST
GLchan (*)[3]) span
.array
->rgb
, NULL
);
281 ASSERT(drawWidth
<= MAX_WIDTH
);
282 for (row
=0; row
<drawHeight
; row
++) {
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
];
291 span
.end
= drawWidth
;
292 _swrast_write_zoomed_rgb_span(ctx
, &span
,
293 (CONST
GLchan (*)[3]) span
.array
->rgb
, zoomY0
, 0);
301 else if (format
== GL_LUMINANCE_ALPHA
&& type
== CHAN_TYPE
302 && ctx
->_ImageTransferState
== 0) {
303 if (ctx
->Visual
.rgbMode
) {
304 GLchan
*src
= (GLchan
*) pixels
305 + (skipRows
* rowLength
+ skipPixels
)*2;
306 if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==1.0F
) {
309 ASSERT(drawWidth
<= MAX_WIDTH
);
310 for (row
=0; row
<drawHeight
; row
++) {
313 for (i
=0;i
<drawWidth
;i
++) {
314 span
.array
->rgba
[i
][0] = *ptr
;
315 span
.array
->rgba
[i
][1] = *ptr
;
316 span
.array
->rgba
[i
][2] = *ptr
++;
317 span
.array
->rgba
[i
][3] = *ptr
++;
319 (*swrast
->Driver
.WriteRGBASpan
)(ctx
, drawWidth
, destX
, destY
,
320 (CONST
GLchan (*)[4]) span
.array
->rgba
, NULL
);
325 else if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==-1.0F
) {
328 ASSERT(drawWidth
<= MAX_WIDTH
);
329 for (row
=0; row
<drawHeight
; row
++) {
332 for (i
=0;i
<drawWidth
;i
++) {
333 span
.array
->rgba
[i
][0] = *ptr
;
334 span
.array
->rgba
[i
][1] = *ptr
;
335 span
.array
->rgba
[i
][2] = *ptr
++;
336 span
.array
->rgba
[i
][3] = *ptr
++;
339 (*swrast
->Driver
.WriteRGBASpan
)(ctx
, drawWidth
, destX
, destY
,
340 (CONST
GLchan (*)[4]) span
.array
->rgba
, NULL
);
347 ASSERT(drawWidth
<= MAX_WIDTH
);
348 for (row
=0; row
<drawHeight
; row
++) {
351 for (i
=0;i
<drawWidth
;i
++) {
352 span
.array
->rgba
[i
][0] = *ptr
;
353 span
.array
->rgba
[i
][1] = *ptr
;
354 span
.array
->rgba
[i
][2] = *ptr
++;
355 span
.array
->rgba
[i
][3] = *ptr
++;
359 span
.end
= drawWidth
;
360 _swrast_write_zoomed_rgba_span(ctx
, &span
,
361 (CONST
GLchan (*)[4]) span
.array
->rgba
, zoomY0
, 0);
369 else if (format
==GL_COLOR_INDEX
&& type
==GL_UNSIGNED_BYTE
) {
370 GLubyte
*src
= (GLubyte
*) pixels
+ skipRows
* rowLength
+ skipPixels
;
371 if (ctx
->Visual
.rgbMode
) {
372 /* convert CI data to RGBA */
373 if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==1.0F
) {
376 for (row
=0; row
<drawHeight
; row
++) {
377 ASSERT(drawWidth
<= MAX_WIDTH
);
378 _mesa_map_ci8_to_rgba(ctx
, drawWidth
, src
, span
.array
->rgba
);
379 (*swrast
->Driver
.WriteRGBASpan
)(ctx
, drawWidth
, destX
, destY
,
380 (const GLchan (*)[4]) span
.array
->rgba
, NULL
);
386 else if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==-1.0F
) {
389 for (row
=0; row
<drawHeight
; row
++) {
390 ASSERT(drawWidth
<= MAX_WIDTH
);
391 _mesa_map_ci8_to_rgba(ctx
, drawWidth
, src
, span
.array
->rgba
);
393 (*swrast
->Driver
.WriteRGBASpan
)(ctx
, drawWidth
, destX
, destY
,
394 (CONST
GLchan (*)[4]) span
.array
->rgba
, NULL
);
402 for (row
=0; row
<drawHeight
; row
++) {
403 ASSERT(drawWidth
<= MAX_WIDTH
);
404 _mesa_map_ci8_to_rgba(ctx
, drawWidth
, src
, span
.array
->rgba
);
407 span
.end
= drawWidth
;
408 _swrast_write_zoomed_rgba_span(ctx
, &span
,
409 (CONST
GLchan (*)[4]) span
.array
->rgba
, zoomY0
, 0);
416 else if (ctx
->_ImageTransferState
==0) {
417 /* write CI data to CI frame buffer */
419 if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==1.0F
) {
421 for (row
=0; row
<drawHeight
; row
++) {
422 (*swrast
->Driver
.WriteCI8Span
)(ctx
, drawWidth
, destX
, destY
,
436 /* can't handle this pixel format and/or data type here */
441 /* can't do a simple draw, have to use slow path */
448 * Draw color index image.
451 draw_index_pixels( GLcontext
*ctx
, GLint x
, GLint y
,
452 GLsizei width
, GLsizei height
,
454 const struct gl_pixelstore_attrib
*unpack
,
455 const GLvoid
*pixels
)
457 const GLboolean zoom
= ctx
->Pixel
.ZoomX
!=1.0 || ctx
->Pixel
.ZoomY
!=1.0;
458 GLint row
, skipPixels
;
461 INIT_SPAN(span
, GL_BITMAP
, 0, 0, SPAN_INDEX
);
464 _swrast_span_default_z(ctx
, &span
);
465 if (ctx
->Fog
.Enabled
)
466 _swrast_span_default_fog(ctx
, &span
);
472 while (skipPixels
< width
) {
473 const GLint spanX
= x
+ (zoom
? 0 : skipPixels
);
475 const GLint spanEnd
= (width
- skipPixels
> MAX_WIDTH
)
476 ? MAX_WIDTH
: (width
- skipPixels
);
477 ASSERT(spanEnd
<= MAX_WIDTH
);
478 for (row
= 0; row
< height
; row
++, spanY
++) {
479 const GLvoid
*source
= _mesa_image_address2d(unpack
, pixels
,
481 GL_COLOR_INDEX
, type
,
483 _mesa_unpack_index_span(ctx
, spanEnd
, GL_UNSIGNED_INT
,
484 span
.array
->index
, type
, source
, unpack
,
485 ctx
->_ImageTransferState
);
487 /* These may get changed during writing/clipping */
493 _swrast_write_zoomed_index_span(ctx
, &span
, y
, skipPixels
);
495 _swrast_write_index_span(ctx
, &span
);
497 skipPixels
+= spanEnd
;
504 * Draw stencil image.
507 draw_stencil_pixels( GLcontext
*ctx
, GLint x
, GLint y
,
508 GLsizei width
, GLsizei height
,
510 const struct gl_pixelstore_attrib
*unpack
,
511 const GLvoid
*pixels
)
513 const GLboolean zoom
= ctx
->Pixel
.ZoomX
!=1.0 || ctx
->Pixel
.ZoomY
!=1.0;
514 const GLint desty
= y
;
515 GLint row
, skipPixels
;
517 if (type
!= GL_BYTE
&&
518 type
!= GL_UNSIGNED_BYTE
&&
520 type
!= GL_UNSIGNED_SHORT
&&
522 type
!= GL_UNSIGNED_INT
&&
525 _mesa_error( ctx
, GL_INVALID_ENUM
, "glDrawPixels(stencil type)");
529 if (ctx
->Visual
.stencilBits
== 0) {
530 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glDrawPixels(no stencil buffer)");
534 /* if width > MAX_WIDTH, have to process image in chunks */
536 while (skipPixels
< width
) {
537 const GLint spanX
= x
;
539 const GLint spanWidth
= (width
- skipPixels
> MAX_WIDTH
)
540 ? MAX_WIDTH
: (width
- skipPixels
);
542 for (row
= 0; row
< height
; row
++, spanY
++) {
543 GLstencil values
[MAX_WIDTH
];
544 GLenum destType
= (sizeof(GLstencil
) == sizeof(GLubyte
))
545 ? GL_UNSIGNED_BYTE
: GL_UNSIGNED_SHORT
;
546 const GLvoid
*source
= _mesa_image_address2d(unpack
, pixels
,
548 GL_COLOR_INDEX
, type
,
550 _mesa_unpack_index_span(ctx
, spanWidth
, destType
, values
,
551 type
, source
, unpack
,
552 ctx
->_ImageTransferState
);
553 if (ctx
->_ImageTransferState
& IMAGE_SHIFT_OFFSET_BIT
) {
554 _mesa_shift_and_offset_stencil(ctx
, spanWidth
, values
);
556 if (ctx
->Pixel
.MapStencilFlag
) {
557 _mesa_map_stencil(ctx
, spanWidth
, values
);
561 _swrast_write_zoomed_stencil_span(ctx
, (GLuint
) spanWidth
,
562 spanX
, spanY
, values
, desty
, 0);
565 _swrast_write_stencil_span(ctx
, (GLuint
) spanWidth
,
566 spanX
, spanY
, values
);
569 skipPixels
+= spanWidth
;
578 draw_depth_pixels( GLcontext
*ctx
, GLint x
, GLint y
,
579 GLsizei width
, GLsizei height
,
581 const struct gl_pixelstore_attrib
*unpack
,
582 const GLvoid
*pixels
)
584 const GLboolean bias_or_scale
= ctx
->Pixel
.DepthBias
!=0.0 || ctx
->Pixel
.DepthScale
!=1.0;
585 const GLboolean zoom
= ctx
->Pixel
.ZoomX
!= 1.0 || ctx
->Pixel
.ZoomY
!= 1.0;
586 const GLint desty
= y
;
589 INIT_SPAN(span
, GL_BITMAP
, 0, 0, SPAN_Z
);
592 && type
!= GL_UNSIGNED_BYTE
594 && type
!= GL_UNSIGNED_SHORT
596 && type
!= GL_UNSIGNED_INT
597 && type
!= GL_FLOAT
) {
598 _mesa_error(ctx
, GL_INVALID_ENUM
, "glDrawPixels(type)");
602 _swrast_span_default_color(ctx
, &span
);
604 if (ctx
->Fog
.Enabled
)
605 _swrast_span_default_fog(ctx
, &span
);
606 if (ctx
->Texture
._EnabledCoordUnits
)
607 _swrast_span_default_texcoords(ctx
, &span
);
609 if (type
== GL_UNSIGNED_SHORT
610 && ctx
->Visual
.depthBits
== 16
613 && ctx
->Visual
.rgbMode
614 && width
<= MAX_WIDTH
) {
615 /* Special case: directly write 16-bit depth values */
616 GLint row
, spanY
= y
;
617 for (row
= 0; row
< height
; row
++, spanY
++) {
618 const GLushort
*zSrc
= (const GLushort
*)
619 _mesa_image_address2d(unpack
, pixels
, width
, height
,
620 GL_DEPTH_COMPONENT
, type
, row
, 0);
622 for (i
= 0; i
< width
; i
++)
623 span
.array
->z
[i
] = zSrc
[i
];
627 _swrast_write_rgba_span(ctx
, &span
);
630 else if (type
== GL_UNSIGNED_INT
631 && sizeof(GLdepth
) == 4
634 && ctx
->Visual
.rgbMode
635 && width
<= MAX_WIDTH
) {
636 /* Special case: shift 32-bit values down to ctx->Visual.depthBits */
637 const GLint shift
= 32 - ctx
->Visual
.depthBits
;
638 GLint row
, spanY
= y
;
639 for (row
= 0; row
< height
; row
++, spanY
++) {
640 const GLuint
*zSrc
= (const GLuint
*)
641 _mesa_image_address2d(unpack
, pixels
, width
, height
,
642 GL_DEPTH_COMPONENT
, type
, row
, 0);
644 MEMCPY(span
.array
->z
, zSrc
, width
* sizeof(GLdepth
));
648 for (col
= 0; col
< width
; col
++)
649 span
.array
->z
[col
] = zSrc
[col
] >> shift
;
654 _swrast_write_rgba_span(ctx
, &span
);
659 GLint row
, skipPixels
= 0;
661 /* in case width > MAX_WIDTH do the copy in chunks */
662 while (skipPixels
< width
) {
663 const GLint spanX
= x
+ (zoom
? 0 : skipPixels
);
665 const GLint spanEnd
= (width
- skipPixels
> MAX_WIDTH
)
666 ? MAX_WIDTH
: (width
- skipPixels
);
667 ASSERT(span
.end
<= MAX_WIDTH
);
668 for (row
= 0; row
< height
; row
++, spanY
++) {
669 GLfloat floatSpan
[MAX_WIDTH
];
670 const GLvoid
*zSrc
= _mesa_image_address2d(unpack
,
671 pixels
, width
, height
,
672 GL_DEPTH_COMPONENT
, type
,
675 /* Set these for each row since the _swrast_write_* function may
676 * change them while clipping.
682 _mesa_unpack_depth_span(ctx
, span
.end
, floatSpan
, type
,
684 /* clamp depth values to [0,1] and convert from floats to ints */
686 const GLfloat zScale
= ctx
->DepthMaxF
;
688 for (i
= 0; i
< span
.end
; i
++) {
689 span
.array
->z
[i
] = (GLdepth
) (floatSpan
[i
] * zScale
);
693 _swrast_write_zoomed_depth_span(ctx
, &span
, desty
, skipPixels
);
695 else if (ctx
->Visual
.rgbMode
) {
696 _swrast_write_rgba_span(ctx
, &span
);
699 _swrast_write_index_span(ctx
, &span
);
702 skipPixels
+= spanEnd
;
713 draw_rgba_pixels( GLcontext
*ctx
, GLint x
, GLint y
,
714 GLsizei width
, GLsizei height
,
715 GLenum format
, GLenum type
,
716 const struct gl_pixelstore_attrib
*unpack
,
717 const GLvoid
*pixels
)
719 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
720 const GLboolean zoom
= ctx
->Pixel
.ZoomX
!=1.0 || ctx
->Pixel
.ZoomY
!=1.0;
721 const GLint desty
= y
;
723 GLfloat
*convImage
= NULL
;
724 GLuint transferOps
= ctx
->_ImageTransferState
;
727 INIT_SPAN(span
, GL_BITMAP
, 0, 0, SPAN_RGBA
);
729 if (!_mesa_is_legal_format_and_type(ctx
, format
, type
)) {
730 _mesa_error(ctx
, GL_INVALID_ENUM
, "glDrawPixels(format or type)");
734 /* Try an optimized glDrawPixels first */
735 if (fast_draw_pixels(ctx
, x
, y
, width
, height
, format
, type
, unpack
, pixels
))
739 _swrast_span_default_z(ctx
, &span
);
740 if (ctx
->Fog
.Enabled
)
741 _swrast_span_default_fog(ctx
, &span
);
742 if (ctx
->Texture
._EnabledCoordUnits
)
743 _swrast_span_default_texcoords(ctx
, &span
);
745 if (SWRAST_CONTEXT(ctx
)->_RasterMask
== 0 && !zoom
&& x
>= 0 && y
>= 0
746 && x
+ width
<= (GLint
) ctx
->DrawBuffer
->Width
747 && y
+ height
<= (GLint
) ctx
->DrawBuffer
->Height
) {
751 quickDraw
= GL_FALSE
;
754 if (ctx
->Pixel
.Convolution2DEnabled
|| ctx
->Pixel
.Separable2DEnabled
) {
755 /* Convolution has to be handled specially. We'll create an
756 * intermediate image, applying all pixel transfer operations
757 * up to convolution. Then we'll convolve the image. Then
758 * we'll proceed with the rest of the transfer operations and
759 * rasterize the image.
762 GLfloat
*dest
, *tmpImage
;
764 tmpImage
= (GLfloat
*) _mesa_malloc(width
* height
* 4 * sizeof(GLfloat
));
766 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glDrawPixels");
769 convImage
= (GLfloat
*) _mesa_malloc(width
* height
* 4 * sizeof(GLfloat
));
771 _mesa_free(tmpImage
);
772 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glDrawPixels");
776 /* Unpack the image and apply transfer ops up to convolution */
778 for (row
= 0; row
< height
; row
++) {
779 const GLvoid
*source
= _mesa_image_address2d(unpack
,
780 pixels
, width
, height
, format
, type
, row
, 0);
781 _mesa_unpack_color_span_float(ctx
, width
, GL_RGBA
, (GLfloat
*) dest
,
782 format
, type
, source
, unpack
,
783 transferOps
& IMAGE_PRE_CONVOLUTION_BITS
);
788 if (ctx
->Pixel
.Convolution2DEnabled
) {
789 _mesa_convolve_2d_image(ctx
, &width
, &height
, tmpImage
, convImage
);
792 ASSERT(ctx
->Pixel
.Separable2DEnabled
);
793 _mesa_convolve_sep_image(ctx
, &width
, &height
, tmpImage
, convImage
);
795 _mesa_free(tmpImage
);
797 /* continue transfer ops and draw the convolved image */
798 unpack
= &ctx
->DefaultPacking
;
802 transferOps
&= IMAGE_POST_CONVOLUTION_BITS
;
809 const GLuint interpMask
= span
.interpMask
;
810 const GLuint arrayMask
= span
.arrayMask
;
811 GLint row
, skipPixels
= 0;
813 /* if the span is wider than MAX_WIDTH we have to do it in chunks */
814 while (skipPixels
< width
) {
815 const GLint spanX
= x
+ (zoom
? 0 : skipPixels
);
817 const GLint spanEnd
= (width
- skipPixels
> MAX_WIDTH
)
818 ? MAX_WIDTH
: (width
- skipPixels
);
819 ASSERT(span
.end
<= MAX_WIDTH
);
821 for (row
= 0; row
< height
; row
++, spanY
++) {
822 const GLvoid
*source
= _mesa_image_address2d(unpack
,
823 pixels
, width
, height
, format
, type
, row
, skipPixels
);
825 /* Set these for each row since the _swrast_write_* function may
826 * change them while clipping.
831 span
.arrayMask
= arrayMask
;
832 span
.interpMask
= interpMask
;
834 _mesa_unpack_color_span_chan(ctx
, span
.end
, GL_RGBA
,
835 (GLchan
*) span
.array
->rgba
,
836 format
, type
, source
, unpack
,
839 if ((ctx
->Pixel
.MinMaxEnabled
&& ctx
->MinMax
.Sink
) ||
840 (ctx
->Pixel
.HistogramEnabled
&& ctx
->Histogram
.Sink
))
843 if (ctx
->Pixel
.PixelTextureEnabled
&& ctx
->Texture
._EnabledUnits
) {
844 _swrast_pixel_texture(ctx
, &span
);
849 (*swrast
->Driver
.WriteRGBASpan
)(ctx
, span
.end
, span
.x
, span
.y
,
850 (CONST
GLchan (*)[4]) span
.array
->rgba
, NULL
);
853 _swrast_write_zoomed_rgba_span(ctx
, &span
,
854 (CONST
GLchan (*)[4]) span
.array
->rgba
, desty
, skipPixels
);
857 _swrast_write_rgba_span(ctx
, &span
);
861 skipPixels
+= spanEnd
;
866 _mesa_free(convImage
);
873 * Execute glDrawPixels
876 _swrast_DrawPixels( GLcontext
*ctx
,
878 GLsizei width
, GLsizei height
,
879 GLenum format
, GLenum type
,
880 const struct gl_pixelstore_attrib
*unpack
,
881 const GLvoid
*pixels
)
883 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
885 if (swrast
->NewState
)
886 _swrast_validate_derived( ctx
);
888 if (unpack
->BufferObj
->Name
) {
889 /* unpack from PBO */
891 if (!_mesa_validate_pbo_access(2, unpack
, width
, height
, 1,
892 format
, type
, pixels
)) {
893 _mesa_error(ctx
, GL_INVALID_OPERATION
,
894 "glDrawPixels(invalid PBO access)");
897 buf
= (GLubyte
*) ctx
->Driver
.MapBuffer(ctx
, GL_PIXEL_UNPACK_BUFFER_EXT
,
901 /* buffer is already mapped - that's an error */
902 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glDrawPixels(PBO is mapped)");
905 pixels
= ADD_POINTERS(buf
, pixels
);
908 RENDER_START(swrast
,ctx
);
911 case GL_STENCIL_INDEX
:
912 draw_stencil_pixels( ctx
, x
, y
, width
, height
, type
, unpack
, pixels
);
914 case GL_DEPTH_COMPONENT
:
915 draw_depth_pixels( ctx
, x
, y
, width
, height
, type
, unpack
, pixels
);
918 if (ctx
->Visual
.rgbMode
)
919 draw_rgba_pixels(ctx
, x
,y
, width
, height
, format
, type
, unpack
, pixels
);
921 draw_index_pixels(ctx
, x
, y
, width
, height
, type
, unpack
, pixels
);
928 case GL_LUMINANCE_ALPHA
:
934 draw_rgba_pixels(ctx
, x
, y
, width
, height
, format
, type
, unpack
, pixels
);
937 _mesa_error( ctx
, GL_INVALID_ENUM
, "glDrawPixels(format)" );
938 /* don't return yet, clean-up */
941 RENDER_FINISH(swrast
,ctx
);
943 if (unpack
->BufferObj
->Name
) {
944 /* done with PBO so unmap it now */
945 ctx
->Driver
.UnmapBuffer(ctx
, GL_PIXEL_UNPACK_BUFFER_EXT
,
952 #if 0 /* experimental */
954 * Execute glDrawDepthPixelsMESA().
957 _swrast_DrawDepthPixelsMESA( GLcontext
*ctx
,
959 GLsizei width
, GLsizei height
,
960 GLenum colorFormat
, GLenum colorType
,
961 const GLvoid
*colors
,
962 GLenum depthType
, const GLvoid
*depths
,
963 const struct gl_pixelstore_attrib
*unpack
)
965 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
967 if (swrast
->NewState
)
968 _swrast_validate_derived( ctx
);
970 RENDER_START(swrast
,ctx
);
972 switch (colorFormat
) {
974 if (ctx
->Visual
.rgbMode
)
975 draw_rgba_pixels(ctx
, x
,y
, width
, height
, colorFormat
, colorType
, unpack
, colors
);
977 draw_index_pixels(ctx
, x
, y
, width
, height
, colorType
, unpack
, colors
);
984 case GL_LUMINANCE_ALPHA
:
990 draw_rgba_pixels(ctx
, x
, y
, width
, height
, colorFormat
, colorType
, unpack
, colors
);
993 _mesa_error( ctx
, GL_INVALID_ENUM
,
994 "glDrawDepthPixelsMESA(colorFormat)" );
997 RENDER_FINISH(swrast
,ctx
);