mirror of https://github.com/blawar/GLideN64.git
Threaded GLideN64 calls
This commit is contained in:
parent
ae025e10ea
commit
5df3f9dbac
|
@ -12,3 +12,4 @@ src/Revision.h
|
|||
/projects/msvc/GLideN64.VC.VC.opendb
|
||||
/projects/msvc/GLideN64.VC.db
|
||||
/projects/msvc/GeneratedFiles
|
||||
.vs
|
||||
|
|
|
@ -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.
|
|
@ -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" />
|
||||
|
|
|
@ -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>
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -28,6 +28,7 @@ struct Config
|
|||
u32 fxaa;
|
||||
u32 multisampling;
|
||||
u32 verticalSync;
|
||||
u32 threadedVideo;
|
||||
} video;
|
||||
|
||||
struct
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -160,6 +160,16 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="vThreadedVideoCheckBox">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Threaded video can improve performance with poor OpenGL drivers at the cost of very marginal input lag, usually less than half a frame</p><p>[Recommended: <span style=" font-style:italic;">Usually off, unless there are performance issues.</span>]</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable threaded video</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="overscanFrame">
|
||||
<property name="minimumSize">
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
};
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
{
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
}
|
|
@ -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 ¤tPool = m_objectPool[_poolId];
|
||||
auto ¤tIndex = 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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
}
|
|
@ -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
|
@ -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);
|
||||
};
|
||||
}
|
|
@ -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
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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>
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -29,7 +29,6 @@ namespace opengl {
|
|||
GLuint m_PBO[_maxPBO];
|
||||
void* m_PBOData[_maxPBO];
|
||||
u32 m_curIndex;
|
||||
GLsync m_fence[_maxPBO];
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ using namespace opengl;
|
|||
ContextImpl::ContextImpl()
|
||||
: m_clampMode(graphics::ClampMode::ClippingEnabled)
|
||||
{
|
||||
initGLFunctions();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
};
|
||||
|
|
@ -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()
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Reference in New Issue