Implements blitFramebuffer

TRAC #12713 Signed-off-by: Nicolas Capens Signed-off-by: Daniel Koch Author: Shannon Woods git-svn-id: https://angleproject.googlecode.com/svn/trunk@389 736b8ea6-26fd-11df-bfd4-992fa37f6226
parent ca7c008a
...@@ -785,6 +785,14 @@ typedef void (GL_APIENTRYP PFNGLENDTILINGQCOMPROC) (GLbitfield preserveMask); ...@@ -785,6 +785,14 @@ typedef void (GL_APIENTRYP PFNGLENDTILINGQCOMPROC) (GLbitfield preserveMask);
/* GL_ANGLE_framebuffer_blit */ /* GL_ANGLE_framebuffer_blit */
#ifndef GL_ANGLE_framebuffer_blit #ifndef GL_ANGLE_framebuffer_blit
#define GL_ANGLE_framebuffer_blit 1 #define GL_ANGLE_framebuffer_blit 1
#ifdef GL_GLEXT_PROTOTYPES
GL_APICALL void GL_APIENTRY glBlitFramebufferANGLE (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter);
#endif
typedef void (GL_APIENTRYP PFNGLBLITFRAMEBUFFERANGLEPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter);
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
......
...@@ -2807,6 +2807,7 @@ void Context::initExtensionString() ...@@ -2807,6 +2807,7 @@ void Context::initExtensionString()
mExtensionString += "GL_OES_packed_depth_stencil "; mExtensionString += "GL_OES_packed_depth_stencil ";
mExtensionString += "GL_EXT_texture_format_BGRA8888 "; mExtensionString += "GL_EXT_texture_format_BGRA8888 ";
mExtensionString += "GL_EXT_read_format_bgra "; mExtensionString += "GL_EXT_read_format_bgra ";
mExtensionString += "GL_ANGLE_framebuffer_blit ";
if (mBufferBackEnd->supportIntIndices()) if (mBufferBackEnd->supportIntIndices())
{ {
...@@ -2825,6 +2826,256 @@ const char *Context::getExtensionString() const ...@@ -2825,6 +2826,256 @@ const char *Context::getExtensionString() const
return mExtensionString.c_str(); return mExtensionString.c_str();
} }
void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask)
{
IDirect3DDevice9 *device = getDevice();
Framebuffer *readFramebuffer = getReadFramebuffer();
Framebuffer *drawFramebuffer = getDrawFramebuffer();
if (!readFramebuffer || readFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE ||
!drawFramebuffer || drawFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
{
return error(GL_INVALID_FRAMEBUFFER_OPERATION);
}
RECT sourceRect;
RECT destRect;
if (srcX0 < srcX1)
{
sourceRect.left = srcX0;
sourceRect.right = srcX1;
destRect.left = dstX0;
destRect.right = dstX1;
}
else
{
sourceRect.left = srcX1;
destRect.left = dstX1;
sourceRect.right = srcX0;
destRect.right = dstX0;
}
// Arguments to StretchRect must be in D3D-style (0-top) coordinates, so we must
// flip our Y-values here
if (srcY0 < srcY1)
{
sourceRect.bottom = srcY1;
destRect.bottom = dstY1;
sourceRect.top = srcY0;
destRect.top = dstY0;
}
else
{
sourceRect.bottom = srcY0;
destRect.bottom = dstY0;
sourceRect.top = srcY1;
destRect.top = dstY1;
}
RECT sourceScissoredRect = sourceRect;
RECT destScissoredRect = destRect;
if (mState.scissorTest)
{
// Only write to parts of the destination framebuffer which pass the scissor test
// Please note: the destRect is now in D3D-style coordinates, so the *top* of the
// rect will be checked against scissorY, rather than the bottom.
if (destRect.left < mState.scissorX)
{
int xDiff = mState.scissorX - destRect.left;
destScissoredRect.left = mState.scissorX;
sourceScissoredRect.left += xDiff;
}
if (destRect.right > mState.scissorX + mState.scissorWidth)
{
int xDiff = destRect.right - (mState.scissorX + mState.scissorWidth);
destScissoredRect.right = mState.scissorX + mState.scissorWidth;
sourceScissoredRect.right -= xDiff;
}
if (destRect.top < mState.scissorY)
{
int yDiff = mState.scissorY - destRect.top;
destScissoredRect.top = mState.scissorY;
sourceScissoredRect.top += yDiff;
}
if (destRect.bottom > mState.scissorY + mState.scissorHeight)
{
int yDiff = destRect.bottom - (mState.scissorY + mState.scissorHeight);
destScissoredRect.bottom = mState.scissorY + mState.scissorHeight;
sourceScissoredRect.bottom -= yDiff;
}
}
bool blitRenderTarget = false;
bool blitDepthStencil = false;
RECT sourceTrimmedRect = sourceScissoredRect;
RECT destTrimmedRect = destScissoredRect;
// The source & destination rectangles also may need to be trimmed if they fall out of the bounds of
// the actual draw and read surfaces.
if (sourceTrimmedRect.left < 0)
{
int xDiff = 0 - sourceTrimmedRect.left;
sourceTrimmedRect.left = 0;
destTrimmedRect.left += xDiff;
}
int readBufferWidth = readFramebuffer->getColorbuffer()->getWidth();
int readBufferHeight = readFramebuffer->getColorbuffer()->getHeight();
int drawBufferWidth = drawFramebuffer->getColorbuffer()->getWidth();
int drawBufferHeight = drawFramebuffer->getColorbuffer()->getHeight();
if (sourceTrimmedRect.right > readBufferWidth)
{
int xDiff = sourceTrimmedRect.right - readBufferWidth;
sourceTrimmedRect.right = readBufferWidth;
destTrimmedRect.right -= xDiff;
}
if (sourceTrimmedRect.top < 0)
{
int yDiff = 0 - sourceTrimmedRect.top;
sourceTrimmedRect.top = 0;
destTrimmedRect.top += yDiff;
}
if (sourceTrimmedRect.bottom > readBufferHeight)
{
int yDiff = sourceTrimmedRect.bottom - readBufferHeight;
sourceTrimmedRect.bottom = readBufferHeight;
destTrimmedRect.bottom -= yDiff;
}
if (destTrimmedRect.left < 0)
{
int xDiff = 0 - destTrimmedRect.left;
destTrimmedRect.left = 0;
sourceTrimmedRect.left += xDiff;
}
if (destTrimmedRect.right > drawBufferWidth)
{
int xDiff = destTrimmedRect.right - drawBufferWidth;
destTrimmedRect.right = drawBufferWidth;
sourceTrimmedRect.right -= xDiff;
}
if (destTrimmedRect.top < 0)
{
int yDiff = 0 - destTrimmedRect.top;
destTrimmedRect.top = 0;
sourceTrimmedRect.top += yDiff;
}
if (destTrimmedRect.bottom > drawBufferHeight)
{
int yDiff = destTrimmedRect.bottom - drawBufferHeight;
destTrimmedRect.bottom = drawBufferHeight;
sourceTrimmedRect.bottom -= yDiff;
}
if (mask & GL_COLOR_BUFFER_BIT)
{
if (readFramebuffer->getColorbufferType() != drawFramebuffer->getColorbufferType() ||
readFramebuffer->getColorbuffer()->getD3DFormat() != drawFramebuffer->getColorbuffer()->getD3DFormat())
{
ERR("Color buffer format conversion in BlitFramebufferANGLE not supported by this implementation");
return error(GL_INVALID_OPERATION);
}
blitRenderTarget = true;
}
if (mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
{
DepthStencilbuffer *readDSBuffer = NULL;
DepthStencilbuffer *drawDSBuffer = NULL;
// We support OES_packed_depth_stencil, and do not support a separately attached depth and stencil buffer, so if we have
// both a depth and stencil buffer, it will be the same buffer.
if (mask & GL_DEPTH_BUFFER_BIT)
{
if (readFramebuffer->getDepthbuffer() && drawFramebuffer->getDepthbuffer())
{
if (readFramebuffer->getDepthbufferType() != drawFramebuffer->getDepthbufferType() ||
readFramebuffer->getDepthbuffer()->getD3DFormat() != drawFramebuffer->getDepthbuffer()->getD3DFormat())
{
return error(GL_INVALID_OPERATION);
}
blitDepthStencil = true;
readDSBuffer = readFramebuffer->getDepthbuffer();
drawDSBuffer = drawFramebuffer->getDepthbuffer();
}
}
if (mask & GL_STENCIL_BUFFER_BIT)
{
if (readFramebuffer->getStencilbuffer() && drawFramebuffer->getStencilbuffer())
{
if (readFramebuffer->getStencilbufferType() != drawFramebuffer->getStencilbufferType() ||
readFramebuffer->getStencilbuffer()->getD3DFormat() != drawFramebuffer->getStencilbuffer()->getD3DFormat())
{
return error(GL_INVALID_OPERATION);
}
blitDepthStencil = true;
readDSBuffer = readFramebuffer->getStencilbuffer();
drawDSBuffer = drawFramebuffer->getStencilbuffer();
}
}
if (sourceTrimmedRect.bottom - sourceTrimmedRect.top < readDSBuffer->getHeight() ||
sourceTrimmedRect.right - sourceTrimmedRect.left < readDSBuffer->getWidth() ||
destTrimmedRect.bottom - destTrimmedRect.top < drawDSBuffer->getHeight() ||
destTrimmedRect.right - destTrimmedRect.left < drawDSBuffer->getWidth() ||
sourceTrimmedRect.top != 0 || destTrimmedRect.top != 0 || sourceTrimmedRect.left != 0 || destTrimmedRect.left != 0)
{
ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
return error(GL_INVALID_OPERATION); // only whole-buffer copies are permitted
}
}
if (blitRenderTarget || blitDepthStencil)
{
egl::Display *display = getDisplay();
display->endScene();
if (blitRenderTarget)
{
HRESULT result = device->StretchRect(readFramebuffer->getRenderTarget(), &sourceTrimmedRect,
drawFramebuffer->getRenderTarget(), &destTrimmedRect, D3DTEXF_NONE);
if (FAILED(result))
{
ERR("BlitFramebufferANGLE failed: StretchRect returned %x.", result);
return;
}
}
if (blitDepthStencil)
{
HRESULT result = device->StretchRect(readFramebuffer->getDepthStencil(), NULL, drawFramebuffer->getDepthStencil(), NULL, D3DTEXF_NONE);
if (FAILED(result))
{
ERR("BlitFramebufferANGLE failed: StretchRect returned %x.", result);
return;
}
}
}
}
} }
extern "C" extern "C"
......
...@@ -376,6 +376,10 @@ class Context ...@@ -376,6 +376,10 @@ class Context
bool supportsShaderModel3() const; bool supportsShaderModel3() const;
const char *getExtensionString() const; const char *getExtensionString() const;
void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask);
Blit *getBlitter() { return mBlit; } Blit *getBlitter() { return mBlit; }
const D3DCAPS9 &getDeviceCaps() { return mDeviceCaps; } const D3DCAPS9 &getDeviceCaps() { return mDeviceCaps; }
......
...@@ -140,6 +140,23 @@ IDirect3DSurface9 *Framebuffer::getRenderTarget() ...@@ -140,6 +140,23 @@ IDirect3DSurface9 *Framebuffer::getRenderTarget()
return NULL; return NULL;
} }
IDirect3DSurface9 *Framebuffer::getDepthStencil()
{
Renderbuffer *depthstencilbuffer = mDepthbufferPointer.get();
if (!depthstencilbuffer)
{
depthstencilbuffer = mStencilbufferPointer.get();
}
if (depthstencilbuffer)
{
return depthstencilbuffer->getDepthStencil();
}
return NULL;
}
unsigned int Framebuffer::getDepthbufferSerial() unsigned int Framebuffer::getDepthbufferSerial()
{ {
Renderbuffer *depthbuffer = mDepthbufferPointer.get(); Renderbuffer *depthbuffer = mDepthbufferPointer.get();
...@@ -152,6 +169,18 @@ unsigned int Framebuffer::getDepthbufferSerial() ...@@ -152,6 +169,18 @@ unsigned int Framebuffer::getDepthbufferSerial()
return 0; return 0;
} }
unsigned int Framebuffer::getStencilbufferSerial()
{
Renderbuffer *stencilbuffer = mStencilbufferPointer.get();
if (stencilbuffer)
{
return stencilbuffer->getSerial();
}
return 0;
}
Colorbuffer *Framebuffer::getColorbuffer() Colorbuffer *Framebuffer::getColorbuffer()
{ {
Renderbuffer *rb = mColorbufferPointer.get(); Renderbuffer *rb = mColorbufferPointer.get();
......
...@@ -44,6 +44,7 @@ class Framebuffer ...@@ -44,6 +44,7 @@ class Framebuffer
unsigned int getRenderTargetSerial(); unsigned int getRenderTargetSerial();
unsigned int getDepthbufferSerial(); unsigned int getDepthbufferSerial();
unsigned int getStencilbufferSerial();
Colorbuffer *getColorbuffer(); Colorbuffer *getColorbuffer();
DepthStencilbuffer *getDepthbuffer(); DepthStencilbuffer *getDepthbuffer();
......
...@@ -68,6 +68,11 @@ GLenum Renderbuffer::getFormat() const ...@@ -68,6 +68,11 @@ GLenum Renderbuffer::getFormat() const
return mStorage->getFormat(); return mStorage->getFormat();
} }
D3DFORMAT Renderbuffer::getD3DFormat() const
{
return mStorage->getD3DFormat();
}
unsigned int Renderbuffer::getSerial() const unsigned int Renderbuffer::getSerial() const
{ {
return mStorage->getSerial(); return mStorage->getSerial();
...@@ -136,6 +141,11 @@ GLenum RenderbufferStorage::getFormat() const ...@@ -136,6 +141,11 @@ GLenum RenderbufferStorage::getFormat() const
return mFormat; return mFormat;
} }
D3DFORMAT RenderbufferStorage::getD3DFormat() const
{
return mD3DFormat;
}
unsigned int RenderbufferStorage::getSerial() const unsigned int RenderbufferStorage::getSerial() const
{ {
return mSerial; return mSerial;
......
...@@ -42,6 +42,7 @@ class RenderbufferStorage ...@@ -42,6 +42,7 @@ class RenderbufferStorage
virtual int getWidth() const; virtual int getWidth() const;
virtual int getHeight() const; virtual int getHeight() const;
GLenum getFormat() const; GLenum getFormat() const;
D3DFORMAT getD3DFormat() const;
unsigned int getSerial() const; unsigned int getSerial() const;
static unsigned int issueSerial(); static unsigned int issueSerial();
...@@ -81,6 +82,7 @@ class Renderbuffer : public RefCountObject ...@@ -81,6 +82,7 @@ class Renderbuffer : public RefCountObject
int getWidth() const; int getWidth() const;
int getHeight() const; int getHeight() const;
GLenum getFormat() const; GLenum getFormat() const;
D3DFORMAT getD3DFormat() const;
unsigned int getSerial() const; unsigned int getSerial() const;
void setStorage(RenderbufferStorage *newStorage); void setStorage(RenderbufferStorage *newStorage);
......
...@@ -5087,6 +5087,54 @@ void __stdcall glViewport(GLint x, GLint y, GLsizei width, GLsizei height) ...@@ -5087,6 +5087,54 @@ void __stdcall glViewport(GLint x, GLint y, GLsizei width, GLsizei height)
} }
} }
void __stdcall glBlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter)
{
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, "
"GLbitfield mask = 0x%X, GLenum filter = 0x%X)",
srcX0, srcY0, srcX1, srcX1, dstX0, dstY0, dstX1, dstY1, mask, filter);
try
{
switch (filter)
{
case GL_NEAREST:
break;
default:
return error(GL_INVALID_ENUM);
}
if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
{
return error(GL_INVALID_VALUE);
}
if (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0)
{
ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation");
return error(GL_INVALID_OPERATION);
}
gl::Context *context = gl::getContext();
if (context)
{
if (context->getReadFramebufferHandle() == context->getDrawFramebufferHandle())
{
ERR("Blits with the same source and destination framebuffer are not supported by this implementation.");
return error(GL_INVALID_OPERATION);
}
context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask);
}
}
catch(std::bad_alloc&)
{
return error(GL_OUT_OF_MEMORY);
}
}
void __stdcall glTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, void __stdcall glTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth,
GLint border, GLenum format, GLenum type, const GLvoid* pixels) GLint border, GLenum format, GLenum type, const GLvoid* pixels)
{ {
...@@ -5116,6 +5164,7 @@ __eglMustCastToProperFunctionPointerType __stdcall glGetProcAddress(const char * ...@@ -5116,6 +5164,7 @@ __eglMustCastToProperFunctionPointerType __stdcall glGetProcAddress(const char *
static const Extension glExtensions[] = static const Extension glExtensions[] =
{ {
{"glTexImage3DOES", (__eglMustCastToProperFunctionPointerType)glTexImage3DOES}, {"glTexImage3DOES", (__eglMustCastToProperFunctionPointerType)glTexImage3DOES},
{"glBlitFramebufferANGLE", (__eglMustCastToProperFunctionPointerType)glBlitFramebufferANGLE}
}; };
for (int ext = 0; ext < sizeof(glExtensions) / sizeof(Extension); ext++) for (int ext = 0; ext < sizeof(glExtensions) / sizeof(Extension); ext++)
......
...@@ -145,6 +145,7 @@ EXPORTS ...@@ -145,6 +145,7 @@ EXPORTS
; Extensions ; Extensions
glTexImage3DOES @143 glTexImage3DOES @143
glBlitFramebufferANGLE @149
; EGL dependencies ; EGL dependencies
glCreateContext @144 NONAME glCreateContext @144 NONAME
......
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