Merge branch 'headless' of http://gitea.inksoul.top/inksoul/plumageRender into headless
commit
9ece9a6c3d
|
@ -100,24 +100,18 @@ namespace vks
|
||||||
*/
|
*/
|
||||||
uint32_t getMemoryType(uint32_t typeBits, VkMemoryPropertyFlags properties, VkBool32 *memTypeFound = nullptr)
|
uint32_t getMemoryType(uint32_t typeBits, VkMemoryPropertyFlags properties, VkBool32 *memTypeFound = nullptr)
|
||||||
{
|
{
|
||||||
for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; i++) {
|
VkPhysicalDeviceMemoryProperties deviceMemoryProperties;
|
||||||
|
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &deviceMemoryProperties);
|
||||||
|
for (uint32_t j = 0; j < deviceMemoryProperties.memoryTypeCount; j++) {
|
||||||
if ((typeBits & 1) == 1) {
|
if ((typeBits & 1) == 1) {
|
||||||
if ((memoryProperties.memoryTypes[i].propertyFlags & properties) == properties) {
|
if ((deviceMemoryProperties.memoryTypes[j].propertyFlags & properties) == properties) {
|
||||||
if (memTypeFound) {
|
return j;
|
||||||
*memTypeFound = true;
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
typeBits >>= 1;
|
typeBits >>= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memTypeFound) {
|
|
||||||
*memTypeFound = false;
|
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
|
||||||
throw std::runtime_error("Could not find a matching memory type");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -79,6 +79,7 @@ namespace vks
|
||||||
ktx_size_t ktxTextureSize = ktxTexture_GetSize(ktxTexture);
|
ktx_size_t ktxTextureSize = ktxTexture_GetSize(ktxTexture);
|
||||||
|
|
||||||
// Get device properties for the requested texture format
|
// Get device properties for the requested texture format
|
||||||
|
|
||||||
VkFormatProperties formatProperties;
|
VkFormatProperties formatProperties;
|
||||||
vkGetPhysicalDeviceFormatProperties(device->physicalDevice, format, &formatProperties);
|
vkGetPhysicalDeviceFormatProperties(device->physicalDevice, format, &formatProperties);
|
||||||
|
|
||||||
|
@ -87,6 +88,7 @@ namespace vks
|
||||||
// optimal tiling instead
|
// optimal tiling instead
|
||||||
// On most implementations linear tiling will only support a very
|
// On most implementations linear tiling will only support a very
|
||||||
// limited amount of formats and features (mip maps, cubemaps, arrays, etc.)
|
// limited amount of formats and features (mip maps, cubemaps, arrays, etc.)
|
||||||
|
|
||||||
VkBool32 useStaging = !forceLinear;
|
VkBool32 useStaging = !forceLinear;
|
||||||
|
|
||||||
VkMemoryAllocateInfo memAllocInfo = vks::initializers::memoryAllocateInfo();
|
VkMemoryAllocateInfo memAllocInfo = vks::initializers::memoryAllocateInfo();
|
||||||
|
|
|
@ -1,630 +0,0 @@
|
||||||
/*
|
|
||||||
* Vulkan texture loader
|
|
||||||
*
|
|
||||||
* Copyright(C) 2016-2017 by Sascha Willems - www.saschawillems.de
|
|
||||||
*
|
|
||||||
* This code is licensed under the MIT license(MIT) (http://opensource.org/licenses/MIT)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string>
|
|
||||||
#include <fstream>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "vulkan/vulkan.h"
|
|
||||||
#include "VulkanTools.h"
|
|
||||||
#include "VulkanDevice.hpp"
|
|
||||||
#define GLM_ENABLE_EXPERIMENTAL
|
|
||||||
#include <gli/gli.hpp>
|
|
||||||
|
|
||||||
|
|
||||||
namespace vks
|
|
||||||
{
|
|
||||||
class Texture {
|
|
||||||
public:
|
|
||||||
vks::VulkanDevice *device;
|
|
||||||
VkImage image = VK_NULL_HANDLE;
|
|
||||||
VkImageLayout imageLayout;
|
|
||||||
VkDeviceMemory deviceMemory;
|
|
||||||
VkImageView view;
|
|
||||||
uint32_t width, height;
|
|
||||||
uint32_t mipLevels;
|
|
||||||
uint32_t layerCount;
|
|
||||||
VkDescriptorImageInfo descriptor;
|
|
||||||
VkSampler sampler;
|
|
||||||
|
|
||||||
void updateDescriptor()
|
|
||||||
{
|
|
||||||
descriptor.sampler = sampler;
|
|
||||||
descriptor.imageView = view;
|
|
||||||
descriptor.imageLayout = imageLayout;
|
|
||||||
}
|
|
||||||
|
|
||||||
void destroy()
|
|
||||||
{
|
|
||||||
vkDestroyImageView(device->logicalDevice, view, nullptr);
|
|
||||||
vkDestroyImage(device->logicalDevice, image, nullptr);
|
|
||||||
if (sampler)
|
|
||||||
{
|
|
||||||
vkDestroySampler(device->logicalDevice, sampler, nullptr);
|
|
||||||
}
|
|
||||||
vkFreeMemory(device->logicalDevice, deviceMemory, nullptr);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class Texture2D : public Texture {
|
|
||||||
public:
|
|
||||||
void loadFromFile(
|
|
||||||
std::string filename,
|
|
||||||
VkFormat format,
|
|
||||||
vks::VulkanDevice *device,
|
|
||||||
VkQueue copyQueue,
|
|
||||||
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
|
|
||||||
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
|
||||||
{
|
|
||||||
|
|
||||||
gli::texture2d tex2D(gli::load(filename.c_str()));
|
|
||||||
|
|
||||||
assert(!tex2D.empty());
|
|
||||||
|
|
||||||
this->device = device;
|
|
||||||
width = static_cast<uint32_t>(tex2D[0].extent().x);
|
|
||||||
height = static_cast<uint32_t>(tex2D[0].extent().y);
|
|
||||||
mipLevels = static_cast<uint32_t>(tex2D.levels());
|
|
||||||
|
|
||||||
// Get device properites for the requested texture format
|
|
||||||
VkFormatProperties formatProperties;
|
|
||||||
vkGetPhysicalDeviceFormatProperties(device->physicalDevice, format, &formatProperties);
|
|
||||||
|
|
||||||
VkMemoryAllocateInfo memAllocInfo{};
|
|
||||||
memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
|
||||||
VkMemoryRequirements memReqs;
|
|
||||||
|
|
||||||
// Use a separate command buffer for texture loading
|
|
||||||
VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
|
||||||
|
|
||||||
// Create a host-visible staging buffer that contains the raw image data
|
|
||||||
VkBuffer stagingBuffer;
|
|
||||||
VkDeviceMemory stagingMemory;
|
|
||||||
|
|
||||||
VkBufferCreateInfo bufferCreateInfo{};
|
|
||||||
bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
|
||||||
bufferCreateInfo.size = tex2D.size();
|
|
||||||
// This buffer is used as a transfer source for the buffer copy
|
|
||||||
bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
|
||||||
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
||||||
|
|
||||||
VK_CHECK_RESULT(vkCreateBuffer(device->logicalDevice, &bufferCreateInfo, nullptr, &stagingBuffer));
|
|
||||||
|
|
||||||
// Get memory requirements for the staging buffer (alignment, memory type bits)
|
|
||||||
vkGetBufferMemoryRequirements(device->logicalDevice, stagingBuffer, &memReqs);
|
|
||||||
|
|
||||||
memAllocInfo.allocationSize = memReqs.size;
|
|
||||||
// Get memory type index for a host visible buffer
|
|
||||||
memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
|
||||||
|
|
||||||
VK_CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &stagingMemory));
|
|
||||||
VK_CHECK_RESULT(vkBindBufferMemory(device->logicalDevice, stagingBuffer, stagingMemory, 0));
|
|
||||||
|
|
||||||
// Copy texture data into staging buffer
|
|
||||||
uint8_t *data;
|
|
||||||
VK_CHECK_RESULT(vkMapMemory(device->logicalDevice, stagingMemory, 0, memReqs.size, 0, (void **)&data));
|
|
||||||
memcpy(data, tex2D.data(), tex2D.size());
|
|
||||||
vkUnmapMemory(device->logicalDevice, stagingMemory);
|
|
||||||
|
|
||||||
// Setup buffer copy regions for each mip level
|
|
||||||
std::vector<VkBufferImageCopy> bufferCopyRegions;
|
|
||||||
uint32_t offset = 0;
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < mipLevels; i++)
|
|
||||||
{
|
|
||||||
VkBufferImageCopy bufferCopyRegion = {};
|
|
||||||
bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
||||||
bufferCopyRegion.imageSubresource.mipLevel = i;
|
|
||||||
bufferCopyRegion.imageSubresource.baseArrayLayer = 0;
|
|
||||||
bufferCopyRegion.imageSubresource.layerCount = 1;
|
|
||||||
bufferCopyRegion.imageExtent.width = static_cast<uint32_t>(tex2D[i].extent().x);
|
|
||||||
bufferCopyRegion.imageExtent.height = static_cast<uint32_t>(tex2D[i].extent().y);
|
|
||||||
bufferCopyRegion.imageExtent.depth = 1;
|
|
||||||
bufferCopyRegion.bufferOffset = offset;
|
|
||||||
|
|
||||||
bufferCopyRegions.push_back(bufferCopyRegion);
|
|
||||||
|
|
||||||
offset += static_cast<uint32_t>(tex2D[i].size());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create optimal tiled target image
|
|
||||||
VkImageCreateInfo imageCreateInfo{};
|
|
||||||
imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
|
||||||
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
|
|
||||||
imageCreateInfo.format = format;
|
|
||||||
imageCreateInfo.mipLevels = mipLevels;
|
|
||||||
imageCreateInfo.arrayLayers = 1;
|
|
||||||
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
||||||
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
|
||||||
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
||||||
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
||||||
imageCreateInfo.extent = { width, height, 1 };
|
|
||||||
imageCreateInfo.usage = imageUsageFlags;
|
|
||||||
// Ensure that the TRANSFER_DST bit is set for staging
|
|
||||||
if (!(imageCreateInfo.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT))
|
|
||||||
{
|
|
||||||
imageCreateInfo.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
|
||||||
}
|
|
||||||
VK_CHECK_RESULT(vkCreateImage(device->logicalDevice, &imageCreateInfo, nullptr, &image));
|
|
||||||
|
|
||||||
vkGetImageMemoryRequirements(device->logicalDevice, image, &memReqs);
|
|
||||||
|
|
||||||
memAllocInfo.allocationSize = memReqs.size;
|
|
||||||
|
|
||||||
memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
|
||||||
VK_CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &deviceMemory));
|
|
||||||
VK_CHECK_RESULT(vkBindImageMemory(device->logicalDevice, image, deviceMemory, 0));
|
|
||||||
|
|
||||||
VkImageSubresourceRange subresourceRange = {};
|
|
||||||
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
||||||
subresourceRange.baseMipLevel = 0;
|
|
||||||
subresourceRange.levelCount = mipLevels;
|
|
||||||
subresourceRange.layerCount = 1;
|
|
||||||
|
|
||||||
// Image barrier for optimal image (target)
|
|
||||||
// Optimal image will be used as destination for the copy
|
|
||||||
{
|
|
||||||
VkImageMemoryBarrier imageMemoryBarrier{};
|
|
||||||
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
|
||||||
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
||||||
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
|
||||||
imageMemoryBarrier.srcAccessMask = 0;
|
|
||||||
imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
|
||||||
imageMemoryBarrier.image = image;
|
|
||||||
imageMemoryBarrier.subresourceRange = subresourceRange;
|
|
||||||
vkCmdPipelineBarrier(copyCmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy mip levels from staging buffer
|
|
||||||
vkCmdCopyBufferToImage(
|
|
||||||
copyCmd,
|
|
||||||
stagingBuffer,
|
|
||||||
image,
|
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
||||||
static_cast<uint32_t>(bufferCopyRegions.size()),
|
|
||||||
bufferCopyRegions.data()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Change texture image layout to shader read after all mip levels have been copied
|
|
||||||
this->imageLayout = imageLayout;
|
|
||||||
{
|
|
||||||
VkImageMemoryBarrier imageMemoryBarrier{};
|
|
||||||
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
|
||||||
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
|
||||||
imageMemoryBarrier.newLayout = imageLayout;
|
|
||||||
imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
|
||||||
imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
|
||||||
imageMemoryBarrier.image = image;
|
|
||||||
imageMemoryBarrier.subresourceRange = subresourceRange;
|
|
||||||
vkCmdPipelineBarrier(copyCmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
|
|
||||||
}
|
|
||||||
|
|
||||||
device->flushCommandBuffer(copyCmd, copyQueue);
|
|
||||||
|
|
||||||
// Clean up staging resources
|
|
||||||
vkFreeMemory(device->logicalDevice, stagingMemory, nullptr);
|
|
||||||
vkDestroyBuffer(device->logicalDevice, stagingBuffer, nullptr);
|
|
||||||
|
|
||||||
VkSamplerCreateInfo samplerCreateInfo{};
|
|
||||||
samplerCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
|
||||||
samplerCreateInfo.magFilter = VK_FILTER_LINEAR;
|
|
||||||
samplerCreateInfo.minFilter = VK_FILTER_LINEAR;
|
|
||||||
samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
|
||||||
samplerCreateInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
|
||||||
samplerCreateInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
|
||||||
samplerCreateInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
|
||||||
samplerCreateInfo.mipLodBias = 0.0f;
|
|
||||||
samplerCreateInfo.compareOp = VK_COMPARE_OP_NEVER;
|
|
||||||
samplerCreateInfo.minLod = 0.0f;
|
|
||||||
samplerCreateInfo.maxLod = (float)mipLevels;
|
|
||||||
samplerCreateInfo.maxAnisotropy = device->enabledFeatures.samplerAnisotropy ? device->properties.limits.maxSamplerAnisotropy : 1.0f;
|
|
||||||
samplerCreateInfo.anisotropyEnable = device->enabledFeatures.samplerAnisotropy;
|
|
||||||
samplerCreateInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
|
|
||||||
VK_CHECK_RESULT(vkCreateSampler(device->logicalDevice, &samplerCreateInfo, nullptr, &sampler));
|
|
||||||
|
|
||||||
VkImageViewCreateInfo viewCreateInfo{};
|
|
||||||
viewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
|
||||||
viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
|
||||||
viewCreateInfo.format = format;
|
|
||||||
viewCreateInfo.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
|
|
||||||
viewCreateInfo.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
|
|
||||||
viewCreateInfo.subresourceRange.levelCount = mipLevels;
|
|
||||||
viewCreateInfo.image = image;
|
|
||||||
VK_CHECK_RESULT(vkCreateImageView(device->logicalDevice, &viewCreateInfo, nullptr, &view));
|
|
||||||
|
|
||||||
updateDescriptor();
|
|
||||||
}
|
|
||||||
|
|
||||||
void loadFromBuffer(
|
|
||||||
void* buffer,
|
|
||||||
VkDeviceSize bufferSize,
|
|
||||||
VkFormat format,
|
|
||||||
uint32_t width,
|
|
||||||
uint32_t height,
|
|
||||||
vks::VulkanDevice *device,
|
|
||||||
VkQueue copyQueue,
|
|
||||||
VkFilter filter = VK_FILTER_LINEAR,
|
|
||||||
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
|
|
||||||
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
|
||||||
{
|
|
||||||
assert(buffer);
|
|
||||||
|
|
||||||
this->device = device;
|
|
||||||
width = width;
|
|
||||||
height = height;
|
|
||||||
mipLevels = 1;
|
|
||||||
|
|
||||||
VkMemoryAllocateInfo memAllocInfo{};
|
|
||||||
memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
|
||||||
VkMemoryRequirements memReqs;
|
|
||||||
// Use a separate command buffer for texture loading
|
|
||||||
VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
|
||||||
|
|
||||||
// Create a host-visible staging buffer that contains the raw image data
|
|
||||||
VkBuffer stagingBuffer;
|
|
||||||
VkDeviceMemory stagingMemory;
|
|
||||||
|
|
||||||
VkBufferCreateInfo bufferCreateInfo{};
|
|
||||||
bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
|
||||||
bufferCreateInfo.size = bufferSize;
|
|
||||||
// This buffer is used as a transfer source for the buffer copy
|
|
||||||
bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
|
||||||
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
||||||
|
|
||||||
VK_CHECK_RESULT(vkCreateBuffer(device->logicalDevice, &bufferCreateInfo, nullptr, &stagingBuffer));
|
|
||||||
|
|
||||||
// Get memory requirements for the staging buffer (alignment, memory type bits)
|
|
||||||
vkGetBufferMemoryRequirements(device->logicalDevice, stagingBuffer, &memReqs);
|
|
||||||
|
|
||||||
memAllocInfo.allocationSize = memReqs.size;
|
|
||||||
// Get memory type index for a host visible buffer
|
|
||||||
memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
|
||||||
|
|
||||||
VK_CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &stagingMemory));
|
|
||||||
VK_CHECK_RESULT(vkBindBufferMemory(device->logicalDevice, stagingBuffer, stagingMemory, 0));
|
|
||||||
|
|
||||||
// Copy texture data into staging buffer
|
|
||||||
uint8_t *data;
|
|
||||||
VK_CHECK_RESULT(vkMapMemory(device->logicalDevice, stagingMemory, 0, memReqs.size, 0, (void **)&data));
|
|
||||||
memcpy(data, buffer, bufferSize);
|
|
||||||
vkUnmapMemory(device->logicalDevice, stagingMemory);
|
|
||||||
|
|
||||||
VkBufferImageCopy bufferCopyRegion = {};
|
|
||||||
bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
||||||
bufferCopyRegion.imageSubresource.mipLevel = 0;
|
|
||||||
bufferCopyRegion.imageSubresource.baseArrayLayer = 0;
|
|
||||||
bufferCopyRegion.imageSubresource.layerCount = 1;
|
|
||||||
bufferCopyRegion.imageExtent.width = width;
|
|
||||||
bufferCopyRegion.imageExtent.height = height;
|
|
||||||
bufferCopyRegion.imageExtent.depth = 1;
|
|
||||||
bufferCopyRegion.bufferOffset = 0;
|
|
||||||
|
|
||||||
// Create optimal tiled target image
|
|
||||||
VkImageCreateInfo imageCreateInfo{};
|
|
||||||
imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
|
||||||
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
|
|
||||||
imageCreateInfo.format = format;
|
|
||||||
imageCreateInfo.mipLevels = mipLevels;
|
|
||||||
imageCreateInfo.arrayLayers = 1;
|
|
||||||
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
||||||
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
|
||||||
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
||||||
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
||||||
imageCreateInfo.extent = { width, height, 1 };
|
|
||||||
imageCreateInfo.usage = imageUsageFlags;
|
|
||||||
// Ensure that the TRANSFER_DST bit is set for staging
|
|
||||||
if (!(imageCreateInfo.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT))
|
|
||||||
{
|
|
||||||
imageCreateInfo.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
|
||||||
}
|
|
||||||
VK_CHECK_RESULT(vkCreateImage(device->logicalDevice, &imageCreateInfo, nullptr, &image));
|
|
||||||
|
|
||||||
vkGetImageMemoryRequirements(device->logicalDevice, image, &memReqs);
|
|
||||||
|
|
||||||
memAllocInfo.allocationSize = memReqs.size;
|
|
||||||
|
|
||||||
memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
|
||||||
VK_CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &deviceMemory));
|
|
||||||
VK_CHECK_RESULT(vkBindImageMemory(device->logicalDevice, image, deviceMemory, 0));
|
|
||||||
|
|
||||||
VkImageSubresourceRange subresourceRange = {};
|
|
||||||
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
||||||
subresourceRange.baseMipLevel = 0;
|
|
||||||
subresourceRange.levelCount = mipLevels;
|
|
||||||
subresourceRange.layerCount = 1;
|
|
||||||
|
|
||||||
{
|
|
||||||
VkImageMemoryBarrier imageMemoryBarrier{};
|
|
||||||
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
|
||||||
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
||||||
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
|
||||||
imageMemoryBarrier.srcAccessMask = 0;
|
|
||||||
imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
|
||||||
imageMemoryBarrier.image = image;
|
|
||||||
imageMemoryBarrier.subresourceRange = subresourceRange;
|
|
||||||
vkCmdPipelineBarrier(copyCmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
|
|
||||||
}
|
|
||||||
|
|
||||||
vkCmdCopyBufferToImage(
|
|
||||||
copyCmd,
|
|
||||||
stagingBuffer,
|
|
||||||
image,
|
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
||||||
1,
|
|
||||||
&bufferCopyRegion
|
|
||||||
);
|
|
||||||
|
|
||||||
this->imageLayout = imageLayout;
|
|
||||||
{
|
|
||||||
VkImageMemoryBarrier imageMemoryBarrier{};
|
|
||||||
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
|
||||||
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
|
||||||
imageMemoryBarrier.newLayout = imageLayout;
|
|
||||||
imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
|
||||||
imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
|
||||||
imageMemoryBarrier.image = image;
|
|
||||||
imageMemoryBarrier.subresourceRange = subresourceRange;
|
|
||||||
vkCmdPipelineBarrier(copyCmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
|
|
||||||
}
|
|
||||||
|
|
||||||
device->flushCommandBuffer(copyCmd, copyQueue);
|
|
||||||
|
|
||||||
// Clean up staging resources
|
|
||||||
vkFreeMemory(device->logicalDevice, stagingMemory, nullptr);
|
|
||||||
vkDestroyBuffer(device->logicalDevice, stagingBuffer, nullptr);
|
|
||||||
|
|
||||||
// Create sampler
|
|
||||||
VkSamplerCreateInfo samplerCreateInfo = {};
|
|
||||||
samplerCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
|
||||||
samplerCreateInfo.magFilter = filter;
|
|
||||||
samplerCreateInfo.minFilter = filter;
|
|
||||||
samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
|
||||||
samplerCreateInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
|
||||||
samplerCreateInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
|
||||||
samplerCreateInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
|
||||||
samplerCreateInfo.mipLodBias = 0.0f;
|
|
||||||
samplerCreateInfo.compareOp = VK_COMPARE_OP_NEVER;
|
|
||||||
samplerCreateInfo.minLod = 0.0f;
|
|
||||||
samplerCreateInfo.maxLod = 0.0f;
|
|
||||||
samplerCreateInfo.maxAnisotropy = 1.0f;
|
|
||||||
VK_CHECK_RESULT(vkCreateSampler(device->logicalDevice, &samplerCreateInfo, nullptr, &sampler));
|
|
||||||
|
|
||||||
// Create image view
|
|
||||||
VkImageViewCreateInfo viewCreateInfo = {};
|
|
||||||
viewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
|
||||||
viewCreateInfo.pNext = NULL;
|
|
||||||
viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
|
||||||
viewCreateInfo.format = format;
|
|
||||||
viewCreateInfo.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
|
|
||||||
viewCreateInfo.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
|
|
||||||
viewCreateInfo.subresourceRange.levelCount = 1;
|
|
||||||
viewCreateInfo.image = image;
|
|
||||||
VK_CHECK_RESULT(vkCreateImageView(device->logicalDevice, &viewCreateInfo, nullptr, &view));
|
|
||||||
|
|
||||||
// Update descriptor image info member that can be used for setting up descriptor sets
|
|
||||||
updateDescriptor();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class TextureCubeMap : public Texture {
|
|
||||||
public:
|
|
||||||
void loadFromFile(
|
|
||||||
std::string filename,
|
|
||||||
VkFormat format,
|
|
||||||
vks::VulkanDevice *device,
|
|
||||||
VkQueue copyQueue,
|
|
||||||
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
|
|
||||||
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
|
||||||
{
|
|
||||||
#if defined(__ANDROID__)
|
|
||||||
// Textures are stored inside the apk on Android (compressed)
|
|
||||||
// So they need to be loaded via the asset manager
|
|
||||||
AAsset* asset = AAssetManager_open(androidApp->activity->assetManager, filename.c_str(), AASSET_MODE_STREAMING);
|
|
||||||
if (!asset) {
|
|
||||||
LOGE("Could not load texture %s", filename.c_str());
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
size_t size = AAsset_getLength(asset);
|
|
||||||
assert(size > 0);
|
|
||||||
|
|
||||||
void *textureData = malloc(size);
|
|
||||||
AAsset_read(asset, textureData, size);
|
|
||||||
AAsset_close(asset);
|
|
||||||
|
|
||||||
gli::texture_cube texCube(gli::load((const char*)textureData, size));
|
|
||||||
|
|
||||||
free(textureData);
|
|
||||||
#else
|
|
||||||
gli::texture_cube texCube(gli::load(filename));
|
|
||||||
#endif
|
|
||||||
assert(!texCube.empty());
|
|
||||||
|
|
||||||
this->device = device;
|
|
||||||
width = static_cast<uint32_t>(texCube.extent().x);
|
|
||||||
height = static_cast<uint32_t>(texCube.extent().y);
|
|
||||||
mipLevels = static_cast<uint32_t>(texCube.levels());
|
|
||||||
|
|
||||||
VkMemoryAllocateInfo memAllocInfo{};
|
|
||||||
memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
|
||||||
VkMemoryRequirements memReqs;
|
|
||||||
|
|
||||||
// Create a host-visible staging buffer that contains the raw image data
|
|
||||||
VkBuffer stagingBuffer;
|
|
||||||
VkDeviceMemory stagingMemory;
|
|
||||||
|
|
||||||
VkBufferCreateInfo bufferCreateInfo{};
|
|
||||||
bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
|
||||||
bufferCreateInfo.size = texCube.size();
|
|
||||||
// This buffer is used as a transfer source for the buffer copy
|
|
||||||
bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
|
||||||
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
||||||
|
|
||||||
VK_CHECK_RESULT(vkCreateBuffer(device->logicalDevice, &bufferCreateInfo, nullptr, &stagingBuffer));
|
|
||||||
|
|
||||||
// Get memory requirements for the staging buffer (alignment, memory type bits)
|
|
||||||
vkGetBufferMemoryRequirements(device->logicalDevice, stagingBuffer, &memReqs);
|
|
||||||
|
|
||||||
memAllocInfo.allocationSize = memReqs.size;
|
|
||||||
// Get memory type index for a host visible buffer
|
|
||||||
memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
|
||||||
|
|
||||||
VK_CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &stagingMemory));
|
|
||||||
VK_CHECK_RESULT(vkBindBufferMemory(device->logicalDevice, stagingBuffer, stagingMemory, 0));
|
|
||||||
|
|
||||||
// Copy texture data into staging buffer
|
|
||||||
uint8_t *data;
|
|
||||||
VK_CHECK_RESULT(vkMapMemory(device->logicalDevice, stagingMemory, 0, memReqs.size, 0, (void **)&data));
|
|
||||||
memcpy(data, texCube.data(), texCube.size());
|
|
||||||
vkUnmapMemory(device->logicalDevice, stagingMemory);
|
|
||||||
|
|
||||||
// Setup buffer copy regions for each face including all of it's miplevels
|
|
||||||
std::vector<VkBufferImageCopy> bufferCopyRegions;
|
|
||||||
size_t offset = 0;
|
|
||||||
|
|
||||||
for (uint32_t face = 0; face < 6; face++) {
|
|
||||||
for (uint32_t level = 0; level < mipLevels; level++) {
|
|
||||||
VkBufferImageCopy bufferCopyRegion = {};
|
|
||||||
bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
||||||
bufferCopyRegion.imageSubresource.mipLevel = level;
|
|
||||||
bufferCopyRegion.imageSubresource.baseArrayLayer = face;
|
|
||||||
bufferCopyRegion.imageSubresource.layerCount = 1;
|
|
||||||
bufferCopyRegion.imageExtent.width = static_cast<uint32_t>(texCube[face][level].extent().x);
|
|
||||||
bufferCopyRegion.imageExtent.height = static_cast<uint32_t>(texCube[face][level].extent().y);
|
|
||||||
bufferCopyRegion.imageExtent.depth = 1;
|
|
||||||
bufferCopyRegion.bufferOffset = offset;
|
|
||||||
|
|
||||||
bufferCopyRegions.push_back(bufferCopyRegion);
|
|
||||||
|
|
||||||
// Increase offset into staging buffer for next level / face
|
|
||||||
offset += texCube[face][level].size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create optimal tiled target image
|
|
||||||
VkImageCreateInfo imageCreateInfo{};
|
|
||||||
imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
|
||||||
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
|
|
||||||
imageCreateInfo.format = format;
|
|
||||||
imageCreateInfo.mipLevels = mipLevels;
|
|
||||||
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
||||||
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
|
||||||
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
||||||
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
||||||
imageCreateInfo.extent = { width, height, 1 };
|
|
||||||
imageCreateInfo.usage = imageUsageFlags;
|
|
||||||
// Ensure that the TRANSFER_DST bit is set for staging
|
|
||||||
if (!(imageCreateInfo.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) {
|
|
||||||
imageCreateInfo.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
|
||||||
}
|
|
||||||
// Cube faces count as array layers in Vulkan
|
|
||||||
imageCreateInfo.arrayLayers = 6;
|
|
||||||
// This flag is required for cube map images
|
|
||||||
imageCreateInfo.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
|
|
||||||
|
|
||||||
|
|
||||||
VK_CHECK_RESULT(vkCreateImage(device->logicalDevice, &imageCreateInfo, nullptr, &image));
|
|
||||||
|
|
||||||
vkGetImageMemoryRequirements(device->logicalDevice, image, &memReqs);
|
|
||||||
|
|
||||||
memAllocInfo.allocationSize = memReqs.size;
|
|
||||||
memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
|
||||||
|
|
||||||
VK_CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &deviceMemory));
|
|
||||||
VK_CHECK_RESULT(vkBindImageMemory(device->logicalDevice, image, deviceMemory, 0));
|
|
||||||
|
|
||||||
// Use a separate command buffer for texture loading
|
|
||||||
VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
|
||||||
|
|
||||||
// Image barrier for optimal image (target)
|
|
||||||
// Set initial layout for all array layers (faces) of the optimal (target) tiled texture
|
|
||||||
VkImageSubresourceRange subresourceRange = {};
|
|
||||||
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
||||||
subresourceRange.baseMipLevel = 0;
|
|
||||||
subresourceRange.levelCount = mipLevels;
|
|
||||||
subresourceRange.layerCount = 6;
|
|
||||||
|
|
||||||
{
|
|
||||||
VkImageMemoryBarrier imageMemoryBarrier{};
|
|
||||||
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
|
||||||
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
||||||
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
|
||||||
imageMemoryBarrier.srcAccessMask = 0;
|
|
||||||
imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
|
||||||
imageMemoryBarrier.image = image;
|
|
||||||
imageMemoryBarrier.subresourceRange = subresourceRange;
|
|
||||||
vkCmdPipelineBarrier(copyCmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy the cube map faces from the staging buffer to the optimal tiled image
|
|
||||||
vkCmdCopyBufferToImage(
|
|
||||||
copyCmd,
|
|
||||||
stagingBuffer,
|
|
||||||
image,
|
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
||||||
static_cast<uint32_t>(bufferCopyRegions.size()),
|
|
||||||
bufferCopyRegions.data());
|
|
||||||
|
|
||||||
// Change texture image layout to shader read after all faces have been copied
|
|
||||||
this->imageLayout = imageLayout;
|
|
||||||
{
|
|
||||||
VkImageMemoryBarrier imageMemoryBarrier{};
|
|
||||||
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
|
||||||
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
|
||||||
imageMemoryBarrier.newLayout = imageLayout;
|
|
||||||
imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
|
||||||
imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
|
||||||
imageMemoryBarrier.image = image;
|
|
||||||
imageMemoryBarrier.subresourceRange = subresourceRange;
|
|
||||||
vkCmdPipelineBarrier(copyCmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
|
|
||||||
}
|
|
||||||
|
|
||||||
device->flushCommandBuffer(copyCmd, copyQueue);
|
|
||||||
|
|
||||||
// Create sampler
|
|
||||||
VkSamplerCreateInfo samplerCreateInfo{};
|
|
||||||
samplerCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
|
||||||
samplerCreateInfo.magFilter = VK_FILTER_LINEAR;
|
|
||||||
samplerCreateInfo.minFilter = VK_FILTER_LINEAR;
|
|
||||||
samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
|
||||||
samplerCreateInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
|
||||||
samplerCreateInfo.addressModeV = samplerCreateInfo.addressModeU;
|
|
||||||
samplerCreateInfo.addressModeW = samplerCreateInfo.addressModeU;
|
|
||||||
samplerCreateInfo.mipLodBias = 0.0f;
|
|
||||||
samplerCreateInfo.maxAnisotropy = device->enabledFeatures.samplerAnisotropy ? device->properties.limits.maxSamplerAnisotropy : 1.0f;
|
|
||||||
samplerCreateInfo.anisotropyEnable = device->enabledFeatures.samplerAnisotropy;
|
|
||||||
samplerCreateInfo.compareOp = VK_COMPARE_OP_NEVER;
|
|
||||||
samplerCreateInfo.minLod = 0.0f;
|
|
||||||
samplerCreateInfo.maxLod = (float)mipLevels;
|
|
||||||
samplerCreateInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
|
|
||||||
VK_CHECK_RESULT(vkCreateSampler(device->logicalDevice, &samplerCreateInfo, nullptr, &sampler));
|
|
||||||
|
|
||||||
// Create image view
|
|
||||||
VkImageViewCreateInfo viewCreateInfo{};
|
|
||||||
viewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
|
||||||
viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_CUBE;
|
|
||||||
viewCreateInfo.format = format;
|
|
||||||
viewCreateInfo.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
|
|
||||||
viewCreateInfo.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
|
|
||||||
viewCreateInfo.subresourceRange.layerCount = 6;
|
|
||||||
viewCreateInfo.subresourceRange.levelCount = mipLevels;
|
|
||||||
viewCreateInfo.image = image;
|
|
||||||
VK_CHECK_RESULT(vkCreateImageView(device->logicalDevice, &viewCreateInfo, nullptr, &view));
|
|
||||||
|
|
||||||
// Clean up staging resources
|
|
||||||
vkFreeMemory(device->logicalDevice, stagingMemory, nullptr);
|
|
||||||
vkDestroyBuffer(device->logicalDevice, stagingBuffer, nullptr);
|
|
||||||
|
|
||||||
// Update descriptor image info member that can be used for setting up descriptor sets
|
|
||||||
updateDescriptor();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -7,7 +7,7 @@
|
||||||
#include "imgui/imgui.h"
|
#include "imgui/imgui.h"
|
||||||
#include "VulkanDevice.hpp"
|
#include "VulkanDevice.hpp"
|
||||||
#include "VulkanUtils.hpp"
|
#include "VulkanUtils.hpp"
|
||||||
#include "VulkanTexture.hpp"
|
#include "VulkanTexture.h"
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
#if defined(__ANDROID__)
|
||||||
#include <android/asset_manager.h>
|
#include <android/asset_manager.h>
|
||||||
|
@ -64,7 +64,7 @@ public:
|
||||||
io.Fonts->AddFontFromFileTTF(ttfFilePath.data(), 16.0f,NULL, io.Fonts->GetGlyphRangesChineseSimplifiedCommon());
|
io.Fonts->AddFontFromFileTTF(ttfFilePath.data(), 16.0f,NULL, io.Fonts->GetGlyphRangesChineseSimplifiedCommon());
|
||||||
#endif
|
#endif
|
||||||
io.Fonts->GetTexDataAsRGBA32(&fontData, &texWidth, &texHeight);
|
io.Fonts->GetTexDataAsRGBA32(&fontData, &texWidth, &texHeight);
|
||||||
fontTexture.loadFromBuffer(fontData, texWidth * texHeight * 4 * sizeof(char), VK_FORMAT_R8G8B8A8_UNORM, texWidth, texHeight, vulkanDevice, queue);
|
fontTexture.fromBuffer(fontData, texWidth * texHeight * 4 * sizeof(char), VK_FORMAT_R8G8B8A8_UNORM, texWidth, texHeight, vulkanDevice, queue);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Setup
|
Setup
|
||||||
|
|
|
@ -39,7 +39,7 @@ function(buildHomework HOMEWORK_NAME)
|
||||||
"render/glTFModel.cpp"
|
"render/glTFModel.cpp"
|
||||||
|
|
||||||
"render/renderFoundation.h" "render/renderFoundation.cpp")
|
"render/renderFoundation.h" "render/renderFoundation.cpp")
|
||||||
target_link_libraries(${HOMEWORK_NAME} base ${Vulkan_LIBRARY} glfw )
|
target_link_libraries(${HOMEWORK_NAME} base ${Vulkan_LIBRARY} )
|
||||||
else(WIN32)
|
else(WIN32)
|
||||||
add_executable(${HOMEWORK_NAME} ${MAIN_CPP} ${SOURCE} ${MAIN_HEADER} ${SHADERS_GLSL} ${SHADERS_HLSL} ${README_FILES})
|
add_executable(${HOMEWORK_NAME} ${MAIN_CPP} ${SOURCE} ${MAIN_HEADER} ${SHADERS_GLSL} ${SHADERS_HLSL} ${README_FILES})
|
||||||
target_link_libraries(${HOMEWORK_NAME} base )
|
target_link_libraries(${HOMEWORK_NAME} base )
|
||||||
|
|
|
@ -32,9 +32,10 @@ void PlumageRender::initVulkan()
|
||||||
|
|
||||||
setupDebugMessager();
|
setupDebugMessager();
|
||||||
|
|
||||||
createSurface();
|
//createSurface();
|
||||||
|
|
||||||
pickupPhysicalDevice();
|
pickupPhysicalDevice();
|
||||||
|
|
||||||
|
createLogicalDevice();
|
||||||
}
|
}
|
||||||
|
|
||||||
VkResult PlumageRender::createInstance()
|
VkResult PlumageRender::createInstance()
|
||||||
|
@ -45,14 +46,10 @@ VkResult PlumageRender::createInstance()
|
||||||
throw std::runtime_error("validation layers requsted,but not available");
|
throw std::runtime_error("validation layers requsted,but not available");
|
||||||
}
|
}
|
||||||
|
|
||||||
//setup appliaction info
|
VkApplicationInfo appInfo = {};
|
||||||
VkApplicationInfo appInfo{};
|
|
||||||
|
|
||||||
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
||||||
appInfo.pApplicationName = "Hello Triangle";
|
appInfo.pApplicationName = name.c_str();
|
||||||
appInfo.applicationVersion = VK_API_VERSION_1_0;
|
appInfo.pEngineName = name.c_str();
|
||||||
appInfo.pEngineName = "No_Engine";
|
|
||||||
appInfo.engineVersion = VK_MAKE_API_VERSION(1, 0, 0,0);
|
|
||||||
appInfo.apiVersion = VK_API_VERSION_1_0;
|
appInfo.apiVersion = VK_API_VERSION_1_0;
|
||||||
|
|
||||||
// setup createInfo
|
// setup createInfo
|
||||||
|
@ -60,33 +57,30 @@ VkResult PlumageRender::createInstance()
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||||
createInfo.pApplicationInfo = &appInfo;
|
createInfo.pApplicationInfo = &appInfo;
|
||||||
|
|
||||||
auto requiredExtensions = getRequiredExtensions();
|
|
||||||
createInfo.enabledExtensionCount = static_cast<uint32_t>(requiredExtensions.size());
|
std::vector<const char*> instanceExtensions = { };
|
||||||
createInfo.ppEnabledExtensionNames = requiredExtensions.data();
|
|
||||||
|
|
||||||
|
|
||||||
// enable validation layer if available in createInfo
|
VkInstanceCreateInfo instanceCreateInfo = {};
|
||||||
VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo{};
|
instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||||
if (settings.validation)
|
instanceCreateInfo.pNext = NULL;
|
||||||
{
|
instanceCreateInfo.pApplicationInfo = &appInfo;
|
||||||
createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
|
|
||||||
createInfo.ppEnabledLayerNames = validationLayers.data();
|
|
||||||
|
|
||||||
populateDebugMessengerCreateInfo(debugCreateInfo);
|
if (settings.validation) {
|
||||||
createInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT*) &debugCreateInfo;
|
instanceExtensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
|
||||||
}
|
instanceExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||||
else
|
|
||||||
{
|
|
||||||
createInfo.enabledLayerCount = 0;
|
|
||||||
createInfo.pNext = nullptr;
|
|
||||||
}
|
}
|
||||||
|
instanceCreateInfo.enabledExtensionCount = (uint32_t)instanceExtensions.size();
|
||||||
|
instanceCreateInfo.ppEnabledExtensionNames = instanceExtensions.data();
|
||||||
|
|
||||||
// throw error in creating instance
|
std::vector<const char*> validationLayerNames;
|
||||||
if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS)
|
if (settings.validation) {
|
||||||
{
|
validationLayerNames.push_back("VK_LAYER_KHRONOS_validation");
|
||||||
throw std::runtime_error("failed to create instance");
|
instanceCreateInfo.enabledLayerCount = (uint32_t)validationLayerNames.size();
|
||||||
|
instanceCreateInfo.ppEnabledLayerNames = validationLayerNames.data();
|
||||||
}
|
}
|
||||||
|
return vkCreateInstance(&instanceCreateInfo, nullptr, &instance);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PlumageRender::checkValidationLayerSupport()
|
bool PlumageRender::checkValidationLayerSupport()
|
||||||
|
@ -119,7 +113,7 @@ bool PlumageRender::checkValidationLayerSupport()
|
||||||
std::vector<const char*> PlumageRender::getRequiredExtensions()
|
std::vector<const char*> PlumageRender::getRequiredExtensions()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/*
|
||||||
uint32_t glfwExtensionCount = 0;
|
uint32_t glfwExtensionCount = 0;
|
||||||
const char** glfwExtensions;
|
const char** glfwExtensions;
|
||||||
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
|
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
|
||||||
|
@ -127,8 +121,8 @@ std::vector<const char*> PlumageRender::getRequiredExtensions()
|
||||||
if (settings.headless)
|
if (settings.headless)
|
||||||
{
|
{
|
||||||
extensions.clear();
|
extensions.clear();
|
||||||
}
|
}*/
|
||||||
|
std::vector<const char*> extensions;
|
||||||
if (settings.validation)
|
if (settings.validation)
|
||||||
{
|
{
|
||||||
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||||
|
@ -142,66 +136,36 @@ std::vector<const char*> PlumageRender::getRequiredExtensions()
|
||||||
|
|
||||||
void PlumageRender::setupDebugMessager()
|
void PlumageRender::setupDebugMessager()
|
||||||
{
|
{
|
||||||
if (!settings.validation)
|
if (settings.validation) {
|
||||||
{
|
vkCreateDebugReportCallback = reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>(vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT"));
|
||||||
return;
|
vkDestroyDebugReportCallback = reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>(vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT"));
|
||||||
}
|
VkDebugReportCallbackCreateInfoEXT debugCreateInfo{};
|
||||||
|
debugCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
|
||||||
VkDebugUtilsMessengerCreateInfoEXT createInfo{};
|
debugCreateInfo.pfnCallback = (PFN_vkDebugReportCallbackEXT)debugMessageCallback;
|
||||||
populateDebugMessengerCreateInfo(createInfo);
|
debugCreateInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
|
||||||
|
debugCreateInfo.pUserData = NULL;
|
||||||
|
VK_CHECK_RESULT(vkCreateDebugReportCallback(instance, &debugCreateInfo, nullptr, &debugReportCallback));
|
||||||
if (CreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger) != VK_SUCCESS)
|
|
||||||
{
|
|
||||||
throw std::runtime_error("failed to set up debug messenger in setupDebugMessenger");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlumageRender::populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& debugCreateInfo)
|
|
||||||
|
VKAPI_ATTR VkBool32 VKAPI_CALL PlumageRender::debugMessageCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg, void* pUserData)
|
||||||
{
|
{
|
||||||
debugCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
|
std::string prefix("");
|
||||||
|
if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
|
||||||
debugCreateInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
|
prefix += "ERROR:";
|
||||||
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
|
};
|
||||||
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
|
if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
|
||||||
debugCreateInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
|
prefix += "WARNING:";
|
||||||
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
|
};
|
||||||
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
|
if (flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) {
|
||||||
debugCreateInfo.pfnUserCallback = &debugCallback;
|
prefix += "DEBUG:";
|
||||||
debugCreateInfo.pUserData = nullptr;
|
}
|
||||||
}
|
std::string debugMessage;
|
||||||
|
std::string msgCodeString = std::to_string(msgCode);
|
||||||
VKAPI_ATTR VkBool32 VKAPI_CALL PlumageRender::debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData)
|
debugMessage = debugMessage + prefix + " [" + pLayerPrefix + "] Code " + msgCodeString + " : " + pMsg;
|
||||||
{
|
std::cout << debugMessage << std::endl;
|
||||||
{
|
|
||||||
std::cerr << "validation layer: " << pCallbackData->pMessage << "/n" << std::endl;
|
|
||||||
|
|
||||||
return VK_FALSE;
|
return VK_FALSE;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VkResult PlumageRender::CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pDebugMessenger)
|
|
||||||
{
|
|
||||||
auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
|
|
||||||
|
|
||||||
if (func != nullptr)
|
|
||||||
{
|
|
||||||
return func(instance, pCreateInfo, pAllocator, pDebugMessenger);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return VK_ERROR_EXTENSION_NOT_PRESENT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlumageRender::DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, const VkAllocationCallbacks* pAllocator)
|
|
||||||
{
|
|
||||||
auto func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");
|
|
||||||
|
|
||||||
if (func != nullptr)
|
|
||||||
{
|
|
||||||
func(instance, debugMessenger, pAllocator);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlumageRender::createSurface()
|
void PlumageRender::createSurface()
|
||||||
|
@ -210,11 +174,11 @@ void PlumageRender::createSurface()
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
if (glfwCreateWindowSurface(instance, window, nullptr, &surface) != VK_SUCCESS)
|
if (glfwCreateWindowSurface(instance, window, nullptr, &surface) != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
throw std::runtime_error("failed to create window surface in createSurface()");
|
throw std::runtime_error("failed to create window surface in createSurface()");
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlumageRender::pickupPhysicalDevice()
|
void PlumageRender::pickupPhysicalDevice()
|
||||||
|
@ -255,17 +219,6 @@ bool PlumageRender::isDeviceSuitable(VkPhysicalDevice device)
|
||||||
bool extensionsSupported = checkDeviceExtensionSupport(device);
|
bool extensionsSupported = checkDeviceExtensionSupport(device);
|
||||||
return extensionsSupported;
|
return extensionsSupported;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{ // 非无头下在检查扩展支持的同时要检查swapchain
|
|
||||||
bool extensionsSupported = checkDeviceExtensionSupport(device);
|
|
||||||
bool swapChainAdequate = false;
|
|
||||||
QueueFamilyIndices indices = findQueueFamilies(device);
|
|
||||||
if (extensionsSupported)
|
|
||||||
{
|
|
||||||
SwapChainSupportDetails swapChainSupport = querySwapChainSupport(device);
|
|
||||||
swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PlumageRender::checkDeviceExtensionSupport(VkPhysicalDevice device)
|
bool PlumageRender::checkDeviceExtensionSupport(VkPhysicalDevice device)
|
||||||
|
@ -286,54 +239,7 @@ bool PlumageRender::checkDeviceExtensionSupport(VkPhysicalDevice device)
|
||||||
return requiredExtensions.empty();
|
return requiredExtensions.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
PlumageRender::QueueFamilyIndices PlumageRender::findQueueFamilies(VkPhysicalDevice device)
|
|
||||||
{
|
|
||||||
QueueFamilyIndices indices;
|
|
||||||
|
|
||||||
uint32_t queueFamilyCount = 0;
|
|
||||||
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
|
|
||||||
|
|
||||||
std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
|
|
||||||
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());
|
|
||||||
|
|
||||||
VkBool32 presentSupport = false;
|
|
||||||
|
|
||||||
// 检查显示队列支持
|
|
||||||
int i = 0;
|
|
||||||
if (!settings.headless)
|
|
||||||
{
|
|
||||||
vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& queueFamily : queueFamilies)
|
|
||||||
{
|
|
||||||
if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
|
|
||||||
indices.graphicsFamily = i;
|
|
||||||
}
|
|
||||||
// 无头下不需要检查present queue
|
|
||||||
if (settings.headless)
|
|
||||||
{
|
|
||||||
if (indices.isGraphicsFamilyComplete())
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (indices.isGraphicsFamilyComplete() && indices.isPresentFamilyComplete())
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (presentSupport)
|
|
||||||
{
|
|
||||||
indices.presentFamily = i;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return indices;
|
|
||||||
}
|
|
||||||
|
|
||||||
PlumageRender::SwapChainSupportDetails PlumageRender::querySwapChainSupport(VkPhysicalDevice device)
|
PlumageRender::SwapChainSupportDetails PlumageRender::querySwapChainSupport(VkPhysicalDevice device)
|
||||||
{
|
{
|
||||||
|
@ -365,35 +271,20 @@ PlumageRender::SwapChainSupportDetails PlumageRender::querySwapChainSupport(VkPh
|
||||||
|
|
||||||
void PlumageRender::createLogicalDevice()
|
void PlumageRender::createLogicalDevice()
|
||||||
{
|
{
|
||||||
QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
|
|
||||||
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
|
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
|
||||||
|
|
||||||
if (settings.headless)
|
if (settings.headless)
|
||||||
{
|
{
|
||||||
VkDeviceQueueCreateInfo queueCreateInfo{};
|
VkDeviceQueueCreateInfo queueCreateInfo{};
|
||||||
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||||
queueCreateInfo.queueFamilyIndex = indices.graphicsFamily.value();
|
queueCreateInfo.queueFamilyIndex = vulkanDevice->queueFamilyIndices.graphics;
|
||||||
queueCreateInfo.queueCount = 1;
|
queueCreateInfo.queueCount = 1;
|
||||||
float queuePriority = 1.0f;
|
float queuePriority = 1.0f;
|
||||||
queueCreateInfo.pQueuePriorities = &queuePriority;
|
queueCreateInfo.pQueuePriorities = &queuePriority;
|
||||||
queueCreateInfos.push_back(queueCreateInfo);
|
queueCreateInfos.push_back(queueCreateInfo);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
|
|
||||||
std::set<uint32_t> uniqueQueueFamilies = { indices.graphicsFamily.value(),indices.presentFamily.value() };
|
|
||||||
|
|
||||||
float queuePriority = 1.0f;
|
|
||||||
for (uint32_t queueFamily : uniqueQueueFamilies)
|
|
||||||
{
|
|
||||||
VkDeviceQueueCreateInfo queueCreateInfo{};
|
|
||||||
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
|
||||||
queueCreateInfo.queueFamilyIndex = queueFamily;
|
|
||||||
queueCreateInfo.queueCount = 1;
|
|
||||||
queueCreateInfo.pQueuePriorities = &queuePriority;
|
|
||||||
queueCreateInfos.push_back(queueCreateInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VkPhysicalDeviceFeatures enableFeatures{};
|
VkPhysicalDeviceFeatures enableFeatures{};
|
||||||
if (deviceFeatures.samplerAnisotropy) {
|
if (deviceFeatures.samplerAnisotropy) {
|
||||||
|
@ -433,171 +324,18 @@ void PlumageRender::createLogicalDevice()
|
||||||
throw std::runtime_error("failed to create logical device");
|
throw std::runtime_error("failed to create logical device");
|
||||||
}
|
}
|
||||||
|
|
||||||
vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicQueue);
|
vkGetDeviceQueue(device, vulkanDevice->queueFamilyIndices.graphics, 0, &graphicQueue);
|
||||||
if (settings.headless)
|
|
||||||
{
|
|
||||||
vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlumageRender::createSwapChain()
|
|
||||||
{
|
|
||||||
if (settings.headless)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SwapChainSupportDetails swapChainSupport = querySwapChainSupport(physicalDevice);
|
|
||||||
|
|
||||||
VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats);
|
|
||||||
VkPresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.presentModes);
|
|
||||||
VkExtent2D extent = chooseSwapExtent(swapChainSupport.capabilities);
|
|
||||||
|
|
||||||
uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;
|
|
||||||
|
|
||||||
if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount)
|
|
||||||
{
|
|
||||||
imageCount = swapChainSupport.capabilities.maxImageCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkSwapchainCreateInfoKHR createInfo{};
|
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
|
||||||
createInfo.surface = surface;
|
|
||||||
|
|
||||||
createInfo.minImageCount = imageCount;
|
|
||||||
createInfo.imageFormat = surfaceFormat.format;
|
|
||||||
createInfo.imageColorSpace = surfaceFormat.colorSpace;
|
|
||||||
createInfo.imageExtent = extent;
|
|
||||||
createInfo.imageArrayLayers = 1;
|
|
||||||
createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
|
||||||
|
|
||||||
QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
|
|
||||||
uint32_t queueFamilyIndices[] = { indices.graphicsFamily.value(),indices.presentFamily.value() };
|
|
||||||
if (indices.graphicsFamily != indices.presentFamily)
|
|
||||||
{
|
|
||||||
createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
|
||||||
createInfo.queueFamilyIndexCount = 2;
|
|
||||||
createInfo.pQueueFamilyIndices = queueFamilyIndices;
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
||||||
createInfo.queueFamilyIndexCount = 0;
|
|
||||||
createInfo.pQueueFamilyIndices = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
createInfo.preTransform = swapChainSupport.capabilities.currentTransform;
|
|
||||||
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
|
||||||
createInfo.presentMode = presentMode;
|
|
||||||
createInfo.clipped = VK_TRUE;
|
|
||||||
createInfo.oldSwapchain = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
|
|
||||||
if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChainKHR) != VK_SUCCESS)
|
|
||||||
{
|
|
||||||
throw std::runtime_error("failed to create swap chain !");
|
|
||||||
}
|
|
||||||
|
|
||||||
vkGetSwapchainImagesKHR(device, swapChainKHR, &imageCount, nullptr);
|
|
||||||
swapChainImages.resize(imageCount);
|
|
||||||
vkGetSwapchainImagesKHR(device, swapChainKHR, &imageCount, swapChainImages.data());
|
|
||||||
// store swap format and swap extent to member variable
|
|
||||||
swapChainImageFormat = surfaceFormat.format;
|
|
||||||
swapChainExtent = extent;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkSurfaceFormatKHR PlumageRender::chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats)
|
|
||||||
{
|
|
||||||
for (const auto& availableFormat : availableFormats) {
|
|
||||||
if (availableFormat.format == VK_FORMAT_B8G8R8_SRGB && availableFormat.colorSpace == VK_COLORSPACE_SRGB_NONLINEAR_KHR)
|
|
||||||
{
|
|
||||||
return availableFormat;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return availableFormats[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
VkPresentModeKHR PlumageRender::chooseSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes)
|
|
||||||
{
|
|
||||||
// Get available present modes
|
|
||||||
uint32_t presentModeCount;
|
|
||||||
VK_CHECK_RESULT(fpGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, NULL));
|
|
||||||
assert(presentModeCount > 0);
|
|
||||||
|
|
||||||
std::vector<VkPresentModeKHR> presentModes(presentModeCount);
|
|
||||||
VK_CHECK_RESULT(fpGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, presentModes.data()));
|
|
||||||
// The VK_PRESENT_MODE_FIFO_KHR mode must always be present as per spec
|
|
||||||
// This mode waits for the vertical blank ("v-sync")
|
|
||||||
// 垂直同步模式
|
|
||||||
VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR;
|
|
||||||
|
|
||||||
// If v-sync is not requested, try to find a mailbox mode
|
|
||||||
// It's the lowest latency non-tearing present mode available
|
|
||||||
if (!settings.vsync)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < presentModeCount; i++)
|
|
||||||
{
|
|
||||||
if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR)
|
|
||||||
{
|
|
||||||
swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if ((swapchainPresentMode != VK_PRESENT_MODE_MAILBOX_KHR) && (presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR))
|
|
||||||
{
|
|
||||||
swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VkExtent2D PlumageRender::chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities)
|
|
||||||
{
|
|
||||||
if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max())
|
|
||||||
{
|
|
||||||
return capabilities.currentExtent;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int width, height;
|
|
||||||
glfwGetFramebufferSize(window, &width, &height);
|
|
||||||
|
|
||||||
VkExtent2D actualExtent = {
|
|
||||||
static_cast<uint32_t>(width),
|
|
||||||
static_cast<uint32_t>(height)
|
|
||||||
};
|
|
||||||
|
|
||||||
actualExtent.width = std::clamp(actualExtent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
|
|
||||||
actualExtent.height = std::clamp(actualExtent.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
|
|
||||||
|
|
||||||
return actualExtent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlumageRender::cleanupSwapChain()
|
|
||||||
{
|
|
||||||
for (auto framebuffer : framebuffers)
|
|
||||||
{
|
|
||||||
vkDestroyFramebuffer(device, framebuffer, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto imageView : swapChainImageViews)
|
|
||||||
{
|
|
||||||
vkDestroyImageView(device, imageView, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
vkDestroySwapchainKHR(device, swapChainKHR, nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlumageRender::createCommandPool()
|
void PlumageRender::createCommandPool()
|
||||||
{
|
{
|
||||||
QueueFamilyIndices queueFamilyIndices = findQueueFamilies(physicalDevice);
|
|
||||||
|
|
||||||
VkCommandPoolCreateInfo poolInfo{};
|
VkCommandPoolCreateInfo poolInfo{};
|
||||||
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||||
poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||||
poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily.value();
|
poolInfo.queueFamilyIndex = vulkanDevice->queueFamilyIndices.graphics;
|
||||||
|
|
||||||
if (vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool) != VK_SUCCESS)
|
if (vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool) != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
|
@ -829,11 +567,9 @@ void PlumageRender::createFramebuffer()
|
||||||
{
|
{
|
||||||
if (settings.headless)
|
if (settings.headless)
|
||||||
{
|
{
|
||||||
auto frameRange = settings.endFrameIndex - settings.startFrameCount;
|
auto frameRange = settings.endFrameIndex - settings.startFrameCount + 1;
|
||||||
|
framebuffers.resize(frameRange);
|
||||||
if (settings.multiSampling)
|
if (settings.multiSampling)
|
||||||
{
|
|
||||||
|
|
||||||
for (int i = 0; i < frameRange; i++)
|
|
||||||
{
|
{
|
||||||
VkImageView attachments[4];
|
VkImageView attachments[4];
|
||||||
attachments[0] = multisampleTarget.colorAttachment.view;
|
attachments[0] = multisampleTarget.colorAttachment.view;
|
||||||
|
@ -849,6 +585,12 @@ void PlumageRender::createFramebuffer()
|
||||||
framebufferCreateInfo.height = settings.height;
|
framebufferCreateInfo.height = settings.height;
|
||||||
framebufferCreateInfo.layers = 1;
|
framebufferCreateInfo.layers = 1;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for (int i = 0; i < frameRange; i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
VK_CHECK_RESULT(vkCreateFramebuffer(device, &framebufferCreateInfo, nullptr, &framebuffers[i]));
|
VK_CHECK_RESULT(vkCreateFramebuffer(device, &framebufferCreateInfo, nullptr, &framebuffers[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -873,12 +615,7 @@ void PlumageRender::createFramebuffer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createImageView();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
createSwapChainFramebuffer();
|
|
||||||
createImageView();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -924,6 +661,8 @@ void PlumageRender::createSwapChainFramebuffer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void PlumageRender::createImageView()
|
void PlumageRender::createImageView()
|
||||||
{
|
{
|
||||||
VkFormat colorAttachmentFormat = VK_FORMAT_R8G8B8A8_UNORM;
|
VkFormat colorAttachmentFormat = VK_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
@ -955,11 +694,10 @@ void PlumageRender::createImageView()
|
||||||
VkMemoryAllocateInfo memAllocInfo{};
|
VkMemoryAllocateInfo memAllocInfo{};
|
||||||
memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||||
memAllocInfo.allocationSize = memReqs.size;
|
memAllocInfo.allocationSize = memReqs.size;
|
||||||
VkBool32 lazyMemTypePresent;
|
|
||||||
memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT, &lazyMemTypePresent);
|
|
||||||
if (!lazyMemTypePresent) {
|
memAllocInfo.memoryTypeIndex = getMemoryTypeIndex(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||||
memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
|
||||||
}
|
|
||||||
VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &multisampleTarget.colorAttachment.memory));
|
VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &multisampleTarget.colorAttachment.memory));
|
||||||
vkBindImageMemory(device, multisampleTarget.colorAttachment.image, multisampleTarget.colorAttachment.memory, 0);
|
vkBindImageMemory(device, multisampleTarget.colorAttachment.image, multisampleTarget.colorAttachment.memory, 0);
|
||||||
|
|
||||||
|
@ -996,10 +734,9 @@ void PlumageRender::createImageView()
|
||||||
vkGetImageMemoryRequirements(device, multisampleTarget.depthAttachment.image, &memReqs);
|
vkGetImageMemoryRequirements(device, multisampleTarget.depthAttachment.image, &memReqs);
|
||||||
memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||||
memAllocInfo.allocationSize = memReqs.size;
|
memAllocInfo.allocationSize = memReqs.size;
|
||||||
memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT, &lazyMemTypePresent);
|
|
||||||
if (!lazyMemTypePresent) {
|
memAllocInfo.memoryTypeIndex = getMemoryTypeIndex(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||||
memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
|
||||||
}
|
|
||||||
VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &multisampleTarget.depthAttachment.memory));
|
VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &multisampleTarget.depthAttachment.memory));
|
||||||
vkBindImageMemory(device, multisampleTarget.depthAttachment.image, multisampleTarget.depthAttachment.memory, 0);
|
vkBindImageMemory(device, multisampleTarget.depthAttachment.image, multisampleTarget.depthAttachment.memory, 0);
|
||||||
|
|
||||||
|
@ -1029,7 +766,7 @@ void PlumageRender::createImageView()
|
||||||
imageCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
imageCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
imageCI.tiling = VK_IMAGE_TILING_OPTIMAL;
|
imageCI.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||||
imageCI.samples = VK_SAMPLE_COUNT_1_BIT;
|
imageCI.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
imageCI.usage = VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
imageCI.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||||
imageCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
imageCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
|
||||||
VK_CHECK_RESULT(vkCreateImage(device, &imageCI, nullptr, &colorAttachment.image));
|
VK_CHECK_RESULT(vkCreateImage(device, &imageCI, nullptr, &colorAttachment.image));
|
||||||
|
@ -1040,14 +777,10 @@ void PlumageRender::createImageView()
|
||||||
VkMemoryAllocateInfo memAllocInfo{};
|
VkMemoryAllocateInfo memAllocInfo{};
|
||||||
memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||||
memAllocInfo.allocationSize = memReqs.size;
|
memAllocInfo.allocationSize = memReqs.size;
|
||||||
VkBool32 lazyMemTypePresent;
|
memAllocInfo.memoryTypeIndex = getMemoryTypeIndex(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||||
memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT, &lazyMemTypePresent);
|
|
||||||
if (!lazyMemTypePresent) {
|
|
||||||
memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
|
||||||
}
|
|
||||||
VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &colorAttachment.memory));
|
VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &colorAttachment.memory));
|
||||||
|
|
||||||
vkBindImageMemory(device, multisampleTarget.colorAttachment.image, colorAttachment.memory, 0);
|
vkBindImageMemory(device, colorAttachment.image, colorAttachment.memory, 0);
|
||||||
|
|
||||||
// Create image view for the color image
|
// Create image view for the color image
|
||||||
VkImageViewCreateInfo imageViewCI{};
|
VkImageViewCreateInfo imageViewCI{};
|
||||||
|
@ -1088,9 +821,9 @@ void PlumageRender::createImageView()
|
||||||
memAlloc.allocationSize = 0;
|
memAlloc.allocationSize = 0;
|
||||||
memAlloc.memoryTypeIndex = 0;
|
memAlloc.memoryTypeIndex = 0;
|
||||||
VkMemoryRequirements depthAttachmentMemReqs;
|
VkMemoryRequirements depthAttachmentMemReqs;
|
||||||
vkGetImageMemoryRequirements(device, depthAttachment.image, &memReqs);
|
vkGetImageMemoryRequirements(device, depthAttachment.image, &depthAttachmentMemReqs);
|
||||||
memAlloc.allocationSize = depthAttachmentMemReqs.size;
|
memAlloc.allocationSize = depthAttachmentMemReqs.size;
|
||||||
memAlloc.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
memAlloc.memoryTypeIndex = getMemoryTypeIndex(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||||
VK_CHECK_RESULT(vkAllocateMemory(device, &memAlloc, nullptr, &depthAttachment.memory));
|
VK_CHECK_RESULT(vkAllocateMemory(device, &memAlloc, nullptr, &depthAttachment.memory));
|
||||||
VK_CHECK_RESULT(vkBindImageMemory(device, depthAttachment.image, depthAttachment.memory, 0));
|
VK_CHECK_RESULT(vkBindImageMemory(device, depthAttachment.image, depthAttachment.memory, 0));
|
||||||
|
|
||||||
|
@ -1104,7 +837,7 @@ void PlumageRender::createImageView()
|
||||||
depthStencilView.image = depthAttachment.image;
|
depthStencilView.image = depthAttachment.image;
|
||||||
depthStencilView.flags = 0;
|
depthStencilView.flags = 0;
|
||||||
depthStencilView.subresourceRange = {};
|
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)
|
if (depthFormat >= VK_FORMAT_D16_UNORM_S8_UINT)
|
||||||
{
|
{
|
||||||
depthStencilView.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
depthStencilView.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||||
|
@ -1159,11 +892,13 @@ void PlumageRender::renderLoop()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
while (!glfwWindowShouldClose(window))
|
while (!glfwWindowShouldClose(window))
|
||||||
{
|
{
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
drawFrame();
|
drawFrame();
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
vkDeviceWaitIdle(device);
|
vkDeviceWaitIdle(device);
|
||||||
}
|
}
|
||||||
|
@ -1207,6 +942,7 @@ bool PlumageRender::swapChainAcquireNextImage(bool framebuffeerResized, uint32_t
|
||||||
|
|
||||||
void PlumageRender::recreateSwapChain()
|
void PlumageRender::recreateSwapChain()
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
int width = 0, height = 0;
|
int width = 0, height = 0;
|
||||||
glfwGetFramebufferSize(window, &width, &height);
|
glfwGetFramebufferSize(window, &width, &height);
|
||||||
while (width == 0 || height == 0)
|
while (width == 0 || height == 0)
|
||||||
|
@ -1225,7 +961,7 @@ void PlumageRender::recreateSwapChain()
|
||||||
|
|
||||||
createSwapChain();
|
createSwapChain();
|
||||||
createImageView();
|
createImageView();
|
||||||
createFramebuffer();
|
createFramebuffer();*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlumageRender::submitToGraphicQueue(uint32_t frameIndex, uint32_t currentBuffer)
|
void PlumageRender::submitToGraphicQueue(uint32_t frameIndex, uint32_t currentBuffer)
|
||||||
|
@ -1429,7 +1165,7 @@ void PlumageRender::buildCommandBuffers()
|
||||||
}
|
}
|
||||||
|
|
||||||
// User interface
|
// User interface
|
||||||
gui->draw(currentCB);
|
//gui->draw(currentCB);
|
||||||
|
|
||||||
vkCmdEndRenderPass(currentCB);
|
vkCmdEndRenderPass(currentCB);
|
||||||
VK_CHECK_RESULT(vkEndCommandBuffer(currentCB));
|
VK_CHECK_RESULT(vkEndCommandBuffer(currentCB));
|
||||||
|
@ -1482,7 +1218,6 @@ void PlumageRender::loadAssets()
|
||||||
|
|
||||||
readDirectory(assetpath + "environments", "*.ktx", environments, false);
|
readDirectory(assetpath + "environments", "*.ktx", environments, false);
|
||||||
|
|
||||||
textures.empty.loadFromFile(PlumageRender::filePath.emptyEnvmapFilePath, VK_FORMAT_R8G8B8A8_UNORM, vulkanDevice, graphicQueue);
|
|
||||||
|
|
||||||
std::string sceneFile = filePath.glTFModelFilePath;
|
std::string sceneFile = filePath.glTFModelFilePath;
|
||||||
std::string envMapFile = filePath.envMapFilePath;
|
std::string envMapFile = filePath.envMapFilePath;
|
||||||
|
@ -1507,9 +1242,13 @@ void PlumageRender::loadAssets()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadScene(sceneFile.c_str());
|
|
||||||
models.skybox.loadFromFile(PlumageRender::filePath.skyboxModleFilePath, vulkanDevice, graphicQueue);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
models.skybox.loadFromFile(PlumageRender::filePath.skyboxModleFilePath, vulkanDevice, graphicQueue);
|
||||||
|
loadScene(sceneFile.c_str());
|
||||||
|
|
||||||
|
textures.empty.loadFromFile(PlumageRender::filePath.emptyEnvmapFilePath, VK_FORMAT_R8G8B8A8_UNORM, vulkanDevice, graphicQueue);
|
||||||
loadEnvironment(envMapFile.c_str());
|
loadEnvironment(envMapFile.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2775,50 +2514,52 @@ void PlumageRender::updateShaderData()
|
||||||
|
|
||||||
void PlumageRender::initWindow(int Width, int Height)
|
void PlumageRender::initWindow(int Width, int Height)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
glfwInit();
|
glfwInit();
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
|
|
||||||
window = glfwCreateWindow(Width, Height, "vulkan", nullptr, nullptr);
|
window = glfwCreateWindow(Width, Height, "vulkan", nullptr, nullptr);
|
||||||
glfwSetWindowUserPointer(window, this);
|
glfwSetWindowUserPointer(window, this);
|
||||||
glfwSetFramebufferSizeCallback(window, framebufferResizeCallback);
|
glfwSetFramebufferSizeCallback(window, framebufferResizeCallback);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
void PlumageRender::framebufferResizeCallback(GLFWwindow* window, int width, int height)
|
void PlumageRender::framebufferResizeCallback(GLFWwindow* window, int width, int height)
|
||||||
{
|
{
|
||||||
auto app = reinterpret_cast<PlumageRender*>(glfwGetWindowUserPointer(window));
|
auto app = reinterpret_cast<PlumageRender*>(glfwGetWindowUserPointer(window));
|
||||||
app->framebufferResized = true;
|
app->framebufferResized = true;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
void PlumageRender::windowResized()
|
|
||||||
{
|
|
||||||
buildCommandBuffers();
|
|
||||||
vkDeviceWaitIdle(device);
|
|
||||||
updateUniformBuffers();
|
|
||||||
//update UI
|
|
||||||
updateUIOverlay();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlumageRender::prepare()
|
void PlumageRender::prepare()
|
||||||
{
|
{
|
||||||
createSwapChain();
|
//createSwapChain();
|
||||||
|
|
||||||
createCommandPool();
|
createCommandPool();
|
||||||
|
|
||||||
createRenderPass();
|
createRenderPass();
|
||||||
|
|
||||||
|
createPipelineCache();
|
||||||
|
|
||||||
|
createImageView();
|
||||||
|
createFramebuffer();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
camera.type = Camera::CameraType::lookat;
|
camera.type = Camera::CameraType::lookat;
|
||||||
|
|
||||||
camera.setPerspective(45.0f, (float)settings.width / (float)settings.height, 0.1f, 256.0f);
|
camera.setPerspective(45.0f, (float)settings.width / (float)settings.height, 0.1f, 256.0f);
|
||||||
camera.rotationSpeed = 0.25f;
|
camera.rotationSpeed = 0.25f;
|
||||||
camera.movementSpeed = 0.1f;
|
camera.movementSpeed = 0.1f;
|
||||||
|
|
||||||
|
auto frameRanges = settings.endFrameIndex - settings.startFrameCount + 1;
|
||||||
waitFences.resize(renderAhead);
|
waitFences.resize(renderAhead);
|
||||||
presentCompleteSemaphores.resize(renderAhead);
|
presentCompleteSemaphores.resize(renderAhead);
|
||||||
renderCompleteSemaphores.resize(renderAhead);
|
renderCompleteSemaphores.resize(renderAhead);
|
||||||
commandBuffers.resize(swapChainImages.size());
|
commandBuffers.resize(frameRanges);
|
||||||
uniformBuffers.resize(swapChainImages.size());
|
uniformBuffers.resize(frameRanges);
|
||||||
descriptorSets.resize(swapChainImages.size());
|
descriptorSets.resize(frameRanges);
|
||||||
// Command buffer execution fences
|
// Command buffer execution fences
|
||||||
for (auto& waitFence : waitFences) {
|
for (auto& waitFence : waitFences) {
|
||||||
VkFenceCreateInfo fenceCI{ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, VK_FENCE_CREATE_SIGNALED_BIT };
|
VkFenceCreateInfo fenceCI{ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, VK_FENCE_CREATE_SIGNALED_BIT };
|
||||||
|
@ -2843,6 +2584,8 @@ void PlumageRender::prepare()
|
||||||
VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, commandBuffers.data()));
|
VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, commandBuffers.data()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
loadAssets();
|
loadAssets();
|
||||||
generateBRDFLUT();
|
generateBRDFLUT();
|
||||||
generateCubemaps();
|
generateCubemaps();
|
||||||
|
@ -2850,26 +2593,15 @@ void PlumageRender::prepare()
|
||||||
setupDescriptors();
|
setupDescriptors();
|
||||||
preparePipelines();
|
preparePipelines();
|
||||||
|
|
||||||
gui = new UI(vulkanDevice, renderPass, graphicQueue, pipelineCache, settings.sampleCount);
|
//gui = new UI(vulkanDevice, renderPass, graphicQueue, pipelineCache, settings.sampleCount);
|
||||||
updateUIOverlay();
|
//updateUIOverlay();
|
||||||
|
|
||||||
buildCommandBuffers();
|
buildCommandBuffers();
|
||||||
|
|
||||||
prepared = true;
|
prepared = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlumageRender::submitWork(VkCommandBuffer cmdBuffer, VkQueue queue)
|
|
||||||
{
|
|
||||||
VkSubmitInfo submitInfo = vks::initializers::submitInfo();
|
|
||||||
submitInfo.commandBufferCount = 1;
|
|
||||||
submitInfo.pCommandBuffers = &cmdBuffer;
|
|
||||||
VkFenceCreateInfo fenceInfo = vks::initializers::fenceCreateInfo();
|
|
||||||
VkFence fence;
|
|
||||||
VK_CHECK_RESULT(vkCreateFence(device, &fenceInfo, nullptr, &fence));
|
|
||||||
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, fence));
|
|
||||||
VK_CHECK_RESULT(vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX));
|
|
||||||
vkDestroyFence(device, fence, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// todo :根据physicalDeviceIndex确定子文件夹路径,frameIndex确定fileName
|
// todo :根据physicalDeviceIndex确定子文件夹路径,frameIndex确定fileName
|
||||||
void PlumageRender::writeImageToFile(std::string filePath)
|
void PlumageRender::writeImageToFile(std::string filePath)
|
||||||
|
@ -2896,11 +2628,10 @@ void PlumageRender::writeImageToFile(std::string filePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Source for the copy is the last rendered swapchain image
|
// Source for the copy is the last rendered swapchain image
|
||||||
if (settings.headless)
|
|
||||||
{
|
|
||||||
VkImage srcImage = colorAttachment.image;
|
VkImage srcImage = colorAttachment.image;
|
||||||
}
|
|
||||||
VkImage srcImage = swapChainImages[currentBuffer];
|
//VkImage srcImage = swapChainImages[currentBuffer];
|
||||||
|
|
||||||
// Create the linear tiled destination image to copy to and to read the memory from
|
// Create the linear tiled destination image to copy to and to read the memory from
|
||||||
VkImageCreateInfo imageCreateCI(vks::initializers::imageCreateInfo());
|
VkImageCreateInfo imageCreateCI(vks::initializers::imageCreateInfo());
|
||||||
|
@ -3238,10 +2969,11 @@ void PlumageRender::render()
|
||||||
|
|
||||||
uint32_t imageIndex;
|
uint32_t imageIndex;
|
||||||
|
|
||||||
|
/*
|
||||||
if (settings.headless)
|
if (settings.headless)
|
||||||
{
|
{
|
||||||
updateUIOverlay();
|
updateUIOverlay();
|
||||||
}
|
}*/
|
||||||
|
|
||||||
//加入写到文件的函数
|
//加入写到文件的函数
|
||||||
//swapChainImage = swapChain.images[frameIndex];
|
//swapChainImage = swapChain.images[frameIndex];
|
||||||
|
@ -3252,10 +2984,11 @@ void PlumageRender::render()
|
||||||
|
|
||||||
VK_CHECK_RESULT(vkWaitForFences(device, 1, &waitFences[frameIndex], VK_TRUE, UINT64_MAX));
|
VK_CHECK_RESULT(vkWaitForFences(device, 1, &waitFences[frameIndex], VK_TRUE, UINT64_MAX));
|
||||||
|
|
||||||
framebufferResized = swapChainAcquireNextImage(framebufferResized, imageIndex, frameIndex);
|
//framebufferResized = swapChainAcquireNextImage(framebufferResized, imageIndex, frameIndex);
|
||||||
|
outputImageSequence();
|
||||||
|
|
||||||
VK_CHECK_RESULT(vkResetFences(device, 1, &waitFences[frameIndex]));
|
VK_CHECK_RESULT(vkResetFences(device, 1, &waitFences[frameIndex]));
|
||||||
outputImageSequence();
|
|
||||||
imageSequenceToVideo();
|
imageSequenceToVideo();
|
||||||
|
|
||||||
// Update UBOs
|
// Update UBOs
|
||||||
|
@ -3267,7 +3000,7 @@ void PlumageRender::render()
|
||||||
|
|
||||||
submitToGraphicQueue(frameIndex,currentBuffer);
|
submitToGraphicQueue(frameIndex,currentBuffer);
|
||||||
|
|
||||||
imageToQueuePresent(frameIndex, imageIndex, framebufferResized);
|
//imageToQueuePresent(frameIndex, imageIndex, framebufferResized);
|
||||||
|
|
||||||
|
|
||||||
frameIndex += 1;
|
frameIndex += 1;
|
||||||
|
@ -3346,7 +3079,7 @@ void PlumageRender::destroyVulkan()
|
||||||
textures.empty.destroy();
|
textures.empty.destroy();
|
||||||
delete gui;
|
delete gui;
|
||||||
// Clean up Vulkan resources
|
// Clean up Vulkan resources
|
||||||
cleanupSwapChain();
|
|
||||||
vkDestroyDescriptorPool(device, descriptorPool, nullptr);
|
vkDestroyDescriptorPool(device, descriptorPool, nullptr);
|
||||||
vkDestroyRenderPass(device, renderPass, nullptr);
|
vkDestroyRenderPass(device, renderPass, nullptr);
|
||||||
for (uint32_t i = 0; i < framebuffers.size(); i++) {
|
for (uint32_t i = 0; i < framebuffers.size(); i++) {
|
||||||
|
@ -3370,7 +3103,7 @@ void PlumageRender::destroyVulkan()
|
||||||
}
|
}
|
||||||
delete vulkanDevice;
|
delete vulkanDevice;
|
||||||
if (settings.validation) {
|
if (settings.validation) {
|
||||||
DestroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr);
|
vkDestroyDebugReportCallback(instance, debugReportCallback, nullptr);
|
||||||
}
|
}
|
||||||
vkDestroyInstance(instance, nullptr);
|
vkDestroyInstance(instance, nullptr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
#define GLFW_INCLUDE_VULKAN
|
#define GLFW_INCLUDE_VULKAN
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
|
#include <stdexcept>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
@ -30,15 +30,15 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <cstdint>
|
#include <cstdlib>
|
||||||
#include <stdexcept>
|
|
||||||
//
|
//
|
||||||
#include <commdlg.h>
|
#include <commdlg.h>
|
||||||
|
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
//#include "VulkanExampleBase.h"
|
//#include "VulkanExampleBase.h"
|
||||||
#include "glTFModel.h"
|
#include "glTFModel.h"
|
||||||
#include <VulkanTexture.hpp>
|
#include <VulkanTexture.h>
|
||||||
#include "VulkanDevice.hpp"
|
#include "VulkanDevice.hpp"
|
||||||
#include "ui.hpp"
|
#include "ui.hpp"
|
||||||
#include <VulkanUtils.hpp>
|
#include <VulkanUtils.hpp>
|
||||||
|
@ -46,12 +46,6 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define ENABLE_VALIDATION false
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class PlumageRender
|
class PlumageRender
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -60,6 +54,10 @@ public:
|
||||||
bool ToneMapping = true;
|
bool ToneMapping = true;
|
||||||
bool pbrEnabled = true;
|
bool pbrEnabled = true;
|
||||||
|
|
||||||
|
PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallback;
|
||||||
|
PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallback;
|
||||||
|
VkDebugReportCallbackEXT debugReportCallback;
|
||||||
|
|
||||||
std::vector<const char*> args;
|
std::vector<const char*> args;
|
||||||
|
|
||||||
GLFWwindow* window;
|
GLFWwindow* window;
|
||||||
|
@ -74,8 +72,9 @@ public:
|
||||||
//"VK_EXT_headless_surface"
|
//"VK_EXT_headless_surface"
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string title;
|
std::string title = "render";
|
||||||
std::string name = "plumage";
|
std::string name = "plumage";
|
||||||
|
VkInstance instance;
|
||||||
Camera camera;
|
Camera camera;
|
||||||
|
|
||||||
VkPhysicalDevice physicalDevice;
|
VkPhysicalDevice physicalDevice;
|
||||||
|
@ -159,7 +158,7 @@ public:
|
||||||
|
|
||||||
}chineseUI;
|
}chineseUI;
|
||||||
|
|
||||||
VkInstance instance;
|
|
||||||
|
|
||||||
struct UniformBufferSet {
|
struct UniformBufferSet {
|
||||||
Buffer scene;
|
Buffer scene;
|
||||||
|
@ -251,9 +250,9 @@ public:
|
||||||
bool validation = true; // 校验层开关
|
bool validation = true; // 校验层开关
|
||||||
bool fullscreen = false; // 全屏开关
|
bool fullscreen = false; // 全屏开关
|
||||||
bool vsync = false; // 垂直同步开关
|
bool vsync = false; // 垂直同步开关
|
||||||
bool multiSampling = true; // 多重采样
|
bool multiSampling = false; // 多重采样
|
||||||
bool rotateModel = true; // 模型自旋转(暂时失效)
|
bool rotateModel = true; // 模型自旋转(暂时失效)
|
||||||
bool headless = false; // 无头开关
|
bool headless = true; // 无头开关
|
||||||
bool outputPNGimage = false;
|
bool outputPNGimage = false;
|
||||||
uint32_t endFrameIndex = 75;
|
uint32_t endFrameIndex = 75;
|
||||||
bool enableSaveToImageSequeue = true; // 图片序列开关(暂时弃用)
|
bool enableSaveToImageSequeue = true; // 图片序列开关(暂时弃用)
|
||||||
|
@ -395,20 +394,7 @@ public:
|
||||||
|
|
||||||
VkCommandPool commandPool;
|
VkCommandPool commandPool;
|
||||||
|
|
||||||
struct QueueFamilyIndices
|
|
||||||
{
|
|
||||||
std::optional<uint32_t> graphicsFamily;
|
|
||||||
std::optional<uint32_t> presentFamily;
|
|
||||||
|
|
||||||
bool isGraphicsFamilyComplete()
|
|
||||||
{
|
|
||||||
return graphicsFamily.has_value();
|
|
||||||
}
|
|
||||||
bool isPresentFamilyComplete()
|
|
||||||
{
|
|
||||||
return presentFamily.has_value();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SwapChainSupportDetails
|
struct SwapChainSupportDetails
|
||||||
{
|
{
|
||||||
|
@ -474,25 +460,21 @@ public:
|
||||||
std::vector<const char*> getRequiredExtensions();
|
std::vector<const char*> getRequiredExtensions();
|
||||||
void setupDebugMessager();
|
void setupDebugMessager();
|
||||||
void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& debugCreateInfo);
|
void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& debugCreateInfo);
|
||||||
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
|
static VKAPI_ATTR VkBool32 VKAPI_CALL debugMessageCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg, void* pUserData);
|
||||||
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
|
||||||
VkDebugUtilsMessageTypeFlagsEXT messageTypes,
|
|
||||||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
|
||||||
void* pUserData);
|
|
||||||
VkResult CreateDebugUtilsMessengerEXT(
|
VkResult CreateDebugUtilsMessengerEXT(
|
||||||
VkInstance instance,
|
VkInstance instance,
|
||||||
const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
|
const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
|
||||||
const VkAllocationCallbacks* pAllocator,
|
const VkAllocationCallbacks* pAllocator,
|
||||||
VkDebugUtilsMessengerEXT* pDebugMessenger);
|
VkDebugUtilsMessengerEXT* pDebugMessenger);
|
||||||
|
|
||||||
void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, const VkAllocationCallbacks* pAllocator);
|
|
||||||
|
|
||||||
void createSurface();
|
void createSurface();
|
||||||
|
|
||||||
void pickupPhysicalDevice();
|
void pickupPhysicalDevice();
|
||||||
bool isDeviceSuitable(VkPhysicalDevice device);
|
bool isDeviceSuitable(VkPhysicalDevice device);
|
||||||
bool checkDeviceExtensionSupport(VkPhysicalDevice device);
|
bool checkDeviceExtensionSupport(VkPhysicalDevice device);
|
||||||
QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device);
|
|
||||||
SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device);
|
SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device);
|
||||||
|
|
||||||
// 创建程序使用的逻辑设备
|
// 创建程序使用的逻辑设备
|
||||||
|
@ -505,7 +487,7 @@ public:
|
||||||
VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats);
|
VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats);
|
||||||
VkPresentModeKHR chooseSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes);
|
VkPresentModeKHR chooseSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes);
|
||||||
VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities);
|
VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities);
|
||||||
void cleanupSwapChain();
|
|
||||||
|
|
||||||
void createCommandPool();
|
void createCommandPool();
|
||||||
|
|
||||||
|
@ -516,6 +498,9 @@ public:
|
||||||
|
|
||||||
void createPipelineCache();
|
void createPipelineCache();
|
||||||
|
|
||||||
|
uint32_t getMemoryTypeIndex(uint32_t typeBits, VkMemoryPropertyFlags properties);
|
||||||
|
|
||||||
|
|
||||||
void createFramebuffer();
|
void createFramebuffer();
|
||||||
void createSwapChainFramebuffer();
|
void createSwapChainFramebuffer();
|
||||||
void createImageView();
|
void createImageView();
|
||||||
|
@ -548,7 +533,6 @@ public:
|
||||||
void updateUniformBuffers();
|
void updateUniformBuffers();
|
||||||
void updateShaderData();
|
void updateShaderData();
|
||||||
void initWindow(int Width,int Height);
|
void initWindow(int Width,int Height);
|
||||||
static void framebufferResizeCallback(GLFWwindow* window, int width, int height);
|
|
||||||
|
|
||||||
void windowResized();
|
void windowResized();
|
||||||
void submitWork(VkCommandBuffer cmdBuffer, VkQueue queue);
|
void submitWork(VkCommandBuffer cmdBuffer, VkQueue queue);
|
||||||
|
@ -558,7 +542,7 @@ public:
|
||||||
void imageSequenceToVideo();
|
void imageSequenceToVideo();
|
||||||
void removeImageSequence();
|
void removeImageSequence();
|
||||||
//void outputScreenShot();
|
//void outputScreenShot();
|
||||||
uint32_t getMemoryTypeIndex(uint32_t typeBits, VkMemoryPropertyFlags properties);
|
|
||||||
virtual void render();
|
virtual void render();
|
||||||
virtual void updateUIOverlay();
|
virtual void updateUIOverlay();
|
||||||
virtual void fileDropped(std::string filename);
|
virtual void fileDropped(std::string filename);
|
||||||
|
|
Loading…
Reference in New Issue