Fix OpenGL device initialization and file shaders
This commit is contained in:
@@ -38,6 +38,7 @@ static PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = nullptr;
|
||||
#define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001
|
||||
#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
|
||||
#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x0001
|
||||
#define XCE_OPENGL_HIDDEN_WINDOW_CLASS L"XCEngineOpenGLHiddenWindow"
|
||||
|
||||
namespace XCEngine {
|
||||
namespace RHI {
|
||||
@@ -120,6 +121,31 @@ FramebufferAttachmentType ResolveDepthAttachmentType(Format format) {
|
||||
: FramebufferAttachmentType::Depth;
|
||||
}
|
||||
|
||||
HWND CreateHiddenOpenGLWindow() {
|
||||
WNDCLASSEXW wc = {};
|
||||
wc.cbSize = sizeof(WNDCLASSEXW);
|
||||
wc.style = CS_OWNDC;
|
||||
wc.lpfnWndProc = DefWindowProcW;
|
||||
wc.hInstance = GetModuleHandle(nullptr);
|
||||
wc.lpszClassName = XCE_OPENGL_HIDDEN_WINDOW_CLASS;
|
||||
|
||||
const ATOM atom = RegisterClassExW(&wc);
|
||||
if (atom == 0 && GetLastError() != ERROR_CLASS_ALREADY_EXISTS) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return CreateWindowExW(
|
||||
0,
|
||||
XCE_OPENGL_HIDDEN_WINDOW_CLASS,
|
||||
L"XCEngineOpenGLHiddenWindow",
|
||||
WS_OVERLAPPED,
|
||||
0, 0, 1, 1,
|
||||
nullptr,
|
||||
nullptr,
|
||||
wc.hInstance,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
OpenGLDevice::OpenGLDevice()
|
||||
@@ -136,28 +162,92 @@ OpenGLDevice::~OpenGLDevice() {
|
||||
}
|
||||
|
||||
bool OpenGLDevice::Initialize(const RHIDeviceDesc& desc) {
|
||||
(void)desc;
|
||||
if (m_initialized) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
m_ownedWindow = CreateHiddenOpenGLWindow();
|
||||
if (!m_ownedWindow) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!AttachWindow(m_ownedWindow)) {
|
||||
DestroyOwnedWindow();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenGLDevice::InitializeWithExistingWindow(HWND hwnd) {
|
||||
if (m_initialized) {
|
||||
return true;
|
||||
return hwnd == m_hwnd ? true : AttachWindow(hwnd);
|
||||
}
|
||||
|
||||
if (!hwnd) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_hwnd = hwnd;
|
||||
m_hdc = ::GetDC(m_hwnd);
|
||||
if (!m_hdc) {
|
||||
return AttachWindow(hwnd);
|
||||
}
|
||||
|
||||
bool OpenGLDevice::AttachWindow(HWND hwnd) {
|
||||
if (!hwnd) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HDC newDC = ::GetDC(hwnd);
|
||||
if (!newDC) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ConfigureWindowPixelFormat(newDC)) {
|
||||
ReleaseDC(hwnd, newDC);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_hglrc != nullptr) {
|
||||
if (!wglMakeCurrent(newDC, m_hglrc)) {
|
||||
ReleaseDC(hwnd, newDC);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_hdc && m_hwnd) {
|
||||
ReleaseDC(m_hwnd, m_hdc);
|
||||
}
|
||||
|
||||
m_hwnd = hwnd;
|
||||
m_hdc = newDC;
|
||||
|
||||
if (m_ownedWindow != nullptr && m_ownedWindow != hwnd) {
|
||||
DestroyOwnedWindow();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
m_hwnd = hwnd;
|
||||
m_hdc = newDC;
|
||||
if (!CreateContextForCurrentWindow()) {
|
||||
ReleaseDC(hwnd, newDC);
|
||||
m_hdc = nullptr;
|
||||
m_hwnd = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenGLDevice::ConfigureWindowPixelFormat(HDC hdc) {
|
||||
if (!hdc) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GetPixelFormat(hdc) != 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
PIXELFORMATDESCRIPTOR pfd = {};
|
||||
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
|
||||
pfd.nVersion = 1;
|
||||
@@ -168,23 +258,25 @@ bool OpenGLDevice::InitializeWithExistingWindow(HWND hwnd) {
|
||||
pfd.cStencilBits = 8;
|
||||
pfd.iLayerType = PFD_MAIN_PLANE;
|
||||
|
||||
int pixelFormat = ChoosePixelFormat(m_hdc, &pfd);
|
||||
int pixelFormat = ChoosePixelFormat(hdc, &pfd);
|
||||
if (!pixelFormat) {
|
||||
ReleaseDC(m_hwnd, m_hdc);
|
||||
m_hdc = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SetPixelFormat(m_hdc, pixelFormat, &pfd)) {
|
||||
ReleaseDC(m_hwnd, m_hdc);
|
||||
m_hdc = nullptr;
|
||||
if (!SetPixelFormat(hdc, pixelFormat, &pfd)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenGLDevice::CreateContextForCurrentWindow() {
|
||||
if (m_hdc == nullptr || m_hwnd == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HGLRC tempRC = wglCreateContext(m_hdc);
|
||||
if (!tempRC) {
|
||||
ReleaseDC(m_hwnd, m_hdc);
|
||||
m_hdc = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -229,26 +321,20 @@ bool OpenGLDevice::InitializeWithExistingWindow(HWND hwnd) {
|
||||
if (m_hglrc) {
|
||||
XCEngine::Debug::Logger::Get().Warning(XCEngine::Debug::LogCategory::General, "Created OpenGL context without debug bit (wglCreateContextAttribsARB failed)");
|
||||
} else {
|
||||
ReleaseDC(m_hwnd, m_hdc);
|
||||
m_hdc = nullptr;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!wglMakeCurrent(m_hdc, m_hglrc)) {
|
||||
wglDeleteContext(m_hglrc);
|
||||
ReleaseDC(m_hwnd, m_hdc);
|
||||
m_hglrc = nullptr;
|
||||
m_hdc = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!gladLoadGL()) {
|
||||
wglMakeCurrent(nullptr, nullptr);
|
||||
wglDeleteContext(m_hglrc);
|
||||
ReleaseDC(m_hwnd, m_hdc);
|
||||
m_hglrc = nullptr;
|
||||
m_hdc = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -328,9 +414,11 @@ void OpenGLDevice::Shutdown() {
|
||||
if (m_hdc && m_hwnd) {
|
||||
ReleaseDC(m_hwnd, m_hdc);
|
||||
m_hdc = nullptr;
|
||||
m_hwnd = nullptr;
|
||||
}
|
||||
|
||||
m_hwnd = nullptr;
|
||||
DestroyOwnedWindow();
|
||||
|
||||
if (m_uniformBufferManager) {
|
||||
m_uniformBufferManager->Shutdown();
|
||||
}
|
||||
@@ -348,6 +436,13 @@ bool OpenGLDevice::MakeContextCurrent() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void OpenGLDevice::DestroyOwnedWindow() {
|
||||
if (m_ownedWindow != nullptr) {
|
||||
DestroyWindow(m_ownedWindow);
|
||||
m_ownedWindow = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLDevice::SwapBuffers() {
|
||||
if (m_hdc) {
|
||||
::SwapBuffers(m_hdc);
|
||||
@@ -451,7 +546,7 @@ RHISwapChain* OpenGLDevice::CreateSwapChain(const SwapChainDesc& desc, RHIComman
|
||||
|
||||
auto* swapChain = new OpenGLSwapChain();
|
||||
HWND hwnd = static_cast<HWND>(desc.windowHandle);
|
||||
if (hwnd && swapChain->Initialize(this, hwnd, desc.width, desc.height)) {
|
||||
if (hwnd && InitializeWithExistingWindow(hwnd) && swapChain->Initialize(this, hwnd, desc.width, desc.height)) {
|
||||
return swapChain;
|
||||
}
|
||||
|
||||
@@ -471,12 +566,17 @@ RHICommandQueue* OpenGLDevice::CreateCommandQueue(const CommandQueueDesc& desc)
|
||||
|
||||
RHIShader* OpenGLDevice::CreateShader(const ShaderCompileDesc& desc) {
|
||||
auto* shader = new OpenGLShader();
|
||||
|
||||
|
||||
if (!MakeContextCurrent()) {
|
||||
delete shader;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (desc.sourceLanguage == ShaderLanguage::GLSL && !desc.source.empty()) {
|
||||
const char* sourceStr = reinterpret_cast<const char*>(desc.source.data());
|
||||
ShaderType shaderType = ShaderType::Vertex;
|
||||
|
||||
std::string profile(desc.profile.begin(), desc.profile.end());
|
||||
|
||||
std::string profile = NarrowAscii(desc.profile);
|
||||
if (profile.find("vs") != std::string::npos) {
|
||||
shaderType = ShaderType::Vertex;
|
||||
} else if (profile.find("ps") != std::string::npos || profile.find("fs") != std::string::npos) {
|
||||
@@ -496,10 +596,13 @@ RHIShader* OpenGLDevice::CreateShader(const ShaderCompileDesc& desc) {
|
||||
|
||||
if (!desc.fileName.empty()) {
|
||||
std::wstring filePath = desc.fileName;
|
||||
std::string entryPoint(desc.entryPoint.begin(), desc.entryPoint.end());
|
||||
std::string profile(desc.profile.begin(), desc.profile.end());
|
||||
shader->CompileFromFile(filePath.c_str(), entryPoint.c_str(), profile.c_str());
|
||||
return shader;
|
||||
std::string entryPoint = NarrowAscii(desc.entryPoint);
|
||||
std::string profile = NarrowAscii(desc.profile);
|
||||
if (shader->CompileFromFile(filePath.c_str(), entryPoint.c_str(), profile.c_str())) {
|
||||
return shader;
|
||||
}
|
||||
delete shader;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
delete shader;
|
||||
|
||||
@@ -3,10 +3,85 @@
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace RHI {
|
||||
|
||||
namespace {
|
||||
|
||||
bool EndsWith(const std::string& value, const char* suffix) {
|
||||
const size_t suffixLength = strlen(suffix);
|
||||
return value.size() >= suffixLength && value.compare(value.size() - suffixLength, suffixLength, suffix) == 0;
|
||||
}
|
||||
|
||||
std::string NarrowAscii(const std::wstring& value) {
|
||||
std::string result;
|
||||
result.reserve(value.size());
|
||||
for (wchar_t ch : value) {
|
||||
result.push_back(static_cast<char>(ch));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ResolveShaderType(const std::string& path, const char* target, ShaderType& type) {
|
||||
if (target != nullptr) {
|
||||
if (strstr(target, "vs_") != nullptr) {
|
||||
type = ShaderType::Vertex;
|
||||
return true;
|
||||
}
|
||||
if (strstr(target, "ps_") != nullptr || strstr(target, "fs_") != nullptr) {
|
||||
type = ShaderType::Fragment;
|
||||
return true;
|
||||
}
|
||||
if (strstr(target, "gs_") != nullptr) {
|
||||
type = ShaderType::Geometry;
|
||||
return true;
|
||||
}
|
||||
if (strstr(target, "cs_") != nullptr) {
|
||||
type = ShaderType::Compute;
|
||||
return true;
|
||||
}
|
||||
if (strstr(target, "hs_") != nullptr || strstr(target, "tcs") != nullptr) {
|
||||
type = ShaderType::TessControl;
|
||||
return true;
|
||||
}
|
||||
if (strstr(target, "ds_") != nullptr || strstr(target, "tes") != nullptr) {
|
||||
type = ShaderType::TessEvaluation;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (EndsWith(path, ".vert") || EndsWith(path, ".vs.glsl")) {
|
||||
type = ShaderType::Vertex;
|
||||
return true;
|
||||
}
|
||||
if (EndsWith(path, ".frag") || EndsWith(path, ".fs.glsl")) {
|
||||
type = ShaderType::Fragment;
|
||||
return true;
|
||||
}
|
||||
if (EndsWith(path, ".geom") || EndsWith(path, ".gs.glsl")) {
|
||||
type = ShaderType::Geometry;
|
||||
return true;
|
||||
}
|
||||
if (EndsWith(path, ".comp") || EndsWith(path, ".cs.glsl")) {
|
||||
type = ShaderType::Compute;
|
||||
return true;
|
||||
}
|
||||
if (EndsWith(path, ".tesc")) {
|
||||
type = ShaderType::TessControl;
|
||||
return true;
|
||||
}
|
||||
if (EndsWith(path, ".tese")) {
|
||||
type = ShaderType::TessEvaluation;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
OpenGLShader::OpenGLShader()
|
||||
: m_program(0), m_uniformsCached(false) {
|
||||
}
|
||||
@@ -211,9 +286,30 @@ bool OpenGLShader::Compile(const char* source, ShaderType type) {
|
||||
}
|
||||
|
||||
bool OpenGLShader::CompileFromFile(const wchar_t* filePath, const char* entryPoint, const char* target) {
|
||||
std::wstring ws(filePath);
|
||||
std::string path(ws.begin(), ws.end());
|
||||
return CompileFromFile(path.c_str(), nullptr);
|
||||
(void)entryPoint;
|
||||
|
||||
if (filePath == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::wstring ws(filePath);
|
||||
const std::string path = NarrowAscii(ws);
|
||||
|
||||
std::ifstream shaderFile(path);
|
||||
if (!shaderFile.is_open()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::stringstream shaderStream;
|
||||
shaderStream << shaderFile.rdbuf();
|
||||
|
||||
ShaderType type = ShaderType::Vertex;
|
||||
if (!ResolveShaderType(path, target, type)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::string source = shaderStream.str();
|
||||
return Compile(source.c_str(), type);
|
||||
}
|
||||
|
||||
bool OpenGLShader::Compile(const void* sourceData, size_t sourceSize, const char* entryPoint, const char* target) {
|
||||
@@ -340,4 +436,4 @@ bool OpenGLShader::CheckLinkErrors(unsigned int program) {
|
||||
}
|
||||
|
||||
} // namespace RHI
|
||||
} // namespace XCEngine
|
||||
} // namespace XCEngine
|
||||
|
||||
Reference in New Issue
Block a user