Reduce instance data size

MoltenVK has no DrawIndex support yet
This commit is contained in:
Benau 2022-10-02 16:41:09 +08:00
parent e1f8294008
commit b2404aadd2
8 changed files with 324 additions and 126 deletions

View File

@ -21,5 +21,9 @@ void main()
f_uv = v_uv; f_uv = v_uv;
f_uv_two = v_uv_two; f_uv_two = v_uv_two;
f_material_id = u_object_buffer.m_objects[gl_InstanceIndex].m_material_id; f_material_id = u_object_buffer.m_objects[gl_InstanceIndex].m_material_id;
#ifdef BIND_MESH_TEXTURES_AT_ONCE
if (f_material_id < 0)
f_material_id = u_material_ids.m_material_id[gl_DrawIDARB];
#endif
f_hue_change = u_object_buffer.m_objects[gl_InstanceIndex].m_hue_change; f_hue_change = u_object_buffer.m_objects[gl_InstanceIndex].m_hue_change;
} }

View File

@ -14,5 +14,9 @@ void main()
f_uv = v_uv + u_object_buffer.m_objects[gl_InstanceIndex].m_texture_trans; f_uv = v_uv + u_object_buffer.m_objects[gl_InstanceIndex].m_texture_trans;
f_uv_two = v_uv_two; f_uv_two = v_uv_two;
f_material_id = u_object_buffer.m_objects[gl_InstanceIndex].m_material_id; f_material_id = u_object_buffer.m_objects[gl_InstanceIndex].m_material_id;
#ifdef BIND_MESH_TEXTURES_AT_ONCE
if (f_material_id < 0)
f_material_id = u_material_ids.m_material_id[gl_DrawIDARB];
#endif
f_hue_change = u_object_buffer.m_objects[gl_InstanceIndex].m_hue_change; f_hue_change = u_object_buffer.m_objects[gl_InstanceIndex].m_hue_change;
} }

View File

@ -22,5 +22,9 @@ void main()
f_uv = v_uv + u_object_buffer.m_objects[gl_InstanceIndex].m_texture_trans; f_uv = v_uv + u_object_buffer.m_objects[gl_InstanceIndex].m_texture_trans;
f_uv_two = v_uv_two; f_uv_two = v_uv_two;
f_material_id = u_object_buffer.m_objects[gl_InstanceIndex].m_material_id; f_material_id = u_object_buffer.m_objects[gl_InstanceIndex].m_material_id;
#ifdef BIND_MESH_TEXTURES_AT_ONCE
if (f_material_id < 0)
f_material_id = u_material_ids.m_material_id[gl_DrawIDARB];
#endif
f_hue_change = u_object_buffer.m_objects[gl_InstanceIndex].m_hue_change; f_hue_change = u_object_buffer.m_objects[gl_InstanceIndex].m_hue_change;
} }

View File

@ -1,3 +1,7 @@
#ifdef BIND_MESH_TEXTURES_AT_ONCE
#extension GL_ARB_shader_draw_parameters : enable
#endif
layout(std140, set = 1, binding = 0) uniform CameraBuffer layout(std140, set = 1, binding = 0) uniform CameraBuffer
{ {
mat4 m_view_matrix; mat4 m_view_matrix;
@ -30,6 +34,13 @@ layout(std140, set = 1, binding = 2) readonly buffer SkinningMatrices
mat4 m_mat[]; mat4 m_mat[];
} u_skinning_matrices; } u_skinning_matrices;
#ifdef BIND_MESH_TEXTURES_AT_ONCE
layout(std430, set = 1, binding = 3) readonly buffer MaterialIDs
{
int m_material_id[];
} u_material_ids;
#endif
layout(location = 0) in vec3 v_position; layout(location = 0) in vec3 v_position;
layout(location = 1) in vec4 v_normal; layout(location = 1) in vec4 v_normal;
layout(location = 2) in vec4 v_color; layout(location = 2) in vec4 v_color;

View File

@ -122,6 +122,7 @@ GEVulkanDrawCall::GEVulkanDrawCall()
m_sbo_data = NULL; m_sbo_data = NULL;
m_object_data_padded_size = 0; m_object_data_padded_size = 0;
m_skinning_data_padded_size = 0; m_skinning_data_padded_size = 0;
m_materials_padded_size = 0;
m_data_padding = NULL; m_data_padding = NULL;
const size_t ubo_padding = m_limits.minUniformBufferOffsetAlignment; const size_t ubo_padding = m_limits.minUniformBufferOffsetAlignment;
const size_t sbo_padding = m_limits.minStorageBufferOffsetAlignment; const size_t sbo_padding = m_limits.minStorageBufferOffsetAlignment;
@ -190,6 +191,7 @@ void GEVulkanDrawCall::addNode(irr::scene::ISceneNode* node)
continue; continue;
const std::string& shader = getShader(node, i); const std::string& shader = getShader(node, i);
m_visible_nodes[buffer][shader].emplace_back(node, i); m_visible_nodes[buffer][shader].emplace_back(node, i);
m_mb_map[buffer] = mesh;
if (anode && !added_skinning && if (anode && !added_skinning &&
!anode->getSkinningMatrices().empty() && !anode->getSkinningMatrices().empty() &&
m_skinning_nodes.find(anode) == m_skinning_nodes.end()) m_skinning_nodes.find(anode) == m_skinning_nodes.end())
@ -209,7 +211,8 @@ void GEVulkanDrawCall::addBillboardNode(irr::scene::ISceneNode* node,
return; return;
irr::video::SMaterial m = node->getMaterial(0); irr::video::SMaterial m = node->getMaterial(0);
TexturesList textures = {}; TexturesList textures = {};
if (!GEVulkanFeatures::supportsDifferentTexturePerDraw()) if (!GEVulkanFeatures::supportsDifferentTexturePerDraw() ||
!GEVulkanFeatures::supportsBindMeshTexturesAtOnce())
textures = getTexturesList(m); textures = getTexturesList(m);
if (m_billboard_buffers.find(textures) == m_billboard_buffers.end()) if (m_billboard_buffers.find(textures) == m_billboard_buffers.end())
m_billboard_buffers[textures] = new GEVulkanBillboardBuffer(m); m_billboard_buffers[textures] = new GEVulkanBillboardBuffer(m);
@ -226,16 +229,17 @@ void GEVulkanDrawCall::generate()
if (!m_visible_nodes.empty() && m_data_layout == VK_NULL_HANDLE) if (!m_visible_nodes.empty() && m_data_layout == VK_NULL_HANDLE)
createVulkanData(); createVulkanData();
std::vector<std::pair<void*, size_t> > data_uploading;
std::unordered_map<irr::scene::ISceneNode*, int> skinning_offets; std::unordered_map<irr::scene::ISceneNode*, int> skinning_offets;
int added_joint = 1; int added_joint = 1;
m_skinning_data_padded_size = sizeof(irr::core::matrix4); m_skinning_data_padded_size = sizeof(irr::core::matrix4);
m_data_uploading.emplace_back((void*)m_data_padding, data_uploading.emplace_back((void*)m_data_padding,
sizeof(irr::core::matrix4)); sizeof(irr::core::matrix4));
for (GEVulkanAnimatedMeshSceneNode* node : m_skinning_nodes) for (GEVulkanAnimatedMeshSceneNode* node : m_skinning_nodes)
{ {
int bone_count = node->getSPM()->getJointCount(); int bone_count = node->getSPM()->getJointCount();
size_t bone_size = sizeof(irr::core::matrix4) * bone_count; size_t bone_size = sizeof(irr::core::matrix4) * bone_count;
m_data_uploading.emplace_back( data_uploading.emplace_back(
(void*)node->getSkinningMatrices().data(), bone_size); (void*)node->getSkinningMatrices().data(), bone_size);
skinning_offets[node] = added_joint; skinning_offets[node] = added_joint;
added_joint += bone_count; added_joint += bone_count;
@ -246,7 +250,7 @@ void GEVulkanDrawCall::generate()
if (padding > 0) if (padding > 0)
{ {
m_skinning_data_padded_size += padding; m_skinning_data_padded_size += padding;
m_data_uploading.emplace_back((void*)m_data_padding, data_uploading.emplace_back((void*)m_data_padding,
padding); padding);
} }
@ -285,14 +289,25 @@ void GEVulkanDrawCall::generate()
}); });
const bool use_base_vertex = GEVulkanFeatures::supportsBaseVertexRendering(); const bool use_base_vertex = GEVulkanFeatures::supportsBaseVertexRendering();
const bool bind_mesh_textures =
GEVulkanFeatures::supportsBindMeshTexturesAtOnce();
unsigned accumulated_instance = 0; unsigned accumulated_instance = 0;
struct InstanceKey
{
std::vector<irr::scene::ISceneNode*> m_nodes;
unsigned m_instance_count;
unsigned m_first_instance;
bool m_hue_change;
};
std::unordered_map<irr::scene::IMesh*, std::vector<InstanceKey> >
instance_keys;
for (auto& p : visible_nodes) for (auto& p : visible_nodes)
{ {
TexturesList textures = getTexturesList(p.first->getMaterial()); TexturesList textures = getTexturesList(p.first->getMaterial());
const irr::video::ITexture** list = &textures[0]; const irr::video::ITexture** list = &textures[0];
int material_id = m_texture_descriptor->getTextureID(list); int material_id = m_texture_descriptor->getTextureID(list);
if (!GEVulkanFeatures::supportsBindMeshTexturesAtOnce()) m_materials[p.first] = material_id;
m_materials[p.first] = material_id;
const bool skinning = p.first->hasSkinning(); const bool skinning = p.first->hasSkinning();
for (auto& q : p.second) for (auto& q : p.second)
@ -306,6 +321,48 @@ void GEVulkanDrawCall::generate()
if (m_graphics_pipelines.find(cur_shader) == if (m_graphics_pipelines.find(cur_shader) ==
m_graphics_pipelines.end()) m_graphics_pipelines.end())
continue; continue;
InstanceKey key;
key.m_nodes.reserve(q.second.size());
key.m_instance_count = visible_count;
key.m_first_instance = accumulated_instance;
key.m_hue_change = false;
bool skip_instance_key = false;
for (auto& r : q.second)
{
if (r.second == BILLBOARD_NODE || r.second == PARTICLE_NODE)
{
skip_instance_key = true;
break;
}
irr::scene::ISceneNode* node = r.first;
const irr::core::matrix4& texture_matrix =
node->getMaterial(r.second).getTextureMatrix(0);
if (texture_matrix[8] != 0.0f || texture_matrix[9] != 0.0f)
{
skip_instance_key = true;
break;
}
auto& ri = node->getMaterial(r.second).getRenderInfo();
if (ri && ri->getHue() > 0.0f)
{
key.m_hue_change = true;
break;
}
key.m_nodes.push_back(node);
}
irr::scene::IMesh* m = m_mb_map[p.first];
auto& cur_key = instance_keys[m];
auto it = cur_key.end();
if (!skip_instance_key)
{
it = std::find_if(cur_key.begin(), cur_key.end(),
[key](const InstanceKey& k)
{
return k.m_nodes == key.m_nodes &&
k.m_instance_count == key.m_instance_count &&
k.m_hue_change == key.m_hue_change;
});
}
for (auto& r : q.second) for (auto& r : q.second)
{ {
irr::scene::ISceneNode* node = r.first; irr::scene::ISceneNode* node = r.first;
@ -345,14 +402,15 @@ void GEVulkanDrawCall::generate()
} }
} }
} }
else else if (skip_instance_key || it == cur_key.end())
{ {
int skinning_offset = -1000; int skinning_offset = -1000;
auto it = skinning_offets.find(node); auto it = skinning_offets.find(node);
if (it != skinning_offets.end()) if (it != skinning_offets.end())
skinning_offset = it->second; skinning_offset = it->second;
m_visible_objects.emplace_back(node, material_id, m_visible_objects.emplace_back(node,
skinning_offset, r.second); bind_mesh_textures ? -1 : material_id, skinning_offset,
r.second);
} }
} }
VkDrawIndexedIndirectCommand cmd; VkDrawIndexedIndirectCommand cmd;
@ -360,17 +418,24 @@ void GEVulkanDrawCall::generate()
cmd.instanceCount = visible_count; cmd.instanceCount = visible_count;
cmd.firstIndex = use_base_vertex ? p.first->getIBOOffset() : 0; cmd.firstIndex = use_base_vertex ? p.first->getIBOOffset() : 0;
cmd.vertexOffset = use_base_vertex ? p.first->getVBOOffset() : 0; cmd.vertexOffset = use_base_vertex ? p.first->getVBOOffset() : 0;
cmd.firstInstance = accumulated_instance; if (skip_instance_key || it == cur_key.end())
accumulated_instance += visible_count; {
cmd.firstInstance = accumulated_instance;
accumulated_instance += visible_count;
}
else
cmd.firstInstance = it->m_first_instance;
const PipelineSettings& settings = const PipelineSettings& settings =
m_graphics_pipelines[cur_shader].second; m_graphics_pipelines[cur_shader].second;
std::string sorting_key = std::string sorting_key =
std::string(1, settings.m_drawing_priority) + cur_shader; std::string(1, settings.m_drawing_priority) + cur_shader;
m_cmds.push_back({ cmd, cur_shader, sorting_key, p.first, m_cmds.push_back({ cmd, cur_shader, sorting_key, p.first,
settings.isTransparent() }); settings.isTransparent() });
if (!skip_instance_key && it == cur_key.end())
cur_key.push_back(key);
} }
} }
if (!GEVulkanFeatures::supportsBindMeshTexturesAtOnce()) if (!bind_mesh_textures)
{ {
std::stable_sort(m_cmds.begin(), m_cmds.end(), std::stable_sort(m_cmds.begin(), m_cmds.end(),
[this](const DrawCallData& a, const DrawCallData& b) [this](const DrawCallData& a, const DrawCallData& b)
@ -395,32 +460,91 @@ void GEVulkanDrawCall::generate()
{ {
const size_t object_data_size = const size_t object_data_size =
sizeof(ObjectData) * m_visible_objects.size(); sizeof(ObjectData) * m_visible_objects.size();
m_data_uploading.emplace_back((void*)m_visible_objects.data(), data_uploading.emplace_back((void*)m_visible_objects.data(),
object_data_size); object_data_size);
m_object_data_padded_size = object_data_size; m_object_data_padded_size = object_data_size;
} }
else else
{ {
m_object_data_padded_size = 0; m_object_data_padded_size = 0;
std::unordered_map<uint32_t, size_t> offset_map;
for (unsigned i = 0; i < m_cmds.size(); i++) for (unsigned i = 0; i < m_cmds.size(); i++)
{ {
auto& cmd = m_cmds[i]; auto& cmd = m_cmds[i];
size_t instance_size = uint32_t first_instance = cmd.m_cmd.firstInstance;
cmd.m_cmd.instanceCount * sizeof(ObjectData); if (offset_map.find(first_instance) == offset_map.end())
m_data_uploading.emplace_back(
&m_visible_objects[cmd.m_cmd.firstInstance], instance_size);
size_t cur_padding = getPadding(m_object_data_padded_size +
instance_size, sbo_alignment);
if (cur_padding > 0)
{ {
instance_size += cur_padding; size_t instance_size =
m_data_uploading.emplace_back((void*)m_data_padding, cmd.m_cmd.instanceCount * sizeof(ObjectData);
cur_padding); data_uploading.emplace_back(
&m_visible_objects[first_instance], instance_size);
size_t cur_padding = getPadding(m_object_data_padded_size +
instance_size, sbo_alignment);
if (cur_padding > 0)
{
instance_size += cur_padding;
data_uploading.emplace_back((void*)m_data_padding,
cur_padding);
}
m_sbo_data_offset.push_back(m_object_data_padded_size);
offset_map[cmd.m_cmd.firstInstance] = m_object_data_padded_size;
m_object_data_padded_size += instance_size;
}
else
{
m_sbo_data_offset.push_back(offset_map.at(first_instance));
} }
m_sbo_data_offset.push_back(m_object_data_padded_size);
m_object_data_padded_size += instance_size;
} }
} }
m_materials_padded_size = 0;
if (bind_mesh_textures && !m_cmds.empty())
{
std::string cur_shader = m_cmds[0].m_shader;
for (unsigned i = 0; i < m_cmds.size(); i++)
{
auto& cmd = m_cmds[i];
auto& material = m_materials_data[cur_shader];
if (cmd.m_shader != cur_shader)
{
size_t material_size = material.second.size() * sizeof(int);
m_data_uploading.emplace_back(
material.second.data(), material_size);
size_t cur_padding = getPadding(m_materials_padded_size +
material_size, sbo_alignment);
if (cur_padding > 0)
{
material_size += cur_padding;
m_data_uploading.emplace_back((void*)m_data_padding,
cur_padding);
}
material.first = m_materials_padded_size;
m_materials_padded_size += material_size;
cur_shader = cmd.m_shader;
}
m_materials_data[cmd.m_shader].second
.push_back(m_materials[cmd.m_mb]);
}
auto& material = m_materials_data[m_cmds.back().m_shader];
size_t material_size = material.second.size() * sizeof(int);
m_data_uploading.emplace_back(
material.second.data(), material_size);
size_t cur_padding = getPadding(m_materials_padded_size +
material_size, sbo_alignment);
if (cur_padding > 0)
{
material_size += cur_padding;
m_data_uploading.emplace_back((void*)m_data_padding,
cur_padding);
}
material.first = m_materials_padded_size;
m_materials_padded_size += material_size;
m_data_uploading.insert(m_data_uploading.end(), data_uploading.begin(),
data_uploading.end());
}
else
std::swap(m_data_uploading, data_uploading);
} // generate } // generate
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -748,42 +872,55 @@ start:
void GEVulkanDrawCall::createVulkanData() void GEVulkanDrawCall::createVulkanData()
{ {
GEVulkanDriver* vk = getVKDriver(); GEVulkanDriver* vk = getVKDriver();
const bool use_base_vertex = GEVulkanFeatures::supportsBaseVertexRendering(); const bool use_dynamic =
!GEVulkanFeatures::supportsBaseVertexRendering() ||
GEVulkanFeatures::supportsBindMeshTexturesAtOnce();
// m_data_layout // m_data_layout
VkDescriptorSetLayoutBinding camera_layout_binding = {}; VkDescriptorSetLayoutBinding camera_layout_binding = {};
camera_layout_binding.binding = 0; camera_layout_binding.binding = 0;
camera_layout_binding.descriptorCount = 1; camera_layout_binding.descriptorCount = 1;
camera_layout_binding.descriptorType = use_base_vertex ? camera_layout_binding.descriptorType = use_dynamic ?
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC :
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
camera_layout_binding.pImmutableSamplers = NULL; camera_layout_binding.pImmutableSamplers = NULL;
camera_layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; camera_layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
VkDescriptorSetLayoutBinding object_data_layout_binding = {}; VkDescriptorSetLayoutBinding object_data_layout_binding = {};
object_data_layout_binding.binding = 1; object_data_layout_binding.binding = 1;
object_data_layout_binding.descriptorCount = 1; object_data_layout_binding.descriptorCount = 1;
object_data_layout_binding.descriptorType = use_base_vertex ? object_data_layout_binding.descriptorType = use_dynamic ?
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER : VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC :
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
object_data_layout_binding.pImmutableSamplers = NULL; object_data_layout_binding.pImmutableSamplers = NULL;
object_data_layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; object_data_layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
VkDescriptorSetLayoutBinding skinning_layout_binding = {}; VkDescriptorSetLayoutBinding skinning_layout_binding = {};
skinning_layout_binding.binding = 2; skinning_layout_binding.binding = 2;
skinning_layout_binding.descriptorCount = 1; skinning_layout_binding.descriptorCount = 1;
skinning_layout_binding.descriptorType = use_base_vertex ? skinning_layout_binding.descriptorType = use_dynamic ?
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER : VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC :
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
skinning_layout_binding.pImmutableSamplers = NULL; skinning_layout_binding.pImmutableSamplers = NULL;
skinning_layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; skinning_layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
std::array<VkDescriptorSetLayoutBinding, 3> bindings = std::vector<VkDescriptorSetLayoutBinding> bindings =
{{ {
camera_layout_binding, camera_layout_binding,
object_data_layout_binding, object_data_layout_binding,
skinning_layout_binding skinning_layout_binding
}}; };
if (GEVulkanFeatures::supportsBindMeshTexturesAtOnce())
{
VkDescriptorSetLayoutBinding material_binding = {};
material_binding.binding = 3;
material_binding.descriptorCount = 1;
material_binding.descriptorType =
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
material_binding.pImmutableSamplers = NULL;
material_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
bindings.push_back(material_binding);
}
VkDescriptorSetLayoutCreateInfo setinfo = {}; VkDescriptorSetLayoutCreateInfo setinfo = {};
setinfo.flags = 0; setinfo.flags = 0;
@ -801,21 +938,23 @@ void GEVulkanDrawCall::createVulkanData()
} }
// m_descriptor_pool // m_descriptor_pool
std::array<VkDescriptorPoolSize, 2> sizes = std::vector<VkDescriptorPoolSize> sizes =
{{ {
{ {
use_base_vertex ? use_dynamic ?
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC :
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
vk->getMaxFrameInFlight() vk->getMaxFrameInFlight()
}, },
{ {
use_base_vertex ? use_dynamic ?
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER : VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC :
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
vk->getMaxFrameInFlight() * 2 vk->getMaxFrameInFlight() * 2
} }
}}; };
if (GEVulkanFeatures::supportsBindMeshTexturesAtOnce())
sizes.push_back(sizes.back());
VkDescriptorPoolCreateInfo pool_info = {}; VkDescriptorPoolCreateInfo pool_info = {};
pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
@ -877,7 +1016,7 @@ void GEVulkanDrawCall::createVulkanData()
createAllPipelines(vk); createAllPipelines(vk);
size_t extra_size = 0; size_t extra_size = 0;
const bool use_multidraw = GEVulkanFeatures::supportsMultiDrawIndirect() && const bool use_multidraw =
GEVulkanFeatures::supportsBindMeshTexturesAtOnce(); GEVulkanFeatures::supportsBindMeshTexturesAtOnce();
VkBufferUsageFlags flags = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; VkBufferUsageFlags flags = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
if (use_multidraw) if (use_multidraw)
@ -913,7 +1052,7 @@ void GEVulkanDrawCall::uploadDynamicData(GEVulkanDriver* vk,
data_uploading.emplace_back((void*)cam->getUBOData(), data_uploading.emplace_back((void*)cam->getUBOData(),
sizeof(GEVulkanCameraUBO)); sizeof(GEVulkanCameraUBO));
const bool use_multidraw = GEVulkanFeatures::supportsMultiDrawIndirect() && const bool use_multidraw =
GEVulkanFeatures::supportsBindMeshTexturesAtOnce(); GEVulkanFeatures::supportsBindMeshTexturesAtOnce();
if (use_multidraw) if (use_multidraw)
{ {
@ -927,34 +1066,30 @@ void GEVulkanDrawCall::uploadDynamicData(GEVulkanDriver* vk,
m_dynamic_data->setCurrentData(data_uploading, cmd); m_dynamic_data->setCurrentData(data_uploading, cmd);
const bool use_base_vertex = GEVulkanFeatures::supportsBaseVertexRendering(); const bool use_base_vertex = GEVulkanFeatures::supportsBaseVertexRendering();
size_t min_size = 0;
if (!use_base_vertex) if (!use_base_vertex)
{ {
// Make sure dynamic offset won't become invaild // Make sure dynamic offset won't become invaild
size_t min_size = m_skinning_data_padded_size + min_size = m_skinning_data_padded_size +
(m_object_data_padded_size * 2); (m_object_data_padded_size * 2);
m_sbo_data->resizeIfNeeded(min_size);
} }
else if (use_multidraw)
{
min_size = (m_materials_padded_size * 2) +
m_skinning_data_padded_size + m_object_data_padded_size;
}
m_sbo_data->resizeIfNeeded(min_size);
m_sbo_data->setCurrentData(m_data_uploading, cmd); m_sbo_data->setCurrentData(m_data_uploading, cmd);
VkBufferMemoryBarrier barrier = {}; VkMemoryBarrier barrier = {};
barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
if (use_multidraw) if (use_multidraw)
barrier.dstAccessMask |= VK_ACCESS_INDIRECT_COMMAND_READ_BIT; barrier.dstAccessMask |= VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.buffer = m_dynamic_data->getCurrentBuffer();
barrier.size = m_dynamic_data->getRealSize();
vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stage, 0, 0, vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stage, 0, 1,
NULL, 1, &barrier, 0, NULL); &barrier, 0, NULL, 0, NULL);
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
barrier.buffer = m_sbo_data->getCurrentBuffer();
barrier.size = m_skinning_data_padded_size + m_object_data_padded_size;
vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stage, 0, 0,
NULL, 1, &barrier, 0, NULL);
} // uploadDynamicData } // uploadDynamicData
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -969,70 +1104,78 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam,
const unsigned cur_frame = vk->getCurrentFrame(); const unsigned cur_frame = vk->getCurrentFrame();
const bool use_base_vertex = GEVulkanFeatures::supportsBaseVertexRendering(); const bool use_base_vertex = GEVulkanFeatures::supportsBaseVertexRendering();
const bool bind_mesh_textures = GEVulkanFeatures::supportsBindMeshTexturesAtOnce();
const bool use_dynamic = !use_base_vertex || bind_mesh_textures;
VkDescriptorBufferInfo ubo_info; VkDescriptorBufferInfo ubo_info;
ubo_info.buffer = m_dynamic_data->getCurrentBuffer(); ubo_info.buffer = m_dynamic_data->getCurrentBuffer();
ubo_info.offset = 0; ubo_info.offset = 0;
ubo_info.range = sizeof(GEVulkanCameraUBO); ubo_info.range = sizeof(GEVulkanCameraUBO);
std::array<VkWriteDescriptorSet, 3> data_set = {}; std::vector<VkWriteDescriptorSet> data_set;
data_set.resize(3, {});
data_set[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; data_set[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
data_set[0].dstSet = m_data_descriptor_sets[cur_frame]; data_set[0].dstSet = m_data_descriptor_sets[cur_frame];
data_set[0].dstBinding = 0; data_set[0].dstBinding = 0;
data_set[0].dstArrayElement = 0; data_set[0].dstArrayElement = 0;
data_set[0].descriptorType = use_base_vertex ? data_set[0].descriptorType = use_dynamic ?
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC :
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
data_set[0].descriptorCount = 1; data_set[0].descriptorCount = 1;
data_set[0].pBufferInfo = &ubo_info; data_set[0].pBufferInfo = &ubo_info;
VkDescriptorBufferInfo sbo_info_objects; VkDescriptorBufferInfo sbo_info_objects;
sbo_info_objects.buffer = m_sbo_data->getCurrentBuffer(); sbo_info_objects.buffer = m_sbo_data->getCurrentBuffer();
sbo_info_objects.offset = m_skinning_data_padded_size; sbo_info_objects.offset =
m_materials_padded_size + m_skinning_data_padded_size;
sbo_info_objects.range = m_object_data_padded_size; sbo_info_objects.range = m_object_data_padded_size;
data_set[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; data_set[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
data_set[1].dstSet = m_data_descriptor_sets[cur_frame]; data_set[1].dstSet = m_data_descriptor_sets[cur_frame];
data_set[1].dstBinding = 1; data_set[1].dstBinding = 1;
data_set[1].dstArrayElement = 0; data_set[1].dstArrayElement = 0;
data_set[1].descriptorType = use_base_vertex ? data_set[1].descriptorType = use_dynamic ?
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER : VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC :
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
data_set[1].descriptorCount = 1; data_set[1].descriptorCount = 1;
data_set[1].pBufferInfo = &sbo_info_objects; data_set[1].pBufferInfo = &sbo_info_objects;
VkDescriptorBufferInfo sbo_info_skinning; VkDescriptorBufferInfo sbo_info_skinning;
sbo_info_skinning.buffer = m_sbo_data->getCurrentBuffer(); sbo_info_skinning.buffer = m_sbo_data->getCurrentBuffer();
sbo_info_skinning.offset = 0; sbo_info_skinning.offset = m_materials_padded_size;
sbo_info_skinning.range = m_skinning_data_padded_size; sbo_info_skinning.range = m_skinning_data_padded_size;
data_set[2].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; data_set[2].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
data_set[2].dstSet = m_data_descriptor_sets[cur_frame]; data_set[2].dstSet = m_data_descriptor_sets[cur_frame];
data_set[2].dstBinding = 2; data_set[2].dstBinding = 2;
data_set[2].dstArrayElement = 0; data_set[2].dstArrayElement = 0;
data_set[2].descriptorType = use_base_vertex ? data_set[2].descriptorType = use_dynamic ?
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER : VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC :
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; ; VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; ;
data_set[2].descriptorCount = 1; data_set[2].descriptorCount = 1;
data_set[2].pBufferInfo = &sbo_info_skinning; data_set[2].pBufferInfo = &sbo_info_skinning;
VkDescriptorBufferInfo sbo_info_material;
sbo_info_material.buffer = m_sbo_data->getCurrentBuffer();
sbo_info_material.offset = 0;
sbo_info_material.range = m_materials_padded_size;
if (bind_mesh_textures)
{
data_set.resize(4, {});
data_set[3].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
data_set[3].dstSet = m_data_descriptor_sets[cur_frame];
data_set[3].dstBinding = 3;
data_set[3].dstArrayElement = 0;
data_set[3].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
data_set[3].descriptorCount = 1;
data_set[3].pBufferInfo = &sbo_info_material;
}
vkUpdateDescriptorSets(vk->getDevice(), data_set.size(), data_set.data(), vkUpdateDescriptorSets(vk->getDevice(), data_set.size(), data_set.data(),
0, NULL); 0, NULL);
m_texture_descriptor->updateDescriptor(); m_texture_descriptor->updateDescriptor();
if (GEVulkanFeatures::supportsBindMeshTexturesAtOnce())
{
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
m_pipeline_layout, 0, 1, m_texture_descriptor->getDescriptorSet(),
0, NULL);
}
if (use_base_vertex) if (use_base_vertex)
{ {
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
m_pipeline_layout, 1, 1, &m_data_descriptor_sets[cur_frame], 0,
NULL);
GEVulkanMeshCache* mc = vk->getVulkanMeshCache(); GEVulkanMeshCache* mc = vk->getVulkanMeshCache();
std::array<VkBuffer, 2> vertex_buffer = std::array<VkBuffer, 2> vertex_buffer =
{{ {{
@ -1071,13 +1214,21 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam,
scissor.extent.height = vp.height; scissor.extent.height = vp.height;
vkCmdSetScissor(cmd, 0, 1, &scissor); vkCmdSetScissor(cmd, 0, 1, &scissor);
const bool use_multidraw = GEVulkanFeatures::supportsMultiDrawIndirect() &&
GEVulkanFeatures::supportsBindMeshTexturesAtOnce();
std::string cur_pipeline = m_cmds[0].m_shader; std::string cur_pipeline = m_cmds[0].m_shader;
bool drawn_skybox = false; bool drawn_skybox = false;
if (use_multidraw) if (bind_mesh_textures)
{ {
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
m_pipeline_layout, 0, 1, m_texture_descriptor->getDescriptorSet(),
0, NULL);
std::array<uint32_t, 4> material_offsets =
{{
0u,
0u,
0u,
0u,
}};
size_t indirect_offset = sizeof(GEVulkanCameraUBO); size_t indirect_offset = sizeof(GEVulkanCameraUBO);
const size_t indirect_size = sizeof(VkDrawIndexedIndirectCommand); const size_t indirect_size = sizeof(VkDrawIndexedIndirectCommand);
unsigned draw_count = 0; unsigned draw_count = 0;
@ -1086,6 +1237,11 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam,
if (m_cmds[i].m_shader != cur_pipeline) if (m_cmds[i].m_shader != cur_pipeline)
{ {
bindPipeline(cmd, cur_pipeline); bindPipeline(cmd, cur_pipeline);
material_offsets[3] = m_materials_data[cur_pipeline].first;
vkCmdBindDescriptorSets(cmd,
VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 1, 1,
&m_data_descriptor_sets[cur_frame], material_offsets.size(),
material_offsets.data());
vkCmdDrawIndexedIndirect(cmd, vkCmdDrawIndexedIndirect(cmd,
m_dynamic_data->getCurrentBuffer(), indirect_offset, m_dynamic_data->getCurrentBuffer(), indirect_offset,
draw_count, indirect_size); draw_count, indirect_size);
@ -1101,16 +1257,17 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam,
vkCmdBindDescriptorSets(cmd, vkCmdBindDescriptorSets(cmd,
VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 0, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 0,
1, m_texture_descriptor->getDescriptorSet(), 0, NULL); 1, m_texture_descriptor->getDescriptorSet(), 0, NULL);
vkCmdBindDescriptorSets(cmd,
VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 1, 1,
&m_data_descriptor_sets[cur_frame], 0, NULL);
} }
continue; continue;
} }
draw_count++; draw_count++;
} }
bindPipeline(cmd, m_cmds.back().m_shader); bindPipeline(cmd, m_cmds.back().m_shader);
material_offsets[3] = m_materials_data[m_cmds.back().m_shader].first;
vkCmdBindDescriptorSets(cmd,
VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 1, 1,
&m_data_descriptor_sets[cur_frame], material_offsets.size(),
material_offsets.data());
vkCmdDrawIndexedIndirect(cmd, vkCmdDrawIndexedIndirect(cmd,
m_dynamic_data->getCurrentBuffer(), indirect_offset, m_dynamic_data->getCurrentBuffer(), indirect_offset,
draw_count, indirect_size); draw_count, indirect_size);
@ -1119,11 +1276,14 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam,
{ {
int cur_mid = m_materials[m_cmds[0].m_mb]; int cur_mid = m_materials[m_cmds[0].m_mb];
bindPipeline(cmd, cur_pipeline); bindPipeline(cmd, cur_pipeline);
if (!GEVulkanFeatures::supportsBindMeshTexturesAtOnce()) vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
m_pipeline_layout, 0, 1,
&m_texture_descriptor->getDescriptorSet()[cur_mid], 0, NULL);
if (use_base_vertex)
{ {
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, vkCmdBindDescriptorSets(cmd,
m_pipeline_layout, 0, 1, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 1, 1,
&m_texture_descriptor->getDescriptorSet()[cur_mid], 0, NULL); &m_data_descriptor_sets[cur_frame], 0, NULL);
} }
for (unsigned i = 0; i < m_cmds.size(); i++) for (unsigned i = 0; i < m_cmds.size(); i++)
{ {
@ -1133,19 +1293,10 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam,
drawn_skybox = true; drawn_skybox = true;
GEVulkanSkyBoxRenderer::render(cmd, cam); GEVulkanSkyBoxRenderer::render(cmd, cam);
if (!GEVulkanFeatures::supportsBindMeshTexturesAtOnce()) vkCmdBindDescriptorSets(cmd,
{ VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 0, 1,
vkCmdBindDescriptorSets(cmd, &m_texture_descriptor->getDescriptorSet()[cur_mid], 0,
VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 0, NULL);
1, &m_texture_descriptor->getDescriptorSet()[cur_mid],
0, NULL);
}
else
{
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
m_pipeline_layout, 0, 1,
m_texture_descriptor->getDescriptorSet(), 0, NULL);
}
if (use_base_vertex) if (use_base_vertex)
{ {
vkCmdBindDescriptorSets(cmd, vkCmdBindDescriptorSets(cmd,
@ -1155,8 +1306,7 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam,
} }
int mid = m_materials[m_cmds[i].m_mb]; int mid = m_materials[m_cmds[i].m_mb];
if (!GEVulkanFeatures::supportsBindMeshTexturesAtOnce() && if (cur_mid != mid)
cur_mid != mid)
{ {
cur_mid = mid; cur_mid = mid;
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,

View File

@ -22,6 +22,7 @@ namespace irr
namespace scene namespace scene
{ {
class ISceneNode; class IBillboardSceneNode; struct SParticle; class ISceneNode; class IBillboardSceneNode; struct SParticle;
class IMesh;
} }
} }
@ -104,6 +105,8 @@ private:
std::vector<std::pair<irr::scene::ISceneNode*, int> > > > std::vector<std::pair<irr::scene::ISceneNode*, int> > > >
m_visible_nodes; m_visible_nodes;
std::unordered_map<GESPMBuffer*, irr::scene::IMesh*> m_mb_map;
GECullingTool* m_culling_tool; GECullingTool* m_culling_tool;
std::vector<DrawCallData> m_cmds; std::vector<DrawCallData> m_cmds;
@ -120,6 +123,8 @@ private:
size_t m_skinning_data_padded_size; size_t m_skinning_data_padded_size;
size_t m_materials_padded_size;
char* m_data_padding; char* m_data_padding;
VkDescriptorSetLayout m_data_layout; VkDescriptorSetLayout m_data_layout;
@ -143,6 +148,9 @@ private:
std::vector<size_t> m_sbo_data_offset; std::vector<size_t> m_sbo_data_offset;
std::unordered_map<std::string, std::pair<uint32_t, std::vector<int> > >
m_materials_data;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void createAllPipelines(GEVulkanDriver* vk); void createAllPipelines(GEVulkanDriver* vk);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -207,12 +215,14 @@ public:
void reset() void reset()
{ {
m_visible_nodes.clear(); m_visible_nodes.clear();
m_mb_map.clear();
m_cmds.clear(); m_cmds.clear();
m_visible_objects.clear(); m_visible_objects.clear();
m_materials.clear(); m_materials.clear();
m_skinning_nodes.clear(); m_skinning_nodes.clear();
m_data_uploading.clear(); m_data_uploading.clear();
m_sbo_data_offset.clear(); m_sbo_data_offset.clear();
m_materials_data.clear();
} }
}; // GEVulkanDrawCall }; // GEVulkanDrawCall

View File

@ -890,17 +890,21 @@ bool GEVulkanDriver::checkDeviceExtensions(VkPhysicalDevice device)
VkPhysicalDeviceProperties properties = {}; VkPhysicalDeviceProperties properties = {};
vkGetPhysicalDeviceProperties(device, &properties); vkGetPhysicalDeviceProperties(device, &properties);
if (properties.apiVersion < VK_API_VERSION_1_2) for (auto& ext : extensions)
{ {
for (auto& ext : extensions) if (properties.apiVersion < VK_API_VERSION_1_2 &&
strcmp(ext.extensionName,
VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME) == 0)
{ {
if (strcmp(ext.extensionName, m_device_extensions.push_back(
VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME) == 0) VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
{ }
m_device_extensions.push_back( else if (properties.apiVersion < VK_API_VERSION_1_1 &&
VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); strcmp(ext.extensionName,
break; VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME) == 0)
} {
m_device_extensions.push_back(
VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME);
} }
} }
@ -1027,6 +1031,13 @@ void GEVulkanDriver::createDevice()
descriptor_indexing_features.descriptorBindingPartiallyBound = descriptor_indexing_features.descriptorBindingPartiallyBound =
GEVulkanFeatures::supportsPartiallyBound(); GEVulkanFeatures::supportsPartiallyBound();
VkPhysicalDeviceShaderDrawParametersFeatures shader_draw = {};
shader_draw.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES;
shader_draw.shaderDrawParameters =
GEVulkanFeatures::supportsShaderDrawParameters();
descriptor_indexing_features.pNext = &shader_draw;
if (m_features.samplerAnisotropy == VK_TRUE) if (m_features.samplerAnisotropy == VK_TRUE)
device_features.samplerAnisotropy = VK_TRUE; device_features.samplerAnisotropy = VK_TRUE;

View File

@ -190,6 +190,9 @@ void GEVulkanFeatures::init(GEVulkanDriver* vk)
g_supports_base_vertex_rendering = mvk_features.baseVertexInstanceDrawing; g_supports_base_vertex_rendering = mvk_features.baseVertexInstanceDrawing;
if (!g_supports_base_vertex_rendering) if (!g_supports_base_vertex_rendering)
g_supports_multi_draw_indirect = false; g_supports_multi_draw_indirect = false;
// https://github.com/KhronosGroup/MoltenVK/issues/1743
g_supports_shader_draw_parameters = false;
#endif #endif
} // init } // init
@ -286,7 +289,8 @@ bool GEVulkanFeatures::supportsPartiallyBound()
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
bool GEVulkanFeatures::supportsBindMeshTexturesAtOnce() bool GEVulkanFeatures::supportsBindMeshTexturesAtOnce()
{ {
if (!g_supports_bind_textures_at_once) if (!g_supports_bind_textures_at_once || !g_supports_multi_draw_indirect ||
!g_supports_shader_draw_parameters)
return false; return false;
const unsigned sampler_count = GEVulkanShaderManager::getSamplerSize() * const unsigned sampler_count = GEVulkanShaderManager::getSamplerSize() *
GEVulkanShaderManager::getMeshTextureLayer(); GEVulkanShaderManager::getMeshTextureLayer();