调整结构

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,18 +1,8 @@
/*
* 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.
@ -20,65 +10,65 @@ namespace vks
*
* @return VkResult of the buffer mapping call
*/
VkResult Buffer::map(VkDeviceSize size, VkDeviceSize offset)
{
VkResult Buffer::map(VkDeviceSize size, VkDeviceSize offset)
{
return vkMapMemory(device, memory, offset, size, 0, &mapped);
}
}
/**
/**
* Unmap a mapped memory range
*
* @note Does not return a result as vkUnmapMemory can't fail
*/
void Buffer::unmap()
{
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)
{
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)
{
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)
{
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
@ -88,17 +78,17 @@ namespace vks
*
* @return VkResult of the flush call
*/
VkResult Buffer::flush(VkDeviceSize size, VkDeviceSize offset)
{
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
@ -108,28 +98,40 @@ namespace vks
*
* @return VkResult of the invalidate call
*/
VkResult Buffer::invalidate(VkDeviceSize size, VkDeviceSize offset)
{
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)
void Buffer::destroy()
{
if (mapped)
{
unmap();
}
vkDestroyBuffer(device, buffer, nullptr);
}
if (memory)
{
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
{
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;
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);
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);
}
}
};
}

View File

@ -1,39 +1,42 @@
/*
* 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)
*/
* 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)
*/
#include "VulkanTexture.h"
#include "vulkan/vulkan_core.h"
namespace vks
namespace VulkanBase
{
void Texture::updateDescriptor()
{
void Texture::updateDescriptor()
{
descriptor.sampler = sampler;
descriptor.imageView = view;
descriptor.imageLayout = imageLayout;
}
}
void Texture::destroy()
{
vkDestroyImageView(device->logicalDevice, view, nullptr);
vkDestroyImage(device->logicalDevice, image, nullptr);
void Texture::destroy()
{
VkDevice logicalDevice = device->getLogicalDevice();
vkDestroyImageView(logicalDevice, view, nullptr);
vkDestroyImage(logicalDevice, image, nullptr);
if (sampler)
{
vkDestroySampler(device->logicalDevice, sampler, nullptr);
}
vkFreeMemory(device->logicalDevice, deviceMemory, nullptr);
vkDestroySampler(logicalDevice, sampler, nullptr);
}
vkFreeMemory(logicalDevice, deviceMemory, nullptr);
}
ktxResult Texture::loadKTXFile(std::string filename, ktxTexture **target)
{
ktxResult Texture::loadKTXFile(std::string filename, ktxTexture **target)
{
ktxResult result = KTX_SUCCESS;
#if defined(__ANDROID__)
AAsset* asset = AAssetManager_open(androidApp->activity->assetManager, filename.c_str(), AASSET_MODE_STREAMING);
if (!asset) {
AAsset *asset = AAssetManager_open(androidApp->activity->assetManager, filename.c_str(), AASSET_MODE_STREAMING);
if (!asset)
{
vks::tools::exitFatal("Could not load texture from " + filename + "\n\nThe file may be part of the additional asset pack.\n\nRun \"download_assets.py\" in the repository root to download the latest version.", -1);
}
size_t size = AAsset_getLength(asset);
@ -44,15 +47,16 @@ namespace vks
result = ktxTexture_CreateFromMemory(textureData, size, KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT, target);
delete[] textureData;
#else
if (!vks::tools::fileExists(filename)) {
if (!vks::tools::fileExists(filename))
{
vks::tools::exitFatal("Could not load texture from " + filename + "\n\nThe file may be part of the additional asset pack.\n\nRun \"download_assets.py\" in the repository root to download the latest version.", -1);
}
result = ktxTexture_CreateFromNamedFile(filename.c_str(), KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT, target);
#endif
return result;
}
}
/**
/**
* Load a 2D texture including all mip levels
*
* @param filename File to load (supports .ktx)
@ -64,13 +68,14 @@ namespace vks
* @param (Optional) forceLinear Force linear tiling (not advised, defaults to false)
*
*/
void Texture2D::loadFromFile(std::string filename, VkFormat format, vks::VulkanDevice *device, VkQueue copyQueue, VkImageUsageFlags imageUsageFlags, VkImageLayout imageLayout, bool forceLinear)
{
ktxTexture* ktxTexture;
void Texture2D::loadFromFile(std::string filename, VkFormat format, VulkanBase::VulkanDevice *device, VkQueue copyQueue, VkImageUsageFlags imageUsageFlags, VkImageLayout imageLayout, bool forceLinear)
{
ktxTexture *ktxTexture;
ktxResult result = loadKTXFile(filename, &ktxTexture);
assert(result == KTX_SUCCESS);
this->device = device;
VkDevice logicalDevice = device->getLogicalDevice();
width = ktxTexture->baseWidth;
height = ktxTexture->baseHeight;
mipLevels = ktxTexture->numLevels;
@ -80,7 +85,7 @@ namespace vks
// Get device properties for the requested texture format
VkFormatProperties formatProperties;
vkGetPhysicalDeviceFormatProperties(device->physicalDevice, format, &formatProperties);
vkGetPhysicalDeviceFormatProperties(device->getPhysicalDevice(), format, &formatProperties);
// Only use linear tiling if requested (and supported by the device)
// Support for linear tiling is mostly limited, so prefer to use
@ -107,23 +112,23 @@ namespace vks
bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VK_CHECK_RESULT(vkCreateBuffer(device->logicalDevice, &bufferCreateInfo, nullptr, &stagingBuffer));
VK_CHECK_RESULT(vkCreateBuffer(logicalDevice, &bufferCreateInfo, nullptr, &stagingBuffer));
// Get memory requirements for the staging buffer (alignment, memory type bits)
vkGetBufferMemoryRequirements(device->logicalDevice, stagingBuffer, &memReqs);
vkGetBufferMemoryRequirements(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));
VK_CHECK_RESULT(vkAllocateMemory(logicalDevice, &memAllocInfo, nullptr, &stagingMemory));
VK_CHECK_RESULT(vkBindBufferMemory(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));
VK_CHECK_RESULT(vkMapMemory(logicalDevice, stagingMemory, 0, memReqs.size, 0, (void **)&data));
memcpy(data, ktxTextureData, ktxTextureSize);
vkUnmapMemory(device->logicalDevice, stagingMemory);
vkUnmapMemory(logicalDevice, stagingMemory);
// Setup buffer copy regions for each mip level
std::vector<VkBufferImageCopy> bufferCopyRegions;
@ -157,22 +162,22 @@ namespace vks
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageCreateInfo.extent = { width, height, 1 };
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));
VK_CHECK_RESULT(vkCreateImage(logicalDevice, &imageCreateInfo, nullptr, &image));
vkGetImageMemoryRequirements(device->logicalDevice, image, &memReqs);
vkGetImageMemoryRequirements(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));
VK_CHECK_RESULT(vkAllocateMemory(logicalDevice, &memAllocInfo, nullptr, &deviceMemory));
VK_CHECK_RESULT(vkBindImageMemory(logicalDevice, image, deviceMemory, 0));
VkImageSubresourceRange subresourceRange = {};
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
@ -196,8 +201,7 @@ namespace vks
image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
static_cast<uint32_t>(bufferCopyRegions.size()),
bufferCopyRegions.data()
);
bufferCopyRegions.data());
// Change texture image layout to shader read after all mip levels have been copied
this->imageLayout = imageLayout;
@ -211,8 +215,8 @@ namespace vks
device->flushCommandBuffer(copyCmd, copyQueue);
// Clean up staging resources
vkFreeMemory(device->logicalDevice, stagingMemory, nullptr);
vkDestroyBuffer(device->logicalDevice, stagingBuffer, nullptr);
vkFreeMemory(logicalDevice, stagingMemory, nullptr);
vkDestroyBuffer(logicalDevice, stagingBuffer, nullptr);
}
else
{
@ -229,7 +233,7 @@ namespace vks
VkImageCreateInfo imageCreateInfo = vks::initializers::imageCreateInfo();
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
imageCreateInfo.format = format;
imageCreateInfo.extent = { width, height, 1 };
imageCreateInfo.extent = {width, height, 1};
imageCreateInfo.mipLevels = 1;
imageCreateInfo.arrayLayers = 1;
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
@ -239,11 +243,11 @@ namespace vks
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
// Load mip map level 0 to linear tiling image
VK_CHECK_RESULT(vkCreateImage(device->logicalDevice, &imageCreateInfo, nullptr, &mappableImage));
VK_CHECK_RESULT(vkCreateImage(logicalDevice, &imageCreateInfo, nullptr, &mappableImage));
// Get memory requirements for this image
// like size and alignment
vkGetImageMemoryRequirements(device->logicalDevice, mappableImage, &memReqs);
vkGetImageMemoryRequirements(logicalDevice, mappableImage, &memReqs);
// Set memory allocation size to required memory size
memAllocInfo.allocationSize = memReqs.size;
@ -251,10 +255,10 @@ namespace vks
memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
// Allocate host memory
VK_CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &mappableMemory));
VK_CHECK_RESULT(vkAllocateMemory(logicalDevice, &memAllocInfo, nullptr, &mappableMemory));
// Bind allocated image for use
VK_CHECK_RESULT(vkBindImageMemory(device->logicalDevice, mappableImage, mappableMemory, 0));
VK_CHECK_RESULT(vkBindImageMemory(logicalDevice, mappableImage, mappableMemory, 0));
// Get sub resource layout
// Mip map count, array layer, etc.
@ -267,15 +271,15 @@ namespace vks
// Get sub resources layout
// Includes row pitch, size offsets, etc.
vkGetImageSubresourceLayout(device->logicalDevice, mappableImage, &subRes, &subResLayout);
vkGetImageSubresourceLayout(logicalDevice, mappableImage, &subRes, &subResLayout);
// Map image memory
VK_CHECK_RESULT(vkMapMemory(device->logicalDevice, mappableMemory, 0, memReqs.size, 0, &data));
VK_CHECK_RESULT(vkMapMemory(logicalDevice, mappableMemory, 0, memReqs.size, 0, &data));
// Copy image data into memory
memcpy(data, ktxTextureData, memReqs.size);
vkUnmapMemory(device->logicalDevice, mappableMemory);
vkUnmapMemory(logicalDevice, mappableMemory);
// Linear tiled images don't need to be staged
// and can be directly used as textures
@ -306,10 +310,19 @@ namespace vks
// Max level-of-detail should match mip level count
samplerCreateInfo.maxLod = (useStaging) ? (float)mipLevels : 0.0f;
// Only enable anisotropic filtering if enabled on the device
samplerCreateInfo.maxAnisotropy = device->enabledFeatures.samplerAnisotropy ? device->properties.limits.maxSamplerAnisotropy : 1.0f;
samplerCreateInfo.anisotropyEnable = device->enabledFeatures.samplerAnisotropy;
if (device->getPhysicalDeviceFeatures().samplerAnisotropy)
{
samplerCreateInfo.maxAnisotropy = device->getPhysicalDeviceProperties().limits.maxSamplerAnisotropy;
}
else
{
samplerCreateInfo.maxAnisotropy = 1.0;
}
samplerCreateInfo.anisotropyEnable = device->getPhysicalDeviceFeatures().samplerAnisotropy;
samplerCreateInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
VK_CHECK_RESULT(vkCreateSampler(device->logicalDevice, &samplerCreateInfo, nullptr, &sampler));
VK_CHECK_RESULT(vkCreateSampler(logicalDevice, &samplerCreateInfo, nullptr, &sampler));
// Create image view
// Textures are not directly accessed by the shaders and
@ -319,18 +332,18 @@ namespace vks
viewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewCreateInfo.format = format;
viewCreateInfo.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
viewCreateInfo.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
// Linear tiling usually won't support mip maps
// Only set mip map count if optimal tiling is used
viewCreateInfo.subresourceRange.levelCount = (useStaging) ? mipLevels : 1;
viewCreateInfo.image = image;
VK_CHECK_RESULT(vkCreateImageView(device->logicalDevice, &viewCreateInfo, nullptr, &view));
VK_CHECK_RESULT(vkCreateImageView(logicalDevice, &viewCreateInfo, nullptr, &view));
// Update descriptor image info member that can be used for setting up descriptor sets
updateDescriptor();
}
}
/**
/**
* Creates a 2D texture from a buffer
*
* @param buffer Buffer containing texture data to upload
@ -344,8 +357,8 @@ namespace vks
* @param (Optional) imageUsageFlags Usage flags for the texture's image (defaults to VK_IMAGE_USAGE_SAMPLED_BIT)
* @param (Optional) imageLayout Usage layout for the texture (defaults VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
*/
void Texture2D::fromBuffer(void* buffer, VkDeviceSize bufferSize, VkFormat format, uint32_t texWidth, uint32_t texHeight, vks::VulkanDevice *device, VkQueue copyQueue, VkFilter filter, VkImageUsageFlags imageUsageFlags, VkImageLayout imageLayout)
{
void Texture2D::loadFromBuffer(void *buffer, VkDeviceSize bufferSize, VkFormat format, uint32_t texWidth, uint32_t texHeight, VulkanBase::VulkanDevice *device, VkQueue copyQueue, VkFilter filter, VkImageUsageFlags imageUsageFlags, VkImageLayout imageLayout)
{
assert(buffer);
this->device = device;
@ -353,6 +366,8 @@ namespace vks
height = texHeight;
mipLevels = 1;
VkDevice logicalDevice = device->getLogicalDevice();
VkMemoryAllocateInfo memAllocInfo = vks::initializers::memoryAllocateInfo();
VkMemoryRequirements memReqs;
@ -369,23 +384,23 @@ namespace vks
bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VK_CHECK_RESULT(vkCreateBuffer(device->logicalDevice, &bufferCreateInfo, nullptr, &stagingBuffer));
VK_CHECK_RESULT(vkCreateBuffer(logicalDevice, &bufferCreateInfo, nullptr, &stagingBuffer));
// Get memory requirements for the staging buffer (alignment, memory type bits)
vkGetBufferMemoryRequirements(device->logicalDevice, stagingBuffer, &memReqs);
vkGetBufferMemoryRequirements(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));
VK_CHECK_RESULT(vkAllocateMemory(logicalDevice, &memAllocInfo, nullptr, &stagingMemory));
VK_CHECK_RESULT(vkBindBufferMemory(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));
VK_CHECK_RESULT(vkMapMemory(logicalDevice, stagingMemory, 0, memReqs.size, 0, (void **)&data));
memcpy(data, buffer, bufferSize);
vkUnmapMemory(device->logicalDevice, stagingMemory);
vkUnmapMemory(logicalDevice, stagingMemory);
VkBufferImageCopy bufferCopyRegion = {};
bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
@ -407,22 +422,22 @@ namespace vks
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageCreateInfo.extent = { width, height, 1 };
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));
VK_CHECK_RESULT(vkCreateImage(logicalDevice, &imageCreateInfo, nullptr, &image));
vkGetImageMemoryRequirements(device->logicalDevice, image, &memReqs);
vkGetImageMemoryRequirements(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));
VK_CHECK_RESULT(vkAllocateMemory(logicalDevice, &memAllocInfo, nullptr, &deviceMemory));
VK_CHECK_RESULT(vkBindImageMemory(logicalDevice, image, deviceMemory, 0));
VkImageSubresourceRange subresourceRange = {};
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
@ -446,8 +461,7 @@ namespace vks
image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1,
&bufferCopyRegion
);
&bufferCopyRegion);
// Change texture image layout to shader read after all mip levels have been copied
this->imageLayout = imageLayout;
@ -461,8 +475,8 @@ namespace vks
device->flushCommandBuffer(copyCmd, copyQueue);
// Clean up staging resources
vkFreeMemory(device->logicalDevice, stagingMemory, nullptr);
vkDestroyBuffer(device->logicalDevice, stagingBuffer, nullptr);
vkFreeMemory(logicalDevice, stagingMemory, nullptr);
vkDestroyBuffer(logicalDevice, stagingBuffer, nullptr);
// Create sampler
VkSamplerCreateInfo samplerCreateInfo = {};
@ -478,7 +492,7 @@ namespace vks
samplerCreateInfo.minLod = 0.0f;
samplerCreateInfo.maxLod = 0.0f;
samplerCreateInfo.maxAnisotropy = 1.0f;
VK_CHECK_RESULT(vkCreateSampler(device->logicalDevice, &samplerCreateInfo, nullptr, &sampler));
VK_CHECK_RESULT(vkCreateSampler(logicalDevice, &samplerCreateInfo, nullptr, &sampler));
// Create image view
VkImageViewCreateInfo viewCreateInfo = {};
@ -486,16 +500,16 @@ namespace vks
viewCreateInfo.pNext = NULL;
viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewCreateInfo.format = format;
viewCreateInfo.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
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));
VK_CHECK_RESULT(vkCreateImageView(logicalDevice, &viewCreateInfo, nullptr, &view));
// Update descriptor image info member that can be used for setting up descriptor sets
updateDescriptor();
}
}
/**
/**
* Load a 2D texture array including all mip levels
*
* @param filename File to load (supports .ktx)
@ -506,9 +520,9 @@ namespace vks
* @param (Optional) imageLayout Usage layout for the texture (defaults VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
*
*/
void Texture2DArray::loadFromFile(std::string filename, VkFormat format, vks::VulkanDevice *device, VkQueue copyQueue, VkImageUsageFlags imageUsageFlags, VkImageLayout imageLayout)
{
ktxTexture* ktxTexture;
void Texture2DArray::loadFromFile(std::string filename, VkFormat format, VulkanBase::VulkanDevice *device, VkQueue copyQueue, VkImageUsageFlags imageUsageFlags, VkImageLayout imageLayout)
{
ktxTexture *ktxTexture;
ktxResult result = loadKTXFile(filename, &ktxTexture);
assert(result == KTX_SUCCESS);
@ -521,6 +535,8 @@ namespace vks
ktx_uint8_t *ktxTextureData = ktxTexture_GetData(ktxTexture);
ktx_size_t ktxTextureSize = ktxTexture_GetSize(ktxTexture);
VkDevice logicalDevice = device->getLogicalDevice();
VkMemoryAllocateInfo memAllocInfo = vks::initializers::memoryAllocateInfo();
VkMemoryRequirements memReqs;
@ -534,23 +550,23 @@ namespace vks
bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VK_CHECK_RESULT(vkCreateBuffer(device->logicalDevice, &bufferCreateInfo, nullptr, &stagingBuffer));
VK_CHECK_RESULT(vkCreateBuffer(logicalDevice, &bufferCreateInfo, nullptr, &stagingBuffer));
// Get memory requirements for the staging buffer (alignment, memory type bits)
vkGetBufferMemoryRequirements(device->logicalDevice, stagingBuffer, &memReqs);
vkGetBufferMemoryRequirements(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));
VK_CHECK_RESULT(vkAllocateMemory(logicalDevice, &memAllocInfo, nullptr, &stagingMemory));
VK_CHECK_RESULT(vkBindBufferMemory(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));
VK_CHECK_RESULT(vkMapMemory(logicalDevice, stagingMemory, 0, memReqs.size, 0, (void **)&data));
memcpy(data, ktxTextureData, ktxTextureSize);
vkUnmapMemory(device->logicalDevice, stagingMemory);
vkUnmapMemory(logicalDevice, stagingMemory);
// Setup buffer copy regions for each layer including all of its miplevels
std::vector<VkBufferImageCopy> bufferCopyRegions;
@ -585,7 +601,7 @@ namespace vks
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageCreateInfo.extent = { width, height, 1 };
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))
@ -595,15 +611,15 @@ namespace vks
imageCreateInfo.arrayLayers = layerCount;
imageCreateInfo.mipLevels = mipLevels;
VK_CHECK_RESULT(vkCreateImage(device->logicalDevice, &imageCreateInfo, nullptr, &image));
VK_CHECK_RESULT(vkCreateImage(logicalDevice, &imageCreateInfo, nullptr, &image));
vkGetImageMemoryRequirements(device->logicalDevice, image, &memReqs);
vkGetImageMemoryRequirements(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));
VK_CHECK_RESULT(vkAllocateMemory(logicalDevice, &memAllocInfo, nullptr, &deviceMemory));
VK_CHECK_RESULT(vkBindImageMemory(logicalDevice, image, deviceMemory, 0));
// Use a separate command buffer for texture loading
VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
@ -652,34 +668,42 @@ namespace vks
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;
if (device->getPhysicalDeviceFeatures().samplerAnisotropy)
{
samplerCreateInfo.maxAnisotropy = device->getPhysicalDeviceProperties().limits.maxSamplerAnisotropy;
}
else
{
samplerCreateInfo.maxAnisotropy = 1.0;
}
samplerCreateInfo.anisotropyEnable = device->getPhysicalDeviceFeatures().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));
VK_CHECK_RESULT(vkCreateSampler(logicalDevice, &samplerCreateInfo, nullptr, &sampler));
// Create image view
VkImageViewCreateInfo viewCreateInfo = vks::initializers::imageViewCreateInfo();
viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
viewCreateInfo.format = format;
viewCreateInfo.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
viewCreateInfo.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
viewCreateInfo.subresourceRange.layerCount = layerCount;
viewCreateInfo.subresourceRange.levelCount = mipLevels;
viewCreateInfo.image = image;
VK_CHECK_RESULT(vkCreateImageView(device->logicalDevice, &viewCreateInfo, nullptr, &view));
VK_CHECK_RESULT(vkCreateImageView(logicalDevice, &viewCreateInfo, nullptr, &view));
// Clean up staging resources
ktxTexture_Destroy(ktxTexture);
vkFreeMemory(device->logicalDevice, stagingMemory, nullptr);
vkDestroyBuffer(device->logicalDevice, stagingBuffer, nullptr);
vkFreeMemory(logicalDevice, stagingMemory, nullptr);
vkDestroyBuffer(logicalDevice, stagingBuffer, nullptr);
// Update descriptor image info member that can be used for setting up descriptor sets
updateDescriptor();
}
}
/**
/**
* Load a cubemap texture including all mip levels from a single file
*
* @param filename File to load (supports .ktx)
@ -690,9 +714,9 @@ namespace vks
* @param (Optional) imageLayout Usage layout for the texture (defaults VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
*
*/
void TextureCubeMap::loadFromFile(std::string filename, VkFormat format, vks::VulkanDevice *device, VkQueue copyQueue, VkImageUsageFlags imageUsageFlags, VkImageLayout imageLayout)
{
ktxTexture* ktxTexture;
void TextureCubeMap::loadFromFile(std::string filename, VkFormat format, VulkanBase::VulkanDevice *device, VkQueue copyQueue, VkImageUsageFlags imageUsageFlags, VkImageLayout imageLayout)
{
ktxTexture *ktxTexture;
ktxResult result = loadKTXFile(filename, &ktxTexture);
assert(result == KTX_SUCCESS);
@ -704,6 +728,8 @@ namespace vks
ktx_uint8_t *ktxTextureData = ktxTexture_GetData(ktxTexture);
ktx_size_t ktxTextureSize = ktxTexture_GetSize(ktxTexture);
VkDevice logicalDevice = device->getLogicalDevice();
VkMemoryAllocateInfo memAllocInfo = vks::initializers::memoryAllocateInfo();
VkMemoryRequirements memReqs;
@ -717,23 +743,23 @@ namespace vks
bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VK_CHECK_RESULT(vkCreateBuffer(device->logicalDevice, &bufferCreateInfo, nullptr, &stagingBuffer));
VK_CHECK_RESULT(vkCreateBuffer(logicalDevice, &bufferCreateInfo, nullptr, &stagingBuffer));
// Get memory requirements for the staging buffer (alignment, memory type bits)
vkGetBufferMemoryRequirements(device->logicalDevice, stagingBuffer, &memReqs);
vkGetBufferMemoryRequirements(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));
VK_CHECK_RESULT(vkAllocateMemory(logicalDevice, &memAllocInfo, nullptr, &stagingMemory));
VK_CHECK_RESULT(vkBindBufferMemory(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));
VK_CHECK_RESULT(vkMapMemory(logicalDevice, stagingMemory, 0, memReqs.size, 0, (void **)&data));
memcpy(data, ktxTextureData, ktxTextureSize);
vkUnmapMemory(device->logicalDevice, stagingMemory);
vkUnmapMemory(logicalDevice, stagingMemory);
// Setup buffer copy regions for each face including all of its mip levels
std::vector<VkBufferImageCopy> bufferCopyRegions;
@ -769,7 +795,7 @@ namespace vks
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageCreateInfo.extent = { width, height, 1 };
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))
@ -781,16 +807,15 @@ namespace vks
// This flag is required for cube map images
imageCreateInfo.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
VK_CHECK_RESULT(vkCreateImage(logicalDevice, &imageCreateInfo, nullptr, &image));
VK_CHECK_RESULT(vkCreateImage(device->logicalDevice, &imageCreateInfo, nullptr, &image));
vkGetImageMemoryRequirements(device->logicalDevice, image, &memReqs);
vkGetImageMemoryRequirements(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));
VK_CHECK_RESULT(vkAllocateMemory(logicalDevice, &memAllocInfo, nullptr, &deviceMemory));
VK_CHECK_RESULT(vkBindImageMemory(logicalDevice, image, deviceMemory, 0));
// Use a separate command buffer for texture loading
VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
@ -839,31 +864,39 @@ namespace vks
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;
if (device->getPhysicalDeviceFeatures().samplerAnisotropy)
{
samplerCreateInfo.maxAnisotropy = device->getPhysicalDeviceProperties().limits.maxSamplerAnisotropy;
}
else
{
samplerCreateInfo.maxAnisotropy = 1.0;
}
samplerCreateInfo.anisotropyEnable = device->getPhysicalDeviceFeatures().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));
VK_CHECK_RESULT(vkCreateSampler(logicalDevice, &samplerCreateInfo, nullptr, &sampler));
// Create image view
VkImageViewCreateInfo viewCreateInfo = vks::initializers::imageViewCreateInfo();
viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_CUBE;
viewCreateInfo.format = format;
viewCreateInfo.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
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));
VK_CHECK_RESULT(vkCreateImageView(logicalDevice, &viewCreateInfo, nullptr, &view));
// Clean up staging resources
ktxTexture_Destroy(ktxTexture);
vkFreeMemory(device->logicalDevice, stagingMemory, nullptr);
vkDestroyBuffer(device->logicalDevice, stagingBuffer, nullptr);
vkFreeMemory(logicalDevice, stagingMemory, nullptr);
vkDestroyBuffer(logicalDevice, stagingBuffer, nullptr);
// Update descriptor image info member that can be used for setting up descriptor sets
updateDescriptor();
}
}
} // namespace VulkanBase

View File

@ -1,37 +1,27 @@
/*
* 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;
public:
VulkanBase::VulkanDevice *device;
VkImage image;
VkImageLayout imageLayout;
VkDeviceMemory deviceMemory;
@ -49,22 +39,22 @@ class Texture
class Texture2D : public Texture
{
public:
public:
void loadFromFile(
std::string filename,
VkFormat format,
vks::VulkanDevice *device,
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 fromBuffer(
void * buffer,
void loadFromBuffer(
void *buffer,
VkDeviceSize bufferSize,
VkFormat format,
uint32_t texWidth,
uint32_t texHeight,
vks::VulkanDevice *device,
VulkanBase::VulkanDevice *device,
VkQueue copyQueue,
VkFilter filter = VK_FILTER_LINEAR,
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
@ -73,11 +63,11 @@ class Texture2D : public Texture
class Texture2DArray : public Texture
{
public:
public:
void loadFromFile(
std::string filename,
VkFormat format,
vks::VulkanDevice *device,
VulkanBase::VulkanDevice *device,
VkQueue copyQueue,
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
@ -85,13 +75,16 @@ class Texture2DArray : public Texture
class TextureCubeMap : public Texture
{
public:
public:
void loadFromFile(
std::string filename,
VkFormat format,
vks::VulkanDevice *device,
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>
@ -33,70 +35,70 @@
// 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); \
} \
}
}
#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); \
} \
}
}
#endif
#define GET_INSTANCE_PROC_ADDR(inst, entrypoint) \
{ \
fp##entrypoint = reinterpret_cast<PFN_vk##entrypoint>(vkGetInstanceProcAddr(inst, "vk"#entrypoint)); \
{ \
fp##entrypoint = reinterpret_cast<PFN_vk##entrypoint>(vkGetInstanceProcAddr(inst, "vk" #entrypoint)); \
if (fp##entrypoint == NULL) \
{ \
exit(1); \
} \
}
}
#define GET_DEVICE_PROC_ADDR(dev, entrypoint) \
{ \
fp##entrypoint = reinterpret_cast<PFN_vk##entrypoint>(vkGetDeviceProcAddr(dev, "vk"#entrypoint)); \
{ \
fp##entrypoint = reinterpret_cast<PFN_vk##entrypoint>(vkGetDeviceProcAddr(dev, "vk" #entrypoint)); \
if (fp##entrypoint == NULL) \
{ \
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(
// 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,
@ -104,8 +106,8 @@ namespace vks
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(
// Uses a fixed sub resource layout with first mip level and layer
void setImageLayout(
VkCommandBuffer cmdbuffer,
VkImage image,
VkImageAspectFlags aspectMask,
@ -114,8 +116,8 @@ namespace vks
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(
/** @brief Insert an image memory barrier into the command buffer */
void insertImageMemoryBarrier(
VkCommandBuffer cmdbuffer,
VkImage image,
VkAccessFlags srcAccessMask,
@ -126,20 +128,20 @@ namespace vks
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"
@ -68,18 +71,22 @@ private:
PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallback;
PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallback;
VkDebugReportCallbackEXT debugReportCallback;
struct MultisampleTarget {
struct {
struct MultisampleTarget
{
struct
{
VkImage image;
VkImageView view;
VkDeviceMemory memory;
} color;
struct {
struct
{
VkImage image;
VkImageView view;
VkDeviceMemory memory;
} depth;
} multisampleTarget;
protected:
VkInstance instance;
VkPhysicalDevice physicalDevice;
@ -87,12 +94,12 @@ protected:
VkPhysicalDeviceFeatures deviceFeatures;
VkPhysicalDeviceMemoryProperties deviceMemoryProperties;
VkDevice device;
vks::VulkanDevice *vulkanDevice;
VulkanBase::VulkanDevice *vulkanDevice;
VkQueue queue;
VkFormat depthFormat;
VkCommandPool cmdPool;
VkRenderPass renderPass;
std::vector<VkFramebuffer>frameBuffers;
std::vector<VkFramebuffer> frameBuffers;
uint32_t currentBuffer = 0;
VkDescriptorPool descriptorPool;
VkPipelineCache pipelineCache;
@ -100,8 +107,9 @@ protected:
std::string title = "Vulkan Example";
std::string name = "vulkanExample";
void windowResize();
public:
static std::vector<const char*> args;
static std::vector<const char *> args;
uint32_t selectedPhysicalDeviceIndex = 0;
bool prepared = false;
uint32_t width = 1280;
@ -112,7 +120,8 @@ public:
bool paused = false;
uint32_t lastFPS = 0;
struct Settings {
struct Settings
{
bool validation = false; // 校验层开关
bool fullscreen = false; // 全屏开关
bool vsync = false; // 垂直同步开关
@ -130,18 +139,21 @@ public:
VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_4_BIT; // 多重采样倍率
} settings;
struct DepthStencil {
struct DepthStencil
{
VkImage image;
VkDeviceMemory mem;
VkImageView view;
} depthStencil;
struct GamePadState {
struct GamePadState
{
glm::vec2 axisLeft = glm::vec2(0.0f);
glm::vec2 axisRight = glm::vec2(0.0f);
} gamePadState;
struct MouseButtons {
struct MouseButtons
{
bool left = false;
bool right = false;
bool middle = false;
@ -155,7 +167,8 @@ public:
// true if application has focused, false if moved to background
bool focused = false;
std::string androidProduct;
struct TouchPoint {
struct TouchPoint
{
int32_t id;
float x;
float y;
@ -184,15 +197,15 @@ public:
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);
#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();
@ -242,7 +255,7 @@ public:
void initxcbConnection();
void handleEvent(const xcb_generic_event_t *event);
#elif defined(VK_USE_PLATFORM_MACOS_MVK)
NSWindow* setupWindow();
NSWindow *setupWindow();
void mouseDragged(float x, float y);
void windowWillResize(float x, float y);
void windowDidResize();

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,6 +23,18 @@
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:
@ -25,45 +43,42 @@ public:
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 getNodeProperty(const tinygltf::Node &node, const tinygltf::Model &model, size_t &vertexCount, size_t &indexCount);
void getSceneDimensions();
ModelBuffer &getModelVertex();
ModelBuffer &getModelIndex();
void destroy(VkDevice device);
void loadNode(glTFNode* parent, const tinygltf::Node& node, uint32_t nodeIndex, const tinygltf::Model& model, LoaderInfo& loaderInfo, float globalscale);
void loadSkins(tinygltf::Model& gltfModel);
void loadTextures(tinygltf::Model& gltfModel, VulkanBase::VulkanDevice* device, VkQueue transferQueue);
void loadTextureSamplers(tinygltf::Model& gltfModel);
void loadMaterials(tinygltf::Model& gltfModel);
void loadAnimations(tinygltf::Model& gltfModel);
void loadFromFile(std::string filename, VulkanBase::VulkanDevice* device, VkQueue transferQueue, float scale = 1.0f);
void 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 drawNode(glTFNode *node, VkCommandBuffer commandBuffer);
void draw(VkCommandBuffer commandBuffer);
void calculateBoundingBox(glTFNode* node, glTFNode* parent);
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);
glTFNode *findNode(glTFNode *parent, uint32_t index);
glTFNode *nodeFromIndex(uint32_t index);
private:
VulkanBase::VulkanDevice *m_device;
VulkanBase::VulkanDevice* m_device;
struct Vertices {
VkBuffer buffer = VK_NULL_HANDLE;
VkDeviceMemory memory;
} m_vertices;
struct Indices {
VkBuffer buffer = VK_NULL_HANDLE;
VkDeviceMemory memory;
} m_indices;
ModelBuffer m_vertices;
ModelBuffer m_indices;
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;
@ -71,14 +86,9 @@ private:
std::vector<glTFAnimation> m_animations;
std::vector<std::string> m_extensions;
struct Dimensions {
glm::vec3 min = glm::vec3(FLT_MAX);
glm::vec3 max = glm::vec3(-FLT_MAX);
} m_dimensions;
AABBDimensions m_dimensions;
};
GLTFLOADER_NAMESPACE_END
#endif // !GLTFMAINMODEL_h

View File

@ -1,6 +1,5 @@
#include "glTFMaterial.h"
GLTFLOADER_NAMESPACE_BEGIN
glTFMaterial::glTFMaterial()
@ -41,44 +40,53 @@ float glTFMaterial::getAlphaCutOff()
return m_alphaCutoff;
}
TextureCoordSet* glTFMaterial::getTextureCoordSet()
TextureCoordSet *glTFMaterial::getTextureCoordSet()
{
return m_texCoordSets;
}
void glTFMaterial::setTextureCoordSet(TextureCoordSet* value)
void glTFMaterial::setTextureCoordSet(TextureCoordSet *value)
{
m_texCoordSets = value;
}
PbrTextureExtension* glTFMaterial::getTextureExtension()
PBR::PbrTextureExtension *glTFMaterial::getTextureExtension()
{
return m_textureExtension;
}
void glTFMaterial::setPbrTextureExtension(PbrTextureExtension* value)
void glTFMaterial::setPbrTextureExtension(PBR::PbrTextureExtension *value)
{
m_textureExtension = value;
}
PbrBaseTexture* glTFMaterial::getPbrBaseTexture()
PBR::PbrBaseTexture *glTFMaterial::getPbrBaseTexture()
{
return m_pbrBaseTexture;
}
void glTFMaterial::setPbrBaseTexture(PbrBaseTexture* value)
void glTFMaterial::setPbrBaseTexture(PBR::PbrBaseTexture *value)
{
m_pbrBaseTexture = value;
}
PbrWorkFlow* glTFMaterial::getPbrWorkFlow()
PBR::PbrWorkFlow *glTFMaterial::getPbrWorkFlow()
{
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>
@ -29,38 +29,34 @@ public:
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;
PbrBaseTexture* m_pbrBaseTexture;
PBR::PbrBaseTexture *m_pbrBaseTexture;
bool m_doubleSided = false;
TextureCoordSet* m_texCoordSets;
PbrTextureExtension* m_textureExtension;
PbrWorkFlow* m_pbrWorkFlow;
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,13 +2,8 @@
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;
}
@ -47,5 +42,32 @@ unsigned int glTFPrimitive::getFirstIndex()
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,18 +3,17 @@
#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();
@ -27,20 +26,24 @@ public:
void setFirstIndex(unsigned int firstIndex);
unsigned int getFirstIndex();
private:
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;
glTFMaterial &m_material;
bool m_hasIndices;
glTFBoundingBox m_boundingBox;
};
GLTFLOADER_NAMESPACE_END
#endif // !GLTFPRIMITIVE_H

View File

@ -8,7 +8,6 @@
#include <tiny_gltf.h>
GLTFLOADER_NAMESPACE_BEGIN
/// @brief gltf模型的贴图
@ -22,11 +21,10 @@ public:
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;
VulkanBase::VulkanDevice *m_device;
VkImage m_image;
VkImageLayout m_imageLayout;
VkDeviceMemory m_deviceMemory;
@ -38,13 +36,6 @@ private:
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,12 +10,12 @@ PbrBaseTexture::~PbrBaseTexture()
{
}
void PbrBaseTexture::setBaseColorTexture(glTFTexture* value)
void PbrBaseTexture::setBaseColorTexture(glTFLoader::glTFTexture *value)
{
m_baseColorTexture = value;
}
glTFTexture* PbrBaseTexture::getBaseColorTexture()
glTFLoader::glTFTexture *PbrBaseTexture::getBaseColorTexture()
{
return m_baseColorTexture;
}
@ -30,22 +30,22 @@ glm::vec4 PbrBaseTexture::getBaseColorFactor()
return m_baseColorFactor;
}
void PbrBaseTexture::setNormalTexture(glTFTexture* value)
void PbrBaseTexture::setNormalTexture(glTFLoader::glTFTexture *value)
{
m_normalTexture = value;
}
glTFTexture* PbrBaseTexture::getNormalTexture()
glTFLoader::glTFTexture *PbrBaseTexture::getNormalTexture()
{
return m_normalTexture;
}
void PbrBaseTexture::setMetallicRoughnessTexture(glTFTexture* value)
void PbrBaseTexture::setMetallicRoughnessTexture(glTFLoader::glTFTexture *value)
{
m_metallicRoughnessTexture = value;
}
glTFTexture* PbrBaseTexture::getMetalicRoughnessTexture()
glTFLoader::glTFTexture *PbrBaseTexture::getMetalicRoughnessTexture()
{
return m_metallicRoughnessTexture;
}
@ -70,17 +70,16 @@ float PbrBaseTexture::getRoughnessFactor()
return m_roughnessFactor;
}
void PbrBaseTexture::setEmissiveTexture(glTFTexture* value)
void PbrBaseTexture::setEmissiveTexture(glTFLoader::glTFTexture *value)
{
m_emissiveTexture = value;
}
glTFTexture* PbrBaseTexture::getEmissiveTexture()
glTFLoader::glTFTexture *PbrBaseTexture::getEmissiveTexture()
{
return m_emissiveTexture;
}
void PbrBaseTexture::setEmissiveFactor(glm::vec4 value)
{
m_emissiveFactor = value;
@ -91,14 +90,14 @@ glm::vec4 PbrBaseTexture::getEmissiveFactor()
return m_emissiveFactor;
}
void PbrBaseTexture::setOcclusionTexture(glTFTexture* value)
void PbrBaseTexture::setOcclusionTexture(glTFLoader::glTFTexture *value)
{
m_occlusionTexture = value;
}
glTFTexture* PbrBaseTexture::getOcclusionTexture()
glTFLoader::glTFTexture *PbrBaseTexture::getOcclusionTexture()
{
return m_occlusionTexture;
}
GLTFLOADER_NAMESPACE_END
PBR_NAMESPACE_END

View File

@ -1,14 +1,13 @@
#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
@ -17,17 +16,17 @@ public:
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 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();
@ -35,35 +34,31 @@ public:
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 setOcclusionTexture(glTFTexture* value);
glTFTexture* getOcclusionTexture();
void setOcclusionTexture(glTFLoader::glTFTexture *value);
glTFLoader::glTFTexture *getOcclusionTexture();
private:
glTFTexture* m_baseColorTexture = nullptr;
glTFLoader::glTFTexture *m_baseColorTexture = nullptr;
glm::vec4 m_baseColorFactor = glm::vec4(1.0f);
glTFTexture* m_normalTexture = nullptr;
glTFLoader::glTFTexture *m_normalTexture = nullptr;
glTFTexture* m_metallicRoughnessTexture = nullptr;
glTFLoader::glTFTexture *m_metallicRoughnessTexture = nullptr;
float m_metallicFactor = 1.0f;
float m_roughnessFactor = 1.0f;
glTFTexture* m_emissiveTexture = nullptr;
glTFLoader::glTFTexture *m_emissiveTexture = nullptr;
glm::vec4 m_emissiveFactor = glm::vec4(1.0f);
glTFTexture* m_occlusionTexture = nullptr;
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,22 +10,22 @@ PbrTextureExtension::~PbrTextureExtension()
{
}
void PbrTextureExtension::setSpecularGlossinessTexture(glTFTexture* _texture)
void PbrTextureExtension::setSpecularGlossinessTexture(glTFLoader::glTFTexture *_texture)
{
m_specularGlossinessTexture = _texture;
}
glTFTexture* PbrTextureExtension::getSpecularGlossinessTexture()
glTFLoader::glTFTexture *PbrTextureExtension::getSpecularGlossinessTexture()
{
return m_specularGlossinessTexture;
}
void PbrTextureExtension::setDiffuseTexture(glTFTexture* _texture)
void PbrTextureExtension::setDiffuseTexture(glTFLoader::glTFTexture *_texture)
{
m_diffuseTexture = _texture;
}
glTFTexture* PbrTextureExtension::getDiffuseTexture()
glTFLoader::glTFTexture *PbrTextureExtension::getDiffuseTexture()
{
return m_diffuseTexture;
}
@ -50,6 +50,4 @@ glm::vec3 PbrTextureExtension::getSpecularFactor()
return m_specularFactor;
}
GLTFLOADER_NAMESPACE_END
PBR_NAMESPACE_END

View File

@ -1,14 +1,13 @@
#ifndef PBRTEXTUREEXTENSION_H
#define PBRTEXTUREEXTENSION_H
#include "glTFModel_Marco.h"
#include "PbrMarco.h"
#include "glTFTexture.h"
#include <glm/glm.hpp>
GLTFLOADER_NAMESPACE_BEGIN
PBR_NAMESPACE_BEGIN
class PbrTextureExtension
{
@ -16,11 +15,11 @@ public:
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();
@ -28,24 +27,13 @@ public:
void setSpecularFactor(glm::vec3 value);
glm::vec3 getSpecularFactor();
private:
glTFTexture* m_specularGlossinessTexture = nullptr;
glTFTexture* m_diffuseTexture = nullptr;
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,9 +1,9 @@
#ifndef PBRWORKFLOW_H
#define PBRWORKFLOW_H
#include "glTFModel_Marco.h"
#include "PbrMarco.h"
GLTFLOADER_NAMESPACE_BEGIN
PBR_NAMESPACE_BEGIN
class PbrWorkFlow
{
@ -18,16 +18,10 @@ public:
bool getSpecularGlossiness();
private:
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);
}
};