5b0a24bfb295bc9b8aa85c39a3db981d8cc7f555
[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 SWcontext *swrast = SWRAST_CONTEXT(ctx);
55 struct sw_span span;
56
57 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA);
58
59 if (!ctx->Current.RasterPosValid) {
60 return GL_TRUE; /* no-op */
61 }
62
63 if (ctx->Depth.Test)
64 _swrast_span_default_z(ctx, &span);
65 if (ctx->Fog.Enabled)
66 _swrast_span_default_fog(ctx, &span);
67 if (ctx->Texture._EnabledCoordUnits)
68 _swrast_span_default_texcoords(ctx, &span);
69
70 if ((SWRAST_CONTEXT(ctx)->_RasterMask & ~CLIP_BIT) == 0
71 && ctx->Texture._EnabledCoordUnits == 0
72 && unpack->Alignment == 1
73 && !unpack->SwapBytes
74 && !unpack->LsbFirst) {
75
76 GLint destX = x;
77 GLint destY = y;
78 GLint drawWidth = width; /* actual width drawn */
79 GLint drawHeight = height; /* actual height drawn */
80 GLint skipPixels = unpack->SkipPixels;
81 GLint skipRows = unpack->SkipRows;
82 GLint rowLength;
83 GLint zoomY0 = 0;
84
85 if (unpack->RowLength > 0)
86 rowLength = unpack->RowLength;
87 else
88 rowLength = width;
89
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.
93 */
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;
100 }
101 if (destX + drawWidth > ctx->DrawBuffer->_Xmax)
102 drawWidth -= (destX + drawWidth - ctx->DrawBuffer->_Xmax);
103 if (drawWidth <= 0)
104 return GL_TRUE;
105
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;
111 }
112 if (destY + drawHeight > ctx->DrawBuffer->_Ymax)
113 drawHeight -= (destY + drawHeight - ctx->DrawBuffer->_Ymax);
114 if (drawHeight <= 0)
115 return GL_TRUE;
116 }
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;
124 }
125 if (destX + drawWidth > ctx->DrawBuffer->_Xmax)
126 drawWidth -= (destX + drawWidth - ctx->DrawBuffer->_Xmax);
127 if (drawWidth <= 0)
128 return GL_TRUE;
129
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;
135 }
136 if (destY - drawHeight < ctx->DrawBuffer->_Ymin)
137 drawHeight -= (ctx->DrawBuffer->_Ymin - (destY - drawHeight));
138 if (drawHeight <= 0)
139 return GL_TRUE;
140 }
141 else {
142 if (drawWidth > MAX_WIDTH)
143 return GL_FALSE; /* fall back to general case path */
144
145 /* save Y value of first row */
146 zoomY0 = IROUND(ctx->Current.RasterPos[1]);
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 (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
168 (CONST GLchan (*)[4]) src, NULL);
169 src += rowLength * 4;
170 destY++;
171 }
172 }
173 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
174 /* upside-down */
175 GLint row;
176 for (row=0; row<drawHeight; row++) {
177 destY--;
178 (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
179 (CONST GLchan (*)[4]) src, NULL);
180 src += rowLength * 4;
181 }
182 }
183 else {
184 /* with zooming */
185 GLint row;
186 for (row=0; row<drawHeight; row++) {
187 span.x = destX;
188 span.y = destY;
189 span.end = drawWidth;
190 _swrast_write_zoomed_rgba_span(ctx, &span,
191 (CONST GLchan (*)[4]) src, zoomY0, 0);
192 src += rowLength * 4;
193 destY++;
194 }
195 }
196 }
197 return GL_TRUE;
198 }
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) {
205 GLint row;
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;
210 destY++;
211 }
212 }
213 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
214 /* upside-down */
215 GLint row;
216 for (row=0; row<drawHeight; row++) {
217 destY--;
218 (*swrast->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
219 (CONST GLchan (*)[3]) src, NULL);
220 src += rowLength * 3;
221 }
222 }
223 else {
224 /* with zooming */
225 GLint row;
226 for (row=0; row<drawHeight; row++) {
227 span.x = destX;
228 span.y = destY;
229 span.end = drawWidth;
230 _swrast_write_zoomed_rgb_span(ctx, &span,
231 (CONST GLchan (*)[3]) src, zoomY0, 0);
232 src += rowLength * 3;
233 destY++;
234 }
235 }
236 }
237 return GL_TRUE;
238 }
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) {
245 /* no zooming */
246 GLint row;
247 ASSERT(drawWidth <= MAX_WIDTH);
248 for (row=0; row<drawHeight; row++) {
249 GLint i;
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];
254 }
255 (*swrast->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
256 (CONST GLchan (*)[3]) span.array->rgb, NULL);
257 src += rowLength;
258 destY++;
259 }
260 }
261 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
262 /* upside-down */
263 GLint row;
264 ASSERT(drawWidth <= MAX_WIDTH);
265 for (row=0; row<drawHeight; row++) {
266 GLint i;
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];
271 }
272 destY--;
273 (*swrast->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
274 (CONST GLchan (*)[3]) span.array->rgb, NULL);
275 src += rowLength;
276 }
277 }
278 else {
279 /* with 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 span.x = destX;
290 span.y = destY;
291 span.end = drawWidth;
292 _swrast_write_zoomed_rgb_span(ctx, &span,
293 (CONST GLchan (*)[3]) span.array->rgb, zoomY0, 0);
294 src += rowLength;
295 destY++;
296 }
297 }
298 }
299 return GL_TRUE;
300 }
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) {
307 /* no zooming */
308 GLint row;
309 ASSERT(drawWidth <= MAX_WIDTH);
310 for (row=0; row<drawHeight; row++) {
311 GLint i;
312 GLchan *ptr = src;
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++;
318 }
319 (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
320 (CONST GLchan (*)[4]) span.array->rgba, NULL);
321 src += rowLength*2;
322 destY++;
323 }
324 }
325 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
326 /* upside-down */
327 GLint row;
328 ASSERT(drawWidth <= MAX_WIDTH);
329 for (row=0; row<drawHeight; row++) {
330 GLint i;
331 GLchan *ptr = src;
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++;
337 }
338 destY--;
339 (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
340 (CONST GLchan (*)[4]) span.array->rgba, NULL);
341 src += rowLength*2;
342 }
343 }
344 else {
345 /* with zooming */
346 GLint row;
347 ASSERT(drawWidth <= MAX_WIDTH);
348 for (row=0; row<drawHeight; row++) {
349 GLchan *ptr = src;
350 GLint i;
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++;
356 }
357 span.x = destX;
358 span.y = destY;
359 span.end = drawWidth;
360 _swrast_write_zoomed_rgba_span(ctx, &span,
361 (CONST GLchan (*)[4]) span.array->rgba, zoomY0, 0);
362 src += rowLength*2;
363 destY++;
364 }
365 }
366 }
367 return GL_TRUE;
368 }
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) {
374 /* no zooming */
375 GLint row;
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);
381 src += rowLength;
382 destY++;
383 }
384 return GL_TRUE;
385 }
386 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
387 /* upside-down */
388 GLint row;
389 for (row=0; row<drawHeight; row++) {
390 ASSERT(drawWidth <= MAX_WIDTH);
391 _mesa_map_ci8_to_rgba(ctx, drawWidth, src, span.array->rgba);
392 destY--;
393 (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
394 (CONST GLchan (*)[4]) span.array->rgba, NULL);
395 src += rowLength;
396 }
397 return GL_TRUE;
398 }
399 else {
400 /* with zooming */
401 GLint row;
402 for (row=0; row<drawHeight; row++) {
403 ASSERT(drawWidth <= MAX_WIDTH);
404 _mesa_map_ci8_to_rgba(ctx, drawWidth, src, span.array->rgba);
405 span.x = destX;
406 span.y = destY;
407 span.end = drawWidth;
408 _swrast_write_zoomed_rgba_span(ctx, &span,
409 (CONST GLchan (*)[4]) span.array->rgba, zoomY0, 0);
410 src += rowLength;
411 destY++;
412 }
413 return GL_TRUE;
414 }
415 }
416 else if (ctx->_ImageTransferState==0) {
417 /* write CI data to CI frame buffer */
418 GLint row;
419 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
420 /* no zooming */
421 for (row=0; row<drawHeight; row++) {
422 (*swrast->Driver.WriteCI8Span)(ctx, drawWidth, destX, destY,
423 src, NULL);
424 src += rowLength;
425 destY++;
426 }
427 return GL_TRUE;
428 }
429 else {
430 /* with zooming */
431 return GL_FALSE;
432 }
433 }
434 }
435 else {
436 /* can't handle this pixel format and/or data type here */
437 return GL_FALSE;
438 }
439 }
440
441 /* can't do a simple draw, have to use slow path */
442 return GL_FALSE;
443 }
444
445
446
447 /*
448 * Draw color index image.
449 */
450 static void
451 draw_index_pixels( GLcontext *ctx, GLint x, GLint y,
452 GLsizei width, GLsizei height,
453 GLenum type,
454 const struct gl_pixelstore_attrib *unpack,
455 const GLvoid *pixels )
456 {
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 (ctx->Fog.Enabled)
466 _swrast_span_default_fog(ctx, &span);
467
468 /*
469 * General solution
470 */
471 skipPixels = 0;
472 while (skipPixels < width) {
473 const GLint spanX = x + (zoom ? 0 : skipPixels);
474 GLint spanY = y;
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,
480 width, height,
481 GL_COLOR_INDEX, type,
482 row, skipPixels);
483 _mesa_unpack_index_span(ctx, spanEnd, GL_UNSIGNED_INT,
484 span.array->index, type, source, unpack,
485 ctx->_ImageTransferState);
486
487 /* These may get changed during writing/clipping */
488 span.x = spanX;
489 span.y = spanY;
490 span.end = spanEnd;
491
492 if (zoom)
493 _swrast_write_zoomed_index_span(ctx, &span, y, skipPixels);
494 else
495 _swrast_write_index_span(ctx, &span);
496 }
497 skipPixels += spanEnd;
498 }
499 }
500
501
502
503 /*
504 * Draw stencil image.
505 */
506 static void
507 draw_stencil_pixels( GLcontext *ctx, GLint x, GLint y,
508 GLsizei width, GLsizei height,
509 GLenum type,
510 const struct gl_pixelstore_attrib *unpack,
511 const GLvoid *pixels )
512 {
513 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
514 const GLint desty = y;
515 GLint row, skipPixels;
516
517 if (type != GL_BYTE &&
518 type != GL_UNSIGNED_BYTE &&
519 type != GL_SHORT &&
520 type != GL_UNSIGNED_SHORT &&
521 type != GL_INT &&
522 type != GL_UNSIGNED_INT &&
523 type != GL_FLOAT &&
524 type != GL_BITMAP) {
525 _mesa_error( ctx, GL_INVALID_ENUM, "glDrawPixels(stencil type)");
526 return;
527 }
528
529 if (ctx->Visual.stencilBits == 0) {
530 _mesa_error( ctx, GL_INVALID_OPERATION, "glDrawPixels(no stencil buffer)");
531 return;
532 }
533
534 /* if width > MAX_WIDTH, have to process image in chunks */
535 skipPixels = 0;
536 while (skipPixels < width) {
537 const GLint spanX = x;
538 GLint spanY = y;
539 const GLint spanWidth = (width - skipPixels > MAX_WIDTH)
540 ? MAX_WIDTH : (width - skipPixels);
541
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,
547 width, height,
548 GL_COLOR_INDEX, type,
549 row, skipPixels);
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);
555 }
556 if (ctx->Pixel.MapStencilFlag) {
557 _mesa_map_stencil(ctx, spanWidth, values);
558 }
559
560 if (zoom) {
561 _swrast_write_zoomed_stencil_span(ctx, (GLuint) spanWidth,
562 spanX, spanY, values, desty, 0);
563 }
564 else {
565 _swrast_write_stencil_span(ctx, (GLuint) spanWidth,
566 spanX, spanY, values);
567 }
568 }
569 skipPixels += spanWidth;
570 }
571 }
572
573
574 /*
575 * Draw depth image.
576 */
577 static void
578 draw_depth_pixels( GLcontext *ctx, GLint x, GLint y,
579 GLsizei width, GLsizei height,
580 GLenum type,
581 const struct gl_pixelstore_attrib *unpack,
582 const GLvoid *pixels )
583 {
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;
587 struct sw_span span;
588
589 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_Z);
590
591 if (type != GL_BYTE
592 && type != GL_UNSIGNED_BYTE
593 && type != GL_SHORT
594 && type != GL_UNSIGNED_SHORT
595 && type != GL_INT
596 && type != GL_UNSIGNED_INT
597 && type != GL_FLOAT) {
598 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawPixels(type)");
599 return;
600 }
601
602 _swrast_span_default_color(ctx, &span);
603
604 if (ctx->Fog.Enabled)
605 _swrast_span_default_fog(ctx, &span);
606 if (ctx->Texture._EnabledCoordUnits)
607 _swrast_span_default_texcoords(ctx, &span);
608
609 if (type == GL_UNSIGNED_SHORT
610 && ctx->Visual.depthBits == 16
611 && !bias_or_scale
612 && !zoom
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);
621 GLint i;
622 for (i = 0; i < width; i++)
623 span.array->z[i] = zSrc[i];
624 span.x = x;
625 span.y = spanY;
626 span.end = width;
627 _swrast_write_rgba_span(ctx, &span);
628 }
629 }
630 else if (type == GL_UNSIGNED_INT
631 && sizeof(GLdepth) == 4
632 && !bias_or_scale
633 && !zoom
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);
643 if (shift == 0) {
644 MEMCPY(span.array->z, zSrc, width * sizeof(GLdepth));
645 }
646 else {
647 GLint col;
648 for (col = 0; col < width; col++)
649 span.array->z[col] = zSrc[col] >> shift;
650 }
651 span.x = x;
652 span.y = spanY;
653 span.end = width;
654 _swrast_write_rgba_span(ctx, &span);
655 }
656 }
657 else {
658 /* General case */
659 GLint row, skipPixels = 0;
660
661 /* in case width > MAX_WIDTH do the copy in chunks */
662 while (skipPixels < width) {
663 const GLint spanX = x + (zoom ? 0 : skipPixels);
664 GLint spanY = y;
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,
673 row, skipPixels);
674
675 /* Set these for each row since the _swrast_write_* function may
676 * change them while clipping.
677 */
678 span.x = spanX;
679 span.y = spanY;
680 span.end = spanEnd;
681
682 _mesa_unpack_depth_span(ctx, span.end, floatSpan, type,
683 zSrc, unpack);
684 /* clamp depth values to [0,1] and convert from floats to ints */
685 {
686 const GLfloat zScale = ctx->DepthMaxF;
687 GLuint i;
688 for (i = 0; i < span.end; i++) {
689 span.array->z[i] = (GLdepth) (floatSpan[i] * zScale);
690 }
691 }
692 if (zoom) {
693 _swrast_write_zoomed_depth_span(ctx, &span, desty, skipPixels);
694 }
695 else if (ctx->Visual.rgbMode) {
696 _swrast_write_rgba_span(ctx, &span);
697 }
698 else {
699 _swrast_write_index_span(ctx, &span);
700 }
701 }
702 skipPixels += spanEnd;
703 }
704 }
705 }
706
707
708
709 /*
710 * Draw RGBA image.
711 */
712 static void
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 )
718 {
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;
722 GLboolean quickDraw;
723 GLfloat *convImage = NULL;
724 GLuint transferOps = ctx->_ImageTransferState;
725 struct sw_span span;
726
727 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA);
728
729 if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
730 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawPixels(format or type)");
731 return;
732 }
733
734 /* Try an optimized glDrawPixels first */
735 if (fast_draw_pixels(ctx, x, y, width, height, format, type, unpack, pixels))
736 return;
737
738 if (ctx->Depth.Test)
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);
744
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) {
748 quickDraw = GL_TRUE;
749 }
750 else {
751 quickDraw = GL_FALSE;
752 }
753
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.
760 */
761 GLint row;
762 GLfloat *dest, *tmpImage;
763
764 tmpImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
765 if (!tmpImage) {
766 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
767 return;
768 }
769 convImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
770 if (!convImage) {
771 _mesa_free(tmpImage);
772 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
773 return;
774 }
775
776 /* Unpack the image and apply transfer ops up to convolution */
777 dest = tmpImage;
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);
784 dest += width * 4;
785 }
786
787 /* do convolution */
788 if (ctx->Pixel.Convolution2DEnabled) {
789 _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage);
790 }
791 else {
792 ASSERT(ctx->Pixel.Separable2DEnabled);
793 _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage);
794 }
795 _mesa_free(tmpImage);
796
797 /* continue transfer ops and draw the convolved image */
798 unpack = &ctx->DefaultPacking;
799 pixels = convImage;
800 format = GL_RGBA;
801 type = GL_FLOAT;
802 transferOps &= IMAGE_POST_CONVOLUTION_BITS;
803 }
804
805 /*
806 * General solution
807 */
808 {
809 const GLuint interpMask = span.interpMask;
810 const GLuint arrayMask = span.arrayMask;
811 GLint row, skipPixels = 0;
812
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);
816 GLint spanY = y;
817 const GLint spanEnd = (width - skipPixels > MAX_WIDTH)
818 ? MAX_WIDTH : (width - skipPixels);
819 ASSERT(span.end <= MAX_WIDTH);
820
821 for (row = 0; row < height; row++, spanY++) {
822 const GLvoid *source = _mesa_image_address2d(unpack,
823 pixels, width, height, format, type, row, skipPixels);
824
825 /* Set these for each row since the _swrast_write_* function may
826 * change them while clipping.
827 */
828 span.x = spanX;
829 span.y = spanY;
830 span.end = spanEnd;
831 span.arrayMask = arrayMask;
832 span.interpMask = interpMask;
833
834 _mesa_unpack_color_span_chan(ctx, span.end, GL_RGBA,
835 (GLchan *) span.array->rgba,
836 format, type, source, unpack,
837 transferOps);
838
839 if ((ctx->Pixel.MinMaxEnabled && ctx->MinMax.Sink) ||
840 (ctx->Pixel.HistogramEnabled && ctx->Histogram.Sink))
841 continue;
842
843 if (ctx->Pixel.PixelTextureEnabled && ctx->Texture._EnabledUnits) {
844 _swrast_pixel_texture(ctx, &span);
845 }
846
847 /* draw the span */
848 if (quickDraw) {
849 (*swrast->Driver.WriteRGBASpan)(ctx, span.end, span.x, span.y,
850 (CONST GLchan (*)[4]) span.array->rgba, NULL);
851 }
852 else if (zoom) {
853 _swrast_write_zoomed_rgba_span(ctx, &span,
854 (CONST GLchan (*)[4]) span.array->rgba, desty, skipPixels);
855 }
856 else {
857 _swrast_write_rgba_span(ctx, &span);
858 }
859 }
860
861 skipPixels += spanEnd;
862 }
863 }
864
865 if (convImage) {
866 _mesa_free(convImage);
867 }
868 }
869
870
871
872 /*
873 * Execute glDrawPixels
874 */
875 void
876 _swrast_DrawPixels( GLcontext *ctx,
877 GLint x, GLint y,
878 GLsizei width, GLsizei height,
879 GLenum format, GLenum type,
880 const struct gl_pixelstore_attrib *unpack,
881 const GLvoid *pixels )
882 {
883 SWcontext *swrast = SWRAST_CONTEXT(ctx);
884
885 if (swrast->NewState)
886 _swrast_validate_derived( ctx );
887
888 if (unpack->BufferObj->Name) {
889 /* unpack from PBO */
890 GLubyte *buf;
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)");
895 return;
896 }
897 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
898 GL_READ_ONLY_ARB,
899 unpack->BufferObj);
900 if (!buf) {
901 /* buffer is already mapped - that's an error */
902 _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawPixels(PBO is mapped)");
903 return;
904 }
905 pixels = ADD_POINTERS(buf, pixels);
906 }
907
908 RENDER_START(swrast,ctx);
909
910 switch (format) {
911 case GL_STENCIL_INDEX:
912 draw_stencil_pixels( ctx, x, y, width, height, type, unpack, pixels );
913 break;
914 case GL_DEPTH_COMPONENT:
915 draw_depth_pixels( ctx, x, y, width, height, type, unpack, pixels );
916 break;
917 case GL_COLOR_INDEX:
918 if (ctx->Visual.rgbMode)
919 draw_rgba_pixels(ctx, x,y, width, height, format, type, unpack, pixels);
920 else
921 draw_index_pixels(ctx, x, y, width, height, type, unpack, pixels);
922 break;
923 case GL_RED:
924 case GL_GREEN:
925 case GL_BLUE:
926 case GL_ALPHA:
927 case GL_LUMINANCE:
928 case GL_LUMINANCE_ALPHA:
929 case GL_RGB:
930 case GL_BGR:
931 case GL_RGBA:
932 case GL_BGRA:
933 case GL_ABGR_EXT:
934 draw_rgba_pixels(ctx, x, y, width, height, format, type, unpack, pixels);
935 break;
936 default:
937 _mesa_error( ctx, GL_INVALID_ENUM, "glDrawPixels(format)" );
938 /* don't return yet, clean-up */
939 }
940
941 RENDER_FINISH(swrast,ctx);
942
943 if (unpack->BufferObj->Name) {
944 /* done with PBO so unmap it now */
945 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
946 unpack->BufferObj);
947 }
948 }
949
950
951
952 #if 0 /* experimental */
953 /*
954 * Execute glDrawDepthPixelsMESA().
955 */
956 void
957 _swrast_DrawDepthPixelsMESA( GLcontext *ctx,
958 GLint x, GLint y,
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 )
964 {
965 SWcontext *swrast = SWRAST_CONTEXT(ctx);
966
967 if (swrast->NewState)
968 _swrast_validate_derived( ctx );
969
970 RENDER_START(swrast,ctx);
971
972 switch (colorFormat) {
973 case GL_COLOR_INDEX:
974 if (ctx->Visual.rgbMode)
975 draw_rgba_pixels(ctx, x,y, width, height, colorFormat, colorType, unpack, colors);
976 else
977 draw_index_pixels(ctx, x, y, width, height, colorType, unpack, colors);
978 break;
979 case GL_RED:
980 case GL_GREEN:
981 case GL_BLUE:
982 case GL_ALPHA:
983 case GL_LUMINANCE:
984 case GL_LUMINANCE_ALPHA:
985 case GL_RGB:
986 case GL_BGR:
987 case GL_RGBA:
988 case GL_BGRA:
989 case GL_ABGR_EXT:
990 draw_rgba_pixels(ctx, x, y, width, height, colorFormat, colorType, unpack, colors);
991 break;
992 default:
993 _mesa_error( ctx, GL_INVALID_ENUM,
994 "glDrawDepthPixelsMESA(colorFormat)" );
995 }
996
997 RENDER_FINISH(swrast,ctx);
998 }
999 #endif