Skip to content

Commit

Permalink
Add new, more capable, WGL offscreen support
Browse files Browse the repository at this point in the history
  • Loading branch information
kintel committed Mar 24, 2024
1 parent 480f33c commit da8b2ce
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 2 deletions.
4 changes: 3 additions & 1 deletion CMakeLists.txt
Expand Up @@ -656,7 +656,9 @@ elseif(WIN32)
if(NOT NULLGL)
set(OFFSCREEN_METHOD "Windows WGL")
message(STATUS "Offscreen OpenGL Context - using Microsoft WGL")
set(PLATFORM_SOURCES ${PLATFORM_SOURCES} src/glview/offscreen-old/OffscreenContextWGL.cc)
set(PLATFORM_SOURCES ${PLATFORM_SOURCES}
src/glview/offscreen-old/OffscreenContextWGL.cc
src/glview/OffscreenContextWGL.cc)
endif()
endif()

Expand Down
7 changes: 6 additions & 1 deletion src/glview/OffscreenContextFactory.cc
Expand Up @@ -8,6 +8,7 @@
#endif
#ifdef _WIN32
#include "offscreen-old/OffscreenContextWGL.h"
#include "OffscreenContextWGL.h"
#endif
#ifdef ENABLE_EGL
#include "offscreen-old/OffscreenContextEGL.h"
Expand Down Expand Up @@ -37,7 +38,7 @@ const char *defaultProvider() {
return "glx";
#endif
#ifdef _WIN32
return "wgl-old";
return "wgl";
#endif
#endif // NULLGL
}
Expand Down Expand Up @@ -96,6 +97,10 @@ std::shared_ptr<OpenGLContext> create(const std::string& provider, const Offscre
return offscreen_old::CreateOffscreenContextWGL(attrib.width, attrib.height,
attrib.majorGLVersion, attrib.minorGLVersion,
attrib.compatibilityProfile);
} else if (provider == "wgl") {
return CreateOffscreenContextWGL(attrib.width, attrib.height,
attrib.majorGLVersion, attrib.minorGLVersion,
attrib.compatibilityProfile);
}
else
#endif
Expand Down
132 changes: 132 additions & 0 deletions src/glview/OffscreenContextWGL.cc
@@ -0,0 +1,132 @@
#include "OffscreenContextWGL.h"

#include <iostream>
#include <sstream>

#undef NOGDI // To access ChoosePixelFormat, PIXELFORMATDESCRIPTOR, etc.
#include <windows.h>
#include <wingdi.h>
#define GLAD_WGL
#define GLAD_WGL_IMPLEMENTATION
#include <glad/wgl.h>

#include "printutils.h"
#include "scope_guard.hpp"

class OffscreenContextWGL : public OffscreenContext {

public:
HWND window = nullptr;
HDC deviceContext = nullptr;
HGLRC renderContext = nullptr;

OffscreenContextWGL(int width, int height) : OffscreenContext(width, height) {}
~OffscreenContextWGL() {
wglMakeCurrent(nullptr, nullptr);
if (this->renderContext) wglDeleteContext(this->renderContext);
if (this->deviceContext) ReleaseDC(this->window, this->deviceContext);
if (this->window) DestroyWindow(this->window);
}

std::string getInfo() const override {
std::stringstream result;
// should probably get some info from WGL context here?
result << "GL context creator: WGL (new)\n"
<< "PNG generator: lodepng\n";

return result.str();
}

bool makeCurrent() const override {
return wglMakeCurrent(this->deviceContext, this->renderContext);
}
};

std::shared_ptr<OffscreenContext> CreateOffscreenContextWGL(size_t width, size_t height,
size_t majorGLVersion, size_t minorGLVersion, bool compatibilityProfile)
{
auto ctx = std::make_shared<OffscreenContextWGL>(width, height);

WNDCLASSEX wndClass = {
.cbSize = sizeof(WNDCLASSEX),
.style = CS_OWNDC,
.lpfnWndProc = &DefWindowProc,
.lpszClassName = L"OpenSCAD"
};
static ATOM atom = RegisterClassEx(&wndClass);

// Create the window. Position and size it.
// Style the window and remove the caption bar (WS_POPUP)
ctx->window = CreateWindowEx(0, MAKEINTATOM(atom), L"openscad", WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP,
CW_USEDEFAULT, CW_USEDEFAULT, width, height, 0, 0, 0, 0);
ctx->deviceContext = GetDC(ctx->window);
if (ctx->deviceContext == nullptr) {
std::cerr << "GetDC() failed: " << std::system_category().message(GetLastError()) << std::endl;
return nullptr;
}

PIXELFORMATDESCRIPTOR pixelFormatDesc = {
.nSize = sizeof(PIXELFORMATDESCRIPTOR),
.nVersion = 1,
.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL,
.iPixelType = PFD_TYPE_RGBA,

.cColorBits = 32,
.cDepthBits = 24,
.cStencilBits = 8
};
int pixelFormat = ChoosePixelFormat(ctx->deviceContext, &pixelFormatDesc);
if (!pixelFormat) {
std::cerr << "ChoosePixelFormat() failed: " << std::system_category().message(GetLastError()) << std::endl;
return nullptr;
}

if (!SetPixelFormat(ctx->deviceContext, pixelFormat, &pixelFormatDesc)) {
std::cerr << "SetPixelFormat() failed: " << std::system_category().message(GetLastError()) << std::endl;
return nullptr;
}

const auto tmpRenderContext = wglCreateContext(ctx->deviceContext);
if (tmpRenderContext == nullptr) {
std::cerr << "wglCreateContext() failed: " << std::system_category().message(GetLastError()) << std::endl;
return nullptr;
}
auto guard = sg::make_scope_guard([tmpRenderContext]() {
wglMakeCurrent(nullptr, nullptr);
wglDeleteContext(tmpRenderContext);
});

if (!wglMakeCurrent(ctx->deviceContext, tmpRenderContext)) {
std::cerr << "wglMakeCurrent() failed: " << std::system_category().message(GetLastError()) << std::endl;
return nullptr;
}

auto wglVersion = gladLoaderLoadWGL(ctx->deviceContext);
if (wglVersion == 0) {
std::cerr << "GLAD: Unable to load WGL" << std::endl;
return nullptr;
}
PRINTDB("GLAD: Loaded WGL %d.%d", GLAD_VERSION_MAJOR(wglVersion) % GLAD_VERSION_MINOR(wglVersion));

if (!wglCreateContextAttribsARB) {
std::cerr << "wglCreateContextAttribsARB() not available" << std::endl;
return nullptr;
}

// Note: If we want to use wglChoosePixelFormatARB() to request a special pixel format, we could do that here.

int attributes[] = {
WGL_CONTEXT_MAJOR_VERSION_ARB, static_cast<int>(majorGLVersion),
WGL_CONTEXT_MINOR_VERSION_ARB, static_cast<int>(minorGLVersion),
WGL_CONTEXT_PROFILE_MASK_ARB,
compatibilityProfile ? WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB : WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
0
};
ctx->renderContext = wglCreateContextAttribsARB(ctx->deviceContext, nullptr, attributes);
if (ctx->renderContext == nullptr) {
std::cerr << "wglCreateContextAttribsARB() failed: " << std::system_category().message(GetLastError()) << std::endl;
return nullptr;
}

return ctx;
}
10 changes: 10 additions & 0 deletions src/glview/OffscreenContextWGL.h
@@ -0,0 +1,10 @@
#pragma once

#include <memory>
#include <string>

#include "OffscreenContext.h"

std::shared_ptr<OffscreenContext> CreateOffscreenContextWGL(
size_t width, size_t height, size_t majorGLVersion,
size_t minorGLVersion, bool compatibilityProfile);

0 comments on commit da8b2ce

Please sign in to comment.