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_uInt16
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 static const BitmapPalette aEmptyPalette
;
121 OpenGLVCLContextZone aContextZone
;
124 VCL_GL_INFO( "OpenGLSalBitmap::Create from FBO: ["
125 << nX
<< ", " << nY
<< "] " << nWidth
<< "x" << nHeight
);
127 GLint nMaxTextureSize
;
128 glGetIntegerv( GL_MAX_TEXTURE_SIZE
, &nMaxTextureSize
);
129 if ( nWidth
> nMaxTextureSize
)
131 nWidth
= nMaxTextureSize
;
132 VCL_GL_INFO( "Width limited to " << nMaxTextureSize
);
135 if ( nHeight
> nMaxTextureSize
)
137 nHeight
= nMaxTextureSize
;
138 VCL_GL_INFO( "Height limited to " << nMaxTextureSize
);
144 // TODO Check the framebuffer configuration
146 maPalette
= aEmptyPalette
;
149 maTexture
= OpenGLTexture( rTex
, nX
, nY
, nWidth
, nHeight
);
151 maTexture
= OpenGLTexture( nX
, nY
, nWidth
, nHeight
);
152 mbDirtyTexture
= false;
153 VCL_GL_INFO( "Created texture " << maTexture
.Id() );
155 assert(mnWidth
== maTexture
.GetWidth() &&
156 mnHeight
== maTexture
.GetHeight());
161 bool OpenGLSalBitmap::Create( const Size
& rSize
, sal_uInt16 nBits
, const BitmapPalette
& rBitmapPalette
)
163 OpenGLVCLContextZone aContextZone
;
166 VCL_GL_INFO( "OpenGLSalBitmap::Create with size: " << rSize
);
168 if( !isValidBitCount( nBits
) )
170 maPalette
= rBitmapPalette
;
172 mnWidth
= rSize
.Width();
173 mnHeight
= rSize
.Height();
177 bool OpenGLSalBitmap::Create( const SalBitmap
& rSalBmp
)
179 return Create( rSalBmp
, rSalBmp
.GetBitCount() );
182 bool OpenGLSalBitmap::Create( const SalBitmap
& rSalBmp
, SalGraphics
* pGraphics
)
184 return Create( rSalBmp
, pGraphics
? pGraphics
->GetBitCount() : rSalBmp
.GetBitCount() );
187 bool OpenGLSalBitmap::Create( const SalBitmap
& rSalBmp
, sal_uInt16 nNewBitCount
)
191 // check that carefully only in the debug mode
192 assert(dynamic_cast<const OpenGLSalBitmap
*>(&rSalBmp
));
194 const OpenGLSalBitmap
& rSourceBitmap
= static_cast<const OpenGLSalBitmap
&>(rSalBmp
);
196 VCL_GL_INFO("OpenGLSalBitmap::Create from BMP: "
197 << rSourceBitmap
.mnWidth
<< "x" << rSourceBitmap
.mnHeight
198 << " Bits old: " << mnBits
<< " new:" << nNewBitCount
);
200 if( isValidBitCount( nNewBitCount
) )
202 // TODO: lfrb: What about the pending operations?!
203 mnBits
= nNewBitCount
;
204 mnBytesPerRow
= rSourceBitmap
.mnBytesPerRow
;
205 mnWidth
= rSourceBitmap
.mnWidth
;
206 mnHeight
= rSourceBitmap
.mnHeight
;
207 maPalette
= rSourceBitmap
.maPalette
;
208 // execute any pending operations on the source bitmap
209 maTexture
= rSourceBitmap
.GetTexture();
210 mbDirtyTexture
= false;
212 // be careful here, we are share & reference-count the
213 // mpUserBuffer, BUT this Create() is called from
214 // Bitmap::ImplMakeUnique().
215 // Consequently, there might be cases when this needs to be made
216 // unique later (when we don't do that right away here), like when
217 // using the BitmapWriteAccess.
218 mpUserBuffer
= rSourceBitmap
.mpUserBuffer
;
225 bool OpenGLSalBitmap::Create( const css::uno::Reference
< css::rendering::XBitmapCanvas
>& /*xBitmapCanvas*/, Size
& /*rSize*/, bool /*bMask*/ )
227 // TODO Is this method needed?
231 OpenGLTexture
& OpenGLSalBitmap::GetTexture() const
233 OpenGLSalBitmap
* pThis
= const_cast<OpenGLSalBitmap
*>(this);
234 if( !maTexture
|| mbDirtyTexture
)
235 pThis
->CreateTexture();
236 VCL_GL_INFO( "Got texture " << maTexture
.Id() );
237 return pThis
->maTexture
;
240 void OpenGLSalBitmap::Destroy()
244 VCL_GL_INFO("Destroy OpenGLSalBitmap texture:" << maTexture
.Id());
245 maTexture
= OpenGLTexture();
246 mpUserBuffer
.reset();
249 bool OpenGLSalBitmap::AllocateUserData()
251 VCL_GL_INFO( "OpenGLSalBitmap::AllocateUserData" );
253 if( mnWidth
&& mnHeight
)
255 mnBytesPerRow
= lclBytesPerRow(mnBits
, mnWidth
);
259 if (mnBytesPerRow
!= 0 && mnHeight
&&
260 mnBytesPerRow
<= std::numeric_limits
<sal_uInt32
>::max() / mnHeight
)
264 size_t nToAllocate
= static_cast<sal_uInt32
>(mnBytesPerRow
) * mnHeight
;
265 #if OSL_DEBUG_LEVEL > 0
266 nToAllocate
+= sizeof(CANARY
);
268 mpUserBuffer
= o3tl::make_shared_array
<sal_uInt8
>(nToAllocate
);
269 #if OSL_DEBUG_LEVEL > 0
270 memcpy(mpUserBuffer
.get() + nToAllocate
- sizeof(CANARY
),
271 CANARY
, sizeof(CANARY
));
275 catch (const std::bad_alloc
&) {}
279 SAL_WARN("vcl.opengl", "bad alloc " << mnBytesPerRow
<< "x" << mnHeight
);
280 mpUserBuffer
.reset();
286 for (size_t i
= 0; i
< size_t(mnBytesPerRow
* mnHeight
); i
++)
287 mpUserBuffer
.get()[i
] = (i
& 0xFF);
291 return mpUserBuffer
.get() != nullptr;
296 class ImplPixelFormat
301 static ImplPixelFormat
* GetFormat( sal_uInt16 nBits
, const BitmapPalette
& rPalette
);
303 virtual void StartLine( sal_uInt8
* pLine
) { mpData
= pLine
; }
304 virtual const BitmapColor
& ReadPixel() = 0;
305 virtual ~ImplPixelFormat() { }
308 class ImplPixelFormat8
: public ImplPixelFormat
311 const BitmapPalette
& mrPalette
;
314 explicit ImplPixelFormat8( const BitmapPalette
& rPalette
)
315 : mrPalette( rPalette
)
318 virtual const BitmapColor
& ReadPixel() override
320 assert( mrPalette
.GetEntryCount() > *mpData
);
321 return mrPalette
[ *mpData
++ ];
325 class ImplPixelFormat4
: public ImplPixelFormat
328 const BitmapPalette
& mrPalette
;
333 explicit ImplPixelFormat4( const BitmapPalette
& rPalette
)
334 : mrPalette( rPalette
)
339 virtual void StartLine( sal_uInt8
* pLine
) override
345 virtual const BitmapColor
& ReadPixel() override
347 sal_uInt32 nIdx
= ( mpData
[mnX
>> 1] >> mnShift
) & 0x0f;
348 assert( mrPalette
.GetEntryCount() > nIdx
);
349 const BitmapColor
& rColor
= mrPalette
[nIdx
];
356 class ImplPixelFormat1
: public ImplPixelFormat
359 const BitmapPalette
& mrPalette
;
363 explicit ImplPixelFormat1( const BitmapPalette
& rPalette
)
364 : mrPalette(rPalette
)
368 virtual void StartLine( sal_uInt8
* pLine
) override
373 virtual const BitmapColor
& ReadPixel() override
375 const BitmapColor
& rColor
= mrPalette
[ (mpData
[mnX
>> 3 ] >> ( 7 - ( mnX
& 7 ) )) & 1];
381 ImplPixelFormat
* ImplPixelFormat::GetFormat( sal_uInt16 nBits
, const BitmapPalette
& rPalette
)
385 case 1: return new ImplPixelFormat1( rPalette
);
386 case 4: return new ImplPixelFormat4( rPalette
);
387 case 8: return new ImplPixelFormat8( rPalette
);
393 void lclInstantiateTexture(OpenGLTexture
& rTexture
, const int nWidth
, const int nHeight
,
394 const GLenum nFormat
, const GLenum nType
, sal_uInt8
* pData
)
396 if (nWidth
== nHeight
)
398 TextureAtlasVector
&sTextureAtlases
= *gTextureAtlases
.get();
399 if (sTextureAtlases
.empty())
401 sTextureAtlases
.push_back(o3tl::make_unique
<FixedTextureAtlasManager
>(8, 8, 16));
402 sTextureAtlases
.push_back(o3tl::make_unique
<FixedTextureAtlasManager
>(8, 8, 24));
403 sTextureAtlases
.push_back(o3tl::make_unique
<FixedTextureAtlasManager
>(8, 8, 32));
404 sTextureAtlases
.push_back(o3tl::make_unique
<FixedTextureAtlasManager
>(8, 8, 48));
405 sTextureAtlases
.push_back(o3tl::make_unique
<FixedTextureAtlasManager
>(8, 8, 64));
407 for (std::unique_ptr
<FixedTextureAtlasManager
> & pTextureAtlas
: sTextureAtlases
)
409 if (nWidth
== pTextureAtlas
->GetSubtextureSize())
411 rTexture
= pTextureAtlas
->InsertBuffer(nWidth
, nHeight
, nFormat
, nType
, pData
);
416 rTexture
= OpenGLTexture (nWidth
, nHeight
, nFormat
, nType
, pData
);
419 // Write color information for 1 and 4 bit palette bitmap scanlines.
422 BitmapPalette
& maPalette
;
423 sal_uInt8 mnColorsPerByte
; // number of colors that are stored in one byte
424 sal_uInt8 mnColorBitSize
; // number of bits a color takes
425 sal_uInt8 mnColorBitMask
; // bit mask used to isolate the color
426 sal_uInt8
* mpCurrentScanline
;
430 ScanlineWriter(BitmapPalette
& aPalette
, sal_Int8 nColorsPerByte
)
431 : maPalette(aPalette
)
432 , mnColorsPerByte(nColorsPerByte
)
433 , 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)
434 , mnColorBitMask((1 << mnColorBitSize
) - 1) // calculate the bit mask from the bit size
435 , mpCurrentScanline(nullptr)
439 void writeRGB(sal_uInt8 nR
, sal_uInt8 nG
, sal_uInt8 nB
)
441 // calculate to which index we will write
442 long nScanlineIndex
= mnX
/ mnColorsPerByte
;
444 // calculate the number of shifts to get the color information to the right place
445 long nShift
= (8 - mnColorBitSize
) - ((mnX
% mnColorsPerByte
) * mnColorBitSize
);
447 sal_uInt16 nColorIndex
= maPalette
.GetBestIndex(BitmapColor(nR
, nG
, nB
));
448 mpCurrentScanline
[nScanlineIndex
] &= ~(mnColorBitMask
<< nShift
); // clear
449 mpCurrentScanline
[nScanlineIndex
] |= (nColorIndex
& mnColorBitMask
) << nShift
; // set
453 void nextLine(sal_uInt8
* pScanline
)
456 mpCurrentScanline
= pScanline
;
460 } // end anonymous namespace
462 Size
OpenGLSalBitmap::GetSize() const
464 return Size(mnWidth
, mnHeight
);
467 GLuint
OpenGLSalBitmap::CreateTexture()
469 VCL_GL_INFO( "::CreateTexture bits: " << mnBits
);
470 GLenum nFormat
= GL_RGBA
;
471 GLenum nType
= GL_UNSIGNED_BYTE
;
472 sal_uInt8
* pData( nullptr );
473 bool bAllocated( false );
475 if (mpUserBuffer
.get() != nullptr)
477 if( mnBits
== 16 || mnBits
== 24 || mnBits
== 32 )
479 // no conversion needed for truecolor
480 pData
= mpUserBuffer
.get();
482 determineTextureFormat(mnBits
, nFormat
, nType
);
484 else if( mnBits
== 8 && maPalette
.IsGreyPalette() )
486 // no conversion needed for grayscale
487 pData
= mpUserBuffer
.get();
488 nFormat
= GL_LUMINANCE
;
489 nType
= GL_UNSIGNED_BYTE
;
493 VCL_GL_INFO( "::CreateTexture - convert from " << mnBits
<< " to 24 bits" );
495 // convert to 24 bits RGB using palette
496 pData
= new sal_uInt8
[mnHeight
* mnWidth
* 3];
498 determineTextureFormat(24, nFormat
, nType
);
500 std::unique_ptr
<ImplPixelFormat
> pSrcFormat(ImplPixelFormat::GetFormat(mnBits
, maPalette
));
502 sal_uInt8
* pSrcData
= mpUserBuffer
.get();
503 sal_uInt8
* pDstData
= pData
;
505 sal_uInt32 nY
= mnHeight
;
508 pSrcFormat
->StartLine( pSrcData
);
510 sal_uInt32 nX
= mnWidth
;
511 if (nFormat
== GL_BGR
)
515 const BitmapColor
& c
= pSrcFormat
->ReadPixel();
516 *pDstData
++ = c
.GetBlue();
517 *pDstData
++ = c
.GetGreen();
518 *pDstData
++ = c
.GetRed();
525 const BitmapColor
& c
= pSrcFormat
->ReadPixel();
526 *pDstData
++ = c
.GetRed();
527 *pDstData
++ = c
.GetGreen();
528 *pDstData
++ = c
.GetBlue();
532 pSrcData
+= mnBytesPerRow
;
537 OpenGLVCLContextZone aContextZone
;
539 lclInstantiateTexture(maTexture
, mnWidth
, mnHeight
, nFormat
, nType
, pData
);
541 VCL_GL_INFO("Created texture " << maTexture
.Id() << " bits: " << mnBits
);
546 mbDirtyTexture
= false;
549 return maTexture
.Id();
552 bool OpenGLSalBitmap::ReadTexture()
554 sal_uInt8
* pData
= mpUserBuffer
.get();
556 GLenum nFormat
= GL_RGBA
;
557 GLenum nType
= GL_UNSIGNED_BYTE
;
559 VCL_GL_INFO( "::ReadTexture " << mnWidth
<< "x" << mnHeight
<< " bits: " << mnBits
);
561 if( pData
== nullptr )
564 OpenGLVCLContextZone aContextZone
;
566 rtl::Reference
<OpenGLContext
> xContext
= OpenGLContext::getVCLContext();
567 xContext
->state().scissor().disable();
568 xContext
->state().stencil().disable();
570 if (mnBits
== 8 || mnBits
== 16 || mnBits
== 24 || mnBits
== 32)
572 determineTextureFormat(mnBits
, nFormat
, nType
);
574 #if OSL_DEBUG_LEVEL > 0
575 // help valgrind & drmemory rescue us - touch last and first bits.
577 pData
[mnBits
/8*mnWidth
*mnHeight
-1] = 0;
578 // if this fails we can read too much into pData
579 assert(mnWidth
== maTexture
.GetWidth() &&
580 mnHeight
== maTexture
.GetHeight());
583 maTexture
.Read(nFormat
, nType
, pData
);
585 #if OSL_DEBUG_LEVEL > 0
586 // If we read over the end of pData we have a real hidden memory
587 // corruption problem !
588 size_t nCanary
= static_cast<sal_uInt32
>(mnBytesPerRow
) * mnHeight
;
589 assert(!memcmp(pData
+ nCanary
, CANARY
, sizeof (CANARY
)));
593 else if (mnBits
== 1 || mnBits
== 4)
594 { // convert buffers from 24-bit RGB to 1 or 4-bit buffer
595 std::vector
<sal_uInt8
> aBuffer(mnWidth
* mnHeight
* 3);
597 sal_uInt8
* pBuffer
= aBuffer
.data();
598 determineTextureFormat(24, nFormat
, nType
);
599 maTexture
.Read(nFormat
, nType
, pBuffer
);
600 sal_uInt16 nSourceBytesPerRow
= lclBytesPerRow(24, mnWidth
);
602 std::unique_ptr
<ScanlineWriter
> pWriter
;
606 pWriter
.reset(new ScanlineWriter(maPalette
, 8));
610 pWriter
.reset(new ScanlineWriter(maPalette
, 2));
614 for (int y
= 0; y
< mnHeight
; ++y
)
616 sal_uInt8
* pSource
= &pBuffer
[y
* nSourceBytesPerRow
];
617 sal_uInt8
* pDestination
= &pData
[y
* mnBytesPerRow
];
619 pWriter
->nextLine(pDestination
);
621 for (int x
= 0; x
< mnWidth
; ++x
)
624 sal_uInt8 nR
= *pSource
++;
625 sal_uInt8 nG
= *pSource
++;
626 sal_uInt8 nB
= *pSource
++;
628 pWriter
->writeRGB(nR
, nG
, nB
);
634 SAL_WARN("vcl.opengl", "::ReadTexture - tx:" << maTexture
.Id() << " @ "
635 << mnWidth
<< "x" << mnHeight
<< "- unimplemented bit depth: "
640 sal_uInt16
OpenGLSalBitmap::GetBitCount() const
645 bool OpenGLSalBitmap::calcChecksumGL(OpenGLTexture
& rInputTexture
, ChecksumType
& rChecksum
) const
647 OUString
FragShader("areaHashCRC64TFragmentShader");
649 rtl::Reference
< OpenGLContext
> xContext
= OpenGLContext::getVCLContext();
650 xContext
->state().scissor().disable();
651 xContext
->state().stencil().disable();
653 static vcl::DeleteOnDeinit
<OpenGLTexture
> gCRCTableTexture(
654 new OpenGLTexture(512, 1, GL_RGBA
, GL_UNSIGNED_BYTE
,
655 vcl_get_crc64_table()));
656 OpenGLTexture
&rCRCTableTexture
= *gCRCTableTexture
.get();
660 int nWidth
= rInputTexture
.GetWidth();
661 int nHeight
= rInputTexture
.GetHeight();
663 OpenGLProgram
* pProgram
= xContext
->UseProgram("textureVertexShader", FragShader
);
664 if (pProgram
== nullptr)
667 int nNewWidth
= ceil( nWidth
/ 4.0 );
668 int nNewHeight
= ceil( nHeight
/ 4.0 );
670 OpenGLTexture aFirstPassTexture
= OpenGLTexture(nNewWidth
, nNewHeight
);
671 OpenGLFramebuffer
* pFramebuffer
= xContext
->AcquireFramebuffer(aFirstPassTexture
);
673 pProgram
->SetUniform1f( "xstep", 1.0 / mnWidth
);
674 pProgram
->SetUniform1f( "ystep", 1.0 / mnHeight
);
676 pProgram
->SetTexture("crc_table", rCRCTableTexture
);
677 pProgram
->SetTexture("sampler", rInputTexture
);
678 pProgram
->DrawTexture(rInputTexture
);
681 OpenGLContext::ReleaseFramebuffer(pFramebuffer
);
687 nWidth
= aFirstPassTexture
.GetWidth();
688 nHeight
= aFirstPassTexture
.GetHeight();
690 pProgram
= xContext
->UseProgram("textureVertexShader", FragShader
);
691 if (pProgram
== nullptr)
694 nNewWidth
= ceil( nWidth
/ 4.0 );
695 nNewHeight
= ceil( nHeight
/ 4.0 );
697 OpenGLTexture aSecondPassTexture
= OpenGLTexture(nNewWidth
, nNewHeight
);
698 pFramebuffer
= xContext
->AcquireFramebuffer(aSecondPassTexture
);
700 pProgram
->SetUniform1f( "xstep", 1.0 / mnWidth
);
701 pProgram
->SetUniform1f( "ystep", 1.0 / mnHeight
);
703 pProgram
->SetTexture("crc_table", rCRCTableTexture
);
704 pProgram
->SetTexture("sampler", aFirstPassTexture
);
705 pProgram
->DrawTexture(aFirstPassTexture
);
708 OpenGLContext::ReleaseFramebuffer(pFramebuffer
);
713 OpenGLTexture
& aFinalTexture
= aSecondPassTexture
;
714 std::vector
<sal_uInt8
> aBuf( aFinalTexture
.GetWidth() * aFinalTexture
.GetHeight() * 4 );
715 aFinalTexture
.Read(GL_RGBA
, GL_UNSIGNED_BYTE
, aBuf
.data());
717 ChecksumType nCrc
= vcl_get_checksum(0, aBuf
.data(), aBuf
.size());
723 void OpenGLSalBitmap::updateChecksum() const
728 if( (mnWidth
* mnHeight
) < (1024*768) || mnWidth
< 128 || mnHeight
< 128 )
730 SalBitmap::updateChecksum();
734 OpenGLSalBitmap
* pThis
= const_cast<OpenGLSalBitmap
*>(this);
736 OpenGLVCLContextZone aContextZone
;
737 OpenGLTexture
& rInputTexture
= GetTexture();
738 pThis
->mbChecksumValid
= calcChecksumGL(rInputTexture
, pThis
->mnChecksum
);
739 if (!pThis
->mbChecksumValid
)
740 SalBitmap::updateChecksum();
743 BitmapBuffer
* OpenGLSalBitmap::AcquireBuffer( BitmapAccessMode nMode
)
745 OpenGLVCLContextZone aContextZone
;
747 if( nMode
!= BitmapAccessMode::Info
)
749 if (!mpUserBuffer
.get())
751 if( !AllocateUserData() )
753 if( maTexture
&& !ReadTexture() )
758 // mpUserBuffer must be unique when we are doing the write access
759 if (nMode
== BitmapAccessMode::Write
&& mpUserBuffer
&& !mpUserBuffer
.unique())
761 std::shared_ptr
<sal_uInt8
> aBuffer(mpUserBuffer
);
763 mpUserBuffer
.reset();
765 memcpy(mpUserBuffer
.get(), aBuffer
.get(), static_cast<sal_uInt32
>(mnBytesPerRow
) * mnHeight
);
768 BitmapBuffer
* pBuffer
= new BitmapBuffer
;
769 pBuffer
->mnWidth
= mnWidth
;
770 pBuffer
->mnHeight
= mnHeight
;
771 pBuffer
->maPalette
= maPalette
;
772 pBuffer
->mnScanlineSize
= mnBytesPerRow
;
773 pBuffer
->mpBits
= mpUserBuffer
.get();
774 pBuffer
->mnBitCount
= mnBits
;
779 pBuffer
->mnFormat
= ScanlineFormat::N1BitMsbPal
;
782 pBuffer
->mnFormat
= ScanlineFormat::N4BitMsnPal
;
785 pBuffer
->mnFormat
= ScanlineFormat::N8BitPal
;
789 pBuffer
->mnFormat
= ScanlineFormat::N16BitTcMsbMask
;
790 ColorMaskElement
aRedMask(0x0000f800);
791 aRedMask
.CalcMaskShift();
792 ColorMaskElement
aGreenMask(0x000007e0);
793 aGreenMask
.CalcMaskShift();
794 ColorMaskElement
aBlueMask(0x0000001f);
795 aBlueMask
.CalcMaskShift();
796 pBuffer
->maColorMask
= ColorMask(aRedMask
, aGreenMask
, aBlueMask
);
801 pBuffer
->mnFormat
= ScanlineFormat::N24BitTcRgb
;
806 pBuffer
->mnFormat
= ScanlineFormat::N32BitTcRgba
;
807 ColorMaskElement
aRedMask(0xff000000);
808 aRedMask
.CalcMaskShift();
809 ColorMaskElement
aGreenMask(0x00ff0000);
810 aGreenMask
.CalcMaskShift();
811 ColorMaskElement
aBlueMask(0x0000ff00);
812 aBlueMask
.CalcMaskShift();
813 pBuffer
->maColorMask
= ColorMask(aRedMask
, aGreenMask
, aBlueMask
);
821 void OpenGLSalBitmap::ReleaseBuffer( BitmapBuffer
* pBuffer
, BitmapAccessMode nMode
)
823 OpenGLVCLContextZone aContextZone
;
825 if( nMode
== BitmapAccessMode::Write
)
827 maTexture
= OpenGLTexture();
828 mbDirtyTexture
= true;
829 mbChecksumValid
= false;
831 // The palette is modified on read during the BitmapWriteAccess,
832 // but of course, often it is not modified; interesting.
833 maPalette
= pBuffer
->maPalette
;
835 // Are there any more ground movements underneath us ?
836 assert( pBuffer
->mnWidth
== mnWidth
);
837 assert( pBuffer
->mnHeight
== mnHeight
);
838 assert( pBuffer
->mnBitCount
== mnBits
);
843 bool OpenGLSalBitmap::GetSystemData( BitmapSystemData
& /*rData*/ )
845 SAL_WARN( "vcl.opengl", "*** NOT IMPLEMENTED *** GetSystemData" );
847 // TODO Implement for ANDROID/OSX/IOS/WIN32
848 X11SalBitmap rBitmap
;
849 BitmapBuffer
* pBuffer
;
851 rBitmap
.Create( GetSize(), mnBits
, maPalette
);
852 pBuffer
= rBitmap
.AcquireBuffer( false );
853 if( pBuffer
== NULL
)
856 if (!mpUserBuffer
.get())
858 if( !AllocateUserData() || !ReadTexture() )
860 rBitmap
.ReleaseBuffer( pBuffer
, false );
865 // TODO Might be more efficient to add a static method to SalBitmap
866 // to get system data from a buffer
867 memcpy( pBuffer
->mpBits
, mpUserBuffer
.get(), mnBytesPerRow
* mnHeight
);
869 rBitmap
.ReleaseBuffer( pBuffer
, false );
870 return rBitmap
.GetSystemData( rData
);
876 bool OpenGLSalBitmap::Replace( const Color
& rSearchColor
, const Color
& rReplaceColor
, sal_uLong nTol
)
878 VCL_GL_INFO("::Replace");
881 rtl::Reference
<OpenGLContext
> xContext
= OpenGLContext::getVCLContext();
882 xContext
->state().scissor().disable();
883 xContext
->state().stencil().disable();
885 OpenGLFramebuffer
* pFramebuffer
;
886 OpenGLProgram
* pProgram
;
889 pProgram
= xContext
->UseProgram( "textureVertexShader",
890 "replaceColorFragmentShader" );
894 OpenGLTexture aNewTex
= OpenGLTexture( mnWidth
, mnHeight
);
895 pFramebuffer
= xContext
->AcquireFramebuffer( aNewTex
);
897 pProgram
->SetTexture( "sampler", maTexture
);
898 pProgram
->SetColor( "search_color", rSearchColor
);
899 pProgram
->SetColor( "replace_color", rReplaceColor
);
900 pProgram
->SetUniform1f( "epsilon", nTol
/ 255.0f
);
901 pProgram
->DrawTexture( maTexture
);
904 OpenGLContext::ReleaseFramebuffer( pFramebuffer
);
911 // Convert texture to greyscale and adjust bitmap metadata
912 bool OpenGLSalBitmap::ConvertToGreyscale()
914 VCL_GL_INFO("::ConvertToGreyscale");
916 // avoid re-converting to 8bits.
917 if ( mnBits
== 8 && maPalette
== Bitmap::GetGreyPalette(256) )
921 rtl::Reference
<OpenGLContext
> xContext
= OpenGLContext::getVCLContext();
922 xContext
->state().scissor().disable();
923 xContext
->state().stencil().disable();
925 OpenGLFramebuffer
* pFramebuffer
;
926 OpenGLProgram
* pProgram
;
929 pProgram
= xContext
->UseProgram("textureVertexShader", "greyscaleFragmentShader");
934 OpenGLTexture
aNewTex(mnWidth
, mnHeight
);
935 pFramebuffer
= xContext
->AcquireFramebuffer(aNewTex
);
936 pProgram
->SetTexture("sampler", maTexture
);
937 pProgram
->DrawTexture(maTexture
);
940 OpenGLContext::ReleaseFramebuffer( pFramebuffer
);
943 maPalette
= Bitmap::GetGreyPalette(256);
945 // AllocateUserData will handle the rest.
946 mpUserBuffer
.reset();
947 mbDirtyTexture
= false;
953 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */