Kaydet (Commit) 6282509c authored tarafından Louis-Francis Ratté-Boulianne's avatar Louis-Francis Ratté-Boulianne Kaydeden (comit) Markus Mohrhard

vcl: Add a way to resize an image using the GPU

Change-Id: I949e13277fa176d64d7fba9a57e3ca6f3f0dd732
üst b4daf82f
......@@ -124,6 +124,7 @@ $(eval $(call gb_Library_use_externals,vcl,\
$(eval $(call gb_Library_add_exception_objects,vcl,\
vcl/opengl/gdiimpl \
vcl/opengl/salbmp \
vcl/opengl/scale \
vcl/opengl/texture \
vcl/source/opengl/OpenGLContext \
vcl/source/opengl/OpenGLHelper \
......
......@@ -10,6 +10,7 @@
$(eval $(call gb_Package_Package,vcl_opengl_shader,$(SRCDIR)/vcl/opengl))
$(eval $(call gb_Package_add_files,vcl_opengl_shader,$(LIBO_ETC_FOLDER)/opengl,\
convolutionFragmentShader.glsl \
maskFragmentShader.glsl \
maskVertexShader.glsl \
maskedTextureFragmentShader.glsl \
......
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#ifndef INCLUDED_VCL_INC_OPENGL_BMPOP_H
#define INCLUDED_VCL_INC_OPENGL_BMPOP_H
class OpenGLSalBitmapOp
{
public:
OpenGLSalBitmapOp() {};
virtual ~OpenGLSalBitmapOp() {};
virtual bool Execute() = 0;
virtual void GetSize( Size& rSize ) const = 0;
};
#endif // INCLUDED_VCL_INC_OPENGL_BMPOP_H
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
......@@ -24,9 +24,13 @@
#include <vcl/opengl/OpenGLContext.hxx>
#include "vcl/salbtype.hxx"
#include "opengl/bmpop.hxx"
#include "opengl/texture.hxx"
#include <salbmp.hxx>
#include <deque>
// - SalBitmap -
struct BitmapBuffer;
......@@ -35,17 +39,18 @@ class BitmapPalette;
class VCL_PLUGIN_PUBLIC OpenGLSalBitmap : public SalBitmap
{
private:
OpenGLContext* mpContext;
GLuint mnTexture;
bool mbDirtyTexture;
BitmapPalette maPalette;
basebmp::RawMemorySharedArray maUserBuffer;
sal_uInt16 mnBits;
sal_uInt16 mnBytesPerRow;
int mnWidth;
int mnHeight;
int mnTexWidth;
int mnTexHeight;
OpenGLContext* mpContext;
OpenGLTextureSharedPtr mpTexture;
bool mbDirtyTexture;
BitmapPalette maPalette;
basebmp::RawMemorySharedArray maUserBuffer;
sal_uInt16 mnBits;
sal_uInt16 mnBytesPerRow;
int mnWidth;
int mnHeight;
int mnBufWidth;
int mnBufHeight;
std::deque< OpenGLSalBitmapOp* > maPendingOps;
public:
OpenGLSalBitmap();
......@@ -87,6 +92,27 @@ private:
void DrawTexture( GLuint nTexture, const SalTwoRect& rPosAry );
bool AllocateUserData();
bool ReadTexture();
private:
GLuint ImplGetTextureProgram();
GLuint mnTexProgram;
GLuint mnTexSamplerUniform;
GLuint ImplGetConvolutionProgram();
GLuint mnConvProgram;
GLuint mnConvSamplerUniform;
GLuint mnConvKernelUniform;
GLuint mnConvKernelSizeUniform;
GLuint mnConvOffsetsUniform;
bool ImplScaleFilter( GLenum nFilter );
void ImplCreateKernel( const double& fScale, const Kernel& rKernel, GLfloat*& pWeights, sal_uInt32& aKernelSize );
bool ImplScaleConvolution( const double& rScaleX, const double& rScaleY, const Kernel& aKernel );
public:
bool ImplScale( const double& rScaleX, const double& rScaleY, sal_uInt32 nScaleFlag );
};
#endif // INCLUDED_VCL_INC_OPENGL_SALBMP_H
......
......@@ -17,8 +17,8 @@
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#ifndef INCLUDED_VCL_OPENGL_TEXTURE_H
#define INCLUDED_VCL_OPENGL_TEXTURE_H
#ifndef INCLUDED_VCL_INC_OPENGL_TEXTURE_H
#define INCLUDED_VCL_INC_OPENGL_TEXTURE_H
#include <boost/shared_ptr.hpp>
#include <GL/glew.h>
......@@ -29,20 +29,26 @@ private:
GLuint mnTexture;
int mnWidth;
int mnHeight;
GLenum mnFilter;
public:
OpenGLTexture();
OpenGLTexture( int nWidth, int nHeight );
OpenGLTexture( int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData );
OpenGLTexture( int nX, int nY, int nWidth, int nHeight );
virtual ~OpenGLTexture();
GLuint Id() const;
void Bind();
void Unbind();
bool Draw();
GLenum GetFilter() const;
void SetFilter( GLenum nFilter );
};
typedef boost::shared_ptr< OpenGLTexture > OpenGLTextureSharedPtr;
#endif // INCLUDED_VCL_OPENGL_TEXTURE_H
#endif // INCLUDED_VCL_INC_OPENGL_TEXTURE_H
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/* TODO Use textureOffset for newest version of GLSL */
uniform sampler2D sampler;
uniform vec2 offsets[16];
uniform float kernel[16];
varying vec2 tex_coord;
void main(void)
{
vec4 sum = texture2D(sampler, tex_coord.st) * kernel[0];
for (int i = 1; i < 16; i++) {
sum += texture2D(sampler, tex_coord.st - offsets[i]) * kernel[i];
sum += texture2D(sampler, tex_coord.st + offsets[i]) * kernel[i];
}
gl_FragColor = sum;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
......@@ -502,6 +502,7 @@ void OpenGLSalGraphicsImpl::drawLine( long nX1, long nY1, long nX2, long nY2 )
void OpenGLSalGraphicsImpl::drawRect( long nX, long nY, long nWidth, long nHeight )
{
maContext.makeCurrent();
glViewport( 0, 0, GetWidth(), GetHeight() );
if( mnFillColor != SALCOLOR_NONE )
{
......@@ -676,6 +677,7 @@ void OpenGLSalGraphicsImpl::drawBitmap( const SalTwoRect& rPosAry, const SalBitm
SAL_INFO( "vcl.opengl", "::drawBitmap" );
maContext.makeCurrent();
glViewport( 0, 0, GetWidth(), GetHeight() );
DrawTexture( nTexture, aSize, rPosAry );
}
......
......@@ -34,20 +34,22 @@ static bool isValidBitCount( sal_uInt16 nBitCount )
OpenGLSalBitmap::OpenGLSalBitmap()
: mpContext(NULL)
, mnTexture(0)
, mbDirtyTexture(true)
, mnBits(0)
, mnBytesPerRow(0)
, mnWidth(0)
, mnHeight(0)
, mnTexWidth(0)
, mnTexHeight(0)
, mnBufWidth(0)
, mnBufHeight(0)
, mnTexProgram(0)
, mnConvProgram(0)
{
}
OpenGLSalBitmap::~OpenGLSalBitmap()
{
Destroy();
SAL_INFO( "vcl.opengl", "~OpenGLSalBitmap" );
}
bool OpenGLSalBitmap::Create( OpenGLContext& rContext, long nX, long nY, long nWidth, long nHeight )
......@@ -55,20 +57,20 @@ bool OpenGLSalBitmap::Create( OpenGLContext& rContext, long nX, long nY, long nW
static const BitmapPalette aEmptyPalette;
Destroy();
SAL_INFO( "vcl.opengl", "OpenGLSalBitmap::Create from FBO" );
mpContext = &rContext;
mpContext->makeCurrent();
mnWidth = mnTexWidth = nWidth;
mnHeight = mnTexHeight = nHeight;
mnWidth = nWidth;
mnHeight = nHeight;
mnBufWidth = 0;
mnBufHeight = 0;
// TODO Check the framebuffer configuration
mnBits = 32;
maPalette = aEmptyPalette;
glGenTextures( 1, &mnTexture );
glBindTexture( GL_TEXTURE_2D, mnTexture );
glCopyTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, nX, nY, nWidth, nHeight, 0 );
glBindTexture( GL_TEXTURE_2D, 0 );
mpTexture.reset( new OpenGLTexture( nX, nY, nWidth, nHeight ) );
return true;
}
......@@ -76,13 +78,14 @@ bool OpenGLSalBitmap::Create( OpenGLContext& rContext, long nX, long nY, long nW
bool OpenGLSalBitmap::Create( const Size& rSize, sal_uInt16 nBits, const BitmapPalette& rBitmapPalette )
{
Destroy();
SAL_INFO( "vcl.opengl", "OpenGLSalBitmap::Create with size" );
if( !isValidBitCount( nBits ) )
return false;
maPalette = rBitmapPalette;
mnBits = nBits;
mnWidth = mnTexWidth = rSize.Width();
mnHeight = mnTexHeight = rSize.Height();
mnWidth = mnBufWidth = rSize.Width();
mnHeight = mnBufHeight = rSize.Height();
return false;
}
......@@ -100,15 +103,20 @@ bool OpenGLSalBitmap::Create( const SalBitmap& rSalBmp, sal_uInt16 nNewBitCount
{
const OpenGLSalBitmap& rSourceBitmap = static_cast<const OpenGLSalBitmap&>(rSalBmp);
SAL_INFO( "vcl.opengl", "OpenGLSalBitmap::Create from BMP " << rSourceBitmap.mnHeight );
if( isValidBitCount( nNewBitCount ) )
{
mnBits = nNewBitCount;
mnTexWidth = rSourceBitmap.mnTexWidth;
mnTexHeight = rSourceBitmap.mnTexHeight;
mnBytesPerRow = rSourceBitmap.mnBytesPerRow;
mnWidth = rSourceBitmap.mnWidth;
mnHeight = rSourceBitmap.mnHeight;
mnBufWidth = rSourceBitmap.mnBufWidth;
mnBufHeight = rSourceBitmap.mnBufHeight;
maPalette = rSourceBitmap.maPalette;
mnTexture = rSourceBitmap.mnTexture;
mpContext = rSourceBitmap.mpContext;
mpTexture = rSourceBitmap.mpTexture;
maUserBuffer = rSourceBitmap.maUserBuffer;
// TODO Copy buffer data if the bitcount and palette are the same
return true;
......@@ -127,13 +135,13 @@ bool OpenGLSalBitmap::Draw( OpenGLContext& rContext, const SalTwoRect& rPosAry )
if( !mpContext )
mpContext = &rContext;
if( !mnTexture || mbDirtyTexture )
if( !mpTexture || mbDirtyTexture )
{
if( !CreateTexture() )
return false;
}
DrawTexture( mnTexture, rPosAry );
//DrawTexture( mnTexture, rPosAry );
return true;
}
......@@ -141,20 +149,23 @@ GLuint OpenGLSalBitmap::GetTexture( OpenGLContext& rContext ) const
{
if( !mpContext )
const_cast<OpenGLSalBitmap*>(this)->mpContext = &rContext;
if( !mnTexture || mbDirtyTexture )
if( !mpTexture || mbDirtyTexture )
const_cast<OpenGLSalBitmap*>(this)->CreateTexture();
return mnTexture;
return mpTexture->Id();
}
void OpenGLSalBitmap::Destroy()
{
DeleteTexture();
SAL_INFO( "vcl.opengl", "Destroy OpenGLSalBitmap" );
maPendingOps.clear();
mpTexture.reset();
maUserBuffer.reset();
}
bool OpenGLSalBitmap::AllocateUserData()
{
Destroy();
SAL_INFO( "vcl.opengl", "OpenGLSalBitmap::AllocateUserData" );
if( mnWidth && mnHeight )
{
......@@ -295,7 +306,13 @@ ImplPixelFormat* ImplPixelFormat::GetFormat( sal_uInt16 nBits, const BitmapPalet
Size OpenGLSalBitmap::GetSize() const
{
return Size( mnWidth, mnHeight );
std::deque< OpenGLSalBitmapOp* >::const_iterator it = maPendingOps.begin();
Size aSize( mnWidth, mnHeight );
while( it != maPendingOps.end() )
(*it++)->GetSize( aSize );
return aSize;
}
GLuint OpenGLSalBitmap::CreateTexture()
......@@ -334,7 +351,7 @@ GLuint OpenGLSalBitmap::CreateTexture()
else
{
// convert to 32 bits RGBA using palette
pData = new sal_uInt8[ mnTexHeight * (mnTexWidth << 2) ];
pData = new sal_uInt8[ mnBufHeight * (mnBufWidth << 2) ];
bAllocated = true;
nFormat = GL_RGBA;
nType = GL_UNSIGNED_BYTE;
......@@ -343,12 +360,12 @@ GLuint OpenGLSalBitmap::CreateTexture()
sal_uInt8* pSrcData = maUserBuffer.get();
sal_uInt8* pDstData = pData;
sal_uInt32 nY = mnTexHeight;
sal_uInt32 nY = mnBufHeight;
while( nY-- )
{
pSrcFormat->StartLine( pSrcData );
sal_uInt32 nX = mnTexWidth;
sal_uInt32 nX = mnBufWidth;
while( nX-- )
{
const BitmapColor& c = pSrcFormat->ReadPixel();
......@@ -364,59 +381,22 @@ GLuint OpenGLSalBitmap::CreateTexture()
}
}
SAL_INFO( "vcl.opengl", "::CreateTexture" );
mpContext->makeCurrent();
if( !mnTexture )
glGenTextures( 1, &mnTexture );
glBindTexture( GL_TEXTURE_2D, mnTexture );
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
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, mnTexWidth, mnTexHeight, 0, nFormat, nType, pData );
glBindTexture( GL_TEXTURE_2D, 0 );
mpTexture.reset( new OpenGLTexture (mnBufWidth, mnBufHeight, nFormat, nType, pData ) );
if( bAllocated )
delete pData;
mbDirtyTexture = false;
return mnTexture;
}
void OpenGLSalBitmap::DeleteTexture()
{
if( mnTexture )
while( !maPendingOps.empty() )
{
mpContext->makeCurrent();
glDeleteTextures( 1, &mnTexture );
mnTexture = 0;
OpenGLSalBitmapOp* pOp = maPendingOps.front();
pOp->Execute();
maPendingOps.pop_front();
}
}
void OpenGLSalBitmap::DrawTexture( GLuint nTexture, const SalTwoRect& /*rPosAry*/ )
{
GLushort aTexCoord[8];
GLushort aVertices[8];
/*if( mnTextureProgram == 0 )
{
if( !CreateTextureProgram() )
return;
}*/
//glUseProgram( mnTextureProgram );
//glUniform1i( mnSamplerUniform, 0 );
glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, nTexture );
glEnableVertexAttribArray( 0 );
glVertexAttribPointer( 0, 8, GL_UNSIGNED_SHORT, GL_FALSE, 0, aTexCoord );
glEnableVertexAttribArray( 1 );
glVertexAttribPointer( 1, 8, GL_UNSIGNED_SHORT, GL_FALSE, 0, aVertices );
glDrawArrays( GL_TRIANGLE_FAN, 0, 4 );
glDisableVertexAttribArray( 0 );
glDisableVertexAttribArray( 1 );
glBindTexture( GL_TEXTURE_2D, 0 );
glUseProgram( 0 );
mbDirtyTexture = false;
return mpTexture->Id();
}
bool OpenGLSalBitmap::ReadTexture()
......@@ -428,17 +408,17 @@ bool OpenGLSalBitmap::ReadTexture()
// TODO Check mnTexWidth and mnTexHeight
mpContext->makeCurrent();
OpenGLHelper::createFramebuffer( mnTexWidth, mnTexHeight, nFramebufferId,
OpenGLHelper::createFramebuffer( mnWidth, mnHeight, nFramebufferId,
nRenderbufferDepthId, nRenderbufferColorId, true );
glBindFramebuffer( GL_FRAMEBUFFER, nFramebufferId );
aPosAry.mnSrcX = aPosAry.mnDestX = 0;
aPosAry.mnSrcY = aPosAry.mnDestY = 0;
aPosAry.mnSrcWidth = aPosAry.mnDestWidth = mnTexWidth;
aPosAry.mnSrcHeight = aPosAry.mnDestHeight = mnTexHeight;
aPosAry.mnSrcWidth = aPosAry.mnDestWidth = mnWidth;
aPosAry.mnSrcHeight = aPosAry.mnDestHeight = mnHeight;
DrawTexture( mnTexture, aPosAry );
glReadPixels( 0, 0, mnTexWidth, mnTexHeight, GL_RGBA, GL_UNSIGNED_BYTE, pData );
//DrawTexture( mnTexture, aPosAry );
glReadPixels( 0, 0, mnWidth, mnHeight, GL_RGBA, GL_UNSIGNED_BYTE, pData );
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
glDeleteFramebuffers( 1, &nFramebufferId );
......@@ -459,7 +439,7 @@ BitmapBuffer* OpenGLSalBitmap::AcquireBuffer( bool /*bReadOnly*/ )
{
if( !AllocateUserData() )
return NULL;
if( mnTexture && !ReadTexture() )
if( mpTexture && !ReadTexture() )
return NULL;
}
......@@ -528,12 +508,4 @@ bool OpenGLSalBitmap::GetSystemData( BitmapSystemData& /*rData*/ )
#endif
}
bool OpenGLSalBitmap::Scale( const double& rScaleX, const double& rScaleY, sal_uInt32 /*nScaleFlag*/ )
{
SAL_INFO( "vcl.opengl", "::Scale" );
mnWidth *= rScaleX;
mnHeight *= rScaleY;
return true;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <sal/config.h>
#include <vcl/opengl/OpenGLHelper.hxx>
#include "vcl/bitmap.hxx"
#include "opengl/bmpop.hxx"
#include "opengl/salbmp.hxx"
#include "opengl/texture.hxx"
class ScaleOp : public OpenGLSalBitmapOp
{
private:
OpenGLSalBitmap* mpBitmap;
double mfScaleX;
double mfScaleY;
sal_uInt32 mnScaleFlag;
public:
ScaleOp( OpenGLSalBitmap* pBitmap, const double& rScaleX, const double& rScaleY, sal_uInt32 nScaleFlag );
bool Execute() SAL_OVERRIDE;
void GetSize( Size& rSize ) const SAL_OVERRIDE;
};
GLuint OpenGLSalBitmap::ImplGetTextureProgram()
{
if( mnTexProgram == 0 )
{
mnTexProgram = OpenGLHelper::LoadShaders( "textureVertexShader",
"textureFragmentShader" );
if( mnTexProgram == 0 )
return 0;
glBindAttribLocation( mnTexProgram, 0, "position" );
glBindAttribLocation( mnTexProgram, 1, "tex_coord_in" );
mnTexSamplerUniform = glGetUniformLocation( mnTexProgram, "sampler" );
}
return mnTexProgram;
}
GLuint OpenGLSalBitmap::ImplGetConvolutionProgram()
{
if( mnConvProgram == 0 )
{
mnConvProgram = OpenGLHelper::LoadShaders( "textureVertexShader",
"convolutionFragmentShader" );
if( mnConvProgram == 0 )
return 0;
glBindAttribLocation( mnConvProgram, 0, "position" );
glBindAttribLocation( mnConvProgram, 1, "tex_coord_in" );
mnConvSamplerUniform = glGetUniformLocation( mnConvProgram, "sampler" );
mnConvKernelUniform = glGetUniformLocation( mnConvProgram, "kernel" );
mnConvOffsetsUniform = glGetUniformLocation( mnConvProgram, "offsets" );
}
return mnConvProgram;
}
bool OpenGLSalBitmap::ImplScaleFilter( GLenum nFilter )
{
OpenGLTexture* pNewTex;
GLuint nProgram;
GLuint nFramebufferId;
GLenum nOldFilter;
nProgram = ImplGetTextureProgram();
if( nProgram == 0 )
return false;
glGenFramebuffers( 1, &nFramebufferId );
glBindFramebuffer( GL_FRAMEBUFFER, nFramebufferId );
glUseProgram( nProgram );
glUniform1i( mnTexSamplerUniform, 0 );
pNewTex = new OpenGLTexture( mnWidth, mnHeight );
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, pNewTex->Id(), 0 );
mpTexture->Bind();
nOldFilter = mpTexture->GetFilter();
mpTexture->SetFilter( nFilter );
mpTexture->Draw();
mpTexture->SetFilter( nOldFilter );
mpTexture->Unbind();
glUseProgram( 0 );
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
glDeleteFramebuffers( 1, &nFramebufferId );
mpTexture.reset( pNewTex );
return true;
}
void OpenGLSalBitmap::ImplCreateKernel(
const double& fScale,
const Kernel& rKernel,
GLfloat*& pWeights,
sal_uInt32& aKernelSize )
{
const double fSamplingRadius(rKernel.GetWidth());
const double fScaledRadius((fScale < 1.0) ? fSamplingRadius / fScale : fSamplingRadius);
const double fFilterFactor((fScale < 1.0) ? fScale : 1.0);
int aNumberOfContributions;
double aSum( 0 );
aNumberOfContributions = (static_cast< sal_uInt32 >(fabs(ceil(fScaledRadius))) * 2) + 1 - 6;
aKernelSize = aNumberOfContributions / 2 + 1;
pWeights = new GLfloat[16];
memset( pWeights, 0, 16 * sizeof( GLfloat ) );
for( sal_uInt32 i(0); i < aKernelSize; i++ )
{
const GLfloat aWeight( rKernel.Calculate( fFilterFactor * i ) );
if( fabs( aWeight ) >= 0.0001 )
{
pWeights[i] = aWeight;
aSum += i > 0 ? aWeight * 2 : aWeight;
}
}
for( sal_uInt32 i(0); i < aKernelSize; i++ )
{
pWeights[i] /= aSum;
}
}
bool OpenGLSalBitmap::ImplScaleConvolution(
const double& rScaleX,
const double& rScaleY,
const Kernel& aKernel )
{
OpenGLTexture* pScratchTex;
OpenGLTexture* pNewTex;
GLfloat* pWeights( 0 );
GLuint nFramebufferId;
GLuint nProgram;
sal_uInt32 nKernelSize;
GLfloat aOffsets[32];
int nNewWidth( mnWidth * rScaleX );
int nNewHeight( mnHeight * rScaleY );
// TODO Make sure the framebuffer is alright
nProgram = ImplGetConvolutionProgram();
if( nProgram == 0 )
return false;
glGenFramebuffers( 1, &nFramebufferId );
glBindFramebuffer( GL_FRAMEBUFFER, nFramebufferId );
glUseProgram( nProgram );
glUniform1i( mnConvSamplerUniform, 0 );
CHECK_GL_ERROR();
// horizontal scaling in scratch texture
pScratchTex = new OpenGLTexture( nNewWidth, mnHeight );
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, pScratchTex->Id(), 0 );
CHECK_GL_ERROR();
for( sal_uInt32 i = 0; i < 16; i++ )
{
aOffsets[i * 2] = i / (double) mnWidth;
aOffsets[i * 2 + 1] = 0;
}
ImplCreateKernel( rScaleX, aKernel, pWeights, nKernelSize );
glUniform1fv( mnConvKernelUniform, 16, pWeights );
CHECK_GL_ERROR();
glUniform2fv( mnConvOffsetsUniform, 16, aOffsets );
CHECK_GL_ERROR();
glViewport( 0, 0, nNewWidth, mnHeight );
mpTexture->Bind();
mpTexture->Draw();
mpTexture->Unbind();
// vertical scaling in final texture
pNewTex = new OpenGLTexture( nNewWidth, nNewHeight );
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, pNewTex->Id(), 0 );
for( sal_uInt32 i = 0; i < 16; i++ )
{
aOffsets[i * 2] = 0;
aOffsets[i * 2 + 1] = i / (double) mnHeight;
}
ImplCreateKernel( rScaleY, aKernel, pWeights, nKernelSize );
glUniform1fv( mnConvKernelUniform, 16, pWeights );
glUniform2fv( mnConvOffsetsUniform, 16, aOffsets );
CHECK_GL_ERROR();
glViewport( 0, 0, nNewWidth, nNewHeight );
pScratchTex->Bind();
pScratchTex->Draw();
pScratchTex->Unbind();
glUseProgram( 0 );
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
glDeleteFramebuffers( 1, &nFramebufferId );
delete pScratchTex;
mpTexture.reset( pNewTex );
mnWidth = nNewWidth;
mnHeight = nNewHeight;
return true;
}
bool OpenGLSalBitmap::ImplScale( const double& rScaleX, const double& rScaleY, sal_uInt32 nScaleFlag )
{
SAL_INFO( "vcl.opengl", "::ImplScale" );
if( nScaleFlag == BMP_SCALE_FAST )
{
return ImplScaleFilter( GL_NEAREST );
}
if( nScaleFlag == BMP_SCALE_BILINEAR )
{
return ImplScaleFilter( GL_LINEAR );
}
else if( nScaleFlag == BMP_SCALE_SUPER )
{
const Lanczos3Kernel aKernel;
return ImplScaleConvolution( rScaleX, rScaleY, aKernel );
}
else if( nScaleFlag == BMP_SCALE_LANCZOS )
{
const Lanczos3Kernel aKernel;
return ImplScaleConvolution( rScaleX, rScaleY, aKernel );
}
SAL_WARN( "vcl.opengl", "Invalid flag for scaling operation" );
return false;
}
ScaleOp::ScaleOp(
OpenGLSalBitmap* pBitmap,
const double& rScaleX,
const double& rScaleY,
sal_uInt32 nScaleFlag )
: mpBitmap( pBitmap )
, mfScaleX( rScaleX )
, mfScaleY( rScaleY )
, mnScaleFlag( nScaleFlag )
{
}
bool ScaleOp::Execute()
{
SAL_INFO( "vcl.opengl", "::Execute" );
return mpBitmap->ImplScale( mfScaleX, mfScaleY, mnScaleFlag );
}
void ScaleOp::GetSize( Size& rSize ) const
{
SAL_INFO( "vcl.opengl", "::GetSize" );
rSize.setWidth( rSize.Width() * mfScaleX );
rSize.setHeight( rSize.Height() * mfScaleY );
}
bool OpenGLSalBitmap::Scale( const double& rScaleX, const double& rScaleY, sal_uInt32 nScaleFlag )
{
SAL_INFO( "vcl.opengl", "::Scale " << nScaleFlag );
if( nScaleFlag == BMP_SCALE_FAST ||
nScaleFlag == BMP_SCALE_BILINEAR ||
nScaleFlag == BMP_SCALE_SUPER ||
nScaleFlag == BMP_SCALE_LANCZOS )
{
//TODO maUserBuffer.reset();
if( mpContext == NULL )
{
SAL_INFO( "vcl.opengl", "Add ScaleOp to pending operations" );
maPendingOps.push_back( new ScaleOp( this, rScaleX, rScaleY, nScaleFlag ) );
}
else
{
ImplScale( rScaleX, rScaleY, nScaleFlag );
}
return true;
}
return false;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
......@@ -17,12 +17,16 @@
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include "texture.hxx"
#include <sal/config.h>
#include "vcl/salbtype.hxx"
#include "opengl/texture.hxx"
OpenGLTexture::OpenGLTexture()
: mnTexture( 0 )
, mnWidth( -1 )
, mnHeight( -1 )
, mnFilter( GL_NEAREST )
{
}
......@@ -30,6 +34,7 @@ OpenGLTexture::OpenGLTexture( int nWidth, int nHeight )
: mnTexture( 0 )
, mnWidth( nWidth )
, mnHeight( nHeight )
, mnFilter( GL_NEAREST )
{
glGenTextures( 1, &mnTexture );
glBindTexture( GL_TEXTURE_2D, mnTexture );
......@@ -41,6 +46,40 @@ OpenGLTexture::OpenGLTexture( int nWidth, int nHeight )
glBindTexture( GL_TEXTURE_2D, 0 );
}
OpenGLTexture::OpenGLTexture( int nX, int nY, int nWidth, int nHeight )
: mnTexture( 0 )
, mnWidth( nWidth )
, mnHeight( nHeight )
, mnFilter( GL_NEAREST )
{
glGenTextures( 1, &mnTexture );
glBindTexture( GL_TEXTURE_2D, mnTexture );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
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 );
glCopyTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, nX, nY, nWidth, nHeight, 0 );
glBindTexture( GL_TEXTURE_2D, 0 );
}
OpenGLTexture::OpenGLTexture( int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData )
: mnTexture( 0 )
, mnWidth( nWidth )
, mnHeight( nHeight )
, mnFilter( GL_NEAREST )
{
if( !mnTexture )
glGenTextures( 1, &mnTexture );
glBindTexture( GL_TEXTURE_2D, mnTexture );
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
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, mnWidth, mnHeight, 0, nFormat, nType, pData );
glBindTexture( GL_TEXTURE_2D, 0 );
}
OpenGLTexture::~OpenGLTexture()
{
if( mnTexture != 0 )
......@@ -52,6 +91,21 @@ GLuint OpenGLTexture::Id() const
return mnTexture;
}
GLenum OpenGLTexture::GetFilter() const
{
return mnFilter;
}
void OpenGLTexture::SetFilter( GLenum nFilter )
{
mnFilter = nFilter;
if( mnTexture )
{
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, nFilter );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, nFilter );
}
}
void OpenGLTexture::Bind()
{
glBindTexture( GL_TEXTURE_2D, mnTexture );
......
......@@ -874,10 +874,23 @@ bool Bitmap::Scale( const double& rScaleX, const double& rScaleY, sal_uInt32 nSc
bRetval = true;
}
if( mpImpBmp && mpImpBmp->ImplScale( rScaleX, rScaleY, nScaleFlag ) )
if( mpImpBmp )
{
// implementation specific scaling
return true;
ImpBitmap* pImpBmp = new ImpBitmap;
if( pImpBmp->ImplCreate( *mpImpBmp ) && pImpBmp->ImplScale( rScaleX, rScaleY, nScaleFlag ) )
{
ImplSetImpBitmap( pImpBmp );
SAL_INFO( "vcl.opengl", "Ref count: " << mpImpBmp->ImplGetRefCount() );
maPrefMapMode = MapMode( MAP_PIXEL );
maPrefSize = pImpBmp->ImplGetSize();
return true;
}
else
{
delete pImpBmp;
}
}
//fdo#33455
......
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