调整结构

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

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; int32_t count = 0;
void* mapped = nullptr; void *mapped = nullptr;
/** @brief Usage flags to be filled by external source at buffer creation (to query at some later point) */ /** @brief Usage flags to be filled by external source at buffer creation (to query at some later point) */
VkBufferUsageFlags usageFlags; VkBufferUsageFlags usageFlags;
/** @brief Memory property flags to be filled by external source at buffer creation (to query at some later point) */ /** @brief Memory property flags to be filled by external source at buffer creation (to query at some later point) */
VkMemoryPropertyFlags memoryPropertyFlags; VkMemoryPropertyFlags memoryPropertyFlags;
VkResult map(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0); void create(VulkanDevice *device, VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkDeviceSize size, bool map = true);
void unmap(); VkResult map(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0);
VkResult bind(VkDeviceSize offset = 0); void unmap();
void setupDescriptor(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0); VkResult bind(VkDeviceSize offset = 0);
void copyTo(void* data, VkDeviceSize size); void setupDescriptor(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0);
VkResult flush(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0); void copyTo(void *data, VkDeviceSize size);
VkResult invalidate(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0); VkResult flush(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0);
void destroy(); VkResult invalidate(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0);
}; void destroy();
} };
VULKANBASE_NAMESPACE_END
#endif

View File

@ -0,0 +1,254 @@
#include "VulkanDevice.h"
#include "VulkanTools.h"
#include <cassert>
#include <stdexcept>
VULKANBASE_NAMESPACE_BEGIN
VulkanDevice::VulkanDevice()
: m_commandPool(VK_NULL_HANDLE)
{
}
VulkanDevice::VulkanDevice(VkPhysicalDevice physicalDevice)
{
/// 检查物理设备是否存在后续使用log方式记录
assert(physicalDevice);
m_physicalDevice = physicalDevice;
/// 获取设备信息
vkGetPhysicalDeviceProperties(physicalDevice, &m_properties);
/// 获取设备支持的功能
vkGetPhysicalDeviceFeatures(physicalDevice, &m_features);
/// 获取设备内存信息,用于创建内存
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &m_memoryProperties);
/// 队列族信息,用于设备创建时获取设置获取的队列
uint32_t queueFamilyCount;
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, nullptr);
/// 检查设备队列族数量必须大于0
assert(queueFamilyCount > 0);
m_queueFamilyProperties.resize(queueFamilyCount);
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, m_queueFamilyProperties.data());
}
VulkanDevice::~VulkanDevice()
{
if (m_commandPool)
{
vkDestroyCommandPool(m_logicalDevice, m_commandPool, nullptr);
}
if (m_logicalDevice)
{
vkDestroyDevice(m_logicalDevice, nullptr);
}
}
VkDevice VulkanDevice::getLogicalDevice()
{
return m_logicalDevice;
}
VkPhysicalDevice VulkanDevice::getPhysicalDevice()
{
return m_physicalDevice;
}
VkPhysicalDeviceProperties VulkanDevice::VulkanDevice::getPhysicalDeviceProperties()
{
return m_properties;
}
VkPhysicalDeviceFeatures VulkanDevice::getPhysicalDeviceFeatures()
{
return m_features;
}
VkPhysicalDeviceMemoryProperties VulkanDevice::getPhysicalDeviceMemoryProperties()
{
return m_memoryProperties;
}
std::vector<VkQueueFamilyProperties> VulkanDevice::getQueueFamilyProperties()
{
return m_queueFamilyProperties;
}
VkCommandPool VulkanDevice::getCommandPool()
{
return m_commandPool;
}
uint32_t VulkanDevice::getMemoryType(uint32_t typeBits, VkMemoryPropertyFlags properties, VkBool32 *memTypeFound)
{
for (uint32_t i = 0; i < m_memoryProperties.memoryTypeCount; i++)
{
if ((typeBits & 1) == 1)
{
if ((m_memoryProperties.memoryTypes[i].propertyFlags & properties) == properties)
{
if (memTypeFound)
{
*memTypeFound = true;
}
return i;
}
}
typeBits >>= 1;
}
if (memTypeFound)
{
*memTypeFound = false;
return 0;
}
else
{
throw std::runtime_error("Could not find a matching memory type");
}
}
uint32_t VulkanDevice::getQueueFamilyIndex(VkQueueFlagBits queueFlags)
{
/// 获取支持计算的队列组索引
if (queueFlags & VK_QUEUE_COMPUTE_BIT)
{
for (uint32_t i = 0; i < static_cast<uint32_t>(m_queueFamilyProperties.size()); i++)
{
if ((m_queueFamilyProperties[i].queueFlags & queueFlags) && ((m_queueFamilyProperties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0))
{
return i;
break;
}
}
}
/// 对于其他的队列类型,如果当前没有单独的计算队列,返回支持标志类型的第一个队列
for (uint32_t i = 0; i < static_cast<uint32_t>(m_queueFamilyProperties.size()); i++)
{
if (m_queueFamilyProperties[i].queueFlags & queueFlags)
{
return i;
break;
}
}
throw std::runtime_error("Could not find a matching queue family index");
}
uint32_t VulkanDevice::getGraphicsQueueFamilyIndex()
{
return m_queueFamilyIndices.graphics;
}
uint32_t VulkanDevice::getComputeQueueFamilyIndex()
{
return m_queueFamilyIndices.compute;
}
VkResult VulkanDevice::createBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkDeviceSize size, VkBuffer *buffer, VkDeviceMemory *memory, void *data)
{
// 创建buffer句柄
VkBufferCreateInfo bufferCreateInfo{};
bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferCreateInfo.usage = usageFlags;
bufferCreateInfo.size = size;
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VK_CHECK_RESULT(vkCreateBuffer(m_logicalDevice, &bufferCreateInfo, nullptr, buffer));
// 创建buffer的设备内存分配信息
VkMemoryRequirements memReqs;
VkMemoryAllocateInfo memAlloc{};
memAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
vkGetBufferMemoryRequirements(m_logicalDevice, *buffer, &memReqs);
memAlloc.allocationSize = memReqs.size;
/// 获取符合buffer的设备内存类型索引
memAlloc.memoryTypeIndex = getMemoryType(memReqs.memoryTypeBits, memoryPropertyFlags);
VK_CHECK_RESULT(vkAllocateMemory(m_logicalDevice, &memAlloc, nullptr, memory));
// 如何buffer指针已经存在复制或者映射该buffer
if (data != nullptr)
{
void *mapped;
VK_CHECK_RESULT(vkMapMemory(m_logicalDevice, *memory, 0, size, 0, &mapped));
memcpy(mapped, data, size);
// 如果host coherency 未设置, 对buffer进行flush让设备侧可见
if ((memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0)
{
VkMappedMemoryRange mappedRange{};
mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
mappedRange.memory = *memory;
mappedRange.offset = 0;
mappedRange.size = size;
vkFlushMappedMemoryRanges(m_logicalDevice, 1, &mappedRange);
}
vkUnmapMemory(m_logicalDevice, *memory);
}
// 绑定设备内存到buffer object
VK_CHECK_RESULT(vkBindBufferMemory(m_logicalDevice, *buffer, *memory, 0));
return VK_SUCCESS;
}
VkCommandPool VulkanDevice::createCommandPool(uint32_t queueFamilyIndex, VkCommandPoolCreateFlags createFlags)
{
/// 创建命令缓冲池
VkCommandPoolCreateInfo cmdPoolInfo = {};
cmdPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
cmdPoolInfo.queueFamilyIndex = queueFamilyIndex;
cmdPoolInfo.flags = createFlags;
VkCommandPool cmdPool;
VK_CHECK_RESULT(vkCreateCommandPool(m_logicalDevice, &cmdPoolInfo, nullptr, &cmdPool));
return cmdPool;
}
VkCommandBuffer VulkanDevice::createCommandBuffer(VkCommandBufferLevel level, bool begin)
{
VkCommandBufferAllocateInfo cmdBufAllocateInfo{};
cmdBufAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
cmdBufAllocateInfo.commandPool = m_commandPool;
cmdBufAllocateInfo.level = level;
cmdBufAllocateInfo.commandBufferCount = 1;
VkCommandBuffer cmdBuffer;
VK_CHECK_RESULT(vkAllocateCommandBuffers(m_logicalDevice, &cmdBufAllocateInfo, &cmdBuffer));
// 开始记录指令buffer
if (begin)
{
beginCommandBuffer(cmdBuffer);
}
return cmdBuffer;
}
void VulkanDevice::beginCommandBuffer(VkCommandBuffer commandBuffer)
{
VkCommandBufferBeginInfo commandBufferBI{};
commandBufferBI.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
VK_CHECK_RESULT(vkBeginCommandBuffer(commandBuffer, &commandBufferBI));
}
void VulkanDevice::flushCommandBuffer(VkCommandBuffer commandBuffer, VkQueue queue, bool free)
{
VK_CHECK_RESULT(vkEndCommandBuffer(commandBuffer));
VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBuffer;
// 创建同步栅栏确保命令buffer执行完毕
VkFenceCreateInfo fenceInfo{};
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
VkFence fence;
VK_CHECK_RESULT(vkCreateFence(m_logicalDevice, &fenceInfo, nullptr, &fence));
// 提交队列
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, fence));
// 等待栅栏发出信号说明命令buffer执行完毕
VK_CHECK_RESULT(vkWaitForFences(m_logicalDevice, 1, &fence, VK_TRUE, 100000000000));
// 同步栅栏使命结束,销毁
vkDestroyFence(m_logicalDevice, fence, nullptr);
// 需要的时候销毁命令buffer
if (free)
{
vkFreeCommandBuffers(m_logicalDevice, m_commandPool, 1, &commandBuffer);
}
}
VULKANBASE_NAMESPACE_END

View File

@ -0,0 +1,104 @@
#ifndef VULKANDEVICE_H
#define VULKANDEVICE_H
#include "VulkanBase_Marco.h"
#include <cstdint>
#include <vector>
#include <vulkan/vulkan.h>
VULKANBASE_NAMESPACE_BEGIN
/// @brief vulkan的设备类
class VulkanDevice
{
public:
VulkanDevice();
VulkanDevice(VkPhysicalDevice physicalDevice);
~VulkanDevice();
public:
VkDevice getLogicalDevice();
VkPhysicalDevice getPhysicalDevice();
VkPhysicalDeviceProperties getPhysicalDeviceProperties();
VkPhysicalDeviceFeatures getPhysicalDeviceFeatures();
VkPhysicalDeviceMemoryProperties getPhysicalDeviceMemoryProperties();
std::vector<VkQueueFamilyProperties> getQueueFamilyProperties();
VkCommandPool getCommandPool();
uint32_t getGraphicsQueueFamilyIndex();
uint32_t getComputeQueueFamilyIndex();
/// @brief 获取已设置所有请求属性位的设备内存类型的索引
/// @param typeBits 请求的每种设备内存类型设置的位掩码通常通过VkMemoryRequirements获取
/// @param properties 要请求的设备内存类型的属性位掩码
/// @param memTypeFound 如果符合的设备内存类型存在则该指针的布尔值为true
/// @return 请求的设备内存类型的索引
/// @throw 如果 memTypeFound 为空且找不到支持需要的属性的设备内存类型,则抛出异常
uint32_t getMemoryType(uint32_t typeBits, VkMemoryPropertyFlags properties, VkBool32 *memTypeFound = nullptr);
/// @brief 获取支持所请求队列标志的队列族的索引
/// @param queueFlags 用于查找队列族索引的队列标志
/// @return 与标志匹配的队列族索引
/// @throw 如果找不到支持所请求标志的队列族索引,则抛出异常
uint32_t getQueueFamilyIndex(VkQueueFlagBits queueFlags);
/// @brief 据分配的物理设备创建逻辑设备,同时获取默认队列族索引
/// @param enabledFeatures 在创建设备时启用某些功能
/// @param enabledExtensions 在创建设备时启用某些扩展
/// @param requestedQueueTypes 指定要从设备请求的队列类型
/// @return 逻辑设备是否成功创建
VkResult createLogicalDevice(VkPhysicalDeviceFeatures enabledFeatures, std::vector<const char *> enabledExtensions, VkQueueFlags requestedQueueTypes = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT);
/// @brief 在设备上创建缓冲区
/// @param usageFlags 缓冲区的使用标志位掩码(即索引、顶点、统一缓冲区)
/// @param memoryPropertyFlags 此缓冲区的内存属性(即设备本地、主机可见、一致)
/// @param size 缓冲区的大小(以字节为单位)
/// @param buffer 指向函数获取的缓冲区句柄的指针
/// @param memory 指向函数获取的设备内存句柄的指针
/// @param data 指向创建后应复制到缓冲区的数据的指针(可选,如果未设置,则不会复制任何数据)
/// @return 如果已创建缓冲区句柄和设备内存并且已复制数据(可选传递),则返回 VK_SUCCESS
VkResult createBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkDeviceSize size, VkBuffer *buffer, VkDeviceMemory *memory, void *data = nullptr);
/// @brief 创建命令池以分配命令缓冲区
/// @param queueFamilyIndex 要为其创建命令池的队列的系列索引
/// @param createFlags 可选)命令池创建标志(默认为 VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT
/// @return 创建的命令缓冲区的句柄
VkCommandPool createCommandPool(uint32_t queueFamilyIndex, VkCommandPoolCreateFlags createFlags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT);
/// @brief 从命令池中分配命令缓冲区
/// @param level 新命令缓冲区的级别(主或次)
/// @param begin 为 true时开始在新命令缓冲区上进行记录
/// @return 分配的命令缓冲区的句柄
VkCommandBuffer createCommandBuffer(VkCommandBufferLevel level, bool begin = false);
/// @brief 开始在指定命令缓冲区记录
/// @param commandBuffer
void beginCommandBuffer(VkCommandBuffer commandBuffer);
/// @brief 停止指定命令缓冲区记录并将其提交到队列,使用栅栏来确保命令缓冲区已完成执行
/// @param commandBuffer 要刷新的命令缓冲区
/// @param queue 要将命令缓冲区提交到的队列
/// @param free 提交后释放命令缓冲区(默认为 true
void flushCommandBuffer(VkCommandBuffer commandBuffer, VkQueue queue, bool free = true);
private:
VkPhysicalDevice m_physicalDevice;
VkDevice m_logicalDevice;
VkPhysicalDeviceProperties m_properties;
VkPhysicalDeviceFeatures m_features;
VkPhysicalDeviceFeatures m_enabledFeatures;
VkPhysicalDeviceMemoryProperties m_memoryProperties;
std::vector<VkQueueFamilyProperties> m_queueFamilyProperties;
VkCommandPool m_commandPool;
struct
{
uint32_t graphics;
uint32_t compute;
} m_queueFamilyIndices;
};
VULKANBASE_NAMESPACE_END
#endif // !VULKANDEVICE_H

View File

@ -1,391 +0,0 @@
/*
* Vulkan device class
*
* Encapsulates a physical Vulkan device and it's logical representation
*
* Copyright (C) 2016-2018 by Sascha Willems - www.saschawillems.de
*
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
*/
#pragma once
#include <cstdio>
#include <exception>
#include <assert.h>
#include <algorithm>
#include <cstring>
#include <vector>
#include "vulkan/vulkan.h"
#if defined(VK_USE_PLATFORM_MACOS_MVK) && (VK_HEADER_VERSION >= 216)
#include <vulkan/vulkan_beta.h>
#endif
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
#include "VulkanAndroid.h"
#endif
#include "VulkanTools.h"
/// @brief 已单独剥离,等待删除
namespace vks
{
struct VulkanDevice
{
VkPhysicalDevice physicalDevice;
VkDevice logicalDevice;
VkPhysicalDeviceProperties properties;
VkPhysicalDeviceFeatures features;
VkPhysicalDeviceFeatures enabledFeatures;
VkPhysicalDeviceMemoryProperties memoryProperties;
std::vector<VkQueueFamilyProperties> queueFamilyProperties;
VkCommandPool commandPool = VK_NULL_HANDLE;
struct {
uint32_t graphics;
uint32_t compute;
} queueFamilyIndices;
operator VkDevice() { return logicalDevice; };
/**
* Default constructor
*
* @param physicalDevice Physical device that is to be used
*/
VulkanDevice(VkPhysicalDevice physicalDevice)
{
assert(physicalDevice);
this->physicalDevice = physicalDevice;
// Store Properties features, limits and properties of the physical device for later use
// Device properties also contain limits and sparse properties
vkGetPhysicalDeviceProperties(physicalDevice, &properties);
// Features should be checked by the examples before using them
vkGetPhysicalDeviceFeatures(physicalDevice, &features);
// Memory properties are used regularly for creating all kinds of buffers
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memoryProperties);
// Queue family properties, used for setting up requested queues upon device creation
uint32_t queueFamilyCount;
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, nullptr);
assert(queueFamilyCount > 0);
queueFamilyProperties.resize(queueFamilyCount);
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, queueFamilyProperties.data());
}
/**
* Default destructor
*
* @note Frees the logical device
*/
~VulkanDevice()
{
if (commandPool) {
vkDestroyCommandPool(logicalDevice, commandPool, nullptr);
}
if (logicalDevice) {
vkDestroyDevice(logicalDevice, nullptr);
}
}
/**
* Get the index of a memory type that has all the requested property bits set
*
* @param typeBits Bitmask with bits set for each memory type supported by the resource to request for (from VkMemoryRequirements)
* @param properties Bitmask of properties for the memory type to request
* @param (Optional) memTypeFound Pointer to a bool that is set to true if a matching memory type has been found
*
* @return Index of the requested memory type
*
* @throw Throws an exception if memTypeFound is null and no memory type could be found that supports the requested properties
*/
uint32_t getMemoryType(uint32_t typeBits, VkMemoryPropertyFlags properties, VkBool32 *memTypeFound = nullptr)
{
for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; i++) {
if ((typeBits & 1) == 1) {
if ((memoryProperties.memoryTypes[i].propertyFlags & properties) == properties) {
if (memTypeFound) {
*memTypeFound = true;
}
return i;
}
}
typeBits >>= 1;
}
if (memTypeFound) {
*memTypeFound = false;
return 0;
} else {
throw std::runtime_error("Could not find a matching memory type");
}
}
/**
* Get the index of a queue family that supports the requested queue flags
*
* @param queueFlags Queue flags to find a queue family index for
*
* @return Index of the queue family index that matches the flags
*
* @throw Throws an exception if no queue family index could be found that supports the requested flags
*/
uint32_t getQueueFamilyIndex(VkQueueFlagBits queueFlags)
{
// Dedicated queue for compute
// Try to find a queue family index that supports compute but not graphics
if (queueFlags & VK_QUEUE_COMPUTE_BIT)
{
for (uint32_t i = 0; i < static_cast<uint32_t>(queueFamilyProperties.size()); i++) {
if ((queueFamilyProperties[i].queueFlags & queueFlags) && ((queueFamilyProperties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0)) {
return i;
break;
}
}
}
// For other queue types or if no separate compute queue is present, return the first one to support the requested flags
for (uint32_t i = 0; i < static_cast<uint32_t>(queueFamilyProperties.size()); i++) {
if (queueFamilyProperties[i].queueFlags & queueFlags) {
return i;
break;
}
}
throw std::runtime_error("Could not find a matching queue family index");
}
/**
* Create the logical device based on the assigned physical device, also gets default queue family indices
*
* @param enabledFeatures Can be used to enable certain features upon device creation
* @param requestedQueueTypes Bit flags specifying the queue types to be requested from the device
*
* @return VkResult of the device creation call
*/
VkResult createLogicalDevice(VkPhysicalDeviceFeatures enabledFeatures, std::vector<const char*> enabledExtensions, VkQueueFlags requestedQueueTypes = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT)
{
// Desired queues need to be requested upon logical device creation
// Due to differing queue family configurations of Vulkan implementations this can be a bit tricky, especially if the application
// requests different queue types
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos{};
// Get queue family indices for the requested queue family types
// Note that the indices may overlap depending on the implementation
const float defaultQueuePriority(0.0f);
// Graphics queue
if (requestedQueueTypes & VK_QUEUE_GRAPHICS_BIT) {
queueFamilyIndices.graphics = getQueueFamilyIndex(VK_QUEUE_GRAPHICS_BIT);
VkDeviceQueueCreateInfo queueInfo{};
queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueInfo.queueFamilyIndex = queueFamilyIndices.graphics;
queueInfo.queueCount = 1;
queueInfo.pQueuePriorities = &defaultQueuePriority;
queueCreateInfos.push_back(queueInfo);
} else {
queueFamilyIndices.graphics = 0;
}
// Dedicated compute queue
if (requestedQueueTypes & VK_QUEUE_COMPUTE_BIT) {
queueFamilyIndices.compute = getQueueFamilyIndex(VK_QUEUE_COMPUTE_BIT);
if (queueFamilyIndices.compute != queueFamilyIndices.graphics) {
// If compute family index differs, we need an additional queue create info for the compute queue
VkDeviceQueueCreateInfo queueInfo{};
queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueInfo.queueFamilyIndex = queueFamilyIndices.compute;
queueInfo.queueCount = 1;
queueInfo.pQueuePriorities = &defaultQueuePriority;
queueCreateInfos.push_back(queueInfo);
}
} else {
// Else we use the same queue
queueFamilyIndices.compute = queueFamilyIndices.graphics;
}
// Create the logical device representation
std::vector<const char*> deviceExtensions(enabledExtensions);
deviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
#if defined(VK_USE_PLATFORM_MACOS_MVK) && (VK_HEADER_VERSION >= 216)
deviceExtensions.push_back(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME);
#endif
VkDeviceCreateInfo deviceCreateInfo = {};
deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
deviceCreateInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());;
deviceCreateInfo.pQueueCreateInfos = queueCreateInfos.data();
deviceCreateInfo.pEnabledFeatures = &enabledFeatures;
if (deviceExtensions.size() > 0) {
deviceCreateInfo.enabledExtensionCount = (uint32_t)deviceExtensions.size();
deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions.data();
}
VkResult result = vkCreateDevice(physicalDevice, &deviceCreateInfo, nullptr, &logicalDevice);
if (result == VK_SUCCESS) {
commandPool = createCommandPool(queueFamilyIndices.graphics);
}
this->enabledFeatures = enabledFeatures;
return result;
}
/**
* Create a buffer on the device
*
* @param usageFlags Usage flag bitmask for the buffer (i.e. index, vertex, uniform buffer)
* @param memoryPropertyFlags Memory properties for this buffer (i.e. device local, host visible, coherent)
* @param size Size of the buffer in byes
* @param buffer Pointer to the buffer handle acquired by the function
* @param memory Pointer to the memory handle acquired by the function
* @param data Pointer to the data that should be copied to the buffer after creation (optional, if not set, no data is copied over)
*
* @return VK_SUCCESS if buffer handle and memory have been created and (optionally passed) data has been copied
*/
VkResult createBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkDeviceSize size, VkBuffer *buffer, VkDeviceMemory *memory, void *data = nullptr)
{
// Create the buffer handle
VkBufferCreateInfo bufferCreateInfo{};
bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferCreateInfo.usage = usageFlags;
bufferCreateInfo.size = size;
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VK_CHECK_RESULT(vkCreateBuffer(logicalDevice, &bufferCreateInfo, nullptr, buffer));
// Create the memory backing up the buffer handle
VkMemoryRequirements memReqs;
VkMemoryAllocateInfo memAlloc{};
memAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
vkGetBufferMemoryRequirements(logicalDevice, *buffer, &memReqs);
memAlloc.allocationSize = memReqs.size;
// Find a memory type index that fits the properties of the buffer
memAlloc.memoryTypeIndex = getMemoryType(memReqs.memoryTypeBits, memoryPropertyFlags);
VK_CHECK_RESULT(vkAllocateMemory(logicalDevice, &memAlloc, nullptr, memory));
// If a pointer to the buffer data has been passed, map the buffer and copy over the data
if (data != nullptr)
{
void *mapped;
VK_CHECK_RESULT(vkMapMemory(logicalDevice, *memory, 0, size, 0, &mapped));
memcpy(mapped, data, size);
// If host coherency hasn't been requested, do a manual flush to make writes visible
if ((memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0)
{
VkMappedMemoryRange mappedRange{};
mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
mappedRange.memory = *memory;
mappedRange.offset = 0;
mappedRange.size = size;
vkFlushMappedMemoryRanges(logicalDevice, 1, &mappedRange);
}
vkUnmapMemory(logicalDevice, *memory);
}
// Attach the memory to the buffer object
VK_CHECK_RESULT(vkBindBufferMemory(logicalDevice, *buffer, *memory, 0));
return VK_SUCCESS;
}
/**
* Create a command pool for allocation command buffers from
*
* @param queueFamilyIndex Family index of the queue to create the command pool for
* @param createFlags (Optional) Command pool creation flags (Defaults to VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT)
*
* @note Command buffers allocated from the created pool can only be submitted to a queue with the same family index
*
* @return A handle to the created command buffer
*/
VkCommandPool createCommandPool(uint32_t queueFamilyIndex, VkCommandPoolCreateFlags createFlags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT)
{
VkCommandPoolCreateInfo cmdPoolInfo = {};
cmdPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
cmdPoolInfo.queueFamilyIndex = queueFamilyIndex;
cmdPoolInfo.flags = createFlags;
VkCommandPool cmdPool;
VK_CHECK_RESULT(vkCreateCommandPool(logicalDevice, &cmdPoolInfo, nullptr, &cmdPool));
return cmdPool;
}
/**
* Allocate a command buffer from the command pool
*
* @param level Level of the new command buffer (primary or secondary)
* @param (Optional) begin If true, recording on the new command buffer will be started (vkBeginCommandBuffer) (Defaults to false)
*
* @return A handle to the allocated command buffer
*/
VkCommandBuffer createCommandBuffer(VkCommandBufferLevel level, bool begin = false)
{
VkCommandBufferAllocateInfo cmdBufAllocateInfo{};
cmdBufAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
cmdBufAllocateInfo.commandPool = commandPool;
cmdBufAllocateInfo.level = level;
cmdBufAllocateInfo.commandBufferCount = 1;
VkCommandBuffer cmdBuffer;
VK_CHECK_RESULT(vkAllocateCommandBuffers(logicalDevice, &cmdBufAllocateInfo, &cmdBuffer));
// If requested, also start recording for the new command buffer
if (begin) {
VkCommandBufferBeginInfo commandBufferBI{};
commandBufferBI.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
VK_CHECK_RESULT(vkBeginCommandBuffer(cmdBuffer, &commandBufferBI));
}
return cmdBuffer;
}
void beginCommandBuffer(VkCommandBuffer commandBuffer)
{
VkCommandBufferBeginInfo commandBufferBI{};
commandBufferBI.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
VK_CHECK_RESULT(vkBeginCommandBuffer(commandBuffer, &commandBufferBI));
}
/**
* Finish command buffer recording and submit it to a queue
*
* @param commandBuffer Command buffer to flush
* @param queue Queue to submit the command buffer to
* @param free (Optional) Free the command buffer once it has been submitted (Defaults to true)
*
* @note The queue that the command buffer is submitted to must be from the same family index as the pool it was allocated from
* @note Uses a fence to ensure command buffer has finished executing
*/
void flushCommandBuffer(VkCommandBuffer commandBuffer, VkQueue queue, bool free = true)
{
VK_CHECK_RESULT(vkEndCommandBuffer(commandBuffer));
VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBuffer;
// Create fence to ensure that the command buffer has finished executing
VkFenceCreateInfo fenceInfo{};
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
VkFence fence;
VK_CHECK_RESULT(vkCreateFence(logicalDevice, &fenceInfo, nullptr, &fence));
// Submit to the queue
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, fence));
// Wait for the fence to signal that command buffer has finished executing
VK_CHECK_RESULT(vkWaitForFences(logicalDevice, 1, &fence, VK_TRUE, 100000000000));
vkDestroyFence(logicalDevice, fence, nullptr);
if (free) {
vkFreeCommandBuffers(logicalDevice, commandPool, 1, &commandBuffer);
}
}
};
}

File diff suppressed because it is too large Load Diff

View File

@ -1,97 +1,90 @@
/* #ifndef VULKANTEXTURE_H
* Vulkan texture loader #define VULKANTEXTURE_H
*
* Copyright(C) by Sascha Willems - www.saschawillems.de
*
* This code is licensed under the MIT license(MIT) (http://opensource.org/licenses/MIT)
*/
#pragma once #include "VulkanBase_Marco.h"
#include "VulkanBuffer.h"
#include "VulkanDevice.h"
#include "VulkanTools.h"
#include <ktx.h>
#include <ktxvulkan.h>
#include <vulkan/vulkan.h>
#include <fstream> #include <fstream>
#include <stdlib.h> #include <stdlib.h>
#include <string> #include <string>
#include <vector> #include <vector>
#include "vulkan/vulkan.h" VULKANBASE_NAMESPACE_BEGIN
#include <ktx.h>
#include <ktxvulkan.h>
#include "VulkanBuffer.h"
#include "VulkanDevice.hpp"
//#include "VulkanTools.h"
#if defined(__ANDROID__)
# include <android/asset_manager.h>
#endif
namespace vks
{
class Texture class Texture
{ {
public: public:
vks::VulkanDevice * device; VulkanBase::VulkanDevice *device;
VkImage image; VkImage image;
VkImageLayout imageLayout; VkImageLayout imageLayout;
VkDeviceMemory deviceMemory; VkDeviceMemory deviceMemory;
VkImageView view; VkImageView view;
uint32_t width, height; uint32_t width, height;
uint32_t mipLevels; uint32_t mipLevels;
uint32_t layerCount; uint32_t layerCount;
VkDescriptorImageInfo descriptor; VkDescriptorImageInfo descriptor;
VkSampler sampler; VkSampler sampler;
void updateDescriptor(); void updateDescriptor();
void destroy(); void destroy();
ktxResult loadKTXFile(std::string filename, ktxTexture **target); ktxResult loadKTXFile(std::string filename, ktxTexture **target);
}; };
class Texture2D : public Texture class Texture2D : public Texture
{ {
public: public:
void loadFromFile( void loadFromFile(
std::string filename, std::string filename,
VkFormat format, VkFormat format,
vks::VulkanDevice *device, VulkanBase::VulkanDevice *device,
VkQueue copyQueue, VkQueue copyQueue,
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT, VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
bool forceLinear = false); bool forceLinear = false);
void fromBuffer( void loadFromBuffer(
void * buffer, void *buffer,
VkDeviceSize bufferSize, VkDeviceSize bufferSize,
VkFormat format, VkFormat format,
uint32_t texWidth, uint32_t texWidth,
uint32_t texHeight, uint32_t texHeight,
vks::VulkanDevice *device, VulkanBase::VulkanDevice *device,
VkQueue copyQueue, VkQueue copyQueue,
VkFilter filter = VK_FILTER_LINEAR, VkFilter filter = VK_FILTER_LINEAR,
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT, VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}; };
class Texture2DArray : public Texture class Texture2DArray : public Texture
{ {
public: public:
void loadFromFile( void loadFromFile(
std::string filename, std::string filename,
VkFormat format, VkFormat format,
vks::VulkanDevice *device, VulkanBase::VulkanDevice *device,
VkQueue copyQueue, VkQueue copyQueue,
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT, VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}; };
class TextureCubeMap : public Texture class TextureCubeMap : public Texture
{ {
public: public:
void loadFromFile( void loadFromFile(
std::string filename, std::string filename,
VkFormat format, VkFormat format,
vks::VulkanDevice *device, VulkanBase::VulkanDevice *device,
VkQueue copyQueue, VkQueue copyQueue,
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT, VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}; };
} // namespace vks
VULKANBASE_NAMESPACE_END
#endif

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

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,218 +54,228 @@
#include "camera.hpp" #include "camera.hpp"
#include "keycodes.hpp" #include "keycodes.hpp"
#include "VulkanDevice.hpp" #include "VulkanDevice.h"
#include "VulkanSwapChain.hpp" #include "VulkanSwapChain.hpp"
#include "imgui.h" #include "imgui.h"
class VulkanExampleBase class VulkanExampleBase
{ {
private: private:
float fpsTimer = 0.0f; float fpsTimer = 0.0f;
uint32_t frameCounter = 0; uint32_t frameCounter = 0;
uint32_t destWidth; uint32_t destWidth;
uint32_t destHeight; uint32_t destHeight;
bool resizing = false; bool resizing = false;
void handleMouseMove(int32_t x, int32_t y); void handleMouseMove(int32_t x, int32_t y);
PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallback; PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallback;
PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallback; PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallback;
VkDebugReportCallbackEXT debugReportCallback; VkDebugReportCallbackEXT debugReportCallback;
struct MultisampleTarget { struct MultisampleTarget
struct { {
VkImage image; struct
VkImageView view; {
VkDeviceMemory memory; VkImage image;
} color; VkImageView view;
struct { VkDeviceMemory memory;
VkImage image; } color;
VkImageView view; struct
VkDeviceMemory memory; {
} depth; VkImage image;
} multisampleTarget; VkImageView view;
VkDeviceMemory memory;
} depth;
} multisampleTarget;
protected: protected:
VkInstance instance; VkInstance instance;
VkPhysicalDevice physicalDevice; VkPhysicalDevice physicalDevice;
VkPhysicalDeviceProperties deviceProperties; VkPhysicalDeviceProperties deviceProperties;
VkPhysicalDeviceFeatures deviceFeatures; VkPhysicalDeviceFeatures deviceFeatures;
VkPhysicalDeviceMemoryProperties deviceMemoryProperties; VkPhysicalDeviceMemoryProperties deviceMemoryProperties;
VkDevice device; VkDevice device;
vks::VulkanDevice *vulkanDevice; VulkanBase::VulkanDevice *vulkanDevice;
VkQueue queue; VkQueue queue;
VkFormat depthFormat; VkFormat depthFormat;
VkCommandPool cmdPool; VkCommandPool cmdPool;
VkRenderPass renderPass; VkRenderPass renderPass;
std::vector<VkFramebuffer>frameBuffers; std::vector<VkFramebuffer> frameBuffers;
uint32_t currentBuffer = 0; uint32_t currentBuffer = 0;
VkDescriptorPool descriptorPool; VkDescriptorPool descriptorPool;
VkPipelineCache pipelineCache; VkPipelineCache pipelineCache;
VulkanSwapChain swapChain; VulkanSwapChain swapChain;
std::string title = "Vulkan Example"; std::string title = "Vulkan Example";
std::string name = "vulkanExample"; std::string name = "vulkanExample";
void windowResize(); void windowResize();
public:
static std::vector<const char*> args;
uint32_t selectedPhysicalDeviceIndex = 0;
bool prepared = false;
uint32_t width = 1280;
uint32_t height = 720;
float frameTimer = 1.0f;
Camera camera;
glm::vec2 mousePos;
bool paused = false;
uint32_t lastFPS = 0;
struct Settings { public:
bool validation = false; // 校验层开关 static std::vector<const char *> args;
bool fullscreen = false; // 全屏开关 uint32_t selectedPhysicalDeviceIndex = 0;
bool vsync = false; // 垂直同步开关 bool prepared = false;
bool multiSampling = true; // 多重采样 uint32_t width = 1280;
bool rotateModel = false; // 模型自旋转(暂时失效) uint32_t height = 720;
bool headless = false; // 无头开关 float frameTimer = 1.0f;
bool outputPNGimage = false; Camera camera;
bool enableSaveToImageSequeue = true; // 图片序列开关(暂时弃用) glm::vec2 mousePos;
uint32_t outputFrameCount = 100; // 图片序列结束帧 bool paused = false;
bool takeScreenShot = false; // 截屏(暂时弃用) uint32_t lastFPS = 0;
uint32_t startFrameCount = 1; // 图片序列开始帧
uint32_t videoFrameRate = 25; struct Settings
{
bool validation = false; // 校验层开关
bool fullscreen = false; // 全屏开关
bool vsync = false; // 垂直同步开关
bool multiSampling = true; // 多重采样
bool rotateModel = false; // 模型自旋转(暂时失效)
bool headless = false; // 无头开关
bool outputPNGimage = false;
bool enableSaveToImageSequeue = true; // 图片序列开关(暂时弃用)
uint32_t outputFrameCount = 100; // 图片序列结束帧
bool takeScreenShot = false; // 截屏(暂时弃用)
uint32_t startFrameCount = 1; // 图片序列开始帧
VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_4_BIT; // 多重采样倍率 uint32_t videoFrameRate = 25;
} settings;
struct DepthStencil {
VkImage image;
VkDeviceMemory mem;
VkImageView view;
} depthStencil;
struct GamePadState { VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_4_BIT; // 多重采样倍率
glm::vec2 axisLeft = glm::vec2(0.0f); } settings;
glm::vec2 axisRight = glm::vec2(0.0f);
} gamePadState;
struct MouseButtons { struct DepthStencil
bool left = false; {
bool right = false; VkImage image;
bool middle = false; VkDeviceMemory mem;
} mouseButtons; VkImageView view;
} depthStencil;
// OS specific struct GamePadState
{
glm::vec2 axisLeft = glm::vec2(0.0f);
glm::vec2 axisRight = glm::vec2(0.0f);
} gamePadState;
struct MouseButtons
{
bool left = false;
bool right = false;
bool middle = false;
} mouseButtons;
// OS specific
#if defined(_WIN32) #if defined(_WIN32)
HWND window; HWND window;
HINSTANCE windowInstance; HINSTANCE windowInstance;
#elif defined(VK_USE_PLATFORM_ANDROID_KHR) #elif defined(VK_USE_PLATFORM_ANDROID_KHR)
// true if application has focused, false if moved to background // true if application has focused, false if moved to background
bool focused = false; bool focused = false;
std::string androidProduct; std::string androidProduct;
struct TouchPoint { struct TouchPoint
int32_t id; {
float x; int32_t id;
float y; float x;
bool down = false; float y;
}; bool down = false;
float pinchDist = 0.0f; };
std::array<TouchPoint, 2> touchPoints; float pinchDist = 0.0f;
std::array<TouchPoint, 2> touchPoints;
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
wl_display *display = nullptr; wl_display *display = nullptr;
wl_registry *registry = nullptr; wl_registry *registry = nullptr;
wl_compositor *compositor = nullptr; wl_compositor *compositor = nullptr;
wl_shell *shell = nullptr; wl_shell *shell = nullptr;
wl_seat *seat = nullptr; wl_seat *seat = nullptr;
wl_pointer *pointer = nullptr; wl_pointer *pointer = nullptr;
wl_keyboard *keyboard = nullptr; wl_keyboard *keyboard = nullptr;
wl_surface *surface = nullptr; wl_surface *surface = nullptr;
wl_shell_surface *shell_surface = nullptr; wl_shell_surface *shell_surface = nullptr;
bool quit = false; bool quit = false;
#elif defined(_DIRECT2DISPLAY) #elif defined(_DIRECT2DISPLAY)
bool quit = false; bool quit = false;
#elif defined(VK_USE_PLATFORM_XCB_KHR) #elif defined(VK_USE_PLATFORM_XCB_KHR)
bool quit = false; bool quit = false;
xcb_connection_t *connection; xcb_connection_t *connection;
xcb_screen_t *screen; xcb_screen_t *screen;
xcb_window_t window; xcb_window_t window;
xcb_intern_atom_reply_t *atom_wm_delete_window; xcb_intern_atom_reply_t *atom_wm_delete_window;
#elif defined(VK_USE_PLATFORM_MACOS_MVK) #elif defined(VK_USE_PLATFORM_MACOS_MVK)
NSWindow* window; NSWindow *window;
#endif #endif
#if defined(_WIN32) #if defined(_WIN32)
HWND setupWindow(HINSTANCE hinstance, WNDPROC wndproc); HWND setupWindow(HINSTANCE hinstance, WNDPROC wndproc);
void handleMessages(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); void handleMessages(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
#elif defined(VK_USE_PLATFORM_ANDROID_KHR) #elif defined(VK_USE_PLATFORM_ANDROID_KHR)
static int32_t handleAppInput(struct android_app* app, AInputEvent* event); static int32_t handleAppInput(struct android_app *app, AInputEvent *event);
static void handleAppCommand(android_app* app, int32_t cmd); static void handleAppCommand(android_app *app, int32_t cmd);
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
wl_shell_surface *setupWindow(); wl_shell_surface *setupWindow();
void initWaylandConnection(); void initWaylandConnection();
static void registryGlobalCb(void *data, struct wl_registry *registry, static void registryGlobalCb(void *data, struct wl_registry *registry,
uint32_t name, const char *interface, uint32_t version); uint32_t name, const char *interface, uint32_t version);
void registryGlobal(struct wl_registry *registry, uint32_t name, void registryGlobal(struct wl_registry *registry, uint32_t name,
const char *interface, uint32_t version); const char *interface, uint32_t version);
static void registryGlobalRemoveCb(void *data, struct wl_registry *registry, static void registryGlobalRemoveCb(void *data, struct wl_registry *registry,
uint32_t name); uint32_t name);
static void seatCapabilitiesCb(void *data, wl_seat *seat, uint32_t caps); static void seatCapabilitiesCb(void *data, wl_seat *seat, uint32_t caps);
void seatCapabilities(wl_seat *seat, uint32_t caps); void seatCapabilities(wl_seat *seat, uint32_t caps);
static void pointerEnterCb(void *data, struct wl_pointer *pointer, static void pointerEnterCb(void *data, struct wl_pointer *pointer,
uint32_t serial, struct wl_surface *surface, wl_fixed_t sx, uint32_t serial, struct wl_surface *surface, wl_fixed_t sx,
wl_fixed_t sy); wl_fixed_t sy);
static void pointerLeaveCb(void *data, struct wl_pointer *pointer, static void pointerLeaveCb(void *data, struct wl_pointer *pointer,
uint32_t serial, struct wl_surface *surface); uint32_t serial, struct wl_surface *surface);
static void pointerMotionCb(void *data, struct wl_pointer *pointer, static void pointerMotionCb(void *data, struct wl_pointer *pointer,
uint32_t time, wl_fixed_t sx, wl_fixed_t sy); uint32_t time, wl_fixed_t sx, wl_fixed_t sy);
void pointerMotion(struct wl_pointer *pointer, void pointerMotion(struct wl_pointer *pointer,
uint32_t time, wl_fixed_t sx, wl_fixed_t sy); uint32_t time, wl_fixed_t sx, wl_fixed_t sy);
static void pointerButtonCb(void *data, struct wl_pointer *wl_pointer, static void pointerButtonCb(void *data, struct wl_pointer *wl_pointer,
uint32_t serial, uint32_t time, uint32_t button, uint32_t state); uint32_t serial, uint32_t time, uint32_t button, uint32_t state);
void pointerButton(struct wl_pointer *wl_pointer, void pointerButton(struct wl_pointer *wl_pointer,
uint32_t serial, uint32_t time, uint32_t button, uint32_t state); uint32_t serial, uint32_t time, uint32_t button, uint32_t state);
static void pointerAxisCb(void *data, struct wl_pointer *wl_pointer, static void pointerAxisCb(void *data, struct wl_pointer *wl_pointer,
uint32_t time, uint32_t axis, wl_fixed_t value); uint32_t time, uint32_t axis, wl_fixed_t value);
void pointerAxis(struct wl_pointer *wl_pointer, void pointerAxis(struct wl_pointer *wl_pointer,
uint32_t time, uint32_t axis, wl_fixed_t value); uint32_t time, uint32_t axis, wl_fixed_t value);
static void keyboardKeymapCb(void *data, struct wl_keyboard *keyboard, static void keyboardKeymapCb(void *data, struct wl_keyboard *keyboard,
uint32_t format, int fd, uint32_t size); uint32_t format, int fd, uint32_t size);
static void keyboardEnterCb(void *data, struct wl_keyboard *keyboard, static void keyboardEnterCb(void *data, struct wl_keyboard *keyboard,
uint32_t serial, struct wl_surface *surface, struct wl_array *keys); uint32_t serial, struct wl_surface *surface, struct wl_array *keys);
static void keyboardLeaveCb(void *data, struct wl_keyboard *keyboard, static void keyboardLeaveCb(void *data, struct wl_keyboard *keyboard,
uint32_t serial, struct wl_surface *surface); uint32_t serial, struct wl_surface *surface);
static void keyboardKeyCb(void *data, struct wl_keyboard *keyboard, static void keyboardKeyCb(void *data, struct wl_keyboard *keyboard,
uint32_t serial, uint32_t time, uint32_t key, uint32_t state); uint32_t serial, uint32_t time, uint32_t key, uint32_t state);
void keyboardKey(struct wl_keyboard *keyboard, void keyboardKey(struct wl_keyboard *keyboard,
uint32_t serial, uint32_t time, uint32_t key, uint32_t state); uint32_t serial, uint32_t time, uint32_t key, uint32_t state);
static void keyboardModifiersCb(void *data, struct wl_keyboard *keyboard, static void keyboardModifiersCb(void *data, struct wl_keyboard *keyboard,
uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched,
uint32_t mods_locked, uint32_t group); uint32_t mods_locked, uint32_t group);
#elif defined(_DIRECT2DISPLAY) #elif defined(_DIRECT2DISPLAY)
// //
#elif defined(VK_USE_PLATFORM_XCB_KHR) #elif defined(VK_USE_PLATFORM_XCB_KHR)
xcb_window_t setupWindow(); xcb_window_t setupWindow();
void initxcbConnection(); void initxcbConnection();
void handleEvent(const xcb_generic_event_t *event); void handleEvent(const xcb_generic_event_t *event);
#elif defined(VK_USE_PLATFORM_MACOS_MVK) #elif defined(VK_USE_PLATFORM_MACOS_MVK)
NSWindow* setupWindow(); NSWindow *setupWindow();
void mouseDragged(float x, float y); void mouseDragged(float x, float y);
void windowWillResize(float x, float y); void windowWillResize(float x, float y);
void windowDidResize(); void windowDidResize();
#endif #endif
VulkanExampleBase(); VulkanExampleBase();
virtual ~VulkanExampleBase(); virtual ~VulkanExampleBase();
void initVulkan();
virtual VkResult createInstance(bool enableValidation); void initVulkan();
virtual void render() = 0;
virtual void windowResized();
virtual void setupFrameBuffer();
virtual void prepare();
virtual void fileDropped(std::string filename);
void initSwapchain(); virtual VkResult createInstance(bool enableValidation);
void setupSwapChain(); virtual void render() = 0;
virtual void windowResized();
virtual void setupFrameBuffer();
virtual void prepare();
virtual void fileDropped(std::string filename);
void renderLoop(); void initSwapchain();
void renderFrame(); void setupSwapChain();
void renderLoop();
void renderFrame();
}; };

File diff suppressed because it is too large Load Diff

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,68 +23,72 @@
GLTFLOADER_NAMESPACE_BEGIN GLTFLOADER_NAMESPACE_BEGIN
struct ModelBuffer
{
VkBuffer buffer = VK_NULL_HANDLE;
VkDeviceMemory memory;
};
struct AABBDimensions
{
glm::vec3 min = glm::vec3(FLT_MAX);
glm::vec3 max = glm::vec3(-FLT_MAX);
};
class glTFMainModel class glTFMainModel
{ {
public: public:
glTFMainModel(); glTFMainModel();
~glTFMainModel(); ~glTFMainModel();
VkSamplerAddressMode getVkWrapMode(int32_t wrapMode); VkSamplerAddressMode getVkWrapMode(int32_t wrapMode);
VkFilter getVkFilterMode(int32_t filterMode); VkFilter getVkFilterMode(int32_t filterMode);
void getNodeProperty(const tinygltf::Node& node, const tinygltf::Model& model, size_t& vertexCount, size_t& indexCount); void getNodeProperty(const tinygltf::Node &node, const tinygltf::Model &model, size_t &vertexCount, size_t &indexCount);
void getSceneDimensions(); void getSceneDimensions();
void destroy(VkDevice device);
void loadNode(glTFNode* parent, const tinygltf::Node& node, uint32_t nodeIndex, const tinygltf::Model& model, LoaderInfo& loaderInfo, float globalscale);
void loadSkins(tinygltf::Model& gltfModel);
void loadTextures(tinygltf::Model& gltfModel, VulkanBase::VulkanDevice* device, VkQueue transferQueue);
void loadTextureSamplers(tinygltf::Model& gltfModel);
void loadMaterials(tinygltf::Model& gltfModel);
void loadAnimations(tinygltf::Model& gltfModel);
void loadFromFile(std::string filename, VulkanBase::VulkanDevice* device, VkQueue transferQueue, float scale = 1.0f);
void drawNode(glTFNode* node, VkCommandBuffer commandBuffer); ModelBuffer &getModelVertex();
void draw(VkCommandBuffer commandBuffer); ModelBuffer &getModelIndex();
void calculateBoundingBox(glTFNode* node, glTFNode* parent); void destroy(VkDevice device);
void updateAnimation(uint32_t index, float time);
glTFNode* findNode(glTFNode* parent, uint32_t index); void loadNode(glTFNode *parent, const tinygltf::Node &node, uint32_t nodeIndex, const tinygltf::Model &model, LoaderInfo &loaderInfo, float globalscale);
glTFNode* nodeFromIndex(uint32_t index); void loadSkins(tinygltf::Model &gltfModel);
void loadTextures(tinygltf::Model &gltfModel, VulkanBase::VulkanDevice *device, VkQueue transferQueue);
void loadTextureSamplers(tinygltf::Model &gltfModel);
void loadMaterials(tinygltf::Model &gltfModel);
void loadAnimations(tinygltf::Model &gltfModel);
void loadFromFile(std::string filename, VulkanBase::VulkanDevice *device, VkQueue transferQueue, float scale = 1.0f);
void drawNode(glTFNode *node, VkCommandBuffer commandBuffer);
void draw(VkCommandBuffer commandBuffer);
void calculateBoundingBox(glTFNode *node, glTFNode *parent);
void updateAnimation(uint32_t index, float time);
glTFNode *findNode(glTFNode *parent, uint32_t index);
glTFNode *nodeFromIndex(uint32_t index);
private: private:
VulkanBase::VulkanDevice *m_device;
VulkanBase::VulkanDevice* m_device; ModelBuffer m_vertices;
ModelBuffer m_indices;
struct Vertices { glm::mat4 m_aabb;
VkBuffer buffer = VK_NULL_HANDLE;
VkDeviceMemory memory;
} m_vertices;
struct Indices {
VkBuffer buffer = VK_NULL_HANDLE;
VkDeviceMemory memory;
} m_indices;
glm::mat4 m_aabb; std::vector<glTFNode *> m_nodes;
std::vector<glTFNode *> m_linearNodes;
std::vector<glTFNode*> m_nodes; std::vector<glTFSkin *> m_skins;
std::vector<glTFNode*> m_linearNodes;
std::vector<glTFSkin*> m_skins; std::vector<glTFTexture> m_textures;
std::vector<VulkanBase::VulkanTextureSampler> m_textureSamplers;
std::vector<glTFTexture> m_textures; std::vector<glTFMaterial> m_materials;
std::vector<VulkanBase::VulkanTextureSampler> m_textureSamplers; std::vector<glTFAnimation> m_animations;
std::vector<glTFMaterial> m_materials; std::vector<std::string> m_extensions;
std::vector<glTFAnimation> m_animations;
std::vector<std::string> m_extensions;
struct Dimensions {
glm::vec3 min = glm::vec3(FLT_MAX);
glm::vec3 max = glm::vec3(-FLT_MAX);
} m_dimensions;
AABBDimensions m_dimensions;
}; };
GLTFLOADER_NAMESPACE_END GLTFLOADER_NAMESPACE_END
#endif // !GLTFMAINMODEL_h #endif // !GLTFMAINMODEL_h

View File

@ -1,6 +1,5 @@
#include "glTFMaterial.h" #include "glTFMaterial.h"
GLTFLOADER_NAMESPACE_BEGIN GLTFLOADER_NAMESPACE_BEGIN
glTFMaterial::glTFMaterial() glTFMaterial::glTFMaterial()
@ -13,72 +12,81 @@ glTFMaterial::~glTFMaterial()
void glTFMaterial::setDoublesided(bool value) void glTFMaterial::setDoublesided(bool value)
{ {
m_doubleSided = value; m_doubleSided = value;
} }
bool glTFMaterial::getDoublesided() bool glTFMaterial::getDoublesided()
{ {
return m_doubleSided; return m_doubleSided;
} }
void glTFMaterial::setAlphaMode(AlphaMode value) void glTFMaterial::setAlphaMode(AlphaMode value)
{ {
m_alphaMode = value; m_alphaMode = value;
} }
AlphaMode glTFMaterial::getAlphaMode() AlphaMode glTFMaterial::getAlphaMode()
{ {
return m_alphaMode; return m_alphaMode;
} }
void glTFMaterial::setAlphaCutOff(float value) void glTFMaterial::setAlphaCutOff(float value)
{ {
m_alphaCutoff = value; m_alphaCutoff = value;
} }
float glTFMaterial::getAlphaCutOff() float glTFMaterial::getAlphaCutOff()
{ {
return m_alphaCutoff; return m_alphaCutoff;
} }
TextureCoordSet* glTFMaterial::getTextureCoordSet() TextureCoordSet *glTFMaterial::getTextureCoordSet()
{ {
return m_texCoordSets; return m_texCoordSets;
} }
void glTFMaterial::setTextureCoordSet(TextureCoordSet* value) void glTFMaterial::setTextureCoordSet(TextureCoordSet *value)
{ {
m_texCoordSets = value; m_texCoordSets = value;
} }
PbrTextureExtension* glTFMaterial::getTextureExtension() PBR::PbrTextureExtension *glTFMaterial::getTextureExtension()
{ {
return m_textureExtension; return m_textureExtension;
} }
void glTFMaterial::setPbrTextureExtension(PbrTextureExtension* value) void glTFMaterial::setPbrTextureExtension(PBR::PbrTextureExtension *value)
{ {
m_textureExtension = value; m_textureExtension = value;
} }
PbrBaseTexture* glTFMaterial::getPbrBaseTexture() PBR::PbrBaseTexture *glTFMaterial::getPbrBaseTexture()
{ {
return m_pbrBaseTexture; return m_pbrBaseTexture;
} }
void glTFMaterial::setPbrBaseTexture(PbrBaseTexture* value) void glTFMaterial::setPbrBaseTexture(PBR::PbrBaseTexture *value)
{ {
m_pbrBaseTexture = value; m_pbrBaseTexture = value;
} }
PbrWorkFlow* glTFMaterial::getPbrWorkFlow() PBR::PbrWorkFlow *glTFMaterial::getPbrWorkFlow()
{ {
return m_pbrWorkFlow; return m_pbrWorkFlow;
} }
void glTFMaterial::setPbrWorkFlow() void glTFMaterial::setPbrWorkFlow(PBR::PbrWorkFlow *value)
{ {
m_pbrWorkFlow; m_pbrWorkFlow = value;
}
void glTFMaterial::setDescriptorSet(VkDescriptorSet value)
{
m_descriptorSet = value;
}
VkDescriptorSet glTFMaterial::getDescriptorSet()
{
return m_descriptorSet;
} }
GLTFLOADER_NAMESPACE_END GLTFLOADER_NAMESPACE_END

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

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,15 +2,10 @@
GLTFLOADER_NAMESPACE_BEGIN GLTFLOADER_NAMESPACE_BEGIN
glTFPrimitive::glTFPrimitive(uint32_t firstIndex, uint32_t indexCount, uint32_t vertexCount, glTFMaterial &material)
: m_firstIndex(firstIndex), m_indexCount(indexCount), m_vertexCount(vertexCount), m_material(material)
glTFPrimitive::glTFPrimitive(uint32_t firstIndex, uint32_t indexCount, uint32_t vertexCount, glTFMaterial& material)
:m_firstIndex(firstIndex)
,m_indexCount(indexCount)
,m_vertexCount(vertexCount)
,m_material(material)
{ {
m_hasIndices = indexCount > 0; m_hasIndices = indexCount > 0;
} }
glTFPrimitive::~glTFPrimitive() glTFPrimitive::~glTFPrimitive()
@ -19,33 +14,60 @@ glTFPrimitive::~glTFPrimitive()
void glTFPrimitive::setBoundingBox(glm::vec3 min, glm::vec3 max) void glTFPrimitive::setBoundingBox(glm::vec3 min, glm::vec3 max)
{ {
m_boundingBox.setBoundingBox(min, max); m_boundingBox.setBoundingBox(min, max);
} }
glTFBoundingBox glTFPrimitive::getBoundingBox() glTFBoundingBox glTFPrimitive::getBoundingBox()
{ {
return m_boundingBox; return m_boundingBox;
} }
void glTFPrimitive::setIndexCount(unsigned int indexCount) void glTFPrimitive::setIndexCount(unsigned int indexCount)
{ {
m_indexCount = indexCount; m_indexCount = indexCount;
} }
unsigned int glTFPrimitive::getIndexCount() unsigned int glTFPrimitive::getIndexCount()
{ {
return m_indexCount; return m_indexCount;
} }
void glTFPrimitive::setFirstIndex(unsigned int firstIndex) void glTFPrimitive::setFirstIndex(unsigned int firstIndex)
{ {
m_firstIndex = firstIndex; m_firstIndex = firstIndex;
} }
unsigned int glTFPrimitive::getFirstIndex() unsigned int glTFPrimitive::getFirstIndex()
{ {
return m_firstIndex; return m_firstIndex;
} }
void glTFPrimitive::setGltfMaterial(glTFMaterial &material)
{
m_material = material;
}
glTFMaterial &glTFPrimitive::getGltfMaterial()
{
return m_material;
}
void glTFPrimitive::setHasIndices(bool hasIndices)
{
m_hasIndices = hasIndices;
}
bool glTFPrimitive::getHasIndices()
{
return m_hasIndices;
}
void glTFPrimitive::setVertexCount(unsigned int vertexCount)
{
m_vertexCount = vertexCount;
}
unsigned int glTFPrimitive::getVertexCount()
{
return m_vertexCount;
}
GLTFLOADER_NAMESPACE_END GLTFLOADER_NAMESPACE_END

View File

@ -3,44 +3,47 @@
#include "glTFModel_Marco.h" #include "glTFModel_Marco.h"
#include "glTFMaterial.h"
#include "glTFBoundingBox.h" #include "glTFBoundingBox.h"
#include "glTFMaterial.h"
#include <glm/glm.hpp> #include <glm/glm.hpp>
GLTFLOADER_NAMESPACE_BEGIN GLTFLOADER_NAMESPACE_BEGIN
class GLTFLOADER_API glTFPrimitive class GLTFLOADER_API glTFPrimitive
{ {
public: public:
glTFPrimitive(uint32_t firstIndex, uint32_t indexCount, uint32_t vertexCount, glTFMaterial& material); glTFPrimitive(uint32_t firstIndex, uint32_t indexCount, uint32_t vertexCount, glTFMaterial &material);
~glTFPrimitive();
void setBoundingBox(glm::vec3 min, glm::vec3 max); ~glTFPrimitive();
glTFBoundingBox getBoundingBox();
void setIndexCount(unsigned int indexCount); void setBoundingBox(glm::vec3 min, glm::vec3 max);
unsigned int getIndexCount(); glTFBoundingBox getBoundingBox();
void setFirstIndex(unsigned int firstIndex); void setIndexCount(unsigned int indexCount);
unsigned int getFirstIndex(); unsigned int getIndexCount();
void setFirstIndex(unsigned int firstIndex);
unsigned int getFirstIndex();
void setGltfMaterial(glTFMaterial &material);
glTFMaterial &getGltfMaterial();
void setHasIndices(bool hasIndices);
bool getHasIndices();
void setVertexCount(unsigned int vertexCount);
unsigned int getVertexCount();
private: private:
unsigned int m_firstIndex;
unsigned int m_firstIndex; unsigned int m_indexCount;
unsigned int m_indexCount; unsigned int m_vertexCount;
unsigned int m_vertexCount; glTFMaterial &m_material;
glTFMaterial& m_material; bool m_hasIndices;
bool m_hasIndices; glTFBoundingBox m_boundingBox;
glTFBoundingBox m_boundingBox;
}; };
GLTFLOADER_NAMESPACE_END GLTFLOADER_NAMESPACE_END
#endif // !GLTFPRIMITIVE_H #endif // !GLTFPRIMITIVE_H

View File

@ -8,43 +8,34 @@
#include <tiny_gltf.h> #include <tiny_gltf.h>
GLTFLOADER_NAMESPACE_BEGIN GLTFLOADER_NAMESPACE_BEGIN
/// @brief gltf模型的贴图 /// @brief gltf模型的贴图
class GLTFLOADER_API glTFTexture class GLTFLOADER_API glTFTexture
{ {
public: public:
glTFTexture(); glTFTexture();
~glTFTexture(); ~glTFTexture();
void updateDescriptor(); void updateDescriptor();
void destroy(); void destroy();
void fromglTfImage(tinygltf::Image& gltfimage, VulkanBase::VulkanTextureSampler textureSampler, VulkanBase::VulkanDevice* device, VkQueue copyQueue); void fromglTfImage(tinygltf::Image &gltfimage, VulkanBase::VulkanTextureSampler textureSampler, VulkanBase::VulkanDevice *device, VkQueue copyQueue);
private: private:
VulkanBase::VulkanDevice *m_device;
VulkanBase::VulkanDevice* m_device; VkImage m_image;
VkImage m_image; VkImageLayout m_imageLayout;
VkImageLayout m_imageLayout; VkDeviceMemory m_deviceMemory;
VkDeviceMemory m_deviceMemory; VkImageView m_view;
VkImageView m_view; unsigned int m_width, m_height;
unsigned int m_width, m_height; unsigned int m_mipLevels;
unsigned int m_mipLevels; unsigned int m_layerCount;
unsigned int m_layerCount; VkDescriptorImageInfo m_descriptor;
VkDescriptorImageInfo m_descriptor; VkSampler m_sampler;
VkSampler m_sampler;
}; };
GLTFLOADER_NAMESPACE_END GLTFLOADER_NAMESPACE_END
#endif // !GLTFTEXTURE_H #endif // !GLTFTEXTURE_H

View File

@ -1,6 +1,6 @@
#include "PbrBaseTexture.h" #include "PbrBaseTexture.h"
GLTFLOADER_NAMESPACE_BEGIN PBR_NAMESPACE_BEGIN
PbrBaseTexture::PbrBaseTexture() PbrBaseTexture::PbrBaseTexture()
{ {
@ -10,95 +10,94 @@ PbrBaseTexture::~PbrBaseTexture()
{ {
} }
void PbrBaseTexture::setBaseColorTexture(glTFTexture* value) void PbrBaseTexture::setBaseColorTexture(glTFLoader::glTFTexture *value)
{ {
m_baseColorTexture = value; m_baseColorTexture = value;
} }
glTFTexture* PbrBaseTexture::getBaseColorTexture() glTFLoader::glTFTexture *PbrBaseTexture::getBaseColorTexture()
{ {
return m_baseColorTexture; return m_baseColorTexture;
} }
void PbrBaseTexture::setBaseColorFactor(glm::vec4 value) void PbrBaseTexture::setBaseColorFactor(glm::vec4 value)
{ {
m_baseColorFactor = value; m_baseColorFactor = value;
} }
glm::vec4 PbrBaseTexture::getBaseColorFactor() glm::vec4 PbrBaseTexture::getBaseColorFactor()
{ {
return m_baseColorFactor; return m_baseColorFactor;
} }
void PbrBaseTexture::setNormalTexture(glTFTexture* value) void PbrBaseTexture::setNormalTexture(glTFLoader::glTFTexture *value)
{ {
m_normalTexture = value; m_normalTexture = value;
} }
glTFTexture* PbrBaseTexture::getNormalTexture() glTFLoader::glTFTexture *PbrBaseTexture::getNormalTexture()
{ {
return m_normalTexture; return m_normalTexture;
} }
void PbrBaseTexture::setMetallicRoughnessTexture(glTFTexture* value) void PbrBaseTexture::setMetallicRoughnessTexture(glTFLoader::glTFTexture *value)
{ {
m_metallicRoughnessTexture = value; m_metallicRoughnessTexture = value;
} }
glTFTexture* PbrBaseTexture::getMetalicRoughnessTexture() glTFLoader::glTFTexture *PbrBaseTexture::getMetalicRoughnessTexture()
{ {
return m_metallicRoughnessTexture; return m_metallicRoughnessTexture;
} }
void PbrBaseTexture::setMetallicFactor(float value) void PbrBaseTexture::setMetallicFactor(float value)
{ {
m_metallicFactor = value; m_metallicFactor = value;
} }
float PbrBaseTexture::getMetallicFactor() float PbrBaseTexture::getMetallicFactor()
{ {
return m_metallicFactor; return m_metallicFactor;
} }
void PbrBaseTexture::setRoughnessFactor(float value) void PbrBaseTexture::setRoughnessFactor(float value)
{ {
m_roughnessFactor = value; m_roughnessFactor = value;
} }
float PbrBaseTexture::getRoughnessFactor() float PbrBaseTexture::getRoughnessFactor()
{ {
return m_roughnessFactor; return m_roughnessFactor;
} }
void PbrBaseTexture::setEmissiveTexture(glTFTexture* value) void PbrBaseTexture::setEmissiveTexture(glTFLoader::glTFTexture *value)
{ {
m_emissiveTexture = value; m_emissiveTexture = value;
} }
glTFTexture* PbrBaseTexture::getEmissiveTexture() glTFLoader::glTFTexture *PbrBaseTexture::getEmissiveTexture()
{ {
return m_emissiveTexture; return m_emissiveTexture;
} }
void PbrBaseTexture::setEmissiveFactor(glm::vec4 value) void PbrBaseTexture::setEmissiveFactor(glm::vec4 value)
{ {
m_emissiveFactor = value; m_emissiveFactor = value;
} }
glm::vec4 PbrBaseTexture::getEmissiveFactor() glm::vec4 PbrBaseTexture::getEmissiveFactor()
{ {
return m_emissiveFactor; return m_emissiveFactor;
} }
void PbrBaseTexture::setOcclusionTexture(glTFTexture* value) void PbrBaseTexture::setOcclusionTexture(glTFLoader::glTFTexture *value)
{ {
m_occlusionTexture = value; m_occlusionTexture = value;
} }
glTFTexture* PbrBaseTexture::getOcclusionTexture() glTFLoader::glTFTexture *PbrBaseTexture::getOcclusionTexture()
{ {
return m_occlusionTexture; return m_occlusionTexture;
} }
GLTFLOADER_NAMESPACE_END PBR_NAMESPACE_END

View File

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

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,46 +10,44 @@ PbrTextureExtension::~PbrTextureExtension()
{ {
} }
void PbrTextureExtension::setSpecularGlossinessTexture(glTFTexture* _texture) void PbrTextureExtension::setSpecularGlossinessTexture(glTFLoader::glTFTexture *_texture)
{ {
m_specularGlossinessTexture = _texture; m_specularGlossinessTexture = _texture;
} }
glTFTexture* PbrTextureExtension::getSpecularGlossinessTexture() glTFLoader::glTFTexture *PbrTextureExtension::getSpecularGlossinessTexture()
{ {
return m_specularGlossinessTexture; return m_specularGlossinessTexture;
} }
void PbrTextureExtension::setDiffuseTexture(glTFTexture* _texture) void PbrTextureExtension::setDiffuseTexture(glTFLoader::glTFTexture *_texture)
{ {
m_diffuseTexture = _texture; m_diffuseTexture = _texture;
} }
glTFTexture* PbrTextureExtension::getDiffuseTexture() glTFLoader::glTFTexture *PbrTextureExtension::getDiffuseTexture()
{ {
return m_diffuseTexture; return m_diffuseTexture;
} }
void PbrTextureExtension::setDiffuseFactor(glm::vec4 value) void PbrTextureExtension::setDiffuseFactor(glm::vec4 value)
{ {
m_diffuseFactor = value; m_diffuseFactor = value;
} }
glm::vec4 PbrTextureExtension::getDiffuseFactor() glm::vec4 PbrTextureExtension::getDiffuseFactor()
{ {
return m_diffuseFactor; return m_diffuseFactor;
} }
void PbrTextureExtension::setSpecularFactor(glm::vec3 value) void PbrTextureExtension::setSpecularFactor(glm::vec3 value)
{ {
m_specularFactor = value; m_specularFactor = value;
} }
glm::vec3 PbrTextureExtension::getSpecularFactor() glm::vec3 PbrTextureExtension::getSpecularFactor()
{ {
return m_specularFactor; return m_specularFactor;
} }
PBR_NAMESPACE_END
GLTFLOADER_NAMESPACE_END

View File

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

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

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