// Copyright (C) 2023 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 namespace Nz { OpenGLSwapchain::OpenGLSwapchain(OpenGLDevice& device, WindowHandle windowHandle, const Vector2ui& windowSize, const SwapchainParameters& parameters) : m_currentFrame(0), m_framebuffer(*this), m_size(windowSize), m_sizeInvalidated(false) { GL::ContextParams contextParams; #ifdef NAZARA_OPENGLRENDERER_DEBUG contextParams.wrapErrorHandling = true; #endif //TODO: Pass swapchain parameters to context m_context = device.CreateContext(contextParams, windowHandle); if (!m_context) throw std::runtime_error("failed to create swapchain context"); // TODO: extract the exact window pixel format PixelFormat colorFormat; switch (contextParams.bitsPerPixel) { case 8: colorFormat = PixelFormat::R8; break; case 16: colorFormat = PixelFormat::RG8; break; case 24: colorFormat = PixelFormat::RGB8; break; case 32: default: colorFormat = PixelFormat::RGBA8; break; } // TODO: extract the exact depth-stencil format PixelFormat depthFormat; if (contextParams.stencilBits > 0) depthFormat = PixelFormat::Depth24Stencil8; else if (contextParams.depthBits > 24) depthFormat = PixelFormat::Depth32F; else if (contextParams.depthBits > 16) depthFormat = PixelFormat::Depth24; else if (contextParams.depthBits > 0) depthFormat = PixelFormat::Depth16; else depthFormat = PixelFormat::Undefined; m_supportedPresentModes = m_context->GetSupportedPresentModes(); #ifdef NAZARA_PLATFORM_WEB m_presentMode = PresentMode::Immediate; //< default present mode #else m_presentMode = PresentMode::VerticalSync; //< default present mode #endif for (PresentMode presentMode : parameters.presentMode) { if (m_supportedPresentModes & presentMode) { SetPresentMode(presentMode); break; } } std::vector attachments; std::vector subpassDescriptions; std::vector subpassDependencies; BuildRenderPass(colorFormat, depthFormat, attachments, subpassDescriptions, subpassDependencies); m_renderPass.emplace(std::move(attachments), std::move(subpassDescriptions), std::move(subpassDependencies)); constexpr std::size_t RenderImageCount = 2; m_renderImage.reserve(RenderImageCount); for (std::size_t i = 0; i < RenderImageCount; ++i) m_renderImage.emplace_back(std::make_unique(*this)); } RenderFrame OpenGLSwapchain::AcquireFrame() { bool sizeInvalidated = m_sizeInvalidated; m_sizeInvalidated = false; return RenderFrame(m_renderImage[m_currentFrame].get(), sizeInvalidated, m_size, 0); } std::shared_ptr OpenGLSwapchain::CreateCommandPool(QueueType /*queueType*/) { return std::make_shared(); } const OpenGLFramebuffer& OpenGLSwapchain::GetFramebuffer(std::size_t i) const { assert(i == 0); NazaraUnused(i); return m_framebuffer; } std::size_t OpenGLSwapchain::GetFramebufferCount() const { return 1; } const OpenGLRenderPass& OpenGLSwapchain::GetRenderPass() const { return *m_renderPass; } PresentMode OpenGLSwapchain::GetPresentMode() const { return m_presentMode; } const Vector2ui& OpenGLSwapchain::GetSize() const { return m_size; } PresentModeFlags OpenGLSwapchain::GetSupportedPresentModes() const { return m_supportedPresentModes; } void OpenGLSwapchain::NotifyResize(const Vector2ui& newSize) { OnRenderTargetSizeChange(this, newSize); m_size = newSize; m_sizeInvalidated = true; } void OpenGLSwapchain::Present() { m_context->SwapBuffers(); m_currentFrame = (m_currentFrame + 1) % m_renderImage.size(); } void OpenGLSwapchain::SetPresentMode(PresentMode presentMode) { NazaraAssert(m_supportedPresentModes & presentMode, "unsupported present mode"); if (m_presentMode != presentMode) { m_context->SetPresentMode(presentMode); m_presentMode = presentMode; } } TransientResources& OpenGLSwapchain::Transient() { return *m_renderImage[m_currentFrame]; } }