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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <sal/config.h>
23 #include <vcl/opengl/OpenGLHelper.hxx>
25 #include <vcl/bitmap.hxx>
26 #include <vcl/checksum.hxx>
27 #include <vcl/outdev.hxx>
28 #include <vcl/salbtype.hxx>
31 #include <vcleventlisteners.hxx>
32 #include <vcl/lazydelete.hxx>
34 #include <o3tl/make_unique.hxx>
35 #include <o3tl/make_shared.hxx>
37 #include <opengl/zone.hxx>
38 #include <opengl/program.hxx>
39 #include <opengl/salbmp.hxx>
40 #include <opengl/RenderState.hxx>
41 #include <opengl/FixedTextureAtlas.hxx>
43 #if OSL_DEBUG_LEVEL > 0
44 # define CANARY "tex-canary"
50 inline bool determineTextureFormat(sal_uInt16 nBits
, GLenum
& nFormat
, GLenum
& nType
)
55 nFormat
= GL_LUMINANCE
;
56 nType
= GL_UNSIGNED_BYTE
;
60 nType
= GL_UNSIGNED_SHORT_5_6_5
;
64 nType
= GL_UNSIGNED_BYTE
;
68 nType
= GL_UNSIGNED_BYTE
;
73 SAL_WARN("vcl.opengl", "Could not determine the appropriate texture format for input bits '" << nBits
<< "'");
77 inline bool isValidBitCount( sal_uInt16 nBitCount
)
79 return (nBitCount
== 1) || (nBitCount
== 4) || (nBitCount
== 8) || (nBitCount
== 16) || (nBitCount
== 24) || (nBitCount
== 32);
82 sal_uInt32
lclBytesPerRow(sal_uInt16 nBits
, int nWidth
)
86 case 1: return (nWidth
+ 7) >> 3;
87 case 4: return (nWidth
+ 1) >> 1;
88 case 8: return nWidth
;
89 case 16: return nWidth
* 2;
90 case 24: return nWidth
* 3;
91 case 32: return nWidth
* 4;
93 OSL_FAIL("vcl::OpenGLSalBitmap::AllocateUserData(), illegal bitcount!");
98 typedef std::vector
<std::unique_ptr
< FixedTextureAtlasManager
> > TextureAtlasVector
;
99 static vcl::DeleteOnDeinit
< TextureAtlasVector
> gTextureAtlases(new TextureAtlasVector
);
103 OpenGLSalBitmap::OpenGLSalBitmap()
104 : mbDirtyTexture(true)
112 OpenGLSalBitmap::~OpenGLSalBitmap()
115 VCL_GL_INFO( "~OpenGLSalBitmap" );
118 bool OpenGLSalBitmap::Create( const OpenGLTexture
& rTex
, long nX
, long nY
, long nWidth
, long nHeight
)
120 DBG_TESTSOLARMUTEX();
121 static const BitmapPalette aEmptyPalette
;
122 OpenGLVCLContextZone aContextZone
;
125 VCL_GL_INFO( "OpenGLSalBitmap::Create from FBO: ["
126 << nX
<< ", " << nY
<< "] " << nWidth
<< "x" << nHeight
);
128 GLint nMaxTextureSize
;
129 glGetIntegerv( GL_MAX_TEXTURE_SIZE
, &nMaxTextureSize
);
130 if ( nWidth
> nMaxTextureSize
)
132 nWidth
= nMaxTextureSize
;
133 VCL_GL_INFO( "Width limited to " << nMaxTextureSize
);
136 if ( nHeight
> nMaxTextureSize
)
138 nHeight
= nMaxTextureSize
;
139 VCL_GL_INFO( "Height limited to " << nMaxTextureSize
);
145 // TODO Check the framebuffer configuration
147 maPalette
= aEmptyPalette
;
150 maTexture
= OpenGLTexture( rTex
, nX
, nY
, nWidth
, nHeight
);
152 maTexture
= OpenGLTexture( nX
, nY
, nWidth
, nHeight
);
153 mbDirtyTexture
= false;
154 VCL_GL_INFO( "Created texture " << maTexture
.Id() );
156 assert(mnWidth
== maTexture
.GetWidth() &&
157 mnHeight
== maTexture
.GetHeight());
162 bool OpenGLSalBitmap::Create( const Size
& rSize
, sal_uInt16 nBits
, const BitmapPalette
& rBitmapPalette
)
164 DBG_TESTSOLARMUTEX();
165 OpenGLVCLContextZone aContextZone
;
168 VCL_GL_INFO( "OpenGLSalBitmap::Create with size: " << rSize
);
170 if( !isValidBitCount( nBits
) )
172 maPalette
= rBitmapPalette
;
174 mnWidth
= rSize
.Width();
175 mnHeight
= rSize
.Height();
177 // Limit size to what GL allows, so later glTexImage2D() won't fail.
178 GLint nMaxTextureSize
;
179 glGetIntegerv(GL_MAX_TEXTURE_SIZE
, &nMaxTextureSize
);
180 if (mnWidth
> nMaxTextureSize
)
181 mnWidth
= nMaxTextureSize
;
182 if (mnHeight
> nMaxTextureSize
)
183 mnHeight
= nMaxTextureSize
;
188 bool OpenGLSalBitmap::Create( const SalBitmap
& rSalBmp
)
190 DBG_TESTSOLARMUTEX();
191 return Create( rSalBmp
, rSalBmp
.GetBitCount() );
194 bool OpenGLSalBitmap::Create( const SalBitmap
& rSalBmp
, SalGraphics
* pGraphics
)
196 DBG_TESTSOLARMUTEX();
197 return Create( rSalBmp
, pGraphics
? pGraphics
->GetBitCount() : rSalBmp
.GetBitCount() );
200 bool OpenGLSalBitmap::Create( const SalBitmap
& rSalBmp
, sal_uInt16 nNewBitCount
)
202 DBG_TESTSOLARMUTEX();
205 // check that carefully only in the debug mode
206 assert(dynamic_cast<const OpenGLSalBitmap
*>(&rSalBmp
));
208 const OpenGLSalBitmap
& rSourceBitmap
= static_cast<const OpenGLSalBitmap
&>(rSalBmp
);
210 VCL_GL_INFO("OpenGLSalBitmap::Create from BMP: "
211 << rSourceBitmap
.mnWidth
<< "x" << rSourceBitmap
.mnHeight
212 << " Bits old: " << mnBits
<< " new:" << nNewBitCount
);
214 if( isValidBitCount( nNewBitCount
) )
216 // TODO: lfrb: What about the pending operations?!
217 mnBits
= nNewBitCount
;
218 mnBytesPerRow
= rSourceBitmap
.mnBytesPerRow
;
219 mnWidth
= rSourceBitmap
.mnWidth
;
220 mnHeight
= rSourceBitmap
.mnHeight
;
221 maPalette
= rSourceBitmap
.maPalette
;
222 // execute any pending operations on the source bitmap
223 maTexture
= rSourceBitmap
.GetTexture();
224 mbDirtyTexture
= false;
226 // be careful here, we are share & reference-count the
227 // mpUserBuffer, BUT this Create() is called from
228 // Bitmap::ImplMakeUnique().
229 // Consequently, there might be cases when this needs to be made
230 // unique later (when we don't do that right away here), like when
231 // using the BitmapWriteAccess.
232 mpUserBuffer
= rSourceBitmap
.mpUserBuffer
;
239 bool OpenGLSalBitmap::Create( const css::uno::Reference
< css::rendering::XBitmapCanvas
>& /*xBitmapCanvas*/, Size
& /*rSize*/, bool /*bMask*/ )
241 DBG_TESTSOLARMUTEX();
242 // TODO Is this method needed?
246 OpenGLTexture
& OpenGLSalBitmap::GetTexture() const
248 OpenGLSalBitmap
* pThis
= const_cast<OpenGLSalBitmap
*>(this);
249 if( !maTexture
|| mbDirtyTexture
)
250 pThis
->CreateTexture();
251 VCL_GL_INFO( "Got texture " << maTexture
.Id() );
252 return pThis
->maTexture
;
255 void OpenGLSalBitmap::Destroy()
259 VCL_GL_INFO("Destroy OpenGLSalBitmap texture:" << maTexture
.Id());
260 maTexture
= OpenGLTexture();
261 mpUserBuffer
.reset();
264 bool OpenGLSalBitmap::AllocateUserData()
266 VCL_GL_INFO( "OpenGLSalBitmap::AllocateUserData" );
268 if( mnWidth
&& mnHeight
)
270 mnBytesPerRow
= lclBytesPerRow(mnBits
, mnWidth
);
274 if (mnBytesPerRow
!= 0 && mnHeight
&&
275 mnBytesPerRow
<= std::numeric_limits
<sal_uInt32
>::max() / mnHeight
)
279 size_t nToAllocate
= mnBytesPerRow
* mnHeight
;
280 #if OSL_DEBUG_LEVEL > 0
281 nToAllocate
+= sizeof(CANARY
);
283 mpUserBuffer
= o3tl::make_shared_array
<sal_uInt8
>(nToAllocate
);
284 #if OSL_DEBUG_LEVEL > 0
285 memcpy(mpUserBuffer
.get() + nToAllocate
- sizeof(CANARY
),
286 CANARY
, sizeof(CANARY
));
290 catch (const std::bad_alloc
&) {}
294 SAL_WARN("vcl.opengl", "bad alloc " << mnBytesPerRow
<< "x" << mnHeight
);
295 mpUserBuffer
.reset();
301 for (size_t i
= 0; i
< size_t(mnBytesPerRow
* mnHeight
); i
++)
302 mpUserBuffer
.get()[i
] = (i
& 0xFF);
306 return mpUserBuffer
.get() != nullptr;
311 class ImplPixelFormat
316 static ImplPixelFormat
* GetFormat( sal_uInt16 nBits
, const BitmapPalette
& rPalette
);
318 virtual void StartLine( sal_uInt8
* pLine
) { mpData
= pLine
; }
319 virtual const BitmapColor
& ReadPixel() = 0;
320 virtual ~ImplPixelFormat() { }
323 class ImplPixelFormat8
: public ImplPixelFormat
326 const BitmapPalette
& mrPalette
;
329 explicit ImplPixelFormat8( const BitmapPalette
& rPalette
)
330 : mrPalette( rPalette
)
333 virtual const BitmapColor
& ReadPixel() override
335 assert( mrPalette
.GetEntryCount() > *mpData
);
336 return mrPalette
[ *mpData
++ ];
340 class ImplPixelFormat4
: public ImplPixelFormat
343 const BitmapPalette
& mrPalette
;
348 explicit ImplPixelFormat4( const BitmapPalette
& rPalette
)
349 : mrPalette( rPalette
)
354 virtual void StartLine( sal_uInt8
* pLine
) override
360 virtual const BitmapColor
& ReadPixel() override
362 sal_uInt32 nIdx
= ( mpData
[mnX
>> 1] >> mnShift
) & 0x0f;
363 assert( mrPalette
.GetEntryCount() > nIdx
);
364 const BitmapColor
& rColor
= mrPalette
[nIdx
];
371 class ImplPixelFormat1
: public ImplPixelFormat
374 const BitmapPalette
& mrPalette
;
378 explicit ImplPixelFormat1( const BitmapPalette
& rPalette
)
379 : mrPalette(rPalette
)
383 virtual void StartLine( sal_uInt8
* pLine
) override
388 virtual const BitmapColor
& ReadPixel() override
390 const BitmapColor
& rColor
= mrPalette
[ (mpData
[mnX
>> 3 ] >> ( 7 - ( mnX
& 7 ) )) & 1];
396 ImplPixelFormat
* ImplPixelFormat::GetFormat( sal_uInt16 nBits
, const BitmapPalette
& rPalette
)
400 case 1: return new ImplPixelFormat1( rPalette
);
401 case 4: return new ImplPixelFormat4( rPalette
);
402 case 8: return new ImplPixelFormat8( rPalette
);
408 void lclInstantiateTexture(OpenGLTexture
& rTexture
, const int nWidth
, const int nHeight
,
409 const GLenum nFormat
, const GLenum nType
, sal_uInt8
const * pData
)
411 if (nWidth
== nHeight
)
413 TextureAtlasVector
&sTextureAtlases
= *gTextureAtlases
.get();
414 if (sTextureAtlases
.empty())
416 sTextureAtlases
.push_back(o3tl::make_unique
<FixedTextureAtlasManager
>(8, 8, 16));
417 sTextureAtlases
.push_back(o3tl::make_unique
<FixedTextureAtlasManager
>(8, 8, 24));
418 sTextureAtlases
.push_back(o3tl::make_unique
<FixedTextureAtlasManager
>(8, 8, 32));
419 sTextureAtlases
.push_back(o3tl::make_unique
<FixedTextureAtlasManager
>(8, 8, 48));
420 sTextureAtlases
.push_back(o3tl::make_unique
<FixedTextureAtlasManager
>(8, 8, 64));
422 for (std::unique_ptr
<FixedTextureAtlasManager
> & pTextureAtlas
: sTextureAtlases
)
424 if (nWidth
== pTextureAtlas
->GetSubtextureSize())
426 rTexture
= pTextureAtlas
->InsertBuffer(nWidth
, nHeight
, nFormat
, nType
, pData
);
431 rTexture
= OpenGLTexture (nWidth
, nHeight
, nFormat
, nType
, pData
);
434 // Write color information for 1 and 4 bit palette bitmap scanlines.
437 BitmapPalette
& maPalette
;
438 sal_uInt8 mnColorsPerByte
; // number of colors that are stored in one byte
439 sal_uInt8 mnColorBitSize
; // number of bits a color takes
440 sal_uInt8 mnColorBitMask
; // bit mask used to isolate the color
441 sal_uInt8
* mpCurrentScanline
;
445 ScanlineWriter(BitmapPalette
& aPalette
, sal_Int8 nColorsPerByte
)
446 : maPalette(aPalette
)
447 , mnColorsPerByte(nColorsPerByte
)
448 , mnColorBitSize(8 / mnColorsPerByte
) // bit size is number of bit in a byte divided by number of colors per byte (8 / 2 = 4 for 4-bit)
449 , mnColorBitMask((1 << mnColorBitSize
) - 1) // calculate the bit mask from the bit size
450 , mpCurrentScanline(nullptr)
454 void writeRGB(sal_uInt8 nR
, sal_uInt8 nG
, sal_uInt8 nB
)
456 // calculate to which index we will write
457 long nScanlineIndex
= mnX
/ mnColorsPerByte
;
459 // calculate the number of shifts to get the color information to the right place
460 long nShift
= (8 - mnColorBitSize
) - ((mnX
% mnColorsPerByte
) * mnColorBitSize
);
462 sal_uInt16 nColorIndex
= maPalette
.GetBestIndex(BitmapColor(nR
, nG
, nB
));
463 mpCurrentScanline
[nScanlineIndex
] &= ~(mnColorBitMask
<< nShift
); // clear
464 mpCurrentScanline
[nScanlineIndex
] |= (nColorIndex
& mnColorBitMask
) << nShift
; // set
468 void nextLine(sal_uInt8
* pScanline
)
471 mpCurrentScanline
= pScanline
;
475 } // end anonymous namespace
477 Size
OpenGLSalBitmap::GetSize() const
479 return Size(mnWidth
, mnHeight
);
482 GLuint
OpenGLSalBitmap::CreateTexture()
484 VCL_GL_INFO( "::CreateTexture bits: " << mnBits
);
485 GLenum nFormat
= GL_RGBA
;
486 GLenum nType
= GL_UNSIGNED_BYTE
;
487 sal_uInt8
* pData( nullptr );
488 bool bAllocated( false );
490 if (mpUserBuffer
.get() != nullptr)
492 if( mnBits
== 16 || mnBits
== 24 || mnBits
== 32 )
494 // no conversion needed for truecolor
495 pData
= mpUserBuffer
.get();
497 determineTextureFormat(mnBits
, nFormat
, nType
);
499 else if( mnBits
== 8 && maPalette
.IsGreyPalette() )
501 // no conversion needed for grayscale
502 pData
= mpUserBuffer
.get();
503 nFormat
= GL_LUMINANCE
;
504 nType
= GL_UNSIGNED_BYTE
;
508 VCL_GL_INFO( "::CreateTexture - convert from " << mnBits
<< " to 24 bits" );
510 // convert to 24 bits RGB using palette
511 pData
= new sal_uInt8
[mnHeight
* mnWidth
* 3];
513 determineTextureFormat(24, nFormat
, nType
);
515 std::unique_ptr
<ImplPixelFormat
> pSrcFormat(ImplPixelFormat::GetFormat(mnBits
, maPalette
));
517 sal_uInt8
* pSrcData
= mpUserBuffer
.get();
518 sal_uInt8
* pDstData
= pData
;
520 sal_uInt32 nY
= mnHeight
;
523 pSrcFormat
->StartLine( pSrcData
);
525 sal_uInt32 nX
= mnWidth
;
526 if (nFormat
== GL_BGR
)
530 const BitmapColor
& c
= pSrcFormat
->ReadPixel();
531 *pDstData
++ = c
.GetBlue();
532 *pDstData
++ = c
.GetGreen();
533 *pDstData
++ = c
.GetRed();
540 const BitmapColor
& c
= pSrcFormat
->ReadPixel();
541 *pDstData
++ = c
.GetRed();
542 *pDstData
++ = c
.GetGreen();
543 *pDstData
++ = c
.GetBlue();
547 pSrcData
+= mnBytesPerRow
;
552 OpenGLVCLContextZone aContextZone
;
554 lclInstantiateTexture(maTexture
, mnWidth
, mnHeight
, nFormat
, nType
, pData
);
556 VCL_GL_INFO("Created texture " << maTexture
.Id() << " bits: " << mnBits
);
561 mbDirtyTexture
= false;
564 return maTexture
.Id();
567 bool OpenGLSalBitmap::ReadTexture()
569 sal_uInt8
* pData
= mpUserBuffer
.get();
571 GLenum nFormat
= GL_RGBA
;
572 GLenum nType
= GL_UNSIGNED_BYTE
;
574 VCL_GL_INFO( "::ReadTexture " << mnWidth
<< "x" << mnHeight
<< " bits: " << mnBits
);
576 if( pData
== nullptr )
579 OpenGLVCLContextZone aContextZone
;
581 rtl::Reference
<OpenGLContext
> xContext
= OpenGLContext::getVCLContext();
582 xContext
->state().scissor().disable();
583 xContext
->state().stencil().disable();
585 if ((mnBits
== 8 && maPalette
.IsGreyPalette()) || mnBits
== 16 || mnBits
== 24 || mnBits
== 32)
587 determineTextureFormat(mnBits
, nFormat
, nType
);
589 #if OSL_DEBUG_LEVEL > 0
590 // help valgrind & drmemory rescue us - touch last and first bits.
592 pData
[mnBits
/8*mnWidth
*mnHeight
-1] = 0;
593 // if this fails we can read too much into pData
594 assert(mnWidth
== maTexture
.GetWidth() &&
595 mnHeight
== maTexture
.GetHeight());
598 maTexture
.Read(nFormat
, nType
, pData
);
600 #if OSL_DEBUG_LEVEL > 0
601 // If we read over the end of pData we have a real hidden memory
602 // corruption problem !
603 size_t nCanary
= mnBytesPerRow
* mnHeight
;
604 assert(!memcmp(pData
+ nCanary
, CANARY
, sizeof (CANARY
)));
608 else if (mnBits
== 1 || mnBits
== 4)
609 { // convert buffers from 24-bit RGB to 1 or 4-bit buffer
610 std::vector
<sal_uInt8
> aBuffer(mnWidth
* mnHeight
* 3);
612 sal_uInt8
* pBuffer
= aBuffer
.data();
613 determineTextureFormat(24, nFormat
, nType
);
614 maTexture
.Read(nFormat
, nType
, pBuffer
);
615 sal_uInt32 nSourceBytesPerRow
= lclBytesPerRow(24, mnWidth
);
617 std::unique_ptr
<ScanlineWriter
> pWriter
;
621 pWriter
.reset(new ScanlineWriter(maPalette
, 8));
625 pWriter
.reset(new ScanlineWriter(maPalette
, 2));
629 for (int y
= 0; y
< mnHeight
; ++y
)
631 sal_uInt8
* pSource
= &pBuffer
[y
* nSourceBytesPerRow
];
632 sal_uInt8
* pDestination
= &pData
[y
* mnBytesPerRow
];
634 pWriter
->nextLine(pDestination
);
636 for (int x
= 0; x
< mnWidth
; ++x
)
639 sal_uInt8 nR
= *pSource
++;
640 sal_uInt8 nG
= *pSource
++;
641 sal_uInt8 nB
= *pSource
++;
643 pWriter
->writeRGB(nR
, nG
, nB
);
649 SAL_WARN("vcl.opengl", "::ReadTexture - tx:" << maTexture
.Id() << " @ "
650 << mnWidth
<< "x" << mnHeight
<< "- unimplemented bit depth: "
655 sal_uInt16
OpenGLSalBitmap::GetBitCount() const
660 bool OpenGLSalBitmap::calcChecksumGL(OpenGLTexture
& rInputTexture
, BitmapChecksum
& rChecksum
) const
662 OUString
FragShader("areaHashCRC64TFragmentShader");
664 rtl::Reference
< OpenGLContext
> xContext
= OpenGLContext::getVCLContext();
665 xContext
->state().scissor().disable();
666 xContext
->state().stencil().disable();
668 static vcl::DeleteOnDeinit
<OpenGLTexture
> gCRCTableTexture(
669 new OpenGLTexture(512, 1, GL_RGBA
, GL_UNSIGNED_BYTE
,
670 vcl_get_crc64_table()));
671 OpenGLTexture
&rCRCTableTexture
= *gCRCTableTexture
.get();
675 int nWidth
= rInputTexture
.GetWidth();
676 int nHeight
= rInputTexture
.GetHeight();
678 OpenGLProgram
* pProgram
= xContext
->UseProgram("textureVertexShader", FragShader
);
679 if (pProgram
== nullptr)
682 int nNewWidth
= ceil( nWidth
/ 4.0 );
683 int nNewHeight
= ceil( nHeight
/ 4.0 );
685 OpenGLTexture aFirstPassTexture
= OpenGLTexture(nNewWidth
, nNewHeight
);
686 OpenGLFramebuffer
* pFramebuffer
= xContext
->AcquireFramebuffer(aFirstPassTexture
);
688 pProgram
->SetUniform1f( "xstep", 1.0 / mnWidth
);
689 pProgram
->SetUniform1f( "ystep", 1.0 / mnHeight
);
691 pProgram
->SetTexture("crc_table", rCRCTableTexture
);
692 pProgram
->SetTexture("sampler", rInputTexture
);
693 pProgram
->DrawTexture(rInputTexture
);
696 OpenGLContext::ReleaseFramebuffer(pFramebuffer
);
702 nWidth
= aFirstPassTexture
.GetWidth();
703 nHeight
= aFirstPassTexture
.GetHeight();
705 pProgram
= xContext
->UseProgram("textureVertexShader", FragShader
);
706 if (pProgram
== nullptr)
709 nNewWidth
= ceil( nWidth
/ 4.0 );
710 nNewHeight
= ceil( nHeight
/ 4.0 );
712 OpenGLTexture aSecondPassTexture
= OpenGLTexture(nNewWidth
, nNewHeight
);
713 pFramebuffer
= xContext
->AcquireFramebuffer(aSecondPassTexture
);
715 pProgram
->SetUniform1f( "xstep", 1.0 / mnWidth
);
716 pProgram
->SetUniform1f( "ystep", 1.0 / mnHeight
);
718 pProgram
->SetTexture("crc_table", rCRCTableTexture
);
719 pProgram
->SetTexture("sampler", aFirstPassTexture
);
720 pProgram
->DrawTexture(aFirstPassTexture
);
723 OpenGLContext::ReleaseFramebuffer(pFramebuffer
);
728 OpenGLTexture
& aFinalTexture
= aSecondPassTexture
;
729 std::vector
<sal_uInt8
> aBuf( aFinalTexture
.GetWidth() * aFinalTexture
.GetHeight() * 4 );
730 aFinalTexture
.Read(GL_RGBA
, GL_UNSIGNED_BYTE
, aBuf
.data());
732 BitmapChecksum nCrc
= vcl_get_checksum(0, aBuf
.data(), aBuf
.size());
738 void OpenGLSalBitmap::updateChecksum() const
743 if( (mnWidth
* mnHeight
) < (1024*768) || mnWidth
< 128 || mnHeight
< 128 )
745 SalBitmap::updateChecksum();
749 OpenGLSalBitmap
* pThis
= const_cast<OpenGLSalBitmap
*>(this);
751 OpenGLVCLContextZone aContextZone
;
752 OpenGLTexture
& rInputTexture
= GetTexture();
753 pThis
->mbChecksumValid
= calcChecksumGL(rInputTexture
, pThis
->mnChecksum
);
754 if (!pThis
->mbChecksumValid
)
755 SalBitmap::updateChecksum();
758 BitmapBuffer
* OpenGLSalBitmap::AcquireBuffer( BitmapAccessMode nMode
)
760 OpenGLVCLContextZone aContextZone
;
762 if( nMode
!= BitmapAccessMode::Info
)
764 if (!mpUserBuffer
.get())
766 if( !AllocateUserData() )
768 if( maTexture
&& !ReadTexture() )
773 // mpUserBuffer must be unique when we are doing the write access
774 if (nMode
== BitmapAccessMode::Write
&& mpUserBuffer
&& mpUserBuffer
.use_count() > 1)
776 std::shared_ptr
<sal_uInt8
> aBuffer(mpUserBuffer
);
778 mpUserBuffer
.reset();
780 memcpy(mpUserBuffer
.get(), aBuffer
.get(), mnBytesPerRow
* mnHeight
);
783 BitmapBuffer
* pBuffer
= new BitmapBuffer
;
784 pBuffer
->mnWidth
= mnWidth
;
785 pBuffer
->mnHeight
= mnHeight
;
786 pBuffer
->maPalette
= maPalette
;
787 pBuffer
->mnScanlineSize
= mnBytesPerRow
;
788 pBuffer
->mpBits
= mpUserBuffer
.get();
789 pBuffer
->mnBitCount
= mnBits
;
794 pBuffer
->mnFormat
= ScanlineFormat::N1BitMsbPal
;
797 pBuffer
->mnFormat
= ScanlineFormat::N4BitMsnPal
;
800 pBuffer
->mnFormat
= ScanlineFormat::N8BitPal
;
804 pBuffer
->mnFormat
= ScanlineFormat::N16BitTcMsbMask
;
805 ColorMaskElement
aRedMask(0x0000f800);
806 aRedMask
.CalcMaskShift();
807 ColorMaskElement
aGreenMask(0x000007e0);
808 aGreenMask
.CalcMaskShift();
809 ColorMaskElement
aBlueMask(0x0000001f);
810 aBlueMask
.CalcMaskShift();
811 pBuffer
->maColorMask
= ColorMask(aRedMask
, aGreenMask
, aBlueMask
);
816 pBuffer
->mnFormat
= ScanlineFormat::N24BitTcRgb
;
821 pBuffer
->mnFormat
= ScanlineFormat::N32BitTcRgba
;
822 ColorMaskElement
aRedMask(0xff000000);
823 aRedMask
.CalcMaskShift();
824 ColorMaskElement
aGreenMask(0x00ff0000);
825 aGreenMask
.CalcMaskShift();
826 ColorMaskElement
aBlueMask(0x0000ff00);
827 aBlueMask
.CalcMaskShift();
828 pBuffer
->maColorMask
= ColorMask(aRedMask
, aGreenMask
, aBlueMask
);
836 void OpenGLSalBitmap::ReleaseBuffer( BitmapBuffer
* pBuffer
, BitmapAccessMode nMode
)
838 OpenGLVCLContextZone aContextZone
;
840 if( nMode
== BitmapAccessMode::Write
)
842 maTexture
= OpenGLTexture();
843 mbDirtyTexture
= true;
844 mbChecksumValid
= false;
846 // The palette is modified on read during the BitmapWriteAccess,
847 // but of course, often it is not modified; interesting.
848 maPalette
= pBuffer
->maPalette
;
850 // Are there any more ground movements underneath us ?
851 assert( pBuffer
->mnWidth
== mnWidth
);
852 assert( pBuffer
->mnHeight
== mnHeight
);
853 assert( pBuffer
->mnBitCount
== mnBits
);
858 bool OpenGLSalBitmap::GetSystemData( BitmapSystemData
& /*rData*/ )
860 SAL_WARN( "vcl.opengl", "*** NOT IMPLEMENTED *** GetSystemData" );
862 // TODO Implement for ANDROID/OSX/IOS/WIN32
863 X11SalBitmap rBitmap
;
864 BitmapBuffer
* pBuffer
;
866 rBitmap
.Create( GetSize(), mnBits
, maPalette
);
867 pBuffer
= rBitmap
.AcquireBuffer( false );
868 if( pBuffer
== NULL
)
871 if (!mpUserBuffer
.get())
873 if( !AllocateUserData() || !ReadTexture() )
875 rBitmap
.ReleaseBuffer( pBuffer
, false );
880 // TODO Might be more efficient to add a static method to SalBitmap
881 // to get system data from a buffer
882 memcpy( pBuffer
->mpBits
, mpUserBuffer
.get(), mnBytesPerRow
* mnHeight
);
884 rBitmap
.ReleaseBuffer( pBuffer
, false );
885 return rBitmap
.GetSystemData( rData
);
891 bool OpenGLSalBitmap::Replace( const Color
& rSearchColor
, const Color
& rReplaceColor
, sal_uInt8 nTol
)
893 VCL_GL_INFO("::Replace");
896 rtl::Reference
<OpenGLContext
> xContext
= OpenGLContext::getVCLContext();
897 xContext
->state().scissor().disable();
898 xContext
->state().stencil().disable();
900 OpenGLFramebuffer
* pFramebuffer
;
901 OpenGLProgram
* pProgram
;
904 pProgram
= xContext
->UseProgram( "textureVertexShader",
905 "replaceColorFragmentShader" );
909 OpenGLTexture aNewTex
= OpenGLTexture( mnWidth
, mnHeight
);
910 pFramebuffer
= xContext
->AcquireFramebuffer( aNewTex
);
912 pProgram
->SetTexture( "sampler", maTexture
);
913 pProgram
->SetColor( "search_color", rSearchColor
);
914 pProgram
->SetColor( "replace_color", rReplaceColor
);
915 pProgram
->SetUniform1f( "epsilon", nTol
/ 255.0f
);
916 pProgram
->DrawTexture( maTexture
);
919 OpenGLContext::ReleaseFramebuffer( pFramebuffer
);
926 // Convert texture to greyscale and adjust bitmap metadata
927 bool OpenGLSalBitmap::ConvertToGreyscale()
929 VCL_GL_INFO("::ConvertToGreyscale");
931 // avoid re-converting to 8bits.
932 if ( mnBits
== 8 && maPalette
== Bitmap::GetGreyPalette(256) )
936 rtl::Reference
<OpenGLContext
> xContext
= OpenGLContext::getVCLContext();
937 xContext
->state().scissor().disable();
938 xContext
->state().stencil().disable();
940 OpenGLFramebuffer
* pFramebuffer
;
941 OpenGLProgram
* pProgram
;
944 pProgram
= xContext
->UseProgram("textureVertexShader", "greyscaleFragmentShader");
949 OpenGLTexture
aNewTex(mnWidth
, mnHeight
);
950 pFramebuffer
= xContext
->AcquireFramebuffer(aNewTex
);
951 pProgram
->SetTexture("sampler", maTexture
);
952 pProgram
->DrawTexture(maTexture
);
955 OpenGLContext::ReleaseFramebuffer( pFramebuffer
);
958 maPalette
= Bitmap::GetGreyPalette(256);
960 // AllocateUserData will handle the rest.
961 mpUserBuffer
.reset();
962 mbDirtyTexture
= false;
968 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */