Branch libreoffice-5-0-4
[LibreOffice.git] / vcl / opengl / salbmp.cxx
blobcbf60c244ba44fefb3aae17224a97c71258093e2
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"
31 #include "opengl/zone.hxx"
32 #include "opengl/program.hxx"
33 #include "opengl/salbmp.hxx"
35 #include "opengl/FixedTextureAtlas.hxx"
37 namespace
40 static bool isValidBitCount( sal_uInt16 nBitCount )
42 return (nBitCount == 1) || (nBitCount == 4) || (nBitCount == 8) || (nBitCount == 16) || (nBitCount == 24) || (nBitCount == 32);
45 static std::vector<std::unique_ptr<FixedTextureAtlasManager>> sTextureAtlases;
49 OpenGLSalBitmap::OpenGLSalBitmap()
50 : mpContext(NULL)
51 , mbDirtyTexture(true)
52 , mnBits(0)
53 , mnBytesPerRow(0)
54 , mnWidth(0)
55 , mnHeight(0)
56 , mnBufWidth(0)
57 , mnBufHeight(0)
61 OpenGLSalBitmap::~OpenGLSalBitmap()
63 Destroy();
64 SAL_INFO( "vcl.opengl", "~OpenGLSalBitmap" );
67 bool OpenGLSalBitmap::Create( const OpenGLTexture& rTex, long nX, long nY, long nWidth, long nHeight )
69 static const BitmapPalette aEmptyPalette;
70 OpenGLZone aZone;
72 Destroy();
73 SAL_INFO( "vcl.opengl", "OpenGLSalBitmap::Create from FBO: [" << nX << ", " << nY << "] " << nWidth << "x" << nHeight );
75 mnWidth = nWidth;
76 mnHeight = nHeight;
77 mnBufWidth = 0;
78 mnBufHeight = 0;
80 // TODO Check the framebuffer configuration
81 mnBits = 32;
82 maPalette = aEmptyPalette;
84 if( rTex )
85 maTexture = OpenGLTexture( rTex, nX, nY, nWidth, nHeight );
86 else
87 maTexture = OpenGLTexture( nX, nY, nWidth, nHeight );
88 mbDirtyTexture = false;
89 SAL_INFO( "vcl.opengl", "Created texture " << maTexture.Id() );
91 return true;
94 bool OpenGLSalBitmap::Create( const Size& rSize, sal_uInt16 nBits, const BitmapPalette& rBitmapPalette )
96 OpenGLZone aZone;
98 Destroy();
99 SAL_INFO( "vcl.opengl", "OpenGLSalBitmap::Create with size: " << rSize );
101 if( !isValidBitCount( nBits ) )
102 return false;
103 maPalette = rBitmapPalette;
104 mnBits = nBits;
105 mnWidth = mnBufWidth = rSize.Width();
106 mnHeight = mnBufHeight = rSize.Height();
107 return false;
110 bool OpenGLSalBitmap::Create( const SalBitmap& rSalBmp )
112 return Create( rSalBmp, rSalBmp.GetBitCount() );
115 bool OpenGLSalBitmap::Create( const SalBitmap& rSalBmp, SalGraphics* pGraphics )
117 return Create( rSalBmp, pGraphics ? pGraphics->GetBitCount() : rSalBmp.GetBitCount() );
120 bool OpenGLSalBitmap::Create( const SalBitmap& rSalBmp, sal_uInt16 nNewBitCount )
122 OpenGLZone aZone;
124 // check that carefully only in the debug mode
125 assert(dynamic_cast<const OpenGLSalBitmap*>(&rSalBmp));
127 const OpenGLSalBitmap& rSourceBitmap = static_cast<const OpenGLSalBitmap&>(rSalBmp);
129 SAL_INFO( "vcl.opengl", "OpenGLSalBitmap::Create from BMP: " << rSourceBitmap.mnWidth << "x" << rSourceBitmap.mnHeight );
131 if( isValidBitCount( nNewBitCount ) )
133 // TODO: lfrb: What about the pending operations?!
134 mnBits = nNewBitCount;
135 mnBytesPerRow = rSourceBitmap.mnBytesPerRow;
136 mnWidth = rSourceBitmap.mnWidth;
137 mnHeight = rSourceBitmap.mnHeight;
138 mnBufWidth = rSourceBitmap.mnBufWidth;
139 mnBufHeight = rSourceBitmap.mnBufHeight;
140 maPalette = rSourceBitmap.maPalette;
141 // execute any pending operations on the source bitmap
142 maTexture = rSourceBitmap.GetTexture();
143 mbDirtyTexture = false;
145 // be careful here, we are share & reference-count the
146 // maUserBuffer, BUT this Create() is called from
147 // Bitmap::ImplMakeUnique().
148 // Consequently, there might be cases when this needs to be made
149 // unique later (when we don't do that right away here), like when
150 // using the BitmapWriteAccess.
151 maUserBuffer = rSourceBitmap.maUserBuffer;
153 return true;
155 return false;
158 bool OpenGLSalBitmap::Create( const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmapCanvas >& /*xBitmapCanvas*/, Size& /*rSize*/, bool /*bMask*/ )
160 // TODO Is this method needed?
161 return false;
164 OpenGLTexture& OpenGLSalBitmap::GetTexture() const
166 OpenGLSalBitmap* pThis = const_cast<OpenGLSalBitmap*>(this);
167 if( !maTexture || mbDirtyTexture )
168 pThis->CreateTexture();
169 else if( !maPendingOps.empty() )
170 pThis->ExecuteOperations();
171 SAL_INFO( "vcl.opengl", "Got texture " << maTexture.Id() );
172 return pThis->maTexture;
175 void OpenGLSalBitmap::Destroy()
177 OpenGLZone aZone;
179 SAL_INFO( "vcl.opengl", "Destroy OpenGLSalBitmap" );
180 maPendingOps.clear();
181 maTexture = OpenGLTexture();
182 maUserBuffer.reset();
185 bool OpenGLSalBitmap::AllocateUserData()
187 SAL_INFO( "vcl.opengl", "OpenGLSalBitmap::AllocateUserData" );
189 if( mnWidth && mnHeight )
191 mnBytesPerRow = 0;
193 switch( mnBits )
195 case 1: mnBytesPerRow = (mnWidth + 7) >> 3; break;
196 case 4: mnBytesPerRow = (mnWidth + 1) >> 1; break;
197 case 8: mnBytesPerRow = mnWidth; break;
198 case 16: mnBytesPerRow = mnWidth << 1; break;
199 case 24: mnBytesPerRow = (mnWidth << 1) + mnWidth; break;
200 case 32: mnBytesPerRow = mnWidth << 2; break;
201 default:
202 OSL_FAIL("vcl::OpenGLSalBitmap::AllocateUserData(), illegal bitcount!");
206 bool alloc = false;
207 if (mnBytesPerRow != 0 && mnHeight &&
208 mnBytesPerRow <= std::numeric_limits<sal_uInt32>::max() / mnHeight)
212 maUserBuffer.reset( new sal_uInt8[static_cast<sal_uInt32>(mnBytesPerRow) * mnHeight] );
213 alloc = true;
215 catch (const std::bad_alloc &) {}
217 if (!alloc)
219 SAL_WARN("vcl.opengl", "bad alloc " << mnBytesPerRow << "x" << mnHeight);
220 maUserBuffer.reset( static_cast<sal_uInt8*>(NULL) );
221 mnBytesPerRow = 0;
223 #ifdef DBG_UTIL
224 else
226 for (size_t i = 0; i < size_t(mnBytesPerRow * mnHeight); i++)
227 maUserBuffer.get()[i] = (i & 0xFF);
229 #endif
231 return maUserBuffer.get() != 0;
234 namespace {
236 class ImplPixelFormat
238 protected:
239 sal_uInt8* mpData;
240 public:
241 static ImplPixelFormat* GetFormat( sal_uInt16 nBits, const BitmapPalette& rPalette );
243 virtual void StartLine( sal_uInt8* pLine ) { mpData = pLine; }
244 virtual const BitmapColor& ReadPixel() = 0;
245 virtual ~ImplPixelFormat() { }
248 class ImplPixelFormat8 : public ImplPixelFormat
250 private:
251 const BitmapPalette& mrPalette;
253 public:
254 ImplPixelFormat8( const BitmapPalette& rPalette )
255 : mrPalette( rPalette )
258 virtual const BitmapColor& ReadPixel() SAL_OVERRIDE
260 assert( mrPalette.GetEntryCount() > *mpData );
261 return mrPalette[ *mpData++ ];
265 class ImplPixelFormat4 : public ImplPixelFormat
267 private:
268 const BitmapPalette& mrPalette;
269 sal_uInt32 mnX;
270 sal_uInt32 mnShift;
272 public:
273 ImplPixelFormat4( const BitmapPalette& rPalette )
274 : mrPalette( rPalette )
275 , mnX(0)
276 , mnShift(4)
279 virtual void StartLine( sal_uInt8* pLine ) SAL_OVERRIDE
281 mpData = pLine;
282 mnX = 0;
283 mnShift = 4;
285 virtual const BitmapColor& ReadPixel() SAL_OVERRIDE
287 sal_uInt32 nIdx = ( mpData[mnX >> 1] >> mnShift) & 0x0f;
288 assert( mrPalette.GetEntryCount() > nIdx );
289 const BitmapColor& rColor = mrPalette[nIdx];
290 mnX++;
291 mnShift ^= 4;
292 return rColor;
296 class ImplPixelFormat1 : public ImplPixelFormat
298 private:
299 const BitmapPalette& mrPalette;
300 sal_uInt32 mnX;
302 public:
303 ImplPixelFormat1( const BitmapPalette& rPalette )
304 : mrPalette(rPalette)
305 , mnX(0)
308 virtual void StartLine( sal_uInt8* pLine ) SAL_OVERRIDE
310 mpData = pLine;
311 mnX = 0;
313 virtual const BitmapColor& ReadPixel() SAL_OVERRIDE
315 const BitmapColor& rColor = mrPalette[ (mpData[mnX >> 3 ] >> ( 7 - ( mnX & 7 ) )) & 1];
316 mnX++;
317 return rColor;
321 ImplPixelFormat* ImplPixelFormat::GetFormat( sal_uInt16 nBits, const BitmapPalette& rPalette )
323 switch( nBits )
325 case 1: return new ImplPixelFormat1( rPalette );
326 case 4: return new ImplPixelFormat4( rPalette );
327 case 8: return new ImplPixelFormat8( rPalette );
330 return 0;
333 void lclInstantiateTexture(OpenGLTexture& rTexture, const int nWidth, const int nHeight,
334 const GLenum nFormat, const GLenum nType, sal_uInt8* pData)
336 if (nWidth == nHeight)
338 if (sTextureAtlases.empty())
340 sTextureAtlases.push_back(std::unique_ptr<FixedTextureAtlasManager>(new FixedTextureAtlasManager(8, 8, 16)));
341 sTextureAtlases.push_back(std::unique_ptr<FixedTextureAtlasManager>(new FixedTextureAtlasManager(8, 8, 24)));
342 sTextureAtlases.push_back(std::unique_ptr<FixedTextureAtlasManager>(new FixedTextureAtlasManager(8, 8, 32)));
343 sTextureAtlases.push_back(std::unique_ptr<FixedTextureAtlasManager>(new FixedTextureAtlasManager(8, 8, 48)));
344 sTextureAtlases.push_back(std::unique_ptr<FixedTextureAtlasManager>(new FixedTextureAtlasManager(8, 8, 64)));
346 for (size_t i = 0; i < sTextureAtlases.size(); i++)
348 if (nWidth == sTextureAtlases[i]->GetSubtextureSize())
350 rTexture = sTextureAtlases[i]->InsertBuffer(nWidth, nHeight, nFormat, nType, pData);
351 return;
355 rTexture = OpenGLTexture (nWidth, nHeight, nFormat, nType, pData);
360 Size OpenGLSalBitmap::GetSize() const
362 OpenGLZone aZone;
364 std::deque< OpenGLSalBitmapOp* >::const_iterator it = maPendingOps.begin();
365 Size aSize( mnWidth, mnHeight );
367 while( it != maPendingOps.end() )
368 (*it++)->GetSize( aSize );
370 return aSize;
373 void OpenGLSalBitmap::ExecuteOperations()
375 makeCurrent();
376 while( !maPendingOps.empty() )
378 OpenGLSalBitmapOp* pOp = maPendingOps.front();
379 pOp->Execute();
380 maPendingOps.pop_front();
384 GLuint OpenGLSalBitmap::CreateTexture()
386 SAL_INFO( "vcl.opengl", "::CreateTexture" );
387 GLenum nFormat = GL_RGBA;
388 GLenum nType = GL_UNSIGNED_BYTE;
389 sal_uInt8* pData( NULL );
390 bool bAllocated( false );
392 if( maUserBuffer.get() != 0 )
394 if( mnBits == 16 || mnBits == 24 || mnBits == 32 )
396 // no conversion needed for truecolor
397 pData = maUserBuffer.get();
399 switch( mnBits )
401 case 16: nFormat = GL_RGB;
402 nType = GL_UNSIGNED_SHORT_5_6_5;
403 break;
404 case 24: nFormat = GL_RGB;
405 nType = GL_UNSIGNED_BYTE;
406 break;
407 case 32: nFormat = GL_RGBA;
408 nType = GL_UNSIGNED_BYTE;
409 break;
412 else if( mnBits == 8 && maPalette.IsGreyPalette() )
414 // no conversion needed for grayscale
415 pData = maUserBuffer.get();
416 nFormat = GL_LUMINANCE;
417 nType = GL_UNSIGNED_BYTE;
419 else
421 // convert to 32 bits RGBA using palette
422 pData = new sal_uInt8[mnBufHeight * mnBufWidth * 4];
423 bAllocated = true;
424 nFormat = GL_RGBA;
425 nType = GL_UNSIGNED_BYTE;
427 ImplPixelFormat* pSrcFormat = ImplPixelFormat::GetFormat( mnBits, maPalette );
428 sal_uInt8* pSrcData = maUserBuffer.get();
429 sal_uInt8* pDstData = pData;
431 sal_uInt32 nY = mnBufHeight;
432 while( nY-- )
434 pSrcFormat->StartLine( pSrcData );
436 sal_uInt32 nX = mnBufWidth;
437 while( nX-- )
439 const BitmapColor& c = pSrcFormat->ReadPixel();
441 *pDstData++ = c.GetRed();
442 *pDstData++ = c.GetGreen();
443 *pDstData++ = c.GetBlue();
444 *pDstData++ = 255;
447 pSrcData += mnBytesPerRow;
452 makeCurrent();
454 lclInstantiateTexture(maTexture, mnBufWidth, mnBufHeight, nFormat, nType, pData);
456 SAL_INFO( "vcl.opengl", "Created texture " << maTexture.Id() );
458 if( bAllocated )
459 delete[] pData;
461 ExecuteOperations();
462 mbDirtyTexture = false;
464 CHECK_GL_ERROR();
465 return maTexture.Id();
468 bool OpenGLSalBitmap::ReadTexture()
470 sal_uInt8* pData = maUserBuffer.get();
472 SAL_INFO( "vcl.opengl", "::ReadTexture " << mnWidth << "x" << mnHeight );
474 if( pData == NULL )
475 return false;
477 if (mnBits == 8 || mnBits == 16 || mnBits == 24 || mnBits == 32)
479 GLenum nFormat = GL_RGBA;
480 GLenum nType = GL_UNSIGNED_BYTE;
482 switch( mnBits )
484 case 8: nFormat = GL_LUMINANCE;
485 nType = GL_UNSIGNED_BYTE;
486 break;
487 case 16: nFormat = GL_RGB;
488 nType = GL_UNSIGNED_SHORT_5_6_5;
489 break;
490 case 24: nFormat = GL_RGB;
491 nType = GL_UNSIGNED_BYTE;
492 break;
493 case 32: nFormat = GL_RGBA;
494 nType = GL_UNSIGNED_BYTE;
495 break;
498 makeCurrent();
499 maTexture.Read(nFormat, nType, pData);
500 mnBufWidth = mnWidth;
501 mnBufHeight = mnHeight;
502 return true;
504 else if (mnBits == 1)
505 { // convert buffers from 24-bit RGB to 1-bit Mask
506 std::vector<sal_uInt8> aBuffer(mnWidth * mnHeight * 3);
507 makeCurrent();
508 sal_uInt8* pBuffer = aBuffer.data();
509 maTexture.Read(GL_RGB, GL_UNSIGNED_BYTE, pBuffer);
511 int nShift = 7;
512 size_t nIndex = 0;
514 sal_uInt8* pCurrent = pBuffer;
516 for (int y = 0; y < mnHeight; ++y)
518 for (int x = 0; x < mnWidth; ++x)
520 if (nShift < 0)
522 nShift = 7;
523 nIndex++;
524 pData[nIndex] = 0;
527 sal_uInt8 nR = *pCurrent++;
528 sal_uInt8 nG = *pCurrent++;
529 sal_uInt8 nB = *pCurrent++;
531 if (nR > 0 && nG > 0 && nB > 0)
533 pData[nIndex] |= (1 << nShift);
535 nShift--;
537 nShift = 7;
538 nIndex++;
539 pData[nIndex] = 0;
541 mnBufWidth = mnWidth;
542 mnBufHeight = mnHeight;
543 return true;
546 SAL_WARN("vcl.opengl", "::ReadTexture - tx:" << maTexture.Id() << " @ "
547 << mnWidth << "x" << mnHeight << "- unimplemented bit depth: "
548 << mnBits);
549 return false;
553 sal_uInt16 OpenGLSalBitmap::GetBitCount() const
555 return mnBits;
558 bool OpenGLSalBitmap::calcChecksumGL(OpenGLTexture& rInputTexture, ChecksumType& rChecksum) const
560 OUString FragShader("areaHashCRC64TFragmentShader");
562 static const OpenGLTexture aCRCTableTexture(512, 1, GL_RGBA, GL_UNSIGNED_BYTE,
563 vcl_get_crc64_table());
565 // First Pass
567 int nWidth = rInputTexture.GetWidth();
568 int nHeight = rInputTexture.GetHeight();
570 OpenGLProgram* pProgram = mpContext->UseProgram("textureVertexShader", FragShader);
571 if (pProgram == 0)
572 return false;
574 int nNewWidth = ceil( nWidth / 4.0 );
575 int nNewHeight = ceil( nHeight / 4.0 );
577 OpenGLTexture aFirstPassTexture = OpenGLTexture(nNewWidth, nNewHeight);
578 OpenGLFramebuffer* pFramebuffer = mpContext->AcquireFramebuffer(aFirstPassTexture);
580 pProgram->SetUniform1f( "xstep", 1.0 / mnWidth );
581 pProgram->SetUniform1f( "ystep", 1.0 / mnHeight );
583 pProgram->SetTexture("crc_table", (OpenGLTexture&)(aCRCTableTexture));
584 pProgram->SetTexture("sampler", rInputTexture);
585 pProgram->DrawTexture(rInputTexture);
586 pProgram->Clean();
588 OpenGLContext::ReleaseFramebuffer(pFramebuffer);
590 CHECK_GL_ERROR();
593 // Second Pass
595 nWidth = aFirstPassTexture.GetWidth();
596 nHeight = aFirstPassTexture.GetHeight();
598 pProgram = mpContext->UseProgram("textureVertexShader", FragShader);
599 if (pProgram == 0)
600 return false;
602 nNewWidth = ceil( nWidth / 4.0 );
603 nNewHeight = ceil( nHeight / 4.0 );
605 OpenGLTexture aSecondPassTexture = OpenGLTexture(nNewWidth, nNewHeight);
606 pFramebuffer = mpContext->AcquireFramebuffer(aSecondPassTexture);
608 pProgram->SetUniform1f( "xstep", 1.0 / mnWidth );
609 pProgram->SetUniform1f( "ystep", 1.0 / mnHeight );
611 pProgram->SetTexture("crc_table", (OpenGLTexture&)(aCRCTableTexture));
612 pProgram->SetTexture("sampler", aFirstPassTexture);
613 pProgram->DrawTexture(aFirstPassTexture);
614 pProgram->Clean();
616 OpenGLContext::ReleaseFramebuffer(pFramebuffer);
618 CHECK_GL_ERROR();
620 // Final CRC on CPU
621 OpenGLTexture& aFinalTexture = aSecondPassTexture;
622 std::vector<sal_uInt8> aBuf( aFinalTexture.GetWidth() * aFinalTexture.GetHeight() * 4 );
623 aFinalTexture.Read(GL_RGBA, GL_UNSIGNED_BYTE, aBuf.data());
625 ChecksumType nCrc = vcl_get_checksum(0, aBuf.data(), aBuf.size());
627 rChecksum = nCrc;
628 return true;
631 void OpenGLSalBitmap::updateChecksum() const
633 if (mbChecksumValid)
634 return;
636 OpenGLSalBitmap* pThis = const_cast<OpenGLSalBitmap*>(this);
638 if (!mpContext.is())
640 pThis->CreateTexture();
643 OpenGLTexture& rInputTexture = pThis->maTexture;
644 int nWidth = rInputTexture.GetWidth();
645 int nHeight = rInputTexture.GetHeight();
647 if( (nWidth * nHeight) < (1024*768) || nWidth < 128 || nHeight < 128 )
649 SalBitmap::updateChecksum();
651 else
653 pThis->mbChecksumValid = calcChecksumGL(rInputTexture, pThis->mnChecksum);
657 rtl::Reference<OpenGLContext> OpenGLSalBitmap::GetBitmapContext()
659 return ImplGetDefaultWindow()->GetGraphics()->GetOpenGLContext();
662 void OpenGLSalBitmap::makeCurrent()
664 ImplSVData* pSVData = ImplGetSVData();
666 // TODO: make sure we can really use the last used context
667 OpenGLContext *pContext = pSVData->maGDIData.mpLastContext;
668 while( pContext && !pContext->isInitialized() )
669 pContext = pContext->mpPrevContext;
670 if( pContext )
671 mpContext = pContext;
672 else
673 mpContext = GetBitmapContext();
674 assert(mpContext.is() && "Couldn't get an OpenGL context");
675 mpContext->makeCurrent();
678 BitmapBuffer* OpenGLSalBitmap::AcquireBuffer( BitmapAccessMode nMode )
680 OpenGLZone aZone;
682 if( nMode != BITMAP_INFO_ACCESS )
684 if( !maUserBuffer.get() )
686 if( !AllocateUserData() )
687 return NULL;
688 if( maTexture && !ReadTexture() )
689 return NULL;
692 if( !maPendingOps.empty() )
694 SAL_INFO( "vcl.opengl", "** Creating texture and reading it back immediately" );
695 if( !CreateTexture() || !AllocateUserData() || !ReadTexture() )
696 return NULL;
700 // maUserBuffer must be unique when we are doing the write access
701 if (nMode == BITMAP_WRITE_ACCESS && maUserBuffer && !maUserBuffer.unique())
703 basebmp::RawMemorySharedArray aBuffer(maUserBuffer);
705 maUserBuffer.reset();
706 AllocateUserData();
707 memcpy(maUserBuffer.get(), aBuffer.get(), static_cast<sal_uInt32>(mnBytesPerRow) * mnHeight);
710 BitmapBuffer* pBuffer = new BitmapBuffer;
711 pBuffer->mnWidth = mnWidth;
712 pBuffer->mnHeight = mnHeight;
713 pBuffer->maPalette = maPalette;
714 pBuffer->mnScanlineSize = mnBytesPerRow;
715 pBuffer->mpBits = maUserBuffer.get();
716 pBuffer->mnBitCount = mnBits;
717 switch( mnBits )
719 case 1: pBuffer->mnFormat = BMP_FORMAT_1BIT_MSB_PAL; break;
720 case 4: pBuffer->mnFormat = BMP_FORMAT_4BIT_MSN_PAL; break;
721 case 8: pBuffer->mnFormat = BMP_FORMAT_8BIT_PAL; break;
722 case 16: pBuffer->mnFormat = BMP_FORMAT_16BIT_TC_MSB_MASK;
723 pBuffer->maColorMask = ColorMask( 0xf800, 0x07e0, 0x001f );
724 break;
725 case 24: pBuffer->mnFormat = BMP_FORMAT_24BIT_TC_RGB; break;
726 case 32: pBuffer->mnFormat = BMP_FORMAT_32BIT_TC_RGBA;
727 pBuffer->maColorMask = ColorMask( 0xff000000, 0x00ff0000, 0x0000ff00 );
728 break;
731 return pBuffer;
734 void OpenGLSalBitmap::ReleaseBuffer( BitmapBuffer* pBuffer, BitmapAccessMode nMode )
736 OpenGLZone aZone;
738 if( nMode == BITMAP_WRITE_ACCESS )
740 maTexture = OpenGLTexture();
741 mbDirtyTexture = true;
742 mbChecksumValid = false;
744 // The palette is modified on read during the BitmapWriteAccess,
745 // but of course, often it is not modified; interesting.
746 maPalette = pBuffer->maPalette;
748 // Are there any more ground movements underneath us ?
749 assert( pBuffer->mnWidth == mnWidth );
750 assert( pBuffer->mnHeight == mnHeight );
751 assert( pBuffer->mnBitCount == mnBits );
753 delete pBuffer;
756 bool OpenGLSalBitmap::GetSystemData( BitmapSystemData& /*rData*/ )
758 SAL_WARN( "vcl.opengl", "*** NOT IMPLEMENTED *** GetSystemData" );
759 #if 0
760 // TODO Implement for ANDROID/OSX/IOS/WIN32
761 X11SalBitmap rBitmap;
762 BitmapBuffer* pBuffer;
764 rBitmap.Create( GetSize(), mnBits, maPalette );
765 pBuffer = rBitmap.AcquireBuffer( false );
766 if( pBuffer == NULL )
767 return false;
769 if( !maUserBuffer.get() )
771 if( !AllocateUserData() || !ReadTexture() )
773 rBitmap.ReleaseBuffer( pBuffer, false );
774 return false;
778 // TODO Might be more efficient to add a static method to SalBitmap
779 // to get system data from a buffer
780 memcpy( pBuffer->mpBits, maUserBuffer.get(), mnBytesPerRow * mnHeight );
782 rBitmap.ReleaseBuffer( pBuffer, false );
783 return rBitmap.GetSystemData( rData );
784 #else
785 return false;
786 #endif
789 bool OpenGLSalBitmap::Crop( const Rectangle& /*rRectPixel*/ )
791 return false;
794 bool OpenGLSalBitmap::Erase( const ::Color& /*rFillColor*/ )
796 return false;
799 bool OpenGLSalBitmap::Replace( const Color& rSearchColor, const Color& rReplaceColor, sal_uLong nTol )
801 OpenGLZone aZone;
803 OpenGLFramebuffer* pFramebuffer;
804 OpenGLProgram* pProgram;
806 GetTexture();
807 makeCurrent();
808 pProgram = mpContext->UseProgram( "textureVertexShader",
809 "replaceColorFragmentShader" );
810 if( !pProgram )
811 return false;
813 OpenGLTexture aNewTex = OpenGLTexture( mnWidth, mnHeight );
814 pFramebuffer = mpContext->AcquireFramebuffer( aNewTex );
816 pProgram->SetTexture( "sampler", maTexture );
817 pProgram->SetColor( "search_color", rSearchColor );
818 pProgram->SetColor( "replace_color", rReplaceColor );
819 pProgram->SetUniform1f( "epsilon", nTol / 255.0f );
820 pProgram->DrawTexture( maTexture );
821 pProgram->Clean();
823 OpenGLContext::ReleaseFramebuffer( pFramebuffer );
824 maTexture = aNewTex;
826 CHECK_GL_ERROR();
827 return true;
830 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */