1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include "ogl_spritedevicehelper.hxx"
11 #include "ogl_spritecanvas.hxx"
12 #include "ogl_canvasbitmap.hxx"
13 #include "ogl_canvastools.hxx"
14 #include "ogl_canvascustomsprite.hxx"
15 #include "ogl_texturecache.hxx"
17 #include <canvas/verbosetrace.hxx>
18 #include <basegfx/tools/canvastools.hxx>
19 #include <basegfx/tools/unopolypolygon.hxx>
21 #include <osl/mutex.hxx>
22 #include <rtl/instance.hxx>
23 #include <com/sun/star/uno/Reference.hxx>
24 #include <com/sun/star/lang/NoSupportException.hpp>
25 #include <com/sun/star/rendering/XColorSpace.hpp>
26 #include <com/sun/star/rendering/XIntegerBitmapColorSpace.hpp>
28 #include <vcl/sysdata.hxx>
29 #include <vcl/syschild.hxx>
30 #include <vcl/canvastools.hxx>
31 #include <toolkit/helper/vclunohelper.hxx>
33 #include <vcl/opengl/OpenGLHelper.hxx>
35 using namespace ::com::sun::star
;
37 static void initContext()
39 // need the backside for mirror effects
40 glDisable(GL_CULL_FACE
);
42 // no perspective, we're 2D
43 glMatrixMode(GL_PROJECTION
);
47 glEnable(GL_POINT_SMOOTH
);
48 glEnable(GL_LINE_SMOOTH
);
49 glEnable(GL_POLYGON_SMOOTH
);
50 glHint(GL_POINT_SMOOTH_HINT
,GL_NICEST
);
51 glHint(GL_LINE_SMOOTH_HINT
,GL_NICEST
);
52 glHint(GL_POLYGON_SMOOTH_HINT
,GL_NICEST
);
53 glShadeModel(GL_FLAT
);
56 static void initTransformation(const ::Size
& rSize
, bool bMirror
=false)
60 (GLsizei
)rSize
.Width(),
61 (GLsizei
)rSize
.Height() );
63 // model coordinate system is already in device pixel
64 glMatrixMode(GL_MODELVIEW
);
66 glTranslated(-1.0, (bMirror
? -1.0 : 1.0), 0.0);
67 glScaled( 2.0 / rSize
.Width(),
68 (bMirror
? 2.0 : -2.0) / rSize
.Height(),
72 glClearColor(0,0,0,0);
73 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
79 SpriteDeviceHelper::SpriteDeviceHelper() :
84 mpTextureCache(new TextureCache()),
85 mnLinearTwoColorGradientProgram(0),
86 mnLinearMultiColorGradientProgram(0),
87 mnRadialTwoColorGradientProgram(0),
88 mnRadialMultiColorGradientProgram(0),
89 mnRectangularTwoColorGradientProgram(0),
90 mnRectangularMultiColorGradientProgram(0)
93 SpriteDeviceHelper::~SpriteDeviceHelper()
96 void SpriteDeviceHelper::init( vcl::Window
& rWindow
,
97 SpriteCanvas
& rSpriteCanvas
,
98 const awt::Rectangle
& rViewArea
)
100 mpSpriteCanvas
= &rSpriteCanvas
;
102 rSpriteCanvas
.setWindow(
103 uno::Reference
<awt::XWindow2
>(
104 VCLUnoHelper::GetInterface(&rWindow
),
105 uno::UNO_QUERY_THROW
) );
107 maContext
.requestLegacyContext();
108 maContext
.init(&rWindow
);
109 // init window context
112 mnLinearMultiColorGradientProgram
=
113 OpenGLHelper::LoadShaders("dummyVertexShader", "linearMultiColorGradientFragmentShader");
115 mnLinearTwoColorGradientProgram
=
116 OpenGLHelper::LoadShaders("dummyVertexShader", "linearTwoColorGradientFragmentShader");
118 mnRadialMultiColorGradientProgram
=
119 OpenGLHelper::LoadShaders("dummyVertexShader", "radialMultiColorGradientFragmentShader");
121 mnRadialTwoColorGradientProgram
=
122 OpenGLHelper::LoadShaders("dummyVertexShader", "radialTwoColorGradientFragmentShader");
124 mnRectangularMultiColorGradientProgram
=
125 OpenGLHelper::LoadShaders("dummyVertexShader", "rectangularMultiColorGradientFragmentShader");
127 mnRectangularTwoColorGradientProgram
=
128 OpenGLHelper::LoadShaders("dummyVertexShader", "rectangularTwoColorGradientFragmentShader");
130 maContext
.makeCurrent();
132 notifySizeUpdate(rViewArea
);
133 // TODO(E3): check for GL_ARB_imaging extension
136 void SpriteDeviceHelper::disposing()
138 // release all references
139 mpSpriteCanvas
= NULL
;
141 mpTextureCache
.reset();
143 if( maContext
.isInitialized() )
145 glDeleteProgram( mnRectangularTwoColorGradientProgram
);
146 glDeleteProgram( mnRectangularMultiColorGradientProgram
);
147 glDeleteProgram( mnRadialTwoColorGradientProgram
);
148 glDeleteProgram( mnRadialMultiColorGradientProgram
);
149 glDeleteProgram( mnLinearTwoColorGradientProgram
);
150 glDeleteProgram( mnLinearMultiColorGradientProgram
);
154 geometry::RealSize2D
SpriteDeviceHelper::getPhysicalResolution()
156 if( !maContext
.isInitialized() )
157 return ::canvas::tools::createInfiniteSize2D(); // we're disposed
159 // Map a one-by-one millimeter box to pixel
160 SystemChildWindow
* pChildWindow
= maContext
.getChildWindow();
161 const MapMode
aOldMapMode( pChildWindow
->GetMapMode() );
162 pChildWindow
->SetMapMode( MapMode(MAP_MM
) );
163 const Size
aPixelSize( pChildWindow
->LogicToPixel(Size(1,1)) );
164 pChildWindow
->SetMapMode( aOldMapMode
);
166 return vcl::unotools::size2DFromSize( aPixelSize
);
169 geometry::RealSize2D
SpriteDeviceHelper::getPhysicalSize()
171 if( !maContext
.isInitialized() )
172 return ::canvas::tools::createInfiniteSize2D(); // we're disposed
174 // Map the pixel dimensions of the output window to millimeter
175 SystemChildWindow
* pChildWindow
= maContext
.getChildWindow();
176 const MapMode
aOldMapMode( pChildWindow
->GetMapMode() );
177 pChildWindow
->SetMapMode( MapMode(MAP_MM
) );
178 const Size
aLogSize( pChildWindow
->PixelToLogic(pChildWindow
->GetOutputSizePixel()) );
179 pChildWindow
->SetMapMode( aOldMapMode
);
181 return vcl::unotools::size2DFromSize( aLogSize
);
184 uno::Reference
< rendering::XLinePolyPolygon2D
> SpriteDeviceHelper::createCompatibleLinePolyPolygon(
185 const uno::Reference
< rendering::XGraphicDevice
>& /*rDevice*/,
186 const uno::Sequence
< uno::Sequence
< geometry::RealPoint2D
> >& points
)
189 if( !mpSpriteCanvas
)
190 return uno::Reference
< rendering::XLinePolyPolygon2D
>(); // we're disposed
192 return uno::Reference
< rendering::XLinePolyPolygon2D
>(
193 new ::basegfx::unotools::UnoPolyPolygon(
194 ::basegfx::unotools::polyPolygonFromPoint2DSequenceSequence( points
)));
197 uno::Reference
< rendering::XBezierPolyPolygon2D
> SpriteDeviceHelper::createCompatibleBezierPolyPolygon(
198 const uno::Reference
< rendering::XGraphicDevice
>& /*rDevice*/,
199 const uno::Sequence
< uno::Sequence
< geometry::RealBezierSegment2D
> >& points
)
202 if( !mpSpriteCanvas
)
203 return uno::Reference
< rendering::XBezierPolyPolygon2D
>(); // we're disposed
205 return uno::Reference
< rendering::XBezierPolyPolygon2D
>(
206 new ::basegfx::unotools::UnoPolyPolygon(
207 ::basegfx::unotools::polyPolygonFromBezier2DSequenceSequence( points
) ) );
210 uno::Reference
< rendering::XBitmap
> SpriteDeviceHelper::createCompatibleBitmap(
211 const uno::Reference
< rendering::XGraphicDevice
>& /*rDevice*/,
212 const geometry::IntegerSize2D
& size
)
215 if( !mpSpriteCanvas
)
216 return uno::Reference
< rendering::XBitmap
>(); // we're disposed
218 return uno::Reference
< rendering::XBitmap
>(
219 new CanvasBitmap( size
,
225 uno::Reference
< rendering::XVolatileBitmap
> SpriteDeviceHelper::createVolatileBitmap(
226 const uno::Reference
< rendering::XGraphicDevice
>& /*rDevice*/,
227 const geometry::IntegerSize2D
& /*size*/ )
229 return uno::Reference
< rendering::XVolatileBitmap
>();
232 uno::Reference
< rendering::XBitmap
> SpriteDeviceHelper::createCompatibleAlphaBitmap(
233 const uno::Reference
< rendering::XGraphicDevice
>& /*rDevice*/,
234 const geometry::IntegerSize2D
& size
)
237 if( !mpSpriteCanvas
)
238 return uno::Reference
< rendering::XBitmap
>(); // we're disposed
240 return uno::Reference
< rendering::XBitmap
>(
241 new CanvasBitmap( size
,
247 uno::Reference
< rendering::XVolatileBitmap
> SpriteDeviceHelper::createVolatileAlphaBitmap(
248 const uno::Reference
< rendering::XGraphicDevice
>& /*rDevice*/,
249 const geometry::IntegerSize2D
& /*size*/ )
251 return uno::Reference
< rendering::XVolatileBitmap
>();
256 /** Functor providing a StrictWeakOrdering for XSprites (over
259 struct SpriteComparator
261 bool operator()( const ::rtl::Reference
<CanvasCustomSprite
>& rLHS
,
262 const ::rtl::Reference
<CanvasCustomSprite
>& rRHS
) const
264 const double nPrioL( rLHS
->getPriority() );
265 const double nPrioR( rRHS
->getPriority() );
267 // if prios are equal, tie-break on ptr value
268 return nPrioL
== nPrioR
? rLHS
.get() < rRHS
.get() : nPrioL
< nPrioR
;
273 bool SpriteDeviceHelper::showBuffer( bool bIsVisible
, bool /*bUpdateAll*/ )
275 // hidden or disposed?
276 if( !bIsVisible
|| !maContext
.isInitialized() || !mpSpriteCanvas
)
279 if( !activateWindowContext() )
282 SystemChildWindow
* pChildWindow
= maContext
.getChildWindow();
283 const ::Size
& rOutputSize
= pChildWindow
->GetSizePixel();
284 initTransformation(rOutputSize
);
286 // render the actual spritecanvas content
287 mpSpriteCanvas
->renderRecordedActions();
289 // render all sprites (in order of priority) on top of that
290 std::vector
< ::rtl::Reference
<CanvasCustomSprite
> > aSprites
;
291 std::copy(maActiveSprites
.begin(),
292 maActiveSprites
.end(),
293 std::back_insert_iterator
<
294 std::vector
< ::rtl::Reference
< CanvasCustomSprite
> > >(aSprites
));
295 std::sort(aSprites
.begin(),
298 std::for_each(aSprites
.begin(),
300 boost::mem_fn(&CanvasCustomSprite::renderSprite
));
303 // frame counter, other info
304 glMatrixMode(GL_MODELVIEW
);
306 glTranslated(-1.0, 1.0, 0.0);
307 glScaled( 2.0 / rOutputSize
.Width(),
308 -2.0 / rOutputSize
.Height(),
311 const double denominator( maLastUpdate
.getElapsedTime() );
312 maLastUpdate
.reset();
314 const double fps(denominator
== 0.0 ? 100.0 : 1.0/denominator
);
315 std::vector
<double> aVec
; aVec
.push_back(fps
);
316 aVec
.push_back(maActiveSprites
.size());
317 aVec
.push_back(mpTextureCache
->getCacheSize());
318 aVec
.push_back(mpTextureCache
->getCacheMissCount());
319 aVec
.push_back(mpTextureCache
->getCacheHitCount());
320 renderOSD( aVec
, 20 );
323 * TODO: moggi: fix it!
324 // switch buffer, sync etc.
325 const unx::Window aXWindow=pChildWindow->GetSystemData()->aWindow;
326 unx::glXSwapBuffers(reinterpret_cast<unx::Display*>(mpDisplay),
328 pChildWindow->Show();
330 XSync( reinterpret_cast<unx::Display*>(mpDisplay), false );
332 maContext
.swapBuffers();
334 // flush texture cache, such that it does not build up
336 // TODO: have max cache size/LRU time in config, prune only on
338 mpTextureCache
->prune();
343 bool SpriteDeviceHelper::switchBuffer( bool bIsVisible
, bool bUpdateAll
)
345 // no difference for VCL canvas
346 return showBuffer( bIsVisible
, bUpdateAll
);
349 uno::Any
SpriteDeviceHelper::isAccelerated() const
351 return ::com::sun::star::uno::makeAny(false);
354 uno::Any
SpriteDeviceHelper::getDeviceHandle() const
356 const SystemChildWindow
* pChildWindow
= maContext
.getChildWindow();
357 return uno::makeAny( reinterpret_cast< sal_Int64
>(pChildWindow
) );
360 uno::Any
SpriteDeviceHelper::getSurfaceHandle() const
365 uno::Reference
<rendering::XColorSpace
> SpriteDeviceHelper::getColorSpace() const
368 return uno::Reference
<rendering::XColorSpace
>(
369 ::canvas::tools::getStdColorSpace(),
373 void SpriteDeviceHelper::notifySizeUpdate( const awt::Rectangle
& rBounds
)
375 if( maContext
.isInitialized() )
377 SystemChildWindow
* pChildWindow
= maContext
.getChildWindow();
378 pChildWindow
->setPosSizePixel(
379 0,0,rBounds
.Width
,rBounds
.Height
);
383 void SpriteDeviceHelper::dumpScreenContent() const
385 SAL_INFO("canvas.ogl", BOOST_CURRENT_FUNCTION
);
388 void SpriteDeviceHelper::show( const ::rtl::Reference
< CanvasCustomSprite
>& xSprite
)
390 maActiveSprites
.insert(xSprite
);
393 void SpriteDeviceHelper::hide( const ::rtl::Reference
< CanvasCustomSprite
>& xSprite
)
395 maActiveSprites
.erase(xSprite
);
398 static void setupUniforms( unsigned int nProgramId
,
399 const ::basegfx::B2DHomMatrix
& rTexTransform
)
401 const GLint nTransformLocation
= glGetUniformLocation(nProgramId
,
403 // OGL is column-major
404 float aTexTransform
[] =
406 float(rTexTransform
.get(0,0)), float(rTexTransform
.get(1,0)),
407 float(rTexTransform
.get(0,1)), float(rTexTransform
.get(1,1)),
408 float(rTexTransform
.get(0,2)), float(rTexTransform
.get(1,2))
410 glUniformMatrix3x2fv(nTransformLocation
,1,false,aTexTransform
);
413 static void setupUniforms( unsigned int nProgramId
,
414 const rendering::ARGBColor
* pColors
,
415 const uno::Sequence
< double >& rStops
,
416 const ::basegfx::B2DHomMatrix
& rTexTransform
)
418 glUseProgram(nProgramId
);
420 GLuint nColorsTexture
;
421 glActiveTexture(GL_TEXTURE0
);
422 glGenTextures(1, &nColorsTexture
);
423 glBindTexture(GL_TEXTURE_1D
, nColorsTexture
);
425 const sal_Int32 nColors
=rStops
.getLength();
426 glTexImage1D( GL_TEXTURE_1D
, 0, GL_RGBA
, nColors
, 0, GL_RGBA
, GL_DOUBLE
, pColors
);
427 glTexParameteri( GL_TEXTURE_1D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
428 glTexParameteri( GL_TEXTURE_1D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
430 GLuint nStopsTexture
;
431 glActiveTexture(GL_TEXTURE1
);
432 glGenTextures(1, &nStopsTexture
);
433 glBindTexture(GL_TEXTURE_1D
, nStopsTexture
);
435 glTexImage1D( GL_TEXTURE_1D
, 0, GL_ALPHA
, nColors
, 0, GL_ALPHA
, GL_DOUBLE
, rStops
.getConstArray() );
436 glTexParameteri( GL_TEXTURE_1D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
437 glTexParameteri( GL_TEXTURE_1D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
439 const GLint nColorArrayLocation
= glGetUniformLocation(nProgramId
,
441 glUniform1i( nColorArrayLocation
, 0 ); // unit 0
443 const GLint nStopArrayLocation
= glGetUniformLocation(nProgramId
,
445 glUniform1i( nStopArrayLocation
, 1 ); // unit 1
447 const GLint nNumColorLocation
= glGetUniformLocation(nProgramId
,
449 glUniform1i( nNumColorLocation
, nColors
-1 );
451 setupUniforms(nProgramId
,rTexTransform
);
454 static void setupUniforms( unsigned int nProgramId
,
455 const rendering::ARGBColor
& rStartColor
,
456 const rendering::ARGBColor
& rEndColor
,
457 const ::basegfx::B2DHomMatrix
& rTexTransform
)
459 glUseProgram(nProgramId
);
461 const GLint nStartColorLocation
= glGetUniformLocation(nProgramId
,
463 glUniform4f(nStartColorLocation
,
469 const GLint nEndColorLocation
= glGetUniformLocation(nProgramId
,
471 glUniform4f(nEndColorLocation
,
477 setupUniforms(nProgramId
,rTexTransform
);
480 void SpriteDeviceHelper::useLinearGradientShader( const rendering::ARGBColor
* pColors
,
481 const uno::Sequence
< double >& rStops
,
482 const ::basegfx::B2DHomMatrix
& rTexTransform
)
484 if( rStops
.getLength() > 2 )
485 setupUniforms(mnLinearMultiColorGradientProgram
, pColors
, rStops
, rTexTransform
);
487 setupUniforms(mnLinearTwoColorGradientProgram
, pColors
[0], pColors
[1], rTexTransform
);
490 void SpriteDeviceHelper::useRadialGradientShader( const rendering::ARGBColor
* pColors
,
491 const uno::Sequence
< double >& rStops
,
492 const ::basegfx::B2DHomMatrix
& rTexTransform
)
494 if( rStops
.getLength() > 2 )
495 setupUniforms(mnRadialMultiColorGradientProgram
, pColors
, rStops
, rTexTransform
);
497 setupUniforms(mnRadialTwoColorGradientProgram
, pColors
[0], pColors
[1], rTexTransform
);
500 void SpriteDeviceHelper::useRectangularGradientShader( const rendering::ARGBColor
* pColors
,
501 const uno::Sequence
< double >& rStops
,
502 const ::basegfx::B2DHomMatrix
& rTexTransform
)
504 if( rStops
.getLength() > 2 )
505 setupUniforms(mnRectangularMultiColorGradientProgram
, pColors
, rStops
, rTexTransform
);
507 setupUniforms(mnRectangularTwoColorGradientProgram
, pColors
[0], pColors
[1], rTexTransform
);
510 bool SpriteDeviceHelper::activateWindowContext()
512 maContext
.makeCurrent();
519 class BufferContextImpl
: public IBufferContext
521 ::basegfx::B2IVector maSize
;
522 GLuint mnFrambufferId
;
526 virtual bool startBufferRendering() SAL_OVERRIDE
528 glBindFramebuffer(GL_FRAMEBUFFER
, mnFrambufferId
);
532 virtual bool endBufferRendering() SAL_OVERRIDE
534 glBindFramebuffer(GL_FRAMEBUFFER
, 0);
538 virtual GLuint
getTextureId() SAL_OVERRIDE
544 BufferContextImpl(const ::basegfx::B2IVector
& rSize
) :
550 OpenGLHelper::createFramebuffer(maSize
.getX(), maSize
.getY(), mnFrambufferId
,
551 mnDepthId
, mnTextureId
, false);
554 virtual ~BufferContextImpl()
556 glDeleteTextures(1, &mnTextureId
);
557 glDeleteRenderbuffers(1, &mnDepthId
);
558 glDeleteFramebuffers(1, &mnFrambufferId
);
563 IBufferContextSharedPtr
SpriteDeviceHelper::createBufferContext(const ::basegfx::B2IVector
& rSize
) const
565 return IBufferContextSharedPtr(new BufferContextImpl(rSize
));
568 TextureCache
& SpriteDeviceHelper::getTextureCache() const
570 return *mpTextureCache
;
574 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */