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); } }