1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <sal/config.h>
21 #include <sal/log.hxx>
22 #include <tools/stream.hxx>
23 #include <vcl/opengl/OpenGLContext.hxx>
24 #include <vcl/opengl/OpenGLHelper.hxx>
25 
26 #include <svdata.hxx>
27 
28 #include <vcl/pngwrite.hxx>
29 
30 #include <opengl/framebuffer.hxx>
31 #include <opengl/texture.hxx>
32 #include <opengl/zone.hxx>
33 #include <opengl/RenderState.hxx>
34 
35 namespace
36 {
37 
38 constexpr GLenum constInternalFormat = GL_RGBA8;
39 
40 } // end anonymous namespace
41 
42 // texture with allocated size
ImplOpenGLTexture(int nWidth,int nHeight,bool bAllocate)43 ImplOpenGLTexture::ImplOpenGLTexture( int nWidth, int nHeight, bool bAllocate ) :
44     mnTexture( 0 ),
45     mnWidth( nWidth ),
46     mnHeight( nHeight ),
47     mnFilter( GL_NEAREST ),
48     mnOptStencil( 0 )
49 {
50     OpenGLVCLContextZone aContextZone;
51 
52     auto& rState = OpenGLContext::getVCLContext()->state();
53     TextureState::generate(mnTexture);
54     rState.texture().active(0);
55     rState.texture().bind(mnTexture);
56 
57     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
58     CHECK_GL_ERROR();
59     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
60     CHECK_GL_ERROR();
61     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
62     CHECK_GL_ERROR();
63     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
64     CHECK_GL_ERROR();
65     if( bAllocate )
66     {
67 #ifdef DBG_UTIL
68         std::vector< sal_uInt8 > buffer;
69         buffer.resize( nWidth * nHeight * 4 );
70         for( size_t i = 0; i < size_t( nWidth * nHeight ); ++i )
71         {   // pre-fill the texture with deterministic garbage
72             bool odd = (i & 0x01);
73             buffer[ i * 4 ] =  odd ? 0x40 : 0xBF;
74             buffer[ i * 4 + 1 ] = 0x80;
75             buffer[ i * 4 + 2 ] = odd ? 0xBF : 0x40;
76             buffer[ i * 4 + 3 ] = 0xFF;
77         }
78         glTexImage2D( GL_TEXTURE_2D, 0, constInternalFormat, nWidth, nHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
79 #else
80         glTexImage2D( GL_TEXTURE_2D, 0, constInternalFormat, nWidth, nHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr );
81 #endif
82         CHECK_GL_ERROR();
83     }
84 
85     VCL_GL_INFO( "OpenGLTexture " << mnTexture << " " << nWidth << "x" << nHeight << " allocate" );
86 }
87 
88 // texture with content retrieved from FBO
ImplOpenGLTexture(int nX,int nY,int nWidth,int nHeight)89 ImplOpenGLTexture::ImplOpenGLTexture( int nX, int nY, int nWidth, int nHeight ) :
90     mnTexture( 0 ),
91     mnWidth( nWidth ),
92     mnHeight( nHeight ),
93     mnFilter( GL_NEAREST ),
94     mnOptStencil( 0 )
95 {
96     OpenGLVCLContextZone aContextZone;
97 
98     // FIXME We need the window height here
99     // nY = GetHeight() - nHeight - nY;
100 
101     auto& rState = OpenGLContext::getVCLContext()->state();
102     TextureState::generate(mnTexture);
103     rState.texture().active(0);
104     rState.texture().bind(mnTexture);
105 
106     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
107     CHECK_GL_ERROR();
108     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
109     CHECK_GL_ERROR();
110     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
111     CHECK_GL_ERROR();
112     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
113     CHECK_GL_ERROR();
114     glCopyTexImage2D( GL_TEXTURE_2D, 0, constInternalFormat, nX, nY, nWidth, nHeight, 0 );
115     CHECK_GL_ERROR();
116 
117     VCL_GL_INFO( "OpenGLTexture " << mnTexture << " " << nWidth << "x" << nHeight << " from x" << nX << ", y" << nY );
118 }
119 
120 // texture from buffer data
ImplOpenGLTexture(int nWidth,int nHeight,int nFormat,int nType,void const * pData)121 ImplOpenGLTexture::ImplOpenGLTexture( int nWidth, int nHeight, int nFormat, int nType, void const * pData ) :
122     mnTexture( 0 ),
123     mnWidth( nWidth ),
124     mnHeight( nHeight ),
125     mnFilter( GL_NEAREST ),
126     mnOptStencil( 0 )
127 {
128     OpenGLVCLContextZone aContextZone;
129 
130     auto& rState = OpenGLContext::getVCLContext()->state();
131     TextureState::generate(mnTexture);
132     rState.texture().active(0);
133     rState.texture().bind(mnTexture);
134 
135     glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
136     CHECK_GL_ERROR();
137     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
138     CHECK_GL_ERROR();
139     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
140     CHECK_GL_ERROR();
141     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
142     CHECK_GL_ERROR();
143     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
144     CHECK_GL_ERROR();
145     glTexImage2D( GL_TEXTURE_2D, 0, constInternalFormat, mnWidth, mnHeight, 0, nFormat, nType, pData );
146     CHECK_GL_ERROR();
147 
148     VCL_GL_INFO( "OpenGLTexture " << mnTexture << " " << nWidth << "x" << nHeight << " from data" );
149 }
150 
AddStencil()151 GLuint ImplOpenGLTexture::AddStencil()
152 {
153     assert( mnOptStencil == 0 );
154 
155     glGenRenderbuffers( 1, &mnOptStencil );
156     CHECK_GL_ERROR();
157     glBindRenderbuffer( GL_RENDERBUFFER, mnOptStencil );
158     CHECK_GL_ERROR();
159     VCL_GL_INFO( "Allocate stencil " << mnWidth << " x " << mnHeight );
160     glRenderbufferStorage( GL_RENDERBUFFER, GL_STENCIL_INDEX,
161                            mnWidth, mnHeight );
162     CHECK_GL_ERROR();
163     glBindRenderbuffer(GL_RENDERBUFFER, 0);
164     CHECK_GL_ERROR();
165 
166     return mnOptStencil;
167 }
168 
~ImplOpenGLTexture()169 ImplOpenGLTexture::~ImplOpenGLTexture()
170 {
171     VCL_GL_INFO( "~OpenGLTexture " << mnTexture );
172     if( mnTexture != 0 )
173     {
174         // During shutdown GL is already de-initialized, so we should not try to create a new context.
175         OpenGLZone aZone;
176         rtl::Reference<OpenGLContext> xContext = OpenGLContext::getVCLContext(false);
177         if( xContext.is() )
178         {
179             // FIXME: this is really not optimal performance-wise.
180 
181             // Check we have been correctly un-bound from all framebuffers.
182             ImplSVData* pSVData = ImplGetSVData();
183             rtl::Reference<OpenGLContext> pContext = pSVData->maGDIData.mpLastContext;
184 
185             if( pContext.is() )
186             {
187                 pContext->makeCurrent();
188                 pContext->UnbindTextureFromFramebuffers( mnTexture );
189             }
190 
191             if( mnOptStencil != 0 )
192             {
193                 glDeleteRenderbuffers( 1, &mnOptStencil );
194                 mnOptStencil = 0;
195             }
196             auto& rState = pContext->state();
197             rState.texture().unbindAndDelete(mnTexture);
198             mnTexture = 0;
199         }
200         else
201         {
202             mnOptStencil = 0;
203             mnTexture = 0;
204         }
205     }
206 }
207 
InsertBuffer(int nX,int nY,int nWidth,int nHeight,int nFormat,int nType,sal_uInt8 const * pData)208 bool ImplOpenGLTexture::InsertBuffer(int nX, int nY, int nWidth, int nHeight, int nFormat, int nType, sal_uInt8 const * pData)
209 {
210     if (!pData || mnTexture == 0)
211         return false;
212 
213     rtl::Reference<OpenGLContext> xContext = OpenGLContext::getVCLContext();
214     xContext->state().texture().active(0);
215     xContext->state().texture().bind(mnTexture);
216 
217     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
218     CHECK_GL_ERROR();
219     glTexSubImage2D(GL_TEXTURE_2D, 0, nX, mnHeight - nY - nHeight, nWidth, nHeight, nFormat, nType, pData);
220     CHECK_GL_ERROR();
221 
222     VCL_GL_INFO( "OpenGLTexture " << mnTexture << " Insert buff. to " << nX << " " << nY
223                                              << " size " << nWidth << "x" << nHeight << " from data" );
224 
225     return true;
226 }
227 
InitializeSlotMechanism(int nInitialSlotSize)228 void ImplOpenGLTexture::InitializeSlotMechanism(int nInitialSlotSize)
229 {
230     if (mpSlotReferences)
231         return;
232 
233     mpSlotReferences.reset(new std::vector<int>(nInitialSlotSize, 0));
234 }
235 
IncreaseRefCount(int nSlotNumber)236 void ImplOpenGLTexture::IncreaseRefCount(int nSlotNumber)
237 {
238     if (mpSlotReferences && nSlotNumber >= 0)
239     {
240         if (nSlotNumber >= int(mpSlotReferences->size()))
241             mpSlotReferences->resize(nSlotNumber + 1, 0);
242 
243         mpSlotReferences->at(nSlotNumber)++;
244     }
245 }
246 
DecreaseRefCount(int nSlotNumber)247 void ImplOpenGLTexture::DecreaseRefCount(int nSlotNumber)
248 {
249     if (mpSlotReferences && nSlotNumber >= 0)
250     {
251         if (nSlotNumber >= int(mpSlotReferences->size()))
252             mpSlotReferences->resize(nSlotNumber, 0);
253 
254         mpSlotReferences->at(nSlotNumber)--;
255 
256         if (mpSlotReferences->at(nSlotNumber) == 0 && mFunctSlotDeallocateCallback)
257         {
258             mFunctSlotDeallocateCallback(nSlotNumber);
259         }
260     }
261 }
262 
OpenGLTexture()263 OpenGLTexture::OpenGLTexture() :
264     maRect( 0, 0, 0, 0 ),
265     mpImpl(),
266     mnSlotNumber(-1)
267 {
268 }
269 
OpenGLTexture(const std::shared_ptr<ImplOpenGLTexture> & rpImpl,tools::Rectangle aRectangle,int nSlotNumber)270 OpenGLTexture::OpenGLTexture(const std::shared_ptr<ImplOpenGLTexture>& rpImpl, tools::Rectangle aRectangle, int nSlotNumber)
271     : maRect(aRectangle)
272     , mpImpl(rpImpl)
273     , mnSlotNumber(nSlotNumber)
274 {
275     if (mpImpl)
276         mpImpl->IncreaseRefCount(nSlotNumber);
277 }
278 
OpenGLTexture(int nWidth,int nHeight,bool bAllocate)279 OpenGLTexture::OpenGLTexture( int nWidth, int nHeight, bool bAllocate )
280     : maRect( Point( 0, 0 ), Size( nWidth, nHeight ) )
281     , mpImpl(new ImplOpenGLTexture(nWidth, nHeight, bAllocate))
282     , mnSlotNumber(-1)
283 {
284 }
285 
OpenGLTexture(int nX,int nY,int nWidth,int nHeight)286 OpenGLTexture::OpenGLTexture( int nX, int nY, int nWidth, int nHeight )
287     : maRect( Point( 0, 0 ), Size( nWidth, nHeight ) )
288     , mpImpl(new ImplOpenGLTexture(nX, nY, nWidth, nHeight))
289     , mnSlotNumber(-1)
290 {
291 }
292 
OpenGLTexture(int nWidth,int nHeight,int nFormat,int nType,void const * pData)293 OpenGLTexture::OpenGLTexture( int nWidth, int nHeight, int nFormat, int nType, void const * pData )
294     : maRect( Point( 0, 0 ), Size( nWidth, nHeight ) )
295     , mpImpl(new ImplOpenGLTexture(nWidth, nHeight, nFormat, nType, pData))
296     , mnSlotNumber(-1)
297 {
298 
299 }
300 
OpenGLTexture(const OpenGLTexture & rTexture)301 OpenGLTexture::OpenGLTexture(const OpenGLTexture& rTexture)
302     : maRect(rTexture.maRect)
303     , mpImpl(rTexture.mpImpl)
304     , mnSlotNumber(rTexture.mnSlotNumber)
305 {
306     if (mpImpl)
307         mpImpl->IncreaseRefCount(mnSlotNumber);
308 }
309 
OpenGLTexture(OpenGLTexture && rTexture)310 OpenGLTexture::OpenGLTexture(OpenGLTexture&& rTexture) noexcept
311     : maRect(rTexture.maRect)
312     , mpImpl(std::move(rTexture.mpImpl))
313     , mnSlotNumber(rTexture.mnSlotNumber)
314 {
315 }
316 
OpenGLTexture(const OpenGLTexture & rTexture,int nX,int nY,int nWidth,int nHeight)317 OpenGLTexture::OpenGLTexture( const OpenGLTexture& rTexture,
318                               int nX, int nY, int nWidth, int nHeight )
319 {
320     maRect = tools::Rectangle( Point( rTexture.maRect.Left() + nX, rTexture.maRect.Top() + nY ),
321                         Size( nWidth, nHeight ) );
322     mpImpl = rTexture.mpImpl;
323     mnSlotNumber = rTexture.mnSlotNumber;
324     if (mpImpl)
325         mpImpl->IncreaseRefCount(mnSlotNumber);
326     VCL_GL_INFO( "Copying texture " << Id() << " [" << maRect.Left() << "," << maRect.Top() << "] " << GetWidth() << "x" << GetHeight() );
327 }
328 
~OpenGLTexture()329 OpenGLTexture::~OpenGLTexture()
330 {
331     if (mpImpl)
332         mpImpl->DecreaseRefCount(mnSlotNumber);
333 }
334 
IsUnique() const335 bool OpenGLTexture::IsUnique() const
336 {
337     return !mpImpl || (mpImpl.use_count() == 1);
338 }
339 
Id() const340 GLuint OpenGLTexture::Id() const
341 {
342     if (mpImpl)
343         return mpImpl->mnTexture;
344     return 0;
345 }
346 
GetWidth() const347 int OpenGLTexture::GetWidth() const
348 {
349     return maRect.GetWidth();
350 }
351 
GetHeight() const352 int OpenGLTexture::GetHeight() const
353 {
354     return maRect.GetHeight();
355 }
356 
StencilId() const357 GLuint OpenGLTexture::StencilId() const
358 {
359     return mpImpl ? mpImpl->mnOptStencil : 0;
360 }
361 
AddStencil()362 GLuint OpenGLTexture::AddStencil()
363 {
364     if (mpImpl)
365         return mpImpl->AddStencil();
366     else
367         return 0;
368 }
369 
GetCoord(GLfloat * pCoord,const SalTwoRect & rPosAry,bool bInverted) const370 void OpenGLTexture::GetCoord( GLfloat* pCoord, const SalTwoRect& rPosAry, bool bInverted ) const
371 {
372     VCL_GL_INFO( "Getting coord " << Id() << " [" << maRect.Left() << "," << maRect.Top() << "] " << GetWidth() << "x" << GetHeight() );
373 
374     if (!IsValid())
375     {
376         pCoord[0] = pCoord[1] = pCoord[2] = pCoord[3] = 0.0f;
377         pCoord[4] = pCoord[5] = pCoord[6] = pCoord[7] = 0.0f;
378         return;
379     }
380 
381     pCoord[0] = pCoord[2] = (maRect.Left() + rPosAry.mnSrcX) / static_cast<double>(mpImpl->mnWidth);
382     pCoord[4] = pCoord[6] = (maRect.Left() + rPosAry.mnSrcX + rPosAry.mnSrcWidth) / static_cast<double>(mpImpl->mnWidth);
383 
384     if( !bInverted )
385     {
386         pCoord[3] = pCoord[5] = 1.0f - (maRect.Top() + rPosAry.mnSrcY) / static_cast<double>(mpImpl->mnHeight);
387         pCoord[1] = pCoord[7] = 1.0f - (maRect.Top() + rPosAry.mnSrcY + rPosAry.mnSrcHeight) / static_cast<double>(mpImpl->mnHeight);
388     }
389     else
390     {
391         pCoord[1] = pCoord[7] = 1.0f - (maRect.Top() + rPosAry.mnSrcY) / static_cast<double>(mpImpl->mnHeight);
392         pCoord[3] = pCoord[5] = 1.0f - (maRect.Top() + rPosAry.mnSrcY + rPosAry.mnSrcHeight) / static_cast<double>(mpImpl->mnHeight);
393     }
394 }
395 
GetTextureRect(const SalTwoRect & rPosAry,GLfloat & x1,GLfloat & x2,GLfloat & y1,GLfloat & y2) const396 void OpenGLTexture::GetTextureRect(const SalTwoRect& rPosAry, GLfloat& x1, GLfloat& x2, GLfloat& y1, GLfloat& y2) const
397 {
398     if (IsValid())
399     {
400         double fTextureWidth(mpImpl->mnWidth);
401         double fTextureHeight(mpImpl->mnHeight);
402 
403         x1 = (maRect.Left() + rPosAry.mnSrcX) / fTextureWidth;
404         x2 = (maRect.Left() + rPosAry.mnSrcX + rPosAry.mnSrcWidth) / fTextureWidth;
405 
406         y1 = 1.0f - (maRect.Top() + rPosAry.mnSrcY) / fTextureHeight;
407         y2 = 1.0f - (maRect.Top() + rPosAry.mnSrcY + rPosAry.mnSrcHeight) / fTextureHeight;
408     }
409 }
410 
411 template <>
FillCoords(std::vector<GLfloat> & rCoords,const SalTwoRect & rPosAry) const412 void OpenGLTexture::FillCoords<GL_TRIANGLE_FAN>(std::vector<GLfloat>& rCoords, const SalTwoRect& rPosAry) const
413 {
414     GLfloat x1 = 0.0f;
415     GLfloat x2 = 0.0f;
416     GLfloat y1 = 0.0f;
417     GLfloat y2 = 0.0f;
418 
419     GetTextureRect(rPosAry, x1, x2, y1, y2);
420 
421     rCoords.insert(rCoords.end(), {
422         x1, y2, x1, y1,
423         x2, y1, x2, y2
424     });
425 }
426 
427 template <>
FillCoords(std::vector<GLfloat> & rCoords,const SalTwoRect & rPosAry) const428 void OpenGLTexture::FillCoords<GL_TRIANGLES>(std::vector<GLfloat>& rCoords, const SalTwoRect& rPosAry) const
429 {
430     GLfloat x1 = 0.0f;
431     GLfloat x2 = 0.0f;
432     GLfloat y1 = 0.0f;
433     GLfloat y2 = 0.0f;
434 
435     GetTextureRect(rPosAry, x1, x2, y1, y2);
436 
437     rCoords.insert(rCoords.end(), {
438         x1, y1, x2, y1, x1, y2,
439         x1, y2, x2, y1, x2, y2
440     });
441 }
442 
GetWholeCoord(GLfloat * pCoord) const443 void OpenGLTexture::GetWholeCoord( GLfloat* pCoord ) const
444 {
445     if( GetWidth() != mpImpl->mnWidth || GetHeight() != mpImpl->mnHeight )
446     {
447         pCoord[0] = pCoord[2] = maRect.Left() / static_cast<double>(mpImpl->mnWidth);
448         pCoord[4] = pCoord[6] = maRect.Right() / static_cast<double>(mpImpl->mnWidth);
449         pCoord[3] = pCoord[5] = 1.0f - maRect.Top() / static_cast<double>(mpImpl->mnHeight);
450         pCoord[1] = pCoord[7] = 1.0f - maRect.Bottom() / static_cast<double>(mpImpl->mnHeight);
451     }
452     else
453     {
454         pCoord[0] = pCoord[2] = 0;
455         pCoord[4] = pCoord[6] = 1;
456         pCoord[1] = pCoord[7] = 0;
457         pCoord[3] = pCoord[5] = 1;
458     }
459 }
460 
GetFilter() const461 GLenum OpenGLTexture::GetFilter() const
462 {
463     if( mpImpl )
464         return mpImpl->mnFilter;
465     return GL_NEAREST;
466 }
467 
CopyData(int nWidth,int nHeight,int nFormat,int nType,sal_uInt8 const * pData)468 bool OpenGLTexture::CopyData(int nWidth, int nHeight, int nFormat, int nType, sal_uInt8 const * pData)
469 {
470     if (!pData || !IsValid())
471         return false;
472 
473     int nX = maRect.Left();
474     int nY = maRect.Top();
475 
476     return mpImpl->InsertBuffer(nX, nY, nWidth, nHeight, nFormat, nType, pData);
477 }
478 
SetFilter(GLenum nFilter)479 void OpenGLTexture::SetFilter( GLenum nFilter )
480 {
481     if( mpImpl )
482     {
483         mpImpl->mnFilter = nFilter;
484         glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, nFilter );
485         CHECK_GL_ERROR();
486         glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, nFilter );
487         CHECK_GL_ERROR();
488     }
489 }
490 
Bind()491 void OpenGLTexture::Bind()
492 {
493     if (IsValid())
494     {
495         OpenGLContext::getVCLContext()->state().texture().bind(mpImpl->mnTexture);
496     }
497     else
498         VCL_GL_INFO( "OpenGLTexture::Binding invalid texture" );
499 
500     CHECK_GL_ERROR();
501 }
502 
Unbind()503 void OpenGLTexture::Unbind()
504 {
505     if (IsValid())
506     {
507         OpenGLContext::getVCLContext()->state().texture().unbind(mpImpl->mnTexture);
508     }
509 }
510 
SaveToFile(const OUString & rFileName)511 void OpenGLTexture::SaveToFile(const OUString& rFileName)
512 {
513     std::vector<sal_uInt8> aBuffer(GetWidth() * GetHeight() * 4);
514     Read(OpenGLHelper::OptimalBufferFormat(), GL_UNSIGNED_BYTE, aBuffer.data());
515     BitmapEx aBitmap = OpenGLHelper::ConvertBufferToBitmapEx(aBuffer.data(), GetWidth(), GetHeight());
516     try
517     {
518         vcl::PNGWriter aWriter(aBitmap);
519         SvFileStream sOutput(rFileName, StreamMode::WRITE);
520         aWriter.Write(sOutput);
521         sOutput.Close();
522     }
523     catch (...)
524     {
525         SAL_WARN("vcl.opengl", "Error writing png to " << rFileName);
526     }
527 }
528 
Read(GLenum nFormat,GLenum nType,sal_uInt8 * pData)529 void OpenGLTexture::Read( GLenum nFormat, GLenum nType, sal_uInt8* pData )
530 {
531     if (!IsValid())
532     {
533         SAL_WARN( "vcl.opengl", "Can't read invalid texture" );
534         return;
535     }
536 
537     OpenGLVCLContextZone aContextZone;
538 
539     VCL_GL_INFO( "Reading texture " << Id() << " " << GetWidth() << "x" << GetHeight() );
540 
541     if( GetWidth() == mpImpl->mnWidth && GetHeight() == mpImpl->mnHeight )
542     {
543         Bind();
544         glPixelStorei( GL_PACK_ALIGNMENT, 1 );
545         CHECK_GL_ERROR();
546         // XXX: Call not available with GLES 2.0
547         glGetTexImage( GL_TEXTURE_2D, 0, nFormat, nType, pData );
548         CHECK_GL_ERROR();
549         Unbind();
550     }
551     else
552     {
553         long nWidth = maRect.GetWidth();
554         long nHeight = maRect.GetHeight();
555         long nX = maRect.Left();
556         long nY = mpImpl->mnHeight - maRect.Top() - nHeight;
557 
558         // Retrieve current context
559         ImplSVData* pSVData = ImplGetSVData();
560         rtl::Reference<OpenGLContext> pContext = pSVData->maGDIData.mpLastContext;
561         OpenGLFramebuffer* pFramebuffer = pContext->AcquireFramebuffer(*this);
562         glPixelStorei(GL_PACK_ALIGNMENT, 1);
563         CHECK_GL_ERROR();
564         glReadPixels(nX, nY, nWidth, nHeight, nFormat, nType, pData);
565         CHECK_GL_ERROR();
566         OpenGLContext::ReleaseFramebuffer(pFramebuffer);
567     }
568 }
569 
operator bool() const570 OpenGLTexture::operator bool() const
571 {
572     return IsValid();
573 }
574 
operator =(const OpenGLTexture & rTexture)575 OpenGLTexture& OpenGLTexture::operator=(const OpenGLTexture& rTexture)
576 {
577     OpenGLTexture aTemp(rTexture);
578     *this = std::move(aTemp);
579     return *this;
580 }
581 
operator =(OpenGLTexture && rTexture)582 OpenGLTexture& OpenGLTexture::operator=(OpenGLTexture&& rTexture)
583 {
584     if (mpImpl)
585         mpImpl->DecreaseRefCount(mnSlotNumber);
586 
587     maRect = rTexture.maRect;
588     mpImpl = std::move(rTexture.mpImpl);
589     mnSlotNumber = rTexture.mnSlotNumber;
590 
591     return *this;
592 }
593 
operator ==(const OpenGLTexture & rTexture) const594 bool OpenGLTexture::operator==( const OpenGLTexture& rTexture ) const
595 {
596     return (mpImpl == rTexture.mpImpl
597          && maRect == rTexture.maRect
598          && mnSlotNumber == rTexture.mnSlotNumber);
599 }
600 
operator !=(const OpenGLTexture & rTexture) const601 bool OpenGLTexture::operator!=( const OpenGLTexture& rTexture ) const
602 {
603     return !( *this == rTexture );
604 }
605 
606 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
607