Global scene memory allocation instead of per-mesh, use VulkanDevice, compiler warnings
This commit is contained in:
parent
e4fb1e6126
commit
053d6423fa
1 changed files with 133 additions and 119 deletions
|
|
@ -1,9 +1,24 @@
|
||||||
/*
|
/*
|
||||||
* Vulkan Example - Rendering a scene with multiple meshes and materials
|
* Vulkan Example - Scene rendering
|
||||||
*
|
*
|
||||||
* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
|
* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
|
||||||
*
|
*
|
||||||
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
|
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
|
||||||
|
*
|
||||||
|
* Summary:
|
||||||
|
* Renders a scene made of multiple meshes with different materials and textures.
|
||||||
|
*
|
||||||
|
* The example loads a scene made up of multiple meshes into one vertex and index buffer to only
|
||||||
|
* have one (big) memory allocation. In Vulkan it's advised to keep number of memory allocations
|
||||||
|
* down and try to allocate large blocks of memory at once instead of having many small allocations.
|
||||||
|
*
|
||||||
|
* Every mesh has a separate material and multiple descriptor sets (set = x layout qualifier in GLSL)
|
||||||
|
* are used to bind a uniform buffer with global matrices and the mesh' material's sampler at once.
|
||||||
|
*
|
||||||
|
* To demonstrate another way of passing data the example also uses push constants for passing
|
||||||
|
* material properties.
|
||||||
|
*
|
||||||
|
* Note that this example is just one way of rendering a scene made up of multiple meshes iin Vulkan.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
@ -63,9 +78,8 @@ struct SceneMaterial
|
||||||
// Stores per-mesh Vulkan resources
|
// Stores per-mesh Vulkan resources
|
||||||
struct SceneMesh
|
struct SceneMesh
|
||||||
{
|
{
|
||||||
vk::Buffer vertexBuffer;
|
// Index of first index in the scene buffer
|
||||||
vk::Buffer indexBuffer;
|
uint32_t indexBase;
|
||||||
|
|
||||||
uint32_t indexCount;
|
uint32_t indexCount;
|
||||||
|
|
||||||
// Pointer to the material used by this mesh
|
// Pointer to the material used by this mesh
|
||||||
|
|
@ -89,6 +103,12 @@ private:
|
||||||
VkDescriptorSetLayout scene;
|
VkDescriptorSetLayout scene;
|
||||||
} descriptorSetLayouts;
|
} descriptorSetLayouts;
|
||||||
|
|
||||||
|
// We will be using one single index and vertex buffer
|
||||||
|
// containing vertices and indices for all meshes in the scene
|
||||||
|
// This allows us to keep memory allocations down
|
||||||
|
vk::Buffer vertexBuffer;
|
||||||
|
vk::Buffer indexBuffer;
|
||||||
|
|
||||||
VkDescriptorSet descriptorSetScene;
|
VkDescriptorSet descriptorSetScene;
|
||||||
|
|
||||||
vkTools::VulkanTextureLoader *textureLoader;
|
vkTools::VulkanTextureLoader *textureLoader;
|
||||||
|
|
@ -211,12 +231,6 @@ private:
|
||||||
|
|
||||||
VK_CHECK_RESULT(vkAllocateDescriptorSets(vulkanDevice->logicalDevice, &allocInfo, &materials[i].descriptorSet));
|
VK_CHECK_RESULT(vkAllocateDescriptorSets(vulkanDevice->logicalDevice, &allocInfo, &materials[i].descriptorSet));
|
||||||
|
|
||||||
VkDescriptorImageInfo texDescriptor =
|
|
||||||
vkTools::initializers::descriptorImageInfo(
|
|
||||||
materials[i].diffuse.sampler,
|
|
||||||
materials[i].diffuse.view,
|
|
||||||
VK_IMAGE_LAYOUT_GENERAL);
|
|
||||||
|
|
||||||
std::vector<VkWriteDescriptorSet> writeDescriptorSets;
|
std::vector<VkWriteDescriptorSet> writeDescriptorSets;
|
||||||
|
|
||||||
// todo : only use image sampler descriptor set and use one scene ubo for matrices
|
// todo : only use image sampler descriptor set and use one scene ubo for matrices
|
||||||
|
|
@ -226,9 +240,9 @@ private:
|
||||||
materials[i].descriptorSet,
|
materials[i].descriptorSet,
|
||||||
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||||
0,
|
0,
|
||||||
&texDescriptor));
|
&materials[i].diffuse.descriptor));
|
||||||
|
|
||||||
vkUpdateDescriptorSets(vulkanDevice->logicalDevice, writeDescriptorSets.size(), writeDescriptorSets.data(), 0, NULL);
|
vkUpdateDescriptorSets(vulkanDevice->logicalDevice, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scene descriptor set
|
// Scene descriptor set
|
||||||
|
|
@ -247,13 +261,16 @@ private:
|
||||||
0,
|
0,
|
||||||
&uniformBuffer.descriptor));
|
&uniformBuffer.descriptor));
|
||||||
|
|
||||||
vkUpdateDescriptorSets(vulkanDevice->logicalDevice, writeDescriptorSets.size(), writeDescriptorSets.data(), 0, NULL);
|
vkUpdateDescriptorSets(vulkanDevice->logicalDevice, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load all meshes from the scene and generate the Vulkan resources
|
// Load all meshes from the scene and generate the buffers for rendering them
|
||||||
// for rendering them
|
|
||||||
void loadMeshes(VkCommandBuffer copyCmd)
|
void loadMeshes(VkCommandBuffer copyCmd)
|
||||||
{
|
{
|
||||||
|
std::vector<Vertex> vertices;
|
||||||
|
std::vector<uint32_t> indices;
|
||||||
|
uint32_t indexBase = 0;
|
||||||
|
|
||||||
meshes.resize(aScene->mNumMeshes);
|
meshes.resize(aScene->mNumMeshes);
|
||||||
for (uint32_t i = 0; i < meshes.size(); i++)
|
for (uint32_t i = 0; i < meshes.size(); i++)
|
||||||
{
|
{
|
||||||
|
|
@ -264,39 +281,42 @@ private:
|
||||||
std::cout << " Faces: " << aMesh->mNumFaces << std::endl;
|
std::cout << " Faces: " << aMesh->mNumFaces << std::endl;
|
||||||
|
|
||||||
meshes[i].material = &materials[aMesh->mMaterialIndex];
|
meshes[i].material = &materials[aMesh->mMaterialIndex];
|
||||||
|
meshes[i].indexBase = indexBase;
|
||||||
|
meshes[i].indexCount = aMesh->mNumFaces * 3;
|
||||||
|
|
||||||
// Vertices
|
// Vertices
|
||||||
std::vector<Vertex> vertices;
|
|
||||||
vertices.resize(aMesh->mNumVertices);
|
|
||||||
|
|
||||||
bool hasUV = aMesh->HasTextureCoords(0);
|
bool hasUV = aMesh->HasTextureCoords(0);
|
||||||
bool hasColor = aMesh->HasVertexColors(0);
|
bool hasColor = aMesh->HasVertexColors(0);
|
||||||
bool hasNormals = aMesh->HasNormals();
|
bool hasNormals = aMesh->HasNormals();
|
||||||
|
|
||||||
for (uint32_t v = 0; v < aMesh->mNumVertices; v++)
|
for (uint32_t v = 0; v < aMesh->mNumVertices; v++)
|
||||||
{
|
{
|
||||||
vertices[v].pos = glm::make_vec3(&aMesh->mVertices[v].x);
|
Vertex vertex;
|
||||||
vertices[v].pos.y = -vertices[v].pos.y;
|
vertex.pos = glm::make_vec3(&aMesh->mVertices[v].x);
|
||||||
vertices[v].uv = hasUV ? glm::make_vec2(&aMesh->mTextureCoords[0][v].x) : glm::vec2(0.0f);
|
vertex.pos.y = -vertex.pos.y;
|
||||||
vertices[v].normal = hasNormals ? glm::make_vec3(&aMesh->mNormals[v].x) : glm::vec3(0.0f);
|
vertex.uv = hasUV ? glm::make_vec2(&aMesh->mTextureCoords[0][v].x) : glm::vec2(0.0f);
|
||||||
vertices[v].normal.y = -vertices[v].normal.y;
|
vertex.normal = hasNormals ? glm::make_vec3(&aMesh->mNormals[v].x) : glm::vec3(0.0f);
|
||||||
vertices[v].color = hasColor ? glm::make_vec3(&aMesh->mColors[0][v].r) : glm::vec3(1.0f);
|
vertex.normal.y = -vertex.normal.y;
|
||||||
|
vertex.color = hasColor ? glm::make_vec3(&aMesh->mColors[0][v].r) : glm::vec3(1.0f);
|
||||||
|
vertices.push_back(vertex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Indices
|
// Indices
|
||||||
std::vector<uint32_t> indices;
|
|
||||||
meshes[i].indexCount = aMesh->mNumFaces * 3;
|
|
||||||
indices.resize(aMesh->mNumFaces * 3);
|
|
||||||
for (uint32_t f = 0; f < aMesh->mNumFaces; f++)
|
for (uint32_t f = 0; f < aMesh->mNumFaces; f++)
|
||||||
{
|
{
|
||||||
memcpy(&indices[f*3], &aMesh->mFaces[f].mIndices[0], sizeof(uint32_t) * 3);
|
for (uint32_t j = 0; j < 3; j++)
|
||||||
|
{
|
||||||
|
indices.push_back(aMesh->mFaces[f].mIndices[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
indexBase += aMesh->mNumFaces * 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create buffers
|
// Create buffers
|
||||||
// todo : only one memory allocation for the whole scene, use offsets to render
|
// For better performance we only create one index and vertex buffer to keep number of memory allocations down
|
||||||
|
size_t vertexDataSize = vertices.size() * sizeof(Vertex);
|
||||||
uint32_t vertexDataSize = vertices.size() * sizeof(Vertex);
|
size_t indexDataSize = indices.size() * sizeof(uint32_t);
|
||||||
uint32_t indexDataSize = indices.size() * sizeof(uint32_t);
|
|
||||||
|
|
||||||
vk::Buffer vertexStaging, indexStaging;
|
vk::Buffer vertexStaging, indexStaging;
|
||||||
|
|
||||||
|
|
@ -306,28 +326,28 @@ private:
|
||||||
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
||||||
&vertexStaging,
|
&vertexStaging,
|
||||||
vertexDataSize,
|
static_cast<uint32_t>(vertexDataSize),
|
||||||
vertices.data()));
|
vertices.data()));
|
||||||
// Target
|
// Target
|
||||||
VK_CHECK_RESULT(vulkanDevice->createBuffer(
|
VK_CHECK_RESULT(vulkanDevice->createBuffer(
|
||||||
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||||
&meshes[i].vertexBuffer,
|
&vertexBuffer,
|
||||||
vertexDataSize));
|
static_cast<uint32_t>(vertexDataSize)));
|
||||||
|
|
||||||
// Index buffer
|
// Index buffer
|
||||||
VK_CHECK_RESULT(vulkanDevice->createBuffer(
|
VK_CHECK_RESULT(vulkanDevice->createBuffer(
|
||||||
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
||||||
&indexStaging,
|
&indexStaging,
|
||||||
indexDataSize,
|
static_cast<uint32_t>(indexDataSize),
|
||||||
indices.data()));
|
indices.data()));
|
||||||
// Target
|
// Target
|
||||||
VK_CHECK_RESULT(vulkanDevice->createBuffer(
|
VK_CHECK_RESULT(vulkanDevice->createBuffer(
|
||||||
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||||
&meshes[i].indexBuffer,
|
&indexBuffer,
|
||||||
indexDataSize));
|
static_cast<uint32_t>(indexDataSize)));
|
||||||
|
|
||||||
// Copy
|
// Copy
|
||||||
VkCommandBufferBeginInfo cmdBufInfo = vkTools::initializers::commandBufferBeginInfo();
|
VkCommandBufferBeginInfo cmdBufInfo = vkTools::initializers::commandBufferBeginInfo();
|
||||||
|
|
@ -339,7 +359,7 @@ private:
|
||||||
vkCmdCopyBuffer(
|
vkCmdCopyBuffer(
|
||||||
copyCmd,
|
copyCmd,
|
||||||
vertexStaging.buffer,
|
vertexStaging.buffer,
|
||||||
meshes[i].vertexBuffer.buffer,
|
vertexBuffer.buffer,
|
||||||
1,
|
1,
|
||||||
©Region);
|
©Region);
|
||||||
|
|
||||||
|
|
@ -347,7 +367,7 @@ private:
|
||||||
vkCmdCopyBuffer(
|
vkCmdCopyBuffer(
|
||||||
copyCmd,
|
copyCmd,
|
||||||
indexStaging.buffer,
|
indexStaging.buffer,
|
||||||
meshes[i].indexBuffer.buffer,
|
indexBuffer.buffer,
|
||||||
1,
|
1,
|
||||||
©Region);
|
©Region);
|
||||||
|
|
||||||
|
|
@ -365,7 +385,6 @@ private:
|
||||||
vertexStaging.destroy();
|
vertexStaging.destroy();
|
||||||
indexStaging.destroy();
|
indexStaging.destroy();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
#if defined(__ANDROID__)
|
#if defined(__ANDROID__)
|
||||||
|
|
@ -427,11 +446,8 @@ public:
|
||||||
// Default destructor
|
// Default destructor
|
||||||
~Scene()
|
~Scene()
|
||||||
{
|
{
|
||||||
for (auto mesh : meshes)
|
vertexBuffer.destroy();
|
||||||
{
|
indexBuffer.destroy();
|
||||||
mesh.vertexBuffer.destroy();
|
|
||||||
mesh.indexBuffer.destroy();
|
|
||||||
}
|
|
||||||
for (auto material : materials)
|
for (auto material : materials)
|
||||||
{
|
{
|
||||||
textureLoader->destroyTexture(material.diffuse);
|
textureLoader->destroyTexture(material.diffuse);
|
||||||
|
|
@ -485,16 +501,18 @@ public:
|
||||||
void render(VkCommandBuffer cmdBuffer, bool wireframe)
|
void render(VkCommandBuffer cmdBuffer, bool wireframe)
|
||||||
{
|
{
|
||||||
VkDeviceSize offsets[1] = { 0 };
|
VkDeviceSize offsets[1] = { 0 };
|
||||||
|
|
||||||
|
// Bind scene vertex and index buffers
|
||||||
|
vkCmdBindVertexBuffers(cmdBuffer, 0, 1, &vertexBuffer.buffer, offsets);
|
||||||
|
vkCmdBindIndexBuffer(cmdBuffer, indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
|
||||||
|
|
||||||
for (size_t i = 0; i < meshes.size(); i++)
|
for (size_t i = 0; i < meshes.size(); i++)
|
||||||
{
|
{
|
||||||
if ((renderSingleScenePart) && (i != scenePartIndex))
|
if ((renderSingleScenePart) && (i != scenePartIndex))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
//if (meshes[i].material->opacity == 0.0f)
|
|
||||||
// continue;
|
|
||||||
|
|
||||||
// todo : per material pipelines
|
// todo : per material pipelines
|
||||||
// vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *mesh.material->pipeline);
|
// vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *mesh.material->pipeline);
|
||||||
|
|
||||||
// We will be using multiple descriptor sets for rendering
|
// We will be using multiple descriptor sets for rendering
|
||||||
// In GLSL the selection is done via the set and binding keywords
|
// In GLSL the selection is done via the set and binding keywords
|
||||||
|
|
@ -519,13 +537,9 @@ public:
|
||||||
sizeof(SceneMaterialProperites),
|
sizeof(SceneMaterialProperites),
|
||||||
&meshes[i].material->properties);
|
&meshes[i].material->properties);
|
||||||
|
|
||||||
vkCmdBindVertexBuffers(cmdBuffer, 0, 1, &meshes[i].vertexBuffer.buffer, offsets);
|
// Render from the global scene vertex buffer using the mesh index offset
|
||||||
vkCmdBindIndexBuffer(cmdBuffer, meshes[i].indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
|
vkCmdDrawIndexed(cmdBuffer, meshes[i].indexCount, 1, 0, meshes[i].indexBase, 0);
|
||||||
vkCmdDrawIndexed(cmdBuffer, meshes[i].indexCount, 1, 0, 0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render transparent objects last
|
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -653,9 +667,9 @@ public:
|
||||||
sizeof(float) * 8);
|
sizeof(float) * 8);
|
||||||
|
|
||||||
vertices.inputState = vkTools::initializers::pipelineVertexInputStateCreateInfo();
|
vertices.inputState = vkTools::initializers::pipelineVertexInputStateCreateInfo();
|
||||||
vertices.inputState.vertexBindingDescriptionCount = vertices.bindingDescriptions.size();
|
vertices.inputState.vertexBindingDescriptionCount = static_cast<uint32_t>(vertices.bindingDescriptions.size());
|
||||||
vertices.inputState.pVertexBindingDescriptions = vertices.bindingDescriptions.data();
|
vertices.inputState.pVertexBindingDescriptions = vertices.bindingDescriptions.data();
|
||||||
vertices.inputState.vertexAttributeDescriptionCount = vertices.attributeDescriptions.size();
|
vertices.inputState.vertexAttributeDescriptionCount = static_cast<uint32_t>(vertices.attributeDescriptions.size());
|
||||||
vertices.inputState.pVertexAttributeDescriptions = vertices.attributeDescriptions.data();
|
vertices.inputState.pVertexAttributeDescriptions = vertices.attributeDescriptions.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -705,7 +719,7 @@ public:
|
||||||
VkPipelineDynamicStateCreateInfo dynamicState =
|
VkPipelineDynamicStateCreateInfo dynamicState =
|
||||||
vkTools::initializers::pipelineDynamicStateCreateInfo(
|
vkTools::initializers::pipelineDynamicStateCreateInfo(
|
||||||
dynamicStateEnables.data(),
|
dynamicStateEnables.data(),
|
||||||
dynamicStateEnables.size(),
|
static_cast<uint32_t>(dynamicStateEnables.size()),
|
||||||
0);
|
0);
|
||||||
|
|
||||||
std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages;
|
std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages;
|
||||||
|
|
@ -728,7 +742,7 @@ public:
|
||||||
pipelineCreateInfo.pViewportState = &viewportState;
|
pipelineCreateInfo.pViewportState = &viewportState;
|
||||||
pipelineCreateInfo.pDepthStencilState = &depthStencilState;
|
pipelineCreateInfo.pDepthStencilState = &depthStencilState;
|
||||||
pipelineCreateInfo.pDynamicState = &dynamicState;
|
pipelineCreateInfo.pDynamicState = &dynamicState;
|
||||||
pipelineCreateInfo.stageCount = shaderStages.size();
|
pipelineCreateInfo.stageCount = static_cast<uint32_t>(shaderStages.size());
|
||||||
pipelineCreateInfo.pStages = shaderStages.data();
|
pipelineCreateInfo.pStages = shaderStages.data();
|
||||||
|
|
||||||
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &scene->pipelines.solid));
|
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &scene->pipelines.solid));
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue