tgsi/ureg: don't emit in/out arrays if drivers don't support ranged declarations
[mesa.git] / src / mesa / swrast / s_copypix.c
1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26 #include "main/glheader.h"
27 #include "main/context.h"
28 #include "main/condrender.h"
29 #include "main/macros.h"
30 #include "main/pixeltransfer.h"
31 #include "main/imports.h"
32
33 #include "s_context.h"
34 #include "s_depth.h"
35 #include "s_span.h"
36 #include "s_stencil.h"
37 #include "s_zoom.h"
38
39
40
41 /**
42 * Determine if there's overlap in an image copy.
43 * This test also compensates for the fact that copies are done from
44 * bottom to top and overlaps can sometimes be handled correctly
45 * without making a temporary image copy.
46 * \return GL_TRUE if the regions overlap, GL_FALSE otherwise.
47 */
48 static GLboolean
49 regions_overlap(GLint srcx, GLint srcy,
50 GLint dstx, GLint dsty,
51 GLint width, GLint height,
52 GLfloat zoomX, GLfloat zoomY)
53 {
54 if (zoomX == 1.0 && zoomY == 1.0) {
55 /* no zoom */
56 if (srcx >= dstx + width || (srcx + width <= dstx)) {
57 return GL_FALSE;
58 }
59 else if (srcy < dsty) { /* this is OK */
60 return GL_FALSE;
61 }
62 else if (srcy > dsty + height) {
63 return GL_FALSE;
64 }
65 else {
66 return GL_TRUE;
67 }
68 }
69 else {
70 /* add one pixel of slop when zooming, just to be safe */
71 if (srcx > (dstx + ((zoomX > 0.0F) ? (width * zoomX + 1.0F) : 0.0F))) {
72 /* src is completely right of dest */
73 return GL_FALSE;
74 }
75 else if (srcx + width + 1.0F < dstx + ((zoomX > 0.0F) ? 0.0F : (width * zoomX))) {
76 /* src is completely left of dest */
77 return GL_FALSE;
78 }
79 else if ((srcy < dsty) && (srcy + height < dsty + (height * zoomY))) {
80 /* src is completely below dest */
81 return GL_FALSE;
82 }
83 else if ((srcy > dsty) && (srcy + height > dsty + (height * zoomY))) {
84 /* src is completely above dest */
85 return GL_FALSE;
86 }
87 else {
88 return GL_TRUE;
89 }
90 }
91 }
92
93
94 /**
95 * RGBA copypixels
96 */
97 static void
98 copy_rgba_pixels(struct gl_context *ctx, GLint srcx, GLint srcy,
99 GLint width, GLint height, GLint destx, GLint desty)
100 {
101 GLfloat *tmpImage, *p;
102 GLint sy, dy, stepy, row;
103 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
104 GLint overlapping;
105 GLuint transferOps = ctx->_ImageTransferState;
106 SWspan span;
107
108 if (!ctx->ReadBuffer->_ColorReadBuffer) {
109 /* no readbuffer - OK */
110 return;
111 }
112
113 if (ctx->DrawBuffer == ctx->ReadBuffer) {
114 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
115 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
116 }
117 else {
118 overlapping = GL_FALSE;
119 }
120
121 /* Determine if copy should be done bottom-to-top or top-to-bottom */
122 if (!overlapping && srcy < desty) {
123 /* top-down max-to-min */
124 sy = srcy + height - 1;
125 dy = desty + height - 1;
126 stepy = -1;
127 }
128 else {
129 /* bottom-up min-to-max */
130 sy = srcy;
131 dy = desty;
132 stepy = 1;
133 }
134
135 INIT_SPAN(span, GL_BITMAP);
136 _swrast_span_default_attribs(ctx, &span);
137 span.arrayMask = SPAN_RGBA;
138 span.arrayAttribs = VARYING_BIT_COL0; /* we'll fill in COL0 attrib values */
139
140 if (overlapping) {
141 tmpImage = malloc(width * height * sizeof(GLfloat) * 4);
142 if (!tmpImage) {
143 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
144 return;
145 }
146 /* read the source image as RGBA/float */
147 p = tmpImage;
148 for (row = 0; row < height; row++) {
149 _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
150 width, srcx, sy + row, p );
151 p += width * 4;
152 }
153 p = tmpImage;
154 }
155 else {
156 tmpImage = NULL; /* silence compiler warnings */
157 p = NULL;
158 }
159
160 assert(width < SWRAST_MAX_WIDTH);
161
162 for (row = 0; row < height; row++, sy += stepy, dy += stepy) {
163 GLvoid *rgba = span.array->attribs[VARYING_SLOT_COL0];
164
165 /* Get row/span of source pixels */
166 if (overlapping) {
167 /* get from buffered image */
168 memcpy(rgba, p, width * sizeof(GLfloat) * 4);
169 p += width * 4;
170 }
171 else {
172 /* get from framebuffer */
173 _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
174 width, srcx, sy, rgba );
175 }
176
177 if (transferOps) {
178 _mesa_apply_rgba_transfer_ops(ctx, transferOps, width,
179 (GLfloat (*)[4]) rgba);
180 }
181
182 /* Write color span */
183 span.x = destx;
184 span.y = dy;
185 span.end = width;
186 span.array->ChanType = GL_FLOAT;
187 if (zoom) {
188 _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span, rgba);
189 }
190 else {
191 _swrast_write_rgba_span(ctx, &span);
192 }
193 }
194
195 span.array->ChanType = CHAN_TYPE; /* restore */
196
197 if (overlapping)
198 free(tmpImage);
199 }
200
201
202 /**
203 * Convert floating point Z values to integer Z values with pixel transfer's
204 * Z scale and bias.
205 */
206 static void
207 scale_and_bias_z(struct gl_context *ctx, GLuint width,
208 const GLfloat depth[], GLuint z[])
209 {
210 const GLuint depthMax = ctx->DrawBuffer->_DepthMax;
211 GLuint i;
212
213 if (depthMax <= 0xffffff &&
214 ctx->Pixel.DepthScale == 1.0 &&
215 ctx->Pixel.DepthBias == 0.0) {
216 /* no scale or bias and no clamping and no worry of overflow */
217 const GLfloat depthMaxF = ctx->DrawBuffer->_DepthMaxF;
218 for (i = 0; i < width; i++) {
219 z[i] = (GLuint) (depth[i] * depthMaxF);
220 }
221 }
222 else {
223 /* need to be careful with overflow */
224 const GLdouble depthMaxF = ctx->DrawBuffer->_DepthMaxF;
225 for (i = 0; i < width; i++) {
226 GLdouble d = depth[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias;
227 d = CLAMP(d, 0.0, 1.0) * depthMaxF;
228 if (d >= depthMaxF)
229 z[i] = depthMax;
230 else
231 z[i] = (GLuint) d;
232 }
233 }
234 }
235
236
237
238 /*
239 * TODO: Optimize!!!!
240 */
241 static void
242 copy_depth_pixels( struct gl_context *ctx, GLint srcx, GLint srcy,
243 GLint width, GLint height,
244 GLint destx, GLint desty )
245 {
246 struct gl_framebuffer *fb = ctx->ReadBuffer;
247 struct gl_renderbuffer *readRb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
248 GLfloat *p, *tmpImage, *depth;
249 GLint sy, dy, stepy;
250 GLint j;
251 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
252 GLint overlapping;
253 SWspan span;
254
255 if (!readRb) {
256 /* no readbuffer - OK */
257 return;
258 }
259
260 INIT_SPAN(span, GL_BITMAP);
261 _swrast_span_default_attribs(ctx, &span);
262 span.arrayMask = SPAN_Z;
263
264 if (ctx->DrawBuffer == ctx->ReadBuffer) {
265 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
266 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
267 }
268 else {
269 overlapping = GL_FALSE;
270 }
271
272 /* Determine if copy should be bottom-to-top or top-to-bottom */
273 if (!overlapping && srcy < desty) {
274 /* top-down max-to-min */
275 sy = srcy + height - 1;
276 dy = desty + height - 1;
277 stepy = -1;
278 }
279 else {
280 /* bottom-up min-to-max */
281 sy = srcy;
282 dy = desty;
283 stepy = 1;
284 }
285
286 if (overlapping) {
287 GLint ssy = sy;
288 tmpImage = malloc(width * height * sizeof(GLfloat));
289 if (!tmpImage) {
290 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
291 return;
292 }
293 p = tmpImage;
294 for (j = 0; j < height; j++, ssy += stepy) {
295 _swrast_read_depth_span_float(ctx, readRb, width, srcx, ssy, p);
296 p += width;
297 }
298 p = tmpImage;
299 }
300 else {
301 tmpImage = NULL; /* silence compiler warning */
302 p = NULL;
303 }
304
305 depth = malloc(width * sizeof(GLfloat));
306 if (!depth) {
307 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels()");
308 goto end;
309 }
310
311 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
312 /* get depth values */
313 if (overlapping) {
314 memcpy(depth, p, width * sizeof(GLfloat));
315 p += width;
316 }
317 else {
318 _swrast_read_depth_span_float(ctx, readRb, width, srcx, sy, depth);
319 }
320
321 /* apply scale and bias */
322 scale_and_bias_z(ctx, width, depth, span.array->z);
323
324 /* write depth values */
325 span.x = destx;
326 span.y = dy;
327 span.end = width;
328 if (zoom)
329 _swrast_write_zoomed_depth_span(ctx, destx, desty, &span);
330 else
331 _swrast_write_rgba_span(ctx, &span);
332 }
333
334 free(depth);
335
336 end:
337 if (overlapping)
338 free(tmpImage);
339 }
340
341
342
343 static void
344 copy_stencil_pixels( struct gl_context *ctx, GLint srcx, GLint srcy,
345 GLint width, GLint height,
346 GLint destx, GLint desty )
347 {
348 struct gl_framebuffer *fb = ctx->ReadBuffer;
349 struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
350 GLint sy, dy, stepy;
351 GLint j;
352 GLubyte *p, *tmpImage, *stencil;
353 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
354 GLint overlapping;
355
356 if (!rb) {
357 /* no readbuffer - OK */
358 return;
359 }
360
361 if (ctx->DrawBuffer == ctx->ReadBuffer) {
362 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
363 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
364 }
365 else {
366 overlapping = GL_FALSE;
367 }
368
369 /* Determine if copy should be bottom-to-top or top-to-bottom */
370 if (!overlapping && srcy < desty) {
371 /* top-down max-to-min */
372 sy = srcy + height - 1;
373 dy = desty + height - 1;
374 stepy = -1;
375 }
376 else {
377 /* bottom-up min-to-max */
378 sy = srcy;
379 dy = desty;
380 stepy = 1;
381 }
382
383 if (overlapping) {
384 GLint ssy = sy;
385 tmpImage = malloc(width * height * sizeof(GLubyte));
386 if (!tmpImage) {
387 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
388 return;
389 }
390 p = tmpImage;
391 for (j = 0; j < height; j++, ssy += stepy) {
392 _swrast_read_stencil_span( ctx, rb, width, srcx, ssy, p );
393 p += width;
394 }
395 p = tmpImage;
396 }
397 else {
398 tmpImage = NULL; /* silence compiler warning */
399 p = NULL;
400 }
401
402 stencil = malloc(width * sizeof(GLubyte));
403 if (!stencil) {
404 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels()");
405 goto end;
406 }
407
408 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
409 /* Get stencil values */
410 if (overlapping) {
411 memcpy(stencil, p, width * sizeof(GLubyte));
412 p += width;
413 }
414 else {
415 _swrast_read_stencil_span( ctx, rb, width, srcx, sy, stencil );
416 }
417
418 _mesa_apply_stencil_transfer_ops(ctx, width, stencil);
419
420 /* Write stencil values */
421 if (zoom) {
422 _swrast_write_zoomed_stencil_span(ctx, destx, desty, width,
423 destx, dy, stencil);
424 }
425 else {
426 _swrast_write_stencil_span( ctx, width, destx, dy, stencil );
427 }
428 }
429
430 free(stencil);
431
432 end:
433 if (overlapping)
434 free(tmpImage);
435 }
436
437
438 /**
439 * Try to do a fast 1:1 blit with memcpy.
440 * \return GL_TRUE if successful, GL_FALSE otherwise.
441 */
442 GLboolean
443 swrast_fast_copy_pixels(struct gl_context *ctx,
444 struct gl_framebuffer *srcFb,
445 struct gl_framebuffer *dstFb,
446 GLint srcX, GLint srcY, GLsizei width, GLsizei height,
447 GLint dstX, GLint dstY, GLenum type)
448 {
449 struct gl_renderbuffer *srcRb, *dstRb;
450 GLint row;
451 GLuint pixelBytes, widthInBytes;
452 GLubyte *srcMap, *dstMap;
453 GLint srcRowStride, dstRowStride;
454
455 if (type == GL_COLOR) {
456 if (dstFb->_NumColorDrawBuffers != 1)
457 return GL_FALSE;
458 srcRb = srcFb->_ColorReadBuffer;
459 dstRb = dstFb->_ColorDrawBuffers[0];
460 }
461 else if (type == GL_STENCIL) {
462 srcRb = srcFb->Attachment[BUFFER_STENCIL].Renderbuffer;
463 dstRb = dstFb->Attachment[BUFFER_STENCIL].Renderbuffer;
464 }
465 else if (type == GL_DEPTH) {
466 srcRb = srcFb->Attachment[BUFFER_DEPTH].Renderbuffer;
467 dstRb = dstFb->Attachment[BUFFER_DEPTH].Renderbuffer;
468 }
469 else {
470 assert(type == GL_DEPTH_STENCIL_EXT);
471 /* XXX correct? */
472 srcRb = srcFb->Attachment[BUFFER_DEPTH].Renderbuffer;
473 dstRb = dstFb->Attachment[BUFFER_DEPTH].Renderbuffer;
474 }
475
476 /* src and dst renderbuffers must be same format */
477 if (!srcRb || !dstRb || srcRb->Format != dstRb->Format) {
478 return GL_FALSE;
479 }
480
481 if (type == GL_STENCIL || type == GL_DEPTH_COMPONENT) {
482 /* can't handle packed depth+stencil here */
483 if (_mesa_is_format_packed_depth_stencil(srcRb->Format) ||
484 _mesa_is_format_packed_depth_stencil(dstRb->Format))
485 return GL_FALSE;
486 }
487 else if (type == GL_DEPTH_STENCIL) {
488 /* can't handle separate depth/stencil buffers */
489 if (srcRb != srcFb->Attachment[BUFFER_STENCIL].Renderbuffer ||
490 dstRb != dstFb->Attachment[BUFFER_STENCIL].Renderbuffer)
491 return GL_FALSE;
492 }
493
494 /* clipping not supported */
495 if (srcX < 0 || srcX + width > (GLint) srcFb->Width ||
496 srcY < 0 || srcY + height > (GLint) srcFb->Height ||
497 dstX < dstFb->_Xmin || dstX + width > dstFb->_Xmax ||
498 dstY < dstFb->_Ymin || dstY + height > dstFb->_Ymax) {
499 return GL_FALSE;
500 }
501
502 pixelBytes = _mesa_get_format_bytes(srcRb->Format);
503 widthInBytes = width * pixelBytes;
504
505 if (srcRb == dstRb) {
506 /* map whole buffer for read/write */
507 /* XXX we could be clever and just map the union region of the
508 * source and dest rects.
509 */
510 GLubyte *map;
511 GLint rowStride;
512
513 ctx->Driver.MapRenderbuffer(ctx, srcRb, 0, 0,
514 srcRb->Width, srcRb->Height,
515 GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
516 &map, &rowStride);
517 if (!map) {
518 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
519 return GL_TRUE; /* don't retry with slow path */
520 }
521
522 srcMap = map + srcY * rowStride + srcX * pixelBytes;
523 dstMap = map + dstY * rowStride + dstX * pixelBytes;
524
525 /* this handles overlapping copies */
526 if (srcY < dstY) {
527 /* copy in reverse (top->down) order */
528 srcMap += rowStride * (height - 1);
529 dstMap += rowStride * (height - 1);
530 srcRowStride = -rowStride;
531 dstRowStride = -rowStride;
532 }
533 else {
534 /* copy in normal (bottom->up) order */
535 srcRowStride = rowStride;
536 dstRowStride = rowStride;
537 }
538 }
539 else {
540 /* different src/dst buffers */
541 ctx->Driver.MapRenderbuffer(ctx, srcRb, srcX, srcY,
542 width, height,
543 GL_MAP_READ_BIT, &srcMap, &srcRowStride);
544 if (!srcMap) {
545 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
546 return GL_TRUE; /* don't retry with slow path */
547 }
548 ctx->Driver.MapRenderbuffer(ctx, dstRb, dstX, dstY,
549 width, height,
550 GL_MAP_WRITE_BIT, &dstMap, &dstRowStride);
551 if (!dstMap) {
552 ctx->Driver.UnmapRenderbuffer(ctx, srcRb);
553 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
554 return GL_TRUE; /* don't retry with slow path */
555 }
556 }
557
558 for (row = 0; row < height; row++) {
559 /* memmove() in case of overlap */
560 memmove(dstMap, srcMap, widthInBytes);
561 dstMap += dstRowStride;
562 srcMap += srcRowStride;
563 }
564
565 ctx->Driver.UnmapRenderbuffer(ctx, srcRb);
566 if (dstRb != srcRb) {
567 ctx->Driver.UnmapRenderbuffer(ctx, dstRb);
568 }
569
570 return GL_TRUE;
571 }
572
573
574 /**
575 * Find/map the renderbuffer that we'll be reading from.
576 * The swrast_render_start() function only maps the drawing buffers,
577 * not the read buffer.
578 */
579 static struct gl_renderbuffer *
580 map_readbuffer(struct gl_context *ctx, GLenum type)
581 {
582 struct gl_framebuffer *fb = ctx->ReadBuffer;
583 struct gl_renderbuffer *rb;
584 struct swrast_renderbuffer *srb;
585
586 switch (type) {
587 case GL_COLOR:
588 rb = fb->Attachment[fb->_ColorReadBufferIndex].Renderbuffer;
589 break;
590 case GL_DEPTH:
591 case GL_DEPTH_STENCIL:
592 rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
593 break;
594 case GL_STENCIL:
595 rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
596 break;
597 default:
598 return NULL;
599 }
600
601 srb = swrast_renderbuffer(rb);
602
603 if (!srb || srb->Map) {
604 /* no buffer, or buffer is mapped already, we're done */
605 return NULL;
606 }
607
608 ctx->Driver.MapRenderbuffer(ctx, rb,
609 0, 0, rb->Width, rb->Height,
610 GL_MAP_READ_BIT,
611 &srb->Map, &srb->RowStride);
612
613 return rb;
614 }
615
616
617 /**
618 * Do software-based glCopyPixels.
619 * By time we get here, all parameters will have been error-checked.
620 */
621 void
622 _swrast_CopyPixels(struct gl_context *ctx,
623 GLint srcx, GLint srcy, GLsizei width, GLsizei height,
624 GLint destx, GLint desty, GLenum type)
625 {
626 SWcontext *swrast = SWRAST_CONTEXT(ctx);
627 struct gl_renderbuffer *rb;
628
629 if (!_mesa_check_conditional_render(ctx))
630 return; /* don't copy */
631
632 if (swrast->NewState)
633 _swrast_validate_derived( ctx );
634
635 if (!(SWRAST_CONTEXT(ctx)->_RasterMask != 0x0 ||
636 ctx->Pixel.ZoomX != 1.0F ||
637 ctx->Pixel.ZoomY != 1.0F ||
638 ctx->_ImageTransferState) &&
639 swrast_fast_copy_pixels(ctx, ctx->ReadBuffer, ctx->DrawBuffer,
640 srcx, srcy, width, height, destx, desty,
641 type)) {
642 /* all done */
643 return;
644 }
645
646 swrast_render_start(ctx);
647 rb = map_readbuffer(ctx, type);
648
649 switch (type) {
650 case GL_COLOR:
651 copy_rgba_pixels( ctx, srcx, srcy, width, height, destx, desty );
652 break;
653 case GL_DEPTH:
654 copy_depth_pixels( ctx, srcx, srcy, width, height, destx, desty );
655 break;
656 case GL_STENCIL:
657 copy_stencil_pixels( ctx, srcx, srcy, width, height, destx, desty );
658 break;
659 case GL_DEPTH_STENCIL_EXT:
660 /* Copy buffers separately (if the fast copy path wasn't taken) */
661 copy_depth_pixels(ctx, srcx, srcy, width, height, destx, desty);
662 copy_stencil_pixels(ctx, srcx, srcy, width, height, destx, desty);
663 break;
664 default:
665 _mesa_problem(ctx, "unexpected type in _swrast_CopyPixels");
666 }
667
668 swrast_render_finish(ctx);
669
670 if (rb) {
671 struct swrast_renderbuffer *srb = swrast_renderbuffer(rb);
672 ctx->Driver.UnmapRenderbuffer(ctx, rb);
673 srb->Map = NULL;
674 }
675 }