Skip to content

Commit

Permalink
#5336: Add HeadlessOpenGLContext module (Windows-only at the moment b…
Browse files Browse the repository at this point in the history
…eing).

This relies on new GLEW dependencies present in the windeps repository.
  • Loading branch information
codereader committed Sep 20, 2020
1 parent 59ff547 commit 8bbf340
Show file tree
Hide file tree
Showing 6 changed files with 168 additions and 17 deletions.
15 changes: 0 additions & 15 deletions include/igl.h
Expand Up @@ -18,21 +18,6 @@ class IGLContext
virtual ~IGLContext() {}
};

// An IGLContextProvider implementation must be able
// to create a valid context and return it as an object
// deriving from IGLContext
// Only one IGLContextProvider-implementing module is
// allowed in a given set of modules.
class IGLContextProvider :
public RegisterableModule
{
public:
virtual ~IGLContextProvider() {}

// Create a GL context and return it
virtual IGLContext::Ptr createContext() = 0;
};

// Interface of the module holding the shared GL context
// of this application. When the shared GL context has been
// created or destroyed, the corresponding events are fired.
Expand Down
108 changes: 108 additions & 0 deletions test/HeadlessOpenGLContext.cpp
@@ -0,0 +1,108 @@
#include "HeadlessOpenGLContext.h"

#ifdef WIN32
#include <GL/wglew.h>
#endif

namespace gl
{

#ifdef WIN32
class HeadlessOpenGLContext :
public IGLContext
{
private:
HGLRC _context;
static HGLRC _tempContext;
public:
HeadlessOpenGLContext()
{
MSG msg = { 0 };
WNDCLASS wc = { 0 };
wc.lpfnWndProc = WndProc;
wc.hInstance = ::GetModuleHandle(nullptr);
wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
wc.lpszClassName = L"testwindow";
wc.style = CS_OWNDC;

if (!RegisterClass(&wc)) throw std::runtime_error("Failed to register the window class");

CreateWindowW(wc.lpszClassName, L"testwindow", WS_OVERLAPPEDWINDOW, 0, 0, 640, 480, 0, 0, wc.hInstance, 0);

while (_tempContext == nullptr && PeekMessage(&msg, NULL, 0, 0, 0) > 0)
{
DispatchMessage(&msg);
}

_context = _tempContext;
_tempContext = nullptr;
}

~HeadlessOpenGLContext()
{
if (_context)
{
wglDeleteContext(_context);
}
}

private:
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
{
PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, //Flags
PFD_TYPE_RGBA,
32, // color depth.
0, 0, 0, 0, 0, 0,
0,
0,
0,
0, 0, 0, 0,
24, // depth buffer bits
8, // stencil bits
0, // aux buffers.
PFD_MAIN_PLANE,
0,
0, 0, 0
};

auto deviceContext = GetDC(hWnd);
int pixelFormat = ChoosePixelFormat(deviceContext, &pfd);

SetPixelFormat(deviceContext, pixelFormat, &pfd);

_tempContext = wglCreateContext(deviceContext);
wglMakeCurrent(deviceContext, _tempContext);
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
};

HGLRC HeadlessOpenGLContext::_tempContext;

#endif

void HeadlessOpenGLContextModule::initialiseModule(const IApplicationContext& ctx)
{}

void HeadlessOpenGLContextModule::createContext()
{
#ifdef WIN32
GlobalOpenGLContext().setSharedContext(std::make_shared<HeadlessOpenGLContext>());
#else
#error "Headless openGL context not implemented for this platform."
#endif
}

}
42 changes: 42 additions & 0 deletions test/HeadlessOpenGLContext.h
@@ -0,0 +1,42 @@
#pragma once

#include "imodule.h"
#include "igl.h"

namespace gl
{

class HeadlessOpenGLContextModule :
public RegisterableModule
{
public:
void createContext();

// Inherited via RegisterableModule
const std::string& getName() const override
{
static std::string _name("HeadlessOpenGLContext");
return _name;
}

const StringSet& getDependencies() const override
{
static StringSet _dependencies;

if (_dependencies.empty())
{
_dependencies.insert(MODULE_SHARED_GL_CONTEXT);
}

return _dependencies;
}

void initialiseModule(const IApplicationContext& ctx) override;

void shutdownModule()
{
GlobalOpenGLContext().setSharedContext(IGLContext::Ptr());
}
};

}
12 changes: 11 additions & 1 deletion test/RadiantTest.h
Expand Up @@ -10,6 +10,7 @@
#include "icommandsystem.h"

#include "TestContext.h"
#include "HeadlessOpenGLContext.h"
#include "module/CoreModule.h"
#include "messages/GameConfigNeededMessage.h"

Expand All @@ -29,6 +30,8 @@ class RadiantTest :

std::size_t _gameSetupListener;

std::shared_ptr<gl::HeadlessOpenGLContextModule> _glContextModule;

protected:
RadiantTest()
{
Expand Down Expand Up @@ -58,6 +61,7 @@ class RadiantTest :
{
// Set up the test game environment
setupGameFolder();
setupOpenGLContext();

// Wire up the game-config-needed handler, we need to respond
_gameSetupListener = _coreModule->get()->getMessageBus().addListener(
Expand All @@ -76,6 +80,8 @@ class RadiantTest :
rError() << "Unhandled Exception: " << ex.what() << std::endl;
abort();
}

_glContextModule->createContext();
}

void TearDown() override
Expand All @@ -93,8 +99,12 @@ class RadiantTest :

protected:
virtual void setupGameFolder()
{}

virtual void setupOpenGLContext()
{

_glContextModule = std::make_shared<gl::HeadlessOpenGLContextModule>();
_coreModule->get()->getModuleRegistry().registerModule(_glContextModule);
}

virtual void loadMap(const std::string& modRelativePath)
Expand Down
6 changes: 6 additions & 0 deletions tools/msvc/Tests/Tests.vcxproj
Expand Up @@ -33,29 +33,35 @@
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="..\properties\DarkRadiant Base Debug x64.props" />
<Import Project="..\properties\Tests.props" />
<Import Project="..\properties\GLEW.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="..\properties\DarkRadiant Base Debug Win32.props" />
<Import Project="..\properties\Tests.props" />
<Import Project="..\properties\GLEW.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="..\properties\DarkRadiant Base Release Win32.props" />
<Import Project="..\properties\Tests.props" />
<Import Project="..\properties\GLEW.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="..\properties\DarkRadiant Base Release x64.props" />
<Import Project="..\properties\Tests.props" />
<Import Project="..\properties\GLEW.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\test\HeadlessOpenGLContext.h" />
<ClInclude Include="..\..\..\test\RadiantTest.h" />
<ClInclude Include="..\..\..\test\TestContext.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\test\CSG.cpp" />
<ClCompile Include="..\..\..\test\HeadlessOpenGLContext.cpp" />
<ClCompile Include="..\..\..\test\test.cpp" />
</ItemGroup>
<ItemDefinitionGroup />
Expand Down
2 changes: 1 addition & 1 deletion tools/msvc/post_build_event_x64.cmd
Expand Up @@ -4,7 +4,7 @@ del ..\..\install\python*.zip

copy ..\..\w64deps\openal\bin\OpenAL32.dll ..\..\install /Y
copy ..\..\w64deps\openal\bin\wrap_oal.dll ..\..\install /Y
copy ..\..\w64deps\glew\lib\glew32.dll ..\..\install /Y
copy ..\..\w64deps\glew\bin\glew32.dll ..\..\install /Y
copy ..\..\w64deps\python\bin\python3*.dll ..\..\install /Y
copy ..\..\w64deps\python\bin\python3*.zip ..\..\install /Y

Expand Down

0 comments on commit 8bbf340

Please sign in to comment.