lok: Don't attempt to select the exact text after a failed search.
[LibreOffice.git] / canvas / source / opengl / ogl_spritedevicehelper.cxx
blob37122d8740ca2b8c0f288fd3e3eebb099e77d2fa
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
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);
44 glLoadIdentity();
46 // misc preferences
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)
58 // use whole window
59 glViewport( 0,0,
60 (GLsizei)rSize.Width(),
61 (GLsizei)rSize.Height() );
63 // model coordinate system is already in device pixel
64 glMatrixMode(GL_MODELVIEW);
65 glLoadIdentity();
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(),
69 1.0 );
71 // clear to black
72 glClearColor(0,0,0,0);
73 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
76 namespace oglcanvas
79 SpriteDeviceHelper::SpriteDeviceHelper() :
80 mpDevice(NULL),
81 mpSpriteCanvas(NULL),
82 maActiveSprites(),
83 maLastUpdate(),
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
110 initContext();
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;
140 mpDevice = 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 )
188 // disposed?
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 )
201 // disposed?
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 )
214 // disposed?
215 if( !mpSpriteCanvas )
216 return uno::Reference< rendering::XBitmap >(); // we're disposed
218 return uno::Reference< rendering::XBitmap >(
219 new CanvasBitmap( size,
220 mpSpriteCanvas,
221 *this,
222 false ) );
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 )
236 // disposed?
237 if( !mpSpriteCanvas )
238 return uno::Reference< rendering::XBitmap >(); // we're disposed
240 return uno::Reference< rendering::XBitmap >(
241 new CanvasBitmap( size,
242 mpSpriteCanvas,
243 *this,
244 true ) );
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 >();
254 namespace
256 /** Functor providing a StrictWeakOrdering for XSprites (over
257 priority)
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 )
277 return false;
279 if( !activateWindowContext() )
280 return false;
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(),
296 aSprites.end(),
297 SpriteComparator());
298 std::for_each(aSprites.begin(),
299 aSprites.end(),
300 boost::mem_fn(&CanvasCustomSprite::renderSprite));
303 // frame counter, other info
304 glMatrixMode(GL_MODELVIEW);
305 glLoadIdentity();
306 glTranslated(-1.0, 1.0, 0.0);
307 glScaled( 2.0 / rOutputSize.Width(),
308 -2.0 / rOutputSize.Height(),
309 1.0 );
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),
327 aXWindow);
328 pChildWindow->Show();
329 unx::glXWaitGL();
330 XSync( reinterpret_cast<unx::Display*>(mpDisplay), false );
332 maContext.swapBuffers();
334 // flush texture cache, such that it does not build up
335 // indefinitely.
336 // TODO: have max cache size/LRU time in config, prune only on
337 // demand
338 mpTextureCache->prune();
340 return true;
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
362 return uno::Any();
365 uno::Reference<rendering::XColorSpace> SpriteDeviceHelper::getColorSpace() const
367 // always the same
368 return uno::Reference<rendering::XColorSpace>(
369 ::canvas::tools::getStdColorSpace(),
370 uno::UNO_QUERY);
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,
402 "m_transform" );
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,
440 "t_colorArray4d" );
441 glUniform1i( nColorArrayLocation, 0 ); // unit 0
443 const GLint nStopArrayLocation = glGetUniformLocation(nProgramId,
444 "t_stopArray1d" );
445 glUniform1i( nStopArrayLocation, 1 ); // unit 1
447 const GLint nNumColorLocation = glGetUniformLocation(nProgramId,
448 "i_nColors" );
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,
462 "v_startColor4d" );
463 glUniform4f(nStartColorLocation,
464 rStartColor.Red,
465 rStartColor.Green,
466 rStartColor.Blue,
467 rStartColor.Alpha);
469 const GLint nEndColorLocation = glGetUniformLocation(nProgramId,
470 "v_endColor4d" );
471 glUniform4f(nEndColorLocation,
472 rEndColor.Red,
473 rEndColor.Green,
474 rEndColor.Blue,
475 rEndColor.Alpha);
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);
486 else
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);
496 else
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);
506 else
507 setupUniforms(mnRectangularTwoColorGradientProgram, pColors[0], pColors[1], rTexTransform);
510 bool SpriteDeviceHelper::activateWindowContext()
512 maContext.makeCurrent();
513 return true;
516 namespace
519 class BufferContextImpl : public IBufferContext
521 ::basegfx::B2IVector maSize;
522 GLuint mnFrambufferId;
523 GLuint mnDepthId;
524 GLuint mnTextureId;
526 virtual bool startBufferRendering() SAL_OVERRIDE
528 glBindFramebuffer(GL_FRAMEBUFFER, mnFrambufferId);
529 return true;
532 virtual bool endBufferRendering() SAL_OVERRIDE
534 glBindFramebuffer(GL_FRAMEBUFFER, 0);
535 return true;
538 virtual GLuint getTextureId() SAL_OVERRIDE
540 return mnTextureId;
543 public:
544 BufferContextImpl(const ::basegfx::B2IVector& rSize) :
545 maSize(rSize),
546 mnFrambufferId(0),
547 mnDepthId(0),
548 mnTextureId(0)
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: */