调整结构
parent
98335c7edc
commit
907b94dcdd
|
|
@ -3,6 +3,7 @@ AccessModifierOffset: -4
|
||||||
AlignConsecutiveMacros: true
|
AlignConsecutiveMacros: true
|
||||||
AlignTrailingComments: true
|
AlignTrailingComments: true
|
||||||
AllowShortFunctionsOnASingleLine: Inline
|
AllowShortFunctionsOnASingleLine: Inline
|
||||||
AllowShortIfStatementsOnASingleLine: false
|
AllowShortIfStatementsOnASingleLine: true
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: true
|
||||||
BreakBeforeBraces: Allman
|
BreakBeforeBraces: Allman
|
||||||
ColumnLimit: 0
|
ColumnLimit: 0
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
// 使用 IntelliSense 了解相关属性。
|
||||||
|
// 悬停以查看现有属性的描述。
|
||||||
|
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Launch",
|
||||||
|
"type": "lldb",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceRoot}/<your program>",
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceRoot}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,756 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
* vulkan 贴图基础封装类
|
||||||
|
* 普通贴图使用stbi加载
|
||||||
|
* ktx格式cubeMap贴图使用ktx库加载
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef VULKANTEXTURE_HPP
|
||||||
|
#define VULKANTEXTURE_HPP
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <corecrt.h>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <fstream>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "VulkanDevice.hpp"
|
||||||
|
#include "VulkanTools.h"
|
||||||
|
#include "ktx.h"
|
||||||
|
#include "stb_image.h"
|
||||||
|
|
||||||
|
#define GLM_ENABLE_EXPERIMENTAL
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
int texWidth, texHeight, texChannels;
|
||||||
|
unsigned char *texImageData = stbi_load(filename.c_str(), &texWidth, &texHeight, &texChannels, 0);
|
||||||
|
|
||||||
|
assert(texImageData == nullptr);
|
||||||
|
|
||||||
|
this->device = device;
|
||||||
|
width = static_cast<uint32_t>(texWidth);
|
||||||
|
height = static_cast<uint32_t>(texHeight);
|
||||||
|
// stb image 不自动生成mipmap层级,使用公式计算
|
||||||
|
mipLevels = static_cast<uint32_t>(std::floor(std::log2(std::max(this->width, this->height)))) + 1;
|
||||||
|
size_t texImageSize = texWidth * texHeight * texChannels;
|
||||||
|
|
||||||
|
// 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 = texImageSize;
|
||||||
|
// 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, texImageData, texImageSize);
|
||||||
|
vkUnmapMemory(device->logicalDevice, stagingMemory);
|
||||||
|
|
||||||
|
// clean up image data
|
||||||
|
stbi_image_free(texImageData);
|
||||||
|
|
||||||
|
// 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 = 1;
|
||||||
|
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_IMAGE_USAGE_TRANSFER_SRC_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 = 1; // 目前只处理第一级
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
// Copy mip levels from staging buffer
|
||||||
|
vkCmdCopyBufferToImage(
|
||||||
|
copyCmd,
|
||||||
|
stagingBuffer,
|
||||||
|
image,
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
|
static_cast<uint32_t>(1),
|
||||||
|
&bufferCopyRegion);
|
||||||
|
|
||||||
|
generateMipmaps(copyCmd, format);
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void generateMipmaps(VkCommandBuffer commandBuffer, VkFormat format)
|
||||||
|
{
|
||||||
|
VkFormatProperties formatProperties;
|
||||||
|
vkGetPhysicalDeviceFormatProperties(device->physicalDevice, format, &formatProperties);
|
||||||
|
|
||||||
|
if (!(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT))
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Texture image format does not support linear blitting!");
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImageMemoryBarrier imageMemoryBarrier{};
|
||||||
|
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||||
|
imageMemoryBarrier.image = image;
|
||||||
|
imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
|
imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
|
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
imageMemoryBarrier.subresourceRange.layerCount = 1;
|
||||||
|
imageMemoryBarrier.subresourceRange.levelCount = 1;
|
||||||
|
|
||||||
|
uint32_t mipWidth = width;
|
||||||
|
uint32_t mipHeight = height;
|
||||||
|
|
||||||
|
for (uint32_t i = 1; i < mipLevels; i++)
|
||||||
|
{
|
||||||
|
imageMemoryBarrier.subresourceRange.baseMipLevel = i - 1;
|
||||||
|
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||||
|
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||||
|
imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||||
|
imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
|
|
||||||
|
vkCmdPipelineBarrier(commandBuffer,
|
||||||
|
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
|
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
nullptr,
|
||||||
|
0,
|
||||||
|
nullptr,
|
||||||
|
1,
|
||||||
|
&imageMemoryBarrier);
|
||||||
|
|
||||||
|
VkImageBlit blit{};
|
||||||
|
blit.srcOffsets[0] = {0, 0, 0};
|
||||||
|
blit.srcOffsets[1] = {static_cast<int32_t>(mipWidth), static_cast<int32_t>(mipHeight), 1};
|
||||||
|
blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
blit.srcSubresource.mipLevel = i - 1;
|
||||||
|
blit.srcSubresource.baseArrayLayer = 0;
|
||||||
|
blit.srcSubresource.layerCount = 1;
|
||||||
|
blit.dstOffsets[0] = {0, 0, 0};
|
||||||
|
int32_t dstOffsetX = 1;
|
||||||
|
int32_t dstOffsetY = 1;
|
||||||
|
if (mipWidth > 1)
|
||||||
|
{
|
||||||
|
dstOffsetX = static_cast<int32_t>(mipWidth / 2);
|
||||||
|
}
|
||||||
|
if (mipHeight > 1)
|
||||||
|
{
|
||||||
|
dstOffsetY = static_cast<int32_t>(mipHeight / 2);
|
||||||
|
}
|
||||||
|
blit.dstOffsets[1] = {dstOffsetX, dstOffsetY, 1};
|
||||||
|
blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
blit.dstSubresource.mipLevel = i;
|
||||||
|
blit.dstSubresource.baseArrayLayer = 0;
|
||||||
|
blit.dstSubresource.layerCount = 1;
|
||||||
|
|
||||||
|
vkCmdBlitImage(commandBuffer,
|
||||||
|
image,
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||||
|
image,
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
|
1,
|
||||||
|
&blit, VK_FILTER_LINEAR);
|
||||||
|
|
||||||
|
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||||
|
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||||
|
imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||||
|
imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
|
|
||||||
|
vkCmdPipelineBarrier(commandBuffer,
|
||||||
|
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
|
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
nullptr,
|
||||||
|
0,
|
||||||
|
nullptr,
|
||||||
|
1,
|
||||||
|
&imageMemoryBarrier);
|
||||||
|
|
||||||
|
if (mipWidth > 1)
|
||||||
|
{
|
||||||
|
mipWidth = mipWidth / 2;
|
||||||
|
}
|
||||||
|
if (mipHeight > 1)
|
||||||
|
{
|
||||||
|
mipHeight = mipHeight / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
imageMemoryBarrier.subresourceRange.baseMipLevel = 0;
|
||||||
|
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||||
|
imageMemoryBarrier.newLayout = imageLayout;
|
||||||
|
imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
|
imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
|
imageMemoryBarrier.subresourceRange.levelCount = mipLevels;
|
||||||
|
|
||||||
|
vkCmdPipelineBarrier(commandBuffer,
|
||||||
|
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
|
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
nullptr,
|
||||||
|
0,
|
||||||
|
nullptr,
|
||||||
|
1,
|
||||||
|
&imageMemoryBarrier);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
ktxTexture *cubeMapTexture = nullptr;
|
||||||
|
KTX_error_code ktxResult = ktxTexture_CreateFromNamedFile(filename.c_str(), KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT, &cubeMapTexture);
|
||||||
|
if (ktxResult != KTX_SUCCESS)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Failed to load KTX texture");
|
||||||
|
}
|
||||||
|
|
||||||
|
this->device = device;
|
||||||
|
width = static_cast<uint32_t>(cubeMapTexture->baseWidth);
|
||||||
|
height = static_cast<uint32_t>(cubeMapTexture->baseHeight);
|
||||||
|
mipLevels = cubeMapTexture->numLevels;
|
||||||
|
layerCount = cubeMapTexture->numLayers;
|
||||||
|
|
||||||
|
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 = cubeMapTexture->dataSize;
|
||||||
|
|
||||||
|
// 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, ktxTexture_GetData(cubeMapTexture), cubeMapTexture->dataSize);
|
||||||
|
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++)
|
||||||
|
{
|
||||||
|
ktx_size_t offset;
|
||||||
|
KTX_error_code result = ktxTexture_GetImageOffset(
|
||||||
|
cubeMapTexture,
|
||||||
|
level, // mip level
|
||||||
|
0, // array layer
|
||||||
|
face, // face
|
||||||
|
&offset);
|
||||||
|
|
||||||
|
if (result != KTX_SUCCESS)
|
||||||
|
{
|
||||||
|
ktxTexture_Destroy(cubeMapTexture);
|
||||||
|
throw std::runtime_error("Failed to get image offset from KTX texture");
|
||||||
|
}
|
||||||
|
|
||||||
|
VkBufferImageCopy bufferCopyRegion = {};
|
||||||
|
bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
bufferCopyRegion.imageSubresource.mipLevel = level;
|
||||||
|
bufferCopyRegion.imageSubresource.baseArrayLayer = face;
|
||||||
|
bufferCopyRegion.imageSubresource.layerCount = 1;
|
||||||
|
|
||||||
|
uint32_t mipWidth = std::max(1u, width >> level);
|
||||||
|
uint32_t mipHeight = std::max(1u, height >> level);
|
||||||
|
|
||||||
|
bufferCopyRegion.imageExtent.width = mipWidth;
|
||||||
|
bufferCopyRegion.imageExtent.height = mipHeight;
|
||||||
|
bufferCopyRegion.imageExtent.depth = 1;
|
||||||
|
bufferCopyRegion.bufferOffset = offset;
|
||||||
|
|
||||||
|
bufferCopyRegions.push_back(bufferCopyRegion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace vks
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -15,8 +15,6 @@ set(GLTF_MODEL_LOADER
|
||||||
"gltf/glTFBoundingBox.cpp"
|
"gltf/glTFBoundingBox.cpp"
|
||||||
"gltf/glTFTexture.h"
|
"gltf/glTFTexture.h"
|
||||||
"gltf/glTFTexture.cpp"
|
"gltf/glTFTexture.cpp"
|
||||||
#"gltf/glTFModel.h"
|
|
||||||
#"gltf/glTFModel.cpp"
|
|
||||||
"gltf/glTFMaterial.h"
|
"gltf/glTFMaterial.h"
|
||||||
"gltf/glTFMaterial.cpp"
|
"gltf/glTFMaterial.cpp"
|
||||||
"gltf/glTFPrimitive.h"
|
"gltf/glTFPrimitive.h"
|
||||||
|
|
@ -35,12 +33,12 @@ set(GLTF_MODEL_LOADER
|
||||||
"gltf/glTFAnimation.cpp"
|
"gltf/glTFAnimation.cpp"
|
||||||
"gltf/glTFMainModel.h"
|
"gltf/glTFMainModel.h"
|
||||||
"gltf/glTFMainModel.cpp"
|
"gltf/glTFMainModel.cpp"
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
aux_source_directory(${PROJECT_SOURCE_DIR}/src/render VULKAN_BASE)
|
aux_source_directory(${PROJECT_SOURCE_DIR}/src/render VULKAN_BASE)
|
||||||
|
aux_source_directory(${PROJECT_SOURCE_DIR}/src/pbr PBR)
|
||||||
|
|
||||||
#include_directories(${3rdParty_gli_path})
|
#include_directories(${3rdParty_gli_path})
|
||||||
include_directories(${3rdParty_glm_path})
|
include_directories(${3rdParty_glm_path})
|
||||||
|
|
@ -65,6 +63,7 @@ if(WIN32)
|
||||||
${MAIN_FILE}
|
${MAIN_FILE}
|
||||||
${GLTF_MODEL_LOADER}
|
${GLTF_MODEL_LOADER}
|
||||||
${VULKAN_BASE}
|
${VULKAN_BASE}
|
||||||
|
${PBR}
|
||||||
|
|
||||||
"render/renderFoundation.h"
|
"render/renderFoundation.h"
|
||||||
"render/renderFoundation.cpp"
|
"render/renderFoundation.cpp"
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,10 @@ file(GLOB BASE_SRC "*.cpp" "*.h" "${3rdParty_imgui_path}/*.cpp" )
|
||||||
include_directories(${3rdParty_ktx_path})
|
include_directories(${3rdParty_ktx_path})
|
||||||
include_directories(${3rdParty_ktx_otherInclude_path})
|
include_directories(${3rdParty_ktx_otherInclude_path})
|
||||||
include_directories(${3rdParty_glm_path})
|
include_directories(${3rdParty_glm_path})
|
||||||
include_directories(${3rdParty_gli_path})
|
include_directories(${3rdParty_stb_path})
|
||||||
include_directories(${3rdParty_vulkan_path})
|
include_directories(${3rdParty_vulkan_path})
|
||||||
include_directories(${3rdParty_imgui_path})
|
include_directories(${3rdParty_imgui_path})
|
||||||
|
|
||||||
message("======================debug=====================")
|
|
||||||
message(${BASE_SRC})
|
|
||||||
|
|
||||||
add_library(base STATIC ${BASE_SRC} ${KTX_SOURCES})
|
add_library(base STATIC ${BASE_SRC} ${KTX_SOURCES})
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
|
|
|
||||||
|
|
@ -1,135 +1,137 @@
|
||||||
/*
|
|
||||||
* Vulkan buffer class
|
|
||||||
*
|
|
||||||
* Encapsulates a Vulkan buffer
|
|
||||||
*
|
|
||||||
* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
|
|
||||||
*
|
|
||||||
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "VulkanBuffer.h"
|
#include "VulkanBuffer.h"
|
||||||
|
#include "VulkanTools.h"
|
||||||
|
|
||||||
namespace vks
|
VULKANBASE_NAMESPACE_BEGIN
|
||||||
{
|
/**
|
||||||
/**
|
* Map a memory range of this buffer. If successful, mapped points to the specified buffer range.
|
||||||
* Map a memory range of this buffer. If successful, mapped points to the specified buffer range.
|
*
|
||||||
*
|
* @param size (Optional) Size of the memory range to map. Pass VK_WHOLE_SIZE to map the complete buffer range.
|
||||||
* @param size (Optional) Size of the memory range to map. Pass VK_WHOLE_SIZE to map the complete buffer range.
|
* @param offset (Optional) Byte offset from beginning
|
||||||
* @param offset (Optional) Byte offset from beginning
|
*
|
||||||
*
|
* @return VkResult of the buffer mapping call
|
||||||
* @return VkResult of the buffer mapping call
|
*/
|
||||||
*/
|
VkResult Buffer::map(VkDeviceSize size, VkDeviceSize offset)
|
||||||
VkResult Buffer::map(VkDeviceSize size, VkDeviceSize offset)
|
{
|
||||||
{
|
return vkMapMemory(device, memory, offset, size, 0, &mapped);
|
||||||
return vkMapMemory(device, memory, offset, size, 0, &mapped);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unmap a mapped memory range
|
* Unmap a mapped memory range
|
||||||
*
|
*
|
||||||
* @note Does not return a result as vkUnmapMemory can't fail
|
* @note Does not return a result as vkUnmapMemory can't fail
|
||||||
*/
|
*/
|
||||||
void Buffer::unmap()
|
void Buffer::unmap()
|
||||||
{
|
{
|
||||||
if (mapped)
|
if (mapped)
|
||||||
{
|
{
|
||||||
vkUnmapMemory(device, memory);
|
vkUnmapMemory(device, memory);
|
||||||
mapped = nullptr;
|
mapped = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attach the allocated memory block to the buffer
|
* Attach the allocated memory block to the buffer
|
||||||
*
|
*
|
||||||
* @param offset (Optional) Byte offset (from the beginning) for the memory region to bind
|
* @param offset (Optional) Byte offset (from the beginning) for the memory region to bind
|
||||||
*
|
*
|
||||||
* @return VkResult of the bindBufferMemory call
|
* @return VkResult of the bindBufferMemory call
|
||||||
*/
|
*/
|
||||||
VkResult Buffer::bind(VkDeviceSize offset)
|
VkResult Buffer::bind(VkDeviceSize offset)
|
||||||
{
|
{
|
||||||
return vkBindBufferMemory(device, buffer, memory, offset);
|
return vkBindBufferMemory(device, buffer, memory, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup the default descriptor for this buffer
|
* Setup the default descriptor for this buffer
|
||||||
*
|
*
|
||||||
* @param size (Optional) Size of the memory range of the descriptor
|
* @param size (Optional) Size of the memory range of the descriptor
|
||||||
* @param offset (Optional) Byte offset from beginning
|
* @param offset (Optional) Byte offset from beginning
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void Buffer::setupDescriptor(VkDeviceSize size, VkDeviceSize offset)
|
void Buffer::setupDescriptor(VkDeviceSize size, VkDeviceSize offset)
|
||||||
{
|
{
|
||||||
descriptor.offset = offset;
|
descriptor.offset = offset;
|
||||||
descriptor.buffer = buffer;
|
descriptor.buffer = buffer;
|
||||||
descriptor.range = size;
|
descriptor.range = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copies the specified data to the mapped buffer
|
* Copies the specified data to the mapped buffer
|
||||||
*
|
*
|
||||||
* @param data Pointer to the data to copy
|
* @param data Pointer to the data to copy
|
||||||
* @param size Size of the data to copy in machine units
|
* @param size Size of the data to copy in machine units
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void Buffer::copyTo(void* data, VkDeviceSize size)
|
void Buffer::copyTo(void *data, VkDeviceSize size)
|
||||||
{
|
{
|
||||||
assert(mapped);
|
assert(mapped);
|
||||||
memcpy(mapped, data, size);
|
memcpy(mapped, data, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flush a memory range of the buffer to make it visible to the device
|
* Flush a memory range of the buffer to make it visible to the device
|
||||||
*
|
*
|
||||||
* @note Only required for non-coherent memory
|
* @note Only required for non-coherent memory
|
||||||
*
|
*
|
||||||
* @param size (Optional) Size of the memory range to flush. Pass VK_WHOLE_SIZE to flush the complete buffer range.
|
* @param size (Optional) Size of the memory range to flush. Pass VK_WHOLE_SIZE to flush the complete buffer range.
|
||||||
* @param offset (Optional) Byte offset from beginning
|
* @param offset (Optional) Byte offset from beginning
|
||||||
*
|
*
|
||||||
* @return VkResult of the flush call
|
* @return VkResult of the flush call
|
||||||
*/
|
*/
|
||||||
VkResult Buffer::flush(VkDeviceSize size, VkDeviceSize offset)
|
VkResult Buffer::flush(VkDeviceSize size, VkDeviceSize offset)
|
||||||
{
|
{
|
||||||
VkMappedMemoryRange mappedRange = {};
|
VkMappedMemoryRange mappedRange = {};
|
||||||
mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
|
mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
|
||||||
mappedRange.memory = memory;
|
mappedRange.memory = memory;
|
||||||
mappedRange.offset = offset;
|
mappedRange.offset = offset;
|
||||||
mappedRange.size = size;
|
mappedRange.size = size;
|
||||||
return vkFlushMappedMemoryRanges(device, 1, &mappedRange);
|
return vkFlushMappedMemoryRanges(device, 1, &mappedRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invalidate a memory range of the buffer to make it visible to the host
|
* Invalidate a memory range of the buffer to make it visible to the host
|
||||||
*
|
*
|
||||||
* @note Only required for non-coherent memory
|
* @note Only required for non-coherent memory
|
||||||
*
|
*
|
||||||
* @param size (Optional) Size of the memory range to invalidate. Pass VK_WHOLE_SIZE to invalidate the complete buffer range.
|
* @param size (Optional) Size of the memory range to invalidate. Pass VK_WHOLE_SIZE to invalidate the complete buffer range.
|
||||||
* @param offset (Optional) Byte offset from beginning
|
* @param offset (Optional) Byte offset from beginning
|
||||||
*
|
*
|
||||||
* @return VkResult of the invalidate call
|
* @return VkResult of the invalidate call
|
||||||
*/
|
*/
|
||||||
VkResult Buffer::invalidate(VkDeviceSize size, VkDeviceSize offset)
|
VkResult Buffer::invalidate(VkDeviceSize size, VkDeviceSize offset)
|
||||||
{
|
{
|
||||||
VkMappedMemoryRange mappedRange = {};
|
VkMappedMemoryRange mappedRange = {};
|
||||||
mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
|
mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
|
||||||
mappedRange.memory = memory;
|
mappedRange.memory = memory;
|
||||||
mappedRange.offset = offset;
|
mappedRange.offset = offset;
|
||||||
mappedRange.size = size;
|
mappedRange.size = size;
|
||||||
return vkInvalidateMappedMemoryRanges(device, 1, &mappedRange);
|
return vkInvalidateMappedMemoryRanges(device, 1, &mappedRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Release all Vulkan resources held by this buffer
|
* Release all Vulkan resources held by this buffer
|
||||||
*/
|
*/
|
||||||
void Buffer::destroy()
|
void Buffer::destroy()
|
||||||
{
|
{
|
||||||
if (buffer)
|
if (mapped)
|
||||||
{
|
{
|
||||||
vkDestroyBuffer(device, buffer, nullptr);
|
unmap();
|
||||||
}
|
}
|
||||||
if (memory)
|
vkDestroyBuffer(device, buffer, nullptr);
|
||||||
{
|
vkFreeMemory(device, memory, nullptr);
|
||||||
vkFreeMemory(device, memory, nullptr);
|
buffer = VK_NULL_HANDLE;
|
||||||
}
|
memory = VK_NULL_HANDLE;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
void Buffer::create(VulkanBase::VulkanDevice *device, VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkDeviceSize size, bool map)
|
||||||
|
{
|
||||||
|
VkDevice logicalDevice = device->getLogicalDevice();
|
||||||
|
device->createBuffer(usageFlags, memoryPropertyFlags, size, &buffer, &memory);
|
||||||
|
descriptor = {buffer, 0, size};
|
||||||
|
if (map)
|
||||||
|
{
|
||||||
|
VK_CHECK_RESULT(vkMapMemory(logicalDevice, memory, 0, size, 0, &mapped));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VULKANBASE_NAMESPACE_END
|
||||||
|
|
@ -1,46 +1,43 @@
|
||||||
/*
|
|
||||||
* Vulkan buffer class
|
|
||||||
*
|
|
||||||
* Encapsulates a Vulkan buffer
|
|
||||||
*
|
|
||||||
* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
|
|
||||||
*
|
|
||||||
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
#ifndef VULKANBUFFER_H
|
||||||
|
#define VULKANBUFFER_H
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "vulkan/vulkan.h"
|
#include "VulkanBase_Marco.h"
|
||||||
#include "VulkanTools.h"
|
#include "VulkanDevice.h"
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
namespace vks
|
VULKANBASE_NAMESPACE_BEGIN
|
||||||
{
|
/**
|
||||||
/**
|
* @brief Encapsulates access to a Vulkan buffer backed up by device memory
|
||||||
* @brief Encapsulates access to a Vulkan buffer backed up by device memory
|
* @note To be filled by an external source like the VulkanDevice
|
||||||
* @note To be filled by an external source like the VulkanDevice
|
*/
|
||||||
*/
|
struct Buffer
|
||||||
struct Buffer
|
{
|
||||||
{
|
VkDevice device;
|
||||||
VkDevice device;
|
VkBuffer buffer = VK_NULL_HANDLE;
|
||||||
VkBuffer buffer = VK_NULL_HANDLE;
|
VkDeviceMemory memory = VK_NULL_HANDLE;
|
||||||
VkDeviceMemory memory = VK_NULL_HANDLE;
|
VkDescriptorBufferInfo descriptor;
|
||||||
VkDescriptorBufferInfo descriptor;
|
VkDeviceSize size = 0;
|
||||||
VkDeviceSize size = 0;
|
VkDeviceSize alignment = 0;
|
||||||
VkDeviceSize alignment = 0;
|
int32_t count = 0;
|
||||||
void* mapped = nullptr;
|
void *mapped = nullptr;
|
||||||
/** @brief Usage flags to be filled by external source at buffer creation (to query at some later point) */
|
/** @brief Usage flags to be filled by external source at buffer creation (to query at some later point) */
|
||||||
VkBufferUsageFlags usageFlags;
|
VkBufferUsageFlags usageFlags;
|
||||||
/** @brief Memory property flags to be filled by external source at buffer creation (to query at some later point) */
|
/** @brief Memory property flags to be filled by external source at buffer creation (to query at some later point) */
|
||||||
VkMemoryPropertyFlags memoryPropertyFlags;
|
VkMemoryPropertyFlags memoryPropertyFlags;
|
||||||
VkResult map(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0);
|
void create(VulkanDevice *device, VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkDeviceSize size, bool map = true);
|
||||||
void unmap();
|
VkResult map(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0);
|
||||||
VkResult bind(VkDeviceSize offset = 0);
|
void unmap();
|
||||||
void setupDescriptor(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0);
|
VkResult bind(VkDeviceSize offset = 0);
|
||||||
void copyTo(void* data, VkDeviceSize size);
|
void setupDescriptor(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0);
|
||||||
VkResult flush(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0);
|
void copyTo(void *data, VkDeviceSize size);
|
||||||
VkResult invalidate(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0);
|
VkResult flush(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0);
|
||||||
void destroy();
|
VkResult invalidate(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0);
|
||||||
};
|
void destroy();
|
||||||
}
|
};
|
||||||
|
|
||||||
|
VULKANBASE_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,254 @@
|
||||||
|
#include "VulkanDevice.h"
|
||||||
|
#include "VulkanTools.h"
|
||||||
|
#include <cassert>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
VULKANBASE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
VulkanDevice::VulkanDevice()
|
||||||
|
: m_commandPool(VK_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanDevice::VulkanDevice(VkPhysicalDevice physicalDevice)
|
||||||
|
{
|
||||||
|
/// 检查物理设备是否存在,后续使用log方式记录
|
||||||
|
assert(physicalDevice);
|
||||||
|
m_physicalDevice = physicalDevice;
|
||||||
|
|
||||||
|
/// 获取设备信息
|
||||||
|
vkGetPhysicalDeviceProperties(physicalDevice, &m_properties);
|
||||||
|
/// 获取设备支持的功能
|
||||||
|
vkGetPhysicalDeviceFeatures(physicalDevice, &m_features);
|
||||||
|
/// 获取设备内存信息,用于创建内存
|
||||||
|
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &m_memoryProperties);
|
||||||
|
/// 队列族信息,用于设备创建时获取设置获取的队列
|
||||||
|
uint32_t queueFamilyCount;
|
||||||
|
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, nullptr);
|
||||||
|
/// 检查设备队列族数量,必须大于0
|
||||||
|
assert(queueFamilyCount > 0);
|
||||||
|
m_queueFamilyProperties.resize(queueFamilyCount);
|
||||||
|
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, m_queueFamilyProperties.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanDevice::~VulkanDevice()
|
||||||
|
{
|
||||||
|
if (m_commandPool)
|
||||||
|
{
|
||||||
|
vkDestroyCommandPool(m_logicalDevice, m_commandPool, nullptr);
|
||||||
|
}
|
||||||
|
if (m_logicalDevice)
|
||||||
|
{
|
||||||
|
vkDestroyDevice(m_logicalDevice, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDevice VulkanDevice::getLogicalDevice()
|
||||||
|
{
|
||||||
|
return m_logicalDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPhysicalDevice VulkanDevice::getPhysicalDevice()
|
||||||
|
{
|
||||||
|
return m_physicalDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPhysicalDeviceProperties VulkanDevice::VulkanDevice::getPhysicalDeviceProperties()
|
||||||
|
{
|
||||||
|
return m_properties;
|
||||||
|
}
|
||||||
|
VkPhysicalDeviceFeatures VulkanDevice::getPhysicalDeviceFeatures()
|
||||||
|
{
|
||||||
|
return m_features;
|
||||||
|
}
|
||||||
|
VkPhysicalDeviceMemoryProperties VulkanDevice::getPhysicalDeviceMemoryProperties()
|
||||||
|
{
|
||||||
|
return m_memoryProperties;
|
||||||
|
}
|
||||||
|
std::vector<VkQueueFamilyProperties> VulkanDevice::getQueueFamilyProperties()
|
||||||
|
{
|
||||||
|
return m_queueFamilyProperties;
|
||||||
|
}
|
||||||
|
VkCommandPool VulkanDevice::getCommandPool()
|
||||||
|
{
|
||||||
|
return m_commandPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t VulkanDevice::getMemoryType(uint32_t typeBits, VkMemoryPropertyFlags properties, VkBool32 *memTypeFound)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < m_memoryProperties.memoryTypeCount; i++)
|
||||||
|
{
|
||||||
|
if ((typeBits & 1) == 1)
|
||||||
|
{
|
||||||
|
if ((m_memoryProperties.memoryTypes[i].propertyFlags & properties) == properties)
|
||||||
|
{
|
||||||
|
if (memTypeFound)
|
||||||
|
{
|
||||||
|
*memTypeFound = true;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
typeBits >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memTypeFound)
|
||||||
|
{
|
||||||
|
*memTypeFound = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Could not find a matching memory type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t VulkanDevice::getQueueFamilyIndex(VkQueueFlagBits queueFlags)
|
||||||
|
{
|
||||||
|
/// 获取支持计算的队列组索引
|
||||||
|
if (queueFlags & VK_QUEUE_COMPUTE_BIT)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < static_cast<uint32_t>(m_queueFamilyProperties.size()); i++)
|
||||||
|
{
|
||||||
|
if ((m_queueFamilyProperties[i].queueFlags & queueFlags) && ((m_queueFamilyProperties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0))
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 对于其他的队列类型,如果当前没有单独的计算队列,返回支持标志类型的第一个队列
|
||||||
|
for (uint32_t i = 0; i < static_cast<uint32_t>(m_queueFamilyProperties.size()); i++)
|
||||||
|
{
|
||||||
|
if (m_queueFamilyProperties[i].queueFlags & queueFlags)
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw std::runtime_error("Could not find a matching queue family index");
|
||||||
|
}
|
||||||
|
uint32_t VulkanDevice::getGraphicsQueueFamilyIndex()
|
||||||
|
{
|
||||||
|
return m_queueFamilyIndices.graphics;
|
||||||
|
}
|
||||||
|
uint32_t VulkanDevice::getComputeQueueFamilyIndex()
|
||||||
|
{
|
||||||
|
return m_queueFamilyIndices.compute;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkResult VulkanDevice::createBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkDeviceSize size, VkBuffer *buffer, VkDeviceMemory *memory, void *data)
|
||||||
|
{
|
||||||
|
// 创建buffer句柄
|
||||||
|
VkBufferCreateInfo bufferCreateInfo{};
|
||||||
|
bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||||
|
bufferCreateInfo.usage = usageFlags;
|
||||||
|
bufferCreateInfo.size = size;
|
||||||
|
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
VK_CHECK_RESULT(vkCreateBuffer(m_logicalDevice, &bufferCreateInfo, nullptr, buffer));
|
||||||
|
|
||||||
|
// 创建buffer的设备内存分配信息
|
||||||
|
VkMemoryRequirements memReqs;
|
||||||
|
VkMemoryAllocateInfo memAlloc{};
|
||||||
|
memAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||||
|
vkGetBufferMemoryRequirements(m_logicalDevice, *buffer, &memReqs);
|
||||||
|
memAlloc.allocationSize = memReqs.size;
|
||||||
|
/// 获取符合buffer的设备内存类型索引
|
||||||
|
memAlloc.memoryTypeIndex = getMemoryType(memReqs.memoryTypeBits, memoryPropertyFlags);
|
||||||
|
VK_CHECK_RESULT(vkAllocateMemory(m_logicalDevice, &memAlloc, nullptr, memory));
|
||||||
|
|
||||||
|
// 如何buffer指针已经存在,复制或者映射该buffer
|
||||||
|
if (data != nullptr)
|
||||||
|
{
|
||||||
|
void *mapped;
|
||||||
|
VK_CHECK_RESULT(vkMapMemory(m_logicalDevice, *memory, 0, size, 0, &mapped));
|
||||||
|
memcpy(mapped, data, size);
|
||||||
|
// 如果host coherency 未设置, 对buffer进行flush,让设备侧可见
|
||||||
|
if ((memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0)
|
||||||
|
{
|
||||||
|
VkMappedMemoryRange mappedRange{};
|
||||||
|
mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
|
||||||
|
mappedRange.memory = *memory;
|
||||||
|
mappedRange.offset = 0;
|
||||||
|
mappedRange.size = size;
|
||||||
|
vkFlushMappedMemoryRanges(m_logicalDevice, 1, &mappedRange);
|
||||||
|
}
|
||||||
|
vkUnmapMemory(m_logicalDevice, *memory);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绑定设备内存到buffer object
|
||||||
|
VK_CHECK_RESULT(vkBindBufferMemory(m_logicalDevice, *buffer, *memory, 0));
|
||||||
|
|
||||||
|
return VK_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkCommandPool VulkanDevice::createCommandPool(uint32_t queueFamilyIndex, VkCommandPoolCreateFlags createFlags)
|
||||||
|
{
|
||||||
|
/// 创建命令缓冲池
|
||||||
|
VkCommandPoolCreateInfo cmdPoolInfo = {};
|
||||||
|
cmdPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||||
|
cmdPoolInfo.queueFamilyIndex = queueFamilyIndex;
|
||||||
|
cmdPoolInfo.flags = createFlags;
|
||||||
|
VkCommandPool cmdPool;
|
||||||
|
VK_CHECK_RESULT(vkCreateCommandPool(m_logicalDevice, &cmdPoolInfo, nullptr, &cmdPool));
|
||||||
|
return cmdPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkCommandBuffer VulkanDevice::createCommandBuffer(VkCommandBufferLevel level, bool begin)
|
||||||
|
{
|
||||||
|
VkCommandBufferAllocateInfo cmdBufAllocateInfo{};
|
||||||
|
cmdBufAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||||
|
cmdBufAllocateInfo.commandPool = m_commandPool;
|
||||||
|
cmdBufAllocateInfo.level = level;
|
||||||
|
cmdBufAllocateInfo.commandBufferCount = 1;
|
||||||
|
|
||||||
|
VkCommandBuffer cmdBuffer;
|
||||||
|
VK_CHECK_RESULT(vkAllocateCommandBuffers(m_logicalDevice, &cmdBufAllocateInfo, &cmdBuffer));
|
||||||
|
|
||||||
|
// 开始记录指令buffer
|
||||||
|
if (begin)
|
||||||
|
{
|
||||||
|
beginCommandBuffer(cmdBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmdBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanDevice::beginCommandBuffer(VkCommandBuffer commandBuffer)
|
||||||
|
{
|
||||||
|
VkCommandBufferBeginInfo commandBufferBI{};
|
||||||
|
commandBufferBI.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||||
|
VK_CHECK_RESULT(vkBeginCommandBuffer(commandBuffer, &commandBufferBI));
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanDevice::flushCommandBuffer(VkCommandBuffer commandBuffer, VkQueue queue, bool free)
|
||||||
|
{
|
||||||
|
VK_CHECK_RESULT(vkEndCommandBuffer(commandBuffer));
|
||||||
|
|
||||||
|
VkSubmitInfo submitInfo{};
|
||||||
|
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||||
|
submitInfo.commandBufferCount = 1;
|
||||||
|
submitInfo.pCommandBuffers = &commandBuffer;
|
||||||
|
|
||||||
|
// 创建同步栅栏,确保命令buffer执行完毕
|
||||||
|
VkFenceCreateInfo fenceInfo{};
|
||||||
|
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||||
|
VkFence fence;
|
||||||
|
VK_CHECK_RESULT(vkCreateFence(m_logicalDevice, &fenceInfo, nullptr, &fence));
|
||||||
|
|
||||||
|
// 提交队列
|
||||||
|
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, fence));
|
||||||
|
// 等待栅栏发出信号说明命令buffer执行完毕
|
||||||
|
VK_CHECK_RESULT(vkWaitForFences(m_logicalDevice, 1, &fence, VK_TRUE, 100000000000));
|
||||||
|
// 同步栅栏使命结束,销毁
|
||||||
|
vkDestroyFence(m_logicalDevice, fence, nullptr);
|
||||||
|
// 需要的时候,销毁命令buffer
|
||||||
|
if (free)
|
||||||
|
{
|
||||||
|
vkFreeCommandBuffers(m_logicalDevice, m_commandPool, 1, &commandBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VULKANBASE_NAMESPACE_END
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
#ifndef VULKANDEVICE_H
|
||||||
|
#define VULKANDEVICE_H
|
||||||
|
|
||||||
|
#include "VulkanBase_Marco.h"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
|
VULKANBASE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
/// @brief vulkan的设备类
|
||||||
|
class VulkanDevice
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
VulkanDevice();
|
||||||
|
VulkanDevice(VkPhysicalDevice physicalDevice);
|
||||||
|
~VulkanDevice();
|
||||||
|
|
||||||
|
public:
|
||||||
|
VkDevice getLogicalDevice();
|
||||||
|
VkPhysicalDevice getPhysicalDevice();
|
||||||
|
VkPhysicalDeviceProperties getPhysicalDeviceProperties();
|
||||||
|
VkPhysicalDeviceFeatures getPhysicalDeviceFeatures();
|
||||||
|
VkPhysicalDeviceMemoryProperties getPhysicalDeviceMemoryProperties();
|
||||||
|
std::vector<VkQueueFamilyProperties> getQueueFamilyProperties();
|
||||||
|
VkCommandPool getCommandPool();
|
||||||
|
uint32_t getGraphicsQueueFamilyIndex();
|
||||||
|
uint32_t getComputeQueueFamilyIndex();
|
||||||
|
|
||||||
|
/// @brief 获取已设置所有请求属性位的设备内存类型的索引
|
||||||
|
/// @param typeBits 请求的每种设备内存类型设置的位掩码,通常通过VkMemoryRequirements获取
|
||||||
|
/// @param properties 要请求的设备内存类型的属性位掩码
|
||||||
|
/// @param memTypeFound 如果符合的设备内存类型存在,则该指针的布尔值为true
|
||||||
|
/// @return 请求的设备内存类型的索引
|
||||||
|
/// @throw 如果 memTypeFound 为空且找不到支持需要的属性的设备内存类型,则抛出异常
|
||||||
|
uint32_t getMemoryType(uint32_t typeBits, VkMemoryPropertyFlags properties, VkBool32 *memTypeFound = nullptr);
|
||||||
|
|
||||||
|
/// @brief 获取支持所请求队列标志的队列族的索引
|
||||||
|
/// @param queueFlags 用于查找队列族索引的队列标志
|
||||||
|
/// @return 与标志匹配的队列族索引
|
||||||
|
/// @throw 如果找不到支持所请求标志的队列族索引,则抛出异常
|
||||||
|
uint32_t getQueueFamilyIndex(VkQueueFlagBits queueFlags);
|
||||||
|
|
||||||
|
/// @brief 据分配的物理设备创建逻辑设备,同时获取默认队列族索引
|
||||||
|
/// @param enabledFeatures 在创建设备时启用某些功能
|
||||||
|
/// @param enabledExtensions 在创建设备时启用某些扩展
|
||||||
|
/// @param requestedQueueTypes 指定要从设备请求的队列类型
|
||||||
|
/// @return 逻辑设备是否成功创建
|
||||||
|
VkResult createLogicalDevice(VkPhysicalDeviceFeatures enabledFeatures, std::vector<const char *> enabledExtensions, VkQueueFlags requestedQueueTypes = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT);
|
||||||
|
|
||||||
|
/// @brief 在设备上创建缓冲区
|
||||||
|
/// @param usageFlags 缓冲区的使用标志位掩码(即索引、顶点、统一缓冲区)
|
||||||
|
/// @param memoryPropertyFlags 此缓冲区的内存属性(即设备本地、主机可见、一致)
|
||||||
|
/// @param size 缓冲区的大小(以字节为单位)
|
||||||
|
/// @param buffer 指向函数获取的缓冲区句柄的指针
|
||||||
|
/// @param memory 指向函数获取的设备内存句柄的指针
|
||||||
|
/// @param data 指向创建后应复制到缓冲区的数据的指针(可选,如果未设置,则不会复制任何数据)
|
||||||
|
/// @return 如果已创建缓冲区句柄和设备内存并且已复制数据(可选传递),则返回 VK_SUCCESS
|
||||||
|
VkResult createBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkDeviceSize size, VkBuffer *buffer, VkDeviceMemory *memory, void *data = nullptr);
|
||||||
|
|
||||||
|
/// @brief 创建命令池以分配命令缓冲区
|
||||||
|
/// @param queueFamilyIndex 要为其创建命令池的队列的系列索引
|
||||||
|
/// @param createFlags 可选)命令池创建标志(默认为 VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT)
|
||||||
|
/// @return 创建的命令缓冲区的句柄
|
||||||
|
VkCommandPool createCommandPool(uint32_t queueFamilyIndex, VkCommandPoolCreateFlags createFlags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT);
|
||||||
|
|
||||||
|
/// @brief 从命令池中分配命令缓冲区
|
||||||
|
/// @param level 新命令缓冲区的级别(主或次)
|
||||||
|
/// @param begin 为 true时开始在新命令缓冲区上进行记录
|
||||||
|
/// @return 分配的命令缓冲区的句柄
|
||||||
|
VkCommandBuffer createCommandBuffer(VkCommandBufferLevel level, bool begin = false);
|
||||||
|
|
||||||
|
/// @brief 开始在指定命令缓冲区记录
|
||||||
|
/// @param commandBuffer
|
||||||
|
void beginCommandBuffer(VkCommandBuffer commandBuffer);
|
||||||
|
|
||||||
|
/// @brief 停止指定命令缓冲区记录并将其提交到队列,使用栅栏来确保命令缓冲区已完成执行
|
||||||
|
/// @param commandBuffer 要刷新的命令缓冲区
|
||||||
|
/// @param queue 要将命令缓冲区提交到的队列
|
||||||
|
/// @param free 提交后释放命令缓冲区(默认为 true)
|
||||||
|
void flushCommandBuffer(VkCommandBuffer commandBuffer, VkQueue queue, bool free = true);
|
||||||
|
|
||||||
|
private:
|
||||||
|
VkPhysicalDevice m_physicalDevice;
|
||||||
|
VkDevice m_logicalDevice;
|
||||||
|
VkPhysicalDeviceProperties m_properties;
|
||||||
|
VkPhysicalDeviceFeatures m_features;
|
||||||
|
VkPhysicalDeviceFeatures m_enabledFeatures;
|
||||||
|
VkPhysicalDeviceMemoryProperties m_memoryProperties;
|
||||||
|
std::vector<VkQueueFamilyProperties> m_queueFamilyProperties;
|
||||||
|
VkCommandPool m_commandPool;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint32_t graphics;
|
||||||
|
uint32_t compute;
|
||||||
|
} m_queueFamilyIndices;
|
||||||
|
};
|
||||||
|
|
||||||
|
VULKANBASE_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // !VULKANDEVICE_H
|
||||||
|
|
@ -1,391 +0,0 @@
|
||||||
/*
|
|
||||||
* Vulkan device class
|
|
||||||
*
|
|
||||||
* Encapsulates a physical Vulkan device and it's logical representation
|
|
||||||
*
|
|
||||||
* Copyright (C) 2016-2018 by Sascha Willems - www.saschawillems.de
|
|
||||||
*
|
|
||||||
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <cstdio>
|
|
||||||
#include <exception>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cstring>
|
|
||||||
#include <vector>
|
|
||||||
#include "vulkan/vulkan.h"
|
|
||||||
|
|
||||||
#if defined(VK_USE_PLATFORM_MACOS_MVK) && (VK_HEADER_VERSION >= 216)
|
|
||||||
#include <vulkan/vulkan_beta.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
|
|
||||||
#include "VulkanAndroid.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "VulkanTools.h"
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief 已单独剥离,等待删除
|
|
||||||
namespace vks
|
|
||||||
{
|
|
||||||
struct VulkanDevice
|
|
||||||
{
|
|
||||||
VkPhysicalDevice physicalDevice;
|
|
||||||
VkDevice logicalDevice;
|
|
||||||
VkPhysicalDeviceProperties properties;
|
|
||||||
VkPhysicalDeviceFeatures features;
|
|
||||||
VkPhysicalDeviceFeatures enabledFeatures;
|
|
||||||
VkPhysicalDeviceMemoryProperties memoryProperties;
|
|
||||||
std::vector<VkQueueFamilyProperties> queueFamilyProperties;
|
|
||||||
VkCommandPool commandPool = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
uint32_t graphics;
|
|
||||||
uint32_t compute;
|
|
||||||
} queueFamilyIndices;
|
|
||||||
|
|
||||||
operator VkDevice() { return logicalDevice; };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default constructor
|
|
||||||
*
|
|
||||||
* @param physicalDevice Physical device that is to be used
|
|
||||||
*/
|
|
||||||
VulkanDevice(VkPhysicalDevice physicalDevice)
|
|
||||||
{
|
|
||||||
assert(physicalDevice);
|
|
||||||
this->physicalDevice = physicalDevice;
|
|
||||||
|
|
||||||
// Store Properties features, limits and properties of the physical device for later use
|
|
||||||
// Device properties also contain limits and sparse properties
|
|
||||||
vkGetPhysicalDeviceProperties(physicalDevice, &properties);
|
|
||||||
// Features should be checked by the examples before using them
|
|
||||||
vkGetPhysicalDeviceFeatures(physicalDevice, &features);
|
|
||||||
// Memory properties are used regularly for creating all kinds of buffers
|
|
||||||
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memoryProperties);
|
|
||||||
// Queue family properties, used for setting up requested queues upon device creation
|
|
||||||
uint32_t queueFamilyCount;
|
|
||||||
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, nullptr);
|
|
||||||
assert(queueFamilyCount > 0);
|
|
||||||
queueFamilyProperties.resize(queueFamilyCount);
|
|
||||||
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, queueFamilyProperties.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default destructor
|
|
||||||
*
|
|
||||||
* @note Frees the logical device
|
|
||||||
*/
|
|
||||||
~VulkanDevice()
|
|
||||||
{
|
|
||||||
if (commandPool) {
|
|
||||||
vkDestroyCommandPool(logicalDevice, commandPool, nullptr);
|
|
||||||
}
|
|
||||||
if (logicalDevice) {
|
|
||||||
vkDestroyDevice(logicalDevice, nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the index of a memory type that has all the requested property bits set
|
|
||||||
*
|
|
||||||
* @param typeBits Bitmask with bits set for each memory type supported by the resource to request for (from VkMemoryRequirements)
|
|
||||||
* @param properties Bitmask of properties for the memory type to request
|
|
||||||
* @param (Optional) memTypeFound Pointer to a bool that is set to true if a matching memory type has been found
|
|
||||||
*
|
|
||||||
* @return Index of the requested memory type
|
|
||||||
*
|
|
||||||
* @throw Throws an exception if memTypeFound is null and no memory type could be found that supports the requested properties
|
|
||||||
*/
|
|
||||||
uint32_t getMemoryType(uint32_t typeBits, VkMemoryPropertyFlags properties, VkBool32 *memTypeFound = nullptr)
|
|
||||||
{
|
|
||||||
for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; i++) {
|
|
||||||
if ((typeBits & 1) == 1) {
|
|
||||||
if ((memoryProperties.memoryTypes[i].propertyFlags & properties) == properties) {
|
|
||||||
if (memTypeFound) {
|
|
||||||
*memTypeFound = true;
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
typeBits >>= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (memTypeFound) {
|
|
||||||
*memTypeFound = false;
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
throw std::runtime_error("Could not find a matching memory type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the index of a queue family that supports the requested queue flags
|
|
||||||
*
|
|
||||||
* @param queueFlags Queue flags to find a queue family index for
|
|
||||||
*
|
|
||||||
* @return Index of the queue family index that matches the flags
|
|
||||||
*
|
|
||||||
* @throw Throws an exception if no queue family index could be found that supports the requested flags
|
|
||||||
*/
|
|
||||||
uint32_t getQueueFamilyIndex(VkQueueFlagBits queueFlags)
|
|
||||||
{
|
|
||||||
// Dedicated queue for compute
|
|
||||||
// Try to find a queue family index that supports compute but not graphics
|
|
||||||
if (queueFlags & VK_QUEUE_COMPUTE_BIT)
|
|
||||||
{
|
|
||||||
for (uint32_t i = 0; i < static_cast<uint32_t>(queueFamilyProperties.size()); i++) {
|
|
||||||
if ((queueFamilyProperties[i].queueFlags & queueFlags) && ((queueFamilyProperties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0)) {
|
|
||||||
return i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// For other queue types or if no separate compute queue is present, return the first one to support the requested flags
|
|
||||||
for (uint32_t i = 0; i < static_cast<uint32_t>(queueFamilyProperties.size()); i++) {
|
|
||||||
if (queueFamilyProperties[i].queueFlags & queueFlags) {
|
|
||||||
return i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw std::runtime_error("Could not find a matching queue family index");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create the logical device based on the assigned physical device, also gets default queue family indices
|
|
||||||
*
|
|
||||||
* @param enabledFeatures Can be used to enable certain features upon device creation
|
|
||||||
* @param requestedQueueTypes Bit flags specifying the queue types to be requested from the device
|
|
||||||
*
|
|
||||||
* @return VkResult of the device creation call
|
|
||||||
*/
|
|
||||||
VkResult createLogicalDevice(VkPhysicalDeviceFeatures enabledFeatures, std::vector<const char*> enabledExtensions, VkQueueFlags requestedQueueTypes = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT)
|
|
||||||
{
|
|
||||||
// Desired queues need to be requested upon logical device creation
|
|
||||||
// Due to differing queue family configurations of Vulkan implementations this can be a bit tricky, especially if the application
|
|
||||||
// requests different queue types
|
|
||||||
|
|
||||||
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos{};
|
|
||||||
|
|
||||||
// Get queue family indices for the requested queue family types
|
|
||||||
// Note that the indices may overlap depending on the implementation
|
|
||||||
|
|
||||||
const float defaultQueuePriority(0.0f);
|
|
||||||
|
|
||||||
// Graphics queue
|
|
||||||
if (requestedQueueTypes & VK_QUEUE_GRAPHICS_BIT) {
|
|
||||||
queueFamilyIndices.graphics = getQueueFamilyIndex(VK_QUEUE_GRAPHICS_BIT);
|
|
||||||
VkDeviceQueueCreateInfo queueInfo{};
|
|
||||||
queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
|
||||||
queueInfo.queueFamilyIndex = queueFamilyIndices.graphics;
|
|
||||||
queueInfo.queueCount = 1;
|
|
||||||
queueInfo.pQueuePriorities = &defaultQueuePriority;
|
|
||||||
queueCreateInfos.push_back(queueInfo);
|
|
||||||
} else {
|
|
||||||
queueFamilyIndices.graphics = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dedicated compute queue
|
|
||||||
if (requestedQueueTypes & VK_QUEUE_COMPUTE_BIT) {
|
|
||||||
queueFamilyIndices.compute = getQueueFamilyIndex(VK_QUEUE_COMPUTE_BIT);
|
|
||||||
if (queueFamilyIndices.compute != queueFamilyIndices.graphics) {
|
|
||||||
// If compute family index differs, we need an additional queue create info for the compute queue
|
|
||||||
VkDeviceQueueCreateInfo queueInfo{};
|
|
||||||
queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
|
||||||
queueInfo.queueFamilyIndex = queueFamilyIndices.compute;
|
|
||||||
queueInfo.queueCount = 1;
|
|
||||||
queueInfo.pQueuePriorities = &defaultQueuePriority;
|
|
||||||
queueCreateInfos.push_back(queueInfo);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Else we use the same queue
|
|
||||||
queueFamilyIndices.compute = queueFamilyIndices.graphics;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the logical device representation
|
|
||||||
std::vector<const char*> deviceExtensions(enabledExtensions);
|
|
||||||
deviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
|
||||||
|
|
||||||
#if defined(VK_USE_PLATFORM_MACOS_MVK) && (VK_HEADER_VERSION >= 216)
|
|
||||||
deviceExtensions.push_back(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
VkDeviceCreateInfo deviceCreateInfo = {};
|
|
||||||
deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
|
||||||
deviceCreateInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());;
|
|
||||||
deviceCreateInfo.pQueueCreateInfos = queueCreateInfos.data();
|
|
||||||
deviceCreateInfo.pEnabledFeatures = &enabledFeatures;
|
|
||||||
|
|
||||||
if (deviceExtensions.size() > 0) {
|
|
||||||
deviceCreateInfo.enabledExtensionCount = (uint32_t)deviceExtensions.size();
|
|
||||||
deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions.data();
|
|
||||||
}
|
|
||||||
|
|
||||||
VkResult result = vkCreateDevice(physicalDevice, &deviceCreateInfo, nullptr, &logicalDevice);
|
|
||||||
|
|
||||||
if (result == VK_SUCCESS) {
|
|
||||||
commandPool = createCommandPool(queueFamilyIndices.graphics);
|
|
||||||
}
|
|
||||||
|
|
||||||
this->enabledFeatures = enabledFeatures;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a buffer on the device
|
|
||||||
*
|
|
||||||
* @param usageFlags Usage flag bitmask for the buffer (i.e. index, vertex, uniform buffer)
|
|
||||||
* @param memoryPropertyFlags Memory properties for this buffer (i.e. device local, host visible, coherent)
|
|
||||||
* @param size Size of the buffer in byes
|
|
||||||
* @param buffer Pointer to the buffer handle acquired by the function
|
|
||||||
* @param memory Pointer to the memory handle acquired by the function
|
|
||||||
* @param data Pointer to the data that should be copied to the buffer after creation (optional, if not set, no data is copied over)
|
|
||||||
*
|
|
||||||
* @return VK_SUCCESS if buffer handle and memory have been created and (optionally passed) data has been copied
|
|
||||||
*/
|
|
||||||
VkResult createBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkDeviceSize size, VkBuffer *buffer, VkDeviceMemory *memory, void *data = nullptr)
|
|
||||||
{
|
|
||||||
// Create the buffer handle
|
|
||||||
VkBufferCreateInfo bufferCreateInfo{};
|
|
||||||
bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
|
||||||
bufferCreateInfo.usage = usageFlags;
|
|
||||||
bufferCreateInfo.size = size;
|
|
||||||
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
||||||
VK_CHECK_RESULT(vkCreateBuffer(logicalDevice, &bufferCreateInfo, nullptr, buffer));
|
|
||||||
|
|
||||||
// Create the memory backing up the buffer handle
|
|
||||||
VkMemoryRequirements memReqs;
|
|
||||||
VkMemoryAllocateInfo memAlloc{};
|
|
||||||
memAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
|
||||||
vkGetBufferMemoryRequirements(logicalDevice, *buffer, &memReqs);
|
|
||||||
memAlloc.allocationSize = memReqs.size;
|
|
||||||
// Find a memory type index that fits the properties of the buffer
|
|
||||||
memAlloc.memoryTypeIndex = getMemoryType(memReqs.memoryTypeBits, memoryPropertyFlags);
|
|
||||||
VK_CHECK_RESULT(vkAllocateMemory(logicalDevice, &memAlloc, nullptr, memory));
|
|
||||||
|
|
||||||
// If a pointer to the buffer data has been passed, map the buffer and copy over the data
|
|
||||||
if (data != nullptr)
|
|
||||||
{
|
|
||||||
void *mapped;
|
|
||||||
VK_CHECK_RESULT(vkMapMemory(logicalDevice, *memory, 0, size, 0, &mapped));
|
|
||||||
memcpy(mapped, data, size);
|
|
||||||
// If host coherency hasn't been requested, do a manual flush to make writes visible
|
|
||||||
if ((memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0)
|
|
||||||
{
|
|
||||||
VkMappedMemoryRange mappedRange{};
|
|
||||||
mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
|
|
||||||
mappedRange.memory = *memory;
|
|
||||||
mappedRange.offset = 0;
|
|
||||||
mappedRange.size = size;
|
|
||||||
vkFlushMappedMemoryRanges(logicalDevice, 1, &mappedRange);
|
|
||||||
}
|
|
||||||
vkUnmapMemory(logicalDevice, *memory);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attach the memory to the buffer object
|
|
||||||
VK_CHECK_RESULT(vkBindBufferMemory(logicalDevice, *buffer, *memory, 0));
|
|
||||||
|
|
||||||
return VK_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a command pool for allocation command buffers from
|
|
||||||
*
|
|
||||||
* @param queueFamilyIndex Family index of the queue to create the command pool for
|
|
||||||
* @param createFlags (Optional) Command pool creation flags (Defaults to VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT)
|
|
||||||
*
|
|
||||||
* @note Command buffers allocated from the created pool can only be submitted to a queue with the same family index
|
|
||||||
*
|
|
||||||
* @return A handle to the created command buffer
|
|
||||||
*/
|
|
||||||
VkCommandPool createCommandPool(uint32_t queueFamilyIndex, VkCommandPoolCreateFlags createFlags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT)
|
|
||||||
{
|
|
||||||
VkCommandPoolCreateInfo cmdPoolInfo = {};
|
|
||||||
cmdPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
|
||||||
cmdPoolInfo.queueFamilyIndex = queueFamilyIndex;
|
|
||||||
cmdPoolInfo.flags = createFlags;
|
|
||||||
VkCommandPool cmdPool;
|
|
||||||
VK_CHECK_RESULT(vkCreateCommandPool(logicalDevice, &cmdPoolInfo, nullptr, &cmdPool));
|
|
||||||
return cmdPool;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allocate a command buffer from the command pool
|
|
||||||
*
|
|
||||||
* @param level Level of the new command buffer (primary or secondary)
|
|
||||||
* @param (Optional) begin If true, recording on the new command buffer will be started (vkBeginCommandBuffer) (Defaults to false)
|
|
||||||
*
|
|
||||||
* @return A handle to the allocated command buffer
|
|
||||||
*/
|
|
||||||
VkCommandBuffer createCommandBuffer(VkCommandBufferLevel level, bool begin = false)
|
|
||||||
{
|
|
||||||
VkCommandBufferAllocateInfo cmdBufAllocateInfo{};
|
|
||||||
cmdBufAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
|
||||||
cmdBufAllocateInfo.commandPool = commandPool;
|
|
||||||
cmdBufAllocateInfo.level = level;
|
|
||||||
cmdBufAllocateInfo.commandBufferCount = 1;
|
|
||||||
|
|
||||||
VkCommandBuffer cmdBuffer;
|
|
||||||
VK_CHECK_RESULT(vkAllocateCommandBuffers(logicalDevice, &cmdBufAllocateInfo, &cmdBuffer));
|
|
||||||
|
|
||||||
// If requested, also start recording for the new command buffer
|
|
||||||
if (begin) {
|
|
||||||
VkCommandBufferBeginInfo commandBufferBI{};
|
|
||||||
commandBufferBI.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
|
||||||
VK_CHECK_RESULT(vkBeginCommandBuffer(cmdBuffer, &commandBufferBI));
|
|
||||||
}
|
|
||||||
|
|
||||||
return cmdBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void beginCommandBuffer(VkCommandBuffer commandBuffer)
|
|
||||||
{
|
|
||||||
VkCommandBufferBeginInfo commandBufferBI{};
|
|
||||||
commandBufferBI.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
|
||||||
VK_CHECK_RESULT(vkBeginCommandBuffer(commandBuffer, &commandBufferBI));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finish command buffer recording and submit it to a queue
|
|
||||||
*
|
|
||||||
* @param commandBuffer Command buffer to flush
|
|
||||||
* @param queue Queue to submit the command buffer to
|
|
||||||
* @param free (Optional) Free the command buffer once it has been submitted (Defaults to true)
|
|
||||||
*
|
|
||||||
* @note The queue that the command buffer is submitted to must be from the same family index as the pool it was allocated from
|
|
||||||
* @note Uses a fence to ensure command buffer has finished executing
|
|
||||||
*/
|
|
||||||
void flushCommandBuffer(VkCommandBuffer commandBuffer, VkQueue queue, bool free = true)
|
|
||||||
{
|
|
||||||
VK_CHECK_RESULT(vkEndCommandBuffer(commandBuffer));
|
|
||||||
|
|
||||||
VkSubmitInfo submitInfo{};
|
|
||||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
|
||||||
submitInfo.commandBufferCount = 1;
|
|
||||||
submitInfo.pCommandBuffers = &commandBuffer;
|
|
||||||
|
|
||||||
// Create fence to ensure that the command buffer has finished executing
|
|
||||||
VkFenceCreateInfo fenceInfo{};
|
|
||||||
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
|
||||||
VkFence fence;
|
|
||||||
VK_CHECK_RESULT(vkCreateFence(logicalDevice, &fenceInfo, nullptr, &fence));
|
|
||||||
|
|
||||||
// Submit to the queue
|
|
||||||
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, fence));
|
|
||||||
// Wait for the fence to signal that command buffer has finished executing
|
|
||||||
VK_CHECK_RESULT(vkWaitForFences(logicalDevice, 1, &fence, VK_TRUE, 100000000000));
|
|
||||||
|
|
||||||
vkDestroyFence(logicalDevice, fence, nullptr);
|
|
||||||
|
|
||||||
if (free) {
|
|
||||||
vkFreeCommandBuffers(logicalDevice, commandPool, 1, &commandBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,97 +1,90 @@
|
||||||
/*
|
#ifndef VULKANTEXTURE_H
|
||||||
* Vulkan texture loader
|
#define VULKANTEXTURE_H
|
||||||
*
|
|
||||||
* Copyright(C) by Sascha Willems - www.saschawillems.de
|
|
||||||
*
|
|
||||||
* This code is licensed under the MIT license(MIT) (http://opensource.org/licenses/MIT)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
#include "VulkanBase_Marco.h"
|
||||||
|
|
||||||
|
#include "VulkanBuffer.h"
|
||||||
|
#include "VulkanDevice.h"
|
||||||
|
#include "VulkanTools.h"
|
||||||
|
|
||||||
|
#include <ktx.h>
|
||||||
|
#include <ktxvulkan.h>
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "vulkan/vulkan.h"
|
VULKANBASE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
#include <ktx.h>
|
|
||||||
#include <ktxvulkan.h>
|
|
||||||
|
|
||||||
#include "VulkanBuffer.h"
|
|
||||||
#include "VulkanDevice.hpp"
|
|
||||||
//#include "VulkanTools.h"
|
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
|
||||||
# include <android/asset_manager.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace vks
|
|
||||||
{
|
|
||||||
class Texture
|
class Texture
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
vks::VulkanDevice * device;
|
VulkanBase::VulkanDevice *device;
|
||||||
VkImage image;
|
VkImage image;
|
||||||
VkImageLayout imageLayout;
|
VkImageLayout imageLayout;
|
||||||
VkDeviceMemory deviceMemory;
|
VkDeviceMemory deviceMemory;
|
||||||
VkImageView view;
|
VkImageView view;
|
||||||
uint32_t width, height;
|
uint32_t width, height;
|
||||||
uint32_t mipLevels;
|
uint32_t mipLevels;
|
||||||
uint32_t layerCount;
|
uint32_t layerCount;
|
||||||
VkDescriptorImageInfo descriptor;
|
VkDescriptorImageInfo descriptor;
|
||||||
VkSampler sampler;
|
VkSampler sampler;
|
||||||
|
|
||||||
void updateDescriptor();
|
void updateDescriptor();
|
||||||
void destroy();
|
void destroy();
|
||||||
ktxResult loadKTXFile(std::string filename, ktxTexture **target);
|
ktxResult loadKTXFile(std::string filename, ktxTexture **target);
|
||||||
};
|
};
|
||||||
|
|
||||||
class Texture2D : public Texture
|
class Texture2D : public Texture
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void loadFromFile(
|
void loadFromFile(
|
||||||
std::string filename,
|
std::string filename,
|
||||||
VkFormat format,
|
VkFormat format,
|
||||||
vks::VulkanDevice *device,
|
VulkanBase::VulkanDevice *device,
|
||||||
VkQueue copyQueue,
|
VkQueue copyQueue,
|
||||||
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
|
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
|
||||||
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||||
bool forceLinear = false);
|
bool forceLinear = false);
|
||||||
void fromBuffer(
|
void loadFromBuffer(
|
||||||
void * buffer,
|
void *buffer,
|
||||||
VkDeviceSize bufferSize,
|
VkDeviceSize bufferSize,
|
||||||
VkFormat format,
|
VkFormat format,
|
||||||
uint32_t texWidth,
|
uint32_t texWidth,
|
||||||
uint32_t texHeight,
|
uint32_t texHeight,
|
||||||
vks::VulkanDevice *device,
|
VulkanBase::VulkanDevice *device,
|
||||||
VkQueue copyQueue,
|
VkQueue copyQueue,
|
||||||
VkFilter filter = VK_FILTER_LINEAR,
|
VkFilter filter = VK_FILTER_LINEAR,
|
||||||
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
|
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
|
||||||
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||||
};
|
};
|
||||||
|
|
||||||
class Texture2DArray : public Texture
|
class Texture2DArray : public Texture
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void loadFromFile(
|
void loadFromFile(
|
||||||
std::string filename,
|
std::string filename,
|
||||||
VkFormat format,
|
VkFormat format,
|
||||||
vks::VulkanDevice *device,
|
VulkanBase::VulkanDevice *device,
|
||||||
VkQueue copyQueue,
|
VkQueue copyQueue,
|
||||||
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
|
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
|
||||||
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||||
};
|
};
|
||||||
|
|
||||||
class TextureCubeMap : public Texture
|
class TextureCubeMap : public Texture
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void loadFromFile(
|
void loadFromFile(
|
||||||
std::string filename,
|
std::string filename,
|
||||||
VkFormat format,
|
VkFormat format,
|
||||||
vks::VulkanDevice *device,
|
VulkanBase::VulkanDevice *device,
|
||||||
VkQueue copyQueue,
|
VkQueue copyQueue,
|
||||||
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
|
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
|
||||||
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||||
};
|
};
|
||||||
} // namespace vks
|
|
||||||
|
VULKANBASE_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -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();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,25 +1,27 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "vulkan/vulkan.h"
|
|
||||||
#include "VulkanInitializers.hpp"
|
#include "VulkanInitializers.hpp"
|
||||||
|
#include "vulkan/vulkan.h"
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
#include <stdlib.h>
|
#include <algorithm>
|
||||||
#include <string>
|
#include <assert.h>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <assert.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <vector>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <math.h>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <fstream>
|
#include <stdio.h>
|
||||||
#include <algorithm>
|
#include <stdlib.h>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#include <windows.h>
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
#elif defined(__ANDROID__)
|
#elif defined(__ANDROID__)
|
||||||
#include "VulkanAndroid.h"
|
#include "VulkanAndroid.h"
|
||||||
#include <android/asset_manager.h>
|
#include <android/asset_manager.h>
|
||||||
|
|
@ -32,114 +34,114 @@
|
||||||
|
|
||||||
// Macro to check and display Vulkan return results
|
// Macro to check and display Vulkan return results
|
||||||
#if defined(__ANDROID__)
|
#if defined(__ANDROID__)
|
||||||
#define VK_CHECK_RESULT(f) \
|
#define VK_CHECK_RESULT(f) \
|
||||||
{ \
|
{ \
|
||||||
VkResult res = (f); \
|
VkResult res = (f); \
|
||||||
if (res != VK_SUCCESS) \
|
if (res != VK_SUCCESS) \
|
||||||
{ \
|
{ \
|
||||||
LOGE("Fatal : VkResult is \" %s \" in %s at line %d", vks::tools::errorString(res).c_str(), __FILE__, __LINE__); \
|
LOGE("Fatal : VkResult is \" %s \" in %s at line %d", vks::tools::errorString(res).c_str(), __FILE__, __LINE__); \
|
||||||
assert(res == VK_SUCCESS); \
|
assert(res == VK_SUCCESS); \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#define VK_CHECK_RESULT(f) \
|
#define VK_CHECK_RESULT(f) \
|
||||||
{ \
|
{ \
|
||||||
VkResult res = (f); \
|
VkResult res = (f); \
|
||||||
if (res != VK_SUCCESS) \
|
if (res != VK_SUCCESS) \
|
||||||
{ \
|
{ \
|
||||||
std::cout << "Fatal : VkResult is \"" << vks::tools::errorString(res) << "\" in " << __FILE__ << " at line " << __LINE__ << "\n"; \
|
std::cout << "Fatal : VkResult is \"" << vks::tools::errorString(res) << "\" in " << __FILE__ << " at line " << __LINE__ << "\n"; \
|
||||||
assert(res == VK_SUCCESS); \
|
assert(res == VK_SUCCESS); \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define GET_INSTANCE_PROC_ADDR(inst, entrypoint) \
|
#define GET_INSTANCE_PROC_ADDR(inst, entrypoint) \
|
||||||
{ \
|
{ \
|
||||||
fp##entrypoint = reinterpret_cast<PFN_vk##entrypoint>(vkGetInstanceProcAddr(inst, "vk"#entrypoint)); \
|
fp##entrypoint = reinterpret_cast<PFN_vk##entrypoint>(vkGetInstanceProcAddr(inst, "vk" #entrypoint)); \
|
||||||
if (fp##entrypoint == NULL) \
|
if (fp##entrypoint == NULL) \
|
||||||
{ \
|
{ \
|
||||||
exit(1); \
|
exit(1); \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define GET_DEVICE_PROC_ADDR(dev, entrypoint) \
|
#define GET_DEVICE_PROC_ADDR(dev, entrypoint) \
|
||||||
{ \
|
{ \
|
||||||
fp##entrypoint = reinterpret_cast<PFN_vk##entrypoint>(vkGetDeviceProcAddr(dev, "vk"#entrypoint)); \
|
fp##entrypoint = reinterpret_cast<PFN_vk##entrypoint>(vkGetDeviceProcAddr(dev, "vk" #entrypoint)); \
|
||||||
if (fp##entrypoint == NULL) \
|
if (fp##entrypoint == NULL) \
|
||||||
{ \
|
{ \
|
||||||
exit(1); \
|
exit(1); \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string getAssetPath();
|
const std::string getAssetPath();
|
||||||
|
|
||||||
namespace vks
|
namespace vks
|
||||||
{
|
{
|
||||||
namespace tools
|
namespace tools
|
||||||
{
|
{
|
||||||
/** @brief Disable message boxes on fatal errors */
|
/** @brief Disable message boxes on fatal errors */
|
||||||
extern bool errorModeSilent;
|
extern bool errorModeSilent;
|
||||||
|
|
||||||
/** @brief Returns an error code as a string */
|
/** @brief Returns an error code as a string */
|
||||||
std::string errorString(VkResult errorCode);
|
std::string errorString(VkResult errorCode);
|
||||||
|
|
||||||
/** @brief Returns the device type as a string */
|
/** @brief Returns the device type as a string */
|
||||||
std::string physicalDeviceTypeString(VkPhysicalDeviceType type);
|
std::string physicalDeviceTypeString(VkPhysicalDeviceType type);
|
||||||
|
|
||||||
// Selected a suitable supported depth format starting with 32 bit down to 16 bit
|
// Selected a suitable supported depth format starting with 32 bit down to 16 bit
|
||||||
// Returns false if none of the depth formats in the list is supported by the device
|
// Returns false if none of the depth formats in the list is supported by the device
|
||||||
VkBool32 getSupportedDepthFormat(VkPhysicalDevice physicalDevice, VkFormat *depthFormat);
|
VkBool32 getSupportedDepthFormat(VkPhysicalDevice physicalDevice, VkFormat *depthFormat);
|
||||||
|
|
||||||
// Returns tru a given format support LINEAR filtering
|
// Returns tru a given format support LINEAR filtering
|
||||||
VkBool32 formatIsFilterable(VkPhysicalDevice physicalDevice, VkFormat format, VkImageTiling tiling);
|
VkBool32 formatIsFilterable(VkPhysicalDevice physicalDevice, VkFormat format, VkImageTiling tiling);
|
||||||
// Returns true if a given format has a stencil part
|
// Returns true if a given format has a stencil part
|
||||||
VkBool32 formatHasStencil(VkFormat format);
|
VkBool32 formatHasStencil(VkFormat format);
|
||||||
|
|
||||||
// Put an image memory barrier for setting an image layout on the sub resource into the given command buffer
|
// Put an image memory barrier for setting an image layout on the sub resource into the given command buffer
|
||||||
void setImageLayout(
|
void setImageLayout(
|
||||||
VkCommandBuffer cmdbuffer,
|
VkCommandBuffer cmdbuffer,
|
||||||
VkImage image,
|
VkImage image,
|
||||||
VkImageLayout oldImageLayout,
|
VkImageLayout oldImageLayout,
|
||||||
VkImageLayout newImageLayout,
|
VkImageLayout newImageLayout,
|
||||||
VkImageSubresourceRange subresourceRange,
|
VkImageSubresourceRange subresourceRange,
|
||||||
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||||
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
|
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
|
||||||
// Uses a fixed sub resource layout with first mip level and layer
|
// Uses a fixed sub resource layout with first mip level and layer
|
||||||
void setImageLayout(
|
void setImageLayout(
|
||||||
VkCommandBuffer cmdbuffer,
|
VkCommandBuffer cmdbuffer,
|
||||||
VkImage image,
|
VkImage image,
|
||||||
VkImageAspectFlags aspectMask,
|
VkImageAspectFlags aspectMask,
|
||||||
VkImageLayout oldImageLayout,
|
VkImageLayout oldImageLayout,
|
||||||
VkImageLayout newImageLayout,
|
VkImageLayout newImageLayout,
|
||||||
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||||
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
|
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
|
||||||
|
|
||||||
/** @brief Insert an image memory barrier into the command buffer */
|
/** @brief Insert an image memory barrier into the command buffer */
|
||||||
void insertImageMemoryBarrier(
|
void insertImageMemoryBarrier(
|
||||||
VkCommandBuffer cmdbuffer,
|
VkCommandBuffer cmdbuffer,
|
||||||
VkImage image,
|
VkImage image,
|
||||||
VkAccessFlags srcAccessMask,
|
VkAccessFlags srcAccessMask,
|
||||||
VkAccessFlags dstAccessMask,
|
VkAccessFlags dstAccessMask,
|
||||||
VkImageLayout oldImageLayout,
|
VkImageLayout oldImageLayout,
|
||||||
VkImageLayout newImageLayout,
|
VkImageLayout newImageLayout,
|
||||||
VkPipelineStageFlags srcStageMask,
|
VkPipelineStageFlags srcStageMask,
|
||||||
VkPipelineStageFlags dstStageMask,
|
VkPipelineStageFlags dstStageMask,
|
||||||
VkImageSubresourceRange subresourceRange);
|
VkImageSubresourceRange subresourceRange);
|
||||||
|
|
||||||
// Display error message and exit on fatal error
|
// Display error message and exit on fatal error
|
||||||
void exitFatal(const std::string& message, int32_t exitCode);
|
void exitFatal(const std::string &message, int32_t exitCode);
|
||||||
void exitFatal(const std::string& message, VkResult resultCode);
|
void exitFatal(const std::string &message, VkResult resultCode);
|
||||||
|
|
||||||
// Load a SPIR-V shader (binary)
|
// Load a SPIR-V shader (binary)
|
||||||
#if defined(__ANDROID__)
|
#if defined(__ANDROID__)
|
||||||
VkShaderModule loadShader(AAssetManager* assetManager, const char *fileName, VkDevice device);
|
VkShaderModule loadShader(AAssetManager *assetManager, const char *fileName, VkDevice device);
|
||||||
#else
|
#else
|
||||||
VkShaderModule loadShader(const char *fileName, VkDevice device);
|
VkShaderModule loadShader(const char *fileName, VkDevice device);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** @brief Checks if a file exists */
|
/** @brief Checks if a file exists */
|
||||||
bool fileExists(const std::string &filename);
|
bool fileExists(const std::string &filename);
|
||||||
|
|
||||||
uint32_t alignedSize(uint32_t value, uint32_t alignment);
|
uint32_t alignedSize(uint32_t value, uint32_t alignment);
|
||||||
}
|
} // namespace tools
|
||||||
}
|
} // namespace vks
|
||||||
|
|
|
||||||
|
|
@ -1,176 +0,0 @@
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <fstream>
|
|
||||||
#include <iostream>
|
|
||||||
#include <string>
|
|
||||||
#include <map>
|
|
||||||
#include "vulkan/vulkan.h"
|
|
||||||
#include "VulkanDevice.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Vulkan buffer object
|
|
||||||
*/
|
|
||||||
struct Buffer {
|
|
||||||
VkDevice device;
|
|
||||||
VkBuffer buffer = VK_NULL_HANDLE;
|
|
||||||
VkDeviceMemory memory = VK_NULL_HANDLE;
|
|
||||||
VkDescriptorBufferInfo descriptor;
|
|
||||||
int32_t count = 0;
|
|
||||||
void *mapped = nullptr;
|
|
||||||
void create(vks::VulkanDevice *device, VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkDeviceSize size, bool map = true) {
|
|
||||||
this->device = device->logicalDevice;
|
|
||||||
device->createBuffer(usageFlags, memoryPropertyFlags, size, &buffer, &memory);
|
|
||||||
descriptor = { buffer, 0, size };
|
|
||||||
if (map) {
|
|
||||||
VK_CHECK_RESULT(vkMapMemory(device->logicalDevice, memory, 0, size, 0, &mapped));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void destroy() {
|
|
||||||
if (mapped) {
|
|
||||||
unmap();
|
|
||||||
}
|
|
||||||
vkDestroyBuffer(device, buffer, nullptr);
|
|
||||||
vkFreeMemory(device, memory, nullptr);
|
|
||||||
buffer = VK_NULL_HANDLE;
|
|
||||||
memory = VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
void map() {
|
|
||||||
VK_CHECK_RESULT(vkMapMemory(device, memory, 0, VK_WHOLE_SIZE, 0, &mapped));
|
|
||||||
}
|
|
||||||
void unmap() {
|
|
||||||
if (mapped) {
|
|
||||||
vkUnmapMemory(device, memory);
|
|
||||||
mapped = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void flush(VkDeviceSize size = VK_WHOLE_SIZE) {
|
|
||||||
VkMappedMemoryRange mappedRange{};
|
|
||||||
mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
|
|
||||||
mappedRange.memory = memory;
|
|
||||||
mappedRange.size = size;
|
|
||||||
VK_CHECK_RESULT(vkFlushMappedMemoryRanges(device, 1, &mappedRange));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
VkPipelineShaderStageCreateInfo loadShader(VkDevice device, std::string filename, VkShaderStageFlagBits stage)
|
|
||||||
{
|
|
||||||
VkPipelineShaderStageCreateInfo shaderStage{};
|
|
||||||
shaderStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
|
||||||
shaderStage.stage = stage;
|
|
||||||
shaderStage.pName = "main";
|
|
||||||
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
|
|
||||||
std::string assetpath = "shaders/" + filename;
|
|
||||||
AAsset* asset = AAssetManager_open(androidApp->activity->assetManager, assetpath.c_str(), AASSET_MODE_STREAMING);
|
|
||||||
assert(asset);
|
|
||||||
size_t size = AAsset_getLength(asset);
|
|
||||||
assert(size > 0);
|
|
||||||
char *shaderCode = new char[size];
|
|
||||||
AAsset_read(asset, shaderCode, size);
|
|
||||||
AAsset_close(asset);
|
|
||||||
VkShaderModule shaderModule;
|
|
||||||
VkShaderModuleCreateInfo moduleCreateInfo;
|
|
||||||
moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
|
||||||
moduleCreateInfo.pNext = NULL;
|
|
||||||
moduleCreateInfo.codeSize = size;
|
|
||||||
moduleCreateInfo.pCode = (uint32_t*)shaderCode;
|
|
||||||
moduleCreateInfo.flags = 0;
|
|
||||||
VK_CHECK_RESULT(vkCreateShaderModule(device, &moduleCreateInfo, NULL, &shaderStage.module));
|
|
||||||
delete[] shaderCode;
|
|
||||||
#else
|
|
||||||
std::ifstream is(filename, std::ios::binary | std::ios::in | std::ios::ate);
|
|
||||||
|
|
||||||
if (is.is_open()) {
|
|
||||||
size_t size = is.tellg();
|
|
||||||
is.seekg(0, std::ios::beg);
|
|
||||||
char* shaderCode = new char[size];
|
|
||||||
is.read(shaderCode, size);
|
|
||||||
is.close();
|
|
||||||
assert(size > 0);
|
|
||||||
VkShaderModuleCreateInfo moduleCreateInfo{};
|
|
||||||
moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
|
||||||
moduleCreateInfo.codeSize = size;
|
|
||||||
moduleCreateInfo.pCode = (uint32_t*)shaderCode;
|
|
||||||
vkCreateShaderModule(device, &moduleCreateInfo, NULL, &shaderStage.module);
|
|
||||||
delete[] shaderCode;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
std::cerr << "Error: Could not open shader file \"" << filename << "\"" << std::endl;
|
|
||||||
shaderStage.module = VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
assert(shaderStage.module != VK_NULL_HANDLE);
|
|
||||||
return shaderStage;
|
|
||||||
}
|
|
||||||
|
|
||||||
void readDirectory(const std::string& directory, const std::string &pattern, std::map<std::string, std::string> &filelist, bool recursive)
|
|
||||||
{
|
|
||||||
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
|
|
||||||
AAssetDir* assetDir = AAssetManager_openDir(androidApp->activity->assetManager, directory.c_str());
|
|
||||||
AAssetDir_rewind(assetDir);
|
|
||||||
const char* assetName;
|
|
||||||
while ((assetName = AAssetDir_getNextFileName(assetDir)) != 0) {
|
|
||||||
std::string filename(assetName);
|
|
||||||
filename.erase(filename.find_last_of("."), std::string::npos);
|
|
||||||
filelist[filename] = directory + "/" + assetName;
|
|
||||||
}
|
|
||||||
AAssetDir_close(assetDir);
|
|
||||||
#elif defined(VK_USE_PLATFORM_WIN32_KHR)
|
|
||||||
std::string searchpattern(directory + "/" + pattern);
|
|
||||||
WIN32_FIND_DATA data;
|
|
||||||
HANDLE hFind;
|
|
||||||
if ((hFind = FindFirstFile(searchpattern.c_str(), &data)) != INVALID_HANDLE_VALUE) {
|
|
||||||
do {
|
|
||||||
std::string filename(data.cFileName);
|
|
||||||
filename.erase(filename.find_last_of("."), std::string::npos);
|
|
||||||
filelist[filename] = directory + "/" + data.cFileName;
|
|
||||||
} while (FindNextFile(hFind, &data) != 0);
|
|
||||||
FindClose(hFind);
|
|
||||||
}
|
|
||||||
if (recursive) {
|
|
||||||
std::string dirpattern = directory + "/*";
|
|
||||||
if ((hFind = FindFirstFile(dirpattern.c_str(), &data)) != INVALID_HANDLE_VALUE) {
|
|
||||||
do {
|
|
||||||
if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
|
||||||
char subdir[MAX_PATH];
|
|
||||||
strcpy(subdir, directory.c_str());
|
|
||||||
strcat(subdir, "/");
|
|
||||||
strcat(subdir, data.cFileName);
|
|
||||||
if ((strcmp(data.cFileName, ".") != 0) && (strcmp(data.cFileName, "..") != 0)) {
|
|
||||||
readDirectory(subdir, pattern, filelist, recursive);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (FindNextFile(hFind, &data) != 0);
|
|
||||||
FindClose(hFind);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#elif defined(__linux__)
|
|
||||||
std::string patternExt = pattern;
|
|
||||||
patternExt.erase(0, pattern.find_last_of("."));
|
|
||||||
struct dirent *entry;
|
|
||||||
DIR *dir = opendir(directory.c_str());
|
|
||||||
if (dir == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
while ((entry = readdir(dir)) != NULL) {
|
|
||||||
if (entry->d_type == DT_REG) {
|
|
||||||
std::string filename(entry->d_name);
|
|
||||||
if (filename.find(patternExt) != std::string::npos) {
|
|
||||||
filename.erase(filename.find_last_of("."), std::string::npos);
|
|
||||||
filelist[filename] = directory + "/" + entry->d_name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (recursive && (entry->d_type == DT_DIR)) {
|
|
||||||
std::string subdir = directory + "/" + entry->d_name;
|
|
||||||
if ((strcmp(entry->d_name, ".") != 0) && (strcmp(entry->d_name, "..") != 0)) {
|
|
||||||
readDirectory(subdir, pattern, filelist, recursive);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
closedir(dir);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
356
src/base/ui.hpp
356
src/base/ui.hpp
|
|
@ -1,356 +0,0 @@
|
||||||
|
|
||||||
#include "VulkanDevice.hpp"
|
|
||||||
#include "VulkanUtils.hpp"
|
|
||||||
#include "VulkanTexture.hpp"
|
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
|
||||||
#include <android/asset_manager.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <vulkan/vulkan.h>
|
|
||||||
|
|
||||||
#include <imgui.h>
|
|
||||||
#include <backends/imgui_impl_vulkan.h>
|
|
||||||
#include <backends/imgui_impl_glfw.h>
|
|
||||||
|
|
||||||
#define GLM_FORCE_RADIANS
|
|
||||||
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
|
|
||||||
#include <glm/glm.hpp>
|
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <array>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
|
|
||||||
struct UI {
|
|
||||||
private:
|
|
||||||
VkDevice device;
|
|
||||||
public:
|
|
||||||
Buffer vertexBuffer, indexBuffer;
|
|
||||||
vks::Texture2D fontTexture;
|
|
||||||
VkPipelineLayout pipelineLayout;
|
|
||||||
VkPipeline pipeline;
|
|
||||||
VkDescriptorPool descriptorPool;
|
|
||||||
VkDescriptorSetLayout descriptorSetLayout;
|
|
||||||
VkDescriptorSet descriptorSet;
|
|
||||||
|
|
||||||
struct PushConstBlock {
|
|
||||||
glm::vec2 scale;
|
|
||||||
glm::vec2 translate;
|
|
||||||
} pushConstBlock;
|
|
||||||
|
|
||||||
UI(vks::VulkanDevice *vulkanDevice, VkRenderPass renderPass, VkQueue queue, VkPipelineCache pipelineCache, VkSampleCountFlagBits multiSampleCount) {
|
|
||||||
|
|
||||||
this->device = vulkanDevice->logicalDevice;
|
|
||||||
|
|
||||||
ImGui::CreateContext();
|
|
||||||
|
|
||||||
/*
|
|
||||||
Font texture loading
|
|
||||||
*/
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
|
||||||
|
|
||||||
/// enable keyborad and gamepad input
|
|
||||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
|
|
||||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
|
|
||||||
|
|
||||||
unsigned char* fontData;
|
|
||||||
int texWidth, texHeight;
|
|
||||||
std::string ttfFilePath = getAssetPath() + "/STXINWEI.TTF";
|
|
||||||
io.Fonts->AddFontFromFileTTF(ttfFilePath.data(), 16.0f,NULL, io.Fonts->GetGlyphRangesChineseSimplifiedCommon());
|
|
||||||
io.Fonts->GetTexDataAsRGBA32(&fontData, &texWidth, &texHeight);
|
|
||||||
fontTexture.loadFromBuffer(fontData, texWidth * texHeight * 4 * sizeof(char), VK_FORMAT_R8G8B8A8_UNORM, texWidth, texHeight, vulkanDevice, queue);
|
|
||||||
|
|
||||||
/*
|
|
||||||
Setup
|
|
||||||
*/
|
|
||||||
ImGuiStyle& style = ImGui::GetStyle();
|
|
||||||
style.FrameBorderSize = 0.0f;
|
|
||||||
style.WindowBorderSize = 0.0f;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Descriptor pool
|
|
||||||
*/
|
|
||||||
std::vector<VkDescriptorPoolSize> poolSizes = {
|
|
||||||
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1 }
|
|
||||||
};
|
|
||||||
VkDescriptorPoolCreateInfo descriptorPoolCI{};
|
|
||||||
descriptorPoolCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
|
||||||
descriptorPoolCI.poolSizeCount = 1;
|
|
||||||
descriptorPoolCI.pPoolSizes = poolSizes.data();
|
|
||||||
descriptorPoolCI.maxSets = 1;
|
|
||||||
VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolCI, nullptr, &descriptorPool));
|
|
||||||
|
|
||||||
/*
|
|
||||||
Descriptor set layout
|
|
||||||
*/
|
|
||||||
VkDescriptorSetLayoutBinding setLayoutBinding{ 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr };
|
|
||||||
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI{};
|
|
||||||
descriptorSetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
|
||||||
descriptorSetLayoutCI.pBindings = &setLayoutBinding;
|
|
||||||
descriptorSetLayoutCI.bindingCount = 1;
|
|
||||||
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorSetLayout));
|
|
||||||
|
|
||||||
/*
|
|
||||||
Descriptor set
|
|
||||||
*/
|
|
||||||
VkDescriptorSetAllocateInfo descriptorSetAllocInfo{};
|
|
||||||
descriptorSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
|
||||||
descriptorSetAllocInfo.descriptorPool = descriptorPool;
|
|
||||||
descriptorSetAllocInfo.pSetLayouts = &descriptorSetLayout;
|
|
||||||
descriptorSetAllocInfo.descriptorSetCount = 1;
|
|
||||||
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocInfo, &descriptorSet));
|
|
||||||
VkWriteDescriptorSet writeDescriptorSet{};
|
|
||||||
writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
|
||||||
writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
|
||||||
writeDescriptorSet.descriptorCount = 1;
|
|
||||||
writeDescriptorSet.dstSet = descriptorSet;
|
|
||||||
writeDescriptorSet.dstBinding = 0;
|
|
||||||
writeDescriptorSet.pImageInfo = &fontTexture.descriptor;
|
|
||||||
vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr);
|
|
||||||
|
|
||||||
/*
|
|
||||||
Pipeline layout
|
|
||||||
*/
|
|
||||||
VkPushConstantRange pushConstantRange{ VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(PushConstBlock) };
|
|
||||||
|
|
||||||
VkPipelineLayoutCreateInfo pipelineLayoutCI{};
|
|
||||||
pipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
|
||||||
pipelineLayoutCI.pushConstantRangeCount = 1;
|
|
||||||
pipelineLayoutCI.pPushConstantRanges = &pushConstantRange;
|
|
||||||
pipelineLayoutCI.setLayoutCount = 1;
|
|
||||||
pipelineLayoutCI.pSetLayouts = &descriptorSetLayout;
|
|
||||||
pipelineLayoutCI.pushConstantRangeCount = 1;
|
|
||||||
pipelineLayoutCI.pPushConstantRanges = &pushConstantRange;
|
|
||||||
VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelineLayout));
|
|
||||||
|
|
||||||
/*
|
|
||||||
Pipeline
|
|
||||||
*/
|
|
||||||
VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI{};
|
|
||||||
inputAssemblyStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
|
||||||
inputAssemblyStateCI.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
|
||||||
|
|
||||||
VkPipelineRasterizationStateCreateInfo rasterizationStateCI{};
|
|
||||||
rasterizationStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
|
||||||
rasterizationStateCI.polygonMode = VK_POLYGON_MODE_FILL;
|
|
||||||
rasterizationStateCI.cullMode = VK_CULL_MODE_NONE;
|
|
||||||
rasterizationStateCI.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
|
|
||||||
rasterizationStateCI.lineWidth = 1.0f;
|
|
||||||
|
|
||||||
VkPipelineColorBlendAttachmentState blendAttachmentState{};
|
|
||||||
blendAttachmentState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
|
||||||
blendAttachmentState.blendEnable = VK_TRUE;
|
|
||||||
blendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
|
||||||
blendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
|
||||||
blendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD;
|
|
||||||
blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
|
||||||
blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
|
||||||
blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD;
|
|
||||||
|
|
||||||
VkPipelineColorBlendStateCreateInfo colorBlendStateCI{};
|
|
||||||
colorBlendStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
|
||||||
colorBlendStateCI.attachmentCount = 1;
|
|
||||||
colorBlendStateCI.pAttachments = &blendAttachmentState;
|
|
||||||
|
|
||||||
VkPipelineDepthStencilStateCreateInfo depthStencilStateCI{};
|
|
||||||
depthStencilStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
|
|
||||||
depthStencilStateCI.depthTestEnable = VK_FALSE;
|
|
||||||
depthStencilStateCI.depthWriteEnable = VK_FALSE;
|
|
||||||
depthStencilStateCI.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
|
|
||||||
depthStencilStateCI.front = depthStencilStateCI.back;
|
|
||||||
depthStencilStateCI.back.compareOp = VK_COMPARE_OP_ALWAYS;
|
|
||||||
|
|
||||||
VkPipelineViewportStateCreateInfo viewportStateCI{};
|
|
||||||
viewportStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
|
||||||
viewportStateCI.viewportCount = 1;
|
|
||||||
viewportStateCI.scissorCount = 1;
|
|
||||||
|
|
||||||
VkPipelineMultisampleStateCreateInfo multisampleStateCI{};
|
|
||||||
multisampleStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
|
||||||
|
|
||||||
if (multiSampleCount > VK_SAMPLE_COUNT_1_BIT) {
|
|
||||||
multisampleStateCI.rasterizationSamples = multiSampleCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<VkDynamicState> dynamicStateEnables = {
|
|
||||||
VK_DYNAMIC_STATE_VIEWPORT,
|
|
||||||
VK_DYNAMIC_STATE_SCISSOR
|
|
||||||
};
|
|
||||||
VkPipelineDynamicStateCreateInfo dynamicStateCI{};
|
|
||||||
dynamicStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
|
||||||
dynamicStateCI.pDynamicStates = dynamicStateEnables.data();
|
|
||||||
dynamicStateCI.dynamicStateCount = static_cast<uint32_t>(dynamicStateEnables.size());
|
|
||||||
|
|
||||||
VkVertexInputBindingDescription vertexInputBinding = { 0, 20, VK_VERTEX_INPUT_RATE_VERTEX };
|
|
||||||
std::vector<VkVertexInputAttributeDescription> vertexInputAttributes = {
|
|
||||||
{ 0, 0, VK_FORMAT_R32G32_SFLOAT, 0 },
|
|
||||||
{ 1, 0, VK_FORMAT_R32G32_SFLOAT, sizeof(float) * 2 },
|
|
||||||
{ 2, 0, VK_FORMAT_R8G8B8A8_UNORM, sizeof(float) * 4 },
|
|
||||||
};
|
|
||||||
VkPipelineVertexInputStateCreateInfo vertexInputStateCI{};
|
|
||||||
vertexInputStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
|
||||||
vertexInputStateCI.vertexBindingDescriptionCount = 1;
|
|
||||||
vertexInputStateCI.pVertexBindingDescriptions = &vertexInputBinding;
|
|
||||||
vertexInputStateCI.vertexAttributeDescriptionCount = static_cast<uint32_t>(vertexInputAttributes.size());
|
|
||||||
vertexInputStateCI.pVertexAttributeDescriptions = vertexInputAttributes.data();
|
|
||||||
|
|
||||||
std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages;
|
|
||||||
|
|
||||||
VkGraphicsPipelineCreateInfo pipelineCI{};
|
|
||||||
pipelineCI.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
|
||||||
pipelineCI.layout = pipelineLayout;
|
|
||||||
pipelineCI.renderPass = renderPass;
|
|
||||||
pipelineCI.pInputAssemblyState = &inputAssemblyStateCI;
|
|
||||||
pipelineCI.pVertexInputState = &vertexInputStateCI;
|
|
||||||
pipelineCI.pRasterizationState = &rasterizationStateCI;
|
|
||||||
pipelineCI.pColorBlendState = &colorBlendStateCI;
|
|
||||||
pipelineCI.pMultisampleState = &multisampleStateCI;
|
|
||||||
pipelineCI.pViewportState = &viewportStateCI;
|
|
||||||
pipelineCI.pDepthStencilState = &depthStencilStateCI;
|
|
||||||
pipelineCI.pDynamicState = &dynamicStateCI;
|
|
||||||
pipelineCI.stageCount = static_cast<uint32_t>(shaderStages.size());
|
|
||||||
pipelineCI.pStages = shaderStages.data();
|
|
||||||
|
|
||||||
pipelineCI.layout = pipelineLayout;
|
|
||||||
std::string uiVertShaderPath = getAssetPath() + "shaders/ui.vert.spv";
|
|
||||||
std::string uiFragShaderPath = getAssetPath() + "shaders/ui.frag.spv";
|
|
||||||
shaderStages = {
|
|
||||||
|
|
||||||
loadShader(device, uiVertShaderPath.data(), VK_SHADER_STAGE_VERTEX_BIT),
|
|
||||||
loadShader(device, uiFragShaderPath.data(), VK_SHADER_STAGE_FRAGMENT_BIT)
|
|
||||||
};
|
|
||||||
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipeline));
|
|
||||||
|
|
||||||
for (auto shaderStage : shaderStages) {
|
|
||||||
vkDestroyShaderModule(device, shaderStage.module, nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~UI() {
|
|
||||||
ImGui::DestroyContext();
|
|
||||||
vertexBuffer.destroy();
|
|
||||||
indexBuffer.destroy();
|
|
||||||
vkDestroyPipeline(device, pipeline, nullptr);
|
|
||||||
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
|
|
||||||
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
|
|
||||||
vkDestroyDescriptorPool(device, descriptorPool, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw(VkCommandBuffer cmdBuffer) {
|
|
||||||
vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
|
||||||
vkCmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr);
|
|
||||||
|
|
||||||
const VkDeviceSize offsets[1] = { 0 };
|
|
||||||
vkCmdBindVertexBuffers(cmdBuffer, 0, 1, &vertexBuffer.buffer, offsets);
|
|
||||||
vkCmdBindIndexBuffer(cmdBuffer, indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT16);
|
|
||||||
|
|
||||||
vkCmdPushConstants(cmdBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(UI::PushConstBlock), &pushConstBlock);
|
|
||||||
|
|
||||||
ImDrawData* imDrawData = ImGui::GetDrawData();
|
|
||||||
int32_t vertexOffset = 0;
|
|
||||||
int32_t indexOffset = 0;
|
|
||||||
for (int32_t j = 0; j < imDrawData->CmdListsCount; j++) {
|
|
||||||
const ImDrawList* cmd_list = imDrawData->CmdLists[j];
|
|
||||||
for (int32_t k = 0; k < cmd_list->CmdBuffer.Size; k++) {
|
|
||||||
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[k];
|
|
||||||
VkRect2D scissorRect;
|
|
||||||
scissorRect.offset.x = std::max((int32_t)(pcmd->ClipRect.x), 0);
|
|
||||||
scissorRect.offset.y = std::max((int32_t)(pcmd->ClipRect.y), 0);
|
|
||||||
scissorRect.extent.width = (uint32_t)(pcmd->ClipRect.z - pcmd->ClipRect.x);
|
|
||||||
scissorRect.extent.height = (uint32_t)(pcmd->ClipRect.w - pcmd->ClipRect.y);
|
|
||||||
vkCmdSetScissor(cmdBuffer, 0, 1, &scissorRect);
|
|
||||||
vkCmdDrawIndexed(cmdBuffer, pcmd->ElemCount, 1, indexOffset, vertexOffset, 0);
|
|
||||||
indexOffset += pcmd->ElemCount;
|
|
||||||
}
|
|
||||||
vertexOffset += cmd_list->VtxBuffer.Size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
bool checkbox(const char* caption, T *value) {
|
|
||||||
bool val = (*value == 1);
|
|
||||||
bool res = ImGui::Checkbox(caption, &val);
|
|
||||||
*value = val;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
bool header(const char *caption) {
|
|
||||||
return ImGui::CollapsingHeader(caption, ImGuiTreeNodeFlags_DefaultOpen);
|
|
||||||
}
|
|
||||||
bool slider(const char* caption, float* value, float min, float max) {
|
|
||||||
return ImGui::SliderFloat(caption, value, min, max);
|
|
||||||
}
|
|
||||||
bool combo(const char *caption, int32_t *itemindex, std::vector<std::string> items) {
|
|
||||||
if (items.empty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
std::vector<const char*> charitems;
|
|
||||||
charitems.reserve(items.size());
|
|
||||||
for (size_t i = 0; i < items.size(); i++) {
|
|
||||||
charitems.push_back(items[i].c_str());
|
|
||||||
}
|
|
||||||
uint32_t itemCount = static_cast<uint32_t>(charitems.size());
|
|
||||||
return ImGui::Combo(caption, itemindex, &charitems[0], itemCount, itemCount);
|
|
||||||
}
|
|
||||||
bool combo(const char *caption, std::string &selectedkey, std::map<std::string, std::string> items) {
|
|
||||||
bool selectionChanged = false;
|
|
||||||
if (ImGui::BeginCombo(caption, selectedkey.c_str())) {
|
|
||||||
for (auto it = items.begin(); it != items.end(); ++it) {
|
|
||||||
const bool isSelected = it->first == selectedkey;
|
|
||||||
if (ImGui::Selectable(it->first.c_str(), isSelected)) {
|
|
||||||
selectionChanged = it->first != selectedkey;
|
|
||||||
selectedkey = it->first;
|
|
||||||
}
|
|
||||||
if (isSelected) {
|
|
||||||
ImGui::SetItemDefaultFocus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ImGui::EndCombo();
|
|
||||||
}
|
|
||||||
return selectionChanged;
|
|
||||||
}
|
|
||||||
bool button(const char *caption) {
|
|
||||||
return ImGui::Button(caption);
|
|
||||||
}
|
|
||||||
bool beginChild(const char* caption, ImVec2 size, bool border)
|
|
||||||
{
|
|
||||||
return ImGui::BeginChild(caption, size, border);
|
|
||||||
}
|
|
||||||
|
|
||||||
void endChild()
|
|
||||||
{
|
|
||||||
return ImGui::EndChild();
|
|
||||||
}
|
|
||||||
|
|
||||||
// menu GUI
|
|
||||||
bool beginMainMenuBar() {
|
|
||||||
return ImGui::BeginMainMenuBar();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool beginMenu(const char* caption)
|
|
||||||
{
|
|
||||||
return ImGui::BeginMenu(caption);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool menuItem(const char* caption)
|
|
||||||
{
|
|
||||||
return ImGui::MenuItem(caption);
|
|
||||||
}
|
|
||||||
void endMenu()
|
|
||||||
{
|
|
||||||
return ImGui::EndMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void endMainMenuBar() {
|
|
||||||
return ImGui::EndMainMenuBar();
|
|
||||||
}
|
|
||||||
|
|
||||||
void text(const char *formatstr, ...) {
|
|
||||||
va_list args;
|
|
||||||
va_start(args, formatstr);
|
|
||||||
ImGui::TextV(formatstr, args);
|
|
||||||
va_end(args);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,24 +1,26 @@
|
||||||
/*
|
/*
|
||||||
* Vulkan Example base class
|
* Vulkan Example base class
|
||||||
*
|
*
|
||||||
* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
|
* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
|
||||||
*
|
*
|
||||||
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
|
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#pragma comment(linker, "/subsystem:windows")
|
#pragma comment(linker, "/subsystem:windows")
|
||||||
#include <windows.h>
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
|
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
|
||||||
#include <android/native_activity.h>
|
#include "VulkanAndroid.h"
|
||||||
#include <android/asset_manager.h>
|
#include <android/asset_manager.h>
|
||||||
|
#include <android/native_activity.h>
|
||||||
#include <android_native_app_glue.h>
|
#include <android_native_app_glue.h>
|
||||||
#include <sys/system_properties.h>
|
#include <sys/system_properties.h>
|
||||||
#include "VulkanAndroid.h"
|
|
||||||
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||||
#include <wayland-client.h>
|
#include <wayland-client.h>
|
||||||
#elif defined(_DIRECT2DISPLAY)
|
#elif defined(_DIRECT2DISPLAY)
|
||||||
|
|
@ -26,24 +28,25 @@
|
||||||
#elif defined(VK_USE_PLATFORM_XCB_KHR)
|
#elif defined(VK_USE_PLATFORM_XCB_KHR)
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
#elif defined(VK_USE_PLATFORM_MACOS_MVK)
|
#elif defined(VK_USE_PLATFORM_MACOS_MVK)
|
||||||
#include <Cocoa/Cocoa.h>
|
|
||||||
#include <Carbon/Carbon.h>
|
#include <Carbon/Carbon.h>
|
||||||
#include <QuartzCore/CAMetalLayer.h>
|
#include <Cocoa/Cocoa.h>
|
||||||
#include <CoreVideo/CVDisplayLink.h>
|
#include <CoreVideo/CVDisplayLink.h>
|
||||||
|
#include <QuartzCore/CAMetalLayer.h>
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <iostream>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#define GLM_FORCE_RADIANS
|
#define GLM_FORCE_RADIANS
|
||||||
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
|
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
|
||||||
#define GLM_ENABLE_EXPERIMENTAL
|
#define GLM_ENABLE_EXPERIMENTAL
|
||||||
#include <glm/glm.hpp>
|
|
||||||
#include <string>
|
|
||||||
#include <sstream>
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "vulkan/vulkan.h"
|
#include "vulkan/vulkan.h"
|
||||||
|
|
||||||
|
|
@ -51,218 +54,228 @@
|
||||||
#include "camera.hpp"
|
#include "camera.hpp"
|
||||||
#include "keycodes.hpp"
|
#include "keycodes.hpp"
|
||||||
|
|
||||||
#include "VulkanDevice.hpp"
|
#include "VulkanDevice.h"
|
||||||
#include "VulkanSwapChain.hpp"
|
#include "VulkanSwapChain.hpp"
|
||||||
|
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
|
||||||
class VulkanExampleBase
|
class VulkanExampleBase
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
float fpsTimer = 0.0f;
|
float fpsTimer = 0.0f;
|
||||||
uint32_t frameCounter = 0;
|
uint32_t frameCounter = 0;
|
||||||
uint32_t destWidth;
|
uint32_t destWidth;
|
||||||
uint32_t destHeight;
|
uint32_t destHeight;
|
||||||
bool resizing = false;
|
bool resizing = false;
|
||||||
void handleMouseMove(int32_t x, int32_t y);
|
void handleMouseMove(int32_t x, int32_t y);
|
||||||
PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallback;
|
PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallback;
|
||||||
PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallback;
|
PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallback;
|
||||||
VkDebugReportCallbackEXT debugReportCallback;
|
VkDebugReportCallbackEXT debugReportCallback;
|
||||||
struct MultisampleTarget {
|
struct MultisampleTarget
|
||||||
struct {
|
{
|
||||||
VkImage image;
|
struct
|
||||||
VkImageView view;
|
{
|
||||||
VkDeviceMemory memory;
|
VkImage image;
|
||||||
} color;
|
VkImageView view;
|
||||||
struct {
|
VkDeviceMemory memory;
|
||||||
VkImage image;
|
} color;
|
||||||
VkImageView view;
|
struct
|
||||||
VkDeviceMemory memory;
|
{
|
||||||
} depth;
|
VkImage image;
|
||||||
} multisampleTarget;
|
VkImageView view;
|
||||||
|
VkDeviceMemory memory;
|
||||||
|
} depth;
|
||||||
|
} multisampleTarget;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
VkInstance instance;
|
VkInstance instance;
|
||||||
VkPhysicalDevice physicalDevice;
|
VkPhysicalDevice physicalDevice;
|
||||||
VkPhysicalDeviceProperties deviceProperties;
|
VkPhysicalDeviceProperties deviceProperties;
|
||||||
VkPhysicalDeviceFeatures deviceFeatures;
|
VkPhysicalDeviceFeatures deviceFeatures;
|
||||||
VkPhysicalDeviceMemoryProperties deviceMemoryProperties;
|
VkPhysicalDeviceMemoryProperties deviceMemoryProperties;
|
||||||
VkDevice device;
|
VkDevice device;
|
||||||
vks::VulkanDevice *vulkanDevice;
|
VulkanBase::VulkanDevice *vulkanDevice;
|
||||||
VkQueue queue;
|
VkQueue queue;
|
||||||
VkFormat depthFormat;
|
VkFormat depthFormat;
|
||||||
VkCommandPool cmdPool;
|
VkCommandPool cmdPool;
|
||||||
VkRenderPass renderPass;
|
VkRenderPass renderPass;
|
||||||
std::vector<VkFramebuffer>frameBuffers;
|
std::vector<VkFramebuffer> frameBuffers;
|
||||||
uint32_t currentBuffer = 0;
|
uint32_t currentBuffer = 0;
|
||||||
VkDescriptorPool descriptorPool;
|
VkDescriptorPool descriptorPool;
|
||||||
VkPipelineCache pipelineCache;
|
VkPipelineCache pipelineCache;
|
||||||
VulkanSwapChain swapChain;
|
VulkanSwapChain swapChain;
|
||||||
std::string title = "Vulkan Example";
|
std::string title = "Vulkan Example";
|
||||||
std::string name = "vulkanExample";
|
std::string name = "vulkanExample";
|
||||||
void windowResize();
|
void windowResize();
|
||||||
public:
|
|
||||||
static std::vector<const char*> args;
|
|
||||||
uint32_t selectedPhysicalDeviceIndex = 0;
|
|
||||||
bool prepared = false;
|
|
||||||
uint32_t width = 1280;
|
|
||||||
uint32_t height = 720;
|
|
||||||
float frameTimer = 1.0f;
|
|
||||||
Camera camera;
|
|
||||||
glm::vec2 mousePos;
|
|
||||||
bool paused = false;
|
|
||||||
uint32_t lastFPS = 0;
|
|
||||||
|
|
||||||
struct Settings {
|
public:
|
||||||
bool validation = false; // 校验层开关
|
static std::vector<const char *> args;
|
||||||
bool fullscreen = false; // 全屏开关
|
uint32_t selectedPhysicalDeviceIndex = 0;
|
||||||
bool vsync = false; // 垂直同步开关
|
bool prepared = false;
|
||||||
bool multiSampling = true; // 多重采样
|
uint32_t width = 1280;
|
||||||
bool rotateModel = false; // 模型自旋转(暂时失效)
|
uint32_t height = 720;
|
||||||
bool headless = false; // 无头开关
|
float frameTimer = 1.0f;
|
||||||
bool outputPNGimage = false;
|
Camera camera;
|
||||||
bool enableSaveToImageSequeue = true; // 图片序列开关(暂时弃用)
|
glm::vec2 mousePos;
|
||||||
uint32_t outputFrameCount = 100; // 图片序列结束帧
|
bool paused = false;
|
||||||
bool takeScreenShot = false; // 截屏(暂时弃用)
|
uint32_t lastFPS = 0;
|
||||||
uint32_t startFrameCount = 1; // 图片序列开始帧
|
|
||||||
|
|
||||||
uint32_t videoFrameRate = 25;
|
struct Settings
|
||||||
|
{
|
||||||
|
bool validation = false; // 校验层开关
|
||||||
|
bool fullscreen = false; // 全屏开关
|
||||||
|
bool vsync = false; // 垂直同步开关
|
||||||
|
bool multiSampling = true; // 多重采样
|
||||||
|
bool rotateModel = false; // 模型自旋转(暂时失效)
|
||||||
|
bool headless = false; // 无头开关
|
||||||
|
bool outputPNGimage = false;
|
||||||
|
bool enableSaveToImageSequeue = true; // 图片序列开关(暂时弃用)
|
||||||
|
uint32_t outputFrameCount = 100; // 图片序列结束帧
|
||||||
|
bool takeScreenShot = false; // 截屏(暂时弃用)
|
||||||
|
uint32_t startFrameCount = 1; // 图片序列开始帧
|
||||||
|
|
||||||
VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_4_BIT; // 多重采样倍率
|
uint32_t videoFrameRate = 25;
|
||||||
} settings;
|
|
||||||
|
|
||||||
struct DepthStencil {
|
|
||||||
VkImage image;
|
|
||||||
VkDeviceMemory mem;
|
|
||||||
VkImageView view;
|
|
||||||
} depthStencil;
|
|
||||||
|
|
||||||
struct GamePadState {
|
VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_4_BIT; // 多重采样倍率
|
||||||
glm::vec2 axisLeft = glm::vec2(0.0f);
|
} settings;
|
||||||
glm::vec2 axisRight = glm::vec2(0.0f);
|
|
||||||
} gamePadState;
|
|
||||||
|
|
||||||
struct MouseButtons {
|
struct DepthStencil
|
||||||
bool left = false;
|
{
|
||||||
bool right = false;
|
VkImage image;
|
||||||
bool middle = false;
|
VkDeviceMemory mem;
|
||||||
} mouseButtons;
|
VkImageView view;
|
||||||
|
} depthStencil;
|
||||||
|
|
||||||
// OS specific
|
struct GamePadState
|
||||||
|
{
|
||||||
|
glm::vec2 axisLeft = glm::vec2(0.0f);
|
||||||
|
glm::vec2 axisRight = glm::vec2(0.0f);
|
||||||
|
} gamePadState;
|
||||||
|
|
||||||
|
struct MouseButtons
|
||||||
|
{
|
||||||
|
bool left = false;
|
||||||
|
bool right = false;
|
||||||
|
bool middle = false;
|
||||||
|
} mouseButtons;
|
||||||
|
|
||||||
|
// OS specific
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
HWND window;
|
HWND window;
|
||||||
HINSTANCE windowInstance;
|
HINSTANCE windowInstance;
|
||||||
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
|
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
|
||||||
// true if application has focused, false if moved to background
|
// true if application has focused, false if moved to background
|
||||||
bool focused = false;
|
bool focused = false;
|
||||||
std::string androidProduct;
|
std::string androidProduct;
|
||||||
struct TouchPoint {
|
struct TouchPoint
|
||||||
int32_t id;
|
{
|
||||||
float x;
|
int32_t id;
|
||||||
float y;
|
float x;
|
||||||
bool down = false;
|
float y;
|
||||||
};
|
bool down = false;
|
||||||
float pinchDist = 0.0f;
|
};
|
||||||
std::array<TouchPoint, 2> touchPoints;
|
float pinchDist = 0.0f;
|
||||||
|
std::array<TouchPoint, 2> touchPoints;
|
||||||
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||||
wl_display *display = nullptr;
|
wl_display *display = nullptr;
|
||||||
wl_registry *registry = nullptr;
|
wl_registry *registry = nullptr;
|
||||||
wl_compositor *compositor = nullptr;
|
wl_compositor *compositor = nullptr;
|
||||||
wl_shell *shell = nullptr;
|
wl_shell *shell = nullptr;
|
||||||
wl_seat *seat = nullptr;
|
wl_seat *seat = nullptr;
|
||||||
wl_pointer *pointer = nullptr;
|
wl_pointer *pointer = nullptr;
|
||||||
wl_keyboard *keyboard = nullptr;
|
wl_keyboard *keyboard = nullptr;
|
||||||
wl_surface *surface = nullptr;
|
wl_surface *surface = nullptr;
|
||||||
wl_shell_surface *shell_surface = nullptr;
|
wl_shell_surface *shell_surface = nullptr;
|
||||||
bool quit = false;
|
bool quit = false;
|
||||||
|
|
||||||
#elif defined(_DIRECT2DISPLAY)
|
#elif defined(_DIRECT2DISPLAY)
|
||||||
bool quit = false;
|
bool quit = false;
|
||||||
#elif defined(VK_USE_PLATFORM_XCB_KHR)
|
#elif defined(VK_USE_PLATFORM_XCB_KHR)
|
||||||
bool quit = false;
|
bool quit = false;
|
||||||
xcb_connection_t *connection;
|
xcb_connection_t *connection;
|
||||||
xcb_screen_t *screen;
|
xcb_screen_t *screen;
|
||||||
xcb_window_t window;
|
xcb_window_t window;
|
||||||
xcb_intern_atom_reply_t *atom_wm_delete_window;
|
xcb_intern_atom_reply_t *atom_wm_delete_window;
|
||||||
#elif defined(VK_USE_PLATFORM_MACOS_MVK)
|
#elif defined(VK_USE_PLATFORM_MACOS_MVK)
|
||||||
NSWindow* window;
|
NSWindow *window;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
HWND setupWindow(HINSTANCE hinstance, WNDPROC wndproc);
|
HWND setupWindow(HINSTANCE hinstance, WNDPROC wndproc);
|
||||||
void handleMessages(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
void handleMessages(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||||
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
|
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
|
||||||
static int32_t handleAppInput(struct android_app* app, AInputEvent* event);
|
static int32_t handleAppInput(struct android_app *app, AInputEvent *event);
|
||||||
static void handleAppCommand(android_app* app, int32_t cmd);
|
static void handleAppCommand(android_app *app, int32_t cmd);
|
||||||
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||||
wl_shell_surface *setupWindow();
|
wl_shell_surface *setupWindow();
|
||||||
void initWaylandConnection();
|
void initWaylandConnection();
|
||||||
static void registryGlobalCb(void *data, struct wl_registry *registry,
|
static void registryGlobalCb(void *data, struct wl_registry *registry,
|
||||||
uint32_t name, const char *interface, uint32_t version);
|
uint32_t name, const char *interface, uint32_t version);
|
||||||
void registryGlobal(struct wl_registry *registry, uint32_t name,
|
void registryGlobal(struct wl_registry *registry, uint32_t name,
|
||||||
const char *interface, uint32_t version);
|
const char *interface, uint32_t version);
|
||||||
static void registryGlobalRemoveCb(void *data, struct wl_registry *registry,
|
static void registryGlobalRemoveCb(void *data, struct wl_registry *registry,
|
||||||
uint32_t name);
|
uint32_t name);
|
||||||
static void seatCapabilitiesCb(void *data, wl_seat *seat, uint32_t caps);
|
static void seatCapabilitiesCb(void *data, wl_seat *seat, uint32_t caps);
|
||||||
void seatCapabilities(wl_seat *seat, uint32_t caps);
|
void seatCapabilities(wl_seat *seat, uint32_t caps);
|
||||||
static void pointerEnterCb(void *data, struct wl_pointer *pointer,
|
static void pointerEnterCb(void *data, struct wl_pointer *pointer,
|
||||||
uint32_t serial, struct wl_surface *surface, wl_fixed_t sx,
|
uint32_t serial, struct wl_surface *surface, wl_fixed_t sx,
|
||||||
wl_fixed_t sy);
|
wl_fixed_t sy);
|
||||||
static void pointerLeaveCb(void *data, struct wl_pointer *pointer,
|
static void pointerLeaveCb(void *data, struct wl_pointer *pointer,
|
||||||
uint32_t serial, struct wl_surface *surface);
|
uint32_t serial, struct wl_surface *surface);
|
||||||
static void pointerMotionCb(void *data, struct wl_pointer *pointer,
|
static void pointerMotionCb(void *data, struct wl_pointer *pointer,
|
||||||
uint32_t time, wl_fixed_t sx, wl_fixed_t sy);
|
uint32_t time, wl_fixed_t sx, wl_fixed_t sy);
|
||||||
void pointerMotion(struct wl_pointer *pointer,
|
void pointerMotion(struct wl_pointer *pointer,
|
||||||
uint32_t time, wl_fixed_t sx, wl_fixed_t sy);
|
uint32_t time, wl_fixed_t sx, wl_fixed_t sy);
|
||||||
static void pointerButtonCb(void *data, struct wl_pointer *wl_pointer,
|
static void pointerButtonCb(void *data, struct wl_pointer *wl_pointer,
|
||||||
uint32_t serial, uint32_t time, uint32_t button, uint32_t state);
|
uint32_t serial, uint32_t time, uint32_t button, uint32_t state);
|
||||||
void pointerButton(struct wl_pointer *wl_pointer,
|
void pointerButton(struct wl_pointer *wl_pointer,
|
||||||
uint32_t serial, uint32_t time, uint32_t button, uint32_t state);
|
uint32_t serial, uint32_t time, uint32_t button, uint32_t state);
|
||||||
static void pointerAxisCb(void *data, struct wl_pointer *wl_pointer,
|
static void pointerAxisCb(void *data, struct wl_pointer *wl_pointer,
|
||||||
uint32_t time, uint32_t axis, wl_fixed_t value);
|
uint32_t time, uint32_t axis, wl_fixed_t value);
|
||||||
void pointerAxis(struct wl_pointer *wl_pointer,
|
void pointerAxis(struct wl_pointer *wl_pointer,
|
||||||
uint32_t time, uint32_t axis, wl_fixed_t value);
|
uint32_t time, uint32_t axis, wl_fixed_t value);
|
||||||
static void keyboardKeymapCb(void *data, struct wl_keyboard *keyboard,
|
static void keyboardKeymapCb(void *data, struct wl_keyboard *keyboard,
|
||||||
uint32_t format, int fd, uint32_t size);
|
uint32_t format, int fd, uint32_t size);
|
||||||
static void keyboardEnterCb(void *data, struct wl_keyboard *keyboard,
|
static void keyboardEnterCb(void *data, struct wl_keyboard *keyboard,
|
||||||
uint32_t serial, struct wl_surface *surface, struct wl_array *keys);
|
uint32_t serial, struct wl_surface *surface, struct wl_array *keys);
|
||||||
static void keyboardLeaveCb(void *data, struct wl_keyboard *keyboard,
|
static void keyboardLeaveCb(void *data, struct wl_keyboard *keyboard,
|
||||||
uint32_t serial, struct wl_surface *surface);
|
uint32_t serial, struct wl_surface *surface);
|
||||||
static void keyboardKeyCb(void *data, struct wl_keyboard *keyboard,
|
static void keyboardKeyCb(void *data, struct wl_keyboard *keyboard,
|
||||||
uint32_t serial, uint32_t time, uint32_t key, uint32_t state);
|
uint32_t serial, uint32_t time, uint32_t key, uint32_t state);
|
||||||
void keyboardKey(struct wl_keyboard *keyboard,
|
void keyboardKey(struct wl_keyboard *keyboard,
|
||||||
uint32_t serial, uint32_t time, uint32_t key, uint32_t state);
|
uint32_t serial, uint32_t time, uint32_t key, uint32_t state);
|
||||||
static void keyboardModifiersCb(void *data, struct wl_keyboard *keyboard,
|
static void keyboardModifiersCb(void *data, struct wl_keyboard *keyboard,
|
||||||
uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched,
|
uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched,
|
||||||
uint32_t mods_locked, uint32_t group);
|
uint32_t mods_locked, uint32_t group);
|
||||||
|
|
||||||
#elif defined(_DIRECT2DISPLAY)
|
#elif defined(_DIRECT2DISPLAY)
|
||||||
//
|
//
|
||||||
#elif defined(VK_USE_PLATFORM_XCB_KHR)
|
#elif defined(VK_USE_PLATFORM_XCB_KHR)
|
||||||
xcb_window_t setupWindow();
|
xcb_window_t setupWindow();
|
||||||
void initxcbConnection();
|
void initxcbConnection();
|
||||||
void handleEvent(const xcb_generic_event_t *event);
|
void handleEvent(const xcb_generic_event_t *event);
|
||||||
#elif defined(VK_USE_PLATFORM_MACOS_MVK)
|
#elif defined(VK_USE_PLATFORM_MACOS_MVK)
|
||||||
NSWindow* setupWindow();
|
NSWindow *setupWindow();
|
||||||
void mouseDragged(float x, float y);
|
void mouseDragged(float x, float y);
|
||||||
void windowWillResize(float x, float y);
|
void windowWillResize(float x, float y);
|
||||||
void windowDidResize();
|
void windowDidResize();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
VulkanExampleBase();
|
VulkanExampleBase();
|
||||||
virtual ~VulkanExampleBase();
|
virtual ~VulkanExampleBase();
|
||||||
|
|
||||||
void initVulkan();
|
|
||||||
|
|
||||||
virtual VkResult createInstance(bool enableValidation);
|
void initVulkan();
|
||||||
virtual void render() = 0;
|
|
||||||
virtual void windowResized();
|
|
||||||
virtual void setupFrameBuffer();
|
|
||||||
virtual void prepare();
|
|
||||||
virtual void fileDropped(std::string filename);
|
|
||||||
|
|
||||||
void initSwapchain();
|
virtual VkResult createInstance(bool enableValidation);
|
||||||
void setupSwapChain();
|
virtual void render() = 0;
|
||||||
|
virtual void windowResized();
|
||||||
|
virtual void setupFrameBuffer();
|
||||||
|
virtual void prepare();
|
||||||
|
virtual void fileDropped(std::string filename);
|
||||||
|
|
||||||
void renderLoop();
|
void initSwapchain();
|
||||||
void renderFrame();
|
void setupSwapChain();
|
||||||
|
|
||||||
|
void renderLoop();
|
||||||
|
void renderFrame();
|
||||||
};
|
};
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,15 +1,21 @@
|
||||||
#ifndef GLTFMAINMODEL_H
|
#ifndef GLTFMAINMODEL_H
|
||||||
#define GLTFMAINMODEL_H
|
#define GLTFMAINMODEL_H
|
||||||
|
|
||||||
|
#ifndef TINYGLTF_NO_STB_IMAGE_WRITE
|
||||||
|
#define TINYGLTF_NO_STB_IMAGE_WRITE
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "glTFModel_Marco.h"
|
#include "glTFModel_Marco.h"
|
||||||
#include "glTFModel_common.h"
|
#include "glTFModel_common.h"
|
||||||
|
|
||||||
#include "VulkanDevice.h"
|
#include "VulkanDevice.h"
|
||||||
|
|
||||||
|
#include "glTFAnimation.h"
|
||||||
#include "glTFNode.h"
|
#include "glTFNode.h"
|
||||||
#include "glTFSkin.h"
|
#include "glTFSkin.h"
|
||||||
#include "glTFTexture.h"
|
#include "glTFTexture.h"
|
||||||
#include "glTFAnimation.h"
|
|
||||||
|
#include <tiny_gltf.h>
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
@ -17,68 +23,72 @@
|
||||||
|
|
||||||
GLTFLOADER_NAMESPACE_BEGIN
|
GLTFLOADER_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
struct ModelBuffer
|
||||||
|
{
|
||||||
|
VkBuffer buffer = VK_NULL_HANDLE;
|
||||||
|
VkDeviceMemory memory;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AABBDimensions
|
||||||
|
{
|
||||||
|
glm::vec3 min = glm::vec3(FLT_MAX);
|
||||||
|
glm::vec3 max = glm::vec3(-FLT_MAX);
|
||||||
|
};
|
||||||
|
|
||||||
class glTFMainModel
|
class glTFMainModel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
glTFMainModel();
|
glTFMainModel();
|
||||||
~glTFMainModel();
|
~glTFMainModel();
|
||||||
|
|
||||||
VkSamplerAddressMode getVkWrapMode(int32_t wrapMode);
|
VkSamplerAddressMode getVkWrapMode(int32_t wrapMode);
|
||||||
VkFilter getVkFilterMode(int32_t filterMode);
|
VkFilter getVkFilterMode(int32_t filterMode);
|
||||||
void getNodeProperty(const tinygltf::Node& node, const tinygltf::Model& model, size_t& vertexCount, size_t& indexCount);
|
void getNodeProperty(const tinygltf::Node &node, const tinygltf::Model &model, size_t &vertexCount, size_t &indexCount);
|
||||||
void getSceneDimensions();
|
void getSceneDimensions();
|
||||||
void destroy(VkDevice device);
|
|
||||||
|
|
||||||
void loadNode(glTFNode* parent, const tinygltf::Node& node, uint32_t nodeIndex, const tinygltf::Model& model, LoaderInfo& loaderInfo, float globalscale);
|
|
||||||
void loadSkins(tinygltf::Model& gltfModel);
|
|
||||||
void loadTextures(tinygltf::Model& gltfModel, VulkanBase::VulkanDevice* device, VkQueue transferQueue);
|
|
||||||
void loadTextureSamplers(tinygltf::Model& gltfModel);
|
|
||||||
void loadMaterials(tinygltf::Model& gltfModel);
|
|
||||||
void loadAnimations(tinygltf::Model& gltfModel);
|
|
||||||
void loadFromFile(std::string filename, VulkanBase::VulkanDevice* device, VkQueue transferQueue, float scale = 1.0f);
|
|
||||||
|
|
||||||
void drawNode(glTFNode* node, VkCommandBuffer commandBuffer);
|
ModelBuffer &getModelVertex();
|
||||||
void draw(VkCommandBuffer commandBuffer);
|
ModelBuffer &getModelIndex();
|
||||||
|
|
||||||
void calculateBoundingBox(glTFNode* node, glTFNode* parent);
|
void destroy(VkDevice device);
|
||||||
void updateAnimation(uint32_t index, float time);
|
|
||||||
glTFNode* findNode(glTFNode* parent, uint32_t index);
|
void loadNode(glTFNode *parent, const tinygltf::Node &node, uint32_t nodeIndex, const tinygltf::Model &model, LoaderInfo &loaderInfo, float globalscale);
|
||||||
glTFNode* nodeFromIndex(uint32_t index);
|
void loadSkins(tinygltf::Model &gltfModel);
|
||||||
|
void loadTextures(tinygltf::Model &gltfModel, VulkanBase::VulkanDevice *device, VkQueue transferQueue);
|
||||||
|
void loadTextureSamplers(tinygltf::Model &gltfModel);
|
||||||
|
void loadMaterials(tinygltf::Model &gltfModel);
|
||||||
|
void loadAnimations(tinygltf::Model &gltfModel);
|
||||||
|
void loadFromFile(std::string filename, VulkanBase::VulkanDevice *device, VkQueue transferQueue, float scale = 1.0f);
|
||||||
|
|
||||||
|
void drawNode(glTFNode *node, VkCommandBuffer commandBuffer);
|
||||||
|
void draw(VkCommandBuffer commandBuffer);
|
||||||
|
|
||||||
|
void calculateBoundingBox(glTFNode *node, glTFNode *parent);
|
||||||
|
void updateAnimation(uint32_t index, float time);
|
||||||
|
glTFNode *findNode(glTFNode *parent, uint32_t index);
|
||||||
|
glTFNode *nodeFromIndex(uint32_t index);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
VulkanBase::VulkanDevice *m_device;
|
||||||
|
|
||||||
VulkanBase::VulkanDevice* m_device;
|
ModelBuffer m_vertices;
|
||||||
|
ModelBuffer m_indices;
|
||||||
|
|
||||||
struct Vertices {
|
glm::mat4 m_aabb;
|
||||||
VkBuffer buffer = VK_NULL_HANDLE;
|
|
||||||
VkDeviceMemory memory;
|
|
||||||
} m_vertices;
|
|
||||||
struct Indices {
|
|
||||||
VkBuffer buffer = VK_NULL_HANDLE;
|
|
||||||
VkDeviceMemory memory;
|
|
||||||
} m_indices;
|
|
||||||
|
|
||||||
glm::mat4 m_aabb;
|
std::vector<glTFNode *> m_nodes;
|
||||||
|
std::vector<glTFNode *> m_linearNodes;
|
||||||
|
|
||||||
std::vector<glTFNode*> m_nodes;
|
std::vector<glTFSkin *> m_skins;
|
||||||
std::vector<glTFNode*> m_linearNodes;
|
|
||||||
|
|
||||||
std::vector<glTFSkin*> m_skins;
|
std::vector<glTFTexture> m_textures;
|
||||||
|
std::vector<VulkanBase::VulkanTextureSampler> m_textureSamplers;
|
||||||
std::vector<glTFTexture> m_textures;
|
std::vector<glTFMaterial> m_materials;
|
||||||
std::vector<VulkanBase::VulkanTextureSampler> m_textureSamplers;
|
std::vector<glTFAnimation> m_animations;
|
||||||
std::vector<glTFMaterial> m_materials;
|
std::vector<std::string> m_extensions;
|
||||||
std::vector<glTFAnimation> m_animations;
|
|
||||||
std::vector<std::string> m_extensions;
|
|
||||||
|
|
||||||
struct Dimensions {
|
|
||||||
glm::vec3 min = glm::vec3(FLT_MAX);
|
|
||||||
glm::vec3 max = glm::vec3(-FLT_MAX);
|
|
||||||
} m_dimensions;
|
|
||||||
|
|
||||||
|
AABBDimensions m_dimensions;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
GLTFLOADER_NAMESPACE_END
|
GLTFLOADER_NAMESPACE_END
|
||||||
|
|
||||||
#endif // !GLTFMAINMODEL_h
|
#endif // !GLTFMAINMODEL_h
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
#include "glTFMaterial.h"
|
#include "glTFMaterial.h"
|
||||||
|
|
||||||
|
|
||||||
GLTFLOADER_NAMESPACE_BEGIN
|
GLTFLOADER_NAMESPACE_BEGIN
|
||||||
|
|
||||||
glTFMaterial::glTFMaterial()
|
glTFMaterial::glTFMaterial()
|
||||||
|
|
@ -13,72 +12,81 @@ glTFMaterial::~glTFMaterial()
|
||||||
|
|
||||||
void glTFMaterial::setDoublesided(bool value)
|
void glTFMaterial::setDoublesided(bool value)
|
||||||
{
|
{
|
||||||
m_doubleSided = value;
|
m_doubleSided = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool glTFMaterial::getDoublesided()
|
bool glTFMaterial::getDoublesided()
|
||||||
{
|
{
|
||||||
return m_doubleSided;
|
return m_doubleSided;
|
||||||
}
|
}
|
||||||
|
|
||||||
void glTFMaterial::setAlphaMode(AlphaMode value)
|
void glTFMaterial::setAlphaMode(AlphaMode value)
|
||||||
{
|
{
|
||||||
m_alphaMode = value;
|
m_alphaMode = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
AlphaMode glTFMaterial::getAlphaMode()
|
AlphaMode glTFMaterial::getAlphaMode()
|
||||||
{
|
{
|
||||||
return m_alphaMode;
|
return m_alphaMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void glTFMaterial::setAlphaCutOff(float value)
|
void glTFMaterial::setAlphaCutOff(float value)
|
||||||
{
|
{
|
||||||
m_alphaCutoff = value;
|
m_alphaCutoff = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
float glTFMaterial::getAlphaCutOff()
|
float glTFMaterial::getAlphaCutOff()
|
||||||
{
|
{
|
||||||
return m_alphaCutoff;
|
return m_alphaCutoff;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureCoordSet* glTFMaterial::getTextureCoordSet()
|
TextureCoordSet *glTFMaterial::getTextureCoordSet()
|
||||||
{
|
{
|
||||||
return m_texCoordSets;
|
return m_texCoordSets;
|
||||||
}
|
}
|
||||||
|
|
||||||
void glTFMaterial::setTextureCoordSet(TextureCoordSet* value)
|
void glTFMaterial::setTextureCoordSet(TextureCoordSet *value)
|
||||||
{
|
{
|
||||||
m_texCoordSets = value;
|
m_texCoordSets = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
PbrTextureExtension* glTFMaterial::getTextureExtension()
|
PBR::PbrTextureExtension *glTFMaterial::getTextureExtension()
|
||||||
{
|
{
|
||||||
return m_textureExtension;
|
return m_textureExtension;
|
||||||
}
|
}
|
||||||
|
|
||||||
void glTFMaterial::setPbrTextureExtension(PbrTextureExtension* value)
|
void glTFMaterial::setPbrTextureExtension(PBR::PbrTextureExtension *value)
|
||||||
{
|
{
|
||||||
m_textureExtension = value;
|
m_textureExtension = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
PbrBaseTexture* glTFMaterial::getPbrBaseTexture()
|
PBR::PbrBaseTexture *glTFMaterial::getPbrBaseTexture()
|
||||||
{
|
{
|
||||||
return m_pbrBaseTexture;
|
return m_pbrBaseTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
void glTFMaterial::setPbrBaseTexture(PbrBaseTexture* value)
|
void glTFMaterial::setPbrBaseTexture(PBR::PbrBaseTexture *value)
|
||||||
{
|
{
|
||||||
m_pbrBaseTexture = value;
|
m_pbrBaseTexture = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
PbrWorkFlow* glTFMaterial::getPbrWorkFlow()
|
PBR::PbrWorkFlow *glTFMaterial::getPbrWorkFlow()
|
||||||
{
|
{
|
||||||
return m_pbrWorkFlow;
|
return m_pbrWorkFlow;
|
||||||
}
|
}
|
||||||
|
|
||||||
void glTFMaterial::setPbrWorkFlow()
|
void glTFMaterial::setPbrWorkFlow(PBR::PbrWorkFlow *value)
|
||||||
{
|
{
|
||||||
m_pbrWorkFlow;
|
m_pbrWorkFlow = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void glTFMaterial::setDescriptorSet(VkDescriptorSet value)
|
||||||
|
{
|
||||||
|
m_descriptorSet = value;
|
||||||
|
}
|
||||||
|
VkDescriptorSet glTFMaterial::getDescriptorSet()
|
||||||
|
{
|
||||||
|
return m_descriptorSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLTFLOADER_NAMESPACE_END
|
GLTFLOADER_NAMESPACE_END
|
||||||
|
|
@ -4,11 +4,11 @@
|
||||||
#include "glTFModel_Marco.h"
|
#include "glTFModel_Marco.h"
|
||||||
#include "glTFModel_common.h"
|
#include "glTFModel_common.h"
|
||||||
|
|
||||||
#include "glTFTexture.h"
|
#include "PbrBaseTexture.h"
|
||||||
#include "PbrTextureCoordSet.h"
|
#include "PbrTextureCoordSet.h"
|
||||||
#include "PbrTextureExtension.h"
|
#include "PbrTextureExtension.h"
|
||||||
#include "PbrBaseTexture.h"
|
|
||||||
#include "PbrWorkFlow.h"
|
#include "PbrWorkFlow.h"
|
||||||
|
#include "glTFTexture.h"
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
|
@ -17,50 +17,46 @@ GLTFLOADER_NAMESPACE_BEGIN
|
||||||
class glTFMaterial
|
class glTFMaterial
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
glTFMaterial();
|
glTFMaterial();
|
||||||
~glTFMaterial();
|
~glTFMaterial();
|
||||||
|
|
||||||
void setDoublesided(bool value);
|
void setDoublesided(bool value);
|
||||||
bool getDoublesided();
|
bool getDoublesided();
|
||||||
|
|
||||||
void setAlphaMode(AlphaMode value);
|
void setAlphaMode(AlphaMode value);
|
||||||
AlphaMode getAlphaMode();
|
AlphaMode getAlphaMode();
|
||||||
|
|
||||||
void setAlphaCutOff(float value);
|
void setAlphaCutOff(float value);
|
||||||
float getAlphaCutOff();
|
float getAlphaCutOff();
|
||||||
|
|
||||||
|
void setDescriptorSet(VkDescriptorSet value);
|
||||||
|
VkDescriptorSet getDescriptorSet();
|
||||||
|
|
||||||
TextureCoordSet* getTextureCoordSet();
|
TextureCoordSet *getTextureCoordSet();
|
||||||
void setTextureCoordSet(TextureCoordSet* value);
|
void setTextureCoordSet(TextureCoordSet *value);
|
||||||
|
|
||||||
PbrTextureExtension* getTextureExtension();
|
PBR::PbrTextureExtension *getTextureExtension();
|
||||||
void setPbrTextureExtension(PbrTextureExtension* value);
|
void setPbrTextureExtension(PBR::PbrTextureExtension *value);
|
||||||
|
|
||||||
PbrBaseTexture* getPbrBaseTexture();
|
PBR::PbrBaseTexture *getPbrBaseTexture();
|
||||||
void setPbrBaseTexture(PbrBaseTexture* value);
|
void setPbrBaseTexture(PBR::PbrBaseTexture *value);
|
||||||
|
|
||||||
PbrWorkFlow* getPbrWorkFlow();
|
PBR::PbrWorkFlow *getPbrWorkFlow();
|
||||||
void setPbrWorkFlow();
|
void setPbrWorkFlow(PBR::PbrWorkFlow *value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
AlphaMode m_alphaMode = ALPHAMODE_OPAQUE;
|
||||||
|
float m_alphaCutoff = 1.0f;
|
||||||
|
|
||||||
AlphaMode m_alphaMode = ALPHAMODE_OPAQUE;
|
PBR::PbrBaseTexture *m_pbrBaseTexture;
|
||||||
float m_alphaCutoff = 1.0f;
|
bool m_doubleSided = false;
|
||||||
|
TextureCoordSet *m_texCoordSets;
|
||||||
PbrBaseTexture* m_pbrBaseTexture;
|
PBR::PbrTextureExtension *m_textureExtension;
|
||||||
bool m_doubleSided = false;
|
PBR::PbrWorkFlow *m_pbrWorkFlow;
|
||||||
TextureCoordSet* m_texCoordSets;
|
|
||||||
PbrTextureExtension* m_textureExtension;
|
|
||||||
PbrWorkFlow* m_pbrWorkFlow;
|
|
||||||
|
|
||||||
VkDescriptorSet m_descriptorSet = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
|
VkDescriptorSet m_descriptorSet = VK_NULL_HANDLE;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GLTFLOADER_NAMESPACE_END
|
GLTFLOADER_NAMESPACE_END
|
||||||
|
|
||||||
#endif // !GLTFMATERIAL_H
|
#endif // !GLTFMATERIAL_H
|
||||||
|
|
|
||||||
|
|
@ -32,9 +32,9 @@
|
||||||
|
|
||||||
|
|
||||||
#include "tiny_gltf.h"
|
#include "tiny_gltf.h"
|
||||||
#include "VulkanDevice.hpp"
|
#include "VulkanDevice.h"
|
||||||
//#include "VulkanUtils.hpp"
|
//#include "VulkanUtils.hpp"
|
||||||
#include "vulkan/vulkan.h"
|
|
||||||
|
|
||||||
#define ENABLE_VALIDATION false
|
#define ENABLE_VALIDATION false
|
||||||
#define MAX_NUM_JOINTS 128u
|
#define MAX_NUM_JOINTS 128u
|
||||||
|
|
@ -64,7 +64,7 @@ namespace glTFModel
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Texture {
|
struct Texture {
|
||||||
vks::VulkanDevice* device;
|
VulkanBase::VulkanDevice* device;
|
||||||
VkImage image;
|
VkImage image;
|
||||||
VkImageLayout imageLayout;
|
VkImageLayout imageLayout;
|
||||||
VkDeviceMemory deviceMemory;
|
VkDeviceMemory deviceMemory;
|
||||||
|
|
@ -77,7 +77,7 @@ namespace glTFModel
|
||||||
void updateDescriptor();
|
void updateDescriptor();
|
||||||
void destroy();
|
void destroy();
|
||||||
// Load a texture from a glTF image (stored as vector of chars loaded via stb_image) and generate a full mip chaing for it
|
// Load a texture from a glTF image (stored as vector of chars loaded via stb_image) and generate a full mip chaing for it
|
||||||
void fromglTfImage(tinygltf::Image& gltfimage, glTFModel::TextureSampler textureSampler, vks::VulkanDevice* device, VkQueue copyQueue);
|
void fromglTfImage(tinygltf::Image& gltfimage, glTFModel::TextureSampler textureSampler, VulkanBase::VulkanDevice* device, VkQueue copyQueue);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Material {
|
struct Material {
|
||||||
|
|
@ -127,7 +127,7 @@ namespace glTFModel
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Mesh {
|
struct Mesh {
|
||||||
vks::VulkanDevice* device;
|
VulkanBase::VulkanDevice* device;
|
||||||
std::vector<Primitive*> primitives;
|
std::vector<Primitive*> primitives;
|
||||||
BoundingBox bb;
|
BoundingBox bb;
|
||||||
BoundingBox aabb;
|
BoundingBox aabb;
|
||||||
|
|
@ -143,7 +143,7 @@ namespace glTFModel
|
||||||
glm::mat4 jointMatrix[128]{};
|
glm::mat4 jointMatrix[128]{};
|
||||||
float jointcount{ 0 };
|
float jointcount{ 0 };
|
||||||
} uniformBlock;
|
} uniformBlock;
|
||||||
Mesh(vks::VulkanDevice* device, glm::mat4 matrix);
|
Mesh(VulkanBase::VulkanDevice* device, glm::mat4 matrix);
|
||||||
~Mesh();
|
~Mesh();
|
||||||
void setBoundingBox(glm::vec3 min, glm::vec3 max);
|
void setBoundingBox(glm::vec3 min, glm::vec3 max);
|
||||||
};
|
};
|
||||||
|
|
@ -199,7 +199,7 @@ namespace glTFModel
|
||||||
|
|
||||||
struct Model {
|
struct Model {
|
||||||
|
|
||||||
vks::VulkanDevice* device;
|
VulkanBase::VulkanDevice* device;
|
||||||
|
|
||||||
struct Vertex {
|
struct Vertex {
|
||||||
glm::vec3 pos;
|
glm::vec3 pos;
|
||||||
|
|
@ -249,13 +249,13 @@ namespace glTFModel
|
||||||
void loadNode(glTFModel::Node* parent, const tinygltf::Node& node, uint32_t nodeIndex, const tinygltf::Model& model, LoaderInfo& loaderInfo, float globalscale);
|
void loadNode(glTFModel::Node* parent, const tinygltf::Node& node, uint32_t nodeIndex, const tinygltf::Model& model, LoaderInfo& loaderInfo, float globalscale);
|
||||||
void getNodeProps(const tinygltf::Node& node, const tinygltf::Model& model, size_t& vertexCount, size_t& indexCount);
|
void getNodeProps(const tinygltf::Node& node, const tinygltf::Model& model, size_t& vertexCount, size_t& indexCount);
|
||||||
void loadSkins(tinygltf::Model& gltfModel);
|
void loadSkins(tinygltf::Model& gltfModel);
|
||||||
void loadTextures(tinygltf::Model& gltfModel, vks::VulkanDevice* device, VkQueue transferQueue);
|
void loadTextures(tinygltf::Model& gltfModel, VulkanBase::VulkanDevice* device, VkQueue transferQueue);
|
||||||
VkSamplerAddressMode getVkWrapMode(int32_t wrapMode);
|
VkSamplerAddressMode getVkWrapMode(int32_t wrapMode);
|
||||||
VkFilter getVkFilterMode(int32_t filterMode);
|
VkFilter getVkFilterMode(int32_t filterMode);
|
||||||
void loadTextureSamplers(tinygltf::Model& gltfModel);
|
void loadTextureSamplers(tinygltf::Model& gltfModel);
|
||||||
void loadMaterials(tinygltf::Model& gltfModel);
|
void loadMaterials(tinygltf::Model& gltfModel);
|
||||||
void loadAnimations(tinygltf::Model& gltfModel);
|
void loadAnimations(tinygltf::Model& gltfModel);
|
||||||
void loadFromFile(std::string filename, vks::VulkanDevice* device, VkQueue transferQueue, float scale = 1.0f);
|
void loadFromFile(std::string filename, VulkanBase::VulkanDevice* device, VkQueue transferQueue, float scale = 1.0f);
|
||||||
void drawNode(Node* node, VkCommandBuffer commandBuffer);
|
void drawNode(Node* node, VkCommandBuffer commandBuffer);
|
||||||
void draw(VkCommandBuffer commandBuffer);
|
void draw(VkCommandBuffer commandBuffer);
|
||||||
void calculateBoundingBox(Node* node, Node* parent);
|
void calculateBoundingBox(Node* node, Node* parent);
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,10 @@
|
||||||
|
|
||||||
GLTFLOADER_NAMESPACE_BEGIN
|
GLTFLOADER_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
glTFPrimitive::glTFPrimitive(uint32_t firstIndex, uint32_t indexCount, uint32_t vertexCount, glTFMaterial &material)
|
||||||
|
: m_firstIndex(firstIndex), m_indexCount(indexCount), m_vertexCount(vertexCount), m_material(material)
|
||||||
glTFPrimitive::glTFPrimitive(uint32_t firstIndex, uint32_t indexCount, uint32_t vertexCount, glTFMaterial& material)
|
|
||||||
:m_firstIndex(firstIndex)
|
|
||||||
,m_indexCount(indexCount)
|
|
||||||
,m_vertexCount(vertexCount)
|
|
||||||
,m_material(material)
|
|
||||||
{
|
{
|
||||||
m_hasIndices = indexCount > 0;
|
m_hasIndices = indexCount > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
glTFPrimitive::~glTFPrimitive()
|
glTFPrimitive::~glTFPrimitive()
|
||||||
|
|
@ -19,33 +14,60 @@ glTFPrimitive::~glTFPrimitive()
|
||||||
|
|
||||||
void glTFPrimitive::setBoundingBox(glm::vec3 min, glm::vec3 max)
|
void glTFPrimitive::setBoundingBox(glm::vec3 min, glm::vec3 max)
|
||||||
{
|
{
|
||||||
m_boundingBox.setBoundingBox(min, max);
|
m_boundingBox.setBoundingBox(min, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
glTFBoundingBox glTFPrimitive::getBoundingBox()
|
glTFBoundingBox glTFPrimitive::getBoundingBox()
|
||||||
{
|
{
|
||||||
return m_boundingBox;
|
return m_boundingBox;
|
||||||
}
|
}
|
||||||
|
|
||||||
void glTFPrimitive::setIndexCount(unsigned int indexCount)
|
void glTFPrimitive::setIndexCount(unsigned int indexCount)
|
||||||
{
|
{
|
||||||
m_indexCount = indexCount;
|
m_indexCount = indexCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int glTFPrimitive::getIndexCount()
|
unsigned int glTFPrimitive::getIndexCount()
|
||||||
{
|
{
|
||||||
return m_indexCount;
|
return m_indexCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
void glTFPrimitive::setFirstIndex(unsigned int firstIndex)
|
void glTFPrimitive::setFirstIndex(unsigned int firstIndex)
|
||||||
{
|
{
|
||||||
m_firstIndex = firstIndex;
|
m_firstIndex = firstIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int glTFPrimitive::getFirstIndex()
|
unsigned int glTFPrimitive::getFirstIndex()
|
||||||
{
|
{
|
||||||
return m_firstIndex;
|
return m_firstIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void glTFPrimitive::setGltfMaterial(glTFMaterial &material)
|
||||||
|
{
|
||||||
|
m_material = material;
|
||||||
|
}
|
||||||
|
|
||||||
|
glTFMaterial &glTFPrimitive::getGltfMaterial()
|
||||||
|
{
|
||||||
|
return m_material;
|
||||||
|
}
|
||||||
|
|
||||||
|
void glTFPrimitive::setHasIndices(bool hasIndices)
|
||||||
|
{
|
||||||
|
m_hasIndices = hasIndices;
|
||||||
|
}
|
||||||
|
bool glTFPrimitive::getHasIndices()
|
||||||
|
{
|
||||||
|
return m_hasIndices;
|
||||||
|
}
|
||||||
|
|
||||||
|
void glTFPrimitive::setVertexCount(unsigned int vertexCount)
|
||||||
|
{
|
||||||
|
m_vertexCount = vertexCount;
|
||||||
|
}
|
||||||
|
unsigned int glTFPrimitive::getVertexCount()
|
||||||
|
{
|
||||||
|
return m_vertexCount;
|
||||||
|
}
|
||||||
|
|
||||||
GLTFLOADER_NAMESPACE_END
|
GLTFLOADER_NAMESPACE_END
|
||||||
|
|
@ -3,44 +3,47 @@
|
||||||
|
|
||||||
#include "glTFModel_Marco.h"
|
#include "glTFModel_Marco.h"
|
||||||
|
|
||||||
#include "glTFMaterial.h"
|
|
||||||
#include "glTFBoundingBox.h"
|
#include "glTFBoundingBox.h"
|
||||||
|
#include "glTFMaterial.h"
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
|
||||||
GLTFLOADER_NAMESPACE_BEGIN
|
GLTFLOADER_NAMESPACE_BEGIN
|
||||||
|
|
||||||
class GLTFLOADER_API glTFPrimitive
|
class GLTFLOADER_API glTFPrimitive
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
glTFPrimitive(uint32_t firstIndex, uint32_t indexCount, uint32_t vertexCount, glTFMaterial& material);
|
glTFPrimitive(uint32_t firstIndex, uint32_t indexCount, uint32_t vertexCount, glTFMaterial &material);
|
||||||
|
|
||||||
~glTFPrimitive();
|
|
||||||
|
|
||||||
void setBoundingBox(glm::vec3 min, glm::vec3 max);
|
~glTFPrimitive();
|
||||||
glTFBoundingBox getBoundingBox();
|
|
||||||
|
|
||||||
void setIndexCount(unsigned int indexCount);
|
void setBoundingBox(glm::vec3 min, glm::vec3 max);
|
||||||
unsigned int getIndexCount();
|
glTFBoundingBox getBoundingBox();
|
||||||
|
|
||||||
void setFirstIndex(unsigned int firstIndex);
|
void setIndexCount(unsigned int indexCount);
|
||||||
unsigned int getFirstIndex();
|
unsigned int getIndexCount();
|
||||||
|
|
||||||
|
void setFirstIndex(unsigned int firstIndex);
|
||||||
|
unsigned int getFirstIndex();
|
||||||
|
|
||||||
|
void setGltfMaterial(glTFMaterial &material);
|
||||||
|
glTFMaterial &getGltfMaterial();
|
||||||
|
|
||||||
|
void setHasIndices(bool hasIndices);
|
||||||
|
bool getHasIndices();
|
||||||
|
|
||||||
|
void setVertexCount(unsigned int vertexCount);
|
||||||
|
unsigned int getVertexCount();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
unsigned int m_firstIndex;
|
||||||
unsigned int m_firstIndex;
|
unsigned int m_indexCount;
|
||||||
unsigned int m_indexCount;
|
unsigned int m_vertexCount;
|
||||||
unsigned int m_vertexCount;
|
glTFMaterial &m_material;
|
||||||
glTFMaterial& m_material;
|
bool m_hasIndices;
|
||||||
bool m_hasIndices;
|
glTFBoundingBox m_boundingBox;
|
||||||
glTFBoundingBox m_boundingBox;
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GLTFLOADER_NAMESPACE_END
|
GLTFLOADER_NAMESPACE_END
|
||||||
|
|
||||||
#endif // !GLTFPRIMITIVE_H
|
#endif // !GLTFPRIMITIVE_H
|
||||||
|
|
|
||||||
|
|
@ -8,43 +8,34 @@
|
||||||
|
|
||||||
#include <tiny_gltf.h>
|
#include <tiny_gltf.h>
|
||||||
|
|
||||||
|
|
||||||
GLTFLOADER_NAMESPACE_BEGIN
|
GLTFLOADER_NAMESPACE_BEGIN
|
||||||
|
|
||||||
/// @brief gltf模型的贴图
|
/// @brief gltf模型的贴图
|
||||||
class GLTFLOADER_API glTFTexture
|
class GLTFLOADER_API glTFTexture
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
glTFTexture();
|
glTFTexture();
|
||||||
~glTFTexture();
|
~glTFTexture();
|
||||||
|
|
||||||
void updateDescriptor();
|
void updateDescriptor();
|
||||||
|
|
||||||
void destroy();
|
void destroy();
|
||||||
|
|
||||||
void fromglTfImage(tinygltf::Image& gltfimage, VulkanBase::VulkanTextureSampler textureSampler, VulkanBase::VulkanDevice* device, VkQueue copyQueue);
|
void fromglTfImage(tinygltf::Image &gltfimage, VulkanBase::VulkanTextureSampler textureSampler, VulkanBase::VulkanDevice *device, VkQueue copyQueue);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
VulkanBase::VulkanDevice *m_device;
|
||||||
VulkanBase::VulkanDevice* m_device;
|
VkImage m_image;
|
||||||
VkImage m_image;
|
VkImageLayout m_imageLayout;
|
||||||
VkImageLayout m_imageLayout;
|
VkDeviceMemory m_deviceMemory;
|
||||||
VkDeviceMemory m_deviceMemory;
|
VkImageView m_view;
|
||||||
VkImageView m_view;
|
unsigned int m_width, m_height;
|
||||||
unsigned int m_width, m_height;
|
unsigned int m_mipLevels;
|
||||||
unsigned int m_mipLevels;
|
unsigned int m_layerCount;
|
||||||
unsigned int m_layerCount;
|
VkDescriptorImageInfo m_descriptor;
|
||||||
VkDescriptorImageInfo m_descriptor;
|
VkSampler m_sampler;
|
||||||
VkSampler m_sampler;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GLTFLOADER_NAMESPACE_END
|
GLTFLOADER_NAMESPACE_END
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // !GLTFTEXTURE_H
|
#endif // !GLTFTEXTURE_H
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#include "PbrBaseTexture.h"
|
#include "PbrBaseTexture.h"
|
||||||
|
|
||||||
GLTFLOADER_NAMESPACE_BEGIN
|
PBR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
PbrBaseTexture::PbrBaseTexture()
|
PbrBaseTexture::PbrBaseTexture()
|
||||||
{
|
{
|
||||||
|
|
@ -10,95 +10,94 @@ PbrBaseTexture::~PbrBaseTexture()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void PbrBaseTexture::setBaseColorTexture(glTFTexture* value)
|
void PbrBaseTexture::setBaseColorTexture(glTFLoader::glTFTexture *value)
|
||||||
{
|
{
|
||||||
m_baseColorTexture = value;
|
m_baseColorTexture = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
glTFTexture* PbrBaseTexture::getBaseColorTexture()
|
glTFLoader::glTFTexture *PbrBaseTexture::getBaseColorTexture()
|
||||||
{
|
{
|
||||||
return m_baseColorTexture;
|
return m_baseColorTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PbrBaseTexture::setBaseColorFactor(glm::vec4 value)
|
void PbrBaseTexture::setBaseColorFactor(glm::vec4 value)
|
||||||
{
|
{
|
||||||
m_baseColorFactor = value;
|
m_baseColorFactor = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec4 PbrBaseTexture::getBaseColorFactor()
|
glm::vec4 PbrBaseTexture::getBaseColorFactor()
|
||||||
{
|
{
|
||||||
return m_baseColorFactor;
|
return m_baseColorFactor;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PbrBaseTexture::setNormalTexture(glTFTexture* value)
|
void PbrBaseTexture::setNormalTexture(glTFLoader::glTFTexture *value)
|
||||||
{
|
{
|
||||||
m_normalTexture = value;
|
m_normalTexture = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
glTFTexture* PbrBaseTexture::getNormalTexture()
|
glTFLoader::glTFTexture *PbrBaseTexture::getNormalTexture()
|
||||||
{
|
{
|
||||||
return m_normalTexture;
|
return m_normalTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PbrBaseTexture::setMetallicRoughnessTexture(glTFTexture* value)
|
void PbrBaseTexture::setMetallicRoughnessTexture(glTFLoader::glTFTexture *value)
|
||||||
{
|
{
|
||||||
m_metallicRoughnessTexture = value;
|
m_metallicRoughnessTexture = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
glTFTexture* PbrBaseTexture::getMetalicRoughnessTexture()
|
glTFLoader::glTFTexture *PbrBaseTexture::getMetalicRoughnessTexture()
|
||||||
{
|
{
|
||||||
return m_metallicRoughnessTexture;
|
return m_metallicRoughnessTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PbrBaseTexture::setMetallicFactor(float value)
|
void PbrBaseTexture::setMetallicFactor(float value)
|
||||||
{
|
{
|
||||||
m_metallicFactor = value;
|
m_metallicFactor = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
float PbrBaseTexture::getMetallicFactor()
|
float PbrBaseTexture::getMetallicFactor()
|
||||||
{
|
{
|
||||||
return m_metallicFactor;
|
return m_metallicFactor;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PbrBaseTexture::setRoughnessFactor(float value)
|
void PbrBaseTexture::setRoughnessFactor(float value)
|
||||||
{
|
{
|
||||||
m_roughnessFactor = value;
|
m_roughnessFactor = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
float PbrBaseTexture::getRoughnessFactor()
|
float PbrBaseTexture::getRoughnessFactor()
|
||||||
{
|
{
|
||||||
return m_roughnessFactor;
|
return m_roughnessFactor;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PbrBaseTexture::setEmissiveTexture(glTFTexture* value)
|
void PbrBaseTexture::setEmissiveTexture(glTFLoader::glTFTexture *value)
|
||||||
{
|
{
|
||||||
m_emissiveTexture = value;
|
m_emissiveTexture = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
glTFTexture* PbrBaseTexture::getEmissiveTexture()
|
glTFLoader::glTFTexture *PbrBaseTexture::getEmissiveTexture()
|
||||||
{
|
{
|
||||||
return m_emissiveTexture;
|
return m_emissiveTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PbrBaseTexture::setEmissiveFactor(glm::vec4 value)
|
void PbrBaseTexture::setEmissiveFactor(glm::vec4 value)
|
||||||
{
|
{
|
||||||
m_emissiveFactor = value;
|
m_emissiveFactor = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec4 PbrBaseTexture::getEmissiveFactor()
|
glm::vec4 PbrBaseTexture::getEmissiveFactor()
|
||||||
{
|
{
|
||||||
return m_emissiveFactor;
|
return m_emissiveFactor;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PbrBaseTexture::setOcclusionTexture(glTFTexture* value)
|
void PbrBaseTexture::setOcclusionTexture(glTFLoader::glTFTexture *value)
|
||||||
{
|
{
|
||||||
m_occlusionTexture = value;
|
m_occlusionTexture = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
glTFTexture* PbrBaseTexture::getOcclusionTexture()
|
glTFLoader::glTFTexture *PbrBaseTexture::getOcclusionTexture()
|
||||||
{
|
{
|
||||||
return m_occlusionTexture;
|
return m_occlusionTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLTFLOADER_NAMESPACE_END
|
PBR_NAMESPACE_END
|
||||||
|
|
@ -1,69 +1,64 @@
|
||||||
#ifndef PBRBASETEXTURE_H
|
#ifndef PBRBASETEXTURE_H
|
||||||
#define PBRBASETEXTURE_H
|
#define PBRBASETEXTURE_H
|
||||||
|
|
||||||
/// todo: 分离为单独的PBR命名空间
|
#include "PbrMarco.h"
|
||||||
#include "glTFModel_Marco.h"
|
|
||||||
|
|
||||||
#include "glTFTexture.h"
|
#include "glTFTexture.h"
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
GLTFLOADER_NAMESPACE_BEGIN
|
PBR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
/// @brief todo:拆分texture基类摆脱gltf限制
|
/// @brief todo:拆分texture基类摆脱gltf限制
|
||||||
class PbrBaseTexture
|
class PbrBaseTexture
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PbrBaseTexture();
|
PbrBaseTexture();
|
||||||
~PbrBaseTexture();
|
~PbrBaseTexture();
|
||||||
|
|
||||||
void setBaseColorTexture(glTFTexture* value);
|
void setBaseColorTexture(glTFLoader::glTFTexture *value);
|
||||||
glTFTexture* getBaseColorTexture();
|
glTFLoader::glTFTexture *getBaseColorTexture();
|
||||||
|
|
||||||
void setBaseColorFactor(glm::vec4 value);
|
void setBaseColorFactor(glm::vec4 value);
|
||||||
glm::vec4 getBaseColorFactor();
|
glm::vec4 getBaseColorFactor();
|
||||||
|
|
||||||
void setNormalTexture(glTFTexture* value);
|
void setNormalTexture(glTFLoader::glTFTexture *value);
|
||||||
glTFTexture* getNormalTexture();
|
glTFLoader::glTFTexture *getNormalTexture();
|
||||||
|
|
||||||
void setMetallicRoughnessTexture(glTFTexture* value);
|
void setMetallicRoughnessTexture(glTFLoader::glTFTexture *value);
|
||||||
glTFTexture* getMetalicRoughnessTexture();
|
glTFLoader::glTFTexture *getMetalicRoughnessTexture();
|
||||||
|
|
||||||
void setMetallicFactor(float value);
|
void setMetallicFactor(float value);
|
||||||
float getMetallicFactor();
|
float getMetallicFactor();
|
||||||
|
|
||||||
void setRoughnessFactor(float value);
|
void setRoughnessFactor(float value);
|
||||||
float getRoughnessFactor();
|
float getRoughnessFactor();
|
||||||
|
|
||||||
void setEmissiveTexture(glTFTexture* value);
|
void setEmissiveTexture(glTFLoader::glTFTexture *value);
|
||||||
glTFTexture* getEmissiveTexture();
|
glTFLoader::glTFTexture *getEmissiveTexture();
|
||||||
|
|
||||||
void setEmissiveFactor(glm::vec4 value);
|
void setEmissiveFactor(glm::vec4 value);
|
||||||
glm::vec4 getEmissiveFactor();
|
glm::vec4 getEmissiveFactor();
|
||||||
|
|
||||||
void setOcclusionTexture(glTFTexture* value);
|
void setOcclusionTexture(glTFLoader::glTFTexture *value);
|
||||||
glTFTexture* getOcclusionTexture();
|
glTFLoader::glTFTexture *getOcclusionTexture();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
glTFLoader::glTFTexture *m_baseColorTexture = nullptr;
|
||||||
|
glm::vec4 m_baseColorFactor = glm::vec4(1.0f);
|
||||||
|
|
||||||
glTFTexture* m_baseColorTexture = nullptr;
|
glTFLoader::glTFTexture *m_normalTexture = nullptr;
|
||||||
glm::vec4 m_baseColorFactor = glm::vec4(1.0f);
|
|
||||||
|
|
||||||
glTFTexture* m_normalTexture = nullptr;
|
glTFLoader::glTFTexture *m_metallicRoughnessTexture = nullptr;
|
||||||
|
float m_metallicFactor = 1.0f;
|
||||||
|
float m_roughnessFactor = 1.0f;
|
||||||
|
|
||||||
glTFTexture* m_metallicRoughnessTexture = nullptr;
|
glTFLoader::glTFTexture *m_emissiveTexture = nullptr;
|
||||||
float m_metallicFactor = 1.0f;
|
glm::vec4 m_emissiveFactor = glm::vec4(1.0f);
|
||||||
float m_roughnessFactor = 1.0f;
|
|
||||||
|
|
||||||
glTFTexture* m_emissiveTexture = nullptr;
|
|
||||||
glm::vec4 m_emissiveFactor = glm::vec4(1.0f);
|
|
||||||
|
|
||||||
glTFTexture* m_occlusionTexture = nullptr;
|
|
||||||
|
|
||||||
|
glTFLoader::glTFTexture *m_occlusionTexture = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
PBR_NAMESPACE_END
|
||||||
|
|
||||||
GLTFLOADER_NAMESPACE_END
|
|
||||||
|
|
||||||
#endif // !PBRBASETEXTURE_H
|
#endif // !PBRBASETEXTURE_H
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define MAX_NUM_JOINTS 128u
|
||||||
|
|
||||||
|
/// 命名空间宏
|
||||||
|
#define PBR_NAMESPACE_BEGIN \
|
||||||
|
namespace PBR \
|
||||||
|
{
|
||||||
|
#define PBR_NAMESPACE_END }
|
||||||
|
|
||||||
|
/// windows 导入导出宏,PBR_EXPORTS将在cmake中定义
|
||||||
|
/// unix-like 下提供符号可见性控制
|
||||||
|
#ifdef PBR_STATIC_BUILD
|
||||||
|
#define PBR_API
|
||||||
|
#define PBR_LOCAL
|
||||||
|
#else
|
||||||
|
#ifdef _WIN32
|
||||||
|
#ifdef PBR_EXPORTS
|
||||||
|
#define PBR_API __declspec(dllexport)
|
||||||
|
#define PBR_LOCAL
|
||||||
|
#else
|
||||||
|
#define PBR_API __declspec(dllimport)
|
||||||
|
#define PBR_LOCAL
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#if __GNUC__ >= 4 || defined(__clang__)
|
||||||
|
#define PBR_API __attribute__((visibility("default")))
|
||||||
|
#define PBR_LOCAL __attribute__((visibility("hidden")))
|
||||||
|
#else
|
||||||
|
#define PBR_API
|
||||||
|
#define PBR_LOCAL
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#include "PbrTextureExtension.h"
|
#include "PbrTextureExtension.h"
|
||||||
|
|
||||||
GLTFLOADER_NAMESPACE_BEGIN
|
PBR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
PbrTextureExtension::PbrTextureExtension()
|
PbrTextureExtension::PbrTextureExtension()
|
||||||
{
|
{
|
||||||
|
|
@ -10,46 +10,44 @@ PbrTextureExtension::~PbrTextureExtension()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void PbrTextureExtension::setSpecularGlossinessTexture(glTFTexture* _texture)
|
void PbrTextureExtension::setSpecularGlossinessTexture(glTFLoader::glTFTexture *_texture)
|
||||||
{
|
{
|
||||||
m_specularGlossinessTexture = _texture;
|
m_specularGlossinessTexture = _texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
glTFTexture* PbrTextureExtension::getSpecularGlossinessTexture()
|
glTFLoader::glTFTexture *PbrTextureExtension::getSpecularGlossinessTexture()
|
||||||
{
|
{
|
||||||
return m_specularGlossinessTexture;
|
return m_specularGlossinessTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PbrTextureExtension::setDiffuseTexture(glTFTexture* _texture)
|
void PbrTextureExtension::setDiffuseTexture(glTFLoader::glTFTexture *_texture)
|
||||||
{
|
{
|
||||||
m_diffuseTexture = _texture;
|
m_diffuseTexture = _texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
glTFTexture* PbrTextureExtension::getDiffuseTexture()
|
glTFLoader::glTFTexture *PbrTextureExtension::getDiffuseTexture()
|
||||||
{
|
{
|
||||||
return m_diffuseTexture;
|
return m_diffuseTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PbrTextureExtension::setDiffuseFactor(glm::vec4 value)
|
void PbrTextureExtension::setDiffuseFactor(glm::vec4 value)
|
||||||
{
|
{
|
||||||
m_diffuseFactor = value;
|
m_diffuseFactor = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec4 PbrTextureExtension::getDiffuseFactor()
|
glm::vec4 PbrTextureExtension::getDiffuseFactor()
|
||||||
{
|
{
|
||||||
return m_diffuseFactor;
|
return m_diffuseFactor;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PbrTextureExtension::setSpecularFactor(glm::vec3 value)
|
void PbrTextureExtension::setSpecularFactor(glm::vec3 value)
|
||||||
{
|
{
|
||||||
m_specularFactor = value;
|
m_specularFactor = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 PbrTextureExtension::getSpecularFactor()
|
glm::vec3 PbrTextureExtension::getSpecularFactor()
|
||||||
{
|
{
|
||||||
return m_specularFactor;
|
return m_specularFactor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PBR_NAMESPACE_END
|
||||||
|
|
||||||
GLTFLOADER_NAMESPACE_END
|
|
||||||
|
|
@ -1,51 +1,39 @@
|
||||||
#ifndef PBRTEXTUREEXTENSION_H
|
#ifndef PBRTEXTUREEXTENSION_H
|
||||||
#define PBRTEXTUREEXTENSION_H
|
#define PBRTEXTUREEXTENSION_H
|
||||||
|
|
||||||
#include "glTFModel_Marco.h"
|
#include "PbrMarco.h"
|
||||||
|
|
||||||
#include "glTFTexture.h"
|
#include "glTFTexture.h"
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
PBR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
GLTFLOADER_NAMESPACE_BEGIN
|
class PbrTextureExtension
|
||||||
|
|
||||||
class PbrTextureExtension
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PbrTextureExtension();
|
PbrTextureExtension();
|
||||||
~PbrTextureExtension();
|
~PbrTextureExtension();
|
||||||
|
|
||||||
void setSpecularGlossinessTexture(glTFTexture* _texture);
|
void setSpecularGlossinessTexture(glTFLoader::glTFTexture *_texture);
|
||||||
glTFTexture* getSpecularGlossinessTexture();
|
glTFLoader::glTFTexture *getSpecularGlossinessTexture();
|
||||||
|
|
||||||
void setDiffuseTexture(glTFTexture* _texture);
|
void setDiffuseTexture(glTFLoader::glTFTexture *_texture);
|
||||||
glTFTexture* getDiffuseTexture();
|
glTFLoader::glTFTexture *getDiffuseTexture();
|
||||||
|
|
||||||
void setDiffuseFactor(glm::vec4 value);
|
void setDiffuseFactor(glm::vec4 value);
|
||||||
glm::vec4 getDiffuseFactor();
|
glm::vec4 getDiffuseFactor();
|
||||||
|
|
||||||
void setSpecularFactor(glm::vec3 value);
|
|
||||||
glm::vec3 getSpecularFactor();
|
|
||||||
|
|
||||||
|
void setSpecularFactor(glm::vec3 value);
|
||||||
|
glm::vec3 getSpecularFactor();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
glTFLoader::glTFTexture *m_specularGlossinessTexture = nullptr;
|
||||||
glTFTexture* m_specularGlossinessTexture = nullptr;
|
glTFLoader::glTFTexture *m_diffuseTexture = nullptr;
|
||||||
glTFTexture* m_diffuseTexture = nullptr;
|
glm::vec4 m_diffuseFactor = glm::vec4(1.0f);
|
||||||
glm::vec4 m_diffuseFactor = glm::vec4(1.0f);
|
glm::vec3 m_specularFactor = glm::vec3(0.0f);
|
||||||
glm::vec3 m_specularFactor = glm::vec3(0.0f);
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
PBR_NAMESPACE_END
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GLTFLOADER_NAMESPACE_END
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // !PbrTextureExtension_h
|
#endif // !PbrTextureExtension_h
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#include "PbrWorkFlow.h"
|
#include "PbrWorkFlow.h"
|
||||||
|
|
||||||
GLTFLOADER_NAMESPACE_BEGIN
|
PBR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
PbrWorkFlow::PbrWorkFlow()
|
PbrWorkFlow::PbrWorkFlow()
|
||||||
{
|
{
|
||||||
|
|
@ -32,4 +32,4 @@ bool PbrWorkFlow::getSpecularGlossiness()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GLTFLOADER_NAMESPACE_END
|
PBR_NAMESPACE_END
|
||||||
|
|
@ -1,33 +1,27 @@
|
||||||
#ifndef PBRWORKFLOW_H
|
#ifndef PBRWORKFLOW_H
|
||||||
#define PBRWORKFLOW_H
|
#define PBRWORKFLOW_H
|
||||||
|
|
||||||
#include "glTFModel_Marco.h"
|
#include "PbrMarco.h"
|
||||||
|
|
||||||
GLTFLOADER_NAMESPACE_BEGIN
|
PBR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
class PbrWorkFlow
|
class PbrWorkFlow
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PbrWorkFlow();
|
PbrWorkFlow();
|
||||||
~PbrWorkFlow();
|
~PbrWorkFlow();
|
||||||
|
|
||||||
void setMetallicRoughness(bool value);
|
void setMetallicRoughness(bool value);
|
||||||
bool getMetallicRoughness();
|
bool getMetallicRoughness();
|
||||||
|
|
||||||
void setSpecularGlossiness(bool value);
|
void setSpecularGlossiness(bool value);
|
||||||
bool getSpecularGlossiness();
|
bool getSpecularGlossiness();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool m_metallicRoughness = true;
|
||||||
bool m_metallicRoughness = true;
|
bool m_specularGlossiness = false;
|
||||||
bool m_specularGlossiness = false;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
PBR_NAMESPACE_END
|
||||||
|
|
||||||
|
|
||||||
GLTFLOADER_NAMESPACE_END
|
|
||||||
|
|
||||||
|
|
||||||
#endif // !PBRWORKFLOW_H
|
#endif // !PBRWORKFLOW_H
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,12 @@
|
||||||
#include "IrradiancePushBlock.h"
|
#include "IrradiancePushBlock.h"
|
||||||
|
|
||||||
|
IrradiancePushBlock::IrradiancePushBlock()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
IrradiancePushBlock::~IrradiancePushBlock()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
// Getter method definitions
|
// Getter method definitions
|
||||||
float IrradiancePushBlock::getDeltaPhi() const
|
float IrradiancePushBlock::getDeltaPhi() const
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,45 +1,45 @@
|
||||||
#include "RenderSceneTextures.h"
|
#include "RenderSceneTextures.h"
|
||||||
|
|
||||||
// Getters
|
// Getters
|
||||||
vks::TextureCubeMap &RenderSceneTextures::getEnvironmentCube()
|
VulkanBase::TextureCubeMap &RenderSceneTextures::getEnvironmentCube()
|
||||||
{
|
{
|
||||||
return m_environmentCube;
|
return m_environmentCube;
|
||||||
}
|
}
|
||||||
vks::Texture2D &RenderSceneTextures::getEmpty()
|
VulkanBase::Texture2D &RenderSceneTextures::getEmpty()
|
||||||
{
|
{
|
||||||
return m_empty;
|
return m_empty;
|
||||||
}
|
}
|
||||||
vks::Texture2D &RenderSceneTextures::getLutBrdf()
|
VulkanBase::Texture2D &RenderSceneTextures::getLutBrdf()
|
||||||
{
|
{
|
||||||
return m_lutBrdf;
|
return m_lutBrdf;
|
||||||
}
|
}
|
||||||
vks::TextureCubeMap &RenderSceneTextures::getIrradianceCube()
|
VulkanBase::TextureCubeMap &RenderSceneTextures::getIrradianceCube()
|
||||||
{
|
{
|
||||||
return m_irradianceCube;
|
return m_irradianceCube;
|
||||||
}
|
}
|
||||||
vks::TextureCubeMap &RenderSceneTextures::getPrefilteredCube()
|
VulkanBase::TextureCubeMap &RenderSceneTextures::getPrefilteredCube()
|
||||||
{
|
{
|
||||||
return m_prefilteredCube;
|
return m_prefilteredCube;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setters
|
// Setters
|
||||||
void RenderSceneTextures::setEnvironmentCube(const vks::TextureCubeMap &texture)
|
void RenderSceneTextures::setEnvironmentCube(const VulkanBase::TextureCubeMap &texture)
|
||||||
{
|
{
|
||||||
m_environmentCube = texture;
|
m_environmentCube = texture;
|
||||||
}
|
}
|
||||||
void RenderSceneTextures::setEmpty(const vks::Texture2D &texture)
|
void RenderSceneTextures::setEmpty(const VulkanBase::Texture2D &texture)
|
||||||
{
|
{
|
||||||
m_empty = texture;
|
m_empty = texture;
|
||||||
}
|
}
|
||||||
void RenderSceneTextures::setLutBrdf(const vks::Texture2D &texture)
|
void RenderSceneTextures::setLutBrdf(const VulkanBase::Texture2D &texture)
|
||||||
{
|
{
|
||||||
m_lutBrdf = texture;
|
m_lutBrdf = texture;
|
||||||
}
|
}
|
||||||
void RenderSceneTextures::setIrradianceCube(const vks::TextureCubeMap &texture)
|
void RenderSceneTextures::setIrradianceCube(const VulkanBase::TextureCubeMap &texture)
|
||||||
{
|
{
|
||||||
m_irradianceCube = texture;
|
m_irradianceCube = texture;
|
||||||
}
|
}
|
||||||
void RenderSceneTextures::setPrefilteredCube(const vks::TextureCubeMap &texture)
|
void RenderSceneTextures::setPrefilteredCube(const VulkanBase::TextureCubeMap &texture)
|
||||||
{
|
{
|
||||||
m_prefilteredCube = texture;
|
m_prefilteredCube = texture;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <VulkanTexture.hpp>
|
#include <VulkanTexture.h>
|
||||||
|
|
||||||
class RenderSceneTextures
|
class RenderSceneTextures
|
||||||
{
|
{
|
||||||
|
|
@ -9,18 +9,18 @@ public:
|
||||||
~RenderSceneTextures();
|
~RenderSceneTextures();
|
||||||
|
|
||||||
// Getters
|
// Getters
|
||||||
vks::TextureCubeMap &getEnvironmentCube();
|
VulkanBase::TextureCubeMap &getEnvironmentCube();
|
||||||
vks::Texture2D &getEmpty();
|
VulkanBase::Texture2D &getEmpty();
|
||||||
vks::Texture2D &getLutBrdf();
|
VulkanBase::Texture2D &getLutBrdf();
|
||||||
vks::TextureCubeMap &getIrradianceCube();
|
VulkanBase::TextureCubeMap &getIrradianceCube();
|
||||||
vks::TextureCubeMap &getPrefilteredCube();
|
VulkanBase::TextureCubeMap &getPrefilteredCube();
|
||||||
|
|
||||||
// Setters
|
// Setters
|
||||||
void setEnvironmentCube(const vks::TextureCubeMap &texture);
|
void setEnvironmentCube(const VulkanBase::TextureCubeMap &texture);
|
||||||
void setEmpty(const vks::Texture2D &texture);
|
void setEmpty(const VulkanBase::Texture2D &texture);
|
||||||
void setLutBrdf(const vks::Texture2D &texture);
|
void setLutBrdf(const VulkanBase::Texture2D &texture);
|
||||||
void setIrradianceCube(const vks::TextureCubeMap &texture);
|
void setIrradianceCube(const VulkanBase::TextureCubeMap &texture);
|
||||||
void setPrefilteredCube(const vks::TextureCubeMap &texture);
|
void setPrefilteredCube(const VulkanBase::TextureCubeMap &texture);
|
||||||
|
|
||||||
// destroy
|
// destroy
|
||||||
void destroyEnvironmentCube();
|
void destroyEnvironmentCube();
|
||||||
|
|
@ -30,9 +30,9 @@ public:
|
||||||
void destroyPrefilteredCube();
|
void destroyPrefilteredCube();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
vks::TextureCubeMap m_environmentCube;
|
VulkanBase::TextureCubeMap m_environmentCube;
|
||||||
vks::Texture2D m_empty;
|
VulkanBase::Texture2D m_empty;
|
||||||
vks::Texture2D m_lutBrdf;
|
VulkanBase::Texture2D m_lutBrdf;
|
||||||
vks::TextureCubeMap m_irradianceCube;
|
VulkanBase::TextureCubeMap m_irradianceCube;
|
||||||
vks::TextureCubeMap m_prefilteredCube;
|
VulkanBase::TextureCubeMap m_prefilteredCube;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,147 @@
|
||||||
|
#include "ShaderLoader.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
ShaderLoader::ShaderLoader()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderLoader::~ShaderLoader()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPipelineShaderStageCreateInfo ShaderLoader::loadShader(VkDevice device, std::string filename, VkShaderStageFlagBits stage)
|
||||||
|
{
|
||||||
|
VkPipelineShaderStageCreateInfo shaderStage{};
|
||||||
|
shaderStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||||
|
shaderStage.stage = stage;
|
||||||
|
shaderStage.pName = "main";
|
||||||
|
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
|
||||||
|
std::string assetpath = "shaders/" + filename;
|
||||||
|
AAsset *asset = AAssetManager_open(androidApp->activity->assetManager, assetpath.c_str(), AASSET_MODE_STREAMING);
|
||||||
|
assert(asset);
|
||||||
|
size_t size = AAsset_getLength(asset);
|
||||||
|
assert(size > 0);
|
||||||
|
char *shaderCode = new char[size];
|
||||||
|
AAsset_read(asset, shaderCode, size);
|
||||||
|
AAsset_close(asset);
|
||||||
|
VkShaderModule shaderModule;
|
||||||
|
VkShaderModuleCreateInfo moduleCreateInfo;
|
||||||
|
moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||||
|
moduleCreateInfo.pNext = NULL;
|
||||||
|
moduleCreateInfo.codeSize = size;
|
||||||
|
moduleCreateInfo.pCode = (uint32_t *)shaderCode;
|
||||||
|
moduleCreateInfo.flags = 0;
|
||||||
|
VK_CHECK_RESULT(vkCreateShaderModule(device, &moduleCreateInfo, NULL, &shaderStage.module));
|
||||||
|
delete[] shaderCode;
|
||||||
|
#else
|
||||||
|
std::ifstream is(filename, std::ios::binary | std::ios::in | std::ios::ate);
|
||||||
|
|
||||||
|
if (is.is_open())
|
||||||
|
{
|
||||||
|
size_t size = is.tellg();
|
||||||
|
is.seekg(0, std::ios::beg);
|
||||||
|
char *shaderCode = new char[size];
|
||||||
|
is.read(shaderCode, size);
|
||||||
|
is.close();
|
||||||
|
assert(size > 0);
|
||||||
|
VkShaderModuleCreateInfo moduleCreateInfo{};
|
||||||
|
moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||||
|
moduleCreateInfo.codeSize = size;
|
||||||
|
moduleCreateInfo.pCode = (uint32_t *)shaderCode;
|
||||||
|
vkCreateShaderModule(device, &moduleCreateInfo, NULL, &shaderStage.module);
|
||||||
|
delete[] shaderCode;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cerr << "Error: Could not open shader file \"" << filename << "\"" << std::endl;
|
||||||
|
shaderStage.module = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return shaderStage;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderLoader::readDirectory(const std::string &directory, const std::string &pattern, std::map<std::string, std::string> &filelist, bool recursive)
|
||||||
|
{
|
||||||
|
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
|
||||||
|
AAssetDir *assetDir = AAssetManager_openDir(androidApp->activity->assetManager, directory.c_str());
|
||||||
|
AAssetDir_rewind(assetDir);
|
||||||
|
const char *assetName;
|
||||||
|
while ((assetName = AAssetDir_getNextFileName(assetDir)) != 0)
|
||||||
|
{
|
||||||
|
std::string filename(assetName);
|
||||||
|
filename.erase(filename.find_last_of("."), std::string::npos);
|
||||||
|
filelist[filename] = directory + "/" + assetName;
|
||||||
|
}
|
||||||
|
AAssetDir_close(assetDir);
|
||||||
|
#elif defined(VK_USE_PLATFORM_WIN32_KHR)
|
||||||
|
std::string searchpattern(directory + "/" + pattern);
|
||||||
|
WIN32_FIND_DATA data;
|
||||||
|
HANDLE hFind;
|
||||||
|
if ((hFind = FindFirstFile(searchpattern.c_str(), &data)) != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
std::string filename(data.cFileName);
|
||||||
|
filename.erase(filename.find_last_of("."), std::string::npos);
|
||||||
|
filelist[filename] = directory + "/" + data.cFileName;
|
||||||
|
} while (FindNextFile(hFind, &data) != 0);
|
||||||
|
FindClose(hFind);
|
||||||
|
}
|
||||||
|
if (recursive)
|
||||||
|
{
|
||||||
|
std::string dirpattern = directory + "/*";
|
||||||
|
if ((hFind = FindFirstFile(dirpattern.c_str(), &data)) != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||||
|
{
|
||||||
|
char subdir[MAX_PATH];
|
||||||
|
strcpy(subdir, directory.c_str());
|
||||||
|
strcat(subdir, "/");
|
||||||
|
strcat(subdir, data.cFileName);
|
||||||
|
if ((strcmp(data.cFileName, ".") != 0) && (strcmp(data.cFileName, "..") != 0))
|
||||||
|
{
|
||||||
|
readDirectory(subdir, pattern, filelist, recursive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (FindNextFile(hFind, &data) != 0);
|
||||||
|
FindClose(hFind);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#elif defined(__linux__)
|
||||||
|
std::string patternExt = pattern;
|
||||||
|
patternExt.erase(0, pattern.find_last_of("."));
|
||||||
|
struct dirent *entry;
|
||||||
|
DIR *dir = opendir(directory.c_str());
|
||||||
|
if (dir == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while ((entry = readdir(dir)) != NULL)
|
||||||
|
{
|
||||||
|
if (entry->d_type == DT_REG)
|
||||||
|
{
|
||||||
|
std::string filename(entry->d_name);
|
||||||
|
if (filename.find(patternExt) != std::string::npos)
|
||||||
|
{
|
||||||
|
filename.erase(filename.find_last_of("."), std::string::npos);
|
||||||
|
filelist[filename] = directory + "/" + entry->d_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (recursive && (entry->d_type == DT_DIR))
|
||||||
|
{
|
||||||
|
std::string subdir = directory + "/" + entry->d_name;
|
||||||
|
if ((strcmp(entry->d_name, ".") != 0) && (strcmp(entry->d_name, "..") != 0))
|
||||||
|
{
|
||||||
|
readDirectory(subdir, pattern, filelist, recursive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
#ifndef SHADERLOADER_H
|
||||||
|
#define SHADERLOADER_H
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
|
class ShaderLoader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ShaderLoader();
|
||||||
|
~ShaderLoader();
|
||||||
|
static VkPipelineShaderStageCreateInfo loadShader(VkDevice device, std::string filename, VkShaderStageFlagBits stage);
|
||||||
|
static void readDirectory(const std::string &directory, const std::string &pattern, std::map<std::string, std::string> &filelist, bool recursive);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -1,213 +0,0 @@
|
||||||
#include "VulkanDevice.h"
|
|
||||||
#include <cassert>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <VulkanTools.h>
|
|
||||||
|
|
||||||
VULKANBASE_NAMESPACE_BEGIN
|
|
||||||
|
|
||||||
VulkanDevice::VulkanDevice()
|
|
||||||
:m_commandPool(VK_NULL_HANDLE)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
VulkanDevice::VulkanDevice(VkPhysicalDevice physicalDevice)
|
|
||||||
{
|
|
||||||
/// 检查物理设备是否存在,后续使用log方式记录
|
|
||||||
assert(physicalDevice);
|
|
||||||
m_physicalDevice = physicalDevice;
|
|
||||||
|
|
||||||
/// 获取设备信息
|
|
||||||
vkGetPhysicalDeviceProperties(physicalDevice, &m_properties);
|
|
||||||
/// 获取设备支持的功能
|
|
||||||
vkGetPhysicalDeviceFeatures(physicalDevice, &m_features);
|
|
||||||
/// 获取设备内存信息,用于创建内存
|
|
||||||
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &m_memoryProperties);
|
|
||||||
/// 队列族信息,用于设备创建时获取设置获取的队列
|
|
||||||
uint32_t queueFamilyCount;
|
|
||||||
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, nullptr);
|
|
||||||
/// 检查设备队列族数量,必须大于0
|
|
||||||
assert(queueFamilyCount > 0);
|
|
||||||
m_queueFamilyProperties.resize(queueFamilyCount);
|
|
||||||
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, m_queueFamilyProperties.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
VulkanDevice::~VulkanDevice()
|
|
||||||
{
|
|
||||||
if (m_commandPool) {
|
|
||||||
vkDestroyCommandPool(m_logicalDevice, m_commandPool, nullptr);
|
|
||||||
}
|
|
||||||
if (m_logicalDevice) {
|
|
||||||
vkDestroyDevice(m_logicalDevice, nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDevice VulkanDevice::getLogicalDevice()
|
|
||||||
{
|
|
||||||
return m_logicalDevice;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkPhysicalDevice VulkanDevice::getPhysicalDevice()
|
|
||||||
{
|
|
||||||
return m_physicalDevice;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t VulkanDevice::getMemoryType(uint32_t typeBits, VkMemoryPropertyFlags properties, VkBool32* memTypeFound)
|
|
||||||
{
|
|
||||||
for (uint32_t i = 0; i < m_memoryProperties.memoryTypeCount; i++) {
|
|
||||||
if ((typeBits & 1) == 1) {
|
|
||||||
if ((m_memoryProperties.memoryTypes[i].propertyFlags & properties) == properties) {
|
|
||||||
if (memTypeFound) {
|
|
||||||
*memTypeFound = true;
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
typeBits >>= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (memTypeFound) {
|
|
||||||
*memTypeFound = false;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw std::runtime_error("Could not find a matching memory type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t VulkanDevice::getQueueFamilyIndex(VkQueueFlagBits queueFlags)
|
|
||||||
{
|
|
||||||
/// 获取支持计算的队列组索引
|
|
||||||
if (queueFlags & VK_QUEUE_COMPUTE_BIT)
|
|
||||||
{
|
|
||||||
for (uint32_t i = 0; i < static_cast<uint32_t>(m_queueFamilyProperties.size()); i++) {
|
|
||||||
if ((m_queueFamilyProperties[i].queueFlags & queueFlags) && ((m_queueFamilyProperties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0)) {
|
|
||||||
return i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 对于其他的队列类型,如果当前没有单独的计算队列,返回支持标志类型的第一个队列
|
|
||||||
for (uint32_t i = 0; i < static_cast<uint32_t>(m_queueFamilyProperties.size()); i++) {
|
|
||||||
if (m_queueFamilyProperties[i].queueFlags & queueFlags) {
|
|
||||||
return i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw std::runtime_error("Could not find a matching queue family index");
|
|
||||||
}
|
|
||||||
|
|
||||||
VkResult VulkanDevice::createBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkDeviceSize size, VkBuffer* buffer, VkDeviceMemory* memory, void* data)
|
|
||||||
{
|
|
||||||
// 创建buffer句柄
|
|
||||||
VkBufferCreateInfo bufferCreateInfo{};
|
|
||||||
bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
|
||||||
bufferCreateInfo.usage = usageFlags;
|
|
||||||
bufferCreateInfo.size = size;
|
|
||||||
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
||||||
VK_CHECK_RESULT(vkCreateBuffer(m_logicalDevice, &bufferCreateInfo, nullptr, buffer));
|
|
||||||
|
|
||||||
// 创建buffer的设备内存分配信息
|
|
||||||
VkMemoryRequirements memReqs;
|
|
||||||
VkMemoryAllocateInfo memAlloc{};
|
|
||||||
memAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
|
||||||
vkGetBufferMemoryRequirements(m_logicalDevice, *buffer, &memReqs);
|
|
||||||
memAlloc.allocationSize = memReqs.size;
|
|
||||||
/// 获取符合buffer的设备内存类型索引
|
|
||||||
memAlloc.memoryTypeIndex = getMemoryType(memReqs.memoryTypeBits, memoryPropertyFlags);
|
|
||||||
VK_CHECK_RESULT(vkAllocateMemory(m_logicalDevice, &memAlloc, nullptr, memory));
|
|
||||||
|
|
||||||
// 如何buffer指针已经存在,复制或者映射该buffer
|
|
||||||
if (data != nullptr)
|
|
||||||
{
|
|
||||||
void* mapped;
|
|
||||||
VK_CHECK_RESULT(vkMapMemory(m_logicalDevice, *memory, 0, size, 0, &mapped));
|
|
||||||
memcpy(mapped, data, size);
|
|
||||||
// 如果host coherency 未设置, 对buffer进行flush,让设备侧可见
|
|
||||||
if ((memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0)
|
|
||||||
{
|
|
||||||
VkMappedMemoryRange mappedRange{};
|
|
||||||
mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
|
|
||||||
mappedRange.memory = *memory;
|
|
||||||
mappedRange.offset = 0;
|
|
||||||
mappedRange.size = size;
|
|
||||||
vkFlushMappedMemoryRanges(m_logicalDevice, 1, &mappedRange);
|
|
||||||
}
|
|
||||||
vkUnmapMemory(m_logicalDevice, *memory);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 绑定设备内存到buffer object
|
|
||||||
VK_CHECK_RESULT(vkBindBufferMemory(m_logicalDevice, *buffer, *memory, 0));
|
|
||||||
|
|
||||||
return VK_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkCommandPool VulkanDevice::createCommandPool(uint32_t queueFamilyIndex, VkCommandPoolCreateFlags createFlags)
|
|
||||||
{
|
|
||||||
/// 创建命令缓冲池
|
|
||||||
VkCommandPoolCreateInfo cmdPoolInfo = {};
|
|
||||||
cmdPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
|
||||||
cmdPoolInfo.queueFamilyIndex = queueFamilyIndex;
|
|
||||||
cmdPoolInfo.flags = createFlags;
|
|
||||||
VkCommandPool cmdPool;
|
|
||||||
VK_CHECK_RESULT(vkCreateCommandPool(m_logicalDevice, &cmdPoolInfo, nullptr, &cmdPool));
|
|
||||||
return cmdPool;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkCommandBuffer VulkanDevice::createCommandBuffer(VkCommandBufferLevel level, bool begin)
|
|
||||||
{
|
|
||||||
VkCommandBufferAllocateInfo cmdBufAllocateInfo{};
|
|
||||||
cmdBufAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
|
||||||
cmdBufAllocateInfo.commandPool = m_commandPool;
|
|
||||||
cmdBufAllocateInfo.level = level;
|
|
||||||
cmdBufAllocateInfo.commandBufferCount = 1;
|
|
||||||
|
|
||||||
VkCommandBuffer cmdBuffer;
|
|
||||||
VK_CHECK_RESULT(vkAllocateCommandBuffers(m_logicalDevice, &cmdBufAllocateInfo, &cmdBuffer));
|
|
||||||
|
|
||||||
// 开始记录指令buffer
|
|
||||||
if (begin) {
|
|
||||||
beginCommandBuffer(cmdBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
return cmdBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanDevice::beginCommandBuffer(VkCommandBuffer commandBuffer)
|
|
||||||
{
|
|
||||||
VkCommandBufferBeginInfo commandBufferBI{};
|
|
||||||
commandBufferBI.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
|
||||||
VK_CHECK_RESULT(vkBeginCommandBuffer(commandBuffer, &commandBufferBI));
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanDevice::flushCommandBuffer(VkCommandBuffer commandBuffer, VkQueue queue, bool free)
|
|
||||||
{
|
|
||||||
VK_CHECK_RESULT(vkEndCommandBuffer(commandBuffer));
|
|
||||||
|
|
||||||
VkSubmitInfo submitInfo{};
|
|
||||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
|
||||||
submitInfo.commandBufferCount = 1;
|
|
||||||
submitInfo.pCommandBuffers = &commandBuffer;
|
|
||||||
|
|
||||||
//创建同步栅栏,确保命令buffer执行完毕
|
|
||||||
VkFenceCreateInfo fenceInfo{};
|
|
||||||
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
|
||||||
VkFence fence;
|
|
||||||
VK_CHECK_RESULT(vkCreateFence(m_logicalDevice, &fenceInfo, nullptr, &fence));
|
|
||||||
|
|
||||||
// 提交队列
|
|
||||||
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, fence));
|
|
||||||
// 等待栅栏发出信号说明命令buffer执行完毕
|
|
||||||
VK_CHECK_RESULT(vkWaitForFences(m_logicalDevice, 1, &fence, VK_TRUE, 100000000000));
|
|
||||||
// 同步栅栏使命结束,销毁
|
|
||||||
vkDestroyFence(m_logicalDevice, fence, nullptr);
|
|
||||||
// 需要的时候,销毁命令buffer
|
|
||||||
if (free) {
|
|
||||||
vkFreeCommandBuffers(m_logicalDevice, m_commandPool, 1, &commandBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VULKANBASE_NAMESPACE_END
|
|
||||||
|
|
@ -1,97 +0,0 @@
|
||||||
#ifndef VULKANDEVICE_H
|
|
||||||
#define VULKANDEVICE_H
|
|
||||||
|
|
||||||
#include "VulkanBase_Marco.h"
|
|
||||||
|
|
||||||
#include <vulkan/vulkan.h>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
VULKANBASE_NAMESPACE_BEGIN
|
|
||||||
|
|
||||||
/// @brief vulkan的设备类
|
|
||||||
class VulkanDevice
|
|
||||||
{
|
|
||||||
/// @brief 构造和setter/getter
|
|
||||||
public:
|
|
||||||
VulkanDevice();
|
|
||||||
VulkanDevice(VkPhysicalDevice physicalDevice);
|
|
||||||
~VulkanDevice();
|
|
||||||
|
|
||||||
VkDevice getLogicalDevice();
|
|
||||||
VkPhysicalDevice getPhysicalDevice();
|
|
||||||
|
|
||||||
public:
|
|
||||||
/// @brief 获取已设置所有请求属性位的设备内存类型的索引
|
|
||||||
/// @param typeBits 请求的每种设备内存类型设置的位掩码,通常通过VkMemoryRequirements获取
|
|
||||||
/// @param properties 要请求的设备内存类型的属性位掩码
|
|
||||||
/// @param memTypeFound 如果符合的设备内存类型存在,则该指针的布尔值为true
|
|
||||||
/// @return 请求的设备内存类型的索引
|
|
||||||
/// @throw 如果 memTypeFound 为空且找不到支持需要的属性的设备内存类型,则抛出异常
|
|
||||||
uint32_t getMemoryType(uint32_t typeBits, VkMemoryPropertyFlags properties, VkBool32* memTypeFound = nullptr);
|
|
||||||
/// @brief 获取支持所请求队列标志的队列族的索引
|
|
||||||
/// @param queueFlags 用于查找队列族索引的队列标志
|
|
||||||
/// @return 与标志匹配的队列族索引
|
|
||||||
/// @throw 如果找不到支持所请求标志的队列族索引,则抛出异常
|
|
||||||
uint32_t getQueueFamilyIndex(VkQueueFlagBits queueFlags);
|
|
||||||
/// @brief 据分配的物理设备创建逻辑设备,同时获取默认队列族索引
|
|
||||||
/// @param enabledFeatures 在创建设备时启用某些功能
|
|
||||||
/// @param enabledExtensions 在创建设备时启用某些扩展
|
|
||||||
/// @param requestedQueueTypes 指定要从设备请求的队列类型
|
|
||||||
/// @return 逻辑设备是否成功创建
|
|
||||||
VkResult createLogicalDevice(VkPhysicalDeviceFeatures enabledFeatures, std::vector<const char*> enabledExtensions, VkQueueFlags requestedQueueTypes = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT);
|
|
||||||
/// @brief 在设备上创建缓冲区
|
|
||||||
/// @param usageFlags 缓冲区的使用标志位掩码(即索引、顶点、统一缓冲区)
|
|
||||||
/// @param memoryPropertyFlags 此缓冲区的内存属性(即设备本地、主机可见、一致)
|
|
||||||
/// @param size 缓冲区的大小(以字节为单位)
|
|
||||||
/// @param buffer 指向函数获取的缓冲区句柄的指针
|
|
||||||
/// @param memory 指向函数获取的设备内存句柄的指针
|
|
||||||
/// @param data 指向创建后应复制到缓冲区的数据的指针(可选,如果未设置,则不会复制任何数据)
|
|
||||||
/// @return 如果已创建缓冲区句柄和设备内存并且已复制数据(可选传递),则返回 VK_SUCCESS
|
|
||||||
VkResult createBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkDeviceSize size, VkBuffer* buffer, VkDeviceMemory* memory, void* data = nullptr);
|
|
||||||
/// @brief 创建命令池以分配命令缓冲区
|
|
||||||
/// @param queueFamilyIndex 要为其创建命令池的队列的系列索引
|
|
||||||
/// @param createFlags 可选)命令池创建标志(默认为 VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT)
|
|
||||||
/// @return 创建的命令缓冲区的句柄
|
|
||||||
VkCommandPool createCommandPool(uint32_t queueFamilyIndex, VkCommandPoolCreateFlags createFlags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT);
|
|
||||||
/// @brief 从命令池中分配命令缓冲区
|
|
||||||
/// @param level 新命令缓冲区的级别(主或次)
|
|
||||||
/// @param begin 为 true时开始在新命令缓冲区上进行记录
|
|
||||||
/// @return 分配的命令缓冲区的句柄
|
|
||||||
VkCommandBuffer createCommandBuffer(VkCommandBufferLevel level, bool begin = false);
|
|
||||||
/// @brief 开始在指定命令缓冲区记录
|
|
||||||
/// @param commandBuffer
|
|
||||||
void beginCommandBuffer(VkCommandBuffer commandBuffer);
|
|
||||||
/// @brief 停止指定命令缓冲区记录并将其提交到队列,使用栅栏来确保命令缓冲区已完成执行
|
|
||||||
/// @param commandBuffer 要刷新的命令缓冲区
|
|
||||||
/// @param queue 要将命令缓冲区提交到的队列
|
|
||||||
/// @param free 提交后释放命令缓冲区(默认为 true)
|
|
||||||
void flushCommandBuffer(VkCommandBuffer commandBuffer, VkQueue queue, bool free = true);
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
VkPhysicalDevice m_physicalDevice;
|
|
||||||
VkDevice m_logicalDevice;
|
|
||||||
VkPhysicalDeviceProperties m_properties;
|
|
||||||
VkPhysicalDeviceFeatures m_features;
|
|
||||||
VkPhysicalDeviceFeatures m_enabledFeatures;
|
|
||||||
VkPhysicalDeviceMemoryProperties m_memoryProperties;
|
|
||||||
std::vector<VkQueueFamilyProperties> m_queueFamilyProperties;
|
|
||||||
VkCommandPool m_commandPool;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
uint32_t graphics;
|
|
||||||
uint32_t compute;
|
|
||||||
} m_queueFamilyIndices;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
VULKANBASE_NAMESPACE_END
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // !VULKANDEVICE_H
|
|
||||||
|
|
@ -1,18 +1,26 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#ifndef TINYGLTF_IMPLEMENTATION
|
#include "render.h"
|
||||||
#define TINYGLTF_IMPLEMENTATION
|
|
||||||
|
#include "PbrBaseTexture.h"
|
||||||
|
#include "PbrTextureCoordSet.h"
|
||||||
|
#include "glTFMainModel.h"
|
||||||
|
|
||||||
#include "PushConstBlockMaterial.h"
|
#include "PushConstBlockMaterial.h"
|
||||||
#include "VulkanTexture.hpp"
|
#include "ShaderLoader.h"
|
||||||
#include "glTFModel.h"
|
#include "VulkanTexture.h"
|
||||||
|
|
||||||
|
#include "glTFMaterial.h"
|
||||||
|
#include "glTFPrimitive.h"
|
||||||
|
#include "glTFSkin.h"
|
||||||
|
#include "glTFTexture.h"
|
||||||
#include "glm/gtc/matrix_transform.hpp"
|
#include "glm/gtc/matrix_transform.hpp"
|
||||||
#include "renderUniformBufferSet.h"
|
#include "renderUniformBufferSet.h"
|
||||||
#include "vulkan/vulkan_core.h"
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#endif
|
|
||||||
#ifndef STB_IMAGE_IMPLEMENTATION
|
#ifndef STB_IMAGE_IMPLEMENTATION
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -21,7 +29,6 @@
|
||||||
#define TINYGLTF_NO_STB_IMAGE_WRITE
|
#define TINYGLTF_NO_STB_IMAGE_WRITE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "render.h"
|
|
||||||
// #include "VulkanUtils.hpp"
|
// #include "VulkanUtils.hpp"
|
||||||
// #include "assetLoader.h"
|
// #include "assetLoader.h"
|
||||||
|
|
||||||
|
|
@ -30,21 +37,21 @@ PlumageRender::PlumageRender()
|
||||||
title = "plumage render";
|
title = "plumage render";
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlumageRender::renderNode(glTFModel::Node *node, uint32_t cbIndex, glTFModel::Material::AlphaMode alphaMode)
|
void PlumageRender::renderNode(glTFLoader::glTFNode *node, uint32_t cbIndex, glTFLoader::AlphaMode alphaMode)
|
||||||
{
|
{
|
||||||
if (node->mesh)
|
if (node->getMesh())
|
||||||
{
|
{
|
||||||
// Render mesh primitives
|
// Render mesh primitives
|
||||||
for (glTFModel::Primitive *primitive : node->mesh->primitives)
|
for (glTFLoader::glTFPrimitive *primitive : node->getMesh()->getPrimitives())
|
||||||
{
|
{
|
||||||
if (primitive->material.alphaMode == alphaMode)
|
if (primitive->getGltfMaterial().getAlphaMode() == alphaMode)
|
||||||
{
|
{
|
||||||
VkPipeline pipeline = VK_NULL_HANDLE;
|
VkPipeline pipeline = VK_NULL_HANDLE;
|
||||||
switch (alphaMode)
|
switch (alphaMode)
|
||||||
{
|
{
|
||||||
case glTFModel::Material::ALPHAMODE_OPAQUE:
|
case glTFLoader::ALPHAMODE_OPAQUE:
|
||||||
case glTFModel::Material::ALPHAMODE_MASK:
|
case glTFLoader::ALPHAMODE_MASK:
|
||||||
if (primitive->material.doubleSided)
|
if (primitive->getGltfMaterial().getDoublesided())
|
||||||
{
|
{
|
||||||
pipeline = m_pipelineList.getPbrDoubleSided();
|
pipeline = m_pipelineList.getPbrDoubleSided();
|
||||||
}
|
}
|
||||||
|
|
@ -53,7 +60,7 @@ void PlumageRender::renderNode(glTFModel::Node *node, uint32_t cbIndex, glTFMode
|
||||||
pipeline = m_pipelineList.getPbr();
|
pipeline = m_pipelineList.getPbr();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case glTFModel::Material::ALPHAMODE_BLEND:
|
case glTFLoader::ALPHAMODE_BLEND:
|
||||||
pipeline = m_pipelineList.getPbrAlphaBlend();
|
pipeline = m_pipelineList.getPbrAlphaBlend();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -66,78 +73,81 @@ void PlumageRender::renderNode(glTFModel::Node *node, uint32_t cbIndex, glTFMode
|
||||||
|
|
||||||
const std::vector<VkDescriptorSet> descriptorsets = {
|
const std::vector<VkDescriptorSet> descriptorsets = {
|
||||||
descriptorSets[cbIndex].getScene(),
|
descriptorSets[cbIndex].getScene(),
|
||||||
primitive->material.descriptorSet,
|
primitive->getGltfMaterial().getDescriptorSet(),
|
||||||
node->mesh->uniformBuffer.descriptorSet,
|
node->getMesh()->getUniformBuffer().descriptorSet,
|
||||||
};
|
};
|
||||||
vkCmdBindDescriptorSets(commandBuffers[cbIndex], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, static_cast<uint32_t>(descriptorsets.size()), descriptorsets.data(), 0, NULL);
|
vkCmdBindDescriptorSets(commandBuffers[cbIndex], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, static_cast<uint32_t>(descriptorsets.size()), descriptorsets.data(), 0, NULL);
|
||||||
|
|
||||||
// Pass material parameters as push constants
|
// Pass material parameters as push constants
|
||||||
PushConstBlockMaterial m_pushConstBlockMaterial;
|
PushConstBlockMaterial m_pushConstBlockMaterial;
|
||||||
m_pushConstBlockMaterial.setEmissiveFactor(primitive->material.emissiveFactor);
|
PBR::PbrBaseTexture *pbrBaseTexture = primitive->getGltfMaterial().getPbrBaseTexture();
|
||||||
|
glTFLoader::TextureCoordSet *texCoordSet = primitive->getGltfMaterial().getTextureCoordSet();
|
||||||
|
m_pushConstBlockMaterial.setEmissiveFactor(pbrBaseTexture->getEmissiveFactor());
|
||||||
// To save push constant space, availabilty and texture coordiante set are combined
|
// To save push constant space, availabilty and texture coordiante set are combined
|
||||||
// -1 = texture not used for this material, >= 0 texture used and index of texture coordinate set
|
// -1 = texture not used for this material, >= 0 texture used and index of texture coordinate set
|
||||||
if (primitive->material.baseColorTexture != nullptr)
|
if (pbrBaseTexture->getBaseColorTexture() != nullptr)
|
||||||
{
|
{
|
||||||
|
|
||||||
m_pushConstBlockMaterial.setColorTextureSet(primitive->material.texCoordSets.baseColor);
|
m_pushConstBlockMaterial.setColorTextureSet(texCoordSet->getBaseColor());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_pushConstBlockMaterial.setColorTextureSet(-1);
|
m_pushConstBlockMaterial.setColorTextureSet(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (primitive->material.normalTexture != nullptr)
|
if (pbrBaseTexture->getNormalTexture() != nullptr)
|
||||||
{
|
{
|
||||||
m_pushConstBlockMaterial.setNormalTextureSet(primitive->material.texCoordSets.normal);
|
m_pushConstBlockMaterial.setNormalTextureSet(texCoordSet->getNormal());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_pushConstBlockMaterial.setNormalTextureSet(-1);
|
m_pushConstBlockMaterial.setNormalTextureSet(-1);
|
||||||
}
|
}
|
||||||
if (primitive->material.occlusionTexture != nullptr)
|
if (pbrBaseTexture->getOcclusionTexture() != nullptr)
|
||||||
{
|
{
|
||||||
m_pushConstBlockMaterial.setOcclusionTextureSet(primitive->material.texCoordSets.occlusion);
|
m_pushConstBlockMaterial.setOcclusionTextureSet(texCoordSet->getOcclusion());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_pushConstBlockMaterial.setOcclusionTextureSet(-1);
|
m_pushConstBlockMaterial.setOcclusionTextureSet(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (primitive->material.emissiveTexture != nullptr)
|
if (pbrBaseTexture->getEmissiveTexture() != nullptr)
|
||||||
{
|
{
|
||||||
m_pushConstBlockMaterial.setEmissiveTextureSet(primitive->material.texCoordSets.emissive);
|
m_pushConstBlockMaterial.setEmissiveTextureSet(texCoordSet->getEmissive());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_pushConstBlockMaterial.setEmissiveTextureSet(-1);
|
m_pushConstBlockMaterial.setEmissiveTextureSet(-1);
|
||||||
}
|
}
|
||||||
if (primitive->material.alphaMode == glTFModel::Material::ALPHAMODE_MASK)
|
if (primitive->getGltfMaterial().getAlphaMode() == glTFLoader::ALPHAMODE_MASK)
|
||||||
{
|
{
|
||||||
m_pushConstBlockMaterial.setAlphaMask(static_cast<float>(primitive->material.alphaMode));
|
m_pushConstBlockMaterial.setAlphaMask(static_cast<float>(primitive->getGltfMaterial().getAlphaMode()));
|
||||||
}
|
}
|
||||||
m_pushConstBlockMaterial.setAlphaMaskCutoff(primitive->material.alphaCutoff);
|
m_pushConstBlockMaterial.setAlphaMaskCutoff(primitive->getGltfMaterial().getAlphaCutOff());
|
||||||
|
|
||||||
// TODO: glTF specs states that metallic roughness should be preferred, even if specular glosiness is present
|
// TODO: glTF specs states that metallic roughness should be preferred, even if specular glosiness is present
|
||||||
|
|
||||||
if (primitive->material.pbrWorkflows.metallicRoughness)
|
glTFLoader::glTFMaterial *material = &primitive->getGltfMaterial();
|
||||||
|
if (material->getPbrWorkFlow()->getMetallicRoughness())
|
||||||
{
|
{
|
||||||
// Metallic roughness workflow
|
// Metallic roughness workflow
|
||||||
m_pushConstBlockMaterial.setWorkflow(static_cast<float>(PBR_WORKFLOW_METALLIC_ROUGHNESS));
|
m_pushConstBlockMaterial.setWorkflow(static_cast<float>(PBR_WORKFLOW_METALLIC_ROUGHNESS));
|
||||||
m_pushConstBlockMaterial.setBaseColorFactor(primitive->material.baseColorFactor);
|
m_pushConstBlockMaterial.setBaseColorFactor(pbrBaseTexture->getBaseColorFactor());
|
||||||
m_pushConstBlockMaterial.setMetallicFactor(primitive->material.metallicFactor);
|
m_pushConstBlockMaterial.setMetallicFactor(pbrBaseTexture->getMetallicFactor());
|
||||||
m_pushConstBlockMaterial.setRoughnessFactor(primitive->material.roughnessFactor);
|
m_pushConstBlockMaterial.setRoughnessFactor(pbrBaseTexture->getRoughnessFactor());
|
||||||
if (primitive->material.metallicRoughnessTexture != nullptr)
|
if (pbrBaseTexture->getMetalicRoughnessTexture() != nullptr)
|
||||||
{
|
{
|
||||||
m_pushConstBlockMaterial.setPhysicalDescriptorTextureSet(primitive->material.texCoordSets.metallicRoughness);
|
m_pushConstBlockMaterial.setPhysicalDescriptorTextureSet(texCoordSet->getMetallicRoughness());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_pushConstBlockMaterial.setPhysicalDescriptorTextureSet(-1);
|
m_pushConstBlockMaterial.setPhysicalDescriptorTextureSet(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (primitive->material.baseColorTexture != nullptr)
|
if (pbrBaseTexture->getBaseColorTexture() != nullptr)
|
||||||
{
|
{
|
||||||
m_pushConstBlockMaterial.setColorTextureSet(primitive->material.texCoordSets.baseColor);
|
m_pushConstBlockMaterial.setColorTextureSet(texCoordSet->getBaseColor());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -145,47 +155,49 @@ void PlumageRender::renderNode(glTFModel::Node *node, uint32_t cbIndex, glTFMode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (primitive->material.pbrWorkflows.specularGlossiness)
|
if (material->getPbrWorkFlow()->getSpecularGlossiness())
|
||||||
{
|
{
|
||||||
|
|
||||||
// Specular glossiness workflow
|
// Specular glossiness workflow
|
||||||
m_pushConstBlockMaterial.setWorkflow(static_cast<float>(PBR_WORKFLOW_SPECULAR_GLOSINESS));
|
m_pushConstBlockMaterial.setWorkflow(static_cast<float>(PBR_WORKFLOW_SPECULAR_GLOSINESS));
|
||||||
if (primitive->material.extension.specularGlossinessTexture != nullptr)
|
if (material->getTextureExtension()->getSpecularGlossinessTexture() != nullptr)
|
||||||
{
|
{
|
||||||
m_pushConstBlockMaterial.setPhysicalDescriptorTextureSet(primitive->material.texCoordSets.specularGlossiness);
|
m_pushConstBlockMaterial.setPhysicalDescriptorTextureSet(texCoordSet->getSpecularGlossiness());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_pushConstBlockMaterial.setPhysicalDescriptorTextureSet(-1);
|
m_pushConstBlockMaterial.setPhysicalDescriptorTextureSet(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (primitive->material.extension.diffuseTexture != nullptr)
|
if (material->getTextureExtension()->getDiffuseTexture() != nullptr)
|
||||||
{
|
{
|
||||||
m_pushConstBlockMaterial.setColorTextureSet(primitive->material.texCoordSets.baseColor);
|
m_pushConstBlockMaterial.setColorTextureSet(texCoordSet->getBaseColor());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_pushConstBlockMaterial.setColorTextureSet(-1);
|
m_pushConstBlockMaterial.setColorTextureSet(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_pushConstBlockMaterial.setDiffuseFactor(primitive->material.extension.diffuseFactor);
|
m_pushConstBlockMaterial.setDiffuseFactor(material->getTextureExtension()->getDiffuseFactor());
|
||||||
m_pushConstBlockMaterial.setSpecularFactor(glm::vec4(primitive->material.extension.specularFactor, 1.0f));
|
m_pushConstBlockMaterial.setSpecularFactor(glm::vec4(material->getTextureExtension()->getSpecularFactor(), 1.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
vkCmdPushConstants(commandBuffers[cbIndex], pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstBlockMaterial), &m_pushConstBlockMaterial);
|
vkCmdPushConstants(commandBuffers[cbIndex], pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstBlockMaterial), &m_pushConstBlockMaterial);
|
||||||
|
|
||||||
if (primitive->hasIndices)
|
if (primitive->getHasIndices())
|
||||||
{
|
{
|
||||||
vkCmdDrawIndexed(commandBuffers[cbIndex], primitive->indexCount, 1, primitive->firstIndex, 0, 0);
|
vkCmdDrawIndexed(commandBuffers[cbIndex], primitive->getIndexCount(), 1, primitive->getFirstIndex(), 0, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
vkCmdDraw(commandBuffers[cbIndex], primitive->vertexCount, 1, 0, 0);
|
vkCmdDraw(commandBuffers[cbIndex], primitive->getVertexCount(), 1, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
for (auto child : node->children)
|
|
||||||
|
std::vector<glTFLoader::glTFNode *> nodeChildren = node->getChildren();
|
||||||
|
for (auto child : nodeChildren)
|
||||||
{
|
{
|
||||||
renderNode(child, cbIndex, alphaMode);
|
renderNode(child, cbIndex, alphaMode);
|
||||||
}
|
}
|
||||||
|
|
@ -249,12 +261,12 @@ void PlumageRender::buildCommandBuffers()
|
||||||
m_sceneModel.getSkyBox().draw(currentCB);
|
m_sceneModel.getSkyBox().draw(currentCB);
|
||||||
}
|
}
|
||||||
|
|
||||||
glTFModel::Model &model = m_sceneModel.getScene();
|
glTFLoader::glTFMainModel &model = m_sceneModel.getScene();
|
||||||
|
|
||||||
vkCmdBindVertexBuffers(currentCB, 0, 1, &model.vertices.buffer, offsets);
|
vkCmdBindVertexBuffers(currentCB, 0, 1, &model.getModelVertex().buffer, offsets);
|
||||||
if (model.indices.buffer != VK_NULL_HANDLE)
|
if (model.getModelIndex().buffer != VK_NULL_HANDLE)
|
||||||
{
|
{
|
||||||
vkCmdBindIndexBuffer(currentCB, model.indices.buffer, 0, VK_INDEX_TYPE_UINT32);
|
vkCmdBindIndexBuffer(currentCB, model.getModelIndex().buffer, 0, VK_INDEX_TYPE_UINT32);
|
||||||
}
|
}
|
||||||
|
|
||||||
boundPipeline = VK_NULL_HANDLE;
|
boundPipeline = VK_NULL_HANDLE;
|
||||||
|
|
@ -329,7 +341,7 @@ void PlumageRender::loadAssets()
|
||||||
std::cout << msg << std::endl;
|
std::cout << msg << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
readDirectory(assetpath + "environments", "*.ktx", environments, false);
|
ShaderLoader::readDirectory(assetpath + "environments", "*.ktx", environments, false);
|
||||||
|
|
||||||
m_sceneTextures.getEmpty().loadFromFile(PlumageRender::m_configFilePath.getEmptyEnvmapFilePath(), VK_FORMAT_R8G8B8A8_UNORM, vulkanDevice, queue);
|
m_sceneTextures.getEmpty().loadFromFile(PlumageRender::m_configFilePath.getEmptyEnvmapFilePath(), VK_FORMAT_R8G8B8A8_UNORM, vulkanDevice, queue);
|
||||||
|
|
||||||
|
|
@ -459,7 +471,7 @@ void PlumageRender::setupDescriptors()
|
||||||
VkDescriptorSetLayout sceneDescriptorSetLayout = m_descriptorSetLayoutList.getScene();
|
VkDescriptorSetLayout sceneDescriptorSetLayout = m_descriptorSetLayoutList.getScene();
|
||||||
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &sceneDescriptorSetLayout));
|
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &sceneDescriptorSetLayout));
|
||||||
|
|
||||||
vks::TextureCubeMap refIrradianceCube = m_sceneTextures.getIrradianceCube();
|
VulkanBase::TextureCubeMap refIrradianceCube = m_sceneTextures.getIrradianceCube();
|
||||||
for (auto i = 0; i < descriptorSets.size(); i++)
|
for (auto i = 0; i < descriptorSets.size(); i++)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
@ -605,7 +617,7 @@ void PlumageRender::setupDescriptors()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vks::TextureCubeMap refPrefilterCube = m_sceneTextures.getPrefilteredCube();
|
VulkanBase::TextureCubeMap refPrefilterCube = m_sceneTextures.getPrefilteredCube();
|
||||||
// Skybox (fixed set)
|
// Skybox (fixed set)
|
||||||
for (auto i = 0; i < uniformBuffers.size(); i++)
|
for (auto i = 0; i < uniformBuffers.size(); i++)
|
||||||
{
|
{
|
||||||
|
|
@ -752,8 +764,8 @@ void PlumageRender::preparePipelines()
|
||||||
|
|
||||||
// Skybox pipeline (background cube)
|
// Skybox pipeline (background cube)
|
||||||
shaderStages = {
|
shaderStages = {
|
||||||
loadShader(device, m_configFilePath.getSkyboxVertShaderPath(), VK_SHADER_STAGE_VERTEX_BIT),
|
ShaderLoader::loadShader(device, m_configFilePath.getSkyboxVertShaderPath(), VK_SHADER_STAGE_VERTEX_BIT),
|
||||||
loadShader(device, m_configFilePath.getSkyboxFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT)};
|
ShaderLoader::loadShader(device, m_configFilePath.getSkyboxFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT)};
|
||||||
VkPipeline skyboxPipeline = m_pipelineList.getSkybox();
|
VkPipeline skyboxPipeline = m_pipelineList.getSkybox();
|
||||||
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &skyboxPipeline));
|
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &skyboxPipeline));
|
||||||
for (auto shaderStage : shaderStages)
|
for (auto shaderStage : shaderStages)
|
||||||
|
|
@ -763,8 +775,8 @@ void PlumageRender::preparePipelines()
|
||||||
|
|
||||||
// PBR pipeline
|
// PBR pipeline
|
||||||
shaderStages = {
|
shaderStages = {
|
||||||
loadShader(device, m_configFilePath.getPbrVertShaderPath(), VK_SHADER_STAGE_VERTEX_BIT),
|
ShaderLoader::loadShader(device, m_configFilePath.getPbrVertShaderPath(), VK_SHADER_STAGE_VERTEX_BIT),
|
||||||
loadShader(device, m_configFilePath.getPbrFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT)};
|
ShaderLoader::loadShader(device, m_configFilePath.getPbrFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT)};
|
||||||
depthStencilStateCI.depthWriteEnable = VK_TRUE;
|
depthStencilStateCI.depthWriteEnable = VK_TRUE;
|
||||||
depthStencilStateCI.depthTestEnable = VK_TRUE;
|
depthStencilStateCI.depthTestEnable = VK_TRUE;
|
||||||
VkPipeline pbrPipeline = m_pipelineList.getPbr();
|
VkPipeline pbrPipeline = m_pipelineList.getPbr();
|
||||||
|
|
@ -807,7 +819,7 @@ void PlumageRender::generateCubemaps()
|
||||||
for (uint32_t target = 0; target < PREFILTEREDENV + 1; target++)
|
for (uint32_t target = 0; target < PREFILTEREDENV + 1; target++)
|
||||||
{
|
{
|
||||||
|
|
||||||
vks::TextureCubeMap cubemap;
|
VulkanBase::TextureCubeMap cubemap;
|
||||||
|
|
||||||
auto tStart = std::chrono::high_resolution_clock::now();
|
auto tStart = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
|
|
@ -1132,14 +1144,14 @@ void PlumageRender::generateCubemaps()
|
||||||
pipelineCI.pStages = shaderStages.data();
|
pipelineCI.pStages = shaderStages.data();
|
||||||
pipelineCI.renderPass = renderpass;
|
pipelineCI.renderPass = renderpass;
|
||||||
|
|
||||||
shaderStages[0] = loadShader(device, m_configFilePath.getFilterVertShaderPath(), VK_SHADER_STAGE_VERTEX_BIT);
|
shaderStages[0] = ShaderLoader::loadShader(device, m_configFilePath.getFilterVertShaderPath(), VK_SHADER_STAGE_VERTEX_BIT);
|
||||||
switch (target)
|
switch (target)
|
||||||
{
|
{
|
||||||
case IRRADIANCE:
|
case IRRADIANCE:
|
||||||
shaderStages[1] = loadShader(device, m_configFilePath.getIrradianceFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT);
|
shaderStages[1] = ShaderLoader::loadShader(device, m_configFilePath.getIrradianceFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
break;
|
break;
|
||||||
case PREFILTEREDENV:
|
case PREFILTEREDENV:
|
||||||
shaderStages[1] = loadShader(device, m_configFilePath.getPrefilterEnvmapFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT);
|
shaderStages[1] = ShaderLoader::loadShader(device, m_configFilePath.getPrefilterEnvmapFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
VkPipeline pipeline;
|
VkPipeline pipeline;
|
||||||
|
|
@ -1360,7 +1372,7 @@ void PlumageRender::generateBRDFLUT()
|
||||||
|
|
||||||
const VkFormat format = VK_FORMAT_R16G16_SFLOAT;
|
const VkFormat format = VK_FORMAT_R16G16_SFLOAT;
|
||||||
const int32_t dim = 2048;
|
const int32_t dim = 2048;
|
||||||
vks::Texture2D RefLutBrdfTex = m_sceneTextures.getLutBrdf();
|
VulkanBase::Texture2D RefLutBrdfTex = m_sceneTextures.getLutBrdf();
|
||||||
|
|
||||||
// Image
|
// Image
|
||||||
VkImageCreateInfo imageCI{};
|
VkImageCreateInfo imageCI{};
|
||||||
|
|
@ -1553,8 +1565,8 @@ void PlumageRender::generateBRDFLUT()
|
||||||
|
|
||||||
// Look-up-table (from BRDF) pipeline
|
// Look-up-table (from BRDF) pipeline
|
||||||
shaderStages = {
|
shaderStages = {
|
||||||
loadShader(device, m_configFilePath.getBrdfVertShaderPath(), VK_SHADER_STAGE_VERTEX_BIT),
|
ShaderLoader::loadShader(device, m_configFilePath.getBrdfVertShaderPath(), VK_SHADER_STAGE_VERTEX_BIT),
|
||||||
loadShader(device, m_configFilePath.getBrdfFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT)};
|
ShaderLoader::loadShader(device, m_configFilePath.getBrdfFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT)};
|
||||||
VkPipeline pipeline;
|
VkPipeline pipeline;
|
||||||
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipeline));
|
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipeline));
|
||||||
for (auto shaderStage : shaderStages)
|
for (auto shaderStage : shaderStages)
|
||||||
|
|
@ -2264,9 +2276,8 @@ void PlumageRender::updateUIOverlay()
|
||||||
if (!filename.empty())
|
if (!filename.empty())
|
||||||
{
|
{
|
||||||
vkDeviceWaitIdle(device);
|
vkDeviceWaitIdle(device);
|
||||||
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
|
std::string stringFilename = std::filesystem::path(filename).string();
|
||||||
|
|
||||||
std::string stringFilename = converter.to_bytes(filename);
|
|
||||||
loadScene(stringFilename);
|
loadScene(stringFilename);
|
||||||
setupDescriptors();
|
setupDescriptors();
|
||||||
updateCBs = true;
|
updateCBs = true;
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@
|
||||||
#include "RenderOffScreen.h"
|
#include "RenderOffScreen.h"
|
||||||
#include "RenderPipelineList.h"
|
#include "RenderPipelineList.h"
|
||||||
#include "RenderSceneTextures.h"
|
#include "RenderSceneTextures.h"
|
||||||
|
#include "glTFMaterial.h"
|
||||||
|
#include "glTFSkin.h"
|
||||||
#include "renderShaderData.h"
|
#include "renderShaderData.h"
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#include <direct.h>
|
#include <direct.h>
|
||||||
|
|
@ -36,8 +38,7 @@
|
||||||
#include "VulkanExampleBase.h"
|
#include "VulkanExampleBase.h"
|
||||||
#include "glTFModel.h"
|
#include "glTFModel.h"
|
||||||
#include "ui.hpp"
|
#include "ui.hpp"
|
||||||
#include <VulkanTexture.hpp>
|
#include <VulkanTexture.h>
|
||||||
#include <VulkanUtils.hpp>
|
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
#define ENABLE_VALIDATION false
|
#define ENABLE_VALIDATION false
|
||||||
|
|
@ -55,6 +56,7 @@
|
||||||
#include "RenderPipelineList.h"
|
#include "RenderPipelineList.h"
|
||||||
#include "RenderSceneTextures.h"
|
#include "RenderSceneTextures.h"
|
||||||
#include "SceneUBOMatrices.h"
|
#include "SceneUBOMatrices.h"
|
||||||
|
#include "ShaderLoader.h"
|
||||||
#include "SkyboxUBOMatrices.h"
|
#include "SkyboxUBOMatrices.h"
|
||||||
#include "VertexStagingBuffer.h"
|
#include "VertexStagingBuffer.h"
|
||||||
#include "renderEffectState.h"
|
#include "renderEffectState.h"
|
||||||
|
|
@ -184,7 +186,7 @@ public:
|
||||||
delete gui;
|
delete gui;
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderNode(glTFModel::Node *node, uint32_t cbIndex, glTFModel::Material::AlphaMode alphaMode);
|
void renderNode(glTFLoader::glTFNode *node, uint32_t cbIndex, glTFLoader::AlphaMode alphaMode);
|
||||||
void loadScene(std::string filename);
|
void loadScene(std::string filename);
|
||||||
void loadEnvironment(std::string filename);
|
void loadEnvironment(std::string filename);
|
||||||
void buildCommandBuffers();
|
void buildCommandBuffers();
|
||||||
|
|
|
||||||
|
|
@ -9,22 +9,22 @@ RenderSceneModel::~RenderSceneModel()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderSceneModel::setScene(glTFModel::Model value)
|
void RenderSceneModel::setScene(glTFLoader::glTFMainModel value)
|
||||||
{
|
{
|
||||||
m_scene = value;
|
m_scene = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
glTFModel::Model &RenderSceneModel::getScene()
|
glTFLoader::glTFMainModel &RenderSceneModel::getScene()
|
||||||
{
|
{
|
||||||
return m_scene;
|
return m_scene;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderSceneModel::setSkyBox(glTFModel::Model value)
|
void RenderSceneModel::setSkyBox(glTFLoader::glTFMainModel value)
|
||||||
{
|
{
|
||||||
m_skybox = value;
|
m_skybox = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
glTFModel::Model &RenderSceneModel::getSkyBox()
|
glTFLoader::glTFMainModel &RenderSceneModel::getSkyBox()
|
||||||
{
|
{
|
||||||
return m_skybox;
|
return m_skybox;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "glTFModel.h"
|
#include "glTFMainModel.h"
|
||||||
#include "vulkan/vulkan.h"
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
class RenderSceneModel
|
class RenderSceneModel
|
||||||
{
|
{
|
||||||
|
|
@ -9,16 +9,16 @@ public:
|
||||||
RenderSceneModel();
|
RenderSceneModel();
|
||||||
~RenderSceneModel();
|
~RenderSceneModel();
|
||||||
|
|
||||||
void setScene(glTFModel::Model value);
|
void setScene(glTFLoader::glTFMainModel value);
|
||||||
glTFModel::Model &getScene();
|
glTFLoader::glTFMainModel &getScene();
|
||||||
|
|
||||||
void setSkyBox(glTFModel::Model value);
|
void setSkyBox(glTFLoader::glTFMainModel value);
|
||||||
glTFModel::Model &getSkyBox();
|
glTFLoader::glTFMainModel &getSkyBox();
|
||||||
|
|
||||||
void destroyScene(VkDevice device);
|
void destroyScene(VkDevice device);
|
||||||
void destroySkyBox(VkDevice device);
|
void destroySkyBox(VkDevice device);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
glTFModel::Model m_scene;
|
glTFLoader::glTFMainModel m_scene;
|
||||||
glTFModel::Model m_skybox;
|
glTFLoader::glTFMainModel m_skybox;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -9,33 +9,33 @@ RenderUniformBufferSet::~RenderUniformBufferSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getter method definitions
|
// Getter method definitions
|
||||||
Buffer &RenderUniformBufferSet::getScene()
|
VulkanBase::Buffer &RenderUniformBufferSet::getScene()
|
||||||
{
|
{
|
||||||
return scene;
|
return scene;
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer &RenderUniformBufferSet::getSkybox()
|
VulkanBase::Buffer &RenderUniformBufferSet::getSkybox()
|
||||||
{
|
{
|
||||||
return skybox;
|
return skybox;
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer &RenderUniformBufferSet::getParams()
|
VulkanBase::Buffer &RenderUniformBufferSet::getParams()
|
||||||
{
|
{
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setter method definitions
|
// Setter method definitions
|
||||||
void RenderUniformBufferSet::setScene(Buffer &buffer)
|
void RenderUniformBufferSet::setScene(VulkanBase::Buffer &buffer)
|
||||||
{
|
{
|
||||||
scene = buffer;
|
scene = buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderUniformBufferSet::setSkybox(Buffer &buffer)
|
void RenderUniformBufferSet::setSkybox(VulkanBase::Buffer &buffer)
|
||||||
{
|
{
|
||||||
skybox = buffer;
|
skybox = buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderUniformBufferSet::setParams(Buffer &buffer)
|
void RenderUniformBufferSet::setParams(VulkanBase::Buffer &buffer)
|
||||||
{
|
{
|
||||||
params = buffer;
|
params = buffer;
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#ifndef RENDER_UNIFORM_BUFFER_SET_H
|
||||||
|
#define RENDER_UNIFORM_BUFFER_SET_H
|
||||||
|
|
||||||
#include "VulkanUtils.hpp"
|
#include "VulkanBuffer.h"
|
||||||
|
|
||||||
class RenderUniformBufferSet
|
class RenderUniformBufferSet
|
||||||
{
|
{
|
||||||
|
|
@ -9,17 +10,19 @@ public:
|
||||||
~RenderUniformBufferSet();
|
~RenderUniformBufferSet();
|
||||||
|
|
||||||
// Getter methods
|
// Getter methods
|
||||||
Buffer &getScene();
|
VulkanBase::Buffer &getScene();
|
||||||
Buffer &getSkybox();
|
VulkanBase::Buffer &getSkybox();
|
||||||
Buffer &getParams();
|
VulkanBase::Buffer &getParams();
|
||||||
|
|
||||||
// Setter methods
|
// Setter methods
|
||||||
void setScene(Buffer &buffer);
|
void setScene(VulkanBase::Buffer &buffer);
|
||||||
void setSkybox(Buffer &buffer);
|
void setSkybox(VulkanBase::Buffer &buffer);
|
||||||
void setParams(Buffer &buffer);
|
void setParams(VulkanBase::Buffer &buffer);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Buffer scene;
|
VulkanBase::Buffer scene;
|
||||||
Buffer skybox;
|
VulkanBase::Buffer skybox;
|
||||||
Buffer params;
|
VulkanBase::Buffer params;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,404 @@
|
||||||
|
|
||||||
|
|
||||||
|
#include <io.h>
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
#include <android/asset_manager.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
|
#include <backends/imgui_impl_glfw.h>
|
||||||
|
#include <backends/imgui_impl_vulkan.h>
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
#define GLM_FORCE_RADIANS
|
||||||
|
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "ShaderLoader.h"
|
||||||
|
#include "VulkanBuffer.h"
|
||||||
|
#include "VulkanDevice.h"
|
||||||
|
#include "VulkanTexture.h"
|
||||||
|
#include "VulkanTools.h"
|
||||||
|
|
||||||
|
struct UI
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
VkDevice device;
|
||||||
|
|
||||||
|
std::string getAssetPath() const
|
||||||
|
{
|
||||||
|
if (_access("./../data/", 0) != -1)
|
||||||
|
{
|
||||||
|
|
||||||
|
return "./../data/";
|
||||||
|
}
|
||||||
|
else if (_access("./data/", 0) != -1)
|
||||||
|
{
|
||||||
|
|
||||||
|
return "./data/";
|
||||||
|
}
|
||||||
|
else if (_access("./../../data/", 0) != -1)
|
||||||
|
{
|
||||||
|
|
||||||
|
return "../../data/";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
return VK_EXAMPLE_DATA_DIR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
VulkanBase::Buffer vertexBuffer, indexBuffer;
|
||||||
|
VulkanBase::Texture2D fontTexture;
|
||||||
|
VkPipelineLayout pipelineLayout;
|
||||||
|
VkPipeline pipeline;
|
||||||
|
VkDescriptorPool descriptorPool;
|
||||||
|
VkDescriptorSetLayout descriptorSetLayout;
|
||||||
|
VkDescriptorSet descriptorSet;
|
||||||
|
|
||||||
|
struct PushConstBlock
|
||||||
|
{
|
||||||
|
glm::vec2 scale;
|
||||||
|
glm::vec2 translate;
|
||||||
|
} pushConstBlock;
|
||||||
|
|
||||||
|
UI(VulkanBase::VulkanDevice *vulkanDevice, VkRenderPass renderPass, VkQueue queue, VkPipelineCache pipelineCache, VkSampleCountFlagBits multiSampleCount)
|
||||||
|
{
|
||||||
|
|
||||||
|
this->device = vulkanDevice->getLogicalDevice();
|
||||||
|
|
||||||
|
ImGui::CreateContext();
|
||||||
|
|
||||||
|
/*
|
||||||
|
Font texture loading
|
||||||
|
*/
|
||||||
|
ImGuiIO &io = ImGui::GetIO();
|
||||||
|
|
||||||
|
/// enable keyborad and gamepad input
|
||||||
|
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
|
||||||
|
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
|
||||||
|
|
||||||
|
unsigned char *fontData;
|
||||||
|
int texWidth, texHeight;
|
||||||
|
std::string ttfFilePath = getAssetPath() + "/STXINWEI.TTF";
|
||||||
|
io.Fonts->AddFontFromFileTTF(ttfFilePath.data(), 16.0f, NULL, io.Fonts->GetGlyphRangesChineseSimplifiedCommon());
|
||||||
|
io.Fonts->GetTexDataAsRGBA32(&fontData, &texWidth, &texHeight);
|
||||||
|
fontTexture.loadFromBuffer(fontData, texWidth * texHeight * 4 * sizeof(char), VK_FORMAT_R8G8B8A8_UNORM, texWidth, texHeight, vulkanDevice, queue);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Setup
|
||||||
|
*/
|
||||||
|
ImGuiStyle &style = ImGui::GetStyle();
|
||||||
|
style.FrameBorderSize = 0.0f;
|
||||||
|
style.WindowBorderSize = 0.0f;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Descriptor pool
|
||||||
|
*/
|
||||||
|
std::vector<VkDescriptorPoolSize> poolSizes = {
|
||||||
|
{VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1}};
|
||||||
|
VkDescriptorPoolCreateInfo descriptorPoolCI{};
|
||||||
|
descriptorPoolCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||||
|
descriptorPoolCI.poolSizeCount = 1;
|
||||||
|
descriptorPoolCI.pPoolSizes = poolSizes.data();
|
||||||
|
descriptorPoolCI.maxSets = 1;
|
||||||
|
VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolCI, nullptr, &descriptorPool));
|
||||||
|
|
||||||
|
/*
|
||||||
|
Descriptor set layout
|
||||||
|
*/
|
||||||
|
VkDescriptorSetLayoutBinding setLayoutBinding{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr};
|
||||||
|
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI{};
|
||||||
|
descriptorSetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||||
|
descriptorSetLayoutCI.pBindings = &setLayoutBinding;
|
||||||
|
descriptorSetLayoutCI.bindingCount = 1;
|
||||||
|
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorSetLayout));
|
||||||
|
|
||||||
|
/*
|
||||||
|
Descriptor set
|
||||||
|
*/
|
||||||
|
VkDescriptorSetAllocateInfo descriptorSetAllocInfo{};
|
||||||
|
descriptorSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||||
|
descriptorSetAllocInfo.descriptorPool = descriptorPool;
|
||||||
|
descriptorSetAllocInfo.pSetLayouts = &descriptorSetLayout;
|
||||||
|
descriptorSetAllocInfo.descriptorSetCount = 1;
|
||||||
|
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocInfo, &descriptorSet));
|
||||||
|
VkWriteDescriptorSet writeDescriptorSet{};
|
||||||
|
writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
|
writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
|
writeDescriptorSet.descriptorCount = 1;
|
||||||
|
writeDescriptorSet.dstSet = descriptorSet;
|
||||||
|
writeDescriptorSet.dstBinding = 0;
|
||||||
|
writeDescriptorSet.pImageInfo = &fontTexture.descriptor;
|
||||||
|
vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Pipeline layout
|
||||||
|
*/
|
||||||
|
VkPushConstantRange pushConstantRange{VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(PushConstBlock)};
|
||||||
|
|
||||||
|
VkPipelineLayoutCreateInfo pipelineLayoutCI{};
|
||||||
|
pipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||||
|
pipelineLayoutCI.pushConstantRangeCount = 1;
|
||||||
|
pipelineLayoutCI.pPushConstantRanges = &pushConstantRange;
|
||||||
|
pipelineLayoutCI.setLayoutCount = 1;
|
||||||
|
pipelineLayoutCI.pSetLayouts = &descriptorSetLayout;
|
||||||
|
pipelineLayoutCI.pushConstantRangeCount = 1;
|
||||||
|
pipelineLayoutCI.pPushConstantRanges = &pushConstantRange;
|
||||||
|
VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelineLayout));
|
||||||
|
|
||||||
|
/*
|
||||||
|
Pipeline
|
||||||
|
*/
|
||||||
|
VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI{};
|
||||||
|
inputAssemblyStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||||||
|
inputAssemblyStateCI.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||||
|
|
||||||
|
VkPipelineRasterizationStateCreateInfo rasterizationStateCI{};
|
||||||
|
rasterizationStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||||
|
rasterizationStateCI.polygonMode = VK_POLYGON_MODE_FILL;
|
||||||
|
rasterizationStateCI.cullMode = VK_CULL_MODE_NONE;
|
||||||
|
rasterizationStateCI.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
|
||||||
|
rasterizationStateCI.lineWidth = 1.0f;
|
||||||
|
|
||||||
|
VkPipelineColorBlendAttachmentState blendAttachmentState{};
|
||||||
|
blendAttachmentState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
||||||
|
blendAttachmentState.blendEnable = VK_TRUE;
|
||||||
|
blendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
||||||
|
blendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||||
|
blendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD;
|
||||||
|
blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||||
|
blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||||
|
blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD;
|
||||||
|
|
||||||
|
VkPipelineColorBlendStateCreateInfo colorBlendStateCI{};
|
||||||
|
colorBlendStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
||||||
|
colorBlendStateCI.attachmentCount = 1;
|
||||||
|
colorBlendStateCI.pAttachments = &blendAttachmentState;
|
||||||
|
|
||||||
|
VkPipelineDepthStencilStateCreateInfo depthStencilStateCI{};
|
||||||
|
depthStencilStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
|
||||||
|
depthStencilStateCI.depthTestEnable = VK_FALSE;
|
||||||
|
depthStencilStateCI.depthWriteEnable = VK_FALSE;
|
||||||
|
depthStencilStateCI.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
|
||||||
|
depthStencilStateCI.front = depthStencilStateCI.back;
|
||||||
|
depthStencilStateCI.back.compareOp = VK_COMPARE_OP_ALWAYS;
|
||||||
|
|
||||||
|
VkPipelineViewportStateCreateInfo viewportStateCI{};
|
||||||
|
viewportStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
||||||
|
viewportStateCI.viewportCount = 1;
|
||||||
|
viewportStateCI.scissorCount = 1;
|
||||||
|
|
||||||
|
VkPipelineMultisampleStateCreateInfo multisampleStateCI{};
|
||||||
|
multisampleStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
||||||
|
|
||||||
|
if (multiSampleCount > VK_SAMPLE_COUNT_1_BIT)
|
||||||
|
{
|
||||||
|
multisampleStateCI.rasterizationSamples = multiSampleCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<VkDynamicState> dynamicStateEnables = {
|
||||||
|
VK_DYNAMIC_STATE_VIEWPORT,
|
||||||
|
VK_DYNAMIC_STATE_SCISSOR};
|
||||||
|
VkPipelineDynamicStateCreateInfo dynamicStateCI{};
|
||||||
|
dynamicStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
||||||
|
dynamicStateCI.pDynamicStates = dynamicStateEnables.data();
|
||||||
|
dynamicStateCI.dynamicStateCount = static_cast<uint32_t>(dynamicStateEnables.size());
|
||||||
|
|
||||||
|
VkVertexInputBindingDescription vertexInputBinding = {0, 20, VK_VERTEX_INPUT_RATE_VERTEX};
|
||||||
|
std::vector<VkVertexInputAttributeDescription> vertexInputAttributes = {
|
||||||
|
{0, 0, VK_FORMAT_R32G32_SFLOAT, 0},
|
||||||
|
{1, 0, VK_FORMAT_R32G32_SFLOAT, sizeof(float) * 2},
|
||||||
|
{2, 0, VK_FORMAT_R8G8B8A8_UNORM, sizeof(float) * 4},
|
||||||
|
};
|
||||||
|
VkPipelineVertexInputStateCreateInfo vertexInputStateCI{};
|
||||||
|
vertexInputStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||||
|
vertexInputStateCI.vertexBindingDescriptionCount = 1;
|
||||||
|
vertexInputStateCI.pVertexBindingDescriptions = &vertexInputBinding;
|
||||||
|
vertexInputStateCI.vertexAttributeDescriptionCount = static_cast<uint32_t>(vertexInputAttributes.size());
|
||||||
|
vertexInputStateCI.pVertexAttributeDescriptions = vertexInputAttributes.data();
|
||||||
|
|
||||||
|
std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages;
|
||||||
|
|
||||||
|
VkGraphicsPipelineCreateInfo pipelineCI{};
|
||||||
|
pipelineCI.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||||||
|
pipelineCI.layout = pipelineLayout;
|
||||||
|
pipelineCI.renderPass = renderPass;
|
||||||
|
pipelineCI.pInputAssemblyState = &inputAssemblyStateCI;
|
||||||
|
pipelineCI.pVertexInputState = &vertexInputStateCI;
|
||||||
|
pipelineCI.pRasterizationState = &rasterizationStateCI;
|
||||||
|
pipelineCI.pColorBlendState = &colorBlendStateCI;
|
||||||
|
pipelineCI.pMultisampleState = &multisampleStateCI;
|
||||||
|
pipelineCI.pViewportState = &viewportStateCI;
|
||||||
|
pipelineCI.pDepthStencilState = &depthStencilStateCI;
|
||||||
|
pipelineCI.pDynamicState = &dynamicStateCI;
|
||||||
|
pipelineCI.stageCount = static_cast<uint32_t>(shaderStages.size());
|
||||||
|
pipelineCI.pStages = shaderStages.data();
|
||||||
|
|
||||||
|
pipelineCI.layout = pipelineLayout;
|
||||||
|
std::string uiVertShaderPath = getAssetPath() + "shaders/ui.vert.spv";
|
||||||
|
std::string uiFragShaderPath = getAssetPath() + "shaders/ui.frag.spv";
|
||||||
|
shaderStages = {
|
||||||
|
|
||||||
|
ShaderLoader::loadShader(device, uiVertShaderPath.data(), VK_SHADER_STAGE_VERTEX_BIT),
|
||||||
|
ShaderLoader::loadShader(device, uiFragShaderPath.data(), VK_SHADER_STAGE_FRAGMENT_BIT)};
|
||||||
|
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipeline));
|
||||||
|
|
||||||
|
for (auto shaderStage : shaderStages)
|
||||||
|
{
|
||||||
|
vkDestroyShaderModule(device, shaderStage.module, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~UI()
|
||||||
|
{
|
||||||
|
ImGui::DestroyContext();
|
||||||
|
vertexBuffer.destroy();
|
||||||
|
indexBuffer.destroy();
|
||||||
|
vkDestroyPipeline(device, pipeline, nullptr);
|
||||||
|
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
|
||||||
|
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
|
||||||
|
vkDestroyDescriptorPool(device, descriptorPool, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw(VkCommandBuffer cmdBuffer)
|
||||||
|
{
|
||||||
|
vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
||||||
|
vkCmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr);
|
||||||
|
|
||||||
|
const VkDeviceSize offsets[1] = {0};
|
||||||
|
vkCmdBindVertexBuffers(cmdBuffer, 0, 1, &vertexBuffer.buffer, offsets);
|
||||||
|
vkCmdBindIndexBuffer(cmdBuffer, indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT16);
|
||||||
|
|
||||||
|
vkCmdPushConstants(cmdBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(UI::PushConstBlock), &pushConstBlock);
|
||||||
|
|
||||||
|
ImDrawData *imDrawData = ImGui::GetDrawData();
|
||||||
|
int32_t vertexOffset = 0;
|
||||||
|
int32_t indexOffset = 0;
|
||||||
|
for (int32_t j = 0; j < imDrawData->CmdListsCount; j++)
|
||||||
|
{
|
||||||
|
const ImDrawList *cmd_list = imDrawData->CmdLists[j];
|
||||||
|
for (int32_t k = 0; k < cmd_list->CmdBuffer.Size; k++)
|
||||||
|
{
|
||||||
|
const ImDrawCmd *pcmd = &cmd_list->CmdBuffer[k];
|
||||||
|
VkRect2D scissorRect;
|
||||||
|
scissorRect.offset.x = std::max((int32_t)(pcmd->ClipRect.x), 0);
|
||||||
|
scissorRect.offset.y = std::max((int32_t)(pcmd->ClipRect.y), 0);
|
||||||
|
scissorRect.extent.width = (uint32_t)(pcmd->ClipRect.z - pcmd->ClipRect.x);
|
||||||
|
scissorRect.extent.height = (uint32_t)(pcmd->ClipRect.w - pcmd->ClipRect.y);
|
||||||
|
vkCmdSetScissor(cmdBuffer, 0, 1, &scissorRect);
|
||||||
|
vkCmdDrawIndexed(cmdBuffer, pcmd->ElemCount, 1, indexOffset, vertexOffset, 0);
|
||||||
|
indexOffset += pcmd->ElemCount;
|
||||||
|
}
|
||||||
|
vertexOffset += cmd_list->VtxBuffer.Size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool checkbox(const char *caption, T *value)
|
||||||
|
{
|
||||||
|
bool val = (*value == 1);
|
||||||
|
bool res = ImGui::Checkbox(caption, &val);
|
||||||
|
*value = val;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
bool header(const char *caption)
|
||||||
|
{
|
||||||
|
return ImGui::CollapsingHeader(caption, ImGuiTreeNodeFlags_DefaultOpen);
|
||||||
|
}
|
||||||
|
bool slider(const char *caption, float *value, float min, float max)
|
||||||
|
{
|
||||||
|
return ImGui::SliderFloat(caption, value, min, max);
|
||||||
|
}
|
||||||
|
bool combo(const char *caption, int32_t *itemindex, std::vector<std::string> items)
|
||||||
|
{
|
||||||
|
if (items.empty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::vector<const char *> charitems;
|
||||||
|
charitems.reserve(items.size());
|
||||||
|
for (size_t i = 0; i < items.size(); i++)
|
||||||
|
{
|
||||||
|
charitems.push_back(items[i].c_str());
|
||||||
|
}
|
||||||
|
uint32_t itemCount = static_cast<uint32_t>(charitems.size());
|
||||||
|
return ImGui::Combo(caption, itemindex, &charitems[0], itemCount, itemCount);
|
||||||
|
}
|
||||||
|
bool combo(const char *caption, std::string &selectedkey, std::map<std::string, std::string> items)
|
||||||
|
{
|
||||||
|
bool selectionChanged = false;
|
||||||
|
if (ImGui::BeginCombo(caption, selectedkey.c_str()))
|
||||||
|
{
|
||||||
|
for (auto it = items.begin(); it != items.end(); ++it)
|
||||||
|
{
|
||||||
|
const bool isSelected = it->first == selectedkey;
|
||||||
|
if (ImGui::Selectable(it->first.c_str(), isSelected))
|
||||||
|
{
|
||||||
|
selectionChanged = it->first != selectedkey;
|
||||||
|
selectedkey = it->first;
|
||||||
|
}
|
||||||
|
if (isSelected)
|
||||||
|
{
|
||||||
|
ImGui::SetItemDefaultFocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndCombo();
|
||||||
|
}
|
||||||
|
return selectionChanged;
|
||||||
|
}
|
||||||
|
bool button(const char *caption)
|
||||||
|
{
|
||||||
|
return ImGui::Button(caption);
|
||||||
|
}
|
||||||
|
bool beginChild(const char *caption, ImVec2 size, bool border)
|
||||||
|
{
|
||||||
|
return ImGui::BeginChild(caption, size, border);
|
||||||
|
}
|
||||||
|
|
||||||
|
void endChild()
|
||||||
|
{
|
||||||
|
return ImGui::EndChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
// menu GUI
|
||||||
|
bool beginMainMenuBar()
|
||||||
|
{
|
||||||
|
return ImGui::BeginMainMenuBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool beginMenu(const char *caption)
|
||||||
|
{
|
||||||
|
return ImGui::BeginMenu(caption);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool menuItem(const char *caption)
|
||||||
|
{
|
||||||
|
return ImGui::MenuItem(caption);
|
||||||
|
}
|
||||||
|
void endMenu()
|
||||||
|
{
|
||||||
|
return ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
void endMainMenuBar()
|
||||||
|
{
|
||||||
|
return ImGui::EndMainMenuBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
void text(const char *formatstr, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, formatstr);
|
||||||
|
ImGui::TextV(formatstr, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue