Version 5.2.0.0.beta1, tag libreoffice-5.2.0.0.beta1
[LibreOffice.git] / vcl / opengl / salbmp.cxx
blobfbfcf6fd1ea526d4e64d37c06b18d8381a9ab013
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
28 #include "svdata.hxx"
29 #include "salgdi.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"
44 #endif
46 namespace
49 inline bool determineTextureFormat(sal_uInt16 nBits, GLenum& nFormat, GLenum& nType)
51 switch(nBits)
53 case 8:
54 nFormat = GL_LUMINANCE;
55 nType = GL_UNSIGNED_BYTE;
56 return true;
57 case 16:
58 #ifdef _WIN32
59 nFormat = GL_BGR;
60 #else
61 nFormat = GL_RGB;
62 #endif
63 nType = GL_UNSIGNED_SHORT_5_6_5;
64 return true;
65 case 24:
66 #ifdef _WIN32
67 nFormat = GL_BGR;
68 #else
69 nFormat = GL_RGB;
70 #endif
71 nType = GL_UNSIGNED_BYTE;
72 return true;
73 case 32:
74 #ifdef _WIN32
75 nFormat = GL_BGRA;
76 #else
77 nFormat = GL_RGBA;
78 #endif
79 nType = GL_UNSIGNED_BYTE;
80 return true;
81 default:
82 break;
84 return false;
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)
94 switch(nBits)
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;
102 default:
103 OSL_FAIL("vcl::OpenGLSalBitmap::AllocateUserData(), illegal bitcount!");
105 return 0;
108 typedef std::vector<std::unique_ptr< FixedTextureAtlasManager > > TextureAtlasVector;
109 static vcl::DeleteOnDeinit< TextureAtlasVector > gTextureAtlases(new TextureAtlasVector());
113 OpenGLSalBitmap::OpenGLSalBitmap()
114 : mbDirtyTexture(true)
115 , mnBits(0)
116 , mnBytesPerRow(0)
117 , mnWidth(0)
118 , mnHeight(0)
122 OpenGLSalBitmap::~OpenGLSalBitmap()
124 Destroy();
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;
133 Destroy();
134 VCL_GL_INFO( "OpenGLSalBitmap::Create from FBO: ["
135 << nX << ", " << nY << "] " << nWidth << "x" << nHeight );
137 mnWidth = nWidth;
138 mnHeight = nHeight;
140 // TODO Check the framebuffer configuration
141 mnBits = 32;
142 maPalette = aEmptyPalette;
144 if( rTex )
145 maTexture = OpenGLTexture( rTex, nX, nY, nWidth, nHeight );
146 else
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());
154 return true;
157 bool OpenGLSalBitmap::Create( const Size& rSize, sal_uInt16 nBits, const BitmapPalette& rBitmapPalette )
159 OpenGLVCLContextZone aContextZone;
161 Destroy();
162 VCL_GL_INFO( "OpenGLSalBitmap::Create with size: " << rSize );
164 if( !isValidBitCount( nBits ) )
165 return false;
166 maPalette = rBitmapPalette;
167 mnBits = nBits;
168 mnWidth = rSize.Width();
169 mnHeight = rSize.Height();
170 return false;
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 )
185 OpenGLZone aZone;
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;
216 return true;
218 return false;
221 bool OpenGLSalBitmap::Create( const css::uno::Reference< css::rendering::XBitmapCanvas >& /*xBitmapCanvas*/, Size& /*rSize*/, bool /*bMask*/ )
223 // TODO Is this method needed?
224 return false;
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()
240 OpenGLZone aZone;
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);
257 bool alloc = false;
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);
266 #endif
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));
271 #endif
272 alloc = true;
274 catch (const std::bad_alloc &) {}
276 if (!alloc)
278 SAL_WARN("vcl.opengl", "bad alloc " << mnBytesPerRow << "x" << mnHeight);
279 mpUserBuffer.reset();
280 mnBytesPerRow = 0;
282 #ifdef DBG_UTIL
283 else
285 for (size_t i = 0; i < size_t(mnBytesPerRow * mnHeight); i++)
286 mpUserBuffer.get()[i] = (i & 0xFF);
288 #endif
290 return mpUserBuffer.get() != nullptr;
293 namespace {
295 class ImplPixelFormat
297 protected:
298 sal_uInt8* mpData;
299 public:
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
309 private:
310 const BitmapPalette& mrPalette;
312 public:
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
326 private:
327 const BitmapPalette& mrPalette;
328 sal_uInt32 mnX;
329 sal_uInt32 mnShift;
331 public:
332 explicit ImplPixelFormat4( const BitmapPalette& rPalette )
333 : mrPalette( rPalette )
334 , mnX(0)
335 , mnShift(4)
338 virtual void StartLine( sal_uInt8* pLine ) override
340 mpData = pLine;
341 mnX = 0;
342 mnShift = 4;
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];
349 mnX++;
350 mnShift ^= 4;
351 return rColor;
355 class ImplPixelFormat1 : public ImplPixelFormat
357 private:
358 const BitmapPalette& mrPalette;
359 sal_uInt32 mnX;
361 public:
362 explicit ImplPixelFormat1( const BitmapPalette& rPalette )
363 : mrPalette(rPalette)
364 , mnX(0)
367 virtual void StartLine( sal_uInt8* pLine ) override
369 mpData = pLine;
370 mnX = 0;
372 virtual const BitmapColor& ReadPixel() override
374 const BitmapColor& rColor = mrPalette[ (mpData[mnX >> 3 ] >> ( 7 - ( mnX & 7 ) )) & 1];
375 mnX++;
376 return rColor;
380 ImplPixelFormat* ImplPixelFormat::GetFormat( sal_uInt16 nBits, const BitmapPalette& rPalette )
382 switch( nBits )
384 case 1: return new ImplPixelFormat1( rPalette );
385 case 4: return new ImplPixelFormat4( rPalette );
386 case 8: return new ImplPixelFormat8( rPalette );
389 return nullptr;
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);
411 return;
415 rTexture = OpenGLTexture (nWidth, nHeight, nFormat, nType, pData);
420 Size OpenGLSalBitmap::GetSize() const
422 OpenGLZone aZone;
424 std::deque< OpenGLSalBitmapOp* >::const_iterator it = maPendingOps.begin();
425 Size aSize( mnWidth, mnHeight );
427 while( it != maPendingOps.end() )
428 (*it++)->GetSize( aSize );
430 return aSize;
433 void OpenGLSalBitmap::ExecuteOperations()
435 while( !maPendingOps.empty() )
437 OpenGLSalBitmapOp* pOp = maPendingOps.front();
438 pOp->Execute();
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;
467 else
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];
473 bAllocated = true;
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;
482 while( nY-- )
484 pSrcFormat->StartLine( pSrcData );
486 sal_uInt32 nX = mnWidth;
487 if (nFormat == GL_BGR)
489 while( nX-- )
491 const BitmapColor& c = pSrcFormat->ReadPixel();
492 *pDstData++ = c.GetBlue();
493 *pDstData++ = c.GetGreen();
494 *pDstData++ = c.GetRed();
497 else // RGB
499 while( nX-- )
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);
519 if( bAllocated )
520 delete[] pData;
522 ExecuteOperations();
523 mbDirtyTexture = false;
525 CHECK_GL_ERROR();
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 )
539 return false;
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.
553 pData[0] = 0;
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());
558 #endif
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)));
567 #endif
568 return true;
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);
578 int nShift = 7;
579 size_t nIndex = 0;
581 sal_uInt8* pCurrent = pBuffer;
583 for (int y = 0; y < mnHeight; ++y)
585 for (int x = 0; x < mnWidth; ++x)
587 if (nShift < 0)
589 nShift = 7;
590 nIndex++;
591 pData[nIndex] = 0;
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);
602 nShift--;
604 nShift = 7;
605 nIndex++;
606 pData[nIndex] = 0;
608 return true;
611 SAL_WARN("vcl.opengl", "::ReadTexture - tx:" << maTexture.Id() << " @ "
612 << mnWidth << "x" << mnHeight << "- unimplemented bit depth: "
613 << mnBits);
614 return false;
618 sal_uInt16 OpenGLSalBitmap::GetBitCount() const
620 return mnBits;
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();
636 // First Pass
638 int nWidth = rInputTexture.GetWidth();
639 int nHeight = rInputTexture.GetHeight();
641 OpenGLProgram* pProgram = xContext->UseProgram("textureVertexShader", FragShader);
642 if (pProgram == nullptr)
643 return false;
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);
657 pProgram->Clean();
659 OpenGLContext::ReleaseFramebuffer(pFramebuffer);
661 CHECK_GL_ERROR();
663 // Second Pass
665 nWidth = aFirstPassTexture.GetWidth();
666 nHeight = aFirstPassTexture.GetHeight();
668 pProgram = xContext->UseProgram("textureVertexShader", FragShader);
669 if (pProgram == nullptr)
670 return false;
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);
684 pProgram->Clean();
686 OpenGLContext::ReleaseFramebuffer(pFramebuffer);
688 CHECK_GL_ERROR();
690 // Final CRC on CPU
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());
697 rChecksum = nCrc;
698 return true;
701 void OpenGLSalBitmap::updateChecksum() const
703 if (mbChecksumValid)
704 return;
706 if( (mnWidth * mnHeight) < (1024*768) || mnWidth < 128 || mnHeight < 128 )
708 SalBitmap::updateChecksum();
709 return;
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() )
735 return nullptr;
736 if( maTexture && !ReadTexture() )
737 return nullptr;
740 if( !maPendingOps.empty() )
742 VCL_GL_INFO( "** Creating texture and reading it back immediately" );
743 if( !CreateTexture() || !AllocateUserData() || !ReadTexture() )
744 return nullptr;
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();
754 AllocateUserData();
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;
766 switch (mnBits)
768 case 1:
769 pBuffer->mnFormat = ScanlineFormat::N1BitMsbPal;
770 break;
771 case 4:
772 pBuffer->mnFormat = ScanlineFormat::N4BitMsnPal;
773 break;
774 case 8:
775 pBuffer->mnFormat = ScanlineFormat::N8BitPal;
776 break;
777 case 16:
779 #ifdef _WIN32
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);
788 #else
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);
797 #endif
798 break;
800 case 24:
802 #ifdef _WIN32
803 pBuffer->mnFormat = ScanlineFormat::N24BitTcBgr;
804 #else
805 pBuffer->mnFormat = ScanlineFormat::N24BitTcRgb;
806 #endif
807 break;
809 case 32:
811 #ifdef _WIN32
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);
820 #else
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);
829 #endif
830 break;
834 return pBuffer;
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 );
856 delete pBuffer;
859 bool OpenGLSalBitmap::GetSystemData( BitmapSystemData& /*rData*/ )
861 SAL_WARN( "vcl.opengl", "*** NOT IMPLEMENTED *** GetSystemData" );
862 #if 0
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 )
870 return false;
872 if (!mpUserBuffer.get())
874 if( !AllocateUserData() || !ReadTexture() )
876 rBitmap.ReleaseBuffer( pBuffer, false );
877 return 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 );
887 #else
888 return false;
889 #endif
892 bool OpenGLSalBitmap::Replace( const Color& rSearchColor, const Color& rReplaceColor, sal_uLong nTol )
894 VCL_GL_INFO("::Replace");
896 OpenGLZone aZone;
897 rtl::Reference<OpenGLContext> xContext = OpenGLContext::getVCLContext();
898 xContext->state()->scissor().disable();
899 xContext->state()->stencil().disable();
901 OpenGLFramebuffer* pFramebuffer;
902 OpenGLProgram* pProgram;
904 GetTexture();
905 pProgram = xContext->UseProgram( "textureVertexShader",
906 "replaceColorFragmentShader" );
907 if( !pProgram )
908 return false;
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 );
918 pProgram->Clean();
920 OpenGLContext::ReleaseFramebuffer( pFramebuffer );
921 maTexture = aNewTex;
923 CHECK_GL_ERROR();
924 return true;
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) )
934 return false;
936 OpenGLZone aZone;
937 rtl::Reference<OpenGLContext> xContext = OpenGLContext::getVCLContext();
938 xContext->state()->scissor().disable();
939 xContext->state()->stencil().disable();
941 OpenGLFramebuffer* pFramebuffer;
942 OpenGLProgram* pProgram;
944 GetTexture();
945 pProgram = xContext->UseProgram("textureVertexShader", "greyscaleFragmentShader");
947 if (!pProgram)
948 return false;
950 OpenGLTexture aNewTex(mnWidth, mnHeight);
951 pFramebuffer = xContext->AcquireFramebuffer(aNewTex);
952 pProgram->SetTexture("sampler", maTexture);
953 pProgram->DrawTexture(maTexture);
954 pProgram->Clean();
956 OpenGLContext::ReleaseFramebuffer( pFramebuffer );
957 maTexture = aNewTex;
958 mnBits = 8;
959 maPalette = Bitmap::GetGreyPalette(256);
961 // AllocateUserData will handle the rest.
962 mpUserBuffer.reset();
963 mbDirtyTexture = false;
965 CHECK_GL_ERROR();
966 return true;
969 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */