glBlitFramebuffer support for depth/stencil formats
Added support for depth and stencil formats for glBlitFramebuffer:
- Blitter now supports quad layout and stencil
- Device::stretchRect() now supports specific buffers, so that a
caller can specifically choose which buffer to copy
Change-Id: Iae0898df11e0a1d3c006113486ed15a3fd2f90a9
Reviewed-on: https://swiftshader-review.googlesource.com/7510
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <capn@google.com>
diff --git a/src/OpenGL/libGLESv2/Context.cpp b/src/OpenGL/libGLESv2/Context.cpp
index 6033efe..0e32336 100644
--- a/src/OpenGL/libGLESv2/Context.cpp
+++ b/src/OpenGL/libGLESv2/Context.cpp
@@ -3873,7 +3873,7 @@
void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
- GLbitfield mask, bool filter)
+ GLbitfield mask, bool filter, bool allowPartialDepthStencilBlit)
{
Framebuffer *readFramebuffer = getReadFramebuffer();
Framebuffer *drawFramebuffer = getDrawFramebuffer();
@@ -4048,7 +4048,8 @@
}
bool blitRenderTarget = false;
- bool blitDepthStencil = false;
+ bool blitDepth = false;
+ bool blitStencil = false;
if(mask & GL_COLOR_BUFFER_BIT)
{
@@ -4083,7 +4084,7 @@
return error(GL_INVALID_OPERATION);
}
- blitDepthStencil = true;
+ blitDepth = true;
readDSBuffer = readFramebuffer->getDepthbuffer();
drawDSBuffer = drawFramebuffer->getDepthbuffer();
}
@@ -4098,15 +4099,15 @@
return error(GL_INVALID_OPERATION);
}
- blitDepthStencil = true;
+ blitStencil = true;
readDSBuffer = readFramebuffer->getStencilbuffer();
drawDSBuffer = drawFramebuffer->getStencilbuffer();
}
}
- if(partialBufferCopy)
+ if(partialBufferCopy && !allowPartialDepthStencilBlit)
{
- ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
+ ERR("Only whole-buffer depth and stencil blits are supported by ANGLE_framebuffer_blit.");
return error(GL_INVALID_OPERATION); // Only whole-buffer copies are permitted
}
@@ -4117,7 +4118,7 @@
}
}
- if(blitRenderTarget || blitDepthStencil)
+ if(blitRenderTarget || blitDepth || blitStencil)
{
if(blitRenderTarget)
{
@@ -4133,7 +4134,7 @@
swap(destRect.y0, destRect.y1);
}
- bool success = device->stretchRect(readRenderTarget, &sourceRect, drawRenderTarget, &destRect, filter);
+ bool success = device->stretchRect(readRenderTarget, &sourceRect, drawRenderTarget, &destRect, (filter ? Device::USE_FILTER : 0) | Device::COLOR_BUFFER);
readRenderTarget->release();
drawRenderTarget->release();
@@ -4145,9 +4146,32 @@
}
}
- if(blitDepthStencil)
+ if(blitDepth)
{
- bool success = device->stretchRect(readFramebuffer->getDepthBuffer(), nullptr, drawFramebuffer->getDepthBuffer(), nullptr, false);
+ egl::Image *readRenderTarget = readFramebuffer->getDepthBuffer();
+ egl::Image *drawRenderTarget = drawFramebuffer->getDepthBuffer();
+
+ bool success = device->stretchRect(readRenderTarget, &sourceRect, drawRenderTarget, &destRect, (filter ? Device::USE_FILTER : 0) | Device::DEPTH_BUFFER);
+
+ readRenderTarget->release();
+ drawRenderTarget->release();
+
+ if(!success)
+ {
+ ERR("BlitFramebuffer failed.");
+ return;
+ }
+ }
+
+ if(blitStencil)
+ {
+ egl::Image *readRenderTarget = readFramebuffer->getStencilBuffer();
+ egl::Image *drawRenderTarget = drawFramebuffer->getStencilBuffer();
+
+ bool success = device->stretchRect(readRenderTarget, &sourceRect, drawRenderTarget, &destRect, (filter ? Device::USE_FILTER : 0) | Device::STENCIL_BUFFER);
+
+ readRenderTarget->release();
+ drawRenderTarget->release();
if(!success)
{
diff --git a/src/OpenGL/libGLESv2/Context.h b/src/OpenGL/libGLESv2/Context.h
index f638c05..cd8194f 100644
--- a/src/OpenGL/libGLESv2/Context.h
+++ b/src/OpenGL/libGLESv2/Context.h
@@ -684,7 +684,7 @@
void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
- GLbitfield mask, bool filter);
+ GLbitfield mask, bool filter, bool allowPartialDepthStencilBlit);
virtual void bindTexImage(egl::Surface *surface);
virtual EGLenum validateSharedImage(EGLenum target, GLuint name, GLuint textureLevel);
diff --git a/src/OpenGL/libGLESv2/Device.cpp b/src/OpenGL/libGLESv2/Device.cpp
index 225ceeb..2e7a2e3 100644
--- a/src/OpenGL/libGLESv2/Device.cpp
+++ b/src/OpenGL/libGLESv2/Device.cpp
@@ -510,7 +510,7 @@
}
}
- bool Device::stretchRect(sw::Surface *source, const sw::SliceRect *sourceRect, sw::Surface *dest, const sw::SliceRect *destRect, bool filter)
+ bool Device::stretchRect(sw::Surface *source, const sw::SliceRect *sourceRect, sw::Surface *dest, const sw::SliceRect *destRect, unsigned char flags)
{
if(!source || !dest)
{
@@ -596,7 +596,12 @@
bool scaling = (sRect.x1 - sRect.x0 != dRect.x1 - dRect.x0) || (sRect.y1 - sRect.y0 != dRect.y1 - dRect.y0);
bool equalFormats = source->getInternalFormat() == dest->getInternalFormat();
- bool depthStencil = egl::Image::isDepth(source->getInternalFormat()) || egl::Image::isStencil(source->getInternalFormat());
+ bool hasQuadLayout = Surface::hasQuadLayout(source->getInternalFormat()) || Surface::hasQuadLayout(dest->getInternalFormat());
+ bool fullCopy = (sRect.x0 == 0) && (sRect.y0 == 0) && (dRect.x0 == 0) && (dRect.y0 == 0) &&
+ (sRect.x1 == sWidth) && (sRect.y1 == sHeight) && (dRect.x1 == dWidth) && (dRect.y0 == dHeight);
+ bool isDepth = (flags & Device::DEPTH_BUFFER) && egl::Image::isDepth(source->getInternalFormat());
+ bool isStencil = (flags & Device::STENCIL_BUFFER) && (egl::Image::isDepth(source->getInternalFormat()) || egl::Image::isStencil(source->getInternalFormat()));
+ bool isColor = (flags & Device::COLOR_BUFFER) == Device::COLOR_BUFFER;
bool alpha0xFF = false;
if((source->getInternalFormat() == FORMAT_A8R8G8B8 && dest->getInternalFormat() == FORMAT_X8R8G8B8) ||
@@ -606,31 +611,31 @@
alpha0xFF = true;
}
- if(depthStencil) // Copy entirely, internally // FIXME: Check
+ if((isDepth || isStencil) && !scaling && equalFormats && (!hasQuadLayout || fullCopy))
{
- if(source->hasDepth())
+ if(source->hasDepth() && isDepth)
{
- sw::byte *sourceBuffer = (sw::byte*)source->lockInternal(0, 0, sourceRect->slice, LOCK_READONLY, PUBLIC);
- sw::byte *destBuffer = (sw::byte*)dest->lockInternal(0, 0, destRect->slice, LOCK_DISCARD, PUBLIC);
+ sw::byte *sourceBuffer = (sw::byte*)source->lockInternal(sRect.x0, sRect.y0, 0, LOCK_READONLY, PUBLIC);
+ sw::byte *destBuffer = (sw::byte*)dest->lockInternal(dRect.x0, dRect.y0, 0, LOCK_DISCARD, PUBLIC);
- copyBuffer(sourceBuffer, destBuffer, source->getWidth(), source->getHeight(), source->getInternalPitchB(), dest->getInternalPitchB(), egl::Image::bytes(source->getInternalFormat()), flipX, flipY);
+ copyBuffer(sourceBuffer, destBuffer, dRect.width(), dRect.height(), source->getInternalPitchB(), dest->getInternalPitchB(), egl::Image::bytes(source->getInternalFormat()), flipX, flipY);
source->unlockInternal();
dest->unlockInternal();
}
- if(source->hasStencil())
+ if(source->hasStencil() && isStencil)
{
- sw::byte *sourceBuffer = (sw::byte*)source->lockStencil(0, 0, 0, PUBLIC);
- sw::byte *destBuffer = (sw::byte*)dest->lockStencil(0, 0, 0, PUBLIC);
+ sw::byte *sourceBuffer = (sw::byte*)source->lockStencil(sRect.x0, sRect.y0, 0, PUBLIC);
+ sw::byte *destBuffer = (sw::byte*)dest->lockStencil(dRect.x0, dRect.y0, 0, PUBLIC);
- copyBuffer(sourceBuffer, destBuffer, source->getWidth(), source->getHeight(), source->getInternalPitchB(), dest->getInternalPitchB(), egl::Image::bytes(source->getInternalFormat()), flipX, flipY);
+ copyBuffer(sourceBuffer, destBuffer, source->getWidth(), source->getHeight(), source->getStencilPitchB(), dest->getStencilPitchB(), egl::Image::bytes(source->getStencilFormat()), flipX, flipY);
source->unlockStencil();
dest->unlockStencil();
}
}
- else if(!scaling && equalFormats)
+ else if((flags & Device::COLOR_BUFFER) && !scaling && equalFormats && (!hasQuadLayout || fullCopy))
{
unsigned char *sourceBytes = (unsigned char*)source->lockInternal(sRect.x0, sRect.y0, sourceRect->slice, LOCK_READONLY, PUBLIC);
unsigned char *destBytes = (unsigned char*)dest->lockInternal(dRect.x0, dRect.y0, destRect->slice, LOCK_READWRITE, PUBLIC);
@@ -656,7 +661,7 @@
source->unlockInternal();
dest->unlockInternal();
}
- else
+ else if(isColor || isDepth || isStencil)
{
if(flipX)
{
@@ -666,7 +671,11 @@
{
swap(dRect.y0, dRect.y1);
}
- blit(source, sRect, dest, dRect, scaling && filter);
+ blit(source, sRect, dest, dRect, scaling && (flags & Device::USE_FILTER), isStencil);
+ }
+ else
+ {
+ UNREACHABLE(false);
}
return true;
diff --git a/src/OpenGL/libGLESv2/Device.hpp b/src/OpenGL/libGLESv2/Device.hpp
index 705597b..13a10de 100644
--- a/src/OpenGL/libGLESv2/Device.hpp
+++ b/src/OpenGL/libGLESv2/Device.hpp
@@ -39,6 +39,15 @@
class Device : public sw::Renderer
{
public:
+ enum : unsigned char
+ {
+ USE_FILTER = 0x01,
+ COLOR_BUFFER = 0x02,
+ DEPTH_BUFFER = 0x04,
+ STENCIL_BUFFER = 0x08,
+ ALL_BUFFERS = COLOR_BUFFER | DEPTH_BUFFER | STENCIL_BUFFER,
+ };
+
explicit Device(sw::Context *context);
virtual ~Device();
@@ -64,7 +73,7 @@
void setVertexShaderConstantF(unsigned int startRegister, const float *constantData, unsigned int count);
void setViewport(const Viewport &viewport);
- bool stretchRect(sw::Surface *sourceSurface, const sw::SliceRect *sourceRect, sw::Surface *destSurface, const sw::SliceRect *destRect, bool filter);
+ bool stretchRect(sw::Surface *sourceSurface, const sw::SliceRect *sourceRect, sw::Surface *destSurface, const sw::SliceRect *destRect, unsigned char flags);
bool stretchCube(sw::Surface *sourceSurface, sw::Surface *destSurface);
void finish();
diff --git a/src/OpenGL/libGLESv2/Texture.cpp b/src/OpenGL/libGLESv2/Texture.cpp
index 50ab54b..deb8ed7 100644
--- a/src/OpenGL/libGLESv2/Texture.cpp
+++ b/src/OpenGL/libGLESv2/Texture.cpp
@@ -480,7 +480,7 @@
Device *device = getDevice();
sw::SliceRect destRect(xoffset, yoffset, xoffset + (sourceRect.x1 - sourceRect.x0), yoffset + (sourceRect.y1 - sourceRect.y0), zoffset);
- bool success = device->stretchRect(source, &sourceRect, dest, &destRect, false);
+ bool success = device->stretchRect(source, &sourceRect, dest, &destRect, Device::ALL_BUFFERS);
if(!success)
{
@@ -926,7 +926,7 @@
return error(GL_OUT_OF_MEMORY);
}
- getDevice()->stretchRect(image[i - 1], 0, image[i], 0, true);
+ getDevice()->stretchRect(image[i - 1], 0, image[i], 0, Device::ALL_BUFFERS | Device::USE_FILTER);
}
}
@@ -1415,7 +1415,7 @@
return error(GL_OUT_OF_MEMORY);
}
- getDevice()->stretchRect(image[f][i - 1], 0, image[f][i], 0, true);
+ getDevice()->stretchRect(image[f][i - 1], 0, image[f][i], 0, Device::ALL_BUFFERS | Device::USE_FILTER);
}
}
}
@@ -2001,7 +2001,7 @@
{
sw::SliceRect srcRect(0, 0, srcw, srch, z);
sw::SliceRect dstRect(0, 0, w, h, z);
- getDevice()->stretchRect(image[i - 1], &srcRect, image[i], &dstRect, true);
+ getDevice()->stretchRect(image[i - 1], &srcRect, image[i], &dstRect, Device::ALL_BUFFERS | Device::USE_FILTER);
}
}
}
diff --git a/src/OpenGL/libGLESv2/libGLESv2.cpp b/src/OpenGL/libGLESv2/libGLESv2.cpp
index 2b7361d..447d800 100644
--- a/src/OpenGL/libGLESv2/libGLESv2.cpp
+++ b/src/OpenGL/libGLESv2/libGLESv2.cpp
@@ -6236,7 +6236,7 @@
}
}
-void BlitFramebufferNV(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
+static void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter, bool allowPartialDepthStencilBlit)
{
TRACE("(GLint srcX0 = %d, GLint srcY0 = %d, GLint srcX1 = %d, GLint srcY1 = %d, "
"GLint dstX0 = %d, GLint dstY0 = %d, GLint dstX1 = %d, GLint dstY1 = %d, "
@@ -6266,10 +6266,15 @@
return error(GL_INVALID_OPERATION);
}
- context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, false);
+ context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, false, allowPartialDepthStencilBlit);
}
}
+void BlitFramebufferNV(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
+{
+ BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter, true);
+}
+
void BlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter)
{
@@ -6279,7 +6284,7 @@
return error(GL_INVALID_OPERATION);
}
- glBlitFramebufferNV(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+ BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter, false);
}
void TexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth,
diff --git a/src/OpenGL/libGLESv2/libGLESv3.cpp b/src/OpenGL/libGLESv2/libGLESv3.cpp
index f50a65c..4c86895 100644
--- a/src/OpenGL/libGLESv2/libGLESv3.cpp
+++ b/src/OpenGL/libGLESv2/libGLESv3.cpp
@@ -1447,7 +1447,7 @@
return error(GL_INVALID_OPERATION);
}
- context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter == GL_LINEAR);
+ context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter == GL_LINEAR, true);
}
}