682 lines
19 KiB
C++
682 lines
19 KiB
C++
/*
|
|
* 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
|