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