Fix OpenGL device initialization and file shaders
This commit is contained in:
@@ -76,12 +76,18 @@ public:
|
|||||||
private:
|
private:
|
||||||
friend class OpenGLSwapChain;
|
friend class OpenGLSwapChain;
|
||||||
|
|
||||||
|
bool AttachWindow(HWND hwnd);
|
||||||
|
bool ConfigureWindowPixelFormat(HDC hdc);
|
||||||
|
bool CreateContextForCurrentWindow();
|
||||||
|
void DestroyOwnedWindow();
|
||||||
|
|
||||||
HDC GetPresentationDC() const { return m_hdc; }
|
HDC GetPresentationDC() const { return m_hdc; }
|
||||||
OpenGLTextureUnitAllocator* GetTextureUnitAllocator() { return m_textureUnitAllocator.get(); }
|
OpenGLTextureUnitAllocator* GetTextureUnitAllocator() { return m_textureUnitAllocator.get(); }
|
||||||
OpenGLUniformBufferManager* GetUniformBufferManager() { return m_uniformBufferManager.get(); }
|
OpenGLUniformBufferManager* GetUniformBufferManager() { return m_uniformBufferManager.get(); }
|
||||||
void SwapBuffers();
|
void SwapBuffers();
|
||||||
|
|
||||||
HWND m_hwnd = nullptr;
|
HWND m_hwnd = nullptr;
|
||||||
|
HWND m_ownedWindow = nullptr;
|
||||||
HDC m_hdc = nullptr;
|
HDC m_hdc = nullptr;
|
||||||
HGLRC m_hglrc = nullptr;
|
HGLRC m_hglrc = nullptr;
|
||||||
RHIDeviceInfo m_deviceInfo;
|
RHIDeviceInfo m_deviceInfo;
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ static PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = nullptr;
|
|||||||
#define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001
|
#define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001
|
||||||
#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
|
#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
|
||||||
#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x0001
|
#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x0001
|
||||||
|
#define XCE_OPENGL_HIDDEN_WINDOW_CLASS L"XCEngineOpenGLHiddenWindow"
|
||||||
|
|
||||||
namespace XCEngine {
|
namespace XCEngine {
|
||||||
namespace RHI {
|
namespace RHI {
|
||||||
@@ -120,6 +121,31 @@ FramebufferAttachmentType ResolveDepthAttachmentType(Format format) {
|
|||||||
: FramebufferAttachmentType::Depth;
|
: 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
|
} // namespace
|
||||||
|
|
||||||
OpenGLDevice::OpenGLDevice()
|
OpenGLDevice::OpenGLDevice()
|
||||||
@@ -136,28 +162,92 @@ OpenGLDevice::~OpenGLDevice() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool OpenGLDevice::Initialize(const RHIDeviceDesc& desc) {
|
bool OpenGLDevice::Initialize(const RHIDeviceDesc& desc) {
|
||||||
|
(void)desc;
|
||||||
if (m_initialized) {
|
if (m_initialized) {
|
||||||
return true;
|
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) {
|
bool OpenGLDevice::InitializeWithExistingWindow(HWND hwnd) {
|
||||||
if (m_initialized) {
|
if (m_initialized) {
|
||||||
return true;
|
return hwnd == m_hwnd ? true : AttachWindow(hwnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hwnd) {
|
if (!hwnd) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_hwnd = hwnd;
|
return AttachWindow(hwnd);
|
||||||
m_hdc = ::GetDC(m_hwnd);
|
}
|
||||||
if (!m_hdc) {
|
|
||||||
|
bool OpenGLDevice::AttachWindow(HWND hwnd) {
|
||||||
|
if (!hwnd) {
|
||||||
return false;
|
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 = {};
|
PIXELFORMATDESCRIPTOR pfd = {};
|
||||||
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
|
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
|
||||||
pfd.nVersion = 1;
|
pfd.nVersion = 1;
|
||||||
@@ -168,23 +258,25 @@ bool OpenGLDevice::InitializeWithExistingWindow(HWND hwnd) {
|
|||||||
pfd.cStencilBits = 8;
|
pfd.cStencilBits = 8;
|
||||||
pfd.iLayerType = PFD_MAIN_PLANE;
|
pfd.iLayerType = PFD_MAIN_PLANE;
|
||||||
|
|
||||||
int pixelFormat = ChoosePixelFormat(m_hdc, &pfd);
|
int pixelFormat = ChoosePixelFormat(hdc, &pfd);
|
||||||
if (!pixelFormat) {
|
if (!pixelFormat) {
|
||||||
ReleaseDC(m_hwnd, m_hdc);
|
|
||||||
m_hdc = nullptr;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!SetPixelFormat(m_hdc, pixelFormat, &pfd)) {
|
if (!SetPixelFormat(hdc, pixelFormat, &pfd)) {
|
||||||
ReleaseDC(m_hwnd, m_hdc);
|
return false;
|
||||||
m_hdc = nullptr;
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenGLDevice::CreateContextForCurrentWindow() {
|
||||||
|
if (m_hdc == nullptr || m_hwnd == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
HGLRC tempRC = wglCreateContext(m_hdc);
|
HGLRC tempRC = wglCreateContext(m_hdc);
|
||||||
if (!tempRC) {
|
if (!tempRC) {
|
||||||
ReleaseDC(m_hwnd, m_hdc);
|
|
||||||
m_hdc = nullptr;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,26 +321,20 @@ bool OpenGLDevice::InitializeWithExistingWindow(HWND hwnd) {
|
|||||||
if (m_hglrc) {
|
if (m_hglrc) {
|
||||||
XCEngine::Debug::Logger::Get().Warning(XCEngine::Debug::LogCategory::General, "Created OpenGL context without debug bit (wglCreateContextAttribsARB failed)");
|
XCEngine::Debug::Logger::Get().Warning(XCEngine::Debug::LogCategory::General, "Created OpenGL context without debug bit (wglCreateContextAttribsARB failed)");
|
||||||
} else {
|
} else {
|
||||||
ReleaseDC(m_hwnd, m_hdc);
|
|
||||||
m_hdc = nullptr;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!wglMakeCurrent(m_hdc, m_hglrc)) {
|
if (!wglMakeCurrent(m_hdc, m_hglrc)) {
|
||||||
wglDeleteContext(m_hglrc);
|
wglDeleteContext(m_hglrc);
|
||||||
ReleaseDC(m_hwnd, m_hdc);
|
|
||||||
m_hglrc = nullptr;
|
m_hglrc = nullptr;
|
||||||
m_hdc = nullptr;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gladLoadGL()) {
|
if (!gladLoadGL()) {
|
||||||
wglMakeCurrent(nullptr, nullptr);
|
wglMakeCurrent(nullptr, nullptr);
|
||||||
wglDeleteContext(m_hglrc);
|
wglDeleteContext(m_hglrc);
|
||||||
ReleaseDC(m_hwnd, m_hdc);
|
|
||||||
m_hglrc = nullptr;
|
m_hglrc = nullptr;
|
||||||
m_hdc = nullptr;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,9 +414,11 @@ void OpenGLDevice::Shutdown() {
|
|||||||
if (m_hdc && m_hwnd) {
|
if (m_hdc && m_hwnd) {
|
||||||
ReleaseDC(m_hwnd, m_hdc);
|
ReleaseDC(m_hwnd, m_hdc);
|
||||||
m_hdc = nullptr;
|
m_hdc = nullptr;
|
||||||
m_hwnd = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_hwnd = nullptr;
|
||||||
|
DestroyOwnedWindow();
|
||||||
|
|
||||||
if (m_uniformBufferManager) {
|
if (m_uniformBufferManager) {
|
||||||
m_uniformBufferManager->Shutdown();
|
m_uniformBufferManager->Shutdown();
|
||||||
}
|
}
|
||||||
@@ -348,6 +436,13 @@ bool OpenGLDevice::MakeContextCurrent() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenGLDevice::DestroyOwnedWindow() {
|
||||||
|
if (m_ownedWindow != nullptr) {
|
||||||
|
DestroyWindow(m_ownedWindow);
|
||||||
|
m_ownedWindow = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void OpenGLDevice::SwapBuffers() {
|
void OpenGLDevice::SwapBuffers() {
|
||||||
if (m_hdc) {
|
if (m_hdc) {
|
||||||
::SwapBuffers(m_hdc);
|
::SwapBuffers(m_hdc);
|
||||||
@@ -451,7 +546,7 @@ RHISwapChain* OpenGLDevice::CreateSwapChain(const SwapChainDesc& desc, RHIComman
|
|||||||
|
|
||||||
auto* swapChain = new OpenGLSwapChain();
|
auto* swapChain = new OpenGLSwapChain();
|
||||||
HWND hwnd = static_cast<HWND>(desc.windowHandle);
|
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;
|
return swapChain;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -472,11 +567,16 @@ RHICommandQueue* OpenGLDevice::CreateCommandQueue(const CommandQueueDesc& desc)
|
|||||||
RHIShader* OpenGLDevice::CreateShader(const ShaderCompileDesc& desc) {
|
RHIShader* OpenGLDevice::CreateShader(const ShaderCompileDesc& desc) {
|
||||||
auto* shader = new OpenGLShader();
|
auto* shader = new OpenGLShader();
|
||||||
|
|
||||||
|
if (!MakeContextCurrent()) {
|
||||||
|
delete shader;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
if (desc.sourceLanguage == ShaderLanguage::GLSL && !desc.source.empty()) {
|
if (desc.sourceLanguage == ShaderLanguage::GLSL && !desc.source.empty()) {
|
||||||
const char* sourceStr = reinterpret_cast<const char*>(desc.source.data());
|
const char* sourceStr = reinterpret_cast<const char*>(desc.source.data());
|
||||||
ShaderType shaderType = ShaderType::Vertex;
|
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) {
|
if (profile.find("vs") != std::string::npos) {
|
||||||
shaderType = ShaderType::Vertex;
|
shaderType = ShaderType::Vertex;
|
||||||
} else if (profile.find("ps") != std::string::npos || profile.find("fs") != std::string::npos) {
|
} 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()) {
|
if (!desc.fileName.empty()) {
|
||||||
std::wstring filePath = desc.fileName;
|
std::wstring filePath = desc.fileName;
|
||||||
std::string entryPoint(desc.entryPoint.begin(), desc.entryPoint.end());
|
std::string entryPoint = NarrowAscii(desc.entryPoint);
|
||||||
std::string profile(desc.profile.begin(), desc.profile.end());
|
std::string profile = NarrowAscii(desc.profile);
|
||||||
shader->CompileFromFile(filePath.c_str(), entryPoint.c_str(), profile.c_str());
|
if (shader->CompileFromFile(filePath.c_str(), entryPoint.c_str(), profile.c_str())) {
|
||||||
return shader;
|
return shader;
|
||||||
|
}
|
||||||
|
delete shader;
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete shader;
|
delete shader;
|
||||||
|
|||||||
@@ -3,10 +3,85 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace XCEngine {
|
namespace XCEngine {
|
||||||
namespace RHI {
|
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()
|
OpenGLShader::OpenGLShader()
|
||||||
: m_program(0), m_uniformsCached(false) {
|
: 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) {
|
bool OpenGLShader::CompileFromFile(const wchar_t* filePath, const char* entryPoint, const char* target) {
|
||||||
std::wstring ws(filePath);
|
(void)entryPoint;
|
||||||
std::string path(ws.begin(), ws.end());
|
|
||||||
return CompileFromFile(path.c_str(), nullptr);
|
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) {
|
bool OpenGLShader::Compile(const void* sourceData, size_t sourceSize, const char* entryPoint, const char* target) {
|
||||||
|
|||||||
@@ -11,21 +11,48 @@ TEST_P(RHITestFixture, Device_Initialize_Shutdown) {
|
|||||||
RHIDevice* device = RHIFactory::CreateRHIDevice(GetBackendType());
|
RHIDevice* device = RHIFactory::CreateRHIDevice(GetBackendType());
|
||||||
ASSERT_NE(device, nullptr);
|
ASSERT_NE(device, nullptr);
|
||||||
|
|
||||||
bool initResult = false;
|
RHIDeviceDesc desc = {};
|
||||||
if (GetBackendType() == RHIType::D3D12) {
|
desc.enableDebugLayer = true;
|
||||||
RHIDeviceDesc desc = {};
|
const bool initResult = device->Initialize(desc);
|
||||||
desc.enableDebugLayer = true;
|
|
||||||
initResult = device->Initialize(desc);
|
|
||||||
} else if (GetBackendType() == RHIType::OpenGL) {
|
|
||||||
auto* oglDevice = static_cast<OpenGLDevice*>(device);
|
|
||||||
initResult = oglDevice->InitializeWithExistingWindow(GetWindowHandle());
|
|
||||||
}
|
|
||||||
ASSERT_TRUE(initResult);
|
ASSERT_TRUE(initResult);
|
||||||
|
|
||||||
device->Shutdown();
|
device->Shutdown();
|
||||||
delete device;
|
delete device;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_P(RHITestFixture, Device_Initialize_OpenGLUnifiedPath_CanCreateSwapChain) {
|
||||||
|
if (GetBackendType() != RHIType::OpenGL) {
|
||||||
|
GTEST_SKIP() << "OpenGL-specific unified initialization verification";
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* device = new OpenGLDevice();
|
||||||
|
ASSERT_NE(device, nullptr);
|
||||||
|
|
||||||
|
RHIDeviceDesc deviceDesc = {};
|
||||||
|
ASSERT_TRUE(device->Initialize(deviceDesc));
|
||||||
|
|
||||||
|
CommandQueueDesc queueDesc = {};
|
||||||
|
queueDesc.queueType = static_cast<uint32_t>(CommandQueueType::Direct);
|
||||||
|
RHICommandQueue* queue = device->CreateCommandQueue(queueDesc);
|
||||||
|
ASSERT_NE(queue, nullptr);
|
||||||
|
|
||||||
|
SwapChainDesc swapDesc = {};
|
||||||
|
swapDesc.windowHandle = GetWindowHandle();
|
||||||
|
swapDesc.width = 320;
|
||||||
|
swapDesc.height = 180;
|
||||||
|
RHISwapChain* swapChain = device->CreateSwapChain(swapDesc, queue);
|
||||||
|
ASSERT_NE(swapChain, nullptr);
|
||||||
|
|
||||||
|
swapChain->Present(0, 0);
|
||||||
|
|
||||||
|
swapChain->Shutdown();
|
||||||
|
delete swapChain;
|
||||||
|
queue->Shutdown();
|
||||||
|
delete queue;
|
||||||
|
device->Shutdown();
|
||||||
|
delete device;
|
||||||
|
}
|
||||||
|
|
||||||
TEST_P(RHITestFixture, Device_GetCapabilities_ReturnsValid) {
|
TEST_P(RHITestFixture, Device_GetCapabilities_ReturnsValid) {
|
||||||
const auto& caps = GetDevice()->GetCapabilities();
|
const auto& caps = GetDevice()->GetCapabilities();
|
||||||
|
|
||||||
|
|||||||
@@ -141,3 +141,39 @@ TEST_P(RHITestFixture, Shader_Shutdown_Invalidates) {
|
|||||||
delete shader;
|
delete shader;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_P(RHITestFixture, Shader_Compile_FromFile_ReturnsValidShader) {
|
||||||
|
ShaderCompileDesc desc = {};
|
||||||
|
if (GetBackendType() == RHIType::D3D12) {
|
||||||
|
desc.fileName = L"tests/RHI/D3D12/integration/quad/Res/Shader/quad.hlsl";
|
||||||
|
desc.entryPoint = L"MainVS";
|
||||||
|
desc.profile = L"vs_5_0";
|
||||||
|
} else {
|
||||||
|
desc.fileName = L"tests/RHI/OpenGL/integration/triangle/Res/Shader/triangle.vert";
|
||||||
|
desc.entryPoint = L"main";
|
||||||
|
desc.profile = L"vs_4_30";
|
||||||
|
}
|
||||||
|
|
||||||
|
RHIShader* shader = GetDevice()->CreateShader(desc);
|
||||||
|
ASSERT_NE(shader, nullptr);
|
||||||
|
EXPECT_TRUE(shader->IsValid());
|
||||||
|
EXPECT_EQ(shader->GetType(), ShaderType::Vertex);
|
||||||
|
shader->Shutdown();
|
||||||
|
delete shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(RHITestFixture, Shader_Compile_MissingFile_ReturnsNullptr) {
|
||||||
|
ShaderCompileDesc desc = {};
|
||||||
|
if (GetBackendType() == RHIType::D3D12) {
|
||||||
|
desc.fileName = L"tests/RHI/D3D12/integration/quad/Res/Shader/does_not_exist.hlsl";
|
||||||
|
desc.entryPoint = L"MainVS";
|
||||||
|
desc.profile = L"vs_5_0";
|
||||||
|
} else {
|
||||||
|
desc.fileName = L"tests/RHI/OpenGL/integration/triangle/Res/Shader/does_not_exist.vert";
|
||||||
|
desc.entryPoint = L"main";
|
||||||
|
desc.profile = L"vs_4_30";
|
||||||
|
}
|
||||||
|
|
||||||
|
RHIShader* shader = GetDevice()->CreateShader(desc);
|
||||||
|
EXPECT_EQ(shader, nullptr);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user