Add GEVulkanDrawCall

This commit is contained in:
Benau 2022-07-18 13:28:07 +08:00
parent 5853d618a6
commit 44b2468003
12 changed files with 394 additions and 60 deletions

View File

@ -23,9 +23,10 @@ endif()
set(GE_SOURCES
src/gl.c
src/ge_culling_tool.cpp
src/ge_dx9_texture.cpp
src/ge_main.cpp
src/ge_texture.cpp
src/ge_dx9_texture.cpp
src/ge_vma.cpp
src/ge_vulkan_2d_renderer.cpp
src/ge_vulkan_animated_mesh_scene_node.cpp
@ -33,6 +34,7 @@ set(GE_SOURCES
src/ge_vulkan_command_loader.cpp
src/ge_vulkan_depth_texture.cpp
src/ge_vulkan_driver.cpp
src/ge_vulkan_draw_call.cpp
src/ge_vulkan_dynamic_buffer.cpp
src/ge_vulkan_features.cpp
src/ge_vulkan_mesh_cache.cpp

View File

@ -2,6 +2,7 @@
#define HEADER_GE_MAIN_HPP
#include <IVideoDriver.h>
#include <matrix4.h>
#include <cstdint>
#include <string>
@ -21,6 +22,7 @@ const std::string& getShaderFolder();
GEConfig* getGEConfig();
void deinit();
uint64_t getMonoTimeMs();
void mathPlaneFrustumf(float* out, const irr::core::matrix4& pvm);
}
#endif

View File

@ -2,13 +2,19 @@
#define HEADER_GE_VULKAN_SCENE_MANAGER_HPP
#include "../source/Irrlicht/CSceneManager.h"
#include <memory>
#include <map>
namespace GE
{
class GEVulkanCameraSceneNode;
class GEVulkanDrawCall;
class GEVulkanSceneManager : public irr::scene::CSceneManager
{
private:
std::map<GEVulkanCameraSceneNode*, std::unique_ptr<GEVulkanDrawCall> > m_draw_calls;
public:
// ------------------------------------------------------------------------
GEVulkanSceneManager(irr::video::IVideoDriver* driver,
@ -38,6 +44,15 @@ public:
const irr::core::vector3df& rotation = irr::core::vector3df(0, 0, 0),
const irr::core::vector3df& scale = irr::core::vector3df(1.0f, 1.0f, 1.0f),
bool alsoAddIfMeshPointerZero = false);
// ------------------------------------------------------------------------
virtual void drawAll(irr::u32 flags = 0xFFFFFFFF);
// ------------------------------------------------------------------------
virtual irr::u32 registerNodeForRendering(irr::scene::ISceneNode* node,
irr::scene::E_SCENE_NODE_RENDER_PASS pass = irr::scene::ESNRP_AUTOMATIC);
// ------------------------------------------------------------------------
void addDrawCall(GEVulkanCameraSceneNode* cam);
// ------------------------------------------------------------------------
void removeDrawCall(GEVulkanCameraSceneNode* cam);
}; // GEVulkanSceneManager
}

View File

@ -0,0 +1,59 @@
#include "ge_culling_tool.hpp"
#include "ge_main.hpp"
#include "ge_spm_buffer.hpp"
#include "ge_vulkan_camera_scene_node.hpp"
#include "ISceneNode.h"
namespace GE
{
// ----------------------------------------------------------------------------
void GECullingTool::init(GEVulkanCameraSceneNode* cam)
{
mathPlaneFrustumf(&m_frustum[0].X, cam->getPVM());
m_cam_bbox = cam->getViewFrustum()->getBoundingBox();
} // init
// ----------------------------------------------------------------------------
bool GECullingTool::isCulled(GESPMBuffer* buffer,
irr::scene::ISceneNode* node)
{
using namespace irr;
using namespace core;
aabbox3df bb = buffer->getBoundingBox();
node->getAbsoluteTransformation().transformBoxEx(bb);
if (!m_cam_bbox.intersectsWithBox(bb))
return true;
quaternion edges[8] =
{
quaternion(bb.MinEdge.X, bb.MinEdge.Y, bb.MinEdge.Z, 1.0f),
quaternion(bb.MaxEdge.X, bb.MinEdge.Y, bb.MinEdge.Z, 1.0f),
quaternion(bb.MinEdge.X, bb.MaxEdge.Y, bb.MinEdge.Z, 1.0f),
quaternion(bb.MaxEdge.X, bb.MaxEdge.Y, bb.MinEdge.Z, 1.0f),
quaternion(bb.MinEdge.X, bb.MinEdge.Y, bb.MaxEdge.Z, 1.0f),
quaternion(bb.MaxEdge.X, bb.MinEdge.Y, bb.MaxEdge.Z, 1.0f),
quaternion(bb.MinEdge.X, bb.MaxEdge.Y, bb.MaxEdge.Z, 1.0f),
quaternion(bb.MaxEdge.X, bb.MaxEdge.Y, bb.MaxEdge.Z, 1.0f)
};
for (int i = 0; i < 6; i++)
{
bool culled = true;
for (int j = 0; j < 8; j++)
{
if (m_frustum[i].dotProduct(edges[j]) >= 0.0)
{
culled = false;
break;
}
}
if (culled)
return true;
}
return false;
} // isCulled
}

View File

@ -0,0 +1,33 @@
#ifndef HEADER_GE_CULLING_TOOL_HPP
#define HEADER_GE_CULLING_TOOL_HPP
#include "aabbox3d.h"
#include "quaternion.h"
#include "matrix4.h"
namespace irr
{
namespace scene { class ISceneNode; }
}
namespace GE
{
class GESPMBuffer;
class GEVulkanCameraSceneNode;
class GECullingTool
{
private:
irr::core::quaternion m_frustum[6];
irr::core::aabbox3df m_cam_bbox;
public:
// ------------------------------------------------------------------------
void init(GEVulkanCameraSceneNode* cam);
// ------------------------------------------------------------------------
bool isCulled(GESPMBuffer* buffer, irr::scene::ISceneNode* node);
}; // GECullingTool
}
#endif

View File

@ -53,4 +53,61 @@ uint64_t getMonoTimeMs()
return value.count();
}
void mathPlaneNormf(float *p)
{
float f = 1.0f / sqrtf(p[0] * p[0] + p[1] * p[1] + p[2] * p[2]);
p[0] *= f;
p[1] *= f;
p[2] *= f;
p[3] *= f;
}
void mathPlaneFrustumf(float* out, const irr::core::matrix4& pvm)
{
// return 6 planes, 24 floats
const float* m = pvm.pointer();
// near
out[0] = m[3] + m[2];
out[1] = m[7] + m[6];
out[2] = m[11] + m[10];
out[3] = m[15] + m[14];
mathPlaneNormf(&out[0]);
// right
out[4] = m[3] - m[0];
out[4 + 1] = m[7] - m[4];
out[4 + 2] = m[11] - m[8];
out[4 + 3] = m[15] - m[12];
mathPlaneNormf(&out[4]);
// left
out[2 * 4] = m[3] + m[0];
out[2 * 4 + 1] = m[7] + m[4];
out[2 * 4 + 2] = m[11] + m[8];
out[2 * 4 + 3] = m[15] + m[12];
mathPlaneNormf(&out[2 * 4]);
// bottom
out[3 * 4] = m[3] + m[1];
out[3 * 4 + 1] = m[7] + m[5];
out[3 * 4 + 2] = m[11] + m[9];
out[3 * 4 + 3] = m[15] + m[13];
mathPlaneNormf(&out[3 * 4]);
// top
out[4 * 4] = m[3] - m[1];
out[4 * 4 + 1] = m[7] - m[5];
out[4 * 4 + 2] = m[11] - m[9];
out[4 * 4 + 3] = m[15] - m[13];
mathPlaneNormf(&out[4 * 4]);
// far
out[5 * 4] = m[3] - m[2];
out[5 * 4 + 1] = m[7] - m[6];
out[5 * 4 + 2] = m[11] - m[10];
out[5 * 4 + 3] = m[15] - m[14];
mathPlaneNormf(&out[5 * 4]);
}
}

View File

@ -3,6 +3,7 @@
#include "ge_main.hpp"
#include "ge_vulkan_driver.hpp"
#include "ge_vulkan_dynamic_buffer.hpp"
#include "ge_vulkan_scene_manager.hpp"
namespace GE
{
@ -16,12 +17,14 @@ GEVulkanCameraSceneNode::GEVulkanCameraSceneNode(irr::scene::ISceneNode* parent,
{
m_buffer = new GEVulkanDynamicBuffer(GVDBT_GPU_RAM,
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, sizeof(GEVulkanCameraUBO));
static_cast<GEVulkanSceneManager*>(SceneManager)->addDrawCall(this);
} // GEVulkanCameraSceneNode
// ----------------------------------------------------------------------------
GEVulkanCameraSceneNode::~GEVulkanCameraSceneNode()
{
delete m_buffer;
static_cast<GEVulkanSceneManager*>(SceneManager)->removeDrawCall(this);
} // ~GEVulkanCameraSceneNode
// ----------------------------------------------------------------------------
@ -51,4 +54,12 @@ void GEVulkanCameraSceneNode::render()
m_ubo_data.m_projection_view_matrix = mat;
} // render
// ----------------------------------------------------------------------------
irr::core::matrix4 GEVulkanCameraSceneNode::getPVM() const
{
// Use the original unedited matrix for culling
return ViewArea.getTransform(irr::video::ETS_PROJECTION) *
ViewArea.getTransform(irr::video::ETS_VIEW);
} // getPVM
}

View File

@ -43,6 +43,8 @@ public:
{ m_viewport = area; }
// ------------------------------------------------------------------------
const irr::core::rect<irr::s32>& getViewPort() const { return m_viewport; }
// ------------------------------------------------------------------------
irr::core::matrix4 getPVM() const;
}; // GEVulkanCameraSceneNode
}

View File

@ -0,0 +1,87 @@
#include "ge_vulkan_draw_call.hpp"
#include "ge_culling_tool.hpp"
#include "ge_spm_buffer.hpp"
#include "ge_vulkan_animated_mesh_scene_node.hpp"
#include "ge_vulkan_camera_scene_node.hpp"
#include "ge_vulkan_mesh_scene_node.hpp"
namespace GE
{
// ----------------------------------------------------------------------------
GEVulkanDrawCall::GEVulkanDrawCall()
{
m_culling_tool = new GECullingTool;
} // GEVulkanDrawCall
// ----------------------------------------------------------------------------
GEVulkanDrawCall::~GEVulkanDrawCall()
{
delete m_culling_tool;
} // ~GEVulkanDrawCall
// ----------------------------------------------------------------------------
void GEVulkanDrawCall::addNode(irr::scene::ISceneNode* node)
{
irr::scene::IMesh* mesh;
if (node->getType() == irr::scene::ESNT_ANIMATED_MESH)
{
mesh = static_cast<
GEVulkanAnimatedMeshSceneNode*>(node)->getMesh();
}
else if (node->getType() == irr::scene::ESNT_MESH)
{
mesh = static_cast<irr::scene::IMeshSceneNode*>(node)->getMesh();
for (unsigned i = 0; i < mesh->getMeshBufferCount(); i++)
{
irr::scene::IMeshBuffer* b = mesh->getMeshBuffer(i);
if (b->getVertexType() != irr::video::EVT_SKINNED_MESH)
return;
}
}
else
return;
for (unsigned i = 0; i < mesh->getMeshBufferCount(); i++)
{
GESPMBuffer* buffer = static_cast<GESPMBuffer*>(
mesh->getMeshBuffer(i));
if (m_culling_tool->isCulled(buffer, node))
continue;
m_visible_nodes[buffer].push_back(node);
}
} // addNode
// ----------------------------------------------------------------------------
void GEVulkanDrawCall::generate()
{
unsigned accumulated_instance = 0;
for (auto& p : m_visible_nodes)
{
unsigned visible_count = p.second.size();
if (visible_count != 0)
{
for (auto* node : p.second)
m_visible_trans.push_back(node->getAbsoluteTransformation());
VkDrawIndexedIndirectCommand cmd;
cmd.indexCount = p.first->getIndexCount();
cmd.instanceCount = visible_count;
cmd.firstIndex = p.first->getIBOOffset();
cmd.vertexOffset = p.first->getVBOOffset();
cmd.firstInstance = accumulated_instance;
accumulated_instance += visible_count;
m_cmds.push_back(cmd);
}
}
} // generate
// ----------------------------------------------------------------------------
void GEVulkanDrawCall::prepare(GEVulkanCameraSceneNode* cam)
{
m_visible_nodes.clear();
m_cmds.clear();
m_visible_trans.clear();
m_culling_tool->init(cam);
} // prepare
}

View File

@ -0,0 +1,47 @@
#ifndef HEADER_GE_VULKAN_DRAW_CALL_HPP
#define HEADER_GE_VULKAN_DRAW_CALL_HPP
#include <unordered_map>
#include <vector>
#include "vulkan_wrapper.h"
#include "matrix4.h"
namespace irr
{
namespace scene { class ISceneNode; }
}
namespace GE
{
class GECullingTool;
class GESPMBuffer;
class GEVulkanCameraSceneNode;
class GEVulkanDrawCall
{
private:
std::unordered_map<GESPMBuffer*, std::vector<irr::scene::ISceneNode*> > m_visible_nodes;
GECullingTool* m_culling_tool;
std::vector<VkDrawIndexedIndirectCommand> m_cmds;
std::vector<irr::core::matrix4> m_visible_trans;
public:
// ------------------------------------------------------------------------
GEVulkanDrawCall();
// ------------------------------------------------------------------------
~GEVulkanDrawCall();
// ------------------------------------------------------------------------
void addNode(irr::scene::ISceneNode* node);
// ------------------------------------------------------------------------
void prepare(GEVulkanCameraSceneNode* cam);
// ------------------------------------------------------------------------
void generate();
}; // GEVulkanDrawCall
}
#endif

View File

@ -1,8 +1,11 @@
#include "ge_vulkan_scene_manager.hpp"
#include "../source/Irrlicht/os.h"
#include "ge_spm.hpp"
#include "ge_vulkan_animated_mesh_scene_node.hpp"
#include "ge_vulkan_camera_scene_node.hpp"
#include "ge_vulkan_draw_call.hpp"
#include "ge_vulkan_mesh_cache.hpp"
#include "ge_vulkan_mesh_scene_node.hpp"
@ -77,9 +80,23 @@ irr::scene::IMeshSceneNode* GEVulkanSceneManager::addMeshSceneNode(
const irr::core::vector3df& scale,
bool alsoAddIfMeshPointerZero)
{
if (!alsoAddIfMeshPointerZero && (!mesh || !dynamic_cast<GESPM*>(mesh)))
if (!alsoAddIfMeshPointerZero && !mesh)
return NULL;
if (mesh)
{
for (unsigned i = 0; i < mesh->getMeshBufferCount(); i++)
{
irr::scene::IMeshBuffer* b = mesh->getMeshBuffer(i);
if (b->getVertexType() != irr::video::EVT_SKINNED_MESH)
{
return irr::scene::CSceneManager::addMeshSceneNode(
mesh, parent, id, position, rotation, scale,
alsoAddIfMeshPointerZero);
}
}
}
if (!parent)
parent = this;
@ -90,4 +107,61 @@ irr::scene::IMeshSceneNode* GEVulkanSceneManager::addMeshSceneNode(
return node;
} // addMeshSceneNode
// ----------------------------------------------------------------------------
void GEVulkanSceneManager::drawAll(irr::u32 flags)
{
static_cast<GEVulkanMeshCache*>(getMeshCache())->updateCache();
GEVulkanCameraSceneNode* cam = NULL;
if (getActiveCamera())
{
cam = static_cast<
GEVulkanCameraSceneNode*>(getActiveCamera());
}
OnAnimate(os::Timer::getTime());
if (cam)
{
cam->render();
auto it = m_draw_calls.find(cam);
if (it == m_draw_calls.end())
return;
it->second->prepare(cam);
OnRegisterSceneNode();
it->second->generate();
}
} // drawAll
// ----------------------------------------------------------------------------
irr::u32 GEVulkanSceneManager::registerNodeForRendering(
irr::scene::ISceneNode* node,
irr::scene::E_SCENE_NODE_RENDER_PASS pass)
{
if (!getActiveCamera())
return 0;
GEVulkanCameraSceneNode* cam = static_cast<
GEVulkanCameraSceneNode*>(getActiveCamera());
if ((node->getType() == irr::scene::ESNT_ANIMATED_MESH &&
pass != irr::scene::ESNRP_SOLID) ||
(node->getType() == irr::scene::ESNT_MESH &&
pass != irr::scene::ESNRP_SOLID))
return 0;
m_draw_calls.at(cam)->addNode(node);
return 1;
} // registerNodeForRendering
// ----------------------------------------------------------------------------
void GEVulkanSceneManager::addDrawCall(GEVulkanCameraSceneNode* cam)
{
m_draw_calls[cam] = std::unique_ptr<GEVulkanDrawCall>(new GEVulkanDrawCall);
} // addDrawCall
// ----------------------------------------------------------------------------
void GEVulkanSceneManager::removeDrawCall(GEVulkanCameraSceneNode* cam)
{
m_draw_calls.erase(cam);
} // removeDrawCall
}

View File

@ -57,6 +57,9 @@
#include <unordered_set>
#include <vector>
#include <ge_main.hpp>
using namespace GE;
namespace SP
{
@ -641,64 +644,6 @@ SPShader* getNormalVisualizer()
return g_normal_visualizer;
} // getNormalVisualizer
// ----------------------------------------------------------------------------
inline void mathPlaneNormf(float *p)
{
float f = 1.0f / sqrtf(p[0] * p[0] + p[1] * p[1] + p[2] * p[2]);
p[0] *= f;
p[1] *= f;
p[2] *= f;
p[3] *= f;
} // mathPlaneNormf
// ----------------------------------------------------------------------------
inline void mathPlaneFrustumf(float* out, const core::matrix4& pvm)
{
// return 6 planes, 24 floats
const float* m = pvm.pointer();
// near
out[0] = m[3] + m[2];
out[1] = m[7] + m[6];
out[2] = m[11] + m[10];
out[3] = m[15] + m[14];
mathPlaneNormf(&out[0]);
// right
out[4] = m[3] - m[0];
out[4 + 1] = m[7] - m[4];
out[4 + 2] = m[11] - m[8];
out[4 + 3] = m[15] - m[12];
mathPlaneNormf(&out[4]);
// left
out[2 * 4] = m[3] + m[0];
out[2 * 4 + 1] = m[7] + m[4];
out[2 * 4 + 2] = m[11] + m[8];
out[2 * 4 + 3] = m[15] + m[12];
mathPlaneNormf(&out[2 * 4]);
// bottom
out[3 * 4] = m[3] + m[1];
out[3 * 4 + 1] = m[7] + m[5];
out[3 * 4 + 2] = m[11] + m[9];
out[3 * 4 + 3] = m[15] + m[13];
mathPlaneNormf(&out[3 * 4]);
// top
out[4 * 4] = m[3] - m[1];
out[4 * 4 + 1] = m[7] - m[5];
out[4 * 4 + 2] = m[11] - m[9];
out[4 * 4 + 3] = m[15] - m[13];
mathPlaneNormf(&out[4 * 4]);
// far
out[5 * 4] = m[3] - m[2];
out[5 * 4 + 1] = m[7] - m[6];
out[5 * 4 + 2] = m[11] - m[10];
out[5 * 4 + 3] = m[15] - m[14];
mathPlaneNormf(&out[5 * 4]);
} // mathPlaneFrustumf
// ----------------------------------------------------------------------------
inline core::vector3df getCorner(const core::aabbox3df& bbox, unsigned n)