Code cleanup

This commit is contained in:
Sascha Willems 2024-01-16 19:32:34 +01:00
parent f211a64153
commit 24591c6570
4 changed files with 108 additions and 112 deletions

View file

@ -128,7 +128,7 @@ public:
// Get device properties for the requested texture format
VkFormatProperties formatProperties;
vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &formatProperties);
// Check if requested image format supports image storage operations required for storing pixesl fromn the compute shader
// Check if requested image format supports image storage operations required for storing pixel from the compute shader
assert(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT);
// Prepare blit target texture

View file

@ -3,6 +3,8 @@
*
* Demonstrates use of descriptor indexing to dynamically index into a variable sized array of images
*
* The sample renders multiple objects with the index of the texture (descriptor) to use passed as a vertex attribute (aka "descriptor indexing")
*
* Relevant code parts are marked with [POI]
*
* Copyright (C) 2021-2023 Sascha Willems - www.saschawillems.de
@ -24,12 +26,12 @@ public:
vks::Buffer indexBuffer;
uint32_t indexCount{ 0 };
vks::Buffer uniformBufferVS;
struct {
struct UniformData {
glm::mat4 projection;
glm::mat4 view;
glm::mat4 model;
} uboVS;
} uniformData;
vks::Buffer uniformBuffer;
VkPipeline pipeline{ VK_NULL_HANDLE };
VkPipelineLayout pipelineLayout{ VK_NULL_HANDLE };
@ -74,15 +76,17 @@ public:
~VulkanExample()
{
for (auto &texture : textures) {
texture.destroy();
if (device) {
for (auto& texture : textures) {
texture.destroy();
}
vkDestroyPipeline(device, pipeline, nullptr);
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
vertexBuffer.destroy();
indexBuffer.destroy();
uniformBuffer.destroy();
}
vkDestroyPipeline(device, pipeline, nullptr);
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
vertexBuffer.destroy();
indexBuffer.destroy();
uniformBufferVS.destroy();
}
// Generate some random textures
@ -106,7 +110,7 @@ public:
}
}
// Generates a line of cubes with randomized per-face texture indices
// Generates a line of cubes with randomized per-face texture indices and uploads them to the GPU
void generateCubes()
{
std::vector<Vertex> vertices;
@ -177,19 +181,27 @@ public:
indexCount = static_cast<uint32_t>(indices.size());
// For the sake of simplicity we won't stage the vertex data to the gpu memory
VK_CHECK_RESULT(vulkanDevice->createBuffer(
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
&vertexBuffer,
vertices.size() * sizeof(Vertex),
vertices.data()));
VK_CHECK_RESULT(vulkanDevice->createBuffer(
VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
&indexBuffer,
indices.size() * sizeof(uint32_t),
indices.data()));
// Create buffers and upload data to the GPU
struct StagingBuffers {
vks::Buffer vertices;
vks::Buffer indices;
} stagingBuffers;
// Host visible source buffers (staging)
VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &stagingBuffers.vertices, vertices.size() * sizeof(Vertex), vertices.data()));
VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &stagingBuffers.indices, indices.size() * sizeof(uint32_t), indices.data()));
// Device local destination buffers
VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &vertexBuffer, vertices.size() * sizeof(Vertex)));
VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &indexBuffer, indices.size() * sizeof(uint32_t)));
// Copy from host do device
vulkanDevice->copyBuffer(&stagingBuffers.vertices, &vertexBuffer, queue);
vulkanDevice->copyBuffer(&stagingBuffers.indices, &indexBuffer, queue);
// Clean up
stagingBuffers.vertices.destroy();
stagingBuffers.indices.destroy();
}
// [POI] Set up descriptor sets and set layout
@ -211,8 +223,7 @@ public:
std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings = {
// Binding 0 : Vertex shader uniform buffer
vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT, 0),
// [POI] Binding 1 contains a texture array that is dynamically non-uniform sampled from
// In the fragment shader:
// [POI] Binding 1 contains a texture array that is dynamically non-uniform sampled from in the fragment shader:
// outFragColor = texture(textures[nonuniformEXT(inTexIndex)], inUV);
vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 1, static_cast<uint32_t>(textures.size()))
};
@ -257,7 +268,7 @@ public:
std::vector<VkWriteDescriptorSet> writeDescriptorSets(2);
writeDescriptorSets[0] = vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBufferVS.descriptor);
writeDescriptorSets[0] = vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffer.descriptor);
// Image descriptors for the texture array
std::vector<VkDescriptorImageInfo> textureDescriptors(textures.size());
@ -284,10 +295,11 @@ public:
void preparePipelines()
{
// Layout
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayout, 1);
VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout));
// Pipeline
VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI = vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0, VK_FALSE);
VkPipelineRasterizationStateCreateInfo rasterizationStateCI = vks::initializers::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, VK_CULL_MODE_NONE, VK_FRONT_FACE_COUNTER_CLOCKWISE, 0);
VkPipelineColorBlendAttachmentState blendAttachmentState = vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE);
@ -335,21 +347,17 @@ public:
void prepareUniformBuffers()
{
VK_CHECK_RESULT(vulkanDevice->createBuffer(
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
&uniformBufferVS,
sizeof(uboVS)));
VK_CHECK_RESULT(uniformBufferVS.map());
VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &uniformBuffer, sizeof(UniformData)));
VK_CHECK_RESULT(uniformBuffer.map());
updateUniformBuffersCamera();
}
void updateUniformBuffersCamera()
{
uboVS.projection = camera.matrices.perspective;
uboVS.view = camera.matrices.view;
uboVS.model = glm::mat4(1.0f);
memcpy(uniformBufferVS.mapped, &uboVS, sizeof(uboVS));
uniformData.projection = camera.matrices.perspective;
uniformData.view = camera.matrices.view;
uniformData.model = glm::mat4(1.0f);
memcpy(uniformBuffer.mapped, &uniformData, sizeof(UniformData));
}
void buildCommandBuffers()
@ -389,15 +397,6 @@ public:
}
}
void draw()
{
VulkanExampleBase::prepareFrame();
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
VulkanExampleBase::submitFrame();
}
void prepare()
{
VulkanExampleBase::prepare();
@ -410,18 +409,21 @@ public:
prepared = true;
}
void draw()
{
VulkanExampleBase::prepareFrame();
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
VulkanExampleBase::submitFrame();
}
virtual void render()
{
if (!prepared)
return;
draw();
if (camera.updated)
updateUniformBuffersCamera();
}
virtual void viewChanged()
{
updateUniformBuffersCamera();
draw();
}
};

View file

@ -1,7 +1,7 @@
/*
* Vulkan Example - Passing vertex attributes using interleaved and separate buffers
*
* Copyright (C) 2022 by Sascha Willems - www.saschawillems.de
* Copyright (C) 2022-2023 by Sascha Willems - www.saschawillems.de
*
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
*/
@ -153,23 +153,25 @@ VulkanExample::VulkanExample() : VulkanExampleBase()
VulkanExample::~VulkanExample()
{
vkDestroyPipeline(device, pipelines.vertexAttributesInterleaved, nullptr);
vkDestroyPipeline(device, pipelines.vertexAttributesSeparate, nullptr);
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.matrices, nullptr);
vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.textures, nullptr);
indices.destroy();
shaderData.buffer.destroy();
separateVertexBuffers.normal.destroy();
separateVertexBuffers.pos.destroy();
separateVertexBuffers.tangent.destroy();
separateVertexBuffers.uv.destroy();
interleavedVertexBuffer.destroy();
for (Image image : scene.images) {
vkDestroyImageView(vulkanDevice->logicalDevice, image.texture.view, nullptr);
vkDestroyImage(vulkanDevice->logicalDevice, image.texture.image, nullptr);
vkDestroySampler(vulkanDevice->logicalDevice, image.texture.sampler, nullptr);
vkFreeMemory(vulkanDevice->logicalDevice, image.texture.deviceMemory, nullptr);
if (device) {
vkDestroyPipeline(device, pipelines.vertexAttributesInterleaved, nullptr);
vkDestroyPipeline(device, pipelines.vertexAttributesSeparate, nullptr);
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.matrices, nullptr);
vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.textures, nullptr);
indices.destroy();
shaderData.buffer.destroy();
separateVertexBuffers.normal.destroy();
separateVertexBuffers.pos.destroy();
separateVertexBuffers.tangent.destroy();
separateVertexBuffers.uv.destroy();
interleavedVertexBuffer.destroy();
for (Image image : scene.images) {
vkDestroyImageView(vulkanDevice->logicalDevice, image.texture.view, nullptr);
vkDestroyImage(vulkanDevice->logicalDevice, image.texture.image, nullptr);
vkDestroySampler(vulkanDevice->logicalDevice, image.texture.sampler, nullptr);
vkFreeMemory(vulkanDevice->logicalDevice, image.texture.deviceMemory, nullptr);
}
}
}
@ -178,6 +180,33 @@ void VulkanExample::getEnabledFeatures()
enabledFeatures.samplerAnisotropy = deviceFeatures.samplerAnisotropy;
}
void VulkanExample::drawSceneNode(VkCommandBuffer commandBuffer, Node node)
{
if (node.mesh.primitives.size() > 0) {
PushConstBlock pushConstBlock;
glm::mat4 nodeMatrix = node.matrix;
Node* currentParent = node.parent;
while (currentParent) {
nodeMatrix = currentParent->matrix * nodeMatrix;
currentParent = currentParent->parent;
}
for (Primitive& primitive : node.mesh.primitives) {
if (primitive.indexCount > 0) {
Material& material = scene.materials[primitive.materialIndex];
pushConstBlock.nodeMatrix = nodeMatrix;
pushConstBlock.alphaMask = (material.alphaMode == "MASK");
pushConstBlock.alphaMaskCutoff = material.alphaCutOff;
vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstBlock), &pushConstBlock);
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 1, 1, &material.descriptorSet, 0, nullptr);
vkCmdDrawIndexed(commandBuffer, primitive.indexCount, 1, primitive.firstIndex, 0, 0);
}
}
}
for (auto& child : node.children) {
drawSceneNode(commandBuffer, child);
}
}
void VulkanExample::buildCommandBuffers()
{
VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();
@ -545,44 +574,10 @@ void VulkanExample::prepare()
prepared = true;
}
void VulkanExample::drawSceneNode(VkCommandBuffer commandBuffer, Node node)
{
if (node.mesh.primitives.size() > 0) {
PushConstBlock pushConstBlock;
glm::mat4 nodeMatrix = node.matrix;
Node* currentParent = node.parent;
while (currentParent) {
nodeMatrix = currentParent->matrix * nodeMatrix;
currentParent = currentParent->parent;
}
for (Primitive& primitive : node.mesh.primitives) {
if (primitive.indexCount > 0) {
Material& material = scene.materials[primitive.materialIndex];
pushConstBlock.nodeMatrix = nodeMatrix;
pushConstBlock.alphaMask = (material.alphaMode == "MASK");
pushConstBlock.alphaMaskCutoff = material.alphaCutOff;
vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstBlock), &pushConstBlock);
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 1, 1, &material.descriptorSet, 0, nullptr);
vkCmdDrawIndexed(commandBuffer, primitive.indexCount, 1, primitive.firstIndex, 0, 0);
}
}
}
for (auto& child : node.children) {
drawSceneNode(commandBuffer, child);
}
}
void VulkanExample::render()
{
renderFrame();
if (camera.updated) {
updateUniformBuffers();
}
}
void VulkanExample::viewChanged()
{
updateUniformBuffers();
renderFrame();
}
void VulkanExample::OnUpdateUIOverlay(vks::UIOverlay* overlay)

View file

@ -1,7 +1,7 @@
/*
* Vulkan Example - Passing vertex attributes using interleaved and separate buffers
*
* Copyright (C) 2022 by Sascha Willems - www.saschawillems.de
*
* Copyright (C) 2022-2023 by Sascha Willems - www.saschawillems.de
*
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
*/
@ -137,6 +137,5 @@ public:
void loadSceneNode(const tinygltf::Node& inputNode, const tinygltf::Model& input, Node* parent);
void drawSceneNode(VkCommandBuffer commandBuffer, Node node);
virtual void render();
virtual void viewChanged();
virtual void OnUpdateUIOverlay(vks::UIOverlay* overlay);
};