1848b8605Smrg/* 2848b8605Smrg * Mesa 3-D graphics library 3848b8605Smrg * 4848b8605Smrg * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 5848b8605Smrg * 6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 7848b8605Smrg * copy of this software and associated documentation files (the "Software"), 8848b8605Smrg * to deal in the Software without restriction, including without limitation 9848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the 11848b8605Smrg * Software is furnished to do so, subject to the following conditions: 12848b8605Smrg * 13848b8605Smrg * The above copyright notice and this permission notice shall be included 14848b8605Smrg * in all copies or substantial portions of the Software. 15848b8605Smrg * 16848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE. 23848b8605Smrg */ 24848b8605Smrg 25848b8605Smrg 26848b8605Smrg#include "main/glheader.h" 27848b8605Smrg#include "main/context.h" 28848b8605Smrg#include "main/condrender.h" 29848b8605Smrg#include "main/macros.h" 30b8e80941Smrg#include "main/blit.h" 31848b8605Smrg#include "main/pixeltransfer.h" 32848b8605Smrg#include "main/imports.h" 33848b8605Smrg 34848b8605Smrg#include "s_context.h" 35848b8605Smrg#include "s_depth.h" 36848b8605Smrg#include "s_span.h" 37848b8605Smrg#include "s_stencil.h" 38848b8605Smrg#include "s_zoom.h" 39848b8605Smrg 40848b8605Smrg 41848b8605Smrg 42848b8605Smrg/** 43848b8605Smrg * Determine if there's overlap in an image copy. 44848b8605Smrg * This test also compensates for the fact that copies are done from 45848b8605Smrg * bottom to top and overlaps can sometimes be handled correctly 46848b8605Smrg * without making a temporary image copy. 47848b8605Smrg * \return GL_TRUE if the regions overlap, GL_FALSE otherwise. 48848b8605Smrg */ 49848b8605Smrgstatic GLboolean 50848b8605Smrgregions_overlap(GLint srcx, GLint srcy, 51848b8605Smrg GLint dstx, GLint dsty, 52848b8605Smrg GLint width, GLint height, 53848b8605Smrg GLfloat zoomX, GLfloat zoomY) 54848b8605Smrg{ 55b8e80941Smrg if (zoomX == 1.0F && zoomY == 1.0F) { 56b8e80941Smrg return _mesa_regions_overlap(srcx, srcy, srcx + width, srcy + height, 57b8e80941Smrg dstx, dsty, dstx + width, dsty + height); 58848b8605Smrg } 59848b8605Smrg else { 60848b8605Smrg /* add one pixel of slop when zooming, just to be safe */ 61848b8605Smrg if (srcx > (dstx + ((zoomX > 0.0F) ? (width * zoomX + 1.0F) : 0.0F))) { 62848b8605Smrg /* src is completely right of dest */ 63848b8605Smrg return GL_FALSE; 64848b8605Smrg } 65848b8605Smrg else if (srcx + width + 1.0F < dstx + ((zoomX > 0.0F) ? 0.0F : (width * zoomX))) { 66848b8605Smrg /* src is completely left of dest */ 67848b8605Smrg return GL_FALSE; 68848b8605Smrg } 69848b8605Smrg else if ((srcy < dsty) && (srcy + height < dsty + (height * zoomY))) { 70848b8605Smrg /* src is completely below dest */ 71848b8605Smrg return GL_FALSE; 72848b8605Smrg } 73848b8605Smrg else if ((srcy > dsty) && (srcy + height > dsty + (height * zoomY))) { 74848b8605Smrg /* src is completely above dest */ 75848b8605Smrg return GL_FALSE; 76848b8605Smrg } 77848b8605Smrg else { 78848b8605Smrg return GL_TRUE; 79848b8605Smrg } 80848b8605Smrg } 81848b8605Smrg} 82848b8605Smrg 83848b8605Smrg 84848b8605Smrg/** 85848b8605Smrg * RGBA copypixels 86848b8605Smrg */ 87848b8605Smrgstatic void 88848b8605Smrgcopy_rgba_pixels(struct gl_context *ctx, GLint srcx, GLint srcy, 89848b8605Smrg GLint width, GLint height, GLint destx, GLint desty) 90848b8605Smrg{ 91848b8605Smrg GLfloat *tmpImage, *p; 92848b8605Smrg GLint sy, dy, stepy, row; 93848b8605Smrg const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; 94848b8605Smrg GLint overlapping; 95848b8605Smrg GLuint transferOps = ctx->_ImageTransferState; 96848b8605Smrg SWspan span; 97848b8605Smrg 98848b8605Smrg if (!ctx->ReadBuffer->_ColorReadBuffer) { 99848b8605Smrg /* no readbuffer - OK */ 100848b8605Smrg return; 101848b8605Smrg } 102848b8605Smrg 103848b8605Smrg if (ctx->DrawBuffer == ctx->ReadBuffer) { 104848b8605Smrg overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, 105848b8605Smrg ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); 106848b8605Smrg } 107848b8605Smrg else { 108848b8605Smrg overlapping = GL_FALSE; 109848b8605Smrg } 110848b8605Smrg 111848b8605Smrg /* Determine if copy should be done bottom-to-top or top-to-bottom */ 112848b8605Smrg if (!overlapping && srcy < desty) { 113848b8605Smrg /* top-down max-to-min */ 114848b8605Smrg sy = srcy + height - 1; 115848b8605Smrg dy = desty + height - 1; 116848b8605Smrg stepy = -1; 117848b8605Smrg } 118848b8605Smrg else { 119848b8605Smrg /* bottom-up min-to-max */ 120848b8605Smrg sy = srcy; 121848b8605Smrg dy = desty; 122848b8605Smrg stepy = 1; 123848b8605Smrg } 124848b8605Smrg 125848b8605Smrg INIT_SPAN(span, GL_BITMAP); 126848b8605Smrg _swrast_span_default_attribs(ctx, &span); 127848b8605Smrg span.arrayMask = SPAN_RGBA; 128848b8605Smrg span.arrayAttribs = VARYING_BIT_COL0; /* we'll fill in COL0 attrib values */ 129848b8605Smrg 130848b8605Smrg if (overlapping) { 131848b8605Smrg tmpImage = malloc(width * height * sizeof(GLfloat) * 4); 132848b8605Smrg if (!tmpImage) { 133848b8605Smrg _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); 134848b8605Smrg return; 135848b8605Smrg } 136848b8605Smrg /* read the source image as RGBA/float */ 137848b8605Smrg p = tmpImage; 138848b8605Smrg for (row = 0; row < height; row++) { 139848b8605Smrg _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer, 140848b8605Smrg width, srcx, sy + row, p ); 141848b8605Smrg p += width * 4; 142848b8605Smrg } 143848b8605Smrg p = tmpImage; 144848b8605Smrg } 145848b8605Smrg else { 146848b8605Smrg tmpImage = NULL; /* silence compiler warnings */ 147848b8605Smrg p = NULL; 148848b8605Smrg } 149848b8605Smrg 150b8e80941Smrg assert(width < SWRAST_MAX_WIDTH); 151848b8605Smrg 152848b8605Smrg for (row = 0; row < height; row++, sy += stepy, dy += stepy) { 153848b8605Smrg GLvoid *rgba = span.array->attribs[VARYING_SLOT_COL0]; 154848b8605Smrg 155848b8605Smrg /* Get row/span of source pixels */ 156848b8605Smrg if (overlapping) { 157848b8605Smrg /* get from buffered image */ 158848b8605Smrg memcpy(rgba, p, width * sizeof(GLfloat) * 4); 159848b8605Smrg p += width * 4; 160848b8605Smrg } 161848b8605Smrg else { 162848b8605Smrg /* get from framebuffer */ 163848b8605Smrg _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer, 164848b8605Smrg width, srcx, sy, rgba ); 165848b8605Smrg } 166848b8605Smrg 167848b8605Smrg if (transferOps) { 168848b8605Smrg _mesa_apply_rgba_transfer_ops(ctx, transferOps, width, 169848b8605Smrg (GLfloat (*)[4]) rgba); 170848b8605Smrg } 171848b8605Smrg 172848b8605Smrg /* Write color span */ 173848b8605Smrg span.x = destx; 174848b8605Smrg span.y = dy; 175848b8605Smrg span.end = width; 176848b8605Smrg span.array->ChanType = GL_FLOAT; 177848b8605Smrg if (zoom) { 178848b8605Smrg _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span, rgba); 179848b8605Smrg } 180848b8605Smrg else { 181848b8605Smrg _swrast_write_rgba_span(ctx, &span); 182848b8605Smrg } 183848b8605Smrg } 184848b8605Smrg 185848b8605Smrg span.array->ChanType = CHAN_TYPE; /* restore */ 186848b8605Smrg 187848b8605Smrg if (overlapping) 188848b8605Smrg free(tmpImage); 189848b8605Smrg} 190848b8605Smrg 191848b8605Smrg 192848b8605Smrg/** 193848b8605Smrg * Convert floating point Z values to integer Z values with pixel transfer's 194848b8605Smrg * Z scale and bias. 195848b8605Smrg */ 196848b8605Smrgstatic void 197848b8605Smrgscale_and_bias_z(struct gl_context *ctx, GLuint width, 198848b8605Smrg const GLfloat depth[], GLuint z[]) 199848b8605Smrg{ 200848b8605Smrg const GLuint depthMax = ctx->DrawBuffer->_DepthMax; 201848b8605Smrg GLuint i; 202848b8605Smrg 203848b8605Smrg if (depthMax <= 0xffffff && 204b8e80941Smrg ctx->Pixel.DepthScale == 1.0F && 205b8e80941Smrg ctx->Pixel.DepthBias == 0.0F) { 206848b8605Smrg /* no scale or bias and no clamping and no worry of overflow */ 207848b8605Smrg const GLfloat depthMaxF = ctx->DrawBuffer->_DepthMaxF; 208848b8605Smrg for (i = 0; i < width; i++) { 209848b8605Smrg z[i] = (GLuint) (depth[i] * depthMaxF); 210848b8605Smrg } 211848b8605Smrg } 212848b8605Smrg else { 213848b8605Smrg /* need to be careful with overflow */ 214848b8605Smrg const GLdouble depthMaxF = ctx->DrawBuffer->_DepthMaxF; 215848b8605Smrg for (i = 0; i < width; i++) { 216848b8605Smrg GLdouble d = depth[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias; 217848b8605Smrg d = CLAMP(d, 0.0, 1.0) * depthMaxF; 218848b8605Smrg if (d >= depthMaxF) 219848b8605Smrg z[i] = depthMax; 220848b8605Smrg else 221848b8605Smrg z[i] = (GLuint) d; 222848b8605Smrg } 223848b8605Smrg } 224848b8605Smrg} 225848b8605Smrg 226848b8605Smrg 227848b8605Smrg 228848b8605Smrg/* 229848b8605Smrg * TODO: Optimize!!!! 230848b8605Smrg */ 231848b8605Smrgstatic void 232848b8605Smrgcopy_depth_pixels( struct gl_context *ctx, GLint srcx, GLint srcy, 233848b8605Smrg GLint width, GLint height, 234848b8605Smrg GLint destx, GLint desty ) 235848b8605Smrg{ 236848b8605Smrg struct gl_framebuffer *fb = ctx->ReadBuffer; 237848b8605Smrg struct gl_renderbuffer *readRb = fb->Attachment[BUFFER_DEPTH].Renderbuffer; 238848b8605Smrg GLfloat *p, *tmpImage, *depth; 239848b8605Smrg GLint sy, dy, stepy; 240848b8605Smrg GLint j; 241848b8605Smrg const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; 242848b8605Smrg GLint overlapping; 243848b8605Smrg SWspan span; 244848b8605Smrg 245848b8605Smrg if (!readRb) { 246848b8605Smrg /* no readbuffer - OK */ 247848b8605Smrg return; 248848b8605Smrg } 249848b8605Smrg 250848b8605Smrg INIT_SPAN(span, GL_BITMAP); 251848b8605Smrg _swrast_span_default_attribs(ctx, &span); 252848b8605Smrg span.arrayMask = SPAN_Z; 253848b8605Smrg 254848b8605Smrg if (ctx->DrawBuffer == ctx->ReadBuffer) { 255848b8605Smrg overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, 256848b8605Smrg ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); 257848b8605Smrg } 258848b8605Smrg else { 259848b8605Smrg overlapping = GL_FALSE; 260848b8605Smrg } 261848b8605Smrg 262848b8605Smrg /* Determine if copy should be bottom-to-top or top-to-bottom */ 263848b8605Smrg if (!overlapping && srcy < desty) { 264848b8605Smrg /* top-down max-to-min */ 265848b8605Smrg sy = srcy + height - 1; 266848b8605Smrg dy = desty + height - 1; 267848b8605Smrg stepy = -1; 268848b8605Smrg } 269848b8605Smrg else { 270848b8605Smrg /* bottom-up min-to-max */ 271848b8605Smrg sy = srcy; 272848b8605Smrg dy = desty; 273848b8605Smrg stepy = 1; 274848b8605Smrg } 275848b8605Smrg 276848b8605Smrg if (overlapping) { 277848b8605Smrg GLint ssy = sy; 278848b8605Smrg tmpImage = malloc(width * height * sizeof(GLfloat)); 279848b8605Smrg if (!tmpImage) { 280848b8605Smrg _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); 281848b8605Smrg return; 282848b8605Smrg } 283848b8605Smrg p = tmpImage; 284848b8605Smrg for (j = 0; j < height; j++, ssy += stepy) { 285848b8605Smrg _swrast_read_depth_span_float(ctx, readRb, width, srcx, ssy, p); 286848b8605Smrg p += width; 287848b8605Smrg } 288848b8605Smrg p = tmpImage; 289848b8605Smrg } 290848b8605Smrg else { 291848b8605Smrg tmpImage = NULL; /* silence compiler warning */ 292848b8605Smrg p = NULL; 293848b8605Smrg } 294848b8605Smrg 295848b8605Smrg depth = malloc(width * sizeof(GLfloat)); 296848b8605Smrg if (!depth) { 297848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels()"); 298848b8605Smrg goto end; 299848b8605Smrg } 300848b8605Smrg 301848b8605Smrg for (j = 0; j < height; j++, sy += stepy, dy += stepy) { 302848b8605Smrg /* get depth values */ 303848b8605Smrg if (overlapping) { 304848b8605Smrg memcpy(depth, p, width * sizeof(GLfloat)); 305848b8605Smrg p += width; 306848b8605Smrg } 307848b8605Smrg else { 308848b8605Smrg _swrast_read_depth_span_float(ctx, readRb, width, srcx, sy, depth); 309848b8605Smrg } 310848b8605Smrg 311848b8605Smrg /* apply scale and bias */ 312848b8605Smrg scale_and_bias_z(ctx, width, depth, span.array->z); 313848b8605Smrg 314848b8605Smrg /* write depth values */ 315848b8605Smrg span.x = destx; 316848b8605Smrg span.y = dy; 317848b8605Smrg span.end = width; 318848b8605Smrg if (zoom) 319848b8605Smrg _swrast_write_zoomed_depth_span(ctx, destx, desty, &span); 320848b8605Smrg else 321848b8605Smrg _swrast_write_rgba_span(ctx, &span); 322848b8605Smrg } 323848b8605Smrg 324848b8605Smrg free(depth); 325848b8605Smrg 326848b8605Smrgend: 327848b8605Smrg if (overlapping) 328848b8605Smrg free(tmpImage); 329848b8605Smrg} 330848b8605Smrg 331848b8605Smrg 332848b8605Smrg 333848b8605Smrgstatic void 334848b8605Smrgcopy_stencil_pixels( struct gl_context *ctx, GLint srcx, GLint srcy, 335848b8605Smrg GLint width, GLint height, 336848b8605Smrg GLint destx, GLint desty ) 337848b8605Smrg{ 338848b8605Smrg struct gl_framebuffer *fb = ctx->ReadBuffer; 339848b8605Smrg struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer; 340848b8605Smrg GLint sy, dy, stepy; 341848b8605Smrg GLint j; 342848b8605Smrg GLubyte *p, *tmpImage, *stencil; 343848b8605Smrg const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; 344848b8605Smrg GLint overlapping; 345848b8605Smrg 346848b8605Smrg if (!rb) { 347848b8605Smrg /* no readbuffer - OK */ 348848b8605Smrg return; 349848b8605Smrg } 350848b8605Smrg 351848b8605Smrg if (ctx->DrawBuffer == ctx->ReadBuffer) { 352848b8605Smrg overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, 353848b8605Smrg ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); 354848b8605Smrg } 355848b8605Smrg else { 356848b8605Smrg overlapping = GL_FALSE; 357848b8605Smrg } 358848b8605Smrg 359848b8605Smrg /* Determine if copy should be bottom-to-top or top-to-bottom */ 360848b8605Smrg if (!overlapping && srcy < desty) { 361848b8605Smrg /* top-down max-to-min */ 362848b8605Smrg sy = srcy + height - 1; 363848b8605Smrg dy = desty + height - 1; 364848b8605Smrg stepy = -1; 365848b8605Smrg } 366848b8605Smrg else { 367848b8605Smrg /* bottom-up min-to-max */ 368848b8605Smrg sy = srcy; 369848b8605Smrg dy = desty; 370848b8605Smrg stepy = 1; 371848b8605Smrg } 372848b8605Smrg 373848b8605Smrg if (overlapping) { 374848b8605Smrg GLint ssy = sy; 375848b8605Smrg tmpImage = malloc(width * height * sizeof(GLubyte)); 376848b8605Smrg if (!tmpImage) { 377848b8605Smrg _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); 378848b8605Smrg return; 379848b8605Smrg } 380848b8605Smrg p = tmpImage; 381848b8605Smrg for (j = 0; j < height; j++, ssy += stepy) { 382848b8605Smrg _swrast_read_stencil_span( ctx, rb, width, srcx, ssy, p ); 383848b8605Smrg p += width; 384848b8605Smrg } 385848b8605Smrg p = tmpImage; 386848b8605Smrg } 387848b8605Smrg else { 388848b8605Smrg tmpImage = NULL; /* silence compiler warning */ 389848b8605Smrg p = NULL; 390848b8605Smrg } 391848b8605Smrg 392848b8605Smrg stencil = malloc(width * sizeof(GLubyte)); 393848b8605Smrg if (!stencil) { 394848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels()"); 395848b8605Smrg goto end; 396848b8605Smrg } 397848b8605Smrg 398848b8605Smrg for (j = 0; j < height; j++, sy += stepy, dy += stepy) { 399848b8605Smrg /* Get stencil values */ 400848b8605Smrg if (overlapping) { 401848b8605Smrg memcpy(stencil, p, width * sizeof(GLubyte)); 402848b8605Smrg p += width; 403848b8605Smrg } 404848b8605Smrg else { 405848b8605Smrg _swrast_read_stencil_span( ctx, rb, width, srcx, sy, stencil ); 406848b8605Smrg } 407848b8605Smrg 408848b8605Smrg _mesa_apply_stencil_transfer_ops(ctx, width, stencil); 409848b8605Smrg 410848b8605Smrg /* Write stencil values */ 411848b8605Smrg if (zoom) { 412848b8605Smrg _swrast_write_zoomed_stencil_span(ctx, destx, desty, width, 413848b8605Smrg destx, dy, stencil); 414848b8605Smrg } 415848b8605Smrg else { 416848b8605Smrg _swrast_write_stencil_span( ctx, width, destx, dy, stencil ); 417848b8605Smrg } 418848b8605Smrg } 419848b8605Smrg 420848b8605Smrg free(stencil); 421848b8605Smrg 422848b8605Smrgend: 423848b8605Smrg if (overlapping) 424848b8605Smrg free(tmpImage); 425848b8605Smrg} 426848b8605Smrg 427848b8605Smrg 428848b8605Smrg/** 429848b8605Smrg * Try to do a fast 1:1 blit with memcpy. 430848b8605Smrg * \return GL_TRUE if successful, GL_FALSE otherwise. 431848b8605Smrg */ 432848b8605SmrgGLboolean 433848b8605Smrgswrast_fast_copy_pixels(struct gl_context *ctx, 434b8e80941Smrg struct gl_framebuffer *srcFb, 435b8e80941Smrg struct gl_framebuffer *dstFb, 436b8e80941Smrg GLint srcX, GLint srcY, GLsizei width, GLsizei height, 437b8e80941Smrg GLint dstX, GLint dstY, GLenum type) 438848b8605Smrg{ 439848b8605Smrg struct gl_renderbuffer *srcRb, *dstRb; 440848b8605Smrg GLint row; 441848b8605Smrg GLuint pixelBytes, widthInBytes; 442848b8605Smrg GLubyte *srcMap, *dstMap; 443848b8605Smrg GLint srcRowStride, dstRowStride; 444848b8605Smrg 445848b8605Smrg if (type == GL_COLOR) { 446848b8605Smrg if (dstFb->_NumColorDrawBuffers != 1) 447848b8605Smrg return GL_FALSE; 448848b8605Smrg srcRb = srcFb->_ColorReadBuffer; 449848b8605Smrg dstRb = dstFb->_ColorDrawBuffers[0]; 450848b8605Smrg } 451848b8605Smrg else if (type == GL_STENCIL) { 452848b8605Smrg srcRb = srcFb->Attachment[BUFFER_STENCIL].Renderbuffer; 453848b8605Smrg dstRb = dstFb->Attachment[BUFFER_STENCIL].Renderbuffer; 454848b8605Smrg } 455848b8605Smrg else if (type == GL_DEPTH) { 456848b8605Smrg srcRb = srcFb->Attachment[BUFFER_DEPTH].Renderbuffer; 457848b8605Smrg dstRb = dstFb->Attachment[BUFFER_DEPTH].Renderbuffer; 458848b8605Smrg } 459848b8605Smrg else { 460b8e80941Smrg assert(type == GL_DEPTH_STENCIL_EXT); 461848b8605Smrg /* XXX correct? */ 462848b8605Smrg srcRb = srcFb->Attachment[BUFFER_DEPTH].Renderbuffer; 463848b8605Smrg dstRb = dstFb->Attachment[BUFFER_DEPTH].Renderbuffer; 464848b8605Smrg } 465848b8605Smrg 466848b8605Smrg /* src and dst renderbuffers must be same format */ 467848b8605Smrg if (!srcRb || !dstRb || srcRb->Format != dstRb->Format) { 468848b8605Smrg return GL_FALSE; 469848b8605Smrg } 470848b8605Smrg 471848b8605Smrg if (type == GL_STENCIL || type == GL_DEPTH_COMPONENT) { 472848b8605Smrg /* can't handle packed depth+stencil here */ 473848b8605Smrg if (_mesa_is_format_packed_depth_stencil(srcRb->Format) || 474848b8605Smrg _mesa_is_format_packed_depth_stencil(dstRb->Format)) 475848b8605Smrg return GL_FALSE; 476848b8605Smrg } 477848b8605Smrg else if (type == GL_DEPTH_STENCIL) { 478848b8605Smrg /* can't handle separate depth/stencil buffers */ 479848b8605Smrg if (srcRb != srcFb->Attachment[BUFFER_STENCIL].Renderbuffer || 480848b8605Smrg dstRb != dstFb->Attachment[BUFFER_STENCIL].Renderbuffer) 481848b8605Smrg return GL_FALSE; 482848b8605Smrg } 483848b8605Smrg 484848b8605Smrg /* clipping not supported */ 485848b8605Smrg if (srcX < 0 || srcX + width > (GLint) srcFb->Width || 486848b8605Smrg srcY < 0 || srcY + height > (GLint) srcFb->Height || 487848b8605Smrg dstX < dstFb->_Xmin || dstX + width > dstFb->_Xmax || 488848b8605Smrg dstY < dstFb->_Ymin || dstY + height > dstFb->_Ymax) { 489848b8605Smrg return GL_FALSE; 490848b8605Smrg } 491848b8605Smrg 492848b8605Smrg pixelBytes = _mesa_get_format_bytes(srcRb->Format); 493848b8605Smrg widthInBytes = width * pixelBytes; 494848b8605Smrg 495848b8605Smrg if (srcRb == dstRb) { 496848b8605Smrg /* map whole buffer for read/write */ 497848b8605Smrg /* XXX we could be clever and just map the union region of the 498848b8605Smrg * source and dest rects. 499848b8605Smrg */ 500848b8605Smrg GLubyte *map; 501848b8605Smrg GLint rowStride; 502848b8605Smrg 503848b8605Smrg ctx->Driver.MapRenderbuffer(ctx, srcRb, 0, 0, 504848b8605Smrg srcRb->Width, srcRb->Height, 505848b8605Smrg GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, 506b8e80941Smrg &map, &rowStride, srcFb->FlipY); 507848b8605Smrg if (!map) { 508848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels"); 509848b8605Smrg return GL_TRUE; /* don't retry with slow path */ 510848b8605Smrg } 511848b8605Smrg 512848b8605Smrg srcMap = map + srcY * rowStride + srcX * pixelBytes; 513848b8605Smrg dstMap = map + dstY * rowStride + dstX * pixelBytes; 514848b8605Smrg 515848b8605Smrg /* this handles overlapping copies */ 516848b8605Smrg if (srcY < dstY) { 517848b8605Smrg /* copy in reverse (top->down) order */ 518848b8605Smrg srcMap += rowStride * (height - 1); 519848b8605Smrg dstMap += rowStride * (height - 1); 520848b8605Smrg srcRowStride = -rowStride; 521848b8605Smrg dstRowStride = -rowStride; 522848b8605Smrg } 523848b8605Smrg else { 524848b8605Smrg /* copy in normal (bottom->up) order */ 525848b8605Smrg srcRowStride = rowStride; 526848b8605Smrg dstRowStride = rowStride; 527848b8605Smrg } 528848b8605Smrg } 529848b8605Smrg else { 530848b8605Smrg /* different src/dst buffers */ 531848b8605Smrg ctx->Driver.MapRenderbuffer(ctx, srcRb, srcX, srcY, 532848b8605Smrg width, height, 533b8e80941Smrg GL_MAP_READ_BIT, &srcMap, &srcRowStride, 534b8e80941Smrg srcFb->FlipY); 535848b8605Smrg if (!srcMap) { 536848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels"); 537848b8605Smrg return GL_TRUE; /* don't retry with slow path */ 538848b8605Smrg } 539848b8605Smrg ctx->Driver.MapRenderbuffer(ctx, dstRb, dstX, dstY, 540848b8605Smrg width, height, 541b8e80941Smrg GL_MAP_WRITE_BIT, &dstMap, &dstRowStride, 542b8e80941Smrg dstFb->FlipY); 543848b8605Smrg if (!dstMap) { 544848b8605Smrg ctx->Driver.UnmapRenderbuffer(ctx, srcRb); 545848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels"); 546848b8605Smrg return GL_TRUE; /* don't retry with slow path */ 547848b8605Smrg } 548848b8605Smrg } 549848b8605Smrg 550848b8605Smrg for (row = 0; row < height; row++) { 551848b8605Smrg /* memmove() in case of overlap */ 552848b8605Smrg memmove(dstMap, srcMap, widthInBytes); 553848b8605Smrg dstMap += dstRowStride; 554848b8605Smrg srcMap += srcRowStride; 555848b8605Smrg } 556848b8605Smrg 557848b8605Smrg ctx->Driver.UnmapRenderbuffer(ctx, srcRb); 558848b8605Smrg if (dstRb != srcRb) { 559848b8605Smrg ctx->Driver.UnmapRenderbuffer(ctx, dstRb); 560848b8605Smrg } 561848b8605Smrg 562848b8605Smrg return GL_TRUE; 563848b8605Smrg} 564848b8605Smrg 565848b8605Smrg 566848b8605Smrg/** 567848b8605Smrg * Find/map the renderbuffer that we'll be reading from. 568848b8605Smrg * The swrast_render_start() function only maps the drawing buffers, 569848b8605Smrg * not the read buffer. 570848b8605Smrg */ 571848b8605Smrgstatic struct gl_renderbuffer * 572848b8605Smrgmap_readbuffer(struct gl_context *ctx, GLenum type) 573848b8605Smrg{ 574848b8605Smrg struct gl_framebuffer *fb = ctx->ReadBuffer; 575848b8605Smrg struct gl_renderbuffer *rb; 576848b8605Smrg struct swrast_renderbuffer *srb; 577848b8605Smrg 578848b8605Smrg switch (type) { 579848b8605Smrg case GL_COLOR: 580848b8605Smrg rb = fb->Attachment[fb->_ColorReadBufferIndex].Renderbuffer; 581848b8605Smrg break; 582848b8605Smrg case GL_DEPTH: 583848b8605Smrg case GL_DEPTH_STENCIL: 584848b8605Smrg rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer; 585848b8605Smrg break; 586848b8605Smrg case GL_STENCIL: 587848b8605Smrg rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer; 588848b8605Smrg break; 589848b8605Smrg default: 590848b8605Smrg return NULL; 591848b8605Smrg } 592848b8605Smrg 593848b8605Smrg srb = swrast_renderbuffer(rb); 594848b8605Smrg 595848b8605Smrg if (!srb || srb->Map) { 596848b8605Smrg /* no buffer, or buffer is mapped already, we're done */ 597848b8605Smrg return NULL; 598848b8605Smrg } 599848b8605Smrg 600848b8605Smrg ctx->Driver.MapRenderbuffer(ctx, rb, 601848b8605Smrg 0, 0, rb->Width, rb->Height, 602848b8605Smrg GL_MAP_READ_BIT, 603b8e80941Smrg &srb->Map, &srb->RowStride, 604b8e80941Smrg fb->FlipY); 605848b8605Smrg 606848b8605Smrg return rb; 607848b8605Smrg} 608848b8605Smrg 609848b8605Smrg 610848b8605Smrg/** 611848b8605Smrg * Do software-based glCopyPixels. 612848b8605Smrg * By time we get here, all parameters will have been error-checked. 613848b8605Smrg */ 614848b8605Smrgvoid 615b8e80941Smrg_swrast_CopyPixels(struct gl_context *ctx, 616b8e80941Smrg GLint srcx, GLint srcy, GLsizei width, GLsizei height, 617b8e80941Smrg GLint destx, GLint desty, GLenum type) 618848b8605Smrg{ 619848b8605Smrg SWcontext *swrast = SWRAST_CONTEXT(ctx); 620848b8605Smrg struct gl_renderbuffer *rb; 621848b8605Smrg 622848b8605Smrg if (!_mesa_check_conditional_render(ctx)) 623848b8605Smrg return; /* don't copy */ 624848b8605Smrg 625848b8605Smrg if (swrast->NewState) 626848b8605Smrg _swrast_validate_derived( ctx ); 627848b8605Smrg 628848b8605Smrg if (!(SWRAST_CONTEXT(ctx)->_RasterMask != 0x0 || 629b8e80941Smrg ctx->Pixel.ZoomX != 1.0F || 630b8e80941Smrg ctx->Pixel.ZoomY != 1.0F || 631b8e80941Smrg ctx->_ImageTransferState) && 632b8e80941Smrg swrast_fast_copy_pixels(ctx, ctx->ReadBuffer, ctx->DrawBuffer, 633b8e80941Smrg srcx, srcy, width, height, destx, desty, 634b8e80941Smrg type)) { 635848b8605Smrg /* all done */ 636848b8605Smrg return; 637848b8605Smrg } 638848b8605Smrg 639848b8605Smrg swrast_render_start(ctx); 640848b8605Smrg rb = map_readbuffer(ctx, type); 641848b8605Smrg 642848b8605Smrg switch (type) { 643848b8605Smrg case GL_COLOR: 644848b8605Smrg copy_rgba_pixels( ctx, srcx, srcy, width, height, destx, desty ); 645848b8605Smrg break; 646848b8605Smrg case GL_DEPTH: 647848b8605Smrg copy_depth_pixels( ctx, srcx, srcy, width, height, destx, desty ); 648848b8605Smrg break; 649848b8605Smrg case GL_STENCIL: 650848b8605Smrg copy_stencil_pixels( ctx, srcx, srcy, width, height, destx, desty ); 651848b8605Smrg break; 652848b8605Smrg case GL_DEPTH_STENCIL_EXT: 653848b8605Smrg /* Copy buffers separately (if the fast copy path wasn't taken) */ 654848b8605Smrg copy_depth_pixels(ctx, srcx, srcy, width, height, destx, desty); 655848b8605Smrg copy_stencil_pixels(ctx, srcx, srcy, width, height, destx, desty); 656848b8605Smrg break; 657848b8605Smrg default: 658848b8605Smrg _mesa_problem(ctx, "unexpected type in _swrast_CopyPixels"); 659848b8605Smrg } 660848b8605Smrg 661848b8605Smrg swrast_render_finish(ctx); 662848b8605Smrg 663848b8605Smrg if (rb) { 664848b8605Smrg struct swrast_renderbuffer *srb = swrast_renderbuffer(rb); 665848b8605Smrg ctx->Driver.UnmapRenderbuffer(ctx, rb); 666848b8605Smrg srb->Map = NULL; 667848b8605Smrg } 668848b8605Smrg} 669