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