Threaded GLideN64 calls

This commit is contained in:
fzurita 2019-02-22 19:40:58 -05:00 committed by Sergey Lipskiy
parent ae025e10ea
commit 5df3f9dbac
40 changed files with 9956 additions and 740 deletions

1
.gitignore vendored
View File

@ -12,3 +12,4 @@ src/Revision.h
/projects/msvc/GLideN64.VC.VC.opendb
/projects/msvc/GLideN64.VC.db
/projects/msvc/GeneratedFiles
.vs

View File

@ -0,0 +1,28 @@
This license applies to all the code in this repository except that written by third
parties, namely the files in benchmarks/ext, which have their own licenses, and Jeff
Preshing's semaphore implementation (used in the blocking queue) which has a zlib
license (embedded in atomicops.h).
Simplified BSD License:
Copyright (c) 2013-2015, Cameron Desrochers
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this list of
conditions and the following disclaimer in the documentation and/or other materials
provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -260,9 +260,17 @@ copy /Y "$(OutDir)$(TargetName).*" "$(Mupen64PluginsDir_x64)")</Command>
<ClCompile Include="..\..\src\Graphics\OpenGLContext\opengl_UnbufferedDrawer.cpp" />
<ClCompile Include="..\..\src\Graphics\OpenGLContext\opengl_Utils.cpp" />
<ClCompile Include="..\..\src\Graphics\OpenGLContext\opengl_BufferedDrawer.cpp" />
<ClCompile Include="..\..\src\Graphics\OpenGLContext\ThreadedOpenGl\opengl_Wrapper.cpp" />
<ClCompile Include="..\..\src\Graphics\OpenGLContext\ThreadedOpenGl\opengl_WrappedFunctions.cpp" />
<ClCompile Include="..\..\src\Graphics\OpenGLContext\ThreadedOpenGl\opengl_Command.cpp" />
<ClCompile Include="..\..\src\Graphics\OpenGLContext\ThreadedOpenGl\opengl_ObjectPool.cpp" />
<ClCompile Include="..\..\src\Graphics\OpenGLContext\ThreadedOpenGl\RingBufferPool.cpp" />
<ClCompile Include="..\..\src\Graphics\OpenGLContext\windows\windows_DisplayWindow.cpp">
<ExcludedFromBuild Condition="'$(Configuration)'=='Debug_mupenplus' Or '$(Configuration)'=='Release_mupenplus'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\Graphics\OpenGLContext\windows\WindowsWGL.cpp">
<ExcludedFromBuild Condition="'$(Configuration)'=='Debug_mupenplus' Or '$(Configuration)'=='Release_mupenplus'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\gSP.cpp" />
<ClCompile Include="..\..\src\iob.cpp">
<ExcludedFromBuild Condition="'$(Platform)'=='Win32'">true</ExcludedFromBuild>
@ -404,6 +412,17 @@ copy /Y "$(OutDir)$(TargetName).*" "$(Mupen64PluginsDir_x64)")</Command>
<ClInclude Include="..\..\src\Graphics\OpenGLContext\opengl_UnbufferedDrawer.h" />
<ClInclude Include="..\..\src\Graphics\OpenGLContext\opengl_Utils.h" />
<ClInclude Include="..\..\src\Graphics\OpenGLContext\opengl_BufferedDrawer.h" />
<ClInclude Include="..\..\src\Graphics\OpenGLContext\ThreadedOpenGl\atomicops.h" />
<ClInclude Include="..\..\src\Graphics\OpenGLContext\ThreadedOpenGl\opengl_Wrapper.h" />
<ClInclude Include="..\..\src\Graphics\OpenGLContext\ThreadedOpenGl\opengl_WrappedFunctions.h" />
<ClInclude Include="..\..\src\Graphics\OpenGLContext\ThreadedOpenGl\BlockingQueue.h" />
<ClInclude Include="..\..\src\Graphics\OpenGLContext\ThreadedOpenGl\opengl_Command.h" />
<ClInclude Include="..\..\src\Graphics\OpenGLContext\ThreadedOpenGl\opengl_ObjectPool.h" />
<ClInclude Include="..\..\src\Graphics\OpenGLContext\ThreadedOpenGl\readerwriterqueue.h" />
<ClInclude Include="..\..\src\Graphics\OpenGLContext\ThreadedOpenGl\RingBufferPool.h" />
<ClInclude Include="..\..\src\Graphics\OpenGLContext\windows\WindowsWGL.h">
<ExcludedFromBuild Condition="'$(Configuration)'=='Debug_mupenplus' Or '$(Configuration)'=='Release_mupenplus'">true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="..\..\src\Graphics\Parameter.h" />
<ClInclude Include="..\..\src\Graphics\Parameters.h" />
<ClInclude Include="..\..\src\Graphics\PixelBuffer.h" />

View File

@ -69,6 +69,12 @@
<Filter Include="Source Files\Graphics\OpenGL\mupen64plus">
<UniqueIdentifier>{77259791-9942-4601-a63f-5a0468e69e49}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\Graphics\OpenGL\ThreadedOpenGL">
<UniqueIdentifier>{09919f83-2933-4b48-a4c7-f7bf6e790304}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Graphics\OpenGL\ThreadedOpenGL">
<UniqueIdentifier>{32e9be50-cb55-445a-9562-bbe05085bbe1}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\Combiner.cpp">
@ -260,6 +266,9 @@
<ClCompile Include="..\..\src\Graphics\OpenGLContext\windows\windows_DisplayWindow.cpp">
<Filter>Source Files\Graphics\OpenGL\windows</Filter>
</ClCompile>
<ClCompile Include="..\..\src\Graphics\OpenGLContext\windows\WindowsWGL.cpp">
<Filter>Source Files\Graphics\OpenGL\windows</Filter>
</ClCompile>
<ClCompile Include="..\..\src\Graphics\OpenGLContext\mupen64plus\mupen64plus_DisplayWindow.cpp">
<Filter>Source Files\Graphics\OpenGL\mupen64plus</Filter>
</ClCompile>
@ -398,6 +407,21 @@
<ClCompile Include="..\..\src\mupenplus\MemoryStatus_mupenplus.cpp">
<Filter>Source Files\mupenplus</Filter>
</ClCompile>
<ClCompile Include="..\..\src\Graphics\OpenGLContext\ThreadedOpenGl\opengl_Wrapper.cpp">
<Filter>Source Files\Graphics\OpenGL\ThreadedOpenGL</Filter>
</ClCompile>
<ClCompile Include="..\..\src\Graphics\OpenGLContext\ThreadedOpenGl\opengl_WrappedFunctions.cpp">
<Filter>Source Files\Graphics\OpenGL\ThreadedOpenGL</Filter>
</ClCompile>
<ClCompile Include="..\..\src\Graphics\OpenGLContext\ThreadedOpenGl\opengl_Command.cpp">
<Filter>Source Files\Graphics\OpenGL\ThreadedOpenGL</Filter>
</ClCompile>
<ClCompile Include="..\..\src\Graphics\OpenGLContext\ThreadedOpenGl\opengl_ObjectPool.cpp">
<Filter>Source Files\Graphics\OpenGL\ThreadedOpenGL</Filter>
</ClCompile>
<ClCompile Include="..\..\src\Graphics\OpenGLContext\ThreadedOpenGl\RingBufferPool.cpp">
<Filter>Source Files\Graphics\OpenGL\ThreadedOpenGL</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\3DMath.h">
@ -634,6 +658,9 @@
<ClInclude Include="..\..\src\Graphics\OpenGLContext\opengl_ColorBufferReaderWithReadPixels.h">
<Filter>Header Files\Graphics\OpenGL</Filter>
</ClInclude>
<ClInclude Include="..\..\src\Graphics\OpenGLContext\windows\WindowsWGL.h">
<Filter>Header Files\Graphics\OpenGL\windows</Filter>
</ClInclude>
<ClInclude Include="..\..\src\TexrectDrawer.h">
<Filter>Header Files</Filter>
</ClInclude>
@ -730,5 +757,29 @@
<ClInclude Include="..\..\src\MemoryStatus.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\src\Graphics\OpenGLContext\ThreadedOpenGl\opengl_Wrapper.h">
<Filter>Header Files\Graphics\OpenGL\ThreadedOpenGL</Filter>
</ClInclude>
<ClInclude Include="..\..\src\Graphics\OpenGLContext\ThreadedOpenGl\opengl_WrappedFunctions.h">
<Filter>Header Files\Graphics\OpenGL\ThreadedOpenGL</Filter>
</ClInclude>
<ClInclude Include="..\..\src\Graphics\OpenGLContext\ThreadedOpenGl\BlockingQueue.h">
<Filter>Header Files\Graphics\OpenGL\ThreadedOpenGL</Filter>
</ClInclude>
<ClInclude Include="..\..\src\Graphics\OpenGLContext\ThreadedOpenGl\opengl_Command.h">
<Filter>Header Files\Graphics\OpenGL\ThreadedOpenGL</Filter>
</ClInclude>
<ClInclude Include="..\..\src\Graphics\OpenGLContext\ThreadedOpenGl\opengl_ObjectPool.h">
<Filter>Header Files\Graphics\OpenGL\ThreadedOpenGL</Filter>
</ClInclude>
<ClInclude Include="..\..\src\Graphics\OpenGLContext\ThreadedOpenGl\RingBufferPool.h">
<Filter>Header Files\Graphics\OpenGL\ThreadedOpenGL</Filter>
</ClInclude>
<ClInclude Include="..\..\src\Graphics\OpenGLContext\ThreadedOpenGl\atomicops.h">
<Filter>Header Files\Graphics\OpenGL\ThreadedOpenGL</Filter>
</ClInclude>
<ClInclude Include="..\..\src\Graphics\OpenGLContext\ThreadedOpenGl\readerwriterqueue.h">
<Filter>Header Files\Graphics\OpenGL\ThreadedOpenGL</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -61,6 +61,11 @@ set(GLideN64_SOURCES
Graphics/CombinerProgram.cpp
Graphics/ObjectHandle.cpp
Graphics/OpenGLContext/GLFunctions.cpp
Graphics/OpenGLContext/ThreadedOpenGl/opengl_Command.cpp
Graphics/OpenGLContext/ThreadedOpenGl/opengl_ObjectPool.cpp
Graphics/OpenGLContext/ThreadedOpenGl/opengl_Wrapper.cpp
Graphics/OpenGLContext/ThreadedOpenGl/opengl_WrappedFunctions.cpp
Graphics/OpenGLContext/ThreadedOpenGl/RingBufferPool.cpp
Graphics/OpenGLContext/opengl_Attributes.cpp
Graphics/OpenGLContext/opengl_BufferedDrawer.cpp
Graphics/OpenGLContext/opengl_BufferManipulationObjectFactory.cpp

View File

@ -25,6 +25,7 @@ void Config::resetToDefaults()
video.fxaa = 0;
video.multisampling = 0;
video.verticalSync = 0;
video.threadedVideo = 0;
texture.maxAnisotropy = 0;
texture.bilinearMode = BILINEAR_STANDARD;

View File

@ -28,6 +28,7 @@ struct Config
u32 fxaa;
u32 multisampling;
u32 verticalSync;
u32 threadedVideo;
} video;
struct

View File

@ -117,6 +117,7 @@ void ConfigDialog::_init()
ui->aliasingLabelVal->setText(QString::number(config.video.multisampling));
ui->anisotropicSlider->setValue(config.texture.maxAnisotropy);
ui->vSyncCheckBox->setChecked(config.video.verticalSync != 0);
ui->vThreadedVideoCheckBox->setChecked(config.video.threadedVideo != 0);
switch (config.texture.bilinearMode) {
case BILINEAR_3POINT:
@ -426,6 +427,8 @@ void ConfigDialog::accept()
config.video.verticalSync = ui->vSyncCheckBox->isChecked() ? 1 : 0;
config.video.threadedVideo = ui->vThreadedVideoCheckBox->isChecked() ? 1 : 0;
// Emulation settings
config.generalEmulation.enableLOD = ui->emulateLodCheckBox->isChecked() ? 1 : 0;
config.generalEmulation.enableNoise = ui->emulateNoiseCheckBox->isChecked() ? 1 : 0;

View File

@ -29,6 +29,7 @@ void _loadSettings(QSettings & settings)
config.video.multisampling = settings.value("multisampling", config.video.multisampling).toInt();
config.video.fxaa= settings.value("fxaa", config.video.fxaa).toInt();
config.video.verticalSync = settings.value("verticalSync", config.video.verticalSync).toInt();
config.video.threadedVideo = settings.value("threadedVideo", config.video.threadedVideo).toInt();
settings.endGroup();
settings.beginGroup("texture");
@ -197,6 +198,7 @@ void writeSettings(const QString & _strIniFolder)
settings.setValue("multisampling", config.video.multisampling);
settings.setValue("fxaa", config.video.fxaa);
settings.setValue("verticalSync", config.video.verticalSync);
settings.setValue("threadedVideo", config.video.threadedVideo);
settings.endGroup();
settings.beginGroup("texture");

View File

@ -160,6 +160,16 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="vThreadedVideoCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Threaded video can improve performance with poor OpenGL drivers at the cost of very marginal input lag, usually less than half a frame&lt;/p&gt;&lt;p&gt;[Recommended: &lt;span style=&quot; font-style:italic;&quot;&gt;Usually off, unless there are performance issues.&lt;/span&gt;]&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Enable threaded video</string>
</property>
</widget>
</item>
<item>
<widget class="QFrame" name="overscanFrame">
<property name="minimumSize">

View File

@ -1,18 +1,21 @@
#include "GLFunctions.h"
#define ASSIGN_PROC_ADR(proc_type, proc_name) ptr##proc_name = gl##proc_name
#ifdef OS_WINDOWS
#define glGetProcAddress wglGetProcAddress
#define GL_GET_PROC_ADR(proc_type, proc_name) g_##proc_name = (proc_type) glGetProcAddress(#proc_name)
#define GL_GET_PROC_ADR(proc_type, proc_name) ptr##proc_name = (proc_type) glGetProcAddress("gl"#proc_name)
#elif defined(VERO4K) || defined(ODROID) || defined(VC)
#define GL_GET_PROC_ADR(proc_type, proc_name) g_##proc_name = (proc_type) dlsym(gles2so, #proc_name);
#define GL_GET_PROC_ADR(proc_type, proc_name) ptr##proc_name = (proc_type) dlsym(gles2so, "gl"#proc_name);
#elif defined(EGL)
#define glGetProcAddress eglGetProcAddress
#define GL_GET_PROC_ADR(proc_type, proc_name) g_##proc_name = (proc_type) glGetProcAddress(#proc_name)
#define GL_GET_PROC_ADR(proc_type, proc_name) ptr##proc_name = (proc_type) glGetProcAddress("gl"#proc_name)
#define GL_GET_PROC_ADR_EGL(proc_type, proc_name) ptr##proc_name = (proc_type) glGetProcAddress("egl"#proc_name)
#elif defined(OS_LINUX)
@ -28,7 +31,7 @@ typedef struct __GLXFBConfigRec *GLXFBConfig;
#define GLX_GLXEXT_PROTOTYPES
#include <GL/glxext.h>
#define glGetProcAddress glXGetProcAddress
#define GL_GET_PROC_ADR(proc_type, proc_name) g_##proc_name = (proc_type) glGetProcAddress((const GLubyte*)#proc_name)
#define GL_GET_PROC_ADR(proc_type, proc_name) ptr##proc_name = (proc_type) glGetProcAddress((const GLubyte*)#proc_name)
#elif defined(OS_MAC_OS_X)
#include <dlfcn.h>
@ -42,7 +45,7 @@ static void* AppleGLGetProcAddress (const char *name)
return (image ? dlsym(image, name) : NULL);
}
#define glGetProcAddress AppleGLGetProcAddress
#define GL_GET_PROC_ADR(proc_type, proc_name) g_##proc_name = (proc_type) glGetProcAddress(#proc_name)
#define GL_GET_PROC_ADR(proc_type, proc_name) ptr##proc_name = (proc_type) glGetProcAddress(#proc_name)
#elif defined(OS_IOS)
#include <dlfcn.h>
@ -53,150 +56,145 @@ static void* IOSGLGetProcAddress (const char *name)
}
#define glGetProcAddress IOSGLGetProcAddress
#define GL_GET_PROC_ADR(proc_type, proc_name) g_##proc_name = (proc_type)glGetProcAddress(#proc_name)
#define GL_GET_PROC_ADR(proc_type, proc_name) ptr##proc_name = (proc_type)glGetProcAddress(#proc_name)
#endif
//GL Fucntions
#ifdef OS_WINDOWS
PFNGLACTIVETEXTUREPROC g_glActiveTexture;
PFNGLBLENDCOLORPROC g_glBlendColor;
#elif defined(EGL) || defined(OS_IOS)
PFNGLBLENDFUNCPROC g_glBlendFunc;
PFNGLPIXELSTOREIPROC g_glPixelStorei;
PFNGLCLEARCOLORPROC g_glClearColor;
PFNGLCULLFACEPROC g_glCullFace;
PFNGLDEPTHFUNCPROC g_glDepthFunc;
PFNGLDEPTHMASKPROC g_glDepthMask;
PFNGLDISABLEPROC g_glDisable;
PFNGLENABLEPROC g_glEnable;
PFNGLPOLYGONOFFSETPROC g_glPolygonOffset;
PFNGLSCISSORPROC g_glScissor;
PFNGLVIEWPORTPROC g_glViewport;
PFNGLBINDTEXTUREPROC g_glBindTexture;
PFNGLTEXIMAGE2DPROC g_glTexImage2D;
PFNGLTEXPARAMETERIPROC g_glTexParameteri;
PFNGLGETINTEGERVPROC g_glGetIntegerv;
PFNGLGETSTRINGPROC g_glGetString;
PFNGLREADPIXELSPROC g_glReadPixels;
PFNGLTEXSUBIMAGE2DPROC g_glTexSubImage2D;
PFNGLDRAWARRAYSPROC g_glDrawArrays;
PFNGLGETERRORPROC g_glGetError;
PFNGLDRAWELEMENTSPROC g_glDrawElements;
PFNGLLINEWIDTHPROC g_glLineWidth;
PFNGLCLEARPROC g_glClear;
PFNGLGETFLOATVPROC g_glGetFloatv;
PFNGLDELETETEXTURESPROC g_glDeleteTextures;
PFNGLGENTEXTURESPROC g_glGenTextures;
PFNGLTEXPARAMETERFPROC g_glTexParameterf;
PFNGLACTIVETEXTUREPROC g_glActiveTexture;
PFNGLBLENDCOLORPROC g_glBlendColor;
PFNGLREADBUFFERPROC g_glReadBuffer;
PFNGLFINISHPROC g_glFinish;
PFNGLBLENDFUNCPROC ptrBlendFunc;
PFNGLPIXELSTOREIPROC ptrPixelStorei;
PFNGLCLEARCOLORPROC ptrClearColor;
PFNGLCULLFACEPROC ptrCullFace;
PFNGLDEPTHFUNCPROC ptrDepthFunc;
PFNGLDEPTHMASKPROC ptrDepthMask;
PFNGLDISABLEPROC ptrDisable;
PFNGLENABLEPROC ptrEnable;
PFNGLPOLYGONOFFSETPROC ptrPolygonOffset;
PFNGLSCISSORPROC ptrScissor;
PFNGLVIEWPORTPROC ptrViewport;
PFNGLBINDTEXTUREPROC ptrBindTexture;
PFNGLTEXIMAGE2DPROC ptrTexImage2D;
PFNGLTEXPARAMETERIPROC ptrTexParameteri;
PFNGLGETINTEGERVPROC ptrGetIntegerv;
PFNGLGETSTRINGPROC ptrGetString;
PFNGLREADPIXELSPROC ptrReadPixels;
PFNGLTEXSUBIMAGE2DPROC ptrTexSubImage2D;
PFNGLDRAWARRAYSPROC ptrDrawArrays;
PFNGLGETERRORPROC ptrGetError;
PFNGLDRAWELEMENTSPROC ptrDrawElements;
PFNGLLINEWIDTHPROC ptrLineWidth;
PFNGLCLEARPROC ptrClear;
PFNGLGETFLOATVPROC ptrGetFloatv;
PFNGLDELETETEXTURESPROC ptrDeleteTextures;
PFNGLGENTEXTURESPROC ptrGenTextures;
PFNGLTEXPARAMETERFPROC ptrTexParameterf;
PFNGLACTIVETEXTUREPROC ptrActiveTexture;
PFNGLBLENDCOLORPROC ptrBlendColor;
PFNGLREADBUFFERPROC ptrReadBuffer;
PFNGLFINISHPROC ptrFinish;
#if defined(OS_ANDROID)
PFNEGLGETNATIVECLIENTBUFFERANDROIDPROC g_eglGetNativeClientBufferANDROID;
PFNEGLGETNATIVECLIENTBUFFERANDROIDPROC ptrGetNativeClientBufferANDROID;
#endif
#endif
PFNGLCREATESHADERPROC g_glCreateShader;
PFNGLCOMPILESHADERPROC g_glCompileShader;
PFNGLSHADERSOURCEPROC g_glShaderSource;
PFNGLCREATEPROGRAMPROC g_glCreateProgram;
PFNGLATTACHSHADERPROC g_glAttachShader;
PFNGLLINKPROGRAMPROC g_glLinkProgram;
PFNGLUSEPROGRAMPROC g_glUseProgram;
PFNGLGETUNIFORMLOCATIONPROC g_glGetUniformLocation;
PFNGLUNIFORM1IPROC g_glUniform1i;
PFNGLUNIFORM1FPROC g_glUniform1f;
PFNGLUNIFORM2FPROC g_glUniform2f;
PFNGLUNIFORM2IPROC g_glUniform2i;
PFNGLUNIFORM4IPROC g_glUniform4i;
PFNGLUNIFORM4FPROC g_glUniform4f;
PFNGLUNIFORM3FVPROC g_glUniform3fv;
PFNGLUNIFORM4FVPROC g_glUniform4fv;
PFNGLDETACHSHADERPROC g_glDetachShader;
PFNGLDELETESHADERPROC g_glDeleteShader;
PFNGLDELETEPROGRAMPROC g_glDeleteProgram;
PFNGLGETPROGRAMINFOLOGPROC g_glGetProgramInfoLog;
PFNGLGETSHADERINFOLOGPROC g_glGetShaderInfoLog;
PFNGLGETSHADERIVPROC g_glGetShaderiv;
PFNGLGETPROGRAMIVPROC g_glGetProgramiv;
PFNGLENABLEVERTEXATTRIBARRAYPROC g_glEnableVertexAttribArray;
PFNGLDISABLEVERTEXATTRIBARRAYPROC g_glDisableVertexAttribArray;
PFNGLVERTEXATTRIBPOINTERPROC g_glVertexAttribPointer;
PFNGLBINDATTRIBLOCATIONPROC g_glBindAttribLocation;
PFNGLVERTEXATTRIB1FPROC g_glVertexAttrib1f;
PFNGLVERTEXATTRIB4FPROC g_glVertexAttrib4f;
PFNGLVERTEXATTRIB4FVPROC g_glVertexAttrib4fv;
PFNGLCREATESHADERPROC ptrCreateShader;
PFNGLCOMPILESHADERPROC ptrCompileShader;
PFNGLSHADERSOURCEPROC ptrShaderSource;
PFNGLCREATEPROGRAMPROC ptrCreateProgram;
PFNGLATTACHSHADERPROC ptrAttachShader;
PFNGLLINKPROGRAMPROC ptrLinkProgram;
PFNGLUSEPROGRAMPROC ptrUseProgram;
PFNGLGETUNIFORMLOCATIONPROC ptrGetUniformLocation;
PFNGLUNIFORM1IPROC ptrUniform1i;
PFNGLUNIFORM1FPROC ptrUniform1f;
PFNGLUNIFORM2FPROC ptrUniform2f;
PFNGLUNIFORM2IPROC ptrUniform2i;
PFNGLUNIFORM4IPROC ptrUniform4i;
PFNGLUNIFORM4FPROC ptrUniform4f;
PFNGLUNIFORM3FVPROC ptrUniform3fv;
PFNGLUNIFORM4FVPROC ptrUniform4fv;
PFNGLDETACHSHADERPROC ptrDetachShader;
PFNGLDELETESHADERPROC ptrDeleteShader;
PFNGLDELETEPROGRAMPROC ptrDeleteProgram;
PFNGLGETPROGRAMINFOLOGPROC ptrGetProgramInfoLog;
PFNGLGETSHADERINFOLOGPROC ptrGetShaderInfoLog;
PFNGLGETSHADERIVPROC ptrGetShaderiv;
PFNGLGETPROGRAMIVPROC ptrGetProgramiv;
PFNGLENABLEVERTEXATTRIBARRAYPROC ptrEnableVertexAttribArray;
PFNGLDISABLEVERTEXATTRIBARRAYPROC ptrDisableVertexAttribArray;
PFNGLVERTEXATTRIBPOINTERPROC ptrVertexAttribPointer;
PFNGLBINDATTRIBLOCATIONPROC ptrBindAttribLocation;
PFNGLVERTEXATTRIB1FPROC ptrVertexAttrib1f;
PFNGLVERTEXATTRIB4FPROC ptrVertexAttrib4f;
PFNGLVERTEXATTRIB4FVPROC ptrVertexAttrib4fv;
// multitexture functions
PFNGLDEPTHRANGEFPROC g_glDepthRangef;
PFNGLCLEARDEPTHFPROC g_glClearDepthf;
PFNGLDEPTHRANGEFPROC ptrDepthRangef;
PFNGLCLEARDEPTHFPROC ptrClearDepthf;
PFNGLDRAWBUFFERSPROC g_glDrawBuffers;
PFNGLBINDFRAMEBUFFERPROC g_glBindFramebuffer;
PFNGLDELETEFRAMEBUFFERSPROC g_glDeleteFramebuffers;
PFNGLGENFRAMEBUFFERSPROC g_glGenFramebuffers;
PFNGLFRAMEBUFFERTEXTURE2DPROC g_glFramebufferTexture2D;
PFNGLTEXIMAGE2DMULTISAMPLEPROC g_glTexImage2DMultisample;
PFNGLTEXSTORAGE2DMULTISAMPLEPROC g_glTexStorage2DMultisample;
PFNGLGENRENDERBUFFERSPROC g_glGenRenderbuffers;
PFNGLBINDRENDERBUFFERPROC g_glBindRenderbuffer;
PFNGLRENDERBUFFERSTORAGEPROC g_glRenderbufferStorage;
PFNGLFRAMEBUFFERRENDERBUFFERPROC g_glFramebufferRenderbuffer;
PFNGLDELETERENDERBUFFERSPROC g_glDeleteRenderbuffers;
PFNGLCHECKFRAMEBUFFERSTATUSPROC g_glCheckFramebufferStatus;
PFNGLBLITFRAMEBUFFERPROC g_glBlitFramebuffer;
PFNGLGENVERTEXARRAYSPROC g_glGenVertexArrays;
PFNGLBINDVERTEXARRAYPROC g_glBindVertexArray;
PFNGLDELETEVERTEXARRAYSPROC g_glDeleteVertexArrays;
PFNGLGENBUFFERSPROC g_glGenBuffers;
PFNGLBINDBUFFERPROC g_glBindBuffer;
PFNGLBUFFERDATAPROC g_glBufferData;
PFNGLMAPBUFFERPROC g_glMapBuffer;
PFNGLMAPBUFFERRANGEPROC g_glMapBufferRange;
PFNGLUNMAPBUFFERPROC g_glUnmapBuffer;
PFNGLDELETEBUFFERSPROC g_glDeleteBuffers;
PFNGLBINDIMAGETEXTUREPROC g_glBindImageTexture;
PFNGLMEMORYBARRIERPROC g_glMemoryBarrier;
PFNGLGETSTRINGIPROC g_glGetStringi;
PFNGLINVALIDATEFRAMEBUFFERPROC g_glInvalidateFramebuffer;
PFNGLBUFFERSTORAGEPROC g_glBufferStorage;
PFNGLFENCESYNCPROC g_glFenceSync;
PFNGLCLIENTWAITSYNCPROC g_glClientWaitSync;
PFNGLDELETESYNCPROC g_glDeleteSync;
PFNGLDRAWBUFFERSPROC ptrDrawBuffers;
PFNGLBINDFRAMEBUFFERPROC ptrBindFramebuffer;
PFNGLDELETEFRAMEBUFFERSPROC ptrDeleteFramebuffers;
PFNGLGENFRAMEBUFFERSPROC ptrGenFramebuffers;
PFNGLFRAMEBUFFERTEXTURE2DPROC ptrFramebufferTexture2D;
PFNGLTEXIMAGE2DMULTISAMPLEPROC ptrTexImage2DMultisample;
PFNGLTEXSTORAGE2DMULTISAMPLEPROC ptrTexStorage2DMultisample;
PFNGLGENRENDERBUFFERSPROC ptrGenRenderbuffers;
PFNGLBINDRENDERBUFFERPROC ptrBindRenderbuffer;
PFNGLRENDERBUFFERSTORAGEPROC ptrRenderbufferStorage;
PFNGLFRAMEBUFFERRENDERBUFFERPROC ptrFramebufferRenderbuffer;
PFNGLDELETERENDERBUFFERSPROC ptrDeleteRenderbuffers;
PFNGLCHECKFRAMEBUFFERSTATUSPROC ptrCheckFramebufferStatus;
PFNGLBLITFRAMEBUFFERPROC ptrBlitFramebuffer;
PFNGLGENVERTEXARRAYSPROC ptrGenVertexArrays;
PFNGLBINDVERTEXARRAYPROC ptrBindVertexArray;
PFNGLDELETEVERTEXARRAYSPROC ptrDeleteVertexArrays;
PFNGLGENBUFFERSPROC ptrGenBuffers;
PFNGLBINDBUFFERPROC ptrBindBuffer;
PFNGLBUFFERDATAPROC ptrBufferData;
PFNGLMAPBUFFERPROC ptrMapBuffer;
PFNGLMAPBUFFERRANGEPROC ptrMapBufferRange;
PFNGLUNMAPBUFFERPROC ptrUnmapBuffer;
PFNGLDELETEBUFFERSPROC ptrDeleteBuffers;
PFNGLBINDIMAGETEXTUREPROC ptrBindImageTexture;
PFNGLMEMORYBARRIERPROC ptrMemoryBarrier;
PFNGLGETSTRINGIPROC ptrGetStringi;
PFNGLINVALIDATEFRAMEBUFFERPROC ptrInvalidateFramebuffer;
PFNGLBUFFERSTORAGEPROC ptrBufferStorage;
PFNGLFENCESYNCPROC ptrFenceSync;
PFNGLCLIENTWAITSYNCPROC ptrClientWaitSync;
PFNGLDELETESYNCPROC ptrDeleteSync;
PFNGLGETUNIFORMBLOCKINDEXPROC g_glGetUniformBlockIndex;
PFNGLUNIFORMBLOCKBINDINGPROC g_glUniformBlockBinding;
PFNGLGETACTIVEUNIFORMBLOCKIVPROC g_glGetActiveUniformBlockiv;
PFNGLGETUNIFORMINDICESPROC g_glGetUniformIndices;
PFNGLGETACTIVEUNIFORMSIVPROC g_glGetActiveUniformsiv;
PFNGLBINDBUFFERBASEPROC g_glBindBufferBase;
PFNGLBUFFERSUBDATAPROC g_glBufferSubData;
PFNGLGETUNIFORMBLOCKINDEXPROC ptrGetUniformBlockIndex;
PFNGLUNIFORMBLOCKBINDINGPROC ptrUniformBlockBinding;
PFNGLGETACTIVEUNIFORMBLOCKIVPROC ptrGetActiveUniformBlockiv;
PFNGLGETUNIFORMINDICESPROC ptrGetUniformIndices;
PFNGLGETACTIVEUNIFORMSIVPROC ptrGetActiveUniformsiv;
PFNGLBINDBUFFERBASEPROC ptrBindBufferBase;
PFNGLBUFFERSUBDATAPROC ptrBufferSubData;
PFNGLGETPROGRAMBINARYPROC g_glGetProgramBinary;
PFNGLPROGRAMBINARYPROC g_glProgramBinary;
PFNGLPROGRAMPARAMETERIPROC g_glProgramParameteri;
PFNGLGETPROGRAMBINARYPROC ptrGetProgramBinary;
PFNGLPROGRAMBINARYPROC ptrProgramBinary;
PFNGLPROGRAMPARAMETERIPROC ptrProgramParameteri;
PFNGLTEXSTORAGE2DPROC g_glTexStorage2D;
PFNGLTEXTURESTORAGE2DPROC g_glTextureStorage2D;
PFNGLTEXTURESUBIMAGE2DPROC g_glTextureSubImage2D;
PFNGLTEXTURESTORAGE2DMULTISAMPLEEXTPROC g_glTextureStorage2DMultisample;
PFNGLTEXTUREPARAMETERIPROC g_glTextureParameteri;
PFNGLTEXTUREPARAMETERFPROC g_glTextureParameterf;
PFNGLCREATETEXTURESPROC g_glCreateTextures;
PFNGLCREATEBUFFERSPROC g_glCreateBuffers;
PFNGLCREATEFRAMEBUFFERSPROC g_glCreateFramebuffers;
PFNGLNAMEDFRAMEBUFFERTEXTUREPROC g_glNamedFramebufferTexture;
PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC g_glDrawRangeElementsBaseVertex;
PFNGLFLUSHMAPPEDBUFFERRANGEPROC g_glFlushMappedBufferRange;
PFNGLTEXTUREBARRIERPROC g_glTextureBarrier;
PFNGLTEXTUREBARRIERNVPROC g_glTextureBarrierNV;
PFNGLCLEARBUFFERFVPROC g_glClearBufferfv;
PFNGLENABLEIPROC g_glEnablei;
PFNGLDISABLEIPROC g_glDisablei;
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC g_glEGLImageTargetTexture2DOES;
PFNGLTEXSTORAGE2DPROC ptrTexStorage2D;
PFNGLTEXTURESTORAGE2DPROC ptrTextureStorage2D;
PFNGLTEXTURESUBIMAGE2DPROC ptrTextureSubImage2D;
PFNGLTEXTURESTORAGE2DMULTISAMPLEEXTPROC ptrTextureStorage2DMultisample;
PFNGLTEXTUREPARAMETERIPROC ptrTextureParameteri;
PFNGLTEXTUREPARAMETERFPROC ptrTextureParameterf;
PFNGLCREATETEXTURESPROC ptrCreateTextures;
PFNGLCREATEBUFFERSPROC ptrCreateBuffers;
PFNGLCREATEFRAMEBUFFERSPROC ptrCreateFramebuffers;
PFNGLNAMEDFRAMEBUFFERTEXTUREPROC ptrNamedFramebufferTexture;
PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC ptrDrawRangeElementsBaseVertex;
PFNGLFLUSHMAPPEDBUFFERRANGEPROC ptrFlushMappedBufferRange;
PFNGLTEXTUREBARRIERPROC ptrTextureBarrier;
PFNGLTEXTUREBARRIERNVPROC ptrTextureBarrierNV;
PFNGLCLEARBUFFERFVPROC ptrClearBufferfv;
PFNGLENABLEIPROC ptrEnablei;
PFNGLDISABLEIPROC ptrDisablei;
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC ptrEGLImageTargetTexture2DOES;
void initGLFunctions()
{
@ -207,143 +205,178 @@ void initGLFunctions()
#elif defined(VERO4K)
void *gles2so = dlopen("/opt/vero3/lib/libGLESv2.so", RTLD_NOW);
#endif
#if defined(EGL) || defined(OS_IOS)
GL_GET_PROC_ADR(PFNGLBLENDFUNCPROC, BlendFunc);
GL_GET_PROC_ADR(PFNGLPIXELSTOREIPROC, PixelStorei);
GL_GET_PROC_ADR(PFNGLCLEARCOLORPROC, ClearColor);
GL_GET_PROC_ADR(PFNGLCULLFACEPROC, CullFace);
GL_GET_PROC_ADR(PFNGLDEPTHFUNCPROC, DepthFunc);
GL_GET_PROC_ADR(PFNGLDEPTHMASKPROC, DepthMask);
GL_GET_PROC_ADR(PFNGLDISABLEPROC, Disable);
GL_GET_PROC_ADR(PFNGLENABLEPROC, Enable);
GL_GET_PROC_ADR(PFNGLPOLYGONOFFSETPROC, PolygonOffset);
GL_GET_PROC_ADR(PFNGLSCISSORPROC, Scissor);
GL_GET_PROC_ADR(PFNGLVIEWPORTPROC, Viewport);
GL_GET_PROC_ADR(PFNGLBINDTEXTUREPROC, BindTexture);
GL_GET_PROC_ADR(PFNGLTEXIMAGE2DPROC, TexImage2D);
GL_GET_PROC_ADR(PFNGLTEXPARAMETERIPROC, TexParameteri);
GL_GET_PROC_ADR(PFNGLGETINTEGERVPROC, GetIntegerv);
GL_GET_PROC_ADR(PFNGLGETSTRINGPROC, GetString);
GL_GET_PROC_ADR(PFNGLREADPIXELSPROC, ReadPixels);
GL_GET_PROC_ADR(PFNGLTEXSUBIMAGE2DPROC, TexSubImage2D);
GL_GET_PROC_ADR(PFNGLDRAWARRAYSPROC, DrawArrays);
GL_GET_PROC_ADR(PFNGLGETERRORPROC, GetError);
GL_GET_PROC_ADR(PFNGLDRAWELEMENTSPROC, DrawElements);
GL_GET_PROC_ADR(PFNGLLINEWIDTHPROC, LineWidth);
GL_GET_PROC_ADR(PFNGLCLEARPROC, Clear);
GL_GET_PROC_ADR(PFNGLGETFLOATVPROC, GetFloatv);
GL_GET_PROC_ADR(PFNGLDELETETEXTURESPROC, DeleteTextures);
GL_GET_PROC_ADR(PFNGLGENTEXTURESPROC, GenTextures);
GL_GET_PROC_ADR(PFNGLTEXPARAMETERFPROC, TexParameterf);
GL_GET_PROC_ADR(PFNGLACTIVETEXTUREPROC, ActiveTexture);
GL_GET_PROC_ADR(PFNGLBLENDCOLORPROC, BlendColor);
GL_GET_PROC_ADR(PFNGLREADBUFFERPROC, ReadBuffer);
GL_GET_PROC_ADR(PFNGLFINISHPROC, Finish);
#if defined(OS_ANDROID)
GL_GET_PROC_ADR_EGL(PFNEGLGETNATIVECLIENTBUFFERANDROIDPROC, GetNativeClientBufferANDROID);
#endif
#else
#ifdef OS_WINDOWS
GL_GET_PROC_ADR(PFNGLACTIVETEXTUREPROC, glActiveTexture);
GL_GET_PROC_ADR(PFNGLBLENDCOLORPROC, glBlendColor);
#elif defined(EGL) || defined(OS_IOS)
GL_GET_PROC_ADR(PFNGLBLENDFUNCPROC, glBlendFunc);
GL_GET_PROC_ADR(PFNGLPIXELSTOREIPROC, glPixelStorei);
GL_GET_PROC_ADR(PFNGLCLEARCOLORPROC, glClearColor);
GL_GET_PROC_ADR(PFNGLCULLFACEPROC, glCullFace);
GL_GET_PROC_ADR(PFNGLDEPTHFUNCPROC, glDepthFunc);
GL_GET_PROC_ADR(PFNGLDEPTHMASKPROC, glDepthMask);
GL_GET_PROC_ADR(PFNGLDISABLEPROC, glDisable);
GL_GET_PROC_ADR(PFNGLENABLEPROC, glEnable);
GL_GET_PROC_ADR(PFNGLPOLYGONOFFSETPROC, glPolygonOffset);
GL_GET_PROC_ADR(PFNGLSCISSORPROC, glScissor);
GL_GET_PROC_ADR(PFNGLVIEWPORTPROC, glViewport);
GL_GET_PROC_ADR(PFNGLBINDTEXTUREPROC, glBindTexture);
GL_GET_PROC_ADR(PFNGLTEXIMAGE2DPROC, glTexImage2D);
GL_GET_PROC_ADR(PFNGLTEXPARAMETERIPROC, glTexParameteri);
GL_GET_PROC_ADR(PFNGLGETINTEGERVPROC, glGetIntegerv);
GL_GET_PROC_ADR(PFNGLGETSTRINGPROC, glGetString);
GL_GET_PROC_ADR(PFNGLREADPIXELSPROC, glReadPixels);
GL_GET_PROC_ADR(PFNGLTEXSUBIMAGE2DPROC, glTexSubImage2D);
GL_GET_PROC_ADR(PFNGLDRAWARRAYSPROC, glDrawArrays);
GL_GET_PROC_ADR(PFNGLGETERRORPROC, glGetError);
GL_GET_PROC_ADR(PFNGLDRAWELEMENTSPROC, glDrawElements);
GL_GET_PROC_ADR(PFNGLLINEWIDTHPROC, glLineWidth);
GL_GET_PROC_ADR(PFNGLCLEARPROC, glClear);
GL_GET_PROC_ADR(PFNGLGETFLOATVPROC, glGetFloatv);
GL_GET_PROC_ADR(PFNGLDELETETEXTURESPROC, glDeleteTextures);
GL_GET_PROC_ADR(PFNGLGENTEXTURESPROC, glGenTextures);
GL_GET_PROC_ADR(PFNGLTEXPARAMETERFPROC, glTexParameterf);
GL_GET_PROC_ADR(PFNGLACTIVETEXTUREPROC, glActiveTexture);
GL_GET_PROC_ADR(PFNGLBLENDCOLORPROC, glBlendColor);
GL_GET_PROC_ADR(PFNGLREADBUFFERPROC, glReadBuffer);
GL_GET_PROC_ADR(PFNGLFINISHPROC, glFinish);
#ifdef OS_ANDROID
GL_GET_PROC_ADR(PFNEGLGETNATIVECLIENTBUFFERANDROIDPROC, eglGetNativeClientBufferANDROID);
GL_GET_PROC_ADR(PFNGLACTIVETEXTUREPROC, ActiveTexture);
GL_GET_PROC_ADR(PFNGLBLENDCOLORPROC, BlendColor);
#else
ASSIGN_PROC_ADR(PFNGLACTIVETEXTUREPROC, ActiveTexture);
ASSIGN_PROC_ADR(PFNGLBLENDCOLORPROC, BlendColor);
#endif
ASSIGN_PROC_ADR(PFNGLBLENDFUNCPROC, BlendFunc);
ASSIGN_PROC_ADR(PFNGLPIXELSTOREIPROC, PixelStorei);
ASSIGN_PROC_ADR(PFNGLCLEARCOLORPROC, ClearColor);
ASSIGN_PROC_ADR(PFNGLCULLFACEPROC, CullFace);
ASSIGN_PROC_ADR(PFNGLDEPTHFUNCPROC, DepthFunc);
ASSIGN_PROC_ADR(PFNGLDEPTHMASKPROC, DepthMask);
ASSIGN_PROC_ADR(PFNGLDISABLEPROC, Disable);
ASSIGN_PROC_ADR(PFNGLENABLEPROC, Enable);
ASSIGN_PROC_ADR(PFNGLPOLYGONOFFSETPROC, PolygonOffset);
ASSIGN_PROC_ADR(PFNGLSCISSORPROC, Scissor);
ASSIGN_PROC_ADR(PFNGLVIEWPORTPROC, Viewport);
ASSIGN_PROC_ADR(PFNGLBINDTEXTUREPROC, BindTexture);
ASSIGN_PROC_ADR(PFNGLTEXIMAGE2DPROC, TexImage2D);
ASSIGN_PROC_ADR(PFNGLTEXPARAMETERIPROC, TexParameteri);
ASSIGN_PROC_ADR(PFNGLGETINTEGERVPROC, GetIntegerv);
ASSIGN_PROC_ADR(PFNGLGETSTRINGPROC, GetString);
ASSIGN_PROC_ADR(PFNGLREADPIXELSPROC, ReadPixels);
ASSIGN_PROC_ADR(PFNGLTEXSUBIMAGE2DPROC, TexSubImage2D);
ASSIGN_PROC_ADR(PFNGLDRAWARRAYSPROC, DrawArrays);
ASSIGN_PROC_ADR(PFNGLGETERRORPROC, GetError);
ASSIGN_PROC_ADR(PFNGLDRAWELEMENTSPROC, DrawElements);
ASSIGN_PROC_ADR(PFNGLLINEWIDTHPROC, LineWidth);
ASSIGN_PROC_ADR(PFNGLCLEARPROC, Clear);
ASSIGN_PROC_ADR(PFNGLGETFLOATVPROC, GetFloatv);
ASSIGN_PROC_ADR(PFNGLDELETETEXTURESPROC, DeleteTextures);
ASSIGN_PROC_ADR(PFNGLGENTEXTURESPROC, GenTextures);
ASSIGN_PROC_ADR(PFNGLTEXPARAMETERFPROC, TexParameterf);
ASSIGN_PROC_ADR(PFNGLREADBUFFERPROC, ReadBuffer);
ASSIGN_PROC_ADR(PFNGLFINISHPROC, Finish);
#endif
GL_GET_PROC_ADR(PFNGLCREATESHADERPROC, glCreateShader);
GL_GET_PROC_ADR(PFNGLCOMPILESHADERPROC, glCompileShader);
GL_GET_PROC_ADR(PFNGLSHADERSOURCEPROC, glShaderSource);
GL_GET_PROC_ADR(PFNGLCREATEPROGRAMPROC, glCreateProgram);
GL_GET_PROC_ADR(PFNGLATTACHSHADERPROC, glAttachShader);
GL_GET_PROC_ADR(PFNGLLINKPROGRAMPROC, glLinkProgram);
GL_GET_PROC_ADR(PFNGLUSEPROGRAMPROC, glUseProgram);
GL_GET_PROC_ADR(PFNGLGETUNIFORMLOCATIONPROC, glGetUniformLocation);
GL_GET_PROC_ADR(PFNGLUNIFORM1IPROC, glUniform1i);
GL_GET_PROC_ADR(PFNGLUNIFORM1FPROC, glUniform1f);
GL_GET_PROC_ADR(PFNGLUNIFORM2FPROC, glUniform2f);
GL_GET_PROC_ADR(PFNGLUNIFORM2IPROC, glUniform2i);
GL_GET_PROC_ADR(PFNGLUNIFORM4IPROC, glUniform4i);
GL_GET_PROC_ADR(PFNGLUNIFORM4FPROC, glUniform4f);
GL_GET_PROC_ADR(PFNGLUNIFORM3FVPROC, glUniform3fv);
GL_GET_PROC_ADR(PFNGLUNIFORM4FVPROC, glUniform4fv);
GL_GET_PROC_ADR(PFNGLDETACHSHADERPROC, glDetachShader);
GL_GET_PROC_ADR(PFNGLDELETESHADERPROC, glDeleteShader);
GL_GET_PROC_ADR(PFNGLDELETEPROGRAMPROC, glDeleteProgram);
GL_GET_PROC_ADR(PFNGLGETPROGRAMINFOLOGPROC, glGetProgramInfoLog);
GL_GET_PROC_ADR(PFNGLGETSHADERINFOLOGPROC, glGetShaderInfoLog);
GL_GET_PROC_ADR(PFNGLGETSHADERIVPROC, glGetShaderiv);
GL_GET_PROC_ADR(PFNGLGETPROGRAMIVPROC, glGetProgramiv);
GL_GET_PROC_ADR(PFNGLCREATESHADERPROC, CreateShader);
GL_GET_PROC_ADR(PFNGLCOMPILESHADERPROC, CompileShader);
GL_GET_PROC_ADR(PFNGLSHADERSOURCEPROC, ShaderSource);
GL_GET_PROC_ADR(PFNGLCREATEPROGRAMPROC, CreateProgram);
GL_GET_PROC_ADR(PFNGLATTACHSHADERPROC, AttachShader);
GL_GET_PROC_ADR(PFNGLLINKPROGRAMPROC, LinkProgram);
GL_GET_PROC_ADR(PFNGLUSEPROGRAMPROC, UseProgram);
GL_GET_PROC_ADR(PFNGLGETUNIFORMLOCATIONPROC, GetUniformLocation);
GL_GET_PROC_ADR(PFNGLUNIFORM1IPROC, Uniform1i);
GL_GET_PROC_ADR(PFNGLUNIFORM1FPROC, Uniform1f);
GL_GET_PROC_ADR(PFNGLUNIFORM2FPROC, Uniform2f);
GL_GET_PROC_ADR(PFNGLUNIFORM2IPROC, Uniform2i);
GL_GET_PROC_ADR(PFNGLUNIFORM4IPROC, Uniform4i);
GL_GET_PROC_ADR(PFNGLUNIFORM4FPROC, Uniform4f);
GL_GET_PROC_ADR(PFNGLUNIFORM3FVPROC, Uniform3fv);
GL_GET_PROC_ADR(PFNGLUNIFORM4FVPROC, Uniform4fv);
GL_GET_PROC_ADR(PFNGLDETACHSHADERPROC, DetachShader);
GL_GET_PROC_ADR(PFNGLDELETESHADERPROC, DeleteShader);
GL_GET_PROC_ADR(PFNGLDELETEPROGRAMPROC, DeleteProgram);
GL_GET_PROC_ADR(PFNGLGETPROGRAMINFOLOGPROC, GetProgramInfoLog);
GL_GET_PROC_ADR(PFNGLGETSHADERINFOLOGPROC, GetShaderInfoLog);
GL_GET_PROC_ADR(PFNGLGETSHADERIVPROC, GetShaderiv);
GL_GET_PROC_ADR(PFNGLGETPROGRAMIVPROC, GetProgramiv);
GL_GET_PROC_ADR(PFNGLENABLEVERTEXATTRIBARRAYPROC, glEnableVertexAttribArray);
GL_GET_PROC_ADR(PFNGLDISABLEVERTEXATTRIBARRAYPROC, glDisableVertexAttribArray);
GL_GET_PROC_ADR(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer);
GL_GET_PROC_ADR(PFNGLBINDATTRIBLOCATIONPROC, glBindAttribLocation);
GL_GET_PROC_ADR(PFNGLVERTEXATTRIB1FPROC, glVertexAttrib1f);
GL_GET_PROC_ADR(PFNGLVERTEXATTRIB4FPROC, glVertexAttrib4f);
GL_GET_PROC_ADR(PFNGLVERTEXATTRIB4FVPROC, glVertexAttrib4fv);
GL_GET_PROC_ADR(PFNGLENABLEVERTEXATTRIBARRAYPROC, EnableVertexAttribArray);
GL_GET_PROC_ADR(PFNGLDISABLEVERTEXATTRIBARRAYPROC, DisableVertexAttribArray);
GL_GET_PROC_ADR(PFNGLVERTEXATTRIBPOINTERPROC, VertexAttribPointer);
GL_GET_PROC_ADR(PFNGLBINDATTRIBLOCATIONPROC, BindAttribLocation);
GL_GET_PROC_ADR(PFNGLVERTEXATTRIB1FPROC, VertexAttrib1f);
GL_GET_PROC_ADR(PFNGLVERTEXATTRIB4FPROC, VertexAttrib4f);
GL_GET_PROC_ADR(PFNGLVERTEXATTRIB4FVPROC, VertexAttrib4fv);
GL_GET_PROC_ADR(PFNGLDEPTHRANGEFPROC, glDepthRangef);
GL_GET_PROC_ADR(PFNGLCLEARDEPTHFPROC, glClearDepthf);
GL_GET_PROC_ADR(PFNGLDEPTHRANGEFPROC, DepthRangef);
GL_GET_PROC_ADR(PFNGLCLEARDEPTHFPROC, ClearDepthf);
GL_GET_PROC_ADR(PFNGLDRAWBUFFERSPROC, glDrawBuffers);
GL_GET_PROC_ADR(PFNGLBINDFRAMEBUFFERPROC, glBindFramebuffer);
GL_GET_PROC_ADR(PFNGLDELETEFRAMEBUFFERSPROC, glDeleteFramebuffers);
GL_GET_PROC_ADR(PFNGLGENFRAMEBUFFERSPROC, glGenFramebuffers);
GL_GET_PROC_ADR(PFNGLFRAMEBUFFERTEXTURE2DPROC, glFramebufferTexture2D);
GL_GET_PROC_ADR(PFNGLTEXIMAGE2DMULTISAMPLEPROC, glTexImage2DMultisample);
GL_GET_PROC_ADR(PFNGLTEXSTORAGE2DMULTISAMPLEPROC, glTexStorage2DMultisample);
GL_GET_PROC_ADR(PFNGLGENRENDERBUFFERSPROC, glGenRenderbuffers);
GL_GET_PROC_ADR(PFNGLBINDRENDERBUFFERPROC, glBindRenderbuffer);
GL_GET_PROC_ADR(PFNGLRENDERBUFFERSTORAGEPROC, glRenderbufferStorage);
GL_GET_PROC_ADR(PFNGLFRAMEBUFFERRENDERBUFFERPROC, glFramebufferRenderbuffer);
GL_GET_PROC_ADR(PFNGLDELETERENDERBUFFERSPROC, glDeleteRenderbuffers);
GL_GET_PROC_ADR(PFNGLCHECKFRAMEBUFFERSTATUSPROC, glCheckFramebufferStatus);
GL_GET_PROC_ADR(PFNGLBLITFRAMEBUFFERPROC, glBlitFramebuffer);
GL_GET_PROC_ADR(PFNGLGENVERTEXARRAYSPROC, glGenVertexArrays);
GL_GET_PROC_ADR(PFNGLBINDVERTEXARRAYPROC, glBindVertexArray);
GL_GET_PROC_ADR(PFNGLDELETEVERTEXARRAYSPROC, glDeleteVertexArrays);
GL_GET_PROC_ADR(PFNGLGENBUFFERSPROC, glGenBuffers);
GL_GET_PROC_ADR(PFNGLBINDBUFFERPROC, glBindBuffer);
GL_GET_PROC_ADR(PFNGLBUFFERDATAPROC, glBufferData);
GL_GET_PROC_ADR(PFNGLMAPBUFFERPROC, glMapBuffer);
GL_GET_PROC_ADR(PFNGLMAPBUFFERRANGEPROC, glMapBufferRange);
GL_GET_PROC_ADR(PFNGLUNMAPBUFFERPROC, glUnmapBuffer);
GL_GET_PROC_ADR(PFNGLDELETEBUFFERSPROC, glDeleteBuffers);
GL_GET_PROC_ADR(PFNGLBINDIMAGETEXTUREPROC, glBindImageTexture);
GL_GET_PROC_ADR(PFNGLMEMORYBARRIERPROC, glMemoryBarrier);
GL_GET_PROC_ADR(PFNGLGETSTRINGIPROC, glGetStringi);
GL_GET_PROC_ADR(PFNGLINVALIDATEFRAMEBUFFERPROC, glInvalidateFramebuffer);
GL_GET_PROC_ADR(PFNGLBUFFERSTORAGEPROC, glBufferStorage);
GL_GET_PROC_ADR(PFNGLFENCESYNCPROC, glFenceSync);
GL_GET_PROC_ADR(PFNGLCLIENTWAITSYNCPROC, glClientWaitSync);
GL_GET_PROC_ADR(PFNGLDELETESYNCPROC, glDeleteSync);
GL_GET_PROC_ADR(PFNGLDRAWBUFFERSPROC, DrawBuffers);
GL_GET_PROC_ADR(PFNGLBINDFRAMEBUFFERPROC, BindFramebuffer);
GL_GET_PROC_ADR(PFNGLDELETEFRAMEBUFFERSPROC, DeleteFramebuffers);
GL_GET_PROC_ADR(PFNGLGENFRAMEBUFFERSPROC, GenFramebuffers);
GL_GET_PROC_ADR(PFNGLFRAMEBUFFERTEXTURE2DPROC, FramebufferTexture2D);
GL_GET_PROC_ADR(PFNGLTEXIMAGE2DMULTISAMPLEPROC, TexImage2DMultisample);
GL_GET_PROC_ADR(PFNGLTEXSTORAGE2DMULTISAMPLEPROC, TexStorage2DMultisample);
GL_GET_PROC_ADR(PFNGLGENRENDERBUFFERSPROC, GenRenderbuffers);
GL_GET_PROC_ADR(PFNGLBINDRENDERBUFFERPROC, BindRenderbuffer);
GL_GET_PROC_ADR(PFNGLRENDERBUFFERSTORAGEPROC, RenderbufferStorage);
GL_GET_PROC_ADR(PFNGLFRAMEBUFFERRENDERBUFFERPROC, FramebufferRenderbuffer);
GL_GET_PROC_ADR(PFNGLDELETERENDERBUFFERSPROC, DeleteRenderbuffers);
GL_GET_PROC_ADR(PFNGLCHECKFRAMEBUFFERSTATUSPROC, CheckFramebufferStatus);
GL_GET_PROC_ADR(PFNGLBLITFRAMEBUFFERPROC, BlitFramebuffer);
GL_GET_PROC_ADR(PFNGLGENVERTEXARRAYSPROC, GenVertexArrays);
GL_GET_PROC_ADR(PFNGLBINDVERTEXARRAYPROC, BindVertexArray);
GL_GET_PROC_ADR(PFNGLDELETEVERTEXARRAYSPROC, DeleteVertexArrays);
GL_GET_PROC_ADR(PFNGLGENBUFFERSPROC, GenBuffers);
GL_GET_PROC_ADR(PFNGLBINDBUFFERPROC, BindBuffer);
GL_GET_PROC_ADR(PFNGLBUFFERDATAPROC, BufferData);
GL_GET_PROC_ADR(PFNGLMAPBUFFERPROC, MapBuffer);
GL_GET_PROC_ADR(PFNGLMAPBUFFERRANGEPROC, MapBufferRange);
GL_GET_PROC_ADR(PFNGLUNMAPBUFFERPROC, UnmapBuffer);
GL_GET_PROC_ADR(PFNGLDELETEBUFFERSPROC, DeleteBuffers);
GL_GET_PROC_ADR(PFNGLBINDIMAGETEXTUREPROC, BindImageTexture);
GL_GET_PROC_ADR(PFNGLMEMORYBARRIERPROC, MemoryBarrier);
GL_GET_PROC_ADR(PFNGLGETSTRINGIPROC, GetStringi);
GL_GET_PROC_ADR(PFNGLINVALIDATEFRAMEBUFFERPROC, InvalidateFramebuffer);
GL_GET_PROC_ADR(PFNGLBUFFERSTORAGEPROC, BufferStorage);
GL_GET_PROC_ADR(PFNGLFENCESYNCPROC, FenceSync);
GL_GET_PROC_ADR(PFNGLCLIENTWAITSYNCPROC, ClientWaitSync);
GL_GET_PROC_ADR(PFNGLDELETESYNCPROC, DeleteSync);
GL_GET_PROC_ADR(PFNGLGETUNIFORMBLOCKINDEXPROC, glGetUniformBlockIndex);
GL_GET_PROC_ADR(PFNGLUNIFORMBLOCKBINDINGPROC, glUniformBlockBinding);
GL_GET_PROC_ADR(PFNGLGETACTIVEUNIFORMBLOCKIVPROC, glGetActiveUniformBlockiv);
GL_GET_PROC_ADR(PFNGLGETUNIFORMINDICESPROC, glGetUniformIndices);
GL_GET_PROC_ADR(PFNGLGETACTIVEUNIFORMSIVPROC, glGetActiveUniformsiv);
GL_GET_PROC_ADR(PFNGLBINDBUFFERBASEPROC, glBindBufferBase);
GL_GET_PROC_ADR(PFNGLBUFFERSUBDATAPROC, glBufferSubData);
GL_GET_PROC_ADR(PFNGLGETUNIFORMBLOCKINDEXPROC, GetUniformBlockIndex);
GL_GET_PROC_ADR(PFNGLUNIFORMBLOCKBINDINGPROC, UniformBlockBinding);
GL_GET_PROC_ADR(PFNGLGETACTIVEUNIFORMBLOCKIVPROC, GetActiveUniformBlockiv);
GL_GET_PROC_ADR(PFNGLGETUNIFORMINDICESPROC, GetUniformIndices);
GL_GET_PROC_ADR(PFNGLGETACTIVEUNIFORMSIVPROC, GetActiveUniformsiv);
GL_GET_PROC_ADR(PFNGLBINDBUFFERBASEPROC, BindBufferBase);
GL_GET_PROC_ADR(PFNGLBUFFERSUBDATAPROC, BufferSubData);
GL_GET_PROC_ADR(PFNGLGETPROGRAMBINARYPROC, glGetProgramBinary);
GL_GET_PROC_ADR(PFNGLPROGRAMBINARYPROC, glProgramBinary);
GL_GET_PROC_ADR(PFNGLPROGRAMPARAMETERIPROC, glProgramParameteri);
GL_GET_PROC_ADR(PFNGLGETPROGRAMBINARYPROC, GetProgramBinary);
GL_GET_PROC_ADR(PFNGLPROGRAMBINARYPROC, ProgramBinary);
GL_GET_PROC_ADR(PFNGLPROGRAMPARAMETERIPROC, ProgramParameteri);
GL_GET_PROC_ADR(PFNGLTEXSTORAGE2DPROC, glTexStorage2D);
GL_GET_PROC_ADR(PFNGLTEXTURESTORAGE2DPROC, glTextureStorage2D);
GL_GET_PROC_ADR(PFNGLTEXTURESUBIMAGE2DPROC, glTextureSubImage2D);
GL_GET_PROC_ADR(PFNGLTEXTURESTORAGE2DMULTISAMPLEEXTPROC, glTextureStorage2DMultisample);
GL_GET_PROC_ADR(PFNGLTEXSTORAGE2DPROC, TexStorage2D);
GL_GET_PROC_ADR(PFNGLTEXTURESTORAGE2DPROC, TextureStorage2D);
GL_GET_PROC_ADR(PFNGLTEXTURESUBIMAGE2DPROC, TextureSubImage2D);
GL_GET_PROC_ADR(PFNGLTEXTURESTORAGE2DMULTISAMPLEEXTPROC, TextureStorage2DMultisample);
GL_GET_PROC_ADR(PFNGLTEXTUREPARAMETERIPROC, glTextureParameteri);
GL_GET_PROC_ADR(PFNGLTEXTUREPARAMETERFPROC, glTextureParameterf);
GL_GET_PROC_ADR(PFNGLCREATETEXTURESPROC, glCreateTextures);
GL_GET_PROC_ADR(PFNGLCREATEBUFFERSPROC, glCreateBuffers);
GL_GET_PROC_ADR(PFNGLCREATEFRAMEBUFFERSPROC, glCreateFramebuffers);
GL_GET_PROC_ADR(PFNGLNAMEDFRAMEBUFFERTEXTUREPROC, glNamedFramebufferTexture);
GL_GET_PROC_ADR(PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC, glDrawRangeElementsBaseVertex);
GL_GET_PROC_ADR(PFNGLFLUSHMAPPEDBUFFERRANGEPROC, glFlushMappedBufferRange);
GL_GET_PROC_ADR(PFNGLTEXTUREBARRIERPROC, glTextureBarrier);
GL_GET_PROC_ADR(PFNGLTEXTUREBARRIERNVPROC, glTextureBarrierNV);
GL_GET_PROC_ADR(PFNGLCLEARBUFFERFVPROC, glClearBufferfv);
GL_GET_PROC_ADR(PFNGLENABLEIPROC, glEnablei);
GL_GET_PROC_ADR(PFNGLDISABLEIPROC, glDisablei);
GL_GET_PROC_ADR(PFNGLEGLIMAGETARGETTEXTURE2DOESPROC, glEGLImageTargetTexture2DOES);
GL_GET_PROC_ADR(PFNGLTEXTUREPARAMETERIPROC, TextureParameteri);
GL_GET_PROC_ADR(PFNGLTEXTUREPARAMETERFPROC, TextureParameterf);
GL_GET_PROC_ADR(PFNGLCREATETEXTURESPROC, CreateTextures);
GL_GET_PROC_ADR(PFNGLCREATEBUFFERSPROC, CreateBuffers);
GL_GET_PROC_ADR(PFNGLCREATEFRAMEBUFFERSPROC, CreateFramebuffers);
GL_GET_PROC_ADR(PFNGLNAMEDFRAMEBUFFERTEXTUREPROC, NamedFramebufferTexture);
GL_GET_PROC_ADR(PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC, DrawRangeElementsBaseVertex);
GL_GET_PROC_ADR(PFNGLFLUSHMAPPEDBUFFERRANGEPROC, FlushMappedBufferRange);
GL_GET_PROC_ADR(PFNGLTEXTUREBARRIERPROC, TextureBarrier);
GL_GET_PROC_ADR(PFNGLTEXTUREBARRIERNVPROC, TextureBarrierNV);
GL_GET_PROC_ADR(PFNGLCLEARBUFFERFVPROC, ClearBufferfv);
GL_GET_PROC_ADR(PFNGLENABLEIPROC, Enablei);
GL_GET_PROC_ADR(PFNGLDISABLEIPROC, Disablei);
GL_GET_PROC_ADR(PFNGLEGLIMAGETARGETTEXTURE2DOESPROC, EGLImageTargetTexture2DOES);
}

View File

@ -4,7 +4,6 @@
#ifdef OS_WINDOWS
#include <windows.h>
#elif defined(OS_LINUX)
//#define GL_GLEXT_PROTOTYPES
#include <winlnxdefs.h>
#endif
@ -16,7 +15,7 @@
#include <OpenGL/OpenGL.h>
#include <stddef.h>
#include <OpenGL/gl3.h>
//#include <OpenGL/gl3ext.h>
#elif defined(OS_IOS)
#include <OpenGLES/ES3/gl.h>
#include <OpenGLES/ES3/glext.h>
@ -30,333 +29,305 @@ typedef double GLdouble;
#include <GL/glcorearb.h>
#else
#include <GL/gl.h>
#include <GL/glcorearb.h>
#endif
#define GL_LUMINANCE 0x1909
#include <GL/glext.h>
#include <stdexcept>
#include <sstream>
#include "Log.h"
#ifdef GL_ERROR_DEBUG
#define CHECKED_GL_FUNCTION(proc_name, ...) checked([&]() { proc_name(__VA_ARGS__);}, #proc_name)
#define CHECKED_GL_FUNCTION_WITH_RETURN(proc_name, ReturnType, ...) checkedWithReturn<ReturnType>([&]() { return proc_name(__VA_ARGS__);}, #proc_name)
#else
#define CHECKED_GL_FUNCTION(proc_name, ...) proc_name(__VA_ARGS__)
#define CHECKED_GL_FUNCTION_WITH_RETURN(proc_name, ReturnType, ...) proc_name(__VA_ARGS__)
#define IS_GL_FUNCTION_VALID(proc_name) ptr##proc_name != nullptr
#if !defined(EGL) && !defined(OS_IOS)
typedef void (APIENTRYP PFNGLPOLYGONOFFSETPROC) (GLfloat factor, GLfloat units);
typedef void (APIENTRYP PFNGLBINDTEXTUREPROC) (GLenum target, GLuint texture);
typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
typedef void (APIENTRYP PFNGLDRAWARRAYSPROC) (GLenum mode, GLint first, GLsizei count);
typedef void (APIENTRYP PFNGLDRAWELEMENTSPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices);
typedef void (APIENTRYP PFNGLDELETETEXTURESPROC) (GLsizei n, const GLuint *textures);
typedef void (APIENTRYP PFNGLGENTEXTURESPROC) (GLsizei n, GLuint *textures);
#endif
#define IS_GL_FUNCTION_VALID(proc_name) g_##proc_name != nullptr
#define GET_GL_FUNCTION(proc_name) g_##proc_name
#if defined(EGL) || defined(OS_IOS)
#define glGetError g_glGetError
#define glBlendFunc(...) CHECKED_GL_FUNCTION(g_glBlendFunc, __VA_ARGS__)
#define glPixelStorei(...) CHECKED_GL_FUNCTION(g_glPixelStorei, __VA_ARGS__)
#define glClearColor(...) CHECKED_GL_FUNCTION(g_glClearColor, __VA_ARGS__)
#define glCullFace(...) CHECKED_GL_FUNCTION(g_glCullFace, __VA_ARGS__)
#define glDepthFunc(...) CHECKED_GL_FUNCTION(g_glDepthFunc, __VA_ARGS__)
#define glDepthMask(...) CHECKED_GL_FUNCTION(g_glDepthMask, __VA_ARGS__)
#define glDisable(...) CHECKED_GL_FUNCTION(g_glDisable, __VA_ARGS__)
#define glEnable(...) CHECKED_GL_FUNCTION(g_glEnable, __VA_ARGS__)
#define glPolygonOffset(...) CHECKED_GL_FUNCTION(g_glPolygonOffset, __VA_ARGS__)
#define glScissor(...) CHECKED_GL_FUNCTION(g_glScissor, __VA_ARGS__)
#define glViewport(...) CHECKED_GL_FUNCTION(g_glViewport, __VA_ARGS__)
#define glBindTexture(...) CHECKED_GL_FUNCTION(g_glBindTexture, __VA_ARGS__)
#define glTexImage2D(...) CHECKED_GL_FUNCTION(g_glTexImage2D, __VA_ARGS__)
#define glTexParameteri(...) CHECKED_GL_FUNCTION(g_glTexParameteri, __VA_ARGS__)
#define glGetIntegerv(...) CHECKED_GL_FUNCTION(g_glGetIntegerv, __VA_ARGS__)
#define glGetString(...) CHECKED_GL_FUNCTION_WITH_RETURN(g_glGetString, const GLubyte*, __VA_ARGS__)
#define glReadPixels(...) CHECKED_GL_FUNCTION(g_glReadPixels, __VA_ARGS__)
#define glTexSubImage2D(...) CHECKED_GL_FUNCTION(g_glTexSubImage2D, __VA_ARGS__)
#define glDrawArrays(...) CHECKED_GL_FUNCTION(g_glDrawArrays, __VA_ARGS__)
#define glDrawElements(...) CHECKED_GL_FUNCTION(g_glDrawElements, __VA_ARGS__)
#define glLineWidth(...) CHECKED_GL_FUNCTION(g_glLineWidth, __VA_ARGS__)
#define glClear(...) CHECKED_GL_FUNCTION(g_glClear, __VA_ARGS__)
#define glGetFloatv(...) CHECKED_GL_FUNCTION(g_glGetFloatv, __VA_ARGS__)
#define glDeleteTextures(...) CHECKED_GL_FUNCTION(g_glDeleteTextures, __VA_ARGS__)
#define glGenTextures(...) CHECKED_GL_FUNCTION(g_glGenTextures, __VA_ARGS__)
#define glTexParameterf(...) CHECKED_GL_FUNCTION(g_glTexParameterf, __VA_ARGS__)
#define glActiveTexture(...) CHECKED_GL_FUNCTION(g_glActiveTexture, __VA_ARGS__)
#define glBlendColor(...) CHECKED_GL_FUNCTION(g_glBlendColor, __VA_ARGS__)
#define glReadBuffer(...) CHECKED_GL_FUNCTION(g_glReadBuffer, __VA_ARGS__)
#define glFinish(...) CHECKED_GL_FUNCTION(g_glFinish, __VA_ARGS__)
extern PFNGLBLENDFUNCPROC ptrBlendFunc;
extern PFNGLPIXELSTOREIPROC ptrPixelStorei;
extern PFNGLCLEARCOLORPROC ptrClearColor;
extern PFNGLCULLFACEPROC ptrCullFace;
extern PFNGLDEPTHFUNCPROC ptrDepthFunc;
extern PFNGLDEPTHMASKPROC ptrDepthMask;
extern PFNGLDISABLEPROC ptrDisable;
extern PFNGLENABLEPROC ptrEnable;
extern PFNGLPOLYGONOFFSETPROC ptrPolygonOffset;
extern PFNGLSCISSORPROC ptrScissor;
extern PFNGLVIEWPORTPROC ptrViewport;
extern PFNGLBINDTEXTUREPROC ptrBindTexture;
extern PFNGLTEXIMAGE2DPROC ptrTexImage2D;
extern PFNGLTEXPARAMETERIPROC ptrTexParameteri;
extern PFNGLGETINTEGERVPROC ptrGetIntegerv;
extern PFNGLGETSTRINGPROC ptrGetString;
extern PFNGLREADPIXELSPROC ptrReadPixels;
extern PFNGLTEXSUBIMAGE2DPROC ptrTexSubImage2D;
extern PFNGLDRAWARRAYSPROC ptrDrawArrays;
extern PFNGLGETERRORPROC ptrGetError;
extern PFNGLDRAWELEMENTSPROC ptrDrawElements;
extern PFNGLLINEWIDTHPROC ptrLineWidth;
extern PFNGLCLEARPROC ptrClear;
extern PFNGLGETFLOATVPROC ptrGetFloatv;
extern PFNGLDELETETEXTURESPROC ptrDeleteTextures;
extern PFNGLGENTEXTURESPROC ptrGenTextures;
extern PFNGLTEXPARAMETERFPROC ptrTexParameterf;
extern PFNGLACTIVETEXTUREPROC ptrActiveTexture;
extern PFNGLBLENDCOLORPROC ptrBlendColor;
extern PFNGLREADBUFFERPROC ptrReadBuffer;
extern PFNGLFINISHPROC ptrFinish;
#if defined(OS_ANDROID)
#define eglGetNativeClientBufferANDROID(...) CHECKED_GL_FUNCTION_WITH_RETURN(g_eglGetNativeClientBufferANDROID, EGLClientBuffer, __VA_ARGS__)
#endif
extern PFNGLBLENDFUNCPROC g_glBlendFunc;
extern PFNGLPIXELSTOREIPROC g_glPixelStorei;
extern PFNGLCLEARCOLORPROC g_glClearColor;
extern PFNGLCULLFACEPROC g_glCullFace;
extern PFNGLDEPTHFUNCPROC g_glDepthFunc;
extern PFNGLDEPTHMASKPROC g_glDepthMask;
extern PFNGLDISABLEPROC g_glDisable;
extern PFNGLENABLEPROC g_glEnable;
extern PFNGLPOLYGONOFFSETPROC g_glPolygonOffset;
extern PFNGLSCISSORPROC g_glScissor;
extern PFNGLVIEWPORTPROC g_glViewport;
extern PFNGLBINDTEXTUREPROC g_glBindTexture;
extern PFNGLTEXIMAGE2DPROC g_glTexImage2D;
extern PFNGLTEXPARAMETERIPROC g_glTexParameteri;
extern PFNGLGETINTEGERVPROC g_glGetIntegerv;
extern PFNGLGETSTRINGPROC g_glGetString;
extern PFNGLREADPIXELSPROC g_glReadPixels;
extern PFNGLTEXSUBIMAGE2DPROC g_glTexSubImage2D;
extern PFNGLDRAWARRAYSPROC g_glDrawArrays;
extern PFNGLGETERRORPROC g_glGetError;
extern PFNGLDRAWELEMENTSPROC g_glDrawElements;
extern PFNGLLINEWIDTHPROC g_glLineWidth;
extern PFNGLCLEARPROC g_glClear;
extern PFNGLGETFLOATVPROC g_glGetFloatv;
extern PFNGLDELETETEXTURESPROC g_glDeleteTextures;
extern PFNGLGENTEXTURESPROC g_glGenTextures;
extern PFNGLTEXPARAMETERFPROC g_glTexParameterf;
extern PFNGLACTIVETEXTUREPROC g_glActiveTexture;
extern PFNGLBLENDCOLORPROC g_glBlendColor;
extern PFNGLREADBUFFERPROC g_glReadBuffer;
extern PFNGLFINISHPROC g_glFinish;
#if defined(OS_ANDROID)
extern PFNEGLGETNATIVECLIENTBUFFERANDROIDPROC g_eglGetNativeClientBufferANDROID;
#endif
extern PFNEGLGETNATIVECLIENTBUFFERANDROIDPROC ptrGetNativeClientBufferANDROID;
#endif
#ifdef OS_WINDOWS
#define glActiveTexture g_glActiveTexture
#define glBlendColor g_glBlendColor
extern PFNGLACTIVETEXTUREPROC g_glActiveTexture;
extern PFNGLBLENDCOLORPROC g_glBlendColor;
extern PFNGLACTIVETEXTUREPROC ptrActiveTexture;
extern PFNGLBLENDCOLORPROC ptrBlendColor;
#endif
#define glCreateShader(...) CHECKED_GL_FUNCTION_WITH_RETURN(g_glCreateShader, GLuint, __VA_ARGS__)
#define glCompileShader(...) CHECKED_GL_FUNCTION(g_glCompileShader, __VA_ARGS__)
#define glShaderSource(...) CHECKED_GL_FUNCTION(g_glShaderSource, __VA_ARGS__)
#define glCreateProgram(...) CHECKED_GL_FUNCTION_WITH_RETURN(g_glCreateProgram, GLuint, __VA_ARGS__)
#define glAttachShader(...) CHECKED_GL_FUNCTION(g_glAttachShader, __VA_ARGS__)
#define glLinkProgram(...) CHECKED_GL_FUNCTION(g_glLinkProgram, __VA_ARGS__)
#define glUseProgram(...) CHECKED_GL_FUNCTION(g_glUseProgram, __VA_ARGS__)
#define glGetUniformLocation(...) CHECKED_GL_FUNCTION_WITH_RETURN(g_glGetUniformLocation, GLint, __VA_ARGS__)
#define glUniform1i(...) CHECKED_GL_FUNCTION(g_glUniform1i, __VA_ARGS__)
#define glUniform1f(...) CHECKED_GL_FUNCTION(g_glUniform1f, __VA_ARGS__)
#define glUniform2f(...) CHECKED_GL_FUNCTION(g_glUniform2f, __VA_ARGS__)
#define glUniform2i(...) CHECKED_GL_FUNCTION(g_glUniform2i, __VA_ARGS__)
#define glUniform4i(...) CHECKED_GL_FUNCTION(g_glUniform4i, __VA_ARGS__)
extern PFNGLCREATESHADERPROC ptrCreateShader;
extern PFNGLCOMPILESHADERPROC ptrCompileShader;
extern PFNGLSHADERSOURCEPROC ptrShaderSource;
extern PFNGLCREATEPROGRAMPROC ptrCreateProgram;
extern PFNGLATTACHSHADERPROC ptrAttachShader;
extern PFNGLLINKPROGRAMPROC ptrLinkProgram;
extern PFNGLUSEPROGRAMPROC ptrUseProgram;
extern PFNGLGETUNIFORMLOCATIONPROC ptrGetUniformLocation;
extern PFNGLUNIFORM1IPROC ptrUniform1i;
extern PFNGLUNIFORM1FPROC ptrUniform1f;
extern PFNGLUNIFORM2FPROC ptrUniform2f;
extern PFNGLUNIFORM2IPROC ptrUniform2i;
extern PFNGLUNIFORM4IPROC ptrUniform4i;
#define glUniform4f(...) CHECKED_GL_FUNCTION(g_glUniform4f, __VA_ARGS__)
#define glUniform3fv(...) CHECKED_GL_FUNCTION(g_glUniform3fv, __VA_ARGS__)
#define glUniform4fv(...) CHECKED_GL_FUNCTION(g_glUniform4fv, __VA_ARGS__)
#define glDetachShader(...) CHECKED_GL_FUNCTION(g_glDetachShader, __VA_ARGS__)
#define glDeleteShader(...) CHECKED_GL_FUNCTION(g_glDeleteShader, __VA_ARGS__)
#define glDeleteProgram(...) CHECKED_GL_FUNCTION(g_glDeleteProgram, __VA_ARGS__)
#define glGetProgramInfoLog(...) CHECKED_GL_FUNCTION(g_glGetProgramInfoLog, __VA_ARGS__)
#define glGetShaderInfoLog(...) CHECKED_GL_FUNCTION(g_glGetShaderInfoLog, __VA_ARGS__)
#define glGetShaderiv(...) CHECKED_GL_FUNCTION(g_glGetShaderiv, __VA_ARGS__)
#define glGetProgramiv(...) CHECKED_GL_FUNCTION(g_glGetProgramiv, __VA_ARGS__)
extern PFNGLUNIFORM4FPROC ptrUniform4f;
extern PFNGLUNIFORM3FVPROC ptrUniform3fv;
extern PFNGLUNIFORM4FVPROC ptrUniform4fv;
extern PFNGLDETACHSHADERPROC ptrDetachShader;
extern PFNGLDELETESHADERPROC ptrDeleteShader;
extern PFNGLDELETEPROGRAMPROC ptrDeleteProgram;
extern PFNGLGETPROGRAMINFOLOGPROC ptrGetProgramInfoLog;
extern PFNGLGETSHADERINFOLOGPROC ptrGetShaderInfoLog;
extern PFNGLGETSHADERIVPROC ptrGetShaderiv;
extern PFNGLGETPROGRAMIVPROC ptrGetProgramiv;
#define glEnableVertexAttribArray(...) CHECKED_GL_FUNCTION(g_glEnableVertexAttribArray, __VA_ARGS__)
#define glDisableVertexAttribArray(...) CHECKED_GL_FUNCTION(g_glDisableVertexAttribArray, __VA_ARGS__)
#define glVertexAttribPointer(...) CHECKED_GL_FUNCTION(g_glVertexAttribPointer, __VA_ARGS__)
#define glBindAttribLocation(...) CHECKED_GL_FUNCTION(g_glBindAttribLocation, __VA_ARGS__)
#define glVertexAttrib1f(...) CHECKED_GL_FUNCTION(g_glVertexAttrib1f, __VA_ARGS__)
#define glVertexAttrib4f(...) CHECKED_GL_FUNCTION(g_glVertexAttrib4f, __VA_ARGS__)
#define glVertexAttrib4fv(...) CHECKED_GL_FUNCTION(g_glVertexAttrib4fv, __VA_ARGS__)
extern PFNGLENABLEVERTEXATTRIBARRAYPROC ptrEnableVertexAttribArray;
extern PFNGLDISABLEVERTEXATTRIBARRAYPROC ptrDisableVertexAttribArray;
extern PFNGLVERTEXATTRIBPOINTERPROC ptrVertexAttribPointer;
extern PFNGLBINDATTRIBLOCATIONPROC ptrBindAttribLocation;
extern PFNGLVERTEXATTRIB1FPROC ptrVertexAttrib1f;
extern PFNGLVERTEXATTRIB4FPROC ptrVertexAttrib4f;
extern PFNGLVERTEXATTRIB4FVPROC ptrVertexAttrib4fv;
#define glDepthRangef(...) CHECKED_GL_FUNCTION(g_glDepthRangef, __VA_ARGS__)
#define glClearDepthf(...) CHECKED_GL_FUNCTION(g_glClearDepthf, __VA_ARGS__)
extern PFNGLDEPTHRANGEFPROC ptrDepthRangef;
extern PFNGLCLEARDEPTHFPROC ptrClearDepthf;
#define glBindBuffer(...) CHECKED_GL_FUNCTION(g_glBindBuffer, __VA_ARGS__)
#define glBindFramebuffer(...) CHECKED_GL_FUNCTION(g_glBindFramebuffer, __VA_ARGS__)
#define glBindRenderbuffer(...) CHECKED_GL_FUNCTION(g_glBindRenderbuffer, __VA_ARGS__)
#define glDrawBuffers(...) CHECKED_GL_FUNCTION(g_glDrawBuffers, __VA_ARGS__)
#define glGenFramebuffers(...) CHECKED_GL_FUNCTION(g_glGenFramebuffers, __VA_ARGS__)
#define glDeleteFramebuffers(...) CHECKED_GL_FUNCTION(g_glDeleteFramebuffers, __VA_ARGS__)
#define glFramebufferTexture2D(...) CHECKED_GL_FUNCTION(g_glFramebufferTexture2D, __VA_ARGS__)
#define glTexImage2DMultisample(...) CHECKED_GL_FUNCTION(g_glTexImage2DMultisample, __VA_ARGS__)
#define glTexStorage2DMultisample(...) CHECKED_GL_FUNCTION(g_glTexStorage2DMultisample, __VA_ARGS__)
#define glGenRenderbuffers(...) CHECKED_GL_FUNCTION(g_glGenRenderbuffers, __VA_ARGS__)
#define glRenderbufferStorage(...) CHECKED_GL_FUNCTION(g_glRenderbufferStorage, __VA_ARGS__)
#define glDeleteRenderbuffers(...) CHECKED_GL_FUNCTION(g_glDeleteRenderbuffers, __VA_ARGS__)
#define glFramebufferRenderbuffer(...) CHECKED_GL_FUNCTION(g_glFramebufferRenderbuffer, __VA_ARGS__)
#define glCheckFramebufferStatus(...) CHECKED_GL_FUNCTION_WITH_RETURN(g_glCheckFramebufferStatus, GLenum, __VA_ARGS__)
#define glBlitFramebuffer(...) CHECKED_GL_FUNCTION(g_glBlitFramebuffer, __VA_ARGS__)
#define glGenVertexArrays(...) CHECKED_GL_FUNCTION(g_glGenVertexArrays, __VA_ARGS__)
#define glBindVertexArray(...) CHECKED_GL_FUNCTION(g_glBindVertexArray, __VA_ARGS__)
#define glDeleteVertexArrays(...) CHECKED_GL_FUNCTION(g_glDeleteVertexArrays, __VA_ARGS__);
#define glGenBuffers(...) CHECKED_GL_FUNCTION(g_glGenBuffers, __VA_ARGS__)
#define glBufferData(...) CHECKED_GL_FUNCTION(g_glBufferData, __VA_ARGS__)
#define glMapBuffer(...) CHECKED_GL_FUNCTION(g_glMapBuffer, __VA_ARGS__)
#define glMapBufferRange(...) CHECKED_GL_FUNCTION_WITH_RETURN(g_glMapBufferRange, void*, __VA_ARGS__)
#define glUnmapBuffer(...) CHECKED_GL_FUNCTION(g_glUnmapBuffer, __VA_ARGS__)
#define glDeleteBuffers(...) CHECKED_GL_FUNCTION(g_glDeleteBuffers, __VA_ARGS__)
#define glBindImageTexture(...) CHECKED_GL_FUNCTION(g_glBindImageTexture, __VA_ARGS__)
#define glMemoryBarrier(...) CHECKED_GL_FUNCTION(g_glMemoryBarrier, __VA_ARGS__)
#define glGetStringi(...) CHECKED_GL_FUNCTION_WITH_RETURN(g_glGetStringi, const GLubyte*, __VA_ARGS__)
#define glInvalidateFramebuffer(...) CHECKED_GL_FUNCTION(g_glInvalidateFramebuffer, __VA_ARGS__)
#define glBufferStorage(...) CHECKED_GL_FUNCTION(g_glBufferStorage, __VA_ARGS__)
#define glFenceSync(...) CHECKED_GL_FUNCTION_WITH_RETURN(g_glFenceSync, GLsync, __VA_ARGS__)
#define glClientWaitSync(...) CHECKED_GL_FUNCTION(g_glClientWaitSync, __VA_ARGS__)
#define glDeleteSync(...) CHECKED_GL_FUNCTION(g_glDeleteSync, __VA_ARGS__)
extern PFNGLDRAWBUFFERSPROC ptrDrawBuffers;
extern PFNGLGENFRAMEBUFFERSPROC ptrGenFramebuffers;
extern PFNGLBINDFRAMEBUFFERPROC ptrBindFramebuffer;
extern PFNGLDELETEFRAMEBUFFERSPROC ptrDeleteFramebuffers;
extern PFNGLFRAMEBUFFERTEXTURE2DPROC ptrFramebufferTexture2D;
extern PFNGLTEXIMAGE2DMULTISAMPLEPROC ptrTexImage2DMultisample;
extern PFNGLTEXSTORAGE2DMULTISAMPLEPROC ptrTexStorage2DMultisample;
extern PFNGLGENRENDERBUFFERSPROC ptrGenRenderbuffers;
extern PFNGLBINDRENDERBUFFERPROC ptrBindRenderbuffer;
extern PFNGLRENDERBUFFERSTORAGEPROC ptrRenderbufferStorage;
extern PFNGLDELETERENDERBUFFERSPROC ptrDeleteRenderbuffers;
extern PFNGLFRAMEBUFFERRENDERBUFFERPROC ptrFramebufferRenderbuffer;
extern PFNGLCHECKFRAMEBUFFERSTATUSPROC ptrCheckFramebufferStatus;
extern PFNGLBLITFRAMEBUFFERPROC ptrBlitFramebuffer;
extern PFNGLGENVERTEXARRAYSPROC ptrGenVertexArrays;
extern PFNGLBINDVERTEXARRAYPROC ptrBindVertexArray;
extern PFNGLDELETEVERTEXARRAYSPROC ptrDeleteVertexArrays;
extern PFNGLGENBUFFERSPROC ptrGenBuffers;
extern PFNGLBINDBUFFERPROC ptrBindBuffer;
extern PFNGLBUFFERDATAPROC ptrBufferData;
extern PFNGLMAPBUFFERPROC ptrMapBuffer;
extern PFNGLMAPBUFFERRANGEPROC ptrMapBufferRange;
extern PFNGLUNMAPBUFFERPROC ptrUnmapBuffer;
extern PFNGLDELETEBUFFERSPROC ptrDeleteBuffers;
extern PFNGLBINDIMAGETEXTUREPROC ptrBindImageTexture;
extern PFNGLMEMORYBARRIERPROC ptrMemoryBarrier;
extern PFNGLGETSTRINGIPROC ptrGetStringi;
extern PFNGLINVALIDATEFRAMEBUFFERPROC ptrInvalidateFramebuffer;
extern PFNGLBUFFERSTORAGEPROC ptrBufferStorage;
extern PFNGLFENCESYNCPROC ptrFenceSync;
extern PFNGLCLIENTWAITSYNCPROC ptrClientWaitSync;
extern PFNGLDELETESYNCPROC ptrDeleteSync;
#define glGetUniformBlockIndex(...) CHECKED_GL_FUNCTION(g_glGetUniformBlockIndex, __VA_ARGS__)
#define glUniformBlockBinding(...) CHECKED_GL_FUNCTION(g_glUniformBlockBinding, __VA_ARGS__)
#define glGetActiveUniformBlockiv(...) CHECKED_GL_FUNCTION(g_glGetActiveUniformBlockiv, __VA_ARGS__)
#define glGetUniformIndices(...) CHECKED_GL_FUNCTION(g_glGetUniformIndices, __VA_ARGS__)
#define glGetActiveUniformsiv(...) CHECKED_GL_FUNCTION(g_glGetActiveUniformsiv, __VA_ARGS__)
#define glBindBufferBase(...) CHECKED_GL_FUNCTION(g_glBindBufferBase, __VA_ARGS__)
#define glBufferSubData(...) CHECKED_GL_FUNCTION(g_glBufferSubData, __VA_ARGS__)
extern PFNGLGETUNIFORMBLOCKINDEXPROC ptrGetUniformBlockIndex;
extern PFNGLUNIFORMBLOCKBINDINGPROC ptrUniformBlockBinding;
extern PFNGLGETACTIVEUNIFORMBLOCKIVPROC ptrGetActiveUniformBlockiv;
extern PFNGLGETUNIFORMINDICESPROC ptrGetUniformIndices;
extern PFNGLGETACTIVEUNIFORMSIVPROC ptrGetActiveUniformsiv;
extern PFNGLBINDBUFFERBASEPROC ptrBindBufferBase;
extern PFNGLBUFFERSUBDATAPROC ptrBufferSubData;
#define glGetProgramBinary(...) CHECKED_GL_FUNCTION(g_glGetProgramBinary, __VA_ARGS__)
#define glProgramBinary(...) CHECKED_GL_FUNCTION(g_glProgramBinary, __VA_ARGS__)
#define glProgramParameteri(...) CHECKED_GL_FUNCTION(g_glProgramParameteri, __VA_ARGS__)
extern PFNGLGETPROGRAMBINARYPROC ptrGetProgramBinary;
extern PFNGLPROGRAMBINARYPROC ptrProgramBinary;
extern PFNGLPROGRAMPARAMETERIPROC ptrProgramParameteri;
#define glTexStorage2D(...) CHECKED_GL_FUNCTION(g_glTexStorage2D, __VA_ARGS__)
#define glTextureStorage2D(...) CHECKED_GL_FUNCTION(g_glTextureStorage2D, __VA_ARGS__)
#define glTextureSubImage2D(...) CHECKED_GL_FUNCTION(g_glTextureSubImage2D, __VA_ARGS__)
#define glTextureStorage2DMultisample(...) CHECKED_GL_FUNCTION(g_glTextureStorage2DMultisample, __VA_ARGS__)
#define glTextureParameteri(...) CHECKED_GL_FUNCTION(g_glTextureParameteri, __VA_ARGS__)
#define glTextureParameterf(...) CHECKED_GL_FUNCTION(g_glTextureParameterf, __VA_ARGS__)
#define glCreateTextures(...) CHECKED_GL_FUNCTION(g_glCreateTextures, __VA_ARGS__)
#define glCreateBuffers(...) CHECKED_GL_FUNCTION(g_glCreateBuffers, __VA_ARGS__)
#define glCreateFramebuffers(...) CHECKED_GL_FUNCTION(g_glCreateFramebuffers, __VA_ARGS__)
#define glNamedFramebufferTexture(...) CHECKED_GL_FUNCTION(g_glNamedFramebufferTexture, __VA_ARGS__)
#define glDrawRangeElementsBaseVertex(...) CHECKED_GL_FUNCTION(g_glDrawRangeElementsBaseVertex, __VA_ARGS__)
#define glFlushMappedBufferRange(...) CHECKED_GL_FUNCTION(g_glFlushMappedBufferRange, __VA_ARGS__)
#define glTextureBarrier(...) CHECKED_GL_FUNCTION(g_glTextureBarrier, __VA_ARGS__)
#define glTextureBarrierNV(...) CHECKED_GL_FUNCTION(g_glTextureBarrierNV, __VA_ARGS__)
#define glClearBufferfv(...) CHECKED_GL_FUNCTION(g_glClearBufferfv, __VA_ARGS__)
#define glEnablei(...) CHECKED_GL_FUNCTION(g_glEnablei, __VA_ARGS__)
#define glDisablei(...) CHECKED_GL_FUNCTION(g_glDisablei, __VA_ARGS__)
#define glEGLImageTargetTexture2DOES(...) CHECKED_GL_FUNCTION(g_glEGLImageTargetTexture2DOES, __VA_ARGS__)
extern PFNGLCREATESHADERPROC g_glCreateShader;
extern PFNGLCOMPILESHADERPROC g_glCompileShader;
extern PFNGLSHADERSOURCEPROC g_glShaderSource;
extern PFNGLCREATEPROGRAMPROC g_glCreateProgram;
extern PFNGLATTACHSHADERPROC g_glAttachShader;
extern PFNGLLINKPROGRAMPROC g_glLinkProgram;
extern PFNGLUSEPROGRAMPROC g_glUseProgram;
extern PFNGLGETUNIFORMLOCATIONPROC g_glGetUniformLocation;
extern PFNGLUNIFORM1IPROC g_glUniform1i;
extern PFNGLUNIFORM1FPROC g_glUniform1f;
extern PFNGLUNIFORM2FPROC g_glUniform2f;
extern PFNGLUNIFORM2IPROC g_glUniform2i;
extern PFNGLUNIFORM4IPROC g_glUniform4i;
extern PFNGLUNIFORM4FPROC g_glUniform4f;
extern PFNGLUNIFORM3FVPROC g_glUniform3fv;
extern PFNGLUNIFORM4FVPROC g_glUniform4fv;
extern PFNGLDETACHSHADERPROC g_glDetachShader;
extern PFNGLDELETESHADERPROC g_glDeleteShader;
extern PFNGLDELETEPROGRAMPROC g_glDeleteProgram;
extern PFNGLGETPROGRAMINFOLOGPROC g_glGetProgramInfoLog;
extern PFNGLGETSHADERINFOLOGPROC g_glGetShaderInfoLog;
extern PFNGLGETSHADERIVPROC g_glGetShaderiv;
extern PFNGLGETPROGRAMIVPROC g_glGetProgramiv;
extern PFNGLENABLEVERTEXATTRIBARRAYPROC g_glEnableVertexAttribArray;
extern PFNGLDISABLEVERTEXATTRIBARRAYPROC g_glDisableVertexAttribArray;
extern PFNGLVERTEXATTRIBPOINTERPROC g_glVertexAttribPointer;
extern PFNGLBINDATTRIBLOCATIONPROC g_glBindAttribLocation;
extern PFNGLVERTEXATTRIB1FPROC g_glVertexAttrib1f;
extern PFNGLVERTEXATTRIB4FPROC g_glVertexAttrib4f;
extern PFNGLVERTEXATTRIB4FVPROC g_glVertexAttrib4fv;
extern PFNGLDEPTHRANGEFPROC g_glDepthRangef;
extern PFNGLCLEARDEPTHFPROC g_glClearDepthf;
extern PFNGLDRAWBUFFERSPROC g_glDrawBuffers;
extern PFNGLGENFRAMEBUFFERSPROC g_glGenFramebuffers;
extern PFNGLBINDFRAMEBUFFERPROC g_glBindFramebuffer;
extern PFNGLDELETEFRAMEBUFFERSPROC g_glDeleteFramebuffers;
extern PFNGLFRAMEBUFFERTEXTURE2DPROC g_glFramebufferTexture2D;
extern PFNGLTEXIMAGE2DMULTISAMPLEPROC g_glTexImage2DMultisample;
extern PFNGLTEXSTORAGE2DMULTISAMPLEPROC g_glTexStorage2DMultisample;
extern PFNGLGENRENDERBUFFERSPROC g_glGenRenderbuffers;
extern PFNGLBINDRENDERBUFFERPROC g_glBindRenderbuffer;
extern PFNGLRENDERBUFFERSTORAGEPROC g_glRenderbufferStorage;
extern PFNGLDELETERENDERBUFFERSPROC g_glDeleteRenderbuffers;
extern PFNGLFRAMEBUFFERRENDERBUFFERPROC g_glFramebufferRenderbuffer;
extern PFNGLCHECKFRAMEBUFFERSTATUSPROC g_glCheckFramebufferStatus;
extern PFNGLBLITFRAMEBUFFERPROC g_glBlitFramebuffer;
extern PFNGLGENVERTEXARRAYSPROC g_glGenVertexArrays;
extern PFNGLBINDVERTEXARRAYPROC g_glBindVertexArray;
extern PFNGLDELETEVERTEXARRAYSPROC g_glDeleteVertexArrays;
extern PFNGLGENBUFFERSPROC g_glGenBuffers;
extern PFNGLBINDBUFFERPROC g_glBindBuffer;
extern PFNGLBUFFERDATAPROC g_glBufferData;
extern PFNGLMAPBUFFERPROC g_glMapBuffer;
extern PFNGLMAPBUFFERRANGEPROC g_glMapBufferRange;
extern PFNGLUNMAPBUFFERPROC g_glUnmapBuffer;
extern PFNGLDELETEBUFFERSPROC g_glDeleteBuffers;
extern PFNGLBINDIMAGETEXTUREPROC g_glBindImageTexture;
extern PFNGLMEMORYBARRIERPROC g_glMemoryBarrier;
extern PFNGLGETSTRINGIPROC g_glGetStringi;
extern PFNGLINVALIDATEFRAMEBUFFERPROC g_glInvalidateFramebuffer;
extern PFNGLBUFFERSTORAGEPROC g_glBufferStorage;
extern PFNGLFENCESYNCPROC g_glFenceSync;
extern PFNGLCLIENTWAITSYNCPROC g_glClientWaitSync;
extern PFNGLDELETESYNCPROC g_glDeleteSync;
extern PFNGLGETUNIFORMBLOCKINDEXPROC g_glGetUniformBlockIndex;
extern PFNGLUNIFORMBLOCKBINDINGPROC g_glUniformBlockBinding;
extern PFNGLGETACTIVEUNIFORMBLOCKIVPROC g_glGetActiveUniformBlockiv;
extern PFNGLGETUNIFORMINDICESPROC g_glGetUniformIndices;
extern PFNGLGETACTIVEUNIFORMSIVPROC g_glGetActiveUniformsiv;
extern PFNGLBINDBUFFERBASEPROC g_glBindBufferBase;
extern PFNGLBUFFERSUBDATAPROC g_glBufferSubData;
extern PFNGLGETPROGRAMBINARYPROC g_glGetProgramBinary;
extern PFNGLPROGRAMBINARYPROC g_glProgramBinary;
extern PFNGLPROGRAMPARAMETERIPROC g_glProgramParameteri;
extern PFNGLTEXSTORAGE2DPROC g_glTexStorage2D;
extern PFNGLTEXTURESTORAGE2DPROC g_glTextureStorage2D;
extern PFNGLTEXTURESUBIMAGE2DPROC g_glTextureSubImage2D;
extern PFNGLTEXTURESTORAGE2DMULTISAMPLEEXTPROC g_glTextureStorage2DMultisample;
extern PFNGLTEXTUREPARAMETERIPROC g_glTextureParameteri;
extern PFNGLTEXTUREPARAMETERFPROC g_glTextureParameterf;
extern PFNGLCREATETEXTURESPROC g_glCreateTextures;
extern PFNGLCREATEBUFFERSPROC g_glCreateBuffers;
extern PFNGLCREATEFRAMEBUFFERSPROC g_glCreateFramebuffers;
extern PFNGLNAMEDFRAMEBUFFERTEXTUREPROC g_glNamedFramebufferTexture;
extern PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC g_glDrawRangeElementsBaseVertex;
extern PFNGLFLUSHMAPPEDBUFFERRANGEPROC g_glFlushMappedBufferRange;
extern PFNGLTEXTUREBARRIERPROC g_glTextureBarrier;
extern PFNGLTEXTUREBARRIERNVPROC g_glTextureBarrierNV;
extern PFNGLCLEARBUFFERFVPROC g_glClearBufferfv;
extern PFNGLENABLEIPROC g_glEnablei;
extern PFNGLDISABLEIPROC g_glDisablei;
extern PFNGLTEXSTORAGE2DPROC ptrTexStorage2D;
extern PFNGLTEXTURESTORAGE2DPROC ptrTextureStorage2D;
extern PFNGLTEXTURESUBIMAGE2DPROC ptrTextureSubImage2D;
extern PFNGLTEXTURESTORAGE2DMULTISAMPLEEXTPROC ptrTextureStorage2DMultisample;
extern PFNGLTEXTUREPARAMETERIPROC ptrTextureParameteri;
extern PFNGLTEXTUREPARAMETERFPROC ptrTextureParameterf;
extern PFNGLCREATETEXTURESPROC ptrCreateTextures;
extern PFNGLCREATEBUFFERSPROC ptrCreateBuffers;
extern PFNGLCREATEFRAMEBUFFERSPROC ptrCreateFramebuffers;
extern PFNGLNAMEDFRAMEBUFFERTEXTUREPROC ptrNamedFramebufferTexture;
extern PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC ptrDrawRangeElementsBaseVertex;
extern PFNGLFLUSHMAPPEDBUFFERRANGEPROC ptrFlushMappedBufferRange;
extern PFNGLTEXTUREBARRIERPROC ptrTextureBarrier;
extern PFNGLTEXTUREBARRIERNVPROC ptrTextureBarrierNV;
extern PFNGLCLEARBUFFERFVPROC ptrClearBufferfv;
extern PFNGLENABLEIPROC ptrEnablei;
extern PFNGLDISABLEIPROC ptrDisablei;
typedef void (APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, void* image);
extern PFNGLEGLIMAGETARGETTEXTURE2DOESPROC g_glEGLImageTargetTexture2DOES;
extern PFNGLEGLIMAGETARGETTEXTURE2DOESPROC ptrEGLImageTargetTexture2DOES;
void initGLFunctions();
template<typename F> void checked(F fn, const char* _functionName)
{
fn();
auto error = glGetError();
if (error != GL_NO_ERROR) {
std::stringstream errorString;
errorString << _functionName << " OpenGL error: 0x" << std::hex << error;
LOG(LOG_ERROR, errorString.str().c_str());
throw std::runtime_error(errorString.str().c_str());
}
}
#define glGetError(...) opengl::FunctionWrapper::wrGetError(__VA_ARGS__)
#define glBlendFunc(...) opengl::FunctionWrapper::wrBlendFunc(__VA_ARGS__)
#define glPixelStorei(...) opengl::FunctionWrapper::wrPixelStorei(__VA_ARGS__)
#define glClearColor(...) opengl::FunctionWrapper::wrClearColor(__VA_ARGS__)
#define glCullFace(...) opengl::FunctionWrapper::wrCullFace(__VA_ARGS__)
#define glDepthFunc(...) opengl::FunctionWrapper::wrDepthFunc(__VA_ARGS__)
#define glDepthMask(...) opengl::FunctionWrapper::wrDepthMask(__VA_ARGS__)
#define glDisable(...) opengl::FunctionWrapper::wrDisable(__VA_ARGS__)
#define glEnable(...) opengl::FunctionWrapper::wrEnable(__VA_ARGS__)
#define glPolygonOffset(...) opengl::FunctionWrapper::wrPolygonOffset(__VA_ARGS__)
#define glScissor(...) opengl::FunctionWrapper::wrScissor(__VA_ARGS__)
#define glViewport(...) opengl::FunctionWrapper::wrViewport(__VA_ARGS__)
#define glBindTexture(...) opengl::FunctionWrapper::wrBindTexture(__VA_ARGS__)
#define glTexImage2D(...) opengl::FunctionWrapper::wrTexImage2D(__VA_ARGS__)
#define glTexParameteri(...) opengl::FunctionWrapper::wrTexParameteri(__VA_ARGS__)
#define glGetIntegerv(...) opengl::FunctionWrapper::wrGetIntegerv(__VA_ARGS__)
#define glGetString(...) opengl::FunctionWrapper::wrGetString(__VA_ARGS__)
#define glReadPixels(...) opengl::FunctionWrapper::wrReadPixels(__VA_ARGS__)
#define glTexSubImage2D(...) opengl::FunctionWrapper::wrTexSubImage2D(__VA_ARGS__)
#define glDrawArrays(...) opengl::FunctionWrapper::wrDrawArrays(__VA_ARGS__)
#define glDrawElements(...) opengl::FunctionWrapper::wrDrawElements(__VA_ARGS__)
#define glLineWidth(...) opengl::FunctionWrapper::wrLineWidth(__VA_ARGS__)
#define glClear(...) opengl::FunctionWrapper::wrClear(__VA_ARGS__)
#define glGetFloatv(...) opengl::FunctionWrapper::wrGetFloatv(__VA_ARGS__)
#define glDeleteTextures(...) opengl::FunctionWrapper::wrDeleteTextures(__VA_ARGS__)
#define glGenTextures(...) opengl::FunctionWrapper::wrGenTextures(__VA_ARGS__)
#define glTexParameterf(...) opengl::FunctionWrapper::wrTexParameterf(__VA_ARGS__)
#define glActiveTexture(...) opengl::FunctionWrapper::wrActiveTexture(__VA_ARGS__)
#define glBlendColor(...) opengl::FunctionWrapper::wrBlendColor(__VA_ARGS__)
#define glReadBuffer(...) opengl::FunctionWrapper::wrReadBuffer(__VA_ARGS__)
#define glFinish(...) opengl::FunctionWrapper::wrFinish(__VA_ARGS__)
#if defined(OS_ANDROID)
#define eglGetNativeClientBufferANDROID(...) opengl::FunctionWrapper::ewrGetNativeClientBufferANDROID(__VA_ARGS__)
#endif
#define glCreateShader(...) opengl::FunctionWrapper::wrCreateShader(__VA_ARGS__)
#define glCompileShader(...) opengl::FunctionWrapper::wrCompileShader(__VA_ARGS__)
#define glShaderSource(...) opengl::FunctionWrapper::wrShaderSource(__VA_ARGS__)
#define glCreateProgram(...) opengl::FunctionWrapper::wrCreateProgram(__VA_ARGS__)
#define glAttachShader(...) opengl::FunctionWrapper::wrAttachShader(__VA_ARGS__)
#define glLinkProgram(...) opengl::FunctionWrapper::wrLinkProgram(__VA_ARGS__)
#define glUseProgram(...) opengl::FunctionWrapper::wrUseProgram(__VA_ARGS__)
#define glGetUniformLocation(...) opengl::FunctionWrapper::wrGetUniformLocation(__VA_ARGS__)
#define glUniform1i(...) opengl::FunctionWrapper::wrUniform1i(__VA_ARGS__)
#define glUniform1f(...) opengl::FunctionWrapper::wrUniform1f(__VA_ARGS__)
#define glUniform2f(...) opengl::FunctionWrapper::wrUniform2f(__VA_ARGS__)
#define glUniform2i(...) opengl::FunctionWrapper::wrUniform2i(__VA_ARGS__)
#define glUniform4i(...) opengl::FunctionWrapper::wrUniform4i(__VA_ARGS__)
template<typename R, typename F> R checkedWithReturn(F fn, const char* _functionName)
{
R returnValue = fn();
auto error = glGetError();
if (error != GL_NO_ERROR) {
std::stringstream errorString;
errorString << _functionName << " OpenGL error: 0x" << std::hex << error;
LOG(LOG_ERROR, errorString.str().c_str());
throw std::runtime_error(errorString.str().c_str());
}
#define glUniform4f(...) opengl::FunctionWrapper::wrUniform4f(__VA_ARGS__)
#define glUniform3fv(...) opengl::FunctionWrapper::wrUniform3fv(__VA_ARGS__)
#define glUniform4fv(...) opengl::FunctionWrapper::wrUniform4fv(__VA_ARGS__)
#define glDetachShader(...) opengl::FunctionWrapper::wrDetachShader(__VA_ARGS__)
#define glDeleteShader(...) opengl::FunctionWrapper::wrDeleteShader(__VA_ARGS__)
#define glDeleteProgram(...) opengl::FunctionWrapper::wrDeleteProgram(__VA_ARGS__)
#define glGetProgramInfoLog(...) opengl::FunctionWrapper::wrGetProgramInfoLog(__VA_ARGS__)
#define glGetShaderInfoLog(...) opengl::FunctionWrapper::wrGetShaderInfoLog(__VA_ARGS__)
#define glGetShaderiv(...) opengl::FunctionWrapper::wrGetShaderiv(__VA_ARGS__)
#define glGetProgramiv(...) opengl::FunctionWrapper::wrGetProgramiv(__VA_ARGS__)
return returnValue;
}
#define glEnableVertexAttribArray(...) opengl::FunctionWrapper::wrEnableVertexAttribArray(__VA_ARGS__)
#define glDisableVertexAttribArray(...) opengl::FunctionWrapper::wrDisableVertexAttribArray(__VA_ARGS__)
#define glVertexAttribPointer(...) opengl::FunctionWrapper::wrVertexAttribPointer(__VA_ARGS__)
#define glBindAttribLocation(...) opengl::FunctionWrapper::wrBindAttribLocation(__VA_ARGS__)
#define glVertexAttrib1f(...) opengl::FunctionWrapper::wrVertexAttrib1f(__VA_ARGS__)
#define glVertexAttrib4f(...) opengl::FunctionWrapper::wrVertexAttrib4f(__VA_ARGS__)
#define glVertexAttrib4fv(...) opengl::FunctionWrapper::wrVertexAttrib4fv(__VA_ARGS__)
#define glDepthRangef(...) opengl::FunctionWrapper::wrDepthRangef(__VA_ARGS__)
#define glClearDepthf(...) opengl::FunctionWrapper::wrClearDepthf(__VA_ARGS__)
#define glBindBuffer(...) opengl::FunctionWrapper::wrBindBuffer(__VA_ARGS__)
#define glBindFramebuffer(...) opengl::FunctionWrapper::wrBindFramebuffer(__VA_ARGS__)
#define glBindRenderbuffer(...) opengl::FunctionWrapper::wrBindRenderbuffer(__VA_ARGS__)
#define glDrawBuffers(...) opengl::FunctionWrapper::wrDrawBuffers(__VA_ARGS__)
#define glGenFramebuffers(...) opengl::FunctionWrapper::wrGenFramebuffers(__VA_ARGS__)
#define glDeleteFramebuffers(...) opengl::FunctionWrapper::wrDeleteFramebuffers(__VA_ARGS__)
#define glFramebufferTexture2D(...) opengl::FunctionWrapper::wrFramebufferTexture2D(__VA_ARGS__)
#define glTexImage2DMultisample(...) opengl::FunctionWrapper::wrTexImage2DMultisample(__VA_ARGS__)
#define glTexStorage2DMultisample(...) opengl::FunctionWrapper::wrTexStorage2DMultisample(__VA_ARGS__)
#define glGenRenderbuffers(...) opengl::FunctionWrapper::wrGenRenderbuffers(__VA_ARGS__)
#define glRenderbufferStorage(...) opengl::FunctionWrapper::wrRenderbufferStorage(__VA_ARGS__)
#define glDeleteRenderbuffers(...) opengl::FunctionWrapper::wrDeleteRenderbuffers(__VA_ARGS__)
#define glFramebufferRenderbuffer(...) opengl::FunctionWrapper::wrFramebufferRenderbuffer(__VA_ARGS__)
#define glCheckFramebufferStatus(...) opengl::FunctionWrapper::wrCheckFramebufferStatus(__VA_ARGS__)
#define glBlitFramebuffer(...) opengl::FunctionWrapper::wrBlitFramebuffer(__VA_ARGS__)
#define glGenVertexArrays(...) opengl::FunctionWrapper::wrGenVertexArrays(__VA_ARGS__)
#define glBindVertexArray(...) opengl::FunctionWrapper::wrBindVertexArray(__VA_ARGS__)
#define glDeleteVertexArrays(...) opengl::FunctionWrapper::wrDeleteVertexArrays(__VA_ARGS__);
#define glGenBuffers(...) opengl::FunctionWrapper::wrGenBuffers(__VA_ARGS__)
#define glBufferData(...) opengl::FunctionWrapper::wrBufferData(__VA_ARGS__)
#define glMapBuffer(...) opengl::FunctionWrapper::wrMapBuffer(__VA_ARGS__)
#define glMapBufferRange(...) opengl::FunctionWrapper::wrMapBufferRange(__VA_ARGS__)
#define glUnmapBuffer(...) opengl::FunctionWrapper::wrUnmapBuffer(__VA_ARGS__)
#define glDeleteBuffers(...) opengl::FunctionWrapper::wrDeleteBuffers(__VA_ARGS__)
#define glBindImageTexture(...) opengl::FunctionWrapper::wrBindImageTexture(__VA_ARGS__)
#define glMemoryBarrier(...) opengl::FunctionWrapper::wrMemoryBarrier(__VA_ARGS__)
#define glGetStringi(...) opengl::FunctionWrapper::wrGetStringi(__VA_ARGS__)
#define glInvalidateFramebuffer(...) opengl::FunctionWrapper::wrInvalidateFramebuffer(__VA_ARGS__)
#define glBufferStorage(...) opengl::FunctionWrapper::wrBufferStorage(__VA_ARGS__)
#define glFenceSync(...) opengl::FunctionWrapper::wrFenceSync(__VA_ARGS__)
#define glClientWaitSync(...) opengl::FunctionWrapper::wrClientWaitSync(__VA_ARGS__)
#define glDeleteSync(...) opengl::FunctionWrapper::wrDeleteSync(__VA_ARGS__)
#define glGetUniformBlockIndex(...) opengl::FunctionWrapper::wrGetUniformBlockIndex(__VA_ARGS__)
#define glUniformBlockBinding(...) opengl::FunctionWrapper::wrUniformBlockBinding(__VA_ARGS__)
#define glGetActiveUniformBlockiv(...) opengl::FunctionWrapper::wrGetActiveUniformBlockiv(__VA_ARGS__)
#define glGetUniformIndices(...) opengl::FunctionWrapper::wrGetUniformIndices(__VA_ARGS__)
#define glGetActiveUniformsiv(...) opengl::FunctionWrapper::wrGetActiveUniformsiv(__VA_ARGS__)
#define glBindBufferBase(...) opengl::FunctionWrapper::wrBindBufferBase(__VA_ARGS__)
#define glBufferSubData(...) opengl::FunctionWrapper::wrBufferSubData(__VA_ARGS__)
#define glGetProgramBinary(...) opengl::FunctionWrapper::wrGetProgramBinary(__VA_ARGS__)
#define glProgramBinary(...) opengl::FunctionWrapper::wrProgramBinary(__VA_ARGS__)
#define glProgramParameteri(...) opengl::FunctionWrapper::wrProgramParameteri(__VA_ARGS__)
#define glTexStorage2D(...) opengl::FunctionWrapper::wrTexStorage2D(__VA_ARGS__)
#define glTextureStorage2D(...) opengl::FunctionWrapper::wrTextureStorage2D(__VA_ARGS__)
#define glTextureSubImage2D(...) opengl::FunctionWrapper::wrTextureSubImage2D(__VA_ARGS__)
#define glTextureStorage2DMultisample(...) opengl::FunctionWrapper::wrTextureStorage2DMultisample(__VA_ARGS__)
#define glTextureParameteri(...) opengl::FunctionWrapper::wrTextureParameteri(__VA_ARGS__)
#define glTextureParameterf(...) opengl::FunctionWrapper::wrTextureParameterf(__VA_ARGS__)
#define glCreateTextures(...) opengl::FunctionWrapper::wrCreateTextures(__VA_ARGS__)
#define glCreateBuffers(...) opengl::FunctionWrapper::wrCreateBuffers(__VA_ARGS__)
#define glCreateFramebuffers(...) opengl::FunctionWrapper::wrCreateFramebuffers(__VA_ARGS__)
#define glNamedFramebufferTexture(...) opengl::FunctionWrapper::wrNamedFramebufferTexture(__VA_ARGS__)
#define glDrawRangeElementsBaseVertex(...) opengl::FunctionWrapper::wrDrawRangeElementsBaseVertex(__VA_ARGS__)
#define glFlushMappedBufferRange(...) opengl::FunctionWrapper::wrFlushMappedBufferRange(__VA_ARGS__)
#define glTextureBarrier(...) opengl::FunctionWrapper::wrTextureBarrier(__VA_ARGS__)
#define glTextureBarrierNV(...) opengl::FunctionWrapper::wrTextureBarrierNV(__VA_ARGS__)
#define glClearBufferfv(...) opengl::FunctionWrapper::wrClearBufferfv(__VA_ARGS__)
#define glEnablei(...) opengl::FunctionWrapper::wrEnablei(__VA_ARGS__)
#define glDisablei(...) opengl::FunctionWrapper::wrDisablei(__VA_ARGS__)
#define glEGLImageTargetTexture2DOES(...) opengl::FunctionWrapper::wrEGLImageTargetTexture2DOES(__VA_ARGS__)
#include "Graphics/OpenGLContext/ThreadedOpenGl/opengl_Wrapper.h"
#endif // GLFUNCTIONS_H

View File

@ -2445,7 +2445,7 @@ graphics::CombinerProgram * CombinerProgramBuilder::buildCombinerProgram(Combine
glAttachShader(program, bUseTextures ? m_vertexShaderTexturedTriangle : m_vertexShaderTriangle);
glAttachShader(program, fragmentShader);
if (CombinerInfo::get().isShaderCacheSupported()) {
if (IS_GL_FUNCTION_VALID(glProgramParameteri))
if (IS_GL_FUNCTION_VALID(ProgramParameteri))
glProgramParameteri(program, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);
}
glLinkProgram(program);

View File

@ -0,0 +1,57 @@
#pragma once
#include <mutex>
#include <condition_variable>
#include <deque>
template <typename T, typename Container = std::deque<T>>
class BlockingQueue
{
private:
std::mutex m_mutex;
std::condition_variable m_condition;
Container m_queue;
public:
void push(T const& value)
{
{
std::unique_lock<std::mutex> lock(this->m_mutex);
m_queue.push_front(value);
}
this->m_condition.notify_one();
}
void pushBack(T const& value)
{
{
std::unique_lock<std::mutex> lock(this->m_mutex);
m_queue.push_back(value);
}
this->m_condition.notify_one();
}
T pop()
{
std::unique_lock<std::mutex> lock(this->m_mutex);
this->m_condition.wait(lock, [this]{ return !this->m_queue.empty(); });
T rc(std::move(this->m_queue.back()));
this->m_queue.pop_back();
return rc;
}
bool tryPop(T & v, std::chrono::milliseconds dur)
{
std::unique_lock<std::mutex> lock(this->m_mutex);
if (!this->m_condition.wait_for(lock, dur, [this]{ return !this->m_queue.empty(); })) {
return false;
}
v = std::move(this->m_queue.back());
this->m_queue.pop_back();
return true;
}
size_t size()
{
return m_queue.size();
}
};

View File

@ -0,0 +1,148 @@
#include "RingBufferPool.h"
#include <memory>
#include <algorithm>
namespace opengl {
PoolBufferPointer::PoolBufferPointer() :
m_offset(0),
m_size(0),
m_realSize(0),
m_isValid(false)
{
}
PoolBufferPointer::PoolBufferPointer(size_t _offset, size_t _size, size_t _realSize, bool _isValid) :
m_offset(_offset),
m_size(_size),
m_realSize(_realSize),
m_isValid(_isValid)
{
}
PoolBufferPointer::PoolBufferPointer(const PoolBufferPointer& other) :
m_offset(other.m_offset),
m_size(other.m_size),
m_realSize(other.m_realSize),
m_isValid(other.m_isValid)
{
}
PoolBufferPointer& PoolBufferPointer::operator=(const PoolBufferPointer& other)
{
m_offset = other.m_offset;
m_size = other.m_size;
m_realSize = other.m_realSize;
m_isValid = other.m_isValid;
return *this;
}
bool PoolBufferPointer::isValid() const
{
return m_isValid;
}
size_t PoolBufferPointer::getSize() const
{
return m_size;
}
RingBufferPool::RingBufferPool(size_t _poolSize) :
m_poolBuffer(_poolSize, 0),
m_inUseStartOffset(0),
m_inUseEndOffset(0),
m_full(false)
{
}
PoolBufferPointer RingBufferPool::createPoolBuffer(const char* _buffer, size_t _bufferSize)
{
size_t realBufferSize = _bufferSize;
size_t remainder = _bufferSize % 4;
if (remainder != 0)
realBufferSize = _bufferSize + 4 - remainder;
size_t tempInUseStart = m_inUseStartOffset;
size_t remaining = tempInUseStart > m_inUseEndOffset || m_full ?
static_cast<size_t>(tempInUseStart - m_inUseEndOffset) :
m_poolBuffer.size() - m_inUseEndOffset + tempInUseStart;
bool isValid = remaining >= realBufferSize;
size_t startOffset = 0;
// We have determined that it fits
if (isValid) {
// We don't want to split data between the end of the ring buffer and the start
// Re-check buffer size if we are going to start at the beginning of the ring buffer
if (m_inUseEndOffset + realBufferSize > m_poolBuffer.size()) {
isValid = realBufferSize < tempInUseStart || tempInUseStart == m_inUseEndOffset;
if (isValid) {
startOffset = 0;
m_inUseEndOffset = realBufferSize;
} else {
{
std::unique_lock<std::mutex> lock(m_mutex);
m_condition.wait(lock, [this, realBufferSize] {
size_t tempInUseStartLocal = m_inUseStartOffset;
return realBufferSize < tempInUseStartLocal ||
tempInUseStartLocal == m_inUseEndOffset;
});
}
return createPoolBuffer(_buffer, _bufferSize);
}
} else {
startOffset = m_inUseEndOffset;
m_inUseEndOffset += realBufferSize;
}
} else {
// Wait until enough space is avalable
{
std::unique_lock<std::mutex> lock(m_mutex);
m_condition.wait(lock, [this, realBufferSize] {
size_t tempInUseStartLocal = m_inUseStartOffset;
size_t remainingLocal =
tempInUseStartLocal > m_inUseEndOffset || m_full ? static_cast<size_t>(
tempInUseStartLocal - m_inUseEndOffset) :
m_poolBuffer.size() - m_inUseEndOffset + tempInUseStartLocal;
return remainingLocal >= realBufferSize;
});
}
return createPoolBuffer(_buffer, _bufferSize);
}
std::copy_n(_buffer, _bufferSize, &m_poolBuffer[startOffset]);
m_full = m_inUseEndOffset == tempInUseStart;
return PoolBufferPointer(startOffset, _bufferSize, realBufferSize, isValid);
}
const char* RingBufferPool::getBufferFromPool(PoolBufferPointer _poolBufferPointer)
{
if (!_poolBufferPointer.isValid()) {
return nullptr;
} else {
return m_poolBuffer.data() + _poolBufferPointer.m_offset;
}
}
void RingBufferPool::removeBufferFromPool(PoolBufferPointer _poolBufferPointer)
{
std::unique_lock<std::mutex> lock(m_mutex);
m_inUseStartOffset = _poolBufferPointer.m_offset + _poolBufferPointer.m_realSize;
m_full = false;
m_condition.notify_one();
}
}

View File

@ -0,0 +1,52 @@
#pragma once
#include <memory>
#include <vector>
#include <atomic>
#include <mutex>
#include <condition_variable>
namespace opengl {
//This class is only thread safe for a single producer and single consumer
class PoolBufferPointer
{
public:
PoolBufferPointer();
PoolBufferPointer(const PoolBufferPointer& other);
PoolBufferPointer& operator=(const PoolBufferPointer& other);
bool isValid() const;
size_t getSize() const;
private:
PoolBufferPointer(size_t _offset, size_t _size, size_t _realSize, bool _isValid);
size_t m_offset;
size_t m_size;
size_t m_realSize;
bool m_isValid;
friend class RingBufferPool;
};
class RingBufferPool
{
public:
explicit RingBufferPool(size_t _poolSize);
PoolBufferPointer createPoolBuffer(const char* _buffer, size_t _bufferSize);
const char* getBufferFromPool(PoolBufferPointer _poolBufferPointer);
void removeBufferFromPool(PoolBufferPointer _poolBufferPointer);
private:
std::atomic<size_t> m_inUseStartOffset;
std::atomic<size_t> m_inUseEndOffset;
std::vector<char> m_poolBuffer;
std::mutex m_mutex;
std::atomic<bool> m_full;
std::condition_variable_any m_condition;
};
}

View File

@ -0,0 +1,675 @@
// ©2013-2016 Cameron Desrochers.
// Distributed under the simplified BSD license (see the license file that
// should have come with this header).
// Uses Jeff Preshing's semaphore implementation (under the terms of its
// separate zlib license, embedded below).
#pragma once
// Provides portable (VC++2010+, Intel ICC 13, GCC 4.7+, and anything C++11 compliant) implementation
// of low-level memory barriers, plus a few semi-portable utility macros (for inlining and alignment).
// Also has a basic atomic type (limited to hardware-supported atomics with no memory ordering guarantees).
// Uses the AE_* prefix for macros (historical reasons), and the "moodycamel" namespace for symbols.
#include <cassert>
#include <type_traits>
#include <cerrno>
#include <cstdint>
#include <ctime>
// Platform detection
#if defined(__INTEL_COMPILER)
#define AE_ICC
#elif defined(_MSC_VER)
#define AE_VCPP
#elif defined(__GNUC__)
#define AE_GCC
#endif
#if defined(_M_IA64) || defined(__ia64__)
#define AE_ARCH_IA64
#elif defined(_WIN64) || defined(__amd64__) || defined(_M_X64) || defined(__x86_64__)
#define AE_ARCH_X64
#elif defined(_M_IX86) || defined(__i386__)
#define AE_ARCH_X86
#elif defined(_M_PPC) || defined(__powerpc__)
#define AE_ARCH_PPC
#else
#define AE_ARCH_UNKNOWN
#endif
// AE_UNUSED
#define AE_UNUSED(x) ((void)x)
// AE_NO_TSAN
#if defined(__has_feature)
#if __has_feature(thread_sanitizer)
#define AE_NO_TSAN __attribute__((no_sanitize("thread")))
#else
#define AE_NO_TSAN
#endif
#else
#define AE_NO_TSAN
#endif
// AE_FORCEINLINE
#if defined(AE_VCPP) || defined(AE_ICC)
#define AE_FORCEINLINE __forceinline
#elif defined(AE_GCC)
//#define AE_FORCEINLINE __attribute__((always_inline))
#define AE_FORCEINLINE inline
#else
#define AE_FORCEINLINE inline
#endif
// AE_ALIGN
#if defined(AE_VCPP) || defined(AE_ICC)
#define AE_ALIGN(x) __declspec(align(x))
#elif defined(AE_GCC)
#define AE_ALIGN(x) __attribute__((aligned(x)))
#else
// Assume GCC compliant syntax...
#define AE_ALIGN(x) __attribute__((aligned(x)))
#endif
// Portable atomic fences implemented below:
namespace moodycamel {
enum memory_order {
memory_order_relaxed,
memory_order_acquire,
memory_order_release,
memory_order_acq_rel,
memory_order_seq_cst,
// memory_order_sync: Forces a full sync:
// #LoadLoad, #LoadStore, #StoreStore, and most significantly, #StoreLoad
memory_order_sync = memory_order_seq_cst
};
} // end namespace moodycamel
#if (defined(AE_VCPP) && (_MSC_VER < 1700 || defined(__cplusplus_cli))) || (defined(AE_ICC) && __INTEL_COMPILER < 1600)
// VS2010 and ICC13 don't support std::atomic_*_fence, implement our own fences
#include <intrin.h>
#if defined(AE_ARCH_X64) || defined(AE_ARCH_X86)
#define AeFullSync _mm_mfence
#define AeLiteSync _mm_mfence
#elif defined(AE_ARCH_IA64)
#define AeFullSync __mf
#define AeLiteSync __mf
#elif defined(AE_ARCH_PPC)
#include <ppcintrinsics.h>
#define AeFullSync __sync
#define AeLiteSync __lwsync
#endif
#ifdef AE_VCPP
#pragma warning(push)
#pragma warning(disable: 4365) // Disable erroneous 'conversion from long to unsigned int, signed/unsigned mismatch' error when using `assert`
#ifdef __cplusplus_cli
#pragma managed(push, off)
#endif
#endif
namespace moodycamel {
AE_FORCEINLINE void compiler_fence(memory_order order) AE_NO_TSAN
{
switch (order) {
case memory_order_relaxed: break;
case memory_order_acquire: _ReadBarrier(); break;
case memory_order_release: _WriteBarrier(); break;
case memory_order_acq_rel: _ReadWriteBarrier(); break;
case memory_order_seq_cst: _ReadWriteBarrier(); break;
default: assert(false);
}
}
// x86/x64 have a strong memory model -- all loads and stores have
// acquire and release semantics automatically (so only need compiler
// barriers for those).
#if defined(AE_ARCH_X86) || defined(AE_ARCH_X64)
AE_FORCEINLINE void fence(memory_order order) AE_NO_TSAN
{
switch (order) {
case memory_order_relaxed: break;
case memory_order_acquire: _ReadBarrier(); break;
case memory_order_release: _WriteBarrier(); break;
case memory_order_acq_rel: _ReadWriteBarrier(); break;
case memory_order_seq_cst:
_ReadWriteBarrier();
AeFullSync();
_ReadWriteBarrier();
break;
default: assert(false);
}
}
#else
AE_FORCEINLINE void fence(memory_order order) AE_NO_TSAN
{
// Non-specialized arch, use heavier memory barriers everywhere just in case :-(
switch (order) {
case memory_order_relaxed:
break;
case memory_order_acquire:
_ReadBarrier();
AeLiteSync();
_ReadBarrier();
break;
case memory_order_release:
_WriteBarrier();
AeLiteSync();
_WriteBarrier();
break;
case memory_order_acq_rel:
_ReadWriteBarrier();
AeLiteSync();
_ReadWriteBarrier();
break;
case memory_order_seq_cst:
_ReadWriteBarrier();
AeFullSync();
_ReadWriteBarrier();
break;
default: assert(false);
}
}
#endif
} // end namespace moodycamel
#else
// Use standard library of atomics
#include <atomic>
namespace moodycamel {
AE_FORCEINLINE void compiler_fence(memory_order order) AE_NO_TSAN
{
switch (order) {
case memory_order_relaxed: break;
case memory_order_acquire: std::atomic_signal_fence(std::memory_order_acquire); break;
case memory_order_release: std::atomic_signal_fence(std::memory_order_release); break;
case memory_order_acq_rel: std::atomic_signal_fence(std::memory_order_acq_rel); break;
case memory_order_seq_cst: std::atomic_signal_fence(std::memory_order_seq_cst); break;
default: assert(false);
}
}
AE_FORCEINLINE void fence(memory_order order) AE_NO_TSAN
{
switch (order) {
case memory_order_relaxed: break;
case memory_order_acquire: std::atomic_thread_fence(std::memory_order_acquire); break;
case memory_order_release: std::atomic_thread_fence(std::memory_order_release); break;
case memory_order_acq_rel: std::atomic_thread_fence(std::memory_order_acq_rel); break;
case memory_order_seq_cst: std::atomic_thread_fence(std::memory_order_seq_cst); break;
default: assert(false);
}
}
} // end namespace moodycamel
#endif
#if !defined(AE_VCPP) || (_MSC_VER >= 1700 && !defined(__cplusplus_cli))
#define AE_USE_STD_ATOMIC_FOR_WEAK_ATOMIC
#endif
#ifdef AE_USE_STD_ATOMIC_FOR_WEAK_ATOMIC
#include <atomic>
#endif
#include <utility>
// WARNING: *NOT* A REPLACEMENT FOR std::atomic. READ CAREFULLY:
// Provides basic support for atomic variables -- no memory ordering guarantees are provided.
// The guarantee of atomicity is only made for types that already have atomic load and store guarantees
// at the hardware level -- on most platforms this generally means aligned pointers and integers (only).
namespace moodycamel {
template<typename T>
class weak_atomic
{
public:
AE_NO_TSAN weak_atomic() { }
#ifdef AE_VCPP
#pragma warning(push)
#pragma warning(disable: 4100) // Get rid of (erroneous) 'unreferenced formal parameter' warning
#endif
template<typename U> AE_NO_TSAN weak_atomic(U&& x) : value(std::forward<U>(x)) { }
#ifdef __cplusplus_cli
// Work around bug with universal reference/nullptr combination that only appears when /clr is on
AE_NO_TSAN weak_atomic(nullptr_t) : value(nullptr) { }
#endif
AE_NO_TSAN weak_atomic(weak_atomic const& other) : value(other.load()) { }
AE_NO_TSAN weak_atomic(weak_atomic&& other) : value(std::move(other.load())) { }
#ifdef AE_VCPP
#pragma warning(pop)
#endif
AE_FORCEINLINE operator T() const AE_NO_TSAN{ return load(); }
#ifndef AE_USE_STD_ATOMIC_FOR_WEAK_ATOMIC
template<typename U> AE_FORCEINLINE weak_atomic const& operator=(U&& x) AE_NO_TSAN{ value = std::forward<U>(x); return *this; }
AE_FORCEINLINE weak_atomic const& operator=(weak_atomic const& other) AE_NO_TSAN{ value = other.value; return *this; }
AE_FORCEINLINE T load() const AE_NO_TSAN{ return value; }
AE_FORCEINLINE T fetch_add_acquire(T increment) AE_NO_TSAN
{
#if defined(AE_ARCH_X64) || defined(AE_ARCH_X86)
if (sizeof(T) == 4) return _InterlockedExchangeAdd((long volatile*)&value, (long)increment);
#if defined(_M_AMD64)
else if (sizeof(T) == 8) return _InterlockedExchangeAdd64((long long volatile*)&value, (long long)increment);
#endif
#else
#error Unsupported platform
#endif
assert(false && "T must be either a 32 or 64 bit type");
return value;
}
AE_FORCEINLINE T fetch_add_release(T increment) AE_NO_TSAN
{
#if defined(AE_ARCH_X64) || defined(AE_ARCH_X86)
if (sizeof(T) == 4) return _InterlockedExchangeAdd((long volatile*)&value, (long)increment);
#if defined(_M_AMD64)
else if (sizeof(T) == 8) return _InterlockedExchangeAdd64((long long volatile*)&value, (long long)increment);
#endif
#else
#error Unsupported platform
#endif
assert(false && "T must be either a 32 or 64 bit type");
return value;
}
#else
template<typename U>
AE_FORCEINLINE weak_atomic const& operator=(U&& x) AE_NO_TSAN
{
value.store(std::forward<U>(x), std::memory_order_relaxed);
return *this;
}
AE_FORCEINLINE weak_atomic const& operator=(weak_atomic const& other) AE_NO_TSAN
{
value.store(other.value.load(std::memory_order_relaxed), std::memory_order_relaxed);
return *this;
}
AE_FORCEINLINE T load() const AE_NO_TSAN{ return value.load(std::memory_order_relaxed); }
AE_FORCEINLINE T fetch_add_acquire(T increment) AE_NO_TSAN
{
return value.fetch_add(increment, std::memory_order_acquire);
}
AE_FORCEINLINE T fetch_add_release(T increment) AE_NO_TSAN
{
return value.fetch_add(increment, std::memory_order_release);
}
#endif
private:
#ifndef AE_USE_STD_ATOMIC_FOR_WEAK_ATOMIC
// No std::atomic support, but still need to circumvent compiler optimizations.
// `volatile` will make memory access slow, but is guaranteed to be reliable.
volatile T value;
#else
std::atomic<T> value;
#endif
};
} // end namespace moodycamel
// Portable single-producer, single-consumer semaphore below:
#if defined(_WIN32)
// Avoid including windows.h in a header; we only need a handful of
// items, so we'll redeclare them here (this is relatively safe since
// the API generally has to remain stable between Windows versions).
// I know this is an ugly hack but it still beats polluting the global
// namespace with thousands of generic names or adding a .cpp for nothing.
extern "C" {
struct _SECURITY_ATTRIBUTES;
__declspec(dllimport) void* __stdcall CreateSemaphoreW(_SECURITY_ATTRIBUTES* lpSemaphoreAttributes, long lInitialCount, long lMaximumCount, const wchar_t* lpName);
__declspec(dllimport) int __stdcall CloseHandle(void* hObject);
__declspec(dllimport) unsigned long __stdcall WaitForSingleObject(void* hHandle, unsigned long dwMilliseconds);
__declspec(dllimport) int __stdcall ReleaseSemaphore(void* hSemaphore, long lReleaseCount, long* lpPreviousCount);
}
#elif defined(__MACH__)
#include <mach/mach.h>
#elif defined(__unix__)
#include <semaphore.h>
#endif
namespace moodycamel
{
// Code in the spsc_sema namespace below is an adaptation of Jeff Preshing's
// portable + lightweight semaphore implementations, originally from
// https://github.com/preshing/cpp11-on-multicore/blob/master/common/sema.h
// LICENSE:
// Copyright (c) 2015 Jeff Preshing
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgement in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
namespace spsc_sema
{
#if defined(_WIN32)
class Semaphore
{
private:
void* m_hSema;
Semaphore(const Semaphore& other);
Semaphore& operator=(const Semaphore& other);
public:
AE_NO_TSAN Semaphore(int initialCount = 0)
{
assert(initialCount >= 0);
const long maxLong = 0x7fffffff;
m_hSema = CreateSemaphoreW(nullptr, initialCount, maxLong, nullptr);
}
AE_NO_TSAN ~Semaphore()
{
CloseHandle(m_hSema);
}
void wait() AE_NO_TSAN
{
const unsigned long infinite = 0xffffffff;
WaitForSingleObject(m_hSema, infinite);
}
bool try_wait() AE_NO_TSAN
{
const unsigned long RC_WAIT_TIMEOUT = 0x00000102;
return WaitForSingleObject(m_hSema, 0) != RC_WAIT_TIMEOUT;
}
bool timed_wait(std::uint64_t usecs) AE_NO_TSAN
{
const unsigned long RC_WAIT_TIMEOUT = 0x00000102;
return WaitForSingleObject(m_hSema, (unsigned long)(usecs / 1000)) != RC_WAIT_TIMEOUT;
}
void signal(int count = 1) AE_NO_TSAN
{
ReleaseSemaphore(m_hSema, count, nullptr);
}
};
#elif defined(__MACH__)
//---------------------------------------------------------
// Semaphore (Apple iOS and OSX)
// Can't use POSIX semaphores due to http://lists.apple.com/archives/darwin-kernel/2009/Apr/msg00010.html
//---------------------------------------------------------
class Semaphore
{
private:
semaphore_t m_sema;
Semaphore(const Semaphore& other);
Semaphore& operator=(const Semaphore& other);
public:
AE_NO_TSAN Semaphore(int initialCount = 0)
{
assert(initialCount >= 0);
semaphore_create(mach_task_self(), &m_sema, SYNC_POLICY_FIFO, initialCount);
}
AE_NO_TSAN ~Semaphore()
{
semaphore_destroy(mach_task_self(), m_sema);
}
void wait() AE_NO_TSAN
{
semaphore_wait(m_sema);
}
bool try_wait() AE_NO_TSAN
{
return timed_wait(0);
}
bool timed_wait(std::int64_t timeout_usecs) AE_NO_TSAN
{
mach_timespec_t ts;
ts.tv_sec = static_cast<unsigned int>(timeout_usecs / 1000000);
ts.tv_nsec = (timeout_usecs % 1000000) * 1000;
// added in OSX 10.10: https://developer.apple.com/library/prerelease/mac/documentation/General/Reference/APIDiffsMacOSX10_10SeedDiff/modules/Darwin.html
kern_return_t rc = semaphore_timedwait(m_sema, ts);
return rc != KERN_OPERATION_TIMED_OUT && rc != KERN_ABORTED;
}
void signal() AE_NO_TSAN
{
semaphore_signal(m_sema);
}
void signal(int count) AE_NO_TSAN
{
while (count-- > 0)
{
semaphore_signal(m_sema);
}
}
};
#elif defined(__unix__)
//---------------------------------------------------------
// Semaphore (POSIX, Linux)
//---------------------------------------------------------
class Semaphore
{
private:
sem_t m_sema;
Semaphore(const Semaphore& other);
Semaphore& operator=(const Semaphore& other);
public:
AE_NO_TSAN Semaphore(int initialCount = 0)
{
assert(initialCount >= 0);
sem_init(&m_sema, 0, initialCount);
}
AE_NO_TSAN ~Semaphore()
{
sem_destroy(&m_sema);
}
void wait() AE_NO_TSAN
{
// http://stackoverflow.com/questions/2013181/gdb-causes-sem-wait-to-fail-with-eintr-error
int rc;
do
{
rc = sem_wait(&m_sema);
} while (rc == -1 && errno == EINTR);
}
bool try_wait() AE_NO_TSAN
{
int rc;
do {
rc = sem_trywait(&m_sema);
} while (rc == -1 && errno == EINTR);
return !(rc == -1 && errno == EAGAIN);
}
bool timed_wait(std::uint64_t usecs) AE_NO_TSAN
{
struct timespec ts;
const int usecs_in_1_sec = 1000000;
const int nsecs_in_1_sec = 1000000000;
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec += usecs / usecs_in_1_sec;
ts.tv_nsec += (usecs % usecs_in_1_sec) * 1000;
// sem_timedwait bombs if you have more than 1e9 in tv_nsec
// so we have to clean things up before passing it in
if (ts.tv_nsec >= nsecs_in_1_sec) {
ts.tv_nsec -= nsecs_in_1_sec;
++ts.tv_sec;
}
int rc;
do {
rc = sem_timedwait(&m_sema, &ts);
} while (rc == -1 && errno == EINTR);
return !(rc == -1 && errno == ETIMEDOUT);
}
void signal() AE_NO_TSAN
{
sem_post(&m_sema);
}
void signal(int count) AE_NO_TSAN
{
while (count-- > 0)
{
sem_post(&m_sema);
}
}
};
#else
#error Unsupported platform! (No semaphore wrapper available)
#endif
//---------------------------------------------------------
// LightweightSemaphore
//---------------------------------------------------------
class LightweightSemaphore
{
public:
typedef std::make_signed<std::size_t>::type ssize_t;
private:
weak_atomic<ssize_t> m_count;
Semaphore m_sema;
bool waitWithPartialSpinning(std::int64_t timeout_usecs = -1) AE_NO_TSAN
{
ssize_t oldCount;
// Is there a better way to set the initial spin count?
// If we lower it to 1000, testBenaphore becomes 15x slower on my Core i7-5930K Windows PC,
// as threads start hitting the kernel semaphore.
int spin = 10000;
while (--spin >= 0)
{
if (m_count.load() > 0)
{
m_count.fetch_add_acquire(-1);
return true;
}
compiler_fence(memory_order_acquire); // Prevent the compiler from collapsing the loop.
}
oldCount = m_count.fetch_add_acquire(-1);
if (oldCount > 0)
return true;
if (timeout_usecs < 0)
{
m_sema.wait();
return true;
}
if (m_sema.timed_wait(timeout_usecs))
return true;
// At this point, we've timed out waiting for the semaphore, but the
// count is still decremented indicating we may still be waiting on
// it. So we have to re-adjust the count, but only if the semaphore
// wasn't signaled enough times for us too since then. If it was, we
// need to release the semaphore too.
while (true)
{
oldCount = m_count.fetch_add_release(1);
if (oldCount < 0)
return false; // successfully restored things to the way they were
// Oh, the producer thread just signaled the semaphore after all. Try again:
oldCount = m_count.fetch_add_acquire(-1);
if (oldCount > 0 && m_sema.try_wait())
return true;
}
}
public:
AE_NO_TSAN LightweightSemaphore(ssize_t initialCount = 0) : m_count(initialCount)
{
assert(initialCount >= 0);
}
bool tryWait() AE_NO_TSAN
{
if (m_count.load() > 0)
{
m_count.fetch_add_acquire(-1);
return true;
}
return false;
}
void wait() AE_NO_TSAN
{
if (!tryWait())
waitWithPartialSpinning();
}
bool wait(std::int64_t timeout_usecs) AE_NO_TSAN
{
return tryWait() || waitWithPartialSpinning(timeout_usecs);
}
void signal(ssize_t count = 1) AE_NO_TSAN
{
assert(count >= 0);
ssize_t oldCount = m_count.fetch_add_release(count);
assert(oldCount >= -1);
if (oldCount < 0)
{
m_sema.signal(1);
}
}
ssize_t availableApprox() const AE_NO_TSAN
{
ssize_t count = m_count.load();
return count > 0 ? count : 0;
}
};
} // end namespace spsc_sema
} // end namespace moodycamel
#if defined(AE_VCPP) && (_MSC_VER < 1700 || defined(__cplusplus_cli))
#pragma warning(pop)
#ifdef __cplusplus_cli
#pragma managed(pop)
#endif
#endif

View File

@ -0,0 +1,73 @@
#include "opengl_Command.h"
#include "Graphics/OpenGLContext/GLFunctions.h"
#include "RingBufferPool.h"
#include <chrono>
namespace opengl {
// 15MB memory pool
RingBufferPool OpenGlCommand::m_ringBufferPool(1024 * 1024 * 15 );
void OpenGlCommand::performCommandSingleThreaded()
{
commandToExecute();
setInUse(false);
#ifdef GL_DEBUG
if (m_isGlCommand) {
auto error = ptrGetError();
if (error != GL_NO_ERROR) {
std::stringstream errorString;
errorString << " OpenGL error: 0x" << std::hex << error << ", on function: " << m_functionName << std::endl;
LOG(LOG_ERROR, errorString.str().c_str());
throw std::runtime_error(errorString.str().c_str());
}
}
#endif
}
bool OpenGlCommand::isTimeToShutdown()
{
return false;
}
void OpenGlCommand::performCommand()
{
std::unique_lock<std::mutex> lock(m_condvarMutex);
performCommandSingleThreaded();
if (m_synced) {
#ifdef GL_DEBUG
if (m_logIfSynced) {
std::stringstream errorString;
errorString << " Executing synced: " << m_functionName << std::endl;
LOG(LOG_ERROR, errorString.str().c_str());
}
#endif
m_executed = true;
m_condition.notify_all();
}
}
void OpenGlCommand::waitOnCommand()
{
std::unique_lock<std::mutex> lock(m_condvarMutex);
if (m_synced && !m_executed) {
m_condition.wait(lock, [this] { return m_executed; });
}
m_executed = false;
}
OpenGlCommand::OpenGlCommand(bool _synced, bool _logIfSynced, const std::string &_functionName,
bool _isGlCommand) :
m_synced(_synced), m_executed(false)
#ifdef GL_DEBUG
, m_logIfSynced(_logIfSynced)
, m_functionName(std::move(_functionName))
, m_isGlCommand(_isGlCommand)
#endif
{
}
}

View File

@ -0,0 +1,56 @@
#pragma once
#include <memory>
#include <vector>
#include <mutex>
#include <atomic>
#include <string>
#include <condition_variable>
#include "opengl_ObjectPool.h"
#include "RingBufferPool.h"
namespace opengl {
class OpenGlCommand : public PoolObject {
public:
void performCommandSingleThreaded();
void performCommand();
void waitOnCommand();
virtual bool isTimeToShutdown();
static RingBufferPool m_ringBufferPool;
protected:
OpenGlCommand(bool _synced, bool _logIfSynced, const std::string &_functionName,
bool _isGlCommand = true);
virtual void commandToExecute() = 0;
template<typename CoomandType>
static std::shared_ptr<CoomandType> getFromPool(int _poolId) {
auto poolObject = OpenGlCommandPool::get().getAvailableObject(_poolId);
if (poolObject == nullptr) {
poolObject = std::shared_ptr<CoomandType>(new CoomandType);
OpenGlCommandPool::get().addObjectToPool(_poolId, poolObject);
}
poolObject->setInUse(true);
return std::static_pointer_cast<CoomandType>(poolObject);
}
#ifdef GL_DEBUG
const bool m_logIfSynced;
const std::string m_functionName;
const bool m_isGlCommand;
#endif
private:
std::atomic<bool> m_synced;
bool m_executed;
std::mutex m_condvarMutex;
std::condition_variable m_condition;
};
}

View File

@ -0,0 +1,106 @@
#include "opengl_ObjectPool.h"
namespace opengl {
PoolObject::PoolObject() :
m_inUse(false), m_poolId(0), m_objectId(0) {
}
bool PoolObject::isInUse()
{
return m_inUse;
}
void PoolObject::setInUse(bool _inUse)
{
m_inUse = _inUse;
}
int PoolObject::getPoolId()
{
return m_poolId;
}
void PoolObject::setPoolId(int _poolId)
{
m_poolId = _poolId;
}
int PoolObject::getObjectId()
{
return m_objectId;
}
void PoolObject::setObjectId(int _objectId)
{
m_objectId = _objectId;
}
OpenGlCommandPool &OpenGlCommandPool::get()
{
static OpenGlCommandPool commandPool;
return commandPool;
}
int OpenGlCommandPool::getNextAvailablePool()
{
m_objectPool.push_back(std::vector<std::shared_ptr<PoolObject>>());
m_objectPoolIndex.push_back(0);
return static_cast<int>(m_objectPool.size() - 1);
}
std::shared_ptr<PoolObject> OpenGlCommandPool::getAvailableObject(int _poolId)
{
auto &currentPool = m_objectPool[_poolId];
auto &currentIndex = m_objectPoolIndex[_poolId];
if (currentPool.empty()) {
return nullptr;
} else if (!currentPool[currentIndex]->isInUse()) {
int objectId = currentIndex;
++currentIndex;
if (currentIndex == currentPool.size()) {
currentIndex = 0;
}
return currentPool[objectId];
} else {
bool found = false;
unsigned int index;
//Not found in most common case, so go ahead and search
for (index = currentIndex; index < currentPool.size() && !found; ++index) {
found = !currentPool[index]->isInUse();
}
if (!found) {
for (index = 0; index < currentIndex && !found; ++index) {
found = !currentPool[index]->isInUse();
}
}
if (found) {
currentIndex = index;
if (currentIndex == currentPool.size()) {
currentIndex = 0;
}
--index;
return currentPool[index];
} else {
currentIndex = 0;
return nullptr;
}
}
}
void OpenGlCommandPool::addObjectToPool(int _poolId, std::shared_ptr<PoolObject> _object)
{
_object->setPoolId(_poolId);
_object->setObjectId(static_cast<int>(m_objectPool[_poolId].size()));
m_objectPool[_poolId].push_back(_object);
}
}

View File

@ -0,0 +1,46 @@
#pragma once
#include <memory>
#include <vector>
namespace opengl {
class PoolObject {
public:
PoolObject();
bool isInUse();
void setInUse(bool _inUse);
int getPoolId();
void setPoolId(int _poolId);
int getObjectId();
void setObjectId(int _objectId);
private:
bool m_inUse;
int m_poolId;
int m_objectId;
};
class OpenGlCommandPool
{
public:
static OpenGlCommandPool& get();
int getNextAvailablePool();
std::shared_ptr<PoolObject> getAvailableObject(int _poolId);
void addObjectToPool(int _poolId, std::shared_ptr<PoolObject> _object);
private:
std::vector<std::vector<std::shared_ptr<PoolObject>>> m_objectPool;
std::vector<int> m_objectPoolIndex;
};
}

View File

@ -0,0 +1,21 @@
#include "opengl_WrappedFunctions.h"
namespace opengl {
std::vector<char> GlDrawArraysUnbufferedCommand::m_attribsData(2 * 1024 * 1024, 0);
std::vector<char> GlDrawElementsUnbufferedCommand::m_attribsData(2 * 1024 * 1024, 0);
GLenum GlMapBufferRangeWriteAsyncCommand::m_targetTemp;
GLintptr GlMapBufferRangeWriteAsyncCommand::m_offsetTemp;
GLsizeiptr GlMapBufferRangeWriteAsyncCommand::m_lengthTemp;
GLbitfield GlMapBufferRangeWriteAsyncCommand::m_accessTemp;
std::unordered_map<int, std::shared_ptr<std::vector<u8>>> GlMapBufferRangeWriteAsyncCommand::m_TempData;
std::unordered_map<int, std::shared_ptr<std::vector<u8>>> GlMapBufferRangeReadAsyncCommand::m_data;
std::mutex GlMapBufferRangeReadAsyncCommand::m_mapMutex;
std::unordered_map<int, GlVertexAttribPointerManager::VertexAttributeData> GlVertexAttribPointerManager::m_vertexAttributePointers;
const void* GlVertexAttribPointerManager::smallestDataPtr = nullptr;
std::unordered_map<int, GlVertexAttribPointerManager::VertexAttributeData> GlVertexAttribPointerManager::m_vertexAttributePointersRender;
const void* GlVertexAttribPointerManager::smallestDataPtrRender = nullptr;
std::unordered_map<GLenum, GLuint> GlBindBufferCommand::m_boundBuffersRender;
std::unordered_map<GLenum, GLuint> GlBindBufferCommand::m_boundBuffers;
GLuint GlReadPixelsAsyncCommand::m_readPixelsBoundBuffer = 0;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,200 @@
#pragma once
#include "Graphics/OpenGLContext/GLFunctions.h"
#include "readerwriterqueue.h"
#include "opengl_WrappedFunctions.h"
#include "opengl_Command.h"
#include <thread>
#ifdef MUPENPLUSAPI
#include <mupenplus/GLideN64_mupenplus.h>
#endif
using namespace moodycamel;
namespace opengl {
class FunctionWrapper
{
private:
static void executeCommand(std::shared_ptr<OpenGlCommand> _command);
static void executePriorityCommand(std::shared_ptr<OpenGlCommand> _command);
static void commandLoop();
static BlockingReaderWriterQueue<std::shared_ptr<OpenGlCommand>> m_commandQueue;
static BlockingReaderWriterQueue<std::shared_ptr<OpenGlCommand>> m_commandQueueHighPriority;
static bool m_threaded_wrapper;
static bool m_shutdown;
static int m_swapBuffersQueued;
static bool m_fastVertexAttributes;
static std::thread m_commandExecutionThread;
static std::mutex m_condvarMutex;
static std::condition_variable m_condition;
static const int MAX_SWAP = 2;
public:
static void setThreadedMode(u32 _threaded);
static void wrBlendFunc(GLenum sfactor, GLenum dfactor);
static void wrPixelStorei(GLenum pname, GLint param);
static void wrClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
static void wrCullFace(GLenum mode);
static void wrDepthFunc(GLenum func);
static void wrDepthMask(GLboolean flag);
static void wrDisable(GLenum cap);
static void wrEnable(GLenum cap);
static void wrDisablei(GLenum target, GLuint index);
static void wrEnablei(GLenum target, GLuint index);
static void wrPolygonOffset(GLfloat factor, GLfloat units);
static void wrScissor(GLint x, GLint y, GLsizei width, GLsizei height);
static void wrViewport(GLint x, GLint y, GLsizei width, GLsizei height);
static void wrBindTexture(GLenum target, GLuint texture);
static void wrTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
static void wrTexParameteri(GLenum target, GLenum pname, GLint param);
static void wrGetIntegerv(GLenum pname, GLint* data);
static const GLubyte* wrGetString(GLenum name);
static void wrReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels);
static void wrTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
static void wrDrawArrays(GLenum mode, GLint first, GLsizei count);
static GLenum wrGetError();
static void wrDrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices);
static void wrLineWidth(GLfloat width);
static void wrClear(GLbitfield mask);
static void wrClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *value);
static void wrGetFloatv(GLenum pname, GLfloat* data);
static void wrDeleteTextures(GLsizei n, const GLuint *textures);
static void wrGenTextures(GLsizei n, GLuint* textures);
static void wrTexParameterf(GLenum target, GLenum pname, GLfloat param);
static void wrActiveTexture(GLenum texture);
static void wrBlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
static void wrReadBuffer(GLenum src);
static GLuint wrCreateShader(GLenum type);
static void wrCompileShader(GLuint shader);
static void wrShaderSource(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
static GLuint wrCreateProgram();
static void wrAttachShader(GLuint program, GLuint shader);
static void wrLinkProgram(GLuint program);
static void wrUseProgram(GLuint program);
static GLint wrGetUniformLocation(GLuint program, const GLchar *name);
static void wrUniform1i(GLint location, GLint v0);
static void wrUniform1f(GLint location, GLfloat v0);
static void wrUniform2f(GLint location, GLfloat v0, GLfloat v1);
static void wrUniform2i(GLint location, GLint v0, GLint v1);
static void wrUniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
static void wrUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
static void wrUniform3fv(GLint location, GLsizei count, const GLfloat *value);
static void wrUniform4fv(GLint location, GLsizei count, const GLfloat *value);
static void wrDetachShader(GLuint program, GLuint shader);
static void wrDeleteShader(GLuint shader);
static void wrDeleteProgram(GLuint program);
static void wrGetProgramInfoLog(GLuint program, GLsizei bufSize, GLsizei* length, GLchar *infoLog);
static void wrGetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar *infoLog);
static void wrGetShaderiv(GLuint shader, GLenum pname, GLint* params);
static void wrGetProgramiv(GLuint program, GLenum pname, GLint* params);
static void wrEnableVertexAttribArray(GLuint index);
static void wrDisableVertexAttribArray(GLuint index);
static void wrVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
static void wrBindAttribLocation(GLuint program, GLuint index, const GLchar *name);
static void wrVertexAttrib1f(GLuint index, GLfloat x);
static void wrVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
static void wrVertexAttrib4fv(GLuint index, const GLfloat *v);
static void wrDepthRangef(GLfloat n, GLfloat f);
static void wrClearDepthf(GLfloat d);
static void wrDrawBuffers(GLsizei n, const GLenum *bufs);
static void wrGenFramebuffers(GLsizei n, GLuint* framebuffers);
static void wrBindFramebuffer(GLenum target, GLuint framebuffer);
static void wrDeleteFramebuffers(GLsizei n, const GLuint *framebuffers);
static void wrFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
static void wrTexImage2DMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
static void wrTexStorage2DMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
static void wrGenRenderbuffers(GLsizei n, GLuint* renderbuffers);
static void wrBindRenderbuffer(GLenum target, GLuint renderbuffer);
static void wrRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
static void wrDeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers);
static void wrFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
static GLenum wrCheckFramebufferStatus(GLenum target);
static void wrBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
static void wrGenVertexArrays(GLsizei n, GLuint* arrays);
static void wrBindVertexArray(GLuint array);
static void wrDeleteVertexArrays(GLsizei n, const GLuint *arrays);
static void wrGenBuffers(GLsizei n, GLuint* buffers);
static void wrBindBuffer(GLenum target, GLuint buffer);
static void wrBufferData(GLenum target, GLsizeiptr size, const void *data, GLenum usage);
static void wrMapBuffer(GLenum target, GLenum access);
static void* wrMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
static GLboolean wrUnmapBuffer(GLenum target);
static void wrDeleteBuffers(GLsizei n, const GLuint *buffers);
static void wrBindImageTexture(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format);
static void wrMemoryBarrier(GLbitfield barriers);
static void wrTextureBarrier();
static void wrTextureBarrierNV();
static const GLubyte* wrGetStringi(GLenum name, GLuint index);
static void wrInvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments);
static void wrBufferStorage(GLenum target, GLsizeiptr size, const void *data, GLbitfield flags);
static GLsync wrFenceSync(GLenum condition, GLbitfield flags);
static void wrClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout);
static void wrDeleteSync(GLsync sync);
static GLuint wrGetUniformBlockIndex(GLuint program, GLchar *uniformBlockName);
static void wrUniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
static void wrGetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params);
static void wrGetUniformIndices(GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint* uniformIndices);
static void wrGetActiveUniformsiv(GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint* params);
static void wrBindBufferBase(GLenum target, GLuint index, GLuint buffer);
static void wrBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void *data);
static void wrGetProgramBinary(GLuint program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, void *binary);
static void wrProgramBinary(GLuint program, GLenum binaryFormat, const void *binary, GLsizei length);
static void wrProgramParameteri(GLuint program, GLenum pname, GLint value);
static void wrTexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
static void wrTextureStorage2D(GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
static void wrTextureSubImage2D(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
static void wrTextureStorage2DMultisample(GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
static void wrTextureParameteri(GLuint texture, GLenum pname, GLint param);
static void wrTextureParameterf(GLuint texture, GLenum pname, GLfloat param);
static void wrCreateTextures(GLenum target, GLsizei n, GLuint* textures);
static void wrCreateBuffers(GLsizei n, GLuint* buffers);
static void wrCreateFramebuffers(GLsizei n, GLuint* framebuffers);
static void wrNamedFramebufferTexture(GLuint framebuffer, GLenum attachment, GLuint texture, GLint level);
static void wrDrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const u16* indices, GLint basevertex);
static void wrFlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length);
static void wrFinish();
static void wrEGLImageTargetTexture2DOES(GLenum target, void* image);
#if defined(OS_ANDROID)
static EGLClientBuffer ewrGetNativeClientBufferANDROID(const AHardwareBuffer *buffer);
#endif
#ifdef MUPENPLUSAPI
//Vid_ext functions
static void CoreVideo_Init();
static void CoreVideo_Quit();
static m64p_error CoreVideo_SetVideoMode(int screenWidth, int screenHeight, int bitsPerPixel, m64p_video_mode mode, m64p_video_flags flags);
static void CoreVideo_GL_SetAttribute(m64p_GLattr attribute, int value);
static void CoreVideo_GL_GetAttribute(m64p_GLattr attribute, int *value);
static void CoreVideo_GL_SwapBuffers();
#else
//Windows GL context functions
static bool windowsStart();
static void windowsStop();
static void windowsSwapBuffers();
#endif
static void ReduceSwapBuffersQueued();
static void WaitForSwapBuffersQueued();
static int getTextureBytes(GLenum format, GLenum type, int width, int height);
};
}

View File

@ -0,0 +1,906 @@
// ©2013-2016 Cameron Desrochers.
// Distributed under the simplified BSD license (see the license file that
// should have come with this header).
#pragma once
#include "atomicops.h"
#include <type_traits>
#include <utility>
#include <cassert>
#include <stdexcept>
#include <new>
#include <cstdint>
#include <cstdlib> // For malloc/free/abort & size_t
#include <memory>
#if __cplusplus > 199711L || _MSC_VER >= 1700 // C++11 or VS2012
#include <chrono>
#endif
// A lock-free queue for a single-consumer, single-producer architecture.
// The queue is also wait-free in the common path (except if more memory
// needs to be allocated, in which case malloc is called).
// Allocates memory sparingly (O(lg(n) times, amortized), and only once if
// the original maximum size estimate is never exceeded.
// Tested on x86/x64 processors, but semantics should be correct for all
// architectures (given the right implementations in atomicops.h), provided
// that aligned integer and pointer accesses are naturally atomic.
// Note that there should only be one consumer thread and producer thread;
// Switching roles of the threads, or using multiple consecutive threads for
// one role, is not safe unless properly synchronized.
// Using the queue exclusively from one thread is fine, though a bit silly.
#ifndef MOODYCAMEL_CACHE_LINE_SIZE
#define MOODYCAMEL_CACHE_LINE_SIZE 64
#endif
#ifndef MOODYCAMEL_EXCEPTIONS_ENABLED
#if (defined(_MSC_VER) && defined(_CPPUNWIND)) || (defined(__GNUC__) && defined(__EXCEPTIONS)) || (!defined(_MSC_VER) && !defined(__GNUC__))
#define MOODYCAMEL_EXCEPTIONS_ENABLED
#endif
#endif
#ifndef MOODYCAMEL_HAS_EMPLACE
#if !defined(_MSC_VER) || _MSC_VER >= 1800 // variadic templates: either a non-MS compiler or VS >= 2013
#define MOODYCAMEL_HAS_EMPLACE 1
#endif
#endif
#ifdef AE_VCPP
#pragma warning(push)
#pragma warning(disable: 4324) // structure was padded due to __declspec(align())
#pragma warning(disable: 4820) // padding was added
#pragma warning(disable: 4127) // conditional expression is constant
#endif
namespace moodycamel {
template<typename T, size_t MAX_BLOCK_SIZE = 512>
class ReaderWriterQueue
{
// Design: Based on a queue-of-queues. The low-level queues are just
// circular buffers with front and tail indices indicating where the
// next element to dequeue is and where the next element can be enqueued,
// respectively. Each low-level queue is called a "block". Each block
// wastes exactly one element's worth of space to keep the design simple
// (if front == tail then the queue is empty, and can't be full).
// The high-level queue is a circular linked list of blocks; again there
// is a front and tail, but this time they are pointers to the blocks.
// The front block is where the next element to be dequeued is, provided
// the block is not empty. The back block is where elements are to be
// enqueued, provided the block is not full.
// The producer thread owns all the tail indices/pointers. The consumer
// thread owns all the front indices/pointers. Both threads read each
// other's variables, but only the owning thread updates them. E.g. After
// the consumer reads the producer's tail, the tail may change before the
// consumer is done dequeuing an object, but the consumer knows the tail
// will never go backwards, only forwards.
// If there is no room to enqueue an object, an additional block (of
// equal size to the last block) is added. Blocks are never removed.
public:
typedef T value_type;
// Constructs a queue that can hold maxSize elements without further
// allocations. If more than MAX_BLOCK_SIZE elements are requested,
// then several blocks of MAX_BLOCK_SIZE each are reserved (including
// at least one extra buffer block).
AE_NO_TSAN explicit ReaderWriterQueue(size_t maxSize = 15)
#ifndef NDEBUG
: enqueuing(false)
,dequeuing(false)
#endif
{
assert(maxSize > 0);
assert(MAX_BLOCK_SIZE == ceilToPow2(MAX_BLOCK_SIZE) && "MAX_BLOCK_SIZE must be a power of 2");
assert(MAX_BLOCK_SIZE >= 2 && "MAX_BLOCK_SIZE must be at least 2");
Block* firstBlock = nullptr;
largestBlockSize = ceilToPow2(maxSize + 1); // We need a spare slot to fit maxSize elements in the block
if (largestBlockSize > MAX_BLOCK_SIZE * 2) {
// We need a spare block in case the producer is writing to a different block the consumer is reading from, and
// wants to enqueue the maximum number of elements. We also need a spare element in each block to avoid the ambiguity
// between front == tail meaning "empty" and "full".
// So the effective number of slots that are guaranteed to be usable at any time is the block size - 1 times the
// number of blocks - 1. Solving for maxSize and applying a ceiling to the division gives us (after simplifying):
size_t initialBlockCount = (maxSize + MAX_BLOCK_SIZE * 2 - 3) / (MAX_BLOCK_SIZE - 1);
largestBlockSize = MAX_BLOCK_SIZE;
Block* lastBlock = nullptr;
for (size_t i = 0; i != initialBlockCount; ++i) {
auto block = make_block(largestBlockSize);
if (block == nullptr) {
#ifdef MOODYCAMEL_EXCEPTIONS_ENABLED
throw std::bad_alloc();
#else
abort();
#endif
}
if (firstBlock == nullptr) {
firstBlock = block;
}
else {
lastBlock->next = block;
}
lastBlock = block;
block->next = firstBlock;
}
}
else {
firstBlock = make_block(largestBlockSize);
if (firstBlock == nullptr) {
#ifdef MOODYCAMEL_EXCEPTIONS_ENABLED
throw std::bad_alloc();
#else
abort();
#endif
}
firstBlock->next = firstBlock;
}
frontBlock = firstBlock;
tailBlock = firstBlock;
// Make sure the reader/writer threads will have the initialized memory setup above:
fence(memory_order_sync);
}
// Note: The queue should not be accessed concurrently while it's
// being moved. It's up to the user to synchronize this.
AE_NO_TSAN ReaderWriterQueue(ReaderWriterQueue&& other)
: frontBlock(other.frontBlock.load()),
tailBlock(other.tailBlock.load()),
largestBlockSize(other.largestBlockSize)
#ifndef NDEBUG
,enqueuing(false)
,dequeuing(false)
#endif
{
other.largestBlockSize = 32;
Block* b = other.make_block(other.largestBlockSize);
if (b == nullptr) {
#ifdef MOODYCAMEL_EXCEPTIONS_ENABLED
throw std::bad_alloc();
#else
abort();
#endif
}
b->next = b;
other.frontBlock = b;
other.tailBlock = b;
}
// Note: The queue should not be accessed concurrently while it's
// being moved. It's up to the user to synchronize this.
ReaderWriterQueue& operator=(ReaderWriterQueue&& other) AE_NO_TSAN
{
Block* b = frontBlock.load();
frontBlock = other.frontBlock.load();
other.frontBlock = b;
b = tailBlock.load();
tailBlock = other.tailBlock.load();
other.tailBlock = b;
std::swap(largestBlockSize, other.largestBlockSize);
return *this;
}
// Note: The queue should not be accessed concurrently while it's
// being deleted. It's up to the user to synchronize this.
AE_NO_TSAN ~ReaderWriterQueue()
{
// Make sure we get the latest version of all variables from other CPUs:
fence(memory_order_sync);
// Destroy any remaining objects in queue and free memory
Block* frontBlock_ = frontBlock;
Block* block = frontBlock_;
do {
Block* nextBlock = block->next;
size_t blockFront = block->front;
size_t blockTail = block->tail;
for (size_t i = blockFront; i != blockTail; i = (i + 1) & block->sizeMask) {
auto element = reinterpret_cast<T*>(block->data + i * sizeof(T));
element->~T();
(void)element;
}
auto rawBlock = block->rawThis;
block->~Block();
std::free(rawBlock);
block = nextBlock;
} while (block != frontBlock_);
}
// Enqueues a copy of element if there is room in the queue.
// Returns true if the element was enqueued, false otherwise.
// Does not allocate memory.
AE_FORCEINLINE bool try_enqueue(T const& element) AE_NO_TSAN
{
return inner_enqueue<CannotAlloc>(element);
}
// Enqueues a moved copy of element if there is room in the queue.
// Returns true if the element was enqueued, false otherwise.
// Does not allocate memory.
AE_FORCEINLINE bool try_enqueue(T&& element) AE_NO_TSAN
{
return inner_enqueue<CannotAlloc>(std::forward<T>(element));
}
#if MOODYCAMEL_HAS_EMPLACE
// Like try_enqueue() but with emplace semantics (i.e. construct-in-place).
template<typename... Args>
AE_FORCEINLINE bool try_emplace(Args&&... args) AE_NO_TSAN
{
return inner_enqueue<CannotAlloc>(std::forward<Args>(args)...);
}
#endif
// Enqueues a copy of element on the queue.
// Allocates an additional block of memory if needed.
// Only fails (returns false) if memory allocation fails.
AE_FORCEINLINE bool enqueue(T const& element) AE_NO_TSAN
{
return inner_enqueue<CanAlloc>(element);
}
// Enqueues a moved copy of element on the queue.
// Allocates an additional block of memory if needed.
// Only fails (returns false) if memory allocation fails.
AE_FORCEINLINE bool enqueue(T&& element) AE_NO_TSAN
{
return inner_enqueue<CanAlloc>(std::forward<T>(element));
}
#if MOODYCAMEL_HAS_EMPLACE
// Like enqueue() but with emplace semantics (i.e. construct-in-place).
template<typename... Args>
AE_FORCEINLINE bool emplace(Args&&... args) AE_NO_TSAN
{
return inner_enqueue<CanAlloc>(std::forward<Args>(args)...);
}
#endif
// Attempts to dequeue an element; if the queue is empty,
// returns false instead. If the queue has at least one element,
// moves front to result using operator=, then returns true.
template<typename U>
bool try_dequeue(U& result) AE_NO_TSAN
{
#ifndef NDEBUG
ReentrantGuard guard(this->dequeuing);
#endif
// High-level pseudocode:
// Remember where the tail block is
// If the front block has an element in it, dequeue it
// Else
// If front block was the tail block when we entered the function, return false
// Else advance to next block and dequeue the item there
// Note that we have to use the value of the tail block from before we check if the front
// block is full or not, in case the front block is empty and then, before we check if the
// tail block is at the front block or not, the producer fills up the front block *and
// moves on*, which would make us skip a filled block. Seems unlikely, but was consistently
// reproducible in practice.
// In order to avoid overhead in the common case, though, we do a double-checked pattern
// where we have the fast path if the front block is not empty, then read the tail block,
// then re-read the front block and check if it's not empty again, then check if the tail
// block has advanced.
Block* frontBlock_ = frontBlock.load();
size_t blockTail = frontBlock_->localTail;
size_t blockFront = frontBlock_->front.load();
if (blockFront != blockTail || blockFront != (frontBlock_->localTail = frontBlock_->tail.load())) {
fence(memory_order_acquire);
non_empty_front_block:
// Front block not empty, dequeue from here
auto element = reinterpret_cast<T*>(frontBlock_->data + blockFront * sizeof(T));
result = std::move(*element);
element->~T();
blockFront = (blockFront + 1) & frontBlock_->sizeMask;
fence(memory_order_release);
frontBlock_->front = blockFront;
}
else if (frontBlock_ != tailBlock.load()) {
fence(memory_order_acquire);
frontBlock_ = frontBlock.load();
blockTail = frontBlock_->localTail = frontBlock_->tail.load();
blockFront = frontBlock_->front.load();
fence(memory_order_acquire);
if (blockFront != blockTail) {
// Oh look, the front block isn't empty after all
goto non_empty_front_block;
}
// Front block is empty but there's another block ahead, advance to it
Block* nextBlock = frontBlock_->next;
// Don't need an acquire fence here since next can only ever be set on the tailBlock,
// and we're not the tailBlock, and we did an acquire earlier after reading tailBlock which
// ensures next is up-to-date on this CPU in case we recently were at tailBlock.
size_t nextBlockFront = nextBlock->front.load();
size_t nextBlockTail = nextBlock->localTail = nextBlock->tail.load();
fence(memory_order_acquire);
// Since the tailBlock is only ever advanced after being written to,
// we know there's for sure an element to dequeue on it
assert(nextBlockFront != nextBlockTail);
AE_UNUSED(nextBlockTail);
// We're done with this block, let the producer use it if it needs
fence(memory_order_release); // Expose possibly pending changes to frontBlock->front from last dequeue
frontBlock = frontBlock_ = nextBlock;
compiler_fence(memory_order_release); // Not strictly needed
auto element = reinterpret_cast<T*>(frontBlock_->data + nextBlockFront * sizeof(T));
result = std::move(*element);
element->~T();
nextBlockFront = (nextBlockFront + 1) & frontBlock_->sizeMask;
fence(memory_order_release);
frontBlock_->front = nextBlockFront;
}
else {
// No elements in current block and no other block to advance to
return false;
}
return true;
}
// Returns a pointer to the front element in the queue (the one that
// would be removed next by a call to `try_dequeue` or `pop`). If the
// queue appears empty at the time the method is called, nullptr is
// returned instead.
// Must be called only from the consumer thread.
T* peek() AE_NO_TSAN
{
#ifndef NDEBUG
ReentrantGuard guard(this->dequeuing);
#endif
// See try_dequeue() for reasoning
Block* frontBlock_ = frontBlock.load();
size_t blockTail = frontBlock_->localTail;
size_t blockFront = frontBlock_->front.load();
if (blockFront != blockTail || blockFront != (frontBlock_->localTail = frontBlock_->tail.load())) {
fence(memory_order_acquire);
non_empty_front_block:
return reinterpret_cast<T*>(frontBlock_->data + blockFront * sizeof(T));
}
else if (frontBlock_ != tailBlock.load()) {
fence(memory_order_acquire);
frontBlock_ = frontBlock.load();
blockTail = frontBlock_->localTail = frontBlock_->tail.load();
blockFront = frontBlock_->front.load();
fence(memory_order_acquire);
if (blockFront != blockTail) {
goto non_empty_front_block;
}
Block* nextBlock = frontBlock_->next;
size_t nextBlockFront = nextBlock->front.load();
fence(memory_order_acquire);
assert(nextBlockFront != nextBlock->tail.load());
return reinterpret_cast<T*>(nextBlock->data + nextBlockFront * sizeof(T));
}
return nullptr;
}
// Removes the front element from the queue, if any, without returning it.
// Returns true on success, or false if the queue appeared empty at the time
// `pop` was called.
bool pop() AE_NO_TSAN
{
#ifndef NDEBUG
ReentrantGuard guard(this->dequeuing);
#endif
// See try_dequeue() for reasoning
Block* frontBlock_ = frontBlock.load();
size_t blockTail = frontBlock_->localTail;
size_t blockFront = frontBlock_->front.load();
if (blockFront != blockTail || blockFront != (frontBlock_->localTail = frontBlock_->tail.load())) {
fence(memory_order_acquire);
non_empty_front_block:
auto element = reinterpret_cast<T*>(frontBlock_->data + blockFront * sizeof(T));
element->~T();
blockFront = (blockFront + 1) & frontBlock_->sizeMask;
fence(memory_order_release);
frontBlock_->front = blockFront;
}
else if (frontBlock_ != tailBlock.load()) {
fence(memory_order_acquire);
frontBlock_ = frontBlock.load();
blockTail = frontBlock_->localTail = frontBlock_->tail.load();
blockFront = frontBlock_->front.load();
fence(memory_order_acquire);
if (blockFront != blockTail) {
goto non_empty_front_block;
}
// Front block is empty but there's another block ahead, advance to it
Block* nextBlock = frontBlock_->next;
size_t nextBlockFront = nextBlock->front.load();
size_t nextBlockTail = nextBlock->localTail = nextBlock->tail.load();
fence(memory_order_acquire);
assert(nextBlockFront != nextBlockTail);
AE_UNUSED(nextBlockTail);
fence(memory_order_release);
frontBlock = frontBlock_ = nextBlock;
compiler_fence(memory_order_release);
auto element = reinterpret_cast<T*>(frontBlock_->data + nextBlockFront * sizeof(T));
element->~T();
nextBlockFront = (nextBlockFront + 1) & frontBlock_->sizeMask;
fence(memory_order_release);
frontBlock_->front = nextBlockFront;
}
else {
// No elements in current block and no other block to advance to
return false;
}
return true;
}
// Returns the approximate number of items currently in the queue.
// Safe to call from both the producer and consumer threads.
inline size_t size_approx() const AE_NO_TSAN
{
size_t result = 0;
Block* frontBlock_ = frontBlock.load();
Block* block = frontBlock_;
do {
fence(memory_order_acquire);
size_t blockFront = block->front.load();
size_t blockTail = block->tail.load();
result += (blockTail - blockFront) & block->sizeMask;
block = block->next.load();
} while (block != frontBlock_);
return result;
}
private:
enum AllocationMode { CanAlloc, CannotAlloc };
#if MOODYCAMEL_HAS_EMPLACE
template<AllocationMode canAlloc, typename... Args>
bool inner_enqueue(Args&&... args) AE_NO_TSAN
#else
template<AllocationMode canAlloc, typename U>
bool inner_enqueue(U&& element) AE_NO_TSAN
#endif
{
#ifndef NDEBUG
ReentrantGuard guard(this->enqueuing);
#endif
// High-level pseudocode (assuming we're allowed to alloc a new block):
// If room in tail block, add to tail
// Else check next block
// If next block is not the head block, enqueue on next block
// Else create a new block and enqueue there
// Advance tail to the block we just enqueued to
Block* tailBlock_ = tailBlock.load();
size_t blockFront = tailBlock_->localFront;
size_t blockTail = tailBlock_->tail.load();
size_t nextBlockTail = (blockTail + 1) & tailBlock_->sizeMask;
if (nextBlockTail != blockFront || nextBlockTail != (tailBlock_->localFront = tailBlock_->front.load())) {
fence(memory_order_acquire);
// This block has room for at least one more element
char* location = tailBlock_->data + blockTail * sizeof(T);
#if MOODYCAMEL_HAS_EMPLACE
new (location) T(std::forward<Args>(args)...);
#else
new (location) T(std::forward<U>(element));
#endif
fence(memory_order_release);
tailBlock_->tail = nextBlockTail;
}
else {
fence(memory_order_acquire);
if (tailBlock_->next.load() != frontBlock) {
// Note that the reason we can't advance to the frontBlock and start adding new entries there
// is because if we did, then dequeue would stay in that block, eventually reading the new values,
// instead of advancing to the next full block (whose values were enqueued first and so should be
// consumed first).
fence(memory_order_acquire); // Ensure we get latest writes if we got the latest frontBlock
// tailBlock is full, but there's a free block ahead, use it
Block* tailBlockNext = tailBlock_->next.load();
size_t nextBlockFront = tailBlockNext->localFront = tailBlockNext->front.load();
nextBlockTail = tailBlockNext->tail.load();
fence(memory_order_acquire);
// This block must be empty since it's not the head block and we
// go through the blocks in a circle
assert(nextBlockFront == nextBlockTail);
tailBlockNext->localFront = nextBlockFront;
char* location = tailBlockNext->data + nextBlockTail * sizeof(T);
#if MOODYCAMEL_HAS_EMPLACE
new (location) T(std::forward<Args>(args)...);
#else
new (location) T(std::forward<U>(element));
#endif
tailBlockNext->tail = (nextBlockTail + 1) & tailBlockNext->sizeMask;
fence(memory_order_release);
tailBlock = tailBlockNext;
}
else if (canAlloc == CanAlloc) {
// tailBlock is full and there's no free block ahead; create a new block
auto newBlockSize = largestBlockSize >= MAX_BLOCK_SIZE ? largestBlockSize : largestBlockSize * 2;
auto newBlock = make_block(newBlockSize);
if (newBlock == nullptr) {
// Could not allocate a block!
return false;
}
largestBlockSize = newBlockSize;
#if MOODYCAMEL_HAS_EMPLACE
new (newBlock->data) T(std::forward<Args>(args)...);
#else
new (newBlock->data) T(std::forward<U>(element));
#endif
assert(newBlock->front == 0);
newBlock->tail = newBlock->localTail = 1;
newBlock->next = tailBlock_->next.load();
tailBlock_->next = newBlock;
// Might be possible for the dequeue thread to see the new tailBlock->next
// *without* seeing the new tailBlock value, but this is OK since it can't
// advance to the next block until tailBlock is set anyway (because the only
// case where it could try to read the next is if it's already at the tailBlock,
// and it won't advance past tailBlock in any circumstance).
fence(memory_order_release);
tailBlock = newBlock;
}
else if (canAlloc == CannotAlloc) {
// Would have had to allocate a new block to enqueue, but not allowed
return false;
}
else {
assert(false && "Should be unreachable code");
return false;
}
}
return true;
}
// Disable copying
ReaderWriterQueue(ReaderWriterQueue const&) { }
// Disable assignment
ReaderWriterQueue& operator=(ReaderWriterQueue const&) { }
AE_FORCEINLINE static size_t ceilToPow2(size_t x)
{
// From http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
--x;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
for (size_t i = 1; i < sizeof(size_t); i <<= 1) {
x |= x >> (i << 3);
}
++x;
return x;
}
template<typename U>
static AE_FORCEINLINE char* align_for(char* ptr) AE_NO_TSAN
{
const std::size_t alignment = std::alignment_of<U>::value;
return ptr + (alignment - (reinterpret_cast<std::uintptr_t>(ptr) % alignment)) % alignment;
}
private:
#ifndef NDEBUG
struct ReentrantGuard
{
AE_NO_TSAN ReentrantGuard(bool& _inSection)
: inSection(_inSection)
{
assert(!inSection && "Concurrent (or re-entrant) enqueue or dequeue operation detected (only one thread at a time may hold the producer or consumer role)");
inSection = true;
}
AE_NO_TSAN ~ReentrantGuard() { inSection = false; }
private:
ReentrantGuard& operator=(ReentrantGuard const&);
private:
bool& inSection;
};
#endif
struct Block
{
// Avoid false-sharing by putting highly contended variables on their own cache lines
weak_atomic<size_t> front; // (Atomic) Elements are read from here
size_t localTail; // An uncontended shadow copy of tail, owned by the consumer
char cachelineFiller0[MOODYCAMEL_CACHE_LINE_SIZE - sizeof(weak_atomic<size_t>) - sizeof(size_t)];
weak_atomic<size_t> tail; // (Atomic) Elements are enqueued here
size_t localFront;
char cachelineFiller1[MOODYCAMEL_CACHE_LINE_SIZE - sizeof(weak_atomic<size_t>) - sizeof(size_t)]; // next isn't very contended, but we don't want it on the same cache line as tail (which is)
weak_atomic<Block*> next; // (Atomic)
char* data; // Contents (on heap) are aligned to T's alignment
const size_t sizeMask;
// size must be a power of two (and greater than 0)
AE_NO_TSAN Block(size_t const& _size, char* _rawThis, char* _data)
: front(0), localTail(0), tail(0), localFront(0), next(nullptr), data(_data), sizeMask(_size - 1), rawThis(_rawThis)
{
}
private:
// C4512 - Assignment operator could not be generated
Block& operator=(Block const&);
public:
char* rawThis;
};
static Block* make_block(size_t capacity) AE_NO_TSAN
{
// Allocate enough memory for the block itself, as well as all the elements it will contain
auto size = sizeof(Block) + std::alignment_of<Block>::value - 1;
size += sizeof(T) * capacity + std::alignment_of<T>::value - 1;
auto newBlockRaw = static_cast<char*>(std::malloc(size));
if (newBlockRaw == nullptr) {
return nullptr;
}
auto newBlockAligned = align_for<Block>(newBlockRaw);
auto newBlockData = align_for<T>(newBlockAligned + sizeof(Block));
return new (newBlockAligned) Block(capacity, newBlockRaw, newBlockData);
}
private:
weak_atomic<Block*> frontBlock; // (Atomic) Elements are enqueued to this block
char cachelineFiller[MOODYCAMEL_CACHE_LINE_SIZE - sizeof(weak_atomic<Block*>)];
weak_atomic<Block*> tailBlock; // (Atomic) Elements are dequeued from this block
size_t largestBlockSize;
#ifndef NDEBUG
bool enqueuing;
bool dequeuing;
#endif
};
// Like ReaderWriterQueue, but also providees blocking operations
template<typename T, size_t MAX_BLOCK_SIZE = 512>
class BlockingReaderWriterQueue
{
private:
typedef ::moodycamel::ReaderWriterQueue<T, MAX_BLOCK_SIZE> ReaderWriterQueue;
public:
explicit BlockingReaderWriterQueue(size_t maxSize = 15) AE_NO_TSAN
: inner(maxSize), sema(new spsc_sema::LightweightSemaphore())
{ }
BlockingReaderWriterQueue(BlockingReaderWriterQueue&& other) AE_NO_TSAN
: inner(std::move(other.inner)), sema(std::move(other.sema))
{ }
BlockingReaderWriterQueue& operator=(BlockingReaderWriterQueue&& other) AE_NO_TSAN
{
std::swap(sema, other.sema);
std::swap(inner, other.inner);
return *this;
}
// Enqueues a copy of element if there is room in the queue.
// Returns true if the element was enqueued, false otherwise.
// Does not allocate memory.
AE_FORCEINLINE bool try_enqueue(T const& element) AE_NO_TSAN
{
if (inner.try_enqueue(element)) {
sema->signal();
return true;
}
return false;
}
// Enqueues a moved copy of element if there is room in the queue.
// Returns true if the element was enqueued, false otherwise.
// Does not allocate memory.
AE_FORCEINLINE bool try_enqueue(T&& element) AE_NO_TSAN
{
if (inner.try_enqueue(std::forward<T>(element))) {
sema->signal();
return true;
}
return false;
}
// Enqueues a copy of element on the queue.
// Allocates an additional block of memory if needed.
// Only fails (returns false) if memory allocation fails.
AE_FORCEINLINE bool enqueue(T const& element) AE_NO_TSAN
{
if (inner.enqueue(element)) {
sema->signal();
return true;
}
return false;
}
// Enqueues a moved copy of element on the queue.
// Allocates an additional block of memory if needed.
// Only fails (returns false) if memory allocation fails.
AE_FORCEINLINE bool enqueue(T&& element) AE_NO_TSAN
{
if (inner.enqueue(std::forward<T>(element))) {
sema->signal();
return true;
}
return false;
}
// Attempts to dequeue an element; if the queue is empty,
// returns false instead. If the queue has at least one element,
// moves front to result using operator=, then returns true.
template<typename U>
bool try_dequeue(U& result) AE_NO_TSAN
{
if (sema->tryWait()) {
bool success = inner.try_dequeue(result);
assert(success);
AE_UNUSED(success);
return true;
}
return false;
}
// Attempts to dequeue an element; if the queue is empty,
// waits until an element is available, then dequeues it.
template<typename U>
void wait_dequeue(U& result) AE_NO_TSAN
{
sema->wait();
bool success = inner.try_dequeue(result);
AE_UNUSED(result);
assert(success);
AE_UNUSED(success);
}
// Attempts to dequeue an element; if the queue is empty,
// waits until an element is available up to the specified timeout,
// then dequeues it and returns true, or returns false if the timeout
// expires before an element can be dequeued.
// Using a negative timeout indicates an indefinite timeout,
// and is thus functionally equivalent to calling wait_dequeue.
template<typename U>
bool wait_dequeue_timed(U& result, std::int64_t timeout_usecs) AE_NO_TSAN
{
if (!sema->wait(timeout_usecs)) {
return false;
}
bool success = inner.try_dequeue(result);
AE_UNUSED(result);
assert(success);
AE_UNUSED(success);
return true;
}
#if __cplusplus > 199711L || _MSC_VER >= 1700
// Attempts to dequeue an element; if the queue is empty,
// waits until an element is available up to the specified timeout,
// then dequeues it and returns true, or returns false if the timeout
// expires before an element can be dequeued.
// Using a negative timeout indicates an indefinite timeout,
// and is thus functionally equivalent to calling wait_dequeue.
template<typename U, typename Rep, typename Period>
inline bool wait_dequeue_timed(U& result, std::chrono::duration<Rep, Period> const& timeout) AE_NO_TSAN
{
return wait_dequeue_timed(result, std::chrono::duration_cast<std::chrono::microseconds>(timeout).count());
}
#endif
// Returns a pointer to the front element in the queue (the one that
// would be removed next by a call to `try_dequeue` or `pop`). If the
// queue appears empty at the time the method is called, nullptr is
// returned instead.
// Must be called only from the consumer thread.
AE_FORCEINLINE T* peek() AE_NO_TSAN
{
return inner.peek();
}
// Removes the front element from the queue, if any, without returning it.
// Returns true on success, or false if the queue appeared empty at the time
// `pop` was called.
AE_FORCEINLINE bool pop() AE_NO_TSAN
{
if (sema->tryWait()) {
bool result = inner.pop();
assert(result);
AE_UNUSED(result);
return true;
}
return false;
}
// Returns the approximate number of items currently in the queue.
// Safe to call from both the producer and consumer threads.
AE_FORCEINLINE size_t size_approx() const AE_NO_TSAN
{
return sema->availableApprox();
}
private:
// Disable copying & assignment
BlockingReaderWriterQueue(BlockingReaderWriterQueue const&) { }
BlockingReaderWriterQueue& operator=(BlockingReaderWriterQueue const&) { }
private:
ReaderWriterQueue inner;
std::unique_ptr<spsc_sema::LightweightSemaphore> sema;
};
} // end namespace moodycamel
#ifdef AE_VCPP
#pragma warning(pop)
#endif

View File

@ -3,6 +3,7 @@
#include <Graphics/Context.h>
#include <Graphics/OpenGLContext/GLFunctions.h>
#include <Graphics/OpenGLContext/opengl_Utils.h>
#include <Graphics/OpenGLContext/ThreadedOpenGl/opengl_Wrapper.h>
#include <mupenplus/GLideN64_mupenplus.h>
#include <GLideN64.h>
#include <Config.h>
@ -18,6 +19,8 @@
#include <bcm_host.h>
#endif
using namespace opengl;
class DisplayWindowMupen64plus : public DisplayWindow
{
public:
@ -49,30 +52,32 @@ void DisplayWindowMupen64plus::_setAttributes()
{
LOG(LOG_VERBOSE, "[gles2GlideN64]: _setAttributes\n");
CoreVideo_GL_SetAttribute(M64P_GL_CONTEXT_PROFILE_MASK, M64P_GL_CONTEXT_PROFILE_CORE);
CoreVideo_GL_SetAttribute(M64P_GL_CONTEXT_MAJOR_VERSION, 3);
CoreVideo_GL_SetAttribute(M64P_GL_CONTEXT_MINOR_VERSION, 3);
FunctionWrapper::CoreVideo_GL_SetAttribute(M64P_GL_CONTEXT_PROFILE_MASK, M64P_GL_CONTEXT_PROFILE_CORE);
FunctionWrapper::CoreVideo_GL_SetAttribute(M64P_GL_CONTEXT_MAJOR_VERSION, 3);
FunctionWrapper::CoreVideo_GL_SetAttribute(M64P_GL_CONTEXT_MINOR_VERSION, 3);
CoreVideo_GL_SetAttribute(M64P_GL_DOUBLEBUFFER, 1);
CoreVideo_GL_SetAttribute(M64P_GL_SWAP_CONTROL, config.video.verticalSync);
CoreVideo_GL_SetAttribute(M64P_GL_BUFFER_SIZE, 32);
CoreVideo_GL_SetAttribute(M64P_GL_DEPTH_SIZE, 16);
FunctionWrapper::CoreVideo_GL_SetAttribute(M64P_GL_DOUBLEBUFFER, 1);
FunctionWrapper::CoreVideo_GL_SetAttribute(M64P_GL_SWAP_CONTROL, config.video.verticalSync);
FunctionWrapper::CoreVideo_GL_SetAttribute(M64P_GL_BUFFER_SIZE, 32);
FunctionWrapper::CoreVideo_GL_SetAttribute(M64P_GL_DEPTH_SIZE, 16);
if (config.video.multisampling > 0 && config.frameBufferEmulation.enable == 0) {
CoreVideo_GL_SetAttribute(M64P_GL_MULTISAMPLEBUFFERS, 1);
FunctionWrapper::CoreVideo_GL_SetAttribute(M64P_GL_MULTISAMPLEBUFFERS, 1);
if (config.video.multisampling <= 2)
CoreVideo_GL_SetAttribute(M64P_GL_MULTISAMPLESAMPLES, 2);
FunctionWrapper::CoreVideo_GL_SetAttribute(M64P_GL_MULTISAMPLESAMPLES, 2);
else if (config.video.multisampling <= 4)
CoreVideo_GL_SetAttribute(M64P_GL_MULTISAMPLESAMPLES, 4);
FunctionWrapper::CoreVideo_GL_SetAttribute(M64P_GL_MULTISAMPLESAMPLES, 4);
else if (config.video.multisampling <= 8)
CoreVideo_GL_SetAttribute(M64P_GL_MULTISAMPLESAMPLES, 8);
FunctionWrapper::CoreVideo_GL_SetAttribute(M64P_GL_MULTISAMPLESAMPLES, 8);
else
CoreVideo_GL_SetAttribute(M64P_GL_MULTISAMPLESAMPLES, 16);
FunctionWrapper::CoreVideo_GL_SetAttribute(M64P_GL_MULTISAMPLESAMPLES, 16);
}
}
bool DisplayWindowMupen64plus::_start()
{
CoreVideo_Init();
FunctionWrapper::setThreadedMode(config.video.threadedVideo);
FunctionWrapper::CoreVideo_Init();
_setAttributes();
m_bFullscreen = config.video.fullscreen > 0;
@ -83,10 +88,10 @@ bool DisplayWindowMupen64plus::_start()
printf("(II) Setting video mode %dx%d...\n", m_screenWidth, m_screenHeight);
const m64p_video_flags flags = M64VIDEOFLAG_SUPPORT_RESIZING;
if (CoreVideo_SetVideoMode(m_screenWidth, m_screenHeight, 0, m_bFullscreen ? M64VIDEO_FULLSCREEN : M64VIDEO_WINDOWED, flags) != M64ERR_SUCCESS) {
if (FunctionWrapper::CoreVideo_SetVideoMode(m_screenWidth, m_screenHeight, 0, m_bFullscreen ? M64VIDEO_FULLSCREEN : M64VIDEO_WINDOWED, flags) != M64ERR_SUCCESS) {
//printf("(EE) Error setting videomode %dx%d\n", m_screenWidth, m_screenHeight);
LOG(LOG_ERROR, "[gles2GlideN64]: Error setting videomode %dx%d\n", m_screenWidth, m_screenHeight);
CoreVideo_Quit();
FunctionWrapper::CoreVideo_Quit();
return false;
}
LOG(LOG_VERBOSE, "[gles2GlideN64]: Create setting videomode %dx%d\n", m_screenWidth, m_screenHeight);
@ -104,7 +109,7 @@ bool DisplayWindowMupen64plus::_start()
void DisplayWindowMupen64plus::_stop()
{
CoreVideo_Quit();
FunctionWrapper::CoreVideo_Quit();
}
void DisplayWindowMupen64plus::_swapBuffers()
@ -119,7 +124,11 @@ void DisplayWindowMupen64plus::_swapBuffers()
gDP.changed |= CHANGED_COMBINE;
(*renderCallback)((gDP.changed&CHANGED_CPU_FB_WRITE) == 0 ? 1 : 0);
}
CoreVideo_GL_SwapBuffers();
//Don't let the command queue grow too big buy waiting on no more swap buffers being queued
FunctionWrapper::WaitForSwapBuffersQueued();
FunctionWrapper::CoreVideo_GL_SwapBuffers();
}
void DisplayWindowMupen64plus::_saveScreenshot()
@ -150,7 +159,7 @@ bool DisplayWindowMupen64plus::_resizeWindow()
printf("(EE) Error setting videomode %dx%d\n", m_screenWidth, m_screenHeight);
m_width = m_screenWidth = config.video.windowedWidth;
m_height = m_screenHeight = config.video.windowedHeight;
CoreVideo_Quit();
FunctionWrapper::CoreVideo_Quit();
return false;
}
_setBufferSize();

View File

@ -7,7 +7,7 @@
using namespace graphics;
using namespace opengl;
const u32 BufferedDrawer::m_bufMaxSize = 4194304;
const u32 BufferedDrawer::m_bufMaxSize = 8 * 1024 * 1024; // 8 MB
#ifndef GL_DEBUG
const GLbitfield BufferedDrawer::m_bufAccessBits = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;
const GLbitfield BufferedDrawer::m_bufMapBits = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;

View File

@ -23,12 +23,12 @@ void CachedEnable::enable(bool _enable)
return;
if (_enable) {
if (m_parameter == enable::BLEND && IS_GL_FUNCTION_VALID(glEnablei))
if (m_parameter == enable::BLEND && IS_GL_FUNCTION_VALID(Enablei))
glEnablei(GLenum(m_parameter), 0);
else
glEnable(GLenum(m_parameter));
} else {
if (m_parameter == enable::BLEND && IS_GL_FUNCTION_VALID(glDisablei))
if (m_parameter == enable::BLEND && IS_GL_FUNCTION_VALID(Disablei))
glDisablei(GLenum(m_parameter), 0);
else
glDisable(GLenum(m_parameter));
@ -40,6 +40,27 @@ u32 CachedEnable::get()
return u32(m_cached);
}
/*---------------CachedBindFramebuffer-------------*/
void CachedBindFramebuffer::bind(graphics::Parameter _target, graphics::ObjectHandle _name) {
if (update(_target, _name))
glBindFramebuffer(GLenum(_target), GLuint(_name));
}
/*---------------CachedBindRenderbuffer-------------*/
void CachedBindRenderbuffer::bind(graphics::Parameter _target, graphics::ObjectHandle _name) {
if (update(_target, _name))
glBindRenderbuffer(GLenum(_target), GLuint(_name));
}
/*---------------CachedBindBuffer-------------*/
void CachedBindBuffer::bind(graphics::Parameter _target, graphics::ObjectHandle _name) {
if (update(_target, _name))
glBindBuffer(GLenum(_target), GLuint(_name));
}
/*---------------CachedBindTexture-------------*/
void CachedBindTexture::bind(Parameter _tmuIndex, Parameter _target, ObjectHandle _name)
@ -152,9 +173,7 @@ void CachedTextureUnpackAlignment::setTextureUnpackAlignment(s32 _param)
/*---------------CachedFunctions-------------*/
CachedFunctions::CachedFunctions(const GLInfo & _glinfo)
: m_bindFramebuffer(GET_GL_FUNCTION(glBindFramebuffer))
, m_bindRenderbuffer(GET_GL_FUNCTION(glBindRenderbuffer))
, m_bindBuffer(GET_GL_FUNCTION(glBindBuffer)) {
{
if (_glinfo.isGLESX) {
// Disable parameters, not avalible for GLESX
m_enables.emplace(GL_DEPTH_CLAMP, Parameter());

View File

@ -110,26 +110,23 @@ namespace opengl {
};
template<typename Bind>
class CachedBind : public Cached2<graphics::Parameter, graphics::ObjectHandle>
class CachedBindFramebuffer : public Cached2<graphics::Parameter, graphics::ObjectHandle>
{
public:
CachedBind(Bind _bind) : m_bind(_bind) {}
void bind(graphics::Parameter _target, graphics::ObjectHandle _name) {
if (update(_target, _name))
m_bind(GLenum(_target), GLuint(_name));
}
private:
Bind m_bind;
void bind(graphics::Parameter _target, graphics::ObjectHandle _name);
};
typedef CachedBind<decltype(GET_GL_FUNCTION(glBindFramebuffer))> CachedBindFramebuffer;
class CachedBindRenderbuffer : public Cached2<graphics::Parameter, graphics::ObjectHandle>
{
public:
void bind(graphics::Parameter _target, graphics::ObjectHandle _name);
};
typedef CachedBind<decltype(GET_GL_FUNCTION(glBindRenderbuffer))> CachedBindRenderbuffer;
typedef CachedBind<decltype(GET_GL_FUNCTION(glBindBuffer))> CachedBindBuffer;
class CachedBindBuffer : public Cached2<graphics::Parameter, graphics::ObjectHandle>
{
public:
void bind(graphics::Parameter _target, graphics::ObjectHandle _name);
};
class CachedBindTexture : public Cached2<graphics::Parameter, graphics::ObjectHandle>
{

View File

@ -30,7 +30,6 @@ void ColorBufferReaderWithBufferStorage::_initBuffers()
// Initialize Pixel Buffer Objects
for (u32 index = 0; index < m_numPBO; ++index) {
m_bindBuffer->bind(Parameter(GL_PIXEL_PACK_BUFFER), ObjectHandle(m_PBO[index]));
m_fence[index] = 0;
glBufferStorage(GL_PIXEL_PACK_BUFFER, m_pTexture->textureBytes, nullptr, GL_MAP_READ_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT | GL_CLIENT_STORAGE_BIT);
m_PBOData[index] = glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, m_pTexture->textureBytes, GL_MAP_READ_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
}
@ -44,7 +43,6 @@ void ColorBufferReaderWithBufferStorage::_destroyBuffers()
for (u32 index = 0; index < m_numPBO; ++index) {
m_PBO[index] = 0;
glDeleteSync(m_fence[index]);
}
}
@ -55,18 +53,11 @@ const u8 * ColorBufferReaderWithBufferStorage::_readPixels(const ReadColorBuffer
GLenum type = GLenum(_params.colorType);
m_bindBuffer->bind(Parameter(GL_PIXEL_PACK_BUFFER), ObjectHandle(m_PBO[m_curIndex]));
glReadPixels(_params.x0, _params.y0, m_pTexture->realWidth, _params.height, format, type, 0);
glReadPixels(_params.x0, _params.y0, m_pTexture->realWidth, _params.height, format, type, nullptr);
if (!_params.sync) {
//Setup a fence sync object so that we know when glReadPixels completes
m_fence[m_curIndex] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
m_curIndex = (m_curIndex + 1) % m_numPBO;
//Wait for glReadPixels to complete for the currently selected PBO
if (m_fence[m_curIndex] != 0) {
glClientWaitSync(m_fence[m_curIndex], 0, 100000000);
glDeleteSync(m_fence[m_curIndex]);
m_fence[m_curIndex] = 0;
}
} else {
glFinish();
}

View File

@ -29,7 +29,6 @@ namespace opengl {
GLuint m_PBO[_maxPBO];
void* m_PBOData[_maxPBO];
u32 m_curIndex;
GLsync m_fence[_maxPBO];
};
}

View File

@ -25,7 +25,7 @@ using namespace opengl;
ContextImpl::ContextImpl()
: m_clampMode(graphics::ClampMode::ClippingEnabled)
{
initGLFunctions();
}

View File

@ -108,20 +108,20 @@ void GLInfo::init() {
bool ext_draw_buffers_indexed = isGLESX && (Utils::isExtensionSupported(*this, "GL_EXT_draw_buffers_indexed") || numericVersion >= 32);
#ifdef EGL
if (isGLESX && bufferStorage)
g_glBufferStorage = (PFNGLBUFFERSTORAGEPROC) eglGetProcAddress("glBufferStorageEXT");
ptrBufferStorage = (PFNGLBUFFERSTORAGEPROC) eglGetProcAddress("glBufferStorageEXT");
if (isGLESX && numericVersion < 32) {
if (ext_draw_buffers_indexed) {
g_glEnablei = (PFNGLENABLEIPROC) eglGetProcAddress("glEnableiEXT");
g_glDisablei = (PFNGLDISABLEIPROC) eglGetProcAddress("glDisableiEXT");
ptrEnablei = (PFNGLENABLEIPROC) eglGetProcAddress("glEnableiEXT");
ptrDisablei = (PFNGLDISABLEIPROC) eglGetProcAddress("glDisableiEXT");
} else {
g_glEnablei = nullptr;
g_glDisablei = nullptr;
ptrEnablei = nullptr;
ptrDisablei = nullptr;
}
}
if (isGLES2 && shaderStorage) {
g_glProgramBinary = (PFNGLPROGRAMBINARYPROC) eglGetProcAddress("glProgramBinaryOES");
g_glGetProgramBinary = (PFNGLGETPROGRAMBINARYPROC) eglGetProcAddress("glGetProgramBinaryOES");
g_glProgramParameteri = nullptr;
ptrProgramBinary = (PFNGLPROGRAMBINARYPROC) eglGetProcAddress("glProgramBinaryOES");
ptrGetProgramBinary = (PFNGLGETPROGRAMBINARYPROC) eglGetProcAddress("glGetProgramBinaryOES");
ptrProgramParameteri = nullptr;
}
#endif
#ifndef OS_ANDROID

View File

@ -0,0 +1,152 @@
#include "WindowsWGL.h"
#include <Config.h>
#include <GLideN64.h>
#include <Graphics/OpenGLContext/GLFunctions.h>
HGLRC WindowsWGL::hRC = NULL;
HDC WindowsWGL::hDC = NULL;
bool WindowsWGL::start()
{
int pixelFormat;
LOG(LOG_APIFUNC, "WindowsWGL::start TEST1\n");
PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
1, // version number
PFD_DRAW_TO_WINDOW | // support window
PFD_SUPPORT_OPENGL | // support OpenGL
PFD_DOUBLEBUFFER, // double buffered
PFD_TYPE_RGBA, // RGBA type
32, // color depth
0, 0, 0, 0, 0, 0, // color bits ignored
0, // no alpha buffer
0, // shift bit ignored
0, // no accumulation buffer
0, 0, 0, 0, // accum bits ignored
32, // z-buffer
0, // no stencil buffer
0, // no auxiliary buffer
PFD_MAIN_PLANE, // main layer
0, // reserved
0, 0, 0 // layer masks ignored
};
LOG(LOG_APIFUNC, "WindowsWGL::start TEST2\n");
if (hWnd == NULL)
hWnd = GetActiveWindow();
LOG(LOG_APIFUNC, "WindowsWGL::start TEST3\n");
if ((hDC = GetDC(hWnd)) == NULL) {
MessageBox(hWnd, L"Error while getting a device context!", pluginNameW, MB_ICONERROR | MB_OK);
return false;
}
LOG(LOG_APIFUNC, "WindowsWGL::start TEST4\n");
if ((pixelFormat = ChoosePixelFormat(hDC, &pfd)) == 0) {
MessageBox(hWnd, L"Unable to find a suitable pixel format!", pluginNameW, MB_ICONERROR | MB_OK);
stop();
return false;
}
LOG(LOG_APIFUNC, "WindowsWGL::start TEST5\n");
if ((SetPixelFormat(hDC, pixelFormat, &pfd)) == FALSE) {
MessageBox(hWnd, L"Error while setting pixel format!", pluginNameW, MB_ICONERROR | MB_OK);
stop();
return false;
}
LOG(LOG_APIFUNC, "WindowsWGL::start TEST6\n");
if ((hRC = wglCreateContext(hDC)) == NULL) {
MessageBox(hWnd, L"Error while creating OpenGL context!", pluginNameW, MB_ICONERROR | MB_OK);
stop();
return false;
}
LOG(LOG_APIFUNC, "WindowsWGL::start TEST7\n");
if ((wglMakeCurrent(hDC, hRC)) == FALSE) {
MessageBox(hWnd, L"Error while making OpenGL context current!", pluginNameW, MB_ICONERROR | MB_OK);
stop();
return false;
}
LOG(LOG_APIFUNC, "WindowsWGL::start TEST7.1\n");
initGLFunctions();
LOG(LOG_APIFUNC, "WindowsWGL::start TEST7.2\n");
LOG(LOG_APIFUNC, "WindowsWGL::start TEST8\n");
PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB =
(PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB");
LOG(LOG_APIFUNC, "WindowsWGL::start TEST9\n");
if (wglGetExtensionsStringARB != NULL) {
const char * wglextensions = wglGetExtensionsStringARB(hDC);
LOG(LOG_APIFUNC, "WindowsWGL::start TEST9.1\n");
if (strstr(wglextensions, "WGL_ARB_create_context_profile") != nullptr) {
LOG(LOG_APIFUNC, "WindowsWGL::start TEST9.1.1\n");
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB =
(PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB");
LOG(LOG_APIFUNC, "WindowsWGL::start TEST9.2\n");
GLint majorVersion = 0;
ptrGetIntegerv(GL_MAJOR_VERSION, &majorVersion);
LOG(LOG_APIFUNC, "WindowsWGL::start TEST9.3\n");
GLint minorVersion = 0;
ptrGetIntegerv(GL_MINOR_VERSION, &minorVersion);
LOG(LOG_APIFUNC, "WindowsWGL::start TEST9.4\n");
const int attribList[] =
{
WGL_CONTEXT_MAJOR_VERSION_ARB, majorVersion,
WGL_CONTEXT_MINOR_VERSION_ARB, minorVersion,
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
0 //End
};
HGLRC coreHrc = wglCreateContextAttribsARB(hDC, 0, attribList);
LOG(LOG_APIFUNC, "WindowsWGL::start TEST9.5\n");
if (coreHrc != NULL) {
wglDeleteContext(hRC);
wglMakeCurrent(hDC, coreHrc);
hRC = coreHrc;
}
}
LOG(LOG_APIFUNC, "WindowsWGL::start TEST9.1.1\n");
if (strstr(wglextensions, "WGL_EXT_swap_control") != nullptr) {
LOG(LOG_APIFUNC, "WindowsWGL::start TEST9.6\n");
PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
LOG(LOG_APIFUNC, "WindowsWGL::start TEST9.7\n");
wglSwapIntervalEXT(config.video.verticalSync);
LOG(LOG_APIFUNC, "WindowsWGL::start TEST9.8\n");
}
}
return true;
}
void WindowsWGL::stop()
{
wglMakeCurrent(NULL, NULL);
if (hRC != NULL) {
wglDeleteContext(hRC);
hRC = NULL;
}
if (hDC != NULL) {
ReleaseDC(hWnd, hDC);
hDC = NULL;
}
}
void WindowsWGL::swapBuffers()
{
if (hDC == NULL)
SwapBuffers(wglGetCurrentDC());
else
SwapBuffers(hDC);
}

View File

@ -0,0 +1,20 @@
#pragma once
#include <stdio.h>
#include <windows.h>
#include <GL/GL.h>
#include <GL/wglext.h>
#include <windows/GLideN64_Windows.h>
class WindowsWGL
{
public:
static bool start();
static void stop();
static void swapBuffers();
private:
static HGLRC hRC;
static HDC hDC;
};

View File

@ -1,6 +1,3 @@
#include <stdio.h>
#include <Graphics/OpenGLContext/GLFunctions.h>
#include <GL/wglext.h>
#include <windows/GLideN64_Windows.h>
#include <GLideN64.h>
#include <Config.h>
@ -11,11 +8,14 @@
#include <Graphics/Context.h>
#include <Graphics/Parameters.h>
#include <DisplayWindow.h>
#include <Graphics/OpenGLContext/ThreadedOpenGl/opengl_Wrapper.h>
using namespace opengl;
class DisplayWindowWindows : public DisplayWindow
{
public:
DisplayWindowWindows() : hRC(NULL), hDC(NULL) {}
DisplayWindowWindows() = default;
private:
bool _start() override;
@ -28,9 +28,6 @@ private:
void _readScreen(void **_pDest, long *_pWidth, long *_pHeight) override;
void _readScreen2(void * _dest, int * _width, int * _height, int _front) override {}
graphics::ObjectHandle _getDefaultFramebuffer() override;
HGLRC hRC;
HDC hDC;
};
DisplayWindow & DisplayWindow::get()
@ -41,122 +38,23 @@ DisplayWindow & DisplayWindow::get()
bool DisplayWindowWindows::_start()
{
int pixelFormat;
PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
1, // version number
PFD_DRAW_TO_WINDOW | // support window
PFD_SUPPORT_OPENGL | // support OpenGL
PFD_DOUBLEBUFFER, // double buffered
PFD_TYPE_RGBA, // RGBA type
32, // color depth
0, 0, 0, 0, 0, 0, // color bits ignored
0, // no alpha buffer
0, // shift bit ignored
0, // no accumulation buffer
0, 0, 0, 0, // accum bits ignored
32, // z-buffer
0, // no stencil buffer
0, // no auxiliary buffer
PFD_MAIN_PLANE, // main layer
0, // reserved
0, 0, 0 // layer masks ignored
};
if (hWnd == NULL)
hWnd = GetActiveWindow();
if ((hDC = GetDC( hWnd )) == NULL) {
MessageBox( hWnd, L"Error while getting a device context!", pluginNameW, MB_ICONERROR | MB_OK );
return false;
}
if ((pixelFormat = ChoosePixelFormat(hDC, &pfd )) == 0) {
MessageBox( hWnd, L"Unable to find a suitable pixel format!", pluginNameW, MB_ICONERROR | MB_OK );
_stop();
return false;
}
if ((SetPixelFormat(hDC, pixelFormat, &pfd )) == FALSE) {
MessageBox( hWnd, L"Error while setting pixel format!", pluginNameW, MB_ICONERROR | MB_OK );
_stop();
return false;
}
if ((hRC = wglCreateContext(hDC)) == NULL) {
MessageBox( hWnd, L"Error while creating OpenGL context!", pluginNameW, MB_ICONERROR | MB_OK );
_stop();
return false;
}
if ((wglMakeCurrent(hDC, hRC)) == FALSE) {
MessageBox( hWnd, L"Error while making OpenGL context current!", pluginNameW, MB_ICONERROR | MB_OK );
_stop();
return false;
}
PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB =
(PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB");
if (wglGetExtensionsStringARB != NULL) {
const char * wglextensions = wglGetExtensionsStringARB(hDC);
if (strstr(wglextensions, "WGL_ARB_create_context_profile") != nullptr) {
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB =
(PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB");
GLint majorVersion = 0;
glGetIntegerv(GL_MAJOR_VERSION, &majorVersion);
GLint minorVersion = 0;
glGetIntegerv(GL_MINOR_VERSION, &minorVersion);
const int attribList[] =
{
WGL_CONTEXT_MAJOR_VERSION_ARB, majorVersion,
WGL_CONTEXT_MINOR_VERSION_ARB, minorVersion,
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
0 //End
};
HGLRC coreHrc = wglCreateContextAttribsARB(hDC, 0, attribList);
if (coreHrc != NULL) {
wglDeleteContext(hRC);
wglMakeCurrent(hDC, coreHrc);
hRC = coreHrc;
}
}
if (strstr(wglextensions, "WGL_EXT_swap_control") != nullptr) {
PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
wglSwapIntervalEXT(config.video.verticalSync);
}
}
FunctionWrapper::setThreadedMode(config.video.threadedVideo);
FunctionWrapper::windowsStart();
return _resizeWindow();
}
void DisplayWindowWindows::_stop()
{
wglMakeCurrent( NULL, NULL );
if (hRC != NULL) {
wglDeleteContext(hRC);
hRC = NULL;
}
if (hDC != NULL) {
ReleaseDC(hWnd, hDC);
hDC = NULL;
}
FunctionWrapper::windowsStop();
}
void DisplayWindowWindows::_swapBuffers()
{
if (hDC == NULL)
SwapBuffers( wglGetCurrentDC() );
else
SwapBuffers( hDC );
//Don't let the command queue grow too big buy waiting on no more swap buffers being queued
FunctionWrapper::WaitForSwapBuffersQueued();
FunctionWrapper::windowsSwapBuffers();
}
void DisplayWindowWindows::_saveScreenshot()

View File

@ -5,11 +5,16 @@
#include "Log.h"
#include "PluginAPI.h"
#include "wst.h"
#include <mutex>
std::mutex g_logMutex;
void LOG(u16 type, const char * format, ...) {
if (type > LOG_LEVEL)
return;
std::unique_lock<std::mutex> lock(g_logMutex);
wchar_t logPath[PLUGIN_PATH_SIZE + 16];
api().GetUserDataPath(logPath);
gln_wcscat(logPath, wst("/gliden64.log"));

View File

@ -68,6 +68,11 @@ MY_LOCAL_SRC_FILES :=
$(SRCDIR)/Graphics/CombinerProgram.cpp \
$(SRCDIR)/Graphics/ObjectHandle.cpp \
$(SRCDIR)/Graphics/OpenGLContext/GLFunctions.cpp \
$(SRCDIR)/Graphics/OpenGLContext/ThreadedOpenGl/opengl_Wrapper.cpp \
$(SRCDIR)/Graphics/OpenGLContext/ThreadedOpenGl/opengl_WrappedFunctions.cpp \
$(SRCDIR)/Graphics/OpenGLContext/ThreadedOpenGl/opengl_Command.cpp \
$(SRCDIR)/Graphics/OpenGLContext/ThreadedOpenGl/opengl_ObjectPool.cpp \
$(SRCDIR)/Graphics/OpenGLContext/ThreadedOpenGl/RingBufferPool.cpp \
$(SRCDIR)/Graphics/OpenGLContext/opengl_Attributes.cpp \
$(SRCDIR)/Graphics/OpenGLContext/opengl_BufferedDrawer.cpp \
$(SRCDIR)/Graphics/OpenGLContext/opengl_BufferManipulationObjectFactory.cpp \

View File

@ -45,6 +45,9 @@ bool Config_SetDefault()
res = ConfigSetDefaultInt(g_configVideoGliden64, "configVersion", CONFIG_VERSION_CURRENT, "Settings version. Don't touch it.");
assert(res == M64ERR_SUCCESS);
res = ConfigSetDefaultBool(g_configVideoGliden64, "ThreadedVideo", config.video.threadedVideo, "Enable threaded video backend");
assert(res == M64ERR_SUCCESS);
res = ConfigSetDefaultInt(g_configVideoGliden64, "MultiSampling", config.video.multisampling, "Enable/Disable MultiSampling (0=off, 2,4,8,16=quality)");
assert(res == M64ERR_SUCCESS);
res = ConfigSetDefaultBool(g_configVideoGliden64, "FXAA", config.video.fxaa, "Enable/Disable Fast Approximate Anti-Aliasing FXAA");
@ -358,7 +361,7 @@ void Config_LoadConfig()
config.video.windowedWidth = ConfigGetParamInt(g_configVideoGeneral, "ScreenWidth");
config.video.windowedHeight = ConfigGetParamInt(g_configVideoGeneral, "ScreenHeight");
config.video.verticalSync = ConfigGetParamBool(g_configVideoGeneral, "VerticalSync");
config.video.threadedVideo = ConfigGetParamBool(g_configVideoGliden64, "ThreadedVideo");
const u32 multisampling = ConfigGetParamInt(g_configVideoGliden64, "MultiSampling");
config.video.multisampling = multisampling == 0 ? 0 : pow2(multisampling);
config.video.fxaa = ConfigGetParamBool(g_configVideoGliden64, "FXAA");