blob: 30c72a90d737d9b6e3342fb547d5f0d3fc0672ac [file] [log] [blame]
// 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/VkImage.hpp"
#include "Vulkan/VkDeviceMemory.hpp"
#include "Vulkan/VkDestroy.h"
#include <algorithm>
namespace vk
{
SwapchainKHR::SwapchainKHR(const VkSwapchainCreateInfoKHR *pCreateInfo, void *mem) :
createInfo(*pCreateInfo),
retired(false)
{
images.resize(pCreateInfo->minImageCount);
resetImages();
}
void SwapchainKHR::destroy(const VkAllocationCallbacks *pAllocator)
{
for(auto& currentImage : images)
{
if (currentImage.imageStatus != NONEXISTENT)
{
vk::Cast(createInfo.surface)->detachImage(&currentImage);
vk::destroy(currentImage.imageMemory, nullptr);
vk::destroy(currentImage.image, nullptr);
currentImage.imageStatus = NONEXISTENT;
}
}
if(!retired)
{
vk::Cast(createInfo.surface)->disassociateSwapchain();
}
}
size_t SwapchainKHR::ComputeRequiredAllocationSize(const VkSwapchainCreateInfoKHR *pCreateInfo)
{
return 0;
}
void SwapchainKHR::retire()
{
if(!retired)
{
retired = true;
vk::Cast(createInfo.surface)->disassociateSwapchain();
for(auto& currentImage : images)
{
if(currentImage.imageStatus == AVAILABLE)
{
vk::Cast(createInfo.surface)->detachImage(&currentImage);
vk::destroy(currentImage.imageMemory, nullptr);
vk::destroy(currentImage.image, nullptr);
currentImage.imageStatus = NONEXISTENT;
}
}
}
}
void SwapchainKHR::resetImages()
{
for(auto& currentImage : images)
{
currentImage.image = VK_NULL_HANDLE;
currentImage.imageMemory = VK_NULL_HANDLE;
currentImage.imageStatus = NONEXISTENT;
}
}
VkResult SwapchainKHR::createImages(VkDevice device)
{
resetImages();
VkImageCreateInfo imageInfo = {};
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
if(createInfo.flags & VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR)
{
imageInfo.flags |= VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT;
}
if(createInfo.flags & VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR)
{
imageInfo.flags |= VK_IMAGE_CREATE_PROTECTED_BIT;
}
imageInfo.imageType = VK_IMAGE_TYPE_2D;
imageInfo.format = createInfo.imageFormat;
imageInfo.extent.height = createInfo.imageExtent.height;
imageInfo.extent.width = createInfo.imageExtent.width;
imageInfo.extent.depth = 1;
imageInfo.mipLevels = 1;
imageInfo.arrayLayers = createInfo.imageArrayLayers;
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageInfo.usage = createInfo.imageUsage;
imageInfo.sharingMode = createInfo.imageSharingMode;
imageInfo.pQueueFamilyIndices = createInfo.pQueueFamilyIndices;
imageInfo.queueFamilyIndexCount = createInfo.queueFamilyIndexCount;
imageInfo.initialLayout = VK_IMAGE_LAYOUT_GENERAL;
VkResult status;
for(auto& currentImage : images)
{
status = vkCreateImage(device, &imageInfo, nullptr, &currentImage.image);
if(status != VK_SUCCESS)
{
return status;
}
VkMemoryRequirements memRequirements = vk::Cast(currentImage.image)->getMemoryRequirements();
VkMemoryAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocInfo.allocationSize = memRequirements.size;
allocInfo.memoryTypeIndex = 0;
status = vkAllocateMemory(device, &allocInfo, nullptr, &currentImage.imageMemory);
if(status != VK_SUCCESS)
{
return status;
}
vkBindImageMemory(device, currentImage.image, currentImage.imageMemory, 0);
currentImage.imageStatus = AVAILABLE;
vk::Cast(createInfo.surface)->attachImage(&currentImage);
}
return VK_SUCCESS;
}
uint32_t SwapchainKHR::getImageCount() const
{
return static_cast<uint32_t >(images.size());
}
VkResult SwapchainKHR::getImages(uint32_t *pSwapchainImageCount, VkImage *pSwapchainImages) const
{
uint32_t count = getImageCount();
uint32_t i;
for (i = 0; i < std::min(*pSwapchainImageCount, count); i++)
{
pSwapchainImages[i] = images[i].image;
}
*pSwapchainImageCount = i;
if (*pSwapchainImageCount < count)
{
return VK_INCOMPLETE;
}
return VK_SUCCESS;
}
VkResult SwapchainKHR::getNextImage(uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex)
{
for(uint32_t i = 0; i < getImageCount(); i++)
{
PresentImage& currentImage = images[i];
if(currentImage.imageStatus == AVAILABLE)
{
currentImage.imageStatus = DRAWING;
*pImageIndex = i;
if(semaphore)
{
vk::Cast(semaphore)->signal();
}
if(fence)
{
vk::Cast(fence)->add();
vk::Cast(fence)->done();
}
return VK_SUCCESS;
}
}
return VK_NOT_READY;
}
void SwapchainKHR::present(uint32_t index)
{
auto & image = images[index];
image.imageStatus = PRESENTING;
vk::Cast(createInfo.surface)->present(&image);
image.imageStatus = AVAILABLE;
if(retired)
{
vk::Cast(createInfo.surface)->detachImage(&image);
vk::destroy(image.imageMemory, nullptr);
vk::destroy(image.image, nullptr);
image.imageStatus = NONEXISTENT;
}
}
}