Commit 73771b1f by Alexis Hetu Committed by Alexis Hétu

Allow blitting with out of bounds source coordinates

Removed early return on source rectangle validation, in order to allow out of bounds coordinates as an input to the blitter. Fixes 31 *out_of_bounds* failures in: dEQP-GLES3.functional.fbo.blit.default_framebuffer Also fixes 3 scissored blit failures in: dEQP-GLES3.functional.fragment_ops.scissor Change-Id: I0751678153aa0fc58bb7aa3a0270c358efb61330 Reviewed-on: https://swiftshader-review.googlesource.com/15388Tested-by: 's avatarAlexis Hétu <sugoi@google.com> Reviewed-by: 's avatarNicolas Capens <nicolascapens@google.com>
parent bc648b9e
...@@ -3947,7 +3947,7 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1 ...@@ -3947,7 +3947,7 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1
sw::SliceRect sourceRect; sw::SliceRect sourceRect;
sw::SliceRect destRect; sw::SliceRect destRect;
bool flipX = (srcX0 < srcX1) ^ (dstX0 < dstX1); bool flipX = (srcX0 < srcX1) ^ (dstX0 < dstX1);
bool flipy = (srcY0 < srcY1) ^ (dstY0 < dstY1); bool flipY = (srcY0 < srcY1) ^ (dstY0 < dstY1);
if(srcX0 < srcX1) if(srcX0 < srcX1)
{ {
...@@ -3993,100 +3993,26 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1 ...@@ -3993,100 +3993,26 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1
destRect.y1 = dstY0; destRect.y1 = dstY0;
} }
sw::Rect sourceScissoredRect = sourceRect; sw::RectF sourceScissoredRect(static_cast<float>(sourceRect.x0), static_cast<float>(sourceRect.y0),
static_cast<float>(sourceRect.x1), static_cast<float>(sourceRect.y1));
sw::Rect destScissoredRect = destRect; sw::Rect destScissoredRect = destRect;
if(mState.scissorTestEnabled) // Only write to parts of the destination framebuffer which pass the scissor test if(mState.scissorTestEnabled) // Only write to parts of the destination framebuffer which pass the scissor test
{ {
if(destRect.x0 < mState.scissorX) sw::Rect scissorRect(mState.scissorX, mState.scissorY, mState.scissorX + mState.scissorWidth, mState.scissorY + mState.scissorHeight);
{ Device::ClipDstRect(sourceScissoredRect, destScissoredRect, scissorRect, flipX, flipY);
int xDiff = mState.scissorX - destRect.x0;
destScissoredRect.x0 = mState.scissorX;
sourceScissoredRect.x0 += xDiff;
}
if(destRect.x1 > mState.scissorX + mState.scissorWidth)
{
int xDiff = destRect.x1 - (mState.scissorX + mState.scissorWidth);
destScissoredRect.x1 = mState.scissorX + mState.scissorWidth;
sourceScissoredRect.x1 -= xDiff;
}
if(destRect.y0 < mState.scissorY)
{
int yDiff = mState.scissorY - destRect.y0;
destScissoredRect.y0 = mState.scissorY;
sourceScissoredRect.y0 += yDiff;
}
if(destRect.y1 > mState.scissorY + mState.scissorHeight)
{
int yDiff = destRect.y1 - (mState.scissorY + mState.scissorHeight);
destScissoredRect.y1 = mState.scissorY + mState.scissorHeight;
sourceScissoredRect.y1 -= yDiff;
}
} }
sw::Rect sourceTrimmedRect = sourceScissoredRect; sw::SliceRectF sourceTrimmedRect = sourceScissoredRect;
sw::Rect destTrimmedRect = destScissoredRect; sw::SliceRect destTrimmedRect = destScissoredRect;
// The source & destination rectangles also may need to be trimmed if they fall out of the bounds of // The source & destination rectangles also may need to be trimmed if
// the actual draw and read surfaces. // they fall out of the bounds of the actual draw and read surfaces.
if(sourceTrimmedRect.x0 < 0) sw::Rect sourceTrimRect(0, 0, readBufferWidth, readBufferHeight);
{ Device::ClipSrcRect(sourceTrimmedRect, destTrimmedRect, sourceTrimRect, flipX, flipY);
int xDiff = 0 - sourceTrimmedRect.x0;
sourceTrimmedRect.x0 = 0;
destTrimmedRect.x0 += xDiff;
}
if(sourceTrimmedRect.x1 > readBufferWidth) sw::Rect destTrimRect(0, 0, drawBufferWidth, drawBufferHeight);
{ Device::ClipDstRect(sourceTrimmedRect, destTrimmedRect, destTrimRect, flipX, flipY);
int xDiff = sourceTrimmedRect.x1 - readBufferWidth;
sourceTrimmedRect.x1 = readBufferWidth;
destTrimmedRect.x1 -= xDiff;
}
if(sourceTrimmedRect.y0 < 0)
{
int yDiff = 0 - sourceTrimmedRect.y0;
sourceTrimmedRect.y0 = 0;
destTrimmedRect.y0 += yDiff;
}
if(sourceTrimmedRect.y1 > readBufferHeight)
{
int yDiff = sourceTrimmedRect.y1 - readBufferHeight;
sourceTrimmedRect.y1 = readBufferHeight;
destTrimmedRect.y1 -= yDiff;
}
if(destTrimmedRect.x0 < 0)
{
int xDiff = 0 - destTrimmedRect.x0;
destTrimmedRect.x0 = 0;
sourceTrimmedRect.x0 += xDiff;
}
if(destTrimmedRect.x1 > drawBufferWidth)
{
int xDiff = destTrimmedRect.x1 - drawBufferWidth;
destTrimmedRect.x1 = drawBufferWidth;
sourceTrimmedRect.x1 -= xDiff;
}
if(destTrimmedRect.y0 < 0)
{
int yDiff = 0 - destTrimmedRect.y0;
destTrimmedRect.y0 = 0;
sourceTrimmedRect.y0 += yDiff;
}
if(destTrimmedRect.y1 > drawBufferHeight)
{
int yDiff = destTrimmedRect.y1 - drawBufferHeight;
destTrimmedRect.y1 = drawBufferHeight;
sourceTrimmedRect.y1 -= yDiff;
}
bool partialBufferCopy = false; bool partialBufferCopy = false;
...@@ -4242,21 +4168,21 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1 ...@@ -4242,21 +4168,21 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1
if(blitRenderTarget || blitDepth || blitStencil) if(blitRenderTarget || blitDepth || blitStencil)
{ {
if(flipX)
{
swap(destTrimmedRect.x0, destTrimmedRect.x1);
}
if(flipY)
{
swap(destTrimmedRect.y0, destTrimmedRect.y1);
}
if(blitRenderTarget) if(blitRenderTarget)
{ {
egl::Image *readRenderTarget = readFramebuffer->getReadRenderTarget(); egl::Image *readRenderTarget = readFramebuffer->getReadRenderTarget();
egl::Image *drawRenderTarget = drawFramebuffer->getRenderTarget(0); egl::Image *drawRenderTarget = drawFramebuffer->getRenderTarget(0);
if(flipX) bool success = device->stretchRect(readRenderTarget, &sourceTrimmedRect, drawRenderTarget, &destTrimmedRect, (filter ? Device::USE_FILTER : 0) | Device::COLOR_BUFFER);
{
swap(destRect.x0, destRect.x1);
}
if(flipy)
{
swap(destRect.y0, destRect.y1);
}
bool success = device->stretchRect(readRenderTarget, &sourceRect, drawRenderTarget, &destRect, (filter ? Device::USE_FILTER : 0) | Device::COLOR_BUFFER);
readRenderTarget->release(); readRenderTarget->release();
drawRenderTarget->release(); drawRenderTarget->release();
...@@ -4273,7 +4199,7 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1 ...@@ -4273,7 +4199,7 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1
egl::Image *readRenderTarget = readFramebuffer->getDepthBuffer(); egl::Image *readRenderTarget = readFramebuffer->getDepthBuffer();
egl::Image *drawRenderTarget = drawFramebuffer->getDepthBuffer(); egl::Image *drawRenderTarget = drawFramebuffer->getDepthBuffer();
bool success = device->stretchRect(readRenderTarget, &sourceRect, drawRenderTarget, &destRect, (filter ? Device::USE_FILTER : 0) | Device::DEPTH_BUFFER); bool success = device->stretchRect(readRenderTarget, &sourceTrimmedRect, drawRenderTarget, &destTrimmedRect, (filter ? Device::USE_FILTER : 0) | Device::DEPTH_BUFFER);
readRenderTarget->release(); readRenderTarget->release();
drawRenderTarget->release(); drawRenderTarget->release();
...@@ -4290,7 +4216,7 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1 ...@@ -4290,7 +4216,7 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1
egl::Image *readRenderTarget = readFramebuffer->getStencilBuffer(); egl::Image *readRenderTarget = readFramebuffer->getStencilBuffer();
egl::Image *drawRenderTarget = drawFramebuffer->getStencilBuffer(); egl::Image *drawRenderTarget = drawFramebuffer->getStencilBuffer();
bool success = device->stretchRect(readRenderTarget, &sourceRect, drawRenderTarget, &destRect, (filter ? Device::USE_FILTER : 0) | Device::STENCIL_BUFFER); bool success = device->stretchRect(readRenderTarget, &sourceTrimmedRect, drawRenderTarget, &destTrimmedRect, (filter ? Device::USE_FILTER : 0) | Device::STENCIL_BUFFER);
readRenderTarget->release(); readRenderTarget->release();
drawRenderTarget->release(); drawRenderTarget->release();
......
...@@ -507,7 +507,7 @@ namespace es2 ...@@ -507,7 +507,7 @@ namespace es2
} }
} }
bool Device::stretchRect(sw::Surface *source, const sw::SliceRect *sourceRect, sw::Surface *dest, const sw::SliceRect *destRect, unsigned char flags) bool Device::stretchRect(sw::Surface *source, const sw::SliceRectF *sourceRect, sw::Surface *dest, const sw::SliceRect *destRect, unsigned char flags)
{ {
if(!source || !dest) if(!source || !dest)
{ {
...@@ -543,10 +543,10 @@ namespace es2 ...@@ -543,10 +543,10 @@ namespace es2
if(sourceRect) if(sourceRect)
{ {
sRect.x0 = (float)(sourceRect->x0); sRect.x0 = sourceRect->x0;
sRect.x1 = (float)(sourceRect->x1); sRect.x1 = sourceRect->x1;
sRect.y0 = (float)(sourceRect->y0); sRect.y0 = sourceRect->y0;
sRect.y1 = (float)(sourceRect->y1); sRect.y1 = sourceRect->y1;
sRect.slice = sourceRect->slice; sRect.slice = sourceRect->slice;
if(sRect.x0 > sRect.x1) if(sRect.x0 > sRect.x1)
...@@ -589,118 +589,16 @@ namespace es2 ...@@ -589,118 +589,16 @@ namespace es2
dRect.x1 = dWidth; dRect.x1 = dWidth;
} }
if(sRect.x0 < 0) sw::Rect srcClipRect(0, 0, sWidth, sHeight);
{ ClipSrcRect(sRect, dRect, srcClipRect, flipX, flipY);
float ratio = static_cast<float>(dRect.width()) / sRect.width();
float offsetf = roundf(-sRect.x0 * ratio);
int offset = static_cast<int>(offsetf);
if(flipX)
{
dRect.x1 -= offset;
}
else
{
dRect.x0 += offset;
}
sRect.x0 += offsetf / ratio;
}
if(sRect.x1 > sWidth)
{
float ratio = static_cast<float>(dRect.width()) / sRect.width();
float offsetf = roundf((sRect.x1 - (float)sWidth) * ratio);
int offset = static_cast<int>(offsetf);
if(flipX)
{
dRect.x0 += offset;
}
else
{
dRect.x1 -= offset;
}
sRect.x1 -= offsetf / ratio;
}
if(sRect.y0 < 0)
{
float ratio = static_cast<float>(dRect.height()) / sRect.height();
float offsetf = roundf(-sRect.y0 * ratio);
int offset = static_cast<int>(offsetf);
if(flipY)
{
dRect.y1 -= offset;
}
else
{
dRect.y0 += offset;
}
sRect.y0 += offsetf / ratio;
}
if(sRect.y1 > sHeight)
{
float ratio = static_cast<float>(dRect.height()) / sRect.height();
float offsetf = roundf((sRect.y1 - (float)sHeight) * ratio);
int offset = static_cast<int>(offsetf);
if(flipY)
{
dRect.y0 += offset;
}
else
{
dRect.y1 -= offset;
}
sRect.y1 -= offsetf / ratio;
}
if(dRect.x0 < 0) sw::Rect dstClipRect(0, 0, dWidth, dHeight);
{ ClipDstRect(sRect, dRect, dstClipRect, flipX, flipY);
float offset = (static_cast<float>(-dRect.x0) / static_cast<float>(dRect.width())) * sRect.width();
if(flipX) if((sRect.width() == 0) || (sRect.height() == 0) ||
{ (dRect.width() == 0) || (dRect.height() == 0))
sRect.x1 -= offset;
}
else
{
sRect.x0 += offset;
}
dRect.x0 = 0;
}
if(dRect.x1 > dWidth)
{
float offset = (static_cast<float>(dRect.x1 - dWidth) / static_cast<float>(dRect.width())) * sRect.width();
if(flipX)
{
sRect.x0 += offset;
}
else
{
sRect.x1 -= offset;
}
dRect.x1 = dWidth;
}
if(dRect.y0 < 0)
{
float offset = (static_cast<float>(-dRect.y0) / static_cast<float>(dRect.height())) * sRect.height();
if(flipY)
{
sRect.y1 -= offset;
}
else
{
sRect.y0 += offset;
}
dRect.y0 = 0;
}
if(dRect.y1 > dHeight)
{ {
float offset = (static_cast<float>(dRect.y1 - dHeight) / static_cast<float>(dRect.height())) * sRect.height(); return true; // no work to do
if(flipY)
{
sRect.y0 += offset;
}
else
{
sRect.y1 -= offset;
}
dRect.y1 = dHeight;
} }
if(!validRectangle(&sRect, source) || !validRectangle(&dRect, dest)) if(!validRectangle(&sRect, source) || !validRectangle(&dRect, dest))
...@@ -723,6 +621,7 @@ namespace es2 ...@@ -723,6 +621,7 @@ namespace es2
int sourcePitchB = isStencil ? source->getStencilPitchB() : source->getInternalPitchB(); int sourcePitchB = isStencil ? source->getStencilPitchB() : source->getInternalPitchB();
int destPitchB = isStencil ? dest->getStencilPitchB() : dest->getInternalPitchB(); int destPitchB = isStencil ? dest->getStencilPitchB() : dest->getInternalPitchB();
bool isOutOfBounds = (sRect.x0 < 0.0f) || (sRect.y0 < 0.0f) || (sRect.x1 > (float)sWidth) || (sRect.y1 > (float)sHeight);
bool scaling = (sRect.width() != (float)dRect.width()) || (sRect.height() != (float)dRect.height()); bool scaling = (sRect.width() != (float)dRect.width()) || (sRect.height() != (float)dRect.height());
bool equalFormats = source->getInternalFormat() == dest->getInternalFormat(); bool equalFormats = source->getInternalFormat() == dest->getInternalFormat();
bool hasQuadLayout = Surface::hasQuadLayout(source->getInternalFormat()) || Surface::hasQuadLayout(dest->getInternalFormat()); bool hasQuadLayout = Surface::hasQuadLayout(source->getInternalFormat()) || Surface::hasQuadLayout(dest->getInternalFormat());
...@@ -739,7 +638,7 @@ namespace es2 ...@@ -739,7 +638,7 @@ namespace es2
alpha0xFF = true; alpha0xFF = true;
} }
if(fullCopy && !scaling && equalFormats && !alpha0xFF && equalSlice && smallMargin && !flipX && !flipY) if(fullCopy && !scaling && !isOutOfBounds && equalFormats && !alpha0xFF && equalSlice && smallMargin && !flipX && !flipY)
{ {
byte *sourceBuffer = isStencil ? (byte*)source->lockStencil(0, 0, 0, PUBLIC) : (byte*)source->lockInternal(0, 0, 0, LOCK_READONLY, PUBLIC); byte *sourceBuffer = isStencil ? (byte*)source->lockStencil(0, 0, 0, PUBLIC) : (byte*)source->lockInternal(0, 0, 0, LOCK_READONLY, PUBLIC);
byte *destBuffer = isStencil ? (byte*)dest->lockStencil(0, 0, 0, PUBLIC) : (byte*)dest->lockInternal(0, 0, 0, LOCK_DISCARD, PUBLIC); byte *destBuffer = isStencil ? (byte*)dest->lockStencil(0, 0, 0, PUBLIC) : (byte*)dest->lockInternal(0, 0, 0, LOCK_DISCARD, PUBLIC);
...@@ -749,7 +648,7 @@ namespace es2 ...@@ -749,7 +648,7 @@ namespace es2
isStencil ? source->unlockStencil() : source->unlockInternal(); isStencil ? source->unlockStencil() : source->unlockInternal();
isStencil ? dest->unlockStencil() : dest->unlockInternal(); isStencil ? dest->unlockStencil() : dest->unlockInternal();
} }
else if(isDepth && !scaling && equalFormats && !hasQuadLayout) else if(isDepth && !scaling && !isOutOfBounds && equalFormats && !hasQuadLayout)
{ {
byte *sourceBuffer = (byte*)source->lockInternal((int)sRect.x0, (int)sRect.y0, 0, LOCK_READONLY, PUBLIC); byte *sourceBuffer = (byte*)source->lockInternal((int)sRect.x0, (int)sRect.y0, 0, LOCK_READONLY, PUBLIC);
byte *destBuffer = (byte*)dest->lockInternal(dRect.x0, dRect.y0, 0, fullCopy ? LOCK_DISCARD : LOCK_WRITEONLY, PUBLIC); byte *destBuffer = (byte*)dest->lockInternal(dRect.x0, dRect.y0, 0, fullCopy ? LOCK_DISCARD : LOCK_WRITEONLY, PUBLIC);
...@@ -759,7 +658,7 @@ namespace es2 ...@@ -759,7 +658,7 @@ namespace es2
source->unlockInternal(); source->unlockInternal();
dest->unlockInternal(); dest->unlockInternal();
} }
else if((flags & Device::COLOR_BUFFER) && !scaling && equalFormats && !hasQuadLayout) else if((flags & Device::COLOR_BUFFER) && !scaling && !isOutOfBounds && equalFormats && !hasQuadLayout)
{ {
byte *sourceBytes = (byte*)source->lockInternal((int)sRect.x0, (int)sRect.y0, sourceRect->slice, LOCK_READONLY, PUBLIC); byte *sourceBytes = (byte*)source->lockInternal((int)sRect.x0, (int)sRect.y0, sourceRect->slice, LOCK_READONLY, PUBLIC);
byte *destBytes = (byte*)dest->lockInternal(dRect.x0, dRect.y0, destRect->slice, fullCopy ? LOCK_DISCARD : LOCK_WRITEONLY, PUBLIC); byte *destBytes = (byte*)dest->lockInternal(dRect.x0, dRect.y0, destRect->slice, fullCopy ? LOCK_DISCARD : LOCK_WRITEONLY, PUBLIC);
...@@ -796,8 +695,7 @@ namespace es2 ...@@ -796,8 +695,7 @@ namespace es2
swap(dRect.y0, dRect.y1); swap(dRect.y0, dRect.y1);
} }
SliceRectF sRectF((float)sRect.x0, (float)sRect.y0, (float)sRect.x1, (float)sRect.y1, sRect.slice); blit(source, sRect, dest, dRect, scaling && (flags & Device::USE_FILTER), isStencil);
blit(source, sRectF, dest, dRect, scaling && (flags & Device::USE_FILTER), isStencil);
} }
else UNREACHABLE(false); else UNREACHABLE(false);
...@@ -1034,17 +932,127 @@ namespace es2 ...@@ -1034,17 +932,127 @@ namespace es2
return false; return false;
} }
if(rect->x0 < 0 || rect->y0 < 0) return true;
}
void Device::ClipDstRect(sw::RectF &srcRect, sw::Rect &dstRect, sw::Rect &clipRect, bool flipX, bool flipY)
{
if(dstRect.x0 < clipRect.x0)
{ {
return false; float offset = (static_cast<float>(clipRect.x0 - dstRect.x0) / static_cast<float>(dstRect.width())) * srcRect.width();
if(flipX)
{
srcRect.x1 -= offset;
}
else
{
srcRect.x0 += offset;
}
dstRect.x0 = clipRect.x0;
} }
if(dstRect.x1 > clipRect.x1)
if(rect->x1 >(float)surface->getWidth() || rect->y1 >(float)surface->getHeight())
{ {
return false; float offset = (static_cast<float>(dstRect.x1 - clipRect.x1) / static_cast<float>(dstRect.width())) * srcRect.width();
if(flipX)
{
srcRect.x0 += offset;
}
else
{
srcRect.x1 -= offset;
}
dstRect.x1 = clipRect.x1;
} }
if(dstRect.y0 < clipRect.y0)
{
float offset = (static_cast<float>(clipRect.y0 - dstRect.y0) / static_cast<float>(dstRect.height())) * srcRect.height();
if(flipY)
{
srcRect.y1 -= offset;
}
else
{
srcRect.y0 += offset;
}
dstRect.y0 = clipRect.y0;
}
if(dstRect.y1 > clipRect.y1)
{
float offset = (static_cast<float>(dstRect.y1 - clipRect.y1) / static_cast<float>(dstRect.height())) * srcRect.height();
if(flipY)
{
srcRect.y0 += offset;
}
else
{
srcRect.y1 -= offset;
}
dstRect.y1 = clipRect.y1;
}
}
return true; void Device::ClipSrcRect(sw::RectF &srcRect, sw::Rect &dstRect, sw::Rect &clipRect, bool flipX, bool flipY)
{
if(srcRect.x0 < static_cast<float>(clipRect.x0))
{
float ratio = static_cast<float>(dstRect.width()) / srcRect.width();
float offsetf = roundf((static_cast<float>(clipRect.x0) - srcRect.x0) * ratio);
int offset = static_cast<int>(offsetf);
if(flipX)
{
dstRect.x1 -= offset;
}
else
{
dstRect.x0 += offset;
}
srcRect.x0 += offsetf / ratio;
}
if(srcRect.x1 > static_cast<float>(clipRect.x1))
{
float ratio = static_cast<float>(dstRect.width()) / srcRect.width();
float offsetf = roundf((srcRect.x1 - static_cast<float>(clipRect.x1)) * ratio);
int offset = static_cast<int>(offsetf);
if(flipX)
{
dstRect.x0 += offset;
}
else
{
dstRect.x1 -= offset;
}
srcRect.x1 -= offsetf / ratio;
}
if(srcRect.y0 < static_cast<float>(clipRect.y0))
{
float ratio = static_cast<float>(dstRect.height()) / srcRect.height();
float offsetf = roundf((static_cast<float>(clipRect.y0) - srcRect.y0) * ratio);
int offset = static_cast<int>(offsetf);
if(flipY)
{
dstRect.y1 -= offset;
}
else
{
dstRect.y0 += offset;
}
srcRect.y0 += offsetf / ratio;
}
if(srcRect.y1 > static_cast<float>(clipRect.y1))
{
float ratio = static_cast<float>(dstRect.height()) / srcRect.height();
float offsetf = roundf((srcRect.y1 - static_cast<float>(clipRect.y1)) * ratio);
int offset = static_cast<int>(offsetf);
if(flipY)
{
dstRect.y0 += offset;
}
else
{
dstRect.y1 -= offset;
}
srcRect.y1 -= offsetf / ratio;
}
} }
void Device::finish() void Device::finish()
......
...@@ -73,10 +73,13 @@ namespace es2 ...@@ -73,10 +73,13 @@ namespace es2
void setVertexShaderConstantF(unsigned int startRegister, const float *constantData, unsigned int count); void setVertexShaderConstantF(unsigned int startRegister, const float *constantData, unsigned int count);
void setViewport(const Viewport &viewport); void setViewport(const Viewport &viewport);
bool stretchRect(sw::Surface *sourceSurface, const sw::SliceRect *sourceRect, sw::Surface *destSurface, const sw::SliceRect *destRect, unsigned char flags); bool stretchRect(sw::Surface *sourceSurface, const sw::SliceRectF *sourceRect, sw::Surface *destSurface, const sw::SliceRect *destRect, unsigned char flags);
bool stretchCube(sw::Surface *sourceSurface, sw::Surface *destSurface); bool stretchCube(sw::Surface *sourceSurface, sw::Surface *destSurface);
void finish(); void finish();
static void ClipDstRect(sw::RectF &srcRect, sw::Rect &dstRect, sw::Rect &clipRect, bool flipX = false, bool flipY = false);
static void ClipSrcRect(sw::RectF &srcRect, sw::Rect &dstRect, sw::Rect &clipRect, bool flipX = false, bool flipY = false);
private: private:
sw::Context *const context; sw::Context *const context;
......
...@@ -460,7 +460,12 @@ bool Texture::copy(egl::Image *source, const sw::SliceRect &sourceRect, GLint xo ...@@ -460,7 +460,12 @@ bool Texture::copy(egl::Image *source, const sw::SliceRect &sourceRect, GLint xo
Device *device = getDevice(); Device *device = getDevice();
sw::SliceRect destRect(xoffset, yoffset, xoffset + (sourceRect.x1 - sourceRect.x0), yoffset + (sourceRect.y1 - sourceRect.y0), zoffset); sw::SliceRect destRect(xoffset, yoffset, xoffset + (sourceRect.x1 - sourceRect.x0), yoffset + (sourceRect.y1 - sourceRect.y0), zoffset);
bool success = device->stretchRect(source, &sourceRect, dest, &destRect, Device::ALL_BUFFERS); sw::SliceRectF sourceRectF(static_cast<float>(sourceRect.x0),
static_cast<float>(sourceRect.y0),
static_cast<float>(sourceRect.x1),
static_cast<float>(sourceRect.y1),
sourceRect.slice);
bool success = device->stretchRect(source, &sourceRectF, dest, &destRect, Device::ALL_BUFFERS);
if(!success) if(!success)
{ {
...@@ -1997,7 +2002,7 @@ void Texture2DArray::generateMipmaps() ...@@ -1997,7 +2002,7 @@ void Texture2DArray::generateMipmaps()
GLsizei srch = image[i - 1]->getHeight(); GLsizei srch = image[i - 1]->getHeight();
for(int z = 0; z < depth; ++z) for(int z = 0; z < depth; ++z)
{ {
sw::SliceRect srcRect(0, 0, srcw, srch, z); sw::SliceRectF srcRect(0.0f, 0.0f, static_cast<float>(srcw), static_cast<float>(srch), z);
sw::SliceRect dstRect(0, 0, w, h, z); sw::SliceRect dstRect(0, 0, w, h, z);
getDevice()->stretchRect(image[i - 1], &srcRect, image[i], &dstRect, Device::ALL_BUFFERS | Device::USE_FILTER); getDevice()->stretchRect(image[i - 1], &srcRect, image[i], &dstRect, Device::ALL_BUFFERS | Device::USE_FILTER);
} }
......
...@@ -1275,6 +1275,12 @@ namespace sw ...@@ -1275,6 +1275,12 @@ namespace sw
Int X = Int(x); Int X = Int(x);
Int Y = Int(y); Int Y = Int(y);
if(state.clampToEdge)
{
X = Clamp(X, 0, sWidth - 1);
Y = Clamp(Y, 0, sHeight - 1);
}
Pointer<Byte> s = source + ComputeOffset(X, Y, sPitchB, srcBytes, srcQuadLayout); Pointer<Byte> s = source + ComputeOffset(X, Y, sPitchB, srcBytes, srcQuadLayout);
if(!read(color, s, state)) if(!read(color, s, state))
...@@ -1296,6 +1302,12 @@ namespace sw ...@@ -1296,6 +1302,12 @@ namespace sw
Int X = Int(x); Int X = Int(x);
Int Y = Int(y); Int Y = Int(y);
if(state.clampToEdge)
{
X = Clamp(X, 0, sWidth - 1);
Y = Clamp(Y, 0, sHeight - 1);
}
Pointer<Byte> s = source + ComputeOffset(X, Y, sPitchB, srcBytes, srcQuadLayout); Pointer<Byte> s = source + ComputeOffset(X, Y, sPitchB, srcBytes, srcQuadLayout);
if(!read(color, s, state)) if(!read(color, s, state))
...@@ -1305,8 +1317,17 @@ namespace sw ...@@ -1305,8 +1317,17 @@ namespace sw
} }
else // Bilinear filtering else // Bilinear filtering
{ {
Float x0 = x - 0.5f; Float X = x;
Float y0 = y - 0.5f; Float Y = y;
if(state.clampToEdge)
{
X = Float(Clamp(Int(x), 0, sWidth - 1));
Y = Float(Clamp(Int(y), 0, sHeight - 1));
}
Float x0 = X - 0.5f;
Float y0 = Y - 0.5f;
Int X0 = Max(Int(x0), 0); Int X0 = Max(Int(x0), 0);
Int Y0 = Max(Int(y0), 0); Int Y0 = Max(Int(y0), 0);
...@@ -1379,6 +1400,10 @@ namespace sw ...@@ -1379,6 +1400,10 @@ namespace sw
} }
State state(options); State state(options);
state.clampToEdge = (sourceRect.x0 < 0.0f) ||
(sourceRect.y0 < 0.0f) ||
(sourceRect.x1 > (float)source->getWidth()) ||
(sourceRect.y1 > (float)source->getHeight());
bool useSourceInternal = !source->isExternalDirty(); bool useSourceInternal = !source->isExternalDirty();
bool useDestInternal = !dest->isExternalDirty(); bool useDestInternal = !dest->isExternalDirty();
......
...@@ -29,9 +29,9 @@ namespace sw ...@@ -29,9 +29,9 @@ namespace sw
{ {
Options() = default; Options() = default;
Options(bool filter, bool useStencil, bool convertSRGB) Options(bool filter, bool useStencil, bool convertSRGB)
: writeMask(0xF), clearOperation(false), filter(filter), useStencil(useStencil), convertSRGB(convertSRGB) {} : writeMask(0xF), clearOperation(false), filter(filter), useStencil(useStencil), convertSRGB(convertSRGB), clampToEdge(false) {}
Options(unsigned int writeMask) Options(unsigned int writeMask)
: writeMask(writeMask), clearOperation(true), filter(false), useStencil(false), convertSRGB(true) {} : writeMask(writeMask), clearOperation(true), filter(false), useStencil(false), convertSRGB(true), clampToEdge(false) {}
union union
{ {
...@@ -50,6 +50,7 @@ namespace sw ...@@ -50,6 +50,7 @@ namespace sw
bool filter : 1; bool filter : 1;
bool useStencil : 1; bool useStencil : 1;
bool convertSRGB : 1; bool convertSRGB : 1;
bool clampToEdge : 1;
}; };
struct State : Options struct State : Options
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment