Reduce vram usage by removing bones data in static spm
This commit is contained in:
parent
d37a3b8c7e
commit
6d74e84609
@ -29,12 +29,15 @@ private:
|
||||
size_t m_vbo_offset;
|
||||
|
||||
size_t m_ibo_offset;
|
||||
|
||||
bool m_has_skinning;
|
||||
public:
|
||||
// ------------------------------------------------------------------------
|
||||
GESPMBuffer()
|
||||
{
|
||||
m_vbo_offset = 0;
|
||||
m_ibo_offset = 0;
|
||||
m_has_skinning = false;
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
virtual const irr::video::SMaterial& getMaterial() const
|
||||
@ -160,6 +163,8 @@ public:
|
||||
void setIBOOffset(size_t offset) { m_ibo_offset = offset; }
|
||||
// ------------------------------------------------------------------------
|
||||
size_t getIBOOffset() const { return m_ibo_offset; }
|
||||
// ------------------------------------------------------------------------
|
||||
bool hasSkinning() const { return m_has_skinning; }
|
||||
};
|
||||
|
||||
} // end namespace irr
|
||||
|
@ -155,16 +155,13 @@ void GEVulkanDrawCall::generate()
|
||||
unsigned visible_count = p.second.size();
|
||||
if (visible_count != 0)
|
||||
{
|
||||
bool skinning = false;
|
||||
bool skinning = p.first->hasSkinning();
|
||||
for (auto* node : p.second)
|
||||
{
|
||||
int skinning_offset = -1000;
|
||||
auto it = skinning_offets.find(node);
|
||||
if (it != skinning_offets.end())
|
||||
{
|
||||
skinning = true;
|
||||
skinning_offset = it->second;
|
||||
}
|
||||
m_visible_objects.emplace_back(node, material_id,
|
||||
skinning_offset);
|
||||
}
|
||||
@ -213,23 +210,27 @@ void GEVulkanDrawCall::createAllPipelines(GEVulkanDriver* vk)
|
||||
{
|
||||
PipelineSettings settings;
|
||||
settings.m_vertex_shader = "spm.vert";
|
||||
settings.m_skinning_vertex_shader = "spm_skinning.vert";
|
||||
settings.m_fragment_shader = "solid.frag";
|
||||
settings.m_shader_name = "solid";
|
||||
createPipeline(vk, settings);
|
||||
|
||||
settings.m_vertex_shader = "spm_skinning.vert";
|
||||
settings.m_shader_name = "solid_skinning";
|
||||
createPipeline(vk, settings);
|
||||
} // createAllPipelines
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GEVulkanDrawCall::createPipeline(GEVulkanDriver* vk,
|
||||
const PipelineSettings& settings)
|
||||
{
|
||||
bool creating_animated_pipeline_for_skinning = false;
|
||||
std::string shader_name = settings.m_shader_name;
|
||||
|
||||
start:
|
||||
VkPipelineShaderStageCreateInfo vert_shader_stage_info = {};
|
||||
vert_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
vert_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
vert_shader_stage_info.module = GEVulkanShaderManager::getShader(settings.m_vertex_shader);
|
||||
vert_shader_stage_info.module = GEVulkanShaderManager::getShader(
|
||||
creating_animated_pipeline_for_skinning ?
|
||||
settings.m_skinning_vertex_shader : settings.m_vertex_shader);
|
||||
vert_shader_stage_info.pName = "main";
|
||||
|
||||
VkPipelineShaderStageCreateInfo frag_shader_stage_info = {};
|
||||
@ -244,10 +245,15 @@ void GEVulkanDrawCall::createPipeline(GEVulkanDriver* vk,
|
||||
frag_shader_stage_info
|
||||
}};
|
||||
|
||||
VkVertexInputBindingDescription binding_description = {};
|
||||
binding_description.binding = 0;
|
||||
binding_description.stride = sizeof(irr::video::S3DVertexSkinnedMesh);
|
||||
binding_description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
size_t bone_pitch = sizeof(int16_t) * 8;
|
||||
size_t static_pitch = sizeof(irr::video::S3DVertexSkinnedMesh) - bone_pitch;
|
||||
std::array<VkVertexInputBindingDescription, 2> binding_descriptions;
|
||||
binding_descriptions[0].binding = 0;
|
||||
binding_descriptions[0].stride = static_pitch;
|
||||
binding_descriptions[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
binding_descriptions[1].binding = 1;
|
||||
binding_descriptions[1].stride = bone_pitch;
|
||||
binding_descriptions[1].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
|
||||
std::array<VkVertexInputAttributeDescription, 8> attribute_descriptions = {};
|
||||
attribute_descriptions[0].binding = 0;
|
||||
@ -274,21 +280,21 @@ void GEVulkanDrawCall::createPipeline(GEVulkanDriver* vk,
|
||||
attribute_descriptions[5].location = 5;
|
||||
attribute_descriptions[5].format = VK_FORMAT_A2B10G10R10_SNORM_PACK32;
|
||||
attribute_descriptions[5].offset = offsetof(irr::video::S3DVertexSkinnedMesh, m_tangent);
|
||||
attribute_descriptions[6].binding = 0;
|
||||
attribute_descriptions[6].binding = 1;
|
||||
attribute_descriptions[6].location = 6;
|
||||
attribute_descriptions[6].format = VK_FORMAT_R16G16B16A16_SINT;
|
||||
attribute_descriptions[6].offset = offsetof(irr::video::S3DVertexSkinnedMesh, m_joint_idx);
|
||||
attribute_descriptions[7].binding = 0;
|
||||
attribute_descriptions[6].offset = 0;
|
||||
attribute_descriptions[7].binding = 1;
|
||||
attribute_descriptions[7].location = 7;
|
||||
attribute_descriptions[7].format = VK_FORMAT_R16G16B16A16_SFLOAT;
|
||||
attribute_descriptions[7].offset = offsetof(irr::video::S3DVertexSkinnedMesh, m_weight);
|
||||
attribute_descriptions[7].offset = sizeof(int16_t) * 4;
|
||||
|
||||
VkPipelineVertexInputStateCreateInfo vertex_input_info = {};
|
||||
vertex_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||
vertex_input_info.vertexBindingDescriptionCount = 1;
|
||||
vertex_input_info.vertexAttributeDescriptionCount = attribute_descriptions.size();
|
||||
vertex_input_info.pVertexBindingDescriptions = &binding_description;
|
||||
vertex_input_info.pVertexAttributeDescriptions = &attribute_descriptions[0];
|
||||
vertex_input_info.vertexBindingDescriptionCount = 2;
|
||||
vertex_input_info.vertexAttributeDescriptionCount = 8;
|
||||
vertex_input_info.pVertexBindingDescriptions = binding_descriptions.data();
|
||||
vertex_input_info.pVertexAttributeDescriptions = attribute_descriptions.data();
|
||||
|
||||
VkPipelineInputAssemblyStateCreateInfo input_assembly = {};
|
||||
input_assembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||||
@ -390,10 +396,19 @@ void GEVulkanDrawCall::createPipeline(GEVulkanDriver* vk,
|
||||
if (result != VK_SUCCESS)
|
||||
{
|
||||
throw std::runtime_error("vkCreateGraphicsPipelines failed for " +
|
||||
settings.m_shader_name);
|
||||
shader_name);
|
||||
}
|
||||
m_graphics_pipelines[settings.m_shader_name] = std::make_pair(
|
||||
m_graphics_pipelines[shader_name] = std::make_pair(
|
||||
graphics_pipeline, settings);
|
||||
|
||||
if (settings.m_skinning_vertex_shader.empty())
|
||||
return;
|
||||
else if (creating_animated_pipeline_for_skinning)
|
||||
return;
|
||||
|
||||
creating_animated_pipeline_for_skinning = true;
|
||||
shader_name = settings.m_shader_name + "_skinning";
|
||||
goto start;
|
||||
} // createPipeline
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -648,10 +663,19 @@ 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);
|
||||
|
||||
VkDeviceSize offsets[] = {0};
|
||||
GEVulkanMeshCache* mc = vk->getVulkanMeshCache();
|
||||
VkBuffer vertex_buffer = mc->getBuffer();
|
||||
vkCmdBindVertexBuffers(cmd, 0, 1, &vertex_buffer, offsets);
|
||||
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);
|
||||
|
@ -42,6 +42,7 @@ struct ObjectData
|
||||
struct PipelineSettings
|
||||
{
|
||||
std::string m_vertex_shader;
|
||||
std::string m_skinning_vertex_shader;
|
||||
std::string m_fragment_shader;
|
||||
std::string m_shader_name;
|
||||
};
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
#include "IAnimatedMesh.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
|
||||
namespace GE
|
||||
@ -19,7 +21,7 @@ GEVulkanMeshCache::GEVulkanMeshCache()
|
||||
m_ge_cache_time = 0;
|
||||
m_buffer = VK_NULL_HANDLE;
|
||||
m_memory = VK_NULL_HANDLE;
|
||||
m_ibo_offset = 0;
|
||||
m_ibo_offset = m_skinning_vbo_offset = 0;
|
||||
} // init
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -36,6 +38,10 @@ void GEVulkanMeshCache::updateCache()
|
||||
m_ge_cache_time = m_irrlicht_cache_time;
|
||||
|
||||
destroy();
|
||||
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, ibo_size;
|
||||
vbo_size = 0;
|
||||
ibo_size = 0;
|
||||
@ -47,14 +53,21 @@ void GEVulkanMeshCache::updateCache()
|
||||
continue;
|
||||
for (unsigned j = 0; j < mesh->getMeshBufferCount(); j++)
|
||||
{
|
||||
scene::IMeshBuffer* mb = mesh->getMeshBuffer(j);
|
||||
vbo_size += mesh->getMeshBuffer(j)->getVertexCount();
|
||||
ibo_size += mesh->getMeshBuffer(j)->getIndexCount();
|
||||
buffers.push_back(static_cast<GESPMBuffer*>(mb));
|
||||
GESPMBuffer* mb = static_cast<GESPMBuffer*>(mesh->getMeshBuffer(j));
|
||||
size_t pitch = mb->hasSkinning() ? total_pitch : static_pitch;
|
||||
vbo_size += mb->getVertexCount() * pitch;
|
||||
ibo_size += mb->getIndexCount();
|
||||
buffers.push_back(mb);
|
||||
}
|
||||
}
|
||||
vbo_size *= getVertexPitchFromType(video::EVT_SKINNED_MESH);
|
||||
ibo_size *= sizeof(uint16_t);
|
||||
// Some devices (Apple for now) require vertex offset of alignment 4 bytes
|
||||
ibo_size += getPadding(ibo_size, 4);
|
||||
std::stable_partition(buffers.begin(), buffers.end(),
|
||||
[](const GESPMBuffer* mb)
|
||||
{
|
||||
return !mb->hasSkinning();
|
||||
});
|
||||
|
||||
VkBuffer staging_buffer = VK_NULL_HANDLE;
|
||||
VmaAllocation staging_memory = VK_NULL_HANDLE;
|
||||
@ -78,12 +91,16 @@ void GEVulkanMeshCache::updateCache()
|
||||
size_t offset = 0;
|
||||
for (GESPMBuffer* spm_buffer : buffers)
|
||||
{
|
||||
size_t copy_size = spm_buffer->getVertexCount() *
|
||||
getVertexPitchFromType(video::EVT_SKINNED_MESH);
|
||||
size_t real_size = spm_buffer->getVertexCount() * total_pitch;
|
||||
size_t copy_size = spm_buffer->getVertexCount() * static_pitch;
|
||||
uint8_t* loc = mapped + offset;
|
||||
memcpy(loc, spm_buffer->getVertices(), copy_size);
|
||||
spm_buffer->setVBOOffset(
|
||||
offset / getVertexPitchFromType(video::EVT_SKINNED_MESH));
|
||||
for (unsigned i = 0; i < real_size; i += total_pitch)
|
||||
{
|
||||
uint8_t* vertices = ((uint8_t*)spm_buffer->getVertices()) + i;
|
||||
memcpy(loc, vertices, static_pitch);
|
||||
loc += static_pitch;
|
||||
}
|
||||
spm_buffer->setVBOOffset(offset / static_pitch);
|
||||
offset += copy_size;
|
||||
}
|
||||
m_ibo_offset = offset;
|
||||
@ -97,6 +114,33 @@ void GEVulkanMeshCache::updateCache()
|
||||
spm_buffer->setIBOOffset(offset / sizeof(uint16_t));
|
||||
offset += copy_size;
|
||||
}
|
||||
m_skinning_vbo_offset = m_ibo_offset + offset;
|
||||
m_skinning_vbo_offset += getPadding(m_skinning_vbo_offset, 4);
|
||||
|
||||
offset = 0;
|
||||
size_t static_vertex_offset = 0;
|
||||
for (GESPMBuffer* spm_buffer : buffers)
|
||||
{
|
||||
if (!spm_buffer->hasSkinning())
|
||||
{
|
||||
static_vertex_offset += spm_buffer->getVertexCount() * bone_pitch;
|
||||
continue;
|
||||
}
|
||||
uint8_t* loc = mapped + offset + m_skinning_vbo_offset;
|
||||
size_t real_size = spm_buffer->getVertexCount() * total_pitch;
|
||||
for (unsigned i = 0; i < real_size; i += total_pitch)
|
||||
{
|
||||
uint8_t* vertices = ((uint8_t*)spm_buffer->getVertices()) + i +
|
||||
static_pitch;
|
||||
memcpy(loc, vertices, bone_pitch);
|
||||
loc += bone_pitch;
|
||||
}
|
||||
offset += spm_buffer->getVertexCount() * bone_pitch;
|
||||
}
|
||||
assert(m_skinning_vbo_offset + offset == vbo_size + ibo_size);
|
||||
assert(static_vertex_offset < m_skinning_vbo_offset);
|
||||
m_skinning_vbo_offset -= static_vertex_offset;
|
||||
|
||||
vmaUnmapMemory(m_vk->getVmaAllocator(), staging_memory);
|
||||
vmaFlushAllocation(m_vk->getVmaAllocator(), staging_memory, 0, offset);
|
||||
|
||||
@ -121,7 +165,7 @@ void GEVulkanMeshCache::destroy()
|
||||
vmaDestroyBuffer(m_vk->getVmaAllocator(), m_buffer, m_memory);
|
||||
m_buffer = VK_NULL_HANDLE;
|
||||
m_memory = VK_NULL_HANDLE;
|
||||
m_ibo_offset = 0;
|
||||
m_ibo_offset = m_skinning_vbo_offset = 0;
|
||||
} // destroy
|
||||
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ private:
|
||||
|
||||
VmaAllocation m_memory;
|
||||
|
||||
size_t m_ibo_offset;
|
||||
size_t m_ibo_offset, m_skinning_vbo_offset;
|
||||
public:
|
||||
// ------------------------------------------------------------------------
|
||||
GEVulkanMeshCache();
|
||||
@ -35,6 +35,8 @@ public:
|
||||
VkBuffer getBuffer() const { return m_buffer; }
|
||||
// ------------------------------------------------------------------------
|
||||
size_t getIBOOffset() const { return m_ibo_offset; }
|
||||
// ------------------------------------------------------------------------
|
||||
size_t getSkinningVBOOffset() const { return m_skinning_vbo_offset; }
|
||||
}; // GEVulkanMeshCache
|
||||
|
||||
}
|
||||
|
@ -105,6 +105,7 @@ scene::IAnimatedMesh* B3DMeshLoader::createMesh(io::IReadFile* f)
|
||||
{
|
||||
SP::SPMeshBuffer* spbuf = spm->getSPMeshBuffer(i);
|
||||
GE::GESPMBuffer* gebuf = new GE::GESPMBuffer();
|
||||
gebuf->m_has_skinning = !spm->isStatic();
|
||||
ge_spm->m_buffer.push_back(gebuf);
|
||||
std::swap(gebuf->m_vertices, spbuf->getVerticesRef());
|
||||
std::swap(gebuf->m_indices, spbuf->getIndicesRef());
|
||||
|
@ -556,6 +556,7 @@ void SPMeshLoader::decompressGESPM(irr::io::IReadFile* spm,
|
||||
// 1.0 in half float (16bit)
|
||||
vertex.m_weight[0] = 15360;
|
||||
}
|
||||
mb->m_has_skinning = true;
|
||||
}
|
||||
vertices.push_back(vertex);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user