diff --git a/samples/15_DrawCube/15_DrawCube.cpp b/samples/15_DrawCube/15_DrawCube.cpp index 7a2e5c2..1dab518 100644 --- a/samples/15_DrawCube/15_DrawCube.cpp +++ b/samples/15_DrawCube/15_DrawCube.cpp @@ -79,7 +79,7 @@ int main(int /*argc*/, char ** /*argv*/) vk::su::updateDescriptorSets(device, descriptorSets[0], vk::DescriptorType::eUniformBuffer, &descriptorBufferInfo); vk::UniquePipelineCache pipelineCache = device->createPipelineCacheUnique(vk::PipelineCacheCreateInfo()); - vk::UniquePipeline graphicsPipeline = vk::su::createGraphicsPipeline(device, pipelineCache, vertexShaderModule, fragmentShaderModule, sizeof(coloredCubeData[0]), true, pipelineLayout, renderPass); + vk::UniquePipeline graphicsPipeline = vk::su::createGraphicsPipeline(device, pipelineCache, vertexShaderModule, fragmentShaderModule, sizeof(coloredCubeData[0]), true, false, pipelineLayout, renderPass); /* VULKAN_KEY_START */ diff --git a/samples/DrawTexturedCube/DrawTexturedCube.cpp b/samples/DrawTexturedCube/DrawTexturedCube.cpp index 420daea..402d1dd 100644 --- a/samples/DrawTexturedCube/DrawTexturedCube.cpp +++ b/samples/DrawTexturedCube/DrawTexturedCube.cpp @@ -87,7 +87,7 @@ int main(int /*argc*/, char ** /*argv*/) vk::su::updateDescriptorSets(device, descriptorSets[0], vk::DescriptorType::eUniformBuffer, &bufferInfo, &imageInfo); vk::UniquePipelineCache pipelineCache = device->createPipelineCacheUnique(vk::PipelineCacheCreateInfo()); - vk::UniquePipeline graphicsPipeline = vk::su::createGraphicsPipeline(device, pipelineCache, vertexShaderModule, fragmentShaderModule, sizeof(texturedCubeData[0]), true, pipelineLayout, renderPass); + vk::UniquePipeline graphicsPipeline = vk::su::createGraphicsPipeline(device, pipelineCache, vertexShaderModule, fragmentShaderModule, sizeof(texturedCubeData[0]), true, true, pipelineLayout, renderPass); /* VULKAN_KEY_START */ diff --git a/samples/DynamicUniform/DynamicUniform.cpp b/samples/DynamicUniform/DynamicUniform.cpp index 777659c..c456ae4 100644 --- a/samples/DynamicUniform/DynamicUniform.cpp +++ b/samples/DynamicUniform/DynamicUniform.cpp @@ -107,7 +107,7 @@ int main(int /*argc*/, char ** /*argv*/) vk::su::updateDescriptorSets(device, descriptorSets[0], vk::DescriptorType::eUniformBufferDynamic, &descriptorBufferInfo); vk::UniquePipelineCache pipelineCache = device->createPipelineCacheUnique(vk::PipelineCacheCreateInfo()); - vk::UniquePipeline graphicsPipeline = vk::su::createGraphicsPipeline(device, pipelineCache, vertexShaderModule, fragmentShaderModule, sizeof(coloredCubeData[0]), true, pipelineLayout, renderPass); + vk::UniquePipeline graphicsPipeline = vk::su::createGraphicsPipeline(device, pipelineCache, vertexShaderModule, fragmentShaderModule, sizeof(coloredCubeData[0]), true, false, pipelineLayout, renderPass); // Get the index of the next available swapchain image: vk::UniqueSemaphore imageAcquiredSemaphore = device->createSemaphoreUnique(vk::SemaphoreCreateInfo()); diff --git a/samples/EnumerateDevicesAdvanced/EnumerateDevicesAdvanced.cpp b/samples/EnumerateDevicesAdvanced/EnumerateDevicesAdvanced.cpp index e3aa089..0050ea9 100644 --- a/samples/EnumerateDevicesAdvanced/EnumerateDevicesAdvanced.cpp +++ b/samples/EnumerateDevicesAdvanced/EnumerateDevicesAdvanced.cpp @@ -23,18 +23,6 @@ static char const* AppName = "EnumerateDevicesAdvanced"; static char const* EngineName = "Vulkan.hpp"; -void print_UUID(uint8_t *pipelineCacheUUID) -{ - for (int j = 0; j < VK_UUID_SIZE; ++j) - { - std::cout << std::setw(2) << (uint32_t)pipelineCacheUUID[j]; - if (j == 3 || j == 5 || j == 7 || j == 9) - { - std::cout << '-'; - } - } -} - int main(int /*argc*/, char ** /*argv*/) { try @@ -70,12 +58,7 @@ int main(int /*argc*/, char ** /*argv*/) std::cout << "deviceName: " << properties.deviceName << '\n'; - std::cout << "pipelineCacheUUID: "; - std::cout << std::setfill('0') << std::hex; - print_UUID(properties.pipelineCacheUUID); - std::cout << std::setfill(' ') << std::dec; - std::cout << '\n'; - std::cout << '\n'; + std::cout << "pipelineCacheUUID: " << vk::su::UUID(properties.pipelineCacheUUID) << "\n\n"; } /* VULKAN_HPP_KEY_END */ diff --git a/samples/ImmutableSampler/ImmutableSampler.cpp b/samples/ImmutableSampler/ImmutableSampler.cpp index ca50e0d..fd0f68a 100644 --- a/samples/ImmutableSampler/ImmutableSampler.cpp +++ b/samples/ImmutableSampler/ImmutableSampler.cpp @@ -109,7 +109,7 @@ int main(int /*argc*/, char ** /*argv*/) /* VULKAN_KEY_END */ vk::UniquePipelineCache pipelineCache = device->createPipelineCacheUnique(vk::PipelineCacheCreateInfo()); - vk::UniquePipeline graphicsPipeline = vk::su::createGraphicsPipeline(device, pipelineCache, vertexShaderModule, fragmentShaderModule, sizeof(texturedCubeData[0]), true, pipelineLayout, renderPass); + vk::UniquePipeline graphicsPipeline = vk::su::createGraphicsPipeline(device, pipelineCache, vertexShaderModule, fragmentShaderModule, sizeof(texturedCubeData[0]), true, true, pipelineLayout, renderPass); vk::UniqueSemaphore imageAcquiredSemaphore = device->createSemaphoreUnique(vk::SemaphoreCreateInfo()); vk::ResultValue currentBuffer = device->acquireNextImageKHR(swapChainData.swapChain.get(), vk::su::FenceTimeout, imageAcquiredSemaphore.get(), nullptr); diff --git a/samples/InputAttachment/InputAttachment.cpp b/samples/InputAttachment/InputAttachment.cpp index 609aaa0..546e0cc 100644 --- a/samples/InputAttachment/InputAttachment.cpp +++ b/samples/InputAttachment/InputAttachment.cpp @@ -155,7 +155,7 @@ int main(int /*argc*/, char ** /*argv*/) device->updateDescriptorSets(vk::ArrayProxy(1, &writeDescriptorSet), nullptr); vk::UniquePipelineCache pipelineCache = device->createPipelineCacheUnique(vk::PipelineCacheCreateInfo()); - vk::UniquePipeline graphicsPipeline = vk::su::createGraphicsPipeline(device, pipelineCache, vertexShaderModule, fragmentShaderModule, 0, false, pipelineLayout, renderPass); + vk::UniquePipeline graphicsPipeline = vk::su::createGraphicsPipeline(device, pipelineCache, vertexShaderModule, fragmentShaderModule, 0, false, false, pipelineLayout, renderPass); vk::UniqueSemaphore imageAcquiredSemaphore = device->createSemaphoreUnique(vk::SemaphoreCreateInfo()); diff --git a/samples/MultipleSets/MultipleSets.cpp b/samples/MultipleSets/MultipleSets.cpp index 1df7b66..c908694 100644 --- a/samples/MultipleSets/MultipleSets.cpp +++ b/samples/MultipleSets/MultipleSets.cpp @@ -93,34 +93,6 @@ void main() } )"; -class MonochromeTextureGenerator -{ -public: - MonochromeTextureGenerator(std::array const& rgb_) - : rgb(rgb_) - {} - - void operator()(void* data, vk::Extent2D &extent) const - { - // fill in with the monochrome color - unsigned char *pImageMemory = static_cast(data); - for (uint32_t row = 0; row < extent.height; row++) - { - for (uint32_t col = 0; col < extent.width; col++) - { - pImageMemory[0] = rgb[0]; - pImageMemory[1] = rgb[1]; - pImageMemory[2] = rgb[2]; - pImageMemory[3] = 255; - pImageMemory += 4; - } - } - } - -private: - std::array const& rgb; -}; - int main(int /*argc*/, char ** /*argv*/) { try @@ -152,7 +124,7 @@ int main(int /*argc*/, char ** /*argv*/) vk::su::TextureData textureData(physicalDevices[0], device); commandBuffers[0]->begin(vk::CommandBufferBeginInfo()); - textureData.setTexture(device, commandBuffers[0], MonochromeTextureGenerator({ 118, 185, 0 })); + textureData.setTexture(device, commandBuffers[0], vk::su::MonochromeTextureGenerator({ 118, 185, 0 })); vk::su::BufferData uniformBufferData(physicalDevices[0], device, sizeof(glm::mat4x4), vk::BufferUsageFlagBits::eUniformBuffer); vk::su::copyToDevice(device, uniformBufferData.deviceMemory, vk::su::createModelViewProjectionClipMatrix(surfaceData.extent)); @@ -207,7 +179,7 @@ int main(int /*argc*/, char ** /*argv*/) /* VULKAN_KEY_END */ vk::UniquePipelineCache pipelineCache = device->createPipelineCacheUnique(vk::PipelineCacheCreateInfo()); - vk::UniquePipeline graphicsPipeline = vk::su::createGraphicsPipeline(device, pipelineCache, vertexShaderModule, fragmentShaderModule, sizeof(texturedCubeData[0]), true, pipelineLayout, renderPass); + vk::UniquePipeline graphicsPipeline = vk::su::createGraphicsPipeline(device, pipelineCache, vertexShaderModule, fragmentShaderModule, sizeof(texturedCubeData[0]), true, true, pipelineLayout, renderPass); // Get the index of the next available swapchain image: vk::UniqueSemaphore imageAcquiredSemaphore = device->createSemaphoreUnique(vk::SemaphoreCreateInfo()); diff --git a/samples/OcclusionQuery/CMakeLists.txt b/samples/OcclusionQuery/CMakeLists.txt new file mode 100644 index 0000000..adbdd0d --- /dev/null +++ b/samples/OcclusionQuery/CMakeLists.txt @@ -0,0 +1,44 @@ +# Copyright(c) 2019, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.2) + +project(OcclusionQuery) + +set(HEADERS + ../utils/geometries.hpp + ../utils/math.hpp + ../utils/shaders.hpp + ../utils/utils.hpp +) + +set(SOURCES + OcclusionQuery.cpp + ../utils/math.cpp + ../utils/shaders.cpp + ../utils/utils.cpp + ../../glslang/StandAlone/ResourceLimits.cpp +) + +source_group(headers FILES ${HEADERS}) +source_group(sources FILES ${SOURCES}) + +add_executable(OcclusionQuery + ${HEADERS} + ${SOURCES} +) + +set_target_properties(OcclusionQuery PROPERTIES FOLDER "Samples") +target_include_directories(OcclusionQuery PUBLIC ${CMAKE_SOURCE_DIR}/glslang) +target_link_libraries(OcclusionQuery PUBLIC glslang SPIRV "${Vulkan_LIBRARIES}") diff --git a/samples/OcclusionQuery/OcclusionQuery.cpp b/samples/OcclusionQuery/OcclusionQuery.cpp new file mode 100644 index 0000000..c939bc4 --- /dev/null +++ b/samples/OcclusionQuery/OcclusionQuery.cpp @@ -0,0 +1,189 @@ +// Copyright(c) 2019, NVIDIA CORPORATION. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// VulkanHpp Samples : OcclusionQuery +// Use occlusion query to determine if drawing renders any samples. + +#include "../utils/geometries.hpp" +#include "../utils/math.hpp" +#include "../utils/shaders.hpp" +#include "../utils/utils.hpp" +#include "vulkan/vulkan.hpp" +#include "SPIRV/GlslangToSpv.h" +#include + +static char const* AppName = "OcclusionQuery"; +static char const* EngineName = "Vulkan.hpp"; + +int main(int /*argc*/, char ** /*argv*/) +{ + try + { + vk::UniqueInstance instance = vk::su::createInstance(AppName, EngineName, vk::su::getInstanceExtensions()); +#if !defined(NDEBUG) + vk::UniqueDebugReportCallbackEXT debugReportCallback = vk::su::createDebugReportCallback(instance); +#endif + + std::vector physicalDevices = instance->enumeratePhysicalDevices(); + assert(!physicalDevices.empty()); + + vk::su::SurfaceData surfaceData(instance, AppName, AppName, vk::Extent2D(500, 500)); + + std::pair graphicsAndPresentQueueFamilyIndex = vk::su::findGraphicsAndPresentQueueFamilyIndex(physicalDevices[0], surfaceData.surface); + vk::UniqueDevice device = vk::su::createDevice(physicalDevices[0], graphicsAndPresentQueueFamilyIndex.first, vk::su::getDeviceExtensions()); + + vk::UniqueCommandPool commandPool = vk::su::createCommandPool(device, graphicsAndPresentQueueFamilyIndex.first); + std::vector commandBuffers = device->allocateCommandBuffersUnique(vk::CommandBufferAllocateInfo(commandPool.get(), vk::CommandBufferLevel::ePrimary, 1)); + + vk::Queue graphicsQueue = device->getQueue(graphicsAndPresentQueueFamilyIndex.first, 0); + vk::Queue presentQueue = device->getQueue(graphicsAndPresentQueueFamilyIndex.second, 0); + + vk::su::SwapChainData swapChainData(physicalDevices[0], device, surfaceData.surface, surfaceData.extent, vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferSrc + , graphicsAndPresentQueueFamilyIndex.first, graphicsAndPresentQueueFamilyIndex.second); + + vk::su::DepthBufferData depthBufferData(physicalDevices[0], device, vk::Format::eD16Unorm, surfaceData.extent); + + vk::su::BufferData uniformBufferData(physicalDevices[0], device, sizeof(glm::mat4x4), vk::BufferUsageFlagBits::eUniformBuffer); + vk::su::copyToDevice(device, uniformBufferData.deviceMemory, vk::su::createModelViewProjectionClipMatrix(surfaceData.extent)); + + vk::UniqueDescriptorSetLayout descriptorSetLayout = vk::su::createDescriptorSetLayout(device); + vk::UniquePipelineLayout pipelineLayout = device->createPipelineLayoutUnique(vk::PipelineLayoutCreateInfo(vk::PipelineLayoutCreateFlags(), 1, &descriptorSetLayout.get())); + + vk::UniqueRenderPass renderPass = vk::su::createRenderPass(device, vk::su::pickColorFormat(physicalDevices[0].getSurfaceFormatsKHR(surfaceData.surface.get())), depthBufferData.format); + + glslang::InitializeProcess(); + vk::UniqueShaderModule vertexShaderModule = vk::su::createShaderModule(device, vk::ShaderStageFlagBits::eVertex, vertexShaderText_PC_C); + vk::UniqueShaderModule fragmentShaderModule = vk::su::createShaderModule(device, vk::ShaderStageFlagBits::eFragment, fragmentShaderText_C_C); + glslang::FinalizeProcess(); + + std::vector framebuffers = vk::su::createFramebuffers(device, renderPass, swapChainData.imageViews, depthBufferData.imageView, surfaceData.extent); + + vk::su::BufferData vertexBufferData(physicalDevices[0], device, sizeof(coloredCubeData), vk::BufferUsageFlagBits::eVertexBuffer); + vk::su::copyToDevice(device, vertexBufferData.deviceMemory, coloredCubeData, sizeof(coloredCubeData) / sizeof(coloredCubeData[0])); + + vk::UniqueDescriptorPool descriptorPool = vk::su::createDescriptorPool(device); + std::vector descriptorSets = device->allocateDescriptorSetsUnique(vk::DescriptorSetAllocateInfo(descriptorPool.get(), 1, &descriptorSetLayout.get())); + + vk::DescriptorBufferInfo descriptorBufferInfo(uniformBufferData.buffer.get(), 0, sizeof(glm::mat4x4)); + vk::su::updateDescriptorSets(device, descriptorSets[0], vk::DescriptorType::eUniformBuffer, &descriptorBufferInfo); + + vk::UniquePipelineCache pipelineCache = device->createPipelineCacheUnique(vk::PipelineCacheCreateInfo()); + vk::UniquePipeline graphicsPipeline = vk::su::createGraphicsPipeline(device, pipelineCache, vertexShaderModule, fragmentShaderModule, sizeof(coloredCubeData[0]), true, false, pipelineLayout, renderPass); + + /* VULKAN_KEY_START */ + + vk::UniqueSemaphore imageAcquiredSemaphore = device->createSemaphoreUnique(vk::SemaphoreCreateInfo(vk::SemaphoreCreateFlags())); + + // Get the index of the next available swapchain image: + vk::ResultValue currentBuffer = device->acquireNextImageKHR(swapChainData.swapChain.get(), UINT64_MAX, imageAcquiredSemaphore.get(), nullptr); + assert(currentBuffer.result == vk::Result::eSuccess); + assert(currentBuffer.value < framebuffers.size()); + + /* Allocate a uniform buffer that will take query results. */ + vk::UniqueBuffer queryResultBuffer = device->createBufferUnique(vk::BufferCreateInfo(vk::BufferCreateFlags(), 4 * sizeof(uint64_t), vk::BufferUsageFlagBits::eUniformBuffer | vk::BufferUsageFlagBits::eTransferDst)); + + vk::MemoryRequirements memoryRequirements = device->getBufferMemoryRequirements(queryResultBuffer.get()); + uint32_t memoryTypeIndex = vk::su::findMemoryType(physicalDevices[0].getMemoryProperties(), memoryRequirements.memoryTypeBits, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent); + vk::UniqueDeviceMemory queryResultMemory = device->allocateMemoryUnique(vk::MemoryAllocateInfo(memoryRequirements.size, memoryTypeIndex)); + + device->bindBufferMemory(queryResultBuffer.get(), queryResultMemory.get(), 0); + + vk::UniqueQueryPool queryPool = device->createQueryPoolUnique(vk::QueryPoolCreateInfo(vk::QueryPoolCreateFlags(), vk::QueryType::eOcclusion, 2, vk::QueryPipelineStatisticFlags())); + + commandBuffers[0]->begin(vk::CommandBufferBeginInfo(vk::CommandBufferUsageFlags())); + commandBuffers[0]->resetQueryPool(queryPool.get(), 0, 2); + + vk::ClearValue clearValues[2]; + clearValues[0].color = vk::ClearColorValue(std::array({ 0.2f, 0.2f, 0.2f, 0.2f })); + clearValues[1].depthStencil = vk::ClearDepthStencilValue(1.0f, 0); + commandBuffers[0]->beginRenderPass(vk::RenderPassBeginInfo(renderPass.get(), framebuffers[currentBuffer.value].get(), vk::Rect2D(vk::Offset2D(), surfaceData.extent), 2, clearValues), vk::SubpassContents::eInline); + + commandBuffers[0]->bindPipeline(vk::PipelineBindPoint::eGraphics, graphicsPipeline.get()); + commandBuffers[0]->bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout.get(), 0, descriptorSets[0].get(), {}); + + VkDeviceSize offset = 0; + commandBuffers[0]->bindVertexBuffers(0, vertexBufferData.buffer.get(), offset); + + vk::Viewport viewport(0.0f, 0.0f, static_cast(surfaceData.extent.width), static_cast(surfaceData.extent.height), 0.0f, 1.0f); + commandBuffers[0]->setViewport(0, viewport); + + vk::Rect2D scissor(vk::Offset2D(0, 0), surfaceData.extent); + commandBuffers[0]->setScissor(0, scissor); + + commandBuffers[0]->beginQuery(queryPool.get(), 0, vk::QueryControlFlags()); + commandBuffers[0]->endQuery(queryPool.get(), 0); + + commandBuffers[0]->beginQuery(queryPool.get(), 1, vk::QueryControlFlags()); + commandBuffers[0]->draw(12 * 3, 1, 0, 0); + commandBuffers[0]->endRenderPass(); + commandBuffers[0]->endQuery(queryPool.get(), 1); + + commandBuffers[0]->copyQueryPoolResults(queryPool.get(), 0, 2, queryResultBuffer.get(), 0, sizeof(uint64_t), vk::QueryResultFlagBits::e64 | vk::QueryResultFlagBits::eWait); + commandBuffers[0]->end(); + + vk::UniqueFence drawFence = device->createFenceUnique(vk::FenceCreateInfo()); + + vk::PipelineStageFlags waitDestinationStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput); + vk::SubmitInfo submitInfo(1, &imageAcquiredSemaphore.get(), &waitDestinationStageMask, 1, &commandBuffers[0].get()); + graphicsQueue.submit(submitInfo, drawFence.get()); + + graphicsQueue.waitIdle(); + + uint64_t samplesPassed[2]; + device->getQueryPoolResults(queryPool.get(), 0, 2, vk::ArrayProxy(4, samplesPassed), sizeof(uint64_t), vk::QueryResultFlagBits::e64 | vk::QueryResultFlagBits::eWait); + + std::cout << "vkGetQueryPoolResults data\n"; + std::cout << "samples_passed[0] = " << samplesPassed[0] << "\n"; + std::cout << "samples_passed[1] = " << samplesPassed[1] << "\n"; + + /* Read back query result from buffer */ + uint64_t *samplesPassedPtr = static_cast(device->mapMemory(queryResultMemory.get(), 0, memoryRequirements.size, vk::MemoryMapFlags())); + + std::cout << "vkCmdCopyQueryPoolResults data\n"; + std::cout << "samples_passed[0] = " << samplesPassedPtr[0] << "\n"; + std::cout << "samples_passed[1] = " << samplesPassedPtr[1] << "\n"; + + device->unmapMemory(queryResultMemory.get()); + + while (vk::Result::eTimeout == device->waitForFences(drawFence.get(), VK_TRUE, vk::su::FenceTimeout)) + ; + + presentQueue.presentKHR(vk::PresentInfoKHR(0, nullptr, 1, &swapChainData.swapChain.get(), ¤tBuffer.value)); + Sleep(1000); + + /* VULKAN_KEY_END */ + +#if defined(VK_USE_PLATFORM_WIN32_KHR) + DestroyWindow(surfaceData.window); +#else +#pragma error "unhandled platform" +#endif + } + catch (vk::SystemError err) + { + std::cout << "vk::SystemError: " << err.what() << std::endl; + exit(-1); + } + catch (std::runtime_error err) + { + std::cout << "std::runtime_error: " << err.what() << std::endl; + exit(-1); + } + catch (...) + { + std::cout << "unknown error\n"; + exit(-1); + } + return 0; +} diff --git a/samples/PipelineCache/CMakeLists.txt b/samples/PipelineCache/CMakeLists.txt new file mode 100644 index 0000000..d80eb92 --- /dev/null +++ b/samples/PipelineCache/CMakeLists.txt @@ -0,0 +1,44 @@ +# Copyright(c) 2019, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.2) + +project(PipelineCache) + +set(HEADERS + ../utils/geometries.hpp + ../utils/math.hpp + ../utils/shaders.hpp + ../utils/utils.hpp +) + +set(SOURCES + PipelineCache.cpp + ../utils/math.cpp + ../utils/shaders.cpp + ../utils/utils.cpp + ../../glslang/StandAlone/ResourceLimits.cpp +) + +source_group(headers FILES ${HEADERS}) +source_group(sources FILES ${SOURCES}) + +add_executable(PipelineCache + ${HEADERS} + ${SOURCES} +) + +set_target_properties(PipelineCache PROPERTIES FOLDER "Samples") +target_include_directories(PipelineCache PUBLIC ${CMAKE_SOURCE_DIR}/glslang) +target_link_libraries(PipelineCache PUBLIC glslang SPIRV "${Vulkan_LIBRARIES}") diff --git a/samples/PipelineCache/PipelineCache.cpp b/samples/PipelineCache/PipelineCache.cpp new file mode 100644 index 0000000..2faf669 --- /dev/null +++ b/samples/PipelineCache/PipelineCache.cpp @@ -0,0 +1,347 @@ +// Copyright(c) 2019, NVIDIA CORPORATION. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// VulkanHpp Samples : PipelineCache +// This sample tries to save and reuse pipeline cache data between runs. + +#include "../utils/geometries.hpp" +#include "../utils/math.hpp" +#include "../utils/shaders.hpp" +#include "../utils/utils.hpp" +#include "vulkan/vulkan.hpp" +#include "SPIRV/GlslangToSpv.h" +#include +#include + +// For timestamp code (getMilliseconds) +#ifdef WIN32 +#include +#else +#include +#endif + +typedef unsigned long long timestamp_t; +timestamp_t getMilliseconds() +{ +#ifdef WIN32 + LARGE_INTEGER frequency; + BOOL useQPC = QueryPerformanceFrequency(&frequency); + if (useQPC) + { + LARGE_INTEGER now; + QueryPerformanceCounter(&now); + return (1000LL * now.QuadPart) / frequency.QuadPart; + } + else + { + return GetTickCount(); + } +#else + struct timeval now; + gettimeofday(&now, NULL); + return (now.tv_usec / 1000) + (timestamp_t)now.tv_sec; +#endif +} + + +static char const* AppName = "PipelineCache"; +static char const* EngineName = "Vulkan.hpp"; + +int main(int /*argc*/, char ** /*argv*/) +{ + try + { + vk::UniqueInstance instance = vk::su::createInstance(AppName, EngineName, vk::su::getInstanceExtensions()); +#if !defined(NDEBUG) + vk::UniqueDebugReportCallbackEXT debugReportCallback = vk::su::createDebugReportCallback(instance); +#endif + + std::vector physicalDevices = instance->enumeratePhysicalDevices(); + vk::PhysicalDeviceProperties properties = physicalDevices[0].getProperties(); + assert(!physicalDevices.empty()); + + vk::su::SurfaceData surfaceData(instance, AppName, AppName, vk::Extent2D(500, 500)); + + std::pair graphicsAndPresentQueueFamilyIndex = vk::su::findGraphicsAndPresentQueueFamilyIndex(physicalDevices[0], surfaceData.surface); + vk::UniqueDevice device = vk::su::createDevice(physicalDevices[0], graphicsAndPresentQueueFamilyIndex.first, vk::su::getDeviceExtensions()); + + vk::UniqueCommandPool commandPool = vk::su::createCommandPool(device, graphicsAndPresentQueueFamilyIndex.first); + std::vector commandBuffers = device->allocateCommandBuffersUnique(vk::CommandBufferAllocateInfo(commandPool.get(), vk::CommandBufferLevel::ePrimary, 1)); + + vk::Queue graphicsQueue = device->getQueue(graphicsAndPresentQueueFamilyIndex.first, 0); + vk::Queue presentQueue = device->getQueue(graphicsAndPresentQueueFamilyIndex.second, 0); + + vk::su::SwapChainData swapChainData(physicalDevices[0], device, surfaceData.surface, surfaceData.extent, vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferSrc + , graphicsAndPresentQueueFamilyIndex.first, graphicsAndPresentQueueFamilyIndex.second); + + vk::su::DepthBufferData depthBufferData(physicalDevices[0], device, vk::Format::eD16Unorm, surfaceData.extent); + + vk::su::TextureData textureData(physicalDevices[0], device); + commandBuffers[0]->begin(vk::CommandBufferBeginInfo()); + textureData.setTexture(device, commandBuffers[0], vk::su::MonochromeTextureGenerator({ 118, 185, 0 })); + + vk::su::BufferData uniformBufferData(physicalDevices[0], device, sizeof(glm::mat4x4), vk::BufferUsageFlagBits::eUniformBuffer); + vk::su::copyToDevice(device, uniformBufferData.deviceMemory, vk::su::createModelViewProjectionClipMatrix(surfaceData.extent)); + + vk::UniqueDescriptorSetLayout descriptorSetLayout = vk::su::createDescriptorSetLayout(device, vk::DescriptorType::eUniformBuffer, true); + vk::UniquePipelineLayout pipelineLayout = device->createPipelineLayoutUnique(vk::PipelineLayoutCreateInfo(vk::PipelineLayoutCreateFlags(), 1, &descriptorSetLayout.get())); + + vk::UniqueRenderPass renderPass = vk::su::createRenderPass(device, vk::su::pickColorFormat(physicalDevices[0].getSurfaceFormatsKHR(surfaceData.surface.get())), depthBufferData.format); + + glslang::InitializeProcess(); + vk::UniqueShaderModule vertexShaderModule = vk::su::createShaderModule(device, vk::ShaderStageFlagBits::eVertex, vertexShaderText_PT_T); + vk::UniqueShaderModule fragmentShaderModule = vk::su::createShaderModule(device, vk::ShaderStageFlagBits::eFragment, fragmentShaderText_T_C); + glslang::FinalizeProcess(); + + std::vector framebuffers = vk::su::createFramebuffers(device, renderPass, swapChainData.imageViews, depthBufferData.imageView, surfaceData.extent); + + vk::su::BufferData vertexBufferData(physicalDevices[0], device, sizeof(texturedCubeData), vk::BufferUsageFlagBits::eVertexBuffer); + vk::su::copyToDevice(device, vertexBufferData.deviceMemory, texturedCubeData, sizeof(texturedCubeData) / sizeof(texturedCubeData[0])); + + vk::UniqueDescriptorPool descriptorPool = vk::su::createDescriptorPool(device, vk::DescriptorType::eUniformBuffer, true); + std::vector descriptorSets = device->allocateDescriptorSetsUnique(vk::DescriptorSetAllocateInfo(descriptorPool.get(), 1, &descriptorSetLayout.get())); + + vk::DescriptorBufferInfo descriptorBufferInfo(uniformBufferData.buffer.get(), 0, sizeof(glm::mat4x4)); + vk::DescriptorImageInfo imageInfo(textureData.textureSampler.get(), textureData.imageData->imageView.get(), vk::ImageLayout::eShaderReadOnlyOptimal); + vk::su::updateDescriptorSets(device, descriptorSets[0], vk::DescriptorType::eUniformBuffer, &descriptorBufferInfo, &imageInfo); + + /* VULKAN_KEY_START */ + + // Check disk for existing cache data + size_t startCacheSize = 0; + char *startCacheData = nullptr; + + std::string cacheFileName = "pipeline_cache_data.bin"; + std::ifstream readCacheStream(cacheFileName, std::ios_base::in | std::ios_base::binary); + if (readCacheStream.good()) + { + // Determine cache size + readCacheStream.seekg(0, readCacheStream.end); + startCacheSize = readCacheStream.tellg(); + readCacheStream.seekg(0, readCacheStream.beg); + + // Allocate memory to hold the initial cache data + startCacheData = new char[startCacheSize]; + + // Read the data into our buffer + readCacheStream.read(startCacheData, startCacheSize); + + // Clean up and print results + readCacheStream.close(); + std::cout << " Pipeline cache HIT!\n"; + std::cout << " cacheData loaded from " << cacheFileName << "\n"; + } + else + { + // No cache found on disk + std::cout << " Pipeline cache miss!\n"; + } + + if (startCacheData != nullptr) + { + // Check for cache validity + // + // TODO: Update this as the spec evolves. The fields are not defined by the header. + // + // The code below supports SDK 0.10 Vulkan spec, which contains the following table: + // + // Offset Size Meaning + // ------ ------------ ------------------------------------------------------------------ + // 0 4 a device ID equal to VkPhysicalDeviceProperties::DeviceId written + // as a stream of bytes, with the least significant byte first + // + // 4 VK_UUID_SIZE a pipeline cache ID equal to VkPhysicalDeviceProperties::pipelineCacheUUID + // + // + // The code must be updated for latest Vulkan spec, which contains the following table: + // + // Offset Size Meaning + // ------ ------------ ------------------------------------------------------------------ + // 0 4 length in bytes of the entire pipeline cache header written as a + // stream of bytes, with the least significant byte first + // 4 4 a VkPipelineCacheHeaderVersion value written as a stream of bytes, + // with the least significant byte first + // 8 4 a vendor ID equal to VkPhysicalDeviceProperties::vendorID written + // as a stream of bytes, with the least significant byte first + // 12 4 a device ID equal to VkPhysicalDeviceProperties::deviceID written + // as a stream of bytes, with the least significant byte first + // 16 VK_UUID_SIZE a pipeline cache ID equal to VkPhysicalDeviceProperties::pipelineCacheUUID + + uint32_t headerLength = 0; + uint32_t cacheHeaderVersion = 0; + uint32_t vendorID = 0; + uint32_t deviceID = 0; + uint8_t pipelineCacheUUID[VK_UUID_SIZE] = {}; + + memcpy(&headerLength, (uint8_t *)startCacheData + 0, 4); + memcpy(&cacheHeaderVersion, (uint8_t *)startCacheData + 4, 4); + memcpy(&vendorID, (uint8_t *)startCacheData + 8, 4); + memcpy(&deviceID, (uint8_t *)startCacheData + 12, 4); + memcpy(pipelineCacheUUID, (uint8_t *)startCacheData + 16, VK_UUID_SIZE); + + // Check each field and report bad values before freeing existing cache + bool badCache = false; + + if (headerLength <= 0) + { + badCache = true; + std::cout << " Bad header length in " << cacheFileName << ".\n"; + std::cout << " Cache contains: " << std::hex << std::setw(8) << headerLength << "\n"; + } + + if (cacheHeaderVersion != VK_PIPELINE_CACHE_HEADER_VERSION_ONE) + { + badCache = true; + std::cout << " Unsupported cache header version in " << cacheFileName << ".\n"; + std::cout << " Cache contains: " << std::hex << std::setw(8) << cacheHeaderVersion << "\n"; + } + + if (vendorID != properties.vendorID) + { + badCache = true; + std::cout << " Vender ID mismatch in " << cacheFileName << ".\n"; + std::cout << " Cache contains: " << std::hex << std::setw(8) << vendorID << "\n"; + std::cout << " Driver expects: " << std::hex << std::setw(8) << properties.vendorID << "\n"; + } + + if (deviceID != properties.deviceID) + { + badCache = true; + std::cout << " Device ID mismatch in " << cacheFileName << ".\n"; + std::cout << " Cache contains: " << std::hex << std::setw(8) << deviceID << "\n"; + std::cout << " Driver expects: " << std::hex << std::setw(8) << properties.deviceID << "\n"; + } + + if (memcmp(pipelineCacheUUID, properties.pipelineCacheUUID, sizeof(pipelineCacheUUID)) != 0) + { + badCache = true; + std::cout << " UUID mismatch in " << cacheFileName << ".\n"; + std::cout << " Cache contains: " << vk::su::UUID(pipelineCacheUUID) << "\n"; + std::cout << " Driver expects: " << vk::su::UUID(properties.pipelineCacheUUID) << "\n"; + } + + if (badCache) + { + // Don't submit initial cache data if any version info is incorrect + free(startCacheData); + startCacheSize = 0; + startCacheData = nullptr; + + // And clear out the old cache file for use in next run + std::cout << " Deleting cache entry " << cacheFileName << " to repopulate.\n"; + if (remove(cacheFileName.c_str()) != 0) + { + std::cerr << "Reading error"; + exit(EXIT_FAILURE); + } + } + } + + // Feed the initial cache data into cache creation + vk::UniquePipelineCache pipelineCache = device->createPipelineCacheUnique(vk::PipelineCacheCreateInfo(vk::PipelineCacheCreateFlags(), startCacheSize, startCacheData)); + + // Free our initialData now that pipeline cache has been created + free(startCacheData); + startCacheData = NULL; + + // Time (roughly) taken to create the graphics pipeline + timestamp_t start = getMilliseconds(); + vk::UniquePipeline graphicsPipeline = vk::su::createGraphicsPipeline(device, pipelineCache, vertexShaderModule, fragmentShaderModule, sizeof(texturedCubeData[0]), true, true, pipelineLayout, renderPass); + timestamp_t elapsed = getMilliseconds() - start; + std::cout << " vkCreateGraphicsPipeline time: " << (double)elapsed << " ms\n"; + + vk::UniqueSemaphore imageAcquiredSemaphore = device->createSemaphoreUnique(vk::SemaphoreCreateInfo(vk::SemaphoreCreateFlags())); + + // Get the index of the next available swapchain image: + vk::ResultValue currentBuffer = device->acquireNextImageKHR(swapChainData.swapChain.get(), UINT64_MAX, imageAcquiredSemaphore.get(), nullptr); + assert(currentBuffer.result == vk::Result::eSuccess); + assert(currentBuffer.value < framebuffers.size()); + + vk::ClearValue clearValues[2]; + clearValues[0].color = vk::ClearColorValue(std::array({ 0.2f, 0.2f, 0.2f, 0.2f })); + clearValues[1].depthStencil = vk::ClearDepthStencilValue(1.0f, 0); + + commandBuffers[0]->beginRenderPass(vk::RenderPassBeginInfo(renderPass.get(), framebuffers[currentBuffer.value].get(), vk::Rect2D(vk::Offset2D(), surfaceData.extent), 2, clearValues), vk::SubpassContents::eInline); + commandBuffers[0]->bindPipeline(vk::PipelineBindPoint::eGraphics, graphicsPipeline.get()); + commandBuffers[0]->bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout.get(), 0, descriptorSets[0].get(), {}); + + VkDeviceSize offset = 0; + commandBuffers[0]->bindVertexBuffers(0, vertexBufferData.buffer.get(), offset); + + vk::Viewport viewport(0.0f, 0.0f, static_cast(surfaceData.extent.width), static_cast(surfaceData.extent.height), 0.0f, 1.0f); + commandBuffers[0]->setViewport(0, viewport); + + vk::Rect2D scissor(vk::Offset2D(0, 0), surfaceData.extent); + commandBuffers[0]->setScissor(0, scissor); + + commandBuffers[0]->draw(12 * 3, 1, 0, 0); + commandBuffers[0]->endRenderPass(); + commandBuffers[0]->end(); + + vk::UniqueFence drawFence = device->createFenceUnique(vk::FenceCreateInfo()); + + vk::PipelineStageFlags waitDestinationStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput); + vk::SubmitInfo submitInfo(1, &imageAcquiredSemaphore.get(), &waitDestinationStageMask, 1, &commandBuffers[0].get()); + graphicsQueue.submit(submitInfo, drawFence.get()); + + while (vk::Result::eTimeout == device->waitForFences(drawFence.get(), VK_TRUE, vk::su::FenceTimeout)) + ; + + presentQueue.presentKHR(vk::PresentInfoKHR(0, nullptr, 1, &swapChainData.swapChain.get(), ¤tBuffer.value)); + Sleep(1000); + + // Store away the cache that we've populated. This could conceivably happen + // earlier, depends on when the pipeline cache stops being populated + // internally. + std::vector endCacheData = device->getPipelineCacheData(pipelineCache.get()); + + // Write the file to disk, overwriting whatever was there + std::ofstream writeCacheStream(cacheFileName, std::ios_base::out | std::ios_base::binary); + if (writeCacheStream.good()) + { + writeCacheStream.write(reinterpret_cast(endCacheData.data()), endCacheData.size()); + writeCacheStream.close(); + std::cout << " cacheData written to " << cacheFileName << "\n"; + } + else + { + // Something bad happened + std::cout << " Unable to write cache data to disk!\n"; + } + + /* VULKAN_KEY_END */ + +#if defined(VK_USE_PLATFORM_WIN32_KHR) + DestroyWindow(surfaceData.window); +#else +#pragma error "unhandled platform" +#endif + } + catch (vk::SystemError err) + { + std::cout << "vk::SystemError: " << err.what() << std::endl; + exit(-1); + } + catch (std::runtime_error err) + { + std::cout << "std::runtime_error: " << err.what() << std::endl; + exit(-1); + } + catch (...) + { + std::cout << "unknown error\n"; + exit(-1); + } + return 0; +} diff --git a/samples/PipelineDerivative/CMakeLists.txt b/samples/PipelineDerivative/CMakeLists.txt new file mode 100644 index 0000000..0efbee9 --- /dev/null +++ b/samples/PipelineDerivative/CMakeLists.txt @@ -0,0 +1,44 @@ +# Copyright(c) 2019, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.2) + +project(PipelineDerivative) + +set(HEADERS + ../utils/geometries.hpp + ../utils/math.hpp + ../utils/shaders.hpp + ../utils/utils.hpp +) + +set(SOURCES + PipelineDerivative.cpp + ../utils/math.cpp + ../utils/shaders.cpp + ../utils/utils.cpp + ../../glslang/StandAlone/ResourceLimits.cpp +) + +source_group(headers FILES ${HEADERS}) +source_group(sources FILES ${SOURCES}) + +add_executable(PipelineDerivative + ${HEADERS} + ${SOURCES} +) + +set_target_properties(PipelineDerivative PROPERTIES FOLDER "Samples") +target_include_directories(PipelineDerivative PUBLIC ${CMAKE_SOURCE_DIR}/glslang) +target_link_libraries(PipelineDerivative PUBLIC glslang SPIRV "${Vulkan_LIBRARIES}") diff --git a/samples/PipelineDerivative/PipelineDerivative.cpp b/samples/PipelineDerivative/PipelineDerivative.cpp new file mode 100644 index 0000000..6be5dc5 --- /dev/null +++ b/samples/PipelineDerivative/PipelineDerivative.cpp @@ -0,0 +1,256 @@ +// Copyright(c) 2019, NVIDIA CORPORATION. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// VulkanHpp Samples : PipelineDerivative +// This sample creates pipeline derivative and draws with it. + +#include "../utils/geometries.hpp" +#include "../utils/math.hpp" +#include "../utils/shaders.hpp" +#include "../utils/utils.hpp" +#include "vulkan/vulkan.hpp" +#include "SPIRV/GlslangToSpv.h" + +// For timestamp code (getMilliseconds) +#ifdef WIN32 +#include +#else +#include +#endif + +typedef unsigned long long timestamp_t; +timestamp_t getMilliseconds() +{ +#ifdef WIN32 + LARGE_INTEGER frequency; + BOOL useQPC = QueryPerformanceFrequency(&frequency); + if (useQPC) + { + LARGE_INTEGER now; + QueryPerformanceCounter(&now); + return (1000LL * now.QuadPart) / frequency.QuadPart; + } + else + { + return GetTickCount(); + } +#else + struct timeval now; + gettimeofday(&now, NULL); + return (now.tv_usec / 1000) + (timestamp_t)now.tv_sec; +#endif +} + + +static char const* AppName = "PipelineDerivative"; +static char const* EngineName = "Vulkan.hpp"; + +int main(int /*argc*/, char ** /*argv*/) +{ + try + { + vk::UniqueInstance instance = vk::su::createInstance(AppName, EngineName, vk::su::getInstanceExtensions()); +#if !defined(NDEBUG) + vk::UniqueDebugReportCallbackEXT debugReportCallback = vk::su::createDebugReportCallback(instance); +#endif + + std::vector physicalDevices = instance->enumeratePhysicalDevices(); + assert(!physicalDevices.empty()); + + vk::su::SurfaceData surfaceData(instance, AppName, AppName, vk::Extent2D(500, 500)); + + std::pair graphicsAndPresentQueueFamilyIndex = vk::su::findGraphicsAndPresentQueueFamilyIndex(physicalDevices[0], surfaceData.surface); + vk::UniqueDevice device = vk::su::createDevice(physicalDevices[0], graphicsAndPresentQueueFamilyIndex.first, vk::su::getDeviceExtensions()); + + vk::UniqueCommandPool commandPool = vk::su::createCommandPool(device, graphicsAndPresentQueueFamilyIndex.first); + std::vector commandBuffers = device->allocateCommandBuffersUnique(vk::CommandBufferAllocateInfo(commandPool.get(), vk::CommandBufferLevel::ePrimary, 1)); + + vk::Queue graphicsQueue = device->getQueue(graphicsAndPresentQueueFamilyIndex.first, 0); + vk::Queue presentQueue = device->getQueue(graphicsAndPresentQueueFamilyIndex.second, 0); + + vk::su::SwapChainData swapChainData(physicalDevices[0], device, surfaceData.surface, surfaceData.extent, vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferSrc + , graphicsAndPresentQueueFamilyIndex.first, graphicsAndPresentQueueFamilyIndex.second); + + vk::su::DepthBufferData depthBufferData(physicalDevices[0], device, vk::Format::eD16Unorm, surfaceData.extent); + + vk::su::TextureData textureData(physicalDevices[0], device); + commandBuffers[0]->begin(vk::CommandBufferBeginInfo()); + textureData.setTexture(device, commandBuffers[0], vk::su::CheckerboardTextureCreator()); + + vk::su::BufferData uniformBufferData(physicalDevices[0], device, sizeof(glm::mat4x4), vk::BufferUsageFlagBits::eUniformBuffer); + vk::su::copyToDevice(device, uniformBufferData.deviceMemory, vk::su::createModelViewProjectionClipMatrix(surfaceData.extent)); + + vk::UniqueDescriptorSetLayout descriptorSetLayout = vk::su::createDescriptorSetLayout(device, vk::DescriptorType::eUniformBuffer, true); + vk::UniquePipelineLayout pipelineLayout = device->createPipelineLayoutUnique(vk::PipelineLayoutCreateInfo(vk::PipelineLayoutCreateFlags(), 1, &descriptorSetLayout.get())); + + vk::UniqueRenderPass renderPass = vk::su::createRenderPass(device, vk::su::pickColorFormat(physicalDevices[0].getSurfaceFormatsKHR(surfaceData.surface.get())), depthBufferData.format); + + glslang::InitializeProcess(); + vk::UniqueShaderModule vertexShaderModule = vk::su::createShaderModule(device, vk::ShaderStageFlagBits::eVertex, vertexShaderText_PT_T); + vk::UniqueShaderModule fragmentShaderModule = vk::su::createShaderModule(device, vk::ShaderStageFlagBits::eFragment, fragmentShaderText_T_C); + glslang::FinalizeProcess(); + + std::vector framebuffers = vk::su::createFramebuffers(device, renderPass, swapChainData.imageViews, depthBufferData.imageView, surfaceData.extent); + + vk::su::BufferData vertexBufferData(physicalDevices[0], device, sizeof(texturedCubeData), vk::BufferUsageFlagBits::eVertexBuffer); + vk::su::copyToDevice(device, vertexBufferData.deviceMemory, texturedCubeData, sizeof(texturedCubeData) / sizeof(texturedCubeData[0])); + + vk::UniqueDescriptorPool descriptorPool = vk::su::createDescriptorPool(device, vk::DescriptorType::eUniformBuffer, true); + std::vector descriptorSets = device->allocateDescriptorSetsUnique(vk::DescriptorSetAllocateInfo(descriptorPool.get(), 1, &descriptorSetLayout.get())); + + vk::DescriptorBufferInfo bufferInfo(uniformBufferData.buffer.get(), 0, sizeof(glm::mat4x4)); + vk::DescriptorImageInfo imageInfo(textureData.textureSampler.get(), textureData.imageData->imageView.get(), vk::ImageLayout::eShaderReadOnlyOptimal); + vk::su::updateDescriptorSets(device, descriptorSets[0], vk::DescriptorType::eUniformBuffer, &bufferInfo, &imageInfo); + + vk::UniquePipelineCache pipelineCache = device->createPipelineCacheUnique(vk::PipelineCacheCreateInfo()); + + /* VULKAN_KEY_START */ + + // Create two pipelines. + // + // First pipeline has VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT set. + // Second pipeline has a modified fragment shader and sets the VK_PIPELINE_CREATE_DERIVATIVE_BIT flag. + + vk::PipelineShaderStageCreateInfo pipelineShaderStageCreateInfos[2] = + { + vk::PipelineShaderStageCreateInfo(vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eVertex, vertexShaderModule.get(), "main"), + vk::PipelineShaderStageCreateInfo(vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eFragment, fragmentShaderModule.get(), "main") + }; + + vk::VertexInputBindingDescription vertexInputBindingDescription(0, sizeof(texturedCubeData[0])); + vk::VertexInputAttributeDescription vertexInputAttributeDescriptions[2] = + { + vk::VertexInputAttributeDescription(0, 0, vk::Format::eR32G32B32A32Sfloat, 0), + vk::VertexInputAttributeDescription(1, 0, vk::Format::eR32G32B32A32Sfloat, 16) + }; + vk::PipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo(vk::PipelineVertexInputStateCreateFlags(), 1, &vertexInputBindingDescription, 2, vertexInputAttributeDescriptions); + + vk::PipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateCreateInfo(vk::PipelineInputAssemblyStateCreateFlags(), vk::PrimitiveTopology::eTriangleList); + + vk::PipelineViewportStateCreateInfo pipelineViewportStateCreateInfo(vk::PipelineViewportStateCreateFlags(), 1, nullptr, 1, nullptr); + + vk::PipelineRasterizationStateCreateInfo pipelineRasterizationStateCreateInfo(vk::PipelineRasterizationStateCreateFlags(), false, false, vk::PolygonMode::eFill, vk::CullModeFlagBits::eBack, vk::FrontFace::eClockwise, false, 0.0f, 0.0f, 0.0f, 1.0f); + + vk::PipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo; + + vk::StencilOpState stencilOpState(vk::StencilOp::eKeep, vk::StencilOp::eKeep, vk::StencilOp::eKeep, vk::CompareOp::eAlways); + vk::PipelineDepthStencilStateCreateInfo pipelineDepthStencilStateCreateInfo(vk::PipelineDepthStencilStateCreateFlags(), true, true, vk::CompareOp::eLessOrEqual, false, false, stencilOpState, stencilOpState); + + vk::ColorComponentFlags colorComponentFlags(vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA); + vk::PipelineColorBlendAttachmentState pipelineColorBlendAttachmentState(false, vk::BlendFactor::eZero, vk::BlendFactor::eZero, vk::BlendOp::eAdd, vk::BlendFactor::eZero, vk::BlendFactor::eZero, vk::BlendOp::eAdd, colorComponentFlags); + vk::PipelineColorBlendStateCreateInfo pipelineColorBlendStateCreateInfo(vk::PipelineColorBlendStateCreateFlags(), false, vk::LogicOp::eNoOp, 1, &pipelineColorBlendAttachmentState, { { (1.0f, 1.0f, 1.0f, 1.0f) } }); + + vk::DynamicState dynamicStates[2] = { vk::DynamicState::eViewport, vk::DynamicState::eScissor }; + vk::PipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo(vk::PipelineDynamicStateCreateFlags(), 2, dynamicStates); + + vk::GraphicsPipelineCreateInfo graphicsPipelineCreateInfo(vk::PipelineCreateFlagBits::eAllowDerivatives, 2, pipelineShaderStageCreateInfos, &pipelineVertexInputStateCreateInfo, + &pipelineInputAssemblyStateCreateInfo, nullptr, &pipelineViewportStateCreateInfo, &pipelineRasterizationStateCreateInfo, &pipelineMultisampleStateCreateInfo, + &pipelineDepthStencilStateCreateInfo, &pipelineColorBlendStateCreateInfo, &pipelineDynamicStateCreateInfo, pipelineLayout.get(), renderPass.get()); + + vk::UniquePipeline basePipeline = device->createGraphicsPipelineUnique(pipelineCache.get(), graphicsPipelineCreateInfo); + + // Now create the derivative pipeline, using a different fragment shader + // This shader will shade the cube faces with interpolated colors + const std::string fragmentShaderText_T_C_2 = R"( +#version 450 + +layout (location = 0) in vec2 inTexCoord; + +layout (location = 0) out vec4 outColor; + +void main() +{ + outColor = vec4(inTexCoord.x, inTexCoord.y, 1.0f - inTexCoord.x - inTexCoord.y, 1.0f); +} +)"; + + // Convert GLSL to SPIR-V + glslang::InitializeProcess(); + vk::UniqueShaderModule fragmentShaderModule2 = vk::su::createShaderModule(device, vk::ShaderStageFlagBits::eFragment, fragmentShaderText_T_C_2); + glslang::FinalizeProcess(); + + // Modify pipeline info to reflect derivation + pipelineShaderStageCreateInfos[1] = vk::PipelineShaderStageCreateInfo(vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eFragment, fragmentShaderModule2.get(), "main"); + graphicsPipelineCreateInfo.flags = vk::PipelineCreateFlagBits::eDerivative; + graphicsPipelineCreateInfo.basePipelineHandle = basePipeline.get(); + graphicsPipelineCreateInfo.basePipelineIndex = -1; + + // And create the derived pipeline + vk::UniquePipeline derivedPipeline = device->createGraphicsPipelineUnique(pipelineCache.get(), graphicsPipelineCreateInfo); + + /* VULKAN_KEY_END */ + + vk::UniqueSemaphore imageAcquiredSemaphore = device->createSemaphoreUnique(vk::SemaphoreCreateInfo(vk::SemaphoreCreateFlags())); + + // Get the index of the next available swapchain image + vk::ResultValue currentBuffer = device->acquireNextImageKHR(swapChainData.swapChain.get(), UINT64_MAX, imageAcquiredSemaphore.get(), nullptr); + assert(currentBuffer.result == vk::Result::eSuccess); + assert(currentBuffer.value < framebuffers.size()); + + vk::ClearValue clearValues[2]; + clearValues[0].color = vk::ClearColorValue(std::array({ 0.2f, 0.2f, 0.2f, 0.2f })); + clearValues[1].depthStencil = vk::ClearDepthStencilValue(1.0f, 0); + + commandBuffers[0]->beginRenderPass(vk::RenderPassBeginInfo(renderPass.get(), framebuffers[currentBuffer.value].get(), vk::Rect2D(vk::Offset2D(), surfaceData.extent), 2, clearValues), vk::SubpassContents::eInline); + commandBuffers[0]->bindPipeline(vk::PipelineBindPoint::eGraphics, derivedPipeline.get()); + commandBuffers[0]->bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout.get(), 0, descriptorSets[0].get(), {}); + + VkDeviceSize offset = 0; + commandBuffers[0]->bindVertexBuffers(0, vertexBufferData.buffer.get(), offset); + + vk::Viewport viewport(0.0f, 0.0f, static_cast(surfaceData.extent.width), static_cast(surfaceData.extent.height), 0.0f, 1.0f); + commandBuffers[0]->setViewport(0, viewport); + + vk::Rect2D scissor(vk::Offset2D(0, 0), surfaceData.extent); + commandBuffers[0]->setScissor(0, scissor); + + commandBuffers[0]->draw(12 * 3, 1, 0, 0); + commandBuffers[0]->endRenderPass(); + commandBuffers[0]->end(); + + vk::UniqueFence drawFence = device->createFenceUnique(vk::FenceCreateInfo()); + + vk::PipelineStageFlags waitDestinationStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput); + vk::SubmitInfo submitInfo(1, &imageAcquiredSemaphore.get(), &waitDestinationStageMask, 1, &commandBuffers[0].get()); + graphicsQueue.submit(submitInfo, drawFence.get()); + + while (vk::Result::eTimeout == device->waitForFences(drawFence.get(), VK_TRUE, vk::su::FenceTimeout)) + ; + + presentQueue.presentKHR(vk::PresentInfoKHR(0, nullptr, 1, &swapChainData.swapChain.get(), ¤tBuffer.value)); + Sleep(1000); + +#if defined(VK_USE_PLATFORM_WIN32_KHR) + DestroyWindow(surfaceData.window); +#else +#pragma error "unhandled platform" +#endif + } + catch (vk::SystemError err) + { + std::cout << "vk::SystemError: " << err.what() << std::endl; + exit(-1); + } + catch (std::runtime_error err) + { + std::cout << "std::runtime_error: " << err.what() << std::endl; + exit(-1); + } + catch (...) + { + std::cout << "unknown error\n"; + exit(-1); + } + return 0; +} diff --git a/samples/PushConstants/CMakeLists.txt b/samples/PushConstants/CMakeLists.txt new file mode 100644 index 0000000..1cce82e --- /dev/null +++ b/samples/PushConstants/CMakeLists.txt @@ -0,0 +1,44 @@ +# Copyright(c) 2019, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.2) + +project(PushConstants) + +set(HEADERS + ../utils/geometries.hpp + ../utils/math.hpp + ../utils/shaders.hpp + ../utils/utils.hpp +) + +set(SOURCES + PushConstants.cpp + ../utils/math.cpp + ../utils/shaders.cpp + ../utils/utils.cpp + ../../glslang/StandAlone/ResourceLimits.cpp +) + +source_group(headers FILES ${HEADERS}) +source_group(sources FILES ${SOURCES}) + +add_executable(PushConstants + ${HEADERS} + ${SOURCES} +) + +set_target_properties(PushConstants PROPERTIES FOLDER "Samples") +target_include_directories(PushConstants PUBLIC ${CMAKE_SOURCE_DIR}/glslang) +target_link_libraries(PushConstants PUBLIC glslang SPIRV "${Vulkan_LIBRARIES}") diff --git a/samples/PushConstants/PushConstants.cpp b/samples/PushConstants/PushConstants.cpp new file mode 100644 index 0000000..fea497b --- /dev/null +++ b/samples/PushConstants/PushConstants.cpp @@ -0,0 +1,212 @@ +// Copyright(c) 2019, NVIDIA CORPORATION. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// VulkanHpp Samples : PushConstants +// Use push constants in a simple shader, validate the correct value was read. + +#include "../utils/geometries.hpp" +#include "../utils/math.hpp" +#include "../utils/shaders.hpp" +#include "../utils/utils.hpp" +#include "vulkan/vulkan.hpp" +#include "SPIRV/GlslangToSpv.h" +#include + +static char const* AppName = "PushConstants"; +static char const* EngineName = "Vulkan.hpp"; + +const std::string fragmentShaderText = R"( +#version 400 + +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +layout (push_constant) uniform pushBlock +{ + int iFoo; + float fBar; +} pushConstantsBlock; + +layout (location = 0) in vec2 inTexCoords; + +layout (location = 0) out vec4 outColor; + +void main() +{ + vec4 green = vec4(0.0f, 1.0f, 0.0f, 1.0f); + vec4 red = vec4(1.0f, 0.0f, 0.0f, 1.0f); + + // Start with passing color + vec4 resColor = green; + + // See if we've read in the correct push constants + if ((pushConstantsBlock.iFoo != 2) || (pushConstantsBlock.fBar != 1.0f)) + { + resColor = red; + } + + // Create a border to see the cube more easily + if ((inTexCoords.x < 0.01f) || (0.99f < inTexCoords.x) + || (inTexCoords.y < 0.01f) || (0.99f < inTexCoords.y)) + { + resColor *= vec4(0.1f, 0.1f, 0.1f, 1.0f); + } + + outColor = resColor; +} +)"; + +int main(int /*argc*/, char ** /*argv*/) +{ + try + { + vk::UniqueInstance instance = vk::su::createInstance(AppName, EngineName, vk::su::getInstanceExtensions()); +#if !defined(NDEBUG) + vk::UniqueDebugReportCallbackEXT debugReportCallback = vk::su::createDebugReportCallback(instance); +#endif + + std::vector physicalDevices = instance->enumeratePhysicalDevices(); + assert(!physicalDevices.empty()); + + vk::su::SurfaceData surfaceData(instance, AppName, AppName, vk::Extent2D(500, 500)); + + std::pair graphicsAndPresentQueueFamilyIndex = vk::su::findGraphicsAndPresentQueueFamilyIndex(physicalDevices[0], surfaceData.surface); + vk::UniqueDevice device = vk::su::createDevice(physicalDevices[0], graphicsAndPresentQueueFamilyIndex.first, vk::su::getDeviceExtensions()); + + vk::UniqueCommandPool commandPool = vk::su::createCommandPool(device, graphicsAndPresentQueueFamilyIndex.first); + std::vector commandBuffers = device->allocateCommandBuffersUnique(vk::CommandBufferAllocateInfo(commandPool.get(), vk::CommandBufferLevel::ePrimary, 1)); + + vk::Queue graphicsQueue = device->getQueue(graphicsAndPresentQueueFamilyIndex.first, 0); + vk::Queue presentQueue = device->getQueue(graphicsAndPresentQueueFamilyIndex.second, 0); + + vk::su::SwapChainData swapChainData(physicalDevices[0], device, surfaceData.surface, surfaceData.extent, vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferSrc + , graphicsAndPresentQueueFamilyIndex.first, graphicsAndPresentQueueFamilyIndex.second); + + vk::su::DepthBufferData depthBufferData(physicalDevices[0], device, vk::Format::eD16Unorm, surfaceData.extent); + + vk::su::BufferData uniformBufferData(physicalDevices[0], device, sizeof(glm::mat4x4), vk::BufferUsageFlagBits::eUniformBuffer); + vk::su::copyToDevice(device, uniformBufferData.deviceMemory, vk::su::createModelViewProjectionClipMatrix(surfaceData.extent)); + + vk::UniqueRenderPass renderPass = vk::su::createRenderPass(device, vk::su::pickColorFormat(physicalDevices[0].getSurfaceFormatsKHR(surfaceData.surface.get())), depthBufferData.format); + + glslang::InitializeProcess(); + vk::UniqueShaderModule vertexShaderModule = vk::su::createShaderModule(device, vk::ShaderStageFlagBits::eVertex, vertexShaderText_PT_T); + vk::UniqueShaderModule fragmentShaderModule = vk::su::createShaderModule(device, vk::ShaderStageFlagBits::eFragment, fragmentShaderText); + glslang::FinalizeProcess(); + + std::vector framebuffers = vk::su::createFramebuffers(device, renderPass, swapChainData.imageViews, depthBufferData.imageView, surfaceData.extent); + + vk::su::BufferData vertexBufferData(physicalDevices[0], device, sizeof(texturedCubeData), vk::BufferUsageFlagBits::eVertexBuffer); + vk::su::copyToDevice(device, vertexBufferData.deviceMemory, texturedCubeData, sizeof(texturedCubeData) / sizeof(texturedCubeData[0])); + + // Create binding and layout for the following, matching contents of shader + // binding 0 = uniform buffer (MVP) + vk::UniqueDescriptorSetLayout descriptorSetLayout = vk::su::createDescriptorSetLayout(device, vk::DescriptorType::eUniformBuffer, false /*!*/); + + /* VULKAN_KEY_START */ + + // Set up our push constant range, which mirrors the declaration of + vk::PushConstantRange pushConstantRanges(vk::ShaderStageFlagBits::eFragment, 0, 8); + vk::UniquePipelineLayout pipelineLayout = device->createPipelineLayoutUnique(vk::PipelineLayoutCreateInfo(vk::PipelineLayoutCreateFlags(), 1, &descriptorSetLayout.get(), 1, &pushConstantRanges)); + + // Create a single pool to contain data for our descriptor set + vk::DescriptorPoolSize poolSizes[2] = + { + vk::DescriptorPoolSize(vk::DescriptorType::eUniformBuffer, 1), + vk::DescriptorPoolSize(vk::DescriptorType::eCombinedImageSampler, 1) + }; + vk::UniqueDescriptorPool descriptorPool = device->createDescriptorPoolUnique(vk::DescriptorPoolCreateInfo(vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet, 1, 2, poolSizes)); + + // Populate descriptor sets + std::vector descriptorSets = device->allocateDescriptorSetsUnique(vk::DescriptorSetAllocateInfo(descriptorPool.get(), 1, &descriptorSetLayout.get())); + + // Populate with info about our uniform buffer for MVP + vk::DescriptorBufferInfo bufferInfo(uniformBufferData.buffer.get(), 0, sizeof(glm::mat4x4)); + device->updateDescriptorSets(vk::WriteDescriptorSet(*descriptorSets[0], 0, 0, 1, vk::DescriptorType::eUniformBuffer, nullptr, &bufferInfo), {}); + + // Create our push constant data, which matches shader expectations + std::array pushConstants = { (unsigned)2, (unsigned)0x3F800000 }; + + // Ensure we have enough room for push constant data + assert((sizeof(pushConstants) <= physicalDevices[0].getProperties().limits.maxPushConstantsSize) && "Too many push constants"); + commandBuffers[0]->begin(vk::CommandBufferBeginInfo()); + commandBuffers[0]->pushConstants(pipelineLayout.get(), vk::ShaderStageFlagBits::eFragment, 0, pushConstants); + + /* VULKAN_KEY_END */ + + vk::UniquePipelineCache pipelineCache = device->createPipelineCacheUnique(vk::PipelineCacheCreateInfo()); + vk::UniquePipeline graphicsPipeline = vk::su::createGraphicsPipeline(device, pipelineCache, vertexShaderModule, fragmentShaderModule, sizeof(texturedCubeData[0]), true, false, pipelineLayout, renderPass); + + vk::UniqueSemaphore imageAcquiredSemaphore = device->createSemaphoreUnique(vk::SemaphoreCreateInfo()); + vk::ResultValue currentBuffer = device->acquireNextImageKHR(swapChainData.swapChain.get(), vk::su::FenceTimeout, imageAcquiredSemaphore.get(), nullptr); + assert(currentBuffer.result == vk::Result::eSuccess); + assert(currentBuffer.value < framebuffers.size()); + + vk::ClearValue clearValues[2]; + clearValues[0].color = vk::ClearColorValue(std::array({ 0.2f, 0.2f, 0.2f, 0.2f })); + clearValues[1].depthStencil = vk::ClearDepthStencilValue(1.0f, 0); + + vk::RenderPassBeginInfo renderPassBeginInfo(renderPass.get(), framebuffers[currentBuffer.value].get(), vk::Rect2D(vk::Offset2D(0, 0), surfaceData.extent), 2, clearValues); + commandBuffers[0]->beginRenderPass(renderPassBeginInfo, vk::SubpassContents::eInline); + commandBuffers[0]->bindPipeline(vk::PipelineBindPoint::eGraphics, graphicsPipeline.get()); + commandBuffers[0]->bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout.get(), 0, descriptorSets[0].get(), nullptr); + + vk::DeviceSize offset = 0; + commandBuffers[0]->bindVertexBuffers(0, vertexBufferData.buffer.get(), offset); + + vk::Viewport viewport(0.0f, 0.0f, static_cast(surfaceData.extent.width), static_cast(surfaceData.extent.height), 0.0f, 1.0f); + commandBuffers[0]->setViewport(0, viewport); + + vk::Rect2D scissor(vk::Offset2D(0, 0), surfaceData.extent); + commandBuffers[0]->setScissor(0, scissor); + + commandBuffers[0]->draw(12 * 3, 1, 0, 0); + commandBuffers[0]->endRenderPass(); + commandBuffers[0]->end(); + + vk::UniqueFence drawFence = device->createFenceUnique(vk::FenceCreateInfo()); + + vk::PipelineStageFlags waitDestinationStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput); + vk::SubmitInfo submitInfo(1, &imageAcquiredSemaphore.get(), &waitDestinationStageMask, 1, &commandBuffers[0].get()); + graphicsQueue.submit(submitInfo, drawFence.get()); + + while (vk::Result::eTimeout == device->waitForFences(drawFence.get(), VK_TRUE, vk::su::FenceTimeout)) + ; + + presentQueue.presentKHR(vk::PresentInfoKHR(0, nullptr, 1, &swapChainData.swapChain.get(), ¤tBuffer.value)); + Sleep(1000); + +#if defined(VK_USE_PLATFORM_WIN32_KHR) + DestroyWindow(surfaceData.window); +#else +#pragma error "unhandled platform" +#endif + } + catch (vk::SystemError err) + { + std::cout << "vk::SystemError: " << err.what() << std::endl; + exit(-1); + } + catch (std::runtime_error err) + { + std::cout << "std::runtime_error: " << err.what() << std::endl; + exit(-1); + } + catch (...) + { + std::cout << "unknown error\n"; + exit(-1); + } + return 0; +} diff --git a/samples/PushDescriptors/CMakeLists.txt b/samples/PushDescriptors/CMakeLists.txt new file mode 100644 index 0000000..5dedb5f --- /dev/null +++ b/samples/PushDescriptors/CMakeLists.txt @@ -0,0 +1,44 @@ +# Copyright(c) 2019, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.2) + +project(PushDescriptors) + +set(HEADERS + ../utils/geometries.hpp + ../utils/math.hpp + ../utils/shaders.hpp + ../utils/utils.hpp +) + +set(SOURCES + PushDescriptors.cpp + ../utils/math.cpp + ../utils/shaders.cpp + ../utils/utils.cpp + ../../glslang/StandAlone/ResourceLimits.cpp +) + +source_group(headers FILES ${HEADERS}) +source_group(sources FILES ${SOURCES}) + +add_executable(PushDescriptors + ${HEADERS} + ${SOURCES} +) + +set_target_properties(PushDescriptors PROPERTIES FOLDER "Samples") +target_include_directories(PushDescriptors PUBLIC ${CMAKE_SOURCE_DIR}/glslang) +target_link_libraries(PushDescriptors PUBLIC glslang SPIRV "${Vulkan_LIBRARIES}") diff --git a/samples/PushDescriptors/PushDescriptors.cpp b/samples/PushDescriptors/PushDescriptors.cpp new file mode 100644 index 0000000..354eb59 --- /dev/null +++ b/samples/PushDescriptors/PushDescriptors.cpp @@ -0,0 +1,183 @@ +// Copyright(c) 2019, NVIDIA CORPORATION. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// VulkanHpp Samples : PushDescriptors +// Use Push Descriptors to Draw Textured Cube + +#include "../utils/geometries.hpp" +#include "../utils/math.hpp" +#include "../utils/shaders.hpp" +#include "../utils/utils.hpp" +#include "vulkan/vulkan.hpp" +#include "SPIRV/GlslangToSpv.h" +#include + +static char const* AppName = "PushDescriptors"; +static char const* EngineName = "Vulkan.hpp"; + +int main(int /*argc*/, char ** /*argv*/) +{ + try + { + /* VULKAN_KEY_START */ + + // To use PUSH_DESCRIPTOR, you must also specify GET_PHYSICAL_DEVICE_PROPERTIES_2 + std::vector extensionProperties = vk::enumerateInstanceExtensionProperties(); + if (std::find_if(extensionProperties.begin(), extensionProperties.end(), [](auto ep) { return (strcmp(ep.extensionName,VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) == 0); }) == extensionProperties.end()) + { + std::cout << "No GET_PHYSICAL_DEVICE_PROPERTIES_2 extension" << std::endl; + return 0; + } + + std::vector instanceExtensions = vk::su::getInstanceExtensions(); + instanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + + bool textured = true; + + vk::UniqueInstance instance = vk::su::createInstance(AppName, EngineName, instanceExtensions); +#if !defined(NDEBUG) + vk::UniqueDebugReportCallbackEXT debugReportCallback = vk::su::createDebugReportCallback(instance); +#endif + + std::vector physicalDevices = instance->enumeratePhysicalDevices(); + assert(!physicalDevices.empty()); + + // Once instance is created, need to make sure the extension is available + extensionProperties = physicalDevices[0].enumerateDeviceExtensionProperties(); + if (std::find_if(extensionProperties.begin(), extensionProperties.end(), [](auto ep) { return (strcmp(ep.extensionName,VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME) == 0); }) == extensionProperties.end()) + { + std::cout << "No extension for push descriptors" << std::endl; + return 0; + } + + std::vector deviceExtensions = vk::su::getDeviceExtensions(); + deviceExtensions.push_back(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME); + + vk::su::SurfaceData surfaceData(instance, AppName, AppName, vk::Extent2D(500, 500)); + + std::pair graphicsAndPresentQueueFamilyIndex = vk::su::findGraphicsAndPresentQueueFamilyIndex(physicalDevices[0], surfaceData.surface); + vk::UniqueDevice device = vk::su::createDevice(physicalDevices[0], graphicsAndPresentQueueFamilyIndex.first, deviceExtensions); + + vk::UniqueCommandPool commandPool = vk::su::createCommandPool(device, graphicsAndPresentQueueFamilyIndex.first); + std::vector commandBuffers = device->allocateCommandBuffersUnique(vk::CommandBufferAllocateInfo(commandPool.get(), vk::CommandBufferLevel::ePrimary, 1)); + + vk::Queue graphicsQueue = device->getQueue(graphicsAndPresentQueueFamilyIndex.first, 0); + vk::Queue presentQueue = device->getQueue(graphicsAndPresentQueueFamilyIndex.second, 0); + + vk::su::SwapChainData swapChainData(physicalDevices[0], device, surfaceData.surface, surfaceData.extent, vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferSrc + , graphicsAndPresentQueueFamilyIndex.first, graphicsAndPresentQueueFamilyIndex.second); + + vk::su::DepthBufferData depthBufferData(physicalDevices[0], device, vk::Format::eD16Unorm, surfaceData.extent); + + vk::su::TextureData textureData(physicalDevices[0], device); + commandBuffers[0]->begin(vk::CommandBufferBeginInfo()); + textureData.setTexture(device, commandBuffers[0], vk::su::CheckerboardTextureCreator()); + + vk::su::BufferData uniformBufferData(physicalDevices[0], device, sizeof(glm::mat4x4), vk::BufferUsageFlagBits::eUniformBuffer); + vk::su::copyToDevice(device, uniformBufferData.deviceMemory, vk::su::createModelViewProjectionClipMatrix(surfaceData.extent)); + + // Need to specify that descriptor set layout will be for push descriptors + vk::UniqueDescriptorSetLayout descriptorSetLayout = vk::su::createDescriptorSetLayout(device, vk::DescriptorType::eUniformBuffer, textured, vk::DescriptorSetLayoutCreateFlagBits::ePushDescriptorKHR); + vk::UniquePipelineLayout pipelineLayout = device->createPipelineLayoutUnique(vk::PipelineLayoutCreateInfo(vk::PipelineLayoutCreateFlags(), 1, &descriptorSetLayout.get())); + + vk::UniqueRenderPass renderPass = vk::su::createRenderPass(device, vk::su::pickColorFormat(physicalDevices[0].getSurfaceFormatsKHR(surfaceData.surface.get())), depthBufferData.format); + + glslang::InitializeProcess(); + vk::UniqueShaderModule vertexShaderModule = vk::su::createShaderModule(device, vk::ShaderStageFlagBits::eVertex, vertexShaderText_PT_T); + vk::UniqueShaderModule fragmentShaderModule = vk::su::createShaderModule(device, vk::ShaderStageFlagBits::eFragment, fragmentShaderText_T_C); + glslang::FinalizeProcess(); + + std::vector framebuffers = vk::su::createFramebuffers(device, renderPass, swapChainData.imageViews, depthBufferData.imageView, surfaceData.extent); + + vk::su::BufferData vertexBufferData(physicalDevices[0], device, sizeof(texturedCubeData), vk::BufferUsageFlagBits::eVertexBuffer); + vk::su::copyToDevice(device, vertexBufferData.deviceMemory, texturedCubeData, sizeof(texturedCubeData) / sizeof(texturedCubeData[0])); + + vk::UniquePipelineCache pipelineCache = device->createPipelineCacheUnique(vk::PipelineCacheCreateInfo()); + vk::UniquePipeline graphicsPipeline = vk::su::createGraphicsPipeline(device, pipelineCache, vertexShaderModule, fragmentShaderModule, sizeof(texturedCubeData[0]), true, true, pipelineLayout, renderPass); + + // Get the index of the next available swapchain image: + vk::UniqueSemaphore imageAcquiredSemaphore = device->createSemaphoreUnique(vk::SemaphoreCreateInfo()); + vk::ResultValue currentBuffer = device->acquireNextImageKHR(swapChainData.swapChain.get(), vk::su::FenceTimeout, imageAcquiredSemaphore.get(), nullptr); + assert(currentBuffer.result == vk::Result::eSuccess); + assert(currentBuffer.value < framebuffers.size()); + + vk::ClearValue clearValues[2]; + clearValues[0].color = vk::ClearColorValue(std::array({ 0.2f, 0.2f, 0.2f, 0.2f })); + clearValues[1].depthStencil = vk::ClearDepthStencilValue(1.0f, 0); + vk::RenderPassBeginInfo renderPassBeginInfo(renderPass.get(), framebuffers[currentBuffer.value].get(), vk::Rect2D(vk::Offset2D(0, 0), surfaceData.extent), 2, clearValues); + commandBuffers[0]->beginRenderPass(renderPassBeginInfo, vk::SubpassContents::eInline); + commandBuffers[0]->bindPipeline(vk::PipelineBindPoint::eGraphics, graphicsPipeline.get()); + + vk::DescriptorBufferInfo bufferInfo(uniformBufferData.buffer.get(), 0, sizeof(glm::mat4x4)); + vk::DescriptorImageInfo imageInfo(textureData.textureSampler.get(), textureData.imageData->imageView.get(), vk::ImageLayout::eShaderReadOnlyOptimal); + vk::WriteDescriptorSet writeDescriptorSets[2] = + { + vk::WriteDescriptorSet({}, 0, 0, 1, vk::DescriptorType::eUniformBuffer, nullptr, &bufferInfo), + vk::WriteDescriptorSet({}, 1, 0, 1, vk::DescriptorType::eCombinedImageSampler, &imageInfo) + }; + + // this call is from an extension and needs the dynamic dispatcher !! + commandBuffers[0]->pushDescriptorSetKHR(vk::PipelineBindPoint::eGraphics, *pipelineLayout, 0, { 2, writeDescriptorSets }, vk::DispatchLoaderDynamic(*instance, *device)); + + vk::DeviceSize offset = 0; + commandBuffers[0]->bindVertexBuffers(0, vertexBufferData.buffer.get(), offset); + + vk::Viewport viewport(0.0f, 0.0f, static_cast(surfaceData.extent.width), static_cast(surfaceData.extent.height), 0.0f, 1.0f); + commandBuffers[0]->setViewport(0, viewport); + + vk::Rect2D scissor(vk::Offset2D(0, 0), surfaceData.extent); + commandBuffers[0]->setScissor(0, scissor); + + commandBuffers[0]->draw(12 * 3, 1, 0, 0); + commandBuffers[0]->endRenderPass(); + commandBuffers[0]->end(); + + vk::UniqueFence drawFence = device->createFenceUnique(vk::FenceCreateInfo()); + + vk::PipelineStageFlags waitDestinationStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput); + vk::SubmitInfo submitInfo(1, &imageAcquiredSemaphore.get(), &waitDestinationStageMask, 1, &commandBuffers[0].get()); + graphicsQueue.submit(submitInfo, drawFence.get()); + + while (vk::Result::eTimeout == device->waitForFences(drawFence.get(), VK_TRUE, vk::su::FenceTimeout)) + ; + + presentQueue.presentKHR(vk::PresentInfoKHR(0, nullptr, 1, &swapChainData.swapChain.get(), ¤tBuffer.value)); + Sleep(1000); + + /* VULKAN_KEY_END */ + + device->waitIdle(); +#if defined(VK_USE_PLATFORM_WIN32_KHR) + DestroyWindow(surfaceData.window); +#else +#pragma error "unhandled platform" +#endif + } + catch (vk::SystemError err) + { + std::cout << "vk::SystemError: " << err.what() << std::endl; + exit(-1); + } + catch (std::runtime_error err) + { + std::cout << "std::runtime_error: " << err.what() << std::endl; + exit(-1); + } + catch (...) + { + std::cout << "unknown error\n"; + exit(-1); + } + return 0; +} diff --git a/samples/utils/math.cpp b/samples/utils/math.cpp index 613a439..da45aa5 100644 --- a/samples/utils/math.cpp +++ b/samples/utils/math.cpp @@ -29,7 +29,7 @@ namespace vk glm::mat4x4 model = glm::mat4x4(1.0f); glm::mat4x4 view = glm::lookAt(glm::vec3(-5.0f, 3.0f, -10.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)); - glm::mat4x4 projection = glm::perspective(fov, 1.0f, 0.1f, 100.0f); + glm::mat4x4 projection = glm::perspective(fov, static_cast(extent.width) / static_cast(extent.height), 0.1f, 100.0f); glm::mat4x4 clip = glm::mat4x4(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.5f, 1.0f); // vulkan clip space has inverted y and half z ! return clip * projection * view * model; } diff --git a/samples/utils/shaders.cpp b/samples/utils/shaders.cpp index d53891c..8f219ac 100644 --- a/samples/utils/shaders.cpp +++ b/samples/utils/shaders.cpp @@ -15,7 +15,7 @@ #include "shaders.hpp" #include "vulkan/vulkan.hpp" -#include "glslang/StandAlone/ResourceLimits.h" +#include "StandAlone/ResourceLimits.h" #include "SPIRV/GlslangToSpv.h" namespace vk diff --git a/samples/utils/utils.cpp b/samples/utils/utils.cpp index bd0d81c..173b577 100644 --- a/samples/utils/utils.cpp +++ b/samples/utils/utils.cpp @@ -15,6 +15,7 @@ #include "utils.hpp" #include "vulkan/vulkan.hpp" +#include PFN_vkCreateDebugReportCallbackEXT pfnVkCreateDebugReportCallbackEXT; PFN_vkDestroyDebugReportCallbackEXT pfnVkDestroyDebugReportCallbackEXT; @@ -64,7 +65,7 @@ namespace vk return device->createDescriptorPoolUnique(descriptorPoolCreateInfo); } - vk::UniqueDescriptorSetLayout createDescriptorSetLayout(vk::UniqueDevice &device, vk::DescriptorType descriptorType, bool textured) + vk::UniqueDescriptorSetLayout createDescriptorSetLayout(vk::UniqueDevice &device, vk::DescriptorType descriptorType, bool textured, vk::DescriptorSetLayoutCreateFlags flags) { std::vector bindings; bindings.push_back(vk::DescriptorSetLayoutBinding(0, descriptorType, 1, vk::ShaderStageFlagBits::eVertex)); @@ -72,8 +73,7 @@ namespace vk { bindings.push_back(vk::DescriptorSetLayoutBinding(1, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment)); } - vk::DescriptorSetLayoutBinding descriptorSetLayoutBinding(0, vk::DescriptorType::eUniformBuffer, 1, vk::ShaderStageFlagBits::eVertex); - return device->createDescriptorSetLayoutUnique(vk::DescriptorSetLayoutCreateInfo({}, checked_cast(bindings.size()), bindings.data())); + return device->createDescriptorSetLayoutUnique(vk::DescriptorSetLayoutCreateInfo(flags, checked_cast(bindings.size()), bindings.data())); } vk::UniqueDevice createDevice(vk::PhysicalDevice physicalDevice, uint32_t queueFamilyIndex, std::vector const& extensions) @@ -108,7 +108,8 @@ namespace vk return framebuffers; } - vk::UniquePipeline createGraphicsPipeline(vk::UniqueDevice &device, vk::UniquePipelineCache &pipelineCache, vk::UniqueShaderModule &vertexShaderModule, vk::UniqueShaderModule &fragmentShaderModule, uint32_t vertexStride, bool depthBuffered, vk::UniquePipelineLayout &pipelineLayout, vk::UniqueRenderPass &renderPass) + vk::UniquePipeline createGraphicsPipeline(vk::UniqueDevice &device, vk::UniquePipelineCache &pipelineCache, vk::UniqueShaderModule &vertexShaderModule, + vk::UniqueShaderModule &fragmentShaderModule, uint32_t vertexStride, bool depthBuffered, bool textured, vk::UniquePipelineLayout &pipelineLayout, vk::UniqueRenderPass &renderPass) { vk::PipelineShaderStageCreateInfo pipelineShaderStageCreateInfos[2] = { @@ -123,7 +124,7 @@ namespace vk vk::VertexInputAttributeDescription vertexInputAttributeDescriptions[2] = { vk::VertexInputAttributeDescription(0, 0, vk::Format::eR32G32B32A32Sfloat, 0), - vk::VertexInputAttributeDescription(1, 0, vk::Format::eR32G32B32A32Sfloat, 16) + vk::VertexInputAttributeDescription(1, 0, textured ? vk::Format::eR32G32Sfloat : vk::Format::eR32G32B32A32Sfloat, 16) }; pipelineVertexInputStateCreateInfo.vertexBindingDescriptionCount = 1; pipelineVertexInputStateCreateInfo.pVertexBindingDescriptions = &vertexInputBindingDescription; @@ -503,6 +504,27 @@ namespace vk } } + MonochromeTextureGenerator::MonochromeTextureGenerator(std::array const& rgb_) + : rgb(rgb_) + {} + + void MonochromeTextureGenerator::operator()(void* data, vk::Extent2D &extent) const + { + // fill in with the monochrome color + unsigned char *pImageMemory = static_cast(data); + for (uint32_t row = 0; row < extent.height; row++) + { + for (uint32_t col = 0; col < extent.width; col++) + { + pImageMemory[0] = rgb[0]; + pImageMemory[1] = rgb[1]; + pImageMemory[2] = rgb[2]; + pImageMemory[3] = 255; + pImageMemory += 4; + } + } + } + TextureData::TextureData(vk::PhysicalDevice &physicalDevice, vk::UniqueDevice &device, vk::ImageUsageFlags usageFlags, vk::FormatFeatureFlags formatFeatureFlags) : format(vk::Format::eR8G8B8A8Unorm) , extent(256, 256) @@ -536,6 +558,11 @@ namespace vk , vk::BorderColor::eFloatOpaqueWhite)); } + UUID::UUID(uint8_t data[VK_UUID_SIZE]) + { + memcpy(m_data, data, VK_UUID_SIZE * sizeof(uint8_t)); + } + #if defined(VK_USE_PLATFORM_WIN32_KHR) LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { @@ -588,3 +615,18 @@ namespace vk #endif } } + +std::ostream& operator<<(std::ostream& os, vk::su::UUID const& uuid) +{ + os << std::setfill('0'); + for (int j = 0; j < VK_UUID_SIZE; ++j) + { + os << std::hex << std::setw(2) << static_cast(uuid.m_data[j]); + if (j == 3 || j == 5 || j == 7 || j == 9) + { + std::cout << '-'; + } + } + os << std::setfill(' '); + return os; +} diff --git a/samples/utils/utils.hpp b/samples/utils/utils.hpp index 156da1f..d9ecd4b 100644 --- a/samples/utils/utils.hpp +++ b/samples/utils/utils.hpp @@ -71,6 +71,18 @@ namespace vk void operator()(void* data, vk::Extent2D &extent) const; }; + class MonochromeTextureGenerator + { + public: + MonochromeTextureGenerator(std::array const& rgb_); + + void operator()(void* data, vk::Extent2D &extent) const; + + private: + std::array const& rgb; + }; + + struct TextureData { TextureData(vk::PhysicalDevice &physicalDevice, vk::UniqueDevice &device, vk::ImageUsageFlags usageFlags = {}, vk::FormatFeatureFlags formatFeatureFlags = {}); @@ -108,6 +120,14 @@ namespace vk vk::UniqueSampler textureSampler; }; + struct UUID + { + public: + UUID(uint8_t data[VK_UUID_SIZE]); + + uint8_t m_data[VK_UUID_SIZE]; + }; + template VULKAN_HPP_INLINE TargetType checked_cast(SourceType value) @@ -155,10 +175,11 @@ namespace vk vk::UniqueCommandPool createCommandPool(vk::UniqueDevice &device, uint32_t queueFamilyIndex); vk::UniqueDebugReportCallbackEXT createDebugReportCallback(vk::UniqueInstance &instance); vk::UniqueDescriptorPool createDescriptorPool(vk::UniqueDevice &device, vk::DescriptorType descriptorType = vk::DescriptorType::eUniformBuffer, bool textured = false); - vk::UniqueDescriptorSetLayout createDescriptorSetLayout(vk::UniqueDevice &device, vk::DescriptorType = vk::DescriptorType::eUniformBuffer, bool textured = false); + vk::UniqueDescriptorSetLayout createDescriptorSetLayout(vk::UniqueDevice &device, vk::DescriptorType = vk::DescriptorType::eUniformBuffer, bool textured = false, vk::DescriptorSetLayoutCreateFlags flags = {}); vk::UniqueDevice createDevice(vk::PhysicalDevice physicalDevice, uint32_t queueFamilyIndex, std::vector const& extensions = {}); std::vector createFramebuffers(vk::UniqueDevice &device, vk::UniqueRenderPass &renderPass, std::vector const& imageViews, vk::UniqueImageView const& depthImageView, vk::Extent2D const& extent); - vk::UniquePipeline createGraphicsPipeline(vk::UniqueDevice &device, vk::UniquePipelineCache &pipelineCache, vk::UniqueShaderModule &vertexShaderModule, vk::UniqueShaderModule &fragmentShaderModule, uint32_t vertexStride, bool depthBuffered, vk::UniquePipelineLayout &pipelineLayout, vk::UniqueRenderPass &renderPass); + vk::UniquePipeline createGraphicsPipeline(vk::UniqueDevice &device, vk::UniquePipelineCache &pipelineCache, vk::UniqueShaderModule &vertexShaderModule, + vk::UniqueShaderModule &fragmentShaderModule, uint32_t vertexStride, bool depthBuffered, bool textured, vk::UniquePipelineLayout &pipelineLayout, vk::UniqueRenderPass &renderPass); vk::UniqueInstance createInstance(std::string const& appName, std::string const& engineName, std::vector const& extensions = {}, uint32_t apiVersion = VK_API_VERSION_1_0); vk::UniqueRenderPass createRenderPass(vk::UniqueDevice &device, vk::Format colorFormat, vk::Format depthFormat, vk::AttachmentLoadOp loadOp = vk::AttachmentLoadOp::eClear, vk::ImageLayout colorFinalLayout = vk::ImageLayout::ePresentSrcKHR); VkBool32 debugReportCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage, void* pUserData); @@ -179,3 +200,5 @@ namespace vk #endif } } + +std::ostream& operator<<(std::ostream& os, vk::su::UUID const& uuid);