11#include <config_vclplug.h>
13#include <osl/file.hxx>
14#include <rtl/bootstrap.hxx>
15#include <rtl/digest.h>
16#include <rtl/strbuf.hxx>
17#include <rtl/ustring.hxx>
20#include <config_folders.h>
24#include <officecfg/Office/Common.hxx>
25#include <com/sun/star/util/XFlushable.hpp>
26#include <com/sun/star/configuration/theDefaultProvider.hpp>
31#include <unordered_map>
55OUString getShaderFolder()
57 OUString aUrl(
"$BRAND_BASE_DIR/" LIBO_ETC_FOLDER);
58 rtl::Bootstrap::expandMacros(aUrl);
60 return aUrl +
"/opengl/";
63OString loadShader(std::u16string_view rFilename)
65 OUString aFileURL = getShaderFolder() + rFilename +
".glsl";
66 osl::File aFile(aFileURL);
67 if(aFile.open(osl_File_OpenFlag_Read) == osl::FileBase::E_None)
71 std::unique_ptr<char[]> content(
new char[nSize+1]);
72 sal_uInt64 nBytesRead = 0;
73 aFile.read(content.get(), nSize, nBytesRead);
74 assert(nSize == nBytesRead);
75 content.get()[nBytesRead] = 0;
76 SAL_INFO(
"vcl.opengl",
"Read " << nBytesRead <<
" bytes from " << aFileURL);
81 SAL_WARN(
"vcl.opengl",
"Could not open " << aFileURL);
87OString& getShaderSource(
const OUString& rFilename)
89 static std::unordered_map<OUString, OString>
aMap;
91 if (
aMap.find(rFilename) ==
aMap.end())
93 aMap[rFilename] = loadShader(rFilename);
96 return aMap[rFilename];
102 int LogCompilerError(GLuint nId,
const OUString &rDetail,
103 const OUString &rName,
bool bShaderNotProgram)
107 int InfoLogLength = 0;
111 if (bShaderNotProgram)
112 glGetShaderiv (nId, GL_INFO_LOG_LENGTH, &InfoLogLength);
114 glGetProgramiv(nId, GL_INFO_LOG_LENGTH, &InfoLogLength);
118 if ( InfoLogLength > 0 )
120 std::vector<char> ErrorMessage(InfoLogLength+1);
121 if (bShaderNotProgram)
122 glGetShaderInfoLog (nId, InfoLogLength,
nullptr, ErrorMessage.data());
124 glGetProgramInfoLog(nId, InfoLogLength,
nullptr, ErrorMessage.data());
127 ErrorMessage.push_back(
'\0');
128 SAL_WARN(
"vcl.opengl", rDetail <<
" shader " << nId <<
" compile for " << rName <<
" failed : " << ErrorMessage.data());
131 SAL_WARN(
"vcl.opengl", rDetail <<
" shader: " << rName <<
" compile " << nId <<
" failed without error log");
140static void addPreamble(OString& rShaderSource, std::string_view rPreamble)
142 if (rPreamble.empty())
145 int nVersionStrStartPos = rShaderSource.indexOf(
"#version");
147 if (nVersionStrStartPos == -1)
149 rShaderSource = OString::Concat(rPreamble) +
"\n" + rShaderSource;
153 int nVersionStrEndPos = rShaderSource.indexOf(
'\n', nVersionStrStartPos);
155 SAL_WARN_IF(nVersionStrEndPos == -1,
"vcl.opengl",
"syntax error in shader");
157 if (nVersionStrEndPos == -1)
158 nVersionStrEndPos = nVersionStrStartPos + 8;
160 OString aVersionLine = rShaderSource.copy(0, nVersionStrEndPos);
161 OString aShaderBody = rShaderSource.copy(nVersionStrEndPos + 1);
163 rShaderSource = aVersionLine +
"\n" + rPreamble +
"\n" + aShaderBody;
169 const sal_uInt32 GLenumSize =
sizeof(GLenum);
172 OString getHexString(
const sal_uInt8* pData, sal_uInt32 nLength)
174 static const char*
const pHexData =
"0123456789ABCDEF";
177 OStringBuffer aHexStr;
184 OStringChar(pHexData[ val & 0xf ]) + OStringChar(pHexData[ val >> 4 ]) );
189 return aHexStr.makeStringAndClear();
192 OString generateMD5(
const void* pData,
size_t length)
194 sal_uInt8 pBuffer[RTL_DIGEST_LENGTH_MD5];
195 rtlDigestError aError = rtl_digest_MD5(pData, length,
196 pBuffer, RTL_DIGEST_LENGTH_MD5);
197 SAL_WARN_IF(aError != rtl_Digest_E_None,
"vcl.opengl",
"md5 generation failed");
199 return getHexString(pBuffer, RTL_DIGEST_LENGTH_MD5);
208 OString::number(DriverBlocklist::GetWindowsVersion());
211 OString getStringDigest(
const OUString& rVertexShaderName,
212 const OUString& rFragmentShaderName,
213 std::string_view rPreamble )
216 OString aVertexShaderSource = getShaderSource( rVertexShaderName );
217 OString aFragmentShaderSource = getShaderSource( rFragmentShaderName );
222 OString aMessage = rPreamble +
223 aVertexShaderSource +
224 aFragmentShaderSource +
227 return generateMD5(aMessage.getStr(), aMessage.getLength());
231 OString getCacheFolder()
233 OUString url(
"${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
"/" SAL_CONFIGFILE(
"bootstrap")
":UserInstallation}/cache/");
234 rtl::Bootstrap::expandMacros(url);
236 osl::Directory::create(url);
242 bool writeProgramBinary(
const OString& rBinaryFileName,
243 const std::vector<sal_uInt8>& rBinary )
245 osl::File aFile(OStringToOUString(rBinaryFileName, RTL_TEXTENCODING_UTF8));
246 osl::FileBase::RC eStatus = aFile.open(
247 osl_File_OpenFlag_Write | osl_File_OpenFlag_Create );
249 if( eStatus != osl::FileBase::E_None )
254 if( eStatus == osl::FileBase::E_EXIST )
257 "No binary program saved. A file with the same hash already exists: '" << rBinaryFileName <<
"'" );
263 sal_uInt64 nBytesWritten = 0;
264 aFile.write( rBinary.data(), rBinary.size(), nBytesWritten );
266 assert( rBinary.size() == nBytesWritten );
271 bool readProgramBinary(
const OString& rBinaryFileName,
272 std::vector<sal_uInt8>& rBinary )
274 osl::File aFile( OStringToOUString( rBinaryFileName, RTL_TEXTENCODING_UTF8 ) );
275 if(aFile.open( osl_File_OpenFlag_Read ) == osl::FileBase::E_None)
277 sal_uInt64 nSize = 0;
278 aFile.getSize( nSize );
279 rBinary.resize( nSize );
280 sal_uInt64 nBytesRead = 0;
281 aFile.read( rBinary.data(), nSize, nBytesRead );
282 assert( nSize == nBytesRead );
283 VCL_GL_INFO(
"Loading file: '" << rBinaryFileName <<
"': success" );
288 VCL_GL_INFO(
"Loading file: '" << rBinaryFileName <<
"': FAIL");
294 OString createFileName( std::u16string_view rVertexShaderName,
295 std::u16string_view rFragmentShaderName,
296 std::u16string_view rGeometryShaderName,
297 std::string_view rDigest )
299 OString aFileName = getCacheFolder() +
302 if (!rGeometryShaderName.empty())
303 aFileName +=
OUStringToOString( rGeometryShaderName, RTL_TEXTENCODING_UTF8 ) +
"-";
304 aFileName += OString::Concat(rDigest) +
".bin";
308 GLint loadProgramBinary( GLuint nProgramID,
const OString& rBinaryFileName )
310 GLint nResult = GL_FALSE;
311 GLenum nBinaryFormat;
312 std::vector<sal_uInt8> aBinary;
313 if( readProgramBinary( rBinaryFileName, aBinary ) && aBinary.size() > GLenumSize )
315 GLint nBinaryLength = aBinary.size() - GLenumSize;
319 for(
size_t i = 0;
i < GLenumSize; ++
i )
321 pBF[
i] = aBinary[nBinaryLength +
i];
325 glProgramBinary( nProgramID, nBinaryFormat, aBinary.data(), nBinaryLength );
328 glGetProgramiv(nProgramID, GL_LINK_STATUS, &nResult);
333 void saveProgramBinary( GLint nProgramID,
const OString& rBinaryFileName )
335 GLint nBinaryLength = 0;
336 GLenum nBinaryFormat = GL_NONE;
338 glGetProgramiv( nProgramID, GL_PROGRAM_BINARY_LENGTH, &nBinaryLength );
339 if( nBinaryLength <= 0 )
341 SAL_WARN(
"vcl.opengl",
"Binary size is zero" );
345 std::vector<sal_uInt8> aBinary( nBinaryLength + GLenumSize );
347 glGetProgramBinary( nProgramID, nBinaryLength,
nullptr, &nBinaryFormat, aBinary.data() );
350 aBinary.insert( aBinary.end(), pBF, pBF + GLenumSize );
352 SAL_INFO(
"vcl.opengl",
"Program id: " << nProgramID );
353 SAL_INFO(
"vcl.opengl",
"Binary length: " << nBinaryLength );
354 SAL_INFO(
"vcl.opengl",
"Binary format: " << nBinaryFormat );
356 if( !writeProgramBinary( rBinaryFileName, aBinary ) )
357 SAL_WARN(
"vcl.opengl",
"Writing binary file '" << rBinaryFileName <<
"': FAIL");
359 SAL_INFO(
"vcl.opengl",
"Writing binary file '" << rBinaryFileName <<
"': success");
364OString OpenGLHelper::GetDigest(
const OUString& rVertexShaderName,
365 const OUString& rFragmentShaderName,
366 std::string_view rPreamble )
368 return getStringDigest(rVertexShaderName, rFragmentShaderName, rPreamble);
373 const OUString& rFragmentShaderName,
374 const OUString& rGeometryShaderName,
375 std::string_view preamble,
376 std::string_view rDigest)
382 bool bHasGeometryShader = !rGeometryShaderName.isEmpty();
385 GLint ProgramID = glCreateProgram();
388 OString aVertexShaderSource = getShaderSource(rVertexShaderName);
389 OString aFragmentShaderSource = getShaderSource(rFragmentShaderName);
390 OString aGeometryShaderSource;
391 if (bHasGeometryShader)
392 aGeometryShaderSource = getShaderSource(rGeometryShaderName);
394 GLint bBinaryResult = GL_FALSE;
395 if (epoxy_has_gl_extension(
"GL_ARB_get_program_binary") && !rDigest.empty())
398 createFileName(rVertexShaderName, rFragmentShaderName, rGeometryShaderName, rDigest);
399 bBinaryResult = loadProgramBinary(ProgramID, aFileName);
403 if( bBinaryResult != GL_FALSE )
406 if (bHasGeometryShader)
407 VCL_GL_INFO(
"Load shader: vertex " << rVertexShaderName <<
" fragment " << rFragmentShaderName <<
" geometry " << rGeometryShaderName);
409 VCL_GL_INFO(
"Load shader: vertex " << rVertexShaderName <<
" fragment " << rFragmentShaderName);
411 GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
412 GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
413 GLuint GeometryShaderID = 0;
414 if (bHasGeometryShader)
415 GeometryShaderID = glCreateShader(GL_GEOMETRY_SHADER);
417 GLint Result = GL_FALSE;
420 if( !preamble.empty())
422 char const * VertexSourcePointer = aVertexShaderSource.getStr();
423 glShaderSource(VertexShaderID, 1, &VertexSourcePointer ,
nullptr);
424 glCompileShader(VertexShaderID);
427 glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
429 return LogCompilerError(VertexShaderID,
"vertex",
430 rVertexShaderName,
true);
433 if( !preamble.empty())
435 char const * FragmentSourcePointer = aFragmentShaderSource.getStr();
436 glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer ,
nullptr);
437 glCompileShader(FragmentShaderID);
440 glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
442 return LogCompilerError(FragmentShaderID,
"fragment",
443 rFragmentShaderName,
true);
445 if (bHasGeometryShader)
448 if( !preamble.empty())
450 char const * GeometrySourcePointer = aGeometryShaderSource.getStr();
451 glShaderSource(GeometryShaderID, 1, &GeometrySourcePointer ,
nullptr);
452 glCompileShader(GeometryShaderID);
455 glGetShaderiv(GeometryShaderID, GL_COMPILE_STATUS, &Result);
457 return LogCompilerError(GeometryShaderID,
"geometry",
458 rGeometryShaderName,
true);
462 glAttachShader(ProgramID, VertexShaderID);
463 glAttachShader(ProgramID, FragmentShaderID);
464 if (bHasGeometryShader)
465 glAttachShader(ProgramID, GeometryShaderID);
467 if (epoxy_has_gl_extension(
"GL_ARB_get_program_binary") && !rDigest.empty())
469 glProgramParameteri(ProgramID, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);
470 glLinkProgram(ProgramID);
471 glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
474 SAL_WARN(
"vcl.opengl",
"linking failed: " << Result );
475 return LogCompilerError(ProgramID,
"program",
"<both>",
false);
478 createFileName(rVertexShaderName, rFragmentShaderName, rGeometryShaderName, rDigest);
479 saveProgramBinary(ProgramID, aFileName);
483 glLinkProgram(ProgramID);
486 glDeleteShader(VertexShaderID);
487 glDeleteShader(FragmentShaderID);
488 if (bHasGeometryShader)
489 glDeleteShader(GeometryShaderID);
492 glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
494 return LogCompilerError(ProgramID,
"program",
"<both>",
false);
506 const OUString& rFragmentShaderName,
507 std::string_view preamble,
508 std::string_view rDigest)
510 return LoadShaders(rVertexShaderName, rFragmentShaderName, OUString(), preamble, rDigest);
514 const OUString& rFragmentShaderName,
515 const OUString& rGeometryShaderName)
517 return LoadShaders(rVertexShaderName, rFragmentShaderName, rGeometryShaderName, std::string_view(), std::string_view());
521 const OUString& rFragmentShaderName)
523 return LoadShaders(rVertexShaderName, rFragmentShaderName, OUString(),
"",
"");
530 std::unique_ptr<sal_uInt8[]> pBuffer(
new sal_uInt8[nWidth*nHeight*4]);
531 glReadPixels(0, 0, nWidth, nHeight,
OptimalBufferFormat(), GL_UNSIGNED_BYTE, pBuffer.get());
536 aWriter.
write( aBitmap );
539 SAL_WARN(
"vcl.opengl",
"Error writing png to " << rFileName);
565 assert(pWriteAccess->IsTopDown());
566 assert(pAlphaWriteAccess->IsTopDown());
569 assert(!pWriteAccess->IsTopDown());
570 assert(!pAlphaWriteAccess->IsTopDown());
578 Scanline pScan = pWriteAccess->GetScanline(
y);
579 Scanline pAlphaScan = pAlphaWriteAccess->GetScanline(
y);
581 Scanline pScan = pWriteAccess->GetScanline(nHeight-1-
y);
582 Scanline pAlphaScan = pAlphaWriteAccess->GetScanline(nHeight-1-
y);
586 *pScan++ = pBuffer[nCurPos];
587 *pScan++ = pBuffer[nCurPos+1];
588 *pScan++ = pBuffer[nCurPos+2];
591 *pAlphaScan++ = pBuffer[nCurPos++];
600 static const struct {
606 {GL_NO_ERROR,
"no error"},
607 {GL_INVALID_ENUM,
"invalid enumerant"},
608 {GL_INVALID_VALUE,
"invalid value"},
609 {GL_INVALID_OPERATION,
"invalid operation"},
610 {GL_STACK_OVERFLOW,
"stack overflow"},
611 {GL_STACK_UNDERFLOW,
"stack underflow"},
612 {GL_OUT_OF_MEMORY,
"out of memory"},
613 {GL_INVALID_FRAMEBUFFER_OPERATION,
"invalid framebuffer operation"},
620 for (
i=0; errors[
i].string;
i++)
622 if (errors[
i].
code == errorCode)
624 return errors[
i].string;
631std::ostream&
operator<<(std::ostream& rStrm,
const glm::vec4& rPos)
633 rStrm <<
"( " << rPos[0] <<
", " << rPos[1] <<
", " << rPos[2] <<
", " << rPos[3] <<
")";
637std::ostream&
operator<<(std::ostream& rStrm,
const glm::vec3& rPos)
639 rStrm <<
"( " << rPos[0] <<
", " << rPos[1] <<
", " << rPos[2] <<
")";
643std::ostream&
operator<<(std::ostream& rStrm,
const glm::mat4& rMatrix)
645 for(
int i = 0;
i < 4; ++
i)
648 for(
int j = 0; j < 4; ++j)
659 GLuint& nRenderbufferDepthId, GLuint& nRenderbufferColorId)
664 glGenRenderbuffers(1, &nRenderbufferDepthId);
665 glBindRenderbuffer(GL_RENDERBUFFER, nRenderbufferDepthId);
666 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, nWidth, nHeight);
667 glBindRenderbuffer(GL_RENDERBUFFER, 0);
669 glGenTextures(1, &nRenderbufferColorId);
670 glBindTexture(GL_TEXTURE_2D, nRenderbufferColorId);
671 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
672 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
673 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
674 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
675 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, nWidth, nHeight, 0,
676 GL_RGBA, GL_UNSIGNED_BYTE,
nullptr);
677 glBindTexture(GL_TEXTURE_2D, 0);
679 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
680 GL_TEXTURE_2D, nRenderbufferColorId, 0);
683 glGenFramebuffers(1, &nFramebufferId);
684 glCheckFramebufferStatus(GL_FRAMEBUFFER);
685 glBindFramebuffer(GL_FRAMEBUFFER, nFramebufferId);
687 glBindRenderbuffer(GL_RENDERBUFFER, nRenderbufferColorId);
688 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, nRenderbufferColorId);
689 glCheckFramebufferStatus(GL_FRAMEBUFFER);
691 glBindRenderbuffer(GL_RENDERBUFFER, nRenderbufferDepthId);
692 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, nRenderbufferDepthId);
693 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
694 if (status != GL_FRAMEBUFFER_COMPLETE)
696 SAL_WARN(
"vcl.opengl",
"invalid framebuffer status");
698 glBindRenderbuffer(GL_RENDERBUFFER, 0);
699 glBindFramebuffer(GL_FRAMEBUFFER, 0);
706 float fVersion = 1.0;
707 const GLubyte* aVersion = glGetString( GL_VERSION );
708 if( aVersion && aVersion[0] )
710 fVersion = aVersion[0] -
'0';
711 if( aVersion[1] ==
'.' && aVersion[2] )
713 fVersion += (aVersion[2] -
'0')/10.0;
728 GLenum glErr = glGetError();
729 if (glErr == GL_NO_ERROR)
735 sError =
"no message available";
737 SAL_WARN(
"vcl.opengl",
"GL Error " << std::hex << std::setw(4) << std::setfill(
'0') << glErr << std::dec << std::setw(0) << std::setfill(
' ') <<
" (" << sError <<
") in file " << pFile <<
" at line " << nLine);
742 SAL_WARN(
"vcl.opengl",
"Breaking potentially recursive glGetError loop");
750 static bool bSet =
false;
751 static bool bDenylisted =
true;
760 if (DriverBlocklist::GetWindowsVersion() == 0x00060001 &&
763 SAL_INFO(
"vcl.opengl",
"Relaxing watchdog timings.");
777 if( getenv(
"SAL_DISABLEGL") !=
nullptr )
783 if( officecfg::Office::Common::VCL::DisableOpenGL::get())
792enum class CrashWatchdogTimingMode
798class CrashWatchdogTimings
801 std::vector<CrashWatchdogTimingsValues> maTimingValues;
802 std::atomic<bool> mbRelaxed;
805 CrashWatchdogTimings();
807 void setRelax(
bool bRelaxed)
809 mbRelaxed = bRelaxed;
814 size_t index = (
eMode == CrashWatchdogTimingMode::SHADER_COMPILE) ? 1 : 0;
817 return maTimingValues[
index];
821CrashWatchdogTimings gWatchdogTimings;
823CrashWatchdogTimings::CrashWatchdogTimings()
825 {{6, 20} , {20, 120} ,
826 {60, 240} , {60, 240} }
841 static bool bDisabled =
false;
848 std::shared_ptr<comphelper::ConfigurationChanges> xChanges(
850 officecfg::Office::Common::VCL::DisableOpenGL::set(
true, xChanges);
854 css::uno::Reference< css::util::XFlushable >(
855 css::configuration::theDefaultProvider::get(
857 css::uno::UNO_QUERY_THROW)->flush();
862 gWatchdogTimings.setRelax(
true);
867 SAL_INFO(
"vcl.watchdog",
"GL watchdog - unchanged "
868 << nUnchanged <<
" enter count " <<
enterCount() <<
" type "
877 CrashWatchdogTimingMode
eMode =
gbInShaderCompile ? CrashWatchdogTimingMode::SHADER_COMPILE : CrashWatchdogTimingMode::NORMAL;
878 return gWatchdogTimings.getWatchdogTimingsValues(
eMode);
884 0,
"%" SAL_PRIxUINT32
": %s", osl_getThreadIdentifier(
nullptr), pStream.str().c_str());
890 1,
"%" SAL_PRIxUINT32
": %s", osl_getThreadIdentifier(
nullptr), pStream.str().c_str());
896 va_start (aArgs, pFormat);
900#define vsnprintf _vsnprintf
902 vsnprintf(pStr,
sizeof(pStr), pFormat, aArgs);
903 pStr[
sizeof(pStr)-20] =
'\0';
907 strcat(pStr,
" (no GL context)");
922 if (epoxy_has_gl_extension(
"GL_KHR_debug"))
923 glDebugMessageInsert(GL_DEBUG_SOURCE_APPLICATION,
927 GL_DEBUG_SEVERITY_LOW,
929 else if (epoxy_has_gl_extension(
"GL_AMD_debug_output"))
930 glDebugMessageInsertAMD(GL_DEBUG_CATEGORY_APPLICATION_AMD,
931 GL_DEBUG_SEVERITY_LOW_AMD,
static void addPreamble(OString &rShaderSource, std::string_view rPreamble)
std::ostream & operator<<(std::ostream &rStrm, const glm::vec4 &rPos)
static bool volatile gbInShaderCompile
#define VCL_GL_INFO(stream)
Helper to do a SAL_INFO as well as a GL log.
static const AtomicCounter & enterCount()
static bool hasCurrent()
Is there a current GL context ?
We want to be able to detect if a given crash came from the OpenGL code, so use this helper to track ...
static const CrashWatchdogTimingsValues & getCrashWatchdogTimingsValues()
static void relaxWatchdogTimings()
static void hardDisable()
Called from a signal handler or watchdog thread if we get a crash or hang in some GL code.
static void checkDebug(int nUnchanged, const CrashWatchdogTimingsValues &aTimingValues)
const OUString & GetAdapterDeviceID() const
const OUString & GetDriverVersion() const
const OUString & GetAdapterVendorID() const
static std::shared_ptr< ConfigurationChanges > create()
bool write(const BitmapEx &rBitmap)
This template handles BitmapAccess the RAII way.
#define SAL_CONFIGFILE(name)
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
std::unique_ptr< sal_Int32[]> pData
Reference< XComponentContext > getProcessComponentContext()
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
HashMap_OWString_Interface aMap
OString getDeviceInfoString(cl_device_id aDeviceId, cl_device_info aDeviceInfo)
static void createFramebuffer(tools::Long nWidth, tools::Long nHeight, GLuint &nFramebufferId, GLuint &nRenderbufferDepthId, GLuint &nRenderbufferColorId)
The caller is responsible for deleting the buffer objects identified by nFramebufferId,...
static float getGLVersion()
Get OpenGL version (needs a context)
static GLenum OptimalBufferFormat()
Returns the optimal buffer format for OpenGL (GL_BGRA or GL_RGBA).
static GLint LoadShaders(const OUString &rVertexShaderName, const OUString &rFragmentShaderName, const OUString &rGeometryShaderName, std::string_view preamble, std::string_view rDigest)
static void debugMsgStreamWarn(std::ostringstream const &pStream)
static const char * GLErrorString(GLenum errorCode)
static BitmapEx ConvertBufferToBitmapEx(const sal_uInt8 *const pBuffer, tools::Long nWidth, tools::Long nHeight)
The caller is responsible for allocating the memory for the buffer before calling this method.
static void checkGLError(const char *aFile, size_t nLine)
static void debugMsgStream(std::ostringstream const &pStream)
static void debugMsgPrint(const int nType, const char *pFormat,...)
Insert a glDebugMessage into the queue - helpful for debugging with apitrace to annotate the output a...
static bool supportsOpenGL()
checks if the system supports all features that are necessary for the OpenGL support
static void renderToFile(tools::Long nWidth, tools::Long nHeight, const OUString &rFileName)
static bool isDeviceDenylisted()
checks if the device/driver pair is on our OpenGL denylist
ImplSVData * ImplGetSVData()