// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) // This file is part of the "Nazara Engine - OpenGL renderer" // For conditions of distribution and use, see copyright notice in Config.hpp #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Nz { OpenGLDevice::OpenGLDevice(GL::Loader& loader, const Renderer::Config& config) : m_loader(loader) { GL::ContextParams params; params.type = loader.GetPreferredContextType(); params.validationLevel = config.validationLevel; #ifdef NAZARA_OPENGLRENDERER_DEBUG params.wrapErrorHandling = true; #endif m_referenceContext = loader.CreateContext(this, params); if (!m_referenceContext) throw std::runtime_error("failed to create reference context"); if (!GL::Context::SetCurrentContext(m_referenceContext.get())) throw std::runtime_error("failed to activate reference context"); const GLubyte* vendorStr = m_referenceContext->glGetString(GL_VENDOR); const GLubyte* rendererStr = m_referenceContext->glGetString(GL_RENDERER); m_deviceInfo.name = "OpenGL Device ("; if (vendorStr) m_deviceInfo.name.append(reinterpret_cast(vendorStr)); if (rendererStr) { if (vendorStr) m_deviceInfo.name += " - "; m_deviceInfo.name.append(reinterpret_cast(rendererStr)); } m_deviceInfo.name += ')'; m_deviceInfo.type = RenderDeviceType::Unknown; // Features if (m_referenceContext->IsExtensionSupported(GL::Extension::TextureFilterAnisotropic)) m_deviceInfo.features.anisotropicFiltering = true; if (m_referenceContext->IsExtensionSupported(GL::Extension::ComputeShader)) m_deviceInfo.features.computeShaders = true; if (m_referenceContext->IsExtensionSupported(GL::Extension::DepthClamp)) m_deviceInfo.features.depthClamping = true; if (m_referenceContext->glPolygonMode) //< not supported in core OpenGL ES, but supported in OpenGL or with GL_NV_polygon_mode extension m_deviceInfo.features.nonSolidFaceFilling = true; if (m_referenceContext->IsExtensionSupported(GL::Extension::StorageBuffers)) m_deviceInfo.features.storageBuffers = true; if (m_referenceContext->IsExtensionSupported(GL::Extension::ShaderImageLoadStore)) { m_deviceInfo.features.textureReadWrite = true; m_deviceInfo.features.textureWriteWithoutFormat = true; } if (m_referenceContext->IsExtensionSupported(GL::Extension::ShaderImageLoadFormatted)) m_deviceInfo.features.textureReadWithoutFormat = true; if (m_referenceContext->IsExtensionSupported(GL::Extension::TextureView)) m_deviceInfo.features.unrestrictedTextureViews = true; // Limits m_deviceInfo.limits.maxUniformBufferSize = m_referenceContext->GetInteger(GL_MAX_UNIFORM_BLOCK_SIZE); m_deviceInfo.limits.minUniformBufferOffsetAlignment = m_referenceContext->GetInteger(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT); if (m_deviceInfo.features.storageBuffers) { m_deviceInfo.limits.maxStorageBufferSize = m_referenceContext->GetInteger(GL_MAX_SHADER_STORAGE_BLOCK_SIZE); m_deviceInfo.limits.minStorageBufferOffsetAlignment = m_referenceContext->GetInteger(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT); } if (m_deviceInfo.features.computeShaders) { m_deviceInfo.limits.maxComputeSharedMemorySize = m_referenceContext->GetInteger(GL_MAX_COMPUTE_SHARED_MEMORY_SIZE); m_deviceInfo.limits.maxComputeWorkGroupInvocations = m_referenceContext->GetInteger(GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS); m_deviceInfo.limits.maxComputeWorkGroupCount = { m_referenceContext->GetInteger(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0), m_referenceContext->GetInteger(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1), m_referenceContext->GetInteger(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2) }; m_deviceInfo.limits.maxComputeWorkGroupSize = { m_referenceContext->GetInteger(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0), m_referenceContext->GetInteger(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 1), m_referenceContext->GetInteger(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 2) }; } m_contexts.insert(m_referenceContext.get()); } OpenGLDevice::~OpenGLDevice() { // Free reference context first as it will unregister itself from m_contexts m_referenceContext.reset(); } std::unique_ptr OpenGLDevice::CreateContext(GL::ContextParams params) const { params.type = m_referenceContext->GetParams().type; auto contextPtr = m_loader.CreateContext(this, params, m_referenceContext.get()); m_contexts.insert(contextPtr.get()); return contextPtr; } std::unique_ptr OpenGLDevice::CreateContext(GL::ContextParams params, WindowHandle handle) const { params.type = m_referenceContext->GetParams().type; auto contextPtr = m_loader.CreateContext(this, params, handle, m_referenceContext.get()); m_contexts.insert(contextPtr.get()); return contextPtr; } const RenderDeviceInfo& OpenGLDevice::GetDeviceInfo() const { return m_deviceInfo; } const RenderDeviceFeatures& OpenGLDevice::GetEnabledFeatures() const { //FIXME return m_deviceInfo.features; } std::shared_ptr OpenGLDevice::InstantiateBuffer(BufferType type, UInt64 size, BufferUsageFlags usageFlags, const void* initialData) { return std::make_shared(*this, type, size, usageFlags, initialData); } std::shared_ptr OpenGLDevice::InstantiateCommandPool(QueueType /*queueType*/) { return std::make_shared(); } std::shared_ptr OpenGLDevice::InstantiateComputePipeline(ComputePipelineInfo pipelineInfo) { return std::make_shared(*this, std::move(pipelineInfo)); } std::shared_ptr OpenGLDevice::InstantiateFramebuffer(unsigned int /*width*/, unsigned int /*height*/, const std::shared_ptr& /*renderPass*/, const std::vector>& attachments) { return std::make_shared(*this, attachments); } std::shared_ptr OpenGLDevice::InstantiateRenderPass(std::vector attachments, std::vector subpassDescriptions, std::vector subpassDependencies) { return std::make_shared(std::move(attachments), std::move(subpassDescriptions), std::move(subpassDependencies)); } std::shared_ptr OpenGLDevice::InstantiateRenderPipeline(RenderPipelineInfo pipelineInfo) { return std::make_shared(*this, std::move(pipelineInfo)); } std::shared_ptr OpenGLDevice::InstantiateRenderPipelineLayout(RenderPipelineLayoutInfo pipelineLayoutInfo) { return std::make_shared(std::move(pipelineLayoutInfo)); } std::shared_ptr OpenGLDevice::InstantiateShaderModule(nzsl::ShaderStageTypeFlags shaderStages, const nzsl::Ast::Module& shaderModule, const nzsl::ShaderWriter::States& states) { return std::make_shared(*this, shaderStages, shaderModule, states); } std::shared_ptr OpenGLDevice::InstantiateShaderModule(nzsl::ShaderStageTypeFlags shaderStages, ShaderLanguage lang, const void* source, std::size_t sourceSize, const nzsl::ShaderWriter::States& states) { return std::make_shared(*this, shaderStages, lang, source, sourceSize, states); } std::shared_ptr OpenGLDevice::InstantiateSwapchain(WindowHandle windowHandle, const Vector2ui& windowSize, const SwapchainParameters& parameters) { return std::make_shared(*this, windowHandle, windowSize, parameters); } std::shared_ptr OpenGLDevice::InstantiateTexture(const TextureInfo& params) { return std::make_shared(*this, params); } std::shared_ptr OpenGLDevice::InstantiateTextureSampler(const TextureSamplerInfo& params) { return std::make_shared(*this, params); } bool OpenGLDevice::IsTextureFormatSupported(PixelFormat format, TextureUsage usage) const { switch (format) { case PixelFormat::Undefined: return false; case PixelFormat::A8: case PixelFormat::BGR8: case PixelFormat::BGR8_SRGB: case PixelFormat::BGRA8: case PixelFormat::BGRA8_SRGB: case PixelFormat::L8: case PixelFormat::LA8: case PixelFormat::R8: case PixelFormat::R8I: case PixelFormat::R8UI: case PixelFormat::R16: case PixelFormat::R16F: case PixelFormat::R16I: case PixelFormat::R16UI: case PixelFormat::R32F: case PixelFormat::R32I: case PixelFormat::R32UI: case PixelFormat::RG8: case PixelFormat::RG8I: case PixelFormat::RG8UI: case PixelFormat::RG16: case PixelFormat::RG16F: case PixelFormat::RG16I: case PixelFormat::RG16UI: case PixelFormat::RG32F: case PixelFormat::RG32I: case PixelFormat::RG32UI: case PixelFormat::RGB5A1: case PixelFormat::RGB8: case PixelFormat::RGB8_SRGB: case PixelFormat::RGB16F: case PixelFormat::RGB16I: case PixelFormat::RGB16UI: case PixelFormat::RGB32F: case PixelFormat::RGB32I: case PixelFormat::RGB32UI: case PixelFormat::RGBA4: case PixelFormat::RGBA8: case PixelFormat::RGBA8_SRGB: case PixelFormat::RGBA16F: case PixelFormat::RGBA16I: case PixelFormat::RGBA16UI: case PixelFormat::RGBA32F: case PixelFormat::RGBA32I: case PixelFormat::RGBA32UI: return usage == TextureUsage::ColorAttachment || usage == TextureUsage::InputAttachment || usage == TextureUsage::ShaderSampling || usage == TextureUsage::ShaderReadWrite || usage == TextureUsage::TransferDestination || usage == TextureUsage::TransferSource; case PixelFormat::DXT1: case PixelFormat::DXT3: case PixelFormat::DXT5: { if (!m_referenceContext->IsExtensionSupported(GL::Extension::TextureCompressionS3tc)) return false; return usage == TextureUsage::InputAttachment || usage == TextureUsage::ShaderSampling || usage == TextureUsage::TransferDestination || usage == TextureUsage::TransferSource; } case PixelFormat::Depth16: case PixelFormat::Depth16Stencil8: case PixelFormat::Depth24: case PixelFormat::Depth24Stencil8: case PixelFormat::Depth32F: case PixelFormat::Depth32FStencil8: case PixelFormat::Stencil1: case PixelFormat::Stencil4: case PixelFormat::Stencil8: case PixelFormat::Stencil16: return usage == TextureUsage::DepthStencilAttachment || usage == TextureUsage::ShaderSampling || usage == TextureUsage::TransferDestination || usage == TextureUsage::TransferSource; } return false; } }