调整结构

reconstruct-gltfLoader
InkSoul 2026-01-01 00:12:08 +08:00
parent 98335c7edc
commit 907b94dcdd
51 changed files with 6281 additions and 6103 deletions

View File

@ -3,6 +3,7 @@ AccessModifierOffset: -4
AlignConsecutiveMacros: true
AlignTrailingComments: true
AllowShortFunctionsOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: false
AllowShortIfStatementsOnASingleLine: true
AllowAllParametersOfDeclarationOnNextLine: true
BreakBeforeBraces: Allman
ColumnLimit: 0

16
.vscode/launch.json vendored 100644
View File

@ -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}"
}
]
}

756
VulkanTexture.hpp 100644
View File

@ -0,0 +1,756 @@
/*
* vulkan
* 使stbi
* ktxcubeMap使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

View File

@ -15,8 +15,6 @@ set(GLTF_MODEL_LOADER
"gltf/glTFBoundingBox.cpp"
"gltf/glTFTexture.h"
"gltf/glTFTexture.cpp"
#"gltf/glTFModel.h"
#"gltf/glTFModel.cpp"
"gltf/glTFMaterial.h"
"gltf/glTFMaterial.cpp"
"gltf/glTFPrimitive.h"
@ -35,12 +33,12 @@ set(GLTF_MODEL_LOADER
"gltf/glTFAnimation.cpp"
"gltf/glTFMainModel.h"
"gltf/glTFMainModel.cpp"
)
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_glm_path})
@ -65,6 +63,7 @@ if(WIN32)
${MAIN_FILE}
${GLTF_MODEL_LOADER}
${VULKAN_BASE}
${PBR}
"render/renderFoundation.h"
"render/renderFoundation.cpp"

View File

@ -4,12 +4,10 @@ file(GLOB BASE_SRC "*.cpp" "*.h" "${3rdParty_imgui_path}/*.cpp" )
include_directories(${3rdParty_ktx_path})
include_directories(${3rdParty_ktx_otherInclude_path})
include_directories(${3rdParty_glm_path})
include_directories(${3rdParty_gli_path})
include_directories(${3rdParty_stb_path})
include_directories(${3rdParty_vulkan_path})
include_directories(${3rdParty_imgui_path})
message("======================debug=====================")
message(${BASE_SRC})
add_library(base STATIC ${BASE_SRC} ${KTX_SOURCES})
if(WIN32)

View File

@ -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 "VulkanTools.h"
namespace vks
VULKANBASE_NAMESPACE_BEGIN
/**
* 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 offset (Optional) Byte offset from beginning
*
* @return VkResult of the buffer mapping call
*/
VkResult Buffer::map(VkDeviceSize size, VkDeviceSize offset)
{
/**
* 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 offset (Optional) Byte offset from beginning
*
* @return VkResult of the buffer mapping call
*/
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
*
* @note Does not return a result as vkUnmapMemory can't fail
*/
void Buffer::unmap()
{
if (mapped)
{
vkUnmapMemory(device, memory);
mapped = nullptr;
}
}
/**
* Unmap a mapped memory range
*
* @note Does not return a result as vkUnmapMemory can't fail
*/
void Buffer::unmap()
{
if (mapped)
{
vkUnmapMemory(device, memory);
mapped = nullptr;
}
}
/**
* Attach the allocated memory block to the buffer
*
* @param offset (Optional) Byte offset (from the beginning) for the memory region to bind
*
* @return VkResult of the bindBufferMemory call
*/
VkResult Buffer::bind(VkDeviceSize offset)
{
return vkBindBufferMemory(device, buffer, memory, offset);
}
/**
* Attach the allocated memory block to the buffer
*
* @param offset (Optional) Byte offset (from the beginning) for the memory region to bind
*
* @return VkResult of the bindBufferMemory call
*/
VkResult Buffer::bind(VkDeviceSize offset)
{
return vkBindBufferMemory(device, buffer, memory, offset);
}
/**
* Setup the default descriptor for this buffer
*
* @param size (Optional) Size of the memory range of the descriptor
* @param offset (Optional) Byte offset from beginning
*
*/
void Buffer::setupDescriptor(VkDeviceSize size, VkDeviceSize offset)
{
descriptor.offset = offset;
descriptor.buffer = buffer;
descriptor.range = size;
}
/**
* Setup the default descriptor for this buffer
*
* @param size (Optional) Size of the memory range of the descriptor
* @param offset (Optional) Byte offset from beginning
*
*/
void Buffer::setupDescriptor(VkDeviceSize size, VkDeviceSize offset)
{
descriptor.offset = offset;
descriptor.buffer = buffer;
descriptor.range = size;
}
/**
* Copies the specified data to the mapped buffer
*
* @param data Pointer to the data to copy
* @param size Size of the data to copy in machine units
*
*/
void Buffer::copyTo(void* data, VkDeviceSize size)
{
assert(mapped);
memcpy(mapped, data, size);
}
/**
* Copies the specified data to the mapped buffer
*
* @param data Pointer to the data to copy
* @param size Size of the data to copy in machine units
*
*/
void Buffer::copyTo(void *data, VkDeviceSize size)
{
assert(mapped);
memcpy(mapped, data, size);
}
/**
* Flush a memory range of the buffer to make it visible to the device
*
* @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 offset (Optional) Byte offset from beginning
*
* @return VkResult of the flush call
*/
VkResult Buffer::flush(VkDeviceSize size, VkDeviceSize offset)
{
VkMappedMemoryRange mappedRange = {};
mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
mappedRange.memory = memory;
mappedRange.offset = offset;
mappedRange.size = size;
return vkFlushMappedMemoryRanges(device, 1, &mappedRange);
}
/**
* Flush a memory range of the buffer to make it visible to the device
*
* @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 offset (Optional) Byte offset from beginning
*
* @return VkResult of the flush call
*/
VkResult Buffer::flush(VkDeviceSize size, VkDeviceSize offset)
{
VkMappedMemoryRange mappedRange = {};
mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
mappedRange.memory = memory;
mappedRange.offset = offset;
mappedRange.size = size;
return vkFlushMappedMemoryRanges(device, 1, &mappedRange);
}
/**
* Invalidate a memory range of the buffer to make it visible to the host
*
* @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 offset (Optional) Byte offset from beginning
*
* @return VkResult of the invalidate call
*/
VkResult Buffer::invalidate(VkDeviceSize size, VkDeviceSize offset)
{
VkMappedMemoryRange mappedRange = {};
mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
mappedRange.memory = memory;
mappedRange.offset = offset;
mappedRange.size = size;
return vkInvalidateMappedMemoryRanges(device, 1, &mappedRange);
}
/**
* Invalidate a memory range of the buffer to make it visible to the host
*
* @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 offset (Optional) Byte offset from beginning
*
* @return VkResult of the invalidate call
*/
VkResult Buffer::invalidate(VkDeviceSize size, VkDeviceSize offset)
{
VkMappedMemoryRange mappedRange = {};
mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
mappedRange.memory = memory;
mappedRange.offset = offset;
mappedRange.size = size;
return vkInvalidateMappedMemoryRanges(device, 1, &mappedRange);
}
/**
* Release all Vulkan resources held by this buffer
*/
void Buffer::destroy()
{
if (buffer)
{
vkDestroyBuffer(device, buffer, nullptr);
}
if (memory)
{
vkFreeMemory(device, memory, nullptr);
}
}
};
/**
* Release all Vulkan resources held by this buffer
*/
void Buffer::destroy()
{
if (mapped)
{
unmap();
}
vkDestroyBuffer(device, buffer, 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

View File

@ -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 "vulkan/vulkan.h"
#include "VulkanTools.h"
#include "VulkanBase_Marco.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
* @note To be filled by an external source like the VulkanDevice
*/
struct Buffer
{
/**
* @brief Encapsulates access to a Vulkan buffer backed up by device memory
* @note To be filled by an external source like the VulkanDevice
*/
struct Buffer
{
VkDevice device;
VkBuffer buffer = VK_NULL_HANDLE;
VkDeviceMemory memory = VK_NULL_HANDLE;
VkDescriptorBufferInfo descriptor;
VkDeviceSize size = 0;
VkDeviceSize alignment = 0;
void* mapped = nullptr;
/** @brief Usage flags to be filled by external source at buffer creation (to query at some later point) */
VkBufferUsageFlags usageFlags;
/** @brief Memory property flags to be filled by external source at buffer creation (to query at some later point) */
VkMemoryPropertyFlags memoryPropertyFlags;
VkResult map(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0);
void unmap();
VkResult bind(VkDeviceSize offset = 0);
void setupDescriptor(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0);
void copyTo(void* data, VkDeviceSize size);
VkResult flush(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0);
VkResult invalidate(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0);
void destroy();
};
}
VkDevice device;
VkBuffer buffer = VK_NULL_HANDLE;
VkDeviceMemory memory = VK_NULL_HANDLE;
VkDescriptorBufferInfo descriptor;
VkDeviceSize size = 0;
VkDeviceSize alignment = 0;
int32_t count = 0;
void *mapped = nullptr;
/** @brief Usage flags to be filled by external source at buffer creation (to query at some later point) */
VkBufferUsageFlags usageFlags;
/** @brief Memory property flags to be filled by external source at buffer creation (to query at some later point) */
VkMemoryPropertyFlags memoryPropertyFlags;
void create(VulkanDevice *device, VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkDeviceSize size, bool map = true);
VkResult map(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0);
void unmap();
VkResult bind(VkDeviceSize offset = 0);
void setupDescriptor(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0);
void copyTo(void *data, VkDeviceSize size);
VkResult flush(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0);
VkResult invalidate(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0);
void destroy();
};
VULKANBASE_NAMESPACE_END
#endif

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,97 +1,90 @@
/*
* Vulkan texture loader
*
* Copyright(C) by Sascha Willems - www.saschawillems.de
*
* This code is licensed under the MIT license(MIT) (http://opensource.org/licenses/MIT)
*/
#ifndef VULKANTEXTURE_H
#define VULKANTEXTURE_H
#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 <stdlib.h>
#include <string>
#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
{
public:
vks::VulkanDevice * device;
VkImage image;
VkImageLayout imageLayout;
VkDeviceMemory deviceMemory;
VkImageView view;
uint32_t width, height;
uint32_t mipLevels;
uint32_t layerCount;
VkDescriptorImageInfo descriptor;
VkSampler sampler;
public:
VulkanBase::VulkanDevice *device;
VkImage image;
VkImageLayout imageLayout;
VkDeviceMemory deviceMemory;
VkImageView view;
uint32_t width, height;
uint32_t mipLevels;
uint32_t layerCount;
VkDescriptorImageInfo descriptor;
VkSampler sampler;
void updateDescriptor();
void destroy();
ktxResult loadKTXFile(std::string filename, ktxTexture **target);
void updateDescriptor();
void destroy();
ktxResult loadKTXFile(std::string filename, ktxTexture **target);
};
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,
bool forceLinear = false);
void fromBuffer(
void * buffer,
VkDeviceSize bufferSize,
VkFormat format,
uint32_t texWidth,
uint32_t texHeight,
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);
public:
void loadFromFile(
std::string filename,
VkFormat format,
VulkanBase::VulkanDevice *device,
VkQueue copyQueue,
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
bool forceLinear = false);
void loadFromBuffer(
void *buffer,
VkDeviceSize bufferSize,
VkFormat format,
uint32_t texWidth,
uint32_t texHeight,
VulkanBase::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);
};
class Texture2DArray : 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);
public:
void loadFromFile(
std::string filename,
VkFormat format,
VulkanBase::VulkanDevice *device,
VkQueue copyQueue,
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
};
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);
public:
void loadFromFile(
std::string filename,
VkFormat format,
VulkanBase::VulkanDevice *device,
VkQueue copyQueue,
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
};
} // namespace vks
VULKANBASE_NAMESPACE_END
#endif

View File

@ -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();
}
};
}

View File

@ -1,25 +1,27 @@

#pragma once
#include "vulkan/vulkan.h"
#include "VulkanInitializers.hpp"
#include "vulkan/vulkan.h"
#include <math.h>
#include <stdlib.h>
#include <string>
#include <algorithm>
#include <assert.h>
#include <cstring>
#include <fstream>
#include <assert.h>
#include <stdio.h>
#include <vector>
#include <iostream>
#include <math.h>
#include <stdexcept>
#include <fstream>
#include <algorithm>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>
#if defined(_WIN32)
#include <windows.h>
#include <fcntl.h>
#include <io.h>
#include <windows.h>
#elif defined(__ANDROID__)
#include "VulkanAndroid.h"
#include <android/asset_manager.h>
@ -32,114 +34,114 @@
// Macro to check and display Vulkan return results
#if defined(__ANDROID__)
#define VK_CHECK_RESULT(f) \
{ \
VkResult res = (f); \
if (res != VK_SUCCESS) \
{ \
LOGE("Fatal : VkResult is \" %s \" in %s at line %d", vks::tools::errorString(res).c_str(), __FILE__, __LINE__); \
assert(res == VK_SUCCESS); \
} \
}
#define VK_CHECK_RESULT(f) \
{ \
VkResult res = (f); \
if (res != VK_SUCCESS) \
{ \
LOGE("Fatal : VkResult is \" %s \" in %s at line %d", vks::tools::errorString(res).c_str(), __FILE__, __LINE__); \
assert(res == VK_SUCCESS); \
} \
}
#else
#define VK_CHECK_RESULT(f) \
{ \
VkResult res = (f); \
if (res != VK_SUCCESS) \
{ \
std::cout << "Fatal : VkResult is \"" << vks::tools::errorString(res) << "\" in " << __FILE__ << " at line " << __LINE__ << "\n"; \
assert(res == VK_SUCCESS); \
} \
}
#define VK_CHECK_RESULT(f) \
{ \
VkResult res = (f); \
if (res != VK_SUCCESS) \
{ \
std::cout << "Fatal : VkResult is \"" << vks::tools::errorString(res) << "\" in " << __FILE__ << " at line " << __LINE__ << "\n"; \
assert(res == VK_SUCCESS); \
} \
}
#endif
#define GET_INSTANCE_PROC_ADDR(inst, entrypoint) \
{ \
fp##entrypoint = reinterpret_cast<PFN_vk##entrypoint>(vkGetInstanceProcAddr(inst, "vk"#entrypoint)); \
if (fp##entrypoint == NULL) \
{ \
exit(1); \
} \
}
#define GET_INSTANCE_PROC_ADDR(inst, entrypoint) \
{ \
fp##entrypoint = reinterpret_cast<PFN_vk##entrypoint>(vkGetInstanceProcAddr(inst, "vk" #entrypoint)); \
if (fp##entrypoint == NULL) \
{ \
exit(1); \
} \
}
#define GET_DEVICE_PROC_ADDR(dev, entrypoint) \
{ \
fp##entrypoint = reinterpret_cast<PFN_vk##entrypoint>(vkGetDeviceProcAddr(dev, "vk"#entrypoint)); \
if (fp##entrypoint == NULL) \
{ \
exit(1); \
} \
}
#define GET_DEVICE_PROC_ADDR(dev, entrypoint) \
{ \
fp##entrypoint = reinterpret_cast<PFN_vk##entrypoint>(vkGetDeviceProcAddr(dev, "vk" #entrypoint)); \
if (fp##entrypoint == NULL) \
{ \
exit(1); \
} \
}
const std::string getAssetPath();
namespace vks
{
namespace tools
{
/** @brief Disable message boxes on fatal errors */
extern bool errorModeSilent;
namespace tools
{
/** @brief Disable message boxes on fatal errors */
extern bool errorModeSilent;
/** @brief Returns an error code as a string */
std::string errorString(VkResult errorCode);
/** @brief Returns an error code as a string */
std::string errorString(VkResult errorCode);
/** @brief Returns the device type as a string */
std::string physicalDeviceTypeString(VkPhysicalDeviceType type);
/** @brief Returns the device type as a string */
std::string physicalDeviceTypeString(VkPhysicalDeviceType type);
// 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
VkBool32 getSupportedDepthFormat(VkPhysicalDevice physicalDevice, VkFormat *depthFormat);
// 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
VkBool32 getSupportedDepthFormat(VkPhysicalDevice physicalDevice, VkFormat *depthFormat);
// Returns tru a given format support LINEAR filtering
VkBool32 formatIsFilterable(VkPhysicalDevice physicalDevice, VkFormat format, VkImageTiling tiling);
// Returns true if a given format has a stencil part
VkBool32 formatHasStencil(VkFormat format);
// Returns tru a given format support LINEAR filtering
VkBool32 formatIsFilterable(VkPhysicalDevice physicalDevice, VkFormat format, VkImageTiling tiling);
// Returns true if a given format has a stencil part
VkBool32 formatHasStencil(VkFormat format);
// Put an image memory barrier for setting an image layout on the sub resource into the given command buffer
void setImageLayout(
VkCommandBuffer cmdbuffer,
VkImage image,
VkImageLayout oldImageLayout,
VkImageLayout newImageLayout,
VkImageSubresourceRange subresourceRange,
VkPipelineStageFlags srcStageMask = 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
void setImageLayout(
VkCommandBuffer cmdbuffer,
VkImage image,
VkImageAspectFlags aspectMask,
VkImageLayout oldImageLayout,
VkImageLayout newImageLayout,
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
// Put an image memory barrier for setting an image layout on the sub resource into the given command buffer
void setImageLayout(
VkCommandBuffer cmdbuffer,
VkImage image,
VkImageLayout oldImageLayout,
VkImageLayout newImageLayout,
VkImageSubresourceRange subresourceRange,
VkPipelineStageFlags srcStageMask = 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
void setImageLayout(
VkCommandBuffer cmdbuffer,
VkImage image,
VkImageAspectFlags aspectMask,
VkImageLayout oldImageLayout,
VkImageLayout newImageLayout,
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
/** @brief Insert an image memory barrier into the command buffer */
void insertImageMemoryBarrier(
VkCommandBuffer cmdbuffer,
VkImage image,
VkAccessFlags srcAccessMask,
VkAccessFlags dstAccessMask,
VkImageLayout oldImageLayout,
VkImageLayout newImageLayout,
VkPipelineStageFlags srcStageMask,
VkPipelineStageFlags dstStageMask,
VkImageSubresourceRange subresourceRange);
/** @brief Insert an image memory barrier into the command buffer */
void insertImageMemoryBarrier(
VkCommandBuffer cmdbuffer,
VkImage image,
VkAccessFlags srcAccessMask,
VkAccessFlags dstAccessMask,
VkImageLayout oldImageLayout,
VkImageLayout newImageLayout,
VkPipelineStageFlags srcStageMask,
VkPipelineStageFlags dstStageMask,
VkImageSubresourceRange subresourceRange);
// Display error message and exit on fatal error
void exitFatal(const std::string& message, int32_t exitCode);
void exitFatal(const std::string& message, VkResult resultCode);
// Display error message and exit on fatal error
void exitFatal(const std::string &message, int32_t exitCode);
void exitFatal(const std::string &message, VkResult resultCode);
// Load a SPIR-V shader (binary)
// Load a SPIR-V shader (binary)
#if defined(__ANDROID__)
VkShaderModule loadShader(AAssetManager* assetManager, const char *fileName, VkDevice device);
VkShaderModule loadShader(AAssetManager *assetManager, const char *fileName, VkDevice device);
#else
VkShaderModule loadShader(const char *fileName, VkDevice device);
VkShaderModule loadShader(const char *fileName, VkDevice device);
#endif
/** @brief Checks if a file exists */
bool fileExists(const std::string &filename);
/** @brief Checks if a file exists */
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

View File

@ -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
}

View File

@ -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

View File

@ -1,24 +1,26 @@
/*
* Vulkan Example base class
*
* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
*
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
*/
* Vulkan Example base class
*
* 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
#ifdef _WIN32
#pragma comment(linker, "/subsystem:windows")
#include <windows.h>
#include <fcntl.h>
#include <io.h>
#include <windows.h>
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
#include <android/native_activity.h>
#include "VulkanAndroid.h"
#include <android/asset_manager.h>
#include <android/native_activity.h>
#include <android_native_app_glue.h>
#include <sys/system_properties.h>
#include "VulkanAndroid.h"
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
#include <wayland-client.h>
#elif defined(_DIRECT2DISPLAY)
@ -26,24 +28,25 @@
#elif defined(VK_USE_PLATFORM_XCB_KHR)
#include <xcb/xcb.h>
#elif defined(VK_USE_PLATFORM_MACOS_MVK)
#include <Cocoa/Cocoa.h>
#include <Carbon/Carbon.h>
#include <QuartzCore/CAMetalLayer.h>
#include <Cocoa/Cocoa.h>
#include <CoreVideo/CVDisplayLink.h>
#include <QuartzCore/CAMetalLayer.h>
#endif
#include <iostream>
#include <chrono>
#include <iostream>
#include <sys/stat.h>
#define GLM_FORCE_RADIANS
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/glm.hpp>
#include <string>
#include <sstream>
#include <array>
#include <glm/glm.hpp>
#include <numeric>
#include <sstream>
#include <string>
#include "vulkan/vulkan.h"
@ -51,7 +54,7 @@
#include "camera.hpp"
#include "keycodes.hpp"
#include "VulkanDevice.hpp"
#include "VulkanDevice.h"
#include "VulkanSwapChain.hpp"
#include "imgui.h"
@ -59,210 +62,220 @@
class VulkanExampleBase
{
private:
float fpsTimer = 0.0f;
uint32_t frameCounter = 0;
uint32_t destWidth;
uint32_t destHeight;
bool resizing = false;
void handleMouseMove(int32_t x, int32_t y);
PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallback;
PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallback;
VkDebugReportCallbackEXT debugReportCallback;
struct MultisampleTarget {
struct {
VkImage image;
VkImageView view;
VkDeviceMemory memory;
} color;
struct {
VkImage image;
VkImageView view;
VkDeviceMemory memory;
} depth;
} multisampleTarget;
float fpsTimer = 0.0f;
uint32_t frameCounter = 0;
uint32_t destWidth;
uint32_t destHeight;
bool resizing = false;
void handleMouseMove(int32_t x, int32_t y);
PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallback;
PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallback;
VkDebugReportCallbackEXT debugReportCallback;
struct MultisampleTarget
{
struct
{
VkImage image;
VkImageView view;
VkDeviceMemory memory;
} color;
struct
{
VkImage image;
VkImageView view;
VkDeviceMemory memory;
} depth;
} multisampleTarget;
protected:
VkInstance instance;
VkPhysicalDevice physicalDevice;
VkPhysicalDeviceProperties deviceProperties;
VkPhysicalDeviceFeatures deviceFeatures;
VkPhysicalDeviceMemoryProperties deviceMemoryProperties;
VkDevice device;
vks::VulkanDevice *vulkanDevice;
VkQueue queue;
VkFormat depthFormat;
VkCommandPool cmdPool;
VkRenderPass renderPass;
std::vector<VkFramebuffer>frameBuffers;
uint32_t currentBuffer = 0;
VkDescriptorPool descriptorPool;
VkPipelineCache pipelineCache;
VulkanSwapChain swapChain;
std::string title = "Vulkan Example";
std::string name = "vulkanExample";
void windowResize();
VkInstance instance;
VkPhysicalDevice physicalDevice;
VkPhysicalDeviceProperties deviceProperties;
VkPhysicalDeviceFeatures deviceFeatures;
VkPhysicalDeviceMemoryProperties deviceMemoryProperties;
VkDevice device;
VulkanBase::VulkanDevice *vulkanDevice;
VkQueue queue;
VkFormat depthFormat;
VkCommandPool cmdPool;
VkRenderPass renderPass;
std::vector<VkFramebuffer> frameBuffers;
uint32_t currentBuffer = 0;
VkDescriptorPool descriptorPool;
VkPipelineCache pipelineCache;
VulkanSwapChain swapChain;
std::string title = "Vulkan Example";
std::string name = "vulkanExample";
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;
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 {
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; // 图片序列开始帧
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; // 图片序列开始帧
uint32_t videoFrameRate = 25;
uint32_t videoFrameRate = 25;
VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_4_BIT; // 多重采样倍率
} settings;
VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_4_BIT; // 多重采样倍率
} settings;
struct DepthStencil {
VkImage image;
VkDeviceMemory mem;
VkImageView view;
} depthStencil;
struct DepthStencil
{
VkImage image;
VkDeviceMemory mem;
VkImageView view;
} depthStencil;
struct GamePadState {
glm::vec2 axisLeft = glm::vec2(0.0f);
glm::vec2 axisRight = glm::vec2(0.0f);
} gamePadState;
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;
struct MouseButtons
{
bool left = false;
bool right = false;
bool middle = false;
} mouseButtons;
// OS specific
// OS specific
#if defined(_WIN32)
HWND window;
HINSTANCE windowInstance;
HWND window;
HINSTANCE windowInstance;
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
// true if application has focused, false if moved to background
bool focused = false;
std::string androidProduct;
struct TouchPoint {
int32_t id;
float x;
float y;
bool down = false;
};
float pinchDist = 0.0f;
std::array<TouchPoint, 2> touchPoints;
// true if application has focused, false if moved to background
bool focused = false;
std::string androidProduct;
struct TouchPoint
{
int32_t id;
float x;
float y;
bool down = false;
};
float pinchDist = 0.0f;
std::array<TouchPoint, 2> touchPoints;
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
wl_display *display = nullptr;
wl_registry *registry = nullptr;
wl_compositor *compositor = nullptr;
wl_shell *shell = nullptr;
wl_seat *seat = nullptr;
wl_pointer *pointer = nullptr;
wl_keyboard *keyboard = nullptr;
wl_surface *surface = nullptr;
wl_shell_surface *shell_surface = nullptr;
bool quit = false;
wl_display *display = nullptr;
wl_registry *registry = nullptr;
wl_compositor *compositor = nullptr;
wl_shell *shell = nullptr;
wl_seat *seat = nullptr;
wl_pointer *pointer = nullptr;
wl_keyboard *keyboard = nullptr;
wl_surface *surface = nullptr;
wl_shell_surface *shell_surface = nullptr;
bool quit = false;
#elif defined(_DIRECT2DISPLAY)
bool quit = false;
bool quit = false;
#elif defined(VK_USE_PLATFORM_XCB_KHR)
bool quit = false;
xcb_connection_t *connection;
xcb_screen_t *screen;
xcb_window_t window;
xcb_intern_atom_reply_t *atom_wm_delete_window;
bool quit = false;
xcb_connection_t *connection;
xcb_screen_t *screen;
xcb_window_t window;
xcb_intern_atom_reply_t *atom_wm_delete_window;
#elif defined(VK_USE_PLATFORM_MACOS_MVK)
NSWindow* window;
NSWindow *window;
#endif
#if defined(_WIN32)
HWND setupWindow(HINSTANCE hinstance, WNDPROC wndproc);
void handleMessages(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
HWND setupWindow(HINSTANCE hinstance, WNDPROC wndproc);
void handleMessages(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
static int32_t handleAppInput(struct android_app* app, AInputEvent* event);
static void handleAppCommand(android_app* app, int32_t cmd);
static int32_t handleAppInput(struct android_app *app, AInputEvent *event);
static void handleAppCommand(android_app *app, int32_t cmd);
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
wl_shell_surface *setupWindow();
void initWaylandConnection();
static void registryGlobalCb(void *data, struct wl_registry *registry,
uint32_t name, const char *interface, uint32_t version);
void registryGlobal(struct wl_registry *registry, uint32_t name,
const char *interface, uint32_t version);
static void registryGlobalRemoveCb(void *data, struct wl_registry *registry,
uint32_t name);
static void seatCapabilitiesCb(void *data, wl_seat *seat, uint32_t caps);
void seatCapabilities(wl_seat *seat, uint32_t caps);
static void pointerEnterCb(void *data, struct wl_pointer *pointer,
uint32_t serial, struct wl_surface *surface, wl_fixed_t sx,
wl_fixed_t sy);
static void pointerLeaveCb(void *data, struct wl_pointer *pointer,
uint32_t serial, struct wl_surface *surface);
static void pointerMotionCb(void *data, struct wl_pointer *pointer,
uint32_t time, wl_fixed_t sx, wl_fixed_t sy);
void pointerMotion(struct wl_pointer *pointer,
uint32_t time, wl_fixed_t sx, wl_fixed_t sy);
static void pointerButtonCb(void *data, struct wl_pointer *wl_pointer,
uint32_t serial, uint32_t time, uint32_t button, uint32_t state);
void pointerButton(struct wl_pointer *wl_pointer,
uint32_t serial, uint32_t time, uint32_t button, uint32_t state);
static void pointerAxisCb(void *data, struct wl_pointer *wl_pointer,
uint32_t time, uint32_t axis, wl_fixed_t value);
void pointerAxis(struct wl_pointer *wl_pointer,
uint32_t time, uint32_t axis, wl_fixed_t value);
static void keyboardKeymapCb(void *data, struct wl_keyboard *keyboard,
uint32_t format, int fd, uint32_t size);
static void keyboardEnterCb(void *data, struct wl_keyboard *keyboard,
uint32_t serial, struct wl_surface *surface, struct wl_array *keys);
static void keyboardLeaveCb(void *data, struct wl_keyboard *keyboard,
uint32_t serial, struct wl_surface *surface);
static void keyboardKeyCb(void *data, struct wl_keyboard *keyboard,
uint32_t serial, uint32_t time, uint32_t key, uint32_t state);
void keyboardKey(struct wl_keyboard *keyboard,
uint32_t serial, uint32_t time, uint32_t key, uint32_t state);
static void keyboardModifiersCb(void *data, struct wl_keyboard *keyboard,
uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched,
uint32_t mods_locked, uint32_t group);
wl_shell_surface *setupWindow();
void initWaylandConnection();
static void registryGlobalCb(void *data, struct wl_registry *registry,
uint32_t name, const char *interface, uint32_t version);
void registryGlobal(struct wl_registry *registry, uint32_t name,
const char *interface, uint32_t version);
static void registryGlobalRemoveCb(void *data, struct wl_registry *registry,
uint32_t name);
static void seatCapabilitiesCb(void *data, wl_seat *seat, uint32_t caps);
void seatCapabilities(wl_seat *seat, uint32_t caps);
static void pointerEnterCb(void *data, struct wl_pointer *pointer,
uint32_t serial, struct wl_surface *surface, wl_fixed_t sx,
wl_fixed_t sy);
static void pointerLeaveCb(void *data, struct wl_pointer *pointer,
uint32_t serial, struct wl_surface *surface);
static void pointerMotionCb(void *data, struct wl_pointer *pointer,
uint32_t time, wl_fixed_t sx, wl_fixed_t sy);
void pointerMotion(struct wl_pointer *pointer,
uint32_t time, wl_fixed_t sx, wl_fixed_t sy);
static void pointerButtonCb(void *data, struct wl_pointer *wl_pointer,
uint32_t serial, uint32_t time, uint32_t button, uint32_t state);
void pointerButton(struct wl_pointer *wl_pointer,
uint32_t serial, uint32_t time, uint32_t button, uint32_t state);
static void pointerAxisCb(void *data, struct wl_pointer *wl_pointer,
uint32_t time, uint32_t axis, wl_fixed_t value);
void pointerAxis(struct wl_pointer *wl_pointer,
uint32_t time, uint32_t axis, wl_fixed_t value);
static void keyboardKeymapCb(void *data, struct wl_keyboard *keyboard,
uint32_t format, int fd, uint32_t size);
static void keyboardEnterCb(void *data, struct wl_keyboard *keyboard,
uint32_t serial, struct wl_surface *surface, struct wl_array *keys);
static void keyboardLeaveCb(void *data, struct wl_keyboard *keyboard,
uint32_t serial, struct wl_surface *surface);
static void keyboardKeyCb(void *data, struct wl_keyboard *keyboard,
uint32_t serial, uint32_t time, uint32_t key, uint32_t state);
void keyboardKey(struct wl_keyboard *keyboard,
uint32_t serial, uint32_t time, uint32_t key, uint32_t state);
static void keyboardModifiersCb(void *data, struct wl_keyboard *keyboard,
uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched,
uint32_t mods_locked, uint32_t group);
#elif defined(_DIRECT2DISPLAY)
//
#elif defined(VK_USE_PLATFORM_XCB_KHR)
xcb_window_t setupWindow();
void initxcbConnection();
void handleEvent(const xcb_generic_event_t *event);
xcb_window_t setupWindow();
void initxcbConnection();
void handleEvent(const xcb_generic_event_t *event);
#elif defined(VK_USE_PLATFORM_MACOS_MVK)
NSWindow* setupWindow();
void mouseDragged(float x, float y);
void windowWillResize(float x, float y);
void windowDidResize();
NSWindow *setupWindow();
void mouseDragged(float x, float y);
void windowWillResize(float x, float y);
void windowDidResize();
#endif
VulkanExampleBase();
virtual ~VulkanExampleBase();
VulkanExampleBase();
virtual ~VulkanExampleBase();
void initVulkan();
void initVulkan();
virtual VkResult createInstance(bool enableValidation);
virtual void render() = 0;
virtual void windowResized();
virtual void setupFrameBuffer();
virtual void prepare();
virtual void fileDropped(std::string filename);
virtual VkResult createInstance(bool enableValidation);
virtual void render() = 0;
virtual void windowResized();
virtual void setupFrameBuffer();
virtual void prepare();
virtual void fileDropped(std::string filename);
void initSwapchain();
void setupSwapChain();
void initSwapchain();
void setupSwapChain();
void renderLoop();
void renderFrame();
void renderLoop();
void renderFrame();
};

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,21 @@
#ifndef GLTFMAINMODEL_H
#define GLTFMAINMODEL_H
#ifndef TINYGLTF_NO_STB_IMAGE_WRITE
#define TINYGLTF_NO_STB_IMAGE_WRITE
#endif
#include "glTFModel_Marco.h"
#include "glTFModel_common.h"
#include "VulkanDevice.h"
#include "glTFAnimation.h"
#include "glTFNode.h"
#include "glTFSkin.h"
#include "glTFTexture.h"
#include "glTFAnimation.h"
#include <tiny_gltf.h>
#include <glm/glm.hpp>
#include <string>
@ -17,68 +23,72 @@
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
{
public:
glTFMainModel();
~glTFMainModel();
glTFMainModel();
~glTFMainModel();
VkSamplerAddressMode getVkWrapMode(int32_t wrapMode);
VkFilter getVkFilterMode(int32_t filterMode);
void getNodeProperty(const tinygltf::Node& node, const tinygltf::Model& model, size_t& vertexCount, size_t& indexCount);
void getSceneDimensions();
void destroy(VkDevice device);
VkSamplerAddressMode getVkWrapMode(int32_t wrapMode);
VkFilter getVkFilterMode(int32_t filterMode);
void getNodeProperty(const tinygltf::Node &node, const tinygltf::Model &model, size_t &vertexCount, size_t &indexCount);
void getSceneDimensions();
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);
ModelBuffer &getModelVertex();
ModelBuffer &getModelIndex();
void drawNode(glTFNode* node, VkCommandBuffer commandBuffer);
void draw(VkCommandBuffer commandBuffer);
void destroy(VkDevice device);
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);
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);
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:
VulkanBase::VulkanDevice *m_device;
VulkanBase::VulkanDevice* m_device;
ModelBuffer m_vertices;
ModelBuffer m_indices;
struct Vertices {
VkBuffer buffer = VK_NULL_HANDLE;
VkDeviceMemory memory;
} m_vertices;
struct Indices {
VkBuffer buffer = VK_NULL_HANDLE;
VkDeviceMemory memory;
} m_indices;
glm::mat4 m_aabb;
glm::mat4 m_aabb;
std::vector<glTFNode *> m_nodes;
std::vector<glTFNode *> m_linearNodes;
std::vector<glTFNode*> m_nodes;
std::vector<glTFNode*> m_linearNodes;
std::vector<glTFSkin *> m_skins;
std::vector<glTFSkin*> m_skins;
std::vector<glTFTexture> m_textures;
std::vector<VulkanBase::VulkanTextureSampler> m_textureSamplers;
std::vector<glTFMaterial> m_materials;
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;
std::vector<glTFTexture> m_textures;
std::vector<VulkanBase::VulkanTextureSampler> m_textureSamplers;
std::vector<glTFMaterial> m_materials;
std::vector<glTFAnimation> m_animations;
std::vector<std::string> m_extensions;
AABBDimensions m_dimensions;
};
GLTFLOADER_NAMESPACE_END
#endif // !GLTFMAINMODEL_h

View File

@ -1,6 +1,5 @@
#include "glTFMaterial.h"
GLTFLOADER_NAMESPACE_BEGIN
glTFMaterial::glTFMaterial()
@ -13,72 +12,81 @@ glTFMaterial::~glTFMaterial()
void glTFMaterial::setDoublesided(bool value)
{
m_doubleSided = value;
m_doubleSided = value;
}
bool glTFMaterial::getDoublesided()
{
return m_doubleSided;
return m_doubleSided;
}
void glTFMaterial::setAlphaMode(AlphaMode value)
{
m_alphaMode = value;
m_alphaMode = value;
}
AlphaMode glTFMaterial::getAlphaMode()
{
return m_alphaMode;
return m_alphaMode;
}
void glTFMaterial::setAlphaCutOff(float value)
{
m_alphaCutoff = value;
m_alphaCutoff = value;
}
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

View File

@ -4,11 +4,11 @@
#include "glTFModel_Marco.h"
#include "glTFModel_common.h"
#include "glTFTexture.h"
#include "PbrBaseTexture.h"
#include "PbrTextureCoordSet.h"
#include "PbrTextureExtension.h"
#include "PbrBaseTexture.h"
#include "PbrWorkFlow.h"
#include "glTFTexture.h"
#include <glm/glm.hpp>
@ -17,50 +17,46 @@ GLTFLOADER_NAMESPACE_BEGIN
class glTFMaterial
{
public:
glTFMaterial();
~glTFMaterial();
glTFMaterial();
~glTFMaterial();
void setDoublesided(bool value);
bool getDoublesided();
void setDoublesided(bool value);
bool getDoublesided();
void setAlphaMode(AlphaMode value);
AlphaMode getAlphaMode();
void setAlphaMode(AlphaMode value);
AlphaMode getAlphaMode();
void setAlphaCutOff(float value);
float getAlphaCutOff();
void setAlphaCutOff(float value);
float getAlphaCutOff();
void setDescriptorSet(VkDescriptorSet value);
VkDescriptorSet getDescriptorSet();
TextureCoordSet* getTextureCoordSet();
void setTextureCoordSet(TextureCoordSet* value);
TextureCoordSet *getTextureCoordSet();
void setTextureCoordSet(TextureCoordSet *value);
PbrTextureExtension* getTextureExtension();
void setPbrTextureExtension(PbrTextureExtension* value);
PBR::PbrTextureExtension *getTextureExtension();
void setPbrTextureExtension(PBR::PbrTextureExtension *value);
PbrBaseTexture* getPbrBaseTexture();
void setPbrBaseTexture(PbrBaseTexture* value);
PBR::PbrBaseTexture *getPbrBaseTexture();
void setPbrBaseTexture(PBR::PbrBaseTexture *value);
PbrWorkFlow* getPbrWorkFlow();
void setPbrWorkFlow();
PBR::PbrWorkFlow *getPbrWorkFlow();
void setPbrWorkFlow(PBR::PbrWorkFlow *value);
private:
AlphaMode m_alphaMode = ALPHAMODE_OPAQUE;
float m_alphaCutoff = 1.0f;
AlphaMode m_alphaMode = ALPHAMODE_OPAQUE;
float m_alphaCutoff = 1.0f;
PbrBaseTexture* m_pbrBaseTexture;
bool m_doubleSided = false;
TextureCoordSet* m_texCoordSets;
PbrTextureExtension* m_textureExtension;
PbrWorkFlow* m_pbrWorkFlow;
VkDescriptorSet m_descriptorSet = VK_NULL_HANDLE;
PBR::PbrBaseTexture *m_pbrBaseTexture;
bool m_doubleSided = false;
TextureCoordSet *m_texCoordSets;
PBR::PbrTextureExtension *m_textureExtension;
PBR::PbrWorkFlow *m_pbrWorkFlow;
VkDescriptorSet m_descriptorSet = VK_NULL_HANDLE;
};
GLTFLOADER_NAMESPACE_END
#endif // !GLTFMATERIAL_H

View File

@ -32,9 +32,9 @@
#include "tiny_gltf.h"
#include "VulkanDevice.hpp"
#include "VulkanDevice.h"
//#include "VulkanUtils.hpp"
#include "vulkan/vulkan.h"
#define ENABLE_VALIDATION false
#define MAX_NUM_JOINTS 128u
@ -64,7 +64,7 @@ namespace glTFModel
};
struct Texture {
vks::VulkanDevice* device;
VulkanBase::VulkanDevice* device;
VkImage image;
VkImageLayout imageLayout;
VkDeviceMemory deviceMemory;
@ -77,7 +77,7 @@ namespace glTFModel
void updateDescriptor();
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
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 {
@ -127,7 +127,7 @@ namespace glTFModel
};
struct Mesh {
vks::VulkanDevice* device;
VulkanBase::VulkanDevice* device;
std::vector<Primitive*> primitives;
BoundingBox bb;
BoundingBox aabb;
@ -143,7 +143,7 @@ namespace glTFModel
glm::mat4 jointMatrix[128]{};
float jointcount{ 0 };
} uniformBlock;
Mesh(vks::VulkanDevice* device, glm::mat4 matrix);
Mesh(VulkanBase::VulkanDevice* device, glm::mat4 matrix);
~Mesh();
void setBoundingBox(glm::vec3 min, glm::vec3 max);
};
@ -199,7 +199,7 @@ namespace glTFModel
struct Model {
vks::VulkanDevice* device;
VulkanBase::VulkanDevice* device;
struct Vertex {
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 getNodeProps(const tinygltf::Node& node, const tinygltf::Model& model, size_t& vertexCount, size_t& indexCount);
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);
VkFilter getVkFilterMode(int32_t filterMode);
void loadTextureSamplers(tinygltf::Model& gltfModel);
void loadMaterials(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 draw(VkCommandBuffer commandBuffer);
void calculateBoundingBox(Node* node, Node* parent);

View File

@ -2,15 +2,10 @@
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()
@ -19,33 +14,60 @@ glTFPrimitive::~glTFPrimitive()
void glTFPrimitive::setBoundingBox(glm::vec3 min, glm::vec3 max)
{
m_boundingBox.setBoundingBox(min, max);
m_boundingBox.setBoundingBox(min, max);
}
glTFBoundingBox glTFPrimitive::getBoundingBox()
{
return m_boundingBox;
return m_boundingBox;
}
void glTFPrimitive::setIndexCount(unsigned int indexCount)
{
m_indexCount = indexCount;
m_indexCount = indexCount;
}
unsigned int glTFPrimitive::getIndexCount()
{
return m_indexCount;
return m_indexCount;
}
void glTFPrimitive::setFirstIndex(unsigned int firstIndex)
{
m_firstIndex = firstIndex;
m_firstIndex = firstIndex;
}
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

View File

@ -3,44 +3,47 @@
#include "glTFModel_Marco.h"
#include "glTFMaterial.h"
#include "glTFBoundingBox.h"
#include "glTFMaterial.h"
#include <glm/glm.hpp>
GLTFLOADER_NAMESPACE_BEGIN
class GLTFLOADER_API glTFPrimitive
{
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();
~glTFPrimitive();
void setBoundingBox(glm::vec3 min, glm::vec3 max);
glTFBoundingBox getBoundingBox();
void setBoundingBox(glm::vec3 min, glm::vec3 max);
glTFBoundingBox getBoundingBox();
void setIndexCount(unsigned int indexCount);
unsigned int getIndexCount();
void setIndexCount(unsigned int indexCount);
unsigned int getIndexCount();
void setFirstIndex(unsigned int firstIndex);
unsigned int getFirstIndex();
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:
unsigned int m_firstIndex;
unsigned int m_indexCount;
unsigned int m_vertexCount;
glTFMaterial& m_material;
bool m_hasIndices;
glTFBoundingBox m_boundingBox;
unsigned int m_firstIndex;
unsigned int m_indexCount;
unsigned int m_vertexCount;
glTFMaterial &m_material;
bool m_hasIndices;
glTFBoundingBox m_boundingBox;
};
GLTFLOADER_NAMESPACE_END
#endif // !GLTFPRIMITIVE_H

View File

@ -8,43 +8,34 @@
#include <tiny_gltf.h>
GLTFLOADER_NAMESPACE_BEGIN
/// @brief gltf模型的贴图
class GLTFLOADER_API glTFTexture
{
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:
VulkanBase::VulkanDevice* m_device;
VkImage m_image;
VkImageLayout m_imageLayout;
VkDeviceMemory m_deviceMemory;
VkImageView m_view;
unsigned int m_width, m_height;
unsigned int m_mipLevels;
unsigned int m_layerCount;
VkDescriptorImageInfo m_descriptor;
VkSampler m_sampler;
VulkanBase::VulkanDevice *m_device;
VkImage m_image;
VkImageLayout m_imageLayout;
VkDeviceMemory m_deviceMemory;
VkImageView m_view;
unsigned int m_width, m_height;
unsigned int m_mipLevels;
unsigned int m_layerCount;
VkDescriptorImageInfo m_descriptor;
VkSampler m_sampler;
};
GLTFLOADER_NAMESPACE_END
#endif // !GLTFTEXTURE_H

View File

@ -1,6 +1,6 @@
#include "PbrBaseTexture.h"
GLTFLOADER_NAMESPACE_BEGIN
PBR_NAMESPACE_BEGIN
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)
{
m_baseColorFactor = value;
m_baseColorFactor = value;
}
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)
{
m_metallicFactor = value;
m_metallicFactor = value;
}
float PbrBaseTexture::getMetallicFactor()
{
return m_metallicFactor;
return m_metallicFactor;
}
void PbrBaseTexture::setRoughnessFactor(float value)
{
m_roughnessFactor = value;
m_roughnessFactor = value;
}
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)
{
m_emissiveFactor = value;
m_emissiveFactor = value;
}
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

View File

@ -1,69 +1,64 @@
#ifndef PBRBASETEXTURE_H
#define PBRBASETEXTURE_H
/// todo 分离为单独的PBR命名空间
#include "glTFModel_Marco.h"
#include "PbrMarco.h"
#include "glTFTexture.h"
#include <glm/glm.hpp>
GLTFLOADER_NAMESPACE_BEGIN
PBR_NAMESPACE_BEGIN
/// @brief todo拆分texture基类摆脱gltf限制
class PbrBaseTexture
{
public:
PbrBaseTexture();
~PbrBaseTexture();
PbrBaseTexture();
~PbrBaseTexture();
void setBaseColorTexture(glTFTexture* value);
glTFTexture* getBaseColorTexture();
void setBaseColorTexture(glTFLoader::glTFTexture *value);
glTFLoader::glTFTexture *getBaseColorTexture();
void setBaseColorFactor(glm::vec4 value);
glm::vec4 getBaseColorFactor();
void setBaseColorFactor(glm::vec4 value);
glm::vec4 getBaseColorFactor();
void setNormalTexture(glTFTexture* value);
glTFTexture* getNormalTexture();
void setNormalTexture(glTFLoader::glTFTexture *value);
glTFLoader::glTFTexture *getNormalTexture();
void setMetallicRoughnessTexture(glTFTexture* value);
glTFTexture* getMetalicRoughnessTexture();
void setMetallicRoughnessTexture(glTFLoader::glTFTexture *value);
glTFLoader::glTFTexture *getMetalicRoughnessTexture();
void setMetallicFactor(float value);
float getMetallicFactor();
void setMetallicFactor(float value);
float getMetallicFactor();
void setRoughnessFactor(float value);
float getRoughnessFactor();
void setRoughnessFactor(float value);
float getRoughnessFactor();
void setEmissiveTexture(glTFTexture* value);
glTFTexture* getEmissiveTexture();
void setEmissiveTexture(glTFLoader::glTFTexture *value);
glTFLoader::glTFTexture *getEmissiveTexture();
void setEmissiveFactor(glm::vec4 value);
glm::vec4 getEmissiveFactor();
void setEmissiveFactor(glm::vec4 value);
glm::vec4 getEmissiveFactor();
void setOcclusionTexture(glTFTexture* value);
glTFTexture* getOcclusionTexture();
void setOcclusionTexture(glTFLoader::glTFTexture *value);
glTFLoader::glTFTexture *getOcclusionTexture();
private:
glTFLoader::glTFTexture *m_baseColorTexture = nullptr;
glm::vec4 m_baseColorFactor = glm::vec4(1.0f);
glTFTexture* m_baseColorTexture = nullptr;
glm::vec4 m_baseColorFactor = glm::vec4(1.0f);
glTFLoader::glTFTexture *m_normalTexture = nullptr;
glTFTexture* m_normalTexture = nullptr;
glTFLoader::glTFTexture *m_metallicRoughnessTexture = nullptr;
float m_metallicFactor = 1.0f;
float m_roughnessFactor = 1.0f;
glTFTexture* m_metallicRoughnessTexture = nullptr;
float m_metallicFactor = 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_emissiveTexture = nullptr;
glm::vec4 m_emissiveFactor = glm::vec4(1.0f);
glTFLoader::glTFTexture *m_occlusionTexture = nullptr;
};
GLTFLOADER_NAMESPACE_END
PBR_NAMESPACE_END
#endif // !PBRBASETEXTURE_H

34
src/pbr/PbrMarco.h 100644
View File

@ -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

View File

@ -1,6 +1,6 @@
#include "PbrTextureExtension.h"
GLTFLOADER_NAMESPACE_BEGIN
PBR_NAMESPACE_BEGIN
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)
{
m_diffuseFactor = value;
m_diffuseFactor = value;
}
glm::vec4 PbrTextureExtension::getDiffuseFactor()
{
return m_diffuseFactor;
return m_diffuseFactor;
}
void PbrTextureExtension::setSpecularFactor(glm::vec3 value)
{
m_specularFactor = value;
m_specularFactor = value;
}
glm::vec3 PbrTextureExtension::getSpecularFactor()
{
return m_specularFactor;
return m_specularFactor;
}
GLTFLOADER_NAMESPACE_END
PBR_NAMESPACE_END

View File

@ -1,51 +1,39 @@
#ifndef PBRTEXTUREEXTENSION_H
#define PBRTEXTUREEXTENSION_H
#include "glTFModel_Marco.h"
#include "PbrMarco.h"
#include "glTFTexture.h"
#include <glm/glm.hpp>
PBR_NAMESPACE_BEGIN
GLTFLOADER_NAMESPACE_BEGIN
class PbrTextureExtension
class PbrTextureExtension
{
public:
PbrTextureExtension();
~PbrTextureExtension();
PbrTextureExtension();
~PbrTextureExtension();
void setSpecularGlossinessTexture(glTFTexture* _texture);
glTFTexture* getSpecularGlossinessTexture();
void setSpecularGlossinessTexture(glTFLoader::glTFTexture *_texture);
glTFLoader::glTFTexture *getSpecularGlossinessTexture();
void setDiffuseTexture(glTFTexture* _texture);
glTFTexture* getDiffuseTexture();
void setDiffuseTexture(glTFLoader::glTFTexture *_texture);
glTFLoader::glTFTexture *getDiffuseTexture();
void setDiffuseFactor(glm::vec4 value);
glm::vec4 getDiffuseFactor();
void setSpecularFactor(glm::vec3 value);
glm::vec3 getSpecularFactor();
void setDiffuseFactor(glm::vec4 value);
glm::vec4 getDiffuseFactor();
void setSpecularFactor(glm::vec3 value);
glm::vec3 getSpecularFactor();
private:
glTFTexture* m_specularGlossinessTexture = nullptr;
glTFTexture* m_diffuseTexture = nullptr;
glm::vec4 m_diffuseFactor = glm::vec4(1.0f);
glm::vec3 m_specularFactor = glm::vec3(0.0f);
glTFLoader::glTFTexture *m_specularGlossinessTexture = nullptr;
glTFLoader::glTFTexture *m_diffuseTexture = nullptr;
glm::vec4 m_diffuseFactor = glm::vec4(1.0f);
glm::vec3 m_specularFactor = glm::vec3(0.0f);
};
GLTFLOADER_NAMESPACE_END
PBR_NAMESPACE_END
#endif // !PbrTextureExtension_h

View File

@ -1,6 +1,6 @@
#include "PbrWorkFlow.h"
GLTFLOADER_NAMESPACE_BEGIN
PBR_NAMESPACE_BEGIN
PbrWorkFlow::PbrWorkFlow()
{
@ -32,4 +32,4 @@ bool PbrWorkFlow::getSpecularGlossiness()
GLTFLOADER_NAMESPACE_END
PBR_NAMESPACE_END

View File

@ -1,33 +1,27 @@
#ifndef PBRWORKFLOW_H
#define PBRWORKFLOW_H
#include "glTFModel_Marco.h"
#include "PbrMarco.h"
GLTFLOADER_NAMESPACE_BEGIN
PBR_NAMESPACE_BEGIN
class PbrWorkFlow
{
public:
PbrWorkFlow();
~PbrWorkFlow();
PbrWorkFlow();
~PbrWorkFlow();
void setMetallicRoughness(bool value);
bool getMetallicRoughness();
void setMetallicRoughness(bool value);
bool getMetallicRoughness();
void setSpecularGlossiness(bool value);
bool getSpecularGlossiness();
void setSpecularGlossiness(bool value);
bool getSpecularGlossiness();
private:
bool m_metallicRoughness = true;
bool m_specularGlossiness = false;
bool m_metallicRoughness = true;
bool m_specularGlossiness = false;
};
GLTFLOADER_NAMESPACE_END
PBR_NAMESPACE_END
#endif // !PBRWORKFLOW_H

View File

@ -1,5 +1,12 @@
#include "IrradiancePushBlock.h"
IrradiancePushBlock::IrradiancePushBlock()
{
}
IrradiancePushBlock::~IrradiancePushBlock()
{
}
// Getter method definitions
float IrradiancePushBlock::getDeltaPhi() const
{

View File

@ -1,45 +1,45 @@
#include "RenderSceneTextures.h"
// Getters
vks::TextureCubeMap &RenderSceneTextures::getEnvironmentCube()
VulkanBase::TextureCubeMap &RenderSceneTextures::getEnvironmentCube()
{
return m_environmentCube;
}
vks::Texture2D &RenderSceneTextures::getEmpty()
VulkanBase::Texture2D &RenderSceneTextures::getEmpty()
{
return m_empty;
}
vks::Texture2D &RenderSceneTextures::getLutBrdf()
VulkanBase::Texture2D &RenderSceneTextures::getLutBrdf()
{
return m_lutBrdf;
}
vks::TextureCubeMap &RenderSceneTextures::getIrradianceCube()
VulkanBase::TextureCubeMap &RenderSceneTextures::getIrradianceCube()
{
return m_irradianceCube;
}
vks::TextureCubeMap &RenderSceneTextures::getPrefilteredCube()
VulkanBase::TextureCubeMap &RenderSceneTextures::getPrefilteredCube()
{
return m_prefilteredCube;
}
// Setters
void RenderSceneTextures::setEnvironmentCube(const vks::TextureCubeMap &texture)
void RenderSceneTextures::setEnvironmentCube(const VulkanBase::TextureCubeMap &texture)
{
m_environmentCube = texture;
}
void RenderSceneTextures::setEmpty(const vks::Texture2D &texture)
void RenderSceneTextures::setEmpty(const VulkanBase::Texture2D &texture)
{
m_empty = texture;
}
void RenderSceneTextures::setLutBrdf(const vks::Texture2D &texture)
void RenderSceneTextures::setLutBrdf(const VulkanBase::Texture2D &texture)
{
m_lutBrdf = texture;
}
void RenderSceneTextures::setIrradianceCube(const vks::TextureCubeMap &texture)
void RenderSceneTextures::setIrradianceCube(const VulkanBase::TextureCubeMap &texture)
{
m_irradianceCube = texture;
}
void RenderSceneTextures::setPrefilteredCube(const vks::TextureCubeMap &texture)
void RenderSceneTextures::setPrefilteredCube(const VulkanBase::TextureCubeMap &texture)
{
m_prefilteredCube = texture;
}

View File

@ -1,6 +1,6 @@
#pragma once
#include <VulkanTexture.hpp>
#include <VulkanTexture.h>
class RenderSceneTextures
{
@ -9,18 +9,18 @@ public:
~RenderSceneTextures();
// Getters
vks::TextureCubeMap &getEnvironmentCube();
vks::Texture2D &getEmpty();
vks::Texture2D &getLutBrdf();
vks::TextureCubeMap &getIrradianceCube();
vks::TextureCubeMap &getPrefilteredCube();
VulkanBase::TextureCubeMap &getEnvironmentCube();
VulkanBase::Texture2D &getEmpty();
VulkanBase::Texture2D &getLutBrdf();
VulkanBase::TextureCubeMap &getIrradianceCube();
VulkanBase::TextureCubeMap &getPrefilteredCube();
// Setters
void setEnvironmentCube(const vks::TextureCubeMap &texture);
void setEmpty(const vks::Texture2D &texture);
void setLutBrdf(const vks::Texture2D &texture);
void setIrradianceCube(const vks::TextureCubeMap &texture);
void setPrefilteredCube(const vks::TextureCubeMap &texture);
void setEnvironmentCube(const VulkanBase::TextureCubeMap &texture);
void setEmpty(const VulkanBase::Texture2D &texture);
void setLutBrdf(const VulkanBase::Texture2D &texture);
void setIrradianceCube(const VulkanBase::TextureCubeMap &texture);
void setPrefilteredCube(const VulkanBase::TextureCubeMap &texture);
// destroy
void destroyEnvironmentCube();
@ -30,9 +30,9 @@ public:
void destroyPrefilteredCube();
private:
vks::TextureCubeMap m_environmentCube;
vks::Texture2D m_empty;
vks::Texture2D m_lutBrdf;
vks::TextureCubeMap m_irradianceCube;
vks::TextureCubeMap m_prefilteredCube;
VulkanBase::TextureCubeMap m_environmentCube;
VulkanBase::Texture2D m_empty;
VulkanBase::Texture2D m_lutBrdf;
VulkanBase::TextureCubeMap m_irradianceCube;
VulkanBase::TextureCubeMap m_prefilteredCube;
};

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,18 +1,26 @@

#pragma once
#ifndef TINYGLTF_IMPLEMENTATION
#define TINYGLTF_IMPLEMENTATION
#include "render.h"
#include "PbrBaseTexture.h"
#include "PbrTextureCoordSet.h"
#include "glTFMainModel.h"
#include "PushConstBlockMaterial.h"
#include "VulkanTexture.hpp"
#include "glTFModel.h"
#include "ShaderLoader.h"
#include "VulkanTexture.h"
#include "glTFMaterial.h"
#include "glTFPrimitive.h"
#include "glTFSkin.h"
#include "glTFTexture.h"
#include "glm/gtc/matrix_transform.hpp"
#include "renderUniformBufferSet.h"
#include "vulkan/vulkan_core.h"
#include <cmath>
#include <cstddef>
#include <vector>
#endif
#ifndef STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION
#endif
@ -21,7 +29,6 @@
#define TINYGLTF_NO_STB_IMAGE_WRITE
#endif
#include "render.h"
// #include "VulkanUtils.hpp"
// #include "assetLoader.h"
@ -30,21 +37,21 @@ PlumageRender::PlumageRender()
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
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;
switch (alphaMode)
{
case glTFModel::Material::ALPHAMODE_OPAQUE:
case glTFModel::Material::ALPHAMODE_MASK:
if (primitive->material.doubleSided)
case glTFLoader::ALPHAMODE_OPAQUE:
case glTFLoader::ALPHAMODE_MASK:
if (primitive->getGltfMaterial().getDoublesided())
{
pipeline = m_pipelineList.getPbrDoubleSided();
}
@ -53,7 +60,7 @@ void PlumageRender::renderNode(glTFModel::Node *node, uint32_t cbIndex, glTFMode
pipeline = m_pipelineList.getPbr();
}
break;
case glTFModel::Material::ALPHAMODE_BLEND:
case glTFLoader::ALPHAMODE_BLEND:
pipeline = m_pipelineList.getPbrAlphaBlend();
break;
}
@ -66,78 +73,81 @@ void PlumageRender::renderNode(glTFModel::Node *node, uint32_t cbIndex, glTFMode
const std::vector<VkDescriptorSet> descriptorsets = {
descriptorSets[cbIndex].getScene(),
primitive->material.descriptorSet,
node->mesh->uniformBuffer.descriptorSet,
primitive->getGltfMaterial().getDescriptorSet(),
node->getMesh()->getUniformBuffer().descriptorSet,
};
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
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
// -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
{
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
{
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
{
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
{
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
if (primitive->material.pbrWorkflows.metallicRoughness)
glTFLoader::glTFMaterial *material = &primitive->getGltfMaterial();
if (material->getPbrWorkFlow()->getMetallicRoughness())
{
// Metallic roughness workflow
m_pushConstBlockMaterial.setWorkflow(static_cast<float>(PBR_WORKFLOW_METALLIC_ROUGHNESS));
m_pushConstBlockMaterial.setBaseColorFactor(primitive->material.baseColorFactor);
m_pushConstBlockMaterial.setMetallicFactor(primitive->material.metallicFactor);
m_pushConstBlockMaterial.setRoughnessFactor(primitive->material.roughnessFactor);
if (primitive->material.metallicRoughnessTexture != nullptr)
m_pushConstBlockMaterial.setBaseColorFactor(pbrBaseTexture->getBaseColorFactor());
m_pushConstBlockMaterial.setMetallicFactor(pbrBaseTexture->getMetallicFactor());
m_pushConstBlockMaterial.setRoughnessFactor(pbrBaseTexture->getRoughnessFactor());
if (pbrBaseTexture->getMetalicRoughnessTexture() != nullptr)
{
m_pushConstBlockMaterial.setPhysicalDescriptorTextureSet(primitive->material.texCoordSets.metallicRoughness);
m_pushConstBlockMaterial.setPhysicalDescriptorTextureSet(texCoordSet->getMetallicRoughness());
}
else
{
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
{
@ -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
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
{
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
{
m_pushConstBlockMaterial.setColorTextureSet(-1);
}
m_pushConstBlockMaterial.setDiffuseFactor(primitive->material.extension.diffuseFactor);
m_pushConstBlockMaterial.setSpecularFactor(glm::vec4(primitive->material.extension.specularFactor, 1.0f));
m_pushConstBlockMaterial.setDiffuseFactor(material->getTextureExtension()->getDiffuseFactor());
m_pushConstBlockMaterial.setSpecularFactor(glm::vec4(material->getTextureExtension()->getSpecularFactor(), 1.0f));
}
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
{
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);
}
@ -249,12 +261,12 @@ void PlumageRender::buildCommandBuffers()
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);
if (model.indices.buffer != VK_NULL_HANDLE)
vkCmdBindVertexBuffers(currentCB, 0, 1, &model.getModelVertex().buffer, offsets);
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;
@ -329,7 +341,7 @@ void PlumageRender::loadAssets()
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);
@ -459,7 +471,7 @@ void PlumageRender::setupDescriptors()
VkDescriptorSetLayout sceneDescriptorSetLayout = m_descriptorSetLayoutList.getScene();
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++)
{
@ -605,7 +617,7 @@ void PlumageRender::setupDescriptors()
}
}
vks::TextureCubeMap refPrefilterCube = m_sceneTextures.getPrefilteredCube();
VulkanBase::TextureCubeMap refPrefilterCube = m_sceneTextures.getPrefilteredCube();
// Skybox (fixed set)
for (auto i = 0; i < uniformBuffers.size(); i++)
{
@ -752,8 +764,8 @@ void PlumageRender::preparePipelines()
// Skybox pipeline (background cube)
shaderStages = {
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.getSkyboxVertShaderPath(), VK_SHADER_STAGE_VERTEX_BIT),
ShaderLoader::loadShader(device, m_configFilePath.getSkyboxFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT)};
VkPipeline skyboxPipeline = m_pipelineList.getSkybox();
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &skyboxPipeline));
for (auto shaderStage : shaderStages)
@ -763,8 +775,8 @@ void PlumageRender::preparePipelines()
// PBR pipeline
shaderStages = {
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.getPbrVertShaderPath(), VK_SHADER_STAGE_VERTEX_BIT),
ShaderLoader::loadShader(device, m_configFilePath.getPbrFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT)};
depthStencilStateCI.depthWriteEnable = VK_TRUE;
depthStencilStateCI.depthTestEnable = VK_TRUE;
VkPipeline pbrPipeline = m_pipelineList.getPbr();
@ -807,7 +819,7 @@ void PlumageRender::generateCubemaps()
for (uint32_t target = 0; target < PREFILTEREDENV + 1; target++)
{
vks::TextureCubeMap cubemap;
VulkanBase::TextureCubeMap cubemap;
auto tStart = std::chrono::high_resolution_clock::now();
@ -1132,14 +1144,14 @@ void PlumageRender::generateCubemaps()
pipelineCI.pStages = shaderStages.data();
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)
{
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;
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;
};
VkPipeline pipeline;
@ -1360,7 +1372,7 @@ void PlumageRender::generateBRDFLUT()
const VkFormat format = VK_FORMAT_R16G16_SFLOAT;
const int32_t dim = 2048;
vks::Texture2D RefLutBrdfTex = m_sceneTextures.getLutBrdf();
VulkanBase::Texture2D RefLutBrdfTex = m_sceneTextures.getLutBrdf();
// Image
VkImageCreateInfo imageCI{};
@ -1553,8 +1565,8 @@ void PlumageRender::generateBRDFLUT()
// Look-up-table (from BRDF) pipeline
shaderStages = {
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.getBrdfVertShaderPath(), VK_SHADER_STAGE_VERTEX_BIT),
ShaderLoader::loadShader(device, m_configFilePath.getBrdfFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT)};
VkPipeline pipeline;
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipeline));
for (auto shaderStage : shaderStages)
@ -2264,9 +2276,8 @@ void PlumageRender::updateUIOverlay()
if (!filename.empty())
{
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);
setupDescriptors();
updateCBs = true;

View File

@ -5,6 +5,8 @@
#include "RenderOffScreen.h"
#include "RenderPipelineList.h"
#include "RenderSceneTextures.h"
#include "glTFMaterial.h"
#include "glTFSkin.h"
#include "renderShaderData.h"
#if defined(_WIN32)
#include <direct.h>
@ -36,8 +38,7 @@
#include "VulkanExampleBase.h"
#include "glTFModel.h"
#include "ui.hpp"
#include <VulkanTexture.hpp>
#include <VulkanUtils.hpp>
#include <VulkanTexture.h>
#include <vulkan/vulkan.h>
#define ENABLE_VALIDATION false
@ -55,6 +56,7 @@
#include "RenderPipelineList.h"
#include "RenderSceneTextures.h"
#include "SceneUBOMatrices.h"
#include "ShaderLoader.h"
#include "SkyboxUBOMatrices.h"
#include "VertexStagingBuffer.h"
#include "renderEffectState.h"
@ -184,7 +186,7 @@ public:
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 loadEnvironment(std::string filename);
void buildCommandBuffers();

View File

@ -9,22 +9,22 @@ RenderSceneModel::~RenderSceneModel()
{
}
void RenderSceneModel::setScene(glTFModel::Model value)
void RenderSceneModel::setScene(glTFLoader::glTFMainModel value)
{
m_scene = value;
}
glTFModel::Model &RenderSceneModel::getScene()
glTFLoader::glTFMainModel &RenderSceneModel::getScene()
{
return m_scene;
}
void RenderSceneModel::setSkyBox(glTFModel::Model value)
void RenderSceneModel::setSkyBox(glTFLoader::glTFMainModel value)
{
m_skybox = value;
}
glTFModel::Model &RenderSceneModel::getSkyBox()
glTFLoader::glTFMainModel &RenderSceneModel::getSkyBox()
{
return m_skybox;
}

View File

@ -1,7 +1,7 @@
#pragma once
#include "glTFModel.h"
#include "vulkan/vulkan.h"
#include "glTFMainModel.h"
#include <vulkan/vulkan.h>
class RenderSceneModel
{
@ -9,16 +9,16 @@ public:
RenderSceneModel();
~RenderSceneModel();
void setScene(glTFModel::Model value);
glTFModel::Model &getScene();
void setScene(glTFLoader::glTFMainModel value);
glTFLoader::glTFMainModel &getScene();
void setSkyBox(glTFModel::Model value);
glTFModel::Model &getSkyBox();
void setSkyBox(glTFLoader::glTFMainModel value);
glTFLoader::glTFMainModel &getSkyBox();
void destroyScene(VkDevice device);
void destroySkyBox(VkDevice device);
private:
glTFModel::Model m_scene;
glTFModel::Model m_skybox;
glTFLoader::glTFMainModel m_scene;
glTFLoader::glTFMainModel m_skybox;
};

View File

@ -9,33 +9,33 @@ RenderUniformBufferSet::~RenderUniformBufferSet()
}
// Getter method definitions
Buffer &RenderUniformBufferSet::getScene()
VulkanBase::Buffer &RenderUniformBufferSet::getScene()
{
return scene;
}
Buffer &RenderUniformBufferSet::getSkybox()
VulkanBase::Buffer &RenderUniformBufferSet::getSkybox()
{
return skybox;
}
Buffer &RenderUniformBufferSet::getParams()
VulkanBase::Buffer &RenderUniformBufferSet::getParams()
{
return params;
}
// Setter method definitions
void RenderUniformBufferSet::setScene(Buffer &buffer)
void RenderUniformBufferSet::setScene(VulkanBase::Buffer &buffer)
{
scene = buffer;
}
void RenderUniformBufferSet::setSkybox(Buffer &buffer)
void RenderUniformBufferSet::setSkybox(VulkanBase::Buffer &buffer)
{
skybox = buffer;
}
void RenderUniformBufferSet::setParams(Buffer &buffer)
void RenderUniformBufferSet::setParams(VulkanBase::Buffer &buffer)
{
params = buffer;
}

View File

@ -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
{
@ -9,17 +10,19 @@ public:
~RenderUniformBufferSet();
// Getter methods
Buffer &getScene();
Buffer &getSkybox();
Buffer &getParams();
VulkanBase::Buffer &getScene();
VulkanBase::Buffer &getSkybox();
VulkanBase::Buffer &getParams();
// Setter methods
void setScene(Buffer &buffer);
void setSkybox(Buffer &buffer);
void setParams(Buffer &buffer);
void setScene(VulkanBase::Buffer &buffer);
void setSkybox(VulkanBase::Buffer &buffer);
void setParams(VulkanBase::Buffer &buffer);
private:
Buffer scene;
Buffer skybox;
Buffer params;
VulkanBase::Buffer scene;
VulkanBase::Buffer skybox;
VulkanBase::Buffer params;
};
#endif

404
src/render/ui.hpp 100644
View File

@ -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);
}
};