Renderer: Implement Framebuffers

This commit is contained in:
Jérôme Leclercq 2021-02-20 19:22:08 +01:00
parent 3ef74d6e1d
commit fb3468854f
32 changed files with 401 additions and 100 deletions

View File

@ -34,6 +34,8 @@ namespace Nz
std::shared_ptr<AbstractBuffer> InstantiateBuffer(BufferType type) override; std::shared_ptr<AbstractBuffer> InstantiateBuffer(BufferType type) override;
std::shared_ptr<CommandPool> InstantiateCommandPool(QueueType queueType) override; std::shared_ptr<CommandPool> InstantiateCommandPool(QueueType queueType) override;
std::shared_ptr<Framebuffer> InstantiateFramebuffer(unsigned int width, unsigned int height, const std::shared_ptr<RenderPass>& renderPass, const std::vector<std::shared_ptr<Texture>>& attachments) override;
std::shared_ptr<RenderPass> InstantiateRenderPass(std::vector<RenderPass::Attachment> attachments, std::vector<RenderPass::SubpassDescription> subpassDescriptions, std::vector<RenderPass::SubpassDependency> subpassDependencies) override;
std::shared_ptr<RenderPipeline> InstantiateRenderPipeline(RenderPipelineInfo pipelineInfo) override; std::shared_ptr<RenderPipeline> InstantiateRenderPipeline(RenderPipelineInfo pipelineInfo) override;
std::shared_ptr<RenderPipelineLayout> InstantiateRenderPipelineLayout(RenderPipelineLayoutInfo pipelineLayoutInfo) override; std::shared_ptr<RenderPipelineLayout> InstantiateRenderPipelineLayout(RenderPipelineLayoutInfo pipelineLayoutInfo) override;
std::shared_ptr<ShaderStage> InstantiateShaderStage(const ShaderAst& shaderAst, const ShaderWriter::States& states) override; std::shared_ptr<ShaderStage> InstantiateShaderStage(const ShaderAst& shaderAst, const ShaderWriter::States& states) override;
@ -42,6 +44,7 @@ namespace Nz
std::shared_ptr<TextureSampler> InstantiateTextureSampler(const TextureSamplerInfo& params) override; std::shared_ptr<TextureSampler> InstantiateTextureSampler(const TextureSamplerInfo& params) override;
inline void NotifyBufferDestruction(GLuint buffer) const; inline void NotifyBufferDestruction(GLuint buffer) const;
inline void NotifyFramebufferDestruction(GLuint fbo) const;
inline void NotifyProgramDestruction(GLuint program) const; inline void NotifyProgramDestruction(GLuint program) const;
inline void NotifySamplerDestruction(GLuint sampler) const; inline void NotifySamplerDestruction(GLuint sampler) const;
inline void NotifyTextureDestruction(GLuint texture) const; inline void NotifyTextureDestruction(GLuint texture) const;

View File

@ -18,6 +18,12 @@ namespace Nz
context->NotifyBufferDestruction(buffer); context->NotifyBufferDestruction(buffer);
} }
inline void OpenGLDevice::NotifyFramebufferDestruction(GLuint fbo) const
{
for (const GL::Context* context : m_contexts)
context->NotifyFramebufferDestruction(fbo);
}
inline void OpenGLDevice::NotifyProgramDestruction(GLuint program) const inline void OpenGLDevice::NotifyProgramDestruction(GLuint program) const
{ {
for (const GL::Context* context : m_contexts) for (const GL::Context* context : m_contexts)

View File

@ -0,0 +1,45 @@
// Copyright (C) 2020 Jérôme Leclercq
// This file is part of the "Nazara Engine - Renderer module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_OPENGLRENDERER_OPENGLWINDOWFRAMEBUFFER_HPP
#define NAZARA_OPENGLRENDERER_OPENGLWINDOWFRAMEBUFFER_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/OpenGLRenderer/OpenGLFramebuffer.hpp>
#include <Nazara/OpenGLRenderer/Wrapper/Framebuffer.hpp>
#include <memory>
#include <vector>
namespace Nz
{
class OpenGLDevice;
class RenderPass;
class Texture;
class NAZARA_OPENGLRENDERER_API OpenGLFboFramebuffer : public OpenGLFramebuffer
{
public:
OpenGLFboFramebuffer(OpenGLDevice& device, const std::vector<std::shared_ptr<Texture>>& attachments);
OpenGLFboFramebuffer(const OpenGLFboFramebuffer&) = delete;
OpenGLFboFramebuffer(OpenGLFboFramebuffer&&) noexcept = default;
~OpenGLFboFramebuffer() = default;
void Activate() const override;
std::size_t GetColorBufferCount() const override;
OpenGLFboFramebuffer& operator=(const OpenGLFboFramebuffer&) = delete;
OpenGLFboFramebuffer& operator=(OpenGLFboFramebuffer&&) = delete;
private:
GL::Framebuffer m_framebuffer;
std::size_t m_colorAttachmentCount;
};
}
#include <Nazara/OpenGLRenderer/OpenGLFboFramebuffer.hpp>
#endif // NAZARA_OPENGLRENDERER_OpenGLWindowFramebuffer_HPP

View File

@ -0,0 +1,12 @@
// Copyright (C) 2020 Jérôme Leclercq
// This file is part of the "Nazara Engine - OpenGL Renderer"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/OpenGLRenderer/OpenGLFramebuffer.hpp>
#include <Nazara/OpenGLRenderer/Debug.hpp>
namespace Nz
{
}
#include <Nazara/OpenGLRenderer/DebugOff.hpp>

View File

@ -34,6 +34,8 @@ namespace Nz
OpenGLTexture& operator=(const OpenGLTexture&) = delete; OpenGLTexture& operator=(const OpenGLTexture&) = delete;
OpenGLTexture& operator=(OpenGLTexture&&) = delete; OpenGLTexture& operator=(OpenGLTexture&&) = delete;
static inline GL::TextureTarget ToTextureTarget(ImageType imageType);
private: private:
GL::Texture m_texture; GL::Texture m_texture;
TextureInfo m_params; TextureInfo m_params;

View File

@ -3,6 +3,7 @@
// For conditions of distribution and use, see copyright notice in Config.hpp // For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/OpenGLRenderer/OpenGLTexture.hpp> #include <Nazara/OpenGLRenderer/OpenGLTexture.hpp>
#include <stdexcept>
#include <Nazara/OpenGLRenderer/Debug.hpp> #include <Nazara/OpenGLRenderer/Debug.hpp>
namespace Nz namespace Nz
@ -11,6 +12,22 @@ namespace Nz
{ {
return m_texture; return m_texture;
} }
inline GL::TextureTarget OpenGLTexture::ToTextureTarget(ImageType imageType)
{
switch (imageType)
{
case ImageType_2D: return GL::TextureTarget::Target2D;
case ImageType_2D_Array: return GL::TextureTarget::Target2D_Array;
case ImageType_3D: return GL::TextureTarget::Target3D;
case ImageType_Cubemap: return GL::TextureTarget::Cubemap;
case ImageType_1D:
case ImageType_1D_Array:
default:
throw std::runtime_error("unsupported texture type");
}
}
} }
#include <Nazara/OpenGLRenderer/DebugOff.hpp> #include <Nazara/OpenGLRenderer/DebugOff.hpp>

View File

@ -36,4 +36,4 @@ namespace Nz
#include <Nazara/OpenGLRenderer/OpenGLWindowFramebuffer.inl> #include <Nazara/OpenGLRenderer/OpenGLWindowFramebuffer.inl>
#endif // NAZARA_OPENGLRENDERER_OpenGLWindowFramebuffer_HPP #endif

View File

@ -2,7 +2,7 @@
// This file is part of the "Nazara Engine - OpenGL Renderer" // This file is part of the "Nazara Engine - OpenGL Renderer"
// For conditions of distribution and use, see copyright notice in Config.hpp // For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/OpenGLRenderer/OpenGLFramebuffer.hpp> #include <Nazara/OpenGLRenderer/OpenGLWindowFramebuffer.hpp>
#include <Nazara/OpenGLRenderer/Debug.hpp> #include <Nazara/OpenGLRenderer/Debug.hpp>
namespace Nz namespace Nz

View File

@ -126,6 +126,7 @@ namespace Nz::GL
bool Initialize(const ContextParams& params); bool Initialize(const ContextParams& params);
inline void NotifyBufferDestruction(GLuint buffer) const; inline void NotifyBufferDestruction(GLuint buffer) const;
inline void NotifyFramebufferDestruction(GLuint fbo) const;
inline void NotifyProgramDestruction(GLuint program) const; inline void NotifyProgramDestruction(GLuint program) const;
inline void NotifySamplerDestruction(GLuint sampler) const; inline void NotifySamplerDestruction(GLuint sampler) const;
inline void NotifyTextureDestruction(GLuint texture) const; inline void NotifyTextureDestruction(GLuint texture) const;

View File

@ -58,6 +58,15 @@ namespace Nz::GL
} }
} }
inline void Context::NotifyFramebufferDestruction(GLuint fbo) const
{
if (m_state.boundDrawFBO == fbo)
m_state.boundDrawFBO = 0;
if (m_state.boundReadFBO == fbo)
m_state.boundReadFBO = 0;
}
inline void Context::NotifyProgramDestruction(GLuint program) const inline void Context::NotifyProgramDestruction(GLuint program) const
{ {
if (m_state.boundProgram == program) if (m_state.boundProgram == program)

View File

@ -36,6 +36,7 @@ typedef void (GL_APIENTRYP PFNGLSPECIALIZESHADERARBPROC) (GLuint shader, const G
cb(glBufferSubData, PFNGLBUFFERSUBDATAPROC) \ cb(glBufferSubData, PFNGLBUFFERSUBDATAPROC) \
cb(glClear, PFNGLCLEARPROC) \ cb(glClear, PFNGLCLEARPROC) \
cb(glClearBufferfi, PFNGLCLEARBUFFERFIPROC) \ cb(glClearBufferfi, PFNGLCLEARBUFFERFIPROC) \
cb(glClearBufferfv, PFNGLCLEARBUFFERFVPROC) \
cb(glClearBufferuiv, PFNGLCLEARBUFFERUIVPROC) \ cb(glClearBufferuiv, PFNGLCLEARBUFFERUIVPROC) \
cb(glClearColor, PFNGLCLEARCOLORPROC) \ cb(glClearColor, PFNGLCLEARCOLORPROC) \
cb(glClearDepthf, PFNGLCLEARDEPTHFPROC) \ cb(glClearDepthf, PFNGLCLEARDEPTHFPROC) \
@ -156,6 +157,9 @@ typedef void (GL_APIENTRYP PFNGLSPECIALIZESHADERARBPROC) (GLuint shader, const G
\ \
extCb(glDebugMessageCallback, PFNGLDEBUGMESSAGECALLBACKPROC) \ extCb(glDebugMessageCallback, PFNGLDEBUGMESSAGECALLBACKPROC) \
\ \
extCb(glMemoryBarrier, PFNGLMEMORYBARRIERPROC) \
extCb(glMemoryBarrierByRegion, PFNGLMEMORYBARRIERBYREGIONPROC) \
\
extCb(glObjectLabel, PFNGLOBJECTLABELPROC) \ extCb(glObjectLabel, PFNGLOBJECTLABELPROC) \
extCb(glPopDebugGroup, PFNGLPOPDEBUGGROUPPROC) \ extCb(glPopDebugGroup, PFNGLPOPDEBUGGROUPPROC) \
extCb(glPushDebugGroup, PFNGLPUSHDEBUGGROUPPROC) \ extCb(glPushDebugGroup, PFNGLPUSHDEBUGGROUPPROC) \

View File

@ -9,6 +9,7 @@
#include <Nazara/Prerequisites.hpp> #include <Nazara/Prerequisites.hpp>
#include <Nazara/Core/MovablePtr.hpp> #include <Nazara/Core/MovablePtr.hpp>
#include <Nazara/Core/MovableValue.hpp>
#include <Nazara/OpenGLRenderer/Wrapper/Context.hpp> #include <Nazara/OpenGLRenderer/Wrapper/Context.hpp>
#include <string> #include <string>
@ -26,6 +27,8 @@ namespace Nz::GL
bool Create(OpenGLDevice& device, CreateArgs... args); bool Create(OpenGLDevice& device, CreateArgs... args);
void Destroy(); void Destroy();
const Context& EnsureDeviceContext() const;
bool IsValid() const; bool IsValid() const;
OpenGLDevice* GetDevice() const; OpenGLDevice* GetDevice() const;
@ -39,8 +42,6 @@ namespace Nz::GL
static constexpr GLuint InvalidObject = 0; static constexpr GLuint InvalidObject = 0;
protected: protected:
const Context& EnsureDeviceContext();
MovablePtr<OpenGLDevice> m_device; MovablePtr<OpenGLDevice> m_device;
MovableValue<GLuint> m_objectId; MovableValue<GLuint> m_objectId;
}; };

View File

@ -46,6 +46,24 @@ namespace Nz::GL
} }
} }
template<typename C, GLenum ObjectType, typename... CreateArgs>
const Context& DeviceObject<C, ObjectType, CreateArgs...>::EnsureDeviceContext() const
{
assert(m_device);
const Context* activeContext = Context::GetCurrentContext();
if (!activeContext || activeContext->GetDevice() != m_device)
{
const Context& referenceContext = m_device->GetReferenceContext();
if (!Context::SetCurrentContext(&referenceContext))
throw std::runtime_error("failed to activate context");
return referenceContext;
}
return *activeContext;
}
template<typename C, GLenum ObjectType, typename... CreateArgs> template<typename C, GLenum ObjectType, typename... CreateArgs>
bool DeviceObject<C, ObjectType, CreateArgs...>::IsValid() const bool DeviceObject<C, ObjectType, CreateArgs...>::IsValid() const
{ {
@ -72,24 +90,6 @@ namespace Nz::GL
if (context.glObjectLabel) if (context.glObjectLabel)
context.glObjectLabel(ObjectType, m_objectId, name.size(), name.data()); context.glObjectLabel(ObjectType, m_objectId, name.size(), name.data());
} }
template<typename C, GLenum ObjectType, typename... CreateArgs>
const Context& DeviceObject<C, ObjectType, CreateArgs...>::EnsureDeviceContext()
{
assert(m_device);
const Context* activeContext = Context::GetCurrentContext();
if (!activeContext || activeContext->GetDevice() != m_device)
{
const Context& referenceContext = m_device->GetReferenceContext();
if (!Context::SetCurrentContext(&referenceContext))
throw std::runtime_error("failed to activate context");
return referenceContext;
}
return *activeContext;
}
} }
#include <Nazara/OpenGLRenderer/DebugOff.hpp> #include <Nazara/OpenGLRenderer/DebugOff.hpp>

View File

@ -4,36 +4,38 @@
#pragma once #pragma once
#ifndef NAZARA_OPENGLRENDERER_VKFRAMEBUFFER_HPP #ifndef NAZARA_OPENGLRENDERER_GLFRAMEBUFFER_HPP
#define NAZARA_OPENGLRENDERER_VKFRAMEBUFFER_HPP #define NAZARA_OPENGLRENDERER_GLFRAMEBUFFER_HPP
#include <Nazara/Prerequisites.hpp> #include <Nazara/Prerequisites.hpp>
#include <Nazara/OpenGLRenderer/Wrapper/DeviceObject.hpp> #include <Nazara/OpenGLRenderer/Wrapper/DeviceObject.hpp>
namespace Nz namespace Nz::GL
{ {
namespace Vk class Framebuffer : public DeviceObject<Framebuffer, GL_FRAMEBUFFER>
{ {
class Framebuffer : public DeviceObject<Framebuffer, VkFramebuffer, VkFramebufferCreateInfo, VK_OBJECT_TYPE_FRAMEBUFFER> friend DeviceObject;
{
friend DeviceObject;
public: public:
Framebuffer() = default; Framebuffer() = default;
Framebuffer(const Framebuffer&) = delete; Framebuffer(const Framebuffer&) = delete;
Framebuffer(Framebuffer&&) = default; Framebuffer(Framebuffer&&) noexcept = default;
~Framebuffer() = default; ~Framebuffer() = default;
Framebuffer& operator=(const Framebuffer&) = delete; inline GLenum Check() const;
Framebuffer& operator=(Framebuffer&&) = delete;
private: inline void Renderbuffer(GLenum attachment, GLenum renderbuffer);
static inline VkResult CreateHelper(Device& device, const VkFramebufferCreateInfo* createInfo, const VkAllocationCallbacks* allocator, VkFramebuffer* handle); inline void Texture2D(GLenum attachment, GLenum textarget, GLuint texture, GLint level = 0);
static inline void DestroyHelper(Device& device, VkFramebuffer handle, const VkAllocationCallbacks* allocator);
}; Framebuffer& operator=(const Framebuffer&) = delete;
} Framebuffer& operator=(Framebuffer&&) noexcept = default;
private:
static inline GLuint CreateHelper(OpenGLDevice& device, const Context& context);
static inline void DestroyHelper(OpenGLDevice& device, const Context& context, GLuint objectId);
};
} }
#include <Nazara/OpenGLRenderer/Wrapper/Framebuffer.inl> #include <Nazara/OpenGLRenderer/Wrapper/Framebuffer.inl>
#endif // NAZARA_OPENGLRENDERER_VKFRAMEBUFFER_HPP #endif

View File

@ -3,21 +3,51 @@
// For conditions of distribution and use, see copyright notice in Config.hpp // For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/OpenGLRenderer/Wrapper/Framebuffer.hpp> #include <Nazara/OpenGLRenderer/Wrapper/Framebuffer.hpp>
#include <Nazara/OpenGLRenderer/OpenGLDevice.hpp>
#include <Nazara/OpenGLRenderer/Debug.hpp> #include <Nazara/OpenGLRenderer/Debug.hpp>
namespace Nz namespace Nz::GL
{ {
namespace Vk inline GLenum Framebuffer::Check() const
{ {
inline VkResult Framebuffer::CreateHelper(Device& device, const VkFramebufferCreateInfo* createInfo, const VkAllocationCallbacks* allocator, VkFramebuffer* handle) assert(m_objectId);
{
return device.vkCreateFramebuffer(device, createInfo, allocator, handle);
}
inline void Framebuffer::DestroyHelper(Device& device, VkFramebuffer handle, const VkAllocationCallbacks* allocator) const Context& context = EnsureDeviceContext();
{ context.BindFramebuffer(m_objectId);
return device.vkDestroyFramebuffer(device, handle, allocator); return context.glCheckFramebufferStatus(GL_FRAMEBUFFER);
} }
inline void Framebuffer::Renderbuffer(GLenum attachment, GLenum renderbuffer)
{
assert(m_objectId);
const Context& context = EnsureDeviceContext();
context.BindFramebuffer(m_objectId);
context.glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, renderbuffer);
}
inline void Framebuffer::Texture2D(GLenum attachment, GLenum textarget, GLuint texture, GLint level)
{
assert(m_objectId);
const Context& context = EnsureDeviceContext();
context.BindFramebuffer(m_objectId);
context.glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, textarget, texture, level);
}
inline GLuint Framebuffer::CreateHelper(OpenGLDevice& /*device*/, const Context& context)
{
GLuint fbo = 0;
context.glGenFramebuffers(1U, &fbo);
return fbo;
}
inline void Framebuffer::DestroyHelper(OpenGLDevice& device, const Context& context, GLuint objectId)
{
context.glDeleteFramebuffers(1U, &objectId);
device.NotifyFramebufferDestruction(objectId);
} }
} }

View File

@ -10,6 +10,8 @@
#include <Nazara/Prerequisites.hpp> #include <Nazara/Prerequisites.hpp>
#include <Nazara/Renderer/Config.hpp> #include <Nazara/Renderer/Config.hpp>
#include <Nazara/Renderer/Enums.hpp> #include <Nazara/Renderer/Enums.hpp>
#include <Nazara/Renderer/Framebuffer.hpp>
#include <Nazara/Renderer/RenderPass.hpp>
#include <Nazara/Renderer/RenderPipeline.hpp> #include <Nazara/Renderer/RenderPipeline.hpp>
#include <Nazara/Renderer/RenderPipelineLayout.hpp> #include <Nazara/Renderer/RenderPipelineLayout.hpp>
#include <Nazara/Renderer/Texture.hpp> #include <Nazara/Renderer/Texture.hpp>
@ -33,6 +35,8 @@ namespace Nz
virtual std::shared_ptr<AbstractBuffer> InstantiateBuffer(BufferType type) = 0; virtual std::shared_ptr<AbstractBuffer> InstantiateBuffer(BufferType type) = 0;
virtual std::shared_ptr<CommandPool> InstantiateCommandPool(QueueType queueType) = 0; virtual std::shared_ptr<CommandPool> InstantiateCommandPool(QueueType queueType) = 0;
virtual std::shared_ptr<Framebuffer> InstantiateFramebuffer(unsigned int width, unsigned int height, const std::shared_ptr<RenderPass>& renderPass, const std::vector<std::shared_ptr<Texture>>& attachments) = 0;
virtual std::shared_ptr<RenderPass> InstantiateRenderPass(std::vector<RenderPass::Attachment> attachments, std::vector<RenderPass::SubpassDescription> subpassDescriptions, std::vector<RenderPass::SubpassDependency> subpassDependencies) = 0;
virtual std::shared_ptr<RenderPipeline> InstantiateRenderPipeline(RenderPipelineInfo pipelineInfo) = 0; virtual std::shared_ptr<RenderPipeline> InstantiateRenderPipeline(RenderPipelineInfo pipelineInfo) = 0;
virtual std::shared_ptr<RenderPipelineLayout> InstantiateRenderPipelineLayout(RenderPipelineLayoutInfo pipelineLayoutInfo) = 0; virtual std::shared_ptr<RenderPipelineLayout> InstantiateRenderPipelineLayout(RenderPipelineLayoutInfo pipelineLayoutInfo) = 0;
virtual std::shared_ptr<ShaderStage> InstantiateShaderStage(const ShaderAst& shaderAst, const ShaderWriter::States& states) = 0; virtual std::shared_ptr<ShaderStage> InstantiateShaderStage(const ShaderAst& shaderAst, const ShaderWriter::States& states) = 0;

View File

@ -15,7 +15,7 @@ namespace Nz
{ {
} }
inline auto Nz::RenderPass::GetAttachment(std::size_t attachmentIndex) const -> const Attachment& inline auto RenderPass::GetAttachment(std::size_t attachmentIndex) const -> const Attachment&
{ {
assert(attachmentIndex < m_attachments.size()); assert(attachmentIndex < m_attachments.size());
return m_attachments[attachmentIndex]; return m_attachments[attachmentIndex];

View File

@ -162,6 +162,7 @@ namespace Nz
PixelFormatContent_Undefined = -1, PixelFormatContent_Undefined = -1,
PixelFormatContent_ColorRGBA, PixelFormatContent_ColorRGBA,
PixelFormatContent_Depth,
PixelFormatContent_DepthStencil, PixelFormatContent_DepthStencil,
PixelFormatContent_Stencil, PixelFormatContent_Stencil,

View File

@ -39,6 +39,8 @@ namespace Nz
inline VkShaderStageFlags ToVulkan(ShaderStageTypeFlags stageType); inline VkShaderStageFlags ToVulkan(ShaderStageTypeFlags stageType);
inline VkStencilOp ToVulkan(StencilOperation stencilOp); inline VkStencilOp ToVulkan(StencilOperation stencilOp);
inline VkImageLayout ToVulkan(TextureLayout textureLayout); inline VkImageLayout ToVulkan(TextureLayout textureLayout);
inline VkImageUsageFlagBits ToVulkan(TextureUsage textureLayout);
inline VkImageUsageFlags ToVulkan(TextureUsageFlags textureLayout);
inline VkVertexInputRate ToVulkan(VertexInputRate inputRate); inline VkVertexInputRate ToVulkan(VertexInputRate inputRate);
NAZARA_VULKANRENDERER_API std::string TranslateVulkanError(VkResult code); NAZARA_VULKANRENDERER_API std::string TranslateVulkanError(VkResult code);

View File

@ -196,9 +196,11 @@ namespace Nz
switch (pixelFormat) switch (pixelFormat)
{ {
case PixelFormat::PixelFormat_BGRA8: return VK_FORMAT_B8G8R8A8_UNORM; case PixelFormat::PixelFormat_BGRA8: return VK_FORMAT_B8G8R8A8_UNORM;
case PixelFormat::PixelFormat_BGRA8_SRGB: return VK_FORMAT_B8G8R8A8_SRGB;
case PixelFormat::PixelFormat_Depth24Stencil8: return VK_FORMAT_D24_UNORM_S8_UINT; case PixelFormat::PixelFormat_Depth24Stencil8: return VK_FORMAT_D24_UNORM_S8_UINT;
case PixelFormat::PixelFormat_Depth32: return VK_FORMAT_D32_SFLOAT; case PixelFormat::PixelFormat_Depth32: return VK_FORMAT_D32_SFLOAT;
case PixelFormat::PixelFormat_RGBA8: return VK_FORMAT_R8G8B8A8_UNORM; case PixelFormat::PixelFormat_RGBA8: return VK_FORMAT_R8G8B8A8_UNORM;
case PixelFormat::PixelFormat_RGBA8_SRGB: return VK_FORMAT_R8G8B8A8_SRGB;
default: break; default: break;
} }
@ -336,10 +338,10 @@ namespace Nz
{ {
switch (textureLayout) switch (textureLayout)
{ {
case TextureLayout::ColorInput: return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; case TextureLayout::ColorInput: return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
case TextureLayout::ColorOutput: return VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR; case TextureLayout::ColorOutput: return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
case TextureLayout::DepthStencilInput: return VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL; case TextureLayout::DepthStencilInput: return VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
case TextureLayout::DepthStencilOutput: return VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; case TextureLayout::DepthStencilOutput: return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
case TextureLayout::Present: return VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; case TextureLayout::Present: return VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
case TextureLayout::TransferSource: return VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; case TextureLayout::TransferSource: return VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
case TextureLayout::TransferDestination: return VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; case TextureLayout::TransferDestination: return VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
@ -350,6 +352,35 @@ namespace Nz
return {}; return {};
} }
VkImageUsageFlagBits ToVulkan(TextureUsage textureLayout)
{
switch (textureLayout)
{
case TextureUsage::ColorOutput: return VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
case TextureUsage::DepthStencilOutput: return VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
case TextureUsage::InputAttachment: return VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
case TextureUsage::ShaderSampling: return VK_IMAGE_USAGE_SAMPLED_BIT;
case TextureUsage::TransferSource: return VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
case TextureUsage::TransferDestination: return VK_IMAGE_USAGE_TRANSFER_DST_BIT;
}
NazaraError("Unhandled TextureUsage 0x" + NumberToString(UnderlyingCast(textureLayout), 16));
return {};
}
VkImageUsageFlags ToVulkan(TextureUsageFlags textureLayout)
{
VkImageUsageFlags imageUsageBits = 0;
for (int i = 0; i <= UnderlyingCast(TextureUsage::Max); ++i)
{
TextureUsage textureUsage = static_cast<TextureUsage>(i);
if (textureLayout.Test(textureUsage))
imageUsageBits |= ToVulkan(textureUsage);
}
return imageUsageBits;
}
inline VkVertexInputRate ToVulkan(VertexInputRate inputRate) inline VkVertexInputRate ToVulkan(VertexInputRate inputRate)
{ {
switch (inputRate) switch (inputRate)
@ -359,7 +390,7 @@ namespace Nz
} }
NazaraError("Unhandled VertexInputRate 0x" + NumberToString(UnderlyingCast(inputRate), 16)); NazaraError("Unhandled VertexInputRate 0x" + NumberToString(UnderlyingCast(inputRate), 16));
return VK_VERTEX_INPUT_RATE_VERTEX; return {};
} }
} }

View File

@ -25,6 +25,8 @@ namespace Nz
std::shared_ptr<AbstractBuffer> InstantiateBuffer(BufferType type) override; std::shared_ptr<AbstractBuffer> InstantiateBuffer(BufferType type) override;
std::shared_ptr<CommandPool> InstantiateCommandPool(QueueType queueType) override; std::shared_ptr<CommandPool> InstantiateCommandPool(QueueType queueType) override;
std::shared_ptr<Framebuffer> InstantiateFramebuffer(unsigned int width, unsigned int height, const std::shared_ptr<RenderPass>& renderPass, const std::vector<std::shared_ptr<Texture>>& attachments) override;
std::shared_ptr<RenderPass> InstantiateRenderPass(std::vector<RenderPass::Attachment> attachments, std::vector<RenderPass::SubpassDescription> subpassDescriptions, std::vector<RenderPass::SubpassDependency> subpassDependencies) override;
std::shared_ptr<RenderPipeline> InstantiateRenderPipeline(RenderPipelineInfo pipelineInfo) override; std::shared_ptr<RenderPipeline> InstantiateRenderPipeline(RenderPipelineInfo pipelineInfo) override;
std::shared_ptr<RenderPipelineLayout> InstantiateRenderPipelineLayout(RenderPipelineLayoutInfo pipelineLayoutInfo) override; std::shared_ptr<RenderPipelineLayout> InstantiateRenderPipelineLayout(RenderPipelineLayoutInfo pipelineLayoutInfo) override;
std::shared_ptr<ShaderStage> InstantiateShaderStage(const ShaderAst& shaderAst, const ShaderWriter::States& states) override; std::shared_ptr<ShaderStage> InstantiateShaderStage(const ShaderAst& shaderAst, const ShaderWriter::States& states) override;

View File

@ -8,13 +8,17 @@
#define NAZARA_VULKANRENDERER_VULKANSINGLEFRAMEBUFFER_HPP #define NAZARA_VULKANRENDERER_VULKANSINGLEFRAMEBUFFER_HPP
#include <Nazara/VulkanRenderer/VulkanFramebuffer.hpp> #include <Nazara/VulkanRenderer/VulkanFramebuffer.hpp>
#include <memory>
namespace Nz namespace Nz
{ {
class RenderPass;
class Texture;
class NAZARA_VULKANRENDERER_API VulkanSingleFramebuffer final : public VulkanFramebuffer class NAZARA_VULKANRENDERER_API VulkanSingleFramebuffer final : public VulkanFramebuffer
{ {
public: public:
inline VulkanSingleFramebuffer(Vk::Framebuffer renderPass); VulkanSingleFramebuffer(Vk::Device& device, unsigned int width, unsigned int height, const std::shared_ptr<RenderPass>& renderPass, const std::vector<std::shared_ptr<Texture>>& attachments);
VulkanSingleFramebuffer(const VulkanSingleFramebuffer&) = delete; VulkanSingleFramebuffer(const VulkanSingleFramebuffer&) = delete;
VulkanSingleFramebuffer(VulkanSingleFramebuffer&&) = delete; VulkanSingleFramebuffer(VulkanSingleFramebuffer&&) = delete;
~VulkanSingleFramebuffer() = default; ~VulkanSingleFramebuffer() = default;

View File

@ -7,12 +7,6 @@
namespace Nz namespace Nz
{ {
inline VulkanSingleFramebuffer::VulkanSingleFramebuffer(Vk::Framebuffer framebuffer) :
VulkanFramebuffer(Type::Single),
m_framebuffer(std::move(framebuffer))
{
}
inline Vk::Framebuffer& VulkanSingleFramebuffer::GetFramebuffer() inline Vk::Framebuffer& VulkanSingleFramebuffer::GetFramebuffer()
{ {
return m_framebuffer; return m_framebuffer;

View File

@ -106,18 +106,19 @@ namespace Nz
for (std::size_t i = 0; i < colorBufferCount; ++i) for (std::size_t i = 0; i < colorBufferCount; ++i)
{ {
Nz::Color color = command.clearValues[i].color; Nz::Color color = command.clearValues[i].color;
std::array<GLuint, 4> clearColor = { color.r, color.g, color.b, color.a }; std::array<GLfloat, 4> clearColor = { color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f };
context->glClearBufferuiv(GL_COLOR, GLint(i), clearColor.data()); context->glClearBufferfv(GL_COLOR, GLint(i), clearColor.data());
} }
context->glClear(GL_DEPTH_BUFFER_BIT);
} }
else else
{ {
Nz::Color color = command.clearValues[0].color; Nz::Color color = command.clearValues[0].color;
context->glClearColor(color.r, color.g, color.b, color.a); context->glClearColor(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f);
context->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
} }
context->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
} }
else else
static_assert(AlwaysFalse<T>::value, "non-exhaustive visitor"); static_assert(AlwaysFalse<T>::value, "non-exhaustive visitor");
@ -131,6 +132,8 @@ namespace Nz
states.shaderBindings->Apply(context); states.shaderBindings->Apply(context);
states.pipeline->Apply(context); states.pipeline->Apply(context);
states.pipeline->FlipY(states.shouldFlipY);
if (states.scissorRegion) if (states.scissorRegion)
context.SetScissorBox(states.scissorRegion->x, states.scissorRegion->y, states.scissorRegion->width, states.scissorRegion->height); context.SetScissorBox(states.scissorRegion->x, states.scissorRegion->y, states.scissorRegion->width, states.scissorRegion->height);

View File

@ -19,7 +19,7 @@ namespace Nz
m_commandBuffer.BeginDebugRegion(regionName, color); m_commandBuffer.BeginDebugRegion(regionName, color);
} }
void OpenGLCommandBufferBuilder::BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti renderRect, std::initializer_list<ClearValues> clearValues) void OpenGLCommandBufferBuilder::BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti /*renderRect*/, std::initializer_list<ClearValues> clearValues)
{ {
m_commandBuffer.SetFramebuffer(static_cast<const OpenGLFramebuffer&>(framebuffer), renderPass, clearValues); m_commandBuffer.SetFramebuffer(static_cast<const OpenGLFramebuffer&>(framebuffer), renderPass, clearValues);
} }

View File

@ -6,6 +6,8 @@
#include <Nazara/Renderer/CommandPool.hpp> #include <Nazara/Renderer/CommandPool.hpp>
#include <Nazara/OpenGLRenderer/OpenGLBuffer.hpp> #include <Nazara/OpenGLRenderer/OpenGLBuffer.hpp>
#include <Nazara/OpenGLRenderer/OpenGLCommandPool.hpp> #include <Nazara/OpenGLRenderer/OpenGLCommandPool.hpp>
#include <Nazara/OpenGLRenderer/OpenGLFboFramebuffer.hpp>
#include <Nazara/OpenGLRenderer/OpenGLRenderPass.hpp>
#include <Nazara/OpenGLRenderer/OpenGLRenderPipeline.hpp> #include <Nazara/OpenGLRenderer/OpenGLRenderPipeline.hpp>
#include <Nazara/OpenGLRenderer/OpenGLRenderPipelineLayout.hpp> #include <Nazara/OpenGLRenderer/OpenGLRenderPipelineLayout.hpp>
#include <Nazara/OpenGLRenderer/OpenGLShaderStage.hpp> #include <Nazara/OpenGLRenderer/OpenGLShaderStage.hpp>
@ -58,6 +60,16 @@ namespace Nz
return std::make_shared<OpenGLCommandPool>(); return std::make_shared<OpenGLCommandPool>();
} }
std::shared_ptr<Framebuffer> OpenGLDevice::InstantiateFramebuffer(unsigned int /*width*/, unsigned int /*height*/, const std::shared_ptr<RenderPass>& /*renderPass*/, const std::vector<std::shared_ptr<Texture>>& attachments)
{
return std::make_shared<OpenGLFboFramebuffer>(*this, attachments);
}
std::shared_ptr<RenderPass> OpenGLDevice::InstantiateRenderPass(std::vector<RenderPass::Attachment> attachments, std::vector<RenderPass::SubpassDescription> subpassDescriptions, std::vector<RenderPass::SubpassDependency> subpassDependencies)
{
return std::make_shared<OpenGLRenderPass>(std::move(attachments), std::move(subpassDescriptions), std::move(subpassDependencies));
}
std::shared_ptr<RenderPipeline> OpenGLDevice::InstantiateRenderPipeline(RenderPipelineInfo pipelineInfo) std::shared_ptr<RenderPipeline> OpenGLDevice::InstantiateRenderPipeline(RenderPipelineInfo pipelineInfo)
{ {
return std::make_shared<OpenGLRenderPipeline>(*this, std::move(pipelineInfo)); return std::make_shared<OpenGLRenderPipeline>(*this, std::move(pipelineInfo));

View File

@ -0,0 +1,92 @@
// Copyright (C) 2020 Jérôme Leclercq
// This file is part of the "Nazara Engine - OpenGL Renderer"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/OpenGLRenderer/OpenGLFboFramebuffer.hpp>
#include <Nazara/OpenGLRenderer/OpenGLRenderPass.hpp>
#include <Nazara/OpenGLRenderer/OpenGLTexture.hpp>
#include <stdexcept>
#include <Nazara/OpenGLRenderer/Debug.hpp>
namespace Nz
{
OpenGLFboFramebuffer::OpenGLFboFramebuffer(OpenGLDevice& device, const std::vector<std::shared_ptr<Texture>>& attachments) :
OpenGLFramebuffer(OpenGLFramebuffer::Type::FBO)
{
if (!m_framebuffer.Create(device))
throw std::runtime_error("failed to create framebuffer object");
std::size_t colorAttachmentCount = 0;
bool hasDepth = false;
bool hasStencil = false;
for (std::size_t i = 0; i < attachments.size(); ++i)
{
assert(attachments[i]);
const OpenGLTexture& glTexture = static_cast<const OpenGLTexture&>(*attachments[i]);
PixelFormat textureFormat = glTexture.GetFormat();
GLenum attachment;
switch (PixelFormatInfo::GetContent(textureFormat))
{
case PixelFormatContent_ColorRGBA:
attachment = GL_COLOR_ATTACHMENT0 + colorAttachmentCount;
colorAttachmentCount++;
break;
case PixelFormatContent_Depth:
if (hasDepth)
throw std::runtime_error("a framebuffer can only have one depth attachment");
attachment = GL_DEPTH_ATTACHMENT;
hasDepth = true;
break;
case PixelFormatContent_DepthStencil:
if (hasDepth)
throw std::runtime_error("a framebuffer can only have one depth attachment");
if (hasStencil)
throw std::runtime_error("a framebuffer can only have one stencil attachment");
attachment = GL_DEPTH_STENCIL_ATTACHMENT;
hasDepth = true;
hasStencil = true;
break;
case PixelFormatContent_Stencil:
if (hasStencil)
throw std::runtime_error("a framebuffer can only have one stencil attachment");
attachment = GL_STENCIL_ATTACHMENT;
hasStencil = true;
break;
case PixelFormatContent_Undefined:
default:
throw std::runtime_error("unhandled pixel format " + PixelFormatInfo::GetName(textureFormat));
}
m_framebuffer.Texture2D(attachment, ToOpenGL(OpenGLTexture::ToTextureTarget(glTexture.GetType())), glTexture.GetTexture().GetObjectId());
}
GLenum status = m_framebuffer.Check();
if (status != GL_FRAMEBUFFER_COMPLETE)
throw std::runtime_error("invalid framebuffer: 0x" + NumberToString(status, 16));
m_colorAttachmentCount = colorAttachmentCount;
}
void OpenGLFboFramebuffer::Activate() const
{
const GL::Context& context = m_framebuffer.EnsureDeviceContext();
context.BindFramebuffer(GL::FramebufferTarget::Draw, m_framebuffer.GetObjectId());
}
std::size_t OpenGLFboFramebuffer::GetColorBufferCount() const
{
return m_colorAttachmentCount;
}
}

View File

@ -68,7 +68,7 @@ namespace Nz
const TextureBinding& texBinding = std::get<TextureBinding>(binding.content); const TextureBinding& texBinding = std::get<TextureBinding>(binding.content);
auto& textureDescriptor = m_owner.GetTextureDescriptor(m_poolIndex, m_bindingIndex, resourceIndex); auto& textureDescriptor = m_owner.GetTextureDescriptor(m_poolIndex, m_bindingIndex, resourceIndex);
textureDescriptor.bindingIndex = binding.bindingIndex; textureDescriptor.bindingIndex = UInt32(binding.bindingIndex);
if (OpenGLTexture* glTexture = static_cast<OpenGLTexture*>(texBinding.texture)) if (OpenGLTexture* glTexture = static_cast<OpenGLTexture*>(texBinding.texture))
{ {
@ -79,29 +79,7 @@ namespace Nz
else else
textureDescriptor.sampler = 0; textureDescriptor.sampler = 0;
switch (glTexture->GetType()) textureDescriptor.textureTarget = OpenGLTexture::ToTextureTarget(glTexture->GetType());
{
case ImageType_2D:
textureDescriptor.textureTarget = GL::TextureTarget::Target2D;
break;
case ImageType_2D_Array:
textureDescriptor.textureTarget = GL::TextureTarget::Target2D_Array;
break;
case ImageType_3D:
textureDescriptor.textureTarget = GL::TextureTarget::Target3D;
break;
case ImageType_Cubemap:
textureDescriptor.textureTarget = GL::TextureTarget::Cubemap;
break;
case ImageType_1D:
case ImageType_1D_Array:
default:
throw std::runtime_error("unsupported texture type");
}
} }
else else
{ {

View File

@ -419,7 +419,7 @@ namespace Nz
RenderPass::AttachmentReference colorReference = { RenderPass::AttachmentReference colorReference = {
0, 0,
TextureLayout::ColorInput TextureLayout::ColorOutput
}; };
std::vector<RenderPass::SubpassDescription> subpasses = { std::vector<RenderPass::SubpassDescription> subpasses = {
@ -475,12 +475,12 @@ namespace Nz
AttachmentStoreOp::Discard, AttachmentStoreOp::Discard,
AttachmentStoreOp::Discard, AttachmentStoreOp::Discard,
TextureLayout::Undefined, TextureLayout::Undefined,
TextureLayout::DepthStencilInput TextureLayout::DepthStencilOutput
}); });
subpasses.front().depthStencilAttachment = RenderPass::AttachmentReference{ subpasses.front().depthStencilAttachment = RenderPass::AttachmentReference{
1, 1,
TextureLayout::DepthStencilInput TextureLayout::DepthStencilOutput
}; };
} }

View File

@ -4,9 +4,11 @@
#include <Nazara/VulkanRenderer/VulkanDevice.hpp> #include <Nazara/VulkanRenderer/VulkanDevice.hpp>
#include <Nazara/VulkanRenderer/VulkanCommandPool.hpp> #include <Nazara/VulkanRenderer/VulkanCommandPool.hpp>
#include <Nazara/VulkanRenderer/VulkanRenderPass.hpp>
#include <Nazara/VulkanRenderer/VulkanRenderPipeline.hpp> #include <Nazara/VulkanRenderer/VulkanRenderPipeline.hpp>
#include <Nazara/VulkanRenderer/VulkanRenderPipelineLayout.hpp> #include <Nazara/VulkanRenderer/VulkanRenderPipelineLayout.hpp>
#include <Nazara/VulkanRenderer/VulkanShaderStage.hpp> #include <Nazara/VulkanRenderer/VulkanShaderStage.hpp>
#include <Nazara/VulkanRenderer/VulkanSingleFramebuffer.hpp>
#include <Nazara/VulkanRenderer/VulkanTexture.hpp> #include <Nazara/VulkanRenderer/VulkanTexture.hpp>
#include <Nazara/VulkanRenderer/VulkanTextureSampler.hpp> #include <Nazara/VulkanRenderer/VulkanTextureSampler.hpp>
#include <Nazara/VulkanRenderer/Debug.hpp> #include <Nazara/VulkanRenderer/Debug.hpp>
@ -25,6 +27,16 @@ namespace Nz
return std::make_shared<VulkanCommandPool>(*this, queueType); return std::make_shared<VulkanCommandPool>(*this, queueType);
} }
std::shared_ptr<Framebuffer> VulkanDevice::InstantiateFramebuffer(unsigned int width, unsigned int height, const std::shared_ptr<RenderPass>& renderPass, const std::vector<std::shared_ptr<Texture>>& attachments)
{
return std::make_shared<VulkanSingleFramebuffer>(*this, width, height, renderPass, attachments);
}
std::shared_ptr<RenderPass> VulkanDevice::InstantiateRenderPass(std::vector<RenderPass::Attachment> attachments, std::vector<RenderPass::SubpassDescription> subpassDescriptions, std::vector<RenderPass::SubpassDependency> subpassDependencies)
{
return std::make_shared<VulkanRenderPass>(*this, std::move(attachments), std::move(subpassDescriptions), std::move(subpassDependencies));
}
std::shared_ptr<RenderPipeline> VulkanDevice::InstantiateRenderPipeline(RenderPipelineInfo pipelineInfo) std::shared_ptr<RenderPipeline> VulkanDevice::InstantiateRenderPipeline(RenderPipelineInfo pipelineInfo)
{ {
return std::make_shared<VulkanRenderPipeline>(*this, std::move(pipelineInfo)); return std::make_shared<VulkanRenderPipeline>(*this, std::move(pipelineInfo));

View File

@ -76,9 +76,9 @@ namespace Nz
VkSubpassDescriptionFlags(0), VkSubpassDescriptionFlags(0),
VK_PIPELINE_BIND_POINT_GRAPHICS, VK_PIPELINE_BIND_POINT_GRAPHICS,
UInt32(subpassInfo.inputAttachments.size()), UInt32(subpassInfo.inputAttachments.size()),
&vkAttachmentReferences[inputAttachmentIndex], (!subpassInfo.inputAttachments.empty()) ? &vkAttachmentReferences[inputAttachmentIndex] : nullptr,
UInt32(subpassInfo.colorAttachment.size()), UInt32(subpassInfo.colorAttachment.size()),
&vkAttachmentReferences[colorAttachmentIndex], (!subpassInfo.colorAttachment.empty()) ? &vkAttachmentReferences[colorAttachmentIndex] : nullptr,
nullptr, nullptr,
(subpassInfo.depthStencilAttachment) ? &vkAttachmentReferences[depthStencilAttachmentIndex] : nullptr, (subpassInfo.depthStencilAttachment) ? &vkAttachmentReferences[depthStencilAttachmentIndex] : nullptr,
0, 0,

View File

@ -3,8 +3,42 @@
// For conditions of distribution and use, see copyright notice in Config.hpp // For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/VulkanRenderer/VulkanSingleFramebuffer.hpp> #include <Nazara/VulkanRenderer/VulkanSingleFramebuffer.hpp>
#include <Nazara/Core/StackArray.hpp>
#include <Nazara/VulkanRenderer/VulkanRenderPass.hpp>
#include <Nazara/VulkanRenderer/VulkanTexture.hpp>
#include <stdexcept>
#include <Nazara/VulkanRenderer/Debug.hpp> #include <Nazara/VulkanRenderer/Debug.hpp>
namespace Nz namespace Nz
{ {
VulkanSingleFramebuffer::VulkanSingleFramebuffer(Vk::Device& device, unsigned int width, unsigned int height, const std::shared_ptr<RenderPass>& renderPass, const std::vector<std::shared_ptr<Texture>>& attachments) :
VulkanFramebuffer(Type::Single)
{
assert(renderPass);
const VulkanRenderPass& vkRenderPass = static_cast<const VulkanRenderPass&>(*renderPass);
StackArray<VkImageView> imageViews = NazaraStackArrayNoInit(VkImageView, attachments.size());
for (std::size_t i = 0; i < attachments.size(); ++i)
{
assert(attachments[i]);
const VulkanTexture& vkTexture = static_cast<const VulkanTexture&>(*attachments[i]);
imageViews[i] = vkTexture.GetImageView();
}
VkFramebufferCreateInfo createInfo = {
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
nullptr,
0,
vkRenderPass.GetRenderPass(),
UInt32(imageViews.size()),
imageViews.data(),
UInt32(width),
UInt32(height),
1
};
if (!m_framebuffer.Create(device, createInfo))
throw std::runtime_error("failed to instantiate Vulkan framebuffer: " + TranslateVulkanError(m_framebuffer.GetLastErrorCode()));
}
} }