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>
22 #include <sal/log.hxx>
23 #include <osl/diagnose.h>
24 #include <tools/debug.hxx>
26 #include <vcl/opengl/OpenGLHelper.hxx>
28 #include <vcl/bitmap.hxx>
29 #include <vcl/checksum.hxx>
30 #include <vcl/outdev.hxx>
33 #include <vcleventlisteners.hxx>
34 #include <vcl/lazydelete.hxx>
36 #include <o3tl/make_shared.hxx>
38 #include <opengl/zone.hxx>
39 #include <opengl/program.hxx>
40 #include <opengl/salbmp.hxx>
41 #include <opengl/RenderState.hxx>
42 #include <opengl/FixedTextureAtlas.hxx>
44 #if OSL_DEBUG_LEVEL > 0
45 # define CANARY "tex-canary"
51 bool determineTextureFormat(sal_uInt16 nBits
, GLenum
& nFormat
, GLenum
& nType
)
56 nFormat
= GL_LUMINANCE
;
57 nType
= GL_UNSIGNED_BYTE
;
61 nType
= GL_UNSIGNED_BYTE
;
65 nType
= GL_UNSIGNED_BYTE
;
70 SAL_WARN("vcl.opengl", "Could not determine the appropriate texture format for input bits '" << nBits
<< "'");
74 bool isValidBitCount( sal_uInt16 nBitCount
)
76 return (nBitCount
== 1) || (nBitCount
== 4) || (nBitCount
== 8) || (nBitCount
== 24) || (nBitCount
== 32);
79 sal_uInt32
lclBytesPerRow(sal_uInt16 nBits
, int nWidth
)
83 case 1: return (nWidth
+ 7) >> 3;
84 case 4: return (nWidth
+ 1) >> 1;
85 case 8: return nWidth
;
86 case 24: return nWidth
* 3;
87 case 32: return nWidth
* 4;
89 OSL_FAIL("vcl::OpenGLSalBitmap::AllocateUserData(), illegal bitcount!");
94 typedef std::vector
<std::unique_ptr
< FixedTextureAtlasManager
> > TextureAtlasVector
;
95 static vcl::DeleteOnDeinit
< TextureAtlasVector
> gTextureAtlases(new TextureAtlasVector
);
99 OpenGLSalBitmap::OpenGLSalBitmap()
100 : mbDirtyTexture(true)
108 OpenGLSalBitmap::~OpenGLSalBitmap()
111 VCL_GL_INFO( "~OpenGLSalBitmap" );
114 void OpenGLSalBitmap::Create( const OpenGLTexture
& rTex
, long nX
, long nY
, long nWidth
, long nHeight
)
116 DBG_TESTSOLARMUTEX();
117 static const BitmapPalette aEmptyPalette
;
118 OpenGLVCLContextZone aContextZone
;
121 VCL_GL_INFO( "OpenGLSalBitmap::Create from FBO: ["
122 << nX
<< ", " << nY
<< "] " << nWidth
<< "x" << nHeight
);
124 GLint nMaxTextureSize
;
125 glGetIntegerv( GL_MAX_TEXTURE_SIZE
, &nMaxTextureSize
);
126 if ( nWidth
> nMaxTextureSize
)
128 nWidth
= nMaxTextureSize
;
129 VCL_GL_INFO( "Width limited to " << nMaxTextureSize
);
132 if ( nHeight
> nMaxTextureSize
)
134 nHeight
= nMaxTextureSize
;
135 VCL_GL_INFO( "Height limited to " << nMaxTextureSize
);
141 // TODO Check the framebuffer configuration
143 maPalette
= aEmptyPalette
;
146 maTexture
= OpenGLTexture( rTex
, nX
, nY
, nWidth
, nHeight
);
148 maTexture
= OpenGLTexture( nX
, nY
, nWidth
, nHeight
);
149 mbDirtyTexture
= false;
150 VCL_GL_INFO( "Created texture " << maTexture
.Id() );
152 assert(mnWidth
== maTexture
.GetWidth() &&
153 mnHeight
== maTexture
.GetHeight());
156 bool OpenGLSalBitmap::Create( const Size
& rSize
, sal_uInt16 nBits
, const BitmapPalette
& rBitmapPalette
)
158 DBG_TESTSOLARMUTEX();
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();
171 // Limit size to what GL allows, so later glTexImage2D() won't fail.
172 GLint nMaxTextureSize
;
173 glGetIntegerv(GL_MAX_TEXTURE_SIZE
, &nMaxTextureSize
);
174 if (mnWidth
> nMaxTextureSize
)
175 mnWidth
= nMaxTextureSize
;
176 if (mnHeight
> nMaxTextureSize
)
177 mnHeight
= nMaxTextureSize
;
182 bool OpenGLSalBitmap::Create( const SalBitmap
& rSalBmp
)
184 DBG_TESTSOLARMUTEX();
185 return Create( rSalBmp
, rSalBmp
.GetBitCount() );
188 bool OpenGLSalBitmap::Create( const SalBitmap
& rSalBmp
, SalGraphics
* pGraphics
)
190 DBG_TESTSOLARMUTEX();
191 return Create( rSalBmp
, pGraphics
? pGraphics
->GetBitCount() : rSalBmp
.GetBitCount() );
194 bool OpenGLSalBitmap::Create( const SalBitmap
& rSalBmp
, sal_uInt16 nNewBitCount
)
196 DBG_TESTSOLARMUTEX();
199 // check that carefully only in the debug mode
200 assert(dynamic_cast<const OpenGLSalBitmap
*>(&rSalBmp
));
202 const OpenGLSalBitmap
& rSourceBitmap
= static_cast<const OpenGLSalBitmap
&>(rSalBmp
);
204 VCL_GL_INFO("OpenGLSalBitmap::Create from BMP: "
205 << rSourceBitmap
.mnWidth
<< "x" << rSourceBitmap
.mnHeight
206 << " Bits old: " << mnBits
<< " new:" << nNewBitCount
);
208 if( isValidBitCount( nNewBitCount
) )
210 // TODO: lfrb: What about the pending operations?!
211 mnBits
= nNewBitCount
;
212 mnBytesPerRow
= rSourceBitmap
.mnBytesPerRow
;
213 mnWidth
= rSourceBitmap
.mnWidth
;
214 mnHeight
= rSourceBitmap
.mnHeight
;
215 maPalette
= rSourceBitmap
.maPalette
;
216 // execute any pending operations on the source bitmap
217 maTexture
= rSourceBitmap
.GetTexture();
218 mbDirtyTexture
= false;
220 // be careful here, we are share & reference-count the
221 // mpUserBuffer, BUT this Create() is called from
222 // Bitmap::ImplMakeUnique().
223 // Consequently, there might be cases when this needs to be made
224 // unique later (when we don't do that right away here), like when
225 // using the BitmapWriteAccess.
226 mpUserBuffer
= rSourceBitmap
.mpUserBuffer
;
233 bool OpenGLSalBitmap::Create( const css::uno::Reference
< css::rendering::XBitmapCanvas
>& /*xBitmapCanvas*/, Size
& /*rSize*/, bool /*bMask*/ )
235 DBG_TESTSOLARMUTEX();
236 // TODO Is this method needed?
240 OpenGLTexture
& OpenGLSalBitmap::GetTexture() const
242 OpenGLSalBitmap
* pThis
= const_cast<OpenGLSalBitmap
*>(this);
243 if( !maTexture
|| mbDirtyTexture
)
244 pThis
->CreateTexture();
245 VCL_GL_INFO( "Got texture " << maTexture
.Id() );
246 return pThis
->maTexture
;
249 void OpenGLSalBitmap::Destroy()
253 VCL_GL_INFO("Destroy OpenGLSalBitmap texture:" << maTexture
.Id());
254 maTexture
= OpenGLTexture();
255 DeallocateUserData();
258 bool OpenGLSalBitmap::AllocateUserData()
260 VCL_GL_INFO( "OpenGLSalBitmap::AllocateUserData" );
262 if( mnWidth
&& mnHeight
)
264 mnBytesPerRow
= lclBytesPerRow(mnBits
, mnWidth
);
268 if (mnBytesPerRow
!= 0 && mnHeight
&&
269 mnBytesPerRow
<= std::numeric_limits
<sal_uInt32
>::max() / mnHeight
)
273 size_t nToAllocate
= mnBytesPerRow
* mnHeight
;
274 #if OSL_DEBUG_LEVEL > 0
275 nToAllocate
+= sizeof(CANARY
);
277 mpUserBuffer
= o3tl::make_shared_array
<sal_uInt8
>(nToAllocate
);
278 #if OSL_DEBUG_LEVEL > 0
279 memcpy(mpUserBuffer
.get() + nToAllocate
- sizeof(CANARY
),
280 CANARY
, sizeof(CANARY
));
284 catch (const std::bad_alloc
&) {}
288 SAL_WARN("vcl.opengl", "bad alloc " << mnBytesPerRow
<< "x" << mnHeight
);
289 DeallocateUserData();
294 for (size_t i
= 0; i
< size_t(mnBytesPerRow
* mnHeight
); i
++)
295 mpUserBuffer
.get()[i
] = (i
& 0xFF);
299 return mpUserBuffer
!= nullptr;
302 void OpenGLSalBitmap::DeallocateUserData()
304 mpUserBuffer
.reset();
310 class ImplPixelFormat
315 static ImplPixelFormat
* GetFormat( sal_uInt16 nBits
, const BitmapPalette
& rPalette
);
317 virtual void StartLine( sal_uInt8
* pLine
) { mpData
= pLine
; }
318 virtual const BitmapColor
& ReadPixel() = 0;
319 virtual ~ImplPixelFormat() { }
322 class ImplPixelFormat8
: public ImplPixelFormat
325 const BitmapPalette
& mrPalette
;
328 explicit ImplPixelFormat8( const BitmapPalette
& rPalette
)
329 : mrPalette( rPalette
)
332 virtual const BitmapColor
& ReadPixel() override
334 assert( mrPalette
.GetEntryCount() > *mpData
);
335 return mrPalette
[ *mpData
++ ];
339 class ImplPixelFormat4
: public ImplPixelFormat
342 const BitmapPalette
& mrPalette
;
347 explicit ImplPixelFormat4( const BitmapPalette
& rPalette
)
348 : mrPalette( rPalette
)
353 virtual void StartLine( sal_uInt8
* pLine
) override
359 virtual const BitmapColor
& ReadPixel() override
361 sal_uInt32 nIdx
= ( mpData
[mnX
>> 1] >> mnShift
) & 0x0f;
362 assert( mrPalette
.GetEntryCount() > nIdx
);
363 const BitmapColor
& rColor
= mrPalette
[nIdx
];
370 class ImplPixelFormat1
: public ImplPixelFormat
373 const BitmapPalette
& mrPalette
;
377 explicit ImplPixelFormat1( const BitmapPalette
& rPalette
)
378 : mrPalette(rPalette
)
382 virtual void StartLine( sal_uInt8
* pLine
) override
387 virtual const BitmapColor
& ReadPixel() override
389 const BitmapColor
& rColor
= mrPalette
[ (mpData
[mnX
>> 3 ] >> ( 7 - ( mnX
& 7 ) )) & 1];
395 ImplPixelFormat
* ImplPixelFormat::GetFormat( sal_uInt16 nBits
, const BitmapPalette
& rPalette
)
399 case 1: return new ImplPixelFormat1( rPalette
);
400 case 4: return new ImplPixelFormat4( rPalette
);
401 case 8: return new ImplPixelFormat8( rPalette
);
407 void lclInstantiateTexture(OpenGLTexture
& rTexture
, const int nWidth
, const int nHeight
,
408 const GLenum nFormat
, const GLenum nType
, sal_uInt8
const * pData
)
410 if (nWidth
== nHeight
)
412 TextureAtlasVector
&sTextureAtlases
= *gTextureAtlases
.get();
413 if (sTextureAtlases
.empty())
415 sTextureAtlases
.push_back(std::make_unique
<FixedTextureAtlasManager
>(8, 8, 16));
416 sTextureAtlases
.push_back(std::make_unique
<FixedTextureAtlasManager
>(8, 8, 24));
417 sTextureAtlases
.push_back(std::make_unique
<FixedTextureAtlasManager
>(8, 8, 32));
418 sTextureAtlases
.push_back(std::make_unique
<FixedTextureAtlasManager
>(8, 8, 48));
419 sTextureAtlases
.push_back(std::make_unique
<FixedTextureAtlasManager
>(8, 8, 64));
421 for (std::unique_ptr
<FixedTextureAtlasManager
> & pTextureAtlas
: sTextureAtlases
)
423 if (nWidth
== pTextureAtlas
->GetSubtextureSize())
425 rTexture
= pTextureAtlas
->InsertBuffer(nWidth
, nHeight
, nFormat
, nType
, pData
);
430 rTexture
= OpenGLTexture (nWidth
, nHeight
, nFormat
, nType
, pData
);
433 // Write color information for 1 and 4 bit palette bitmap scanlines.
436 BitmapPalette
& maPalette
;
437 sal_uInt8
const mnColorsPerByte
; // number of colors that are stored in one byte
438 sal_uInt8
const mnColorBitSize
; // number of bits a color takes
439 sal_uInt8
const mnColorBitMask
; // bit mask used to isolate the color
440 sal_uInt8
* mpCurrentScanline
;
444 ScanlineWriter(BitmapPalette
& aPalette
, sal_Int8 nColorsPerByte
)
445 : maPalette(aPalette
)
446 , mnColorsPerByte(nColorsPerByte
)
447 , 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)
448 , mnColorBitMask((1 << mnColorBitSize
) - 1) // calculate the bit mask from the bit size
449 , mpCurrentScanline(nullptr)
453 void writeRGB(sal_uInt8 nR
, sal_uInt8 nG
, sal_uInt8 nB
)
455 // calculate to which index we will write
456 long nScanlineIndex
= mnX
/ mnColorsPerByte
;
458 // calculate the number of shifts to get the color information to the right place
459 long nShift
= (8 - mnColorBitSize
) - ((mnX
% mnColorsPerByte
) * mnColorBitSize
);
461 sal_uInt16 nColorIndex
= maPalette
.GetBestIndex(BitmapColor(nR
, nG
, nB
));
462 mpCurrentScanline
[nScanlineIndex
] &= ~(mnColorBitMask
<< nShift
); // clear
463 mpCurrentScanline
[nScanlineIndex
] |= (nColorIndex
& mnColorBitMask
) << nShift
; // set
467 void nextLine(sal_uInt8
* pScanline
)
470 mpCurrentScanline
= pScanline
;
474 } // end anonymous namespace
476 Size
OpenGLSalBitmap::GetSize() const
478 return Size(mnWidth
, mnHeight
);
481 GLuint
OpenGLSalBitmap::CreateTexture()
483 VCL_GL_INFO( "::CreateTexture bits: " << mnBits
);
484 GLenum nFormat
= GL_RGBA
;
485 GLenum nType
= GL_UNSIGNED_BYTE
;
486 sal_uInt8
* pData( nullptr );
487 bool bAllocated( false );
489 if (mpUserBuffer
!= nullptr)
491 if( mnBits
== 24 || mnBits
== 32 )
493 // no conversion needed for truecolor
494 pData
= mpUserBuffer
.get();
496 determineTextureFormat(mnBits
, nFormat
, nType
);
500 VCL_GL_INFO( "::CreateTexture - convert from " << mnBits
<< " to 24 bits" );
502 // convert to 24 bits RGB using palette
503 pData
= new sal_uInt8
[mnHeight
* mnWidth
* 3];
505 determineTextureFormat(24, nFormat
, nType
);
507 std::unique_ptr
<ImplPixelFormat
> pSrcFormat(ImplPixelFormat::GetFormat(mnBits
, maPalette
));
509 sal_uInt8
* pSrcData
= mpUserBuffer
.get();
510 sal_uInt8
* pDstData
= pData
;
512 sal_uInt32 nY
= mnHeight
;
515 pSrcFormat
->StartLine( pSrcData
);
517 sal_uInt32 nX
= mnWidth
;
518 if (nFormat
== GL_BGR
)
522 const BitmapColor
& c
= pSrcFormat
->ReadPixel();
523 *pDstData
++ = c
.GetBlue();
524 *pDstData
++ = c
.GetGreen();
525 *pDstData
++ = c
.GetRed();
532 const BitmapColor
& c
= pSrcFormat
->ReadPixel();
533 *pDstData
++ = c
.GetRed();
534 *pDstData
++ = c
.GetGreen();
535 *pDstData
++ = c
.GetBlue();
539 pSrcData
+= mnBytesPerRow
;
544 OpenGLVCLContextZone aContextZone
;
546 lclInstantiateTexture(maTexture
, mnWidth
, mnHeight
, nFormat
, nType
, pData
);
548 VCL_GL_INFO("Created texture " << maTexture
.Id() << " bits: " << mnBits
);
553 mbDirtyTexture
= false;
556 return maTexture
.Id();
559 bool OpenGLSalBitmap::ReadTexture()
561 sal_uInt8
* pData
= mpUserBuffer
.get();
563 GLenum nFormat
= GL_RGBA
;
564 GLenum nType
= GL_UNSIGNED_BYTE
;
566 VCL_GL_INFO( "::ReadTexture " << mnWidth
<< "x" << mnHeight
<< " bits: " << mnBits
);
568 if( pData
== nullptr )
571 OpenGLVCLContextZone aContextZone
;
573 rtl::Reference
<OpenGLContext
> xContext
= OpenGLContext::getVCLContext();
574 xContext
->state().scissor().disable();
575 xContext
->state().stencil().disable();
577 if ((mnBits
== 8 && maPalette
.IsGreyPalette()) || mnBits
== 24 || mnBits
== 32)
579 determineTextureFormat(mnBits
, nFormat
, nType
);
581 #if OSL_DEBUG_LEVEL > 0
582 // help valgrind & drmemory rescue us - touch last and first bits.
584 pData
[mnBits
/8*mnWidth
*mnHeight
-1] = 0;
585 // if this fails we can read too much into pData
586 assert(mnWidth
== maTexture
.GetWidth() &&
587 mnHeight
== maTexture
.GetHeight());
590 maTexture
.Read(nFormat
, nType
, pData
);
592 #if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
593 // If we read over the end of pData we have a real hidden memory
594 // corruption problem !
595 size_t nCanary
= mnBytesPerRow
* mnHeight
;
596 assert(!memcmp(pData
+ nCanary
, CANARY
, sizeof (CANARY
)));
600 else if (mnBits
== 1 || mnBits
== 4 || mnBits
== 8)
601 { // convert buffers from 24-bit RGB to 1,4 or 8-bit buffer
602 std::vector
<sal_uInt8
> aBuffer(mnWidth
* mnHeight
* 3);
604 sal_uInt8
* pBuffer
= aBuffer
.data();
605 determineTextureFormat(24, nFormat
, nType
);
606 maTexture
.Read(nFormat
, nType
, pBuffer
);
607 sal_uInt32 nSourceBytesPerRow
= lclBytesPerRow(24, mnWidth
);
609 std::unique_ptr
<ScanlineWriter
> pWriter
;
613 pWriter
.reset(new ScanlineWriter(maPalette
, 8));
616 pWriter
.reset(new ScanlineWriter(maPalette
, 2));
619 pWriter
.reset(new ScanlineWriter(maPalette
, 1));
625 for (int y
= 0; y
< mnHeight
; ++y
)
627 sal_uInt8
* pSource
= &pBuffer
[y
* nSourceBytesPerRow
];
628 sal_uInt8
* pDestination
= &pData
[y
* mnBytesPerRow
];
630 pWriter
->nextLine(pDestination
);
632 for (int x
= 0; x
< mnWidth
; ++x
)
635 sal_uInt8 nR
= *pSource
++;
636 sal_uInt8 nG
= *pSource
++;
637 sal_uInt8 nB
= *pSource
++;
639 pWriter
->writeRGB(nR
, nG
, nB
);
645 SAL_WARN("vcl.opengl", "::ReadTexture - tx:" << maTexture
.Id() << " @ "
646 << mnWidth
<< "x" << mnHeight
<< "- unimplemented bit depth: "
651 sal_uInt16
OpenGLSalBitmap::GetBitCount() const
656 bool OpenGLSalBitmap::calcChecksumGL(OpenGLTexture
& rInputTexture
, BitmapChecksum
& rChecksum
) const
658 OUString
FragShader("areaHashCRC64TFragmentShader");
660 rtl::Reference
< OpenGLContext
> xContext
= OpenGLContext::getVCLContext();
661 xContext
->state().scissor().disable();
662 xContext
->state().stencil().disable();
664 static vcl::DeleteOnDeinit
<OpenGLTexture
> gCRCTableTexture(
665 new OpenGLTexture(512, 1, GL_RGBA
, GL_UNSIGNED_BYTE
,
666 vcl_get_crc64_table()));
667 OpenGLTexture
&rCRCTableTexture
= *gCRCTableTexture
.get();
671 int nWidth
= rInputTexture
.GetWidth();
672 int nHeight
= rInputTexture
.GetHeight();
674 OpenGLProgram
* pProgram
= xContext
->UseProgram("textureVertexShader", FragShader
);
675 if (pProgram
== nullptr)
678 int nNewWidth
= ceil( nWidth
/ 4.0 );
679 int nNewHeight
= ceil( nHeight
/ 4.0 );
681 OpenGLTexture
aFirstPassTexture(nNewWidth
, nNewHeight
);
682 OpenGLFramebuffer
* pFramebuffer
= xContext
->AcquireFramebuffer(aFirstPassTexture
);
684 pProgram
->SetUniform1f( "xstep", 1.0 / mnWidth
);
685 pProgram
->SetUniform1f( "ystep", 1.0 / mnHeight
);
687 pProgram
->SetTexture("crc_table", rCRCTableTexture
);
688 pProgram
->SetTexture("sampler", rInputTexture
);
689 pProgram
->DrawTexture(rInputTexture
);
692 OpenGLContext::ReleaseFramebuffer(pFramebuffer
);
698 nWidth
= aFirstPassTexture
.GetWidth();
699 nHeight
= aFirstPassTexture
.GetHeight();
701 pProgram
= xContext
->UseProgram("textureVertexShader", FragShader
);
702 if (pProgram
== nullptr)
705 nNewWidth
= ceil( nWidth
/ 4.0 );
706 nNewHeight
= ceil( nHeight
/ 4.0 );
708 OpenGLTexture
aSecondPassTexture(nNewWidth
, nNewHeight
);
709 pFramebuffer
= xContext
->AcquireFramebuffer(aSecondPassTexture
);
711 pProgram
->SetUniform1f( "xstep", 1.0 / mnWidth
);
712 pProgram
->SetUniform1f( "ystep", 1.0 / mnHeight
);
714 pProgram
->SetTexture("crc_table", rCRCTableTexture
);
715 pProgram
->SetTexture("sampler", aFirstPassTexture
);
716 pProgram
->DrawTexture(aFirstPassTexture
);
719 OpenGLContext::ReleaseFramebuffer(pFramebuffer
);
724 OpenGLTexture
& aFinalTexture
= aSecondPassTexture
;
725 std::vector
<sal_uInt8
> aBuf( aFinalTexture
.GetWidth() * aFinalTexture
.GetHeight() * 4 );
726 aFinalTexture
.Read(GL_RGBA
, GL_UNSIGNED_BYTE
, aBuf
.data());
728 BitmapChecksum nCrc
= vcl_get_checksum(0, aBuf
.data(), aBuf
.size());
734 void OpenGLSalBitmap::updateChecksum() const
739 if( (mnWidth
* mnHeight
) < (1024*768) || mnWidth
< 128 || mnHeight
< 128 )
741 SalBitmap::updateChecksum();
745 OpenGLSalBitmap
* pThis
= const_cast<OpenGLSalBitmap
*>(this);
747 OpenGLVCLContextZone aContextZone
;
748 OpenGLTexture
& rInputTexture
= GetTexture();
749 pThis
->mbChecksumValid
= calcChecksumGL(rInputTexture
, pThis
->mnChecksum
);
750 if (!pThis
->mbChecksumValid
)
751 SalBitmap::updateChecksum();
754 BitmapBuffer
* OpenGLSalBitmap::AcquireBuffer( BitmapAccessMode nMode
)
756 OpenGLVCLContextZone aContextZone
;
758 if( nMode
!= BitmapAccessMode::Info
)
760 if (!mpUserBuffer
.get())
762 if( !AllocateUserData() )
764 if( maTexture
&& !ReadTexture() )
766 DeallocateUserData();
772 // mpUserBuffer must be unique when we are doing the write access
773 if (nMode
== BitmapAccessMode::Write
&& mpUserBuffer
&& mpUserBuffer
.use_count() > 1)
775 std::shared_ptr
<sal_uInt8
> aBuffer(mpUserBuffer
);
777 mpUserBuffer
.reset();
779 memcpy(mpUserBuffer
.get(), aBuffer
.get(), mnBytesPerRow
* mnHeight
);
782 BitmapBuffer
* pBuffer
= new BitmapBuffer
;
783 pBuffer
->mnWidth
= mnWidth
;
784 pBuffer
->mnHeight
= mnHeight
;
785 pBuffer
->maPalette
= maPalette
;
786 pBuffer
->mnScanlineSize
= mnBytesPerRow
;
787 pBuffer
->mpBits
= mpUserBuffer
.get();
788 pBuffer
->mnBitCount
= mnBits
;
793 pBuffer
->mnFormat
= ScanlineFormat::N1BitMsbPal
;
796 pBuffer
->mnFormat
= ScanlineFormat::N4BitMsnPal
;
799 pBuffer
->mnFormat
= ScanlineFormat::N8BitPal
;
803 pBuffer
->mnFormat
= ScanlineFormat::N24BitTcRgb
;
808 pBuffer
->mnFormat
= ScanlineFormat::N32BitTcRgba
;
809 ColorMaskElement
aRedMask(0xff000000);
810 aRedMask
.CalcMaskShift();
811 ColorMaskElement
aGreenMask(0x00ff0000);
812 aGreenMask
.CalcMaskShift();
813 ColorMaskElement
aBlueMask(0x0000ff00);
814 aBlueMask
.CalcMaskShift();
815 pBuffer
->maColorMask
= ColorMask(aRedMask
, aGreenMask
, aBlueMask
);
818 default: assert(false);
824 void OpenGLSalBitmap::ReleaseBuffer( BitmapBuffer
* pBuffer
, BitmapAccessMode nMode
)
826 OpenGLVCLContextZone aContextZone
;
828 if( nMode
== BitmapAccessMode::Write
)
830 maTexture
= OpenGLTexture();
831 mbDirtyTexture
= true;
832 mbChecksumValid
= false;
834 // The palette is modified on read during the BitmapWriteAccess,
835 // but of course, often it is not modified; interesting.
836 maPalette
= pBuffer
->maPalette
;
838 // Are there any more ground movements underneath us ?
839 assert( pBuffer
->mnWidth
== mnWidth
);
840 assert( pBuffer
->mnHeight
== mnHeight
);
841 assert( pBuffer
->mnBitCount
== mnBits
);
846 bool OpenGLSalBitmap::GetSystemData( BitmapSystemData
& /*rData*/ )
848 SAL_WARN( "vcl.opengl", "*** NOT IMPLEMENTED *** GetSystemData" );
850 // TODO Implement for ANDROID/OSX/IOS/WIN32
851 X11SalBitmap rBitmap
;
852 BitmapBuffer
* pBuffer
;
854 rBitmap
.Create( GetSize(), mnBits
, maPalette
);
855 pBuffer
= rBitmap
.AcquireBuffer( false );
856 if( pBuffer
== NULL
)
859 if (!mpUserBuffer
.get())
861 if( !AllocateUserData() || !ReadTexture() )
863 rBitmap
.ReleaseBuffer( pBuffer
, false );
864 DeallocateUserData();
869 // TODO Might be more efficient to add a static method to SalBitmap
870 // to get system data from a buffer
871 memcpy( pBuffer
->mpBits
, mpUserBuffer
.get(), mnBytesPerRow
* mnHeight
);
873 rBitmap
.ReleaseBuffer( pBuffer
, false );
874 return rBitmap
.GetSystemData( rData
);
880 bool OpenGLSalBitmap::Replace( const Color
& rSearchColor
, const Color
& rReplaceColor
, sal_uInt8 nTol
)
882 VCL_GL_INFO("::Replace");
885 rtl::Reference
<OpenGLContext
> xContext
= OpenGLContext::getVCLContext();
886 xContext
->state().scissor().disable();
887 xContext
->state().stencil().disable();
889 OpenGLFramebuffer
* pFramebuffer
;
890 OpenGLProgram
* pProgram
;
893 pProgram
= xContext
->UseProgram( "textureVertexShader",
894 "replaceColorFragmentShader" );
898 OpenGLTexture
aNewTex( mnWidth
, mnHeight
);
899 pFramebuffer
= xContext
->AcquireFramebuffer( aNewTex
);
901 pProgram
->SetTexture( "sampler", maTexture
);
902 pProgram
->SetColor( "search_color", rSearchColor
);
903 pProgram
->SetColor( "replace_color", rReplaceColor
);
904 pProgram
->SetUniform1f( "epsilon", nTol
/ 255.0f
);
905 pProgram
->DrawTexture( maTexture
);
908 OpenGLContext::ReleaseFramebuffer( pFramebuffer
);
915 // Convert texture to greyscale and adjust bitmap metadata
916 bool OpenGLSalBitmap::ConvertToGreyscale()
918 VCL_GL_INFO("::ConvertToGreyscale");
920 // avoid re-converting to 8bits.
921 if ( mnBits
== 8 && maPalette
== Bitmap::GetGreyPalette(256) )
925 rtl::Reference
<OpenGLContext
> xContext
= OpenGLContext::getVCLContext();
926 xContext
->state().scissor().disable();
927 xContext
->state().stencil().disable();
929 OpenGLFramebuffer
* pFramebuffer
;
930 OpenGLProgram
* pProgram
;
933 pProgram
= xContext
->UseProgram("textureVertexShader", "greyscaleFragmentShader");
938 OpenGLTexture
aNewTex(mnWidth
, mnHeight
);
939 pFramebuffer
= xContext
->AcquireFramebuffer(aNewTex
);
940 pProgram
->SetTexture("sampler", maTexture
);
941 pProgram
->DrawTexture(maTexture
);
944 OpenGLContext::ReleaseFramebuffer( pFramebuffer
);
947 maPalette
= Bitmap::GetGreyPalette(256);
949 // AllocateUserData will handle the rest.
950 DeallocateUserData();
951 mbDirtyTexture
= false;
957 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */