tdf#154285 Check upper bound of arguments in SbRtl_Minute function
[LibreOffice.git] / canvas / source / opengl / ogl_spritedevicehelper.cxx
blob571764986fca115b4b64ff03cc112b96f059fc96
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 <sal/config.h>
11 #include <sal/log.hxx>
13 #include <basegfx/matrix/b2dhommatrix.hxx>
14 #include <basegfx/utils/canvastools.hxx>
15 #include <basegfx/utils/unopolypolygon.hxx>
16 #include <com/sun/star/awt/XTopWindow.hpp>
17 #include <com/sun/star/rendering/XIntegerBitmapColorSpace.hpp>
18 #include <com/sun/star/uno/Reference.hxx>
19 #include <toolkit/helper/vclunohelper.hxx>
20 #include <vcl/canvastools.hxx>
21 #include <vcl/opengl/OpenGLHelper.hxx>
22 #include <vcl/syschild.hxx>
24 #include "ogl_spritedevicehelper.hxx"
25 #include "ogl_spritecanvas.hxx"
26 #include "ogl_canvasbitmap.hxx"
27 #include "ogl_canvastools.hxx"
28 #include "ogl_canvascustomsprite.hxx"
29 #include "ogl_texturecache.hxx"
31 using namespace ::com::sun::star;
33 static void initContext()
35 // need the backside for mirror effects
36 glDisable(GL_CULL_FACE);
38 // no perspective, we're 2D
39 glMatrixMode(GL_PROJECTION);
40 glLoadIdentity();
42 // misc preferences
43 glEnable(GL_POINT_SMOOTH);
44 glEnable(GL_LINE_SMOOTH);
45 glEnable(GL_POLYGON_SMOOTH);
46 glHint(GL_POINT_SMOOTH_HINT,GL_NICEST);
47 glHint(GL_LINE_SMOOTH_HINT,GL_NICEST);
48 glHint(GL_POLYGON_SMOOTH_HINT,GL_NICEST);
49 glShadeModel(GL_FLAT);
52 static void initTransformation(const ::Size& rSize)
54 // use whole window
55 glViewport( 0,0,
56 static_cast<GLsizei>(rSize.Width()),
57 static_cast<GLsizei>(rSize.Height()) );
59 // model coordinate system is already in device pixel
60 glMatrixMode(GL_MODELVIEW);
61 glLoadIdentity();
62 glTranslated(-1.0, 1.0, 0.0);
63 glScaled( 2.0 / rSize.Width(),
64 -2.0 / rSize.Height(),
65 1.0 );
67 // clear to black
68 glClearColor(0,0,0,0);
69 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
72 namespace oglcanvas
75 SpriteDeviceHelper::SpriteDeviceHelper() :
76 mpSpriteCanvas(nullptr),
77 mpTextureCache(std::make_shared<TextureCache>()),
78 mnLinearTwoColorGradientProgram(0),
79 mnLinearMultiColorGradientProgram(0),
80 mnRadialTwoColorGradientProgram(0),
81 mnRadialMultiColorGradientProgram(0),
82 mnRectangularTwoColorGradientProgram(0),
83 mnRectangularMultiColorGradientProgram(0),
84 mxContext(OpenGLContext::Create())
87 SpriteDeviceHelper::~SpriteDeviceHelper()
88 { mxContext->dispose(); }
90 void SpriteDeviceHelper::init( vcl::Window& rWindow,
91 SpriteCanvas& rSpriteCanvas,
92 const awt::Rectangle& rViewArea )
94 mpSpriteCanvas = &rSpriteCanvas;
96 rSpriteCanvas.setWindow(
97 uno::Reference<awt::XWindow2>(
98 VCLUnoHelper::GetInterface(&rWindow),
99 uno::UNO_QUERY_THROW) );
101 mxContext->requestLegacyContext();
102 mxContext->init(&rWindow);
103 // init window context
104 initContext();
106 mnLinearMultiColorGradientProgram =
107 OpenGLHelper::LoadShaders(u"dummyVertexShader"_ustr, u"linearMultiColorGradientFragmentShader"_ustr);
109 mnLinearTwoColorGradientProgram =
110 OpenGLHelper::LoadShaders(u"dummyVertexShader"_ustr, u"linearTwoColorGradientFragmentShader"_ustr);
112 mnRadialMultiColorGradientProgram =
113 OpenGLHelper::LoadShaders(u"dummyVertexShader"_ustr, u"radialMultiColorGradientFragmentShader"_ustr);
115 mnRadialTwoColorGradientProgram =
116 OpenGLHelper::LoadShaders(u"dummyVertexShader"_ustr, u"radialTwoColorGradientFragmentShader"_ustr);
118 mnRectangularMultiColorGradientProgram =
119 OpenGLHelper::LoadShaders(u"dummyVertexShader"_ustr, u"rectangularMultiColorGradientFragmentShader"_ustr);
121 mnRectangularTwoColorGradientProgram =
122 OpenGLHelper::LoadShaders(u"dummyVertexShader"_ustr, u"rectangularTwoColorGradientFragmentShader"_ustr);
124 mxContext->makeCurrent();
126 notifySizeUpdate(rViewArea);
127 // TODO(E3): check for GL_ARB_imaging extension
130 void SpriteDeviceHelper::disposing()
132 // release all references
133 mpSpriteCanvas = nullptr;
134 mpTextureCache.reset();
136 if( mxContext->isInitialized() )
138 glDeleteProgram( mnRectangularTwoColorGradientProgram );
139 glDeleteProgram( mnRectangularMultiColorGradientProgram );
140 glDeleteProgram( mnRadialTwoColorGradientProgram );
141 glDeleteProgram( mnRadialMultiColorGradientProgram );
142 glDeleteProgram( mnLinearTwoColorGradientProgram );
143 glDeleteProgram( mnLinearMultiColorGradientProgram );
147 geometry::RealSize2D SpriteDeviceHelper::getPhysicalResolution()
149 if( !mxContext->isInitialized() )
150 return ::canvas::tools::createInfiniteSize2D(); // we're disposed
152 // Map a one-by-one millimeter box to pixel
153 SystemChildWindow* pChildWindow = mxContext->getChildWindow();
154 const MapMode aOldMapMode( pChildWindow->GetMapMode() );
155 pChildWindow->SetMapMode( MapMode(MapUnit::MapMM) );
156 const Size aPixelSize( pChildWindow->LogicToPixel(Size(1,1)) );
157 pChildWindow->SetMapMode( aOldMapMode );
159 return vcl::unotools::size2DFromSize( aPixelSize );
162 geometry::RealSize2D SpriteDeviceHelper::getPhysicalSize()
164 if( !mxContext->isInitialized() )
165 return ::canvas::tools::createInfiniteSize2D(); // we're disposed
167 // Map the pixel dimensions of the output window to millimeter
168 SystemChildWindow* pChildWindow = mxContext->getChildWindow();
169 const MapMode aOldMapMode( pChildWindow->GetMapMode() );
170 pChildWindow->SetMapMode( MapMode(MapUnit::MapMM) );
171 const Size aLogSize( pChildWindow->PixelToLogic(pChildWindow->GetOutputSizePixel()) );
172 pChildWindow->SetMapMode( aOldMapMode );
174 return vcl::unotools::size2DFromSize( aLogSize );
177 uno::Reference< rendering::XLinePolyPolygon2D > SpriteDeviceHelper::createCompatibleLinePolyPolygon(
178 const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/,
179 const uno::Sequence< uno::Sequence< geometry::RealPoint2D > >& points )
181 // disposed?
182 if( !mpSpriteCanvas )
183 return uno::Reference< rendering::XLinePolyPolygon2D >(); // we're disposed
185 return uno::Reference< rendering::XLinePolyPolygon2D >(
186 new ::basegfx::unotools::UnoPolyPolygon(
187 ::basegfx::unotools::polyPolygonFromPoint2DSequenceSequence( points )));
190 uno::Reference< rendering::XBezierPolyPolygon2D > SpriteDeviceHelper::createCompatibleBezierPolyPolygon(
191 const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/,
192 const uno::Sequence< uno::Sequence< geometry::RealBezierSegment2D > >& points )
194 // disposed?
195 if( !mpSpriteCanvas )
196 return uno::Reference< rendering::XBezierPolyPolygon2D >(); // we're disposed
198 return uno::Reference< rendering::XBezierPolyPolygon2D >(
199 new ::basegfx::unotools::UnoPolyPolygon(
200 ::basegfx::unotools::polyPolygonFromBezier2DSequenceSequence( points ) ) );
203 uno::Reference< rendering::XBitmap > SpriteDeviceHelper::createCompatibleBitmap(
204 const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/,
205 const geometry::IntegerSize2D& size )
207 // disposed?
208 if( !mpSpriteCanvas )
209 return uno::Reference< rendering::XBitmap >(); // we're disposed
211 return uno::Reference< rendering::XBitmap >(
212 new CanvasBitmap( size,
213 mpSpriteCanvas,
214 *this ) );
217 uno::Reference< rendering::XVolatileBitmap > SpriteDeviceHelper::createVolatileBitmap(
218 const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/,
219 const geometry::IntegerSize2D& /*size*/ )
221 return uno::Reference< rendering::XVolatileBitmap >();
224 uno::Reference< rendering::XBitmap > SpriteDeviceHelper::createCompatibleAlphaBitmap(
225 const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/,
226 const geometry::IntegerSize2D& size )
228 // disposed?
229 if( !mpSpriteCanvas )
230 return uno::Reference< rendering::XBitmap >(); // we're disposed
232 return uno::Reference< rendering::XBitmap >(
233 new CanvasBitmap( size,
234 mpSpriteCanvas,
235 *this ) );
238 uno::Reference< rendering::XVolatileBitmap > SpriteDeviceHelper::createVolatileAlphaBitmap(
239 const uno::Reference< rendering::XGraphicDevice >& /*rDevice*/,
240 const geometry::IntegerSize2D& /*size*/ )
242 return uno::Reference< rendering::XVolatileBitmap >();
245 namespace
247 /** Functor providing a StrictWeakOrdering for XSprites (over
248 priority)
250 struct SpriteComparator
252 bool operator()( const ::rtl::Reference<CanvasCustomSprite>& rLHS,
253 const ::rtl::Reference<CanvasCustomSprite>& rRHS ) const
255 const double nPrioL( rLHS->getPriority() );
256 const double nPrioR( rRHS->getPriority() );
258 // if prios are equal, tie-break on ptr value
259 return nPrioL == nPrioR ? rLHS.get() < rRHS.get() : nPrioL < nPrioR;
264 bool SpriteDeviceHelper::showBuffer( bool bIsVisible, SAL_UNUSED_PARAMETER bool /*bUpdateAll*/ )
266 // hidden or disposed?
267 if( !bIsVisible || !mxContext->isInitialized() || !mpSpriteCanvas )
268 return false;
270 mxContext->makeCurrent();
272 SystemChildWindow* pChildWindow = mxContext->getChildWindow();
273 const ::Size aOutputSize = pChildWindow->GetSizePixel();
274 initTransformation(aOutputSize);
276 // render the actual spritecanvas content
277 mpSpriteCanvas->renderRecordedActions();
279 // render all sprites (in order of priority) on top of that
280 std::vector< ::rtl::Reference<CanvasCustomSprite> > aSprites(
281 maActiveSprites.begin(),
282 maActiveSprites.end());
283 std::sort(aSprites.begin(),
284 aSprites.end(),
285 SpriteComparator());
286 for( const auto& rSprite : aSprites )
287 rSprite->renderSprite();
290 // frame counter, other info
291 glMatrixMode(GL_MODELVIEW);
292 glLoadIdentity();
293 glTranslated(-1.0, 1.0, 0.0);
294 glScaled( 2.0 / aOutputSize.Width(),
295 -2.0 / aOutputSize.Height(),
296 1.0 );
298 const double denominator( maLastUpdate.getElapsedTime() );
299 maLastUpdate.reset();
301 const double fps(denominator == 0.0 ? 100.0 : 1.0/denominator);
302 std::vector<double> aVec { fps, static_cast<double>(maActiveSprites.size()),
303 static_cast<double>(mpTextureCache->getCacheSize()),
304 static_cast<double>(mpTextureCache->getCacheMissCount()),
305 static_cast<double>(mpTextureCache->getCacheHitCount()) };
306 renderOSD( aVec, 20 );
309 * TODO: moggi: fix it!
310 // switch buffer, sync etc.
311 const unx::Window aXWindow=pChildWindow->GetSystemData()->aWindow;
312 unx::glXSwapBuffers(reinterpret_cast<unx::Display*>(mpDisplay),
313 aXWindow);
314 pChildWindow->Show();
315 unx::glXWaitGL();
316 XSync( reinterpret_cast<unx::Display*>(mpDisplay), false );
318 mxContext->swapBuffers();
320 // flush texture cache, such that it does not build up
321 // indefinitely.
322 // TODO: have max cache size/LRU time in config, prune only on
323 // demand
324 mpTextureCache->prune();
326 return true;
329 bool SpriteDeviceHelper::switchBuffer( bool bIsVisible, bool bUpdateAll )
331 // no difference for VCL canvas
332 return showBuffer( bIsVisible, bUpdateAll );
335 uno::Any SpriteDeviceHelper::isAccelerated() const
337 return css::uno::Any(false);
340 uno::Any SpriteDeviceHelper::getDeviceHandle() const
342 const SystemChildWindow* pChildWindow = mxContext->getChildWindow();
343 const OutputDevice* pDevice = pChildWindow ? pChildWindow->GetOutDev() : nullptr;
344 return uno::Any(reinterpret_cast<sal_Int64>(pDevice));
347 uno::Any SpriteDeviceHelper::getSurfaceHandle() const
349 return uno::Any();
352 uno::Reference<rendering::XColorSpace> SpriteDeviceHelper::getColorSpace() const
354 // always the same
355 return ::canvas::tools::getStdColorSpace();
358 void SpriteDeviceHelper::notifySizeUpdate( const awt::Rectangle& rBounds )
360 if( mxContext->isInitialized() )
362 SystemChildWindow* pChildWindow = mxContext->getChildWindow();
363 pChildWindow->setPosSizePixel(
364 0,0,rBounds.Width,rBounds.Height);
368 void SpriteDeviceHelper::dumpScreenContent() const
370 SAL_INFO("canvas.ogl", __func__ );
373 void SpriteDeviceHelper::show( const ::rtl::Reference< CanvasCustomSprite >& xSprite )
375 maActiveSprites.insert(xSprite);
378 void SpriteDeviceHelper::hide( const ::rtl::Reference< CanvasCustomSprite >& xSprite )
380 maActiveSprites.erase(xSprite);
383 static void setupUniforms( unsigned int nProgramId,
384 const ::basegfx::B2DHomMatrix& rTexTransform )
386 const GLint nTransformLocation = glGetUniformLocation(nProgramId,
387 "m_transform" );
388 // OGL is column-major
389 float aTexTransform[] =
391 float(rTexTransform.get(0,0)), float(rTexTransform.get(1,0)),
392 float(rTexTransform.get(0,1)), float(rTexTransform.get(1,1)),
393 float(rTexTransform.get(0,2)), float(rTexTransform.get(1,2))
395 glUniformMatrix3x2fv(nTransformLocation,1,false,aTexTransform);
398 static void setupUniforms( unsigned int nProgramId,
399 const rendering::ARGBColor* pColors,
400 const uno::Sequence< double >& rStops,
401 const ::basegfx::B2DHomMatrix& rTexTransform )
403 glUseProgram(nProgramId);
405 GLuint nColorsTexture;
406 glActiveTexture(GL_TEXTURE0);
407 glGenTextures(1, &nColorsTexture);
408 glBindTexture(GL_TEXTURE_1D, nColorsTexture);
410 const sal_Int32 nColors=rStops.getLength();
411 glTexImage1D( GL_TEXTURE_1D, 0, GL_RGBA, nColors, 0, GL_RGBA, GL_DOUBLE, pColors );
412 glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
413 glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
415 GLuint nStopsTexture;
416 glActiveTexture(GL_TEXTURE1);
417 glGenTextures(1, &nStopsTexture);
418 glBindTexture(GL_TEXTURE_1D, nStopsTexture);
420 glTexImage1D( GL_TEXTURE_1D, 0, GL_ALPHA, nColors, 0, GL_ALPHA, GL_DOUBLE, rStops.getConstArray() );
421 glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
422 glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
424 const GLint nColorArrayLocation = glGetUniformLocation(nProgramId,
425 "t_colorArray4d" );
426 glUniform1i( nColorArrayLocation, 0 ); // unit 0
428 const GLint nStopArrayLocation = glGetUniformLocation(nProgramId,
429 "t_stopArray1d" );
430 glUniform1i( nStopArrayLocation, 1 ); // unit 1
432 const GLint nNumColorLocation = glGetUniformLocation(nProgramId,
433 "i_nColors" );
434 glUniform1i( nNumColorLocation, nColors-1 );
436 setupUniforms(nProgramId,rTexTransform);
439 static void setupUniforms( unsigned int nProgramId,
440 const rendering::ARGBColor& rStartColor,
441 const rendering::ARGBColor& rEndColor,
442 const ::basegfx::B2DHomMatrix& rTexTransform )
444 glUseProgram(nProgramId);
446 const GLint nStartColorLocation = glGetUniformLocation(nProgramId,
447 "v_startColor4d" );
448 glUniform4f(nStartColorLocation,
449 rStartColor.Red,
450 rStartColor.Green,
451 rStartColor.Blue,
452 rStartColor.Alpha);
454 const GLint nEndColorLocation = glGetUniformLocation(nProgramId,
455 "v_endColor4d" );
456 glUniform4f(nEndColorLocation,
457 rEndColor.Red,
458 rEndColor.Green,
459 rEndColor.Blue,
460 rEndColor.Alpha);
462 setupUniforms(nProgramId,rTexTransform);
465 void SpriteDeviceHelper::useLinearGradientShader( const rendering::ARGBColor* pColors,
466 const uno::Sequence< double >& rStops,
467 const ::basegfx::B2DHomMatrix& rTexTransform )
469 if( rStops.getLength() > 2 )
470 setupUniforms(mnLinearMultiColorGradientProgram, pColors, rStops, rTexTransform);
471 else
472 setupUniforms(mnLinearTwoColorGradientProgram, pColors[0], pColors[1], rTexTransform);
475 void SpriteDeviceHelper::useRadialGradientShader( const rendering::ARGBColor* pColors,
476 const uno::Sequence< double >& rStops,
477 const ::basegfx::B2DHomMatrix& rTexTransform )
479 if( rStops.getLength() > 2 )
480 setupUniforms(mnRadialMultiColorGradientProgram, pColors, rStops, rTexTransform);
481 else
482 setupUniforms(mnRadialTwoColorGradientProgram, pColors[0], pColors[1], rTexTransform);
485 void SpriteDeviceHelper::useRectangularGradientShader( const rendering::ARGBColor* pColors,
486 const uno::Sequence< double >& rStops,
487 const ::basegfx::B2DHomMatrix& rTexTransform )
489 if( rStops.getLength() > 2 )
490 setupUniforms(mnRectangularMultiColorGradientProgram, pColors, rStops, rTexTransform);
491 else
492 setupUniforms(mnRectangularTwoColorGradientProgram, pColors[0], pColors[1], rTexTransform);
495 namespace
498 class BufferContextImpl : public IBufferContext
500 GLuint mnFramebufferId;
501 GLuint mnDepthId;
502 GLuint mnTextureId;
504 virtual void startBufferRendering() override
506 glBindFramebuffer(GL_FRAMEBUFFER, mnFramebufferId);
509 virtual void endBufferRendering() override
511 glBindFramebuffer(GL_FRAMEBUFFER, 0);
514 virtual GLuint getTextureId() override
516 return mnTextureId;
519 public:
520 explicit BufferContextImpl(const ::basegfx::B2IVector& rSize) :
521 mnFramebufferId(0),
522 mnDepthId(0),
523 mnTextureId(0)
525 OpenGLHelper::createFramebuffer(rSize.getX(), rSize.getY(), mnFramebufferId,
526 mnDepthId, mnTextureId);
529 virtual ~BufferContextImpl() override
531 glDeleteTextures(1, &mnTextureId);
532 glDeleteRenderbuffers(1, &mnDepthId);
533 glDeleteFramebuffers(1, &mnFramebufferId);
538 IBufferContextSharedPtr SpriteDeviceHelper::createBufferContext(const ::basegfx::B2IVector& rSize) const
540 return std::make_shared<BufferContextImpl>(rSize);
543 TextureCache& SpriteDeviceHelper::getTextureCache() const
545 return *mpTextureCache;
549 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */