0f7d66ad9e21ad99d0e5ac67a6a7e590f5c20552
[reactos.git] / reactos / dll / opengl / mesa / src / mesa / swrast / s_drawpix.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.1
4 *
5 * Copyright (C) 1999-2007 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 "main/glheader.h"
27 #include "main/bufferobj.h"
28 #include "main/colormac.h"
29 #include "main/context.h"
30 #include "main/format_pack.h"
31 #include "main/image.h"
32 #include "main/imports.h"
33 #include "main/macros.h"
34 #include "main/pack.h"
35 #include "main/pbo.h"
36 #include "main/pixeltransfer.h"
37 #include "main/state.h"
38
39 #include "s_context.h"
40 #include "s_span.h"
41 #include "s_stencil.h"
42 #include "s_zoom.h"
43
44
45 /**
46 * Handle a common case of drawing GL_RGB/GL_UNSIGNED_BYTE into a
47 * MESA_FORMAT_XRGB888 or MESA_FORMAT_ARGB888 renderbuffer.
48 */
49 static void
50 fast_draw_rgb_ubyte_pixels(struct gl_context *ctx,
51 struct gl_renderbuffer *rb,
52 GLint x, GLint y,
53 GLsizei width, GLsizei height,
54 const struct gl_pixelstore_attrib *unpack,
55 const GLvoid *pixels)
56 {
57 const GLubyte *src = (const GLubyte *)
58 _mesa_image_address2d(unpack, pixels, width,
59 height, GL_RGB, GL_UNSIGNED_BYTE, 0, 0);
60 const GLint srcRowStride = _mesa_image_row_stride(unpack, width,
61 GL_RGB, GL_UNSIGNED_BYTE);
62 GLint i, j;
63 GLubyte *dst;
64 GLint dstRowStride;
65
66 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height,
67 GL_MAP_WRITE_BIT, &dst, &dstRowStride);
68
69 if (!dst) {
70 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
71 return;
72 }
73
74 if (ctx->Pixel.ZoomY == -1.0f) {
75 dst = dst + (height - 1) * dstRowStride;
76 dstRowStride = -dstRowStride;
77 }
78
79 for (i = 0; i < height; i++) {
80 GLuint *dst4 = (GLuint *) dst;
81 for (j = 0; j < width; j++) {
82 dst4[j] = PACK_COLOR_8888(0xff, src[j*3+0], src[j*3+1], src[j*3+2]);
83 }
84 dst += dstRowStride;
85 src += srcRowStride;
86 }
87
88 ctx->Driver.UnmapRenderbuffer(ctx, rb);
89 }
90
91
92 /**
93 * Handle a common case of drawing GL_RGBA/GL_UNSIGNED_BYTE into a
94 * MESA_FORMAT_ARGB888 or MESA_FORMAT_xRGB888 renderbuffer.
95 */
96 static void
97 fast_draw_rgba_ubyte_pixels(struct gl_context *ctx,
98 struct gl_renderbuffer *rb,
99 GLint x, GLint y,
100 GLsizei width, GLsizei height,
101 const struct gl_pixelstore_attrib *unpack,
102 const GLvoid *pixels)
103 {
104 const GLubyte *src = (const GLubyte *)
105 _mesa_image_address2d(unpack, pixels, width,
106 height, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0);
107 const GLint srcRowStride =
108 _mesa_image_row_stride(unpack, width, GL_RGBA, GL_UNSIGNED_BYTE);
109 GLint i, j;
110 GLubyte *dst;
111 GLint dstRowStride;
112
113 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height,
114 GL_MAP_WRITE_BIT, &dst, &dstRowStride);
115
116 if (!dst) {
117 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
118 return;
119 }
120
121 if (ctx->Pixel.ZoomY == -1.0f) {
122 dst = dst + (height - 1) * dstRowStride;
123 dstRowStride = -dstRowStride;
124 }
125
126 for (i = 0; i < height; i++) {
127 GLuint *dst4 = (GLuint *) dst;
128 for (j = 0; j < width; j++) {
129 dst4[j] = PACK_COLOR_8888(src[j*4+3], src[j*4+0],
130 src[j*4+1], src[j*4+2]);
131 }
132 dst += dstRowStride;
133 src += srcRowStride;
134 }
135
136 ctx->Driver.UnmapRenderbuffer(ctx, rb);
137 }
138
139
140 /**
141 * Handle a common case of drawing a format/type combination that
142 * exactly matches the renderbuffer format.
143 */
144 static void
145 fast_draw_generic_pixels(struct gl_context *ctx,
146 struct gl_renderbuffer *rb,
147 GLint x, GLint y,
148 GLsizei width, GLsizei height,
149 GLenum format, GLenum type,
150 const struct gl_pixelstore_attrib *unpack,
151 const GLvoid *pixels)
152 {
153 const GLubyte *src = (const GLubyte *)
154 _mesa_image_address2d(unpack, pixels, width,
155 height, format, type, 0, 0);
156 const GLint srcRowStride =
157 _mesa_image_row_stride(unpack, width, format, type);
158 const GLint rowLength = width * _mesa_get_format_bytes(rb->Format);
159 GLint i;
160 GLubyte *dst;
161 GLint dstRowStride;
162
163 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height,
164 GL_MAP_WRITE_BIT, &dst, &dstRowStride);
165
166 if (!dst) {
167 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
168 return;
169 }
170
171 if (ctx->Pixel.ZoomY == -1.0f) {
172 dst = dst + (height - 1) * dstRowStride;
173 dstRowStride = -dstRowStride;
174 }
175
176 for (i = 0; i < height; i++) {
177 memcpy(dst, src, rowLength);
178 dst += dstRowStride;
179 src += srcRowStride;
180 }
181
182 ctx->Driver.UnmapRenderbuffer(ctx, rb);
183 }
184
185
186 /**
187 * Try to do a fast and simple RGB(a) glDrawPixels.
188 * Return: GL_TRUE if success, GL_FALSE if slow path must be used instead
189 */
190 static GLboolean
191 fast_draw_rgba_pixels(struct gl_context *ctx, GLint x, GLint y,
192 GLsizei width, GLsizei height,
193 GLenum format, GLenum type,
194 const struct gl_pixelstore_attrib *userUnpack,
195 const GLvoid *pixels)
196 {
197 struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0];
198 SWcontext *swrast = SWRAST_CONTEXT(ctx);
199 struct gl_pixelstore_attrib unpack;
200
201 if (!rb)
202 return GL_TRUE; /* no-op */
203
204 if (ctx->DrawBuffer->_NumColorDrawBuffers > 1 ||
205 (swrast->_RasterMask & ~CLIP_BIT) ||
206 ctx->Texture._EnabledCoordUnits ||
207 userUnpack->SwapBytes ||
208 ctx->Pixel.ZoomX != 1.0f ||
209 fabsf(ctx->Pixel.ZoomY) != 1.0f ||
210 ctx->_ImageTransferState) {
211 /* can't handle any of those conditions */
212 return GL_FALSE;
213 }
214
215 unpack = *userUnpack;
216
217 /* clipping */
218 if (!_mesa_clip_drawpixels(ctx, &x, &y, &width, &height, &unpack)) {
219 /* image was completely clipped: no-op, all done */
220 return GL_TRUE;
221 }
222
223 if (format == GL_RGB &&
224 type == GL_UNSIGNED_BYTE &&
225 (rb->Format == MESA_FORMAT_XRGB8888 ||
226 rb->Format == MESA_FORMAT_ARGB8888)) {
227 fast_draw_rgb_ubyte_pixels(ctx, rb, x, y, width, height,
228 &unpack, pixels);
229 return GL_TRUE;
230 }
231
232 if (format == GL_RGBA &&
233 type == GL_UNSIGNED_BYTE &&
234 (rb->Format == MESA_FORMAT_XRGB8888 ||
235 rb->Format == MESA_FORMAT_ARGB8888)) {
236 fast_draw_rgba_ubyte_pixels(ctx, rb, x, y, width, height,
237 &unpack, pixels);
238 return GL_TRUE;
239 }
240
241 if (_mesa_format_matches_format_and_type(rb->Format, format, type)) {
242 fast_draw_generic_pixels(ctx, rb, x, y, width, height,
243 format, type, &unpack, pixels);
244 return GL_TRUE;
245 }
246
247 /* can't handle this pixel format and/or data type */
248 return GL_FALSE;
249 }
250
251
252
253 /*
254 * Draw stencil image.
255 */
256 static void
257 draw_stencil_pixels( struct gl_context *ctx, GLint x, GLint y,
258 GLsizei width, GLsizei height,
259 GLenum type,
260 const struct gl_pixelstore_attrib *unpack,
261 const GLvoid *pixels )
262 {
263 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0;
264 const GLenum destType = GL_UNSIGNED_BYTE;
265 GLint skipPixels;
266
267 /* if width > MAX_WIDTH, have to process image in chunks */
268 skipPixels = 0;
269 while (skipPixels < width) {
270 const GLint spanX = x + skipPixels;
271 const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH);
272 GLint row;
273 for (row = 0; row < height; row++) {
274 const GLint spanY = y + row;
275 GLubyte values[MAX_WIDTH];
276 const GLvoid *source = _mesa_image_address2d(unpack, pixels,
277 width, height,
278 GL_STENCIL_INDEX, type,
279 row, skipPixels);
280 _mesa_unpack_stencil_span(ctx, spanWidth, destType, values,
281 type, source, unpack,
282 ctx->_ImageTransferState);
283 if (zoom) {
284 _swrast_write_zoomed_stencil_span(ctx, x, y, spanWidth,
285 spanX, spanY, values);
286 }
287 else {
288 _swrast_write_stencil_span(ctx, spanWidth, spanX, spanY, values);
289 }
290 }
291 skipPixels += spanWidth;
292 }
293 }
294
295
296 /*
297 * Draw depth image.
298 */
299 static void
300 draw_depth_pixels( struct gl_context *ctx, GLint x, GLint y,
301 GLsizei width, GLsizei height,
302 GLenum type,
303 const struct gl_pixelstore_attrib *unpack,
304 const GLvoid *pixels )
305 {
306 const GLboolean scaleOrBias
307 = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0;
308 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0;
309 SWspan span;
310
311 INIT_SPAN(span, GL_BITMAP);
312 span.arrayMask = SPAN_Z;
313 _swrast_span_default_attribs(ctx, &span);
314
315 if (type == GL_UNSIGNED_SHORT
316 && ctx->DrawBuffer->Visual.depthBits == 16
317 && !scaleOrBias
318 && !zoom
319 && width <= MAX_WIDTH
320 && !unpack->SwapBytes) {
321 /* Special case: directly write 16-bit depth values */
322 GLint row;
323 for (row = 0; row < height; row++) {
324 const GLushort *zSrc = (const GLushort *)
325 _mesa_image_address2d(unpack, pixels, width, height,
326 GL_DEPTH_COMPONENT, type, row, 0);
327 GLint i;
328 for (i = 0; i < width; i++)
329 span.array->z[i] = zSrc[i];
330 span.x = x;
331 span.y = y + row;
332 span.end = width;
333 _swrast_write_rgba_span(ctx, &span);
334 }
335 }
336 else if (type == GL_UNSIGNED_INT
337 && !scaleOrBias
338 && !zoom
339 && width <= MAX_WIDTH
340 && !unpack->SwapBytes) {
341 /* Special case: shift 32-bit values down to Visual.depthBits */
342 const GLint shift = 32 - ctx->DrawBuffer->Visual.depthBits;
343 GLint row;
344 for (row = 0; row < height; row++) {
345 const GLuint *zSrc = (const GLuint *)
346 _mesa_image_address2d(unpack, pixels, width, height,
347 GL_DEPTH_COMPONENT, type, row, 0);
348 if (shift == 0) {
349 memcpy(span.array->z, zSrc, width * sizeof(GLuint));
350 }
351 else {
352 GLint col;
353 for (col = 0; col < width; col++)
354 span.array->z[col] = zSrc[col] >> shift;
355 }
356 span.x = x;
357 span.y = y + row;
358 span.end = width;
359 _swrast_write_rgba_span(ctx, &span);
360 }
361 }
362 else {
363 /* General case */
364 const GLuint depthMax = ctx->DrawBuffer->_DepthMax;
365 GLint skipPixels = 0;
366
367 /* in case width > MAX_WIDTH do the copy in chunks */
368 while (skipPixels < width) {
369 const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH);
370 GLint row;
371 ASSERT(span.end <= MAX_WIDTH);
372 for (row = 0; row < height; row++) {
373 const GLvoid *zSrc = _mesa_image_address2d(unpack,
374 pixels, width, height,
375 GL_DEPTH_COMPONENT, type,
376 row, skipPixels);
377
378 /* Set these for each row since the _swrast_write_* function may
379 * change them while clipping.
380 */
381 span.x = x + skipPixels;
382 span.y = y + row;
383 span.end = spanWidth;
384
385 _mesa_unpack_depth_span(ctx, spanWidth,
386 GL_UNSIGNED_INT, span.array->z, depthMax,
387 type, zSrc, unpack);
388 if (zoom) {
389 _swrast_write_zoomed_depth_span(ctx, x, y, &span);
390 }
391 else {
392 _swrast_write_rgba_span(ctx, &span);
393 }
394 }
395 skipPixels += spanWidth;
396 }
397 }
398 }
399
400
401
402 /**
403 * Draw RGBA image.
404 */
405 static void
406 draw_rgba_pixels( struct gl_context *ctx, GLint x, GLint y,
407 GLsizei width, GLsizei height,
408 GLenum format, GLenum type,
409 const struct gl_pixelstore_attrib *unpack,
410 const GLvoid *pixels )
411 {
412 const GLint imgX = x, imgY = y;
413 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
414 GLfloat *convImage = NULL;
415 GLbitfield transferOps = ctx->_ImageTransferState;
416 SWspan span;
417
418 /* Try an optimized glDrawPixels first */
419 if (fast_draw_rgba_pixels(ctx, x, y, width, height, format, type,
420 unpack, pixels)) {
421 return;
422 }
423
424 swrast_render_start(ctx);
425
426 INIT_SPAN(span, GL_BITMAP);
427 _swrast_span_default_attribs(ctx, &span);
428 span.arrayMask = SPAN_RGBA;
429 span.arrayAttribs = FRAG_BIT_COL0; /* we're fill in COL0 attrib values */
430
431 if (ctx->DrawBuffer->_NumColorDrawBuffers > 0) {
432 GLenum datatype = _mesa_get_format_datatype(
433 ctx->DrawBuffer->_ColorDrawBuffers[0]->Format);
434 if (datatype != GL_FLOAT &&
435 ctx->Color.ClampFragmentColor != GL_FALSE) {
436 /* need to clamp colors before applying fragment ops */
437 transferOps |= IMAGE_CLAMP_BIT;
438 }
439 }
440
441 /*
442 * General solution
443 */
444 {
445 const GLbitfield interpMask = span.interpMask;
446 const GLbitfield arrayMask = span.arrayMask;
447 const GLint srcStride
448 = _mesa_image_row_stride(unpack, width, format, type);
449 GLint skipPixels = 0;
450 /* use span array for temp color storage */
451 GLfloat *rgba = (GLfloat *) span.array->attribs[FRAG_ATTRIB_COL0];
452
453 /* if the span is wider than MAX_WIDTH we have to do it in chunks */
454 while (skipPixels < width) {
455 const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH);
456 const GLubyte *source
457 = (const GLubyte *) _mesa_image_address2d(unpack, pixels,
458 width, height, format,
459 type, 0, skipPixels);
460 GLint row;
461
462 for (row = 0; row < height; row++) {
463 /* get image row as float/RGBA */
464 _mesa_unpack_color_span_float(ctx, spanWidth, GL_RGBA, rgba,
465 format, type, source, unpack,
466 transferOps);
467 /* Set these for each row since the _swrast_write_* functions
468 * may change them while clipping/rendering.
469 */
470 span.array->ChanType = GL_FLOAT;
471 span.x = x + skipPixels;
472 span.y = y + row;
473 span.end = spanWidth;
474 span.arrayMask = arrayMask;
475 span.interpMask = interpMask;
476 if (zoom) {
477 _swrast_write_zoomed_rgba_span(ctx, imgX, imgY, &span, rgba);
478 }
479 else {
480 _swrast_write_rgba_span(ctx, &span);
481 }
482
483 source += srcStride;
484 } /* for row */
485
486 skipPixels += spanWidth;
487 } /* while skipPixels < width */
488
489 /* XXX this is ugly/temporary, to undo above change */
490 span.array->ChanType = CHAN_TYPE;
491 }
492
493 if (convImage) {
494 free(convImage);
495 }
496
497 swrast_render_finish(ctx);
498 }
499
500 /**
501 * Execute software-based glDrawPixels.
502 * By time we get here, all error checking will have been done.
503 */
504 void
505 _swrast_DrawPixels( struct gl_context *ctx,
506 GLint x, GLint y,
507 GLsizei width, GLsizei height,
508 GLenum format, GLenum type,
509 const struct gl_pixelstore_attrib *unpack,
510 const GLvoid *pixels )
511 {
512 SWcontext *swrast = SWRAST_CONTEXT(ctx);
513 GLboolean save_vp_override = ctx->VertexProgram._Overriden;
514
515 /* We are creating fragments directly, without going through vertex
516 * programs.
517 *
518 * This override flag tells the fragment processing code that its input
519 * comes from a non-standard source, and it may therefore not rely on
520 * optimizations that assume e.g. constant color if there is no color
521 * vertex array.
522 */
523 _mesa_set_vp_override(ctx, GL_TRUE);
524
525 if (ctx->NewState)
526 _mesa_update_state(ctx);
527
528 if (swrast->NewState)
529 _swrast_validate_derived( ctx );
530
531 pixels = _mesa_map_pbo_source(ctx, unpack, pixels);
532 if (!pixels) {
533 _mesa_set_vp_override(ctx, save_vp_override);
534 return;
535 }
536
537 /*
538 * By time we get here, all error checking should have been done.
539 */
540 switch (format) {
541 case GL_STENCIL_INDEX:
542 swrast_render_start(ctx);
543 draw_stencil_pixels( ctx, x, y, width, height, type, unpack, pixels );
544 swrast_render_finish(ctx);
545 break;
546 case GL_DEPTH_COMPONENT:
547 swrast_render_start(ctx);
548 draw_depth_pixels( ctx, x, y, width, height, type, unpack, pixels );
549 swrast_render_finish(ctx);
550 break;
551 default:
552 /* all other formats should be color formats */
553 draw_rgba_pixels(ctx, x, y, width, height, format, type, unpack, pixels);
554 }
555
556 _mesa_set_vp_override(ctx, save_vp_override);
557
558 _mesa_unmap_pbo_source(ctx, unpack);
559 }