Add code to render vbo and ibo individually for some devices
This commit is contained in:
parent
0ad22efcf7
commit
00e7b04f13
@ -47,6 +47,7 @@ set(GE_SOURCES
|
||||
src/ge_vulkan_texture_descriptor.cpp
|
||||
src/ge_gl_texture.cpp
|
||||
src/ge_spm.cpp
|
||||
src/ge_spm_buffer.cpp
|
||||
)
|
||||
|
||||
if(NOT APPLE OR DLOPEN_MOLTENVK)
|
||||
|
@ -1,10 +1,14 @@
|
||||
#ifndef HEADER_GE_SPM_BUFFER_HPP
|
||||
#define HEADER_GE_SPM_BUFFER_HPP
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
#include "IMeshBuffer.h"
|
||||
|
||||
#include "ge_vma.hpp"
|
||||
#include "vulkan_wrapper.h"
|
||||
|
||||
class B3DMeshLoader;
|
||||
class SPMeshLoader;
|
||||
|
||||
@ -30,6 +34,12 @@ private:
|
||||
|
||||
size_t m_ibo_offset;
|
||||
|
||||
size_t m_skinning_vbo_offset;
|
||||
|
||||
VkBuffer m_buffer;
|
||||
|
||||
VmaAllocation m_memory;
|
||||
|
||||
bool m_has_skinning;
|
||||
public:
|
||||
// ------------------------------------------------------------------------
|
||||
@ -37,9 +47,14 @@ public:
|
||||
{
|
||||
m_vbo_offset = 0;
|
||||
m_ibo_offset = 0;
|
||||
m_skinning_vbo_offset = 0;
|
||||
m_buffer = VK_NULL_HANDLE;
|
||||
m_memory = VK_NULL_HANDLE;
|
||||
m_has_skinning = false;
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
~GESPMBuffer() { destroyVertexIndexBuffer(); }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual const irr::video::SMaterial& getMaterial() const
|
||||
{ return m_material; }
|
||||
// ------------------------------------------------------------------------
|
||||
@ -165,6 +180,28 @@ public:
|
||||
size_t getIBOOffset() const { return m_ibo_offset; }
|
||||
// ------------------------------------------------------------------------
|
||||
bool hasSkinning() const { return m_has_skinning; }
|
||||
// ------------------------------------------------------------------------
|
||||
void bindVertexIndexBuffer(VkCommandBuffer cmd)
|
||||
{
|
||||
std::array<VkBuffer, 2> vertex_buffer =
|
||||
{{
|
||||
m_buffer,
|
||||
m_buffer
|
||||
}};
|
||||
std::array<VkDeviceSize, 2> offsets =
|
||||
{{
|
||||
0,
|
||||
m_skinning_vbo_offset
|
||||
}};
|
||||
vkCmdBindVertexBuffers(cmd, 0, vertex_buffer.size(),
|
||||
vertex_buffer.data(), offsets.data());
|
||||
vkCmdBindIndexBuffer(cmd, m_buffer, m_ibo_offset,
|
||||
VK_INDEX_TYPE_UINT16);
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
void createVertexIndexBuffer();
|
||||
// ------------------------------------------------------------------------
|
||||
void destroyVertexIndexBuffer();
|
||||
};
|
||||
|
||||
} // end namespace irr
|
||||
|
@ -45,7 +45,10 @@ void GESPM::finalize()
|
||||
{
|
||||
m_bounding_box.reset(0.0f, 0.0f, 0.0f);
|
||||
for (unsigned i = 0; i < m_buffer.size(); i++)
|
||||
{
|
||||
m_bounding_box.addInternalBox(m_buffer[i]->getBoundingBox());
|
||||
m_buffer[i]->createVertexIndexBuffer();
|
||||
}
|
||||
|
||||
for (Armature& arm : getArmatures())
|
||||
{
|
||||
|
103
lib/graphics_engine/src/ge_spm_buffer.cpp
Normal file
103
lib/graphics_engine/src/ge_spm_buffer.cpp
Normal file
@ -0,0 +1,103 @@
|
||||
#include "ge_spm_buffer.hpp"
|
||||
|
||||
#include "ge_main.hpp"
|
||||
#include "ge_vulkan_driver.hpp"
|
||||
#include "ge_vulkan_features.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace GE
|
||||
{
|
||||
// ----------------------------------------------------------------------------
|
||||
void GESPMBuffer::createVertexIndexBuffer()
|
||||
{
|
||||
if (GEVulkanFeatures::supportsBaseVertexRendering())
|
||||
return;
|
||||
|
||||
GEVulkanDriver* vk = getVKDriver();
|
||||
size_t total_pitch = getVertexPitchFromType(video::EVT_SKINNED_MESH);
|
||||
size_t bone_pitch = sizeof(int16_t) * 8;
|
||||
size_t static_pitch = total_pitch - bone_pitch;
|
||||
size_t vbo_size = getVertexCount() * static_pitch;
|
||||
m_ibo_offset = vbo_size;
|
||||
size_t ibo_size = getIndexCount() * sizeof(uint16_t);
|
||||
size_t total_size = vbo_size + ibo_size;
|
||||
if (m_has_skinning)
|
||||
{
|
||||
total_size += getPadding(total_size, 4);
|
||||
m_skinning_vbo_offset = total_size;
|
||||
total_size += getVertexCount() * bone_pitch;
|
||||
}
|
||||
|
||||
VkBuffer staging_buffer = VK_NULL_HANDLE;
|
||||
VmaAllocation staging_memory = VK_NULL_HANDLE;
|
||||
VmaAllocationCreateInfo staging_buffer_create_info = {};
|
||||
staging_buffer_create_info.usage = VMA_MEMORY_USAGE_AUTO;
|
||||
staging_buffer_create_info.flags =
|
||||
VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
|
||||
staging_buffer_create_info.preferredFlags = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||
|
||||
if (!vk->createBuffer(total_size,
|
||||
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
|
||||
VK_BUFFER_USAGE_TRANSFER_SRC_BIT, staging_buffer_create_info,
|
||||
staging_buffer, staging_memory))
|
||||
{
|
||||
throw std::runtime_error("createVertexIndexBuffer create staging "
|
||||
"buffer failed");
|
||||
}
|
||||
|
||||
uint8_t* mapped;
|
||||
if (vmaMapMemory(vk->getVmaAllocator(), staging_memory,
|
||||
(void**)&mapped) != VK_SUCCESS)
|
||||
throw std::runtime_error("createVertexIndexBuffer vmaMapMemory failed");
|
||||
|
||||
size_t real_size = getVertexCount() * total_pitch;
|
||||
uint8_t* loc = mapped;
|
||||
for (unsigned i = 0; i < real_size; i += total_pitch)
|
||||
{
|
||||
uint8_t* vertices = ((uint8_t*)getVertices()) + i;
|
||||
memcpy(loc, vertices, static_pitch);
|
||||
loc += static_pitch;
|
||||
}
|
||||
memcpy(loc, m_indices.data(), m_indices.size() * sizeof(uint16_t));
|
||||
|
||||
if (m_has_skinning)
|
||||
{
|
||||
loc = mapped + m_skinning_vbo_offset;
|
||||
for (unsigned i = 0; i < real_size; i += total_pitch)
|
||||
{
|
||||
uint8_t* vertices = ((uint8_t*)getVertices()) + i +
|
||||
static_pitch;
|
||||
memcpy(loc, vertices, bone_pitch);
|
||||
loc += bone_pitch;
|
||||
}
|
||||
}
|
||||
|
||||
vmaUnmapMemory(vk->getVmaAllocator(), staging_memory);
|
||||
vmaFlushAllocation(vk->getVmaAllocator(), staging_memory, 0, total_size);
|
||||
|
||||
VmaAllocationCreateInfo local_create_info = {};
|
||||
local_create_info.usage = VMA_MEMORY_USAGE_AUTO;
|
||||
if (!vk->createBuffer(total_size,
|
||||
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
|
||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT, local_create_info, m_buffer,
|
||||
m_memory))
|
||||
throw std::runtime_error("updateCache create buffer failed");
|
||||
|
||||
vk->copyBuffer(staging_buffer, m_buffer, total_size);
|
||||
vmaDestroyBuffer(vk->getVmaAllocator(), staging_buffer, staging_memory);
|
||||
} // createVertexIndexBuffer
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GESPMBuffer::destroyVertexIndexBuffer()
|
||||
{
|
||||
if (m_buffer == VK_NULL_HANDLE || m_memory == VK_NULL_HANDLE)
|
||||
return;
|
||||
|
||||
getVKDriver()->waitIdle();
|
||||
vmaDestroyBuffer(getVKDriver()->getVmaAllocator(), m_buffer, m_memory);
|
||||
m_buffer = VK_NULL_HANDLE;
|
||||
m_memory = VK_NULL_HANDLE;
|
||||
} // destroyVertexIndexBuffer
|
||||
|
||||
}
|
@ -172,6 +172,7 @@ void GEVulkanDrawCall::generate()
|
||||
return nodes_area.at(a.first) < nodes_area.at(b.first) ;
|
||||
});
|
||||
|
||||
const bool use_base_vertex = GEVulkanFeatures::supportsBaseVertexRendering();
|
||||
unsigned accumulated_instance = 0;
|
||||
for (auto& p : visible_nodes)
|
||||
{
|
||||
@ -190,7 +191,12 @@ void GEVulkanDrawCall::generate()
|
||||
const irr::video::ITexture** list = &textures[0];
|
||||
const int material_id = m_texture_descriptor->getTextureID(list);
|
||||
if (!GEVulkanFeatures::supportsBindMeshTexturesAtOnce())
|
||||
m_materials[p.first->getVBOOffset()] = material_id;
|
||||
{
|
||||
if (use_base_vertex)
|
||||
m_materials[p.first->getVBOOffset()] = material_id;
|
||||
else
|
||||
m_materials[(size_t)p.first] = material_id;
|
||||
}
|
||||
|
||||
const bool skinning = p.first->hasSkinning();
|
||||
for (auto& q : p.second)
|
||||
@ -217,25 +223,37 @@ void GEVulkanDrawCall::generate()
|
||||
VkDrawIndexedIndirectCommand cmd;
|
||||
cmd.indexCount = p.first->getIndexCount();
|
||||
cmd.instanceCount = visible_count;
|
||||
cmd.firstIndex = p.first->getIBOOffset();
|
||||
cmd.vertexOffset = p.first->getVBOOffset();
|
||||
cmd.firstIndex = use_base_vertex ? p.first->getIBOOffset() : 0;
|
||||
cmd.vertexOffset = use_base_vertex ? p.first->getVBOOffset() : 0;
|
||||
cmd.firstInstance = accumulated_instance;
|
||||
accumulated_instance += visible_count;
|
||||
const PipelineSettings& settings =
|
||||
m_graphics_pipelines[cur_shader].second;
|
||||
std::string sorting_key =
|
||||
std::string(1, settings.m_drawing_priority) + cur_shader;
|
||||
m_cmds.push_back({ cmd, cur_shader, sorting_key });
|
||||
m_cmds.push_back({ cmd, cur_shader, sorting_key, p.first });
|
||||
}
|
||||
}
|
||||
if (!GEVulkanFeatures::supportsBindMeshTexturesAtOnce())
|
||||
{
|
||||
std::stable_sort(m_cmds.begin(), m_cmds.end(),
|
||||
[this](const DrawCallData& a, const DrawCallData& b)
|
||||
{
|
||||
return m_materials[a.m_cmd.vertexOffset] <
|
||||
m_materials[b.m_cmd.vertexOffset];
|
||||
});
|
||||
if (use_base_vertex)
|
||||
{
|
||||
std::stable_sort(m_cmds.begin(), m_cmds.end(),
|
||||
[this](const DrawCallData& a, const DrawCallData& b)
|
||||
{
|
||||
return m_materials[a.m_cmd.vertexOffset] <
|
||||
m_materials[b.m_cmd.vertexOffset];
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
std::stable_sort(m_cmds.begin(), m_cmds.end(),
|
||||
[this](const DrawCallData& a, const DrawCallData& b)
|
||||
{
|
||||
return m_materials[(size_t)a.m_mb] <
|
||||
m_materials[(size_t)b.m_mb];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
std::stable_sort(m_cmds.begin(), m_cmds.end(),
|
||||
@ -888,25 +906,25 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam,
|
||||
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
m_pipeline_layout, 1, 1, &m_data_descriptor_sets[cur_frame], 0,
|
||||
NULL);
|
||||
|
||||
GEVulkanMeshCache* mc = vk->getVulkanMeshCache();
|
||||
std::array<VkBuffer, 2> vertex_buffer =
|
||||
{{
|
||||
mc->getBuffer(),
|
||||
mc->getBuffer()
|
||||
}};
|
||||
std::array<VkDeviceSize, 2> offsets =
|
||||
{{
|
||||
0,
|
||||
mc->getSkinningVBOOffset()
|
||||
}};
|
||||
vkCmdBindVertexBuffers(cmd, 0, vertex_buffer.size(),
|
||||
vertex_buffer.data(), offsets.data());
|
||||
|
||||
vkCmdBindIndexBuffer(cmd, mc->getBuffer(), mc->getIBOOffset(),
|
||||
VK_INDEX_TYPE_UINT16);
|
||||
}
|
||||
|
||||
GEVulkanMeshCache* mc = vk->getVulkanMeshCache();
|
||||
std::array<VkBuffer, 2> vertex_buffer =
|
||||
{{
|
||||
mc->getBuffer(),
|
||||
mc->getBuffer()
|
||||
}};
|
||||
std::array<VkDeviceSize, 2> offsets =
|
||||
{{
|
||||
0,
|
||||
mc->getSkinningVBOOffset()
|
||||
}};
|
||||
vkCmdBindVertexBuffers(cmd, 0, vertex_buffer.size(), vertex_buffer.data(),
|
||||
offsets.data());
|
||||
|
||||
vkCmdBindIndexBuffer(cmd, mc->getBuffer(), mc->getIBOOffset(),
|
||||
VK_INDEX_TYPE_UINT16);
|
||||
|
||||
VkViewport vp;
|
||||
vp.x = cam->getViewPort().UpperLeftCorner.X;
|
||||
vp.y = cam->getViewPort().UpperLeftCorner.Y;
|
||||
@ -956,7 +974,11 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam,
|
||||
}
|
||||
else
|
||||
{
|
||||
int cur_mid = m_materials[m_cmds[0].m_cmd.vertexOffset];
|
||||
int cur_mid = 0;
|
||||
if (use_base_vertex)
|
||||
cur_mid = m_materials[m_cmds[0].m_cmd.vertexOffset];
|
||||
else
|
||||
cur_mid = m_materials[(size_t)m_cmds[0].m_mb];
|
||||
bindPipeline(cmd, cur_pipeline);
|
||||
if (!GEVulkanFeatures::supportsBindMeshTexturesAtOnce())
|
||||
{
|
||||
@ -967,7 +989,11 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam,
|
||||
for (unsigned i = 0; i < m_cmds.size(); i++)
|
||||
{
|
||||
const VkDrawIndexedIndirectCommand& cur_cmd = m_cmds[i].m_cmd;
|
||||
int mid = m_materials[cur_cmd.vertexOffset];
|
||||
int mid = 0;
|
||||
if (use_base_vertex)
|
||||
mid = m_materials[cur_cmd.vertexOffset];
|
||||
else
|
||||
mid = m_materials[(size_t)m_cmds[i].m_mb];
|
||||
if (!GEVulkanFeatures::supportsBindMeshTexturesAtOnce() &&
|
||||
cur_mid != mid)
|
||||
{
|
||||
@ -993,6 +1019,7 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam,
|
||||
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
m_pipeline_layout, 1, 1, &m_data_descriptor_sets[cur_frame],
|
||||
dynamic_offsets.size(), dynamic_offsets.data());
|
||||
m_cmds[i].m_mb->bindVertexIndexBuffer(cmd);
|
||||
}
|
||||
vkCmdDrawIndexed(cmd, cur_cmd.indexCount, cur_cmd.instanceCount,
|
||||
cur_cmd.firstIndex, cur_cmd.vertexOffset,
|
||||
|
@ -62,6 +62,7 @@ struct DrawCallData
|
||||
VkDrawIndexedIndirectCommand m_cmd;
|
||||
std::string m_shader;
|
||||
std::string m_sorting_key;
|
||||
GESPMBuffer* m_mb;
|
||||
};
|
||||
|
||||
class GEVulkanDrawCall
|
||||
@ -96,7 +97,7 @@ private:
|
||||
std::unordered_map<std::string, std::pair<VkPipeline, PipelineSettings> >
|
||||
m_graphics_pipelines;
|
||||
|
||||
std::unordered_map<int32_t, int> m_materials;
|
||||
std::unordered_map<size_t, int> m_materials;
|
||||
|
||||
GEVulkanTextureDescriptor* m_texture_descriptor;
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
#include "ge_vulkan_mesh_cache.hpp"
|
||||
|
||||
#include "ge_main.hpp"
|
||||
|
||||
#include "ge_spm_buffer.hpp"
|
||||
#include "ge_vulkan_driver.hpp"
|
||||
#include "ge_vulkan_features.hpp"
|
||||
|
||||
#include "IAnimatedMesh.h"
|
||||
|
||||
@ -33,6 +35,9 @@ void GEVulkanMeshCache::meshCacheChanged()
|
||||
// ----------------------------------------------------------------------------
|
||||
void GEVulkanMeshCache::updateCache()
|
||||
{
|
||||
if (!GEVulkanFeatures::supportsBaseVertexRendering())
|
||||
return;
|
||||
|
||||
if (m_irrlicht_cache_time <= m_ge_cache_time)
|
||||
return;
|
||||
m_ge_cache_time = m_irrlicht_cache_time;
|
||||
@ -161,10 +166,30 @@ void GEVulkanMeshCache::updateCache()
|
||||
void GEVulkanMeshCache::destroy()
|
||||
{
|
||||
m_vk->waitIdle();
|
||||
m_vk->setDisableWaitIdle(true);
|
||||
if (!GEVulkanFeatures::supportsBaseVertexRendering())
|
||||
{
|
||||
for (unsigned i = 0; i < Meshes.size(); i++)
|
||||
{
|
||||
scene::IAnimatedMesh* mesh = Meshes[i].Mesh;
|
||||
if (mesh->getMeshType() != scene::EAMT_SPM)
|
||||
continue;
|
||||
for (unsigned j = 0; j < mesh->getMeshBufferCount(); j++)
|
||||
{
|
||||
GESPMBuffer* mb = static_cast<GESPMBuffer*>(
|
||||
mesh->getMeshBuffer(j));
|
||||
mb->destroyVertexIndexBuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vmaDestroyBuffer(m_vk->getVmaAllocator(), m_buffer, m_memory);
|
||||
m_buffer = VK_NULL_HANDLE;
|
||||
m_memory = VK_NULL_HANDLE;
|
||||
}
|
||||
m_vk->setDisableWaitIdle(false);
|
||||
|
||||
vmaDestroyBuffer(m_vk->getVmaAllocator(), m_buffer, m_memory);
|
||||
m_buffer = VK_NULL_HANDLE;
|
||||
m_memory = VK_NULL_HANDLE;
|
||||
m_ibo_offset = m_skinning_vbo_offset = 0;
|
||||
} // destroy
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user