/* * Ensure that we are able to use the given physical memory range. * * We abort if the destination physical range overlaps us, or if it * goes outside the bounds of memory. */ static void ensure_phys_range_valid(paddr_t paddr_min, paddr_t paddr_max) { /* Ensure that the kernel physical load address doesn't overwrite us. */ if (regions_overlap(paddr_min, paddr_max - 1, (word_t)_start, (word_t)_end - 1)) { printf("Kernel load address would overlap ELF-loader!\n"); abort(); } }
static void builder_invalidate_region(struct builder *bld, struct eu_region *r) { for (int i = 0; i < ARRAY_LENGTH(bld->regs); i++) { if ((bld->regs[i].contents & BUILDER_REG_CONTENTS_EU_REG) && regions_overlap(r, &bld->regs[i].region)) { bld->regs[i].contents &= ~BUILDER_REG_CONTENTS_EU_REG; ksim_trace(TRACE_AVX, "*** invalidate g%d.%d (ymm%d)\n", bld->regs[i].region.offset / 32, bld->regs[i].region.offset & 31, i); } } }
/** * This isn't terribly efficient. If a driver really has combined * depth/stencil buffers the driver should implement an optimized * CopyPixels function. */ static void copy_depth_stencil_pixels(GLcontext *ctx, const GLint srcX, const GLint srcY, const GLint width, const GLint height, const GLint destX, const GLint destY) { struct gl_renderbuffer *stencilReadRb, *depthReadRb, *depthDrawRb; GLint sy, dy, stepy; GLint j; GLstencil *tempStencilImage = NULL, *stencilPtr = NULL; GLfloat *tempDepthImage = NULL, *depthPtr = NULL; const GLfloat depthScale = ctx->DrawBuffer->_DepthMaxF; const GLuint stencilMask = ctx->Stencil.WriteMask[0]; const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; const GLboolean shiftOrOffset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset; const GLboolean scaleOrBias = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0; GLint overlapping; depthDrawRb = ctx->DrawBuffer->_DepthBuffer; depthReadRb = ctx->ReadBuffer->_DepthBuffer; stencilReadRb = ctx->ReadBuffer->_StencilBuffer; ASSERT(depthDrawRb); ASSERT(depthReadRb); ASSERT(stencilReadRb); /* Determine if copy should be bottom-to-top or top-to-bottom */ if (srcY < destY) { /* top-down max-to-min */ sy = srcY + height - 1; dy = destY + height - 1; stepy = -1; } else { /* bottom-up min-to-max */ sy = srcY; dy = destY; stepy = 1; } if (ctx->DrawBuffer == ctx->ReadBuffer) { overlapping = regions_overlap(srcX, srcY, destX, destY, width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); } else { overlapping = GL_FALSE; } if (overlapping) { GLint ssy = sy; if (stencilMask != 0x0) { tempStencilImage = (GLstencil *) _mesa_malloc(width * height * sizeof(GLstencil)); if (!tempStencilImage) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels"); return; } /* get copy of stencil pixels */ stencilPtr = tempStencilImage; for (j = 0; j < height; j++, ssy += stepy) { _swrast_read_stencil_span(ctx, stencilReadRb, width, srcX, ssy, stencilPtr); stencilPtr += width; } stencilPtr = tempStencilImage; } if (ctx->Depth.Mask) { tempDepthImage = (GLfloat *) _mesa_malloc(width * height * sizeof(GLfloat)); if (!tempDepthImage) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels"); _mesa_free(tempStencilImage); return; } /* get copy of depth pixels */ depthPtr = tempDepthImage; for (j = 0; j < height; j++, ssy += stepy) { _swrast_read_depth_span_float(ctx, depthReadRb, width, srcX, ssy, depthPtr); depthPtr += width; } depthPtr = tempDepthImage; } } for (j = 0; j < height; j++, sy += stepy, dy += stepy) { if (stencilMask != 0x0) { GLstencil stencil[MAX_WIDTH]; /* Get stencil values */ if (overlapping) { _mesa_memcpy(stencil, stencilPtr, width * sizeof(GLstencil)); stencilPtr += width; } else { _swrast_read_stencil_span(ctx, stencilReadRb, width, srcX, sy, stencil); } /* Apply shift, offset, look-up table */ if (shiftOrOffset) { _mesa_shift_and_offset_stencil(ctx, width, stencil); } if (ctx->Pixel.MapStencilFlag) { _mesa_map_stencil(ctx, width, stencil); } /* Write values */ if (zoom) { _swrast_write_zoomed_stencil_span(ctx, destX, destY, width, destX, dy, stencil); } else { _swrast_write_stencil_span( ctx, width, destX, dy, stencil ); } } if (ctx->Depth.Mask) { GLfloat depth[MAX_WIDTH]; GLuint zVals32[MAX_WIDTH]; GLushort zVals16[MAX_WIDTH]; GLvoid *zVals; GLuint zBytes; /* get depth values */ if (overlapping) { _mesa_memcpy(depth, depthPtr, width * sizeof(GLfloat)); depthPtr += width; } else { _swrast_read_depth_span_float(ctx, depthReadRb, width, srcX, sy, depth); } /* scale & bias */ if (scaleOrBias) { _mesa_scale_and_bias_depth(ctx, width, depth); } /* convert to integer Z values */ if (depthDrawRb->DataType == GL_UNSIGNED_SHORT) { GLint k; for (k = 0; k < width; k++) zVals16[k] = (GLushort) (depth[k] * depthScale); zVals = zVals16; zBytes = 2; } else { GLint k; for (k = 0; k < width; k++) zVals32[k] = (GLuint) (depth[k] * depthScale); zVals = zVals32; zBytes = 4; } /* Write values */ if (zoom) { _swrast_write_zoomed_z_span(ctx, destX, destY, width, destX, dy, zVals); } else { _swrast_put_row(ctx, depthDrawRb, width, destX, dy, zVals, zBytes); } } } if (tempStencilImage) _mesa_free(tempStencilImage); if (tempDepthImage) _mesa_free(tempDepthImage); }
static void copy_stencil_pixels( GLcontext *ctx, GLint srcx, GLint srcy, GLint width, GLint height, GLint destx, GLint desty ) { struct gl_framebuffer *fb = ctx->ReadBuffer; struct gl_renderbuffer *rb = fb->_StencilBuffer; GLint sy, dy, stepy; GLint j; GLstencil *p, *tmpImage; const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset; GLint overlapping; if (!rb) { /* no readbuffer - OK */ return; } /* Determine if copy should be bottom-to-top or top-to-bottom */ if (srcy < desty) { /* top-down max-to-min */ sy = srcy + height - 1; dy = desty + height - 1; stepy = -1; } else { /* bottom-up min-to-max */ sy = srcy; dy = desty; stepy = 1; } if (ctx->DrawBuffer == ctx->ReadBuffer) { overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); } else { overlapping = GL_FALSE; } if (overlapping) { GLint ssy = sy; tmpImage = (GLstencil *) _mesa_malloc(width * height * sizeof(GLstencil)); if (!tmpImage) { _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); return; } p = tmpImage; for (j = 0; j < height; j++, ssy += stepy) { _swrast_read_stencil_span( ctx, rb, width, srcx, ssy, p ); p += width; } p = tmpImage; } else { tmpImage = NULL; /* silence compiler warning */ p = NULL; } for (j = 0; j < height; j++, sy += stepy, dy += stepy) { GLstencil stencil[MAX_WIDTH]; /* Get stencil values */ if (overlapping) { _mesa_memcpy(stencil, p, width * sizeof(GLstencil)); p += width; } else { _swrast_read_stencil_span( ctx, rb, width, srcx, sy, stencil ); } /* Apply shift, offset, look-up table */ if (shift_or_offset) { _mesa_shift_and_offset_stencil( ctx, width, stencil ); } if (ctx->Pixel.MapStencilFlag) { _mesa_map_stencil( ctx, width, stencil ); } /* Write stencil values */ if (zoom) { _swrast_write_zoomed_stencil_span(ctx, destx, desty, width, destx, dy, stencil); } else { _swrast_write_stencil_span( ctx, width, destx, dy, stencil ); } } if (overlapping) _mesa_free(tmpImage); }
/* * TODO: Optimize!!!! */ static void copy_depth_pixels( GLcontext *ctx, GLint srcx, GLint srcy, GLint width, GLint height, GLint destx, GLint desty ) { SWcontext *swrast = SWRAST_CONTEXT(ctx); struct gl_framebuffer *fb = ctx->ReadBuffer; struct gl_renderbuffer *readRb = fb->_DepthBuffer; const GLfloat depthMax = fb->_DepthMaxF; GLfloat *p, *tmpImage; GLint sy, dy, stepy; GLint i, j; const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; GLint overlapping; struct sw_span span; if (!readRb) { /* no readbuffer - OK */ return; } INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_Z); /* Determine if copy should be bottom-to-top or top-to-bottom */ if (srcy<desty) { /* top-down max-to-min */ sy = srcy + height - 1; dy = desty + height - 1; stepy = -1; } else { /* bottom-up min-to-max */ sy = srcy; dy = desty; stepy = 1; } if (ctx->DrawBuffer == ctx->ReadBuffer) { overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); } else { overlapping = GL_FALSE; } _swrast_span_default_color(ctx, &span); if (swrast->_FogEnabled) _swrast_span_default_fog(ctx, &span); if (overlapping) { GLint ssy = sy; tmpImage = (GLfloat *) _mesa_malloc(width * height * sizeof(GLfloat)); if (!tmpImage) { _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); return; } p = tmpImage; for (j = 0; j < height; j++, ssy += stepy) { _swrast_read_depth_span_float(ctx, readRb, width, srcx, ssy, p); p += width; } p = tmpImage; } else { tmpImage = NULL; /* silence compiler warning */ p = NULL; } for (j = 0; j < height; j++, sy += stepy, dy += stepy) { GLfloat depth[MAX_WIDTH]; /* get depth values */ if (overlapping) { _mesa_memcpy(depth, p, width * sizeof(GLfloat)); p += width; } else { _swrast_read_depth_span_float(ctx, readRb, width, srcx, sy, depth); } /* apply scale and bias */ for (i = 0; i < width; i++) { GLfloat d = depth[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias; span.array->z[i] = (GLuint) (CLAMP(d, 0.0F, 1.0F) * depthMax); } /* write depth values */ span.x = destx; span.y = dy; span.end = width; if (fb->Visual.rgbMode) { if (zoom) _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span, (const GLchan (*)[4]) span.array->rgba); else _swrast_write_rgba_span(ctx, &span); } else { if (zoom) _swrast_write_zoomed_index_span(ctx, destx, desty, &span); else _swrast_write_index_span(ctx, &span); } } if (overlapping) _mesa_free(tmpImage); }
static void copy_ci_pixels( GLcontext *ctx, GLint srcx, GLint srcy, GLint width, GLint height, GLint destx, GLint desty ) { SWcontext *swrast = SWRAST_CONTEXT(ctx); GLuint *tmpImage,*p; GLint sy, dy, stepy; GLint j; const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset; GLint overlapping; struct sw_span span; if (!ctx->ReadBuffer->_ColorReadBuffer) { /* no readbuffer - OK */ return; } INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_INDEX); /* Determine if copy should be bottom-to-top or top-to-bottom */ if (srcy<desty) { /* top-down max-to-min */ sy = srcy + height - 1; dy = desty + height - 1; stepy = -1; } else { /* bottom-up min-to-max */ sy = srcy; dy = desty; stepy = 1; } if (ctx->DrawBuffer == ctx->ReadBuffer) { overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); } else { overlapping = GL_FALSE; } if (ctx->Depth.Test) _swrast_span_default_z(ctx, &span); if (swrast->_FogEnabled) _swrast_span_default_fog(ctx, &span); if (overlapping) { GLint ssy = sy; tmpImage = (GLuint *) _mesa_malloc(width * height * sizeof(GLuint)); if (!tmpImage) { _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); return; } /* read the image */ p = tmpImage; for (j = 0; j < height; j++, ssy += stepy) { _swrast_read_index_span( ctx, ctx->ReadBuffer->_ColorReadBuffer, width, srcx, ssy, p ); p += width; } p = tmpImage; } else { tmpImage = NULL; /* silence compiler warning */ p = NULL; } for (j = 0; j < height; j++, sy += stepy, dy += stepy) { /* Get color indexes */ if (overlapping) { _mesa_memcpy(span.array->index, p, width * sizeof(GLuint)); p += width; } else { _swrast_read_index_span( ctx, ctx->ReadBuffer->_ColorReadBuffer, width, srcx, sy, span.array->index ); } /* Apply shift, offset, look-up table */ if (shift_or_offset) { _mesa_shift_and_offset_ci( ctx, width, span.array->index ); } if (ctx->Pixel.MapColorFlag) { _mesa_map_ci( ctx, width, span.array->index ); } /* write color indexes */ span.x = destx; span.y = dy; span.end = width; if (zoom) _swrast_write_zoomed_index_span(ctx, destx, desty, &span); else _swrast_write_index_span(ctx, &span); } if (overlapping) _mesa_free(tmpImage); }
/* * RGBA copypixels */ static void copy_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy, GLint width, GLint height, GLint destx, GLint desty) { SWcontext *swrast = SWRAST_CONTEXT(ctx); struct gl_renderbuffer *drawRb; GLchan *tmpImage,*p; GLboolean quick_draw; GLint sy, dy, stepy, j; const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; GLint overlapping; const GLuint transferOps = ctx->_ImageTransferState; struct sw_span span; if (!ctx->ReadBuffer->_ColorReadBuffer) { /* no readbuffer - OK */ return; } INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA); if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) { copy_conv_rgba_pixels(ctx, srcx, srcy, width, height, destx, desty); return; } /* Determine if copy should be done bottom-to-top or top-to-bottom */ if (srcy < desty) { /* top-down max-to-min */ sy = srcy + height - 1; dy = desty + height - 1; stepy = -1; } else { /* bottom-up min-to-max */ sy = srcy; dy = desty; stepy = 1; } if (ctx->DrawBuffer == ctx->ReadBuffer) { overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); } else { overlapping = GL_FALSE; } if (ctx->Depth.Test) _swrast_span_default_z(ctx, &span); if (swrast->_FogEnabled) _swrast_span_default_fog(ctx, &span); if (SWRAST_CONTEXT(ctx)->_RasterMask == 0 && !zoom && destx >= 0 && destx + width <= (GLint) ctx->DrawBuffer->Width) { quick_draw = GL_TRUE; drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0][0]; } else { quick_draw = GL_FALSE; drawRb = NULL; } if (overlapping) { GLint ssy = sy; tmpImage = (GLchan *) _mesa_malloc(width * height * sizeof(GLchan) * 4); if (!tmpImage) { _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); return; } /* read the source image */ p = tmpImage; for (j = 0; j < height; j++, ssy += stepy) { _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer, width, srcx, ssy, (GLchan (*)[4]) p ); p += width * 4; } p = tmpImage; } else { tmpImage = NULL; /* silence compiler warnings */ p = NULL; } for (j = 0; j < height; j++, sy += stepy, dy += stepy) { /* Get source pixels */ if (overlapping) { /* get from buffered image */ ASSERT(width < MAX_WIDTH); _mesa_memcpy(span.array->rgba, p, width * sizeof(GLchan) * 4); p += width * 4; } else { /* get from framebuffer */ ASSERT(width < MAX_WIDTH); _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer, width, srcx, sy, span.array->rgba ); } if (transferOps) { GLfloat rgbaFloat[MAX_WIDTH][4]; /* convert to float, transfer, convert back to chan */ chan_span_to_float(width, (CONST GLchan (*)[4]) span.array->rgba, rgbaFloat); _mesa_apply_rgba_transfer_ops(ctx, transferOps, width, rgbaFloat); float_span_to_chan(width, (CONST GLfloat (*)[4]) rgbaFloat, span.array->rgba); } /* Write color span */ if (quick_draw && dy >= 0 && dy < (GLint) ctx->DrawBuffer->Height) { drawRb->PutRow(ctx, drawRb, width, destx, dy, span.array->rgba, NULL); } else { span.x = destx; span.y = dy; span.end = width; if (zoom) { _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span, (CONST GLchan (*)[4]) span.array->rgba); } else { _swrast_write_rgba_span(ctx, &span); } } } if (overlapping) _mesa_free(tmpImage); }
static void copy_stencil_pixels( struct gl_context *ctx, GLint srcx, GLint srcy, GLint width, GLint height, GLint destx, GLint desty ) { struct gl_framebuffer *fb = ctx->ReadBuffer; struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer; GLint sy, dy, stepy; GLint j; GLubyte *p, *tmpImage, *stencil; const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; GLint overlapping; if (!rb) { /* no readbuffer - OK */ return; } if (ctx->DrawBuffer == ctx->ReadBuffer) { overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); } else { overlapping = GL_FALSE; } /* Determine if copy should be bottom-to-top or top-to-bottom */ if (!overlapping && srcy < desty) { /* top-down max-to-min */ sy = srcy + height - 1; dy = desty + height - 1; stepy = -1; } else { /* bottom-up min-to-max */ sy = srcy; dy = desty; stepy = 1; } if (overlapping) { GLint ssy = sy; tmpImage = malloc(width * height * sizeof(GLubyte)); if (!tmpImage) { _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); return; } p = tmpImage; for (j = 0; j < height; j++, ssy += stepy) { _swrast_read_stencil_span( ctx, rb, width, srcx, ssy, p ); p += width; } p = tmpImage; } else { tmpImage = NULL; /* silence compiler warning */ p = NULL; } stencil = malloc(width * sizeof(GLubyte)); if (!stencil) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels()"); goto end; } for (j = 0; j < height; j++, sy += stepy, dy += stepy) { /* Get stencil values */ if (overlapping) { memcpy(stencil, p, width * sizeof(GLubyte)); p += width; } else { _swrast_read_stencil_span( ctx, rb, width, srcx, sy, stencil ); } _mesa_apply_stencil_transfer_ops(ctx, width, stencil); /* Write stencil values */ if (zoom) { _swrast_write_zoomed_stencil_span(ctx, destx, desty, width, destx, dy, stencil); } else { _swrast_write_stencil_span( ctx, width, destx, dy, stencil ); } } free(stencil); end: if (overlapping) free(tmpImage); }
/** * Try to do a glCopyPixels for simple cases with a blit by calling * pipe->resource_copy_region(). * * We can do this when we're copying color pixels (depth/stencil * eventually) with no pixel zoom, no pixel transfer ops, no * per-fragment ops, the src/dest regions don't overlap and the * src/dest pixel formats are the same. */ static GLboolean blit_copy_pixels(struct gl_context *ctx, GLint srcx, GLint srcy, GLsizei width, GLsizei height, GLint dstx, GLint dsty, GLenum type) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct gl_pixelstore_attrib pack, unpack; GLint readX, readY, readW, readH; if (type == GL_COLOR && ctx->Pixel.ZoomX == 1.0 && ctx->Pixel.ZoomY == 1.0 && ctx->_ImageTransferState == 0x0 && !ctx->Color.BlendEnabled && !ctx->Color.AlphaEnabled && !ctx->Depth.Test && !ctx->Fog.Enabled && !ctx->Stencil.Enabled && !ctx->FragmentProgram.Enabled && !ctx->VertexProgram.Enabled && !ctx->Shader.CurrentFragmentProgram && st_fb_orientation(ctx->ReadBuffer) == st_fb_orientation(ctx->DrawBuffer) && ctx->DrawBuffer->_NumColorDrawBuffers == 1 && !ctx->Query.CondRenderQuery) { struct st_renderbuffer *rbRead, *rbDraw; GLint drawX, drawY; /* * Clip the read region against the src buffer bounds. * We'll still allocate a temporary buffer/texture for the original * src region size but we'll only read the region which is on-screen. * This may mean that we draw garbage pixels into the dest region, but * that's expected. */ readX = srcx; readY = srcy; readW = width; readH = height; pack = ctx->DefaultPacking; if (!_mesa_clip_readpixels(ctx, &readX, &readY, &readW, &readH, &pack)) return GL_TRUE; /* all done */ /* clip against dest buffer bounds and scissor box */ drawX = dstx + pack.SkipPixels; drawY = dsty + pack.SkipRows; unpack = pack; if (!_mesa_clip_drawpixels(ctx, &drawX, &drawY, &readW, &readH, &unpack)) return GL_TRUE; /* all done */ readX = readX - pack.SkipPixels + unpack.SkipPixels; readY = readY - pack.SkipRows + unpack.SkipRows; rbRead = st_get_color_read_renderbuffer(ctx); rbDraw = st_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]); if ((rbRead != rbDraw || !regions_overlap(readX, readY, drawX, drawY, readW, readH)) && rbRead->Base.Format == rbDraw->Base.Format) { struct pipe_box srcBox; /* flip src/dst position if needed */ if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { /* both buffers will have the same orientation */ readY = ctx->ReadBuffer->Height - readY - readH; drawY = ctx->DrawBuffer->Height - drawY - readH; } u_box_2d(readX, readY, readW, readH, &srcBox); pipe->resource_copy_region(pipe, rbDraw->texture, rbDraw->rtt_level, drawX, drawY, 0, rbRead->texture, rbRead->rtt_level, &srcBox); return GL_TRUE; } } return GL_FALSE; }
/** * RGBA copypixels */ static void copy_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy, GLint width, GLint height, GLint destx, GLint desty) { SWcontext *swrast = SWRAST_CONTEXT(ctx); GLfloat *tmpImage, *p; GLint sy, dy, stepy, row; const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; GLint overlapping; GLuint transferOps = ctx->_ImageTransferState; SWspan span; if (!ctx->ReadBuffer->_ColorReadBuffer) { /* no readbuffer - OK */ return; } if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) { copy_conv_rgba_pixels(ctx, srcx, srcy, width, height, destx, desty); return; } else if (ctx->Pixel.Convolution1DEnabled) { /* make sure we don't apply 1D convolution */ transferOps &= ~(IMAGE_CONVOLUTION_BIT | IMAGE_POST_CONVOLUTION_SCALE_BIAS); } if (ctx->DrawBuffer == ctx->ReadBuffer) { overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); } else { overlapping = GL_FALSE; } /* Determine if copy should be done bottom-to-top or top-to-bottom */ if (!overlapping && srcy < desty) { /* top-down max-to-min */ sy = srcy + height - 1; dy = desty + height - 1; stepy = -1; } else { /* bottom-up min-to-max */ sy = srcy; dy = desty; stepy = 1; } INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA); if (ctx->Depth.Test) _swrast_span_default_z(ctx, &span); if (swrast->_FogEnabled) _swrast_span_default_fog(ctx, &span); _swrast_span_default_secondary_color(ctx, &span); if (overlapping) { tmpImage = (GLfloat *) _mesa_malloc(width * height * sizeof(GLfloat) * 4); if (!tmpImage) { _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); return; } /* read the source image as RGBA/float */ p = tmpImage; for (row = 0; row < height; row++) { _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer, width, srcx, sy + row, GL_FLOAT, p ); p += width * 4; } p = tmpImage; } else { tmpImage = NULL; /* silence compiler warnings */ p = NULL; } ASSERT(width < MAX_WIDTH); for (row = 0; row < height; row++, sy += stepy, dy += stepy) { GLvoid *rgba = span.array->attribs[FRAG_ATTRIB_COL0]; /* Get row/span of source pixels */ if (overlapping) { /* get from buffered image */ _mesa_memcpy(rgba, p, width * sizeof(GLfloat) * 4); p += width * 4; } else { /* get from framebuffer */ _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer, width, srcx, sy, GL_FLOAT, rgba ); } if (transferOps) { _mesa_apply_rgba_transfer_ops(ctx, transferOps, width, (GLfloat (*)[4]) rgba); } /* Write color span */ span.x = destx; span.y = dy; span.end = width; span.array->ChanType = GL_FLOAT; if (zoom) { _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span, rgba); } else { _swrast_write_rgba_span(ctx, &span); } } span.array->ChanType = CHAN_TYPE; /* restore */ if (overlapping) _mesa_free(tmpImage); }
/* * TODO: Optimize!!!! */ static void copy_depth_pixels( GLcontext *ctx, GLint srcx, GLint srcy, GLint width, GLint height, GLint destx, GLint desty ) { struct gl_framebuffer *fb = ctx->ReadBuffer; struct gl_renderbuffer *readRb = fb->_DepthBuffer; GLfloat *p, *tmpImage; GLint sy, dy, stepy; GLint j; const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; GLint overlapping; SWspan span; if (!readRb) { /* no readbuffer - OK */ return; } INIT_SPAN(span, GL_BITMAP); _swrast_span_default_attribs(ctx, &span); span.arrayMask = SPAN_Z; if (ctx->DrawBuffer == ctx->ReadBuffer) { overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); } else { overlapping = GL_FALSE; } /* Determine if copy should be bottom-to-top or top-to-bottom */ if (!overlapping && srcy < desty) { /* top-down max-to-min */ sy = srcy + height - 1; dy = desty + height - 1; stepy = -1; } else { /* bottom-up min-to-max */ sy = srcy; dy = desty; stepy = 1; } if (overlapping) { GLint ssy = sy; tmpImage = (GLfloat *) malloc(width * height * sizeof(GLfloat)); if (!tmpImage) { _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); return; } p = tmpImage; for (j = 0; j < height; j++, ssy += stepy) { _swrast_read_depth_span_float(ctx, readRb, width, srcx, ssy, p); p += width; } p = tmpImage; } else { tmpImage = NULL; /* silence compiler warning */ p = NULL; } for (j = 0; j < height; j++, sy += stepy, dy += stepy) { GLfloat depth[MAX_WIDTH]; /* get depth values */ if (overlapping) { memcpy(depth, p, width * sizeof(GLfloat)); p += width; } else { _swrast_read_depth_span_float(ctx, readRb, width, srcx, sy, depth); } /* apply scale and bias */ scale_and_bias_z(ctx, width, depth, span.array->z); /* write depth values */ span.x = destx; span.y = dy; span.end = width; if (zoom) _swrast_write_zoomed_depth_span(ctx, destx, desty, &span); else _swrast_write_rgba_span(ctx, &span); } if (overlapping) free(tmpImage); }
/** * Copy pixel block from src surface to dst surface. * Overlapping regions are acceptable. * Flipping and stretching are supported. * \param filter one of PIPE_TEX_MIPFILTER_NEAREST/LINEAR * \param writemask controls which channels in the dest surface are sourced * from the src surface. Disabled channels are sourced * from (0,0,0,1). */ void util_blit_pixels(struct blit_state *ctx, struct pipe_resource *src_tex, unsigned src_level, int srcX0, int srcY0, int srcX1, int srcY1, int srcZ0, struct pipe_surface *dst, int dstX0, int dstY0, int dstX1, int dstY1, float z, uint filter, uint writemask, uint zs_writemask) { struct pipe_context *pipe = ctx->pipe; struct pipe_screen *screen = pipe->screen; enum pipe_format src_format, dst_format; struct pipe_sampler_view *sampler_view = NULL; struct pipe_sampler_view sv_templ; struct pipe_surface *dst_surface; struct pipe_framebuffer_state fb; const int srcW = abs(srcX1 - srcX0); const int srcH = abs(srcY1 - srcY0); unsigned offset; boolean overlap; float s0, t0, s1, t1; boolean normalized; boolean is_stencil, is_depth, blit_depth, blit_stencil; const struct util_format_description *src_desc = util_format_description(src_tex->format); assert(filter == PIPE_TEX_MIPFILTER_NEAREST || filter == PIPE_TEX_MIPFILTER_LINEAR); assert(src_level <= src_tex->last_level); /* do the regions overlap? */ overlap = src_tex == dst->texture && dst->u.tex.level == src_level && dst->u.tex.first_layer == srcZ0 && regions_overlap(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1); src_format = util_format_linear(src_tex->format); dst_format = util_format_linear(dst->texture->format); /* See whether we will blit depth or stencil. */ is_depth = util_format_has_depth(src_desc); is_stencil = util_format_has_stencil(src_desc); blit_depth = is_depth && (zs_writemask & BLIT_WRITEMASK_Z); blit_stencil = is_stencil && (zs_writemask & BLIT_WRITEMASK_STENCIL); assert((writemask && !zs_writemask && !is_depth && !is_stencil) || (!writemask && (blit_depth || blit_stencil))); /* * Check for simple case: no format conversion, no flipping, no stretching, * no overlapping, same number of samples. * Filter mode should not matter since there's no stretching. */ if (formats_compatible(src_format, dst_format) && src_tex->nr_samples == dst->texture->nr_samples && is_stencil == blit_stencil && is_depth == blit_depth && srcX0 < srcX1 && dstX0 < dstX1 && srcY0 < srcY1 && dstY0 < dstY1 && (dstX1 - dstX0) == (srcX1 - srcX0) && (dstY1 - dstY0) == (srcY1 - srcY0) && !overlap) { struct pipe_box src_box; src_box.x = srcX0; src_box.y = srcY0; src_box.z = srcZ0; src_box.width = srcW; src_box.height = srcH; src_box.depth = 1; pipe->resource_copy_region(pipe, dst->texture, dst->u.tex.level, dstX0, dstY0, dst->u.tex.first_layer,/* dest */ src_tex, src_level, &src_box); return; } /* XXX Reading multisample textures is unimplemented. */ assert(src_tex->nr_samples <= 1); if (src_tex->nr_samples > 1) { return; } /* It's a mistake to call this function with a stencil format and * without shader stencil export. We don't do software fallbacks here. * Ignore stencil and only copy depth. */ if (blit_stencil && !ctx->has_stencil_export) { blit_stencil = FALSE; if (!blit_depth) return; } if (dst_format == dst->format) { dst_surface = dst; } else { struct pipe_surface templ = *dst; templ.format = dst_format; dst_surface = pipe->create_surface(pipe, dst->texture, &templ); } /* Create a temporary texture when src and dest alias. */ if (src_tex == dst_surface->texture && dst_surface->u.tex.level == src_level && dst_surface->u.tex.first_layer == srcZ0) { /* Make a temporary texture which contains a copy of the source pixels. * Then we'll sample from the temporary texture. */ struct pipe_resource texTemp; struct pipe_resource *tex; struct pipe_sampler_view sv_templ; struct pipe_box src_box; const int srcLeft = MIN2(srcX0, srcX1); const int srcTop = MIN2(srcY0, srcY1); if (srcLeft != srcX0) { /* left-right flip */ int tmp = dstX0; dstX0 = dstX1; dstX1 = tmp; } if (srcTop != srcY0) { /* up-down flip */ int tmp = dstY0; dstY0 = dstY1; dstY1 = tmp; } /* create temp texture */ memset(&texTemp, 0, sizeof(texTemp)); texTemp.target = ctx->internal_target; texTemp.format = src_format; texTemp.last_level = 0; texTemp.width0 = srcW; texTemp.height0 = srcH; texTemp.depth0 = 1; texTemp.array_size = 1; texTemp.bind = PIPE_BIND_SAMPLER_VIEW; tex = screen->resource_create(screen, &texTemp); if (!tex) return; src_box.x = srcLeft; src_box.y = srcTop; src_box.z = srcZ0; src_box.width = srcW; src_box.height = srcH; src_box.depth = 1; /* load temp texture */ pipe->resource_copy_region(pipe, tex, 0, 0, 0, 0, /* dest */ src_tex, src_level, &src_box); normalized = tex->target != PIPE_TEXTURE_RECT; if(normalized) { s0 = 0.0f; s1 = 1.0f; t0 = 0.0f; t1 = 1.0f; } else { s0 = 0; s1 = srcW; t0 = 0; t1 = srcH; } u_sampler_view_default_template(&sv_templ, tex, tex->format); if (!blit_depth && blit_stencil) { /* set a stencil-only format, e.g. Z24S8 --> X24S8 */ sv_templ.format = util_format_stencil_only(tex->format); assert(sv_templ.format != PIPE_FORMAT_NONE); } sampler_view = pipe->create_sampler_view(pipe, tex, &sv_templ); if (!sampler_view) { pipe_resource_reference(&tex, NULL); return; } pipe_resource_reference(&tex, NULL); } else { /* Directly sample from the source resource/texture */ u_sampler_view_default_template(&sv_templ, src_tex, src_format); if (!blit_depth && blit_stencil) { /* set a stencil-only format, e.g. Z24S8 --> X24S8 */ sv_templ.format = util_format_stencil_only(src_format); assert(sv_templ.format != PIPE_FORMAT_NONE); } sampler_view = pipe->create_sampler_view(pipe, src_tex, &sv_templ); if (!sampler_view) { return; } s0 = srcX0; s1 = srcX1; t0 = srcY0; t1 = srcY1; normalized = sampler_view->texture->target != PIPE_TEXTURE_RECT; if(normalized) { s0 /= (float)(u_minify(sampler_view->texture->width0, src_level)); s1 /= (float)(u_minify(sampler_view->texture->width0, src_level)); t0 /= (float)(u_minify(sampler_view->texture->height0, src_level)); t1 /= (float)(u_minify(sampler_view->texture->height0, src_level)); } } assert(screen->is_format_supported(screen, sampler_view->format, ctx->internal_target, sampler_view->texture->nr_samples, PIPE_BIND_SAMPLER_VIEW)); assert(screen->is_format_supported(screen, dst_format, ctx->internal_target, dst_surface->texture->nr_samples, is_depth || is_stencil ? PIPE_BIND_DEPTH_STENCIL : PIPE_BIND_RENDER_TARGET)); /* save state (restored below) */ cso_save_blend(ctx->cso); cso_save_depth_stencil_alpha(ctx->cso); cso_save_rasterizer(ctx->cso); cso_save_sample_mask(ctx->cso); cso_save_samplers(ctx->cso, PIPE_SHADER_FRAGMENT); cso_save_sampler_views(ctx->cso, PIPE_SHADER_FRAGMENT); cso_save_stream_outputs(ctx->cso); cso_save_viewport(ctx->cso); cso_save_framebuffer(ctx->cso); cso_save_fragment_shader(ctx->cso); cso_save_vertex_shader(ctx->cso); cso_save_geometry_shader(ctx->cso); cso_save_vertex_elements(ctx->cso); cso_save_aux_vertex_buffer_slot(ctx->cso); cso_save_render_condition(ctx->cso); /* set misc state we care about */ if (writemask) cso_set_blend(ctx->cso, &ctx->blend_write_color); else cso_set_blend(ctx->cso, &ctx->blend_keep_color); cso_set_sample_mask(ctx->cso, ~0); cso_set_rasterizer(ctx->cso, &ctx->rasterizer); cso_set_vertex_elements(ctx->cso, 2, ctx->velem); cso_set_stream_outputs(ctx->cso, 0, NULL, 0); cso_set_render_condition(ctx->cso, NULL, 0); /* default sampler state */ ctx->sampler.normalized_coords = normalized; ctx->sampler.min_img_filter = filter; ctx->sampler.mag_img_filter = filter; ctx->sampler.min_lod = src_level; ctx->sampler.max_lod = src_level; /* Depth stencil state, fragment shader and sampler setup depending on what * we blit. */ if (blit_depth && blit_stencil) { cso_single_sampler(ctx->cso, PIPE_SHADER_FRAGMENT, 0, &ctx->sampler); /* don't filter stencil */ ctx->sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; ctx->sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; cso_single_sampler(ctx->cso, PIPE_SHADER_FRAGMENT, 1, &ctx->sampler); cso_set_depth_stencil_alpha(ctx->cso, &ctx->dsa_write_depthstencil); set_depthstencil_fragment_shader(ctx, sampler_view->texture->target); } else if (blit_depth) { cso_single_sampler(ctx->cso, PIPE_SHADER_FRAGMENT, 0, &ctx->sampler); cso_set_depth_stencil_alpha(ctx->cso, &ctx->dsa_write_depth); set_depth_fragment_shader(ctx, sampler_view->texture->target); } else if (blit_stencil) { /* don't filter stencil */ ctx->sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; ctx->sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; cso_single_sampler(ctx->cso, PIPE_SHADER_FRAGMENT, 0, &ctx->sampler); cso_set_depth_stencil_alpha(ctx->cso, &ctx->dsa_write_stencil); set_stencil_fragment_shader(ctx, sampler_view->texture->target); } else { /* color */ cso_single_sampler(ctx->cso, PIPE_SHADER_FRAGMENT, 0, &ctx->sampler); cso_set_depth_stencil_alpha(ctx->cso, &ctx->dsa_keep_depthstencil); set_fragment_shader(ctx, writemask, sampler_view->texture->target); } cso_single_sampler_done(ctx->cso, PIPE_SHADER_FRAGMENT); /* textures */ if (blit_depth && blit_stencil) { /* Setup two samplers, one for depth and the other one for stencil. */ struct pipe_sampler_view templ; struct pipe_sampler_view *views[2]; templ = *sampler_view; templ.format = util_format_stencil_only(templ.format); assert(templ.format != PIPE_FORMAT_NONE); views[0] = sampler_view; views[1] = pipe->create_sampler_view(pipe, views[0]->texture, &templ); cso_set_sampler_views(ctx->cso, PIPE_SHADER_FRAGMENT, 2, views); pipe_sampler_view_reference(&views[1], NULL); } else { cso_set_sampler_views(ctx->cso, PIPE_SHADER_FRAGMENT, 1, &sampler_view); } /* viewport */ ctx->viewport.scale[0] = 0.5f * dst_surface->width; ctx->viewport.scale[1] = 0.5f * dst_surface->height; ctx->viewport.scale[2] = 0.5f; ctx->viewport.scale[3] = 1.0f; ctx->viewport.translate[0] = 0.5f * dst_surface->width; ctx->viewport.translate[1] = 0.5f * dst_surface->height; ctx->viewport.translate[2] = 0.5f; ctx->viewport.translate[3] = 0.0f; cso_set_viewport(ctx->cso, &ctx->viewport); set_vertex_shader(ctx); cso_set_geometry_shader_handle(ctx->cso, NULL); /* drawing dest */ memset(&fb, 0, sizeof(fb)); fb.width = dst_surface->width; fb.height = dst_surface->height; if (blit_depth || blit_stencil) { fb.zsbuf = dst_surface; } else { fb.nr_cbufs = 1; fb.cbufs[0] = dst_surface; } cso_set_framebuffer(ctx->cso, &fb); /* draw quad */ offset = setup_vertex_data_tex(ctx, (float) dstX0 / dst_surface->width * 2.0f - 1.0f, (float) dstY0 / dst_surface->height * 2.0f - 1.0f, (float) dstX1 / dst_surface->width * 2.0f - 1.0f, (float) dstY1 / dst_surface->height * 2.0f - 1.0f, s0, t0, s1, t1, z); if (ctx->vbuf) { util_draw_vertex_buffer(ctx->pipe, ctx->cso, ctx->vbuf, cso_get_aux_vertex_buffer_slot(ctx->cso), offset, PIPE_PRIM_TRIANGLE_FAN, 4, /* verts */ 2); /* attribs/vert */ } /* restore state we changed */ cso_restore_blend(ctx->cso); cso_restore_depth_stencil_alpha(ctx->cso); cso_restore_rasterizer(ctx->cso); cso_restore_sample_mask(ctx->cso); cso_restore_samplers(ctx->cso, PIPE_SHADER_FRAGMENT); cso_restore_sampler_views(ctx->cso, PIPE_SHADER_FRAGMENT); cso_restore_viewport(ctx->cso); cso_restore_framebuffer(ctx->cso); cso_restore_fragment_shader(ctx->cso); cso_restore_vertex_shader(ctx->cso); cso_restore_geometry_shader(ctx->cso); cso_restore_vertex_elements(ctx->cso); cso_restore_aux_vertex_buffer_slot(ctx->cso); cso_restore_stream_outputs(ctx->cso); cso_restore_render_condition(ctx->cso); pipe_sampler_view_reference(&sampler_view, NULL); if (dst_surface != dst) pipe_surface_reference(&dst_surface, NULL); }
static bool opt_cmod_propagation_local(const gen_device_info *devinfo, bblock_t *block) { bool progress = false; int ip = block->end_ip + 1; foreach_inst_in_block_reverse_safe(fs_inst, inst, block) { ip--; if ((inst->opcode != BRW_OPCODE_AND && inst->opcode != BRW_OPCODE_CMP && inst->opcode != BRW_OPCODE_MOV) || inst->predicate != BRW_PREDICATE_NONE || !inst->dst.is_null() || inst->src[0].file != VGRF || inst->src[0].abs) continue; /* Only an AND.NZ can be propagated. Many AND.Z instructions are * generated (for ir_unop_not in fs_visitor::emit_bool_to_cond_code). * Propagating those would require inverting the condition on the CMP. * This changes both the flag value and the register destination of the * CMP. That result may be used elsewhere, so we can't change its value * on a whim. */ if (inst->opcode == BRW_OPCODE_AND && !(inst->src[1].is_one() && inst->conditional_mod == BRW_CONDITIONAL_NZ && !inst->src[0].negate)) continue; if (inst->opcode == BRW_OPCODE_CMP && !inst->src[1].is_zero()) continue; if (inst->opcode == BRW_OPCODE_MOV && inst->conditional_mod != BRW_CONDITIONAL_NZ) continue; bool read_flag = false; foreach_inst_in_block_reverse_starting_from(fs_inst, scan_inst, inst) { if (regions_overlap(scan_inst->dst, scan_inst->size_written, inst->src[0], inst->size_read(0))) { if (scan_inst->is_partial_write() || scan_inst->dst.offset != inst->src[0].offset || scan_inst->exec_size != inst->exec_size) break; /* CMP's result is the same regardless of dest type. */ if (inst->conditional_mod == BRW_CONDITIONAL_NZ && scan_inst->opcode == BRW_OPCODE_CMP && (inst->dst.type == BRW_REGISTER_TYPE_D || inst->dst.type == BRW_REGISTER_TYPE_UD)) { inst->remove(block); progress = true; break; } /* If the AND wasn't handled by the previous case, it isn't safe * to remove it. */ if (inst->opcode == BRW_OPCODE_AND) break; /* Comparisons operate differently for ints and floats */ if (scan_inst->dst.type != inst->dst.type && (scan_inst->dst.type == BRW_REGISTER_TYPE_F || inst->dst.type == BRW_REGISTER_TYPE_F)) break; /* If the instruction generating inst's source also wrote the * flag, and inst is doing a simple .nz comparison, then inst * is redundant - the appropriate value is already in the flag * register. Delete inst. */ if (inst->conditional_mod == BRW_CONDITIONAL_NZ && !inst->src[0].negate && scan_inst->flags_written()) { inst->remove(block); progress = true; break; } /* The conditional mod of the CMP/CMPN instructions behaves * specially because the flag output is not calculated from the * result of the instruction, but the other way around, which * means that even if the condmod to propagate and the condmod * from the CMP instruction are the same they will in general give * different results because they are evaluated based on different * inputs. */ if (scan_inst->opcode == BRW_OPCODE_CMP || scan_inst->opcode == BRW_OPCODE_CMPN) break; /* Otherwise, try propagating the conditional. */ enum brw_conditional_mod cond = inst->src[0].negate ? brw_swap_cmod(inst->conditional_mod) : inst->conditional_mod; if (scan_inst->can_do_cmod() && ((!read_flag && scan_inst->conditional_mod == BRW_CONDITIONAL_NONE) || scan_inst->conditional_mod == cond)) { scan_inst->conditional_mod = cond; inst->remove(block); progress = true; } break; } if (scan_inst->flags_written()) break; read_flag = read_flag || scan_inst->flags_read(devinfo); } }
/** * RGBA copypixels */ static void copy_rgba_pixels(struct gl_context *ctx, GLint srcx, GLint srcy, GLint width, GLint height, GLint destx, GLint desty) { GLfloat *tmpImage, *p; GLint sy, dy, stepy, row; const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; GLint overlapping; GLuint transferOps = ctx->_ImageTransferState; SWspan span; if (!ctx->ReadBuffer->_ColorReadBuffer) { /* no readbuffer - OK */ return; } if (ctx->DrawBuffer == ctx->ReadBuffer) { overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); } else { overlapping = GL_FALSE; } /* Determine if copy should be done bottom-to-top or top-to-bottom */ if (!overlapping && srcy < desty) { /* top-down max-to-min */ sy = srcy + height - 1; dy = desty + height - 1; stepy = -1; } else { /* bottom-up min-to-max */ sy = srcy; dy = desty; stepy = 1; } INIT_SPAN(span, GL_BITMAP); _swrast_span_default_attribs(ctx, &span); span.arrayMask = SPAN_RGBA; span.arrayAttribs = VARYING_BIT_COL0; /* we'll fill in COL0 attrib values */ if (overlapping) { tmpImage = malloc(width * height * sizeof(GLfloat) * 4); if (!tmpImage) { _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); return; } /* read the source image as RGBA/float */ p = tmpImage; for (row = 0; row < height; row++) { _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer, width, srcx, sy + row, p ); p += width * 4; } p = tmpImage; } else { tmpImage = NULL; /* silence compiler warnings */ p = NULL; } ASSERT(width < SWRAST_MAX_WIDTH); for (row = 0; row < height; row++, sy += stepy, dy += stepy) { GLvoid *rgba = span.array->attribs[VARYING_SLOT_COL0]; /* Get row/span of source pixels */ if (overlapping) { /* get from buffered image */ memcpy(rgba, p, width * sizeof(GLfloat) * 4); p += width * 4; } else { /* get from framebuffer */ _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer, width, srcx, sy, rgba ); } if (transferOps) { _mesa_apply_rgba_transfer_ops(ctx, transferOps, width, (GLfloat (*)[4]) rgba); } /* Write color span */ span.x = destx; span.y = dy; span.end = width; span.array->ChanType = GL_FLOAT; if (zoom) { _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span, rgba); } else { _swrast_write_rgba_span(ctx, &span); } } span.array->ChanType = CHAN_TYPE; /* restore */ if (overlapping) free(tmpImage); }
static bool opt_saturate_propagation_local(fs_visitor *v, bblock_t *block) { bool progress = false; int ip = block->end_ip + 1; foreach_inst_in_block_reverse(fs_inst, inst, block) { ip--; if (inst->opcode != BRW_OPCODE_MOV || !inst->saturate || inst->dst.file != VGRF || inst->dst.type != inst->src[0].type || inst->src[0].file != VGRF || inst->src[0].abs) continue; int src_var = v->live_intervals->var_from_reg(inst->src[0]); int src_end_ip = v->live_intervals->end[src_var]; bool interfered = false; foreach_inst_in_block_reverse_starting_from(fs_inst, scan_inst, inst) { if (regions_overlap(scan_inst->dst, scan_inst->size_written, inst->src[0], inst->size_read(0))) { if (scan_inst->is_partial_write() || (scan_inst->dst.type != inst->dst.type && !scan_inst->can_change_types())) break; if (scan_inst->saturate) { inst->saturate = false; progress = true; } else if (src_end_ip == ip || inst->dst.equals(inst->src[0])) { if (scan_inst->can_do_saturate()) { if (scan_inst->dst.type != inst->dst.type) { scan_inst->dst.type = inst->dst.type; for (int i = 0; i < scan_inst->sources; i++) { scan_inst->src[i].type = inst->dst.type; } } if (inst->src[0].negate) { if (scan_inst->opcode == BRW_OPCODE_MUL) { scan_inst->src[0].negate = !scan_inst->src[0].negate; inst->src[0].negate = false; } else if (scan_inst->opcode == BRW_OPCODE_MAD) { scan_inst->src[0].negate = !scan_inst->src[0].negate; scan_inst->src[1].negate = !scan_inst->src[1].negate; inst->src[0].negate = false; } else if (scan_inst->opcode == BRW_OPCODE_ADD) { if (scan_inst->src[1].file == IMM) { if (!brw_negate_immediate(scan_inst->src[1].type, &scan_inst->src[1].as_brw_reg())) { break; } } else { scan_inst->src[1].negate = !scan_inst->src[1].negate; } scan_inst->src[0].negate = !scan_inst->src[0].negate; inst->src[0].negate = false; } else { break; } } scan_inst->saturate = true; inst->saturate = false; progress = true; } } break; } for (int i = 0; i < scan_inst->sources; i++) { if (scan_inst->src[i].file == VGRF && scan_inst->src[i].nr == inst->src[0].nr && scan_inst->src[i].offset / REG_SIZE == inst->src[0].offset / REG_SIZE) { if (scan_inst->opcode != BRW_OPCODE_MOV || !scan_inst->saturate || scan_inst->src[0].abs || scan_inst->src[0].negate || scan_inst->src[0].abs != inst->src[0].abs || scan_inst->src[0].negate != inst->src[0].negate) { interfered = true; break; } } } if (interfered) break; } }
/** * Copy pixel block from src surface to dst surface. * Overlapping regions are acceptable. * Flipping and stretching are supported. * \param filter one of PIPE_TEX_MIPFILTER_NEAREST/LINEAR * \param writemask controls which channels in the dest surface are sourced * from the src surface. Disabled channels are sourced * from (0,0,0,1). */ void util_blit_pixels(struct blit_state *ctx, struct pipe_resource *src_tex, unsigned src_level, int srcX0, int srcY0, int srcX1, int srcY1, int srcZ0, struct pipe_surface *dst, int dstX0, int dstY0, int dstX1, int dstY1, float z, uint filter, uint writemask, uint zs_writemask) { struct pipe_context *pipe = ctx->pipe; enum pipe_format src_format, dst_format; const int srcW = abs(srcX1 - srcX0); const int srcH = abs(srcY1 - srcY0); boolean overlap; boolean is_stencil, is_depth, blit_depth, blit_stencil; const struct util_format_description *src_desc = util_format_description(src_tex->format); struct pipe_blit_info info; assert(filter == PIPE_TEX_MIPFILTER_NEAREST || filter == PIPE_TEX_MIPFILTER_LINEAR); assert(src_level <= src_tex->last_level); /* do the regions overlap? */ overlap = src_tex == dst->texture && dst->u.tex.level == src_level && dst->u.tex.first_layer == srcZ0 && regions_overlap(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1); src_format = util_format_linear(src_tex->format); dst_format = util_format_linear(dst->texture->format); /* See whether we will blit depth or stencil. */ is_depth = util_format_has_depth(src_desc); is_stencil = util_format_has_stencil(src_desc); blit_depth = is_depth && (zs_writemask & BLIT_WRITEMASK_Z); blit_stencil = is_stencil && (zs_writemask & BLIT_WRITEMASK_STENCIL); assert((writemask && !zs_writemask && !is_depth && !is_stencil) || (!writemask && (blit_depth || blit_stencil))); /* * XXX: z parameter is deprecated. dst->u.tex.first_layer * specificies the destination layer. */ assert(z == 0.0f); /* * Check for simple case: no format conversion, no flipping, no stretching, * no overlapping, same number of samples. * Filter mode should not matter since there's no stretching. */ if (formats_compatible(src_format, dst_format) && src_tex->nr_samples == dst->texture->nr_samples && is_stencil == blit_stencil && is_depth == blit_depth && srcX0 < srcX1 && dstX0 < dstX1 && srcY0 < srcY1 && dstY0 < dstY1 && (dstX1 - dstX0) == (srcX1 - srcX0) && (dstY1 - dstY0) == (srcY1 - srcY0) && !overlap) { struct pipe_box src_box; src_box.x = srcX0; src_box.y = srcY0; src_box.z = srcZ0; src_box.width = srcW; src_box.height = srcH; src_box.depth = 1; pipe->resource_copy_region(pipe, dst->texture, dst->u.tex.level, dstX0, dstY0, dst->u.tex.first_layer,/* dest */ src_tex, src_level, &src_box); return; } memset(&info, 0, sizeof info); info.dst.resource = dst->texture; info.dst.level = dst->u.tex.level; info.dst.box.x = dstX0; info.dst.box.y = dstY0; info.dst.box.z = dst->u.tex.first_layer; info.dst.box.width = dstX1 - dstX0; info.dst.box.height = dstY1 - dstY0; assert(info.dst.box.width >= 0); assert(info.dst.box.height >= 0); info.dst.box.depth = 1; info.dst.format = dst->texture->format; info.src.resource = src_tex; info.src.level = src_level; info.src.box.x = srcX0; info.src.box.y = srcY0; info.src.box.z = srcZ0; info.src.box.width = srcX1 - srcX0; info.src.box.height = srcY1 - srcY0; info.src.box.depth = 1; info.src.format = src_tex->format; info.mask = writemask | (zs_writemask << 4); info.filter = filter; info.scissor_enable = 0; pipe->blit(pipe, &info); }
static void copy_ci_pixels( GLcontext *ctx, GLint srcx, GLint srcy, GLint width, GLint height, GLint destx, GLint desty ) { GLuint *tmpImage,*p; GLint sy, dy, stepy; GLint j; const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; GLint overlapping; SWspan span; if (!ctx->ReadBuffer->_ColorReadBuffer) { /* no readbuffer - OK */ return; } INIT_SPAN(span, GL_BITMAP); _swrast_span_default_attribs(ctx, &span); span.arrayMask = SPAN_INDEX; if (ctx->DrawBuffer == ctx->ReadBuffer) { overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); } else { overlapping = GL_FALSE; } /* Determine if copy should be bottom-to-top or top-to-bottom */ if (!overlapping && srcy < desty) { /* top-down max-to-min */ sy = srcy + height - 1; dy = desty + height - 1; stepy = -1; } else { /* bottom-up min-to-max */ sy = srcy; dy = desty; stepy = 1; } if (overlapping) { GLint ssy = sy; tmpImage = (GLuint *) _mesa_malloc(width * height * sizeof(GLuint)); if (!tmpImage) { _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); return; } /* read the image */ p = tmpImage; for (j = 0; j < height; j++, ssy += stepy) { _swrast_read_index_span( ctx, ctx->ReadBuffer->_ColorReadBuffer, width, srcx, ssy, p ); p += width; } p = tmpImage; } else { tmpImage = NULL; /* silence compiler warning */ p = NULL; } for (j = 0; j < height; j++, sy += stepy, dy += stepy) { /* Get color indexes */ if (overlapping) { _mesa_memcpy(span.array->index, p, width * sizeof(GLuint)); p += width; } else { _swrast_read_index_span( ctx, ctx->ReadBuffer->_ColorReadBuffer, width, srcx, sy, span.array->index ); } if (ctx->_ImageTransferState) _mesa_apply_ci_transfer_ops(ctx, ctx->_ImageTransferState, width, span.array->index); /* write color indexes */ span.x = destx; span.y = dy; span.end = width; if (zoom) _swrast_write_zoomed_index_span(ctx, destx, desty, &span); else _swrast_write_index_span(ctx, &span); } if (overlapping) _mesa_free(tmpImage); }