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 .
20 #include <sal/config.h>
22 #include <vcl/opengl/OpenGLHelper.hxx>
24 #include <vcl/bitmap.hxx>
25 #include <vcl/checksum.hxx>
26 #include <vcl/outdev.hxx>
27 #include <vcl/salbtype.hxx>
30 #include "vcleventlisteners.hxx"
31 #include <vcl/lazydelete.hxx>
33 #include <o3tl/make_unique.hxx>
34 #include <o3tl/make_shared.hxx>
36 #include "opengl/zone.hxx"
37 #include "opengl/program.hxx"
38 #include "opengl/salbmp.hxx"
39 #include "opengl/RenderState.hxx"
40 #include "opengl/FixedTextureAtlas.hxx"
42 #if OSL_DEBUG_LEVEL > 0
43 # define CANARY "tex-canary"
49 inline bool determineTextureFormat(sal_uInt16 nBits
, GLenum
& nFormat
, GLenum
& nType
)
54 nFormat
= GL_LUMINANCE
;
55 nType
= GL_UNSIGNED_BYTE
;
63 nType
= GL_UNSIGNED_SHORT_5_6_5
;
71 nType
= GL_UNSIGNED_BYTE
;
79 nType
= GL_UNSIGNED_BYTE
;
87 inline bool isValidBitCount( sal_uInt16 nBitCount
)
89 return (nBitCount
== 1) || (nBitCount
== 4) || (nBitCount
== 8) || (nBitCount
== 16) || (nBitCount
== 24) || (nBitCount
== 32);
92 sal_uInt16
lclBytesPerRow(sal_uInt16 nBits
, int nWidth
)
96 case 1: return (nWidth
+ 7) >> 3;
97 case 4: return (nWidth
+ 1) >> 1;
98 case 8: return nWidth
;
99 case 16: return nWidth
* 2;
100 case 24: return nWidth
* 3;
101 case 32: return nWidth
* 4;
103 OSL_FAIL("vcl::OpenGLSalBitmap::AllocateUserData(), illegal bitcount!");
108 typedef std::vector
<std::unique_ptr
< FixedTextureAtlasManager
> > TextureAtlasVector
;
109 static vcl::DeleteOnDeinit
< TextureAtlasVector
> gTextureAtlases(new TextureAtlasVector());
113 OpenGLSalBitmap::OpenGLSalBitmap()
114 : mbDirtyTexture(true)
122 OpenGLSalBitmap::~OpenGLSalBitmap()
125 VCL_GL_INFO( "~OpenGLSalBitmap" );
128 bool OpenGLSalBitmap::Create( const OpenGLTexture
& rTex
, long nX
, long nY
, long nWidth
, long nHeight
)
130 static const BitmapPalette aEmptyPalette
;
131 OpenGLVCLContextZone aContextZone
;
134 VCL_GL_INFO( "OpenGLSalBitmap::Create from FBO: ["
135 << nX
<< ", " << nY
<< "] " << nWidth
<< "x" << nHeight
);
140 // TODO Check the framebuffer configuration
142 maPalette
= aEmptyPalette
;
145 maTexture
= OpenGLTexture( rTex
, nX
, nY
, nWidth
, nHeight
);
147 maTexture
= OpenGLTexture( nX
, nY
, nWidth
, nHeight
);
148 mbDirtyTexture
= false;
149 VCL_GL_INFO( "Created texture " << maTexture
.Id() );
151 assert(mnWidth
== maTexture
.GetWidth() &&
152 mnHeight
== maTexture
.GetHeight());
157 bool OpenGLSalBitmap::Create( const Size
& rSize
, sal_uInt16 nBits
, const BitmapPalette
& rBitmapPalette
)
159 OpenGLVCLContextZone aContextZone
;
162 VCL_GL_INFO( "OpenGLSalBitmap::Create with size: " << rSize
);
164 if( !isValidBitCount( nBits
) )
166 maPalette
= rBitmapPalette
;
168 mnWidth
= rSize
.Width();
169 mnHeight
= rSize
.Height();
173 bool OpenGLSalBitmap::Create( const SalBitmap
& rSalBmp
)
175 return Create( rSalBmp
, rSalBmp
.GetBitCount() );
178 bool OpenGLSalBitmap::Create( const SalBitmap
& rSalBmp
, SalGraphics
* pGraphics
)
180 return Create( rSalBmp
, pGraphics
? pGraphics
->GetBitCount() : rSalBmp
.GetBitCount() );
183 bool OpenGLSalBitmap::Create( const SalBitmap
& rSalBmp
, sal_uInt16 nNewBitCount
)
187 // check that carefully only in the debug mode
188 assert(dynamic_cast<const OpenGLSalBitmap
*>(&rSalBmp
));
190 const OpenGLSalBitmap
& rSourceBitmap
= static_cast<const OpenGLSalBitmap
&>(rSalBmp
);
192 VCL_GL_INFO("OpenGLSalBitmap::Create from BMP: "
193 << rSourceBitmap
.mnWidth
<< "x" << rSourceBitmap
.mnHeight
194 << " Bits old: " << mnBits
<< " new:" << nNewBitCount
);
196 if( isValidBitCount( nNewBitCount
) )
198 // TODO: lfrb: What about the pending operations?!
199 mnBits
= nNewBitCount
;
200 mnBytesPerRow
= rSourceBitmap
.mnBytesPerRow
;
201 mnWidth
= rSourceBitmap
.mnWidth
;
202 mnHeight
= rSourceBitmap
.mnHeight
;
203 maPalette
= rSourceBitmap
.maPalette
;
204 // execute any pending operations on the source bitmap
205 maTexture
= rSourceBitmap
.GetTexture();
206 mbDirtyTexture
= false;
208 // be careful here, we are share & reference-count the
209 // mpUserBuffer, BUT this Create() is called from
210 // Bitmap::ImplMakeUnique().
211 // Consequently, there might be cases when this needs to be made
212 // unique later (when we don't do that right away here), like when
213 // using the BitmapWriteAccess.
214 mpUserBuffer
= rSourceBitmap
.mpUserBuffer
;
221 bool OpenGLSalBitmap::Create( const css::uno::Reference
< css::rendering::XBitmapCanvas
>& /*xBitmapCanvas*/, Size
& /*rSize*/, bool /*bMask*/ )
223 // TODO Is this method needed?
227 OpenGLTexture
& OpenGLSalBitmap::GetTexture() const
229 OpenGLSalBitmap
* pThis
= const_cast<OpenGLSalBitmap
*>(this);
230 if( !maTexture
|| mbDirtyTexture
)
231 pThis
->CreateTexture();
232 else if( !maPendingOps
.empty() )
233 pThis
->ExecuteOperations();
234 VCL_GL_INFO( "Got texture " << maTexture
.Id() );
235 return pThis
->maTexture
;
238 void OpenGLSalBitmap::Destroy()
242 VCL_GL_INFO("Destroy OpenGLSalBitmap texture:" << maTexture
.Id());
243 maPendingOps
.clear();
244 maTexture
= OpenGLTexture();
245 mpUserBuffer
.reset();
248 bool OpenGLSalBitmap::AllocateUserData()
250 VCL_GL_INFO( "OpenGLSalBitmap::AllocateUserData" );
252 if( mnWidth
&& mnHeight
)
254 mnBytesPerRow
= lclBytesPerRow(mnBits
, mnWidth
);
258 if (mnBytesPerRow
!= 0 && mnHeight
&&
259 mnBytesPerRow
<= std::numeric_limits
<sal_uInt32
>::max() / mnHeight
)
263 size_t nToAllocate
= static_cast<sal_uInt32
>(mnBytesPerRow
) * mnHeight
;
264 #if OSL_DEBUG_LEVEL > 0
265 nToAllocate
+= sizeof(CANARY
);
267 mpUserBuffer
= o3tl::make_shared_array
<sal_uInt8
>(nToAllocate
);
268 #if OSL_DEBUG_LEVEL > 0
269 memcpy(mpUserBuffer
.get() + nToAllocate
- sizeof(CANARY
),
270 CANARY
, sizeof(CANARY
));
274 catch (const std::bad_alloc
&) {}
278 SAL_WARN("vcl.opengl", "bad alloc " << mnBytesPerRow
<< "x" << mnHeight
);
279 mpUserBuffer
.reset();
285 for (size_t i
= 0; i
< size_t(mnBytesPerRow
* mnHeight
); i
++)
286 mpUserBuffer
.get()[i
] = (i
& 0xFF);
290 return mpUserBuffer
.get() != nullptr;
295 class ImplPixelFormat
300 static ImplPixelFormat
* GetFormat( sal_uInt16 nBits
, const BitmapPalette
& rPalette
);
302 virtual void StartLine( sal_uInt8
* pLine
) { mpData
= pLine
; }
303 virtual const BitmapColor
& ReadPixel() = 0;
304 virtual ~ImplPixelFormat() { }
307 class ImplPixelFormat8
: public ImplPixelFormat
310 const BitmapPalette
& mrPalette
;
313 explicit ImplPixelFormat8( const BitmapPalette
& rPalette
)
314 : mrPalette( rPalette
)
317 virtual const BitmapColor
& ReadPixel() override
319 assert( mrPalette
.GetEntryCount() > *mpData
);
320 return mrPalette
[ *mpData
++ ];
324 class ImplPixelFormat4
: public ImplPixelFormat
327 const BitmapPalette
& mrPalette
;
332 explicit ImplPixelFormat4( const BitmapPalette
& rPalette
)
333 : mrPalette( rPalette
)
338 virtual void StartLine( sal_uInt8
* pLine
) override
344 virtual const BitmapColor
& ReadPixel() override
346 sal_uInt32 nIdx
= ( mpData
[mnX
>> 1] >> mnShift
) & 0x0f;
347 assert( mrPalette
.GetEntryCount() > nIdx
);
348 const BitmapColor
& rColor
= mrPalette
[nIdx
];
355 class ImplPixelFormat1
: public ImplPixelFormat
358 const BitmapPalette
& mrPalette
;
362 explicit ImplPixelFormat1( const BitmapPalette
& rPalette
)
363 : mrPalette(rPalette
)
367 virtual void StartLine( sal_uInt8
* pLine
) override
372 virtual const BitmapColor
& ReadPixel() override
374 const BitmapColor
& rColor
= mrPalette
[ (mpData
[mnX
>> 3 ] >> ( 7 - ( mnX
& 7 ) )) & 1];
380 ImplPixelFormat
* ImplPixelFormat::GetFormat( sal_uInt16 nBits
, const BitmapPalette
& rPalette
)
384 case 1: return new ImplPixelFormat1( rPalette
);
385 case 4: return new ImplPixelFormat4( rPalette
);
386 case 8: return new ImplPixelFormat8( rPalette
);
392 void lclInstantiateTexture(OpenGLTexture
& rTexture
, const int nWidth
, const int nHeight
,
393 const GLenum nFormat
, const GLenum nType
, sal_uInt8
* pData
)
395 if (nWidth
== nHeight
)
397 TextureAtlasVector
&sTextureAtlases
= *gTextureAtlases
.get();
398 if (sTextureAtlases
.empty())
400 sTextureAtlases
.push_back(o3tl::make_unique
<FixedTextureAtlasManager
>(8, 8, 16));
401 sTextureAtlases
.push_back(o3tl::make_unique
<FixedTextureAtlasManager
>(8, 8, 24));
402 sTextureAtlases
.push_back(o3tl::make_unique
<FixedTextureAtlasManager
>(8, 8, 32));
403 sTextureAtlases
.push_back(o3tl::make_unique
<FixedTextureAtlasManager
>(8, 8, 48));
404 sTextureAtlases
.push_back(o3tl::make_unique
<FixedTextureAtlasManager
>(8, 8, 64));
406 for (std::unique_ptr
<FixedTextureAtlasManager
> & pTextureAtlas
: sTextureAtlases
)
408 if (nWidth
== pTextureAtlas
->GetSubtextureSize())
410 rTexture
= pTextureAtlas
->InsertBuffer(nWidth
, nHeight
, nFormat
, nType
, pData
);
415 rTexture
= OpenGLTexture (nWidth
, nHeight
, nFormat
, nType
, pData
);
420 Size
OpenGLSalBitmap::GetSize() const
424 std::deque
< OpenGLSalBitmapOp
* >::const_iterator it
= maPendingOps
.begin();
425 Size
aSize( mnWidth
, mnHeight
);
427 while( it
!= maPendingOps
.end() )
428 (*it
++)->GetSize( aSize
);
433 void OpenGLSalBitmap::ExecuteOperations()
435 while( !maPendingOps
.empty() )
437 OpenGLSalBitmapOp
* pOp
= maPendingOps
.front();
439 maPendingOps
.pop_front();
443 GLuint
OpenGLSalBitmap::CreateTexture()
445 VCL_GL_INFO( "::CreateTexture bits: " << mnBits
);
446 GLenum nFormat
= GL_RGBA
;
447 GLenum nType
= GL_UNSIGNED_BYTE
;
448 sal_uInt8
* pData( nullptr );
449 bool bAllocated( false );
451 if (mpUserBuffer
.get() != nullptr)
453 if( mnBits
== 16 || mnBits
== 24 || mnBits
== 32 )
455 // no conversion needed for truecolor
456 pData
= mpUserBuffer
.get();
458 determineTextureFormat(mnBits
, nFormat
, nType
);
460 else if( mnBits
== 8 && maPalette
.IsGreyPalette() )
462 // no conversion needed for grayscale
463 pData
= mpUserBuffer
.get();
464 nFormat
= GL_LUMINANCE
;
465 nType
= GL_UNSIGNED_BYTE
;
469 VCL_GL_INFO( "::CreateTexture - convert from " << mnBits
<< " to 24 bits" );
471 // convert to 24 bits RGB using palette
472 pData
= new sal_uInt8
[mnHeight
* mnWidth
* 3];
474 determineTextureFormat(24, nFormat
, nType
);
476 std::unique_ptr
<ImplPixelFormat
> pSrcFormat(ImplPixelFormat::GetFormat(mnBits
, maPalette
));
478 sal_uInt8
* pSrcData
= mpUserBuffer
.get();
479 sal_uInt8
* pDstData
= pData
;
481 sal_uInt32 nY
= mnHeight
;
484 pSrcFormat
->StartLine( pSrcData
);
486 sal_uInt32 nX
= mnWidth
;
487 if (nFormat
== GL_BGR
)
491 const BitmapColor
& c
= pSrcFormat
->ReadPixel();
492 *pDstData
++ = c
.GetBlue();
493 *pDstData
++ = c
.GetGreen();
494 *pDstData
++ = c
.GetRed();
501 const BitmapColor
& c
= pSrcFormat
->ReadPixel();
502 *pDstData
++ = c
.GetRed();
503 *pDstData
++ = c
.GetGreen();
504 *pDstData
++ = c
.GetBlue();
508 pSrcData
+= mnBytesPerRow
;
513 OpenGLVCLContextZone aContextZone
;
515 lclInstantiateTexture(maTexture
, mnWidth
, mnHeight
, nFormat
, nType
, pData
);
517 VCL_GL_INFO("Created texture " << maTexture
.Id() << " bits: " << mnBits
);
523 mbDirtyTexture
= false;
526 return maTexture
.Id();
529 bool OpenGLSalBitmap::ReadTexture()
531 sal_uInt8
* pData
= mpUserBuffer
.get();
533 GLenum nFormat
= GL_RGBA
;
534 GLenum nType
= GL_UNSIGNED_BYTE
;
536 VCL_GL_INFO( "::ReadTexture " << mnWidth
<< "x" << mnHeight
<< " bits: " << mnBits
);
538 if( pData
== nullptr )
541 OpenGLVCLContextZone aContextZone
;
543 rtl::Reference
<OpenGLContext
> xContext
= OpenGLContext::getVCLContext();
544 xContext
->state()->scissor().disable();
545 xContext
->state()->stencil().disable();
547 if (mnBits
== 8 || mnBits
== 16 || mnBits
== 24 || mnBits
== 32)
549 determineTextureFormat(mnBits
, nFormat
, nType
);
551 #if OSL_DEBUG_LEVEL > 0
552 // help valgrind & drmemory rescue us - touch last and first bits.
554 pData
[mnBits
/8*mnWidth
*mnHeight
-1] = 0;
555 // if this fails we can read too much into pData
556 assert(mnWidth
== maTexture
.GetWidth() &&
557 mnHeight
== maTexture
.GetHeight());
560 maTexture
.Read(nFormat
, nType
, pData
);
562 #if OSL_DEBUG_LEVEL > 0
563 // If we read over the end of pData we have a real hidden memory
564 // corruption problem !
565 size_t nCanary
= static_cast<sal_uInt32
>(mnBytesPerRow
) * mnHeight
;
566 assert(!memcmp(pData
+ nCanary
, CANARY
, sizeof (CANARY
)));
570 else if (mnBits
== 1)
571 { // convert buffers from 24-bit RGB to 1-bit Mask
572 std::vector
<sal_uInt8
> aBuffer(mnWidth
* mnHeight
* 3);
574 sal_uInt8
* pBuffer
= aBuffer
.data();
575 determineTextureFormat(24, nFormat
, nType
);
576 maTexture
.Read(nFormat
, nType
, pBuffer
);
581 sal_uInt8
* pCurrent
= pBuffer
;
583 for (int y
= 0; y
< mnHeight
; ++y
)
585 for (int x
= 0; x
< mnWidth
; ++x
)
594 sal_uInt8 nR
= *pCurrent
++;
595 sal_uInt8 nG
= *pCurrent
++;
596 sal_uInt8 nB
= *pCurrent
++;
598 if (nR
> 0 && nG
> 0 && nB
> 0)
600 pData
[nIndex
] |= (1 << nShift
);
611 SAL_WARN("vcl.opengl", "::ReadTexture - tx:" << maTexture
.Id() << " @ "
612 << mnWidth
<< "x" << mnHeight
<< "- unimplemented bit depth: "
618 sal_uInt16
OpenGLSalBitmap::GetBitCount() const
623 bool OpenGLSalBitmap::calcChecksumGL(OpenGLTexture
& rInputTexture
, ChecksumType
& rChecksum
) const
625 OUString
FragShader("areaHashCRC64TFragmentShader");
627 rtl::Reference
< OpenGLContext
> xContext
= OpenGLContext::getVCLContext();
628 xContext
->state()->scissor().disable();
629 xContext
->state()->stencil().disable();
631 static vcl::DeleteOnDeinit
<OpenGLTexture
> gCRCTableTexture(
632 new OpenGLTexture(512, 1, GL_RGBA
, GL_UNSIGNED_BYTE
,
633 vcl_get_crc64_table()));
634 OpenGLTexture
&rCRCTableTexture
= *gCRCTableTexture
.get();
638 int nWidth
= rInputTexture
.GetWidth();
639 int nHeight
= rInputTexture
.GetHeight();
641 OpenGLProgram
* pProgram
= xContext
->UseProgram("textureVertexShader", FragShader
);
642 if (pProgram
== nullptr)
645 int nNewWidth
= ceil( nWidth
/ 4.0 );
646 int nNewHeight
= ceil( nHeight
/ 4.0 );
648 OpenGLTexture aFirstPassTexture
= OpenGLTexture(nNewWidth
, nNewHeight
);
649 OpenGLFramebuffer
* pFramebuffer
= xContext
->AcquireFramebuffer(aFirstPassTexture
);
651 pProgram
->SetUniform1f( "xstep", 1.0 / mnWidth
);
652 pProgram
->SetUniform1f( "ystep", 1.0 / mnHeight
);
654 pProgram
->SetTexture("crc_table", rCRCTableTexture
);
655 pProgram
->SetTexture("sampler", rInputTexture
);
656 pProgram
->DrawTexture(rInputTexture
);
659 OpenGLContext::ReleaseFramebuffer(pFramebuffer
);
665 nWidth
= aFirstPassTexture
.GetWidth();
666 nHeight
= aFirstPassTexture
.GetHeight();
668 pProgram
= xContext
->UseProgram("textureVertexShader", FragShader
);
669 if (pProgram
== nullptr)
672 nNewWidth
= ceil( nWidth
/ 4.0 );
673 nNewHeight
= ceil( nHeight
/ 4.0 );
675 OpenGLTexture aSecondPassTexture
= OpenGLTexture(nNewWidth
, nNewHeight
);
676 pFramebuffer
= xContext
->AcquireFramebuffer(aSecondPassTexture
);
678 pProgram
->SetUniform1f( "xstep", 1.0 / mnWidth
);
679 pProgram
->SetUniform1f( "ystep", 1.0 / mnHeight
);
681 pProgram
->SetTexture("crc_table", rCRCTableTexture
);
682 pProgram
->SetTexture("sampler", aFirstPassTexture
);
683 pProgram
->DrawTexture(aFirstPassTexture
);
686 OpenGLContext::ReleaseFramebuffer(pFramebuffer
);
691 OpenGLTexture
& aFinalTexture
= aSecondPassTexture
;
692 std::vector
<sal_uInt8
> aBuf( aFinalTexture
.GetWidth() * aFinalTexture
.GetHeight() * 4 );
693 aFinalTexture
.Read(GL_RGBA
, GL_UNSIGNED_BYTE
, aBuf
.data());
695 ChecksumType nCrc
= vcl_get_checksum(0, aBuf
.data(), aBuf
.size());
701 void OpenGLSalBitmap::updateChecksum() const
706 if( (mnWidth
* mnHeight
) < (1024*768) || mnWidth
< 128 || mnHeight
< 128 )
708 SalBitmap::updateChecksum();
712 OpenGLSalBitmap
* pThis
= const_cast<OpenGLSalBitmap
*>(this);
714 OpenGLVCLContextZone aContextZone
;
715 OpenGLTexture
& rInputTexture
= GetTexture();
716 pThis
->mbChecksumValid
= calcChecksumGL(rInputTexture
, pThis
->mnChecksum
);
717 if (!pThis
->mbChecksumValid
)
718 SalBitmap::updateChecksum();
721 rtl::Reference
<OpenGLContext
> OpenGLSalBitmap::GetBitmapContext()
723 return ImplGetDefaultWindow()->GetGraphics()->GetOpenGLContext();
726 BitmapBuffer
* OpenGLSalBitmap::AcquireBuffer( BitmapAccessMode nMode
)
728 OpenGLVCLContextZone aContextZone
;
730 if( nMode
!= BitmapAccessMode::Info
)
732 if (!mpUserBuffer
.get())
734 if( !AllocateUserData() )
736 if( maTexture
&& !ReadTexture() )
740 if( !maPendingOps
.empty() )
742 VCL_GL_INFO( "** Creating texture and reading it back immediately" );
743 if( !CreateTexture() || !AllocateUserData() || !ReadTexture() )
748 // mpUserBuffer must be unique when we are doing the write access
749 if (nMode
== BitmapAccessMode::Write
&& mpUserBuffer
&& !mpUserBuffer
.unique())
751 std::shared_ptr
<sal_uInt8
> aBuffer(mpUserBuffer
);
753 mpUserBuffer
.reset();
755 memcpy(mpUserBuffer
.get(), aBuffer
.get(), static_cast<sal_uInt32
>(mnBytesPerRow
) * mnHeight
);
758 BitmapBuffer
* pBuffer
= new BitmapBuffer
;
759 pBuffer
->mnWidth
= mnWidth
;
760 pBuffer
->mnHeight
= mnHeight
;
761 pBuffer
->maPalette
= maPalette
;
762 pBuffer
->mnScanlineSize
= mnBytesPerRow
;
763 pBuffer
->mpBits
= mpUserBuffer
.get();
764 pBuffer
->mnBitCount
= mnBits
;
769 pBuffer
->mnFormat
= ScanlineFormat::N1BitMsbPal
;
772 pBuffer
->mnFormat
= ScanlineFormat::N4BitMsnPal
;
775 pBuffer
->mnFormat
= ScanlineFormat::N8BitPal
;
780 pBuffer
->mnFormat
= ScanlineFormat::N16BitTcLsbMask
;
781 ColorMaskElement
aRedMask(0x00007c00);
782 aRedMask
.CalcMaskShift();
783 ColorMaskElement
aGreenMask(0x000003e0);
784 aGreenMask
.CalcMaskShift();
785 ColorMaskElement
aBlueMask(0x0000001f);
786 aBlueMask
.CalcMaskShift();
787 pBuffer
->maColorMask
= ColorMask(aRedMask
, aGreenMask
, aBlueMask
);
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
);
803 pBuffer
->mnFormat
= ScanlineFormat::N24BitTcBgr
;
805 pBuffer
->mnFormat
= ScanlineFormat::N24BitTcRgb
;
812 pBuffer
->mnFormat
= ScanlineFormat::N32BitTcBgra
;
813 ColorMaskElement
aRedMask(0x00ff0000);
814 aRedMask
.CalcMaskShift();
815 ColorMaskElement
aGreenMask(0x0000ff00);
816 aGreenMask
.CalcMaskShift();
817 ColorMaskElement
aBlueMask(0x000000ff);
818 aBlueMask
.CalcMaskShift();
819 pBuffer
->maColorMask
= ColorMask(aRedMask
, aGreenMask
, aBlueMask
);
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
);
837 void OpenGLSalBitmap::ReleaseBuffer( BitmapBuffer
* pBuffer
, BitmapAccessMode nMode
)
839 OpenGLVCLContextZone aContextZone
;
841 if( nMode
== BitmapAccessMode::Write
)
843 maTexture
= OpenGLTexture();
844 mbDirtyTexture
= true;
845 mbChecksumValid
= false;
847 // The palette is modified on read during the BitmapWriteAccess,
848 // but of course, often it is not modified; interesting.
849 maPalette
= pBuffer
->maPalette
;
851 // Are there any more ground movements underneath us ?
852 assert( pBuffer
->mnWidth
== mnWidth
);
853 assert( pBuffer
->mnHeight
== mnHeight
);
854 assert( pBuffer
->mnBitCount
== mnBits
);
859 bool OpenGLSalBitmap::GetSystemData( BitmapSystemData
& /*rData*/ )
861 SAL_WARN( "vcl.opengl", "*** NOT IMPLEMENTED *** GetSystemData" );
863 // TODO Implement for ANDROID/OSX/IOS/WIN32
864 X11SalBitmap rBitmap
;
865 BitmapBuffer
* pBuffer
;
867 rBitmap
.Create( GetSize(), mnBits
, maPalette
);
868 pBuffer
= rBitmap
.AcquireBuffer( false );
869 if( pBuffer
== NULL
)
872 if (!mpUserBuffer
.get())
874 if( !AllocateUserData() || !ReadTexture() )
876 rBitmap
.ReleaseBuffer( pBuffer
, false );
881 // TODO Might be more efficient to add a static method to SalBitmap
882 // to get system data from a buffer
883 memcpy( pBuffer
->mpBits
, mpUserBuffer
.get(), mnBytesPerRow
* mnHeight
);
885 rBitmap
.ReleaseBuffer( pBuffer
, false );
886 return rBitmap
.GetSystemData( rData
);
892 bool OpenGLSalBitmap::Replace( const Color
& rSearchColor
, const Color
& rReplaceColor
, sal_uLong nTol
)
894 VCL_GL_INFO("::Replace");
897 rtl::Reference
<OpenGLContext
> xContext
= OpenGLContext::getVCLContext();
898 xContext
->state()->scissor().disable();
899 xContext
->state()->stencil().disable();
901 OpenGLFramebuffer
* pFramebuffer
;
902 OpenGLProgram
* pProgram
;
905 pProgram
= xContext
->UseProgram( "textureVertexShader",
906 "replaceColorFragmentShader" );
910 OpenGLTexture aNewTex
= OpenGLTexture( mnWidth
, mnHeight
);
911 pFramebuffer
= xContext
->AcquireFramebuffer( aNewTex
);
913 pProgram
->SetTexture( "sampler", maTexture
);
914 pProgram
->SetColor( "search_color", rSearchColor
);
915 pProgram
->SetColor( "replace_color", rReplaceColor
);
916 pProgram
->SetUniform1f( "epsilon", nTol
/ 255.0f
);
917 pProgram
->DrawTexture( maTexture
);
920 OpenGLContext::ReleaseFramebuffer( pFramebuffer
);
927 // Convert texture to greyscale and adjust bitmap metadata
928 bool OpenGLSalBitmap::ConvertToGreyscale()
930 VCL_GL_INFO("::ConvertToGreyscale");
932 // avoid re-converting to 8bits.
933 if ( mnBits
== 8 && maPalette
== Bitmap::GetGreyPalette(256) )
937 rtl::Reference
<OpenGLContext
> xContext
= OpenGLContext::getVCLContext();
938 xContext
->state()->scissor().disable();
939 xContext
->state()->stencil().disable();
941 OpenGLFramebuffer
* pFramebuffer
;
942 OpenGLProgram
* pProgram
;
945 pProgram
= xContext
->UseProgram("textureVertexShader", "greyscaleFragmentShader");
950 OpenGLTexture
aNewTex(mnWidth
, mnHeight
);
951 pFramebuffer
= xContext
->AcquireFramebuffer(aNewTex
);
952 pProgram
->SetTexture("sampler", maTexture
);
953 pProgram
->DrawTexture(maTexture
);
956 OpenGLContext::ReleaseFramebuffer( pFramebuffer
);
959 maPalette
= Bitmap::GetGreyPalette(256);
961 // AllocateUserData will handle the rest.
962 mpUserBuffer
.reset();
963 mbDirtyTexture
= false;
969 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */