diff options
author | Louis-Francis Ratté-Boulianne <lfrb@collabora.com> | 2014-11-13 21:37:54 -0500 |
---|---|---|
committer | Markus Mohrhard <markus.mohrhard@googlemail.com> | 2014-11-15 12:17:43 +0100 |
commit | dce9610afed674ecec23497a1a004193a6cf3bf1 (patch) | |
tree | 7b0e2063667645ae3a4259a08c0ab1d2fce0eaf1 /vcl/opengl/texture.cxx | |
parent | 330b7b310193f3290cbd4c340659f72d12c352e1 (diff) |
vcl: Improve OpenGLTexture implementation by allowing implicit sharing
Conflicts:
vcl/opengl/gdiimpl.cxx
Change-Id: I6421265325e72023d1affe671d75488185772786
Diffstat (limited to 'vcl/opengl/texture.cxx')
-rw-r--r-- | vcl/opengl/texture.cxx | 243 |
1 files changed, 206 insertions, 37 deletions
diff --git a/vcl/opengl/texture.cxx b/vcl/opengl/texture.cxx index 0c8dc1d69b8e..005fb66afa2e 100644 --- a/vcl/opengl/texture.cxx +++ b/vcl/opengl/texture.cxx @@ -24,19 +24,12 @@ #include "opengl/texture.hxx" -OpenGLTexture::OpenGLTexture() -: mnTexture( 0 ) -, mnWidth( -1 ) -, mnHeight( -1 ) -, mnFilter( GL_NEAREST ) -{ -} - -OpenGLTexture::OpenGLTexture( int nWidth, int nHeight ) -: mnTexture( 0 ) -, mnWidth( nWidth ) -, mnHeight( nHeight ) -, mnFilter( GL_NEAREST ) +// texture with allocated size +ImplOpenGLTexture::ImplOpenGLTexture( int nWidth, int nHeight, bool bAllocate ) : + mnRefCount( 1 ), + mnWidth( nWidth ), + mnHeight( nHeight ), + mnFilter( GL_NEAREST ) { glGenTextures( 1, &mnTexture ); glBindTexture( GL_TEXTURE_2D, mnTexture ); @@ -44,15 +37,18 @@ OpenGLTexture::OpenGLTexture( int nWidth, int nHeight ) glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); - glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, nWidth, nHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL ); + if( bAllocate ) + glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, nWidth, nHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL ); glBindTexture( GL_TEXTURE_2D, 0 ); } -OpenGLTexture::OpenGLTexture( int nX, int nY, int nWidth, int nHeight ) -: mnTexture( 0 ) -, mnWidth( nWidth ) -, mnHeight( nHeight ) -, mnFilter( GL_NEAREST ) +// texture with content retrieved from FBO +ImplOpenGLTexture::ImplOpenGLTexture( int nX, int nY, int nWidth, int nHeight ) : + mnRefCount( 1 ), + mnTexture( 0 ), + mnWidth( nWidth ), + mnHeight( nHeight ), + mnFilter( GL_NEAREST ) { glGenTextures( 1, &mnTexture ); glBindTexture( GL_TEXTURE_2D, mnTexture ); @@ -66,11 +62,13 @@ OpenGLTexture::OpenGLTexture( int nX, int nY, int nWidth, int nHeight ) CHECK_GL_ERROR(); } -OpenGLTexture::OpenGLTexture( int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData ) -: mnTexture( 0 ) -, mnWidth( nWidth ) -, mnHeight( nHeight ) -, mnFilter( GL_NEAREST ) +// texture from buffer data +ImplOpenGLTexture::ImplOpenGLTexture( int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData ) : + mnRefCount( 1 ), + mnTexture( 0 ), + mnWidth( nWidth ), + mnHeight( nHeight ), + mnFilter( GL_NEAREST ) { if( !mnTexture ) glGenTextures( 1, &mnTexture ); @@ -84,37 +82,119 @@ OpenGLTexture::OpenGLTexture( int nWidth, int nHeight, int nFormat, int nType, s glBindTexture( GL_TEXTURE_2D, 0 ); } -OpenGLTexture::~OpenGLTexture() +ImplOpenGLTexture::~ImplOpenGLTexture() { + SAL_INFO( "vcl.opengl", "~OpenGLTexture " << mnTexture ); if( mnTexture != 0 ) glDeleteTextures( 1, &mnTexture ); } +OpenGLTexture::OpenGLTexture() : + maRect( 0, 0, 0, 0 ), + mpImpl( NULL ) +{ +} + +OpenGLTexture::OpenGLTexture( int nWidth, int nHeight, bool bAllocate ) : + maRect( Point( 0, 0 ), Size( nWidth, nHeight ) ) +{ + mpImpl = new ImplOpenGLTexture( nWidth, nHeight, bAllocate ); +} + +OpenGLTexture::OpenGLTexture( int nX, int nY, int nWidth, int nHeight ) : + maRect( Point( 0, 0 ), Size( nWidth, nHeight ) ) +{ + mpImpl = new ImplOpenGLTexture( nX, nY, nWidth, nHeight ); +} + +OpenGLTexture::OpenGLTexture( int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData ) : + maRect( Point( 0, 0 ), Size( nWidth, nHeight ) ) +{ + mpImpl = new ImplOpenGLTexture( nWidth, nHeight, nFormat, nType, pData ); +} + +OpenGLTexture::OpenGLTexture( const OpenGLTexture& rTexture ) +{ + maRect = rTexture.maRect; + mpImpl = rTexture.mpImpl; + if( mpImpl ) + mpImpl->mnRefCount++; +} + +OpenGLTexture::OpenGLTexture( const OpenGLTexture& rTexture, + int nX, int nY, int nWidth, int nHeight ) +{ + maRect = Rectangle( Point( rTexture.maRect.Left() + nX, rTexture.maRect.Top() + nY ), + Size( nWidth, nHeight ) ); + mpImpl = rTexture.mpImpl; + if( mpImpl ) + mpImpl->mnRefCount++; + SAL_INFO( "vcl.opengl", "Copying texture " << Id() << " [" << maRect.Left() << "," << maRect.Top() << "] " << GetWidth() << "x" << GetHeight() ); +} + +OpenGLTexture::~OpenGLTexture() +{ + if( mpImpl ) + { + if( mpImpl->mnRefCount == 1 ) + delete mpImpl; + else + mpImpl->mnRefCount--; + } +} + +bool OpenGLTexture::IsUnique() const +{ + return ( mpImpl == NULL || mpImpl->mnRefCount == 1 ); +} + GLuint OpenGLTexture::Id() const { - return mnTexture; + if( mpImpl ) + return mpImpl->mnTexture; + return 0; } int OpenGLTexture::GetWidth() const { - return mnWidth; + return maRect.GetWidth(); } int OpenGLTexture::GetHeight() const { - return mnHeight; + return maRect.GetHeight(); +} + +void OpenGLTexture::GetCoord( GLfloat* pCoord, const SalTwoRect& rPosAry, bool bInverted ) const +{ + SAL_INFO( "vcl.opengl", "Getting coord " << Id() << " [" << maRect.Left() << "," << maRect.Top() << "] " << GetWidth() << "x" << GetHeight() ); + pCoord[0] = pCoord[2] = (maRect.Left() + rPosAry.mnSrcX) / (double) mpImpl->mnWidth; + pCoord[4] = pCoord[6] = (maRect.Left() + rPosAry.mnSrcX + rPosAry.mnSrcWidth) / (double) mpImpl->mnWidth; + + if( !bInverted ) + { + pCoord[3] = pCoord[5] = 1.0f - (maRect.Top() + rPosAry.mnSrcY) / (double) mpImpl->mnHeight; + pCoord[1] = pCoord[7] = 1.0f - (maRect.Top() + rPosAry.mnSrcY + rPosAry.mnSrcHeight) / (double) mpImpl->mnHeight; + } + else + { + pCoord[1] = pCoord[7] = 1.0f - (maRect.Top() + rPosAry.mnSrcY) / (double) mpImpl->mnHeight; + pCoord[3] = pCoord[5] = 1.0f - (maRect.Top() + rPosAry.mnSrcY + rPosAry.mnSrcHeight) / (double) mpImpl->mnHeight; + } } GLenum OpenGLTexture::GetFilter() const { - return mnFilter; + if( mpImpl ) + return mpImpl->mnFilter; + return GL_NEAREST; } void OpenGLTexture::SetFilter( GLenum nFilter ) { - mnFilter = nFilter; - if( mnTexture ) + if( mpImpl ) { + mpImpl->mnFilter = nFilter; glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, nFilter ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, nFilter ); } @@ -122,23 +202,38 @@ void OpenGLTexture::SetFilter( GLenum nFilter ) void OpenGLTexture::Bind() { - glBindTexture( GL_TEXTURE_2D, mnTexture ); + if( mpImpl ) + glBindTexture( GL_TEXTURE_2D, mpImpl->mnTexture ); } void OpenGLTexture::Unbind() { - glBindTexture( GL_TEXTURE_2D, 0 ); + if( mpImpl ) + glBindTexture( GL_TEXTURE_2D, 0 ); } bool OpenGLTexture::Draw() { - const GLfloat aPosition[8] = { -1, -1, -1, 1, 1, 1, 1, -1 }; - const GLfloat aTexCoord[8] = { 0, 0, 0, 1, 1, 1, 1, 0 }; + GLfloat aPosition[8] = { -1, -1, -1, 1, 1, 1, 1, -1 }; + GLfloat aTexCoord[8] = { 0, 0, 0, 1, 1, 1, 1, 0 }; - if( mnTexture == 0 ) + if( mpImpl == NULL ) + { + SAL_WARN( "vcl.opengl", "Can't draw invalid texture" ); return false; + } - glBindTexture( GL_TEXTURE_2D, mnTexture ); + SAL_INFO( "vcl.opengl", "Drawing texture " << Id() << " [" << maRect.Left() << "," << maRect.Top() << "] " << GetWidth() << "x" << GetHeight() ); + if( GetWidth() != mpImpl->mnWidth || GetHeight() != mpImpl->mnHeight ) + { + // FIXME: lfrb: check math + aTexCoord[0] = aTexCoord[2] = maRect.Left() / (double) mpImpl->mnWidth; + aTexCoord[4] = aTexCoord[6] = maRect.Right() / (double) mpImpl->mnWidth; + aTexCoord[1] = aTexCoord[7] = maRect.Top() / (double) mpImpl->mnHeight; + aTexCoord[3] = aTexCoord[5] = maRect.Bottom() / (double) mpImpl->mnHeight; + } + + glBindTexture( GL_TEXTURE_2D, mpImpl->mnTexture ); glEnableVertexAttribArray( 0 ); glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, 0, aPosition ); glEnableVertexAttribArray( 1 ); @@ -151,4 +246,78 @@ bool OpenGLTexture::Draw() return true; } +void OpenGLTexture::Read( GLenum nFormat, GLenum nType, sal_uInt8* pData ) +{ + if( mpImpl == NULL ) + { + SAL_WARN( "vcl.opengl", "Can't read invalid texture" ); + return; + } + + Bind(); + glPixelStorei( GL_PACK_ALIGNMENT, 1 ); + + SAL_INFO( "vcl.opengl", "Reading texture " << Id() << " " << GetWidth() << "x" << GetHeight() ); + + if( GetWidth() == mpImpl->mnWidth && GetHeight() == mpImpl->mnHeight ) + { + // XXX: Call not available with GLES 2.0 + glGetTexImage( GL_TEXTURE_2D, 0, nFormat, nType, pData ); + } + else + { + GLuint nFramebufferId; + glGenFramebuffers( 1, &nFramebufferId ); + glBindFramebuffer( GL_FRAMEBUFFER, nFramebufferId ); + CHECK_GL_ERROR(); + + glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, Id(), 0 ); + CHECK_GL_ERROR(); + glReadPixels( maRect.Left(), mpImpl->mnHeight - maRect.Top(), GetWidth(), GetHeight(), nFormat, nType, pData ); + CHECK_GL_ERROR(); + + glBindFramebuffer( GL_FRAMEBUFFER, 0 ); + glDeleteFramebuffers( 1, &nFramebufferId ); + + int bpp = (nFormat == GL_RGB) ? 3 : 4; + memset( pData, 255, GetWidth() * GetHeight() * bpp ); + } + + Unbind(); + CHECK_GL_ERROR(); +} + +OpenGLTexture::operator bool() const +{ + return ( mpImpl != NULL ); +} + +OpenGLTexture& OpenGLTexture::operator=( const OpenGLTexture& rTexture ) +{ + if( rTexture.mpImpl ) + rTexture.mpImpl->mnRefCount++; + if( mpImpl ) + { + if( mpImpl->mnRefCount == 1 ) + delete mpImpl; + else + mpImpl->mnRefCount--; + } + + maRect = rTexture.maRect; + mpImpl = rTexture.mpImpl; + + return *this; +} + +bool OpenGLTexture::operator==( const OpenGLTexture& rTexture ) const +{ + return (mpImpl == rTexture.mpImpl && maRect == rTexture.maRect ); +} + +bool OpenGLTexture::operator!=( const OpenGLTexture& rTexture ) const +{ + return !( *this == rTexture ); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |