nss: upgrade to release 3.73
[LibreOffice.git] / vcl / opengl / salbmp.cxx
blobfb4ee7bb0f04f9365581df1035e93d072610f802
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 <memory>
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>
31 #include <svdata.hxx>
32 #include <salgdi.hxx>
33 #include <vcleventlisteners.hxx>
34 #include <vcl/lazydelete.hxx>
35 #include <scanlinewriter.hxx>
37 #include <o3tl/make_shared.hxx>
39 #include <opengl/zone.hxx>
40 #include <opengl/program.hxx>
41 #include <opengl/salbmp.hxx>
42 #include <opengl/RenderState.hxx>
43 #include <opengl/FixedTextureAtlas.hxx>
45 #if OSL_DEBUG_LEVEL > 0
46 # define CANARY "tex-canary"
47 #endif
49 namespace
52 bool determineTextureFormat(sal_uInt16 nBits, GLenum& nFormat, GLenum& nType)
54 switch(nBits)
56 case 8:
57 nFormat = GL_LUMINANCE;
58 nType = GL_UNSIGNED_BYTE;
59 return true;
60 case 24:
61 nFormat = GL_RGB;
62 nType = GL_UNSIGNED_BYTE;
63 return true;
64 case 32:
65 nFormat = GL_RGBA;
66 nType = GL_UNSIGNED_BYTE;
67 return true;
68 default:
69 break;
71 SAL_WARN("vcl.opengl", "Could not determine the appropriate texture format for input bits '" << nBits << "'");
72 return false;
75 bool isValidBitCount( sal_uInt16 nBitCount )
77 return (nBitCount == 1) || (nBitCount == 4) || (nBitCount == 8) || (nBitCount == 24) || (nBitCount == 32);
80 sal_uInt32 lclBytesPerRow(sal_uInt16 nBits, int nWidth)
82 switch(nBits)
84 case 1: return (nWidth + 7) >> 3;
85 case 4: return (nWidth + 1) >> 1;
86 case 8: return nWidth;
87 case 24: return nWidth * 3;
88 case 32: return nWidth * 4;
89 default:
90 OSL_FAIL("vcl::OpenGLSalBitmap::AllocateUserData(), illegal bitcount!");
92 return 0;
96 OpenGLSalBitmap::OpenGLSalBitmap()
97 : mbDirtyTexture(true)
98 , mnBits(0)
99 , mnBytesPerRow(0)
100 , mnWidth(0)
101 , mnHeight(0)
105 OpenGLSalBitmap::~OpenGLSalBitmap()
107 Destroy();
108 VCL_GL_INFO( "~OpenGLSalBitmap" );
111 void OpenGLSalBitmap::Create( const OpenGLTexture& rTex, tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight )
113 DBG_TESTSOLARMUTEX();
114 static const BitmapPalette aEmptyPalette;
115 OpenGLVCLContextZone aContextZone;
117 Destroy();
118 VCL_GL_INFO( "OpenGLSalBitmap::Create from FBO: ["
119 << nX << ", " << nY << "] " << nWidth << "x" << nHeight );
121 GLint nMaxTextureSize;
122 glGetIntegerv( GL_MAX_TEXTURE_SIZE, &nMaxTextureSize );
123 if ( nWidth > nMaxTextureSize )
125 nWidth = nMaxTextureSize;
126 VCL_GL_INFO( "Width limited to " << nMaxTextureSize );
129 if ( nHeight > nMaxTextureSize )
131 nHeight = nMaxTextureSize;
132 VCL_GL_INFO( "Height limited to " << nMaxTextureSize );
135 mnWidth = nWidth;
136 mnHeight = nHeight;
138 // TODO Check the framebuffer configuration
139 mnBits = 32;
140 maPalette = aEmptyPalette;
142 if( rTex )
143 maTexture = OpenGLTexture( rTex, nX, nY, nWidth, nHeight );
144 else
145 maTexture = OpenGLTexture( nX, nY, nWidth, nHeight );
146 mbDirtyTexture = false;
147 VCL_GL_INFO( "Created texture " << maTexture.Id() );
149 assert(mnWidth == maTexture.GetWidth() &&
150 mnHeight == maTexture.GetHeight());
153 bool OpenGLSalBitmap::Create( const Size& rSize, sal_uInt16 nBits, const BitmapPalette& rBitmapPalette )
155 DBG_TESTSOLARMUTEX();
156 OpenGLVCLContextZone aContextZone;
158 Destroy();
159 VCL_GL_INFO( "OpenGLSalBitmap::Create with size: " << rSize );
161 if( !isValidBitCount( nBits ) )
162 return false;
163 maPalette = rBitmapPalette;
164 mnBits = nBits;
165 mnWidth = rSize.Width();
166 mnHeight = rSize.Height();
168 // Limit size to what GL allows, so later glTexImage2D() won't fail.
169 GLint nMaxTextureSize;
170 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &nMaxTextureSize);
171 if (mnWidth > nMaxTextureSize)
172 mnWidth = nMaxTextureSize;
173 if (mnHeight > nMaxTextureSize)
174 mnHeight = nMaxTextureSize;
176 return false;
179 bool OpenGLSalBitmap::Create( const SalBitmap& rSalBmp )
181 DBG_TESTSOLARMUTEX();
182 return Create( rSalBmp, rSalBmp.GetBitCount() );
185 bool OpenGLSalBitmap::Create( const SalBitmap& rSalBmp, SalGraphics* pGraphics )
187 DBG_TESTSOLARMUTEX();
188 return Create( rSalBmp, pGraphics ? pGraphics->GetBitCount() : rSalBmp.GetBitCount() );
191 bool OpenGLSalBitmap::Create( const SalBitmap& rSalBmp, sal_uInt16 nNewBitCount )
193 DBG_TESTSOLARMUTEX();
194 OpenGLZone aZone;
196 // check that carefully only in the debug mode
197 assert(dynamic_cast<const OpenGLSalBitmap*>(&rSalBmp));
199 const OpenGLSalBitmap& rSourceBitmap = static_cast<const OpenGLSalBitmap&>(rSalBmp);
201 VCL_GL_INFO("OpenGLSalBitmap::Create from BMP: "
202 << rSourceBitmap.mnWidth << "x" << rSourceBitmap.mnHeight
203 << " Bits old: " << mnBits << " new:" << nNewBitCount );
205 if( isValidBitCount( nNewBitCount ) )
207 // TODO: lfrb: What about the pending operations?!
208 mnBits = nNewBitCount;
209 mnBytesPerRow = rSourceBitmap.mnBytesPerRow;
210 mnWidth = rSourceBitmap.mnWidth;
211 mnHeight = rSourceBitmap.mnHeight;
212 maPalette = rSourceBitmap.maPalette;
213 // execute any pending operations on the source bitmap
214 maTexture = rSourceBitmap.GetTexture();
215 mbDirtyTexture = false;
217 // be careful here, we are share & reference-count the
218 // mpUserBuffer, BUT this Create() is called from
219 // Bitmap::ImplMakeUnique().
220 // Consequently, there might be cases when this needs to be made
221 // unique later (when we don't do that right away here), like when
222 // using the BitmapWriteAccess.
223 mpUserBuffer = rSourceBitmap.mpUserBuffer;
225 return true;
227 return false;
230 bool OpenGLSalBitmap::Create( const css::uno::Reference< css::rendering::XBitmapCanvas >& /*xBitmapCanvas*/, Size& /*rSize*/, bool /*bMask*/ )
232 DBG_TESTSOLARMUTEX();
233 // TODO Is this method needed?
234 return false;
237 OpenGLTexture& OpenGLSalBitmap::GetTexture() const
239 OpenGLSalBitmap* pThis = const_cast<OpenGLSalBitmap*>(this);
240 if( !maTexture || mbDirtyTexture )
241 pThis->CreateTexture();
242 VCL_GL_INFO( "Got texture " << maTexture.Id() );
243 return pThis->maTexture;
246 void OpenGLSalBitmap::Destroy()
248 OpenGLZone aZone;
250 VCL_GL_INFO("Destroy OpenGLSalBitmap texture:" << maTexture.Id());
251 maTexture = OpenGLTexture();
252 DeallocateUserData();
255 bool OpenGLSalBitmap::AllocateUserData()
257 VCL_GL_INFO( "OpenGLSalBitmap::AllocateUserData" );
259 if( mnWidth && mnHeight )
261 mnBytesPerRow = lclBytesPerRow(mnBits, mnWidth);
264 bool alloc = false;
265 if (mnBytesPerRow != 0 && mnHeight &&
266 mnBytesPerRow <= std::numeric_limits<sal_uInt32>::max() / mnHeight)
270 size_t nToAllocate = mnBytesPerRow * mnHeight;
271 #if OSL_DEBUG_LEVEL > 0
272 nToAllocate += sizeof(CANARY);
273 #endif
274 mpUserBuffer = o3tl::make_shared_array<sal_uInt8>(nToAllocate);
275 #if OSL_DEBUG_LEVEL > 0
276 memcpy(mpUserBuffer.get() + nToAllocate - sizeof(CANARY),
277 CANARY, sizeof(CANARY));
278 #endif
279 alloc = true;
281 catch (const std::bad_alloc &) {}
283 if (!alloc)
285 SAL_WARN("vcl.opengl", "bad alloc " << mnBytesPerRow << "x" << mnHeight);
286 DeallocateUserData();
288 #ifdef DBG_UTIL
289 else
291 for (size_t i = 0; i < size_t(mnBytesPerRow * mnHeight); i++)
292 mpUserBuffer.get()[i] = (i & 0xFF);
294 #endif
296 return mpUserBuffer != nullptr;
299 void OpenGLSalBitmap::DeallocateUserData()
301 mpUserBuffer.reset();
302 mnBytesPerRow = 0;
305 namespace {
307 void lclInstantiateTexture(OpenGLTexture& rTexture, const int nWidth, const int nHeight,
308 const GLenum nFormat, const GLenum nType, sal_uInt8 const * pData)
310 if (nWidth == nHeight)
312 typedef std::vector<std::unique_ptr<FixedTextureAtlasManager>> TextureAtlasVector;
313 static vcl::DeleteOnDeinit<TextureAtlasVector> aTextureAtlases([]() {
314 TextureAtlasVector* p = new TextureAtlasVector;
315 p->reserve(5);
316 p->push_back(std::make_unique<FixedTextureAtlasManager>(8, 8, 16));
317 p->push_back(std::make_unique<FixedTextureAtlasManager>(8, 8, 24));
318 p->push_back(std::make_unique<FixedTextureAtlasManager>(8, 8, 32));
319 p->push_back(std::make_unique<FixedTextureAtlasManager>(8, 8, 48));
320 p->push_back(std::make_unique<FixedTextureAtlasManager>(8, 8, 64));
321 return p;
322 }());
323 for (std::unique_ptr<FixedTextureAtlasManager>& pTextureAtlas : *aTextureAtlases.get())
325 if (nWidth == pTextureAtlas->GetSubtextureSize())
327 rTexture = pTextureAtlas->InsertBuffer(nWidth, nHeight, nFormat, nType, pData);
328 return;
332 rTexture = OpenGLTexture (nWidth, nHeight, nFormat, nType, pData);
335 } // end anonymous namespace
337 Size OpenGLSalBitmap::GetSize() const
339 return Size(mnWidth, mnHeight);
342 GLuint OpenGLSalBitmap::CreateTexture()
344 VCL_GL_INFO( "::CreateTexture bits: " << mnBits);
345 GLenum nFormat = GL_RGBA;
346 GLenum nType = GL_UNSIGNED_BYTE;
347 sal_uInt8* pData( nullptr );
348 bool bAllocated( false );
350 if (mpUserBuffer != nullptr)
352 if( mnBits == 24 || mnBits == 32 )
354 // no conversion needed for truecolor
355 pData = mpUserBuffer.get();
357 determineTextureFormat(mnBits, nFormat, nType);
359 else if( mnBits == 8 && maPalette.IsGreyPalette8Bit() )
361 // no conversion needed for 8bit grayscale
362 pData = mpUserBuffer.get();
363 nFormat = GL_LUMINANCE;
364 nType = GL_UNSIGNED_BYTE;
366 else
368 VCL_GL_INFO( "::CreateTexture - convert from " << mnBits << " to 24 bits" );
369 // convert to 24 bits RGB using palette
370 determineTextureFormat(24, nFormat, nType);
371 pData = convertDataBitCount( mpUserBuffer.get(), mnWidth, mnHeight,
372 mnBits, mnBytesPerRow, maPalette,
373 nFormat == GL_BGR ? BitConvert::BGR : BitConvert::RGB ).release();
374 bAllocated = true;
378 OpenGLVCLContextZone aContextZone;
380 lclInstantiateTexture(maTexture, mnWidth, mnHeight, nFormat, nType, pData);
382 VCL_GL_INFO("Created texture " << maTexture.Id() << " bits: " << mnBits);
384 if( bAllocated )
385 delete[] pData;
387 mbDirtyTexture = false;
389 CHECK_GL_ERROR();
390 return maTexture.Id();
393 bool OpenGLSalBitmap::ReadTexture()
395 sal_uInt8* pData = mpUserBuffer.get();
397 GLenum nFormat = GL_RGBA;
398 GLenum nType = GL_UNSIGNED_BYTE;
400 VCL_GL_INFO( "::ReadTexture " << mnWidth << "x" << mnHeight << " bits: " << mnBits);
402 if( pData == nullptr )
403 return false;
405 OpenGLVCLContextZone aContextZone;
407 rtl::Reference<OpenGLContext> xContext = OpenGLContext::getVCLContext();
408 xContext->state().scissor().disable();
409 xContext->state().stencil().disable();
411 if ((mnBits == 8 && maPalette.IsGreyPalette8Bit()) || mnBits == 24 || mnBits == 32)
413 determineTextureFormat(mnBits, nFormat, nType);
415 #if OSL_DEBUG_LEVEL > 0
416 // help valgrind & drmemory rescue us - touch last and first bits.
417 pData[0] = 0;
418 pData[mnBits/8*mnWidth*mnHeight-1] = 0;
419 // if this fails we can read too much into pData
420 assert(mnWidth == maTexture.GetWidth() &&
421 mnHeight == maTexture.GetHeight());
422 #endif
424 maTexture.Read(nFormat, nType, pData);
426 #if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
427 // If we read over the end of pData we have a real hidden memory
428 // corruption problem !
429 size_t nCanary = mnBytesPerRow * mnHeight;
430 assert(!memcmp(pData + nCanary, CANARY, sizeof (CANARY)));
431 #endif
432 return true;
434 else if (mnBits == 1 || mnBits == 4 || mnBits == 8)
435 { // convert buffers from 24-bit RGB to 1,4 or 8-bit buffer
436 std::vector<sal_uInt8> aBuffer(mnWidth * mnHeight * 3);
438 sal_uInt8* pBuffer = aBuffer.data();
439 determineTextureFormat(24, nFormat, nType);
440 maTexture.Read(nFormat, nType, pBuffer);
441 sal_uInt32 nSourceBytesPerRow = lclBytesPerRow(24, mnWidth);
443 std::unique_ptr<vcl::ScanlineWriter> pWriter = vcl::ScanlineWriter::Create(mnBits, maPalette);
444 for (int y = 0; y < mnHeight; ++y)
446 sal_uInt8* pSource = &pBuffer[y * nSourceBytesPerRow];
447 sal_uInt8* pDestination = &pData[y * mnBytesPerRow];
449 pWriter->nextLine(pDestination);
451 for (int x = 0; x < mnWidth; ++x)
453 // read source
454 sal_uInt8 nR = *pSource++;
455 sal_uInt8 nG = *pSource++;
456 sal_uInt8 nB = *pSource++;
458 pWriter->writeRGB(nR, nG, nB);
461 return true;
464 SAL_WARN("vcl.opengl", "::ReadTexture - tx:" << maTexture.Id() << " @ "
465 << mnWidth << "x" << mnHeight << "- unimplemented bit depth: "
466 << mnBits);
467 return false;
470 sal_uInt16 OpenGLSalBitmap::GetBitCount() const
472 return mnBits;
475 bool OpenGLSalBitmap::calcChecksumGL(OpenGLTexture& rInputTexture, BitmapChecksum& rChecksum) const
477 OUString FragShader("areaHashCRC64TFragmentShader");
479 rtl::Reference< OpenGLContext > xContext = OpenGLContext::getVCLContext();
480 xContext->state().scissor().disable();
481 xContext->state().stencil().disable();
483 static vcl::DeleteOnDeinit<OpenGLTexture> gCRCTableTexture(
484 new OpenGLTexture(512, 1, GL_RGBA, GL_UNSIGNED_BYTE,
485 vcl_get_crc64_table()));
486 OpenGLTexture &rCRCTableTexture = *gCRCTableTexture.get();
488 // First Pass
490 int nWidth = rInputTexture.GetWidth();
491 int nHeight = rInputTexture.GetHeight();
493 OpenGLProgram* pProgram = xContext->UseProgram("textureVertexShader", FragShader);
494 if (pProgram == nullptr)
495 return false;
497 int nNewWidth = ceil( nWidth / 4.0 );
498 int nNewHeight = ceil( nHeight / 4.0 );
500 OpenGLTexture aFirstPassTexture(nNewWidth, nNewHeight);
501 OpenGLFramebuffer* pFramebuffer = xContext->AcquireFramebuffer(aFirstPassTexture);
503 pProgram->SetUniform1f( "xstep", 1.0 / mnWidth );
504 pProgram->SetUniform1f( "ystep", 1.0 / mnHeight );
506 pProgram->SetTexture("crc_table", rCRCTableTexture);
507 pProgram->SetTexture("sampler", rInputTexture);
508 pProgram->DrawTexture(rInputTexture);
509 pProgram->Clean();
511 OpenGLContext::ReleaseFramebuffer(pFramebuffer);
513 CHECK_GL_ERROR();
515 // Second Pass
517 nWidth = aFirstPassTexture.GetWidth();
518 nHeight = aFirstPassTexture.GetHeight();
520 pProgram = xContext->UseProgram("textureVertexShader", FragShader);
521 if (pProgram == nullptr)
522 return false;
524 nNewWidth = ceil( nWidth / 4.0 );
525 nNewHeight = ceil( nHeight / 4.0 );
527 OpenGLTexture aSecondPassTexture(nNewWidth, nNewHeight);
528 pFramebuffer = xContext->AcquireFramebuffer(aSecondPassTexture);
530 pProgram->SetUniform1f( "xstep", 1.0 / mnWidth );
531 pProgram->SetUniform1f( "ystep", 1.0 / mnHeight );
533 pProgram->SetTexture("crc_table", rCRCTableTexture);
534 pProgram->SetTexture("sampler", aFirstPassTexture);
535 pProgram->DrawTexture(aFirstPassTexture);
536 pProgram->Clean();
538 OpenGLContext::ReleaseFramebuffer(pFramebuffer);
540 CHECK_GL_ERROR();
542 // Final CRC on CPU
543 OpenGLTexture& aFinalTexture = aSecondPassTexture;
544 std::vector<sal_uInt8> aBuf( aFinalTexture.GetWidth() * aFinalTexture.GetHeight() * 4 );
545 aFinalTexture.Read(GL_RGBA, GL_UNSIGNED_BYTE, aBuf.data());
547 BitmapChecksum nCrc = vcl_get_checksum(0, aBuf.data(), aBuf.size());
549 rChecksum = nCrc;
550 return true;
553 void OpenGLSalBitmap::updateChecksum() const
555 if (mbChecksumValid)
556 return;
558 if( (mnWidth * mnHeight) < (1024*768) || mnWidth < 128 || mnHeight < 128 )
560 SalBitmap::updateChecksum();
561 return;
564 OpenGLSalBitmap* pThis = const_cast<OpenGLSalBitmap*>(this);
566 OpenGLVCLContextZone aContextZone;
567 OpenGLTexture& rInputTexture = GetTexture();
568 pThis->mbChecksumValid = calcChecksumGL(rInputTexture, pThis->mnChecksum);
569 if (!pThis->mbChecksumValid)
570 SalBitmap::updateChecksum();
573 BitmapBuffer* OpenGLSalBitmap::AcquireBuffer( BitmapAccessMode nMode )
575 OpenGLVCLContextZone aContextZone;
577 if( nMode != BitmapAccessMode::Info )
579 if (!mpUserBuffer)
581 if( !AllocateUserData() )
582 return nullptr;
583 if( maTexture && !ReadTexture() )
585 DeallocateUserData();
586 return nullptr;
591 // mpUserBuffer must be unique when we are doing the write access
592 if (nMode == BitmapAccessMode::Write && mpUserBuffer && mpUserBuffer.use_count() > 1)
594 std::shared_ptr<sal_uInt8> aBuffer(mpUserBuffer);
596 mpUserBuffer.reset();
597 AllocateUserData();
598 memcpy(mpUserBuffer.get(), aBuffer.get(), mnBytesPerRow * mnHeight);
601 BitmapBuffer* pBuffer = new BitmapBuffer;
602 pBuffer->mnWidth = mnWidth;
603 pBuffer->mnHeight = mnHeight;
604 pBuffer->maPalette = maPalette;
605 pBuffer->mnScanlineSize = mnBytesPerRow;
606 pBuffer->mpBits = mpUserBuffer.get();
607 pBuffer->mnBitCount = mnBits;
609 switch (mnBits)
611 case 1:
612 pBuffer->mnFormat = ScanlineFormat::N1BitMsbPal;
613 break;
614 case 4:
615 pBuffer->mnFormat = ScanlineFormat::N4BitMsnPal;
616 break;
617 case 8:
618 pBuffer->mnFormat = ScanlineFormat::N8BitPal;
619 break;
620 case 24:
622 pBuffer->mnFormat = ScanlineFormat::N24BitTcRgb;
623 break;
625 case 32:
627 pBuffer->mnFormat = ScanlineFormat::N32BitTcRgba;
628 ColorMaskElement aRedMask(0xff000000);
629 aRedMask.CalcMaskShift();
630 ColorMaskElement aGreenMask(0x00ff0000);
631 aGreenMask.CalcMaskShift();
632 ColorMaskElement aBlueMask(0x0000ff00);
633 aBlueMask.CalcMaskShift();
634 pBuffer->maColorMask = ColorMask(aRedMask, aGreenMask, aBlueMask);
635 break;
637 default: assert(false);
640 return pBuffer;
643 void OpenGLSalBitmap::ReleaseBuffer( BitmapBuffer* pBuffer, BitmapAccessMode nMode )
645 OpenGLVCLContextZone aContextZone;
647 if( nMode == BitmapAccessMode::Write )
649 maTexture = OpenGLTexture();
650 mbDirtyTexture = true;
651 mbChecksumValid = false;
653 // The palette is modified on read during the BitmapWriteAccess,
654 // but of course, often it is not modified; interesting.
655 maPalette = pBuffer->maPalette;
657 // Are there any more ground movements underneath us ?
658 assert( pBuffer->mnWidth == mnWidth );
659 assert( pBuffer->mnHeight == mnHeight );
660 assert( pBuffer->mnBitCount == mnBits );
662 delete pBuffer;
665 bool OpenGLSalBitmap::GetSystemData( BitmapSystemData& /*rData*/ )
667 SAL_WARN( "vcl.opengl", "*** NOT IMPLEMENTED *** GetSystemData" );
668 #if 0
669 // TODO Implement for ANDROID/OSX/IOS/WIN32
670 X11SalBitmap rBitmap;
671 BitmapBuffer* pBuffer;
673 rBitmap.Create( GetSize(), mnBits, maPalette );
674 pBuffer = rBitmap.AcquireBuffer( false );
675 if( pBuffer == NULL )
676 return false;
678 if (!mpUserBuffer.get())
680 if( !AllocateUserData() || !ReadTexture() )
682 rBitmap.ReleaseBuffer( pBuffer, false );
683 DeallocateUserData();
684 return false;
688 // TODO Might be more efficient to add a static method to SalBitmap
689 // to get system data from a buffer
690 memcpy( pBuffer->mpBits, mpUserBuffer.get(), mnBytesPerRow * mnHeight );
692 rBitmap.ReleaseBuffer( pBuffer, false );
693 return rBitmap.GetSystemData( rData );
694 #else
695 return false;
696 #endif
699 bool OpenGLSalBitmap::Replace( const Color& rSearchColor, const Color& rReplaceColor, sal_uInt8 nTol )
701 VCL_GL_INFO("::Replace");
703 OpenGLZone aZone;
704 rtl::Reference<OpenGLContext> xContext = OpenGLContext::getVCLContext();
705 xContext->state().scissor().disable();
706 xContext->state().stencil().disable();
708 OpenGLFramebuffer* pFramebuffer;
709 OpenGLProgram* pProgram;
711 GetTexture();
712 pProgram = xContext->UseProgram( "textureVertexShader",
713 "replaceColorFragmentShader" );
714 if( !pProgram )
715 return false;
717 OpenGLTexture aNewTex( mnWidth, mnHeight );
718 pFramebuffer = xContext->AcquireFramebuffer( aNewTex );
720 pProgram->SetTexture( "sampler", maTexture );
721 pProgram->SetColor( "search_color", rSearchColor );
722 pProgram->SetColor( "replace_color", rReplaceColor );
723 pProgram->SetUniform1f( "epsilon", nTol / 255.0f );
724 pProgram->DrawTexture( maTexture );
725 pProgram->Clean();
727 OpenGLContext::ReleaseFramebuffer( pFramebuffer );
728 maTexture = aNewTex;
730 CHECK_GL_ERROR();
731 return true;
734 // Convert texture to greyscale and adjust bitmap metadata
735 bool OpenGLSalBitmap::ConvertToGreyscale()
737 VCL_GL_INFO("::ConvertToGreyscale");
739 // avoid re-converting to 8bits.
740 if ( mnBits == 8 && maPalette.IsGreyPalette8Bit())
741 return true;
743 OpenGLZone aZone;
744 rtl::Reference<OpenGLContext> xContext = OpenGLContext::getVCLContext();
745 xContext->state().scissor().disable();
746 xContext->state().stencil().disable();
748 OpenGLFramebuffer* pFramebuffer;
749 OpenGLProgram* pProgram;
751 GetTexture();
752 pProgram = xContext->UseProgram("textureVertexShader", "greyscaleFragmentShader");
754 if (!pProgram)
755 return false;
757 OpenGLTexture aNewTex(mnWidth, mnHeight);
758 pFramebuffer = xContext->AcquireFramebuffer(aNewTex);
759 pProgram->SetTexture("sampler", maTexture);
760 pProgram->DrawTexture(maTexture);
761 pProgram->Clean();
763 OpenGLContext::ReleaseFramebuffer( pFramebuffer );
764 maTexture = aNewTex;
765 mnBits = 8;
766 maPalette = Bitmap::GetGreyPalette(256);
768 // AllocateUserData will handle the rest.
769 DeallocateUserData();
770 mbDirtyTexture = false;
772 CHECK_GL_ERROR();
773 return true;
776 // This is needed to just make the bitmap usable as an alpha channel.
777 // Converting to 8bit grey will do.
778 bool OpenGLSalBitmap::InterpretAs8Bit()
780 return ConvertToGreyscale();
783 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */