调整结构

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 AlignConsecutiveMacros: true
AlignTrailingComments: true AlignTrailingComments: true
AllowShortFunctionsOnASingleLine: Inline AllowShortFunctionsOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: false AllowShortIfStatementsOnASingleLine: true
AllowAllParametersOfDeclarationOnNextLine: true
BreakBeforeBraces: Allman BreakBeforeBraces: Allman
ColumnLimit: 0 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/glTFBoundingBox.cpp"
"gltf/glTFTexture.h" "gltf/glTFTexture.h"
"gltf/glTFTexture.cpp" "gltf/glTFTexture.cpp"
#"gltf/glTFModel.h"
#"gltf/glTFModel.cpp"
"gltf/glTFMaterial.h" "gltf/glTFMaterial.h"
"gltf/glTFMaterial.cpp" "gltf/glTFMaterial.cpp"
"gltf/glTFPrimitive.h" "gltf/glTFPrimitive.h"
@ -35,12 +33,12 @@ set(GLTF_MODEL_LOADER
"gltf/glTFAnimation.cpp" "gltf/glTFAnimation.cpp"
"gltf/glTFMainModel.h" "gltf/glTFMainModel.h"
"gltf/glTFMainModel.cpp" "gltf/glTFMainModel.cpp"
) )
aux_source_directory(${PROJECT_SOURCE_DIR}/src/render VULKAN_BASE) aux_source_directory(${PROJECT_SOURCE_DIR}/src/render VULKAN_BASE)
aux_source_directory(${PROJECT_SOURCE_DIR}/src/pbr PBR)
#include_directories(${3rdParty_gli_path}) #include_directories(${3rdParty_gli_path})
include_directories(${3rdParty_glm_path}) include_directories(${3rdParty_glm_path})
@ -65,6 +63,7 @@ if(WIN32)
${MAIN_FILE} ${MAIN_FILE}
${GLTF_MODEL_LOADER} ${GLTF_MODEL_LOADER}
${VULKAN_BASE} ${VULKAN_BASE}
${PBR}
"render/renderFoundation.h" "render/renderFoundation.h"
"render/renderFoundation.cpp" "render/renderFoundation.cpp"

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_path})
include_directories(${3rdParty_ktx_otherInclude_path}) include_directories(${3rdParty_ktx_otherInclude_path})
include_directories(${3rdParty_glm_path}) include_directories(${3rdParty_glm_path})
include_directories(${3rdParty_gli_path}) include_directories(${3rdParty_stb_path})
include_directories(${3rdParty_vulkan_path}) include_directories(${3rdParty_vulkan_path})
include_directories(${3rdParty_imgui_path}) include_directories(${3rdParty_imgui_path})
message("======================debug=====================")
message(${BASE_SRC})
add_library(base STATIC ${BASE_SRC} ${KTX_SOURCES}) add_library(base STATIC ${BASE_SRC} ${KTX_SOURCES})
if(WIN32) if(WIN32)

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 "VulkanBuffer.h"
#include "VulkanTools.h"
namespace vks VULKANBASE_NAMESPACE_BEGIN
{ /**
/**
* Map a memory range of this buffer. If successful, mapped points to the specified buffer range. * Map a memory range of this buffer. If successful, mapped points to the specified buffer range.
* *
* @param size (Optional) Size of the memory range to map. Pass VK_WHOLE_SIZE to map the complete buffer range. * @param size (Optional) Size of the memory range to map. Pass VK_WHOLE_SIZE to map the complete buffer range.
@ -20,65 +10,65 @@ namespace vks
* *
* @return VkResult of the buffer mapping call * @return VkResult of the buffer mapping call
*/ */
VkResult Buffer::map(VkDeviceSize size, VkDeviceSize offset) VkResult Buffer::map(VkDeviceSize size, VkDeviceSize offset)
{ {
return vkMapMemory(device, memory, offset, size, 0, &mapped); return vkMapMemory(device, memory, offset, size, 0, &mapped);
} }
/** /**
* Unmap a mapped memory range * Unmap a mapped memory range
* *
* @note Does not return a result as vkUnmapMemory can't fail * @note Does not return a result as vkUnmapMemory can't fail
*/ */
void Buffer::unmap() void Buffer::unmap()
{ {
if (mapped) if (mapped)
{ {
vkUnmapMemory(device, memory); vkUnmapMemory(device, memory);
mapped = nullptr; mapped = nullptr;
} }
} }
/** /**
* Attach the allocated memory block to the buffer * Attach the allocated memory block to the buffer
* *
* @param offset (Optional) Byte offset (from the beginning) for the memory region to bind * @param offset (Optional) Byte offset (from the beginning) for the memory region to bind
* *
* @return VkResult of the bindBufferMemory call * @return VkResult of the bindBufferMemory call
*/ */
VkResult Buffer::bind(VkDeviceSize offset) VkResult Buffer::bind(VkDeviceSize offset)
{ {
return vkBindBufferMemory(device, buffer, memory, offset); return vkBindBufferMemory(device, buffer, memory, offset);
} }
/** /**
* Setup the default descriptor for this buffer * Setup the default descriptor for this buffer
* *
* @param size (Optional) Size of the memory range of the descriptor * @param size (Optional) Size of the memory range of the descriptor
* @param offset (Optional) Byte offset from beginning * @param offset (Optional) Byte offset from beginning
* *
*/ */
void Buffer::setupDescriptor(VkDeviceSize size, VkDeviceSize offset) void Buffer::setupDescriptor(VkDeviceSize size, VkDeviceSize offset)
{ {
descriptor.offset = offset; descriptor.offset = offset;
descriptor.buffer = buffer; descriptor.buffer = buffer;
descriptor.range = size; descriptor.range = size;
} }
/** /**
* Copies the specified data to the mapped buffer * Copies the specified data to the mapped buffer
* *
* @param data Pointer to the data to copy * @param data Pointer to the data to copy
* @param size Size of the data to copy in machine units * @param size Size of the data to copy in machine units
* *
*/ */
void Buffer::copyTo(void* data, VkDeviceSize size) void Buffer::copyTo(void *data, VkDeviceSize size)
{ {
assert(mapped); assert(mapped);
memcpy(mapped, data, size); memcpy(mapped, data, size);
} }
/** /**
* Flush a memory range of the buffer to make it visible to the device * Flush a memory range of the buffer to make it visible to the device
* *
* @note Only required for non-coherent memory * @note Only required for non-coherent memory
@ -88,17 +78,17 @@ namespace vks
* *
* @return VkResult of the flush call * @return VkResult of the flush call
*/ */
VkResult Buffer::flush(VkDeviceSize size, VkDeviceSize offset) VkResult Buffer::flush(VkDeviceSize size, VkDeviceSize offset)
{ {
VkMappedMemoryRange mappedRange = {}; VkMappedMemoryRange mappedRange = {};
mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
mappedRange.memory = memory; mappedRange.memory = memory;
mappedRange.offset = offset; mappedRange.offset = offset;
mappedRange.size = size; mappedRange.size = size;
return vkFlushMappedMemoryRanges(device, 1, &mappedRange); return vkFlushMappedMemoryRanges(device, 1, &mappedRange);
} }
/** /**
* Invalidate a memory range of the buffer to make it visible to the host * Invalidate a memory range of the buffer to make it visible to the host
* *
* @note Only required for non-coherent memory * @note Only required for non-coherent memory
@ -108,28 +98,40 @@ namespace vks
* *
* @return VkResult of the invalidate call * @return VkResult of the invalidate call
*/ */
VkResult Buffer::invalidate(VkDeviceSize size, VkDeviceSize offset) VkResult Buffer::invalidate(VkDeviceSize size, VkDeviceSize offset)
{ {
VkMappedMemoryRange mappedRange = {}; VkMappedMemoryRange mappedRange = {};
mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
mappedRange.memory = memory; mappedRange.memory = memory;
mappedRange.offset = offset; mappedRange.offset = offset;
mappedRange.size = size; mappedRange.size = size;
return vkInvalidateMappedMemoryRanges(device, 1, &mappedRange); return vkInvalidateMappedMemoryRanges(device, 1, &mappedRange);
} }
/** /**
* Release all Vulkan resources held by this buffer * Release all Vulkan resources held by this buffer
*/ */
void Buffer::destroy() void Buffer::destroy()
{ {
if (buffer) if (mapped)
{ {
unmap();
}
vkDestroyBuffer(device, buffer, nullptr); vkDestroyBuffer(device, buffer, nullptr);
}
if (memory)
{
vkFreeMemory(device, memory, nullptr); vkFreeMemory(device, memory, nullptr);
buffer = VK_NULL_HANDLE;
memory = VK_NULL_HANDLE;
}
void Buffer::create(VulkanBase::VulkanDevice *device, VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkDeviceSize size, bool map)
{
VkDevice logicalDevice = device->getLogicalDevice();
device->createBuffer(usageFlags, memoryPropertyFlags, size, &buffer, &memory);
descriptor = {buffer, 0, size};
if (map)
{
VK_CHECK_RESULT(vkMapMemory(logicalDevice, memory, 0, size, 0, &mapped));
} }
} }
};
VULKANBASE_NAMESPACE_END

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 <vector>
#include "vulkan/vulkan.h" #include "VulkanBase_Marco.h"
#include "VulkanTools.h" #include "VulkanDevice.h"
#include <vulkan/vulkan.h>
namespace vks VULKANBASE_NAMESPACE_BEGIN
{ /**
/**
* @brief Encapsulates access to a Vulkan buffer backed up by device memory * @brief Encapsulates access to a Vulkan buffer backed up by device memory
* @note To be filled by an external source like the VulkanDevice * @note To be filled by an external source like the VulkanDevice
*/ */
struct Buffer struct Buffer
{ {
VkDevice device; VkDevice device;
VkBuffer buffer = VK_NULL_HANDLE; VkBuffer buffer = VK_NULL_HANDLE;
VkDeviceMemory memory = VK_NULL_HANDLE; VkDeviceMemory memory = VK_NULL_HANDLE;
VkDescriptorBufferInfo descriptor; VkDescriptorBufferInfo descriptor;
VkDeviceSize size = 0; VkDeviceSize size = 0;
VkDeviceSize alignment = 0; VkDeviceSize alignment = 0;
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) */ /** @brief Usage flags to be filled by external source at buffer creation (to query at some later point) */
VkBufferUsageFlags usageFlags; VkBufferUsageFlags usageFlags;
/** @brief Memory property flags to be filled by external source at buffer creation (to query at some later point) */ /** @brief Memory property flags to be filled by external source at buffer creation (to query at some later point) */
VkMemoryPropertyFlags memoryPropertyFlags; VkMemoryPropertyFlags memoryPropertyFlags;
void create(VulkanDevice *device, VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkDeviceSize size, bool map = true);
VkResult map(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0); VkResult map(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0);
void unmap(); void unmap();
VkResult bind(VkDeviceSize offset = 0); VkResult bind(VkDeviceSize offset = 0);
void setupDescriptor(VkDeviceSize size = VK_WHOLE_SIZE, 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 flush(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0);
VkResult invalidate(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0); VkResult invalidate(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0);
void destroy(); 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 * Vulkan texture loader
* *
* Copyright(C) by Sascha Willems - www.saschawillems.de * Copyright(C) by Sascha Willems - www.saschawillems.de
* *
* This code is licensed under the MIT license(MIT) (http://opensource.org/licenses/MIT) * This code is licensed under the MIT license(MIT) (http://opensource.org/licenses/MIT)
*/ */
#include "VulkanTexture.h" #include "VulkanTexture.h"
#include "vulkan/vulkan_core.h"
namespace vks namespace VulkanBase
{
void Texture::updateDescriptor()
{ {
void Texture::updateDescriptor()
{
descriptor.sampler = sampler; descriptor.sampler = sampler;
descriptor.imageView = view; descriptor.imageView = view;
descriptor.imageLayout = imageLayout; descriptor.imageLayout = imageLayout;
} }
void Texture::destroy() void Texture::destroy()
{ {
vkDestroyImageView(device->logicalDevice, view, nullptr); VkDevice logicalDevice = device->getLogicalDevice();
vkDestroyImage(device->logicalDevice, image, nullptr); vkDestroyImageView(logicalDevice, view, nullptr);
vkDestroyImage(logicalDevice, image, nullptr);
if (sampler) if (sampler)
{ {
vkDestroySampler(device->logicalDevice, sampler, nullptr); vkDestroySampler(logicalDevice, sampler, nullptr);
}
vkFreeMemory(device->logicalDevice, deviceMemory, 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; ktxResult result = KTX_SUCCESS;
#if defined(__ANDROID__) #if defined(__ANDROID__)
AAsset* asset = AAssetManager_open(androidApp->activity->assetManager, filename.c_str(), AASSET_MODE_STREAMING); AAsset *asset = AAssetManager_open(androidApp->activity->assetManager, filename.c_str(), AASSET_MODE_STREAMING);
if (!asset) { 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); 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); 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); result = ktxTexture_CreateFromMemory(textureData, size, KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT, target);
delete[] textureData; delete[] textureData;
#else #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); 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); result = ktxTexture_CreateFromNamedFile(filename.c_str(), KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT, target);
#endif #endif
return result; return result;
} }
/** /**
* Load a 2D texture including all mip levels * Load a 2D texture including all mip levels
* *
* @param filename File to load (supports .ktx) * @param filename File to load (supports .ktx)
@ -64,13 +68,14 @@ namespace vks
* @param (Optional) forceLinear Force linear tiling (not advised, defaults to false) * @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) void Texture2D::loadFromFile(std::string filename, VkFormat format, VulkanBase::VulkanDevice *device, VkQueue copyQueue, VkImageUsageFlags imageUsageFlags, VkImageLayout imageLayout, bool forceLinear)
{ {
ktxTexture* ktxTexture; ktxTexture *ktxTexture;
ktxResult result = loadKTXFile(filename, &ktxTexture); ktxResult result = loadKTXFile(filename, &ktxTexture);
assert(result == KTX_SUCCESS); assert(result == KTX_SUCCESS);
this->device = device; this->device = device;
VkDevice logicalDevice = device->getLogicalDevice();
width = ktxTexture->baseWidth; width = ktxTexture->baseWidth;
height = ktxTexture->baseHeight; height = ktxTexture->baseHeight;
mipLevels = ktxTexture->numLevels; mipLevels = ktxTexture->numLevels;
@ -80,7 +85,7 @@ namespace vks
// Get device properties for the requested texture format // Get device properties for the requested texture format
VkFormatProperties formatProperties; VkFormatProperties formatProperties;
vkGetPhysicalDeviceFormatProperties(device->physicalDevice, format, &formatProperties); vkGetPhysicalDeviceFormatProperties(device->getPhysicalDevice(), format, &formatProperties);
// Only use linear tiling if requested (and supported by the device) // Only use linear tiling if requested (and supported by the device)
// Support for linear tiling is mostly limited, so prefer to use // 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.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; 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) // Get memory requirements for the staging buffer (alignment, memory type bits)
vkGetBufferMemoryRequirements(device->logicalDevice, stagingBuffer, &memReqs); vkGetBufferMemoryRequirements(logicalDevice, stagingBuffer, &memReqs);
memAllocInfo.allocationSize = memReqs.size; memAllocInfo.allocationSize = memReqs.size;
// Get memory type index for a host visible buffer // 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); 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(vkAllocateMemory(logicalDevice, &memAllocInfo, nullptr, &stagingMemory));
VK_CHECK_RESULT(vkBindBufferMemory(device->logicalDevice, stagingBuffer, stagingMemory, 0)); VK_CHECK_RESULT(vkBindBufferMemory(logicalDevice, stagingBuffer, stagingMemory, 0));
// Copy texture data into staging buffer // Copy texture data into staging buffer
uint8_t *data; 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); memcpy(data, ktxTextureData, ktxTextureSize);
vkUnmapMemory(device->logicalDevice, stagingMemory); vkUnmapMemory(logicalDevice, stagingMemory);
// Setup buffer copy regions for each mip level // Setup buffer copy regions for each mip level
std::vector<VkBufferImageCopy> bufferCopyRegions; std::vector<VkBufferImageCopy> bufferCopyRegions;
@ -157,22 +162,22 @@ namespace vks
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageCreateInfo.extent = { width, height, 1 }; imageCreateInfo.extent = {width, height, 1};
imageCreateInfo.usage = imageUsageFlags; imageCreateInfo.usage = imageUsageFlags;
// Ensure that the TRANSFER_DST bit is set for staging // Ensure that the TRANSFER_DST bit is set for staging
if (!(imageCreateInfo.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) if (!(imageCreateInfo.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT))
{ {
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.allocationSize = memReqs.size;
memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VK_CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &deviceMemory)); VK_CHECK_RESULT(vkAllocateMemory(logicalDevice, &memAllocInfo, nullptr, &deviceMemory));
VK_CHECK_RESULT(vkBindImageMemory(device->logicalDevice, image, deviceMemory, 0)); VK_CHECK_RESULT(vkBindImageMemory(logicalDevice, image, deviceMemory, 0));
VkImageSubresourceRange subresourceRange = {}; VkImageSubresourceRange subresourceRange = {};
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
@ -196,8 +201,7 @@ namespace vks
image, image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
static_cast<uint32_t>(bufferCopyRegions.size()), static_cast<uint32_t>(bufferCopyRegions.size()),
bufferCopyRegions.data() bufferCopyRegions.data());
);
// Change texture image layout to shader read after all mip levels have been copied // Change texture image layout to shader read after all mip levels have been copied
this->imageLayout = imageLayout; this->imageLayout = imageLayout;
@ -211,8 +215,8 @@ namespace vks
device->flushCommandBuffer(copyCmd, copyQueue); device->flushCommandBuffer(copyCmd, copyQueue);
// Clean up staging resources // Clean up staging resources
vkFreeMemory(device->logicalDevice, stagingMemory, nullptr); vkFreeMemory(logicalDevice, stagingMemory, nullptr);
vkDestroyBuffer(device->logicalDevice, stagingBuffer, nullptr); vkDestroyBuffer(logicalDevice, stagingBuffer, nullptr);
} }
else else
{ {
@ -229,7 +233,7 @@ namespace vks
VkImageCreateInfo imageCreateInfo = vks::initializers::imageCreateInfo(); VkImageCreateInfo imageCreateInfo = vks::initializers::imageCreateInfo();
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
imageCreateInfo.format = format; imageCreateInfo.format = format;
imageCreateInfo.extent = { width, height, 1 }; imageCreateInfo.extent = {width, height, 1};
imageCreateInfo.mipLevels = 1; imageCreateInfo.mipLevels = 1;
imageCreateInfo.arrayLayers = 1; imageCreateInfo.arrayLayers = 1;
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
@ -239,11 +243,11 @@ namespace vks
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
// Load mip map level 0 to linear tiling image // 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 // Get memory requirements for this image
// like size and alignment // like size and alignment
vkGetImageMemoryRequirements(device->logicalDevice, mappableImage, &memReqs); vkGetImageMemoryRequirements(logicalDevice, mappableImage, &memReqs);
// Set memory allocation size to required memory size // Set memory allocation size to required memory size
memAllocInfo.allocationSize = memReqs.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); memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
// Allocate host memory // 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 // 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 // Get sub resource layout
// Mip map count, array layer, etc. // Mip map count, array layer, etc.
@ -267,15 +271,15 @@ namespace vks
// Get sub resources layout // Get sub resources layout
// Includes row pitch, size offsets, etc. // Includes row pitch, size offsets, etc.
vkGetImageSubresourceLayout(device->logicalDevice, mappableImage, &subRes, &subResLayout); vkGetImageSubresourceLayout(logicalDevice, mappableImage, &subRes, &subResLayout);
// Map image memory // 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 // Copy image data into memory
memcpy(data, ktxTextureData, memReqs.size); memcpy(data, ktxTextureData, memReqs.size);
vkUnmapMemory(device->logicalDevice, mappableMemory); vkUnmapMemory(logicalDevice, mappableMemory);
// Linear tiled images don't need to be staged // Linear tiled images don't need to be staged
// and can be directly used as textures // and can be directly used as textures
@ -306,10 +310,19 @@ namespace vks
// Max level-of-detail should match mip level count // Max level-of-detail should match mip level count
samplerCreateInfo.maxLod = (useStaging) ? (float)mipLevels : 0.0f; samplerCreateInfo.maxLod = (useStaging) ? (float)mipLevels : 0.0f;
// Only enable anisotropic filtering if enabled on the device // 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; 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 // Create image view
// Textures are not directly accessed by the shaders and // 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.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewCreateInfo.format = format; 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 // Linear tiling usually won't support mip maps
// Only set mip map count if optimal tiling is used // Only set mip map count if optimal tiling is used
viewCreateInfo.subresourceRange.levelCount = (useStaging) ? mipLevels : 1; viewCreateInfo.subresourceRange.levelCount = (useStaging) ? mipLevels : 1;
viewCreateInfo.image = image; 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 // Update descriptor image info member that can be used for setting up descriptor sets
updateDescriptor(); updateDescriptor();
} }
/** /**
* Creates a 2D texture from a buffer * Creates a 2D texture from a buffer
* *
* @param buffer Buffer containing texture data to upload * @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) 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) * @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); assert(buffer);
this->device = device; this->device = device;
@ -353,6 +366,8 @@ namespace vks
height = texHeight; height = texHeight;
mipLevels = 1; mipLevels = 1;
VkDevice logicalDevice = device->getLogicalDevice();
VkMemoryAllocateInfo memAllocInfo = vks::initializers::memoryAllocateInfo(); VkMemoryAllocateInfo memAllocInfo = vks::initializers::memoryAllocateInfo();
VkMemoryRequirements memReqs; VkMemoryRequirements memReqs;
@ -369,23 +384,23 @@ namespace vks
bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; 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) // Get memory requirements for the staging buffer (alignment, memory type bits)
vkGetBufferMemoryRequirements(device->logicalDevice, stagingBuffer, &memReqs); vkGetBufferMemoryRequirements(logicalDevice, stagingBuffer, &memReqs);
memAllocInfo.allocationSize = memReqs.size; memAllocInfo.allocationSize = memReqs.size;
// Get memory type index for a host visible buffer // 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); 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(vkAllocateMemory(logicalDevice, &memAllocInfo, nullptr, &stagingMemory));
VK_CHECK_RESULT(vkBindBufferMemory(device->logicalDevice, stagingBuffer, stagingMemory, 0)); VK_CHECK_RESULT(vkBindBufferMemory(logicalDevice, stagingBuffer, stagingMemory, 0));
// Copy texture data into staging buffer // Copy texture data into staging buffer
uint8_t *data; 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); memcpy(data, buffer, bufferSize);
vkUnmapMemory(device->logicalDevice, stagingMemory); vkUnmapMemory(logicalDevice, stagingMemory);
VkBufferImageCopy bufferCopyRegion = {}; VkBufferImageCopy bufferCopyRegion = {};
bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
@ -407,22 +422,22 @@ namespace vks
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageCreateInfo.extent = { width, height, 1 }; imageCreateInfo.extent = {width, height, 1};
imageCreateInfo.usage = imageUsageFlags; imageCreateInfo.usage = imageUsageFlags;
// Ensure that the TRANSFER_DST bit is set for staging // Ensure that the TRANSFER_DST bit is set for staging
if (!(imageCreateInfo.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) if (!(imageCreateInfo.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT))
{ {
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.allocationSize = memReqs.size;
memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VK_CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &deviceMemory)); VK_CHECK_RESULT(vkAllocateMemory(logicalDevice, &memAllocInfo, nullptr, &deviceMemory));
VK_CHECK_RESULT(vkBindImageMemory(device->logicalDevice, image, deviceMemory, 0)); VK_CHECK_RESULT(vkBindImageMemory(logicalDevice, image, deviceMemory, 0));
VkImageSubresourceRange subresourceRange = {}; VkImageSubresourceRange subresourceRange = {};
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
@ -446,8 +461,7 @@ namespace vks
image, image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1, 1,
&bufferCopyRegion &bufferCopyRegion);
);
// Change texture image layout to shader read after all mip levels have been copied // Change texture image layout to shader read after all mip levels have been copied
this->imageLayout = imageLayout; this->imageLayout = imageLayout;
@ -461,8 +475,8 @@ namespace vks
device->flushCommandBuffer(copyCmd, copyQueue); device->flushCommandBuffer(copyCmd, copyQueue);
// Clean up staging resources // Clean up staging resources
vkFreeMemory(device->logicalDevice, stagingMemory, nullptr); vkFreeMemory(logicalDevice, stagingMemory, nullptr);
vkDestroyBuffer(device->logicalDevice, stagingBuffer, nullptr); vkDestroyBuffer(logicalDevice, stagingBuffer, nullptr);
// Create sampler // Create sampler
VkSamplerCreateInfo samplerCreateInfo = {}; VkSamplerCreateInfo samplerCreateInfo = {};
@ -478,7 +492,7 @@ namespace vks
samplerCreateInfo.minLod = 0.0f; samplerCreateInfo.minLod = 0.0f;
samplerCreateInfo.maxLod = 0.0f; samplerCreateInfo.maxLod = 0.0f;
samplerCreateInfo.maxAnisotropy = 1.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 // Create image view
VkImageViewCreateInfo viewCreateInfo = {}; VkImageViewCreateInfo viewCreateInfo = {};
@ -486,16 +500,16 @@ namespace vks
viewCreateInfo.pNext = NULL; viewCreateInfo.pNext = NULL;
viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewCreateInfo.format = format; 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.subresourceRange.levelCount = 1;
viewCreateInfo.image = image; 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 // Update descriptor image info member that can be used for setting up descriptor sets
updateDescriptor(); updateDescriptor();
} }
/** /**
* Load a 2D texture array including all mip levels * Load a 2D texture array including all mip levels
* *
* @param filename File to load (supports .ktx) * @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) * @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) void Texture2DArray::loadFromFile(std::string filename, VkFormat format, VulkanBase::VulkanDevice *device, VkQueue copyQueue, VkImageUsageFlags imageUsageFlags, VkImageLayout imageLayout)
{ {
ktxTexture* ktxTexture; ktxTexture *ktxTexture;
ktxResult result = loadKTXFile(filename, &ktxTexture); ktxResult result = loadKTXFile(filename, &ktxTexture);
assert(result == KTX_SUCCESS); assert(result == KTX_SUCCESS);
@ -521,6 +535,8 @@ namespace vks
ktx_uint8_t *ktxTextureData = ktxTexture_GetData(ktxTexture); ktx_uint8_t *ktxTextureData = ktxTexture_GetData(ktxTexture);
ktx_size_t ktxTextureSize = ktxTexture_GetSize(ktxTexture); ktx_size_t ktxTextureSize = ktxTexture_GetSize(ktxTexture);
VkDevice logicalDevice = device->getLogicalDevice();
VkMemoryAllocateInfo memAllocInfo = vks::initializers::memoryAllocateInfo(); VkMemoryAllocateInfo memAllocInfo = vks::initializers::memoryAllocateInfo();
VkMemoryRequirements memReqs; VkMemoryRequirements memReqs;
@ -534,23 +550,23 @@ namespace vks
bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; 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) // Get memory requirements for the staging buffer (alignment, memory type bits)
vkGetBufferMemoryRequirements(device->logicalDevice, stagingBuffer, &memReqs); vkGetBufferMemoryRequirements(logicalDevice, stagingBuffer, &memReqs);
memAllocInfo.allocationSize = memReqs.size; memAllocInfo.allocationSize = memReqs.size;
// Get memory type index for a host visible buffer // 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); 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(vkAllocateMemory(logicalDevice, &memAllocInfo, nullptr, &stagingMemory));
VK_CHECK_RESULT(vkBindBufferMemory(device->logicalDevice, stagingBuffer, stagingMemory, 0)); VK_CHECK_RESULT(vkBindBufferMemory(logicalDevice, stagingBuffer, stagingMemory, 0));
// Copy texture data into staging buffer // Copy texture data into staging buffer
uint8_t *data; 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); memcpy(data, ktxTextureData, ktxTextureSize);
vkUnmapMemory(device->logicalDevice, stagingMemory); vkUnmapMemory(logicalDevice, stagingMemory);
// Setup buffer copy regions for each layer including all of its miplevels // Setup buffer copy regions for each layer including all of its miplevels
std::vector<VkBufferImageCopy> bufferCopyRegions; std::vector<VkBufferImageCopy> bufferCopyRegions;
@ -585,7 +601,7 @@ namespace vks
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageCreateInfo.extent = { width, height, 1 }; imageCreateInfo.extent = {width, height, 1};
imageCreateInfo.usage = imageUsageFlags; imageCreateInfo.usage = imageUsageFlags;
// Ensure that the TRANSFER_DST bit is set for staging // Ensure that the TRANSFER_DST bit is set for staging
if (!(imageCreateInfo.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) if (!(imageCreateInfo.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT))
@ -595,15 +611,15 @@ namespace vks
imageCreateInfo.arrayLayers = layerCount; imageCreateInfo.arrayLayers = layerCount;
imageCreateInfo.mipLevels = mipLevels; 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.allocationSize = memReqs.size;
memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VK_CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &deviceMemory)); VK_CHECK_RESULT(vkAllocateMemory(logicalDevice, &memAllocInfo, nullptr, &deviceMemory));
VK_CHECK_RESULT(vkBindImageMemory(device->logicalDevice, image, deviceMemory, 0)); VK_CHECK_RESULT(vkBindImageMemory(logicalDevice, image, deviceMemory, 0));
// Use a separate command buffer for texture loading // Use a separate command buffer for texture loading
VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
@ -652,34 +668,42 @@ namespace vks
samplerCreateInfo.addressModeV = samplerCreateInfo.addressModeU; samplerCreateInfo.addressModeV = samplerCreateInfo.addressModeU;
samplerCreateInfo.addressModeW = samplerCreateInfo.addressModeU; samplerCreateInfo.addressModeW = samplerCreateInfo.addressModeU;
samplerCreateInfo.mipLodBias = 0.0f; samplerCreateInfo.mipLodBias = 0.0f;
samplerCreateInfo.maxAnisotropy = device->enabledFeatures.samplerAnisotropy ? device->properties.limits.maxSamplerAnisotropy : 1.0f; if (device->getPhysicalDeviceFeatures().samplerAnisotropy)
samplerCreateInfo.anisotropyEnable = device->enabledFeatures.samplerAnisotropy; {
samplerCreateInfo.maxAnisotropy = device->getPhysicalDeviceProperties().limits.maxSamplerAnisotropy;
}
else
{
samplerCreateInfo.maxAnisotropy = 1.0;
}
samplerCreateInfo.anisotropyEnable = device->getPhysicalDeviceFeatures().samplerAnisotropy;
samplerCreateInfo.compareOp = VK_COMPARE_OP_NEVER; samplerCreateInfo.compareOp = VK_COMPARE_OP_NEVER;
samplerCreateInfo.minLod = 0.0f; samplerCreateInfo.minLod = 0.0f;
samplerCreateInfo.maxLod = (float)mipLevels; samplerCreateInfo.maxLod = (float)mipLevels;
samplerCreateInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; 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 // Create image view
VkImageViewCreateInfo viewCreateInfo = vks::initializers::imageViewCreateInfo(); VkImageViewCreateInfo viewCreateInfo = vks::initializers::imageViewCreateInfo();
viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
viewCreateInfo.format = format; 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.layerCount = layerCount;
viewCreateInfo.subresourceRange.levelCount = mipLevels; viewCreateInfo.subresourceRange.levelCount = mipLevels;
viewCreateInfo.image = image; viewCreateInfo.image = image;
VK_CHECK_RESULT(vkCreateImageView(device->logicalDevice, &viewCreateInfo, nullptr, &view)); VK_CHECK_RESULT(vkCreateImageView(logicalDevice, &viewCreateInfo, nullptr, &view));
// Clean up staging resources // Clean up staging resources
ktxTexture_Destroy(ktxTexture); ktxTexture_Destroy(ktxTexture);
vkFreeMemory(device->logicalDevice, stagingMemory, nullptr); vkFreeMemory(logicalDevice, stagingMemory, nullptr);
vkDestroyBuffer(device->logicalDevice, stagingBuffer, nullptr); vkDestroyBuffer(logicalDevice, stagingBuffer, nullptr);
// Update descriptor image info member that can be used for setting up descriptor sets // Update descriptor image info member that can be used for setting up descriptor sets
updateDescriptor(); updateDescriptor();
} }
/** /**
* Load a cubemap texture including all mip levels from a single file * Load a cubemap texture including all mip levels from a single file
* *
* @param filename File to load (supports .ktx) * @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) * @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) void TextureCubeMap::loadFromFile(std::string filename, VkFormat format, VulkanBase::VulkanDevice *device, VkQueue copyQueue, VkImageUsageFlags imageUsageFlags, VkImageLayout imageLayout)
{ {
ktxTexture* ktxTexture; ktxTexture *ktxTexture;
ktxResult result = loadKTXFile(filename, &ktxTexture); ktxResult result = loadKTXFile(filename, &ktxTexture);
assert(result == KTX_SUCCESS); assert(result == KTX_SUCCESS);
@ -704,6 +728,8 @@ namespace vks
ktx_uint8_t *ktxTextureData = ktxTexture_GetData(ktxTexture); ktx_uint8_t *ktxTextureData = ktxTexture_GetData(ktxTexture);
ktx_size_t ktxTextureSize = ktxTexture_GetSize(ktxTexture); ktx_size_t ktxTextureSize = ktxTexture_GetSize(ktxTexture);
VkDevice logicalDevice = device->getLogicalDevice();
VkMemoryAllocateInfo memAllocInfo = vks::initializers::memoryAllocateInfo(); VkMemoryAllocateInfo memAllocInfo = vks::initializers::memoryAllocateInfo();
VkMemoryRequirements memReqs; VkMemoryRequirements memReqs;
@ -717,23 +743,23 @@ namespace vks
bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; 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) // Get memory requirements for the staging buffer (alignment, memory type bits)
vkGetBufferMemoryRequirements(device->logicalDevice, stagingBuffer, &memReqs); vkGetBufferMemoryRequirements(logicalDevice, stagingBuffer, &memReqs);
memAllocInfo.allocationSize = memReqs.size; memAllocInfo.allocationSize = memReqs.size;
// Get memory type index for a host visible buffer // 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); 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(vkAllocateMemory(logicalDevice, &memAllocInfo, nullptr, &stagingMemory));
VK_CHECK_RESULT(vkBindBufferMemory(device->logicalDevice, stagingBuffer, stagingMemory, 0)); VK_CHECK_RESULT(vkBindBufferMemory(logicalDevice, stagingBuffer, stagingMemory, 0));
// Copy texture data into staging buffer // Copy texture data into staging buffer
uint8_t *data; 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); memcpy(data, ktxTextureData, ktxTextureSize);
vkUnmapMemory(device->logicalDevice, stagingMemory); vkUnmapMemory(logicalDevice, stagingMemory);
// Setup buffer copy regions for each face including all of its mip levels // Setup buffer copy regions for each face including all of its mip levels
std::vector<VkBufferImageCopy> bufferCopyRegions; std::vector<VkBufferImageCopy> bufferCopyRegions;
@ -769,7 +795,7 @@ namespace vks
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageCreateInfo.extent = { width, height, 1 }; imageCreateInfo.extent = {width, height, 1};
imageCreateInfo.usage = imageUsageFlags; imageCreateInfo.usage = imageUsageFlags;
// Ensure that the TRANSFER_DST bit is set for staging // Ensure that the TRANSFER_DST bit is set for staging
if (!(imageCreateInfo.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) if (!(imageCreateInfo.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT))
@ -781,16 +807,15 @@ namespace vks
// This flag is required for cube map images // This flag is required for cube map images
imageCreateInfo.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; 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(logicalDevice, image, &memReqs);
vkGetImageMemoryRequirements(device->logicalDevice, image, &memReqs);
memAllocInfo.allocationSize = memReqs.size; memAllocInfo.allocationSize = memReqs.size;
memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VK_CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &deviceMemory)); VK_CHECK_RESULT(vkAllocateMemory(logicalDevice, &memAllocInfo, nullptr, &deviceMemory));
VK_CHECK_RESULT(vkBindImageMemory(device->logicalDevice, image, deviceMemory, 0)); VK_CHECK_RESULT(vkBindImageMemory(logicalDevice, image, deviceMemory, 0));
// Use a separate command buffer for texture loading // Use a separate command buffer for texture loading
VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
@ -839,31 +864,39 @@ namespace vks
samplerCreateInfo.addressModeV = samplerCreateInfo.addressModeU; samplerCreateInfo.addressModeV = samplerCreateInfo.addressModeU;
samplerCreateInfo.addressModeW = samplerCreateInfo.addressModeU; samplerCreateInfo.addressModeW = samplerCreateInfo.addressModeU;
samplerCreateInfo.mipLodBias = 0.0f; samplerCreateInfo.mipLodBias = 0.0f;
samplerCreateInfo.maxAnisotropy = device->enabledFeatures.samplerAnisotropy ? device->properties.limits.maxSamplerAnisotropy : 1.0f; if (device->getPhysicalDeviceFeatures().samplerAnisotropy)
samplerCreateInfo.anisotropyEnable = device->enabledFeatures.samplerAnisotropy; {
samplerCreateInfo.maxAnisotropy = device->getPhysicalDeviceProperties().limits.maxSamplerAnisotropy;
}
else
{
samplerCreateInfo.maxAnisotropy = 1.0;
}
samplerCreateInfo.anisotropyEnable = device->getPhysicalDeviceFeatures().samplerAnisotropy;
samplerCreateInfo.compareOp = VK_COMPARE_OP_NEVER; samplerCreateInfo.compareOp = VK_COMPARE_OP_NEVER;
samplerCreateInfo.minLod = 0.0f; samplerCreateInfo.minLod = 0.0f;
samplerCreateInfo.maxLod = (float)mipLevels; samplerCreateInfo.maxLod = (float)mipLevels;
samplerCreateInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; 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 // Create image view
VkImageViewCreateInfo viewCreateInfo = vks::initializers::imageViewCreateInfo(); VkImageViewCreateInfo viewCreateInfo = vks::initializers::imageViewCreateInfo();
viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_CUBE; viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_CUBE;
viewCreateInfo.format = format; 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.layerCount = 6;
viewCreateInfo.subresourceRange.levelCount = mipLevels; viewCreateInfo.subresourceRange.levelCount = mipLevels;
viewCreateInfo.image = image; viewCreateInfo.image = image;
VK_CHECK_RESULT(vkCreateImageView(device->logicalDevice, &viewCreateInfo, nullptr, &view)); VK_CHECK_RESULT(vkCreateImageView(logicalDevice, &viewCreateInfo, nullptr, &view));
// Clean up staging resources // Clean up staging resources
ktxTexture_Destroy(ktxTexture); ktxTexture_Destroy(ktxTexture);
vkFreeMemory(device->logicalDevice, stagingMemory, nullptr); vkFreeMemory(logicalDevice, stagingMemory, nullptr);
vkDestroyBuffer(device->logicalDevice, stagingBuffer, nullptr); vkDestroyBuffer(logicalDevice, stagingBuffer, nullptr);
// Update descriptor image info member that can be used for setting up descriptor sets // Update descriptor image info member that can be used for setting up descriptor sets
updateDescriptor(); updateDescriptor();
}
} }
} // namespace VulkanBase

View File

@ -1,37 +1,27 @@
/* #ifndef VULKANTEXTURE_H
* Vulkan texture loader #define VULKANTEXTURE_H
*
* Copyright(C) by Sascha Willems - www.saschawillems.de
*
* This code is licensed under the MIT license(MIT) (http://opensource.org/licenses/MIT)
*/
#pragma once #include "VulkanBase_Marco.h"
#include "VulkanBuffer.h"
#include "VulkanDevice.h"
#include "VulkanTools.h"
#include <ktx.h>
#include <ktxvulkan.h>
#include <vulkan/vulkan.h>
#include <fstream> #include <fstream>
#include <stdlib.h> #include <stdlib.h>
#include <string> #include <string>
#include <vector> #include <vector>
#include "vulkan/vulkan.h" VULKANBASE_NAMESPACE_BEGIN
#include <ktx.h>
#include <ktxvulkan.h>
#include "VulkanBuffer.h"
#include "VulkanDevice.hpp"
//#include "VulkanTools.h"
#if defined(__ANDROID__)
# include <android/asset_manager.h>
#endif
namespace vks
{
class Texture class Texture
{ {
public: public:
vks::VulkanDevice * device; VulkanBase::VulkanDevice *device;
VkImage image; VkImage image;
VkImageLayout imageLayout; VkImageLayout imageLayout;
VkDeviceMemory deviceMemory; VkDeviceMemory deviceMemory;
@ -49,22 +39,22 @@ class Texture
class Texture2D : public Texture class Texture2D : public Texture
{ {
public: public:
void loadFromFile( void loadFromFile(
std::string filename, std::string filename,
VkFormat format, VkFormat format,
vks::VulkanDevice *device, VulkanBase::VulkanDevice *device,
VkQueue copyQueue, VkQueue copyQueue,
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT, VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
bool forceLinear = false); bool forceLinear = false);
void fromBuffer( void loadFromBuffer(
void * buffer, void *buffer,
VkDeviceSize bufferSize, VkDeviceSize bufferSize,
VkFormat format, VkFormat format,
uint32_t texWidth, uint32_t texWidth,
uint32_t texHeight, uint32_t texHeight,
vks::VulkanDevice *device, VulkanBase::VulkanDevice *device,
VkQueue copyQueue, VkQueue copyQueue,
VkFilter filter = VK_FILTER_LINEAR, VkFilter filter = VK_FILTER_LINEAR,
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT, VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
@ -73,11 +63,11 @@ class Texture2D : public Texture
class Texture2DArray : public Texture class Texture2DArray : public Texture
{ {
public: public:
void loadFromFile( void loadFromFile(
std::string filename, std::string filename,
VkFormat format, VkFormat format,
vks::VulkanDevice *device, VulkanBase::VulkanDevice *device,
VkQueue copyQueue, VkQueue copyQueue,
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT, VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
@ -85,13 +75,16 @@ class Texture2DArray : public Texture
class TextureCubeMap : public Texture class TextureCubeMap : public Texture
{ {
public: public:
void loadFromFile( void loadFromFile(
std::string filename, std::string filename,
VkFormat format, VkFormat format,
vks::VulkanDevice *device, VulkanBase::VulkanDevice *device,
VkQueue copyQueue, VkQueue copyQueue,
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT, VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}; };
} // namespace vks
VULKANBASE_NAMESPACE_END
#endif

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

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 * Vulkan Example base class
* *
* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de * Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
* *
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) * This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
*/ */
#pragma once #pragma once
#ifdef _WIN32 #ifdef _WIN32
#pragma comment(linker, "/subsystem:windows") #pragma comment(linker, "/subsystem:windows")
#include <windows.h>
#include <fcntl.h> #include <fcntl.h>
#include <io.h> #include <io.h>
#include <windows.h>
#elif defined(VK_USE_PLATFORM_ANDROID_KHR) #elif defined(VK_USE_PLATFORM_ANDROID_KHR)
#include <android/native_activity.h> #include "VulkanAndroid.h"
#include <android/asset_manager.h> #include <android/asset_manager.h>
#include <android/native_activity.h>
#include <android_native_app_glue.h> #include <android_native_app_glue.h>
#include <sys/system_properties.h> #include <sys/system_properties.h>
#include "VulkanAndroid.h"
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
#include <wayland-client.h> #include <wayland-client.h>
#elif defined(_DIRECT2DISPLAY) #elif defined(_DIRECT2DISPLAY)
@ -26,24 +28,25 @@
#elif defined(VK_USE_PLATFORM_XCB_KHR) #elif defined(VK_USE_PLATFORM_XCB_KHR)
#include <xcb/xcb.h> #include <xcb/xcb.h>
#elif defined(VK_USE_PLATFORM_MACOS_MVK) #elif defined(VK_USE_PLATFORM_MACOS_MVK)
#include <Cocoa/Cocoa.h>
#include <Carbon/Carbon.h> #include <Carbon/Carbon.h>
#include <QuartzCore/CAMetalLayer.h> #include <Cocoa/Cocoa.h>
#include <CoreVideo/CVDisplayLink.h> #include <CoreVideo/CVDisplayLink.h>
#include <QuartzCore/CAMetalLayer.h>
#endif #endif
#include <iostream>
#include <chrono> #include <chrono>
#include <iostream>
#include <sys/stat.h> #include <sys/stat.h>
#define GLM_FORCE_RADIANS #define GLM_FORCE_RADIANS
#define GLM_FORCE_DEPTH_ZERO_TO_ONE #define GLM_FORCE_DEPTH_ZERO_TO_ONE
#define GLM_ENABLE_EXPERIMENTAL #define GLM_ENABLE_EXPERIMENTAL
#include <glm/glm.hpp>
#include <string>
#include <sstream>
#include <array> #include <array>
#include <glm/glm.hpp>
#include <numeric> #include <numeric>
#include <sstream>
#include <string>
#include "vulkan/vulkan.h" #include "vulkan/vulkan.h"
@ -51,7 +54,7 @@
#include "camera.hpp" #include "camera.hpp"
#include "keycodes.hpp" #include "keycodes.hpp"
#include "VulkanDevice.hpp" #include "VulkanDevice.h"
#include "VulkanSwapChain.hpp" #include "VulkanSwapChain.hpp"
#include "imgui.h" #include "imgui.h"
@ -68,18 +71,22 @@ private:
PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallback; PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallback;
PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallback; PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallback;
VkDebugReportCallbackEXT debugReportCallback; VkDebugReportCallbackEXT debugReportCallback;
struct MultisampleTarget { struct MultisampleTarget
struct { {
struct
{
VkImage image; VkImage image;
VkImageView view; VkImageView view;
VkDeviceMemory memory; VkDeviceMemory memory;
} color; } color;
struct { struct
{
VkImage image; VkImage image;
VkImageView view; VkImageView view;
VkDeviceMemory memory; VkDeviceMemory memory;
} depth; } depth;
} multisampleTarget; } multisampleTarget;
protected: protected:
VkInstance instance; VkInstance instance;
VkPhysicalDevice physicalDevice; VkPhysicalDevice physicalDevice;
@ -87,12 +94,12 @@ protected:
VkPhysicalDeviceFeatures deviceFeatures; VkPhysicalDeviceFeatures deviceFeatures;
VkPhysicalDeviceMemoryProperties deviceMemoryProperties; VkPhysicalDeviceMemoryProperties deviceMemoryProperties;
VkDevice device; VkDevice device;
vks::VulkanDevice *vulkanDevice; VulkanBase::VulkanDevice *vulkanDevice;
VkQueue queue; VkQueue queue;
VkFormat depthFormat; VkFormat depthFormat;
VkCommandPool cmdPool; VkCommandPool cmdPool;
VkRenderPass renderPass; VkRenderPass renderPass;
std::vector<VkFramebuffer>frameBuffers; std::vector<VkFramebuffer> frameBuffers;
uint32_t currentBuffer = 0; uint32_t currentBuffer = 0;
VkDescriptorPool descriptorPool; VkDescriptorPool descriptorPool;
VkPipelineCache pipelineCache; VkPipelineCache pipelineCache;
@ -100,8 +107,9 @@ protected:
std::string title = "Vulkan Example"; std::string title = "Vulkan Example";
std::string name = "vulkanExample"; std::string name = "vulkanExample";
void windowResize(); void windowResize();
public: public:
static std::vector<const char*> args; static std::vector<const char *> args;
uint32_t selectedPhysicalDeviceIndex = 0; uint32_t selectedPhysicalDeviceIndex = 0;
bool prepared = false; bool prepared = false;
uint32_t width = 1280; uint32_t width = 1280;
@ -112,7 +120,8 @@ public:
bool paused = false; bool paused = false;
uint32_t lastFPS = 0; uint32_t lastFPS = 0;
struct Settings { struct Settings
{
bool validation = false; // 校验层开关 bool validation = false; // 校验层开关
bool fullscreen = false; // 全屏开关 bool fullscreen = false; // 全屏开关
bool vsync = false; // 垂直同步开关 bool vsync = false; // 垂直同步开关
@ -130,18 +139,21 @@ public:
VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_4_BIT; // 多重采样倍率 VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_4_BIT; // 多重采样倍率
} settings; } settings;
struct DepthStencil { struct DepthStencil
{
VkImage image; VkImage image;
VkDeviceMemory mem; VkDeviceMemory mem;
VkImageView view; VkImageView view;
} depthStencil; } depthStencil;
struct GamePadState { struct GamePadState
{
glm::vec2 axisLeft = glm::vec2(0.0f); glm::vec2 axisLeft = glm::vec2(0.0f);
glm::vec2 axisRight = glm::vec2(0.0f); glm::vec2 axisRight = glm::vec2(0.0f);
} gamePadState; } gamePadState;
struct MouseButtons { struct MouseButtons
{
bool left = false; bool left = false;
bool right = false; bool right = false;
bool middle = false; bool middle = false;
@ -155,7 +167,8 @@ public:
// true if application has focused, false if moved to background // true if application has focused, false if moved to background
bool focused = false; bool focused = false;
std::string androidProduct; std::string androidProduct;
struct TouchPoint { struct TouchPoint
{
int32_t id; int32_t id;
float x; float x;
float y; float y;
@ -184,15 +197,15 @@ public:
xcb_window_t window; xcb_window_t window;
xcb_intern_atom_reply_t *atom_wm_delete_window; xcb_intern_atom_reply_t *atom_wm_delete_window;
#elif defined(VK_USE_PLATFORM_MACOS_MVK) #elif defined(VK_USE_PLATFORM_MACOS_MVK)
NSWindow* window; NSWindow *window;
#endif #endif
#if defined(_WIN32) #if defined(_WIN32)
HWND setupWindow(HINSTANCE hinstance, WNDPROC wndproc); HWND setupWindow(HINSTANCE hinstance, WNDPROC wndproc);
void handleMessages(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); void handleMessages(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
#elif defined(VK_USE_PLATFORM_ANDROID_KHR) #elif defined(VK_USE_PLATFORM_ANDROID_KHR)
static int32_t handleAppInput(struct android_app* app, AInputEvent* event); static int32_t handleAppInput(struct android_app *app, AInputEvent *event);
static void handleAppCommand(android_app* app, int32_t cmd); static void handleAppCommand(android_app *app, int32_t cmd);
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
wl_shell_surface *setupWindow(); wl_shell_surface *setupWindow();
void initWaylandConnection(); void initWaylandConnection();
@ -242,7 +255,7 @@ public:
void initxcbConnection(); void initxcbConnection();
void handleEvent(const xcb_generic_event_t *event); void handleEvent(const xcb_generic_event_t *event);
#elif defined(VK_USE_PLATFORM_MACOS_MVK) #elif defined(VK_USE_PLATFORM_MACOS_MVK)
NSWindow* setupWindow(); NSWindow *setupWindow();
void mouseDragged(float x, float y); void mouseDragged(float x, float y);
void windowWillResize(float x, float y); void windowWillResize(float x, float y);
void windowDidResize(); void windowDidResize();

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,21 @@
#ifndef GLTFMAINMODEL_H #ifndef GLTFMAINMODEL_H
#define GLTFMAINMODEL_H #define GLTFMAINMODEL_H
#ifndef TINYGLTF_NO_STB_IMAGE_WRITE
#define TINYGLTF_NO_STB_IMAGE_WRITE
#endif
#include "glTFModel_Marco.h" #include "glTFModel_Marco.h"
#include "glTFModel_common.h" #include "glTFModel_common.h"
#include "VulkanDevice.h" #include "VulkanDevice.h"
#include "glTFAnimation.h"
#include "glTFNode.h" #include "glTFNode.h"
#include "glTFSkin.h" #include "glTFSkin.h"
#include "glTFTexture.h" #include "glTFTexture.h"
#include "glTFAnimation.h"
#include <tiny_gltf.h>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <string> #include <string>
@ -17,6 +23,18 @@
GLTFLOADER_NAMESPACE_BEGIN GLTFLOADER_NAMESPACE_BEGIN
struct ModelBuffer
{
VkBuffer buffer = VK_NULL_HANDLE;
VkDeviceMemory memory;
};
struct AABBDimensions
{
glm::vec3 min = glm::vec3(FLT_MAX);
glm::vec3 max = glm::vec3(-FLT_MAX);
};
class glTFMainModel class glTFMainModel
{ {
public: public:
@ -25,45 +43,42 @@ public:
VkSamplerAddressMode getVkWrapMode(int32_t wrapMode); VkSamplerAddressMode getVkWrapMode(int32_t wrapMode);
VkFilter getVkFilterMode(int32_t filterMode); VkFilter getVkFilterMode(int32_t filterMode);
void getNodeProperty(const tinygltf::Node& node, const tinygltf::Model& model, size_t& vertexCount, size_t& indexCount); void getNodeProperty(const tinygltf::Node &node, const tinygltf::Model &model, size_t &vertexCount, size_t &indexCount);
void getSceneDimensions(); void getSceneDimensions();
ModelBuffer &getModelVertex();
ModelBuffer &getModelIndex();
void destroy(VkDevice device); void destroy(VkDevice device);
void loadNode(glTFNode* parent, const tinygltf::Node& node, uint32_t nodeIndex, const tinygltf::Model& model, LoaderInfo& loaderInfo, float globalscale); 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 loadSkins(tinygltf::Model &gltfModel);
void loadTextures(tinygltf::Model& gltfModel, VulkanBase::VulkanDevice* device, VkQueue transferQueue); void loadTextures(tinygltf::Model &gltfModel, VulkanBase::VulkanDevice *device, VkQueue transferQueue);
void loadTextureSamplers(tinygltf::Model& gltfModel); void loadTextureSamplers(tinygltf::Model &gltfModel);
void loadMaterials(tinygltf::Model& gltfModel); void loadMaterials(tinygltf::Model &gltfModel);
void loadAnimations(tinygltf::Model& gltfModel); void loadAnimations(tinygltf::Model &gltfModel);
void loadFromFile(std::string filename, VulkanBase::VulkanDevice* device, VkQueue transferQueue, float scale = 1.0f); 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 draw(VkCommandBuffer commandBuffer);
void calculateBoundingBox(glTFNode* node, glTFNode* parent); void calculateBoundingBox(glTFNode *node, glTFNode *parent);
void updateAnimation(uint32_t index, float time); void updateAnimation(uint32_t index, float time);
glTFNode* findNode(glTFNode* parent, uint32_t index); glTFNode *findNode(glTFNode *parent, uint32_t index);
glTFNode* nodeFromIndex(uint32_t index); glTFNode *nodeFromIndex(uint32_t index);
private: private:
VulkanBase::VulkanDevice *m_device;
VulkanBase::VulkanDevice* m_device; ModelBuffer m_vertices;
ModelBuffer m_indices;
struct Vertices {
VkBuffer buffer = VK_NULL_HANDLE;
VkDeviceMemory memory;
} m_vertices;
struct Indices {
VkBuffer buffer = VK_NULL_HANDLE;
VkDeviceMemory memory;
} m_indices;
glm::mat4 m_aabb; glm::mat4 m_aabb;
std::vector<glTFNode*> m_nodes; std::vector<glTFNode *> m_nodes;
std::vector<glTFNode*> m_linearNodes; std::vector<glTFNode *> m_linearNodes;
std::vector<glTFSkin*> m_skins; std::vector<glTFSkin *> m_skins;
std::vector<glTFTexture> m_textures; std::vector<glTFTexture> m_textures;
std::vector<VulkanBase::VulkanTextureSampler> m_textureSamplers; std::vector<VulkanBase::VulkanTextureSampler> m_textureSamplers;
@ -71,14 +86,9 @@ private:
std::vector<glTFAnimation> m_animations; std::vector<glTFAnimation> m_animations;
std::vector<std::string> m_extensions; std::vector<std::string> m_extensions;
struct Dimensions { AABBDimensions m_dimensions;
glm::vec3 min = glm::vec3(FLT_MAX);
glm::vec3 max = glm::vec3(-FLT_MAX);
} m_dimensions;
}; };
GLTFLOADER_NAMESPACE_END GLTFLOADER_NAMESPACE_END
#endif // !GLTFMAINMODEL_h #endif // !GLTFMAINMODEL_h

View File

@ -1,6 +1,5 @@
#include "glTFMaterial.h" #include "glTFMaterial.h"
GLTFLOADER_NAMESPACE_BEGIN GLTFLOADER_NAMESPACE_BEGIN
glTFMaterial::glTFMaterial() glTFMaterial::glTFMaterial()
@ -41,44 +40,53 @@ float glTFMaterial::getAlphaCutOff()
return m_alphaCutoff; return m_alphaCutoff;
} }
TextureCoordSet* glTFMaterial::getTextureCoordSet() TextureCoordSet *glTFMaterial::getTextureCoordSet()
{ {
return m_texCoordSets; return m_texCoordSets;
} }
void glTFMaterial::setTextureCoordSet(TextureCoordSet* value) void glTFMaterial::setTextureCoordSet(TextureCoordSet *value)
{ {
m_texCoordSets = value; m_texCoordSets = value;
} }
PbrTextureExtension* glTFMaterial::getTextureExtension() PBR::PbrTextureExtension *glTFMaterial::getTextureExtension()
{ {
return m_textureExtension; return m_textureExtension;
} }
void glTFMaterial::setPbrTextureExtension(PbrTextureExtension* value) void glTFMaterial::setPbrTextureExtension(PBR::PbrTextureExtension *value)
{ {
m_textureExtension = value; m_textureExtension = value;
} }
PbrBaseTexture* glTFMaterial::getPbrBaseTexture() PBR::PbrBaseTexture *glTFMaterial::getPbrBaseTexture()
{ {
return m_pbrBaseTexture; return m_pbrBaseTexture;
} }
void glTFMaterial::setPbrBaseTexture(PbrBaseTexture* value) void glTFMaterial::setPbrBaseTexture(PBR::PbrBaseTexture *value)
{ {
m_pbrBaseTexture = value; m_pbrBaseTexture = value;
} }
PbrWorkFlow* glTFMaterial::getPbrWorkFlow() PBR::PbrWorkFlow *glTFMaterial::getPbrWorkFlow()
{ {
return m_pbrWorkFlow; return m_pbrWorkFlow;
} }
void glTFMaterial::setPbrWorkFlow() void glTFMaterial::setPbrWorkFlow(PBR::PbrWorkFlow *value)
{ {
m_pbrWorkFlow; m_pbrWorkFlow = value;
}
void glTFMaterial::setDescriptorSet(VkDescriptorSet value)
{
m_descriptorSet = value;
}
VkDescriptorSet glTFMaterial::getDescriptorSet()
{
return m_descriptorSet;
} }
GLTFLOADER_NAMESPACE_END GLTFLOADER_NAMESPACE_END

View File

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

View File

@ -32,9 +32,9 @@
#include "tiny_gltf.h" #include "tiny_gltf.h"
#include "VulkanDevice.hpp" #include "VulkanDevice.h"
//#include "VulkanUtils.hpp" //#include "VulkanUtils.hpp"
#include "vulkan/vulkan.h"
#define ENABLE_VALIDATION false #define ENABLE_VALIDATION false
#define MAX_NUM_JOINTS 128u #define MAX_NUM_JOINTS 128u
@ -64,7 +64,7 @@ namespace glTFModel
}; };
struct Texture { struct Texture {
vks::VulkanDevice* device; VulkanBase::VulkanDevice* device;
VkImage image; VkImage image;
VkImageLayout imageLayout; VkImageLayout imageLayout;
VkDeviceMemory deviceMemory; VkDeviceMemory deviceMemory;
@ -77,7 +77,7 @@ namespace glTFModel
void updateDescriptor(); void updateDescriptor();
void destroy(); void destroy();
// Load a texture from a glTF image (stored as vector of chars loaded via stb_image) and generate a full mip chaing for it // Load a texture from a glTF image (stored as vector of chars loaded via stb_image) and generate a full mip chaing for it
void fromglTfImage(tinygltf::Image& gltfimage, glTFModel::TextureSampler textureSampler, vks::VulkanDevice* device, VkQueue copyQueue); void fromglTfImage(tinygltf::Image& gltfimage, glTFModel::TextureSampler textureSampler, VulkanBase::VulkanDevice* device, VkQueue copyQueue);
}; };
struct Material { struct Material {
@ -127,7 +127,7 @@ namespace glTFModel
}; };
struct Mesh { struct Mesh {
vks::VulkanDevice* device; VulkanBase::VulkanDevice* device;
std::vector<Primitive*> primitives; std::vector<Primitive*> primitives;
BoundingBox bb; BoundingBox bb;
BoundingBox aabb; BoundingBox aabb;
@ -143,7 +143,7 @@ namespace glTFModel
glm::mat4 jointMatrix[128]{}; glm::mat4 jointMatrix[128]{};
float jointcount{ 0 }; float jointcount{ 0 };
} uniformBlock; } uniformBlock;
Mesh(vks::VulkanDevice* device, glm::mat4 matrix); Mesh(VulkanBase::VulkanDevice* device, glm::mat4 matrix);
~Mesh(); ~Mesh();
void setBoundingBox(glm::vec3 min, glm::vec3 max); void setBoundingBox(glm::vec3 min, glm::vec3 max);
}; };
@ -199,7 +199,7 @@ namespace glTFModel
struct Model { struct Model {
vks::VulkanDevice* device; VulkanBase::VulkanDevice* device;
struct Vertex { struct Vertex {
glm::vec3 pos; glm::vec3 pos;
@ -249,13 +249,13 @@ namespace glTFModel
void loadNode(glTFModel::Node* parent, const tinygltf::Node& node, uint32_t nodeIndex, const tinygltf::Model& model, LoaderInfo& loaderInfo, float globalscale); void loadNode(glTFModel::Node* parent, const tinygltf::Node& node, uint32_t nodeIndex, const tinygltf::Model& model, LoaderInfo& loaderInfo, float globalscale);
void getNodeProps(const tinygltf::Node& node, const tinygltf::Model& model, size_t& vertexCount, size_t& indexCount); void getNodeProps(const tinygltf::Node& node, const tinygltf::Model& model, size_t& vertexCount, size_t& indexCount);
void loadSkins(tinygltf::Model& gltfModel); void loadSkins(tinygltf::Model& gltfModel);
void loadTextures(tinygltf::Model& gltfModel, vks::VulkanDevice* device, VkQueue transferQueue); void loadTextures(tinygltf::Model& gltfModel, VulkanBase::VulkanDevice* device, VkQueue transferQueue);
VkSamplerAddressMode getVkWrapMode(int32_t wrapMode); VkSamplerAddressMode getVkWrapMode(int32_t wrapMode);
VkFilter getVkFilterMode(int32_t filterMode); VkFilter getVkFilterMode(int32_t filterMode);
void loadTextureSamplers(tinygltf::Model& gltfModel); void loadTextureSamplers(tinygltf::Model& gltfModel);
void loadMaterials(tinygltf::Model& gltfModel); void loadMaterials(tinygltf::Model& gltfModel);
void loadAnimations(tinygltf::Model& gltfModel); void loadAnimations(tinygltf::Model& gltfModel);
void loadFromFile(std::string filename, vks::VulkanDevice* device, VkQueue transferQueue, float scale = 1.0f); void loadFromFile(std::string filename, VulkanBase::VulkanDevice* device, VkQueue transferQueue, float scale = 1.0f);
void drawNode(Node* node, VkCommandBuffer commandBuffer); void drawNode(Node* node, VkCommandBuffer commandBuffer);
void draw(VkCommandBuffer commandBuffer); void draw(VkCommandBuffer commandBuffer);
void calculateBoundingBox(Node* node, Node* parent); void calculateBoundingBox(Node* node, Node* parent);

View File

@ -2,13 +2,8 @@
GLTFLOADER_NAMESPACE_BEGIN GLTFLOADER_NAMESPACE_BEGIN
glTFPrimitive::glTFPrimitive(uint32_t firstIndex, uint32_t indexCount, uint32_t vertexCount, glTFMaterial &material)
: m_firstIndex(firstIndex), m_indexCount(indexCount), m_vertexCount(vertexCount), m_material(material)
glTFPrimitive::glTFPrimitive(uint32_t firstIndex, uint32_t indexCount, uint32_t vertexCount, glTFMaterial& material)
:m_firstIndex(firstIndex)
,m_indexCount(indexCount)
,m_vertexCount(vertexCount)
,m_material(material)
{ {
m_hasIndices = indexCount > 0; m_hasIndices = indexCount > 0;
} }
@ -47,5 +42,32 @@ unsigned int glTFPrimitive::getFirstIndex()
return m_firstIndex; return m_firstIndex;
} }
void glTFPrimitive::setGltfMaterial(glTFMaterial &material)
{
m_material = material;
}
glTFMaterial &glTFPrimitive::getGltfMaterial()
{
return m_material;
}
void glTFPrimitive::setHasIndices(bool hasIndices)
{
m_hasIndices = hasIndices;
}
bool glTFPrimitive::getHasIndices()
{
return m_hasIndices;
}
void glTFPrimitive::setVertexCount(unsigned int vertexCount)
{
m_vertexCount = vertexCount;
}
unsigned int glTFPrimitive::getVertexCount()
{
return m_vertexCount;
}
GLTFLOADER_NAMESPACE_END GLTFLOADER_NAMESPACE_END

View File

@ -3,18 +3,17 @@
#include "glTFModel_Marco.h" #include "glTFModel_Marco.h"
#include "glTFMaterial.h"
#include "glTFBoundingBox.h" #include "glTFBoundingBox.h"
#include "glTFMaterial.h"
#include <glm/glm.hpp> #include <glm/glm.hpp>
GLTFLOADER_NAMESPACE_BEGIN GLTFLOADER_NAMESPACE_BEGIN
class GLTFLOADER_API glTFPrimitive class GLTFLOADER_API glTFPrimitive
{ {
public: public:
glTFPrimitive(uint32_t firstIndex, uint32_t indexCount, uint32_t vertexCount, glTFMaterial& material); glTFPrimitive(uint32_t firstIndex, uint32_t indexCount, uint32_t vertexCount, glTFMaterial &material);
~glTFPrimitive(); ~glTFPrimitive();
@ -27,20 +26,24 @@ public:
void setFirstIndex(unsigned int firstIndex); void setFirstIndex(unsigned int firstIndex);
unsigned int getFirstIndex(); 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_firstIndex;
unsigned int m_indexCount; unsigned int m_indexCount;
unsigned int m_vertexCount; unsigned int m_vertexCount;
glTFMaterial& m_material; glTFMaterial &m_material;
bool m_hasIndices; bool m_hasIndices;
glTFBoundingBox m_boundingBox; glTFBoundingBox m_boundingBox;
}; };
GLTFLOADER_NAMESPACE_END GLTFLOADER_NAMESPACE_END
#endif // !GLTFPRIMITIVE_H #endif // !GLTFPRIMITIVE_H

View File

@ -8,7 +8,6 @@
#include <tiny_gltf.h> #include <tiny_gltf.h>
GLTFLOADER_NAMESPACE_BEGIN GLTFLOADER_NAMESPACE_BEGIN
/// @brief gltf模型的贴图 /// @brief gltf模型的贴图
@ -22,11 +21,10 @@ public:
void destroy(); void destroy();
void fromglTfImage(tinygltf::Image& gltfimage, VulkanBase::VulkanTextureSampler textureSampler, VulkanBase::VulkanDevice* device, VkQueue copyQueue); void fromglTfImage(tinygltf::Image &gltfimage, VulkanBase::VulkanTextureSampler textureSampler, VulkanBase::VulkanDevice *device, VkQueue copyQueue);
private: private:
VulkanBase::VulkanDevice *m_device;
VulkanBase::VulkanDevice* m_device;
VkImage m_image; VkImage m_image;
VkImageLayout m_imageLayout; VkImageLayout m_imageLayout;
VkDeviceMemory m_deviceMemory; VkDeviceMemory m_deviceMemory;
@ -38,13 +36,6 @@ private:
VkSampler m_sampler; VkSampler m_sampler;
}; };
GLTFLOADER_NAMESPACE_END GLTFLOADER_NAMESPACE_END
#endif // !GLTFTEXTURE_H #endif // !GLTFTEXTURE_H

View File

@ -1,6 +1,6 @@
#include "PbrBaseTexture.h" #include "PbrBaseTexture.h"
GLTFLOADER_NAMESPACE_BEGIN PBR_NAMESPACE_BEGIN
PbrBaseTexture::PbrBaseTexture() PbrBaseTexture::PbrBaseTexture()
{ {
@ -10,12 +10,12 @@ PbrBaseTexture::~PbrBaseTexture()
{ {
} }
void PbrBaseTexture::setBaseColorTexture(glTFTexture* value) void PbrBaseTexture::setBaseColorTexture(glTFLoader::glTFTexture *value)
{ {
m_baseColorTexture = value; m_baseColorTexture = value;
} }
glTFTexture* PbrBaseTexture::getBaseColorTexture() glTFLoader::glTFTexture *PbrBaseTexture::getBaseColorTexture()
{ {
return m_baseColorTexture; return m_baseColorTexture;
} }
@ -30,22 +30,22 @@ glm::vec4 PbrBaseTexture::getBaseColorFactor()
return m_baseColorFactor; return m_baseColorFactor;
} }
void PbrBaseTexture::setNormalTexture(glTFTexture* value) void PbrBaseTexture::setNormalTexture(glTFLoader::glTFTexture *value)
{ {
m_normalTexture = value; m_normalTexture = value;
} }
glTFTexture* PbrBaseTexture::getNormalTexture() glTFLoader::glTFTexture *PbrBaseTexture::getNormalTexture()
{ {
return m_normalTexture; return m_normalTexture;
} }
void PbrBaseTexture::setMetallicRoughnessTexture(glTFTexture* value) void PbrBaseTexture::setMetallicRoughnessTexture(glTFLoader::glTFTexture *value)
{ {
m_metallicRoughnessTexture = value; m_metallicRoughnessTexture = value;
} }
glTFTexture* PbrBaseTexture::getMetalicRoughnessTexture() glTFLoader::glTFTexture *PbrBaseTexture::getMetalicRoughnessTexture()
{ {
return m_metallicRoughnessTexture; return m_metallicRoughnessTexture;
} }
@ -70,17 +70,16 @@ float PbrBaseTexture::getRoughnessFactor()
return m_roughnessFactor; return m_roughnessFactor;
} }
void PbrBaseTexture::setEmissiveTexture(glTFTexture* value) void PbrBaseTexture::setEmissiveTexture(glTFLoader::glTFTexture *value)
{ {
m_emissiveTexture = value; m_emissiveTexture = value;
} }
glTFTexture* PbrBaseTexture::getEmissiveTexture() glTFLoader::glTFTexture *PbrBaseTexture::getEmissiveTexture()
{ {
return m_emissiveTexture; return m_emissiveTexture;
} }
void PbrBaseTexture::setEmissiveFactor(glm::vec4 value) void PbrBaseTexture::setEmissiveFactor(glm::vec4 value)
{ {
m_emissiveFactor = value; m_emissiveFactor = value;
@ -91,14 +90,14 @@ glm::vec4 PbrBaseTexture::getEmissiveFactor()
return m_emissiveFactor; return m_emissiveFactor;
} }
void PbrBaseTexture::setOcclusionTexture(glTFTexture* value) void PbrBaseTexture::setOcclusionTexture(glTFLoader::glTFTexture *value)
{ {
m_occlusionTexture = value; m_occlusionTexture = value;
} }
glTFTexture* PbrBaseTexture::getOcclusionTexture() glTFLoader::glTFTexture *PbrBaseTexture::getOcclusionTexture()
{ {
return m_occlusionTexture; return m_occlusionTexture;
} }
GLTFLOADER_NAMESPACE_END PBR_NAMESPACE_END

View File

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

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" #include "PbrTextureExtension.h"
GLTFLOADER_NAMESPACE_BEGIN PBR_NAMESPACE_BEGIN
PbrTextureExtension::PbrTextureExtension() PbrTextureExtension::PbrTextureExtension()
{ {
@ -10,22 +10,22 @@ PbrTextureExtension::~PbrTextureExtension()
{ {
} }
void PbrTextureExtension::setSpecularGlossinessTexture(glTFTexture* _texture) void PbrTextureExtension::setSpecularGlossinessTexture(glTFLoader::glTFTexture *_texture)
{ {
m_specularGlossinessTexture = _texture; m_specularGlossinessTexture = _texture;
} }
glTFTexture* PbrTextureExtension::getSpecularGlossinessTexture() glTFLoader::glTFTexture *PbrTextureExtension::getSpecularGlossinessTexture()
{ {
return m_specularGlossinessTexture; return m_specularGlossinessTexture;
} }
void PbrTextureExtension::setDiffuseTexture(glTFTexture* _texture) void PbrTextureExtension::setDiffuseTexture(glTFLoader::glTFTexture *_texture)
{ {
m_diffuseTexture = _texture; m_diffuseTexture = _texture;
} }
glTFTexture* PbrTextureExtension::getDiffuseTexture() glTFLoader::glTFTexture *PbrTextureExtension::getDiffuseTexture()
{ {
return m_diffuseTexture; return m_diffuseTexture;
} }
@ -50,6 +50,4 @@ glm::vec3 PbrTextureExtension::getSpecularFactor()
return m_specularFactor; return m_specularFactor;
} }
PBR_NAMESPACE_END
GLTFLOADER_NAMESPACE_END

View File

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

View File

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

View File

@ -1,9 +1,9 @@
#ifndef PBRWORKFLOW_H #ifndef PBRWORKFLOW_H
#define PBRWORKFLOW_H #define PBRWORKFLOW_H
#include "glTFModel_Marco.h" #include "PbrMarco.h"
GLTFLOADER_NAMESPACE_BEGIN PBR_NAMESPACE_BEGIN
class PbrWorkFlow class PbrWorkFlow
{ {
@ -18,16 +18,10 @@ public:
bool getSpecularGlossiness(); bool getSpecularGlossiness();
private: private:
bool m_metallicRoughness = true; bool m_metallicRoughness = true;
bool m_specularGlossiness = false; bool m_specularGlossiness = false;
}; };
PBR_NAMESPACE_END
GLTFLOADER_NAMESPACE_END
#endif // !PBRWORKFLOW_H #endif // !PBRWORKFLOW_H

View File

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

View File

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

View File

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

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 #include "render.h"
#define TINYGLTF_IMPLEMENTATION
#include "PbrBaseTexture.h"
#include "PbrTextureCoordSet.h"
#include "glTFMainModel.h"
#include "PushConstBlockMaterial.h" #include "PushConstBlockMaterial.h"
#include "VulkanTexture.hpp" #include "ShaderLoader.h"
#include "glTFModel.h" #include "VulkanTexture.h"
#include "glTFMaterial.h"
#include "glTFPrimitive.h"
#include "glTFSkin.h"
#include "glTFTexture.h"
#include "glm/gtc/matrix_transform.hpp" #include "glm/gtc/matrix_transform.hpp"
#include "renderUniformBufferSet.h" #include "renderUniformBufferSet.h"
#include "vulkan/vulkan_core.h"
#include <cmath> #include <cmath>
#include <cstddef> #include <cstddef>
#include <vector>
#endif
#ifndef STB_IMAGE_IMPLEMENTATION #ifndef STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
#endif #endif
@ -21,7 +29,6 @@
#define TINYGLTF_NO_STB_IMAGE_WRITE #define TINYGLTF_NO_STB_IMAGE_WRITE
#endif #endif
#include "render.h"
// #include "VulkanUtils.hpp" // #include "VulkanUtils.hpp"
// #include "assetLoader.h" // #include "assetLoader.h"
@ -30,21 +37,21 @@ PlumageRender::PlumageRender()
title = "plumage render"; title = "plumage render";
} }
void PlumageRender::renderNode(glTFModel::Node *node, uint32_t cbIndex, glTFModel::Material::AlphaMode alphaMode) void PlumageRender::renderNode(glTFLoader::glTFNode *node, uint32_t cbIndex, glTFLoader::AlphaMode alphaMode)
{ {
if (node->mesh) if (node->getMesh())
{ {
// Render mesh primitives // Render mesh primitives
for (glTFModel::Primitive *primitive : node->mesh->primitives) for (glTFLoader::glTFPrimitive *primitive : node->getMesh()->getPrimitives())
{ {
if (primitive->material.alphaMode == alphaMode) if (primitive->getGltfMaterial().getAlphaMode() == alphaMode)
{ {
VkPipeline pipeline = VK_NULL_HANDLE; VkPipeline pipeline = VK_NULL_HANDLE;
switch (alphaMode) switch (alphaMode)
{ {
case glTFModel::Material::ALPHAMODE_OPAQUE: case glTFLoader::ALPHAMODE_OPAQUE:
case glTFModel::Material::ALPHAMODE_MASK: case glTFLoader::ALPHAMODE_MASK:
if (primitive->material.doubleSided) if (primitive->getGltfMaterial().getDoublesided())
{ {
pipeline = m_pipelineList.getPbrDoubleSided(); pipeline = m_pipelineList.getPbrDoubleSided();
} }
@ -53,7 +60,7 @@ void PlumageRender::renderNode(glTFModel::Node *node, uint32_t cbIndex, glTFMode
pipeline = m_pipelineList.getPbr(); pipeline = m_pipelineList.getPbr();
} }
break; break;
case glTFModel::Material::ALPHAMODE_BLEND: case glTFLoader::ALPHAMODE_BLEND:
pipeline = m_pipelineList.getPbrAlphaBlend(); pipeline = m_pipelineList.getPbrAlphaBlend();
break; break;
} }
@ -66,78 +73,81 @@ void PlumageRender::renderNode(glTFModel::Node *node, uint32_t cbIndex, glTFMode
const std::vector<VkDescriptorSet> descriptorsets = { const std::vector<VkDescriptorSet> descriptorsets = {
descriptorSets[cbIndex].getScene(), descriptorSets[cbIndex].getScene(),
primitive->material.descriptorSet, primitive->getGltfMaterial().getDescriptorSet(),
node->mesh->uniformBuffer.descriptorSet, node->getMesh()->getUniformBuffer().descriptorSet,
}; };
vkCmdBindDescriptorSets(commandBuffers[cbIndex], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, static_cast<uint32_t>(descriptorsets.size()), descriptorsets.data(), 0, NULL); vkCmdBindDescriptorSets(commandBuffers[cbIndex], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, static_cast<uint32_t>(descriptorsets.size()), descriptorsets.data(), 0, NULL);
// Pass material parameters as push constants // Pass material parameters as push constants
PushConstBlockMaterial m_pushConstBlockMaterial; PushConstBlockMaterial m_pushConstBlockMaterial;
m_pushConstBlockMaterial.setEmissiveFactor(primitive->material.emissiveFactor); PBR::PbrBaseTexture *pbrBaseTexture = primitive->getGltfMaterial().getPbrBaseTexture();
glTFLoader::TextureCoordSet *texCoordSet = primitive->getGltfMaterial().getTextureCoordSet();
m_pushConstBlockMaterial.setEmissiveFactor(pbrBaseTexture->getEmissiveFactor());
// To save push constant space, availabilty and texture coordiante set are combined // To save push constant space, availabilty and texture coordiante set are combined
// -1 = texture not used for this material, >= 0 texture used and index of texture coordinate set // -1 = texture not used for this material, >= 0 texture used and index of texture coordinate set
if (primitive->material.baseColorTexture != nullptr) if (pbrBaseTexture->getBaseColorTexture() != nullptr)
{ {
m_pushConstBlockMaterial.setColorTextureSet(primitive->material.texCoordSets.baseColor); m_pushConstBlockMaterial.setColorTextureSet(texCoordSet->getBaseColor());
} }
else else
{ {
m_pushConstBlockMaterial.setColorTextureSet(-1); m_pushConstBlockMaterial.setColorTextureSet(-1);
} }
if (primitive->material.normalTexture != nullptr) if (pbrBaseTexture->getNormalTexture() != nullptr)
{ {
m_pushConstBlockMaterial.setNormalTextureSet(primitive->material.texCoordSets.normal); m_pushConstBlockMaterial.setNormalTextureSet(texCoordSet->getNormal());
} }
else else
{ {
m_pushConstBlockMaterial.setNormalTextureSet(-1); m_pushConstBlockMaterial.setNormalTextureSet(-1);
} }
if (primitive->material.occlusionTexture != nullptr) if (pbrBaseTexture->getOcclusionTexture() != nullptr)
{ {
m_pushConstBlockMaterial.setOcclusionTextureSet(primitive->material.texCoordSets.occlusion); m_pushConstBlockMaterial.setOcclusionTextureSet(texCoordSet->getOcclusion());
} }
else else
{ {
m_pushConstBlockMaterial.setOcclusionTextureSet(-1); m_pushConstBlockMaterial.setOcclusionTextureSet(-1);
} }
if (primitive->material.emissiveTexture != nullptr) if (pbrBaseTexture->getEmissiveTexture() != nullptr)
{ {
m_pushConstBlockMaterial.setEmissiveTextureSet(primitive->material.texCoordSets.emissive); m_pushConstBlockMaterial.setEmissiveTextureSet(texCoordSet->getEmissive());
} }
else else
{ {
m_pushConstBlockMaterial.setEmissiveTextureSet(-1); m_pushConstBlockMaterial.setEmissiveTextureSet(-1);
} }
if (primitive->material.alphaMode == glTFModel::Material::ALPHAMODE_MASK) if (primitive->getGltfMaterial().getAlphaMode() == glTFLoader::ALPHAMODE_MASK)
{ {
m_pushConstBlockMaterial.setAlphaMask(static_cast<float>(primitive->material.alphaMode)); m_pushConstBlockMaterial.setAlphaMask(static_cast<float>(primitive->getGltfMaterial().getAlphaMode()));
} }
m_pushConstBlockMaterial.setAlphaMaskCutoff(primitive->material.alphaCutoff); m_pushConstBlockMaterial.setAlphaMaskCutoff(primitive->getGltfMaterial().getAlphaCutOff());
// TODO: glTF specs states that metallic roughness should be preferred, even if specular glosiness is present // TODO: glTF specs states that metallic roughness should be preferred, even if specular glosiness is present
if (primitive->material.pbrWorkflows.metallicRoughness) glTFLoader::glTFMaterial *material = &primitive->getGltfMaterial();
if (material->getPbrWorkFlow()->getMetallicRoughness())
{ {
// Metallic roughness workflow // Metallic roughness workflow
m_pushConstBlockMaterial.setWorkflow(static_cast<float>(PBR_WORKFLOW_METALLIC_ROUGHNESS)); m_pushConstBlockMaterial.setWorkflow(static_cast<float>(PBR_WORKFLOW_METALLIC_ROUGHNESS));
m_pushConstBlockMaterial.setBaseColorFactor(primitive->material.baseColorFactor); m_pushConstBlockMaterial.setBaseColorFactor(pbrBaseTexture->getBaseColorFactor());
m_pushConstBlockMaterial.setMetallicFactor(primitive->material.metallicFactor); m_pushConstBlockMaterial.setMetallicFactor(pbrBaseTexture->getMetallicFactor());
m_pushConstBlockMaterial.setRoughnessFactor(primitive->material.roughnessFactor); m_pushConstBlockMaterial.setRoughnessFactor(pbrBaseTexture->getRoughnessFactor());
if (primitive->material.metallicRoughnessTexture != nullptr) if (pbrBaseTexture->getMetalicRoughnessTexture() != nullptr)
{ {
m_pushConstBlockMaterial.setPhysicalDescriptorTextureSet(primitive->material.texCoordSets.metallicRoughness); m_pushConstBlockMaterial.setPhysicalDescriptorTextureSet(texCoordSet->getMetallicRoughness());
} }
else else
{ {
m_pushConstBlockMaterial.setPhysicalDescriptorTextureSet(-1); m_pushConstBlockMaterial.setPhysicalDescriptorTextureSet(-1);
} }
if (primitive->material.baseColorTexture != nullptr) if (pbrBaseTexture->getBaseColorTexture() != nullptr)
{ {
m_pushConstBlockMaterial.setColorTextureSet(primitive->material.texCoordSets.baseColor); m_pushConstBlockMaterial.setColorTextureSet(texCoordSet->getBaseColor());
} }
else else
{ {
@ -145,47 +155,49 @@ void PlumageRender::renderNode(glTFModel::Node *node, uint32_t cbIndex, glTFMode
} }
} }
if (primitive->material.pbrWorkflows.specularGlossiness) if (material->getPbrWorkFlow()->getSpecularGlossiness())
{ {
// Specular glossiness workflow // Specular glossiness workflow
m_pushConstBlockMaterial.setWorkflow(static_cast<float>(PBR_WORKFLOW_SPECULAR_GLOSINESS)); m_pushConstBlockMaterial.setWorkflow(static_cast<float>(PBR_WORKFLOW_SPECULAR_GLOSINESS));
if (primitive->material.extension.specularGlossinessTexture != nullptr) if (material->getTextureExtension()->getSpecularGlossinessTexture() != nullptr)
{ {
m_pushConstBlockMaterial.setPhysicalDescriptorTextureSet(primitive->material.texCoordSets.specularGlossiness); m_pushConstBlockMaterial.setPhysicalDescriptorTextureSet(texCoordSet->getSpecularGlossiness());
} }
else else
{ {
m_pushConstBlockMaterial.setPhysicalDescriptorTextureSet(-1); m_pushConstBlockMaterial.setPhysicalDescriptorTextureSet(-1);
} }
if (primitive->material.extension.diffuseTexture != nullptr) if (material->getTextureExtension()->getDiffuseTexture() != nullptr)
{ {
m_pushConstBlockMaterial.setColorTextureSet(primitive->material.texCoordSets.baseColor); m_pushConstBlockMaterial.setColorTextureSet(texCoordSet->getBaseColor());
} }
else else
{ {
m_pushConstBlockMaterial.setColorTextureSet(-1); m_pushConstBlockMaterial.setColorTextureSet(-1);
} }
m_pushConstBlockMaterial.setDiffuseFactor(primitive->material.extension.diffuseFactor); m_pushConstBlockMaterial.setDiffuseFactor(material->getTextureExtension()->getDiffuseFactor());
m_pushConstBlockMaterial.setSpecularFactor(glm::vec4(primitive->material.extension.specularFactor, 1.0f)); m_pushConstBlockMaterial.setSpecularFactor(glm::vec4(material->getTextureExtension()->getSpecularFactor(), 1.0f));
} }
vkCmdPushConstants(commandBuffers[cbIndex], pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstBlockMaterial), &m_pushConstBlockMaterial); vkCmdPushConstants(commandBuffers[cbIndex], pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstBlockMaterial), &m_pushConstBlockMaterial);
if (primitive->hasIndices) if (primitive->getHasIndices())
{ {
vkCmdDrawIndexed(commandBuffers[cbIndex], primitive->indexCount, 1, primitive->firstIndex, 0, 0); vkCmdDrawIndexed(commandBuffers[cbIndex], primitive->getIndexCount(), 1, primitive->getFirstIndex(), 0, 0);
} }
else else
{ {
vkCmdDraw(commandBuffers[cbIndex], primitive->vertexCount, 1, 0, 0); vkCmdDraw(commandBuffers[cbIndex], primitive->getVertexCount(), 1, 0, 0);
} }
} }
} }
}; };
for (auto child : node->children)
std::vector<glTFLoader::glTFNode *> nodeChildren = node->getChildren();
for (auto child : nodeChildren)
{ {
renderNode(child, cbIndex, alphaMode); renderNode(child, cbIndex, alphaMode);
} }
@ -249,12 +261,12 @@ void PlumageRender::buildCommandBuffers()
m_sceneModel.getSkyBox().draw(currentCB); m_sceneModel.getSkyBox().draw(currentCB);
} }
glTFModel::Model &model = m_sceneModel.getScene(); glTFLoader::glTFMainModel &model = m_sceneModel.getScene();
vkCmdBindVertexBuffers(currentCB, 0, 1, &model.vertices.buffer, offsets); vkCmdBindVertexBuffers(currentCB, 0, 1, &model.getModelVertex().buffer, offsets);
if (model.indices.buffer != VK_NULL_HANDLE) if (model.getModelIndex().buffer != VK_NULL_HANDLE)
{ {
vkCmdBindIndexBuffer(currentCB, model.indices.buffer, 0, VK_INDEX_TYPE_UINT32); vkCmdBindIndexBuffer(currentCB, model.getModelIndex().buffer, 0, VK_INDEX_TYPE_UINT32);
} }
boundPipeline = VK_NULL_HANDLE; boundPipeline = VK_NULL_HANDLE;
@ -329,7 +341,7 @@ void PlumageRender::loadAssets()
std::cout << msg << std::endl; std::cout << msg << std::endl;
} }
readDirectory(assetpath + "environments", "*.ktx", environments, false); ShaderLoader::readDirectory(assetpath + "environments", "*.ktx", environments, false);
m_sceneTextures.getEmpty().loadFromFile(PlumageRender::m_configFilePath.getEmptyEnvmapFilePath(), VK_FORMAT_R8G8B8A8_UNORM, vulkanDevice, queue); m_sceneTextures.getEmpty().loadFromFile(PlumageRender::m_configFilePath.getEmptyEnvmapFilePath(), VK_FORMAT_R8G8B8A8_UNORM, vulkanDevice, queue);
@ -459,7 +471,7 @@ void PlumageRender::setupDescriptors()
VkDescriptorSetLayout sceneDescriptorSetLayout = m_descriptorSetLayoutList.getScene(); VkDescriptorSetLayout sceneDescriptorSetLayout = m_descriptorSetLayoutList.getScene();
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &sceneDescriptorSetLayout)); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &sceneDescriptorSetLayout));
vks::TextureCubeMap refIrradianceCube = m_sceneTextures.getIrradianceCube(); VulkanBase::TextureCubeMap refIrradianceCube = m_sceneTextures.getIrradianceCube();
for (auto i = 0; i < descriptorSets.size(); i++) for (auto i = 0; i < descriptorSets.size(); i++)
{ {
@ -605,7 +617,7 @@ void PlumageRender::setupDescriptors()
} }
} }
vks::TextureCubeMap refPrefilterCube = m_sceneTextures.getPrefilteredCube(); VulkanBase::TextureCubeMap refPrefilterCube = m_sceneTextures.getPrefilteredCube();
// Skybox (fixed set) // Skybox (fixed set)
for (auto i = 0; i < uniformBuffers.size(); i++) for (auto i = 0; i < uniformBuffers.size(); i++)
{ {
@ -752,8 +764,8 @@ void PlumageRender::preparePipelines()
// Skybox pipeline (background cube) // Skybox pipeline (background cube)
shaderStages = { shaderStages = {
loadShader(device, m_configFilePath.getSkyboxVertShaderPath(), VK_SHADER_STAGE_VERTEX_BIT), ShaderLoader::loadShader(device, m_configFilePath.getSkyboxVertShaderPath(), VK_SHADER_STAGE_VERTEX_BIT),
loadShader(device, m_configFilePath.getSkyboxFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT)}; ShaderLoader::loadShader(device, m_configFilePath.getSkyboxFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT)};
VkPipeline skyboxPipeline = m_pipelineList.getSkybox(); VkPipeline skyboxPipeline = m_pipelineList.getSkybox();
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &skyboxPipeline)); VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &skyboxPipeline));
for (auto shaderStage : shaderStages) for (auto shaderStage : shaderStages)
@ -763,8 +775,8 @@ void PlumageRender::preparePipelines()
// PBR pipeline // PBR pipeline
shaderStages = { shaderStages = {
loadShader(device, m_configFilePath.getPbrVertShaderPath(), VK_SHADER_STAGE_VERTEX_BIT), ShaderLoader::loadShader(device, m_configFilePath.getPbrVertShaderPath(), VK_SHADER_STAGE_VERTEX_BIT),
loadShader(device, m_configFilePath.getPbrFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT)}; ShaderLoader::loadShader(device, m_configFilePath.getPbrFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT)};
depthStencilStateCI.depthWriteEnable = VK_TRUE; depthStencilStateCI.depthWriteEnable = VK_TRUE;
depthStencilStateCI.depthTestEnable = VK_TRUE; depthStencilStateCI.depthTestEnable = VK_TRUE;
VkPipeline pbrPipeline = m_pipelineList.getPbr(); VkPipeline pbrPipeline = m_pipelineList.getPbr();
@ -807,7 +819,7 @@ void PlumageRender::generateCubemaps()
for (uint32_t target = 0; target < PREFILTEREDENV + 1; target++) for (uint32_t target = 0; target < PREFILTEREDENV + 1; target++)
{ {
vks::TextureCubeMap cubemap; VulkanBase::TextureCubeMap cubemap;
auto tStart = std::chrono::high_resolution_clock::now(); auto tStart = std::chrono::high_resolution_clock::now();
@ -1132,14 +1144,14 @@ void PlumageRender::generateCubemaps()
pipelineCI.pStages = shaderStages.data(); pipelineCI.pStages = shaderStages.data();
pipelineCI.renderPass = renderpass; pipelineCI.renderPass = renderpass;
shaderStages[0] = loadShader(device, m_configFilePath.getFilterVertShaderPath(), VK_SHADER_STAGE_VERTEX_BIT); shaderStages[0] = ShaderLoader::loadShader(device, m_configFilePath.getFilterVertShaderPath(), VK_SHADER_STAGE_VERTEX_BIT);
switch (target) switch (target)
{ {
case IRRADIANCE: case IRRADIANCE:
shaderStages[1] = loadShader(device, m_configFilePath.getIrradianceFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT); shaderStages[1] = ShaderLoader::loadShader(device, m_configFilePath.getIrradianceFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT);
break; break;
case PREFILTEREDENV: case PREFILTEREDENV:
shaderStages[1] = loadShader(device, m_configFilePath.getPrefilterEnvmapFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT); shaderStages[1] = ShaderLoader::loadShader(device, m_configFilePath.getPrefilterEnvmapFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT);
break; break;
}; };
VkPipeline pipeline; VkPipeline pipeline;
@ -1360,7 +1372,7 @@ void PlumageRender::generateBRDFLUT()
const VkFormat format = VK_FORMAT_R16G16_SFLOAT; const VkFormat format = VK_FORMAT_R16G16_SFLOAT;
const int32_t dim = 2048; const int32_t dim = 2048;
vks::Texture2D RefLutBrdfTex = m_sceneTextures.getLutBrdf(); VulkanBase::Texture2D RefLutBrdfTex = m_sceneTextures.getLutBrdf();
// Image // Image
VkImageCreateInfo imageCI{}; VkImageCreateInfo imageCI{};
@ -1553,8 +1565,8 @@ void PlumageRender::generateBRDFLUT()
// Look-up-table (from BRDF) pipeline // Look-up-table (from BRDF) pipeline
shaderStages = { shaderStages = {
loadShader(device, m_configFilePath.getBrdfVertShaderPath(), VK_SHADER_STAGE_VERTEX_BIT), ShaderLoader::loadShader(device, m_configFilePath.getBrdfVertShaderPath(), VK_SHADER_STAGE_VERTEX_BIT),
loadShader(device, m_configFilePath.getBrdfFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT)}; ShaderLoader::loadShader(device, m_configFilePath.getBrdfFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT)};
VkPipeline pipeline; VkPipeline pipeline;
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipeline)); VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipeline));
for (auto shaderStage : shaderStages) for (auto shaderStage : shaderStages)
@ -2264,9 +2276,8 @@ void PlumageRender::updateUIOverlay()
if (!filename.empty()) if (!filename.empty())
{ {
vkDeviceWaitIdle(device); vkDeviceWaitIdle(device);
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter; std::string stringFilename = std::filesystem::path(filename).string();
std::string stringFilename = converter.to_bytes(filename);
loadScene(stringFilename); loadScene(stringFilename);
setupDescriptors(); setupDescriptors();
updateCBs = true; updateCBs = true;

View File

@ -5,6 +5,8 @@
#include "RenderOffScreen.h" #include "RenderOffScreen.h"
#include "RenderPipelineList.h" #include "RenderPipelineList.h"
#include "RenderSceneTextures.h" #include "RenderSceneTextures.h"
#include "glTFMaterial.h"
#include "glTFSkin.h"
#include "renderShaderData.h" #include "renderShaderData.h"
#if defined(_WIN32) #if defined(_WIN32)
#include <direct.h> #include <direct.h>
@ -36,8 +38,7 @@
#include "VulkanExampleBase.h" #include "VulkanExampleBase.h"
#include "glTFModel.h" #include "glTFModel.h"
#include "ui.hpp" #include "ui.hpp"
#include <VulkanTexture.hpp> #include <VulkanTexture.h>
#include <VulkanUtils.hpp>
#include <vulkan/vulkan.h> #include <vulkan/vulkan.h>
#define ENABLE_VALIDATION false #define ENABLE_VALIDATION false
@ -55,6 +56,7 @@
#include "RenderPipelineList.h" #include "RenderPipelineList.h"
#include "RenderSceneTextures.h" #include "RenderSceneTextures.h"
#include "SceneUBOMatrices.h" #include "SceneUBOMatrices.h"
#include "ShaderLoader.h"
#include "SkyboxUBOMatrices.h" #include "SkyboxUBOMatrices.h"
#include "VertexStagingBuffer.h" #include "VertexStagingBuffer.h"
#include "renderEffectState.h" #include "renderEffectState.h"
@ -184,7 +186,7 @@ public:
delete gui; delete gui;
} }
void renderNode(glTFModel::Node *node, uint32_t cbIndex, glTFModel::Material::AlphaMode alphaMode); void renderNode(glTFLoader::glTFNode *node, uint32_t cbIndex, glTFLoader::AlphaMode alphaMode);
void loadScene(std::string filename); void loadScene(std::string filename);
void loadEnvironment(std::string filename); void loadEnvironment(std::string filename);
void buildCommandBuffers(); void buildCommandBuffers();

View File

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

View File

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

View File

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

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

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