Add render to texture support in GEVulkanDriver

This commit is contained in:
Benau
2022-07-24 11:38:02 +08:00
parent 99d565f961
commit da0cce6cd6
11 changed files with 322 additions and 17 deletions

View File

@@ -36,6 +36,7 @@ set(GE_SOURCES
src/ge_vulkan_driver.cpp
src/ge_vulkan_draw_call.cpp
src/ge_vulkan_dynamic_buffer.cpp
src/ge_vulkan_fbo_texture.cpp
src/ge_vulkan_features.cpp
src/ge_vulkan_mesh_cache.cpp
src/ge_vulkan_mesh_scene_node.cpp

View File

@@ -23,6 +23,7 @@ using namespace video;
namespace GE
{
class GEVulkanFBOTexture;
class GEVulkanDepthTexture;
class GEVulkanMeshCache;
class GEVulkanTextureDescriptor;
@@ -68,7 +69,7 @@ namespace GE
//! sets a render target
virtual bool setRenderTarget(video::ITexture* texture,
bool clearBackBuffer=true, bool clearZBuffer=true,
SColor color=video::SColor(0,0,0,0)) { return true; }
SColor color=video::SColor(0,0,0,0));
//! Sets multiple render targets
virtual bool setRenderTarget(const core::array<video::IRenderTarget>& texture,
@@ -231,7 +232,7 @@ namespace GE
//! Creates a render target texture.
virtual ITexture* addRenderTargetTexture(const core::dimension2d<u32>& size,
const io::path& name, const ECOLOR_FORMAT format = ECF_UNKNOWN, const bool useStencil = false) { return NULL; }
const io::path& name, const ECOLOR_FORMAT format = ECF_UNKNOWN, const bool useStencil = false);
//! Clears the ZBuffer.
virtual void clearZBuffer() {}
@@ -316,6 +317,7 @@ namespace GE
unsigned int getCurrentImageIndex() const { return m_image_index; }
constexpr static unsigned getMaxFrameInFlight() { return 2; }
video::SColor getClearColor() const { return m_clear_color; }
video::SColor getRTTClearColor() const { return m_rtt_clear_color; }
const core::rect<s32>& getCurrentClip() const { return m_clip; }
video::ITexture* getWhiteTexture() const { return m_white_texture; }
video::ITexture* getTransparentTexture() const
@@ -349,6 +351,9 @@ namespace GE
GEVulkanMeshCache* getVulkanMeshCache() const;
GEVulkanTextureDescriptor* getMeshTextureDescriptor() const
{ return m_mesh_texture_descriptor; }
GEVulkanFBOTexture* getRTTTexture() const { return m_rtt_texture; }
void handleDeletedTextures();
void addRTTPolyCount(unsigned count) { m_rtt_polycount += count; }
private:
struct SwapChainSupportDetails
{
@@ -465,7 +470,7 @@ namespace GE
unsigned int m_current_frame;
uint32_t m_image_index;
video::SColor m_clear_color;
video::SColor m_clear_color, m_rtt_clear_color;
core::rect<s32> m_clip;
core::rect<s32> m_viewport;
core::matrix4 m_pre_rotation_matrix;
@@ -479,6 +484,8 @@ namespace GE
IrrlichtDevice* m_irrlicht_device;
GEVulkanDepthTexture* m_depth_texture;
GEVulkanTextureDescriptor* m_mesh_texture_descriptor;
GEVulkanFBOTexture* m_rtt_texture;
u32 m_rtt_polycount;
void createInstance(SDL_Window* window);
void findPhysicalDevice();
@@ -502,7 +509,6 @@ namespace GE
void destroySwapChainRelated(bool handle_surface);
void createSwapChainRelated(bool handle_surface);
void buildCommandBuffers();
void handleDeletedTextures();
};
}

View File

@@ -15,6 +15,8 @@ class GEVulkanSceneManager : public irr::scene::CSceneManager
private:
std::map<GEVulkanCameraSceneNode*, std::unique_ptr<GEVulkanDrawCall> > m_draw_calls;
// ------------------------------------------------------------------------
void drawAllInternal();
public:
// ------------------------------------------------------------------------
GEVulkanSceneManager(irr::video::IVideoDriver* driver,

View File

@@ -35,8 +35,12 @@ void GEVulkanCameraSceneNode::render()
// The easiest way to compensate for that is to flip the sign on the
// scaling factor of the Y axis in the projection matrix.
m_ubo_data.m_projection_matrix(1, 1) *= -1.0f;
m_ubo_data.m_projection_matrix = getVKDriver()->getPreRotationMatrix() *
m_ubo_data.m_projection_matrix;
GEVulkanDriver* vk = getVKDriver();
if (!vk->getRTTTexture())
{
m_ubo_data.m_projection_matrix = vk->getPreRotationMatrix() *
m_ubo_data.m_projection_matrix;
}
irr::core::matrix4 mat;
ViewArea.getTransform(irr::video::ETS_VIEW).getInverse(mat);

View File

@@ -7,6 +7,7 @@
#include "ge_vulkan_camera_scene_node.hpp"
#include "ge_vulkan_driver.hpp"
#include "ge_vulkan_dynamic_buffer.hpp"
#include "ge_vulkan_fbo_texture.hpp"
#include "ge_vulkan_features.hpp"
#include "ge_vulkan_mesh_cache.hpp"
#include "ge_vulkan_mesh_scene_node.hpp"
@@ -137,10 +138,7 @@ void GEVulkanDrawCall::generate()
// ----------------------------------------------------------------------------
void GEVulkanDrawCall::prepare(GEVulkanCameraSceneNode* cam)
{
m_visible_nodes.clear();
m_cmds.clear();
m_visible_objects.clear();
m_materials.clear();
reset();
m_culling_tool->init(cam);
} // prepare
@@ -392,7 +390,8 @@ void GEVulkanDrawCall::createVulkanData()
pipeline_info.pColorBlendState = &color_blending;
pipeline_info.pDynamicState = &dynamic_state_info;
pipeline_info.layout = m_pipeline_layout;
pipeline_info.renderPass = vk->getRenderPass();
pipeline_info.renderPass = vk->getRTTTexture() ?
vk->getRTTTexture()->getRTTRenderPass() : vk->getRenderPass();
pipeline_info.subpass = 0;
pipeline_info.basePipelineHandle = VK_NULL_HANDLE;
@@ -422,7 +421,7 @@ void GEVulkanDrawCall::uploadDynamicData(GEVulkanDriver* vk,
GEVulkanCameraSceneNode* cam,
VkCommandBuffer custom_cmd)
{
if (!m_dynamic_data)
if (!m_dynamic_data || m_cmds.empty())
return;
VkCommandBuffer cmd =

View File

@@ -92,6 +92,14 @@ public:
result += (cmd.indexCount / 3) * cmd.instanceCount;
return result;
}
// ------------------------------------------------------------------------
void reset()
{
m_visible_nodes.clear();
m_cmds.clear();
m_visible_objects.clear();
m_materials.clear();
}
}; // GEVulkanDrawCall
}

View File

@@ -7,6 +7,7 @@
#include "ge_vulkan_command_loader.hpp"
#include "ge_vulkan_depth_texture.hpp"
#include "ge_vulkan_draw_call.hpp"
#include "ge_vulkan_fbo_texture.hpp"
#include "ge_vulkan_features.hpp"
#include "ge_vulkan_mesh_cache.hpp"
#include "ge_vulkan_scene_manager.hpp"
@@ -490,7 +491,8 @@ GEVulkanDriver::GEVulkanDriver(const SIrrlichtCreationParameters& params,
IrrlichtDevice* device)
: CNullDriver(io, core::dimension2d<u32>(0, 0)),
m_params(params), m_irrlicht_device(device),
m_depth_texture(NULL), m_mesh_texture_descriptor(NULL)
m_depth_texture(NULL), m_mesh_texture_descriptor(NULL),
m_rtt_texture(NULL), m_rtt_polycount(0)
{
m_vk.reset(new VK());
m_physical_device = VK_NULL_HANDLE;
@@ -503,6 +505,7 @@ GEVulkanDriver::GEVulkanDriver(const SIrrlichtCreationParameters& params,
m_current_frame = 0;
m_image_index = 0;
m_clear_color = video::SColor(0);
m_rtt_clear_color = m_clear_color;
m_white_texture = NULL;
m_transparent_texture = NULL;
m_pre_rotation_matrix = core::matrix4(core::matrix4::EM4CONST_IDENTITY);
@@ -1562,6 +1565,8 @@ bool GEVulkanDriver::beginScene(bool backBuffer, bool zBuffer, SColor color,
return false;
m_clear_color = color;
PrimitivesDrawn = m_rtt_polycount;
m_rtt_polycount = 0;
return true;
} // beginScene
@@ -2075,6 +2080,9 @@ void GEVulkanDriver::getRotatedRect2D(VkRect2D* rect)
// ----------------------------------------------------------------------------
void GEVulkanDriver::getRotatedViewport(VkViewport* vp)
{
if (m_rtt_texture)
return;
VkRect2D rect;
rect.offset.x = vp->x;
rect.offset.y = vp->y;
@@ -2274,6 +2282,27 @@ void GEVulkanDriver::handleDeletedTextures()
m_mesh_texture_descriptor->handleDeletedTextures();
} // handleDeletedTextures
// ----------------------------------------------------------------------------
ITexture* GEVulkanDriver::addRenderTargetTexture(const core::dimension2d<u32>& size,
const io::path& name, const ECOLOR_FORMAT format,
const bool useStencil)
{
GEVulkanFBOTexture* rtt = new GEVulkanFBOTexture(size, true/*create_depth*/);
rtt->createRTT();
return rtt;
} // addRenderTargetTexture
// ----------------------------------------------------------------------------
bool GEVulkanDriver::setRenderTarget(video::ITexture* texture,
bool clearBackBuffer, bool clearZBuffer,
SColor color)
{
m_rtt_texture = dynamic_cast<GEVulkanFBOTexture*>(texture);
if (m_rtt_texture)
m_rtt_clear_color = color;
return true;
} // setRenderTarget
}
namespace irr

View File

@@ -0,0 +1,146 @@
#include "ge_vulkan_fbo_texture.hpp"
#include "ge_main.hpp"
#include "ge_vulkan_depth_texture.hpp"
#include "ge_vulkan_driver.hpp"
#include <array>
#include <exception>
namespace GE
{
GEVulkanFBOTexture::GEVulkanFBOTexture(const core::dimension2d<u32>& size,
bool create_depth)
: GEVulkanTexture()
{
m_vk = getVKDriver();
m_vulkan_device = m_vk->getDevice();
m_image = VK_NULL_HANDLE;
m_vma_allocation = VK_NULL_HANDLE;
m_has_mipmaps = false;
m_locked_data = NULL;
m_size = m_orig_size = m_max_size = size;
m_texture_size = m_size.Width * m_size.Height * 4;
m_internal_format = VK_FORMAT_R8G8B8A8_UNORM;
if (!createImage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
VK_IMAGE_USAGE_SAMPLED_BIT))
throw std::runtime_error("createImage failed for fbo texture");
if (!createImageView(VK_IMAGE_ASPECT_COLOR_BIT))
throw std::runtime_error("createImageView failed for fbo texture");
m_depth_texture = NULL;
m_rtt_render_pass = VK_NULL_HANDLE;
m_rtt_frame_buffer = VK_NULL_HANDLE;
if (create_depth)
m_depth_texture = new GEVulkanDepthTexture(m_vk, size);
} // GEVulkanFBOTexture
// ----------------------------------------------------------------------------
GEVulkanFBOTexture::~GEVulkanFBOTexture()
{
delete m_depth_texture;
if (m_rtt_frame_buffer != VK_NULL_HANDLE)
{
clearVulkanData();
vkDestroyFramebuffer(m_vk->getDevice(), m_rtt_frame_buffer, NULL);
m_vk->handleDeletedTextures();
m_image_view.reset();
m_image = VK_NULL_HANDLE;
m_vma_allocation = VK_NULL_HANDLE;
}
if (m_rtt_render_pass != VK_NULL_HANDLE)
vkDestroyRenderPass(m_vk->getDevice(), m_rtt_render_pass, NULL);
} // ~GEVulkanFBOTexture
// ----------------------------------------------------------------------------
void GEVulkanFBOTexture::createRTT()
{
if (!m_depth_texture)
return;
std::array<VkAttachmentDescription, 2> attchment_desc = {};
// Color attachment
attchment_desc[0].format = m_internal_format;
attchment_desc[0].samples = VK_SAMPLE_COUNT_1_BIT;
attchment_desc[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attchment_desc[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attchment_desc[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attchment_desc[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attchment_desc[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attchment_desc[0].finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
// Depth attachment
attchment_desc[1].format = m_depth_texture->getInternalFormat();
attchment_desc[1].samples = VK_SAMPLE_COUNT_1_BIT;
attchment_desc[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attchment_desc[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attchment_desc[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attchment_desc[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attchment_desc[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attchment_desc[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkAttachmentReference color_reference = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
VkAttachmentReference depth_reference = { 1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
VkSubpassDescription subpass_desc = {};
subpass_desc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass_desc.colorAttachmentCount = 1;
subpass_desc.pColorAttachments = &color_reference;
subpass_desc.pDepthStencilAttachment = &depth_reference;
// Use subpass dependencies for layout transitions
std::array<VkSubpassDependency, 2> dependencies;
dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
dependencies[0].dstSubpass = 0;
dependencies[0].srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[0].srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
dependencies[1].srcSubpass = 0;
dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL;
dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[1].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[1].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
// Create the actual render pass
VkRenderPassCreateInfo render_pass_info = {};
render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
render_pass_info.attachmentCount = attchment_desc.size();
render_pass_info.pAttachments = attchment_desc.data();
render_pass_info.subpassCount = 1;
render_pass_info.pSubpasses = &subpass_desc;
render_pass_info.dependencyCount = dependencies.size();
render_pass_info.pDependencies = dependencies.data();
if (vkCreateRenderPass(m_vk->getDevice(), &render_pass_info, NULL,
&m_rtt_render_pass) != VK_SUCCESS)
throw std::runtime_error("vkCreateRenderPass failed in createFBOdata");
std::array<VkImageView, 2> attachments =
{{
*(m_image_view.get()),
(VkImageView)m_depth_texture->getTextureHandler(),
}};
VkFramebufferCreateInfo framebuffer_info = {};
framebuffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
framebuffer_info.renderPass = m_rtt_render_pass;
framebuffer_info.attachmentCount = attachments.size();
framebuffer_info.pAttachments = attachments.data();
framebuffer_info.width = m_size.Width;
framebuffer_info.height = m_size.Height;
framebuffer_info.layers = 1;
if (vkCreateFramebuffer(m_vk->getDevice(), &framebuffer_info,
NULL, &m_rtt_frame_buffer) != VK_SUCCESS)
throw std::runtime_error("vkCreateFramebuffer failed in createFBOdata");
} // createRTT
}

View File

@@ -0,0 +1,61 @@
#ifndef HEADER_GE_VULKAN_FBO_TEXTURE_HPP
#define HEADER_GE_VULKAN_FBO_TEXTURE_HPP
#include "ge_vulkan_texture.hpp"
namespace GE
{
class GEVulkanDepthTexture;
class GEVulkanFBOTexture : public GEVulkanTexture
{
private:
GEVulkanDepthTexture* m_depth_texture;
VkRenderPass m_rtt_render_pass;
VkFramebuffer m_rtt_frame_buffer;
public:
// ------------------------------------------------------------------------
GEVulkanFBOTexture(const core::dimension2d<u32>& size, bool create_depth);
// ------------------------------------------------------------------------
virtual ~GEVulkanFBOTexture();
// ------------------------------------------------------------------------
virtual void* lock(video::E_TEXTURE_LOCK_MODE mode =
video::ETLM_READ_WRITE, u32 mipmap_level = 0)
{ return NULL; }
// ------------------------------------------------------------------------
virtual void unlock() {}
// ------------------------------------------------------------------------
virtual const core::dimension2d<u32>& getOriginalSize() const
{ return m_orig_size; }
// ------------------------------------------------------------------------
virtual const core::dimension2d<u32>& getSize() const { return m_size; }
// ------------------------------------------------------------------------
virtual bool hasMipMaps() const { return false; }
// ------------------------------------------------------------------------
virtual void regenerateMipMapLevels(void* mipmap_data = NULL) {}
// ------------------------------------------------------------------------
virtual u64 getTextureHandler() const
{ return (u64)*(m_image_view.get()); }
// ------------------------------------------------------------------------
virtual unsigned int getTextureSize() const { return m_texture_size; }
// ------------------------------------------------------------------------
virtual void reload() {}
// ------------------------------------------------------------------------
virtual void updateTexture(void* data, irr::video::ECOLOR_FORMAT format,
u32 w, u32 h, u32 x, u32 y) {}
// ------------------------------------------------------------------------
virtual std::shared_ptr<VkImageView> getImageView() const
{ return m_image_view; }
// ------------------------------------------------------------------------
void createRTT();
// ------------------------------------------------------------------------
VkRenderPass getRTTRenderPass() const { return m_rtt_render_pass; }
// ------------------------------------------------------------------------
VkFramebuffer getRTTFramebuffer() const { return m_rtt_frame_buffer; }
}; // GEVulkanFBOTexture
}
#endif

View File

@@ -5,8 +5,10 @@
#include "ge_spm.hpp"
#include "ge_vulkan_animated_mesh_scene_node.hpp"
#include "ge_vulkan_camera_scene_node.hpp"
#include "ge_vulkan_command_loader.hpp"
#include "ge_vulkan_draw_call.hpp"
#include "ge_vulkan_driver.hpp"
#include "ge_vulkan_fbo_texture.hpp"
#include "ge_vulkan_mesh_cache.hpp"
#include "ge_vulkan_mesh_scene_node.hpp"
#include "ge_vulkan_texture_descriptor.hpp"
@@ -118,7 +120,7 @@ irr::scene::IMeshSceneNode* GEVulkanSceneManager::addMeshSceneNode(
} // addMeshSceneNode
// ----------------------------------------------------------------------------
void GEVulkanSceneManager::drawAll(irr::u32 flags)
void GEVulkanSceneManager::drawAllInternal()
{
static_cast<GEVulkanMeshCache*>(getMeshCache())->updateCache();
GEVulkanCameraSceneNode* cam = NULL;
@@ -139,6 +141,53 @@ void GEVulkanSceneManager::drawAll(irr::u32 flags)
OnRegisterSceneNode();
it->second->generate();
}
} // drawAllInternal
// ----------------------------------------------------------------------------
void GEVulkanSceneManager::drawAll(irr::u32 flags)
{
drawAllInternal();
GEVulkanDriver* vk = static_cast<GEVulkanDriver*>(getVideoDriver());
GEVulkanFBOTexture* rtt = vk->getRTTTexture();
if (!rtt)
return;
std::array<VkClearValue, 2> clear_values = {};
video::SColorf cf(vk->getRTTClearColor());
clear_values[0].color =
{
cf.getRed(), cf.getGreen(), cf.getBlue(), cf.getAlpha()
};
clear_values[1].depthStencil = {1.0f, 0};
VkCommandBuffer cmd = GEVulkanCommandLoader::beginSingleTimeCommands();
GEVulkanCameraSceneNode* cam = static_cast<
GEVulkanCameraSceneNode*>(getActiveCamera());
std::unique_ptr<GEVulkanDrawCall>& dc = m_draw_calls.at(cam);
dc->uploadDynamicData(vk, cam, cmd);
VkRenderPassBeginInfo render_pass_info = {};
render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
render_pass_info.renderPass = rtt->getRTTRenderPass();
render_pass_info.framebuffer = rtt->getRTTFramebuffer();
render_pass_info.renderArea.offset = {0, 0};
render_pass_info.renderArea.extent =
{ rtt->getSize().Width, rtt->getSize().Height };
render_pass_info.clearValueCount = (uint32_t)(clear_values.size());
render_pass_info.pClearValues = &clear_values[0];
vkCmdBeginRenderPass(cmd, &render_pass_info, VK_SUBPASS_CONTENTS_INLINE);
cam->setViewPort(
core::recti(0, 0, rtt->getSize().Width, rtt->getSize().Height));
dc->render(vk, cam, cmd);
vk->addRTTPolyCount(dc->getPolyCount());
dc->reset();
vkCmdEndRenderPass(cmd);
GEVulkanCommandLoader::endSingleTimeCommands(cmd);
vk->handleDeletedTextures();
} // drawAll
// ----------------------------------------------------------------------------

View File

@@ -49,9 +49,9 @@ GL1RenderTarget::GL1RenderTarget(const irr::core::dimension2du &dimension,
GL1RenderTarget::~GL1RenderTarget()
{
/*assert(m_old_rtt_mini_map->getReferenceCount() == 1);
irr_driver->removeTexture(m_old_rtt_mini_map);
m_old_rtt_mini_map = NULL;*/
// GE doesn't add rtt texture to cache
if (m_render_target_texture->getDriverType() == video::EDT_VULKAN)
m_render_target_texture->drop();
}
//-----------------------------------------------------------------------------