cleanup and refactoring

This commit is contained in:
CDaut 2024-05-25 11:53:25 +02:00
parent 2302158928
commit 76f6bf62a4
Signed by: clara
GPG key ID: 223391B52FAD4463
1285 changed files with 757994 additions and 8 deletions

View file

@ -0,0 +1,98 @@
## Table of Contents
- [appwindowprofiler_gl.hpp](#appwindowprofiler_glhpp)
- [contextwindow_gl.hpp](#contextwindow_glhpp)
- [error_gl.hpp](#error_glhpp)
- [extensions_gl.hpp](#extensions_glhpp)
- [profiler_gl.hpp](#profiler_glhpp)
- [programmanager_gl.hpp](#programmanager_glhpp)
## appwindowprofiler_gl.hpp
### class nvgl::AppWindowProfilerGL
nvgl::AppWindowProfilerGL derives from nvh::AppWindowProfiler
and overrides the context and swapbuffer functions.
To influence the context creation modify
`m_contextInfo` prior running AppWindowProfiler::run,
which triggers window, and context creation etc.
The class comes with a nvgl::ProfilerGL instance that references the
AppWindowProfiler::m_profiler's data.
## contextwindow_gl.hpp
### struct nvgl::ContextWindowCreateInfo
Set up the context properties for a OpenGL ContextWindow.
e.g. version, core/compatibiltiy etc.
### class nvgl::ContextWindow
nvgl::ContextWindow sets up an OpenGL context from a provided `GLFWwindow`.
Makes use of `glDebugMessageCallback` to hook up an error callback
and loads all extensions provided by `extensions_gl.hpp`
## error_gl.hpp
### functions in nvgl
Several utility functions that aid debugging. Check if all bindings
are cleared, framebuffer complete etc.
### template class nvgl::CheckBufferContent
Utility wrapper to downlad buffer data into a temp vector for debugging
### class nvgl::CheckBufferResidency
nvgl::CheckBufferResidency utility class to test if a certain gpu address is coming from
a resident buffer. Register the address of buffers in advance.
## extensions_gl.hpp
### function load_GL
> An OpenGL Extension loader
Provides a subset of OpenGL Extensions generated by `extensions_gl.lua`.
The framework uses a sanitized OpenGL header that is mostly core functionality.
`GL/glsubset.h` is generated using a enablelist by the lua script
from `GL/glcustom.h` (which is mostly based on `glcorearb.h` with some
additional extensions and features)
## profiler_gl.hpp
### class nvgl::ProfilerGL
nvgl::ProfilerGL extends Profiler and uses `glQueryCounter(... GL_TIMESTAMP)`
to compute the GPU time of a section.
`glPushDebugGroup` and `glPopDebugGroup` are used within each timed
section, so that the section names can show up in NSightGraphics,
renderdoc or comparable tools.
## programmanager_gl.hpp
### class nvgl::ProgramManager
The nvgl::ProgramManager manages OpenGL programs generated from shader files (GLSL)
Using ShaderFileManager it will find the files and resolve #include for GLSL.
You must add include directories to the base-class for this.
It also comes with some convenience functions to reload shaders etc.
That is why we pass out the ProgramID rather than a GLuint directly.
Example:
```cpp
ProgramManager mgr;
// derived from ShaderFileManager
mgr.addDirectory("/shaders/")
// injected after #version directive
mgr.m_prepend = "#define USE_NOISE 1\n";
id = mgr.createProgram({{GL_VERTEX_SHADER, "object.vert.glsl"},{GL_FRAGMENT_SHADER, "object.frag.glsl"}}):
glUseProgram(mgr.get(id));
```

View file

@ -0,0 +1,43 @@
/*
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#include "appwindowprofiler_gl.hpp"
#include <nvh/misc.hpp>
namespace nvgl {
void AppWindowProfilerGL::contextInit()
{
// create OpenGL stuff at last
m_contextWindow.init(&m_contextInfo, m_internal, m_windowName.c_str());
// create other additional OpenGL tools
m_profilerGL.init();
m_windowState.m_swapSize[0] = NVPWindow::getWidth();
m_windowState.m_swapSize[1] = NVPWindow::getHeight();
}
void AppWindowProfilerGL::contextDeinit()
{
m_profilerGL.deinit();
m_contextWindow.deinit();
}
} // namespace nvgl

View file

@ -0,0 +1,94 @@
/*
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef NV_WINDOWPROFILER_GL_INCLUDED
#define NV_WINDOWPROFILER_GL_INCLUDED
#include "contextwindow_gl.hpp"
#include "profiler_gl.hpp"
#include <nvh/appwindowprofiler.hpp>
//////////////////////////////////////////////////////////////////////////
/** @DOC_START
# class nvgl::AppWindowProfilerGL
nvgl::AppWindowProfilerGL derives from nvh::AppWindowProfiler
and overrides the context and swapbuffer functions.
To influence the context creation modify
`m_contextInfo` prior running AppWindowProfiler::run,
which triggers window, and context creation etc.
The class comes with a nvgl::ProfilerGL instance that references the
AppWindowProfiler::m_profiler's data.
@DOC_END */
namespace nvgl {
#define NV_PROFILE_GL_SECTION(name) nvgl::ProfilerGL::Section _tempTimer(m_profilerGL, name)
#define NV_PROFILE_GL_SPLIT() m_profilerGL.accumulationSplit()
class AppWindowProfilerGL : public nvh::AppWindowProfiler
{
public:
AppWindowProfilerGL(bool singleThreaded = true)
: nvh::AppWindowProfiler(singleThreaded)
, m_profilerGL(&m_profiler)
{
m_contextInfo.robust = false;
m_contextInfo.core = false;
#ifdef NDEBUG
m_contextInfo.debug = false;
#else
m_contextInfo.debug = true;
#endif
m_contextInfo.share = NULL;
m_contextInfo.major = 4;
m_contextInfo.minor = 5;
}
nvgl::ContextWindowCreateInfo m_contextInfo;
ContextWindow m_contextWindow;
nvgl::ProfilerGL m_profilerGL;
int run(const std::string& name, int argc, const char** argv, int width, int height)
{
return AppWindowProfiler::run(name, argc, argv, width, height, true);
}
virtual void contextInit() override;
virtual void contextDeinit() override;
virtual void swapResize(int width, int height) override
{
m_windowState.m_swapSize[0] = width;
m_windowState.m_swapSize[1] = height;
}
virtual void swapPrepare() override {}
virtual void swapBuffers() override { m_contextWindow.swapBuffers(); }
virtual void swapVsync(bool state) override { m_contextWindow.swapInterval(state ? 1 : 0); }
virtual const char* contextGetDeviceName() override { return m_contextWindow.m_deviceName.c_str(); }
};
} // namespace nvgl
#endif

View file

@ -0,0 +1,288 @@
/*
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
/// @DOC_SKIP (keyword to exclude this file from automatic README.md generation)
#ifndef NV_BASEGL_H_INCLUDED
#define NV_BASEGL_H_INCLUDED
#include "extensions_gl.hpp"
#include <cstdio>
#define NV_BUFFER_OFFSET(i) ((char*)NULL + (i))
namespace nvgl {
/** @DOC_START
# struct nvgl::BufferBinding
Wraps buffer, offset, size, gpu address
@DOC_END */
struct BufferBinding
{
GLuint buffer = 0;
GLintptr offset = 0;
GLsizeiptr size = 0;
GLuint64 bufferADDR;
BufferBinding() {}
BufferBinding(GLuint inBuffer, GLintptr inOffset, GLsizeiptr inSize, GLuint64 inBufferADDR)
{
buffer = inBuffer;
size = inSize;
offset = inOffset;
bufferADDR = inBufferADDR + inOffset;
}
};
/** @DOC_START
# struct nvgl::TextureBuffer
A `GL_TEXTURE_BUFFER` that references the provided buffer.
Wraps texture and bindless texture handle.
@DOC_END */
struct TextureBuffer
{
GLuint tex = 0;
GLuint64 texADDR = 0;
void create(GLuint buffer, GLintptr offset, GLsizeiptr sz, GLenum format)
{
glCreateTextures(GL_TEXTURE_BUFFER, 1, &tex);
glTextureBufferRange(tex, format, buffer, offset, sz);
if(has_GL_ARB_bindless_texture)
{
texADDR = glGetTextureHandleARB(tex);
glMakeTextureHandleResidentARB(texADDR);
}
}
void destroy()
{
if(texADDR)
{
glMakeTextureHandleNonResidentARB(texADDR);
}
glDeleteTextures(1, &tex);
}
};
/** @DOC_START
# struct nvgl::Buffer
Wraps buffer as well as optionally creates a `GL_TEXTURE_BUFFER` if
a non-null `format` is provided. If bindless is available it will
also create bindless handles for all resources and make them resident.
If the `flags` contain `GL_MAP_PERSISTENT_BIT` it will also map
the buffer and keep the host pointer.
@DOC_END */
struct Buffer
{
GLuint buffer = 0;
GLuint tex = 0;
GLuint64 bufferADDR = 0;
GLuint64 texADDR = 0;
GLsizeiptr size = 0;
void* mapped = nullptr;
void create(GLsizeiptr sz, const void* data, GLuint flags, GLenum format)
{
size = sz;
glCreateBuffers(1, &buffer);
glNamedBufferStorage(buffer, sz, data, flags);
if(has_GL_NV_shader_buffer_load)
{
glGetNamedBufferParameterui64vNV(buffer, GL_BUFFER_GPU_ADDRESS_NV, &bufferADDR);
glMakeNamedBufferResidentNV(buffer, GL_READ_WRITE);
}
if(format)
{
glCreateTextures(GL_TEXTURE_BUFFER, 1, &tex);
glTextureBuffer(tex, format, buffer);
if(has_GL_ARB_bindless_texture)
{
texADDR = glGetTextureHandleARB(tex);
glMakeTextureHandleResidentARB(texADDR);
}
}
if(flags & GL_MAP_PERSISTENT_BIT)
{
mapped = glMapNamedBufferRange(buffer, 0, sz,
flags & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT));
}
}
void destroy()
{
if(mapped)
{
glUnmapNamedBuffer(buffer);
}
if(tex)
{
if(texADDR)
{
glMakeTextureHandleNonResidentARB(texADDR);
}
glDeleteTextures(1, &tex);
}
if(bufferADDR)
{
glMakeNamedBufferNonResidentNV(buffer);
}
glDeleteBuffers(1, &buffer);
}
operator GLuint() const { return buffer; }
};
inline size_t uboAligned(size_t size)
{
return ((size + 255) / 256) * 256;
}
inline void bindMultiTexture(GLenum target, GLenum textarget, GLuint tex)
{
glActiveTexture(target);
glBindTexture(textarget, tex);
}
/** @DOC_START
# nvgl resource functions
Functions that wrap glCreate/glDelete and operate on `GLuint& obj`.
The "new" functions delete the existing object if non-null and create a new one.
The "delete" functions delete non-null objects.
* newBuffer / deleteBuffer
* newTextureView
* newTexture / deleteTexture
* newFramebuffer / deleteFramebuffer
* newSampler / deleteSampler
* newQuery / deleteQuery
* newVertexArray / deleteVertexArray
```cpp
// typical use-case
FrameBuffer::resize(int with, int height){
newFramebuffer(m_fbo);
newTexture(m_color, GL_TEXTURE_2D);
newTexture(m_depthStencil, GL_TEXTURE_2D);
glTextureStorage2D(m_color, ...)
glTextureStorage2D(m_depthStencil, ...)
glNamedFramebufferTexture(m_fbo, GL_COLOR_ATTACHMENT0, m_color, 0);
glNamedFramebufferTexture(m_fbo, GL_DEPTH_STENCIL_ATTACHMENT, m_depthStencil, 0);
}
```
@DOC_END */
inline void newBuffer(GLuint& glid)
{
if(glid)
glDeleteBuffers(1, &glid);
glCreateBuffers(1, &glid);
}
inline void deleteBuffer(GLuint& glid)
{
if(glid)
glDeleteBuffers(1, &glid);
glid = 0;
}
inline void newTextureView(GLuint& glid)
{
if(glid)
glDeleteTextures(1, &glid);
glGenTextures(1, &glid);
}
inline void newTexture(GLuint& glid, GLenum target)
{
if(glid)
glDeleteTextures(1, &glid);
glCreateTextures(target, 1, &glid);
}
inline void deleteTexture(GLuint& glid)
{
if(glid)
glDeleteTextures(1, &glid);
glid = 0;
}
inline void newFramebuffer(GLuint& glid)
{
if(glid)
glDeleteFramebuffers(1, &glid);
glCreateFramebuffers(1, &glid);
}
inline void deleteFramebuffer(GLuint& glid)
{
if(glid)
glDeleteFramebuffers(1, &glid);
glid = 0;
}
inline void newSampler(GLuint& glid)
{
if(glid)
glDeleteSamplers(1, &glid);
glCreateSamplers(1, &glid);
}
inline void deleteSampler(GLuint& glid)
{
if(glid)
glDeleteSamplers(1, &glid);
glid = 0;
}
inline void newQuery(GLuint& glid, GLenum target)
{
if(glid)
glDeleteQueries(1, &glid);
glCreateQueries(target, 1, &glid);
}
inline void deleteQuery(GLuint& glid)
{
if(glid)
glDeleteQueries(1, &glid);
glid = 0;
}
inline void newVertexArray(GLuint& glid)
{
if(glid)
glCreateVertexArrays(1, &glid);
glGenVertexArrays(1, &glid);
}
inline void deleteVertexArray(GLuint& glid)
{
if(glid)
glDeleteVertexArrays(1, &glid);
glid = 0;
}
} // namespace nvgl
#endif

View file

@ -0,0 +1,682 @@
/*
* Copyright (c) 2013-2021, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2013-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
//--------------------------------------------------------------------
#include <nvgl/contextwindow_gl.hpp>
#include <nvgl/error_gl.hpp>
#include <nvgl/extensions_gl.hpp>
#ifdef WIN32
#define GLFW_EXPOSE_NATIVE_WIN32
#include <GLFW/glfw3native.h>
#include <GL/wgl.h>
#include "resources.h"
#include <windows.h>
#include <windowsx.h>
#elif defined LINUX
#define GLFW_EXPOSE_NATIVE_GLX
#define GLFW_EXPOSE_NATIVE_X11
#include <GL/glx.h>
#include <GLFW/glfw3native.h>
#endif
#include <fileformats/bmp.hpp>
#include <nvh/nvprint.hpp>
#include <algorithm>
#include <fcntl.h>
#include <fstream>
#include <iostream>
#include <stdio.h>
#include <string>
#include <vector>
namespace nvgl {
//------------------------------------------------------------------------------
// OGL callback
//------------------------------------------------------------------------------
#ifndef NDEBUG
static void APIENTRY myOpenGLCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const GLvoid* userParam)
{
ContextWindow* window = (ContextWindow*)userParam;
GLenum filter = window->m_debugFilter;
GLenum severitycmp = severity;
// minor fixup for filtering so notification becomes lowest priority
if(GL_DEBUG_SEVERITY_NOTIFICATION == filter)
{
filter = GL_DEBUG_SEVERITY_LOW_ARB + 1;
}
if(GL_DEBUG_SEVERITY_NOTIFICATION == severitycmp)
{
severitycmp = GL_DEBUG_SEVERITY_LOW_ARB + 1;
}
if(!filter || severitycmp <= filter)
{
//static std::map<GLuint, bool> ignoreMap;
//if(ignoreMap[id] == true)
// return;
const char* strSource = "0";
const char* strType = strSource;
switch(source)
{
case GL_DEBUG_SOURCE_API_ARB:
strSource = "API";
break;
case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB:
strSource = "WINDOWS";
break;
case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB:
strSource = "SHADER COMP.";
break;
case GL_DEBUG_SOURCE_THIRD_PARTY_ARB:
strSource = "3RD PARTY";
break;
case GL_DEBUG_SOURCE_APPLICATION_ARB:
strSource = "APP";
break;
case GL_DEBUG_SOURCE_OTHER_ARB:
strSource = "OTHER";
break;
}
switch(type)
{
case GL_DEBUG_TYPE_ERROR_ARB:
strType = "ERROR";
break;
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB:
strType = "Deprecated";
break;
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB:
strType = "Undefined";
break;
case GL_DEBUG_TYPE_PORTABILITY_ARB:
strType = "Portability";
break;
case GL_DEBUG_TYPE_PERFORMANCE_ARB:
strType = "Performance";
break;
case GL_DEBUG_TYPE_OTHER_ARB:
strType = "Other";
break;
}
switch(severity)
{
case GL_DEBUG_SEVERITY_HIGH_ARB:
LOGE("ARB_debug : %s High - %s - %s : %s\n", window->m_debugTitle.c_str(), strSource, strType, message);
break;
case GL_DEBUG_SEVERITY_MEDIUM_ARB:
LOGW("ARB_debug : %s Medium - %s - %s : %s\n", window->m_debugTitle.c_str(), strSource, strType, message);
break;
case GL_DEBUG_SEVERITY_LOW_ARB:
LOGI("ARB_debug : %s Low - %s - %s : %s\n", window->m_debugTitle.c_str(), strSource, strType, message);
break;
default:
//LOGI("ARB_debug : comment - %s - %s : %s\n", strSource, strType, message);
break;
}
}
}
#endif
// from GLFW 3.0
static int stringInExtensionString(const char* string, const char* exts)
{
const GLubyte* extensions = (const GLubyte*)exts;
const GLubyte* start;
GLubyte* where;
GLubyte* terminator;
// It takes a bit of care to be fool-proof about parsing the
// OpenGL extensions string. Don't be fooled by sub-strings,
// etc.
start = extensions;
for(;;)
{
where = (GLubyte*)strstr((const char*)start, string);
if(!where)
return GL_FALSE;
terminator = where + strlen(string);
if(where == start || *(where - 1) == ' ')
{
if(*terminator == ' ' || *terminator == '\0')
break;
}
start = terminator;
}
return GL_TRUE;
}
#ifdef WIN32
//////////////////////////////////////////////////////////////////////////
// WIN 32
static HMODULE s_module = NULL;
struct ContextWindowInternalGL
{
HDC m_hDCaffinity = NULL;
HDC m_hDC = NULL;
HGLRC m_hRC = NULL;
PFNWGLSWAPINTERVALEXTPROC m_wglSwapIntervalEXT = NULL;
PFNWGLGETEXTENSIONSSTRINGARBPROC m_wglGetExtensionsStringARB = NULL;
PFNWGLDELETEDCNVPROC m_wglDeleteDCNV = NULL;
bool init(const ContextWindowCreateInfo& settings, GLFWwindow* sourcewindow, ContextWindow* ctxwindow)
{
GLuint PixelFormat;
HWND hWnd = glfwGetWin32Window(sourcewindow);
HINSTANCE hInstance = GetModuleHandle(NULL);
PIXELFORMATDESCRIPTOR pfd;
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cDepthBits = settings.depth;
pfd.cStencilBits = settings.stencil;
if(settings.stereo)
{
pfd.dwFlags |= PFD_STEREO;
}
if(settings.MSAA > 1)
{
HWND hWndDummy = CreateWindowEx(NULL, "Static", "Dummy", WS_OVERLAPPEDWINDOW, 0, 0, 10, 10, NULL, NULL, hInstance, NULL);
m_hDC = GetDC(hWndDummy);
PixelFormat = ChoosePixelFormat(m_hDC, &pfd);
SetPixelFormat(m_hDC, PixelFormat, &pfd);
m_hRC = wglCreateContext(m_hDC);
wglMakeCurrent(m_hDC, m_hRC);
PFNWGLCHOOSEPIXELFORMATARBPROC fn_wglChoosePixelFormatARB =
(PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
ReleaseDC(hWndDummy, m_hDC);
m_hDC = GetDC(hWnd);
int attri[] = {WGL_DRAW_TO_WINDOW_ARB,
true,
WGL_PIXEL_TYPE_ARB,
WGL_TYPE_RGBA_ARB,
WGL_SUPPORT_OPENGL_ARB,
true,
WGL_ACCELERATION_ARB,
WGL_FULL_ACCELERATION_ARB,
WGL_DOUBLE_BUFFER_ARB,
true,
WGL_DEPTH_BITS_ARB,
settings.depth,
WGL_STENCIL_BITS_ARB,
settings.stencil,
WGL_SAMPLE_BUFFERS_ARB,
1,
WGL_SAMPLES_ARB,
settings.MSAA,
0,
0};
GLuint nfmts;
int fmt;
if(!fn_wglChoosePixelFormatARB(m_hDC, attri, NULL, 1, &fmt, &nfmts))
{
wglDeleteContext(m_hRC);
return false;
}
wglDeleteContext(m_hRC);
DestroyWindow(hWndDummy);
if(!SetPixelFormat(m_hDC, fmt, &pfd))
return false;
}
else
{
m_hDC = GetDC(hWnd);
PixelFormat = ChoosePixelFormat(m_hDC, &pfd);
SetPixelFormat(m_hDC, PixelFormat, &pfd);
}
m_hRC = wglCreateContext(m_hDC);
wglMakeCurrent(m_hDC, m_hRC);
HDC hdcContext = m_hDC;
if(settings.device)
{
PFNWGLENUMGPUSNVPROC fn_wglEnumGpusNV = (PFNWGLENUMGPUSNVPROC)wglGetProcAddress("wglEnumGpusNV");
PFNWGLENUMGPUDEVICESNVPROC fn_wglEnumGpuDevicesNV =
(PFNWGLENUMGPUDEVICESNVPROC)wglGetProcAddress("wglEnumGpuDevicesNV");
PFNWGLCREATEAFFINITYDCNVPROC fn_wglCreateAffinityDCNV =
(PFNWGLCREATEAFFINITYDCNVPROC)wglGetProcAddress("wglCreateAffinityDCNV");
m_wglDeleteDCNV = (PFNWGLDELETEDCNVPROC)wglGetProcAddress("wglDeleteDCNV");
if(fn_wglEnumGpusNV && fn_wglCreateAffinityDCNV && m_wglDeleteDCNV)
{
const uint32_t MAX_GPU = 4;
HGPUNV hGPU[MAX_GPU];
_GPU_DEVICE devices[MAX_GPU];
HGPUNV GpuMask[2] = {0};
uint32_t gpuIndex = 0;
// Get a list of the first MAX_GPU GPUs in the system
while((gpuIndex < MAX_GPU) && fn_wglEnumGpusNV(gpuIndex, &hGPU[gpuIndex]))
{
fn_wglEnumGpuDevicesNV(hGPU[gpuIndex], 0, &devices[gpuIndex]);
gpuIndex++;
}
GpuMask[0] = hGPU[settings.device];
// delete old
wglMakeCurrent(NULL, NULL);
wglDeleteContext(m_hRC);
m_hDCaffinity = fn_wglCreateAffinityDCNV(GpuMask);
hdcContext = m_hDCaffinity;
PixelFormat = ChoosePixelFormat(m_hDCaffinity, &pfd);
SetPixelFormat(m_hDCaffinity, PixelFormat, &pfd);
m_hRC = wglCreateContext(m_hDCaffinity);
wglMakeCurrent(m_hDC, m_hRC);
}
}
PFNWGLCREATECONTEXTATTRIBSARBPROC fn_wglCreateContextAttribsARB =
(PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB");
if(fn_wglCreateContextAttribsARB)
{
HGLRC hRC = NULL;
std::vector<int> attribList;
#define ADDATTRIB(a, b) \
{ \
attribList.push_back(a); \
attribList.push_back(b); \
}
int maj = settings.major;
int min = settings.minor;
ADDATTRIB(WGL_CONTEXT_MAJOR_VERSION_ARB, maj)
ADDATTRIB(WGL_CONTEXT_MINOR_VERSION_ARB, min)
if(settings.core)
ADDATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB)
else
ADDATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB)
int ctxtflags = 0;
if(settings.debug)
ctxtflags |= WGL_CONTEXT_DEBUG_BIT_ARB;
if(settings.robust)
ctxtflags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB;
if(settings.forward) // use it if you want errors when compat options still used
ctxtflags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
ADDATTRIB(WGL_CONTEXT_FLAGS_ARB, ctxtflags);
ADDATTRIB(0, 0)
int* p = &(attribList[0]);
if(!(hRC = fn_wglCreateContextAttribsARB(hdcContext, 0, p)))
{
GLint MajorVersionContext = 0;
GLint MinorVersionContext = 0;
glGetIntegerv(GL_MAJOR_VERSION, &MajorVersionContext);
glGetIntegerv(GL_MINOR_VERSION, &MinorVersionContext);
if((MajorVersionContext * 100 + MinorVersionContext * 10) < (maj * 100 + min * 10))
{
LOGE("OpenGL version %d.%d not available. Only %d.%d found\n", maj, min, MajorVersionContext, MinorVersionContext);
}
LOGE("wglCreateContextAttribsARB() failed for OpenGL context.\n");
return false;
}
if(!wglMakeCurrent(m_hDC, hRC))
{
LOGE("wglMakeCurrent() failed for OpenGL context.\n");
}
else
{
wglDeleteContext(m_hRC);
m_hRC = hRC;
#ifndef NDEBUG
PFNGLDEBUGMESSAGECALLBACKARBPROC fn_glDebugMessageCallbackARB =
(PFNGLDEBUGMESSAGECALLBACKARBPROC)wglGetProcAddress("glDebugMessageCallbackARB");
PFNGLDEBUGMESSAGECONTROLARBPROC fn_glDebugMessageControlARB =
(PFNGLDEBUGMESSAGECONTROLARBPROC)wglGetProcAddress("glDebugMessageControlARB");
if(fn_glDebugMessageCallbackARB)
{
glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
fn_glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
fn_glDebugMessageCallbackARB(myOpenGLCallback, ctxwindow);
}
#endif
}
}
m_wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
m_wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB");
if(!s_module)
{
s_module = LoadLibraryA("opengl32.dll");
}
return true;
}
void deinit()
{
wglDeleteContext(m_hRC);
if(m_hDCaffinity)
{
m_wglDeleteDCNV(m_hDCaffinity);
}
}
};
void ContextWindow::makeContextCurrent()
{
wglMakeCurrent(m_internal->m_hDC, m_internal->m_hRC);
}
void ContextWindow::makeContextNonCurrent()
{
wglMakeCurrent(0, 0);
}
int ContextWindow::extensionSupported(const char* name)
{
// we are not using the glew query, as glew will only report
// those extension it knows about, not what the actual driver may support
int i;
GLint count;
// Check if extension is in the modern OpenGL extensions string list
// This should be safe to use since GL 3.0 is around for a long time :)
glGetIntegerv(GL_NUM_EXTENSIONS, &count);
for(i = 0; i < count; i++)
{
const char* en = (const char*)glGetStringi(GL_EXTENSIONS, i);
if(!en)
{
return GL_FALSE;
}
if(strcmp(en, name) == 0)
return GL_TRUE;
}
// Check platform specifc gets
const char* exts = NULL;
if(m_internal->m_wglGetExtensionsStringARB)
{
exts = m_internal->m_wglGetExtensionsStringARB(m_internal->m_hDC);
}
if(!exts)
{
return FALSE;
}
return stringInExtensionString(name, exts);
}
void* ContextWindow::sysGetProcAddress(const char* name)
{
void* p = (void*)wglGetProcAddress(name);
if(p == 0 || (p == (void*)0x1) || (p == (void*)0x2) || (p == (void*)0x3) || (p == (void*)-1))
{
p = (void*)GetProcAddress(s_module, name);
}
return p;
}
void ContextWindow::swapInterval(int i)
{
m_internal->m_wglSwapIntervalEXT(i);
}
void ContextWindow::swapBuffers()
{
SwapBuffers(m_internal->m_hDC);
}
#else
struct ContextWindowInternalGL
{
GLFWwindow* m_glfwwindow = nullptr;
bool init(const ContextWindowCreateInfo& settings, GLFWwindow* sourcewindow, ContextWindow* ctxwindow)
{
m_glfwwindow = sourcewindow;
glfwMakeContextCurrent(m_glfwwindow);
#ifndef NDEBUG
PFNGLDEBUGMESSAGECALLBACKARBPROC fn_glDebugMessageCallbackARB =
(PFNGLDEBUGMESSAGECALLBACKARBPROC)glfwGetProcAddress("glDebugMessageCallbackARB");
PFNGLDEBUGMESSAGECONTROLARBPROC fn_glDebugMessageControlARB =
(PFNGLDEBUGMESSAGECONTROLARBPROC)glfwGetProcAddress("glDebugMessageControlARB");
if(fn_glDebugMessageCallbackARB)
{
glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
fn_glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
fn_glDebugMessageCallbackARB(myOpenGLCallback, ctxwindow);
}
#endif
return true;
}
void deinit() {}
};
void ContextWindow::makeContextCurrent()
{
glfwMakeContextCurrent(m_internal->m_glfwwindow);
}
void ContextWindow::makeContextNonCurrent()
{
glfwMakeContextCurrent(NULL);
}
int ContextWindow::extensionSupported(const char* name)
{
// we are not using the glew query, as glew will only report
// those extension it knows about, not what the actual driver may support
int i;
GLint count;
// Check if extension is in the modern OpenGL extensions string list
// This should be safe to use since GL 3.0 is around for a long time :)
glGetIntegerv(GL_NUM_EXTENSIONS, &count);
for(i = 0; i < count; i++)
{
const char* en = (const char*)glGetStringi(GL_EXTENSIONS, i);
if(!en)
{
return GL_FALSE;
}
if(strcmp(en, name) == 0)
return GL_TRUE;
}
// Check platform specifc gets
const char* exts = glXQueryExtensionsString(glfwGetX11Display(), 0);
if(!exts)
{
return GL_FALSE;
}
return stringInExtensionString(name, exts);
}
void* ContextWindow::sysGetProcAddress(const char* name)
{
void* p = (void*)glfwGetProcAddress(name);
return p;
}
void ContextWindow::swapInterval(int i)
{
glfwSwapInterval(i);
}
void ContextWindow::swapBuffers()
{
glfwSwapBuffers(m_internal->m_glfwwindow);
}
#endif
//////////////////////////////////////////////////////////////////////////
ContextWindow::ContextWindow()
{
if(m_internal)
{
delete m_internal;
}
}
//------------------------------------------------------------------------------
bool ContextWindow::init(const ContextWindowCreateInfo* cflags, GLFWwindow* sourcewindow, const char* dbgTitle)
{
if(!m_internal)
{
m_internal = new ContextWindowInternalGL;
}
ContextWindowCreateInfo settings;
if(cflags)
{
settings = *cflags;
}
m_debugFilter = GL_DEBUG_SEVERITY_HIGH_ARB;
m_debugTitle = dbgTitle;
if(m_internal->init(settings, sourcewindow, this))
{
load_GL(ContextWindow::sysGetProcAddress);
const char* renderer = (const char*)glGetString(GL_RENDERER);
GLint major = 0;
glGetIntegerv(GL_MAJOR_VERSION, &major);
GLint minor = 0;
glGetIntegerv(GL_MINOR_VERSION, &minor);
if(major < settings.major || (major == settings.major && minor < settings.minor))
{
LOGE(" OpenGL context version too low: required %d.%d, found %d.%d\n", settings.major, settings.minor, major, minor);
return false;
}
int version = major * 10 + minor;
int success = 1;
#define HAS_VERSION(MA, MI) \
if(version >= (MA * 10 + MI)) \
success = success && has_GL_VERSION_##MA##_##MI;
HAS_VERSION(1, 1);
HAS_VERSION(1, 2);
HAS_VERSION(1, 3);
HAS_VERSION(1, 4);
HAS_VERSION(1, 5);
HAS_VERSION(2, 0);
HAS_VERSION(2, 1);
HAS_VERSION(3, 0);
HAS_VERSION(3, 1);
HAS_VERSION(3, 2);
HAS_VERSION(3, 3);
HAS_VERSION(4, 0);
HAS_VERSION(4, 1);
HAS_VERSION(4, 2);
HAS_VERSION(4, 3);
HAS_VERSION(4, 4);
HAS_VERSION(4, 5);
HAS_VERSION(4, 6);
#undef HAS_VERSION
if(!success)
{
LOGE(" OpenGL context version incomplete symbols\n");
return false;
}
m_deviceName = std::string(renderer);
return true;
}
return false;
}
void* ContextWindow::getProcAddress(const char* name)
{
return sysGetProcAddress(name);
}
void ContextWindow::screenshot(const char* filename, int x, int y, int width, int height, unsigned char* data)
{
glFinish();
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
glReadPixels(x, y, width, height, GL_BGRA, GL_UNSIGNED_BYTE, data);
if(filename)
{
saveBMP(filename, width, height, data);
}
}
void ContextWindow::deinit()
{
makeContextNonCurrent();
m_internal->deinit();
}
} // namespace nvgl

View file

@ -0,0 +1,120 @@
/*
* Copyright (c) 2013-2021, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2013-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
//--------------------------------------------------------------------
#pragma once
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#include <stdint.h>
#include <string>
namespace nvgl {
/** @DOC_START
# struct nvgl::ContextWindowCreateInfo
Set up the context properties for a OpenGL ContextWindow.
e.g. version, core/compatibiltiy etc.
@DOC_END */
struct ContextWindowCreateInfo
{
int major;
int minor;
int device;
int MSAA;
int depth;
int stencil;
bool debug;
bool robust;
bool core;
bool forward;
bool stereo;
class ContextWindow* share;
ContextWindowCreateInfo(int _major = 4,
int _minor = 3,
bool _core = false,
int _MSAA = 0,
int _depth = 24,
int _stencil = 8,
bool _debug = false,
bool _robust = false,
bool _forward = false,
bool _stereo = false,
class ContextWindow* _share = 0)
{
major = _major;
minor = _minor;
MSAA = _MSAA;
depth = _depth;
stencil = _stencil;
core = _core;
debug = _debug;
robust = _robust;
forward = _forward;
stereo = _stereo;
share = _share;
device = 0;
}
};
/** @DOC_START
# class nvgl::ContextWindow
nvgl::ContextWindow sets up an OpenGL context from a provided `GLFWwindow`.
Makes use of `glDebugMessageCallback` to hook up an error callback
and loads all extensions provided by `extensions_gl.hpp`
@DOC_END */
class ContextWindow
{
public:
struct ContextWindowInternalGL* m_internal = nullptr;
uint32_t m_debugFilter = 0;
std::string m_debugTitle;
std::string m_deviceName;
ContextWindow(ContextWindow const&) = delete;
ContextWindow& operator=(ContextWindow const&) = delete;
ContextWindow();
bool init(const ContextWindowCreateInfo* cflags, GLFWwindow* window, const char* dbgTitle = "test");
void deinit();
void swapInterval(int i);
void swapBuffers();
int extensionSupported(const char* name);
void* getProcAddress(const char* name);
void makeContextCurrent();
void makeContextNonCurrent();
void screenshot(const char* filename, int x, int y, int width, int height, unsigned char* data);
// TODO: check if this is really necessary : local method getProcAddressGL could be enough
static void* sysGetProcAddress(const char* name);
};
} // namespace nvgl

View file

@ -0,0 +1,399 @@
/*
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#include "error_gl.hpp"
#include <algorithm>
namespace nvgl {
bool checkNamedFramebuffer(GLuint fbo)
{
GLenum status = glCheckNamedFramebufferStatus(fbo, GL_FRAMEBUFFER);
switch(status)
{
case GL_FRAMEBUFFER_UNDEFINED:
LOGE("OpenGL Error(%s)\n", "GL_FRAMEBUFFER_UNDEFINED");
break;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
LOGE("OpenGL Error(%s)\n", "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
LOGE("OpenGL Error(%s)\n", "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
LOGE("OpenGL Error(%s)\n", "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER");
break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
LOGE("OpenGL Error(%s)\n", "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER");
break;
case GL_FRAMEBUFFER_UNSUPPORTED:
LOGE("OpenGL Error(%s)\n", "GL_FRAMEBUFFER_UNSUPPORTED");
break;
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
LOGE("OpenGL Error(%s)\n", "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE");
break;
case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS:
LOGE("OpenGL Error(%s)\n", "GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS");
break;
}
return status != GL_FRAMEBUFFER_COMPLETE;
}
bool checkGLVersion(GLint MajorVersionRequire, GLint MinorVersionRequire)
{
GLint MajorVersionContext = 0;
GLint MinorVersionContext = 0;
glGetIntegerv(GL_MAJOR_VERSION, &MajorVersionContext);
glGetIntegerv(GL_MINOR_VERSION, &MinorVersionContext);
return (MajorVersionContext * 100 + MinorVersionContext * 10) >= (MajorVersionRequire * 100 + MinorVersionRequire * 10);
}
bool checkExtension(char const* String)
{
GLint ExtensionCount = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &ExtensionCount);
for(GLint i = 0; i < ExtensionCount; ++i)
if(std::string((char const*)glGetStringi(GL_EXTENSIONS, i)) == std::string(String))
return true;
return false;
}
bool checkError(const char* Title)
{
int Error;
if((Error = glGetError()) != GL_NO_ERROR)
{
std::string ErrorString;
switch(Error)
{
case GL_INVALID_ENUM:
ErrorString = "GL_INVALID_ENUM";
break;
case GL_INVALID_VALUE:
ErrorString = "GL_INVALID_VALUE";
break;
case GL_INVALID_OPERATION:
ErrorString = "GL_INVALID_OPERATION";
break;
case GL_INVALID_FRAMEBUFFER_OPERATION:
ErrorString = "GL_INVALID_FRAMEBUFFER_OPERATION";
break;
case GL_OUT_OF_MEMORY:
ErrorString = "GL_OUT_OF_MEMORY";
break;
default:
ErrorString = "UNKNOWN";
break;
}
LOGE("OpenGL Error(%s): %s\n", ErrorString.c_str(), Title);
}
return Error == GL_NO_ERROR;
}
bool checkBindings(int bindingBits, const char* marker, int num)
{
bool bound = false;
GLint obj = 0;
#define GLERRCHECKBOUND(name, obj) \
glGetIntegerv(name, (obj)); \
if(*(obj)) \
{ \
bound = true; \
LOGW("OpenGL bound: %s\n", #name); \
}
#define GLERRCHECKBOUNDFN(fn, what, obj) \
fn; \
if(*(obj)) \
{ \
bound = true; \
LOGW("OpenGL bound: %s\n", what); \
}
#define GLERRCHECKBOUNDUNIT(i, name, obj) \
glGetIntegerv(name, (obj)); \
if(*(obj)) \
{ \
bound = true; \
LOGW("OpenGL bound: %s %d\n", #name, i); \
}
#define GLERRCHECKBOUNDINDEXED(name, i, obj) \
glGetIntegeri_v(name, i, (obj)); \
if(*(obj)) \
{ \
bound = true; \
LOGW("OpenGL bound: %s %d\n", #name, i); \
}
if(bindingBits & CHECKBINDING_VAO_BIT)
{
GLERRCHECKBOUND(GL_VERTEX_ARRAY_BINDING, &obj);
}
if(bindingBits & CHECKBINDING_FBO_BIT)
{
GLERRCHECKBOUND(GL_DRAW_FRAMEBUFFER_BINDING, &obj);
GLERRCHECKBOUND(GL_READ_FRAMEBUFFER_BINDING, &obj);
}
if(bindingBits & CHECKBINDING_PROGRAM_BIT)
{
GLERRCHECKBOUND(GL_CURRENT_PROGRAM, &obj);
GLERRCHECKBOUND(GL_PROGRAM_PIPELINE_BINDING, &obj);
}
if(bindingBits & CHECKBINDING_IMAGES_BIT)
{
GLint units;
glGetIntegerv(GL_MAX_IMAGE_UNITS, &units);
for(int i = 0; i < units; i++)
{
GLERRCHECKBOUNDINDEXED(GL_IMAGE_BINDING_NAME, i, &obj);
}
}
if(bindingBits & CHECKBINDING_BUFFERS_BIT)
{
GLERRCHECKBOUND(GL_ARRAY_BUFFER_BINDING, &obj);
GLERRCHECKBOUND(GL_ELEMENT_ARRAY_BUFFER_BINDING, &obj);
GLERRCHECKBOUND(GL_PIXEL_PACK_BUFFER_BINDING, &obj);
GLERRCHECKBOUND(GL_PIXEL_UNPACK_BUFFER_BINDING, &obj);
GLERRCHECKBOUND(GL_UNIFORM_BUFFER_BINDING, &obj);
GLERRCHECKBOUND(GL_TRANSFORM_FEEDBACK_BINDING, &obj);
GLERRCHECKBOUND(GL_SHADER_STORAGE_BUFFER_BINDING, &obj);
GLERRCHECKBOUND(GL_ATOMIC_COUNTER_BUFFER_BINDING, &obj);
GLERRCHECKBOUND(GL_TEXTURE_BUFFER_BINDING, &obj);
GLERRCHECKBOUND(GL_COPY_READ_BUFFER_BINDING, &obj);
GLERRCHECKBOUND(GL_COPY_WRITE_BUFFER_BINDING, &obj);
GLint units;
glGetIntegerv(GL_MAX_VERTEX_ATTRIB_BINDINGS, &units);
for(int i = 0; i < units; i++)
{
GLERRCHECKBOUNDINDEXED(GL_VERTEX_BINDING_BUFFER, i, &obj);
}
glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &units);
for(int i = 0; i < units; i++)
{
GLERRCHECKBOUNDINDEXED(GL_UNIFORM_BUFFER_BINDING, i, &obj);
}
glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_BUFFERS, &units);
for(int i = 0; i < units; i++)
{
GLERRCHECKBOUNDINDEXED(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, i, &obj);
}
glGetIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, &units);
for(int i = 0; i < units; i++)
{
GLERRCHECKBOUNDINDEXED(GL_SHADER_STORAGE_BUFFER_BINDING, i, &obj);
}
glGetIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, &units);
for(int i = 0; i < units; i++)
{
GLERRCHECKBOUNDINDEXED(GL_ATOMIC_COUNTER_BUFFER_BINDING, i, &obj);
}
}
if(bindingBits & (CHECKBINDING_TEXTURES_BIT | CHECKBINDING_SAMPLERS_BIT))
{
GLint currentUnit;
GLint units;
glGetIntegerv(GL_ACTIVE_TEXTURE, &currentUnit);
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &units);
for(int i = 0; i < units; i++)
{
glActiveTexture(GL_TEXTURE0 + i);
if(bindingBits & CHECKBINDING_TEXTURES_BIT)
{
GLERRCHECKBOUNDUNIT(i, GL_TEXTURE_BINDING_1D, &obj);
GLERRCHECKBOUNDUNIT(i, GL_TEXTURE_BINDING_2D, &obj);
GLERRCHECKBOUNDUNIT(i, GL_TEXTURE_BINDING_3D, &obj);
GLERRCHECKBOUNDUNIT(i, GL_TEXTURE_BINDING_1D_ARRAY, &obj);
GLERRCHECKBOUNDUNIT(i, GL_TEXTURE_BINDING_2D_ARRAY, &obj);
GLERRCHECKBOUNDUNIT(i, GL_TEXTURE_BINDING_CUBE_MAP, &obj);
GLERRCHECKBOUNDUNIT(i, GL_TEXTURE_BINDING_CUBE_MAP_ARRAY, &obj);
GLERRCHECKBOUNDUNIT(i, GL_TEXTURE_BINDING_2D_MULTISAMPLE, &obj);
GLERRCHECKBOUNDUNIT(i, GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY, &obj);
GLERRCHECKBOUNDUNIT(i, GL_TEXTURE_BINDING_CUBE_MAP, &obj);
GLERRCHECKBOUNDUNIT(i, GL_TEXTURE_BINDING_CUBE_MAP_ARRAY, &obj);
GLERRCHECKBOUNDUNIT(i, GL_TEXTURE_BINDING_BUFFER, &obj);
GLERRCHECKBOUNDUNIT(i, GL_TEXTURE_BINDING_RECTANGLE, &obj);
}
if(bindingBits & CHECKBINDING_SAMPLERS_BIT)
{
GLERRCHECKBOUND(GL_SAMPLER_BINDING, &obj);
}
}
glActiveTexture(currentUnit);
}
if(bindingBits & CHECKBINDING_XFB_BIT)
{
GLERRCHECKBOUND(GL_TRANSFORM_FEEDBACK_BINDING, &obj);
}
if(bindingBits & CHECKBINDING_VATTRIBS_BIT)
{
GLint units;
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &units);
GLint enabled;
for(int i = 0; i < units; i++)
{
glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &enabled);
if(enabled)
{
bound = true;
LOGW("OpenGL enabled: vertex %d\n", i);
}
}
}
if(bound)
{
if(marker)
{
LOGW("%s %d\n\n", marker, num);
}
else
{
LOGW("\n");
}
}
#undef GLERRCHECKBOUNDUNIT
#undef GLERRCHECKBOUND
#undef GLERRCHECKBOUNDINDEXED
#undef GLERRCHECKBOUNDFN
return !bound;
}
bool checkTextureTarget(GLuint texture, GLenum target)
{
GLenum param;
glGetTextureParameterIiv(texture, GL_TEXTURE_TARGET, (GLint*)&param);
return param == target;
}
bool checkTextureTarget(GLuint texture, GLenum target, const char* name, const char* marker, int num)
{
if(!checkTextureTarget(texture, target))
{
if(marker)
{
LOGW("OpenGL unexpected texture target (%s)\n - %s %d\n", name, marker, num);
}
else
{
LOGW("OpenGL unexpected texture target (%s)\n", name);
}
return false;
}
return true;
}
//////////////////////////////////////////////////////////////////////////
void CheckBufferResidency::addAddress(uint64_t address, uint64_t size)
{
Entry entry;
entry.address = address;
entry.size = size;
m_entries.push_back(entry);
m_dirty = true;
}
void CheckBufferResidency::removeAddress(uint64_t address)
{
size_t idx = find(address);
m_entries[idx] = m_entries[m_entries.size() - 1];
m_entries.pop_back();
m_dirty = true;
}
bool CheckBufferResidency::checkAddress(uint64_t address)
{
size_t idx = find(address);
return (idx != ~0);
}
size_t CheckBufferResidency::find(uint64_t address)
{
if(m_entries.empty())
return ~0;
if(m_dirty)
{
sort();
}
size_t count = m_entries.size();
size_t begin = 0;
while(count > 0)
{
size_t idx = begin;
size_t step = count / 2;
idx += step;
if(m_entries[idx].address < address)
{
begin = idx + 1;
count -= step + 1;
}
else
{
count = step;
}
}
if(begin == m_entries.size() || m_entries[begin].address != address)
{
begin = std::max(begin - 1, size_t(0));
}
if(m_entries[begin].address <= address && address < m_entries[begin].address + m_entries[begin].size)
{
return begin;
}
else
{
return ~0;
}
}
void CheckBufferResidency::sort()
{
std::sort(m_entries.begin(), m_entries.end(), Entry_compare);
m_dirty = false;
}
} // namespace nvgl

View file

@ -0,0 +1,136 @@
/*
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef NVGL_ERROR_INCLUDED
#define NVGL_ERROR_INCLUDED
#include <include_gl.h>
#include <string>
#include <vector>
#include <nvh/nvprint.hpp>
/** @DOC_START
# functions in nvgl
Several utility functions that aid debugging. Check if all bindings
are cleared, framebuffer complete etc.
@DOC_END */
namespace nvgl {
// tests if version is available
bool checkGLVersion(GLint MajorVersionRequire, GLint MinorVersionRequire);
// tests if extension string is available
bool checkExtension(char const* String);
// tests against any gl error
bool checkError(const char* Title);
// tests for framebuffer incompleteness, also prints errors
bool checkNamedFramebuffer(GLuint fbo);
enum CheckBindingBits
{
CHECKBINDING_VAO_BIT = 1 << 0,
CHECKBINDING_FBO_BIT = 1 << 1,
CHECKBINDING_PROGRAM_BIT = 1 << 2,
CHECKBINDING_TEXTURES_BIT = 1 << 3,
CHECKBINDING_SAMPLERS_BIT = 1 << 4,
CHECKBINDING_BUFFERS_BIT = 1 << 5,
CHECKBINDING_IMAGES_BIT = 1 << 6,
CHECKBINDING_XFB_BIT = 1 << 7,
CHECKBINDING_VATTRIBS_BIT = 1 << 8,
CHECKBINDING_ALL_BITS = ~0,
};
#ifndef NDEBUG
#define DBG_CHECKBINDINGS(bindingBits) nvgl::checkBindings(bindingBits, __FILE__, __LINE__);
#else
#define DBG_CHECKBINDINGS(bindingBits)
#endif
// tests if the bindings specified by the bits are set to 0
bool checkBindings(int bindingBits, const char* marker = NULL, int num = 0);
// tests if the texture has the expected target
bool checkTextureTarget(GLuint texture, GLenum target);
bool checkTextureTarget(GLuint texture, GLenum target, const char* name, const char* marker = NULL, int num = 0);
/** @DOC_START
# template class nvgl::CheckBufferContent
Utility wrapper to downlad buffer data into a temp vector for debugging
@DOC_END */
template <class T>
class CheckBufferContent
{
public:
std::vector<T> content;
CheckBufferContent(GLuint buffer, size_t offset, size_t size)
{
size_t elements = size / sizeof(T);
content.resize(elements);
glGetNamedBufferSubData(buffer, offset, elements * sizeof(T), content.data());
elements = elements;
}
};
/** @DOC_START
# class nvgl::CheckBufferResidency
nvgl::CheckBufferResidency utility class to test if a certain gpu address is coming from
a resident buffer. Register the address of buffers in advance.
@DOC_END */
class CheckBufferResidency
{
public:
void addAddress(uint64_t address, uint64_t size);
void removeAddress(uint64_t address);
bool checkAddress(uint64_t address);
size_t getEntryNum() const { return m_entries.size(); }
private:
struct Entry
{
uint64_t address = 0;
uint64_t size = 0;
Entry() {}
Entry(uint64_t address, uint64_t size = 0)
: address(address)
, size(size)
{
}
};
size_t find(uint64_t address);
static bool Entry_compare(const Entry& a, const Entry& b) { return a.address < b.address; }
void sort();
bool m_dirty;
std::vector<Entry> m_entries;
};
} // namespace nvgl
#endif //NV_ERROR_INCLUDED

View file

@ -0,0 +1,2 @@
..\..\nvpro_internal\luajit\win_x64\luajit.exe extensions_gl.lua
pause

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,312 @@
/* auto generated by extensions_gl.lua */
/*
* Copyright (c) 2018-2021, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2018-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
/** @DOC_START
# function load_GL
> An OpenGL Extension loader
Provides a subset of OpenGL Extensions generated by `extensions_gl.lua`.
The framework uses a sanitized OpenGL header that is mostly core functionality.
`GL/glsubset.h` is generated using a enablelist by the lua script
from `GL/glcustom.h` (which is mostly based on `glcorearb.h` with some
additional extensions and features)
@DOC_END */
#pragma once
#define GL_GLEXT_PROTOTYPES
#include <GL/glsubset.h>
typedef void* (* nvGLLoaderGetProcFN)(const char* name);
/* structs */
/* GL_NV_command_list */
typedef struct {
GLuint header;
} TerminateSequenceCommandNV;
typedef struct {
GLuint header;
} NOPCommandNV;
typedef struct {
GLuint header;
GLuint count;
GLuint firstIndex;
GLuint baseVertex;
} DrawElementsCommandNV;
typedef struct {
GLuint header;
GLuint count;
GLuint first;
} DrawArraysCommandNV;
typedef struct {
GLuint header;
GLenum mode;
GLuint count;
GLuint instanceCount;
GLuint firstIndex;
GLuint baseVertex;
GLuint baseInstance;
} DrawElementsInstancedCommandNV;
typedef struct {
GLuint header;
GLenum mode;
GLuint count;
GLuint instanceCount;
GLuint first;
GLuint baseInstance;
} DrawArraysInstancedCommandNV;
typedef struct {
GLuint header;
GLuint addressLo;
GLuint addressHi;
GLuint typeSizeInByte;
} ElementAddressCommandNV;
typedef struct {
GLuint header;
GLuint index;
GLuint addressLo;
GLuint addressHi;
} AttributeAddressCommandNV;
typedef struct {
GLuint header;
GLushort index;
GLushort stage;
GLuint addressLo;
GLuint addressHi;
} UniformAddressCommandNV;
typedef struct {
GLuint header;
float red;
float green;
float blue;
float alpha;
} BlendColorCommandNV;
typedef struct {
GLuint header;
GLuint frontStencilRef;
GLuint backStencilRef;
} StencilRefCommandNV;
typedef struct {
GLuint header;
float lineWidth;
} LineWidthCommandNV;
typedef struct {
GLuint header;
float scale;
float bias;
} PolygonOffsetCommandNV;
typedef struct {
GLuint header;
float alphaRef;
} AlphaRefCommandNV;
typedef struct {
GLuint header;
GLuint x;
GLuint y;
GLuint width;
GLuint height;
} ViewportCommandNV; /* only ViewportIndex 0 */
typedef struct {
GLuint header;
GLuint x;
GLuint y;
GLuint width;
GLuint height;
} ScissorCommandNV; /* only ViewportIndex 0 */
typedef struct {
GLuint header;
GLuint frontFace; /* 0 for CW, 1 for CCW */
} FrontFaceCommandNV;
/* loader */
void load_GL(nvGLLoaderGetProcFN fnGetProcAddress);
/* availables */
extern int has_GL_VERSION_1_1;
extern int has_GL_VERSION_1_2;
extern int has_GL_VERSION_1_3;
extern int has_GL_VERSION_1_4;
extern int has_GL_VERSION_1_5;
extern int has_GL_VERSION_2_0;
extern int has_GL_VERSION_2_1;
extern int has_GL_VERSION_3_0;
extern int has_GL_VERSION_3_1;
extern int has_GL_VERSION_3_2;
extern int has_GL_VERSION_3_3;
extern int has_GL_VERSION_4_0;
extern int has_GL_VERSION_4_1;
extern int has_GL_VERSION_4_2;
extern int has_GL_VERSION_4_3;
extern int has_GL_VERSION_4_4;
extern int has_GL_VERSION_4_5;
extern int has_GL_VERSION_4_6;
extern int has_GL_ARB_bindless_texture;
extern int has_GL_ARB_cl_event;
extern int has_GL_ARB_debug_output;
extern int has_GL_ARB_indirect_parameters;
extern int has_GL_ARB_shading_language_include;
extern int has_GL_ARB_texture_filter_minmax;
extern int has_GL_ARB_texture_float;
extern int has_GL_EXT_memory_object;
extern int has_GL_EXT_memory_object_fd;
extern int has_GL_EXT_memory_object_win32;
extern int has_GL_EXT_semaphore;
extern int has_GL_EXT_semaphore_fd;
extern int has_GL_EXT_semaphore_win32;
extern int has_GL_EXT_texture_compression_latc;
extern int has_GL_EXT_texture_compression_s3tc;
extern int has_GL_NV_bindless_texture;
extern int has_GL_NV_blend_equation_advanced;
extern int has_GL_NV_clip_space_w_scaling;
extern int has_GL_NV_command_list;
extern int has_GL_NV_compute_shader_derivatives;
extern int has_GL_NV_conservative_raster;
extern int has_GL_NV_conservative_raster_dilate;
extern int has_GL_NV_conservative_raster_pre_snap;
extern int has_GL_NV_conservative_raster_pre_snap_triangles;
extern int has_GL_NV_conservative_raster_underestimation;
extern int has_GL_NV_draw_vulkan_image;
extern int has_GL_NV_draw_texture;
extern int has_GL_NV_fill_rectangle;
extern int has_GL_NV_fragment_coverage_to_color;
extern int has_GL_NV_fragment_shader_barycentric;
extern int has_GL_NV_fragment_shader_interlock;
extern int has_GL_NV_framebuffer_mixed_samples;
extern int has_GL_NV_gpu_multicast;
extern int has_GL_NV_gpu_shader5;
extern int has_GL_NV_internalformat_sample_query;
extern int has_GL_NV_memory_attachment;
extern int has_GL_NV_mesh_shader;
extern int has_GL_NV_path_rendering;
extern int has_GL_NV_representative_fragment_test;
extern int has_GL_NV_sample_locations;
extern int has_GL_NV_sample_mask_override_coverage;
extern int has_GL_NV_scissor_exclusive;
extern int has_GL_NV_shader_atomic_int64;
extern int has_GL_NV_shader_buffer_load;
extern int has_GL_NV_shader_buffer_store;
extern int has_GL_NV_shader_texture_footprint;
extern int has_GL_NV_shader_thread_group;
extern int has_GL_NV_shader_thread_shuffle;
extern int has_GL_NV_shading_rate_image;
extern int has_GL_NV_stereo_view_rendering;
extern int has_GL_NV_texture_multisample;
extern int has_GL_NV_uniform_buffer_unified_memory;
extern int has_GL_NV_vertex_buffer_unified_memory;
extern int has_GL_NV_viewport_swizzle;
extern int has_GL_NVX_gpu_memory_info;
extern int has_GL_NV_query_resource;
extern int has_GL_NV_query_resource_tag;
/* loaders */
int load_GL_VERSION_1_1(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_VERSION_1_2(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_VERSION_1_3(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_VERSION_1_4(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_VERSION_1_5(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_VERSION_2_0(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_VERSION_2_1(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_VERSION_3_0(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_VERSION_3_1(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_VERSION_3_2(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_VERSION_3_3(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_VERSION_4_0(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_VERSION_4_1(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_VERSION_4_2(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_VERSION_4_3(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_VERSION_4_4(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_VERSION_4_5(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_VERSION_4_6(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_ARB_bindless_texture(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_ARB_cl_event(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_ARB_debug_output(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_ARB_indirect_parameters(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_ARB_shading_language_include(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_ARB_texture_filter_minmax(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_ARB_texture_float(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_EXT_memory_object(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_EXT_memory_object_fd(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_EXT_memory_object_win32(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_EXT_semaphore(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_EXT_semaphore_fd(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_EXT_semaphore_win32(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_EXT_texture_compression_latc(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_EXT_texture_compression_s3tc(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_bindless_texture(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_blend_equation_advanced(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_clip_space_w_scaling(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_command_list(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_compute_shader_derivatives(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_conservative_raster(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_conservative_raster_dilate(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_conservative_raster_pre_snap(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_conservative_raster_pre_snap_triangles(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_conservative_raster_underestimation(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_draw_vulkan_image(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_draw_texture(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_fill_rectangle(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_fragment_coverage_to_color(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_fragment_shader_barycentric(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_fragment_shader_interlock(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_framebuffer_mixed_samples(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_gpu_multicast(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_gpu_shader5(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_internalformat_sample_query(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_memory_attachment(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_mesh_shader(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_path_rendering(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_representative_fragment_test(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_sample_locations(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_sample_mask_override_coverage(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_scissor_exclusive(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_shader_atomic_int64(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_shader_buffer_load(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_shader_buffer_store(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_shader_texture_footprint(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_shader_thread_group(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_shader_thread_shuffle(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_shading_rate_image(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_stereo_view_rendering(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_texture_multisample(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_uniform_buffer_unified_memory(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_vertex_buffer_unified_memory(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_viewport_swizzle(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NVX_gpu_memory_info(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_query_resource(nvGLLoaderGetProcFN fnGetProcAddress);
int load_GL_NV_query_resource_tag(nvGLLoaderGetProcFN fnGetProcAddress);

View file

@ -0,0 +1,525 @@
--[[
/*
* Copyright (c) 2018-2021, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2018-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
HOW TO USE
* look if extension exists in ../GL/glcustom.h
if not, then merge it from official https://www.khronos.org/registry/OpenGL/api/GL/glext.h
* check out:
extensions_gl.lua
extensions_gl.hpp
extensions_gl.cpp
../GL/glsubset.h
* edit the "subsetExtensions" string below, to add the extensions you need
* run this file with a lua interpreter
e.g get https://github.com/rjpcomputing/luaforwindows/blob/master/files/lua5.1.dll
and https://github.com/rjpcomputing/luaforwindows/blob/master/files/lua5.1.exe
then run "lua.exe extensions_gl.lua" in this directory
* if the extension is still missing, then merge the extension from official glext.h into ../GL/glcustom.h
and rerun the script
]]
local subsetExtensions =
[[
GL_ARB_debug_output
GL_ARB_shading_language_include
GL_ARB_indirect_parameters
GL_ARB_bindless_texture
GL_ARB_texture_filter_minmax
GL_ARB_texture_float
GL_ARB_cl_event
WGL_ARB_pixel_format
GL_NV_bindless_texture
GL_NV_blend_equation_advanced
GL_NV_clip_space_w_scaling
GL_NV_command_list
GL_NV_compute_shader_derivatives
GL_NV_conservative_raster
GL_NV_conservative_raster_dilate
GL_NV_conservative_raster_pre_snap
GL_NV_conservative_raster_pre_snap_triangles
GL_NV_conservative_raster_underestimation
GL_NV_draw_texture
GL_NV_draw_vulkan_image
GL_NV_fill_rectangle
GL_NV_fragment_coverage_to_color
GL_NV_fragment_shader_barycentric
GL_NV_fragment_shader_interlock
GL_NV_framebuffer_mixed_samples
GL_NV_gpu_multicast
GL_NV_gpu_shader5
GL_NV_internalformat_sample_query
GL_NV_memory_attachment
GL_NV_mesh_shader
GL_NV_path_rendering
GL_NV_representative_fragment_test
GL_NV_sample_locations
GL_NV_sample_mask_override_coverage
GL_NV_scissor_exclusive
GL_NV_shader_atomic_int64
GL_NV_shader_buffer_load
GL_NV_shader_buffer_store
GL_NV_shader_texture_footprint
GL_NV_shader_thread_group
GL_NV_shader_thread_shuffle
GL_NV_shading_rate_image
GL_NV_stereo_view_rendering
GL_NV_texture_multisample
GL_NV_uniform_buffer_unified_memory
GL_NV_vertex_buffer_unified_memory
GL_NV_viewport_swizzle
GL_NVX_gpu_memory_info
GL_EXT_texture_compression_latc
GL_EXT_texture_compression_s3tc
GL_EXT_memory_object
GL_EXT_semaphore
GL_EXT_semaphore_win32
GL_EXT_semaphore_fd
GL_EXT_memory_object_fd
GL_EXT_memory_object_win32
GL_NV_query_resource
GL_NV_query_resource_tag
]]
local function generate(outfilename, header, enablelist)
local function subsetheader(filename, outfilename, enablelist, prefix)
local f = io.open(filename,"r")
local str = f:read("*a")
f:close()
str = str:gsub("__gl_glcustom_h_", "__gl_glsubset_h_")
if (enablelist) then
local search = ("#ifndef $_[%w_]+\n#define $_[%w_]+ 1\n.-#endif /%* $_[%w_]+ %*/\n\n"):gsub("%$",prefix)
local num
str,num = str:gsub(search,
function(cap)
local feature = cap:match("#ifndef ("..prefix.."_[%w_]+)")
local is_version = feature:match(prefix.."_VERSION")
if (is_version or not enablelist or enablelist[feature]) then
return cap
else
return ""
end
end)
end
if (outfilename) then
print(outfilename)
local f = io.open(outfilename,"w")
assert(f,"could not open"..outfilename.." for writing (check out?)")
f:write(str)
f:close()
end
return str
end
local function extractFeatureDefs(str, enablelist, prefix, api, apientry)
local features = {}
local disables = {}
for feature,defstr in str:gmatch(("#ifndef ($_[%w_]+)\n#define $_[%w_]+ 1\n(.-)#endif /%* $_"):gsub("%$", prefix)) do
local is_version = feature:match(prefix.."_VERSION")
if (is_version or not enablelist or enablelist[feature]) then
local defs = ""
for def in defstr:gmatch(("#ifdef $_$EXT_PROTOTYPES(.-)#endif\n"):gsub("%$", prefix)) do
def = def:gsub(api, ""):gsub(apientry, "")
defs = defs..def
end
table.insert(features, {feature=feature, defs=defs})
elseif (not is_version) then
table.insert(disables, feature)
end
end
return features, disables
end
local function toTab(str)
local tab = {}
for name in str:gmatch("[%w_]+") do
tab[name] = true
end
return tab
end
local enablelist = enablelist and toTab(enablelist)
local parsed = subsetheader("../GL/glcustom.h", "../GL/glsubset.h", enablelist, "GL")
local gl_features, gl_disables = extractFeatureDefs(parsed, enablelist, "GL", "GLAPI ", "APIENTRY ")
local availables_header = ""
local availables_source = ""
local loaders_header = ""
local loaders_source = ""
local loaders_all = ""
local function process(f, prefix, api, apientry)
local major,minor = f.feature:match(prefix.."_VERSION_(%d)_(%d)")
major,minor = tonumber(major), tonumber(minor)
availables_header = availables_header.."extern int has_"..f.feature..";\n"
availables_source = availables_source.."int has_"..f.feature.." = 0;\n"
loaders_header = loaders_header.."int load_"..f.feature.."(nvGLLoaderGetProcFN fnGetProcAddress);\n"
local defs = "\n"..f.defs:gsub("%s*%*%s*","* ")
local func = ""
local initfunc = ""
local success = ""
local variable = ""
for const,ret,name,arg in defs:gmatch("\n([%w_]-%s*)([%w_%*]+)%s+([%w_]+)%s*(%b());") do
local prot = "PFN"..string.upper(name).."PROC"
local mangled = "pfn_"..name
local exec = ret ~= "void" and "return " or ""
const = const == "\n" and "" or const
exec = exec..mangled.."("
if (arg ~= "(void)") then
for a in arg:sub(2,-2):gmatch("([^,%%]+),?") do
local am = a:gsub("%b[]",""):match("([%w_]+)$")
assert(am,a)
exec = exec..am..","
end
exec = exec:sub(1,-2)..");"
else
exec = exec..");"
end
variable = variable.."static "..prot.." "..mangled.." = 0;\n"
func = func..api..const..ret.." "..apientry..name..arg.."\n{\n"
func = func.." assert("..mangled..");\n"
func = func.." "..exec.."\n"
func = func.."}\n"
initfunc = initfunc.." "..mangled..' = ('..prot..')fnGetProcAddress("'..name..'");\n'
success = success.." success = success && ("..mangled..' != 0);\n'
end
local test
if (major and minor) then
test = "has_version("..major..","..minor..")"
else
test = 'has_extension("'..f.feature..'")'
end
-- already defined in win32 opengl32.dll
local skip_functions = (prefix == "GL" and major == 1 and minor < 2) or
(prefix == "WGL" and major == 1 and minor == 0)
loaders_source = loaders_source.."/* /////////////////////////////////// */\n"
loaders_source = loaders_source.."/* "..f.feature.." */\n\n"
loaders_source = loaders_source..variable.."\n"
--loaders_source = loaders_source..(skip_functions and "#ifndef WIN32\n" or "")
loaders_source = loaders_source..func.."\n"
--loaders_source = loaders_source..(skip_functions and "#endif\n" or "")
loaders_source = loaders_source.."int load_"..f.feature.."(nvGLLoaderGetProcFN fnGetProcAddress)\n{\n"
loaders_source = loaders_source..initfunc
loaders_source = loaders_source.." int success = "..test..";\n"
loaders_source = loaders_source..success
loaders_source = loaders_source.." return success;\n}\n\n"
print("output written", f.feature)
loaders_all = loaders_all.." has_"..f.feature.." = load_"..f.feature.."(fnGetProcAddress);\n"
end
for i,f in ipairs(gl_features) do
process(f, "GL", "GLAPI ", "APIENTRY ")
end
local disables = ""
for i,f in ipairs(gl_disables) do
disables = disables.."#define "..f.." 0\n"
end
local fheader = io.open(outfilename..".hpp", "w")
local fsource = io.open(outfilename..".cpp", "w")
assert(fheader, "could not open "..outfilename..".hpp for writing (check out?)")
assert(fsource, "could not open "..outfilename..".cpp for writing (check out?)")
local structs = ""
if (enablelist and enablelist.GL_NV_command_list) then
structs = structs..[[
/* GL_NV_command_list */
typedef struct {
GLuint header;
} TerminateSequenceCommandNV;
typedef struct {
GLuint header;
} NOPCommandNV;
typedef struct {
GLuint header;
GLuint count;
GLuint firstIndex;
GLuint baseVertex;
} DrawElementsCommandNV;
typedef struct {
GLuint header;
GLuint count;
GLuint first;
} DrawArraysCommandNV;
typedef struct {
GLuint header;
GLenum mode;
GLuint count;
GLuint instanceCount;
GLuint firstIndex;
GLuint baseVertex;
GLuint baseInstance;
} DrawElementsInstancedCommandNV;
typedef struct {
GLuint header;
GLenum mode;
GLuint count;
GLuint instanceCount;
GLuint first;
GLuint baseInstance;
} DrawArraysInstancedCommandNV;
typedef struct {
GLuint header;
GLuint addressLo;
GLuint addressHi;
GLuint typeSizeInByte;
} ElementAddressCommandNV;
typedef struct {
GLuint header;
GLuint index;
GLuint addressLo;
GLuint addressHi;
} AttributeAddressCommandNV;
typedef struct {
GLuint header;
GLushort index;
GLushort stage;
GLuint addressLo;
GLuint addressHi;
} UniformAddressCommandNV;
typedef struct {
GLuint header;
float red;
float green;
float blue;
float alpha;
} BlendColorCommandNV;
typedef struct {
GLuint header;
GLuint frontStencilRef;
GLuint backStencilRef;
} StencilRefCommandNV;
typedef struct {
GLuint header;
float lineWidth;
} LineWidthCommandNV;
typedef struct {
GLuint header;
float scale;
float bias;
} PolygonOffsetCommandNV;
typedef struct {
GLuint header;
float alphaRef;
} AlphaRefCommandNV;
typedef struct {
GLuint header;
GLuint x;
GLuint y;
GLuint width;
GLuint height;
} ViewportCommandNV; /* only ViewportIndex 0 */
typedef struct {
GLuint header;
GLuint x;
GLuint y;
GLuint width;
GLuint height;
} ScissorCommandNV; /* only ViewportIndex 0 */
typedef struct {
GLuint header;
GLuint frontFace; /* 0 for CW, 1 for CCW */
} FrontFaceCommandNV;
]]
end
fheader:write(header..[[
/*
* Copyright (c) 2018-2021, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2018-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
/** @DOC_START
# OpenGL Extension loader
Provides a subset of OpenGL Extensions generated by `extensions_gl.lua`.
The framework uses a sanitized OpenGL header that is mostly core functionality.
`GL/glsubset.h` is generated using a enablelist by the lua script
from `GL/glcustom.h` (which is mostly based on `glcorearb.h` with some
additional extensions and features)
@DOC_END */
#pragma once
#define GL_GLEXT_PROTOTYPES
#include <GL/glsubset.h>
typedef void* (* nvGLLoaderGetProcFN)(const char* name);
/* structs */
]]..structs..[[
/* loader */
void load_GL(nvGLLoaderGetProcFN fnGetProcAddress);
/* availables */
]]..availables_header..[[
/* loaders */
]]..loaders_header..[[
]])
fsource:write(header..[[
/*
* Copyright (c) 2018-2021, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2018-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#include <assert.h>
#include <cstring>
#include "]]..outfilename..[[.hpp"
/* availables */
]]..availables_source..[[
/* tests */
static int has_extension(const char* name)
{
GLint numExtensions = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions);
for (int i = 0; i < numExtensions; i++) {
const char* ext = (const char*)glGetStringi(GL_EXTENSIONS, i);
if (strcmp(name, ext) == 0) {
return true;
}
}
return false;
}
static int has_version(int major, int minor)
{
GLint ctx_major;
GLint ctx_minor;
glGetIntegerv(GL_MAJOR_VERSION, &ctx_major);
glGetIntegerv(GL_MINOR_VERSION, &ctx_minor);
return (ctx_major >= major && (ctx_major > major || ctx_minor >= minor));
}
/* loaders */
void load_GL(nvGLLoaderGetProcFN fnGetProcAddress)
{
]]..loaders_all..[[
}
/* loaders */
]]..loaders_source..[[
]])
end
do
generate("extensions_gl",
"/* auto generated by extensions_gl.lua */",
subsetExtensions)
end

View file

@ -0,0 +1,101 @@
/*
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
/// @DOC_SKIP (keyword to exclude this file from automatic README.md generation)
#ifndef NV_GLSLTYPES_INCLUDED
#define NV_GLSLTYPES_INCLUDED
/** @DOC_START
# type definitions for nvgl and nvmath
Sets up vector, matrix etc. types available in GLSL
@DOC_END */
#include <stdint.h>
namespace nvgl
{
typedef uint64_t sampler1D;
typedef uint64_t sampler2D;
typedef uint64_t sampler2DMS;
typedef uint64_t sampler3D;
typedef uint64_t samplerBuffer;
typedef uint64_t samplerCube;
typedef uint64_t sampler1DArray;
typedef uint64_t sampler2DArray;
typedef uint64_t sampler2DMSArray;
typedef uint64_t samplerCubeArray;
typedef uint64_t usampler1D;
typedef uint64_t usampler2D;
typedef uint64_t usampler2DMS;
typedef uint64_t usampler3D;
typedef uint64_t usamplerBuffer;
typedef uint64_t usamplerCube;
typedef uint64_t usampler1DArray;
typedef uint64_t usampler2DArray;
typedef uint64_t usampler2DMSArray;
typedef uint64_t usamplerCubeArray;
typedef uint64_t isampler1D;
typedef uint64_t isampler2D;
typedef uint64_t isampler2DMS;
typedef uint64_t isampler3D;
typedef uint64_t isamplerBuffer;
typedef uint64_t isamplerCube;
typedef uint64_t isampler1DArray;
typedef uint64_t isampler2DArray;
typedef uint64_t isampler2DMSArray;
typedef uint64_t isamplerCubeArray;
typedef uint64_t image1D;
typedef uint64_t image2D;
typedef uint64_t image2DMS;
typedef uint64_t image3D;
typedef uint64_t imageBuffer;
typedef uint64_t imageCube;
typedef uint64_t image1DArray;
typedef uint64_t image2DArray;
typedef uint64_t image2DMSArray;
typedef uint64_t imageCubeArray;
typedef uint64_t uimage1D;
typedef uint64_t uimage2D;
typedef uint64_t uimage2DMS;
typedef uint64_t uimage3D;
typedef uint64_t uimageBuffer;
typedef uint64_t uimageCube;
typedef uint64_t uimage1DArray;
typedef uint64_t uimage2DArray;
typedef uint64_t uimage2DMSArray;
typedef uint64_t uimageCubeArray;
typedef uint64_t iimage1D;
typedef uint64_t iimage2D;
typedef uint64_t iimage2DMS;
typedef uint64_t iimage3D;
typedef uint64_t iimageBuffer;
typedef uint64_t iimageCube;
typedef uint64_t iimage1DArray;
typedef uint64_t iimage2DArray;
typedef uint64_t iimage2DMSArray;
typedef uint64_t iimageCubeArray;
}
#endif

View file

@ -0,0 +1,109 @@
/*
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#include "profiler_gl.hpp"
#include <assert.h>
//////////////////////////////////////////////////////////////////////////
namespace nvgl {
void ProfilerGL::resizeQueries()
{
uint32_t timers = getRequiredTimers();
uint32_t old = (uint32_t)m_queries.size();
if(old == timers)
{
return;
}
m_queries.resize(timers, 0);
uint32_t add = timers - old;
glGenQueries(add, &m_queries[old]);
}
void ProfilerGL::init()
{
resizeQueries();
}
void ProfilerGL::deinit()
{
if(m_queries.empty())
return;
glDeleteQueries((GLuint)m_queries.size(), m_queries.data());
m_queries.clear();
}
nvh::Profiler::SectionID ProfilerGL::beginSection(const char* name, bool singleShot)
{
nvh::Profiler::gpuTimeProvider_fn fnProvider = [&](SectionID i, uint32_t queryFrame, double& gpuTime) {
uint32_t idxBegin = getTimerIdx(i, queryFrame, true);
uint32_t idxEnd = getTimerIdx(i, queryFrame, false);
GLint available = 0;
glGetQueryObjectiv(m_queries[idxEnd], GL_QUERY_RESULT_AVAILABLE, &available);
if(available)
{
GLuint64 beginTime;
GLuint64 endTime;
glGetQueryObjectui64v(m_queries[idxBegin], GL_QUERY_RESULT, &beginTime);
glGetQueryObjectui64v(m_queries[idxEnd], GL_QUERY_RESULT, &endTime);
gpuTime = double(endTime - beginTime) / double(1000);
return true;
}
else
{
return false;
}
};
SectionID slot = Profiler::beginSection(name, "GL ", fnProvider, singleShot);
if(m_queries.size() != getRequiredTimers())
{
resizeQueries();
}
glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, -1, name);
uint32_t idx = getTimerIdx(slot, getSubFrame(slot), true);
glQueryCounter(m_queries[idx], GL_TIMESTAMP);
return slot;
}
void ProfilerGL::endSection(SectionID slot)
{
uint32_t idx = getTimerIdx(slot, getSubFrame(slot), false);
glQueryCounter(m_queries[idx], GL_TIMESTAMP);
glPopDebugGroup();
Profiler::endSection(slot);
}
} // namespace nvgl

View file

@ -0,0 +1,86 @@
/*
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef NV_PROFILERGL_INCLUDED
#define NV_PROFILERGL_INCLUDED
#include "../nvh/profiler.hpp"
#include "extensions_gl.hpp"
namespace nvgl {
//////////////////////////////////////////////////////////////////////////
/** @DOC_START
# class nvgl::ProfilerGL
nvgl::ProfilerGL extends Profiler and uses `glQueryCounter(... GL_TIMESTAMP)`
to compute the GPU time of a section.
`glPushDebugGroup` and `glPopDebugGroup` are used within each timed
section, so that the section names can show up in NSightGraphics,
renderdoc or comparable tools.
@DOC_END */
class ProfilerGL : public nvh::Profiler
{
public:
// utility class to call begin/end within local scope
class Section
{
public:
Section(ProfilerGL& profiler, const char* name, bool singleShot = false)
: m_profiler(profiler)
{
m_id = profiler.beginSection(name, singleShot);
}
~Section() { m_profiler.endSection(m_id); }
private:
SectionID m_id;
ProfilerGL& m_profiler;
};
// recurring, must be within beginFrame/endFrame
Section timeRecurring(const char* name) { return Section(*this, name, false); }
// singleShot, results are available after FRAME_DELAY many endFrame
Section timeSingle(const char* name) { return Section(*this, name, true); }
//////////////////////////////////////////////////////////////////////////
ProfilerGL(nvh::Profiler* masterProfiler = nullptr)
: Profiler(masterProfiler)
{
}
void init();
void deinit();
SectionID beginSection(const char* name, bool singleShot = false);
void endSection(SectionID slot);
private:
void resizeQueries();
std::vector<GLuint> m_queries;
};
} // namespace nvgl
#endif

View file

@ -0,0 +1,463 @@
/*
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#include "programmanager_gl.hpp"
#include <algorithm>
#include <assert.h>
#include <fstream>
#include <iostream>
#include <sstream>
#include <stdarg.h>
#include <stdio.h>
#include <nvh/fileoperations.hpp>
#include <nvh/nvprint.hpp>
namespace nvgl {
static bool checkProgram(GLuint program)
{
if(!program)
return false;
GLint result = GL_FALSE;
glGetProgramiv(program, GL_LINK_STATUS, &result);
int infoLogLength;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);
if(infoLogLength > 1
#ifdef NDEBUG
&& result == GL_FALSE
#endif
)
{
std::vector<char> buffer(infoLogLength);
glGetProgramInfoLog(program, infoLogLength, NULL, &buffer[0]);
LOGW("%s\n", &buffer[0]);
}
return result == GL_TRUE;
}
static bool checkShader(GLuint shader, std::string const& filename)
{
if(!shader)
return false;
GLint result = GL_FALSE;
glGetShaderiv(shader, GL_COMPILE_STATUS, &result);
LOGI("%s ...\n", filename.c_str());
int infoLogLength;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
if(infoLogLength > 1
#ifdef NDEBUG
&& result == GL_FALSE
#endif
)
{
std::vector<char> buffer(infoLogLength);
glGetShaderInfoLog(shader, infoLogLength, NULL, &buffer[0]);
LOGW("%s\n", &buffer[0]);
}
return result == GL_TRUE;
}
bool ProgramManager::setupProgram(Program& prog)
{
prog.program = 0;
if(prog.definitions.empty())
return false;
m_supportsExtendedInclude = has_GL_ARB_shading_language_include != 0;
std::string combinedPrepend = m_prepend;
std::string combinedFilenames;
for(size_t i = 0; i < prog.definitions.size(); i++)
{
combinedPrepend += prog.definitions[i].prepend;
combinedFilenames += prog.definitions[i].filename;
}
bool allFound = true;
for(size_t i = 0; i < prog.definitions.size(); i++)
{
Definition& definition = prog.definitions[i];
if(definition.filetype == FILETYPE_DEFAULT)
{
definition.filetype = m_filetype;
}
if(m_rawOnly)
{
definition.content = getContent(definition.filename, definition.filenameFound);
}
else
{
char const* strDefine = "";
switch(definition.type)
{
case GL_VERTEX_SHADER:
strDefine = "#define _VERTEX_SHADER_ 1\n";
break;
case GL_FRAGMENT_SHADER:
strDefine = "#define _FRAGMENT_SHADER_ 1\n";
break;
case GL_COMPUTE_SHADER:
strDefine = "#define _COMPUTE_SHADER_ 1\n";
break;
case GL_GEOMETRY_SHADER:
strDefine = "#define _GEOMETRY_SHADER_ 1\n";
break;
case GL_TESS_CONTROL_SHADER:
strDefine = "#define _TESS_CONTROL_SHADER_ 1\n";
break;
case GL_TESS_EVALUATION_SHADER:
strDefine = "#define _TESS_EVALUATION_SHADER_ 1\n";
break;
#if GL_NV_mesh_shader
case GL_MESH_SHADER_NV:
strDefine = "#define _MESH_SHADER_ 1\n";
break;
case GL_TASK_SHADER_NV:
strDefine = "#define _TASK_SHADER_ 1\n";
break;
#endif
}
definition.content = manualInclude(definition.filename, definition.filenameFound,
m_prepend + definition.prepend + std::string(strDefine), false);
}
allFound = allFound && !definition.content.empty();
}
if(m_preprocessOnly)
{
prog.program = PREPROCESS_ONLY_PROGRAM;
return true;
}
else
{
prog.program = glCreateProgram();
if(!m_useCacheFile.empty() && has_GL_VERSION_4_1)
{
glProgramParameteri(prog.program, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);
}
}
bool loadedCache = false;
if(!m_useCacheFile.empty() && (!allFound || m_preferCache) && has_GL_VERSION_4_1)
{
// try cache
loadedCache = loadBinary(prog.program, combinedPrepend, combinedFilenames);
}
if(!loadedCache)
{
for(size_t i = 0; i < prog.definitions.size(); i++)
{
Definition& definition = prog.definitions[i];
GLuint shader = 0;
if(!definition.content.empty())
{
char const* sourcePointer = definition.content.c_str();
shader = glCreateShader(definition.type);
glShaderSource(shader, 1, &sourcePointer, NULL);
glCompileShader(shader);
}
if(!shader || !checkShader(shader, definition.filename))
{
glDeleteShader(shader);
glDeleteProgram(prog.program);
prog.program = 0;
return false;
}
glAttachShader(prog.program, shader);
glDeleteShader(shader);
}
glLinkProgram(prog.program);
}
if(checkProgram(prog.program))
{
if(!m_useCacheFile.empty() && !loadedCache && has_GL_VERSION_4_1)
{
saveBinary(prog.program, combinedPrepend, combinedFilenames);
}
return true;
}
glDeleteProgram(prog.program);
prog.program = 0;
return false;
}
ProgramID ProgramManager::createProgram(const Definition& def0,
const Definition& def1 /*= ShaderDefinition()*/,
const Definition& def2 /*= ShaderDefinition()*/,
const Definition& def3 /*= ShaderDefinition()*/,
const Definition& def4 /*= ShaderDefinition()*/)
{
std::vector<ProgramManager::Definition> defs;
defs.push_back(def0);
if(def1.type)
defs.push_back(def1);
if(def2.type)
defs.push_back(def2);
if(def3.type)
defs.push_back(def3);
if(def4.type)
defs.push_back(def4);
return createProgram(defs);
}
ProgramID ProgramManager::createProgram(const std::vector<ProgramManager::Definition>& definitions)
{
Program prog;
prog.definitions = definitions;
setupProgram(prog);
for(size_t i = 0; i < m_programs.size(); i++)
{
if(m_programs[i].definitions.empty())
{
m_programs[i] = prog;
return i;
}
}
m_programs.push_back(prog);
return m_programs.size() - 1;
}
bool ProgramManager::areProgramsValid()
{
bool valid = true;
for(size_t i = 0; i < m_programs.size(); i++)
{
valid = valid && isValid((ProgramID)i);
}
return valid;
}
void ProgramManager::deletePrograms()
{
for(size_t i = 0; i < m_programs.size(); i++)
{
if(m_programs[i].program && m_programs[i].program != PREPROCESS_ONLY_PROGRAM)
{
glDeleteProgram(m_programs[i].program);
}
m_programs[i].program = 0;
}
}
void ProgramManager::reloadProgram(ProgramID i)
{
if(!isValid(i))
return;
bool old = m_preprocessOnly;
if(m_programs[i].program && m_programs[i].program != PREPROCESS_ONLY_PROGRAM)
{
glDeleteProgram(m_programs[i].program);
}
m_preprocessOnly = m_programs[i].program == PREPROCESS_ONLY_PROGRAM;
m_programs[i].program = 0;
if(!m_programs[i].definitions.empty())
{
setupProgram(m_programs[i]);
}
m_preprocessOnly = old;
}
void ProgramManager::reloadPrograms()
{
LOGI("Reloading programs...\n");
for(size_t i = 0; i < m_programs.size(); i++)
{
reloadProgram((ProgramID)i);
}
LOGI("done\n");
}
bool ProgramManager::isValid(ProgramID idx) const
{
return idx.isValid() && (m_programs[idx].definitions.empty() || m_programs[idx].program != 0);
}
unsigned int ProgramManager::get(ProgramID idx) const
{
assert(m_programs[idx].program != PREPROCESS_ONLY_PROGRAM);
return m_programs[idx].program;
}
void ProgramManager::destroyProgram(ProgramID idx)
{
if(m_programs[idx].program && m_programs[idx].program != PREPROCESS_ONLY_PROGRAM)
{
glDeleteProgram(m_programs[idx].program);
}
m_programs[idx].program = 0;
m_programs[idx].definitions.clear();
}
//-----------------------------------------------------------------------------
// MurmurHash2A, by Austin Appleby
// This is a variant of MurmurHash2 modified to use the Merkle-Damgard
// construction. Bulk speed should be identical to Murmur2, small-key speed
// will be 10%-20% slower due to the added overhead at the end of the hash.
// This variant fixes a minor issue where null keys were more likely to
// collide with each other than expected, and also makes the algorithm
// more amenable to incremental implementations. All other caveats from
// MurmurHash2 still apply.
#define mmix(h, k) \
{ \
k *= m; \
k ^= k >> r; \
k *= m; \
h *= m; \
h ^= k; \
}
static unsigned int strMurmurHash2A(const void* key, size_t len, unsigned int seed)
{
const unsigned int m = 0x5bd1e995;
const int r = 24;
unsigned int l = (unsigned int)len;
const unsigned char* data = (const unsigned char*)key;
unsigned int h = seed;
unsigned int t = 0;
while(len >= 4)
{
unsigned int k = *(unsigned int*)data;
mmix(h, k);
data += 4;
len -= 4;
}
switch(len)
{
case 3:
t ^= data[2] << 16;
case 2:
t ^= data[1] << 8;
case 1:
t ^= data[0];
};
mmix(h, t);
mmix(h, l);
h ^= h >> 13;
h *= m;
h ^= h >> 15;
return h;
}
#undef mmix
static size_t strHexFromByte(char* buffer, size_t bufferlen, const void* data, size_t len)
{
const char tostr[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
const unsigned char* d = (const unsigned char*)data;
char* out = buffer;
size_t i = 0;
for(; i < len && (i * 2) + 1 < bufferlen; i++, d++, out += 2)
{
unsigned int val = *d;
unsigned int hi = val / 16;
unsigned int lo = val % 16;
out[0] = tostr[hi];
out[1] = tostr[lo];
}
return i * 2;
}
std::string ProgramManager::binaryName(const std::string& combinedPrepend, const std::string& combinedFilenames)
{
unsigned int hashCombine = combinedPrepend.empty() ? 0 : strMurmurHash2A(&combinedPrepend[0], combinedPrepend.size(), 127);
unsigned int hashFilenames = strMurmurHash2A(&combinedFilenames[0], combinedFilenames.size(), 129);
std::string hexCombine;
std::string hexFilenames;
hexCombine.resize(8);
hexFilenames.resize(8);
strHexFromByte(&hexCombine[0], 8, &hashCombine, 4);
strHexFromByte(&hexFilenames[0], 8, &hashFilenames, 4);
return m_useCacheFile + "_" + hexCombine + "_" + hexFilenames + ".glp";
}
bool ProgramManager::loadBinary(GLuint program, const std::string& combinedPrepend, const std::string& combinedFilenames)
{
std::string filename = binaryName(combinedPrepend, combinedFilenames);
std::string filenameFound;
std::string binraw = nvh::loadFile(filename, true, m_directories, filenameFound);
if(!binraw.empty())
{
const char* bindata = &binraw[0];
glProgramBinary(program, *(GLenum*)bindata, bindata + 4, GLsizei(binraw.size() - 4));
return checkProgram(program);
}
return false;
}
void ProgramManager::saveBinary(GLuint program, const std::string& combinedPrepend, const std::string& combinedFilenames)
{
std::string filename = binaryName(combinedPrepend, combinedFilenames);
GLint datasize;
GLint datasize2;
glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &datasize);
std::string binraw;
binraw.resize(datasize + 4ULL);
char* bindata = &binraw[0];
glGetProgramBinary(program, datasize, &datasize2, (GLenum*)bindata, bindata + 4);
std::ofstream binfile;
binfile.open(filename.c_str(), std::ios::binary | std::ios::out);
if(binfile.is_open())
{
binfile.write(bindata, datasize + 4ULL);
}
}
} // namespace nvgl

View file

@ -0,0 +1,162 @@
/*
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef NV_PROGRAMMANAGER_INCLUDED
#define NV_PROGRAMMANAGER_INCLUDED
#include "extensions_gl.hpp"
#include <stdio.h>
#include <string>
#include <vector>
#include <nvh/nvprint.hpp>
#include <nvh/shaderfilemanager.hpp>
namespace nvgl {
//////////////////////////////////////////////////////////////////////////
/** @DOC_START
# class nvgl::ProgramManager
The nvgl::ProgramManager manages OpenGL programs generated from shader files (GLSL)
Using ShaderFileManager it will find the files and resolve #include for GLSL.
You must add include directories to the base-class for this.
It also comes with some convenience functions to reload shaders etc.
That is why we pass out the ProgramID rather than a GLuint directly.
Example:
```cpp
ProgramManager mgr;
// derived from ShaderFileManager
mgr.addDirectory("/shaders/")
// injected after #version directive
mgr.m_prepend = "#define USE_NOISE 1\n";
id = mgr.createProgram({{GL_VERTEX_SHADER, "object.vert.glsl"},{GL_FRAGMENT_SHADER, "object.frag.glsl"}}):
glUseProgram(mgr.get(id));
```
@DOC_END */
class ProgramID
{
public:
size_t m_value;
ProgramID()
: m_value(size_t(~0))
{
}
ProgramID(size_t b)
: m_value(b)
{
}
ProgramID& operator=(size_t b)
{
m_value = b;
return *this;
}
bool isValid() const { return m_value != size_t(~0); }
operator bool() const { return isValid(); }
operator size_t() const { return m_value; }
friend bool operator==(const ProgramID& lhs, const ProgramID& rhs) { return rhs.m_value == lhs.m_value; }
};
class ProgramManager : public nvh::ShaderFileManager
{
public:
static const uint32_t PREPROCESS_ONLY_PROGRAM = ~0;
struct Program
{
Program()
: program(0)
{
}
uint32_t program;
std::vector<Definition> definitions;
};
ProgramID createProgram(const std::vector<Definition>& definitions);
ProgramID createProgram(const Definition& def0,
const Definition& def1 = Definition(),
const Definition& def2 = Definition(),
const Definition& def3 = Definition(),
const Definition& def4 = Definition());
void destroyProgram(ProgramID idx);
void reloadProgram(ProgramID idx);
void reloadPrograms();
void deletePrograms();
bool areProgramsValid();
bool isValid(ProgramID idx) const;
unsigned int get(ProgramID idx) const;
//////////////////////////////////////////////////////////////////////////
// special purpose use, normally not required to touch
// if not empty then we will store program binaries in files that use the cachefile as prefix
// m_useCacheFile + "_"... implementation dependent
std::string m_useCacheFile;
// look for cachefiles first, otherwise look for original glsl files
bool m_preferCache;
// don't create actual program, only preprocess definition strings
bool m_preprocessOnly;
// don't create actual program, treat filename as raw
bool m_rawOnly;
ProgramManager(ProgramManager const&) = delete;
ProgramManager& operator=(ProgramManager const&) = delete;
ProgramManager()
: m_preprocessOnly(false)
, m_preferCache(false)
, m_rawOnly(false)
{
m_filetype = FILETYPE_GLSL;
}
private:
bool setupProgram(Program& prog);
bool loadBinary(GLuint program, const std::string& combinedPrepend, const std::string& combinedFilenames);
void saveBinary(GLuint program, const std::string& combinedPrepend, const std::string& combinedFilenames);
std::string binaryName(const std::string& combinedPrepend, const std::string& combinedFilenames);
std::vector<Program> m_programs;
};
} // namespace nvgl
#endif