diff --git a/CMakeLists.txt b/CMakeLists.txt index b71d1aed..90a05c8b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -130,11 +130,11 @@ endif() IF(MSVC) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc") ELSEIF(APPLE) - if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fobjc-arc -ObjC++") - ELSE() + #if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + # SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fobjc-arc -ObjC++") + #ELSE() SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fobjc-arc -xobjective-c++") - ENDIF() + #ENDIF() ENDIF(MSVC) IF(WIN32) diff --git a/base/VulkanDevice.cpp b/base/VulkanDevice.cpp index 8f1d99b9..1b20febf 100644 --- a/base/VulkanDevice.cpp +++ b/base/VulkanDevice.cpp @@ -8,13 +8,13 @@ * This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) */ +#if (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK)) +// SRS - Enable beta extensions and make VK_KHR_portability_subset visible +#define VK_ENABLE_BETA_EXTENSIONS +#endif #include #include -#if defined(VK_USE_PLATFORM_MACOS_MVK) && (VK_HEADER_VERSION >= 216) -#include -#endif - namespace vks { /** @@ -116,6 +116,7 @@ namespace vks /** * Get the index of a queue family that supports the requested queue flags + * SRS - support VkQueueFlags parameter for requesting multiple flags vs. VkQueueFlagBits for a single flag only * * @param queueFlags Queue flags to find a queue family index for * @@ -123,15 +124,15 @@ namespace vks * * @throw Throws an exception if no queue family index could be found that supports the requested flags */ - uint32_t VulkanDevice::getQueueFamilyIndex(VkQueueFlagBits queueFlags) const + uint32_t VulkanDevice::getQueueFamilyIndex(VkQueueFlags queueFlags) const { // Dedicated queue for compute // Try to find a queue family index that supports compute but not graphics - if (queueFlags & VK_QUEUE_COMPUTE_BIT) + if ((queueFlags & VK_QUEUE_COMPUTE_BIT) == queueFlags) { for (uint32_t i = 0; i < static_cast(queueFamilyProperties.size()); i++) { - if ((queueFamilyProperties[i].queueFlags & queueFlags) && ((queueFamilyProperties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0)) + if ((queueFamilyProperties[i].queueFlags & VK_QUEUE_COMPUTE_BIT) && ((queueFamilyProperties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0)) { return i; } @@ -140,11 +141,11 @@ namespace vks // Dedicated queue for transfer // Try to find a queue family index that supports transfer but not graphics and compute - if (queueFlags & VK_QUEUE_TRANSFER_BIT) + if ((queueFlags & VK_QUEUE_TRANSFER_BIT) == queueFlags) { for (uint32_t i = 0; i < static_cast(queueFamilyProperties.size()); i++) { - if ((queueFamilyProperties[i].queueFlags & queueFlags) && ((queueFamilyProperties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0) && ((queueFamilyProperties[i].queueFlags & VK_QUEUE_COMPUTE_BIT) == 0)) + if ((queueFamilyProperties[i].queueFlags & VK_QUEUE_TRANSFER_BIT) && ((queueFamilyProperties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0) && ((queueFamilyProperties[i].queueFlags & VK_QUEUE_COMPUTE_BIT) == 0)) { return i; } @@ -154,7 +155,7 @@ namespace vks // For other queue types or if no separate compute queue is present, return the first one to support the requested flags for (uint32_t i = 0; i < static_cast(queueFamilyProperties.size()); i++) { - if (queueFamilyProperties[i].queueFlags & queueFlags) + if ((queueFamilyProperties[i].queueFlags & queueFlags) == queueFlags) { return i; } @@ -229,7 +230,7 @@ namespace vks queueFamilyIndices.transfer = getQueueFamilyIndex(VK_QUEUE_TRANSFER_BIT); if ((queueFamilyIndices.transfer != queueFamilyIndices.graphics) && (queueFamilyIndices.transfer != queueFamilyIndices.compute)) { - // If compute family index differs, we need an additional queue create info for the compute queue + // If transfer family index differs, we need an additional queue create info for the transfer queue VkDeviceQueueCreateInfo queueInfo{}; queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queueInfo.queueFamilyIndex = queueFamilyIndices.transfer; @@ -252,10 +253,6 @@ namespace vks deviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); } -#if defined(VK_USE_PLATFORM_MACOS_MVK) && (VK_HEADER_VERSION >= 216) - deviceExtensions.push_back(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME); -#endif - VkDeviceCreateInfo deviceCreateInfo = {}; deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; deviceCreateInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size());; @@ -279,6 +276,14 @@ namespace vks enableDebugMarkers = true; } +#if (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK)) && defined(VK_KHR_portability_subset) + // SRS - When running on iOS/macOS with MoltenVK and VK_KHR_portability_subset is defined and supported by the device, enable the extension + if (extensionSupported(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME)) + { + deviceExtensions.push_back(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME); + } +#endif + if (deviceExtensions.size() > 0) { for (const char* enabledExtension : deviceExtensions) diff --git a/base/VulkanDevice.h b/base/VulkanDevice.h index 0bb49879..fc41506a 100644 --- a/base/VulkanDevice.h +++ b/base/VulkanDevice.h @@ -55,7 +55,7 @@ struct VulkanDevice explicit VulkanDevice(VkPhysicalDevice physicalDevice); ~VulkanDevice(); uint32_t getMemoryType(uint32_t typeBits, VkMemoryPropertyFlags properties, VkBool32 *memTypeFound = nullptr) const; - uint32_t getQueueFamilyIndex(VkQueueFlagBits queueFlags) const; + uint32_t getQueueFamilyIndex(VkQueueFlags queueFlags) const; VkResult createLogicalDevice(VkPhysicalDeviceFeatures enabledFeatures, std::vector enabledExtensions, void *pNextChain, bool useSwapChain = true, VkQueueFlags requestedQueueTypes = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT); VkResult createBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkDeviceSize size, VkBuffer *buffer, VkDeviceMemory *memory, void *data = nullptr); VkResult createBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, vks::Buffer *buffer, VkDeviceSize size, void *data = nullptr); diff --git a/base/VulkanSwapChain.cpp b/base/VulkanSwapChain.cpp index 432fee10..e12405dd 100644 --- a/base/VulkanSwapChain.cpp +++ b/base/VulkanSwapChain.cpp @@ -229,7 +229,7 @@ void VulkanSwapChain::connect(VkInstance instance, VkPhysicalDevice physicalDevi * @param height Pointer to the height of the swapchain (may be adjusted to fit the requirements of the swapchain) * @param vsync (Optional) Can be used to force vsync-ed rendering (by using VK_PRESENT_MODE_FIFO_KHR as presentation mode) */ -void VulkanSwapChain::create(uint32_t *width, uint32_t *height, bool vsync) +void VulkanSwapChain::create(uint32_t *width, uint32_t *height, bool vsync, bool fullscreen) { // Store the current swap chain handle so we can use it later on to ease up recreation VkSwapchainKHR oldSwapchain = swapChain; @@ -290,6 +290,17 @@ void VulkanSwapChain::create(uint32_t *width, uint32_t *height, bool vsync) // Determine the number of images uint32_t desiredNumberOfSwapchainImages = surfCaps.minImageCount + 1; +#if (defined(VK_USE_PLATFORM_MACOS_MVK) && defined(VK_EXAMPLE_XCODE_GENERATED)) + // SRS - Work around known MoltenVK issue re 2x frame rate when vsync (VK_PRESENT_MODE_FIFO_KHR) enabled + struct utsname sysInfo; + uname(&sysInfo); + // SRS - When vsync is on, use minImageCount when not in fullscreen or when running on Apple Silcon + // This forces swapchain image acquire frame rate to match display vsync frame rate + if (vsync && (!fullscreen || strcmp(sysInfo.machine, "arm64") == 0)) + { + desiredNumberOfSwapchainImages = surfCaps.minImageCount; + } +#endif if ((surfCaps.maxImageCount > 0) && (desiredNumberOfSwapchainImages > surfCaps.maxImageCount)) { desiredNumberOfSwapchainImages = surfCaps.maxImageCount; diff --git a/base/VulkanSwapChain.h b/base/VulkanSwapChain.h index 686bf498..8d591100 100644 --- a/base/VulkanSwapChain.h +++ b/base/VulkanSwapChain.h @@ -23,6 +23,10 @@ #include "VulkanAndroid.h" #endif +#ifdef __APPLE__ +#include +#endif + typedef struct _SwapChainBuffers { VkImage image; VkImageView view; @@ -73,7 +77,7 @@ public: #endif #endif void connect(VkInstance instance, VkPhysicalDevice physicalDevice, VkDevice device); - void create(uint32_t* width, uint32_t* height, bool vsync = false); + void create(uint32_t* width, uint32_t* height, bool vsync = false, bool fullscreen = false); VkResult acquireNextImage(VkSemaphore presentCompleteSemaphore, uint32_t* imageIndex); VkResult queuePresent(VkQueue queue, uint32_t imageIndex, VkSemaphore waitSemaphore = VK_NULL_HANDLE); void cleanup(); diff --git a/base/VulkanTools.cpp b/base/VulkanTools.cpp index 1827ddf5..9659073e 100644 --- a/base/VulkanTools.cpp +++ b/base/VulkanTools.cpp @@ -8,6 +8,8 @@ #include "VulkanTools.h" +#if !(defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK)) +// iOS & macOS: VulkanExampleBase::getAssetPath() implemented externally to allow access to Objective-C components const std::string getAssetPath() { #if defined(VK_USE_PLATFORM_ANDROID_KHR) @@ -18,6 +20,7 @@ const std::string getAssetPath() return "./../data/"; #endif } +#endif namespace vks { diff --git a/base/VulkanUIOverlay.cpp b/base/VulkanUIOverlay.cpp index b18e2a5a..df25273f 100644 --- a/base/VulkanUIOverlay.cpp +++ b/base/VulkanUIOverlay.cpp @@ -78,11 +78,15 @@ namespace vks } #else const std::string filename = getAssetPath() + "Roboto-Medium.ttf"; - io.Fonts->AddFontFromFileTTF(filename.c_str(), 16.0f); -#endif + io.Fonts->AddFontFromFileTTF(filename.c_str(), 16.0f * scale); +#endif io.Fonts->GetTexDataAsRGBA32(&fontData, &texWidth, &texHeight); VkDeviceSize uploadSize = texWidth*texHeight * 4 * sizeof(char); + //SRS - Set ImGui style scale factor to handle retina and other HiDPI displays (same as font scaling above) + ImGuiStyle& style = ImGui::GetStyle(); + style.ScaleAllSizes(scale); + // Create target image for copy VkImageCreateInfo imageInfo = vks::initializers::imageCreateInfo(); imageInfo.imageType = VK_IMAGE_TYPE_2D; @@ -213,7 +217,7 @@ namespace vks } /** Prepare a separate pipeline for the UI overlay rendering decoupled from the main application */ - void UIOverlay::preparePipeline(const VkPipelineCache pipelineCache, const VkRenderPass renderPass) + void UIOverlay::preparePipeline(const VkPipelineCache pipelineCache, const VkRenderPass renderPass, const VkFormat colorFormat, const VkFormat depthFormat) { // Pipeline layout // Push constants for UI rendering parameters @@ -272,6 +276,19 @@ namespace vks pipelineCreateInfo.stageCount = static_cast(shaders.size()); pipelineCreateInfo.pStages = shaders.data(); pipelineCreateInfo.subpass = subpass; + +#if defined(VK_KHR_dynamic_rendering) + // SRS - if we are using dynamic rendering (i.e. renderPass null), must define color, depth and stencil attachments at pipeline create time + VkPipelineRenderingCreateInfo pipelineRenderingCreateInfo = {}; + if (renderPass == VK_NULL_HANDLE) { + pipelineRenderingCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO; + pipelineRenderingCreateInfo.colorAttachmentCount = 1; + pipelineRenderingCreateInfo.pColorAttachmentFormats = &colorFormat; + pipelineRenderingCreateInfo.depthAttachmentFormat = depthFormat; + pipelineRenderingCreateInfo.stencilAttachmentFormat = depthFormat; + pipelineCreateInfo.pNext = &pipelineRenderingCreateInfo; + } +#endif // Vertex bindings an attributes based on ImGui vertex definition std::vector vertexInputBindings = { @@ -322,7 +339,6 @@ namespace vks } // Index buffer - VkDeviceSize indexSize = imDrawData->TotalIdxCount * sizeof(ImDrawIdx); if ((indexBuffer.buffer == VK_NULL_HANDLE) || (indexCount < imDrawData->TotalIdxCount)) { indexBuffer.unmap(); indexBuffer.destroy(); @@ -492,4 +508,4 @@ namespace vks ImGui::TextV(formatstr, args); va_end(args); } -} \ No newline at end of file +} diff --git a/base/VulkanUIOverlay.h b/base/VulkanUIOverlay.h index 7d45179b..aa222363 100644 --- a/base/VulkanUIOverlay.h +++ b/base/VulkanUIOverlay.h @@ -69,7 +69,7 @@ namespace vks UIOverlay(); ~UIOverlay(); - void preparePipeline(const VkPipelineCache pipelineCache, const VkRenderPass renderPass); + void preparePipeline(const VkPipelineCache pipelineCache, const VkRenderPass renderPass, const VkFormat colorFormat, const VkFormat depthFormat); void prepareResources(); bool update(); @@ -89,4 +89,4 @@ namespace vks bool button(const char* caption); void text(const char* formatstr, ...); }; -} \ No newline at end of file +} diff --git a/base/keycodes.hpp b/base/keycodes.hpp index d9d7f654..ca4fd5aa 100644 --- a/base/keycodes.hpp +++ b/base/keycodes.hpp @@ -40,15 +40,24 @@ #define GAMEPAD_BUTTON_START 0x1006 #define TOUCH_DOUBLE_TAP 0x1100 -#elif defined(VK_USE_PLATFORM_IOS_MVK) -// Use numeric keys instead of function keys. -// Use main keyboard plus/minus instead of keypad plus/minus -// Use Delete key instead of Escape key. -#define KEY_ESCAPE 0x33 -#define KEY_F1 '1' -#define KEY_F2 '2' -#define KEY_F3 '3' -#define KEY_F4 '4' +// for textoverlay example +#define KEY_SPACE 0x3E // AKEYCODE_SPACE +#define KEY_KPADD 0x9D // AKEYCODE_NUMPAD_ADD + +#elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK)) +#if !defined(VK_EXAMPLE_XCODE_GENERATED) +// For iOS and macOS pre-configured Xcode example project: Use character keycodes +// - Use numeric keys as optional alternative to function keys +#define KEY_DELETE 0x7F +#define KEY_ESCAPE 0x1B +#define KEY_F1 0xF704 // NSF1FunctionKey +#define KEY_F2 0xF705 // NSF2FunctionKey +#define KEY_F3 0xF706 // NSF3FunctionKey +#define KEY_F4 0xF707 // NSF4FunctionKey +#define KEY_1 '1' +#define KEY_2 '2' +#define KEY_3 '3' +#define KEY_4 '4' #define KEY_W 'w' #define KEY_A 'a' #define KEY_S 's' @@ -62,32 +71,42 @@ #define KEY_L 'l' #define KEY_N 'n' #define KEY_O 'o' +#define KEY_Q 'q' #define KEY_T 't' +#define KEY_Z 'z' -#elif defined(VK_USE_PLATFORM_MACOS_MVK) -// For compatibility with iOS UX and absent keypad on MacBook: -// - Use numeric keys instead of function keys +#else // defined(VK_EXAMPLE_XCODE_GENERATED) +// For cross-platform cmake-generated Xcode project: Use ANSI keyboard keycodes +// - Use numeric keys as optional alternative to function keys // - Use main keyboard plus/minus instead of keypad plus/minus -// - Use Delete key instead of Escape key -#define KEY_ESCAPE 0x33 -#define KEY_F1 0x12 -#define KEY_F2 0x13 -#define KEY_F3 0x14 -#define KEY_F4 0x15 -#define KEY_W 0x0D -#define KEY_A 0x00 -#define KEY_S 0x01 -#define KEY_D 0x02 -#define KEY_P 0x23 -#define KEY_SPACE 0x31 -#define KEY_KPADD 0x18 -#define KEY_KPSUB 0x1B -#define KEY_B 0x0B -#define KEY_F 0x03 -#define KEY_L 0x25 -#define KEY_N 0x2D -#define KEY_O 0x1F -#define KEY_T 0x11 +#include +#define KEY_DELETE kVK_Delete +#define KEY_ESCAPE kVK_Escape +#define KEY_F1 kVK_F1 +#define KEY_F2 kVK_F2 +#define KEY_F3 kVK_F3 +#define KEY_F4 kVK_F4 +#define KEY_1 kVK_ANSI_1 +#define KEY_2 kVK_ANSI_2 +#define KEY_3 kVK_ANSI_3 +#define KEY_4 kVK_ANSI_4 +#define KEY_W kVK_ANSI_W +#define KEY_A kVK_ANSI_A +#define KEY_S kVK_ANSI_S +#define KEY_D kVK_ANSI_D +#define KEY_P kVK_ANSI_P +#define KEY_SPACE kVK_Space +#define KEY_KPADD kVK_ANSI_Equal +#define KEY_KPSUB kVK_ANSI_Minus +#define KEY_B kVK_ANSI_B +#define KEY_F kVK_ANSI_F +#define KEY_L kVK_ANSI_L +#define KEY_N kVK_ANSI_N +#define KEY_O kVK_ANSI_O +#define KEY_Q kVK_ANSI_Q +#define KEY_T kVK_ANSI_T +#define KEY_Z kVK_ANSI_Z +#endif #elif defined(VK_USE_PLATFORM_DIRECTFB_EXT) #define KEY_ESCAPE DIKS_ESCAPE @@ -114,6 +133,7 @@ #include // todo: hack for bloom example +#define KEY_ESCAPE KEY_ESC #define KEY_KPADD KEY_KPPLUS #define KEY_KPSUB KEY_KPMINUS @@ -137,4 +157,4 @@ #define KEY_N 0x39 #define KEY_O 0x20 #define KEY_T 0x1C -#endif \ No newline at end of file +#endif diff --git a/base/vulkanexamplebase.cpp b/base/vulkanexamplebase.cpp index c6a23bfd..6d6b7d1b 100644 --- a/base/vulkanexamplebase.cpp +++ b/base/vulkanexamplebase.cpp @@ -10,7 +10,6 @@ #if (defined(VK_USE_PLATFORM_MACOS_MVK) && defined(VK_EXAMPLE_XCODE_GENERATED)) #include -#include #include #include #endif @@ -54,12 +53,7 @@ VkResult VulkanExampleBase::createInstance(bool enableValidation) #elif defined(VK_USE_PLATFORM_HEADLESS_EXT) instanceExtensions.push_back(VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME); #endif - -#if defined(VK_USE_PLATFORM_MACOS_MVK) && (VK_HEADER_VERSION >= 216) - instanceExtensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); - instanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); -#endif - + // Get extensions supported by the instance and store for later use uint32_t extCount = 0; vkEnumerateInstanceExtensionProperties(nullptr, &extCount, nullptr); @@ -75,6 +69,14 @@ VkResult VulkanExampleBase::createInstance(bool enableValidation) } } +#if (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK)) + // SRS - When running on iOS/macOS with MoltenVK, enable VK_KHR_get_physical_device_properties2 if not already enabled by the example (required by VK_KHR_portability_subset) + if (std::find(enabledInstanceExtensions.begin(), enabledInstanceExtensions.end(), VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) == enabledInstanceExtensions.end()) + { + enabledInstanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + } +#endif + // Enabled requested instance extensions if (enabledInstanceExtensions.size() > 0) { @@ -94,14 +96,20 @@ VkResult VulkanExampleBase::createInstance(bool enableValidation) instanceCreateInfo.pNext = NULL; instanceCreateInfo.pApplicationInfo = &appInfo; -#if defined(VK_USE_PLATFORM_MACOS_MVK) && (VK_HEADER_VERSION >= 216) - instanceCreateInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; +#if (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK)) && defined(VK_KHR_portability_enumeration) + // SRS - When running on iOS/macOS with MoltenVK and VK_KHR_portability_enumeration is defined and supported by the instance, enable the extension and the flag + if (std::find(supportedInstanceExtensions.begin(), supportedInstanceExtensions.end(), VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME) != supportedInstanceExtensions.end()) + { + instanceExtensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); + instanceCreateInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; + } #endif if (instanceExtensions.size() > 0) { if (settings.validation) { + instanceExtensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME); // SRS - Dependency when VK_EXT_DEBUG_MARKER is enabled instanceExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); } instanceCreateInfo.enabledExtensionCount = (uint32_t)instanceExtensions.size(); @@ -209,7 +217,7 @@ void VulkanExampleBase::prepare() loadShader(getShadersPath() + "base/uioverlay.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT), }; UIOverlay.prepareResources(); - UIOverlay.preparePipeline(pipelineCache, renderPass); + UIOverlay.preparePipeline(pipelineCache, renderPass, swapChain.colorFormat, depthFormat); } } @@ -241,7 +249,12 @@ void VulkanExampleBase::nextFrame() render(); frameCounter++; auto tEnd = std::chrono::high_resolution_clock::now(); +#if (defined(VK_USE_PLATFORM_IOS_MVK) || (defined(VK_USE_PLATFORM_MACOS_MVK) && !defined(VK_EXAMPLE_XCODE_GENERATED))) + // SRS - Calculate tDiff as time between frames vs. rendering time for iOS/macOS displayLink-driven examples project + auto tDiff = std::chrono::duration(tEnd - tPrevEnd).count(); +#else auto tDiff = std::chrono::duration(tEnd - tStart).count(); +#endif frameTimer = (float)tDiff / 1000.0f; camera.update(frameTimer); if (camera.moving()) @@ -270,12 +283,17 @@ void VulkanExampleBase::nextFrame() frameCounter = 0; lastTimestamp = tEnd; } + tPrevEnd = tEnd; + // TODO: Cap UI overlay update rates updateOverlay(); } void VulkanExampleBase::renderLoop() { +// SRS - for non-apple plaforms, handle benchmarking here within VulkanExampleBase::renderLoop() +// - for macOS, handle benchmarking within NSApp rendering loop via displayLinkOutputCb() +#if !(defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK)) if (benchmark.active) { benchmark.run([=] { render(); }, vulkanDevice->properties); vkDeviceWaitIdle(device); @@ -284,10 +302,12 @@ void VulkanExampleBase::renderLoop() } return; } +#endif destWidth = width; destHeight = height; lastTimestamp = std::chrono::high_resolution_clock::now(); + tPrevEnd = lastTimestamp; #if defined(_WIN32) MSG msg; bool quitMessageReceived = false; @@ -650,13 +670,14 @@ void VulkanExampleBase::updateOverlay() io.DeltaTime = frameTimer; io.MousePos = ImVec2(mousePos.x, mousePos.y); - io.MouseDown[0] = mouseButtons.left; - io.MouseDown[1] = mouseButtons.right; + io.MouseDown[0] = mouseButtons.left && UIOverlay.visible; + io.MouseDown[1] = mouseButtons.right && UIOverlay.visible; + io.MouseDown[2] = mouseButtons.middle && UIOverlay.visible; ImGui::NewFrame(); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0); - ImGui::SetNextWindowPos(ImVec2(10, 10)); + ImGui::SetNextWindowPos(ImVec2(10 * UIOverlay.scale, 10 * UIOverlay.scale)); ImGui::SetNextWindowSize(ImVec2(0, 0), ImGuiSetCond_FirstUseEver); ImGui::Begin("Vulkan Example", nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove); ImGui::TextUnformatted(title.c_str()); @@ -691,7 +712,7 @@ void VulkanExampleBase::updateOverlay() void VulkanExampleBase::drawUI(const VkCommandBuffer commandBuffer) { - if (settings.overlay) { + if (settings.overlay && UIOverlay.visible) { const VkViewport viewport = vks::initializers::viewport((float)width, (float)height, 0.0f, 1.0f); const VkRect2D scissor = vks::initializers::rect2D(width, height, 0, 0); vkCmdSetViewport(commandBuffer, 0, 1, &viewport); @@ -705,9 +726,13 @@ void VulkanExampleBase::prepareFrame() { // Acquire the next image from the swap chain VkResult result = swapChain.acquireNextImage(semaphores.presentComplete, ¤tBuffer); - // Recreate the swapchain if it's no longer compatible with the surface (OUT_OF_DATE) or no longer optimal for presentation (SUBOPTIMAL) + // Recreate the swapchain if it's no longer compatible with the surface (OUT_OF_DATE) + // SRS - If no longer optimal (VK_SUBOPTIMAL_KHR), wait until submitFrame() in case number of swapchain images will change on resize if ((result == VK_ERROR_OUT_OF_DATE_KHR) || (result == VK_SUBOPTIMAL_KHR)) { - windowResize(); + if (result == VK_ERROR_OUT_OF_DATE_KHR) { + windowResize(); + } + return; } else { VK_CHECK_RESULT(result); @@ -717,15 +742,16 @@ void VulkanExampleBase::prepareFrame() void VulkanExampleBase::submitFrame() { VkResult result = swapChain.queuePresent(queue, currentBuffer, semaphores.renderComplete); - if (!((result == VK_SUCCESS) || (result == VK_SUBOPTIMAL_KHR))) { + // Recreate the swapchain if it's no longer compatible with the surface (OUT_OF_DATE) or no longer optimal for presentation (SUBOPTIMAL) + if ((result == VK_ERROR_OUT_OF_DATE_KHR) || (result == VK_SUBOPTIMAL_KHR)) { + windowResize(); if (result == VK_ERROR_OUT_OF_DATE_KHR) { - // Swap chain is no longer compatible with the surface and needs to be recreated - windowResize(); return; - } else { - VK_CHECK_RESULT(result); } } + else { + VK_CHECK_RESULT(result); + } VK_CHECK_RESULT(vkQueueWaitIdle(queue)); } @@ -1195,9 +1221,8 @@ void VulkanExampleBase::handleMessages(HWND hWnd, UINT uMsg, WPARAM wParam, LPAR paused = !paused; break; case KEY_F1: - if (settings.overlay) { - UIOverlay.visible = !UIOverlay.visible; - } + UIOverlay.visible = !UIOverlay.visible; + UIOverlay.updated = true; break; case KEY_ESCAPE: PostQuitMessage(0); @@ -1374,7 +1399,7 @@ int32_t VulkanExampleBase::handleAppInput(struct android_app* app, AInputEvent* bool handled = false; if (vulkanExample->settings.overlay) { ImGuiIO& io = ImGui::GetIO(); - handled = io.WantCaptureMouse; + handled = io.WantCaptureMouse && vulkanExample->UIOverlay.visible; } if (!handled) { int32_t eventX = AMotionEvent_getX(event, 0); @@ -1426,15 +1451,22 @@ int32_t VulkanExampleBase::handleAppInput(struct android_app* app, AInputEvent* case AKEYCODE_BUTTON_Y: vulkanExample->keyPressed(GAMEPAD_BUTTON_Y); break; + case AKEYCODE_1: // support keyboards with no function keys + case AKEYCODE_F1: case AKEYCODE_BUTTON_L1: - vulkanExample->keyPressed(GAMEPAD_BUTTON_L1); + vulkanExample->UIOverlay.visible = !vulkanExample->UIOverlay.visible; + vulkanExample->UIOverlay.updated = true; break; case AKEYCODE_BUTTON_R1: vulkanExample->keyPressed(GAMEPAD_BUTTON_R1); break; + case AKEYCODE_P: case AKEYCODE_BUTTON_START: vulkanExample->paused = !vulkanExample->paused; break; + default: + vulkanExample->keyPressed(keyCode); // handle example-specific key press events + break; }; LOGD("Button %d pressed", keyCode); @@ -1496,6 +1528,8 @@ void VulkanExampleBase::handleAppCommand(android_app * app, int32_t cmd) #if defined(VK_EXAMPLE_XCODE_GENERATED) @interface AppDelegate : NSObject { +@public + VulkanExampleBase *vulkanExample; } @end @@ -1504,13 +1538,50 @@ void VulkanExampleBase::handleAppCommand(android_app * app, int32_t cmd) { } +// SRS - Dispatch rendering loop onto a queue for max frame rate concurrent rendering vs displayLink vsync rendering +// - vsync command line option (-vs) on macOS now works like other platforms (using VK_PRESENT_MODE_FIFO_KHR) +dispatch_group_t concurrentGroup; + +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification +{ + [NSApp activateIgnoringOtherApps:YES]; // SRS - Make sure app window launches in front of Xcode window + + concurrentGroup = dispatch_group_create(); + dispatch_queue_t concurrentQueue = dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0); + dispatch_group_async(concurrentGroup, concurrentQueue, ^{ + + while (!vulkanExample->quit) { + vulkanExample->displayLinkOutputCb(); + } + }); + + // SRS - When benchmarking, set up termination notification on main thread when concurrent queue completes + if (vulkanExample->benchmark.active) { + dispatch_queue_t notifyQueue = dispatch_get_main_queue(); + dispatch_group_notify(concurrentGroup, notifyQueue, ^{ [NSApp terminate:nil]; }); + } +} + - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender { return YES; } +// SRS - Tell rendering loop to quit, then wait for concurrent queue to terminate before deleting vulkanExample +- (void)applicationWillTerminate:(NSNotification *)aNotification +{ + vulkanExample->quit = YES; + dispatch_group_wait(concurrentGroup, DISPATCH_TIME_FOREVER); + vkDeviceWaitIdle(vulkanExample->vulkanDevice->logicalDevice); + delete(vulkanExample); +} + @end +const std::string getAssetPath() { + return [NSBundle.mainBundle.resourcePath stringByAppendingString: @"/../../data/"].UTF8String; +} + static CVReturn displayLinkOutputCallback(CVDisplayLinkRef displayLink, const CVTimeStamp *inNow, const CVTimeStamp *inOutputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *displayLinkContext) @@ -1550,7 +1621,9 @@ static CVReturn displayLinkOutputCallback(CVDisplayLinkRef displayLink, const CV - (void)viewDidMoveToWindow { CVDisplayLinkCreateWithActiveCGDisplays(&displayLink); - CVDisplayLinkSetOutputCallback(displayLink, &displayLinkOutputCallback, vulkanExample); + // SRS - Disable displayLink vsync rendering in favour of max frame rate concurrent rendering + // - vsync command line option (-vs) on macOS now works like other platforms (using VK_PRESENT_MODE_FIFO_KHR) + //CVDisplayLinkSetOutputCallback(displayLink, &displayLinkOutputCallback, vulkanExample); CVDisplayLinkStart(displayLink); } @@ -1559,29 +1632,41 @@ static CVReturn displayLinkOutputCallback(CVDisplayLinkRef displayLink, const CV return YES; } +- (BOOL)acceptsFirstMouse:(NSEvent *)event +{ + return YES; +} + - (void)keyDown:(NSEvent*)event { switch (event.keyCode) { - case kVK_ANSI_P: + case KEY_P: vulkanExample->paused = !vulkanExample->paused; break; - case kVK_Escape: + case KEY_1: // support keyboards with no function keys + case KEY_F1: + vulkanExample->UIOverlay.visible = !vulkanExample->UIOverlay.visible; + vulkanExample->UIOverlay.updated = true; + break; + case KEY_DELETE: // support keyboards with no escape key + case KEY_ESCAPE: [NSApp terminate:nil]; break; - case kVK_ANSI_W: + case KEY_W: vulkanExample->camera.keys.up = true; break; - case kVK_ANSI_S: + case KEY_S: vulkanExample->camera.keys.down = true; break; - case kVK_ANSI_A: + case KEY_A: vulkanExample->camera.keys.left = true; break; - case kVK_ANSI_D: + case KEY_D: vulkanExample->camera.keys.right = true; break; default: + vulkanExample->keyPressed(event.keyCode); // handle example-specific key press events break; } } @@ -1590,17 +1675,17 @@ static CVReturn displayLinkOutputCallback(CVDisplayLinkRef displayLink, const CV { switch (event.keyCode) { - case kVK_ANSI_W: + case KEY_W: vulkanExample->camera.keys.up = false; break; - case kVK_ANSI_S: + case KEY_S: vulkanExample->camera.keys.down = false; break; - case kVK_ANSI_A: + case KEY_A: vulkanExample->camera.keys.left = false; - break; - case kVK_ANSI_D: - vulkanExample->camera.keys.right = false; + break; + case KEY_D: + vulkanExample->camera.keys.right = false; break; default: break; @@ -1624,27 +1709,51 @@ static CVReturn displayLinkOutputCallback(CVDisplayLinkRef displayLink, const CV - (void)mouseUp:(NSEvent *)event { - auto point = [self getMouseLocalPoint:event]; - vulkanExample->mousePos = glm::vec2(point.x, point.y); vulkanExample->mouseButtons.left = false; } -- (void)otherMouseDown:(NSEvent *)event +- (void)rightMouseDown:(NSEvent *)event { + auto point = [self getMouseLocalPoint:event]; + vulkanExample->mousePos = glm::vec2(point.x, point.y); vulkanExample->mouseButtons.right = true; } -- (void)otherMouseUp:(NSEvent *)event +- (void)rightMouseUp:(NSEvent *)event { vulkanExample->mouseButtons.right = false; } +- (void)otherMouseDown:(NSEvent *)event +{ + auto point = [self getMouseLocalPoint:event]; + vulkanExample->mousePos = glm::vec2(point.x, point.y); + vulkanExample->mouseButtons.middle = true; +} + +- (void)otherMouseUp:(NSEvent *)event +{ + vulkanExample->mouseButtons.middle = false; +} + - (void)mouseDragged:(NSEvent *)event { auto point = [self getMouseLocalPoint:event]; vulkanExample->mouseDragged(point.x, point.y); } +- (void)rightMouseDragged:(NSEvent *)event +{ + auto point = [self getMouseLocalPoint:event]; + vulkanExample->mouseDragged(point.x, point.y); +} + +- (void)otherMouseDragged:(NSEvent *)event +{ + auto point = [self getMouseLocalPoint:event]; + vulkanExample->mouseDragged(point.x, point.y); +} + - (void)mouseMoved:(NSEvent *)event { auto point = [self getMouseLocalPoint:event]; @@ -1656,8 +1765,12 @@ static CVReturn displayLinkOutputCallback(CVDisplayLinkRef displayLink, const CV short wheelDelta = [event deltaY]; vulkanExample->camera.translate(glm::vec3(0.0f, 0.0f, -(float)wheelDelta * 0.05f * vulkanExample->camera.movementSpeed)); + vulkanExample->viewUpdated = true; } +// SRS - Window resizing already handled by windowResize() in VulkanExampleBase::submitFrame() +// - handling window resize events here is redundant and can cause thread interaction problems +/* - (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)frameSize { CVDisplayLinkStop(displayLink); @@ -1670,6 +1783,17 @@ static CVReturn displayLinkOutputCallback(CVDisplayLinkRef displayLink, const CV vulkanExample->windowDidResize(); CVDisplayLinkStart(displayLink); } +*/ + +- (void)windowWillEnterFullScreen:(NSNotification *)notification +{ + vulkanExample->settings.fullscreen = true; +} + +- (void)windowWillExitFullScreen:(NSNotification *)notification +{ + vulkanExample->settings.fullscreen = false; +} - (BOOL)windowShouldClose:(NSWindow *)sender { @@ -1679,6 +1803,7 @@ static CVReturn displayLinkOutputCallback(CVDisplayLinkRef displayLink, const CV - (void)windowWillClose:(NSNotification *)notification { CVDisplayLinkStop(displayLink); + CVDisplayLinkRelease(displayLink); } @end @@ -1689,7 +1814,9 @@ void* VulkanExampleBase::setupWindow(void* view) #if defined(VK_EXAMPLE_XCODE_GENERATED) NSApp = [NSApplication sharedApplication]; [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; - [NSApp setDelegate:[AppDelegate new]]; + auto nsAppDelegate = [AppDelegate new]; + nsAppDelegate->vulkanExample = this; + [NSApp setDelegate:nsAppDelegate]; const auto kContentRect = NSMakeRect(0.0f, 0.0f, width, height); const auto kWindowStyle = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable; @@ -1702,6 +1829,9 @@ void* VulkanExampleBase::setupWindow(void* view) [window setAcceptsMouseMovedEvents:YES]; [window center]; [window makeKeyAndOrderFront:nil]; + if (settings.fullscreen) { + [window toggleFullScreen:nil]; + } auto nsView = [[View alloc] initWithFrame:kContentRect]; nsView->vulkanExample = this; @@ -1716,6 +1846,17 @@ void* VulkanExampleBase::setupWindow(void* view) void VulkanExampleBase::displayLinkOutputCb() { +#if defined(VK_EXAMPLE_XCODE_GENERATED) + if (benchmark.active) { + benchmark.run([=] { render(); }, vulkanDevice->properties); + if (benchmark.filename != "") { + benchmark.saveResults(); + } + quit = true; // SRS - quit NSApp rendering loop when benchmarking complete + return; + } +#endif + if (prepared) nextFrame(); } @@ -1895,9 +2036,8 @@ void VulkanExampleBase::handleEvent(const DFBWindowEvent *event) paused = !paused; break; case KEY_F1: - if (settings.overlay) { - settings.overlay = !settings.overlay; - } + UIOverlay.visible = !UIOverlay.visible; + UIOverlay.updated = true; break; default: break; @@ -2070,10 +2210,12 @@ void VulkanExampleBase::keyboardKey(struct wl_keyboard *keyboard, paused = !paused; break; case KEY_F1: - if (state && settings.overlay) - settings.overlay = !settings.overlay; + if (state) { + UIOverlay.visible = !UIOverlay.visible; + UIOverlay.updated = true; + } break; - case KEY_ESC: + case KEY_ESCAPE: quit = true; break; } @@ -2431,9 +2573,8 @@ void VulkanExampleBase::handleEvent(const xcb_generic_event_t *event) paused = !paused; break; case KEY_F1: - if (settings.overlay) { - settings.overlay = !settings.overlay; - } + UIOverlay.visible = !UIOverlay.visible; + UIOverlay.updated = true; break; } } @@ -2695,6 +2836,12 @@ void VulkanExampleBase::windowResize() destroyCommandBuffers(); createCommandBuffers(); buildCommandBuffers(); + + // SRS - Recreate fences in case number of swapchain images has changed on resize + for (auto& fence : waitFences) { + vkDestroyFence(device, fence, nullptr); + } + createSynchronizationPrimitives(); vkDeviceWaitIdle(device); @@ -2718,7 +2865,7 @@ void VulkanExampleBase::handleMouseMove(int32_t x, int32_t y) if (settings.overlay) { ImGuiIO& io = ImGui::GetIO(); - handled = io.WantCaptureMouse; + handled = io.WantCaptureMouse && UIOverlay.visible; } mouseMoved((float)x, (float)y, handled); @@ -2736,7 +2883,7 @@ void VulkanExampleBase::handleMouseMove(int32_t x, int32_t y) viewUpdated = true; } if (mouseButtons.middle) { - camera.translate(glm::vec3(-dx * 0.01f, -dy * 0.01f, 0.0f)); + camera.translate(glm::vec3(-dx * 0.005f, -dy * 0.005f, 0.0f)); viewUpdated = true; } mousePos = glm::vec2((float)x, (float)y); @@ -2765,7 +2912,7 @@ void VulkanExampleBase::initSwapchain() void VulkanExampleBase::setupSwapChain() { - swapChain.create(&width, &height, settings.vsync); + swapChain.create(&width, &height, settings.vsync, settings.fullscreen); } void VulkanExampleBase::OnUpdateUIOverlay(vks::UIOverlay *overlay) {} diff --git a/base/vulkanexamplebase.h b/base/vulkanexamplebase.h index 14644f6b..9f814cf9 100644 --- a/base/vulkanexamplebase.h +++ b/base/vulkanexamplebase.h @@ -96,7 +96,6 @@ class VulkanExampleBase { private: std::string getWindowTitle(); - bool viewUpdated = false; uint32_t destWidth; uint32_t destHeight; bool resizing = false; @@ -119,7 +118,7 @@ protected: // Frame counter to display fps uint32_t frameCounter = 0; uint32_t lastFPS = 0; - std::chrono::time_point lastTimestamp; + std::chrono::time_point lastTimestamp, tPrevEnd; // Vulkan instance, stores all per-application states VkInstance instance; std::vector supportedInstanceExtensions; @@ -177,6 +176,7 @@ protected: public: bool prepared = false; bool resized = false; + bool viewUpdated = false; uint32_t width = 1280; uint32_t height = 720; @@ -254,6 +254,9 @@ public: int64_t lastTapTime = 0; #elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK)) void* view; +#if defined(VK_EXAMPLE_XCODE_GENERATED) + bool quit = false; +#endif #elif defined(VK_USE_PLATFORM_DIRECTFB_EXT) bool quit = false; IDirectFB *dfb = nullptr; diff --git a/bin/benchmark-all.py b/bin/benchmark-all.py index 78773df2..2bb6fe43 100644 --- a/bin/benchmark-all.py +++ b/bin/benchmark-all.py @@ -10,38 +10,57 @@ EXAMPLES = [ "computecullandlod", "computenbody", "computeparticles", + "computeraytracing", "computeshader", + "conditionalrender", + "conservativeraster", "debugmarker", "deferred", "deferredmultisampling", "deferredshadows", + "descriptorindexing", + "descriptorsets", "displacement", "distancefieldfonts", + "dynamicrendering", "dynamicuniformbuffer", "gears", "geometryshader", + "gltfloading", + "gltfscenerendering", + "gltfskinning", + "graphicspipelinelibrary", "hdr", "imgui", "indirectdraw", + "inlineuniformblocks", + "inputattachments", "instancing", - "mesh", "multisampling", "multithreading", + "multiview", + "negativeviewportheight", "occlusionquery", "offscreen", + "oit", "parallaxmapping", "particlefire", "pbrbasic", "pbribl", "pbrtexture", "pipelines", + "pipelinestatistics", "pushconstants", + "pushdescriptors", "radialblur", - "raytracing", - "scenerendering", + "rayquery", + "raytracingbasic", + "raytracingcallable", + "raytracingreflections", + "raytracingshadows", "shadowmapping", + "shadowmappingcascade", "shadowmappingomni", - "skeletalanimation", "specializationconstants", "sphericalenvmapping", "ssao", @@ -54,9 +73,12 @@ EXAMPLES = [ "texture3d", "texturearray", "texturecubemap", + "texturecubemaparray", "texturemipmapgen", "texturesparseresidency", "triangle", + "variablerateshading", + "vertexattributes", "viewportarray", "vulkanscene" ] @@ -71,7 +93,7 @@ os.makedirs("./benchmark", exist_ok=True) for example in EXAMPLES: print("---- (%d/%d) Running %s in benchmark mode ----" % (CURR_INDEX+1, len(EXAMPLES), example)) - if platform.system() == 'Linux': + if platform.system() == 'Linux' or platform.system() == 'Darwin': RESULT_CODE = subprocess.call("./%s %s -bf ./benchmark/%s.csv 5" % (example, ARGS, example), shell=True) else: RESULT_CODE = subprocess.call("%s %s -bf ./benchmark/%s.csv 5" % (example, ARGS, example)) diff --git a/data/shaders/glsl/conservativeraster/fullscreen.frag b/data/shaders/glsl/conservativeraster/fullscreen.frag index e5c1e497..b46ee0d3 100644 --- a/data/shaders/glsl/conservativeraster/fullscreen.frag +++ b/data/shaders/glsl/conservativeraster/fullscreen.frag @@ -1,6 +1,6 @@ #version 450 -layout (binding = 1) uniform sampler2D samplerColor; +layout (binding = 0) uniform sampler2D samplerColor; layout (location = 0) in vec2 inUV; layout (location = 0) out vec4 outFragColor; diff --git a/data/shaders/glsl/conservativeraster/fullscreen.frag.spv b/data/shaders/glsl/conservativeraster/fullscreen.frag.spv index 401a7434..a4aedf4a 100644 Binary files a/data/shaders/glsl/conservativeraster/fullscreen.frag.spv and b/data/shaders/glsl/conservativeraster/fullscreen.frag.spv differ diff --git a/data/shaders/glsl/gltfloading/mesh.frag b/data/shaders/glsl/gltfloading/mesh.frag index fb415cef..866dd316 100644 --- a/data/shaders/glsl/gltfloading/mesh.frag +++ b/data/shaders/glsl/gltfloading/mesh.frag @@ -17,7 +17,7 @@ void main() vec3 N = normalize(inNormal); vec3 L = normalize(inLightVec); vec3 V = normalize(inViewVec); - vec3 R = reflect(-L, N); + vec3 R = reflect(L, N); vec3 diffuse = max(dot(N, L), 0.15) * inColor; vec3 specular = pow(max(dot(R, V), 0.0), 16.0) * vec3(0.75); outFragColor = vec4(diffuse * color.rgb + specular, 1.0); diff --git a/data/shaders/glsl/gltfloading/mesh.frag.spv b/data/shaders/glsl/gltfloading/mesh.frag.spv index 5cd56265..00c5c46a 100644 Binary files a/data/shaders/glsl/gltfloading/mesh.frag.spv and b/data/shaders/glsl/gltfloading/mesh.frag.spv differ diff --git a/data/shaders/glsl/gltfloading/mesh.vert b/data/shaders/glsl/gltfloading/mesh.vert index 2760684e..e2da4ece 100644 --- a/data/shaders/glsl/gltfloading/mesh.vert +++ b/data/shaders/glsl/gltfloading/mesh.vert @@ -10,6 +10,7 @@ layout (set = 0, binding = 0) uniform UBOScene mat4 projection; mat4 view; vec4 lightPos; + vec4 viewPos; } uboScene; layout(push_constant) uniform PushConsts { @@ -32,6 +33,6 @@ void main() vec4 pos = uboScene.view * vec4(inPos, 1.0); outNormal = mat3(uboScene.view) * inNormal; vec3 lPos = mat3(uboScene.view) * uboScene.lightPos.xyz; - outLightVec = lPos - pos.xyz; - outViewVec = -pos.xyz; + outLightVec = uboScene.lightPos.xyz - pos.xyz; + outViewVec = uboScene.viewPos.xyz - pos.xyz; } \ No newline at end of file diff --git a/data/shaders/glsl/gltfloading/mesh.vert.spv b/data/shaders/glsl/gltfloading/mesh.vert.spv index cf6fc4ac..4fe54ca9 100644 Binary files a/data/shaders/glsl/gltfloading/mesh.vert.spv and b/data/shaders/glsl/gltfloading/mesh.vert.spv differ diff --git a/data/shaders/glsl/offscreen/mirror.frag b/data/shaders/glsl/offscreen/mirror.frag index 9c784dc2..faa75c59 100644 --- a/data/shaders/glsl/offscreen/mirror.frag +++ b/data/shaders/glsl/offscreen/mirror.frag @@ -2,8 +2,7 @@ layout (binding = 1) uniform sampler2D samplerColor; -layout (location = 0) in vec2 inUV; -layout (location = 1) in vec4 inPos; +layout (location = 0) in vec4 inPos; layout (location = 0) out vec4 outFragColor; diff --git a/data/shaders/glsl/offscreen/mirror.frag.spv b/data/shaders/glsl/offscreen/mirror.frag.spv index 7f382743..a94d88da 100644 Binary files a/data/shaders/glsl/offscreen/mirror.frag.spv and b/data/shaders/glsl/offscreen/mirror.frag.spv differ diff --git a/data/shaders/glsl/offscreen/mirror.vert b/data/shaders/glsl/offscreen/mirror.vert index 738333fe..f0941fad 100644 --- a/data/shaders/glsl/offscreen/mirror.vert +++ b/data/shaders/glsl/offscreen/mirror.vert @@ -1,7 +1,6 @@ #version 450 layout (location = 0) in vec3 inPos; -layout (location = 1) in vec2 inUV; layout (binding = 0) uniform UBO { @@ -10,12 +9,10 @@ layout (binding = 0) uniform UBO mat4 model; } ubo; -layout (location = 0) out vec2 outUV; -layout (location = 1) out vec4 outPos; +layout (location = 0) out vec4 outPos; void main() { - outUV = inUV; outPos = ubo.projection * ubo.view * ubo.model * vec4(inPos.xyz, 1.0); gl_Position = outPos; } diff --git a/data/shaders/glsl/offscreen/mirror.vert.spv b/data/shaders/glsl/offscreen/mirror.vert.spv index 16b29306..7a7977e3 100644 Binary files a/data/shaders/glsl/offscreen/mirror.vert.spv and b/data/shaders/glsl/offscreen/mirror.vert.spv differ diff --git a/data/shaders/glsl/texturemipmapgen/texture.frag b/data/shaders/glsl/texturemipmapgen/texture.frag index edb92b59..3717d5ec 100644 --- a/data/shaders/glsl/texturemipmapgen/texture.frag +++ b/data/shaders/glsl/texturemipmapgen/texture.frag @@ -5,16 +5,25 @@ layout (set = 0, binding = 2) uniform sampler samplers[3]; layout (location = 0) in vec2 inUV; layout (location = 1) in float inLodBias; -layout (location = 2) flat in int inSamplerIndex; -layout (location = 3) in vec3 inNormal; -layout (location = 4) in vec3 inViewVec; -layout (location = 5) in vec3 inLightVec; +layout (location = 2) in vec3 inNormal; +layout (location = 3) in vec3 inViewVec; +layout (location = 4) in vec3 inLightVec; + +layout (binding = 0) uniform UBO +{ + mat4 projection; + mat4 view; + mat4 model; + vec4 viewPos; + float lodBias; + int samplerIndex; +} ubo; layout (location = 0) out vec4 outFragColor; void main() { - vec4 color = texture(sampler2D(textureColor, samplers[inSamplerIndex]), inUV, inLodBias); + vec4 color = texture(sampler2D(textureColor, samplers[uniform.samplerIndex]), inUV, inLodBias); vec3 N = normalize(inNormal); vec3 L = normalize(inLightVec); diff --git a/data/shaders/glsl/texturemipmapgen/texture.vert b/data/shaders/glsl/texturemipmapgen/texture.vert index 55770880..5d04b795 100644 --- a/data/shaders/glsl/texturemipmapgen/texture.vert +++ b/data/shaders/glsl/texturemipmapgen/texture.vert @@ -16,21 +16,14 @@ layout (binding = 0) uniform UBO layout (location = 0) out vec2 outUV; layout (location = 1) out float outLodBias; -layout (location = 2) flat out int outSamplerIndex; -layout (location = 3) out vec3 outNormal; -layout (location = 4) out vec3 outViewVec; -layout (location = 5) out vec3 outLightVec; - -out gl_PerVertex -{ - vec4 gl_Position; -}; +layout (location = 2) out vec3 outNormal; +layout (location = 3) out vec3 outViewVec; +layout (location = 4) out vec3 outLightVec; void main() { outUV = inUV * vec2(2.0, 1.0); outLodBias = ubo.lodBias; - outSamplerIndex = ubo.samplerIndex; vec3 worldPos = vec3(ubo.model * vec4(inPos, 1.0)); diff --git a/data/shaders/hlsl/gltfloading/mesh.frag b/data/shaders/hlsl/gltfloading/mesh.frag index 914421a0..a574c7a1 100644 --- a/data/shaders/hlsl/gltfloading/mesh.frag +++ b/data/shaders/hlsl/gltfloading/mesh.frag @@ -24,7 +24,7 @@ float4 main(VSOutput input) : SV_TARGET float3 N = normalize(input.Normal); float3 L = normalize(input.LightVec); float3 V = normalize(input.ViewVec); - float3 R = reflect(-L, N); + float3 R = reflect(L, N); float3 diffuse = max(dot(N, L), 0.0) * input.Color; float3 specular = pow(max(dot(R, V), 0.0), 16.0) * float3(0.75, 0.75, 0.75); return float4(diffuse * color.rgb + specular, 1.0); diff --git a/data/shaders/hlsl/gltfloading/mesh.frag.spv b/data/shaders/hlsl/gltfloading/mesh.frag.spv index a801c5f2..4eafff86 100644 Binary files a/data/shaders/hlsl/gltfloading/mesh.frag.spv and b/data/shaders/hlsl/gltfloading/mesh.frag.spv differ diff --git a/data/shaders/hlsl/gltfloading/mesh.vert b/data/shaders/hlsl/gltfloading/mesh.vert index a47967ac..3f46fbc5 100644 --- a/data/shaders/hlsl/gltfloading/mesh.vert +++ b/data/shaders/hlsl/gltfloading/mesh.vert @@ -13,6 +13,7 @@ struct UBO float4x4 projection; float4x4 view; float4 lightPos; + float4 viewPos; }; cbuffer ubo : register(b0) { UBO ubo; } @@ -42,8 +43,7 @@ VSOutput main(VSInput input) float4 pos = mul(ubo.view, float4(input.Pos, 1.0)); output.Normal = mul((float3x3)ubo.view, input.Normal); - float3 lPos = mul((float3x3)ubo.view, ubo.lightPos.xyz); - output.LightVec = lPos - pos.xyz; - output.ViewVec = -pos.xyz; + output.LightVec = ubo.lightPos.xyz - pos.xyz; + output.ViewVec = ubo.viewPos.xyz - pos.xyz; return output; } \ No newline at end of file diff --git a/data/shaders/hlsl/gltfloading/mesh.vert.spv b/data/shaders/hlsl/gltfloading/mesh.vert.spv index 3061fec4..612219e6 100644 Binary files a/data/shaders/hlsl/gltfloading/mesh.vert.spv and b/data/shaders/hlsl/gltfloading/mesh.vert.spv differ diff --git a/data/shaders/hlsl/offscreen/mirror.frag b/data/shaders/hlsl/offscreen/mirror.frag index b9c68b7e..72a3aa73 100644 --- a/data/shaders/hlsl/offscreen/mirror.frag +++ b/data/shaders/hlsl/offscreen/mirror.frag @@ -5,8 +5,7 @@ SamplerState samplerColor : register(s1); struct VSOutput { -[[vk::location(0)]] float2 UV : TEXCOORD0; -[[vk::location(1)]] float4 ProjCoord : POSITION0; +[[vk::location(0)]] float4 ProjCoord : POSITION0; }; float4 main(VSOutput input, bool FrontFacing : SV_IsFrontFace) : SV_TARGET diff --git a/data/shaders/hlsl/offscreen/mirror.frag.spv b/data/shaders/hlsl/offscreen/mirror.frag.spv index 89f23ca2..ff33a17b 100644 Binary files a/data/shaders/hlsl/offscreen/mirror.frag.spv and b/data/shaders/hlsl/offscreen/mirror.frag.spv differ diff --git a/data/shaders/hlsl/offscreen/mirror.vert b/data/shaders/hlsl/offscreen/mirror.vert index 671a3138..f7c547eb 100644 --- a/data/shaders/hlsl/offscreen/mirror.vert +++ b/data/shaders/hlsl/offscreen/mirror.vert @@ -3,7 +3,6 @@ struct VSInput { [[vk::location(0)]] float3 Pos : POSITION0; -[[vk::location(1)]] float2 UV : TEXCOORD0; }; struct UBO @@ -18,14 +17,12 @@ cbuffer ubo : register(b0) { UBO ubo; } struct VSOutput { float4 Pos : SV_POSITION; -[[vk::location(0)]] float2 UV : TEXCOORD0; -[[vk::location(1)]] float4 ProjCoord : POSITION0; +[[vk::location(0)]] float4 ProjCoord : POSITION0; }; VSOutput main(VSInput input) { VSOutput output = (VSOutput)0; - output.UV = input.UV; output.ProjCoord = mul(ubo.projection, mul(ubo.view, mul(ubo.model, float4(input.Pos.xyz, 1.0)))); output.Pos = output.ProjCoord; return output; diff --git a/data/shaders/hlsl/offscreen/mirror.vert.spv b/data/shaders/hlsl/offscreen/mirror.vert.spv index 6c1d5e98..83e55df2 100644 Binary files a/data/shaders/hlsl/offscreen/mirror.vert.spv and b/data/shaders/hlsl/offscreen/mirror.vert.spv differ diff --git a/data/shaders/hlsl/texturemipmapgen/texture.frag b/data/shaders/hlsl/texturemipmapgen/texture.frag index 9f58e19d..b14d63d1 100644 --- a/data/shaders/hlsl/texturemipmapgen/texture.frag +++ b/data/shaders/hlsl/texturemipmapgen/texture.frag @@ -3,19 +3,30 @@ Texture2D textureColor : register(t1); SamplerState samplers[3] : register(s2); +struct UBO +{ + float4x4 projection; + float4x4 view; + float4x4 model; + float4 viewPos; + float lodBias; + int samplerIndex; +}; + +cbuffer ubo : register(b0) { UBO ubo; } + struct VSOutput { [[vk::location(0)]] float2 UV : TEXCOORD0; [[vk::location(1)]] float LodBias : TEXCOORD3; -[[vk::location(2)]] int SamplerIndex : TEXCOORD4; -[[vk::location(3)]] float3 Normal : NORMAL0; -[[vk::location(4)]] float3 ViewVec : TEXCOORD1; -[[vk::location(5)]] float3 LightVec : TEXCOORD2; +[[vk::location(2)]] float3 Normal : NORMAL0; +[[vk::location(3)]] float3 ViewVec : TEXCOORD1; +[[vk::location(4)]] float3 LightVec : TEXCOORD2; }; float4 main(VSOutput input) : SV_TARGET { - float4 color = textureColor.Sample(samplers[input.SamplerIndex], input.UV, int2(0, 0), input.LodBias); + float4 color = textureColor.Sample(samplers[ubo.samplerIndex], input.UV, int2(0, 0), input.LodBias); float3 N = normalize(input.Normal); float3 L = normalize(input.LightVec); diff --git a/data/shaders/hlsl/texturemipmapgen/texture.frag.spv b/data/shaders/hlsl/texturemipmapgen/texture.frag.spv index 89a19160..838dd550 100644 Binary files a/data/shaders/hlsl/texturemipmapgen/texture.frag.spv and b/data/shaders/hlsl/texturemipmapgen/texture.frag.spv differ diff --git a/data/shaders/hlsl/texturemipmapgen/texture.vert b/data/shaders/hlsl/texturemipmapgen/texture.vert index 8b5f3036..6bcd982d 100644 --- a/data/shaders/hlsl/texturemipmapgen/texture.vert +++ b/data/shaders/hlsl/texturemipmapgen/texture.vert @@ -24,10 +24,9 @@ struct VSOutput float4 Pos : SV_POSITION; [[vk::location(0)]] float2 UV : TEXCOORD0; [[vk::location(1)]] float LodBias : TEXCOORD3; -[[vk::location(2)]] int SamplerIndex : TEXCOORD4; -[[vk::location(3)]] float3 Normal : NORMAL0; -[[vk::location(4)]] float3 ViewVec : TEXCOORD1; -[[vk::location(5)]] float3 LightVec : TEXCOORD2; +[[vk::location(2)]] float3 Normal : NORMAL0; +[[vk::location(3)]] float3 ViewVec : TEXCOORD1; +[[vk::location(4)]] float3 LightVec : TEXCOORD2; }; VSOutput main(VSInput input) @@ -35,7 +34,6 @@ VSOutput main(VSInput input) VSOutput output = (VSOutput)0; output.UV = input.UV * float2(2.0, 1.0); output.LodBias = ubo.lodBias; - output.SamplerIndex = ubo.samplerIndex; float3 worldPos = mul(ubo.model, float4(input.Pos, 1.0)).xyz; diff --git a/data/shaders/hlsl/texturemipmapgen/texture.vert.spv b/data/shaders/hlsl/texturemipmapgen/texture.vert.spv index de4cb544..cbfc816b 100644 Binary files a/data/shaders/hlsl/texturemipmapgen/texture.vert.spv and b/data/shaders/hlsl/texturemipmapgen/texture.vert.spv differ diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 45a0b43f..e8a04ae2 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -11,6 +11,26 @@ function(buildExample EXAMPLE_NAME) if(EXISTS ${EXAMPLE_FOLDER}/${EXAMPLE_NAME}.h) SET(MAIN_HEADER ${EXAMPLE_FOLDER}/${EXAMPLE_NAME}.h) ENDIF() + if(APPLE) + # SRS - Use MacPorts paths as default since the same on x86 and Apple Silicon, can override for homebrew on cmake command line + if(NOT OpenMP_omp_LIBRARY AND EXISTS /opt/local/lib/libomp/libomp.dylib) + set(OpenMP_omp_LIBRARY /opt/local/lib/libomp/libomp.dylib) + endif() + if(CMAKE_C_COMPILER_ID MATCHES "Clang\$") + set(OpenMP_C_FLAGS "-Xclang -fopenmp") + set(OpenMP_C_LIB_NAMES "omp") + if(NOT OpenMP_C_INCLUDE_DIR AND EXISTS /opt/local/include/libomp) + set(OpenMP_C_INCLUDE_DIR /opt/local/include/libomp) + endif() + endif() + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang\$") + set(OpenMP_CXX_FLAGS "-Xclang -fopenmp") + set(OpenMP_CXX_LIB_NAMES "omp") + if(NOT OpenMP_CXX_INCLUDE_DIR AND EXISTS /opt/local/include/libomp) + set(OpenMP_CXX_INCLUDE_DIR /opt/local/include/libomp) + endif() + endif() + endif() find_package(OpenMP) # imgui example requires additional source files IF(${EXAMPLE_NAME} STREQUAL "imgui") @@ -39,12 +59,9 @@ function(buildExample EXAMPLE_NAME) endif(WIN32) set_target_properties(${EXAMPLE_NAME} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/bin) - if(OpenMP_CXX_FOUND) - target_compile_options(${EXAMPLE_NAME} PRIVATE ${OpenMP_CXX_FLAGS}) - IF(${EXAMPLE_NAME} STREQUAL "texture3d") - if(OpenMP_CXX_FOUND) - target_link_libraries(${EXAMPLE_NAME} OpenMP::OpenMP_CXX) - endif() + if(${EXAMPLE_NAME} STREQUAL "texture3d") + if(OpenMP_CXX_FOUND) + target_link_libraries(${EXAMPLE_NAME} OpenMP::OpenMP_CXX) endif() endif() diff --git a/examples/computecloth/computecloth.cpp b/examples/computecloth/computecloth.cpp index b08fd55c..5d4ae92a 100644 --- a/examples/computecloth/computecloth.cpp +++ b/examples/computecloth/computecloth.cpp @@ -101,6 +101,7 @@ public: ~VulkanExample() { // Graphics + graphics.indices.destroy(); graphics.uniformBuffer.destroy(); vkDestroyPipeline(device, graphics.pipelines.cloth, nullptr); vkDestroyPipeline(device, graphics.pipelines.sphere, nullptr); @@ -135,12 +136,12 @@ public: textureCloth.loadFromFile(getAssetPath() + "textures/vulkan_cloth_rgba.ktx", VK_FORMAT_R8G8B8A8_UNORM, vulkanDevice, queue); } - void addGraphicsToComputeBarriers(VkCommandBuffer commandBuffer) + void addGraphicsToComputeBarriers(VkCommandBuffer commandBuffer, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask) { if (specializedComputeQueue) { VkBufferMemoryBarrier bufferBarrier = vks::initializers::bufferMemoryBarrier(); - bufferBarrier.srcAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; - bufferBarrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + bufferBarrier.srcAccessMask = srcAccessMask; + bufferBarrier.dstAccessMask = dstAccessMask; bufferBarrier.srcQueueFamilyIndex = vulkanDevice->queueFamilyIndices.graphics; bufferBarrier.dstQueueFamilyIndex = vulkanDevice->queueFamilyIndices.compute; bufferBarrier.size = VK_WHOLE_SIZE; @@ -151,8 +152,8 @@ public: bufferBarrier.buffer = compute.storageBuffers.output.buffer; bufferBarriers.push_back(bufferBarrier); vkCmdPipelineBarrier(commandBuffer, - VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, - VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + srcStageMask, + dstStageMask, VK_FLAGS_NONE, 0, nullptr, static_cast(bufferBarriers.size()), bufferBarriers.data(), @@ -165,8 +166,8 @@ public: VkBufferMemoryBarrier bufferBarrier = vks::initializers::bufferMemoryBarrier(); bufferBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; bufferBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - bufferBarrier.srcQueueFamilyIndex = vulkanDevice->queueFamilyIndices.compute; - bufferBarrier.dstQueueFamilyIndex = vulkanDevice->queueFamilyIndices.compute; + bufferBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + bufferBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; bufferBarrier.size = VK_WHOLE_SIZE; std::vector bufferBarriers; bufferBarrier.buffer = compute.storageBuffers.input.buffer; @@ -183,12 +184,12 @@ public: 0, nullptr); } - void addComputeToGraphicsBarriers(VkCommandBuffer commandBuffer) + void addComputeToGraphicsBarriers(VkCommandBuffer commandBuffer, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask) { if (specializedComputeQueue) { VkBufferMemoryBarrier bufferBarrier = vks::initializers::bufferMemoryBarrier(); - bufferBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; - bufferBarrier.dstAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; + bufferBarrier.srcAccessMask = srcAccessMask; + bufferBarrier.dstAccessMask = dstAccessMask; bufferBarrier.srcQueueFamilyIndex = vulkanDevice->queueFamilyIndices.compute; bufferBarrier.dstQueueFamilyIndex = vulkanDevice->queueFamilyIndices.graphics; bufferBarrier.size = VK_WHOLE_SIZE; @@ -199,8 +200,8 @@ public: bufferBarriers.push_back(bufferBarrier); vkCmdPipelineBarrier( commandBuffer, - VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, - VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, + srcStageMask, + dstStageMask, VK_FLAGS_NONE, 0, nullptr, static_cast(bufferBarriers.size()), bufferBarriers.data(), @@ -233,7 +234,7 @@ public: VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo)); // Acquire storage buffers from compute queue - addComputeToGraphicsBarriers(drawCmdBuffers[i]); + addComputeToGraphicsBarriers(drawCmdBuffers[i], 0, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT); // Draw the particle system using the update vertex buffer @@ -266,7 +267,7 @@ public: vkCmdEndRenderPass(drawCmdBuffers[i]); // release the storage buffers to the compute queue - addGraphicsToComputeBarriers(drawCmdBuffers[i]); + addGraphicsToComputeBarriers(drawCmdBuffers[i], VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, 0, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT); VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i])); } @@ -284,7 +285,7 @@ public: VK_CHECK_RESULT(vkBeginCommandBuffer(compute.commandBuffers[i], &cmdBufInfo)); // Acquire the storage buffers from the graphics queue - addGraphicsToComputeBarriers(compute.commandBuffers[i]); + addGraphicsToComputeBarriers(compute.commandBuffers[i], 0, VK_ACCESS_SHADER_WRITE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); vkCmdBindPipeline(compute.commandBuffers[i], VK_PIPELINE_BIND_POINT_COMPUTE, compute.pipeline); @@ -312,7 +313,7 @@ public: } // release the storage buffers back to the graphics queue - addComputeToGraphicsBarriers(compute.commandBuffers[i]); + addComputeToGraphicsBarriers(compute.commandBuffers[i], VK_ACCESS_SHADER_WRITE_BIT, 0, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT); vkEndCommandBuffer(compute.commandBuffers[i]); } } @@ -395,7 +396,7 @@ public: // Add an initial release barrier to the graphics queue, // so that when the compute command buffer executes for the first time // it doesn't complain about a lack of a corresponding "release" to its "acquire" - addGraphicsToComputeBarriers(copyCmd); + addGraphicsToComputeBarriers(copyCmd, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, 0, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT); vulkanDevice->flushCommandBuffer(copyCmd, queue, true); stagingBuffer.destroy(); @@ -670,13 +671,14 @@ public: void updateComputeUBO() { if (!paused) { - compute.ubo.deltaT = 0.000005f; + //compute.ubo.deltaT = 0.000005f; // todo: base on frametime - //compute.ubo.deltaT = frameTimer * 0.0075f; + // SRS - Clamp frameTimer to max 20ms refresh period (e.g. if blocked on resize), otherwise image breakup can occur + compute.ubo.deltaT = fmin(frameTimer, 0.02) * 0.0025f; if (simulateWind) { std::default_random_engine rndEngine(benchmark.active ? 0 : (unsigned)time(nullptr)); - std::uniform_real_distribution rd(1.0f, 6.0f); + std::uniform_real_distribution rd(1.0f, 12.0f); compute.ubo.gravity.x = cos(glm::radians(-timer * 360.0f)) * (rd(rndEngine) - rd(rndEngine)); compute.ubo.gravity.z = sin(glm::radians(timer * 360.0f)) * (rd(rndEngine) - rd(rndEngine)); } diff --git a/examples/computecullandlod/computecullandlod.cpp b/examples/computecullandlod/computecullandlod.cpp index c1888659..5b5296d5 100644 --- a/examples/computecullandlod/computecullandlod.cpp +++ b/examples/computecullandlod/computecullandlod.cpp @@ -149,6 +149,32 @@ public: VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo)); + // Acquire barrier + if (vulkanDevice->queueFamilyIndices.graphics != vulkanDevice->queueFamilyIndices.compute) + { + VkBufferMemoryBarrier buffer_barrier = + { + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, + nullptr, + 0, + VK_ACCESS_INDIRECT_COMMAND_READ_BIT, + vulkanDevice->queueFamilyIndices.compute, + vulkanDevice->queueFamilyIndices.graphics, + indirectCommandsBuffer.buffer, + 0, + indirectCommandsBuffer.descriptor.range + }; + + vkCmdPipelineBarrier( + drawCmdBuffers[i], + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, + 0, + 0, nullptr, + 1, &buffer_barrier, + 0, nullptr); + } + vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); VkViewport viewport = vks::initializers::viewport((float)width, (float)height, 0.0f, 1.0f); @@ -169,7 +195,7 @@ public: if (vulkanDevice->features.multiDrawIndirect) { - vkCmdDrawIndexedIndirect(drawCmdBuffers[i], indirectCommandsBuffer.buffer, 0, indirectCommands.size(), sizeof(VkDrawIndexedIndirectCommand)); + vkCmdDrawIndexedIndirect(drawCmdBuffers[i], indirectCommandsBuffer.buffer, 0, static_cast(indirectCommands.size()), sizeof(VkDrawIndexedIndirectCommand)); } else { @@ -184,6 +210,32 @@ public: vkCmdEndRenderPass(drawCmdBuffers[i]); + // Release barrier + if (vulkanDevice->queueFamilyIndices.graphics != vulkanDevice->queueFamilyIndices.compute) + { + VkBufferMemoryBarrier buffer_barrier = + { + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, + nullptr, + VK_ACCESS_INDIRECT_COMMAND_READ_BIT, + 0, + vulkanDevice->queueFamilyIndices.graphics, + vulkanDevice->queueFamilyIndices.compute, + indirectCommandsBuffer.buffer, + 0, + indirectCommandsBuffer.descriptor.range + }; + + vkCmdPipelineBarrier( + drawCmdBuffers[i], + VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + 0, + 0, nullptr, + 1, &buffer_barrier, + 0, nullptr); + } + VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i])); } } @@ -200,23 +252,32 @@ public: VK_CHECK_RESULT(vkBeginCommandBuffer(compute.commandBuffer, &cmdBufInfo)); + // Acquire barrier // Add memory barrier to ensure that the indirect commands have been consumed before the compute shader updates them - VkBufferMemoryBarrier bufferBarrier = vks::initializers::bufferMemoryBarrier(); - bufferBarrier.buffer = indirectCommandsBuffer.buffer; - bufferBarrier.size = indirectCommandsBuffer.descriptor.range; - bufferBarrier.srcAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT; - bufferBarrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT; - bufferBarrier.srcQueueFamilyIndex = vulkanDevice->queueFamilyIndices.graphics; - bufferBarrier.dstQueueFamilyIndex = vulkanDevice->queueFamilyIndices.compute; + if (vulkanDevice->queueFamilyIndices.graphics != vulkanDevice->queueFamilyIndices.compute) + { + VkBufferMemoryBarrier buffer_barrier = + { + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, + nullptr, + 0, + VK_ACCESS_SHADER_WRITE_BIT, + vulkanDevice->queueFamilyIndices.graphics, + vulkanDevice->queueFamilyIndices.compute, + indirectCommandsBuffer.buffer, + 0, + indirectCommandsBuffer.descriptor.range + }; - vkCmdPipelineBarrier( - compute.commandBuffer, - VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, - VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, - VK_FLAGS_NONE, - 0, nullptr, - 1, &bufferBarrier, - 0, nullptr); + vkCmdPipelineBarrier( + compute.commandBuffer, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_FLAGS_NONE, + 0, nullptr, + 1, &buffer_barrier, + 0, nullptr); + } vkCmdBindPipeline(compute.commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, compute.pipeline); vkCmdBindDescriptorSets(compute.commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, compute.pipelineLayout, 0, 1, &compute.descriptorSet, 0, 0); @@ -226,22 +287,32 @@ public: // It also determines the lod to use depending on distance to the viewer. vkCmdDispatch(compute.commandBuffer, objectCount / 16, 1, 1); + // Release barrier // Add memory barrier to ensure that the compute shader has finished writing the indirect command buffer before it's consumed - bufferBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; - bufferBarrier.dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT; - bufferBarrier.buffer = indirectCommandsBuffer.buffer; - bufferBarrier.size = indirectCommandsBuffer.descriptor.range; - bufferBarrier.srcQueueFamilyIndex = vulkanDevice->queueFamilyIndices.compute; - bufferBarrier.dstQueueFamilyIndex = vulkanDevice->queueFamilyIndices.graphics; + if (vulkanDevice->queueFamilyIndices.graphics != vulkanDevice->queueFamilyIndices.compute) + { + VkBufferMemoryBarrier buffer_barrier = + { + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, + nullptr, + VK_ACCESS_SHADER_WRITE_BIT, + 0, + vulkanDevice->queueFamilyIndices.compute, + vulkanDevice->queueFamilyIndices.graphics, + indirectCommandsBuffer.buffer, + 0, + indirectCommandsBuffer.descriptor.range + }; - vkCmdPipelineBarrier( - compute.commandBuffer, - VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, - VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, - VK_FLAGS_NONE, - 0, nullptr, - 1, &bufferBarrier, - 0, nullptr); + vkCmdPipelineBarrier( + compute.commandBuffer, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + VK_FLAGS_NONE, + 0, nullptr, + 1, &buffer_barrier, + 0, nullptr); + } // todo: barrier for indirect stats buffer? @@ -424,7 +495,38 @@ public: &instanceBuffer, stagingBuffer.size)); - vulkanDevice->copyBuffer(&stagingBuffer, &instanceBuffer, queue); + // Copy from staging buffer to instance buffer + VkCommandBuffer copyCmd = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); + VkBufferCopy copyRegion = {}; + copyRegion.size = stagingBuffer.size; + vkCmdCopyBuffer(copyCmd, stagingBuffer.buffer, instanceBuffer.buffer, 1, ©Region); + // Add an initial release barrier to the graphics queue, + // so that when the compute command buffer executes for the first time + // it doesn't complain about a lack of a corresponding "release" to its "acquire" + if (vulkanDevice->queueFamilyIndices.graphics != vulkanDevice->queueFamilyIndices.compute) + { VkBufferMemoryBarrier buffer_barrier = + { + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, + nullptr, + VK_ACCESS_INDIRECT_COMMAND_READ_BIT, + 0, + vulkanDevice->queueFamilyIndices.graphics, + vulkanDevice->queueFamilyIndices.compute, + indirectCommandsBuffer.buffer, + 0, + indirectCommandsBuffer.descriptor.range + }; + + vkCmdPipelineBarrier( + copyCmd, + VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + 0, + 0, nullptr, + 1, &buffer_barrier, + 0, nullptr); + } + vulkanDevice->flushCommandBuffer(copyCmd, queue, true); stagingBuffer.destroy(); @@ -710,6 +812,11 @@ public: } } + virtual void viewChanged() + { + updateUniformBuffer(true); + } + virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { if (overlay->header("Settings")) { @@ -726,4 +833,4 @@ public: } }; -VULKAN_EXAMPLE_MAIN() \ No newline at end of file +VULKAN_EXAMPLE_MAIN() diff --git a/examples/computeheadless/computeheadless.cpp b/examples/computeheadless/computeheadless.cpp index 5095222d..d11a2235 100644 --- a/examples/computeheadless/computeheadless.cpp +++ b/examples/computeheadless/computeheadless.cpp @@ -26,6 +26,9 @@ #include #include +#if defined(VK_USE_PLATFORM_MACOS_MVK) +#define VK_ENABLE_BETA_EXTENSIONS +#endif #include #include "VulkanTools.h" @@ -145,9 +148,10 @@ public: const char* validationLayers[] = { "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation", "VK_LAYER_LUNARG_object_tracker","VK_LAYER_LUNARG_core_validation", "VK_LAYER_LUNARG_swapchain", "VK_LAYER_GOOGLE_unique_objects" }; layerCount = 6; #else - const char* validationLayers[] = { "VK_LAYER_LUNARG_standard_validation" }; + const char* validationLayers[] = { "VK_LAYER_KHRONOS_validation" }; layerCount = 1; #endif + std::vector instanceExtensions = {}; #if DEBUG // Check if layers are available uint32_t instanceLayerCount; @@ -170,14 +174,39 @@ public: } } - const char *validationExt = VK_EXT_DEBUG_REPORT_EXTENSION_NAME; if (layersAvailable) { + instanceExtensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME); instanceCreateInfo.ppEnabledLayerNames = validationLayers; instanceCreateInfo.enabledLayerCount = layerCount; - instanceCreateInfo.enabledExtensionCount = 1; - instanceCreateInfo.ppEnabledExtensionNames = &validationExt; } #endif +#if defined(VK_USE_PLATFORM_MACOS_MVK) + // SRS - When running on macOS with MoltenVK, enable VK_KHR_get_physical_device_properties2 (required by VK_KHR_portability_subset) + instanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); +#if defined(VK_KHR_portability_enumeration) + // SRS - When running on macOS with MoltenVK and VK_KHR_portability_enumeration is defined and supported by the instance, enable the extension and the flag + uint32_t instanceExtCount = 0; + vkEnumerateInstanceExtensionProperties(nullptr, &instanceExtCount, nullptr); + if (instanceExtCount > 0) + { + std::vector extensions(instanceExtCount); + if (vkEnumerateInstanceExtensionProperties(nullptr, &instanceExtCount, &extensions.front()) == VK_SUCCESS) + { + for (VkExtensionProperties extension : extensions) + { + if (strcmp(extension.extensionName, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME) == 0) + { + instanceExtensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); + instanceCreateInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; + break; + } + } + } + } +#endif +#endif + instanceCreateInfo.enabledExtensionCount = (uint32_t)instanceExtensions.size(); + instanceCreateInfo.ppEnabledExtensionNames = instanceExtensions.data(); VK_CHECK_RESULT(vkCreateInstance(&instanceCreateInfo, nullptr, &instance)); #if defined(VK_USE_PLATFORM_ANDROID_KHR) @@ -233,6 +262,29 @@ public: deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; deviceCreateInfo.queueCreateInfoCount = 1; deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo; + std::vector deviceExtensions = {}; +#if defined(VK_USE_PLATFORM_MACOS_MVK) && defined(VK_KHR_portability_subset) + // SRS - When running on macOS with MoltenVK and VK_KHR_portability_subset is defined and supported by the device, enable the extension + uint32_t deviceExtCount = 0; + vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &deviceExtCount, nullptr); + if (deviceExtCount > 0) + { + std::vector extensions(deviceExtCount); + if (vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &deviceExtCount, &extensions.front()) == VK_SUCCESS) + { + for (VkExtensionProperties extension : extensions) + { + if (strcmp(extension.extensionName, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME) == 0) + { + deviceExtensions.push_back(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME); + break; + } + } + } + } +#endif + deviceCreateInfo.enabledExtensionCount = (uint32_t)deviceExtensions.size(); + deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions.data(); VK_CHECK_RESULT(vkCreateDevice(physicalDevice, &deviceCreateInfo, nullptr, &device)); // Get a compute queue @@ -562,4 +614,4 @@ int main() { delete(vulkanExample); return 0; } -#endif \ No newline at end of file +#endif diff --git a/examples/computenbody/computenbody.cpp b/examples/computenbody/computenbody.cpp index 0d9b2a32..dec0a00f 100644 --- a/examples/computenbody/computenbody.cpp +++ b/examples/computenbody/computenbody.cpp @@ -160,7 +160,7 @@ public: vkCmdPipelineBarrier( drawCmdBuffers[i], - VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, 0, nullptr, @@ -207,7 +207,7 @@ public: vkCmdPipelineBarrier( drawCmdBuffers[i], VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, - VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 1, &buffer_barrier, @@ -243,7 +243,7 @@ public: vkCmdPipelineBarrier( compute.commandBuffer, - VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, @@ -300,7 +300,7 @@ public: vkCmdPipelineBarrier( compute.commandBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, - VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 1, &buffer_barrier, @@ -417,7 +417,7 @@ public: vkCmdPipelineBarrier( copyCmd, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, - VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 1, &buffer_barrier, @@ -620,6 +620,13 @@ public: // Semaphore for compute & graphics sync VkSemaphoreCreateInfo semaphoreCreateInfo = vks::initializers::semaphoreCreateInfo(); VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &graphics.semaphore)); + + // Signal the semaphore + VkSubmitInfo submitInfo = vks::initializers::submitInfo(); + submitInfo.signalSemaphoreCount = 1; + submitInfo.pSignalSemaphores = &graphics.semaphore; + VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); + VK_CHECK_RESULT(vkQueueWaitIdle(queue)); } void prepareCompute() @@ -736,17 +743,12 @@ public: VkSemaphoreCreateInfo semaphoreCreateInfo = vks::initializers::semaphoreCreateInfo(); VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &compute.semaphore)); - // Signal the semaphore - VkSubmitInfo submitInfo = vks::initializers::submitInfo(); - submitInfo.signalSemaphoreCount = 1; - submitInfo.pSignalSemaphores = &compute.semaphore; - VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); - VK_CHECK_RESULT(vkQueueWaitIdle(queue)); - // Build a single command buffer containing the compute dispatch commands buildComputeCommandBuffer(); + // SRS - By reordering compute and graphics within draw(), the following code is no longer needed: // If graphics and compute queue family indices differ, acquire and immediately release the storage buffer, so that the initial acquire from the graphics command buffers are matched up properly + /* if (graphics.queueFamilyIndex != compute.queueFamilyIndex) { // Create a transient command buffer for setting up the initial buffer transfer state @@ -796,6 +798,7 @@ public: vulkanDevice->flushCommandBuffer(transferCmd, compute.queue, compute.commandPool); } + */ } // Prepare and initialize uniform buffer containing shader uniforms @@ -841,6 +844,20 @@ public: void draw() { + // Wait for rendering finished + VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + + // Submit compute commands + VkSubmitInfo computeSubmitInfo = vks::initializers::submitInfo(); + computeSubmitInfo.commandBufferCount = 1; + computeSubmitInfo.pCommandBuffers = &compute.commandBuffer; + computeSubmitInfo.waitSemaphoreCount = 1; + computeSubmitInfo.pWaitSemaphores = &graphics.semaphore; + computeSubmitInfo.pWaitDstStageMask = &waitStageMask; + computeSubmitInfo.signalSemaphoreCount = 1; + computeSubmitInfo.pSignalSemaphores = &compute.semaphore; + VK_CHECK_RESULT(vkQueueSubmit(compute.queue, 1, &computeSubmitInfo, VK_NULL_HANDLE)); + VulkanExampleBase::prepareFrame(); VkPipelineStageFlags graphicsWaitStageMasks[] = { VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; @@ -858,20 +875,6 @@ public: VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); VulkanExampleBase::submitFrame(); - - // Wait for rendering finished - VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; - - // Submit compute commands - VkSubmitInfo computeSubmitInfo = vks::initializers::submitInfo(); - computeSubmitInfo.commandBufferCount = 1; - computeSubmitInfo.pCommandBuffers = &compute.commandBuffer; - computeSubmitInfo.waitSemaphoreCount = 1; - computeSubmitInfo.pWaitSemaphores = &graphics.semaphore; - computeSubmitInfo.pWaitDstStageMask = &waitStageMask; - computeSubmitInfo.signalSemaphoreCount = 1; - computeSubmitInfo.pSignalSemaphores = &compute.semaphore; - VK_CHECK_RESULT(vkQueueSubmit(compute.queue, 1, &computeSubmitInfo, VK_NULL_HANDLE)); } void prepare() @@ -899,6 +902,11 @@ public: updateGraphicsUniformBuffers(); } } + + virtual void viewChanged() + { + updateGraphicsUniformBuffers(); + } }; -VULKAN_EXAMPLE_MAIN() \ No newline at end of file +VULKAN_EXAMPLE_MAIN() diff --git a/examples/computeparticles/computeparticles.cpp b/examples/computeparticles/computeparticles.cpp index 48bfe07e..87f91a6d 100644 --- a/examples/computeparticles/computeparticles.cpp +++ b/examples/computeparticles/computeparticles.cpp @@ -86,6 +86,7 @@ public: vkDestroyPipeline(device, graphics.pipeline, nullptr); vkDestroyPipelineLayout(device, graphics.pipelineLayout, nullptr); vkDestroyDescriptorSetLayout(device, graphics.descriptorSetLayout, nullptr); + vkDestroySemaphore(device, graphics.semaphore, nullptr); // Compute compute.storageBuffer.destroy(); @@ -148,7 +149,7 @@ public: vkCmdPipelineBarrier( drawCmdBuffers[i], - VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, 0, nullptr, @@ -195,7 +196,7 @@ public: vkCmdPipelineBarrier( drawCmdBuffers[i], VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, - VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 1, &buffer_barrier, @@ -233,7 +234,7 @@ public: vkCmdPipelineBarrier( compute.commandBuffer, - VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, @@ -266,7 +267,7 @@ public: vkCmdPipelineBarrier( compute.commandBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, - VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 1, &buffer_barrier, @@ -335,7 +336,7 @@ public: vkCmdPipelineBarrier( copyCmd, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, - VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 1, &buffer_barrier, @@ -551,6 +552,13 @@ public: // Semaphore for compute & graphics sync VkSemaphoreCreateInfo semaphoreCreateInfo = vks::initializers::semaphoreCreateInfo(); VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &graphics.semaphore)); + + // Signal the semaphore + VkSubmitInfo submitInfo = vks::initializers::submitInfo(); + submitInfo.signalSemaphoreCount = 1; + submitInfo.pSignalSemaphores = &graphics.semaphore; + VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); + VK_CHECK_RESULT(vkQueueWaitIdle(queue)); } void prepareCompute() @@ -636,17 +644,12 @@ public: VkSemaphoreCreateInfo semaphoreCreateInfo = vks::initializers::semaphoreCreateInfo(); VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &compute.semaphore)); - // Signal the semaphore - VkSubmitInfo submitInfo = vks::initializers::submitInfo(); - submitInfo.signalSemaphoreCount = 1; - submitInfo.pSignalSemaphores = &compute.semaphore; - VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); - VK_CHECK_RESULT(vkQueueWaitIdle(queue)); - // Build a single command buffer containing the compute dispatch commands buildComputeCommandBuffer(); + // SRS - By reordering compute and graphics within draw(), the following code is no longer needed: // If graphics and compute queue family indices differ, acquire and immediately release the storage buffer, so that the initial acquire from the graphics command buffers are matched up properly + /* if (graphics.queueFamilyIndex != compute.queueFamilyIndex) { // Create a transient command buffer for setting up the initial buffer transfer state @@ -696,6 +699,7 @@ public: vulkanDevice->flushCommandBuffer(transferCmd, compute.queue, compute.commandPool); } + */ } // Prepare and initialize uniform buffer containing shader uniforms @@ -716,7 +720,7 @@ public: void updateUniformBuffers() { - compute.ubo.deltaT = frameTimer * 2.5f; + compute.ubo.deltaT = paused ? 0.0f : frameTimer * 2.5f; if (!attachToCursor) { compute.ubo.destX = sin(glm::radians(timer * 360.0f)) * 0.75f; @@ -735,6 +739,20 @@ public: void draw() { + // Wait for rendering finished + VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + + // Submit compute commands + VkSubmitInfo computeSubmitInfo = vks::initializers::submitInfo(); + computeSubmitInfo.commandBufferCount = 1; + computeSubmitInfo.pCommandBuffers = &compute.commandBuffer; + computeSubmitInfo.waitSemaphoreCount = 1; + computeSubmitInfo.pWaitSemaphores = &graphics.semaphore; + computeSubmitInfo.pWaitDstStageMask = &waitStageMask; + computeSubmitInfo.signalSemaphoreCount = 1; + computeSubmitInfo.pSignalSemaphores = &compute.semaphore; + VK_CHECK_RESULT(vkQueueSubmit(compute.queue, 1, &computeSubmitInfo, VK_NULL_HANDLE)); + VulkanExampleBase::prepareFrame(); VkPipelineStageFlags graphicsWaitStageMasks[] = { VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; @@ -752,21 +770,6 @@ public: VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); VulkanExampleBase::submitFrame(); - - // Wait for rendering finished - VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; - - // Submit compute commands - VkSubmitInfo computeSubmitInfo = vks::initializers::submitInfo(); - computeSubmitInfo.commandBufferCount = 1; - computeSubmitInfo.pCommandBuffers = &compute.commandBuffer; - computeSubmitInfo.waitSemaphoreCount = 1; - computeSubmitInfo.pWaitSemaphores = &graphics.semaphore; - computeSubmitInfo.pWaitDstStageMask = &waitStageMask; - computeSubmitInfo.signalSemaphoreCount = 1; - computeSubmitInfo.pSignalSemaphores = &compute.semaphore; - VK_CHECK_RESULT(vkQueueSubmit(compute.queue, 1, &computeSubmitInfo, VK_NULL_HANDLE)); - } void prepare() diff --git a/examples/computeraytracing/computeraytracing.cpp b/examples/computeraytracing/computeraytracing.cpp index 6a9036c2..6cb83490 100644 --- a/examples/computeraytracing/computeraytracing.cpp +++ b/examples/computeraytracing/computeraytracing.cpp @@ -223,16 +223,38 @@ public: imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; imageMemoryBarrier.image = textureComputeTarget.image; imageMemoryBarrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; - imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; - imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - vkCmdPipelineBarrier( - drawCmdBuffers[i], - VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - VK_FLAGS_NONE, - 0, nullptr, - 0, nullptr, - 1, &imageMemoryBarrier); + if (vulkanDevice->queueFamilyIndices.graphics != vulkanDevice->queueFamilyIndices.compute) + { + // Acquire barrier for graphics queue + imageMemoryBarrier.srcAccessMask = 0; + imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + imageMemoryBarrier.srcQueueFamilyIndex = vulkanDevice->queueFamilyIndices.compute; + imageMemoryBarrier.dstQueueFamilyIndex = vulkanDevice->queueFamilyIndices.graphics; + vkCmdPipelineBarrier( + drawCmdBuffers[i], + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_FLAGS_NONE, + 0, nullptr, + 0, nullptr, + 1, &imageMemoryBarrier); + } + else + { + // Combined barrier on single queue family + imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + vkCmdPipelineBarrier( + drawCmdBuffers[i], + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_FLAGS_NONE, + 0, nullptr, + 0, nullptr, + 1, &imageMemoryBarrier); + } vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); @@ -252,6 +274,23 @@ public: vkCmdEndRenderPass(drawCmdBuffers[i]); + if (vulkanDevice->queueFamilyIndices.graphics != vulkanDevice->queueFamilyIndices.compute) + { + // Release barrier from graphics queue + imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + imageMemoryBarrier.dstAccessMask = 0; + imageMemoryBarrier.srcQueueFamilyIndex = vulkanDevice->queueFamilyIndices.graphics; + imageMemoryBarrier.dstQueueFamilyIndex = vulkanDevice->queueFamilyIndices.compute; + vkCmdPipelineBarrier( + drawCmdBuffers[i], + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + VK_FLAGS_NONE, + 0, nullptr, + 0, nullptr, + 1, &imageMemoryBarrier); + } + VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i])); } @@ -262,12 +301,52 @@ public: VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo(); VK_CHECK_RESULT(vkBeginCommandBuffer(compute.commandBuffer, &cmdBufInfo)); + + VkImageMemoryBarrier imageMemoryBarrier = {}; + imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; + imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; + imageMemoryBarrier.image = textureComputeTarget.image; + imageMemoryBarrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; + if (vulkanDevice->queueFamilyIndices.graphics != vulkanDevice->queueFamilyIndices.compute) + { + // Acquire barrier for compute queue + imageMemoryBarrier.srcAccessMask = 0; + imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + imageMemoryBarrier.srcQueueFamilyIndex = vulkanDevice->queueFamilyIndices.graphics; + imageMemoryBarrier.dstQueueFamilyIndex = vulkanDevice->queueFamilyIndices.compute; + vkCmdPipelineBarrier( + compute.commandBuffer, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_FLAGS_NONE, + 0, nullptr, + 0, nullptr, + 1, &imageMemoryBarrier); + } vkCmdBindPipeline(compute.commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, compute.pipeline); vkCmdBindDescriptorSets(compute.commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, compute.pipelineLayout, 0, 1, &compute.descriptorSet, 0, 0); vkCmdDispatch(compute.commandBuffer, textureComputeTarget.width / 16, textureComputeTarget.height / 16, 1); + if (vulkanDevice->queueFamilyIndices.graphics != vulkanDevice->queueFamilyIndices.compute) + { + // Release barrier from compute queue + imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + imageMemoryBarrier.dstAccessMask = 0; + imageMemoryBarrier.srcQueueFamilyIndex = vulkanDevice->queueFamilyIndices.compute; + imageMemoryBarrier.dstQueueFamilyIndex = vulkanDevice->queueFamilyIndices.graphics; + vkCmdPipelineBarrier( + compute.commandBuffer, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + VK_FLAGS_NONE, + 0, nullptr, + 0, nullptr, + 1, &imageMemoryBarrier); + } + vkEndCommandBuffer(compute.commandBuffer); } @@ -361,6 +440,30 @@ public: copyCmd = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); copyRegion.size = storageBufferSize; vkCmdCopyBuffer(copyCmd, stagingBuffer.buffer, compute.storageBuffers.planes.buffer, 1, ©Region); + // Add an initial release barrier to the graphics queue, + // so that when the compute command buffer executes for the first time + // it doesn't complain about a lack of a corresponding "release" to its "acquire" + if (vulkanDevice->queueFamilyIndices.graphics != vulkanDevice->queueFamilyIndices.compute) + { + VkImageMemoryBarrier imageMemoryBarrier = {}; + imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; + imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; + imageMemoryBarrier.image = textureComputeTarget.image; + imageMemoryBarrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; + imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + imageMemoryBarrier.dstAccessMask = 0; + imageMemoryBarrier.srcQueueFamilyIndex = vulkanDevice->queueFamilyIndices.graphics; + imageMemoryBarrier.dstQueueFamilyIndex = vulkanDevice->queueFamilyIndices.compute; + vkCmdPipelineBarrier( + copyCmd, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + VK_FLAGS_NONE, + 0, nullptr, + 0, nullptr, + 1, &imageMemoryBarrier); + } vulkanDevice->flushCommandBuffer(copyCmd, queue, true); stagingBuffer.destroy(); @@ -689,9 +792,9 @@ public: void prepare() { VulkanExampleBase::prepare(); + prepareTextureTarget(&textureComputeTarget, TEX_DIM, TEX_DIM, VK_FORMAT_R8G8B8A8_UNORM); prepareStorageBuffers(); prepareUniformBuffers(); - prepareTextureTarget(&textureComputeTarget, TEX_DIM, TEX_DIM, VK_FORMAT_R8G8B8A8_UNORM); setupDescriptorSetLayout(); preparePipelines(); setupDescriptorPool(); diff --git a/examples/computeshader/computeshader.cpp b/examples/computeshader/computeshader.cpp index 7e9b4d47..b9a33210 100644 --- a/examples/computeshader/computeshader.cpp +++ b/examples/computeshader/computeshader.cpp @@ -654,6 +654,12 @@ public: } } + virtual void viewChanged() + { + camera.setPerspective(60.0f, (float)width * 0.5f / (float)height, 1.0f, 256.0f); + updateUniformBuffers(); + } + virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { if (overlay->header("Settings")) { diff --git a/examples/conditionalrender/conditionalrender.cpp b/examples/conditionalrender/conditionalrender.cpp index 3c8195e9..61790206 100644 --- a/examples/conditionalrender/conditionalrender.cpp +++ b/examples/conditionalrender/conditionalrender.cpp @@ -330,6 +330,11 @@ public: } } + virtual void viewChanged() + { + updateUniformBuffers(); + } + virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { if (overlay->header("Visibility")) { @@ -349,7 +354,7 @@ public: } ImGui::NewLine(); - ImGui::BeginChild("InnerRegion", ImVec2(200.0f, 400.0f), false); + ImGui::BeginChild("InnerRegion", ImVec2(200.0f * overlay->scale, 400.0f * overlay->scale), false); for (auto node : scene.linearNodes) { // Add visibility toggle checkboxes for all model nodes with a mesh if (node->mesh) { @@ -365,4 +370,4 @@ public: }; -VULKAN_EXAMPLE_MAIN() \ No newline at end of file +VULKAN_EXAMPLE_MAIN() diff --git a/examples/conservativeraster/conservativeraster.cpp b/examples/conservativeraster/conservativeraster.cpp index 19cc838c..c2d7b518 100644 --- a/examples/conservativeraster/conservativeraster.cpp +++ b/examples/conservativeraster/conservativeraster.cpp @@ -478,8 +478,6 @@ public: // Scene rendering setLayoutBindings = { vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT, 0), // Binding 0: Vertex shader uniform buffer - vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 1), // Binding 1: Fragment shader image sampler - vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT, 2) // Binding 2: Fragment shader uniform buffer }; descriptorLayout = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings.data(), static_cast(setLayoutBindings.size())); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayouts.scene)); @@ -488,8 +486,7 @@ public: // Fullscreen pass setLayoutBindings = { - vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT, 0), // Binding 0: Vertex shader uniform buffer - vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 1) // Binding 1: Fragment shader image sampler + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 0) // Binding 0: Fragment shader image sampler }; descriptorLayout = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings.data(), static_cast(setLayoutBindings.size())); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayouts.fullscreen)); @@ -513,7 +510,7 @@ public: descriptorSetAllocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayouts.fullscreen, 1); VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocInfo, &descriptorSets.fullscreen)); std::vector writeDescriptorSets = { - vks::initializers::writeDescriptorSet(descriptorSets.fullscreen, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, &offscreenPass.descriptor), + vks::initializers::writeDescriptorSet(descriptorSets.fullscreen, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 0, &offscreenPass.descriptor), }; vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr); } diff --git a/examples/debugmarker/debugmarker.cpp b/examples/debugmarker/debugmarker.cpp index dc5e42a8..8b7c7348 100644 --- a/examples/debugmarker/debugmarker.cpp +++ b/examples/debugmarker/debugmarker.cpp @@ -777,6 +777,10 @@ public: updateUniformBuffers(); } + virtual void viewChanged() + { + updateUniformBuffers(); + } virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { @@ -796,4 +800,4 @@ public: } }; -VULKAN_EXAMPLE_MAIN() \ No newline at end of file +VULKAN_EXAMPLE_MAIN() diff --git a/examples/deferred/deferred.cpp b/examples/deferred/deferred.cpp index 0994e2f9..fb1c3ebd 100644 --- a/examples/deferred/deferred.cpp +++ b/examples/deferred/deferred.cpp @@ -190,7 +190,9 @@ public: } if (usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { - aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + if (format >= VK_FORMAT_D16_UNORM_S8_UINT) + aspectMask |=VK_IMAGE_ASPECT_STENCIL_BIT; imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; } @@ -809,6 +811,11 @@ public: } } + virtual void viewChanged() + { + updateUniformBufferOffscreen(); + } + virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { if (overlay->header("Settings")) { diff --git a/examples/deferredmultisampling/deferredmultisampling.cpp b/examples/deferredmultisampling/deferredmultisampling.cpp index 3e95ae45..0b6f6805 100644 --- a/examples/deferredmultisampling/deferredmultisampling.cpp +++ b/examples/deferredmultisampling/deferredmultisampling.cpp @@ -647,6 +647,11 @@ public: } } + virtual void viewChanged() + { + updateUniformBufferOffscreen(); + } + virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { if (overlay->header("Settings")) { diff --git a/examples/deferredshadows/deferredshadows.cpp b/examples/deferredshadows/deferredshadows.cpp index 033ce34a..ac7a017b 100644 --- a/examples/deferredshadows/deferredshadows.cpp +++ b/examples/deferredshadows/deferredshadows.cpp @@ -808,6 +808,11 @@ public: } } + virtual void viewChanged() + { + updateUniformBufferOffscreen(); + } + virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { if (overlay->header("Settings")) { diff --git a/examples/descriptorindexing/descriptorindexing.cpp b/examples/descriptorindexing/descriptorindexing.cpp index 354d3b55..d0a016ac 100644 --- a/examples/descriptorindexing/descriptorindexing.cpp +++ b/examples/descriptorindexing/descriptorindexing.cpp @@ -409,6 +409,11 @@ public: updateUniformBuffersCamera(); } + virtual void viewChanged() + { + updateUniformBuffersCamera(); + } + }; VULKAN_EXAMPLE_MAIN() \ No newline at end of file diff --git a/examples/descriptorsets/descriptorsets.cpp b/examples/descriptorsets/descriptorsets.cpp index 5afbf6aa..b3955c82 100644 --- a/examples/descriptorsets/descriptorsets.cpp +++ b/examples/descriptorsets/descriptorsets.cpp @@ -362,7 +362,7 @@ public: if (!prepared) return; draw(); - if (animate) { + if (animate && !paused) { cubes[0].rotation.x += 2.5f * frameTimer; if (cubes[0].rotation.x > 360.0f) cubes[0].rotation.x -= 360.0f; @@ -370,7 +370,7 @@ public: if (cubes[1].rotation.x > 360.0f) cubes[1].rotation.x -= 360.0f; } - if ((camera.updated) || (animate)) { + if ((camera.updated) || (animate && !paused)) { updateUniformBuffers(); } } @@ -383,4 +383,4 @@ public: } }; -VULKAN_EXAMPLE_MAIN() \ No newline at end of file +VULKAN_EXAMPLE_MAIN() diff --git a/examples/displacement/displacement.cpp b/examples/displacement/displacement.cpp index 125ff200..2ae6b0ff 100644 --- a/examples/displacement/displacement.cpp +++ b/examples/displacement/displacement.cpp @@ -385,6 +385,12 @@ public: updateUniformBuffers(); } } + + virtual void viewChanged() + { + updateUniformBuffers(); + } + virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { if (overlay->header("Settings")) { @@ -408,4 +414,4 @@ public: } }; -VULKAN_EXAMPLE_MAIN() \ No newline at end of file +VULKAN_EXAMPLE_MAIN() diff --git a/examples/distancefieldfonts/distancefieldfonts.cpp b/examples/distancefieldfonts/distancefieldfonts.cpp index 30cafc75..d3c67d9f 100644 --- a/examples/distancefieldfonts/distancefieldfonts.cpp +++ b/examples/distancefieldfonts/distancefieldfonts.cpp @@ -643,6 +643,7 @@ public: virtual void viewChanged() { + camera.setPerspective(splitScreen ? 30.0f : 45.0f, (float)width / (float)(height * ((splitScreen) ? 0.5f : 1.0f)), 1.0f, 256.0f); updateUniformBuffers(); } @@ -663,4 +664,4 @@ public: } }; -VULKAN_EXAMPLE_MAIN() \ No newline at end of file +VULKAN_EXAMPLE_MAIN() diff --git a/examples/dynamicrendering/dynamicrendering.cpp b/examples/dynamicrendering/dynamicrendering.cpp index 5c5712c6..d7975934 100644 --- a/examples/dynamicrendering/dynamicrendering.cpp +++ b/examples/dynamicrendering/dynamicrendering.cpp @@ -42,7 +42,15 @@ public: camera.setPerspective(60.0f, (float)width / (float)height, 0.1f, 256.0f); enabledInstanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + enabledDeviceExtensions.push_back(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME); + + // Since we are not requiring Vulkan 1.2, we need to enable some additional extensios as required per the spec + enabledDeviceExtensions.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME); + enabledDeviceExtensions.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME); + enabledDeviceExtensions.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); + enabledDeviceExtensions.push_back(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME); + } ~VulkanExample() @@ -157,6 +165,8 @@ public: vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); model.draw(drawCmdBuffers[i], vkglTF::RenderFlags::BindImages, pipelineLayout); + + drawUI(drawCmdBuffers[i]); // End dynamic rendering vkCmdEndRenderingKHR(drawCmdBuffers[i]); diff --git a/examples/gltfloading/gltfloading.cpp b/examples/gltfloading/gltfloading.cpp index eae2e3da..7a38fcef 100644 --- a/examples/gltfloading/gltfloading.cpp +++ b/examples/gltfloading/gltfloading.cpp @@ -1,7 +1,7 @@ /* * Vulkan Example - glTF scene loading and rendering * -* Copyright (C) 2020-2021 by Sascha Willems - www.saschawillems.de +* Copyright (C) 2020-2022 by Sascha Willems - www.saschawillems.de * * This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) */ @@ -78,9 +78,14 @@ public: // A node represents an object in the glTF scene graph struct Node { Node* parent; - std::vector children; + std::vector children; Mesh mesh; glm::mat4 matrix; + ~Node() { + for (auto& child : children) { + delete child; + } + } }; // A glTF material stores information in e.g. the texture that is attached to it and colors @@ -109,10 +114,13 @@ public: std::vector images; std::vector textures; std::vector materials; - std::vector nodes; + std::vector nodes; ~VulkanglTFModel() { + for (auto node : nodes) { + delete node; + } // Release all Vulkan resources allocated for the model vkDestroyBuffer(vulkanDevice->logicalDevice, vertices.buffer, nullptr); vkFreeMemory(vulkanDevice->logicalDevice, vertices.memory, nullptr); @@ -195,29 +203,30 @@ public: void loadNode(const tinygltf::Node& inputNode, const tinygltf::Model& input, VulkanglTFModel::Node* parent, std::vector& indexBuffer, std::vector& vertexBuffer) { - VulkanglTFModel::Node node{}; - node.matrix = glm::mat4(1.0f); + VulkanglTFModel::Node* node = new VulkanglTFModel::Node{}; + node->matrix = glm::mat4(1.0f); + node->parent = parent; // Get the local node matrix // It's either made up from translation, rotation, scale or a 4x4 matrix if (inputNode.translation.size() == 3) { - node.matrix = glm::translate(node.matrix, glm::vec3(glm::make_vec3(inputNode.translation.data()))); + node->matrix = glm::translate(node->matrix, glm::vec3(glm::make_vec3(inputNode.translation.data()))); } if (inputNode.rotation.size() == 4) { glm::quat q = glm::make_quat(inputNode.rotation.data()); - node.matrix *= glm::mat4(q); + node->matrix *= glm::mat4(q); } if (inputNode.scale.size() == 3) { - node.matrix = glm::scale(node.matrix, glm::vec3(glm::make_vec3(inputNode.scale.data()))); + node->matrix = glm::scale(node->matrix, glm::vec3(glm::make_vec3(inputNode.scale.data()))); } if (inputNode.matrix.size() == 16) { - node.matrix = glm::make_mat4x4(inputNode.matrix.data()); + node->matrix = glm::make_mat4x4(inputNode.matrix.data()); }; // Load node's children if (inputNode.children.size() > 0) { for (size_t i = 0; i < inputNode.children.size(); i++) { - loadNode(input.nodes[inputNode.children[i]], input , &node, indexBuffer, vertexBuffer); + loadNode(input.nodes[inputNode.children[i]], input , node, indexBuffer, vertexBuffer); } } @@ -309,7 +318,7 @@ public: primitive.firstIndex = firstIndex; primitive.indexCount = indexCount; primitive.materialIndex = glTFPrimitive.material; - node.mesh.primitives.push_back(primitive); + node->mesh.primitives.push_back(primitive); } } @@ -326,20 +335,20 @@ public: */ // Draw a single node including child nodes (if present) - void drawNode(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout, VulkanglTFModel::Node node) + void drawNode(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout, VulkanglTFModel::Node* node) { - if (node.mesh.primitives.size() > 0) { + if (node->mesh.primitives.size() > 0) { // Pass the node's matrix via push constants // Traverse the node hierarchy to the top-most parent to get the final matrix of the current node - glm::mat4 nodeMatrix = node.matrix; - VulkanglTFModel::Node* currentParent = node.parent; + glm::mat4 nodeMatrix = node->matrix; + VulkanglTFModel::Node* currentParent = node->parent; while (currentParent) { nodeMatrix = currentParent->matrix * nodeMatrix; currentParent = currentParent->parent; } // Pass the final matrix to the vertex shader using push constants vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::mat4), &nodeMatrix); - for (VulkanglTFModel::Primitive& primitive : node.mesh.primitives) { + for (VulkanglTFModel::Primitive& primitive : node->mesh.primitives) { if (primitive.indexCount > 0) { // Get the texture index for this primitive VulkanglTFModel::Texture texture = textures[materials[primitive.materialIndex].baseColorTextureIndex]; @@ -349,7 +358,7 @@ public: } } } - for (auto& child : node.children) { + for (auto& child : node->children) { drawNode(commandBuffer, pipelineLayout, child); } } @@ -382,6 +391,7 @@ public: glm::mat4 projection; glm::mat4 model; glm::vec4 lightPos = glm::vec4(5.0f, 5.0f, -5.0f, 1.0f); + glm::vec4 viewPos; } values; } shaderData; @@ -404,7 +414,7 @@ public: camera.type = Camera::CameraType::lookat; camera.flipY = true; camera.setPosition(glm::vec3(0.0f, -0.1f, -1.0f)); - camera.setRotation(glm::vec3(0.0f, -135.0f, 0.0f)); + camera.setRotation(glm::vec3(0.0f, 45.0f, 0.0f)); camera.setPerspective(60.0f, (float)width / (float)height, 0.1f, 256.0f); } @@ -707,6 +717,7 @@ public: { shaderData.values.projection = camera.matrices.perspective; shaderData.values.model = camera.matrices.view; + shaderData.values.viewPos = camera.viewPos; memcpy(shaderData.buffer.mapped, &shaderData.values, sizeof(shaderData.values)); } @@ -729,6 +740,11 @@ public: } } + virtual void viewChanged() + { + updateUniformBuffers(); + } + virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { if (overlay->header("Settings")) { @@ -739,4 +755,4 @@ public: } }; -VULKAN_EXAMPLE_MAIN() \ No newline at end of file +VULKAN_EXAMPLE_MAIN() diff --git a/examples/gltfscenerendering/gltfscenerendering.cpp b/examples/gltfscenerendering/gltfscenerendering.cpp index 64f062f1..7ba5ee0f 100644 --- a/examples/gltfscenerendering/gltfscenerendering.cpp +++ b/examples/gltfscenerendering/gltfscenerendering.cpp @@ -1,7 +1,7 @@ /* * Vulkan Example - Scene rendering * -* Copyright (C) 2020-2021 by Sascha Willems - www.saschawillems.de +* Copyright (C) 2020-202- by Sascha Willems - www.saschawillems.de * * This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) * @@ -20,6 +20,9 @@ VulkanglTFScene::~VulkanglTFScene() { + for (auto node : nodes) { + delete node; + } // Release all Vulkan resources allocated for the model vkDestroyBuffer(vulkanDevice->logicalDevice, vertices.buffer, nullptr); vkFreeMemory(vulkanDevice->logicalDevice, vertices.memory, nullptr); @@ -87,30 +90,31 @@ void VulkanglTFScene::loadMaterials(tinygltf::Model& input) void VulkanglTFScene::loadNode(const tinygltf::Node& inputNode, const tinygltf::Model& input, VulkanglTFScene::Node* parent, std::vector& indexBuffer, std::vector& vertexBuffer) { - VulkanglTFScene::Node node{}; - node.name = inputNode.name; + VulkanglTFScene::Node* node = new VulkanglTFScene::Node{}; + node->name = inputNode.name; + node->parent = parent; // Get the local node matrix // It's either made up from translation, rotation, scale or a 4x4 matrix - node.matrix = glm::mat4(1.0f); + node->matrix = glm::mat4(1.0f); if (inputNode.translation.size() == 3) { - node.matrix = glm::translate(node.matrix, glm::vec3(glm::make_vec3(inputNode.translation.data()))); + node->matrix = glm::translate(node->matrix, glm::vec3(glm::make_vec3(inputNode.translation.data()))); } if (inputNode.rotation.size() == 4) { glm::quat q = glm::make_quat(inputNode.rotation.data()); - node.matrix *= glm::mat4(q); + node->matrix *= glm::mat4(q); } if (inputNode.scale.size() == 3) { - node.matrix = glm::scale(node.matrix, glm::vec3(glm::make_vec3(inputNode.scale.data()))); + node->matrix = glm::scale(node->matrix, glm::vec3(glm::make_vec3(inputNode.scale.data()))); } if (inputNode.matrix.size() == 16) { - node.matrix = glm::make_mat4x4(inputNode.matrix.data()); + node->matrix = glm::make_mat4x4(inputNode.matrix.data()); }; // Load node's children if (inputNode.children.size() > 0) { for (size_t i = 0; i < inputNode.children.size(); i++) { - loadNode(input.nodes[inputNode.children[i]], input, &node, indexBuffer, vertexBuffer); + loadNode(input.nodes[inputNode.children[i]], input, node, indexBuffer, vertexBuffer); } } @@ -210,7 +214,7 @@ void VulkanglTFScene::loadNode(const tinygltf::Node& inputNode, const tinygltf:: primitive.firstIndex = firstIndex; primitive.indexCount = indexCount; primitive.materialIndex = glTFPrimitive.material; - node.mesh.primitives.push_back(primitive); + node->mesh.primitives.push_back(primitive); } } @@ -232,23 +236,23 @@ VkDescriptorImageInfo VulkanglTFScene::getTextureDescriptor(const size_t index) */ // Draw a single node including child nodes (if present) -void VulkanglTFScene::drawNode(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout, VulkanglTFScene::Node node) +void VulkanglTFScene::drawNode(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout, VulkanglTFScene::Node* node) { - if (!node.visible) { + if (!node->visible) { return; } - if (node.mesh.primitives.size() > 0) { + if (node->mesh.primitives.size() > 0) { // Pass the node's matrix via push constants // Traverse the node hierarchy to the top-most parent to get the final matrix of the current node - glm::mat4 nodeMatrix = node.matrix; - VulkanglTFScene::Node* currentParent = node.parent; + glm::mat4 nodeMatrix = node->matrix; + VulkanglTFScene::Node* currentParent = node->parent; while (currentParent) { nodeMatrix = currentParent->matrix * nodeMatrix; currentParent = currentParent->parent; } // Pass the final matrix to the vertex shader using push constants vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::mat4), &nodeMatrix); - for (VulkanglTFScene::Primitive& primitive : node.mesh.primitives) { + for (VulkanglTFScene::Primitive& primitive : node->mesh.primitives) { if (primitive.indexCount > 0) { VulkanglTFScene::Material& material = materials[primitive.materialIndex]; // POI: Bind the pipeline for the node's material @@ -258,7 +262,7 @@ void VulkanglTFScene::drawNode(VkCommandBuffer commandBuffer, VkPipelineLayout p } } } - for (auto& child : node.children) { + for (auto& child : node->children) { drawNode(commandBuffer, pipelineLayout, child); } } @@ -631,26 +635,31 @@ void VulkanExample::render() } } +void VulkanExample::viewChanged() +{ + updateUniformBuffers(); +} + void VulkanExample::OnUpdateUIOverlay(vks::UIOverlay* overlay) { if (overlay->header("Visibility")) { if (overlay->button("All")) { - std::for_each(glTFScene.nodes.begin(), glTFScene.nodes.end(), [](VulkanglTFScene::Node &node) { node.visible = true; }); + std::for_each(glTFScene.nodes.begin(), glTFScene.nodes.end(), [](VulkanglTFScene::Node* node) { node->visible = true; }); buildCommandBuffers(); } ImGui::SameLine(); if (overlay->button("None")) { - std::for_each(glTFScene.nodes.begin(), glTFScene.nodes.end(), [](VulkanglTFScene::Node &node) { node.visible = false; }); + std::for_each(glTFScene.nodes.begin(), glTFScene.nodes.end(), [](VulkanglTFScene::Node* node) { node->visible = false; }); buildCommandBuffers(); } ImGui::NewLine(); // POI: Create a list of glTF nodes for visibility toggle - ImGui::BeginChild("#nodelist", ImVec2(200.0f, 340.0f), false); - for (auto &node : glTFScene.nodes) + ImGui::BeginChild("#nodelist", ImVec2(200.0f * overlay->scale, 340.0f * overlay->scale), false); + for (auto& node : glTFScene.nodes) { - if (overlay->checkBox(node.name.c_str(), &node.visible)) + if (overlay->checkBox(node->name.c_str(), &node->visible)) { buildCommandBuffers(); } @@ -659,4 +668,4 @@ void VulkanExample::OnUpdateUIOverlay(vks::UIOverlay* overlay) } } -VULKAN_EXAMPLE_MAIN() \ No newline at end of file +VULKAN_EXAMPLE_MAIN() diff --git a/examples/gltfscenerendering/gltfscenerendering.h b/examples/gltfscenerendering/gltfscenerendering.h index 8e6b6355..b29c90b1 100644 --- a/examples/gltfscenerendering/gltfscenerendering.h +++ b/examples/gltfscenerendering/gltfscenerendering.h @@ -1,7 +1,7 @@ /* * Vulkan Example - Scene rendering * -* Copyright (C) 2020 by Sascha Willems - www.saschawillems.de +* Copyright (C) 2020-2022 by Sascha Willems - www.saschawillems.de * * This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) * @@ -76,11 +76,16 @@ public: // A node represents an object in the glTF scene graph struct Node { Node* parent; - std::vector children; + std::vector children; Mesh mesh; glm::mat4 matrix; std::string name; bool visible = true; + ~Node() { + for (auto& child : children) { + delete child; + } + } }; // A glTF material stores information in e.g. the texture that is attached to it and colors @@ -113,7 +118,7 @@ public: std::vector images; std::vector textures; std::vector materials; - std::vector nodes; + std::vector nodes; std::string path; @@ -123,7 +128,7 @@ public: void loadTextures(tinygltf::Model& input); void loadMaterials(tinygltf::Model& input); void loadNode(const tinygltf::Node& inputNode, const tinygltf::Model& input, VulkanglTFScene::Node* parent, std::vector& indexBuffer, std::vector& vertexBuffer); - void drawNode(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout, VulkanglTFScene::Node node); + void drawNode(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout, VulkanglTFScene::Node* node); void draw(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout); }; @@ -162,5 +167,6 @@ public: void updateUniformBuffers(); void prepare(); virtual void render(); + virtual void viewChanged(); virtual void OnUpdateUIOverlay(vks::UIOverlay* overlay); -}; \ No newline at end of file +}; diff --git a/examples/gltfskinning/gltfskinning.cpp b/examples/gltfskinning/gltfskinning.cpp index d7988b83..f019395e 100644 --- a/examples/gltfskinning/gltfskinning.cpp +++ b/examples/gltfskinning/gltfskinning.cpp @@ -995,6 +995,11 @@ void VulkanExample::render() } } +void VulkanExample::viewChanged() +{ + updateUniformBuffers(); +} + void VulkanExample::OnUpdateUIOverlay(vks::UIOverlay *overlay) { if (overlay->header("Settings")) @@ -1006,4 +1011,4 @@ void VulkanExample::OnUpdateUIOverlay(vks::UIOverlay *overlay) } } -VULKAN_EXAMPLE_MAIN() \ No newline at end of file +VULKAN_EXAMPLE_MAIN() diff --git a/examples/gltfskinning/gltfskinning.h b/examples/gltfskinning/gltfskinning.h index 9423c01c..67f9c070 100644 --- a/examples/gltfskinning/gltfskinning.h +++ b/examples/gltfskinning/gltfskinning.h @@ -232,5 +232,6 @@ class VulkanExample : public VulkanExampleBase void updateUniformBuffers(); void prepare(); virtual void render(); + virtual void viewChanged(); virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay); }; diff --git a/examples/graphicspipelinelibrary/graphicspipelinelibrary.cpp b/examples/graphicspipelinelibrary/graphicspipelinelibrary.cpp index b15bc245..79922a4f 100644 --- a/examples/graphicspipelinelibrary/graphicspipelinelibrary.cpp +++ b/examples/graphicspipelinelibrary/graphicspipelinelibrary.cpp @@ -16,12 +16,14 @@ class VulkanExample: public VulkanExampleBase { public: + bool linkTimeOptimization = true; + vkglTF::Model scene; struct UBOVS { glm::mat4 projection; glm::mat4 modelView; - glm::vec4 lightPos = glm::vec4(0.0f, 2.0f, 1.0f, 0.0f); + glm::vec4 lightPos = glm::vec4(0.0f, -2.0f, 1.0f, 0.0f); } uboVS; vks::Buffer uniformBuffer; @@ -35,6 +37,7 @@ public: VkPipeline vertexInputInterface; VkPipeline preRasterizationShaders; VkPipeline fragmentOutputInterface; + std::vector fragmentShaders; } pipelineLibrary; std::vector pipelines{}; @@ -80,6 +83,13 @@ public: for (auto pipeline : pipelines) { vkDestroyPipeline(device, pipeline, nullptr); } + for (auto pipeline : pipelineLibrary.fragmentShaders) { + vkDestroyPipeline(device, pipeline, nullptr); + } + vkDestroyPipeline(device, pipelineLibrary.fragmentOutputInterface, nullptr); + vkDestroyPipeline(device, pipelineLibrary.preRasterizationShaders, nullptr); + vkDestroyPipeline(device, pipelineLibrary.vertexInputInterface, nullptr); + vkDestroyPipelineCache(device, threadPipelineCache, nullptr); vkDestroyPipelineLayout(device, pipelineLayout, nullptr); vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); uniformBuffer.destroy(); @@ -238,14 +248,14 @@ public: VkPipelineVertexInputStateCreateInfo vertexInputState = *vkglTF::Vertex::getPipelineVertexInputState({ vkglTF::VertexComponent::Position, vkglTF::VertexComponent::Normal, vkglTF::VertexComponent::Color }); VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0, VK_FALSE); - VkGraphicsPipelineCreateInfo pipelineCI{}; - pipelineCI.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - pipelineCI.flags = VK_PIPELINE_CREATE_LIBRARY_BIT_KHR | VK_PIPELINE_CREATE_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT; - pipelineCI.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - pipelineCI.pNext = &libraryInfo; - pipelineCI.pInputAssemblyState = &inputAssemblyState; - pipelineCI.pVertexInputState = &vertexInputState; - VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelineLibrary.vertexInputInterface)); + VkGraphicsPipelineCreateInfo pipelineLibraryCI{}; + pipelineLibraryCI.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipelineLibraryCI.flags = VK_PIPELINE_CREATE_LIBRARY_BIT_KHR | VK_PIPELINE_CREATE_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT; + pipelineLibraryCI.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipelineLibraryCI.pNext = &libraryInfo; + pipelineLibraryCI.pInputAssemblyState = &inputAssemblyState; + pipelineLibraryCI.pVertexInputState = &vertexInputState; + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineLibraryCI, nullptr, &pipelineLibrary.vertexInputInterface)); } // Creata a pipeline library for the vertex shader stage @@ -285,18 +295,18 @@ public: shaderStageCI.stage = VK_SHADER_STAGE_VERTEX_BIT; shaderStageCI.pName = "main"; - VkGraphicsPipelineCreateInfo pipelineCI{}; - pipelineCI.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - pipelineCI.pNext = &libraryInfo; - pipelineCI.renderPass = renderPass; - pipelineCI.flags = VK_PIPELINE_CREATE_LIBRARY_BIT_KHR | VK_PIPELINE_CREATE_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT; - pipelineCI.stageCount = 1; - pipelineCI.pStages = &shaderStageCI; - pipelineCI.layout = pipelineLayout; - pipelineCI.pDynamicState = &dynamicInfo; - pipelineCI.pViewportState = &viewportState; - pipelineCI.pRasterizationState = &rasterizationState; - VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelineLibrary.preRasterizationShaders)); + VkGraphicsPipelineCreateInfo pipelineLibraryCI{}; + pipelineLibraryCI.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipelineLibraryCI.pNext = &libraryInfo; + pipelineLibraryCI.renderPass = renderPass; + pipelineLibraryCI.flags = VK_PIPELINE_CREATE_LIBRARY_BIT_KHR | VK_PIPELINE_CREATE_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT; + pipelineLibraryCI.stageCount = 1; + pipelineLibraryCI.pStages = &shaderStageCI; + pipelineLibraryCI.layout = pipelineLayout; + pipelineLibraryCI.pDynamicState = &dynamicInfo; + pipelineLibraryCI.pViewportState = &viewportState; + pipelineLibraryCI.pRasterizationState = &rasterizationState; + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineLibraryCI, nullptr, &pipelineLibrary.preRasterizationShaders)); } // Create a pipeline library for the fragment output interface @@ -314,6 +324,7 @@ public: pipelineLibraryCI.pNext = &libraryInfo; pipelineLibraryCI.layout = pipelineLayout; pipelineLibraryCI.renderPass = renderPass; + pipelineLibraryCI.flags = VK_PIPELINE_CREATE_LIBRARY_BIT_KHR | VK_PIPELINE_CREATE_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT; pipelineLibraryCI.pColorBlendState = &colorBlendState; pipelineLibraryCI.pMultisampleState = &multisampleState; VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineLibraryCI, nullptr, &pipelineLibrary.fragmentOutputInterface)); @@ -393,15 +404,15 @@ public: pipelineCI.renderPass = renderPass; pipelineCI.pDepthStencilState = &depthStencilState; pipelineCI.pMultisampleState = &multisampleState; - VkPipeline fragment_shader = VK_NULL_HANDLE; - VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, threadPipelineCache, 1, &pipelineCI, nullptr, &fragment_shader)); + VkPipeline fragmentShader = VK_NULL_HANDLE; + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, threadPipelineCache, 1, &pipelineCI, nullptr, &fragmentShader)); // Create the pipeline using the pre-built pipeline library parts // Except for above fragment shader part all parts have been pre-built and will be re-used std::vector libraries = { pipelineLibrary.vertexInputInterface, pipelineLibrary.preRasterizationShaders, - fragment_shader, + fragmentShader, pipelineLibrary.fragmentOutputInterface }; // Link the library parts into a graphics pipeline @@ -417,12 +428,20 @@ public: VkGraphicsPipelineCreateInfo executablePipelineCI{}; executablePipelineCI.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; executablePipelineCI.pNext = &pipelineLibraryCI; - executablePipelineCI.flags |= optimized ? VK_PIPELINE_CREATE_LINK_TIME_OPTIMIZATION_BIT_EXT : 0; + executablePipelineCI.layout = pipelineLayout; + if (linkTimeOptimization) + { + // If link time optimization is activated in the UI, we set the VK_PIPELINE_CREATE_LINK_TIME_OPTIMIZATION_BIT_EXT flag which will let the implementation do additional optimizations at link time + // This trades in pipeline creation time for run-time performance + executablePipelineCI.flags = VK_PIPELINE_CREATE_LINK_TIME_OPTIMIZATION_BIT_EXT; + } VkPipeline executable = VK_NULL_HANDLE; VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, threadPipelineCache, 1, &executablePipelineCI, nullptr, &executable)); pipelines.push_back(executable); + // Push fragment shader to list for deletion in the sample's destructor + pipelineLibrary.fragmentShaders.push_back(fragmentShader); } // Prepare and initialize uniform buffer containing shader uniforms @@ -502,6 +521,7 @@ public: virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { + overlay->checkBox("Link time optimization", &linkTimeOptimization); if (overlay->button("New pipeline")) { // Spwan a thread to create a new pipeline in the background std::thread pipelineGenerationThread(&VulkanExample::threadFn, this); diff --git a/examples/hdr/hdr.cpp b/examples/hdr/hdr.cpp index cda5b452..09da292f 100644 --- a/examples/hdr/hdr.cpp +++ b/examples/hdr/hdr.cpp @@ -314,7 +314,9 @@ public: } if (usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { - aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + if (format >= VK_FORMAT_D16_UNORM_S8_UINT) + aspectMask |=VK_IMAGE_ASPECT_STENCIL_BIT; imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; } @@ -870,6 +872,11 @@ public: updateUniformBuffers(); } + virtual void viewChanged() + { + updateUniformBuffers(); + } + virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { if (overlay->header("Settings")) { diff --git a/examples/imgui/main.cpp b/examples/imgui/main.cpp index 3f5f4382..91a3b1e0 100644 --- a/examples/imgui/main.cpp +++ b/examples/imgui/main.cpp @@ -45,6 +45,7 @@ private: VkDescriptorSetLayout descriptorSetLayout; VkDescriptorSet descriptorSet; vks::VulkanDevice *device; + VkPhysicalDeviceDriverProperties driverProperties = {}; VulkanExampleBase *example; public: // UI params are set via push constants @@ -57,6 +58,12 @@ public: { device = example->vulkanDevice; ImGui::CreateContext(); + + //SRS - Set ImGui font and style scale factors to handle retina and other HiDPI displays + ImGuiIO& io = ImGui::GetIO(); + io.FontGlobalScale = example->UIOverlay.scale; + ImGuiStyle& style = ImGui::GetStyle(); + style.ScaleAllSizes(example->UIOverlay.scale); }; ~ImGUI() @@ -103,6 +110,16 @@ public: io.Fonts->GetTexDataAsRGBA32(&fontData, &texWidth, &texHeight); VkDeviceSize uploadSize = texWidth*texHeight * 4 * sizeof(char); + //SRS - Get Vulkan device driver information if available, use later for display + if (device->extensionSupported(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME)) + { + VkPhysicalDeviceProperties2 deviceProperties2 = {}; + deviceProperties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + deviceProperties2.pNext = &driverProperties; + driverProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES; + vkGetPhysicalDeviceProperties2(device->physicalDevice, &deviceProperties2); + } + // Create target image for copy VkImageCreateInfo imageInfo = vks::initializers::imageCreateInfo(); imageInfo.imageType = VK_IMAGE_TYPE_2D; @@ -325,10 +342,15 @@ public: // Init imGui windows and elements - ImVec4 clear_color = ImColor(114, 144, 154); - static float f = 0.0f; + // SRS - Set initial position of default Debug window (note: Debug window sets its own initial size, use ImGuiSetCond_Always to override) + ImGui::SetWindowPos(ImVec2(20 * example->UIOverlay.scale, 20 * example->UIOverlay.scale), ImGuiSetCond_FirstUseEver); + ImGui::SetWindowSize(ImVec2(300 * example->UIOverlay.scale, 300 * example->UIOverlay.scale), ImGuiSetCond_Always); ImGui::TextUnformatted(example->title.c_str()); ImGui::TextUnformatted(device->properties.deviceName); + + //SRS - Display Vulkan API version and device driver information if available (otherwise blank) + ImGui::Text("Vulkan API %i.%i.%i", VK_API_VERSION_MAJOR(device->properties.apiVersion), VK_API_VERSION_MINOR(device->properties.apiVersion), VK_API_VERSION_PATCH(device->properties.apiVersion)); + ImGui::Text("%s %s", driverProperties.driverName, driverProperties.driverInfo); // Update frame time display if (updateFrameGraph) { @@ -349,7 +371,9 @@ public: ImGui::InputFloat3("position", &example->camera.position.x, 2); ImGui::InputFloat3("rotation", &example->camera.rotation.x, 2); - ImGui::SetNextWindowSize(ImVec2(200, 200), ImGuiSetCond_FirstUseEver); + // SRS - Set initial position and size of Example settings window + ImGui::SetNextWindowPos(ImVec2(20 * example->UIOverlay.scale, 360 * example->UIOverlay.scale), ImGuiSetCond_FirstUseEver); + ImGui::SetNextWindowSize(ImVec2(300 * example->UIOverlay.scale, 200 * example->UIOverlay.scale), ImGuiSetCond_FirstUseEver); ImGui::Begin("Example settings"); ImGui::Checkbox("Render models", &uiSettings.displayModels); ImGui::Checkbox("Display logos", &uiSettings.displayLogos); @@ -358,7 +382,7 @@ public: ImGui::SliderFloat("Light speed", &uiSettings.lightSpeed, 0.1f, 1.0f); ImGui::End(); - ImGui::SetNextWindowPos(ImVec2(650, 20), ImGuiSetCond_FirstUseEver); + //SRS - ShowDemoWindow() sets its own initial position and size, cannot override here ImGui::ShowDemoWindow(); // Render to generate draw buffers @@ -499,6 +523,10 @@ public: camera.setPosition(glm::vec3(0.0f, 0.0f, -4.8f)); camera.setRotation(glm::vec3(4.5f, -380.0f, 0.0f)); camera.setPerspective(45.0f, (float)width / (float)height, 0.1f, 256.0f); + + //SRS - Enable VK_KHR_get_physical_device_properties2 to retrieve device driver information for display + enabledInstanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + // Don't use the ImGui overlay of the base framework in this sample settings.overlay = false; } @@ -568,7 +596,9 @@ public: } // Render imGui - imGui->drawFrame(drawCmdBuffers[i]); + if (UIOverlay.visible) { + imGui->drawFrame(drawCmdBuffers[i]); + } vkCmdEndRenderPass(drawCmdBuffers[i]); @@ -720,8 +750,9 @@ public: io.DeltaTime = frameTimer; io.MousePos = ImVec2(mousePos.x, mousePos.y); - io.MouseDown[0] = mouseButtons.left; - io.MouseDown[1] = mouseButtons.right; + io.MouseDown[0] = mouseButtons.left && UIOverlay.visible; + io.MouseDown[1] = mouseButtons.right && UIOverlay.visible; + io.MouseDown[2] = mouseButtons.middle && UIOverlay.visible; draw(); @@ -737,7 +768,7 @@ public: virtual void mouseMoved(double x, double y, bool &handled) { ImGuiIO& io = ImGui::GetIO(); - handled = io.WantCaptureMouse; + handled = io.WantCaptureMouse && UIOverlay.visible; } }; diff --git a/examples/indirectdraw/indirectdraw.cpp b/examples/indirectdraw/indirectdraw.cpp index c5e373a9..4baee4aa 100644 --- a/examples/indirectdraw/indirectdraw.cpp +++ b/examples/indirectdraw/indirectdraw.cpp @@ -499,6 +499,11 @@ public: } } + virtual void viewChanged() + { + updateUniformBuffer(true); + } + virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { if (!vulkanDevice->features.multiDrawIndirect) { @@ -512,4 +517,4 @@ public: } }; -VULKAN_EXAMPLE_MAIN() \ No newline at end of file +VULKAN_EXAMPLE_MAIN() diff --git a/examples/inlineuniformblocks/inlineuniformblocks.cpp b/examples/inlineuniformblocks/inlineuniformblocks.cpp index 1dafe711..04b11bf7 100644 --- a/examples/inlineuniformblocks/inlineuniformblocks.cpp +++ b/examples/inlineuniformblocks/inlineuniformblocks.cpp @@ -357,6 +357,11 @@ public: updateUniformBuffers(); } + virtual void viewChanged() + { + updateUniformBuffers(); + } + /* [POI] Update descriptor sets at runtime */ @@ -401,4 +406,4 @@ public: }; -VULKAN_EXAMPLE_MAIN() \ No newline at end of file +VULKAN_EXAMPLE_MAIN() diff --git a/examples/inputattachments/inputattachments.cpp b/examples/inputattachments/inputattachments.cpp index 4b454b08..3fd2c828 100644 --- a/examples/inputattachments/inputattachments.cpp +++ b/examples/inputattachments/inputattachments.cpp @@ -180,11 +180,23 @@ public: for (auto i = 0; i < attachments.size(); i++) { clearAttachment(&attachments[i].color); clearAttachment(&attachments[i].depth); + } + + // SRS - Recreate attachments and descriptors in case number of swapchain images has changed on resize + attachments.resize(swapChain.imageCount); + for (auto i = 0; i < attachments.size(); i++) { createAttachment(colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, &attachments[i].color); createAttachment(depthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, &attachments[i].depth); - // Since the framebuffers/attachments are referred in the descriptor sets, these need to be updated too - updateAttachmentReadDescriptors(i); } + + vkDestroyPipelineLayout(device, pipelineLayouts.attachmentWrite, nullptr); + vkDestroyPipelineLayout(device, pipelineLayouts.attachmentRead, nullptr); + vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.attachmentWrite, nullptr); + vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.attachmentRead, nullptr); + vkDestroyDescriptorPool(device, descriptorPool, nullptr); + + // Since the framebuffers/attachments are referred in the descriptor sets, these need to be updated on resize + setupDescriptors(); } VkImageView views[3]; @@ -594,6 +606,11 @@ public: } } + virtual void viewChanged() + { + updateUniformBuffers(); + } + virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { if (overlay->header("Settings")) { diff --git a/examples/instancing/instancing.cpp b/examples/instancing/instancing.cpp index d8dbe2b7..74feb2f7 100644 --- a/examples/instancing/instancing.cpp +++ b/examples/instancing/instancing.cpp @@ -482,6 +482,11 @@ public: } } + virtual void viewChanged() + { + updateUniformBuffer(true); + } + virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { if (overlay->header("Statistics")) { @@ -490,4 +495,4 @@ public: } }; -VULKAN_EXAMPLE_MAIN() \ No newline at end of file +VULKAN_EXAMPLE_MAIN() diff --git a/examples/multisampling/multisampling.cpp b/examples/multisampling/multisampling.cpp index 408e18f7..9fe2a0ed 100644 --- a/examples/multisampling/multisampling.cpp +++ b/examples/multisampling/multisampling.cpp @@ -48,6 +48,7 @@ public: VkPipelineLayout pipelineLayout; VkDescriptorSet descriptorSet; VkDescriptorSetLayout descriptorSetLayout; + VkExtent2D attachmentSize; VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION) { @@ -186,7 +187,9 @@ public: viewInfo.components.g = VK_COMPONENT_SWIZZLE_G; viewInfo.components.b = VK_COMPONENT_SWIZZLE_B; viewInfo.components.a = VK_COMPONENT_SWIZZLE_A; - viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + if (depthFormat >= VK_FORMAT_D16_UNORM_S8_UINT) + viewInfo.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; viewInfo.subresourceRange.levelCount = 1; viewInfo.subresourceRange.layerCount = 1; @@ -199,6 +202,8 @@ public: void setupRenderPass() { // Overrides the virtual function of the base class + + attachmentSize = { width, height }; std::array attachments = {}; @@ -290,6 +295,20 @@ public: { // Overrides the virtual function of the base class + // SRS - If the window is resized, the MSAA attachments need to be released and recreated + if (attachmentSize.width != width || attachmentSize.height != height) + { + attachmentSize = { width, height }; + + // Destroy MSAA target + vkDestroyImage(device, multisampleTarget.color.image, nullptr); + vkDestroyImageView(device, multisampleTarget.color.view, nullptr); + vkFreeMemory(device, multisampleTarget.color.memory, nullptr); + vkDestroyImage(device, multisampleTarget.depth.image, nullptr); + vkDestroyImageView(device, multisampleTarget.depth.view, nullptr); + vkFreeMemory(device, multisampleTarget.depth.memory, nullptr); + } + std::array attachments; setupMultisampleTarget(); @@ -524,6 +543,11 @@ public: } } + virtual void viewChanged() + { + updateUniformBuffers(); + } + // Returns the maximum sample count usable by the platform VkSampleCountFlagBits getMaxUsableSampleCount() { diff --git a/examples/multithreading/multithreading.cpp b/examples/multithreading/multithreading.cpp index 38ef02f2..e071c521 100644 --- a/examples/multithreading/multithreading.cpp +++ b/examples/multithreading/multithreading.cpp @@ -321,9 +321,7 @@ public: vkCmdBindPipeline(secondaryCommandBuffers.ui, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.starsphere); - if (settings.overlay) { - drawUI(secondaryCommandBuffers.ui); - } + drawUI(secondaryCommandBuffers.ui); VK_CHECK_RESULT(vkEndCommandBuffer(secondaryCommandBuffers.ui)); } @@ -527,6 +525,11 @@ public: } } + virtual void viewChanged() + { + updateMatrices(); + } + virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { if (overlay->header("Statistics")) { @@ -539,4 +542,4 @@ public: } }; -VULKAN_EXAMPLE_MAIN() \ No newline at end of file +VULKAN_EXAMPLE_MAIN() diff --git a/examples/multiview/multiview.cpp b/examples/multiview/multiview.cpp index a73992f3..8879037e 100644 --- a/examples/multiview/multiview.cpp +++ b/examples/multiview/multiview.cpp @@ -98,6 +98,7 @@ public: vkDestroySampler(device, multiviewPass.sampler, nullptr); vkDestroyFramebuffer(device, multiviewPass.frameBuffer, nullptr); + vkFreeCommandBuffers(device, cmdPool, static_cast(multiviewPass.commandBuffers.size()), multiviewPass.commandBuffers.data()); vkDestroySemaphore(device, multiviewPass.semaphore, nullptr); for (auto& fence : multiviewPass.waitFences) { vkDestroyFence(device, fence, nullptr); @@ -150,7 +151,9 @@ public: depthStencilView.format = depthFormat; depthStencilView.flags = 0; depthStencilView.subresourceRange = {}; - depthStencilView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + depthStencilView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + if (depthFormat >= VK_FORMAT_D16_UNORM_S8_UINT) + depthStencilView.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; depthStencilView.subresourceRange.baseMipLevel = 0; depthStencilView.subresourceRange.levelCount = 1; depthStencilView.subresourceRange.baseArrayLayer = 0; @@ -337,6 +340,9 @@ public: void buildCommandBuffers() { + if (resized) + return; + /* View display */ @@ -392,11 +398,6 @@ public: Multiview layered attachment scene rendering */ - multiviewPass.commandBuffers.resize(drawCmdBuffers.size()); - - VkCommandBufferAllocateInfo cmdBufAllocateInfo = vks::initializers::commandBufferAllocateInfo(cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, static_cast(drawCmdBuffers.size())); - VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, multiviewPass.commandBuffers.data())); - { VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo(); @@ -467,13 +468,18 @@ public: */ VkDescriptorSetAllocateInfo allocateInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout, 1); VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocateInfo, &descriptorSet)); + updateDescriptors(); + } + + void updateDescriptors() + { std::vector writeDescriptorSets = { vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffer.descriptor), vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, &multiviewPass.descriptor), }; vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr); } - + void preparePipelines() { @@ -669,6 +675,11 @@ public: prepareUniformBuffers(); prepareDescriptors(); preparePipelines(); + + VkCommandBufferAllocateInfo cmdBufAllocateInfo = vks::initializers::commandBufferAllocateInfo(cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, static_cast(drawCmdBuffers.size())); + multiviewPass.commandBuffers.resize(drawCmdBuffers.size()); + VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, multiviewPass.commandBuffers.data())); + buildCommandBuffers(); VkFenceCreateInfo fenceCreateInfo = vks::initializers::fenceCreateInfo(VK_FENCE_CREATE_SIGNALED_BIT); @@ -680,6 +691,45 @@ public: prepared = true; } + // SRS - Recreate and update Multiview resources when window size has changed + virtual void windowResized() + { + vkDestroyImageView(device, multiviewPass.color.view, nullptr); + vkDestroyImage(device, multiviewPass.color.image, nullptr); + vkFreeMemory(device, multiviewPass.color.memory, nullptr); + vkDestroyImageView(device, multiviewPass.depth.view, nullptr); + vkDestroyImage(device, multiviewPass.depth.image, nullptr); + vkFreeMemory(device, multiviewPass.depth.memory, nullptr); + + vkDestroyRenderPass(device, multiviewPass.renderPass, nullptr); + vkDestroySampler(device, multiviewPass.sampler, nullptr); + vkDestroyFramebuffer(device, multiviewPass.frameBuffer, nullptr); + + prepareMultiview(); + updateDescriptors(); + + // SRS - Recreate Multiview command buffers in case number of swapchain images has changed on resize + vkFreeCommandBuffers(device, cmdPool, static_cast(multiviewPass.commandBuffers.size()), multiviewPass.commandBuffers.data()); + + VkCommandBufferAllocateInfo cmdBufAllocateInfo = vks::initializers::commandBufferAllocateInfo(cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, static_cast(drawCmdBuffers.size())); + multiviewPass.commandBuffers.resize(drawCmdBuffers.size()); + VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, multiviewPass.commandBuffers.data())); + + resized = false; + buildCommandBuffers(); + + // SRS - Recreate Multiview fences in case number of swapchain images has changed on resize + for (auto& fence : multiviewPass.waitFences) { + vkDestroyFence(device, fence, nullptr); + } + + VkFenceCreateInfo fenceCreateInfo = vks::initializers::fenceCreateInfo(VK_FENCE_CREATE_SIGNALED_BIT); + multiviewPass.waitFences.resize(multiviewPass.commandBuffers.size()); + for (auto& fence : multiviewPass.waitFences) { + VK_CHECK_RESULT(vkCreateFence(device, &fenceCreateInfo, nullptr, &fence)); + } + } + virtual void render() { if (!prepared) @@ -690,6 +740,11 @@ public: } } + virtual void viewChanged() + { + updateUniformBuffers(); + } + virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { if (overlay->header("Settings")) { @@ -704,4 +759,4 @@ public: }; -VULKAN_EXAMPLE_MAIN() \ No newline at end of file +VULKAN_EXAMPLE_MAIN() diff --git a/examples/offscreen/offscreen.cpp b/examples/offscreen/offscreen.cpp index 4ae6cbe7..8c39f7ec 100644 --- a/examples/offscreen/offscreen.cpp +++ b/examples/offscreen/offscreen.cpp @@ -209,7 +209,9 @@ public: depthStencilView.format = fbDepthFormat; depthStencilView.flags = 0; depthStencilView.subresourceRange = {}; - depthStencilView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + depthStencilView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + if (fbDepthFormat >= VK_FORMAT_D16_UNORM_S8_UINT) + depthStencilView.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; depthStencilView.subresourceRange.baseMipLevel = 0; depthStencilView.subresourceRange.levelCount = 1; depthStencilView.subresourceRange.baseArrayLayer = 0; diff --git a/examples/oit/oit.cpp b/examples/oit/oit.cpp index 2743f974..77bdd68e 100644 --- a/examples/oit/oit.cpp +++ b/examples/oit/oit.cpp @@ -507,7 +507,7 @@ private: vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL); } - void buildCommandBuffers() + void buildCommandBuffers() override { if (resized) return; @@ -656,4 +656,4 @@ private: VkDeviceSize objectUniformBufferSize; }; -VULKAN_EXAMPLE_MAIN() \ No newline at end of file +VULKAN_EXAMPLE_MAIN() diff --git a/examples/particlefire/particlefire.cpp b/examples/particlefire/particlefire.cpp index b4b9bb55..e966d545 100644 --- a/examples/particlefire/particlefire.cpp +++ b/examples/particlefire/particlefire.cpp @@ -589,6 +589,11 @@ public: updateUniformBuffers(); } } + + virtual void viewChanged() + { + updateUniformBuffers(); + } }; -VULKAN_EXAMPLE_MAIN() \ No newline at end of file +VULKAN_EXAMPLE_MAIN() diff --git a/examples/pbrtexture/pbrtexture.cpp b/examples/pbrtexture/pbrtexture.cpp index 5be56716..e69c8b78 100644 --- a/examples/pbrtexture/pbrtexture.cpp +++ b/examples/pbrtexture/pbrtexture.cpp @@ -1340,6 +1340,11 @@ public: } } + virtual void viewChanged() + { + updateUniformBuffers(); + } + virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { if (overlay->header("Settings")) { diff --git a/examples/pipelines/pipelines.cpp b/examples/pipelines/pipelines.cpp index 68d0415a..13034073 100644 --- a/examples/pipelines/pipelines.cpp +++ b/examples/pipelines/pipelines.cpp @@ -334,6 +334,12 @@ public: } } + virtual void viewChanged() + { + camera.setPerspective(60.0f, (float)(width / 3.0f) / (float)height, 0.1f, 256.0f); + updateUniformBuffers(); + } + virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { if (!deviceFeatures.fillModeNonSolid) { @@ -344,4 +350,4 @@ public: } }; -VULKAN_EXAMPLE_MAIN() \ No newline at end of file +VULKAN_EXAMPLE_MAIN() diff --git a/examples/pushdescriptors/pushdescriptors.cpp b/examples/pushdescriptors/pushdescriptors.cpp index 080f5b41..a6f6094d 100644 --- a/examples/pushdescriptors/pushdescriptors.cpp +++ b/examples/pushdescriptors/pushdescriptors.cpp @@ -262,7 +262,7 @@ public: memcpy(cube.uniformBuffer.mapped, &cube.modelMat, sizeof(glm::mat4)); } - if (animate) { + if (animate && !paused) { cubes[0].rotation.x += 2.5f * frameTimer; if (cubes[0].rotation.x > 360.0f) cubes[0].rotation.x -= 360.0f; @@ -323,7 +323,7 @@ public: if (!prepared) return; draw(); - if (animate) { + if (animate && !paused) { cubes[0].rotation.x += 2.5f * frameTimer; if (cubes[0].rotation.x > 360.0f) cubes[0].rotation.x -= 360.0f; @@ -337,6 +337,11 @@ public: } } + virtual void viewChanged() + { + updateUniformBuffers(); + } + virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { if (overlay->header("Settings")) { @@ -348,4 +353,4 @@ public: } }; -VULKAN_EXAMPLE_MAIN() \ No newline at end of file +VULKAN_EXAMPLE_MAIN() diff --git a/examples/radialblur/radialblur.cpp b/examples/radialblur/radialblur.cpp index 22daed60..9b54883e 100644 --- a/examples/radialblur/radialblur.cpp +++ b/examples/radialblur/radialblur.cpp @@ -208,7 +208,9 @@ public: depthStencilView.format = fbDepthFormat; depthStencilView.flags = 0; depthStencilView.subresourceRange = {}; - depthStencilView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + depthStencilView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + if (fbDepthFormat >= VK_FORMAT_D16_UNORM_S8_UINT) + depthStencilView.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; depthStencilView.subresourceRange.baseMipLevel = 0; depthStencilView.subresourceRange.levelCount = 1; depthStencilView.subresourceRange.baseArrayLayer = 0; diff --git a/examples/renderheadless/renderheadless.cpp b/examples/renderheadless/renderheadless.cpp index ba41bf8a..d259ff77 100644 --- a/examples/renderheadless/renderheadless.cpp +++ b/examples/renderheadless/renderheadless.cpp @@ -30,6 +30,9 @@ #include #include +#if defined(VK_USE_PLATFORM_MACOS_MVK) +#define VK_ENABLE_BETA_EXTENSIONS +#endif #include #include "VulkanTools.h" @@ -175,9 +178,10 @@ public: const char* validationLayers[] = { "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation", "VK_LAYER_LUNARG_object_tracker","VK_LAYER_LUNARG_core_validation", "VK_LAYER_LUNARG_swapchain", "VK_LAYER_GOOGLE_unique_objects" }; layerCount = 6; #else - const char* validationLayers[] = { "VK_LAYER_LUNARG_standard_validation" }; + const char* validationLayers[] = { "VK_LAYER_KHRONOS_validation" }; layerCount = 1; #endif + std::vector instanceExtensions = {}; #if DEBUG // Check if layers are available uint32_t instanceLayerCount; @@ -200,14 +204,39 @@ public: } } - const char *validationExt = VK_EXT_DEBUG_REPORT_EXTENSION_NAME; if (layersAvailable) { + instanceExtensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME); instanceCreateInfo.ppEnabledLayerNames = validationLayers; instanceCreateInfo.enabledLayerCount = layerCount; - instanceCreateInfo.enabledExtensionCount = 1; - instanceCreateInfo.ppEnabledExtensionNames = &validationExt; } #endif +#if defined(VK_USE_PLATFORM_MACOS_MVK) + // SRS - When running on macOS with MoltenVK, enable VK_KHR_get_physical_device_properties2 (required by VK_KHR_portability_subset) + instanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); +#if defined(VK_KHR_portability_enumeration) + // SRS - When running on macOS with MoltenVK and VK_KHR_portability_enumeration is defined and supported by the instance, enable the extension and the flag + uint32_t instanceExtCount = 0; + vkEnumerateInstanceExtensionProperties(nullptr, &instanceExtCount, nullptr); + if (instanceExtCount > 0) + { + std::vector extensions(instanceExtCount); + if (vkEnumerateInstanceExtensionProperties(nullptr, &instanceExtCount, &extensions.front()) == VK_SUCCESS) + { + for (VkExtensionProperties extension : extensions) + { + if (strcmp(extension.extensionName, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME) == 0) + { + instanceExtensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); + instanceCreateInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; + break; + } + } + } + } +#endif +#endif + instanceCreateInfo.enabledExtensionCount = (uint32_t)instanceExtensions.size(); + instanceCreateInfo.ppEnabledExtensionNames = instanceExtensions.data(); VK_CHECK_RESULT(vkCreateInstance(&instanceCreateInfo, nullptr, &instance)); #if defined(VK_USE_PLATFORM_ANDROID_KHR) @@ -262,6 +291,29 @@ public: deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; deviceCreateInfo.queueCreateInfoCount = 1; deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo; + std::vector deviceExtensions = {}; +#if defined(VK_USE_PLATFORM_MACOS_MVK) && defined(VK_KHR_portability_subset) + // SRS - When running on macOS with MoltenVK and VK_KHR_portability_subset is defined and supported by the device, enable the extension + uint32_t deviceExtCount = 0; + vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &deviceExtCount, nullptr); + if (deviceExtCount > 0) + { + std::vector extensions(deviceExtCount); + if (vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &deviceExtCount, &extensions.front()) == VK_SUCCESS) + { + for (VkExtensionProperties extension : extensions) + { + if (strcmp(extension.extensionName, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME) == 0) + { + deviceExtensions.push_back(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME); + break; + } + } + } + } +#endif + deviceCreateInfo.enabledExtensionCount = (uint32_t)deviceExtensions.size(); + deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions.data(); VK_CHECK_RESULT(vkCreateDevice(physicalDevice, &deviceCreateInfo, nullptr, &device)); // Get a graphics queue @@ -418,7 +470,9 @@ public: depthStencilView.format = depthFormat; depthStencilView.flags = 0; depthStencilView.subresourceRange = {}; - depthStencilView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + depthStencilView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + if (depthFormat >= VK_FORMAT_D16_UNORM_S8_UINT) + depthStencilView.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; depthStencilView.subresourceRange.baseMipLevel = 0; depthStencilView.subresourceRange.levelCount = 1; depthStencilView.subresourceRange.baseArrayLayer = 0; @@ -894,4 +948,4 @@ int main() { delete(vulkanExample); return 0; } -#endif \ No newline at end of file +#endif diff --git a/examples/shadowmappingomni/shadowmappingomni.cpp b/examples/shadowmappingomni/shadowmappingomni.cpp index 72e82bd5..3835ac01 100644 --- a/examples/shadowmappingomni/shadowmappingomni.cpp +++ b/examples/shadowmappingomni/shadowmappingomni.cpp @@ -291,7 +291,9 @@ public: depthStencilView.format = fbDepthFormat; depthStencilView.flags = 0; depthStencilView.subresourceRange = {}; - depthStencilView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + depthStencilView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + if (fbDepthFormat >= VK_FORMAT_D16_UNORM_S8_UINT) + depthStencilView.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; depthStencilView.subresourceRange.baseMipLevel = 0; depthStencilView.subresourceRange.levelCount = 1; depthStencilView.subresourceRange.baseArrayLayer = 0; diff --git a/examples/specializationconstants/specializationconstants.cpp b/examples/specializationconstants/specializationconstants.cpp index 0384086d..d0692d03 100644 --- a/examples/specializationconstants/specializationconstants.cpp +++ b/examples/specializationconstants/specializationconstants.cpp @@ -320,10 +320,10 @@ public: } } - virtual void windowResized() + virtual void viewChanged() { updateUniformBuffers(); } }; -VULKAN_EXAMPLE_MAIN() \ No newline at end of file +VULKAN_EXAMPLE_MAIN() diff --git a/examples/sphericalenvmapping/sphericalenvmapping.cpp b/examples/sphericalenvmapping/sphericalenvmapping.cpp index 883184aa..9bf8ce3e 100644 --- a/examples/sphericalenvmapping/sphericalenvmapping.cpp +++ b/examples/sphericalenvmapping/sphericalenvmapping.cpp @@ -277,6 +277,11 @@ public: } } + virtual void viewChanged() + { + updateUniformBuffers(); + } + virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { if (overlay->header("Settings")) { @@ -288,4 +293,4 @@ public: }; -VULKAN_EXAMPLE_MAIN() \ No newline at end of file +VULKAN_EXAMPLE_MAIN() diff --git a/examples/ssao/ssao.cpp b/examples/ssao/ssao.cpp index 92558908..cb87d6fa 100644 --- a/examples/ssao/ssao.cpp +++ b/examples/ssao/ssao.cpp @@ -196,7 +196,9 @@ public: } if (usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { - aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + if (format >= VK_FORMAT_D16_UNORM_S8_UINT) + aspectMask |=VK_IMAGE_ASPECT_STENCIL_BIT; } assert(aspectMask > 0); @@ -944,6 +946,12 @@ public: } } + virtual void viewChanged() + { + updateUniformBufferMatrices(); + updateUniformBufferSSAOParams(); + } + virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { if (overlay->header("Settings")) { diff --git a/examples/subpasses/subpasses.cpp b/examples/subpasses/subpasses.cpp index d1e4ea93..9f59df3c 100644 --- a/examples/subpasses/subpasses.cpp +++ b/examples/subpasses/subpasses.cpp @@ -903,6 +903,12 @@ public: } } + virtual void viewChanged() + { + updateUniformBufferDeferredMatrices(); + updateUniformBufferDeferredLights(); + } + virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { if (overlay->header("Subpasses")) { diff --git a/examples/terraintessellation/terraintessellation.cpp b/examples/terraintessellation/terraintessellation.cpp index 80a79e27..30bcbd1e 100644 --- a/examples/terraintessellation/terraintessellation.cpp +++ b/examples/terraintessellation/terraintessellation.cpp @@ -828,6 +828,11 @@ public: } } + virtual void viewChanged() + { + updateUniformBuffers(); + } + virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { if (overlay->header("Settings")) { @@ -853,4 +858,4 @@ public: } }; -VULKAN_EXAMPLE_MAIN() \ No newline at end of file +VULKAN_EXAMPLE_MAIN() diff --git a/examples/tessellation/tessellation.cpp b/examples/tessellation/tessellation.cpp index 444a0789..87b5b8fd 100644 --- a/examples/tessellation/tessellation.cpp +++ b/examples/tessellation/tessellation.cpp @@ -326,6 +326,12 @@ public: } } + virtual void viewChanged() + { + camera.setPerspective(45.0f, (float)(width * ((splitScreen) ? 0.5f : 1.0f)) / (float)height, 0.1f, 256.0f); + updateUniformBuffers(); + } + virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { if (overlay->header("Settings")) { diff --git a/examples/textoverlay/textoverlay.cpp b/examples/textoverlay/textoverlay.cpp index 85b70727..ca5cc412 100644 --- a/examples/textoverlay/textoverlay.cpp +++ b/examples/textoverlay/textoverlay.cpp @@ -31,6 +31,7 @@ private: uint32_t *frameBufferWidth; uint32_t *frameBufferHeight; + float scale; VkSampler sampler; VkImage image; @@ -70,6 +71,7 @@ public: VkFormat depthformat, uint32_t *framebufferwidth, uint32_t *framebufferheight, + float scale, std::vector shaderstages) { this->vulkanDevice = vulkanDevice; @@ -87,6 +89,7 @@ public: this->frameBufferWidth = framebufferwidth; this->frameBufferHeight = framebufferheight; + this->scale = scale; cmdBuffers.resize(framebuffers.size()); prepareResources(); @@ -490,8 +493,8 @@ public: assert(mapped != nullptr); - const float charW = 1.5f / *frameBufferWidth; - const float charH = 1.5f / *frameBufferHeight; + const float charW = 1.5f * scale / *frameBufferWidth; + const float charH = 1.5f * scale / *frameBufferHeight; float fbW = (float)*frameBufferWidth; float fbH = (float)*frameBufferHeight; @@ -514,6 +517,8 @@ public: case alignCenter: x -= textWidth / 2.0f; break; + case alignLeft: + break; } // Generate a uv mapped quad per char in the new text @@ -698,23 +703,23 @@ public: { textOverlay->beginTextUpdate(); - textOverlay->addText(title, 5.0f, 5.0f, TextOverlay::alignLeft); + textOverlay->addText(title, 5.0f * UIOverlay.scale, 5.0f * UIOverlay.scale, TextOverlay::alignLeft); std::stringstream ss; ss << std::fixed << std::setprecision(2) << (frameTimer * 1000.0f) << "ms (" << lastFPS << " fps)"; - textOverlay->addText(ss.str(), 5.0f, 25.0f, TextOverlay::alignLeft); + textOverlay->addText(ss.str(), 5.0f * UIOverlay.scale, 25.0f * UIOverlay.scale, TextOverlay::alignLeft); - textOverlay->addText(deviceProperties.deviceName, 5.0f, 45.0f, TextOverlay::alignLeft); + textOverlay->addText(deviceProperties.deviceName, 5.0f * UIOverlay.scale, 45.0f * UIOverlay.scale, TextOverlay::alignLeft); // Display current model view matrix - textOverlay->addText("model view matrix", (float)width, 5.0f, TextOverlay::alignRight); + textOverlay->addText("model view matrix", (float)width - 5.0f * UIOverlay.scale, 5.0f * UIOverlay.scale, TextOverlay::alignRight); for (uint32_t i = 0; i < 4; i++) { ss.str(""); ss << std::fixed << std::setprecision(2) << std::showpos; ss << uboVS.modelView[0][i] << " " << uboVS.modelView[1][i] << " " << uboVS.modelView[2][i] << " " << uboVS.modelView[3][i]; - textOverlay->addText(ss.str(), (float)width, 25.0f + (float)i * 20.0f, TextOverlay::alignRight); + textOverlay->addText(ss.str(), (float)width - 5.0f * UIOverlay.scale, (25.0f + (float)i * 20.0f) * UIOverlay.scale, TextOverlay::alignRight); } glm::vec3 projected = glm::project(glm::vec3(0.0f), uboVS.modelView, uboVS.projection, glm::vec4(0, 0, (float)width, (float)height)); @@ -722,8 +727,8 @@ public: #if defined(__ANDROID__) #else - textOverlay->addText("Press \"space\" to toggle text overlay", 5.0f, 65.0f, TextOverlay::alignLeft); - textOverlay->addText("Hold middle mouse button and drag to move", 5.0f, 85.0f, TextOverlay::alignLeft); + textOverlay->addText("Press \"space\" to toggle text overlay", 5.0f * UIOverlay.scale, 65.0f * UIOverlay.scale, TextOverlay::alignLeft); + textOverlay->addText("Hold middle mouse button and drag to move", 5.0f * UIOverlay.scale, 85.0f * UIOverlay.scale, TextOverlay::alignLeft); #endif textOverlay->endTextUpdate(); } @@ -840,6 +845,7 @@ public: depthFormat, &width, &height, + UIOverlay.scale, shaderStages ); updateTextOverlay(); @@ -885,6 +891,10 @@ public: if (!prepared) return; draw(); + if (camera.updated) + { + updateUniformBuffers(); + } if (frameCounter == 0) { vkDeviceWaitIdle(device); @@ -892,19 +902,19 @@ public: } } + virtual void windowResized() + { + // SRS - Recreate text overlay resources in case number of swapchain images has changed on resize + delete textOverlay; + prepareTextOverlay(); + } + virtual void viewChanged() { - vkDeviceWaitIdle(device); updateUniformBuffers(); updateTextOverlay(); } - virtual void windowResized() - { - updateTextOverlay(); - } - -#if !defined(__ANDROID__) virtual void keyPressed(uint32_t keyCode) { switch (keyCode) @@ -914,7 +924,6 @@ public: textOverlay->visible = !textOverlay->visible; } } -#endif }; -VULKAN_EXAMPLE_MAIN() \ No newline at end of file +VULKAN_EXAMPLE_MAIN() diff --git a/examples/texture3d/texture3d.cpp b/examples/texture3d/texture3d.cpp index f2f672e2..773848c2 100644 --- a/examples/texture3d/texture3d.cpp +++ b/examples/texture3d/texture3d.cpp @@ -773,6 +773,11 @@ public: updateUniformBuffers(camera.updated); } + virtual void viewChanged() + { + updateUniformBuffers(true); + } + virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { if (overlay->header("Settings")) { diff --git a/examples/texturearray/texturearray.cpp b/examples/texturearray/texturearray.cpp index 41cd5392..921addea 100644 --- a/examples/texturearray/texturearray.cpp +++ b/examples/texturearray/texturearray.cpp @@ -550,6 +550,10 @@ public: updateUniformBuffersCamera(); } + virtual void viewChanged() + { + updateUniformBuffersCamera(); + } }; -VULKAN_EXAMPLE_MAIN() \ No newline at end of file +VULKAN_EXAMPLE_MAIN() diff --git a/examples/texturecubemaparray/texturecubemaparray.cpp b/examples/texturecubemaparray/texturecubemaparray.cpp index 6d9c5494..6e649d82 100644 --- a/examples/texturecubemaparray/texturecubemaparray.cpp +++ b/examples/texturecubemaparray/texturecubemaparray.cpp @@ -529,6 +529,11 @@ public: } } + virtual void viewChanged() + { + updateUniformBuffers(); + } + virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { if (overlay->header("Settings")) { @@ -548,4 +553,4 @@ public: } }; -VULKAN_EXAMPLE_MAIN() \ No newline at end of file +VULKAN_EXAMPLE_MAIN() diff --git a/examples/texturemipmapgen/texturemipmapgen.cpp b/examples/texturemipmapgen/texturemipmapgen.cpp index 1fae3773..d74dab51 100644 --- a/examples/texturemipmapgen/texturemipmapgen.cpp +++ b/examples/texturemipmapgen/texturemipmapgen.cpp @@ -443,7 +443,7 @@ public: { std::vector setLayoutBindings = { // Binding 0: Vertex shader uniform buffer - vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT, 0), + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0), // Binding 1: Sampled image vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_SHADER_STAGE_FRAGMENT_BIT, 1), // Binding 2: Sampler array (3 descriptors) diff --git a/examples/texturesparseresidency/texturesparseresidency.cpp b/examples/texturesparseresidency/texturesparseresidency.cpp index 0875a6ec..10889474 100644 --- a/examples/texturesparseresidency/texturesparseresidency.cpp +++ b/examples/texturesparseresidency/texturesparseresidency.cpp @@ -708,6 +708,11 @@ void VulkanExample::render() } } +void VulkanExample::viewChanged() +{ + updateUniformBuffers(); +} + // Fills a buffer with random colors void VulkanExample::randomPattern(uint8_t* buffer, uint32_t width, uint32_t height) { diff --git a/examples/texturesparseresidency/texturesparseresidency.h b/examples/texturesparseresidency/texturesparseresidency.h index e061dc9e..5da19e18 100644 --- a/examples/texturesparseresidency/texturesparseresidency.h +++ b/examples/texturesparseresidency/texturesparseresidency.h @@ -116,6 +116,7 @@ public: void updateUniformBuffers(); void prepare(); virtual void render(); + virtual void viewChanged(); void uploadContent(VirtualTexturePage page, VkImage image); void fillRandomPages(); void fillMipTail(); diff --git a/examples/triangle/triangle.cpp b/examples/triangle/triangle.cpp index 77e4df8f..dd5ab472 100644 --- a/examples/triangle/triangle.cpp +++ b/examples/triangle/triangle.cpp @@ -109,7 +109,7 @@ public: // Fences // Used to check the completion of queue operations (e.g. command buffer execution) - std::vector waitFences; + std::vector queueCompleteFences; VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION) { @@ -145,7 +145,7 @@ public: vkDestroySemaphore(device, presentCompleteSemaphore, nullptr); vkDestroySemaphore(device, renderCompleteSemaphore, nullptr); - for (auto& fence : waitFences) + for (auto& fence : queueCompleteFences) { vkDestroyFence(device, fence, nullptr); } @@ -193,8 +193,8 @@ public: fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; // Create in signaled state so we don't wait on first render of each command buffer fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; - waitFences.resize(drawCmdBuffers.size()); - for (auto& fence : waitFences) + queueCompleteFences.resize(drawCmdBuffers.size()); + for (auto& fence : queueCompleteFences) { VK_CHECK_RESULT(vkCreateFence(device, &fenceCreateInfo, nullptr, &fence)); } @@ -334,12 +334,26 @@ public: void draw() { +#if defined(VK_USE_PLATFORM_MACOS_MVK) + // SRS - on macOS use swapchain helper function with common semaphores/fences for proper resize handling // Get next image in the swap chain (back/front buffer) - VK_CHECK_RESULT(swapChain.acquireNextImage(presentCompleteSemaphore, ¤tBuffer)); + prepareFrame(); // Use a fence to wait until the command buffer has finished execution before using it again VK_CHECK_RESULT(vkWaitForFences(device, 1, &waitFences[currentBuffer], VK_TRUE, UINT64_MAX)); VK_CHECK_RESULT(vkResetFences(device, 1, &waitFences[currentBuffer])); +#else + // SRS - on other platforms use original bare code with local semaphores/fences for illustrative purposes + // Get next image in the swap chain (back/front buffer) + VkResult acquire = swapChain.acquireNextImage(presentCompleteSemaphore, ¤tBuffer); + if (!((acquire == VK_SUCCESS) || (acquire == VK_SUBOPTIMAL_KHR))) { + VK_CHECK_RESULT(acquire); + } + + // Use a fence to wait until the command buffer has finished execution before using it again + VK_CHECK_RESULT(vkWaitForFences(device, 1, &queueCompleteFences[currentBuffer], VK_TRUE, UINT64_MAX)); + VK_CHECK_RESULT(vkResetFences(device, 1, &queueCompleteFences[currentBuffer])); +#endif // Pipeline stage at which the queue submission will wait (via pWaitSemaphores) VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; @@ -347,16 +361,29 @@ public: VkSubmitInfo submitInfo = {}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.pWaitDstStageMask = &waitStageMask; // Pointer to the list of pipeline stages that the semaphore waits will occur at - submitInfo.pWaitSemaphores = &presentCompleteSemaphore; // Semaphore(s) to wait upon before the submitted command buffer starts executing submitInfo.waitSemaphoreCount = 1; // One wait semaphore - submitInfo.pSignalSemaphores = &renderCompleteSemaphore; // Semaphore(s) to be signaled when command buffers have completed submitInfo.signalSemaphoreCount = 1; // One signal semaphore submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer]; // Command buffers(s) to execute in this batch (submission) submitInfo.commandBufferCount = 1; // One command buffer +#if defined(VK_USE_PLATFORM_MACOS_MVK) + // SRS - on macOS use swapchain helper function with common semaphores/fences for proper resize handling + submitInfo.pWaitSemaphores = &semaphores.presentComplete; // Semaphore(s) to wait upon before the submitted command buffer starts executing + submitInfo.pSignalSemaphores = &semaphores.renderComplete; // Semaphore(s) to be signaled when command buffers have completed + // Submit to the graphics queue passing a wait fence VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, waitFences[currentBuffer])); + // Present the current buffer to the swap chain + submitFrame(); +#else + // SRS - on other platforms use original bare code with local semaphores/fences for illustrative purposes + submitInfo.pWaitSemaphores = &presentCompleteSemaphore; // Semaphore(s) to wait upon before the submitted command buffer starts executing + submitInfo.pSignalSemaphores = &renderCompleteSemaphore; // Semaphore(s) to be signaled when command buffers have completed + + // Submit to the graphics queue passing a wait fence + VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, queueCompleteFences[currentBuffer])); + // Present the current buffer to the swap chain // Pass the semaphore signaled by the command buffer submission from the submit info as the wait semaphore for swap chain presentation // This ensures that the image is not presented to the windowing system until all commands have been submitted @@ -364,7 +391,7 @@ public: if (!((present == VK_SUCCESS) || (present == VK_SUBOPTIMAL_KHR))) { VK_CHECK_RESULT(present); } - +#endif } // Prepare vertex and index buffers for an indexed triangle diff --git a/examples/vertexattributes/vertexattributes.cpp b/examples/vertexattributes/vertexattributes.cpp index b10f9991..5607b051 100644 --- a/examples/vertexattributes/vertexattributes.cpp +++ b/examples/vertexattributes/vertexattributes.cpp @@ -580,6 +580,11 @@ void VulkanExample::render() } } +void VulkanExample::viewChanged() +{ + updateUniformBuffers(); +} + void VulkanExample::OnUpdateUIOverlay(vks::UIOverlay* overlay) { if (overlay->header("Vertex buffer attributes")) { @@ -596,4 +601,4 @@ void VulkanExample::OnUpdateUIOverlay(vks::UIOverlay* overlay) } } -VULKAN_EXAMPLE_MAIN() \ No newline at end of file +VULKAN_EXAMPLE_MAIN() diff --git a/examples/vertexattributes/vertexattributes.h b/examples/vertexattributes/vertexattributes.h index af480ab0..1630ee5d 100644 --- a/examples/vertexattributes/vertexattributes.h +++ b/examples/vertexattributes/vertexattributes.h @@ -139,5 +139,6 @@ 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); -}; \ No newline at end of file +}; diff --git a/xcode/MVKExample.cpp b/xcode/MVKExample.cpp index 6db1c1cd..646074ce 100644 --- a/xcode/MVKExample.cpp +++ b/xcode/MVKExample.cpp @@ -10,21 +10,126 @@ #include "examples.h" void MVKExample::renderFrame() { - _vulkanExample->renderFrame(); + _vulkanExample->renderFrame(); } -void MVKExample::keyPressed(uint32_t keyCode) { - _vulkanExample->keyPressed(keyCode); +void MVKExample::displayLinkOutputCb() { // SRS - expose VulkanExampleBase::displayLinkOutputCb() to DemoViewController + _vulkanExample->displayLinkOutputCb(); } -MVKExample::MVKExample(void* view) { +void MVKExample::keyPressed(uint32_t keyChar) { // SRS - handle keyboard key presses only (e.g. Pause, Space, etc) + switch (keyChar) + { + case KEY_P: + _vulkanExample->paused = !_vulkanExample->paused; + break; + case KEY_1: // SRS - support keyboards with no function keys + case KEY_F1: + _vulkanExample->UIOverlay.visible = !_vulkanExample->UIOverlay.visible; + _vulkanExample->UIOverlay.updated = true; + break; + default: + _vulkanExample->keyPressed(keyChar); + break; + } +} + +void MVKExample::keyDown(uint32_t keyChar) { // SRS - handle physical keyboard key down/up actions and presses + switch (keyChar) + { + case KEY_W: + case KEY_Z: // for French AZERTY keyboards + _vulkanExample->camera.keys.up = true; + break; + case KEY_S: + _vulkanExample->camera.keys.down = true; + break; + case KEY_A: + case KEY_Q: // for French AZERTY keyboards + _vulkanExample->camera.keys.left = true; + break; + case KEY_D: + _vulkanExample->camera.keys.right = true; + break; + default: + MVKExample::keyPressed(keyChar); + break; + } +} + +void MVKExample::keyUp(uint32_t keyChar) { + switch (keyChar) + { + case KEY_W: + case KEY_Z: // for French AZERTY keyboards + _vulkanExample->camera.keys.up = false; + break; + case KEY_S: + _vulkanExample->camera.keys.down = false; + break; + case KEY_A: + case KEY_Q: // for French AZERTY keyboards + _vulkanExample->camera.keys.left = false; + break; + case KEY_D: + _vulkanExample->camera.keys.right = false; + break; + default: + break; + } +} + +void MVKExample::mouseDown(double x, double y) { + _vulkanExample->mousePos = glm::vec2(x, y); + _vulkanExample->mouseButtons.left = true; +} + +void MVKExample::mouseUp() { + _vulkanExample->mouseButtons.left = false; +} + +void MVKExample::rightMouseDown(double x, double y) { + _vulkanExample->mousePos = glm::vec2(x, y); + _vulkanExample->mouseButtons.right = true; +} + +void MVKExample::rightMouseUp() { + _vulkanExample->mouseButtons.right = false; +} + +void MVKExample::otherMouseDown(double x, double y) { + _vulkanExample->mousePos = glm::vec2(x, y); + _vulkanExample->mouseButtons.middle = true; +} + +void MVKExample::otherMouseUp() { + _vulkanExample->mouseButtons.middle = false; +} + +void MVKExample::mouseDragged(double x, double y) { + _vulkanExample->mouseDragged(x, y); +} + +void MVKExample::scrollWheel(short wheelDelta) { + _vulkanExample->camera.translate(glm::vec3(0.0f, 0.0f, wheelDelta * 0.05f * _vulkanExample->camera.movementSpeed)); + _vulkanExample->viewUpdated = true; +} + +void MVKExample::fullScreen(bool fullscreen) { + _vulkanExample->settings.fullscreen = fullscreen; +} + +MVKExample::MVKExample(void* view, double scaleUI) { _vulkanExample = new VulkanExample(); _vulkanExample->initVulkan(); _vulkanExample->setupWindow(view); - _vulkanExample->initSwapchain(); + _vulkanExample->settings.vsync = true; // SRS - set vsync flag since this iOS/macOS example app uses displayLink vsync rendering + _vulkanExample->UIOverlay.scale = scaleUI; // SRS - set UIOverlay scale to maintain relative proportions/readability on retina displays _vulkanExample->prepare(); + _vulkanExample->renderLoop(); // SRS - this inits destWidth/destHeight/lastTimestamp/tPrevEnd, then falls through and returns } MVKExample::~MVKExample() { - delete _vulkanExample; + vkDeviceWaitIdle(_vulkanExample->vulkanDevice->logicalDevice); + delete(_vulkanExample); } diff --git a/xcode/MVKExample.h b/xcode/MVKExample.h index 93d921ec..bdbf3a11 100644 --- a/xcode/MVKExample.h +++ b/xcode/MVKExample.h @@ -13,10 +13,25 @@ class MVKExample { public: - void renderFrame(); - void keyPressed(uint32_t keyCode); - - MVKExample(void* view); + void renderFrame(); + void displayLinkOutputCb(); // SRS - expose VulkanExampleBase::displayLinkOutputCb() to DemoViewController + + void keyPressed(uint32_t keyChar); // SRS - expose keyboard events to DemoViewController + void keyDown(uint32_t keyChar); + void keyUp(uint32_t keyChar); + + void mouseDown(double x, double y); // SRS - expose mouse events to DemoViewController + void mouseUp(); + void rightMouseDown(double x, double y); + void rightMouseUp(); + void otherMouseDown(double x, double y); + void otherMouseUp(); + void mouseDragged(double x, double y); + void scrollWheel(short wheelDelta); + + void fullScreen(bool fullscreen); // SRS - expose VulkanExampleBase::settings.fullscreen to DemoView (macOS only) + + MVKExample(void* view, double scaleUI); // SRS - support UIOverlay scaling parameter based on device and display type ~MVKExample(); protected: diff --git a/xcode/examples.h b/xcode/examples.h index 20b7ab89..c6107e4f 100644 --- a/xcode/examples.h +++ b/xcode/examples.h @@ -17,7 +17,7 @@ * * For example, to run the pipelines example, you would add the MVK_pipelines define macro * to the Preprocessor Macros (aka GCC_PREPROCESSOR_DEFINITIONS) entry of the Xcode project, - * overwriting any otheor value there. + * overwriting any other value there. * * If you choose to add a #define statement to this file, be sure to clear the existing macro * from the Preprocessor Macros (aka GCC_PREPROCESSOR_DEFINITIONS) compiler setting in Xcode. @@ -27,10 +27,21 @@ // In the list below, the comments indicate entries that, // under certain conditions, that may not run as expected. -#define MVK_vulkanscene +// Uncomment the next line and select example here if not using a Preprocessor Macro to define example +//#define MVK_vulkanscene + +// COMMON - Include VulkanglTFModel.cpp in all examples other than ones that already include/customize tiny_gltf.h directly +#if !defined(MVK_gltfloading) && !defined(MVK_gltfskinning) && !defined(MVK_gltfscenerendering) && !defined(MVK_vertexattributes) +# include "../base/VulkanglTFModel.cpp" +#endif + // BASICS +#ifdef MVK_triangle +# include "../examples/triangle/triangle.cpp" +#endif + #ifdef MVK_pipelines # include "../examples/pipelines/pipelines.cpp" #endif @@ -39,26 +50,38 @@ # include "../examples/texture/texture.cpp" #endif -// Does not run. Metal does not support passing matrices between shader stages. +#ifdef MVK_texture3d +# include "../examples/texture3d/texture3d.cpp" +#endif + #ifdef MVK_texturecubemap # include "../examples/texturecubemap/texturecubemap.cpp" #endif -// Runs in Release mode. Does not run in Debug mode, as Metal validation will -// assert that UBO buffer length is too short for UBO size declared in shader. -#ifdef MVK_texturearray -# include "../examples/texturearray/texturearray.cpp" +#ifdef MVK_texturecubemaparray +# include "../examples/texturecubemaparray/texturecubemaparray.cpp" #endif -#ifdef MVK_mesh -# include "../examples/mesh/mesh.cpp" +#ifdef MVK_texturearray +# include "../examples/texturearray/texturearray.cpp" #endif #ifdef MVK_dynamicuniformbuffer # include "../examples/dynamicuniformbuffer/dynamicuniformbuffer.cpp" #endif -// Does not run. Metal does not support passing arrays between shader stages. +#ifdef MVK_inlineuniformblocks +# include "../examples/inlineuniformblocks/inlineuniformblocks.cpp" +#endif + +#ifdef MVK_inputattachments +# include "../examples/inputattachments/inputattachments.cpp" +#endif + +#ifdef MVK_negativeviewportheight +# include "../examples/negativeviewportheight/negativeviewportheight.cpp" +#endif + #ifdef MVK_pushconstants # include "../examples/pushconstants/pushconstants.cpp" #endif @@ -71,6 +94,14 @@ # include "../examples/offscreen/offscreen.cpp" #endif +#ifdef MVK_stencilbuffer +# include "../examples/stencilbuffer/stencilbuffer.cpp" +#endif + +#ifdef MVK_subpasses +# include "../examples/subpasses/subpasses.cpp" +#endif + #ifdef MVK_radialblur # include "../examples/radialblur/radialblur.cpp" #endif @@ -83,6 +114,11 @@ # include "../examples/particlefire/particlefire.cpp" #endif +// No headless target when using xcode examples project, builds/runs fine using vulkanExamples project. +#ifdef MVK_renderheadless +# include "../examples/renderheadless/renderheadless.cpp" +#endif + // ADVANCED @@ -90,8 +126,12 @@ # include "../examples/multithreading/multithreading.cpp" #endif -#ifdef MVK_scenerendering -# include "../examples/scenerendering/scenerendering.cpp" +#ifdef MVK_gltfscenerendering +# include "../examples/gltfscenerendering/gltfscenerendering.cpp" +#endif + +#ifdef MVK_multiview +# include "../examples/multiview/multiview.cpp" #endif #ifdef MVK_instancing @@ -102,7 +142,6 @@ # include "../examples/indirectdraw/indirectdraw.cpp" #endif -// Does not run. Metal does not support passing matrices between shader stages. #ifdef MVK_hdr # include "../examples/hdr/hdr.cpp" #endif @@ -111,11 +150,15 @@ # include "../examples/occlusionquery/occlusionquery.cpp" #endif -// Does not run. Sampler arrays require Metal 2. #ifdef MVK_texturemipmapgen # include "../examples/texturemipmapgen/texturemipmapgen.cpp" #endif +// Does not run. Sparse binding not supported by MoltenVK/Metal. +#ifdef MVK_texturesparseresidency +# include "../examples/texturesparseresidency/texturesparseresidency.cpp" +#endif + #ifdef MVK_multisampling # include "../examples/multisampling/multisampling.cpp" #endif @@ -124,50 +167,214 @@ # include "../examples/shadowmapping/shadowmapping.cpp" #endif +#ifdef MVK_shadowmappingcascade +# include "../examples/shadowmappingcascade/shadowmappingcascade.cpp" +#endif + #ifdef MVK_shadowmappingomni # include "../examples/shadowmappingomni/shadowmappingomni.cpp" #endif -#ifdef MVK_skeletalanimation -# include "../examples/skeletalanimation/skeletalanimation.cpp" +#ifdef MVK_gltfloading +# include "../examples/gltfloading/gltfloading.cpp" +#endif + +#ifdef MVK_gltfskinning +# include "../examples/gltfskinning/gltfskinning.cpp" #endif #ifdef MVK_bloom # include "../examples/bloom/bloom.cpp" #endif -// Runs in Release mode. Debug mode Metal validation will assert -// UBO buffer length is too short for UBO size declared in shader. +#ifdef MVK_vertexattributes +# include "../examples/vertexattributes/vertexattributes.cpp" +#endif + +// Does not run. MoltenVK/Metal does not support stores and atomic operations in the fragment stage. +#ifdef MVK_oit +# include "../examples/oit/oit.cpp" +#endif + + +// DEFERRED + #ifdef MVK_deferred # include "../examples/deferred/deferred.cpp" #endif +#ifdef MVK_deferredmultisampling +# include "../examples/deferredmultisampling/deferredmultisampling.cpp" +#endif + +#ifdef MVK_ssao +# include "../examples/ssao/ssao.cpp" +#endif + + +// DESCRIPTORS + +#ifdef MVK_descriptorsets +# include "../examples/descriptorsets/descriptorsets.cpp" +#endif + +#ifdef MVK_pushdescriptors +# include "../examples/pushdescriptors/pushdescriptors.cpp" +#endif + +// Does not run. Shader compilation fails with MoltenVK. +#ifdef MVK_descriptorindexing +# include "../examples/descriptorindexing/descriptorindexing.cpp" +#endif + + +// PHYSICALLY BASED RENDERING + +#ifdef MVK_pbrbasic +# include "../examples/pbrbasic/pbrbasic.cpp" +#endif + +#ifdef MVK_pbribl +# include "../examples/pbribl/pbribl.cpp" +#endif + +#ifdef MVK_pbrtexture +# include "../examples/pbrtexture/pbrtexture.cpp" +#endif + + +// RAY TRACING - Currently unsupported by MoltenVK/Metal + +// Does not run. Missing Vulkan extensions for ray tracing +#ifdef MVK_rayquery +# include "../examples/rayquery/rayquery.cpp" +#endif + +// Does not run. Missing Vulkan extensions for ray tracing +#ifdef MVK_raytracingbasic +# include "../examples/raytracingbasic/raytracingbasic.cpp" +#endif + +// Does not run. Missing Vulkan extensions for ray tracing +#ifdef MVK_raytracingcallable +# include "../examples/raytracingcallable/raytracingcallable.cpp" +#endif + +// Does not run. Missing Vulkan extensions for ray tracing +#ifdef MVK_raytracingreflections +# include "../examples/raytracingreflections/raytracingreflections.cpp" +#endif + +// Does not run. Missing Vulkan extensions for ray tracing +#ifdef MVK_raytracingshadows +# include "../examples/raytracingshadows/raytracingshadows.cpp" +#endif + + +// COMPUTE + +#ifdef MVK_computeparticles +# include "../examples/computeparticles/computeparticles.cpp" +#endif + +#ifdef MVK_computenbody +# include "../examples/computenbody/computenbody.cpp" +#endif + +#ifdef MVK_computeraytracing +# include "../examples/computeraytracing/computeraytracing.cpp" +#endif + +#ifdef MVK_computecullandlod +# include "../examples/computecullandlod/computecullandlod.cpp" +#endif + +#ifdef MVK_computeshader +# include "../examples/computeshader/computeshader.cpp" +#endif + +#ifdef MVK_computecloth +# include "../examples/computecloth/computecloth.cpp" +#endif + +// No headless target when using xcode examples project, builds/runs fine using vulkanExamples project. +#ifdef MVK_computeheadless +# include "../examples/computeheadless/computeheadless.cpp" +#endif + + +// TESSELLATION + +#ifdef MVK_terraintessellation +# include "../examples/terraintessellation/terraintessellation.cpp" +#endif + +#ifdef MVK_tessellation +# include "../examples/tessellation/tessellation.cpp" +#endif + +#ifdef MVK_displacement +# include "../examples/displacement/displacement.cpp" +#endif + + +// GEOMETRY SHADER - Unsupported by Metal + +// Does not run. Metal does not support geometry shaders. +#ifdef MVK_geometryshader +# include "../examples/geometryshader/geometryshader.cpp" +#endif + // Does not run. Metal does not support geometry shaders. #ifdef MVK_deferredshadows # include "../examples/deferredshadows/deferredshadows.cpp" #endif -// Runs in Release mode, but does not display content. -// Metal does not support the use of specialization constants to set array lengths, -#ifdef MVK_ssao -# include "../examples/ssao/ssao.cpp" +// Does not run. Metal does not support geometry shaders. +#ifdef MVK_viewportarray +# include "../examples/viewportarray/viewportarray.cpp" #endif -// COMPUTE - Currently unsupported by MoltenVK +// EXTENSIONS +// Does not run. Requires VK_EXT_conditional_rendering. +#ifdef MVK_conditionalrender +# include "../examples/conditionalrender/conditionalrender.cpp" +#endif -// TESSELLATION - Currently unsupported by MoltenVK +// Does not run. Requires VK_EXT_conservative_rasterization. +#ifdef MVK_conservativeraster +# include "../examples/conservativeraster/conservativeraster.cpp" +#endif +// Does not run. Requires VK_NV_shading_rate_image. +#ifdef MVK_variablerateshading +# include "../examples/variablerateshading/variablerateshading.cpp" +#endif -// GEOMETRY SHADER - Unsupported by Metal +// Does not run. Requires VK_KHR_pipeline_library and VK_EXT_graphics_pipeline_library. +#ifdef MVK_graphicspipelinelibrary +# include "../examples/graphicspipelinelibrary/graphicspipelinelibrary.cpp" +#endif +// Does not run yet. Requires VK_KHR_dynamic_rendering (under development in MoltenVK) +#ifdef MVK_dynamicrendering +# include "../examples/dynamicrendering/dynamicrendering.cpp" +#endif -// EXTENSIONS - Currently unsupported by MoltenVK +// Runs. Requires VK_EXT_debug_marker. +#ifdef MVK_debugmarker +# include "../examples/debugmarker/debugmarker.cpp" +#endif // MISC +#ifdef MVK_screenshot +# include "../examples/screenshot/screenshot.cpp" +#endif + #ifdef MVK_parallaxmapping # include "../examples/parallaxmapping/parallaxmapping.cpp" #endif @@ -178,13 +385,22 @@ #ifdef MVK_gears # include "../examples/gears/gears.cpp" +# include "../examples/gears/vulkangear.cpp" #endif #ifdef MVK_distancefieldfonts # include "../examples/distancefieldfonts/distancefieldfonts.cpp" #endif +// Does not run. MoltenVK/Metal does not support pipeline statistics. +#ifdef MVK_pipelinestatistics +# include "../examples/pipelinestatistics/pipelinestatistics.cpp" +#endif + +#ifdef MVK_imgui +# include "../examples/imgui/main.cpp" +#endif + #ifdef MVK_vulkanscene # include "../examples/vulkanscene/vulkanscene.cpp" #endif - diff --git a/xcode/examples.xcodeproj/project.pbxproj b/xcode/examples.xcodeproj/project.pbxproj index ba6eec40..4b9237ca 100644 --- a/xcode/examples.xcodeproj/project.pbxproj +++ b/xcode/examples.xcodeproj/project.pbxproj @@ -16,7 +16,7 @@ A9532B761EF99894000A09E2 /* libMoltenVK.dylib in CopyFiles */ = {isa = PBXBuildFile; fileRef = A9532B751EF99894000A09E2 /* libMoltenVK.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; A9532B771EF9991A000A09E2 /* libMoltenVK.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = A9532B751EF99894000A09E2 /* libMoltenVK.dylib */; }; A9532B781EF99937000A09E2 /* libMoltenVK.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = A9581BAB1EEB64EC00247309 /* libMoltenVK.dylib */; }; - A9581BA81EEB648C00247309 /* libzlibstatic.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A9581BA71EEB648C00247309 /* libzlibstatic.a */; }; + A9581BA81EEB648C00247309 /* (null) in Frameworks */ = {isa = PBXBuildFile; }; A9581BAC1EEB64EC00247309 /* libMoltenVK.dylib in CopyFiles */ = {isa = PBXBuildFile; fileRef = A9581BAB1EEB64EC00247309 /* libMoltenVK.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; A98703D91E9D382A0066959C /* data in Resources */ = {isa = PBXBuildFile; fileRef = A98703D81E9D382A0066959C /* data */; }; A98703DA1E9D382A0066959C /* data in Resources */ = {isa = PBXBuildFile; fileRef = A98703D81E9D382A0066959C /* data */; }; @@ -34,16 +34,53 @@ A9B67B911C3AAEA200373FFD /* macOS.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A9B67B8B1C3AAEA200373FFD /* macOS.xcassets */; }; A9BC9B1C1EE8421F00384233 /* MVKExample.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9BC9B1A1EE8421F00384233 /* MVKExample.cpp */; }; A9BC9B1D1EE8421F00384233 /* MVKExample.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9BC9B1A1EE8421F00384233 /* MVKExample.cpp */; }; + AA54A1B426E5274500485C4A /* VulkanBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA54A1B226E5274500485C4A /* VulkanBuffer.cpp */; }; + AA54A1B526E5274500485C4A /* VulkanBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA54A1B226E5274500485C4A /* VulkanBuffer.cpp */; }; + AA54A1B826E5275300485C4A /* VulkanDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA54A1B626E5275300485C4A /* VulkanDevice.cpp */; }; + AA54A1B926E5275300485C4A /* VulkanDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA54A1B626E5275300485C4A /* VulkanDevice.cpp */; }; + AA54A1C026E5276C00485C4A /* VulkanSwapChain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA54A1BF26E5276C00485C4A /* VulkanSwapChain.cpp */; }; + AA54A1C126E5276C00485C4A /* VulkanSwapChain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA54A1BF26E5276C00485C4A /* VulkanSwapChain.cpp */; }; + AA54A1C426E5277600485C4A /* VulkanTexture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA54A1C326E5277600485C4A /* VulkanTexture.cpp */; }; + AA54A1C526E5277600485C4A /* VulkanTexture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA54A1C326E5277600485C4A /* VulkanTexture.cpp */; }; + AA54A6B826E52CE300485C4A /* memstream.c in Sources */ = {isa = PBXBuildFile; fileRef = AA54A1DD26E52CE100485C4A /* memstream.c */; }; + AA54A6B926E52CE300485C4A /* memstream.c in Sources */ = {isa = PBXBuildFile; fileRef = AA54A1DD26E52CE100485C4A /* memstream.c */; }; + AA54A6BA26E52CE300485C4A /* vk_funclist.inl in Resources */ = {isa = PBXBuildFile; fileRef = AA54A1DE26E52CE100485C4A /* vk_funclist.inl */; }; + AA54A6BB26E52CE300485C4A /* vk_funclist.inl in Resources */ = {isa = PBXBuildFile; fileRef = AA54A1DE26E52CE100485C4A /* vk_funclist.inl */; }; + AA54A6BC26E52CE300485C4A /* etcdec.cxx in Sources */ = {isa = PBXBuildFile; fileRef = AA54A1E026E52CE100485C4A /* etcdec.cxx */; }; + AA54A6BD26E52CE300485C4A /* etcdec.cxx in Sources */ = {isa = PBXBuildFile; fileRef = AA54A1E026E52CE100485C4A /* etcdec.cxx */; }; + AA54A6BE26E52CE300485C4A /* checkheader.c in Sources */ = {isa = PBXBuildFile; fileRef = AA54A1E126E52CE100485C4A /* checkheader.c */; }; + AA54A6BF26E52CE300485C4A /* checkheader.c in Sources */ = {isa = PBXBuildFile; fileRef = AA54A1E126E52CE100485C4A /* checkheader.c */; }; + AA54A6C026E52CE300485C4A /* errstr.c in Sources */ = {isa = PBXBuildFile; fileRef = AA54A1E226E52CE100485C4A /* errstr.c */; }; + AA54A6C126E52CE300485C4A /* errstr.c in Sources */ = {isa = PBXBuildFile; fileRef = AA54A1E226E52CE100485C4A /* errstr.c */; }; + AA54A6C226E52CE300485C4A /* writer.c in Sources */ = {isa = PBXBuildFile; fileRef = AA54A1E326E52CE100485C4A /* writer.c */; }; + AA54A6C326E52CE300485C4A /* writer.c in Sources */ = {isa = PBXBuildFile; fileRef = AA54A1E326E52CE100485C4A /* writer.c */; }; + AA54A6C426E52CE300485C4A /* filestream.c in Sources */ = {isa = PBXBuildFile; fileRef = AA54A1E426E52CE100485C4A /* filestream.c */; }; + AA54A6C526E52CE300485C4A /* filestream.c in Sources */ = {isa = PBXBuildFile; fileRef = AA54A1E426E52CE100485C4A /* filestream.c */; }; + AA54A6C626E52CE300485C4A /* mainpage.md in Resources */ = {isa = PBXBuildFile; fileRef = AA54A1E626E52CE100485C4A /* mainpage.md */; }; + AA54A6C726E52CE300485C4A /* mainpage.md in Resources */ = {isa = PBXBuildFile; fileRef = AA54A1E626E52CE100485C4A /* mainpage.md */; }; + AA54A6CA26E52CE300485C4A /* texture.c in Sources */ = {isa = PBXBuildFile; fileRef = AA54A1EA26E52CE100485C4A /* texture.c */; }; + AA54A6CB26E52CE300485C4A /* texture.c in Sources */ = {isa = PBXBuildFile; fileRef = AA54A1EA26E52CE100485C4A /* texture.c */; }; + AA54A6CC26E52CE300485C4A /* hashlist.c in Sources */ = {isa = PBXBuildFile; fileRef = AA54A1ED26E52CE100485C4A /* hashlist.c */; }; + AA54A6CD26E52CE400485C4A /* hashlist.c in Sources */ = {isa = PBXBuildFile; fileRef = AA54A1ED26E52CE100485C4A /* hashlist.c */; }; + AA54A6CE26E52CE400485C4A /* vk_funcs.c in Sources */ = {isa = PBXBuildFile; fileRef = AA54A1EE26E52CE100485C4A /* vk_funcs.c */; }; + AA54A6CF26E52CE400485C4A /* vk_funcs.c in Sources */ = {isa = PBXBuildFile; fileRef = AA54A1EE26E52CE100485C4A /* vk_funcs.c */; }; + AA54A6D226E52CE400485C4A /* hashtable.c in Sources */ = {isa = PBXBuildFile; fileRef = AA54A1F626E52CE100485C4A /* hashtable.c */; }; + AA54A6D326E52CE400485C4A /* hashtable.c in Sources */ = {isa = PBXBuildFile; fileRef = AA54A1F626E52CE100485C4A /* hashtable.c */; }; + AA54A6D826E52CE400485C4A /* swap.c in Sources */ = {isa = PBXBuildFile; fileRef = AA54A1F926E52CE100485C4A /* swap.c */; }; + AA54A6D926E52CE400485C4A /* swap.c in Sources */ = {isa = PBXBuildFile; fileRef = AA54A1F926E52CE100485C4A /* swap.c */; }; + AA54A6DE26E52CE400485C4A /* imgui_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA54A20426E52CE100485C4A /* imgui_widgets.cpp */; }; + AA54A6DF26E52CE400485C4A /* imgui_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA54A20426E52CE100485C4A /* imgui_widgets.cpp */; }; + AA54A6E026E52CE400485C4A /* imgui.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA54A20626E52CE100485C4A /* imgui.cpp */; }; + AA54A6E126E52CE400485C4A /* imgui.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA54A20626E52CE100485C4A /* imgui.cpp */; }; + AA54A6E226E52CE400485C4A /* LICENSE.txt in Resources */ = {isa = PBXBuildFile; fileRef = AA54A20926E52CE100485C4A /* LICENSE.txt */; }; + AA54A6E326E52CE400485C4A /* LICENSE.txt in Resources */ = {isa = PBXBuildFile; fileRef = AA54A20926E52CE100485C4A /* LICENSE.txt */; }; + AA54A6E426E52CE400485C4A /* imgui_demo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA54A20A26E52CE100485C4A /* imgui_demo.cpp */; }; + AA54A6E526E52CE400485C4A /* imgui_demo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA54A20A26E52CE100485C4A /* imgui_demo.cpp */; }; + AA54A6E626E52CE400485C4A /* imgui_draw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA54A20B26E52CE100485C4A /* imgui_draw.cpp */; }; + AA54A6E726E52CE400485C4A /* imgui_draw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA54A20B26E52CE100485C4A /* imgui_draw.cpp */; }; + AAB0D0BF26F24001005DC611 /* VulkanRaytracingSample.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AAB0D0BE26F24001005DC611 /* VulkanRaytracingSample.cpp */; }; + AAB0D0C026F24001005DC611 /* VulkanRaytracingSample.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AAB0D0BE26F24001005DC611 /* VulkanRaytracingSample.cpp */; }; C9788FD52044D78D00AB0892 /* VulkanAndroid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C9788FD32044D78D00AB0892 /* VulkanAndroid.cpp */; }; - C9A79EF12045045E00696219 /* stb_textedit.h in Sources */ = {isa = PBXBuildFile; fileRef = C9A79EE82045045D00696219 /* stb_textedit.h */; }; - C9A79EF22045045E00696219 /* imconfig.h in Sources */ = {isa = PBXBuildFile; fileRef = C9A79EE92045045D00696219 /* imconfig.h */; }; - C9A79EF32045045E00696219 /* imgui_demo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C9A79EEA2045045D00696219 /* imgui_demo.cpp */; }; - C9A79EF42045045E00696219 /* imgui_draw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C9A79EEB2045045D00696219 /* imgui_draw.cpp */; }; - C9A79EF52045045E00696219 /* imgui_internal.h in Sources */ = {isa = PBXBuildFile; fileRef = C9A79EEC2045045E00696219 /* imgui_internal.h */; }; - C9A79EF62045045E00696219 /* stb_rect_pack.h in Sources */ = {isa = PBXBuildFile; fileRef = C9A79EED2045045E00696219 /* stb_rect_pack.h */; }; - C9A79EF72045045E00696219 /* imgui.h in Sources */ = {isa = PBXBuildFile; fileRef = C9A79EEE2045045E00696219 /* imgui.h */; }; - C9A79EF82045045E00696219 /* stb_truetype.h in Sources */ = {isa = PBXBuildFile; fileRef = C9A79EEF2045045E00696219 /* stb_truetype.h */; }; - C9A79EF92045045E00696219 /* imgui.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C9A79EF02045045E00696219 /* imgui.cpp */; }; C9A79EFC204504E000696219 /* VulkanUIOverlay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C9A79EFB204504E000696219 /* VulkanUIOverlay.cpp */; }; C9A79EFD2045051D00696219 /* VulkanUIOverlay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C9A79EFB204504E000696219 /* VulkanUIOverlay.cpp */; }; C9A79EFE2045051D00696219 /* VulkanUIOverlay.h in Sources */ = {isa = PBXBuildFile; fileRef = C9A79EFA204504E000696219 /* VulkanUIOverlay.h */; }; @@ -78,44 +115,35 @@ 1D6058910D05DD3D006BFB54 /* examples.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = examples.app; sourceTree = BUILT_PRODUCTS_DIR; }; 2D500B990D5A79CF00DBA0E3 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; A92F37071C7E1B2B008F8BC9 /* examples.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = examples.h; sourceTree = ""; }; - A94A67231B7BDE9B00F6D7C4 /* MetalGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalGL.framework; path = ../../MetalGL/macOS/MetalGL.framework; sourceTree = ""; }; - A94A67241B7BDE9B00F6D7C4 /* MetalGLShaderConverter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalGLShaderConverter.framework; path = ../../MetalGLShaderConverter/macOS/MetalGLShaderConverter.framework; sourceTree = ""; }; A951FF001E9C349000FA9144 /* camera.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = camera.hpp; sourceTree = ""; }; A951FF011E9C349000FA9144 /* frustum.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = frustum.hpp; sourceTree = ""; }; A951FF021E9C349000FA9144 /* keycodes.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = keycodes.hpp; sourceTree = ""; }; A951FF031E9C349000FA9144 /* threadpool.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = threadpool.hpp; sourceTree = ""; }; - A951FF061E9C349000FA9144 /* VulkanBuffer.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = VulkanBuffer.hpp; sourceTree = ""; }; A951FF071E9C349000FA9144 /* VulkanDebug.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VulkanDebug.cpp; sourceTree = ""; }; A951FF081E9C349000FA9144 /* VulkanDebug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VulkanDebug.h; sourceTree = ""; }; - A951FF091E9C349000FA9144 /* VulkanDevice.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = VulkanDevice.hpp; sourceTree = ""; }; A951FF0A1E9C349000FA9144 /* vulkanexamplebase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = vulkanexamplebase.cpp; sourceTree = ""; }; A951FF0B1E9C349000FA9144 /* vulkanexamplebase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vulkanexamplebase.h; sourceTree = ""; }; A951FF0C1E9C349000FA9144 /* VulkanFrameBuffer.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = VulkanFrameBuffer.hpp; sourceTree = ""; }; A951FF0D1E9C349000FA9144 /* VulkanHeightmap.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = VulkanHeightmap.hpp; sourceTree = ""; }; A951FF0E1E9C349000FA9144 /* VulkanInitializers.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = VulkanInitializers.hpp; sourceTree = ""; }; - A951FF0F1E9C349000FA9144 /* VulkanModel.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = VulkanModel.hpp; sourceTree = ""; }; - A951FF101E9C349000FA9144 /* VulkanSwapChain.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = VulkanSwapChain.hpp; sourceTree = ""; }; - A951FF121E9C349000FA9144 /* VulkanTexture.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = VulkanTexture.hpp; sourceTree = ""; }; A951FF131E9C349000FA9144 /* VulkanTools.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VulkanTools.cpp; sourceTree = ""; }; A951FF141E9C349000FA9144 /* VulkanTools.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VulkanTools.h; sourceTree = ""; }; - A9532B751EF99894000A09E2 /* libMoltenVK.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libMoltenVK.dylib; path = MoltenVK/iOS/libMoltenVK.dylib; sourceTree = ""; }; - A9581BAB1EEB64EC00247309 /* libMoltenVK.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libMoltenVK.dylib; path = MoltenVK/macOS/libMoltenVK.dylib; sourceTree = ""; }; + A9532B751EF99894000A09E2 /* libMoltenVK.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libMoltenVK.dylib; path = MoltenVK/dylib/iOS/libMoltenVK.dylib; sourceTree = ""; }; + A9581BAB1EEB64EC00247309 /* libMoltenVK.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libMoltenVK.dylib; path = MoltenVK/dylib/macOS/libMoltenVK.dylib; sourceTree = ""; }; A977BCFE1B66BB010067E5BF /* examples.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = examples.app; sourceTree = BUILT_PRODUCTS_DIR; }; - A977BD211B67186B0067E5BF /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/System/Library/Frameworks/AppKit.framework; sourceTree = DEVELOPER_DIR; }; - A977BD221B67186B0067E5BF /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/System/Library/Frameworks/CoreGraphics.framework; sourceTree = DEVELOPER_DIR; }; - A977BD231B67186B0067E5BF /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; - A977BD251B67186B0067E5BF /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/System/Library/Frameworks/Metal.framework; sourceTree = DEVELOPER_DIR; }; - A977BD261B67186B0067E5BF /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/System/Library/Frameworks/QuartzCore.framework; sourceTree = DEVELOPER_DIR; }; + A977BD211B67186B0067E5BF /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; + A977BD221B67186B0067E5BF /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + A977BD231B67186B0067E5BF /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + A977BD251B67186B0067E5BF /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; }; + A977BD261B67186B0067E5BF /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; A98703D81E9D382A0066959C /* data */ = {isa = PBXFileReference; lastKnownFileType = folder; name = data; path = ../data; sourceTree = ""; }; A9A222171B5D69F40050A5F9 /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; }; - A9B5D09B1CF8830B00D7CBDD /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; }; A9B67B6B1C3AAE9800373FFD /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; A9B67B6C1C3AAE9800373FFD /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; A9B67B6E1C3AAE9800373FFD /* DemoViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DemoViewController.h; sourceTree = ""; }; A9B67B6F1C3AAE9800373FFD /* DemoViewController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DemoViewController.mm; sourceTree = ""; }; A9B67B701C3AAE9800373FFD /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; A9B67B711C3AAE9800373FFD /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - A9B67B721C3AAE9800373FFD /* Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Prefix.pch; sourceTree = ""; }; A9B67B741C3AAE9800373FFD /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; A9B67B751C3AAE9800373FFD /* Default~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default~ipad.png"; sourceTree = ""; }; A9B67B761C3AAE9800373FFD /* Icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Icon.png; sourceTree = ""; }; @@ -126,26 +154,58 @@ A9B67B851C3AAEA200373FFD /* DemoViewController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DemoViewController.mm; sourceTree = ""; }; A9B67B861C3AAEA200373FFD /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; A9B67B871C3AAEA200373FFD /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - A9B67B881C3AAEA200373FFD /* Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Prefix.pch; sourceTree = ""; }; A9B67B8A1C3AAEA200373FFD /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; A9B67B8B1C3AAEA200373FFD /* macOS.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = macOS.xcassets; sourceTree = ""; }; A9B6B7641C0F795D00A9E33A /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = System/Library/Frameworks/CoreAudio.framework; sourceTree = SDKROOT; }; A9BC9B1A1EE8421F00384233 /* MVKExample.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MVKExample.cpp; sourceTree = ""; }; A9BC9B1B1EE8421F00384233 /* MVKExample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKExample.h; sourceTree = ""; }; A9CDEA271B6A782C00F7B008 /* GLKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GLKit.framework; path = System/Library/Frameworks/GLKit.framework; sourceTree = SDKROOT; }; - A9E264761B671B0A00FE691A /* libc++.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libc++.dylib"; path = "Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/lib/libc++.dylib"; sourceTree = DEVELOPER_DIR; }; + AA54A1B226E5274500485C4A /* VulkanBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VulkanBuffer.cpp; sourceTree = ""; }; + AA54A1B326E5274500485C4A /* VulkanBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VulkanBuffer.h; sourceTree = ""; }; + AA54A1B626E5275300485C4A /* VulkanDevice.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VulkanDevice.cpp; sourceTree = ""; }; + AA54A1B726E5275300485C4A /* VulkanDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VulkanDevice.h; sourceTree = ""; }; + AA54A1BA26E5276000485C4A /* VulkanglTFModel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VulkanglTFModel.cpp; sourceTree = ""; }; + AA54A1BB26E5276000485C4A /* VulkanglTFModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VulkanglTFModel.h; sourceTree = ""; }; + AA54A1BE26E5276C00485C4A /* VulkanSwapChain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VulkanSwapChain.h; sourceTree = ""; }; + AA54A1BF26E5276C00485C4A /* VulkanSwapChain.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VulkanSwapChain.cpp; sourceTree = ""; }; + AA54A1C226E5277600485C4A /* VulkanTexture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VulkanTexture.h; sourceTree = ""; }; + AA54A1C326E5277600485C4A /* VulkanTexture.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VulkanTexture.cpp; sourceTree = ""; }; + AA54A1DD26E52CE100485C4A /* memstream.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = memstream.c; sourceTree = ""; }; + AA54A1DE26E52CE100485C4A /* vk_funclist.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = vk_funclist.inl; sourceTree = ""; }; + AA54A1E026E52CE100485C4A /* etcdec.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = etcdec.cxx; sourceTree = ""; }; + AA54A1E126E52CE100485C4A /* checkheader.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = checkheader.c; sourceTree = ""; }; + AA54A1E226E52CE100485C4A /* errstr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = errstr.c; sourceTree = ""; }; + AA54A1E326E52CE100485C4A /* writer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = writer.c; sourceTree = ""; }; + AA54A1E426E52CE100485C4A /* filestream.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = filestream.c; sourceTree = ""; }; + AA54A1E626E52CE100485C4A /* mainpage.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = mainpage.md; sourceTree = ""; }; + AA54A1E926E52CE100485C4A /* vk_format.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vk_format.h; sourceTree = ""; }; + AA54A1EA26E52CE100485C4A /* texture.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = texture.c; sourceTree = ""; }; + AA54A1EB26E52CE100485C4A /* ktxint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ktxint.h; sourceTree = ""; }; + AA54A1EC26E52CE100485C4A /* stream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stream.h; sourceTree = ""; }; + AA54A1ED26E52CE100485C4A /* hashlist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hashlist.c; sourceTree = ""; }; + AA54A1EE26E52CE100485C4A /* vk_funcs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vk_funcs.c; sourceTree = ""; }; + AA54A1F026E52CE100485C4A /* uthash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = uthash.h; sourceTree = ""; }; + AA54A1F226E52CE100485C4A /* memstream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = memstream.h; sourceTree = ""; }; + AA54A1F526E52CE100485C4A /* filestream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = filestream.h; sourceTree = ""; }; + AA54A1F626E52CE100485C4A /* hashtable.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hashtable.c; sourceTree = ""; }; + AA54A1F926E52CE100485C4A /* swap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = swap.c; sourceTree = ""; }; + AA54A1FB26E52CE100485C4A /* vk_funcs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vk_funcs.h; sourceTree = ""; }; + AA54A20126E52CE100485C4A /* imgui.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = imgui.h; sourceTree = ""; }; + AA54A20226E52CE100485C4A /* imstb_textedit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = imstb_textedit.h; sourceTree = ""; }; + AA54A20326E52CE100485C4A /* imconfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = imconfig.h; sourceTree = ""; }; + AA54A20426E52CE100485C4A /* imgui_widgets.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = imgui_widgets.cpp; sourceTree = ""; }; + AA54A20526E52CE100485C4A /* imstb_truetype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = imstb_truetype.h; sourceTree = ""; }; + AA54A20626E52CE100485C4A /* imgui.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = imgui.cpp; sourceTree = ""; }; + AA54A20726E52CE100485C4A /* imgui_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = imgui_internal.h; sourceTree = ""; }; + AA54A20826E52CE100485C4A /* imstb_rectpack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = imstb_rectpack.h; sourceTree = ""; }; + AA54A20926E52CE100485C4A /* LICENSE.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE.txt; sourceTree = ""; }; + AA54A20A26E52CE100485C4A /* imgui_demo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = imgui_demo.cpp; sourceTree = ""; }; + AA54A20B26E52CE100485C4A /* imgui_draw.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = imgui_draw.cpp; sourceTree = ""; }; + AAB0D0BE26F24001005DC611 /* VulkanRaytracingSample.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VulkanRaytracingSample.cpp; sourceTree = ""; }; + AAB0D0C126F2400E005DC611 /* VulkanRaytracingSample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VulkanRaytracingSample.h; sourceTree = ""; }; C9788FD02044D78D00AB0892 /* benchmark.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = benchmark.hpp; sourceTree = ""; }; C9788FD22044D78D00AB0892 /* VulkanAndroid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VulkanAndroid.h; sourceTree = ""; }; C9788FD32044D78D00AB0892 /* VulkanAndroid.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VulkanAndroid.cpp; sourceTree = ""; }; - C9A79EE82045045D00696219 /* stb_textedit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = stb_textedit.h; path = ../external/imgui/stb_textedit.h; sourceTree = ""; }; - C9A79EE92045045D00696219 /* imconfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = imconfig.h; path = ../external/imgui/imconfig.h; sourceTree = ""; }; - C9A79EEA2045045D00696219 /* imgui_demo.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_demo.cpp; path = ../external/imgui/imgui_demo.cpp; sourceTree = ""; }; - C9A79EEB2045045D00696219 /* imgui_draw.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_draw.cpp; path = ../external/imgui/imgui_draw.cpp; sourceTree = ""; }; - C9A79EEC2045045E00696219 /* imgui_internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = imgui_internal.h; path = ../external/imgui/imgui_internal.h; sourceTree = ""; }; - C9A79EED2045045E00696219 /* stb_rect_pack.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = stb_rect_pack.h; path = ../external/imgui/stb_rect_pack.h; sourceTree = ""; }; - C9A79EEE2045045E00696219 /* imgui.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = imgui.h; path = ../external/imgui/imgui.h; sourceTree = ""; }; - C9A79EEF2045045E00696219 /* stb_truetype.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = stb_truetype.h; path = ../external/imgui/stb_truetype.h; sourceTree = ""; }; - C9A79EF02045045E00696219 /* imgui.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = imgui.cpp; path = ../external/imgui/imgui.cpp; sourceTree = ""; }; C9A79EFA204504E000696219 /* VulkanUIOverlay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VulkanUIOverlay.h; sourceTree = ""; }; C9A79EFB204504E000696219 /* VulkanUIOverlay.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VulkanUIOverlay.cpp; sourceTree = ""; }; /* End PBXFileReference section */ @@ -156,7 +216,7 @@ buildActionMask = 2147483647; files = ( A9532B771EF9991A000A09E2 /* libMoltenVK.dylib in Frameworks */, - A9581BA81EEB648C00247309 /* libzlibstatic.a in Frameworks */, + A9581BA81EEB648C00247309 /* (null) in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -183,19 +243,11 @@ 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = { isa = PBXGroup; children = ( - C9A79EE92045045D00696219 /* imconfig.h */, - C9A79EEA2045045D00696219 /* imgui_demo.cpp */, - C9A79EEB2045045D00696219 /* imgui_draw.cpp */, - C9A79EEC2045045E00696219 /* imgui_internal.h */, - C9A79EF02045045E00696219 /* imgui.cpp */, - C9A79EEE2045045E00696219 /* imgui.h */, - C9A79EED2045045E00696219 /* stb_rect_pack.h */, - C9A79EE82045045D00696219 /* stb_textedit.h */, - C9A79EEF2045045E00696219 /* stb_truetype.h */, A92F37071C7E1B2B008F8BC9 /* examples.h */, A9BC9B1B1EE8421F00384233 /* MVKExample.h */, A9BC9B1A1EE8421F00384233 /* MVKExample.cpp */, A951FEFF1E9C349000FA9144 /* base */, + AA54A1CF26E52CE100485C4A /* external */, A98703D81E9D382A0066959C /* data */, A9B67B6A1C3AAE9800373FFD /* iOS */, A9B67B811C3AAEA200373FFD /* macOS */, @@ -210,8 +262,6 @@ children = ( A9581BAB1EEB64EC00247309 /* libMoltenVK.dylib */, A9532B751EF99894000A09E2 /* libMoltenVK.dylib */, - A9581BA71EEB648C00247309 /* libzlibstatic.a */, - A9B5D09B1CF8830B00D7CBDD /* libc++.tbd */, A9B6B7641C0F795D00A9E33A /* CoreAudio.framework */, A9ADEC601B6EC2EB00DBA48C /* iOS */, A9ADEC611B6EC2F300DBA48C /* macOS */, @@ -231,18 +281,25 @@ A951FF011E9C349000FA9144 /* frustum.hpp */, A951FF021E9C349000FA9144 /* keycodes.hpp */, A951FF031E9C349000FA9144 /* threadpool.hpp */, - A951FF061E9C349000FA9144 /* VulkanBuffer.hpp */, + AA54A1B226E5274500485C4A /* VulkanBuffer.cpp */, + AA54A1B326E5274500485C4A /* VulkanBuffer.h */, A951FF071E9C349000FA9144 /* VulkanDebug.cpp */, A951FF081E9C349000FA9144 /* VulkanDebug.h */, - A951FF091E9C349000FA9144 /* VulkanDevice.hpp */, + AA54A1B626E5275300485C4A /* VulkanDevice.cpp */, + AA54A1B726E5275300485C4A /* VulkanDevice.h */, A951FF0A1E9C349000FA9144 /* vulkanexamplebase.cpp */, A951FF0B1E9C349000FA9144 /* vulkanexamplebase.h */, A951FF0C1E9C349000FA9144 /* VulkanFrameBuffer.hpp */, A951FF0D1E9C349000FA9144 /* VulkanHeightmap.hpp */, A951FF0E1E9C349000FA9144 /* VulkanInitializers.hpp */, - A951FF0F1E9C349000FA9144 /* VulkanModel.hpp */, - A951FF101E9C349000FA9144 /* VulkanSwapChain.hpp */, - A951FF121E9C349000FA9144 /* VulkanTexture.hpp */, + AA54A1BA26E5276000485C4A /* VulkanglTFModel.cpp */, + AA54A1BB26E5276000485C4A /* VulkanglTFModel.h */, + AAB0D0BE26F24001005DC611 /* VulkanRaytracingSample.cpp */, + AAB0D0C126F2400E005DC611 /* VulkanRaytracingSample.h */, + AA54A1BF26E5276C00485C4A /* VulkanSwapChain.cpp */, + AA54A1BE26E5276C00485C4A /* VulkanSwapChain.h */, + AA54A1C326E5277600485C4A /* VulkanTexture.cpp */, + AA54A1C226E5277600485C4A /* VulkanTexture.h */, A951FF131E9C349000FA9144 /* VulkanTools.cpp */, A951FF141E9C349000FA9144 /* VulkanTools.h */, ); @@ -265,14 +322,11 @@ A9ADEC611B6EC2F300DBA48C /* macOS */ = { isa = PBXGroup; children = ( - A94A67231B7BDE9B00F6D7C4 /* MetalGL.framework */, - A94A67241B7BDE9B00F6D7C4 /* MetalGLShaderConverter.framework */, - A9E264761B671B0A00FE691A /* libc++.dylib */, A977BD251B67186B0067E5BF /* Metal.framework */, - A977BD261B67186B0067E5BF /* QuartzCore.framework */, - A977BD211B67186B0067E5BF /* AppKit.framework */, A977BD221B67186B0067E5BF /* CoreGraphics.framework */, + A977BD261B67186B0067E5BF /* QuartzCore.framework */, A977BD231B67186B0067E5BF /* Foundation.framework */, + A977BD211B67186B0067E5BF /* AppKit.framework */, ); name = macOS; sourceTree = ""; @@ -286,7 +340,6 @@ A9B67B6F1C3AAE9800373FFD /* DemoViewController.mm */, A9B67B701C3AAE9800373FFD /* Info.plist */, A9B67B711C3AAE9800373FFD /* main.m */, - A9B67B721C3AAE9800373FFD /* Prefix.pch */, A9B67B731C3AAE9800373FFD /* Resources */, ); path = iOS; @@ -312,7 +365,6 @@ A9B67B851C3AAEA200373FFD /* DemoViewController.mm */, A9B67B861C3AAEA200373FFD /* Info.plist */, A9B67B871C3AAEA200373FFD /* main.m */, - A9B67B881C3AAEA200373FFD /* Prefix.pch */, A9B67B891C3AAEA200373FFD /* Resources */, ); path = macOS; @@ -327,6 +379,69 @@ path = Resources; sourceTree = ""; }; + AA54A1CF26E52CE100485C4A /* external */ = { + isa = PBXGroup; + children = ( + AA54A1D626E52CE100485C4A /* ktx */, + AA54A20026E52CE100485C4A /* imgui */, + ); + name = external; + path = ../external; + sourceTree = ""; + }; + AA54A1D626E52CE100485C4A /* ktx */ = { + isa = PBXGroup; + children = ( + AA54A1DC26E52CE100485C4A /* lib */, + ); + path = ktx; + sourceTree = ""; + }; + AA54A1DC26E52CE100485C4A /* lib */ = { + isa = PBXGroup; + children = ( + AA54A1E126E52CE100485C4A /* checkheader.c */, + AA54A1E226E52CE100485C4A /* errstr.c */, + AA54A1E026E52CE100485C4A /* etcdec.cxx */, + AA54A1E426E52CE100485C4A /* filestream.c */, + AA54A1F526E52CE100485C4A /* filestream.h */, + AA54A1ED26E52CE100485C4A /* hashlist.c */, + AA54A1F626E52CE100485C4A /* hashtable.c */, + AA54A1EB26E52CE100485C4A /* ktxint.h */, + AA54A1E626E52CE100485C4A /* mainpage.md */, + AA54A1DD26E52CE100485C4A /* memstream.c */, + AA54A1F226E52CE100485C4A /* memstream.h */, + AA54A1EC26E52CE100485C4A /* stream.h */, + AA54A1F926E52CE100485C4A /* swap.c */, + AA54A1EA26E52CE100485C4A /* texture.c */, + AA54A1F026E52CE100485C4A /* uthash.h */, + AA54A1E926E52CE100485C4A /* vk_format.h */, + AA54A1DE26E52CE100485C4A /* vk_funclist.inl */, + AA54A1EE26E52CE100485C4A /* vk_funcs.c */, + AA54A1FB26E52CE100485C4A /* vk_funcs.h */, + AA54A1E326E52CE100485C4A /* writer.c */, + ); + path = lib; + sourceTree = ""; + }; + AA54A20026E52CE100485C4A /* imgui */ = { + isa = PBXGroup; + children = ( + AA54A20326E52CE100485C4A /* imconfig.h */, + AA54A20A26E52CE100485C4A /* imgui_demo.cpp */, + AA54A20B26E52CE100485C4A /* imgui_draw.cpp */, + AA54A20726E52CE100485C4A /* imgui_internal.h */, + AA54A20426E52CE100485C4A /* imgui_widgets.cpp */, + AA54A20626E52CE100485C4A /* imgui.cpp */, + AA54A20126E52CE100485C4A /* imgui.h */, + AA54A20826E52CE100485C4A /* imstb_rectpack.h */, + AA54A20226E52CE100485C4A /* imstb_textedit.h */, + AA54A20526E52CE100485C4A /* imstb_truetype.h */, + AA54A20926E52CE100485C4A /* LICENSE.txt */, + ); + path = imgui; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -409,6 +524,9 @@ files = ( A9B67B7F1C3AAE9800373FFD /* Icon.png in Resources */, A9B67B801C3AAE9800373FFD /* Main.storyboard in Resources */, + AA54A6C626E52CE300485C4A /* mainpage.md in Resources */, + AA54A6E226E52CE400485C4A /* LICENSE.txt in Resources */, + AA54A6BA26E52CE300485C4A /* vk_funclist.inl in Resources */, A9B67B7E1C3AAE9800373FFD /* Default~ipad.png in Resources */, A9B67B7D1C3AAE9800373FFD /* Default-568h@2x.png in Resources */, A98703D91E9D382A0066959C /* data in Resources */, @@ -419,6 +537,9 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + AA54A6E326E52CE400485C4A /* LICENSE.txt in Resources */, + AA54A6BB26E52CE300485C4A /* vk_funclist.inl in Resources */, + AA54A6C726E52CE300485C4A /* mainpage.md in Resources */, A9B67B911C3AAEA200373FFD /* macOS.xcassets in Resources */, A98703DA1E9D382A0066959C /* data in Resources */, A9B67B901C3AAEA200373FFD /* Main.storyboard in Resources */, @@ -432,15 +553,35 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + AA54A1C426E5277600485C4A /* VulkanTexture.cpp in Sources */, + AA54A6CE26E52CE400485C4A /* vk_funcs.c in Sources */, + AA54A6C426E52CE300485C4A /* filestream.c in Sources */, + AA54A6C026E52CE300485C4A /* errstr.c in Sources */, A951FF171E9C349000FA9144 /* VulkanDebug.cpp in Sources */, + AA54A6E626E52CE400485C4A /* imgui_draw.cpp in Sources */, A9BC9B1C1EE8421F00384233 /* MVKExample.cpp in Sources */, + AA54A6BC26E52CE300485C4A /* etcdec.cxx in Sources */, + AA54A6D226E52CE400485C4A /* hashtable.c in Sources */, + AA54A6B826E52CE300485C4A /* memstream.c in Sources */, + AA54A6C226E52CE300485C4A /* writer.c in Sources */, C9A79EFC204504E000696219 /* VulkanUIOverlay.cpp in Sources */, + AA54A6DE26E52CE400485C4A /* imgui_widgets.cpp in Sources */, A9B67B7A1C3AAE9800373FFD /* DemoViewController.mm in Sources */, A9B67B781C3AAE9800373FFD /* AppDelegate.m in Sources */, + AA54A6CA26E52CE300485C4A /* texture.c in Sources */, + AAB0D0BF26F24001005DC611 /* VulkanRaytracingSample.cpp in Sources */, C9788FD52044D78D00AB0892 /* VulkanAndroid.cpp in Sources */, A951FF1B1E9C349000FA9144 /* VulkanTools.cpp in Sources */, + AA54A6CC26E52CE300485C4A /* hashlist.c in Sources */, A951FF191E9C349000FA9144 /* vulkanexamplebase.cpp in Sources */, + AA54A1B426E5274500485C4A /* VulkanBuffer.cpp in Sources */, + AA54A6D826E52CE400485C4A /* swap.c in Sources */, + AA54A6BE26E52CE300485C4A /* checkheader.c in Sources */, A9B67B7C1C3AAE9800373FFD /* main.m in Sources */, + AA54A1B826E5275300485C4A /* VulkanDevice.cpp in Sources */, + AA54A1C026E5276C00485C4A /* VulkanSwapChain.cpp in Sources */, + AA54A6E426E52CE400485C4A /* imgui_demo.cpp in Sources */, + AA54A6E026E52CE400485C4A /* imgui.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -449,23 +590,34 @@ buildActionMask = 2147483647; files = ( C9A79EFD2045051D00696219 /* VulkanUIOverlay.cpp in Sources */, + AA54A6CF26E52CE400485C4A /* vk_funcs.c in Sources */, + AA54A6C526E52CE300485C4A /* filestream.c in Sources */, + AA54A6C126E52CE300485C4A /* errstr.c in Sources */, C9A79EFE2045051D00696219 /* VulkanUIOverlay.h in Sources */, - C9A79EF12045045E00696219 /* stb_textedit.h in Sources */, - C9A79EF22045045E00696219 /* imconfig.h in Sources */, - C9A79EF32045045E00696219 /* imgui_demo.cpp in Sources */, - C9A79EF42045045E00696219 /* imgui_draw.cpp in Sources */, - C9A79EF52045045E00696219 /* imgui_internal.h in Sources */, - C9A79EF62045045E00696219 /* stb_rect_pack.h in Sources */, - C9A79EF72045045E00696219 /* imgui.h in Sources */, - C9A79EF82045045E00696219 /* stb_truetype.h in Sources */, - C9A79EF92045045E00696219 /* imgui.cpp in Sources */, + AA54A6E726E52CE400485C4A /* imgui_draw.cpp in Sources */, + AA54A1B526E5274500485C4A /* VulkanBuffer.cpp in Sources */, + AA54A6BD26E52CE300485C4A /* etcdec.cxx in Sources */, + AA54A6D326E52CE400485C4A /* hashtable.c in Sources */, + AA54A6B926E52CE300485C4A /* memstream.c in Sources */, + AA54A6C326E52CE300485C4A /* writer.c in Sources */, + AA54A1B926E5275300485C4A /* VulkanDevice.cpp in Sources */, + AA54A6DF26E52CE400485C4A /* imgui_widgets.cpp in Sources */, A951FF181E9C349000FA9144 /* VulkanDebug.cpp in Sources */, + AA54A6CB26E52CE300485C4A /* texture.c in Sources */, + AAB0D0C026F24001005DC611 /* VulkanRaytracingSample.cpp in Sources */, A9BC9B1D1EE8421F00384233 /* MVKExample.cpp in Sources */, A9B67B8C1C3AAEA200373FFD /* AppDelegate.m in Sources */, + AA54A1C126E5276C00485C4A /* VulkanSwapChain.cpp in Sources */, + AA54A6CD26E52CE400485C4A /* hashlist.c in Sources */, A9B67B8F1C3AAEA200373FFD /* main.m in Sources */, + AA54A1C526E5277600485C4A /* VulkanTexture.cpp in Sources */, + AA54A6D926E52CE400485C4A /* swap.c in Sources */, + AA54A6BF26E52CE300485C4A /* checkheader.c in Sources */, A951FF1C1E9C349000FA9144 /* VulkanTools.cpp in Sources */, A951FF1A1E9C349000FA9144 /* vulkanexamplebase.cpp in Sources */, A9B67B8D1C3AAEA200373FFD /* DemoViewController.mm in Sources */, + AA54A6E526E52CE400485C4A /* imgui_demo.cpp in Sources */, + AA54A6E126E52CE400485C4A /* imgui.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -477,7 +629,7 @@ buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; DEVELOPMENT_TEAM = VU3TCKU48B; - GCC_PREFIX_HEADER = "$(SRCROOT)/iOS/Prefix.pch"; + GCC_PREFIX_HEADER = ""; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", "DEBUG=1", @@ -486,14 +638,13 @@ ); GCC_WARN_64_TO_32_BIT_CONVERSION = NO; INFOPLIST_FILE = "$(SRCROOT)/iOS/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "@executable_path"; - LIBRARY_SEARCH_PATHS = ( - "\"$(SRCROOT)/MoltenVK/iOS\"", - ); + LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/MoltenVK/dylib/iOS\""; SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; TARGETED_DEVICE_FAMILY = "1,2"; - VALID_ARCHS = arm64; + VALID_ARCHS = "$(ARCHS_STANDARD)"; }; name = Debug; }; @@ -502,21 +653,20 @@ buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; DEVELOPMENT_TEAM = VU3TCKU48B; - GCC_PREFIX_HEADER = "$(SRCROOT)/iOS/Prefix.pch"; + GCC_PREFIX_HEADER = ""; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", VK_USE_PLATFORM_IOS_MVK, ); GCC_WARN_64_TO_32_BIT_CONVERSION = NO; INFOPLIST_FILE = "$(SRCROOT)/iOS/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "@executable_path"; - LIBRARY_SEARCH_PATHS = ( - "\"$(SRCROOT)/MoltenVK/iOS\"", - ); + LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/MoltenVK/dylib/iOS\""; SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; TARGETED_DEVICE_FAMILY = "1,2"; - VALID_ARCHS = arm64; + VALID_ARCHS = "$(ARCHS_STANDARD)"; }; name = Release; }; @@ -526,23 +676,16 @@ ARCHS = "$(ARCHS_STANDARD)"; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; COMBINE_HIDPI_IMAGES = YES; - GCC_PREFIX_HEADER = "$(SRCROOT)/macOS/Prefix.pch"; + GCC_PREFIX_HEADER = ""; GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - _DEBUG, - VK_USE_PLATFORM_MACOS_MVK, - ); - "GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = ( + "$(inherited)", "DEBUG=1", _DEBUG, VK_USE_PLATFORM_MACOS_MVK, ); INFOPLIST_FILE = "$(SRCROOT)/macOS/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "@executable_path"; - LIBRARY_SEARCH_PATHS = ( - "\"$(SRCROOT)/MoltenVK/macOS\"", - "$(PROJECT_DIR)/MoltenVK/macOS", - ); + LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/MoltenVK/dylib/macOS\""; MACOSX_DEPLOYMENT_TARGET = 10.11; SDKROOT = macosx; }; @@ -554,16 +697,16 @@ ARCHS = "$(ARCHS_STANDARD)"; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; COMBINE_HIDPI_IMAGES = YES; - GCC_PREFIX_HEADER = "$(SRCROOT)/macOS/Prefix.pch"; - GCC_PREPROCESSOR_DEFINITIONS = VK_USE_PLATFORM_MACOS_MVK; - "GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = VK_USE_PLATFORM_MACOS_MVK; + GCC_PREFIX_HEADER = ""; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + VK_USE_PLATFORM_MACOS_MVK, + ); INFOPLIST_FILE = "$(SRCROOT)/macOS/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "@executable_path"; - LIBRARY_SEARCH_PATHS = ( - "\"$(SRCROOT)/MoltenVK/macOS\"", - "$(PROJECT_DIR)/MoltenVK/macOS", - ); + LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/MoltenVK/dylib/macOS\""; MACOSX_DEPLOYMENT_TARGET = 10.11; + ONLY_ACTIVE_ARCH = NO; SDKROOT = macosx; }; name = Release; @@ -611,6 +754,7 @@ HEADER_SEARCH_PATHS = ( "\"$(SRCROOT)/MoltenVK/include\"", "\"$(SRCROOT)/../external\"/**", + "\"$(SRCROOT)/../base\"", ); ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.moltenvk.${PRODUCT_NAME:identifier}"; @@ -658,6 +802,7 @@ HEADER_SEARCH_PATHS = ( "\"$(SRCROOT)/MoltenVK/include\"", "\"$(SRCROOT)/../external\"/**", + "\"$(SRCROOT)/../base\"", ); PRODUCT_BUNDLE_IDENTIFIER = "com.moltenvk.${PRODUCT_NAME:identifier}"; PRODUCT_NAME = "${PROJECT}"; diff --git a/xcode/ios/AppDelegate.h b/xcode/ios/AppDelegate.h index 5023d3dd..02bc20ab 100644 --- a/xcode/ios/AppDelegate.h +++ b/xcode/ios/AppDelegate.h @@ -10,6 +10,7 @@ @interface AppDelegate : UIResponder @property (strong, nonatomic) UIWindow *window; +@property (strong, nonatomic) UIViewController *viewController; @end diff --git a/xcode/ios/AppDelegate.m b/xcode/ios/AppDelegate.m index 8d69ac3b..430a9591 100644 --- a/xcode/ios/AppDelegate.m +++ b/xcode/ios/AppDelegate.m @@ -6,6 +6,7 @@ */ #import "AppDelegate.h" +#import "DemoViewController.h" @interface AppDelegate () @@ -39,6 +40,7 @@ - (void)applicationWillTerminate:(UIApplication *)application { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. + [(DemoViewController *)_viewController shutdownExample]; } @end diff --git a/xcode/ios/DemoViewController.h b/xcode/ios/DemoViewController.h index 81d04021..bc908bbb 100644 --- a/xcode/ios/DemoViewController.h +++ b/xcode/ios/DemoViewController.h @@ -13,6 +13,7 @@ /** The main view controller for the demo storyboard. */ @interface DemoViewController : UIViewController +-(void) shutdownExample; @end diff --git a/xcode/ios/DemoViewController.mm b/xcode/ios/DemoViewController.mm index 2629623f..00328952 100644 --- a/xcode/ios/DemoViewController.mm +++ b/xcode/ios/DemoViewController.mm @@ -6,11 +6,12 @@ */ #import "DemoViewController.h" +#import "AppDelegate.h" #include "MVKExample.h" -const std::string VulkanExampleBase::getAssetPath() { +const std::string getAssetPath() { return [NSBundle.mainBundle.resourcePath stringByAppendingString: @"/data/"].UTF8String; } @@ -22,6 +23,7 @@ const std::string VulkanExampleBase::getAssetPath() { MVKExample* _mvkExample; CADisplayLink* _displayLink; BOOL _viewHasAppeared; + CGPoint _startPoint; } /** Since this is a single-view app, init Vulkan when the view is loaded. */ @@ -30,20 +32,40 @@ const std::string VulkanExampleBase::getAssetPath() { self.view.contentScaleFactor = UIScreen.mainScreen.nativeScale; - _mvkExample = new MVKExample(self.view); - + _mvkExample = new MVKExample(self.view, 1.0f); // SRS - Use 1x scale factor for UIOverlay on iOS + + // SRS - Enable AppDelegate to call into DemoViewController for handling app lifecycle events (e.g. termination) + auto appDelegate = (AppDelegate *)UIApplication.sharedApplication.delegate; + appDelegate.viewController = self; + uint32_t fps = 60; _displayLink = [CADisplayLink displayLinkWithTarget: self selector: @selector(renderFrame)]; [_displayLink setFrameInterval: 60 / fps]; [_displayLink addToRunLoop: NSRunLoop.currentRunLoop forMode: NSDefaultRunLoopMode]; - // Setup tap gesture to toggle virtual keyboard - UITapGestureRecognizer* tapSelector = [[UITapGestureRecognizer alloc] - initWithTarget: self action: @selector(handleTapGesture:)]; - tapSelector.numberOfTapsRequired = 1; + // Setup double tap gesture to toggle virtual keyboard + UITapGestureRecognizer* tapSelector = [[[UITapGestureRecognizer alloc] + initWithTarget: self action: @selector(handleTapGesture:)] autorelease]; + tapSelector.numberOfTapsRequired = 2; tapSelector.cancelsTouchesInView = YES; + tapSelector.requiresExclusiveTouchType = YES; [self.view addGestureRecognizer: tapSelector]; + // SRS - Setup pan gesture to detect and activate translation + UIPanGestureRecognizer* panSelector = [[[UIPanGestureRecognizer alloc] + initWithTarget: self action: @selector(handlePanGesture:)] autorelease]; + panSelector.minimumNumberOfTouches = 2; + panSelector.cancelsTouchesInView = YES; + panSelector.requiresExclusiveTouchType = YES; + [self.view addGestureRecognizer: panSelector]; + + // SRS - Setup pinch gesture to detect and activate zoom + UIPinchGestureRecognizer* pinchSelector = [[[UIPinchGestureRecognizer alloc] + initWithTarget: self action: @selector(handlePinchGesture:)] autorelease]; + pinchSelector.cancelsTouchesInView = YES; + pinchSelector.requiresExclusiveTouchType = YES; + [self.view addGestureRecognizer: pinchSelector]; + _viewHasAppeared = NO; } @@ -55,12 +77,13 @@ const std::string VulkanExampleBase::getAssetPath() { -(BOOL) canBecomeFirstResponder { return _viewHasAppeared; } -(void) renderFrame { - _mvkExample->renderFrame(); + //_mvkExample->renderFrame(); + _mvkExample->displayLinkOutputCb(); // SRS - Call displayLinkOutputCb() to animate frames vs. renderFrame() for static image } --(void) dealloc { - delete _mvkExample; - [super dealloc]; +-(void) shutdownExample { + [_displayLink invalidate]; + delete _mvkExample; } // Toggle the display of the virtual keyboard @@ -72,18 +95,13 @@ const std::string VulkanExampleBase::getAssetPath() { } } -// Display and hide the keyboard by tapping on the view +// Display and hide the keyboard by double tapping on the view -(void) handleTapGesture: (UITapGestureRecognizer*) gestureRecognizer { if (gestureRecognizer.state == UIGestureRecognizerStateEnded) { [self toggleKeyboard]; } } -// Handle keyboard input --(void) handleKeyboardInput: (unichar) keycode { - _mvkExample->keyPressed(keycode); -} - #pragma mark UIKeyInput methods @@ -92,16 +110,99 @@ const std::string VulkanExampleBase::getAssetPath() { // A key on the keyboard has been pressed. -(void) insertText: (NSString*) text { - unichar keycode = (text.length > 0) ? [text characterAtIndex: 0] : 0; - [self handleKeyboardInput: keycode]; + unichar keychar = (text.length > 0) ? [text.lowercaseString characterAtIndex: 0] : 0; + _mvkExample->keyPressed(keychar); } // The delete backward key has been pressed. -(void) deleteBackward { - [self handleKeyboardInput: 0x33]; + _mvkExample->keyPressed(KEY_DELETE); } +#pragma mark UITouch methods + +-(CGPoint) getTouchLocalPoint:(UIEvent*) theEvent { + UITouch *touch = [[theEvent allTouches] anyObject]; + CGPoint point = [touch locationInView: self.view]; + point.x *= self.view.contentScaleFactor; + point.y *= self.view.contentScaleFactor; + return point; +} + +// SRS - Handle touch events +-(void) touchesBegan:(NSSet*) touches withEvent:(UIEvent*) theEvent { + if (touches.count == 1) { + auto point = [self getTouchLocalPoint: theEvent]; + _mvkExample->mouseDown(point.x, point.y); + } +} + +-(void) touchesMoved:(NSSet*) touches withEvent:(UIEvent*) theEvent { + if (touches.count == 1) { + auto point = [self getTouchLocalPoint: theEvent]; + _mvkExample->mouseDragged(point.x, point.y); + } +} + +-(void) touchesEnded:(NSSet*) touches withEvent:(UIEvent*) theEvent { + _mvkExample->mouseUp(); +} + +-(void) touchesCancelled:(NSSet*) touches withEvent:(UIEvent*) theEvent { + _mvkExample->mouseUp(); +} + +#pragma mark UIGesture methods + +-(CGPoint) getGestureLocalPoint:(UIGestureRecognizer*) gestureRecognizer { + CGPoint point = [gestureRecognizer locationInView: self.view]; + point.x *= self.view.contentScaleFactor; + point.y *= self.view.contentScaleFactor; + return point; +} + +// SRS - Respond to pan gestures for translation +-(void) handlePanGesture: (UIPanGestureRecognizer*) gestureRecognizer { + switch (gestureRecognizer.state) { + case UIGestureRecognizerStateBegan: { + _startPoint = [self getGestureLocalPoint: gestureRecognizer]; + _mvkExample->otherMouseDown(_startPoint.x, _startPoint.y); + break; + } + case UIGestureRecognizerStateChanged: { + auto translation = [gestureRecognizer translationInView: self.view]; + translation.x *= self.view.contentScaleFactor; + translation.y *= self.view.contentScaleFactor; + _mvkExample->mouseDragged(_startPoint.x + translation.x, _startPoint.y + translation.y); + break; + } + default: { + _mvkExample->otherMouseUp(); + break; + } + } +} + +// SRS - Respond to pinch gestures for zoom +-(void) handlePinchGesture: (UIPinchGestureRecognizer*) gestureRecognizer { + switch (gestureRecognizer.state) { + case UIGestureRecognizerStateBegan: { + _startPoint = [self getGestureLocalPoint: gestureRecognizer]; + _mvkExample->rightMouseDown(_startPoint.x, _startPoint.y); + break; + } + case UIGestureRecognizerStateChanged: { + _mvkExample->mouseDragged(_startPoint.x, _startPoint.y - self.view.frame.size.height * log(gestureRecognizer.scale)); + break; + } + default: { + _mvkExample->rightMouseUp(); + break; + } + } +} + @end diff --git a/xcode/ios/Info.plist b/xcode/ios/Info.plist index eb0fa65a..e61fdb6f 100644 --- a/xcode/ios/Info.plist +++ b/xcode/ios/Info.plist @@ -20,6 +20,8 @@ APPL CFBundleVersion 1.0 + CFBundleShortVersionString + 1.0 LSApplicationCategoryType UIMainStoryboardFile diff --git a/xcode/macos/AppDelegate.h b/xcode/macos/AppDelegate.h index 3eb638e9..852413ce 100644 --- a/xcode/macos/AppDelegate.h +++ b/xcode/macos/AppDelegate.h @@ -9,4 +9,6 @@ @interface AppDelegate : NSObject +@property (strong, nonatomic) NSViewController *viewController; + @end diff --git a/xcode/macos/AppDelegate.m b/xcode/macos/AppDelegate.m index c3ce3b24..2a97e646 100644 --- a/xcode/macos/AppDelegate.m +++ b/xcode/macos/AppDelegate.m @@ -6,6 +6,7 @@ */ #import "AppDelegate.h" +#import "DemoViewController.h" @interface AppDelegate () @@ -19,6 +20,7 @@ - (void)applicationWillTerminate:(NSNotification *)aNotification { // Insert code here to tear down your application + [(DemoViewController *)_viewController shutdownExample]; } - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender { diff --git a/xcode/macos/DemoViewController.h b/xcode/macos/DemoViewController.h index 3cbedc48..c6337cfb 100644 --- a/xcode/macos/DemoViewController.h +++ b/xcode/macos/DemoViewController.h @@ -13,6 +13,7 @@ /** The main view controller for the demo storyboard. */ @interface DemoViewController : NSViewController +-(void) shutdownExample; @end diff --git a/xcode/macos/DemoViewController.mm b/xcode/macos/DemoViewController.mm index 657f0b5f..128931df 100644 --- a/xcode/macos/DemoViewController.mm +++ b/xcode/macos/DemoViewController.mm @@ -6,12 +6,12 @@ */ #import "DemoViewController.h" +#import "AppDelegate.h" #import #include "MVKExample.h" - -const std::string VulkanExampleBase::getAssetPath() { +const std::string getAssetPath() { return [NSBundle.mainBundle.resourcePath stringByAppendingString: @"/data/"].UTF8String; } @@ -22,16 +22,18 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* target) { - ((MVKExample*)target)->renderFrame(); + //((MVKExample*)target)->renderFrame(); + ((MVKExample*)target)->displayLinkOutputCb(); // SRS - Call displayLinkOutputCb() to animate frames vs. renderFrame() for static image return kCVReturnSuccess; } +CALayer* layer; +MVKExample* _mvkExample; #pragma mark - #pragma mark DemoViewController @implementation DemoViewController { - MVKExample* _mvkExample; CVDisplayLinkRef _displayLink; } @@ -39,24 +41,23 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, -(void) viewDidLoad { [super viewDidLoad]; - self.view.wantsLayer = YES; // Back the view with a layer created by the makeBackingLayer method. + self.view.wantsLayer = YES; // Back the view with a layer created by the makeBackingLayer method (called immediately on set) - _mvkExample = new MVKExample(self.view); + _mvkExample = new MVKExample(self.view, layer.contentsScale); // SRS - Use backing layer scale factor for UIOverlay on macOS + // SRS - Enable AppDelegate to call into DemoViewController for handling application lifecycle events (e.g. termination) + auto appDelegate = (AppDelegate *)NSApplication.sharedApplication.delegate; + appDelegate.viewController = self; + CVDisplayLinkCreateWithActiveCGDisplays(&_displayLink); CVDisplayLinkSetOutputCallback(_displayLink, &DisplayLinkCallback, _mvkExample); CVDisplayLinkStart(_displayLink); } --(void) dealloc { +-(void) shutdownExample { + CVDisplayLinkStop(_displayLink); CVDisplayLinkRelease(_displayLink); delete _mvkExample; - [super dealloc]; -} - -// Handle keyboard input --(void) keyDown:(NSEvent*) theEvent { - _mvkExample->keyPressed(theEvent.keyCode); } @end @@ -75,12 +76,113 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, /** If the wantsLayer property is set to YES, this method will be invoked to return a layer instance. */ -(CALayer*) makeBackingLayer { - CALayer* layer = [self.class.layerClass layer]; + layer = [self.class.layerClass layer]; CGSize viewScale = [self convertSizeToBacking: CGSizeMake(1.0, 1.0)]; layer.contentsScale = MIN(viewScale.width, viewScale.height); return layer; } +// SRS - Activate mouse cursor tracking within the view, set view as window delegate, and center the window +- (void) viewDidMoveToWindow { + auto trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds] options: (NSTrackingMouseMoved | NSTrackingActiveAlways | NSTrackingInVisibleRect) owner:self userInfo:nil]; + [self addTrackingArea: trackingArea]; + + [self.window setDelegate: self.window.contentView]; + [self.window center]; +} + -(BOOL) acceptsFirstResponder { return YES; } +// SRS - Handle keyboard events +-(void) keyDown:(NSEvent*) theEvent { + NSString *text = [theEvent charactersIgnoringModifiers]; + unichar keychar = (text.length > 0) ? [text.lowercaseString characterAtIndex: 0] : 0; + switch (keychar) + { + case KEY_DELETE: // support keyboards with no escape key + case KEY_ESCAPE: + [NSApp terminate:nil]; + break; + default: + _mvkExample->keyDown(keychar); + break; + } +} + +-(void) keyUp:(NSEvent*) theEvent { + NSString *text = [theEvent charactersIgnoringModifiers]; + unichar keychar = (text.length > 0) ? [text.lowercaseString characterAtIndex: 0] : 0; + _mvkExample->keyUp(keychar); +} + +// SRS - Handle mouse events +-(NSPoint) getMouseLocalPoint:(NSEvent*) theEvent { + NSPoint location = [theEvent locationInWindow]; + NSPoint point = [self convertPointToBacking:location]; + point.y = self.frame.size.height*self.window.backingScaleFactor - point.y; + return point; +} + +-(void) mouseDown:(NSEvent*) theEvent { + auto point = [self getMouseLocalPoint:theEvent]; + _mvkExample->mouseDown(point.x, point.y); +} + +-(void) mouseUp:(NSEvent*) theEvent { + _mvkExample->mouseUp(); +} + +-(void) rightMouseDown:(NSEvent*) theEvent { + auto point = [self getMouseLocalPoint:theEvent]; + _mvkExample->rightMouseDown(point.x, point.y); +} + +-(void) rightMouseUp:(NSEvent*) theEvent { + _mvkExample->rightMouseUp(); +} + +-(void) otherMouseDown:(NSEvent*) theEvent { + auto point = [self getMouseLocalPoint:theEvent]; + _mvkExample->otherMouseDown(point.x, point.y); +} + +-(void) otherMouseUp:(NSEvent*) theEvent { + _mvkExample->otherMouseUp(); +} + +-(void) mouseDragged:(NSEvent*) theEvent { + auto point = [self getMouseLocalPoint:theEvent]; + _mvkExample->mouseDragged(point.x, point.y); +} + +-(void) rightMouseDragged:(NSEvent*) theEvent { + auto point = [self getMouseLocalPoint:theEvent]; + _mvkExample->mouseDragged(point.x, point.y); +} + +-(void) otherMouseDragged:(NSEvent*) theEvent { + auto point = [self getMouseLocalPoint:theEvent]; + _mvkExample->mouseDragged(point.x, point.y); +} + +-(void) mouseMoved:(NSEvent*) theEvent { + auto point = [self getMouseLocalPoint:theEvent]; + _mvkExample->mouseDragged(point.x, point.y); +} + +-(void) scrollWheel:(NSEvent*) theEvent { + short wheelDelta = [theEvent deltaY]; + _mvkExample->scrollWheel(wheelDelta); +} + +- (void)windowWillEnterFullScreen:(NSNotification *)notification +{ + _mvkExample->fullScreen(true); +} + +- (void)windowWillExitFullScreen:(NSNotification *)notification +{ + _mvkExample->fullScreen(false); +} + @end diff --git a/xcode/macos/Resources/Main.storyboard b/xcode/macos/Resources/Main.storyboard index 52913366..6ba73adf 100644 --- a/xcode/macos/Resources/Main.storyboard +++ b/xcode/macos/Resources/Main.storyboard @@ -1,8 +1,8 @@ - + - + @@ -101,12 +101,13 @@ - + - + - - + + + @@ -121,7 +122,7 @@ - +