#define WIN32_LEAN_AND_MEAN #define NOMINMAX #include #include #include "XCEngine/RHI/OpenGL/OpenGLDevice.h" #include "XCEngine/RHI/OpenGL/OpenGLBuffer.h" #include "XCEngine/RHI/OpenGL/OpenGLTexture.h" #include "XCEngine/RHI/OpenGL/OpenGLShader.h" #include "XCEngine/RHI/OpenGL/OpenGLPipelineState.h" #include "XCEngine/RHI/OpenGL/OpenGLFence.h" #include "XCEngine/RHI/OpenGL/OpenGLSampler.h" #include "XCEngine/RHI/OpenGL/OpenGLCommandList.h" #include "XCEngine/RHI/OpenGL/OpenGLCommandQueue.h" #include "XCEngine/RHI/OpenGL/OpenGLSwapChain.h" #include "XCEngine/RHI/OpenGL/OpenGLTextureUnitAllocator.h" #include "XCEngine/RHI/OpenGL/OpenGLUniformBufferManager.h" #include "XCEngine/RHI/OpenGL/OpenGLFramebuffer.h" #include "XCEngine/RHI/OpenGL/OpenGLRenderPass.h" #include "XCEngine/RHI/OpenGL/OpenGLResourceView.h" #include "XCEngine/RHI/OpenGL/OpenGLDescriptorPool.h" #include "XCEngine/RHI/OpenGL/OpenGLDescriptorSet.h" #include "XCEngine/Debug/Logger.h" typedef const char* (WINAPI* PFNWGLGETEXTENSIONSSTRINGARBPROC)(HDC hdc); typedef BOOL (WINAPI* PFNWGLCHOOSEPIXELFORMATARBPROC)(HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats); typedef HGLRC (WINAPI* PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC hdc, HGLRC hShareContext, const int* attribList); static PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = nullptr; static PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = nullptr; static PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = nullptr; #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 #define WGL_CONTEXT_FLAGS_ARB 0x2094 #define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001 #define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 #define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x0001 namespace XCEngine { namespace RHI { OpenGLDevice::OpenGLDevice() : m_hwnd(nullptr) , m_hdc(nullptr) , m_hglrc(nullptr) , m_initialized(false) { m_textureUnitAllocator = std::make_unique(); m_uniformBufferManager = std::make_unique(); } OpenGLDevice::~OpenGLDevice() { Shutdown(); } bool OpenGLDevice::Initialize(const RHIDeviceDesc& desc) { if (m_initialized) { return true; } return false; } bool OpenGLDevice::InitializeWithExistingWindow(HWND hwnd) { if (m_initialized) { return true; } if (!hwnd) { return false; } m_hwnd = hwnd; m_hdc = ::GetDC(m_hwnd); if (!m_hdc) { return false; } PIXELFORMATDESCRIPTOR pfd = {}; 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 = 24; pfd.cStencilBits = 8; pfd.iLayerType = PFD_MAIN_PLANE; int pixelFormat = ChoosePixelFormat(m_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; return false; } HGLRC tempRC = wglCreateContext(m_hdc); if (!tempRC) { ReleaseDC(m_hwnd, m_hdc); m_hdc = nullptr; return false; } if (!wglMakeCurrent(m_hdc, tempRC)) { wglDeleteContext(tempRC); ReleaseDC(m_hwnd, m_hdc); m_hdc = nullptr; return false; } wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB"); if (wglGetExtensionsStringARB) { const char* extensions = wglGetExtensionsStringARB(m_hdc); if (extensions && strstr(extensions, "WGL_ARB_pixel_format")) { wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB"); } if (extensions && strstr(extensions, "WGL_ARB_create_context")) { wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB"); } } wglMakeCurrent(nullptr, nullptr); wglDeleteContext(tempRC); if (wglCreateContextAttribsARB) { int debugAttribs[] = { WGL_CONTEXT_MAJOR_VERSION_ARB, 4, WGL_CONTEXT_MINOR_VERSION_ARB, 6, WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB, WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, 0, 0 }; m_hglrc = wglCreateContextAttribsARB(m_hdc, nullptr, debugAttribs); if (m_hglrc) { XCEngine::Debug::Logger::Get().Info(XCEngine::Debug::LogCategory::General, "Created OpenGL debug context with WGL_ARB_create_context"); } } if (!m_hglrc) { m_hglrc = wglCreateContext(m_hdc); 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; } GLint contextFlags = 0; glGetIntegerv(GL_CONTEXT_FLAGS, &contextFlags); if (contextFlags & GL_CONTEXT_FLAG_DEBUG_BIT) { XCEngine::Debug::Logger::Get().Info(XCEngine::Debug::LogCategory::General, "OpenGL debug context is active"); } else { XCEngine::Debug::Logger::Get().Warning(XCEngine::Debug::LogCategory::General, "OpenGL debug context is NOT active"); } const char* vendor = reinterpret_cast(glGetString(GL_VENDOR)); const char* renderer = reinterpret_cast(glGetString(GL_RENDERER)); const char* version = reinterpret_cast(glGetString(GL_VERSION)); m_deviceInfo.vendor = std::wstring(vendor ? vendor : "", vendor ? vendor + strlen(vendor) : nullptr); m_deviceInfo.renderer = std::wstring(renderer ? renderer : "", renderer ? renderer + strlen(renderer) : nullptr); m_deviceInfo.version = std::wstring(version ? version : "", version ? version + strlen(version) : nullptr); GLint majorVersion = 0, minorVersion = 0; glGetIntegerv(GL_MAJOR_VERSION, &majorVersion); glGetIntegerv(GL_MINOR_VERSION, &minorVersion); m_deviceInfo.majorVersion = static_cast(majorVersion); m_deviceInfo.minorVersion = static_cast(minorVersion); m_capabilities.majorVersion = majorVersion; m_capabilities.minorVersion = minorVersion; m_capabilities.bSupportsGeometryShaders = true; m_capabilities.bSupportsComputeShaders = GLVersion.major >= 4 && GLVersion.minor >= 3; m_capabilities.bSupportsTessellation = GLVersion.major >= 4 && GLVersion.minor >= 1; m_capabilities.bSupportsExplicitMultiThreading = false; GLint maxTexSize = 0; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize); m_capabilities.maxTexture2DSize = static_cast(maxTexSize); GLint maxCubeSize = 0; glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &maxCubeSize); m_capabilities.maxTextureCubeSize = static_cast(maxCubeSize); GLint maxRenderTargets = 0; glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxRenderTargets); m_capabilities.maxRenderTargets = static_cast(maxRenderTargets); m_capabilities.maxColorAttachments = static_cast(maxRenderTargets); GLint maxViewports = 0; glGetIntegerv(GL_MAX_VIEWPORTS, &maxViewports); m_capabilities.maxViewports = static_cast(maxViewports); GLint maxAnisotropy = 0; glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY, &maxAnisotropy); m_capabilities.maxAnisotropy = static_cast(maxAnisotropy); GLint maxAttribs = 0; glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttribs); m_capabilities.maxVertexAttribs = static_cast(maxAttribs); GLint maxTextureUnits = 0; glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits); m_textureUnitAllocator->Initialize(static_cast(maxTextureUnits)); GLint maxUniformBlocks = 0; glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &maxUniformBlocks); m_uniformBufferManager->Initialize(static_cast(maxUniformBlocks)); m_initialized = true; return true; } void OpenGLDevice::Shutdown() { if (m_hglrc) { wglMakeCurrent(nullptr, nullptr); wglDeleteContext(m_hglrc); m_hglrc = nullptr; } if (m_hdc && m_hwnd) { ReleaseDC(m_hwnd, m_hdc); m_hdc = nullptr; m_hwnd = nullptr; } if (m_uniformBufferManager) { m_uniformBufferManager->Shutdown(); } if (m_textureUnitAllocator) { m_textureUnitAllocator->Shutdown(); } m_initialized = false; } bool OpenGLDevice::MakeContextCurrent() { if (m_hdc && m_hglrc) { return ::wglMakeCurrent(m_hdc, m_hglrc) == TRUE; } return false; } void OpenGLDevice::SwapBuffers() { if (m_hdc) { ::SwapBuffers(m_hdc); } } RHIBuffer* OpenGLDevice::CreateBuffer(const BufferDesc& desc) { auto* buffer = new OpenGLBuffer(); OpenGLBufferType bufferType = OpenGLBufferType::Vertex; switch (desc.bufferType) { case 1: bufferType = OpenGLBufferType::Index; break; case 2: bufferType = OpenGLBufferType::Uniform; break; default: bufferType = OpenGLBufferType::Vertex; break; } buffer->Initialize(bufferType, desc.size, nullptr, false); buffer->SetStride(desc.stride); return buffer; } RHITexture* OpenGLDevice::CreateTexture(const TextureDesc& desc) { auto* texture = new OpenGLTexture(); OpenGLTextureType type = OpenGLTextureType::Texture2D; switch (desc.textureType) { case 0: type = OpenGLTextureType::Texture1D; break; case 2: type = OpenGLTextureType::Texture2DArray; break; case 3: type = OpenGLTextureType::Texture3D; break; case 4: type = OpenGLTextureType::TextureCube; break; default: type = OpenGLTextureType::Texture2D; break; } OpenGLFormat format = OpenGLFormat::RGBA8; switch (desc.format) { case 1: format = OpenGLFormat::R8; break; case 2: format = OpenGLFormat::RG8; break; case 3: format = OpenGLFormat::RGBA8; break; case 4: format = OpenGLFormat::RGBA16F; break; case 5: format = OpenGLFormat::RGBA32F; break; case 6: format = OpenGLFormat::RGBA16F; break; case 7: format = OpenGLFormat::RGBA32F; break; case 8: format = OpenGLFormat::Depth24Stencil8; break; case 9: format = OpenGLFormat::Depth32F; break; default: format = OpenGLFormat::RGBA8; break; } texture->Initialize(type, desc.width, desc.height, desc.depth, desc.mipLevels, format, nullptr); texture->SetFormat(static_cast(desc.format)); return texture; } RHISwapChain* OpenGLDevice::CreateSwapChain(const SwapChainDesc& desc) { auto* swapChain = new OpenGLSwapChain(); HWND hwnd = static_cast(desc.windowHandle); if (hwnd) { swapChain->Initialize(this, hwnd, desc.width, desc.height); } return swapChain; } RHICommandList* OpenGLDevice::CreateCommandList(const CommandListDesc& desc) { auto* cmdList = new OpenGLCommandList(); return cmdList; } RHICommandQueue* OpenGLDevice::CreateCommandQueue(const CommandQueueDesc& desc) { auto* queue = new OpenGLCommandQueue(); return queue; } RHIShader* OpenGLDevice::CreateShader(const ShaderCompileDesc& desc) { auto* shader = new OpenGLShader(); if (desc.sourceLanguage == ShaderLanguage::GLSL && !desc.source.empty()) { const char* sourceStr = reinterpret_cast(desc.source.data()); ShaderType shaderType = ShaderType::Vertex; std::string profile(desc.profile.begin(), desc.profile.end()); if (profile.find("vs") != std::string::npos) { shaderType = ShaderType::Vertex; } else if (profile.find("ps") != std::string::npos || profile.find("fs") != std::string::npos) { shaderType = ShaderType::Fragment; } else if (profile.find("gs") != std::string::npos) { shaderType = ShaderType::Geometry; } else if (profile.find("cs") != std::string::npos) { shaderType = ShaderType::Compute; } if (shader->Compile(sourceStr, shaderType)) { return shader; } delete shader; return nullptr; } 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; } delete shader; return nullptr; } RHIPipelineState* OpenGLDevice::CreatePipelineState(const GraphicsPipelineDesc& desc) { auto* pso = new OpenGLPipelineState(); pso->SetInputLayout(desc.inputLayout); pso->SetRasterizerState(desc.rasterizerState); pso->SetBlendState(desc.blendState); pso->SetDepthStencilState(desc.depthStencilState); pso->SetTopology(desc.topologyType); pso->SetRenderTargetFormats(desc.renderTargetCount, desc.renderTargetFormats, desc.depthStencilFormat); pso->SetSampleCount(desc.sampleCount); return pso; } RHIPipelineLayout* OpenGLDevice::CreatePipelineLayout(const RHIPipelineLayoutDesc& desc) { return nullptr; } RHIFence* OpenGLDevice::CreateFence(const FenceDesc& desc) { auto* fence = new OpenGLFence(); fence->Initialize(desc.initialValue > 0); return fence; } RHISampler* OpenGLDevice::CreateSampler(const SamplerDesc& desc) { auto* sampler = new OpenGLSampler(); OpenGLSamplerDesc samplerDesc = {}; sampler->Initialize(samplerDesc); return sampler; } RHIRenderPass* OpenGLDevice::CreateRenderPass( uint32_t colorAttachmentCount, const AttachmentDesc* colorAttachments, const AttachmentDesc* depthStencilAttachment) { auto* renderPass = new OpenGLRenderPass(); if (!renderPass->Initialize(colorAttachmentCount, colorAttachments, depthStencilAttachment)) { delete renderPass; return nullptr; } return renderPass; } RHIFramebuffer* OpenGLDevice::CreateFramebuffer( class RHIRenderPass* renderPass, uint32_t width, uint32_t height, uint32_t colorAttachmentCount, RHIResourceView** colorAttachments, RHIResourceView* depthStencilAttachment) { auto* framebuffer = new OpenGLFramebuffer(); if (!framebuffer->Initialize(renderPass, width, height, colorAttachmentCount, colorAttachments, depthStencilAttachment)) { delete framebuffer; return nullptr; } return framebuffer; } RHIDescriptorPool* OpenGLDevice::CreateDescriptorPool(const DescriptorPoolDesc& desc) { auto* pool = new OpenGLDescriptorPool(); if (pool->Initialize(desc)) { pool->SetTextureUnitAllocator(m_textureUnitAllocator.get()); return pool; } delete pool; return nullptr; } RHIDescriptorSet* OpenGLDevice::CreateDescriptorSet(RHIDescriptorPool* pool, const DescriptorSetLayoutDesc& layout) { if (pool == nullptr) { return nullptr; } return pool->AllocateSet(layout); } RHIResourceView* OpenGLDevice::CreateRenderTargetView(RHITexture* texture, const ResourceViewDesc& desc) { if (!texture) { return nullptr; } auto* glTexture = static_cast(texture); FramebufferDesc fbDesc = {}; fbDesc.width = static_cast(texture->GetWidth()); fbDesc.height = static_cast(texture->GetHeight()); FramebufferAttachment colorAttachment = {}; colorAttachment.texture = glTexture->GetID(); colorAttachment.mipLevel = static_cast(desc.mipLevel); colorAttachment.type = FramebufferAttachmentType::Color; colorAttachment.format = desc.format; fbDesc.colorAttachments.push_back(colorAttachment); auto* framebuffer = new OpenGLFramebuffer(); if (!framebuffer->Initialize(fbDesc)) { delete framebuffer; return nullptr; } auto* view = new OpenGLResourceView(); if (!view->InitializeAsRenderTarget(glTexture, desc, framebuffer)) { delete framebuffer; delete view; return nullptr; } return view; } RHIResourceView* OpenGLDevice::CreateDepthStencilView(RHITexture* texture, const ResourceViewDesc& desc) { if (!texture) { return nullptr; } auto* glTexture = static_cast(texture); FramebufferDesc fbDesc = {}; fbDesc.width = static_cast(texture->GetWidth()); fbDesc.height = static_cast(texture->GetHeight()); FramebufferAttachment depthAttachment = {}; depthAttachment.texture = glTexture->GetID(); depthAttachment.mipLevel = static_cast(desc.mipLevel); depthAttachment.type = FramebufferAttachmentType::DepthStencil; depthAttachment.format = desc.format; fbDesc.depthAttachment = depthAttachment; auto* framebuffer = new OpenGLFramebuffer(); if (!framebuffer->Initialize(fbDesc)) { delete framebuffer; return nullptr; } auto* view = new OpenGLResourceView(); if (!view->InitializeAsDepthStencil(glTexture, desc, framebuffer)) { delete framebuffer; delete view; return nullptr; } return view; } RHIResourceView* OpenGLDevice::CreateShaderResourceView(RHITexture* texture, const ResourceViewDesc& desc) { if (!texture) { return nullptr; } auto* glTexture = static_cast(texture); auto* view = new OpenGLResourceView(); if (!view->InitializeAsShaderResource(glTexture, desc, m_textureUnitAllocator.get())) { delete view; return nullptr; } return view; } RHIResourceView* OpenGLDevice::CreateUnorderedAccessView(RHITexture* texture, const ResourceViewDesc& desc) { if (!texture) { return nullptr; } auto* glTexture = static_cast(texture); auto* view = new OpenGLResourceView(); if (!view->InitializeAsUnorderedAccess(glTexture, desc, m_textureUnitAllocator.get())) { delete view; return nullptr; } return view; } const RHICapabilities& OpenGLDevice::GetCapabilities() const { return m_capabilities; } const RHIDeviceInfo& OpenGLDevice::GetDeviceInfo() const { return m_deviceInfo; } void* OpenGLDevice::GetNativeDevice() { return m_hglrc; } void* OpenGLDevice::GetNativeHandle() const { return nullptr; } } // namespace RHI } // namespace XCEngine