Renderer: Implement Framebuffers
This commit is contained in:
parent
3ef74d6e1d
commit
fb3468854f
|
|
@ -34,6 +34,8 @@ namespace Nz
|
|||
|
||||
std::shared_ptr<AbstractBuffer> InstantiateBuffer(BufferType type) 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<RenderPipelineLayout> InstantiateRenderPipelineLayout(RenderPipelineLayoutInfo pipelineLayoutInfo) 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;
|
||||
|
||||
inline void NotifyBufferDestruction(GLuint buffer) const;
|
||||
inline void NotifyFramebufferDestruction(GLuint fbo) const;
|
||||
inline void NotifyProgramDestruction(GLuint program) const;
|
||||
inline void NotifySamplerDestruction(GLuint sampler) const;
|
||||
inline void NotifyTextureDestruction(GLuint texture) const;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,12 @@ namespace Nz
|
|||
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
|
||||
{
|
||||
for (const GL::Context* context : m_contexts)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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>
|
||||
|
|
@ -34,6 +34,8 @@ namespace Nz
|
|||
OpenGLTexture& operator=(const OpenGLTexture&) = delete;
|
||||
OpenGLTexture& operator=(OpenGLTexture&&) = delete;
|
||||
|
||||
static inline GL::TextureTarget ToTextureTarget(ImageType imageType);
|
||||
|
||||
private:
|
||||
GL::Texture m_texture;
|
||||
TextureInfo m_params;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/OpenGLRenderer/OpenGLTexture.hpp>
|
||||
#include <stdexcept>
|
||||
#include <Nazara/OpenGLRenderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
|
|
@ -11,6 +12,22 @@ namespace Nz
|
|||
{
|
||||
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>
|
||||
|
|
|
|||
|
|
@ -36,4 +36,4 @@ namespace Nz
|
|||
|
||||
#include <Nazara/OpenGLRenderer/OpenGLWindowFramebuffer.inl>
|
||||
|
||||
#endif // NAZARA_OPENGLRENDERER_OpenGLWindowFramebuffer_HPP
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// 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/OpenGLWindowFramebuffer.hpp>
|
||||
#include <Nazara/OpenGLRenderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
|
|
|
|||
|
|
@ -126,6 +126,7 @@ namespace Nz::GL
|
|||
bool Initialize(const ContextParams& params);
|
||||
|
||||
inline void NotifyBufferDestruction(GLuint buffer) const;
|
||||
inline void NotifyFramebufferDestruction(GLuint fbo) const;
|
||||
inline void NotifyProgramDestruction(GLuint program) const;
|
||||
inline void NotifySamplerDestruction(GLuint sampler) const;
|
||||
inline void NotifyTextureDestruction(GLuint texture) const;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
if (m_state.boundProgram == program)
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ typedef void (GL_APIENTRYP PFNGLSPECIALIZESHADERARBPROC) (GLuint shader, const G
|
|||
cb(glBufferSubData, PFNGLBUFFERSUBDATAPROC) \
|
||||
cb(glClear, PFNGLCLEARPROC) \
|
||||
cb(glClearBufferfi, PFNGLCLEARBUFFERFIPROC) \
|
||||
cb(glClearBufferfv, PFNGLCLEARBUFFERFVPROC) \
|
||||
cb(glClearBufferuiv, PFNGLCLEARBUFFERUIVPROC) \
|
||||
cb(glClearColor, PFNGLCLEARCOLORPROC) \
|
||||
cb(glClearDepthf, PFNGLCLEARDEPTHFPROC) \
|
||||
|
|
@ -156,6 +157,9 @@ typedef void (GL_APIENTRYP PFNGLSPECIALIZESHADERARBPROC) (GLuint shader, const G
|
|||
\
|
||||
extCb(glDebugMessageCallback, PFNGLDEBUGMESSAGECALLBACKPROC) \
|
||||
\
|
||||
extCb(glMemoryBarrier, PFNGLMEMORYBARRIERPROC) \
|
||||
extCb(glMemoryBarrierByRegion, PFNGLMEMORYBARRIERBYREGIONPROC) \
|
||||
\
|
||||
extCb(glObjectLabel, PFNGLOBJECTLABELPROC) \
|
||||
extCb(glPopDebugGroup, PFNGLPOPDEBUGGROUPPROC) \
|
||||
extCb(glPushDebugGroup, PFNGLPUSHDEBUGGROUPPROC) \
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Core/MovablePtr.hpp>
|
||||
#include <Nazara/Core/MovableValue.hpp>
|
||||
#include <Nazara/OpenGLRenderer/Wrapper/Context.hpp>
|
||||
#include <string>
|
||||
|
||||
|
|
@ -26,6 +27,8 @@ namespace Nz::GL
|
|||
bool Create(OpenGLDevice& device, CreateArgs... args);
|
||||
void Destroy();
|
||||
|
||||
const Context& EnsureDeviceContext() const;
|
||||
|
||||
bool IsValid() const;
|
||||
|
||||
OpenGLDevice* GetDevice() const;
|
||||
|
|
@ -39,8 +42,6 @@ namespace Nz::GL
|
|||
static constexpr GLuint InvalidObject = 0;
|
||||
|
||||
protected:
|
||||
const Context& EnsureDeviceContext();
|
||||
|
||||
MovablePtr<OpenGLDevice> m_device;
|
||||
MovableValue<GLuint> m_objectId;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
bool DeviceObject<C, ObjectType, CreateArgs...>::IsValid() const
|
||||
{
|
||||
|
|
@ -72,24 +90,6 @@ namespace Nz::GL
|
|||
if (context.glObjectLabel)
|
||||
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>
|
||||
|
|
|
|||
|
|
@ -4,36 +4,38 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_OPENGLRENDERER_VKFRAMEBUFFER_HPP
|
||||
#define NAZARA_OPENGLRENDERER_VKFRAMEBUFFER_HPP
|
||||
#ifndef NAZARA_OPENGLRENDERER_GLFRAMEBUFFER_HPP
|
||||
#define NAZARA_OPENGLRENDERER_GLFRAMEBUFFER_HPP
|
||||
|
||||
#include <Nazara/Prerequisites.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:
|
||||
Framebuffer() = default;
|
||||
Framebuffer(const Framebuffer&) = delete;
|
||||
Framebuffer(Framebuffer&&) = default;
|
||||
~Framebuffer() = default;
|
||||
public:
|
||||
Framebuffer() = default;
|
||||
Framebuffer(const Framebuffer&) = delete;
|
||||
Framebuffer(Framebuffer&&) noexcept = default;
|
||||
~Framebuffer() = default;
|
||||
|
||||
Framebuffer& operator=(const Framebuffer&) = delete;
|
||||
Framebuffer& operator=(Framebuffer&&) = delete;
|
||||
inline GLenum Check() const;
|
||||
|
||||
private:
|
||||
static inline VkResult CreateHelper(Device& device, const VkFramebufferCreateInfo* createInfo, const VkAllocationCallbacks* allocator, VkFramebuffer* handle);
|
||||
static inline void DestroyHelper(Device& device, VkFramebuffer handle, const VkAllocationCallbacks* allocator);
|
||||
};
|
||||
}
|
||||
inline void Renderbuffer(GLenum attachment, GLenum renderbuffer);
|
||||
inline void Texture2D(GLenum attachment, GLenum textarget, GLuint texture, GLint level = 0);
|
||||
|
||||
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>
|
||||
|
||||
#endif // NAZARA_OPENGLRENDERER_VKFRAMEBUFFER_HPP
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -3,21 +3,51 @@
|
|||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/OpenGLRenderer/Wrapper/Framebuffer.hpp>
|
||||
#include <Nazara/OpenGLRenderer/OpenGLDevice.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)
|
||||
{
|
||||
return device.vkCreateFramebuffer(device, createInfo, allocator, handle);
|
||||
}
|
||||
assert(m_objectId);
|
||||
|
||||
inline void Framebuffer::DestroyHelper(Device& device, VkFramebuffer handle, const VkAllocationCallbacks* allocator)
|
||||
{
|
||||
return device.vkDestroyFramebuffer(device, handle, allocator);
|
||||
}
|
||||
const Context& context = EnsureDeviceContext();
|
||||
context.BindFramebuffer(m_objectId);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@
|
|||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Renderer/Config.hpp>
|
||||
#include <Nazara/Renderer/Enums.hpp>
|
||||
#include <Nazara/Renderer/Framebuffer.hpp>
|
||||
#include <Nazara/Renderer/RenderPass.hpp>
|
||||
#include <Nazara/Renderer/RenderPipeline.hpp>
|
||||
#include <Nazara/Renderer/RenderPipelineLayout.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<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<RenderPipelineLayout> InstantiateRenderPipelineLayout(RenderPipelineLayoutInfo pipelineLayoutInfo) = 0;
|
||||
virtual std::shared_ptr<ShaderStage> InstantiateShaderStage(const ShaderAst& shaderAst, const ShaderWriter::States& states) = 0;
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
return m_attachments[attachmentIndex];
|
||||
|
|
|
|||
|
|
@ -162,6 +162,7 @@ namespace Nz
|
|||
PixelFormatContent_Undefined = -1,
|
||||
|
||||
PixelFormatContent_ColorRGBA,
|
||||
PixelFormatContent_Depth,
|
||||
PixelFormatContent_DepthStencil,
|
||||
PixelFormatContent_Stencil,
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ namespace Nz
|
|||
inline VkShaderStageFlags ToVulkan(ShaderStageTypeFlags stageType);
|
||||
inline VkStencilOp ToVulkan(StencilOperation stencilOp);
|
||||
inline VkImageLayout ToVulkan(TextureLayout textureLayout);
|
||||
inline VkImageUsageFlagBits ToVulkan(TextureUsage textureLayout);
|
||||
inline VkImageUsageFlags ToVulkan(TextureUsageFlags textureLayout);
|
||||
inline VkVertexInputRate ToVulkan(VertexInputRate inputRate);
|
||||
|
||||
NAZARA_VULKANRENDERER_API std::string TranslateVulkanError(VkResult code);
|
||||
|
|
|
|||
|
|
@ -196,9 +196,11 @@ namespace Nz
|
|||
switch (pixelFormat)
|
||||
{
|
||||
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_Depth32: return VK_FORMAT_D32_SFLOAT;
|
||||
case PixelFormat::PixelFormat_RGBA8: return VK_FORMAT_R8G8B8A8_UNORM;
|
||||
case PixelFormat::PixelFormat_RGBA8_SRGB: return VK_FORMAT_R8G8B8A8_SRGB;
|
||||
default: break;
|
||||
}
|
||||
|
||||
|
|
@ -336,10 +338,10 @@ namespace Nz
|
|||
{
|
||||
switch (textureLayout)
|
||||
{
|
||||
case TextureLayout::ColorInput: return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
case TextureLayout::ColorOutput: return VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR;
|
||||
case TextureLayout::DepthStencilInput: return VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL;
|
||||
case TextureLayout::DepthStencilOutput: return VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL;
|
||||
case TextureLayout::ColorInput: return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
case TextureLayout::ColorOutput: return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
case TextureLayout::DepthStencilInput: return VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
|
||||
case TextureLayout::DepthStencilOutput: return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
case TextureLayout::Present: return VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
case TextureLayout::TransferSource: return VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
case TextureLayout::TransferDestination: return VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
|
|
@ -350,6 +352,35 @@ namespace Nz
|
|||
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)
|
||||
{
|
||||
switch (inputRate)
|
||||
|
|
@ -359,7 +390,7 @@ namespace Nz
|
|||
}
|
||||
|
||||
NazaraError("Unhandled VertexInputRate 0x" + NumberToString(UnderlyingCast(inputRate), 16));
|
||||
return VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ namespace Nz
|
|||
|
||||
std::shared_ptr<AbstractBuffer> InstantiateBuffer(BufferType type) 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<RenderPipelineLayout> InstantiateRenderPipelineLayout(RenderPipelineLayoutInfo pipelineLayoutInfo) override;
|
||||
std::shared_ptr<ShaderStage> InstantiateShaderStage(const ShaderAst& shaderAst, const ShaderWriter::States& states) override;
|
||||
|
|
|
|||
|
|
@ -8,13 +8,17 @@
|
|||
#define NAZARA_VULKANRENDERER_VULKANSINGLEFRAMEBUFFER_HPP
|
||||
|
||||
#include <Nazara/VulkanRenderer/VulkanFramebuffer.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class RenderPass;
|
||||
class Texture;
|
||||
|
||||
class NAZARA_VULKANRENDERER_API VulkanSingleFramebuffer final : public VulkanFramebuffer
|
||||
{
|
||||
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(VulkanSingleFramebuffer&&) = delete;
|
||||
~VulkanSingleFramebuffer() = default;
|
||||
|
|
|
|||
|
|
@ -7,12 +7,6 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
inline VulkanSingleFramebuffer::VulkanSingleFramebuffer(Vk::Framebuffer framebuffer) :
|
||||
VulkanFramebuffer(Type::Single),
|
||||
m_framebuffer(std::move(framebuffer))
|
||||
{
|
||||
}
|
||||
|
||||
inline Vk::Framebuffer& VulkanSingleFramebuffer::GetFramebuffer()
|
||||
{
|
||||
return m_framebuffer;
|
||||
|
|
|
|||
|
|
@ -106,18 +106,19 @@ namespace Nz
|
|||
for (std::size_t i = 0; i < colorBufferCount; ++i)
|
||||
{
|
||||
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
|
||||
{
|
||||
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
|
||||
static_assert(AlwaysFalse<T>::value, "non-exhaustive visitor");
|
||||
|
|
@ -131,6 +132,8 @@ namespace Nz
|
|||
states.shaderBindings->Apply(context);
|
||||
states.pipeline->Apply(context);
|
||||
|
||||
states.pipeline->FlipY(states.shouldFlipY);
|
||||
|
||||
if (states.scissorRegion)
|
||||
context.SetScissorBox(states.scissorRegion->x, states.scissorRegion->y, states.scissorRegion->width, states.scissorRegion->height);
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ namespace Nz
|
|||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
#include <Nazara/Renderer/CommandPool.hpp>
|
||||
#include <Nazara/OpenGLRenderer/OpenGLBuffer.hpp>
|
||||
#include <Nazara/OpenGLRenderer/OpenGLCommandPool.hpp>
|
||||
#include <Nazara/OpenGLRenderer/OpenGLFboFramebuffer.hpp>
|
||||
#include <Nazara/OpenGLRenderer/OpenGLRenderPass.hpp>
|
||||
#include <Nazara/OpenGLRenderer/OpenGLRenderPipeline.hpp>
|
||||
#include <Nazara/OpenGLRenderer/OpenGLRenderPipelineLayout.hpp>
|
||||
#include <Nazara/OpenGLRenderer/OpenGLShaderStage.hpp>
|
||||
|
|
@ -58,6 +60,16 @@ namespace Nz
|
|||
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)
|
||||
{
|
||||
return std::make_shared<OpenGLRenderPipeline>(*this, std::move(pipelineInfo));
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -68,7 +68,7 @@ namespace Nz
|
|||
const TextureBinding& texBinding = std::get<TextureBinding>(binding.content);
|
||||
|
||||
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))
|
||||
{
|
||||
|
|
@ -79,29 +79,7 @@ namespace Nz
|
|||
else
|
||||
textureDescriptor.sampler = 0;
|
||||
|
||||
switch (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");
|
||||
}
|
||||
textureDescriptor.textureTarget = OpenGLTexture::ToTextureTarget(glTexture->GetType());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -419,7 +419,7 @@ namespace Nz
|
|||
|
||||
RenderPass::AttachmentReference colorReference = {
|
||||
0,
|
||||
TextureLayout::ColorInput
|
||||
TextureLayout::ColorOutput
|
||||
};
|
||||
|
||||
std::vector<RenderPass::SubpassDescription> subpasses = {
|
||||
|
|
@ -475,12 +475,12 @@ namespace Nz
|
|||
AttachmentStoreOp::Discard,
|
||||
AttachmentStoreOp::Discard,
|
||||
TextureLayout::Undefined,
|
||||
TextureLayout::DepthStencilInput
|
||||
TextureLayout::DepthStencilOutput
|
||||
});
|
||||
|
||||
subpasses.front().depthStencilAttachment = RenderPass::AttachmentReference{
|
||||
1,
|
||||
TextureLayout::DepthStencilInput
|
||||
TextureLayout::DepthStencilOutput
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,9 +4,11 @@
|
|||
|
||||
#include <Nazara/VulkanRenderer/VulkanDevice.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanCommandPool.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanRenderPass.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanRenderPipeline.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanRenderPipelineLayout.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanShaderStage.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanSingleFramebuffer.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanTexture.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanTextureSampler.hpp>
|
||||
#include <Nazara/VulkanRenderer/Debug.hpp>
|
||||
|
|
@ -25,6 +27,16 @@ namespace Nz
|
|||
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)
|
||||
{
|
||||
return std::make_shared<VulkanRenderPipeline>(*this, std::move(pipelineInfo));
|
||||
|
|
|
|||
|
|
@ -76,9 +76,9 @@ namespace Nz
|
|||
VkSubpassDescriptionFlags(0),
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
UInt32(subpassInfo.inputAttachments.size()),
|
||||
&vkAttachmentReferences[inputAttachmentIndex],
|
||||
(!subpassInfo.inputAttachments.empty()) ? &vkAttachmentReferences[inputAttachmentIndex] : nullptr,
|
||||
UInt32(subpassInfo.colorAttachment.size()),
|
||||
&vkAttachmentReferences[colorAttachmentIndex],
|
||||
(!subpassInfo.colorAttachment.empty()) ? &vkAttachmentReferences[colorAttachmentIndex] : nullptr,
|
||||
nullptr,
|
||||
(subpassInfo.depthStencilAttachment) ? &vkAttachmentReferences[depthStencilAttachmentIndex] : nullptr,
|
||||
0,
|
||||
|
|
|
|||
|
|
@ -3,8 +3,42 @@
|
|||
// For conditions of distribution and use, see copyright notice in Config.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>
|
||||
|
||||
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()));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue