// Copyright 2019 The SwiftShader Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "VkSwapchainKHR.hpp" #include "Vulkan/VkDeviceMemory.hpp" #include "Vulkan/VkFence.hpp" #include "Vulkan/VkImage.hpp" #include "Vulkan/VkSemaphore.hpp" #include #include namespace vk { SwapchainKHR::SwapchainKHR(const VkSwapchainCreateInfoKHR *pCreateInfo, void *mem) : surface(vk::Cast(pCreateInfo->surface)) , images(reinterpret_cast(mem)) , imageCount(pCreateInfo->minImageCount) , retired(false) { memset(reinterpret_cast(images), 0, imageCount * sizeof(PresentImage)); } void SwapchainKHR::destroy(const VkAllocationCallbacks *pAllocator) { for(uint32_t i = 0; i < imageCount; i++) { PresentImage ¤tImage = images[i]; if(currentImage.exists()) { surface->detachImage(¤tImage); currentImage.clear(); } } if(!retired) { surface->disassociateSwapchain(); } vk::deallocate(images, pAllocator); } size_t SwapchainKHR::ComputeRequiredAllocationSize(const VkSwapchainCreateInfoKHR *pCreateInfo) { return pCreateInfo->minImageCount * sizeof(PresentImage); } void SwapchainKHR::retire() { if(!retired) { retired = true; surface->disassociateSwapchain(); for(uint32_t i = 0; i < imageCount; i++) { PresentImage ¤tImage = images[i]; if(currentImage.isAvailable()) { surface->detachImage(¤tImage); currentImage.clear(); } } } } void SwapchainKHR::resetImages() { for(uint32_t i = 0; i < imageCount; i++) { images[i].clear(); } } VkResult SwapchainKHR::createImages(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo) { resetImages(); VkImageCreateInfo imageInfo = {}; imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; if(pCreateInfo->flags & VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR) { imageInfo.flags |= VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT; } if(pCreateInfo->flags & VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR) { imageInfo.flags |= VK_IMAGE_CREATE_PROTECTED_BIT; } imageInfo.imageType = VK_IMAGE_TYPE_2D; imageInfo.format = pCreateInfo->imageFormat; imageInfo.extent.height = pCreateInfo->imageExtent.height; imageInfo.extent.width = pCreateInfo->imageExtent.width; imageInfo.extent.depth = 1; imageInfo.mipLevels = 1; imageInfo.arrayLayers = pCreateInfo->imageArrayLayers; imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageInfo.usage = pCreateInfo->imageUsage; imageInfo.sharingMode = pCreateInfo->imageSharingMode; imageInfo.pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices; imageInfo.queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount; imageInfo.initialLayout = VK_IMAGE_LAYOUT_GENERAL; VkMemoryAllocateInfo allocInfo = {}; allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocInfo.allocationSize = 0; allocInfo.memoryTypeIndex = 0; VkResult status; for(uint32_t i = 0; i < imageCount; i++) { PresentImage ¤tImage = images[i]; status = currentImage.allocateImage(device, imageInfo); if(status != VK_SUCCESS) { return status; } allocInfo.allocationSize = currentImage.getImage()->getMemoryRequirements().size; status = currentImage.allocateAndBindImageMemory(device, allocInfo); if(status != VK_SUCCESS) { return status; } surface->attachImage(¤tImage); } return VK_SUCCESS; } uint32_t SwapchainKHR::getImageCount() const { return imageCount; } VkResult SwapchainKHR::getImages(uint32_t *pSwapchainImageCount, VkImage *pSwapchainImages) const { uint32_t i; for(i = 0; i < std::min(*pSwapchainImageCount, imageCount); i++) { pSwapchainImages[i] = images[i].asVkImage(); } *pSwapchainImageCount = i; if(*pSwapchainImageCount < imageCount) { return VK_INCOMPLETE; } return VK_SUCCESS; } VkResult SwapchainKHR::getNextImage(uint64_t timeout, BinarySemaphore *semaphore, Fence *fence, uint32_t *pImageIndex) { for(uint32_t i = 0; i < imageCount; i++) { PresentImage ¤tImage = images[i]; if(currentImage.isAvailable()) { currentImage.setStatus(DRAWING); *pImageIndex = i; if(semaphore) { semaphore->signal(); } if(fence) { fence->complete(); } return VK_SUCCESS; } } return (timeout > 0) ? VK_TIMEOUT : VK_NOT_READY; } VkResult SwapchainKHR::present(uint32_t index) { auto &image = images[index]; image.setStatus(PRESENTING); VkResult result = surface->present(&image); image.setStatus(AVAILABLE); if(retired) { surface->detachImage(&image); image.clear(); } return result; } } // namespace vk