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