Moved the clipping of blit rectangles to bounds or scissors into the Renderers since rounding to integers can cause errors when stretching in ES3.
TRAC #23650
Author: Geoff Lang
Signed-off-by: Jamie Madill
Signed-off-by: Shannon Woods
diff --git a/src/libGLESv2/renderer/Blit11.cpp b/src/libGLESv2/renderer/Blit11.cpp
index 2256117..7279f52 100644
--- a/src/libGLESv2/renderer/Blit11.cpp
+++ b/src/libGLESv2/renderer/Blit11.cpp
@@ -53,7 +53,8 @@
Blit11::Blit11(rx::Renderer11 *renderer)
: mRenderer(renderer), mShaderMap(compareBlitParameters), mVertexBuffer(NULL),
- mPointSampler(NULL), mLinearSampler(NULL), mRasterizerState(NULL), mDepthStencilState(NULL),
+ mPointSampler(NULL), mLinearSampler(NULL), mScissorEnabledRasterizerState(NULL),
+ mScissorDisabledRasterizerState(NULL), mDepthStencilState(NULL),
mQuad2DIL(NULL), mQuad2DVS(NULL), mDepthPS(NULL),
mQuad3DIL(NULL), mQuad3DVS(NULL), mQuad3DGS(NULL)
{
@@ -120,13 +121,18 @@
rasterDesc.SlopeScaledDepthBias = 0.0f;
rasterDesc.DepthBiasClamp = 0.0f;
rasterDesc.DepthClipEnable = TRUE;
- rasterDesc.ScissorEnable = FALSE;
rasterDesc.MultisampleEnable = FALSE;
rasterDesc.AntialiasedLineEnable = FALSE;
- result = device->CreateRasterizerState(&rasterDesc, &mRasterizerState);
+ rasterDesc.ScissorEnable = TRUE;
+ result = device->CreateRasterizerState(&rasterDesc, &mScissorEnabledRasterizerState);
ASSERT(SUCCEEDED(result));
- d3d11::SetDebugName(mRasterizerState, "Blit11 rasterizer state");
+ d3d11::SetDebugName(mScissorEnabledRasterizerState, "Blit11 scissoring rasterizer state");
+
+ rasterDesc.ScissorEnable = FALSE;
+ result = device->CreateRasterizerState(&rasterDesc, &mScissorDisabledRasterizerState);
+ ASSERT(SUCCEEDED(result));
+ d3d11::SetDebugName(mScissorDisabledRasterizerState, "Blit11 no scissoring rasterizer state");
D3D11_DEPTH_STENCIL_DESC depthStencilDesc;
depthStencilDesc.DepthEnable = true;
@@ -193,7 +199,8 @@
SafeRelease(mVertexBuffer);
SafeRelease(mPointSampler);
SafeRelease(mLinearSampler);
- SafeRelease(mRasterizerState);
+ SafeRelease(mScissorEnabledRasterizerState);
+ SafeRelease(mScissorDisabledRasterizerState);
SafeRelease(mDepthStencilState);
SafeRelease(mQuad2DIL);
@@ -209,18 +216,8 @@
bool Blit11::copyTexture(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize,
ID3D11RenderTargetView *dest, const gl::Box &destArea, const gl::Extents &destSize,
- GLenum destFormat, GLenum filter)
+ const gl::Rectangle *scissor, GLenum destFormat, GLenum filter)
{
- if(sourceArea.x < 0 || sourceArea.x + sourceArea.width > sourceSize.width ||
- sourceArea.y < 0 || sourceArea.y + sourceArea.height > sourceSize.height ||
- sourceArea.z < 0 || sourceArea.z + sourceArea.depth > sourceSize.depth ||
- destArea.x < 0 || destArea.x + destArea.width > destSize.width ||
- destArea.y < 0 || destArea.y + destArea.height > destSize.height ||
- destArea.z < 0 || destArea.z + destArea.depth > destSize.depth )
- {
- return false;
- }
-
HRESULT result;
ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
@@ -269,7 +266,22 @@
// Apply state
deviceContext->OMSetBlendState(NULL, NULL, 0xFFFFFFF);
deviceContext->OMSetDepthStencilState(NULL, 0xFFFFFFFF);
- deviceContext->RSSetState(mRasterizerState);
+
+ if (scissor)
+ {
+ D3D11_RECT scissorRect;
+ scissorRect.left = scissor->x;
+ scissorRect.right = scissor->x + scissor->width;
+ scissorRect.top = scissor->y;
+ scissorRect.bottom = scissor->y + scissor->height;
+
+ deviceContext->RSSetScissorRects(1, &scissorRect);
+ deviceContext->RSSetState(mScissorEnabledRasterizerState);
+ }
+ else
+ {
+ deviceContext->RSSetState(mScissorDisabledRasterizerState);
+ }
// Apply shaders
deviceContext->IASetInputLayout(shader.mInputLayout);
@@ -326,49 +338,6 @@
return true;
}
-static ID3D11Resource *createStagingTexture(ID3D11Device *device, ID3D11DeviceContext *context,
- ID3D11Resource *source, unsigned int subresource,
- const gl::Extents &size, unsigned int cpuAccessFlags)
-{
- ID3D11Texture2D *sourceTexture = d3d11::DynamicCastComObject<ID3D11Texture2D>(source);
- if (!sourceTexture)
- {
- return NULL;
- }
-
- D3D11_TEXTURE2D_DESC sourceDesc;
- sourceTexture->GetDesc(&sourceDesc);
-
- if (sourceDesc.SampleDesc.Count > 1)
- {
- // Creating a staging texture of a multisampled texture is not supported
- SafeRelease(sourceTexture);
- return NULL;
- }
-
- D3D11_TEXTURE2D_DESC stagingDesc;
- stagingDesc.Width = size.width;
- stagingDesc.Height = size.height;
- stagingDesc.MipLevels = 1;
- stagingDesc.ArraySize = 1;
- stagingDesc.Format = sourceDesc.Format;
- stagingDesc.SampleDesc.Count = 1;
- stagingDesc.SampleDesc.Quality = 0;
- stagingDesc.Usage = D3D11_USAGE_STAGING;
- stagingDesc.CPUAccessFlags = cpuAccessFlags;
- stagingDesc.MiscFlags = 0;
- stagingDesc.BindFlags = 0;
-
- SafeRelease(sourceTexture);
-
- ID3D11Texture2D *stagingTexture = NULL;
- HRESULT result = device->CreateTexture2D(&stagingDesc, NULL, &stagingTexture);
-
- context->CopySubresourceRegion(stagingTexture, 0, 0, 0, 0, source, subresource, NULL);
-
- return stagingTexture;
-}
-
static DXGI_FORMAT getTextureFormat(ID3D11Resource *resource)
{
ID3D11Texture2D *texture = d3d11::DynamicCastComObject<ID3D11Texture2D>(resource);
@@ -385,6 +354,36 @@
return desc.Format;
}
+static ID3D11Resource *createStagingTexture(ID3D11Device *device, ID3D11DeviceContext *context,
+ ID3D11Resource *source, unsigned int subresource,
+ const gl::Extents &size, unsigned int cpuAccessFlags)
+{
+ D3D11_TEXTURE2D_DESC stagingDesc;
+ stagingDesc.Width = size.width;
+ stagingDesc.Height = size.height;
+ stagingDesc.MipLevels = 1;
+ stagingDesc.ArraySize = 1;
+ stagingDesc.Format = getTextureFormat(source);
+ stagingDesc.SampleDesc.Count = 1;
+ stagingDesc.SampleDesc.Quality = 0;
+ stagingDesc.Usage = D3D11_USAGE_STAGING;
+ stagingDesc.CPUAccessFlags = cpuAccessFlags;
+ stagingDesc.MiscFlags = 0;
+ stagingDesc.BindFlags = 0;
+
+ ID3D11Texture2D *stagingTexture = NULL;
+ HRESULT result = device->CreateTexture2D(&stagingDesc, NULL, &stagingTexture);
+ if (FAILED(result))
+ {
+ ERR("Failed to create staging texture for depth stencil blit. HRESULT: 0x%X.", result);
+ return NULL;
+ }
+
+ context->CopySubresourceRegion(stagingTexture, 0, 0, 0, 0, source, subresource, NULL);
+
+ return stagingTexture;
+}
+
inline static void generateVertexCoords(const gl::Box &sourceArea, const gl::Extents &sourceSize,
const gl::Box &destArea, const gl::Extents &destSize,
float *x1, float *y1, float *x2, float *y2,
@@ -450,15 +449,17 @@
}
bool Blit11::copyStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize,
- ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize)
+ ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize,
+ const gl::Rectangle *scissor)
{
return copyDepthStencil(source, sourceSubresource, sourceArea, sourceSize,
dest, destSubresource, destArea, destSize,
- true);
+ scissor, true);
}
bool Blit11::copyDepth(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize,
- ID3D11DepthStencilView *dest, const gl::Box &destArea, const gl::Extents &destSize)
+ ID3D11DepthStencilView *dest, const gl::Box &destArea, const gl::Extents &destSize,
+ const gl::Rectangle *scissor)
{
HRESULT result;
ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
@@ -488,7 +489,22 @@
// Apply state
deviceContext->OMSetBlendState(NULL, NULL, 0xFFFFFFF);
deviceContext->OMSetDepthStencilState(mDepthStencilState, 0xFFFFFFFF);
- deviceContext->RSSetState(mRasterizerState);
+
+ if (scissor)
+ {
+ D3D11_RECT scissorRect;
+ scissorRect.left = scissor->x;
+ scissorRect.right = scissor->x + scissor->width;
+ scissorRect.top = scissor->y;
+ scissorRect.bottom = scissor->y + scissor->height;
+
+ deviceContext->RSSetScissorRects(1, &scissorRect);
+ deviceContext->RSSetState(mScissorEnabledRasterizerState);
+ }
+ else
+ {
+ deviceContext->RSSetState(mScissorDisabledRasterizerState);
+ }
// Apply shaders
deviceContext->IASetInputLayout(mQuad2DIL);
@@ -539,16 +555,17 @@
}
bool Blit11::copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize,
- ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize)
+ ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize,
+ const gl::Rectangle *scissor)
{
return copyDepthStencil(source, sourceSubresource, sourceArea, sourceSize,
dest, destSubresource, destArea, destSize,
- false);
+ scissor, false);
}
bool Blit11::copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize,
ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize,
- bool stencilOnly)
+ const gl::Rectangle *scissor, bool stencilOnly)
{
ID3D11Device *device = mRenderer->getDevice();
ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
@@ -556,6 +573,13 @@
ID3D11Resource *sourceStaging = createStagingTexture(device, deviceContext, source, sourceSubresource, sourceSize, D3D11_CPU_ACCESS_READ);
ID3D11Resource *destStaging = createStagingTexture(device, deviceContext, dest, destSubresource, destSize, D3D11_CPU_ACCESS_WRITE);
+ if (!sourceStaging || !destStaging)
+ {
+ SafeRelease(sourceStaging);
+ SafeRelease(destStaging);
+ return false;
+ }
+
DXGI_FORMAT format = getTextureFormat(source);
ASSERT(format == getTextureFormat(dest));
@@ -568,7 +592,7 @@
copySize = d3d11::GetStencilBits(format) / 8;
// It would be expensive to have non-byte sized stencil sizes since it would
- // require reading from the destination, currently there arn't any though.
+ // require reading from the destination, currently there aren't any though.
ASSERT(d3d11::GetStencilBits(format) % 8 == 0 &&
d3d11::GetStencilOffset(format) % 8 == 0);
}
@@ -577,34 +601,66 @@
deviceContext->Map(sourceStaging, 0, D3D11_MAP_READ, 0, &sourceMapping);
deviceContext->Map(destStaging, 0, D3D11_MAP_WRITE, 0, &destMapping);
- int startDestY = std::min(destArea.y, destArea.y + destArea.height);
- int endDestY = std::max(destArea.y, destArea.y + destArea.height);
-
- int startDestX = std::min(destArea.x, destArea.x + destArea.width);
- int endDestX = std::max(destArea.x, destArea.x + destArea.width);
-
- for (int y = startDestY; y < endDestY; y++)
+ if (!sourceMapping.pData || !destMapping.pData)
{
- float yPerc = static_cast<float>(y - startDestY) / (endDestY - startDestY - 1);
- unsigned int readRow = sourceArea.y + floor(yPerc * (sourceArea.height - 1) + 0.5f);
+ if (!sourceMapping.pData)
+ {
+ deviceContext->Unmap(sourceStaging, 0);
+ }
+ if (!destMapping.pData)
+ {
+ deviceContext->Unmap(destStaging, 0);
+ }
+ SafeRelease(sourceStaging);
+ SafeRelease(destStaging);
+ return false;
+ }
+
+ gl::Rectangle clippedDestArea(destArea.x, destArea.y, destArea.width, destArea.height);
+
+ // Clip dest area to the destination size
+ gl::ClipRectangle(clippedDestArea, gl::Rectangle(0, 0, destSize.width, destSize.height), &clippedDestArea);
+
+ // Clip dest area to the scissor
+ if (scissor)
+ {
+ gl::ClipRectangle(clippedDestArea, *scissor, &clippedDestArea);
+ }
+
+ // Determine if entire rows can be copied at once instead of each individual pixel, requires that there is
+ // no out of bounds lookups required, the entire pixel is copied and no stretching
+ bool wholeRowCopy = sourceArea.width == clippedDestArea.width &&
+ sourceArea.x >= 0 && sourceArea.x + sourceArea.width <= sourceSize.width &&
+ copySize == pixelSize;
+
+ for (int y = clippedDestArea.y; y < clippedDestArea.y + clippedDestArea.height; y++)
+ {
+ float yPerc = static_cast<float>(y - destArea.y) / (destArea.height - 1);
+
+ // Interpolate using the original source rectangle to determine which row to sample from while clamping to the edges
+ unsigned int readRow = gl::clamp(sourceArea.y + floor(yPerc * (sourceArea.height - 1) + 0.5f), 0, sourceSize.height - 1);
unsigned int writeRow = y;
- if (sourceArea.width == destArea.width && copySize == pixelSize)
+ if (wholeRowCopy)
{
void *sourceRow = reinterpret_cast<char*>(sourceMapping.pData) +
- readRow * sourceMapping.RowPitch;
+ readRow * sourceMapping.RowPitch +
+ sourceArea.x * pixelSize;
void *destRow = reinterpret_cast<char*>(destMapping.pData) +
- writeRow * destMapping.RowPitch;
+ writeRow * destMapping.RowPitch +
+ destArea.x * pixelSize;
memcpy(destRow, sourceRow, pixelSize * destArea.width);
}
else
{
- for (int x = startDestX; x < endDestX; x++)
+ for (int x = clippedDestArea.x; x < clippedDestArea.x + clippedDestArea.width; x++)
{
- float xPerc = static_cast<float>(x - startDestX) / (endDestX - startDestX - 1);
- unsigned int readColumn = sourceArea.x + floor(xPerc * (sourceArea.width - 1) + 0.5f);
+ float xPerc = static_cast<float>(x - destArea.x) / (destArea.width - 1);
+
+ // Interpolate the original source rectangle to determine which column to sample from while clamping to the edges
+ unsigned int readColumn = gl::clamp(sourceArea.x + floor(xPerc * (sourceArea.width - 1) + 0.5f), 0, sourceSize.width - 1);
unsigned int writeColumn = x;
void *sourcePixel = reinterpret_cast<char*>(sourceMapping.pData) +
diff --git a/src/libGLESv2/renderer/Blit11.h b/src/libGLESv2/renderer/Blit11.h
index 49468df..0e5eb77 100644
--- a/src/libGLESv2/renderer/Blit11.h
+++ b/src/libGLESv2/renderer/Blit11.h
@@ -30,16 +30,19 @@
bool copyTexture(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize,
ID3D11RenderTargetView *dest, const gl::Box &destArea, const gl::Extents &destSize,
- GLenum destFormat, GLenum filter);
+ const gl::Rectangle *scissor, GLenum destFormat, GLenum filter);
bool copyStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize,
- ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize);
+ ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize,
+ const gl::Rectangle *scissor);
bool copyDepth(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize,
- ID3D11DepthStencilView *dest, const gl::Box &destArea, const gl::Extents &destSize);
+ ID3D11DepthStencilView *dest, const gl::Box &destArea, const gl::Extents &destSize,
+ const gl::Rectangle *scissor);
bool copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize,
- ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize);
+ ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize,
+ const gl::Rectangle *scissor);
private:
rx::Renderer11 *mRenderer;
@@ -53,7 +56,7 @@
bool copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize,
ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize,
- bool stencilOnly);
+ const gl::Rectangle *scissor, bool stencilOnly);
static bool compareBlitParameters(const BlitParameters &a, const BlitParameters &b);
@@ -84,7 +87,8 @@
ID3D11Buffer *mVertexBuffer;
ID3D11SamplerState *mPointSampler;
ID3D11SamplerState *mLinearSampler;
- ID3D11RasterizerState *mRasterizerState;
+ ID3D11RasterizerState *mScissorEnabledRasterizerState;
+ ID3D11RasterizerState *mScissorDisabledRasterizerState;
ID3D11DepthStencilState *mDepthStencilState;
ID3D11InputLayout *mQuad2DIL;
diff --git a/src/libGLESv2/renderer/Renderer.h b/src/libGLESv2/renderer/Renderer.h
index 41b28d5..d3c9dda 100644
--- a/src/libGLESv2/renderer/Renderer.h
+++ b/src/libGLESv2/renderer/Renderer.h
@@ -225,7 +225,7 @@
GLint xoffset, GLint yoffset, GLint zOffset, TextureStorageInterface2DArray *storage, GLint level) = 0;
virtual bool blitRect(gl::Framebuffer *readTarget, const gl::Rectangle &readRect, gl::Framebuffer *drawTarget, const gl::Rectangle &drawRect,
- bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter) = 0;
+ const gl::Rectangle *scissor, bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter) = 0;
virtual void readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
GLsizei outputPitch, bool packReverseRowOrder, GLint packAlignment, void* pixels) = 0;
diff --git a/src/libGLESv2/renderer/Renderer11.cpp b/src/libGLESv2/renderer/Renderer11.cpp
index 837be4b..3872e71 100644
--- a/src/libGLESv2/renderer/Renderer11.cpp
+++ b/src/libGLESv2/renderer/Renderer11.cpp
@@ -2416,7 +2416,7 @@
// Use nearest filtering because source and destination are the same size for the direct
// copy
- bool ret = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize,
+ bool ret = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL,
destFormat, GL_NEAREST);
return ret;
@@ -2475,7 +2475,7 @@
// Use nearest filtering because source and destination are the same size for the direct
// copy
- bool ret = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize,
+ bool ret = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL,
destFormat, GL_NEAREST);
return ret;
@@ -2534,7 +2534,7 @@
// Use nearest filtering because source and destination are the same size for the direct
// copy
- bool ret = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize,
+ bool ret = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL,
destFormat, GL_NEAREST);
return ret;
@@ -2595,7 +2595,7 @@
// Use nearest filtering because source and destination are the same size for the direct
// copy
- bool ret = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize,
+ bool ret = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL,
destFormat, GL_NEAREST);
return ret;
@@ -2794,7 +2794,7 @@
}
bool Renderer11::blitRect(gl::Framebuffer *readTarget, const gl::Rectangle &readRect, gl::Framebuffer *drawTarget, const gl::Rectangle &drawRect,
- bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter)
+ const gl::Rectangle *scissor, bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter)
{
if (blitRenderTarget)
{
@@ -2822,7 +2822,7 @@
RenderTarget *drawRenderTarget = drawBuffer->getRenderTarget();
- if (!blitRenderbufferRect(readRect, drawRect, readRenderTarget, drawRenderTarget, filter,
+ if (!blitRenderbufferRect(readRect, drawRect, readRenderTarget, drawRenderTarget, filter, scissor,
blitRenderTarget, false, false))
{
return false;
@@ -2851,7 +2851,7 @@
RenderTarget *readRenderTarget = readBuffer->getDepthStencil();
RenderTarget *drawRenderTarget = drawBuffer->getDepthStencil();
- if (!blitRenderbufferRect(readRect, drawRect, readRenderTarget, drawRenderTarget, filter,
+ if (!blitRenderbufferRect(readRect, drawRect, readRenderTarget, drawRenderTarget, filter, scissor,
false, blitDepth, blitStencil))
{
return false;
@@ -3080,7 +3080,8 @@
}
bool Renderer11::blitRenderbufferRect(const gl::Rectangle &readRect, const gl::Rectangle &drawRect, RenderTarget *readRenderTarget,
- RenderTarget *drawRenderTarget, GLenum filter, bool colorBlit, bool depthBlit, bool stencilBlit)
+ RenderTarget *drawRenderTarget, GLenum filter, const gl::Rectangle *scissor,
+ bool colorBlit, bool depthBlit, bool stencilBlit)
{
// Since blitRenderbufferRect is called for each render buffer that needs to be blitted,
// it should never be the case that both color and depth/stencil need to be blitted at
@@ -3148,16 +3149,37 @@
return gl::error(GL_OUT_OF_MEMORY, false);
}
- bool wholeBufferCopy = readRect.x == 0 && readRect.width == readRenderTarget11->getWidth() &&
- readRect.y == 0 && readRect.height == readRenderTarget11->getHeight() &&
- drawRect.x == 0 && drawRect.width == drawRenderTarget->getWidth() &&
- drawRect.y == 0 && drawRect.height == drawRenderTarget->getHeight();
+ gl::Extents readSize(readRenderTarget->getWidth(), readRenderTarget->getHeight(), 1);
+ gl::Extents drawSize(drawRenderTarget->getWidth(), drawRenderTarget->getHeight(), 1);
+
+ bool scissorNeeded = scissor && gl::ClipRectangle(drawRect, *scissor, NULL);
+
+ bool wholeBufferCopy = !scissorNeeded &&
+ readRect.x == 0 && readRect.width == readSize.width &&
+ readRect.y == 0 && readRect.height == readSize.height &&
+ drawRect.x == 0 && drawRect.width == drawSize.width &&
+ drawRect.y == 0 && drawRect.height == drawSize.height;
bool stretchRequired = readRect.width != drawRect.width || readRect.height != drawRect.height;
+ bool flipRequired = readRect.width < 0 || readRect.height < 0 || drawRect.width < 0 || readRect.height < 0;
+
+ bool outOfBounds = readRect.x < 0 || readRect.x + readRect.width > readSize.width ||
+ readRect.y < 0 || readRect.y + readRect.height > readSize.height ||
+ drawRect.x < 0 || drawRect.x + drawRect.width > drawSize.width ||
+ drawRect.y < 0 || drawRect.y + drawRect.height > drawSize.height;
+
+ bool hasDepth = gl::GetDepthBits(drawRenderTarget11->getActualFormat(), getCurrentClientVersion()) > 0;
+ bool hasStencil = gl::GetStencilBits(drawRenderTarget11->getActualFormat(), getCurrentClientVersion()) > 0;
+ bool partialDSBlit = (hasDepth && depthBlit) != (hasStencil && stencilBlit);
+
if (readRenderTarget11->getActualFormat() == drawRenderTarget->getActualFormat() &&
- !stretchRequired && (!(depthBlit || stencilBlit) || wholeBufferCopy))
+ !stretchRequired && !outOfBounds && !flipRequired && !partialDSBlit &&
+ (!(depthBlit || stencilBlit) || wholeBufferCopy))
{
+ UINT dstX = drawRect.x;
+ UINT dstY = drawRect.y;
+
D3D11_BOX readBox;
readBox.left = readRect.x;
readBox.right = readRect.x + readRect.width;
@@ -3166,40 +3188,66 @@
readBox.front = 0;
readBox.back = 1;
+ if (scissorNeeded)
+ {
+ // drawRect is guaranteed to have positive width and height because stretchRequired is false.
+ ASSERT(drawRect.width >= 0 || drawRect.height >= 0);
+
+ if (drawRect.x < scissor->x)
+ {
+ dstX = scissor->x;
+ readBox.left += (scissor->x - drawRect.x);
+ }
+ if (drawRect.y < scissor->y)
+ {
+ dstY = scissor->y;
+ readBox.top += (scissor->y - drawRect.y);
+ }
+ if (drawRect.x + drawRect.width > scissor->x + scissor->width)
+ {
+ readBox.right -= ((drawRect.x + drawRect.width) - (scissor->x + scissor->width));
+ }
+ if (drawRect.y + drawRect.height > scissor->y + scissor->height)
+ {
+ readBox.bottom -= ((drawRect.y + drawRect.height) - (scissor->y + scissor->height));
+ }
+ }
+
// D3D11 needs depth-stencil CopySubresourceRegions to have a NULL pSrcBox
// We also require complete framebuffer copies for depth-stencil blit.
D3D11_BOX *pSrcBox = wholeBufferCopy ? NULL : &readBox;
- mDeviceContext->CopySubresourceRegion(drawTexture, drawSubresource, drawRect.x, drawRect.y, 0,
+ mDeviceContext->CopySubresourceRegion(drawTexture, drawSubresource, dstX, dstY, 0,
readTexture, readSubresource, pSrcBox);
result = true;
}
else
{
gl::Box readArea(readRect.x, readRect.y, 0, readRect.width, readRect.height, 1);
- gl::Extents readSize(readRenderTarget->getWidth(), readRenderTarget->getHeight(), 1);
-
gl::Box drawArea(drawRect.x, drawRect.y, 0, drawRect.width, drawRect.height, 1);
- gl::Extents drawSize(drawRenderTarget->getWidth(), drawRenderTarget->getHeight(), 1);
if (depthBlit && stencilBlit)
{
result = mBlit->copyDepthStencil(readTexture, readSubresource, readArea, readSize,
- drawTexture, drawSubresource, drawArea, drawSize);
+ drawTexture, drawSubresource, drawArea, drawSize,
+ scissor);
}
else if (depthBlit)
{
- result = mBlit->copyDepth(readSRV, readArea, readSize, drawDSV, drawArea, drawSize);
+ result = mBlit->copyDepth(readSRV, readArea, readSize, drawDSV, drawArea, drawSize,
+ scissor);
}
else if (stencilBlit)
{
result = mBlit->copyStencil(readTexture, readSubresource, readArea, readSize,
- drawTexture, drawSubresource, drawArea, drawSize);
+ drawTexture, drawSubresource, drawArea, drawSize,
+ scissor);
}
else
{
GLenum format = gl::GetFormat(drawRenderTarget->getInternalFormat(), getCurrentClientVersion());
- result = mBlit->copyTexture(readSRV, readArea, readSize, drawRTV, drawArea, drawSize, format, filter);
+ result = mBlit->copyTexture(readSRV, readArea, readSize, drawRTV, drawArea, drawSize,
+ scissor, format, filter);
}
}
diff --git a/src/libGLESv2/renderer/Renderer11.h b/src/libGLESv2/renderer/Renderer11.h
index e41b12a..c280f2e 100644
--- a/src/libGLESv2/renderer/Renderer11.h
+++ b/src/libGLESv2/renderer/Renderer11.h
@@ -169,7 +169,7 @@
GLint xoffset, GLint yoffset, GLint zOffset, TextureStorageInterface2DArray *storage, GLint level);
virtual bool blitRect(gl::Framebuffer *readTarget, const gl::Rectangle &readRect, gl::Framebuffer *drawTarget, const gl::Rectangle &drawRect,
- bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter);
+ const gl::Rectangle *scissor, bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter);
virtual void readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
GLsizei outputPitch, bool packReverseRowOrder, GLint packAlignment, void* pixels);
@@ -225,7 +225,8 @@
rx::Range getViewportBounds() const;
bool blitRenderbufferRect(const gl::Rectangle &readRect, const gl::Rectangle &drawRect, RenderTarget *readRenderTarget,
- RenderTarget *drawRenderTarget, GLenum filter, bool colorBlit, bool depthBlit, bool stencilBlit);
+ RenderTarget *drawRenderTarget, GLenum filter, const gl::Rectangle *scissor,
+ bool colorBlit, bool depthBlit, bool stencilBlit);
ID3D11Texture2D *resolveMultisampledTexture(ID3D11Texture2D *source, unsigned int subresource);
HMODULE mD3d11Module;
diff --git a/src/libGLESv2/renderer/Renderer9.cpp b/src/libGLESv2/renderer/Renderer9.cpp
index 522700b..c699fc9 100644
--- a/src/libGLESv2/renderer/Renderer9.cpp
+++ b/src/libGLESv2/renderer/Renderer9.cpp
@@ -2715,7 +2715,7 @@
}
bool Renderer9::blitRect(gl::Framebuffer *readFramebuffer, const gl::Rectangle &readRect, gl::Framebuffer *drawFramebuffer, const gl::Rectangle &drawRect,
- bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter)
+ const gl::Rectangle *scissor, bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter)
{
ASSERT(filter == GL_NEAREST);
@@ -2754,6 +2754,9 @@
return gl::error(GL_OUT_OF_MEMORY, false);
}
+ gl::Extents srcSize(readRenderTarget->getWidth(), readRenderTarget->getHeight(), 1);
+ gl::Extents dstSize(drawRenderTarget->getWidth(), drawRenderTarget->getHeight(), 1);
+
RECT srcRect;
srcRect.left = readRect.x;
srcRect.right = readRect.x + readRect.width;
@@ -2766,6 +2769,75 @@
dstRect.top = drawRect.y;
dstRect.bottom = drawRect.y + drawRect.height;
+ // Clip the rectangles to the scissor rectangle
+ if (scissor)
+ {
+ if (dstRect.left < scissor->x)
+ {
+ srcRect.left += (scissor->x - dstRect.left);
+ dstRect.left = scissor->x;
+ }
+ if (dstRect.top < scissor->y)
+ {
+ srcRect.top += (scissor->y - dstRect.top);
+ dstRect.top = scissor->y;
+ }
+ if (dstRect.right > scissor->x + scissor->width)
+ {
+ srcRect.right -= (dstRect.right - (scissor->x + scissor->width));
+ dstRect.right = scissor->x + scissor->width;
+ }
+ if (dstRect.bottom > scissor->y + scissor->height)
+ {
+ srcRect.bottom -= (dstRect.bottom - (scissor->y + scissor->height));
+ dstRect.bottom = scissor->y + scissor->height;
+ }
+ }
+
+ // Clip the rectangles to the destination size
+ if (dstRect.left < 0)
+ {
+ srcRect.left += -dstRect.left;
+ dstRect.left = 0;
+ }
+ if (dstRect.right > dstSize.width)
+ {
+ srcRect.right -= (dstRect.right - dstSize.width);
+ dstRect.right = dstSize.width;
+ }
+ if (dstRect.top < 0)
+ {
+ srcRect.top += -dstRect.top;
+ dstRect.top = 0;
+ }
+ if (dstRect.bottom > dstSize.height)
+ {
+ srcRect.bottom -= (dstRect.bottom - dstSize.height);
+ dstRect.bottom = dstSize.height;
+ }
+
+ // Clip the rectangles to the source size
+ if (srcRect.left < 0)
+ {
+ dstRect.left += -srcRect.left;
+ srcRect.left = 0;
+ }
+ if (srcRect.right > srcSize.width)
+ {
+ dstRect.right -= (srcRect.right - srcSize.width);
+ srcRect.right = srcSize.width;
+ }
+ if (srcRect.top < 0)
+ {
+ dstRect.top += -srcRect.top;
+ srcRect.top = 0;
+ }
+ if (srcRect.bottom > srcSize.height)
+ {
+ dstRect.bottom -= (srcRect.bottom - srcSize.height);
+ srcRect.bottom = srcSize.height;
+ }
+
HRESULT result = mDevice->StretchRect(readSurface, &srcRect, drawSurface, &dstRect, D3DTEXF_NONE);
SafeRelease(readSurface);
diff --git a/src/libGLESv2/renderer/Renderer9.h b/src/libGLESv2/renderer/Renderer9.h
index 99902d7..0a4c2b2 100644
--- a/src/libGLESv2/renderer/Renderer9.h
+++ b/src/libGLESv2/renderer/Renderer9.h
@@ -186,7 +186,7 @@
GLint xoffset, GLint yoffset, GLint zOffset, TextureStorageInterface2DArray *storage, GLint level);
virtual bool blitRect(gl::Framebuffer *readTarget, const gl::Rectangle &readRect, gl::Framebuffer *drawTarget, const gl::Rectangle &drawRect,
- bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter);
+ const gl::Rectangle *scissor, bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter);
virtual void readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
GLsizei outputPitch, bool packReverseRowOrder, GLint packAlignment, void* pixels);
diff --git a/src/libGLESv2/renderer/TextureStorage11.cpp b/src/libGLESv2/renderer/TextureStorage11.cpp
index 5a7054e..ed73525 100644
--- a/src/libGLESv2/renderer/TextureStorage11.cpp
+++ b/src/libGLESv2/renderer/TextureStorage11.cpp
@@ -140,7 +140,8 @@
Blit11 *blitter = mRenderer->getBlitter();
return blitter->copyDepthStencil(srcTexture, sourceSubresource, copyArea, texSize,
- dstTexture, dstSubresource, copyArea, texSize);
+ dstTexture, dstSubresource, copyArea, texSize,
+ NULL);
}
else
{
@@ -180,7 +181,7 @@
Blit11 *blitter = mRenderer->getBlitter();
- blitter->copyTexture(sourceSRV, sourceArea, sourceSize, destRTV, destArea, destSize,
+ blitter->copyTexture(sourceSRV, sourceArea, sourceSize, destRTV, destArea, destSize, NULL,
gl::GetFormat(source->getInternalFormat(), mRenderer->getCurrentClientVersion()),
GL_LINEAR);
}