调整结构

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,17 +1,7 @@
/*
* 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.
* *
@ -123,13 +113,25 @@ namespace vks
*/ */
void Buffer::destroy() void Buffer::destroy()
{ {
if (buffer) if (mapped)
{ {
unmap();
}
vkDestroyBuffer(device, buffer, nullptr); vkDestroyBuffer(device, buffer, nullptr);
}
if (memory)
{
vkFreeMemory(device, memory, nullptr); vkFreeMemory(device, memory, nullptr);
buffer = VK_NULL_HANDLE;
memory = VK_NULL_HANDLE;
}
void Buffer::create(VulkanBase::VulkanDevice *device, VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkDeviceSize size, bool map)
{
VkDevice logicalDevice = device->getLogicalDevice();
device->createBuffer(usageFlags, memoryPropertyFlags, size, &buffer, &memory);
descriptor = {buffer, 0, size};
if (map)
{
VK_CHECK_RESULT(vkMapMemory(logicalDevice, memory, 0, size, 0, &mapped));
} }
} }
};
VULKANBASE_NAMESPACE_END

View File

@ -1,22 +1,14 @@
/*
* 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
@ -29,11 +21,13 @@ namespace vks
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;
void create(VulkanDevice *device, VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkDeviceSize size, bool map = true);
VkResult map(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0); VkResult map(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0);
void unmap(); void unmap();
VkResult bind(VkDeviceSize offset = 0); VkResult bind(VkDeviceSize offset = 0);
@ -43,4 +37,7 @@ namespace vks
VkResult invalidate(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0); VkResult invalidate(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0);
void destroy(); void destroy();
}; };
}
VULKANBASE_NAMESPACE_END
#endif

View File

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

View File

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

View File

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

View File

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

View File

@ -1,37 +1,27 @@
/* #ifndef VULKANTEXTURE_H
* Vulkan texture loader #define VULKANTEXTURE_H
*
* Copyright(C) by Sascha Willems - www.saschawillems.de
*
* This code is licensed under the MIT license(MIT) (http://opensource.org/licenses/MIT)
*/
#pragma once #include "VulkanBase_Marco.h"
#include "VulkanBuffer.h"
#include "VulkanDevice.h"
#include "VulkanTools.h"
#include <ktx.h>
#include <ktxvulkan.h>
#include <vulkan/vulkan.h>
#include <fstream> #include <fstream>
#include <stdlib.h> #include <stdlib.h>
#include <string> #include <string>
#include <vector> #include <vector>
#include "vulkan/vulkan.h" VULKANBASE_NAMESPACE_BEGIN
#include <ktx.h>
#include <ktxvulkan.h>
#include "VulkanBuffer.h"
#include "VulkanDevice.hpp"
//#include "VulkanTools.h"
#if defined(__ANDROID__)
# include <android/asset_manager.h>
#endif
namespace vks
{
class Texture class Texture
{ {
public: public:
vks::VulkanDevice * device; VulkanBase::VulkanDevice *device;
VkImage image; VkImage image;
VkImageLayout imageLayout; VkImageLayout imageLayout;
VkDeviceMemory deviceMemory; VkDeviceMemory deviceMemory;
@ -53,18 +43,18 @@ class Texture2D : public Texture
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,
@ -77,7 +67,7 @@ class Texture2DArray : public Texture
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);
@ -89,9 +79,12 @@ class TextureCubeMap : public Texture
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>
@ -141,5 +143,5 @@ namespace vks
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);
}
};

View File

@ -8,19 +8,21 @@
#include "VulkanExampleBase.h" #include "VulkanExampleBase.h"
std::vector<const char *> VulkanExampleBase::args; std::vector<const char *> VulkanExampleBase::args;
VKAPI_ATTR VkBool32 VKAPI_CALL debugMessageCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg, void *pUserData) VKAPI_ATTR VkBool32 VKAPI_CALL debugMessageCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg, void *pUserData)
{ {
std::string prefix(""); std::string prefix("");
if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) { if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT)
{
prefix += "ERROR:"; prefix += "ERROR:";
}; };
if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) { if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT)
{
prefix += "WARNING:"; prefix += "WARNING:";
}; };
if (flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) { if (flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT)
{
prefix += "DEBUG:"; prefix += "DEBUG:";
} }
std::stringstream debugMessage; std::stringstream debugMessage;
@ -77,11 +79,8 @@ VkResult VulkanExampleBase::createInstance(bool enableValidation)
instanceExtensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); instanceExtensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
instanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); instanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
#endif #endif
} }
VkInstanceCreateInfo instanceCreateInfo = {}; VkInstanceCreateInfo instanceCreateInfo = {};
instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
instanceCreateInfo.pNext = NULL; instanceCreateInfo.pNext = NULL;
@ -93,21 +92,21 @@ VkResult VulkanExampleBase::createInstance(bool enableValidation)
if (instanceExtensions.size() > 0) if (instanceExtensions.size() > 0)
{ {
if (settings.validation) { if (settings.validation)
{
instanceExtensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME); instanceExtensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
} }
instanceCreateInfo.enabledExtensionCount = (uint32_t)instanceExtensions.size(); instanceCreateInfo.enabledExtensionCount = (uint32_t)instanceExtensions.size();
instanceCreateInfo.ppEnabledExtensionNames = instanceExtensions.data(); instanceCreateInfo.ppEnabledExtensionNames = instanceExtensions.data();
} }
std::vector<const char *> validationLayerNames; std::vector<const char *> validationLayerNames;
if (settings.validation) { if (settings.validation)
{
validationLayerNames.push_back("VK_LAYER_KHRONOS_validation"); validationLayerNames.push_back("VK_LAYER_KHRONOS_validation");
instanceCreateInfo.enabledLayerCount = (uint32_t)validationLayerNames.size(); instanceCreateInfo.enabledLayerCount = (uint32_t)validationLayerNames.size();
instanceCreateInfo.ppEnabledLayerNames = validationLayerNames.data(); instanceCreateInfo.ppEnabledLayerNames = validationLayerNames.data();
} }
return vkCreateInstance(&instanceCreateInfo, nullptr, &instance); return vkCreateInstance(&instanceCreateInfo, nullptr, &instance);
} }
void VulkanExampleBase::prepare() void VulkanExampleBase::prepare()
{ {
@ -135,7 +134,8 @@ void VulkanExampleBase::prepare()
Render pass Render pass
*/ */
if (settings.multiSampling) { if (settings.multiSampling)
{
std::array<VkAttachmentDescription, 4> attachments = {}; std::array<VkAttachmentDescription, 4> attachments = {};
// Multisampled attachment that we render to // Multisampled attachment that we render to
@ -228,7 +228,8 @@ void VulkanExampleBase::prepare()
renderPassCI.pDependencies = dependencies.data(); renderPassCI.pDependencies = dependencies.data();
VK_CHECK_RESULT(vkCreateRenderPass(device, &renderPassCI, nullptr, &renderPass)); VK_CHECK_RESULT(vkCreateRenderPass(device, &renderPassCI, nullptr, &renderPass));
} }
else { else
{
std::array<VkAttachmentDescription, 2> attachments = {}; std::array<VkAttachmentDescription, 2> attachments = {};
// Color attachment // Color attachment
attachments[0].format = swapChain.colorFormat; attachments[0].format = swapChain.colorFormat;
@ -325,7 +326,8 @@ void VulkanExampleBase::renderFrame()
frameTimer = (float)tDiff / 1000.0f; frameTimer = (float)tDiff / 1000.0f;
camera.update(frameTimer); camera.update(frameTimer);
fpsTimer += (float)tDiff; fpsTimer += (float)tDiff;
if (fpsTimer > 1000.0f) { if (fpsTimer > 1000.0f)
{
lastFPS = static_cast<uint32_t>((float)frameCounter * (1000.0f / fpsTimer)); lastFPS = static_cast<uint32_t>((float)frameCounter * (1000.0f / fpsTimer));
fpsTimer = 0.0f; fpsTimer = 0.0f;
frameCounter = 0; frameCounter = 0;
@ -339,16 +341,20 @@ void VulkanExampleBase::renderLoop()
#if defined(_WIN32) #if defined(_WIN32)
MSG msg; MSG msg;
bool quitMessageReceived = false; bool quitMessageReceived = false;
while (!quitMessageReceived) { while (!quitMessageReceived)
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { {
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg); TranslateMessage(&msg);
DispatchMessage(&msg); DispatchMessage(&msg);
if (msg.message == WM_QUIT) { if (msg.message == WM_QUIT)
{
quitMessageReceived = true; quitMessageReceived = true;
break; break;
} }
} }
if (!IsIconic(window)) { if (!IsIconic(window))
{
renderFrame(); renderFrame();
} }
} }
@ -408,13 +414,17 @@ void VulkanExampleBase::renderLoop()
if (camera.type != Camera::CameraType::firstperson) if (camera.type != Camera::CameraType::firstperson)
{ {
// Rotate // Rotate
if (std::abs(gamePadState.axisLeft.x) > deadZone) { if (std::abs(gamePadState.axisLeft.x) > deadZone)
{
camera.rotate(glm::vec3(0.0f, gamePadState.axisLeft.x * 0.5f, 0.0f)); camera.rotate(glm::vec3(0.0f, gamePadState.axisLeft.x * 0.5f, 0.0f));
} }
if (std::abs(gamePadState.axisLeft.y) > deadZone) { if (std::abs(gamePadState.axisLeft.y) > deadZone)
{
camera.rotate(glm::vec3(gamePadState.axisLeft.y * 0.5f, 0.0f, 0.0f)); camera.rotate(glm::vec3(gamePadState.axisLeft.y * 0.5f, 0.0f, 0.0f));
} }
} else { }
else
{
camera.updatePad(gamePadState.axisLeft, gamePadState.axisRight, frameTimer); camera.updatePad(gamePadState.axisLeft, gamePadState.axisRight, frameTimer);
} }
} }
@ -504,22 +514,33 @@ VulkanExampleBase::VulkanExampleBase()
// Parse command line arguments // Parse command line arguments
for (size_t i = 0; i < args.size(); i++) for (size_t i = 0; i < args.size(); i++)
{ {
if (args[i] == std::string("-validation")) { if (args[i] == std::string("-validation"))
{
settings.validation = true; settings.validation = true;
} }
if (args[i] == std::string("-vsync")) { if (args[i] == std::string("-vsync"))
{
settings.vsync = true; settings.vsync = true;
} }
if ((args[i] == std::string("-f")) || (args[i] == std::string("--fullscreen"))) { if ((args[i] == std::string("-f")) || (args[i] == std::string("--fullscreen")))
{
settings.fullscreen = true; settings.fullscreen = true;
} }
if ((args[i] == std::string("-w")) || (args[i] == std::string("--width"))) { if ((args[i] == std::string("-w")) || (args[i] == std::string("--width")))
{
uint32_t w = strtol(args[i + 1], &numConvPtr, 10); uint32_t w = strtol(args[i + 1], &numConvPtr, 10);
if (numConvPtr != args[i + 1]) { width = w; }; if (numConvPtr != args[i + 1])
{
width = w;
};
} }
if ((args[i] == std::string("-h")) || (args[i] == std::string("--height"))) { if ((args[i] == std::string("-h")) || (args[i] == std::string("--height")))
{
uint32_t h = strtol(args[i + 1], &numConvPtr, 10); uint32_t h = strtol(args[i + 1], &numConvPtr, 10);
if (numConvPtr != args[i + 1]) { height = h; }; if (numConvPtr != args[i + 1])
{
height = h;
};
} }
} }
@ -551,7 +572,8 @@ VulkanExampleBase::~VulkanExampleBase()
swapChain.cleanup(); swapChain.cleanup();
vkDestroyDescriptorPool(device, descriptorPool, nullptr); vkDestroyDescriptorPool(device, descriptorPool, nullptr);
vkDestroyRenderPass(device, renderPass, nullptr); vkDestroyRenderPass(device, renderPass, nullptr);
for (uint32_t i = 0; i < frameBuffers.size(); i++) { for (uint32_t i = 0; i < frameBuffers.size(); i++)
{
vkDestroyFramebuffer(device, frameBuffers[i], nullptr); vkDestroyFramebuffer(device, frameBuffers[i], nullptr);
} }
vkDestroyImageView(device, depthStencil.view, nullptr); vkDestroyImageView(device, depthStencil.view, nullptr);
@ -559,7 +581,8 @@ VulkanExampleBase::~VulkanExampleBase()
vkFreeMemory(device, depthStencil.mem, nullptr); vkFreeMemory(device, depthStencil.mem, nullptr);
vkDestroyPipelineCache(device, pipelineCache, nullptr); vkDestroyPipelineCache(device, pipelineCache, nullptr);
vkDestroyCommandPool(device, cmdPool, nullptr); vkDestroyCommandPool(device, cmdPool, nullptr);
if (settings.multiSampling) { if (settings.multiSampling)
{
vkDestroyImage(device, multisampleTarget.color.image, nullptr); vkDestroyImage(device, multisampleTarget.color.image, nullptr);
vkDestroyImageView(device, multisampleTarget.color.view, nullptr); vkDestroyImageView(device, multisampleTarget.color.view, nullptr);
vkFreeMemory(device, multisampleTarget.color.memory, nullptr); vkFreeMemory(device, multisampleTarget.color.memory, nullptr);
@ -568,7 +591,8 @@ VulkanExampleBase::~VulkanExampleBase()
vkFreeMemory(device, multisampleTarget.depth.memory, nullptr); vkFreeMemory(device, multisampleTarget.depth.memory, nullptr);
} }
delete vulkanDevice; delete vulkanDevice;
if (settings.validation) { if (settings.validation)
{
vkDestroyDebugReportCallback(instance, debugReportCallback, nullptr); vkDestroyDebugReportCallback(instance, debugReportCallback, nullptr);
} }
vkDestroyInstance(instance, nullptr); vkDestroyInstance(instance, nullptr);
@ -601,7 +625,8 @@ void VulkanExampleBase::initVulkan()
Instance creation Instance creation
*/ */
err = createInstance(settings.validation); err = createInstance(settings.validation);
if (err) { if (err)
{
std::cerr << "Could not create Vulkan instance!" << std::endl; std::cerr << "Could not create Vulkan instance!" << std::endl;
exit(err); exit(err);
} }
@ -613,7 +638,8 @@ void VulkanExampleBase::initVulkan()
/* /*
Validation layers Validation layers
*/ */
if (settings.validation) { if (settings.validation)
{
vkCreateDebugReportCallback = reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>(vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT")); vkCreateDebugReportCallback = reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>(vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT"));
vkDestroyDebugReportCallback = reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>(vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT")); vkDestroyDebugReportCallback = reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>(vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT"));
VkDebugReportCallbackCreateInfoEXT debugCreateInfo{}; VkDebugReportCallbackCreateInfoEXT debugCreateInfo{};
@ -631,20 +657,27 @@ void VulkanExampleBase::initVulkan()
assert(gpuCount > 0); assert(gpuCount > 0);
std::vector<VkPhysicalDevice> physicalDevices(gpuCount); std::vector<VkPhysicalDevice> physicalDevices(gpuCount);
err = vkEnumeratePhysicalDevices(instance, &gpuCount, physicalDevices.data()); err = vkEnumeratePhysicalDevices(instance, &gpuCount, physicalDevices.data());
if (err) { if (err)
{
std::cerr << "Could not enumerate physical devices!" << std::endl; std::cerr << "Could not enumerate physical devices!" << std::endl;
exit(err); exit(err);
} }
uint32_t selectedDevice = 0; uint32_t selectedDevice = 0;
#if !defined(VK_USE_PLATFORM_ANDROID_KHR) #if !defined(VK_USE_PLATFORM_ANDROID_KHR)
for (size_t i = 0; i < args.size(); i++) { for (size_t i = 0; i < args.size(); i++)
if ((args[i] == std::string("-g")) || (args[i] == std::string("--gpu"))) { {
if ((args[i] == std::string("-g")) || (args[i] == std::string("--gpu")))
{
char *endptr; char *endptr;
selectedPhysicalDeviceIndex = strtol(args[i + 1], &endptr, 10); selectedPhysicalDeviceIndex = strtol(args[i + 1], &endptr, 10);
if (endptr != args[i + 1]) { if (endptr != args[i + 1])
if (selectedPhysicalDeviceIndex > gpuCount - 1) { {
if (selectedPhysicalDeviceIndex > gpuCount - 1)
{
std::cerr << "Selected device index " << selectedPhysicalDeviceIndex << " is out of range, reverting to device 0 (use -listgpus to show available Vulkan devices)" << std::endl; std::cerr << "Selected device index " << selectedPhysicalDeviceIndex << " is out of range, reverting to device 0 (use -listgpus to show available Vulkan devices)" << std::endl;
} else { }
else
{
std::cout << "Selected Vulkan device " << selectedPhysicalDeviceIndex << std::endl; std::cout << "Selected Vulkan device " << selectedPhysicalDeviceIndex << std::endl;
selectedDevice = selectedPhysicalDeviceIndex; selectedDevice = selectedPhysicalDeviceIndex;
} }
@ -663,33 +696,37 @@ void VulkanExampleBase::initVulkan()
/* /*
Device creation Device creation
*/ */
vulkanDevice = new vks::VulkanDevice(physicalDevice); vulkanDevice = new VulkanBase::VulkanDevice(physicalDevice);
VkPhysicalDeviceFeatures enabledFeatures{}; VkPhysicalDeviceFeatures enabledFeatures{};
if (deviceFeatures.samplerAnisotropy) { if (deviceFeatures.samplerAnisotropy)
{
enabledFeatures.samplerAnisotropy = VK_TRUE; enabledFeatures.samplerAnisotropy = VK_TRUE;
} }
std::vector<const char *> enabledExtensions{}; std::vector<const char *> enabledExtensions{};
VkResult res = vulkanDevice->createLogicalDevice(enabledFeatures, enabledExtensions); VkResult res = vulkanDevice->createLogicalDevice(enabledFeatures, enabledExtensions);
if (res != VK_SUCCESS) { if (res != VK_SUCCESS)
{
std::cerr << "Could not create Vulkan device!" << std::endl; std::cerr << "Could not create Vulkan device!" << std::endl;
exit(res); exit(res);
} }
device = vulkanDevice->logicalDevice; device = vulkanDevice->getLogicalDevice();
/* /*
Graphics queue Graphics queue
*/ */
vkGetDeviceQueue(device, vulkanDevice->queueFamilyIndices.graphics, 0, &queue); vkGetDeviceQueue(device, vulkanDevice->getGraphicsQueueFamilyIndex(), 0, &queue);
/* /*
Suitable depth format Suitable depth format
*/ */
std::vector<VkFormat> depthFormats = {VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D32_SFLOAT, VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D16_UNORM_S8_UINT, VK_FORMAT_D16_UNORM}; std::vector<VkFormat> depthFormats = {VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D32_SFLOAT, VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D16_UNORM_S8_UINT, VK_FORMAT_D16_UNORM};
VkBool32 validDepthFormat = false; VkBool32 validDepthFormat = false;
for (auto& format : depthFormats) { for (auto &format : depthFormats)
{
VkFormatProperties formatProps; VkFormatProperties formatProps;
vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &formatProps); vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &formatProps);
if (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) { if (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
{
depthFormat = format; depthFormat = format;
validDepthFormat = true; validDepthFormat = true;
break; break;
@ -704,11 +741,13 @@ void VulkanExampleBase::initVulkan()
androidProduct = ""; androidProduct = "";
char prop[PROP_VALUE_MAX + 1]; char prop[PROP_VALUE_MAX + 1];
int len = __system_property_get("ro.product.manufacturer", prop); int len = __system_property_get("ro.product.manufacturer", prop);
if (len > 0) { if (len > 0)
{
androidProduct += std::string(prop) + " "; androidProduct += std::string(prop) + " ";
}; };
len = __system_property_get("ro.product.model", prop); len = __system_property_get("ro.product.model", prop);
if (len > 0) { if (len > 0)
{
androidProduct += std::string(prop); androidProduct += std::string(prop);
}; };
LOGD("androidProduct = %s", androidProduct.c_str()); LOGD("androidProduct = %s", androidProduct.c_str());
@ -736,7 +775,8 @@ HWND VulkanExampleBase::setupWindow(HINSTANCE hinstance, WNDPROC wndproc)
wndClass.lpszClassName = name.c_str(); wndClass.lpszClassName = name.c_str();
wndClass.hIconSm = LoadIcon(NULL, IDI_WINLOGO); wndClass.hIconSm = LoadIcon(NULL, IDI_WINLOGO);
if (!RegisterClassEx(&wndClass)) { if (!RegisterClassEx(&wndClass))
{
std::cout << "Could not register window class!\n"; std::cout << "Could not register window class!\n";
fflush(stdout); fflush(stdout);
exit(1); exit(1);
@ -745,7 +785,8 @@ HWND VulkanExampleBase::setupWindow(HINSTANCE hinstance, WNDPROC wndproc)
int screenWidth = GetSystemMetrics(SM_CXSCREEN); int screenWidth = GetSystemMetrics(SM_CXSCREEN);
int screenHeight = GetSystemMetrics(SM_CYSCREEN); int screenHeight = GetSystemMetrics(SM_CYSCREEN);
if (settings.fullscreen) { if (settings.fullscreen)
{
DEVMODE dmScreenSettings; DEVMODE dmScreenSettings;
memset(&dmScreenSettings, 0, sizeof(dmScreenSettings)); memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
dmScreenSettings.dmSize = sizeof(dmScreenSettings); dmScreenSettings.dmSize = sizeof(dmScreenSettings);
@ -753,11 +794,16 @@ HWND VulkanExampleBase::setupWindow(HINSTANCE hinstance, WNDPROC wndproc)
dmScreenSettings.dmPelsHeight = screenHeight; dmScreenSettings.dmPelsHeight = screenHeight;
dmScreenSettings.dmBitsPerPel = 32; dmScreenSettings.dmBitsPerPel = 32;
dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
if ((width != (uint32_t)screenWidth) && (height != (uint32_t)screenHeight)) { if ((width != (uint32_t)screenWidth) && (height != (uint32_t)screenHeight))
if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) { {
if (MessageBox(NULL, "Fullscreen Mode not supported!\n Switch to window mode?", "Error", MB_YESNO | MB_ICONEXCLAMATION) == IDYES) { if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
{
if (MessageBox(NULL, "Fullscreen Mode not supported!\n Switch to window mode?", "Error", MB_YESNO | MB_ICONEXCLAMATION) == IDYES)
{
settings.fullscreen = false; settings.fullscreen = false;
} else { }
else
{
return nullptr; return nullptr;
} }
} }
@ -767,10 +813,13 @@ HWND VulkanExampleBase::setupWindow(HINSTANCE hinstance, WNDPROC wndproc)
DWORD dwExStyle; DWORD dwExStyle;
DWORD dwStyle; DWORD dwStyle;
if (settings.fullscreen) { if (settings.fullscreen)
{
dwExStyle = WS_EX_APPWINDOW; dwExStyle = WS_EX_APPWINDOW;
dwStyle = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; dwStyle = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
} else { }
else
{
dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
} }
@ -796,13 +845,15 @@ HWND VulkanExampleBase::setupWindow(HINSTANCE hinstance, WNDPROC wndproc)
hinstance, hinstance,
NULL); NULL);
if (!settings.fullscreen) { if (!settings.fullscreen)
{
uint32_t x = (GetSystemMetrics(SM_CXSCREEN) - windowRect.right) / 2; uint32_t x = (GetSystemMetrics(SM_CXSCREEN) - windowRect.right) / 2;
uint32_t y = (GetSystemMetrics(SM_CYSCREEN) - windowRect.bottom) / 2; uint32_t y = (GetSystemMetrics(SM_CYSCREEN) - windowRect.bottom) / 2;
SetWindowPos(window, 0, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE); SetWindowPos(window, 0, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
} }
if (!window) { if (!window)
{
printf("Could not create window!\n"); printf("Could not create window!\n");
fflush(stdout); fflush(stdout);
return nullptr; return nullptr;
@ -912,8 +963,10 @@ void VulkanExampleBase::handleMessages(HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
break; break;
} }
case WM_SIZE: case WM_SIZE:
if ((prepared) && (wParam != SIZE_MINIMIZED)) { if ((prepared) && (wParam != SIZE_MINIMIZED))
if ((resizing) || ((wParam == SIZE_MAXIMIZED) || (wParam == SIZE_RESTORED))) { {
if ((resizing) || ((wParam == SIZE_MAXIMIZED) || (wParam == SIZE_RESTORED)))
{
destWidth = LOWORD(lParam); destWidth = LOWORD(lParam);
destHeight = HIWORD(lParam); destHeight = HIWORD(lParam);
windowResize(); windowResize();
@ -933,8 +986,10 @@ void VulkanExampleBase::handleMessages(HWND hWnd, UINT uMsg, WPARAM wParam, LPAR
// extract files here // extract files here
char filename[MAX_PATH]; char filename[MAX_PATH];
uint32_t count = DragQueryFileA(hDrop, -1, nullptr, 0); uint32_t count = DragQueryFileA(hDrop, -1, nullptr, 0);
for (uint32_t i = 0; i < count; ++i) { for (uint32_t i = 0; i < count; ++i)
if (DragQueryFileA(hDrop, i, filename, MAX_PATH)) { {
if (DragQueryFileA(hDrop, i, filename, MAX_PATH))
{
fname = filename; fname = filename;
} }
break; break;
@ -955,8 +1010,10 @@ int32_t VulkanExampleBase::handleAppInput(struct android_app* app, AInputEvent*
if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION)
{ {
int32_t eventSource = AInputEvent_getSource(event); int32_t eventSource = AInputEvent_getSource(event);
switch (eventSource) { switch (eventSource)
case AINPUT_SOURCE_JOYSTICK: { {
case AINPUT_SOURCE_JOYSTICK:
{
// Left thumbstick // Left thumbstick
vulkanExample->gamePadState.axisLeft.x = AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_X, 0); vulkanExample->gamePadState.axisLeft.x = AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_X, 0);
vulkanExample->gamePadState.axisLeft.y = AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_Y, 0); vulkanExample->gamePadState.axisLeft.y = AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_Y, 0);
@ -969,31 +1026,39 @@ int32_t VulkanExampleBase::handleAppInput(struct android_app* app, AInputEvent*
// FIXME: Reusing code for TOUCHSCREEN seemingly works well for MOUSE event source, // FIXME: Reusing code for TOUCHSCREEN seemingly works well for MOUSE event source,
// but it would be better to provide a dedicated event handling logic for MOUSE event source. // but it would be better to provide a dedicated event handling logic for MOUSE event source.
case AINPUT_SOURCE_MOUSE: case AINPUT_SOURCE_MOUSE:
case AINPUT_SOURCE_TOUCHSCREEN: { case AINPUT_SOURCE_TOUCHSCREEN:
{
int32_t action = AMotionEvent_getAction(event); int32_t action = AMotionEvent_getAction(event);
int32_t pointerCount = AMotionEvent_getPointerCount(event); int32_t pointerCount = AMotionEvent_getPointerCount(event);
int32_t flags = action & AMOTION_EVENT_ACTION_MASK; int32_t flags = action & AMOTION_EVENT_ACTION_MASK;
switch (flags) { switch (flags)
{
case AMOTION_EVENT_ACTION_DOWN: case AMOTION_EVENT_ACTION_DOWN:
case AMOTION_EVENT_ACTION_POINTER_DOWN: { case AMOTION_EVENT_ACTION_POINTER_DOWN:
for (uint32_t i = 0; i < pointerCount; i++) { {
for (uint32_t i = 0; i < pointerCount; i++)
{
vulkanExample->touchPoints[i].x = AMotionEvent_getX(event, i); vulkanExample->touchPoints[i].x = AMotionEvent_getX(event, i);
vulkanExample->touchPoints[i].y = AMotionEvent_getY(event, i); vulkanExample->touchPoints[i].y = AMotionEvent_getY(event, i);
}; };
int32_t pointerIndex = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; int32_t pointerIndex = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
if (pointerIndex < 2) { if (pointerIndex < 2)
{
vulkanExample->touchPoints[pointerIndex].down = true; vulkanExample->touchPoints[pointerIndex].down = true;
} }
if (pointerCount < 2) { if (pointerCount < 2)
{
// Detect single tap // Detect single tap
int64_t eventTime = AMotionEvent_getEventTime(event); int64_t eventTime = AMotionEvent_getEventTime(event);
int64_t downTime = AMotionEvent_getDownTime(event); int64_t downTime = AMotionEvent_getDownTime(event);
if (eventTime - downTime <= vks::android::TAP_TIMEOUT) { if (eventTime - downTime <= vks::android::TAP_TIMEOUT)
{
float deadZone = (160.f / vks::android::screenDensity) * vks::android::TAP_SLOP * vks::android::TAP_SLOP; float deadZone = (160.f / vks::android::screenDensity) * vks::android::TAP_SLOP * vks::android::TAP_SLOP;
float x = AMotionEvent_getX(event, 0) - vulkanExample->touchPoints[0].x; float x = AMotionEvent_getX(event, 0) - vulkanExample->touchPoints[0].x;
float y = AMotionEvent_getY(event, 0) - vulkanExample->touchPoints[0].y; float y = AMotionEvent_getY(event, 0) - vulkanExample->touchPoints[0].y;
if ((x * x + y * y) < deadZone) { if ((x * x + y * y) < deadZone)
{
vulkanExample->mousePos.x = vulkanExample->touchPoints[0].x; vulkanExample->mousePos.x = vulkanExample->touchPoints[0].x;
vulkanExample->mousePos.y = vulkanExample->touchPoints[0].y; vulkanExample->mousePos.y = vulkanExample->touchPoints[0].y;
vulkanExample->mouseButtons.left = true; vulkanExample->mouseButtons.left = true;
@ -1003,21 +1068,28 @@ int32_t VulkanExampleBase::handleAppInput(struct android_app* app, AInputEvent*
break; break;
} }
case AMOTION_EVENT_ACTION_UP: case AMOTION_EVENT_ACTION_UP:
case AMOTION_EVENT_ACTION_POINTER_UP: { case AMOTION_EVENT_ACTION_POINTER_UP:
{
int32_t pointerIndex = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; int32_t pointerIndex = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
if (pointerIndex < 2) { if (pointerIndex < 2)
{
vulkanExample->touchPoints[pointerIndex].down = false; vulkanExample->touchPoints[pointerIndex].down = false;
} }
if (pointerCount < 2) { if (pointerCount < 2)
{
vulkanExample->touchPoints[1].down = false; vulkanExample->touchPoints[1].down = false;
} }
break; break;
} }
case AMOTION_EVENT_ACTION_MOVE: { case AMOTION_EVENT_ACTION_MOVE:
{
// Pinch and zoom // Pinch and zoom
if (!uiMouseCapture && vulkanExample->touchPoints[0].down && vulkanExample->touchPoints[1].down) { if (!uiMouseCapture && vulkanExample->touchPoints[0].down && vulkanExample->touchPoints[1].down)
for (uint32_t i = 0; i < pointerCount; i++) { {
if (vulkanExample->touchPoints[i].down) { for (uint32_t i = 0; i < pointerCount; i++)
{
if (vulkanExample->touchPoints[i].down)
{
vulkanExample->touchPoints[i].x = AMotionEvent_getX(event, i); vulkanExample->touchPoints[i].x = AMotionEvent_getX(event, i);
vulkanExample->touchPoints[i].y = AMotionEvent_getY(event, i); vulkanExample->touchPoints[i].y = AMotionEvent_getY(event, i);
} }
@ -1025,16 +1097,21 @@ int32_t VulkanExampleBase::handleAppInput(struct android_app* app, AInputEvent*
float dx = vulkanExample->touchPoints[1].x - vulkanExample->touchPoints[0].x; float dx = vulkanExample->touchPoints[1].x - vulkanExample->touchPoints[0].x;
float dy = vulkanExample->touchPoints[1].y - vulkanExample->touchPoints[0].y; float dy = vulkanExample->touchPoints[1].y - vulkanExample->touchPoints[0].y;
float d = sqrt(dx * dx + dy * dy); float d = sqrt(dx * dx + dy * dy);
if (d < vulkanExample->pinchDist) { if (d < vulkanExample->pinchDist)
{
vulkanExample->camera.translate(glm::vec3(0.0f, 0.0f, 0.03f)); vulkanExample->camera.translate(glm::vec3(0.0f, 0.0f, 0.03f));
}; };
if (d > vulkanExample->pinchDist) { if (d > vulkanExample->pinchDist)
{
vulkanExample->camera.translate(glm::vec3(0.0f, 0.0f, -0.03f)); vulkanExample->camera.translate(glm::vec3(0.0f, 0.0f, -0.03f));
}; };
vulkanExample->pinchDist = d; vulkanExample->pinchDist = d;
} else { }
else
{
// Rotate // Rotate
if (!uiMouseCapture && vulkanExample->touchPoints[0].down) { if (!uiMouseCapture && vulkanExample->touchPoints[0].down)
{
int32_t eventX = AMotionEvent_getX(event, 0); int32_t eventX = AMotionEvent_getX(event, 0);
int32_t eventY = AMotionEvent_getY(event, 0); int32_t eventY = AMotionEvent_getY(event, 0);
@ -1275,8 +1352,13 @@ void VulkanExampleBase::seatCapabilities(wl_seat *seat, uint32_t caps)
{ {
pointer = wl_seat_get_pointer(seat); pointer = wl_seat_get_pointer(seat);
static const struct wl_pointer_listener pointer_listener = static const struct wl_pointer_listener pointer_listener =
{ pointerEnterCb, pointerLeaveCb, pointerMotionCb, pointerButtonCb, {
pointerAxisCb, }; pointerEnterCb,
pointerLeaveCb,
pointerMotionCb,
pointerButtonCb,
pointerAxisCb,
};
wl_pointer_add_listener(pointer, &pointer_listener, this); wl_pointer_add_listener(pointer, &pointer_listener, this);
} }
else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && pointer) else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && pointer)
@ -1289,8 +1371,13 @@ void VulkanExampleBase::seatCapabilities(wl_seat *seat, uint32_t caps)
{ {
keyboard = wl_seat_get_keyboard(seat); keyboard = wl_seat_get_keyboard(seat);
static const struct wl_keyboard_listener keyboard_listener = static const struct wl_keyboard_listener keyboard_listener =
{ keyboardKeymapCb, keyboardEnterCb, keyboardLeaveCb, keyboardKeyCb, {
keyboardModifiersCb, }; keyboardKeymapCb,
keyboardEnterCb,
keyboardLeaveCb,
keyboardKeyCb,
keyboardModifiersCb,
};
wl_keyboard_add_listener(keyboard, &keyboard_listener, this); wl_keyboard_add_listener(keyboard, &keyboard_listener, this);
} }
else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && keyboard) else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && keyboard)
@ -1319,7 +1406,9 @@ void VulkanExampleBase::registryGlobal(wl_registry *registry, uint32_t name,
1); 1);
static const struct wl_seat_listener seat_listener = static const struct wl_seat_listener seat_listener =
{ seatCapabilitiesCb, }; {
seatCapabilitiesCb,
};
wl_seat_add_listener(seat, &seat_listener, this); wl_seat_add_listener(seat, &seat_listener, this);
} }
} }
@ -1469,7 +1558,8 @@ void VulkanExampleBase::initxcbConnection()
int scr; int scr;
connection = xcb_connect(NULL, &scr); connection = xcb_connect(NULL, &scr);
if (connection == NULL) { if (connection == NULL)
{
printf("Could not find a compatible Vulkan ICD!\n"); printf("Could not find a compatible Vulkan ICD!\n");
fflush(stdout); fflush(stdout);
exit(1); exit(1);
@ -1488,7 +1578,8 @@ void VulkanExampleBase::handleEvent(const xcb_generic_event_t *event)
{ {
case XCB_CLIENT_MESSAGE: case XCB_CLIENT_MESSAGE:
if ((*(xcb_client_message_event_t *)event).data.data32[0] == if ((*(xcb_client_message_event_t *)event).data.data32[0] ==
(*atom_wm_delete_window).atom) { (*atom_wm_delete_window).atom)
{
quit = true; quit = true;
} }
break; break;
@ -1814,14 +1905,17 @@ void VulkanExampleBase::windowDidResize()
} }
#endif #endif
void VulkanExampleBase::windowResized() {} void VulkanExampleBase::windowResized()
{
}
void VulkanExampleBase::setupFrameBuffer() void VulkanExampleBase::setupFrameBuffer()
{ {
/* /*
MSAA MSAA
*/ */
if (settings.multiSampling) { if (settings.multiSampling)
{
// Check if device supports requested sample count for color and depth frame buffer // Check if device supports requested sample count for color and depth frame buffer
// assert((deviceProperties.limits.framebufferColorSampleCounts >= sampleCount) && (deviceProperties.limits.framebufferDepthSampleCounts >= sampleCount)); // assert((deviceProperties.limits.framebufferColorSampleCounts >= sampleCount) && (deviceProperties.limits.framebufferDepthSampleCounts >= sampleCount));
@ -1848,7 +1942,8 @@ void VulkanExampleBase::setupFrameBuffer()
memAllocInfo.allocationSize = memReqs.size; memAllocInfo.allocationSize = memReqs.size;
VkBool32 lazyMemTypePresent; VkBool32 lazyMemTypePresent;
memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT, &lazyMemTypePresent); memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT, &lazyMemTypePresent);
if (!lazyMemTypePresent) { if (!lazyMemTypePresent)
{
memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
} }
VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &multisampleTarget.color.memory)); VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &multisampleTarget.color.memory));
@ -1888,7 +1983,8 @@ void VulkanExampleBase::setupFrameBuffer()
memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
memAllocInfo.allocationSize = memReqs.size; memAllocInfo.allocationSize = memReqs.size;
memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT, &lazyMemTypePresent); memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT, &lazyMemTypePresent);
if (!lazyMemTypePresent) { if (!lazyMemTypePresent)
{
memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
} }
VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &multisampleTarget.depth.memory)); VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &multisampleTarget.depth.memory));
@ -1908,7 +2004,6 @@ void VulkanExampleBase::setupFrameBuffer()
VK_CHECK_RESULT(vkCreateImageView(device, &imageViewCI, nullptr, &multisampleTarget.depth.view)); VK_CHECK_RESULT(vkCreateImageView(device, &imageViewCI, nullptr, &multisampleTarget.depth.view));
} }
// Depth/Stencil attachment is the same for all frame buffers // Depth/Stencil attachment is the same for all frame buffers
VkImageCreateInfo image = {}; VkImageCreateInfo image = {};
@ -1958,12 +2053,14 @@ void VulkanExampleBase::setupFrameBuffer()
VkImageView attachments[4]; VkImageView attachments[4];
if (settings.multiSampling) { if (settings.multiSampling)
{
attachments[0] = multisampleTarget.color.view; attachments[0] = multisampleTarget.color.view;
attachments[2] = multisampleTarget.depth.view; attachments[2] = multisampleTarget.depth.view;
attachments[3] = depthStencil.view; attachments[3] = depthStencil.view;
} }
else { else
{
attachments[1] = depthStencil.view; attachments[1] = depthStencil.view;
} }
@ -1979,11 +2076,14 @@ void VulkanExampleBase::setupFrameBuffer()
// Create frame buffers for every swap chain image // Create frame buffers for every swap chain image
frameBuffers.resize(swapChain.imageCount); frameBuffers.resize(swapChain.imageCount);
for (uint32_t i = 0; i < frameBuffers.size(); i++) { for (uint32_t i = 0; i < frameBuffers.size(); i++)
if (settings.multiSampling) { {
if (settings.multiSampling)
{
attachments[1] = swapChain.buffers[i].view; attachments[1] = swapChain.buffers[i].view;
} }
else { else
{
attachments[0] = swapChain.buffers[i].view; attachments[0] = swapChain.buffers[i].view;
} }
VK_CHECK_RESULT(vkCreateFramebuffer(device, &frameBufferCI, nullptr, &frameBuffers[i])); VK_CHECK_RESULT(vkCreateFramebuffer(device, &frameBufferCI, nullptr, &frameBuffers[i]));
@ -1992,7 +2092,8 @@ void VulkanExampleBase::setupFrameBuffer()
void VulkanExampleBase::windowResize() void VulkanExampleBase::windowResize()
{ {
if (!prepared) { if (!prepared)
{
return; return;
} }
prepared = false; prepared = false;
@ -2001,7 +2102,8 @@ void VulkanExampleBase::windowResize()
width = destWidth; width = destWidth;
height = destHeight; height = destHeight;
setupSwapChain(); setupSwapChain();
if (settings.multiSampling) { if (settings.multiSampling)
{
vkDestroyImageView(device, multisampleTarget.color.view, nullptr); vkDestroyImageView(device, multisampleTarget.color.view, nullptr);
vkDestroyImage(device, multisampleTarget.color.image, nullptr); vkDestroyImage(device, multisampleTarget.color.image, nullptr);
vkFreeMemory(device, multisampleTarget.color.memory, nullptr); vkFreeMemory(device, multisampleTarget.color.memory, nullptr);
@ -2012,7 +2114,8 @@ void VulkanExampleBase::windowResize()
vkDestroyImageView(device, depthStencil.view, nullptr); vkDestroyImageView(device, depthStencil.view, nullptr);
vkDestroyImage(device, depthStencil.image, nullptr); vkDestroyImage(device, depthStencil.image, nullptr);
vkFreeMemory(device, depthStencil.mem, nullptr); vkFreeMemory(device, depthStencil.mem, nullptr);
for (uint32_t i = 0; i < frameBuffers.size(); i++) { for (uint32_t i = 0; i < frameBuffers.size(); i++)
{
vkDestroyFramebuffer(device, frameBuffers[i], nullptr); vkDestroyFramebuffer(device, frameBuffers[i], nullptr);
} }
setupFrameBuffer(); setupFrameBuffer();
@ -2032,23 +2135,28 @@ void VulkanExampleBase::handleMouseMove(int32_t x, int32_t y)
ImGuiIO &io = ImGui::GetIO(); ImGuiIO &io = ImGui::GetIO();
bool handled = io.WantCaptureMouse; bool handled = io.WantCaptureMouse;
if (handled) { if (handled)
{
mousePos = glm::vec2((float)x, (float)y); mousePos = glm::vec2((float)x, (float)y);
return; return;
} }
if (handled) { if (handled)
{
mousePos = glm::vec2((float)x, (float)y); mousePos = glm::vec2((float)x, (float)y);
return; return;
} }
if (mouseButtons.left) { if (mouseButtons.left)
{
camera.rotate(glm::vec3(dy * camera.rotationSpeed, -dx * camera.rotationSpeed, 0.0f)); camera.rotate(glm::vec3(dy * camera.rotationSpeed, -dx * camera.rotationSpeed, 0.0f));
} }
if (mouseButtons.right) { if (mouseButtons.right)
{
camera.translate(glm::vec3(-0.0f, 0.0f, dy * .005f * camera.movementSpeed)); camera.translate(glm::vec3(-0.0f, 0.0f, dy * .005f * camera.movementSpeed));
} }
if (mouseButtons.middle) { if (mouseButtons.middle)
{
camera.translate(glm::vec3(-dx * 0.01f, dy * 0.01f, 0.0f)); camera.translate(glm::vec3(-dx * 0.01f, dy * 0.01f, 0.0f));
} }
mousePos = glm::vec2((float)x, (float)y); mousePos = glm::vec2((float)x, (float)y);

View File

@ -10,15 +10,17 @@
#ifdef _WIN32 #ifdef _WIN32
#pragma comment(linker, "/subsystem:windows") #pragma comment(linker, "/subsystem:windows")
#include <windows.h>
#include <fcntl.h> #include <fcntl.h>
#include <io.h> #include <io.h>
#include <windows.h>
#elif defined(VK_USE_PLATFORM_ANDROID_KHR) #elif defined(VK_USE_PLATFORM_ANDROID_KHR)
#include <android/native_activity.h> #include "VulkanAndroid.h"
#include <android/asset_manager.h> #include <android/asset_manager.h>
#include <android/native_activity.h>
#include <android_native_app_glue.h> #include <android_native_app_glue.h>
#include <sys/system_properties.h> #include <sys/system_properties.h>
#include "VulkanAndroid.h"
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
#include <wayland-client.h> #include <wayland-client.h>
#elif defined(_DIRECT2DISPLAY) #elif defined(_DIRECT2DISPLAY)
@ -26,24 +28,25 @@
#elif defined(VK_USE_PLATFORM_XCB_KHR) #elif defined(VK_USE_PLATFORM_XCB_KHR)
#include <xcb/xcb.h> #include <xcb/xcb.h>
#elif defined(VK_USE_PLATFORM_MACOS_MVK) #elif defined(VK_USE_PLATFORM_MACOS_MVK)
#include <Cocoa/Cocoa.h>
#include <Carbon/Carbon.h> #include <Carbon/Carbon.h>
#include <QuartzCore/CAMetalLayer.h> #include <Cocoa/Cocoa.h>
#include <CoreVideo/CVDisplayLink.h> #include <CoreVideo/CVDisplayLink.h>
#include <QuartzCore/CAMetalLayer.h>
#endif #endif
#include <iostream>
#include <chrono> #include <chrono>
#include <iostream>
#include <sys/stat.h> #include <sys/stat.h>
#define GLM_FORCE_RADIANS #define GLM_FORCE_RADIANS
#define GLM_FORCE_DEPTH_ZERO_TO_ONE #define GLM_FORCE_DEPTH_ZERO_TO_ONE
#define GLM_ENABLE_EXPERIMENTAL #define GLM_ENABLE_EXPERIMENTAL
#include <glm/glm.hpp>
#include <string>
#include <sstream>
#include <array> #include <array>
#include <glm/glm.hpp>
#include <numeric> #include <numeric>
#include <sstream>
#include <string>
#include "vulkan/vulkan.h" #include "vulkan/vulkan.h"
@ -51,7 +54,7 @@
#include "camera.hpp" #include "camera.hpp"
#include "keycodes.hpp" #include "keycodes.hpp"
#include "VulkanDevice.hpp" #include "VulkanDevice.h"
#include "VulkanSwapChain.hpp" #include "VulkanSwapChain.hpp"
#include "imgui.h" #include "imgui.h"
@ -68,18 +71,22 @@ private:
PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallback; PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallback;
PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallback; PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallback;
VkDebugReportCallbackEXT debugReportCallback; VkDebugReportCallbackEXT debugReportCallback;
struct MultisampleTarget { struct MultisampleTarget
struct { {
struct
{
VkImage image; VkImage image;
VkImageView view; VkImageView view;
VkDeviceMemory memory; VkDeviceMemory memory;
} color; } color;
struct { struct
{
VkImage image; VkImage image;
VkImageView view; VkImageView view;
VkDeviceMemory memory; VkDeviceMemory memory;
} depth; } depth;
} multisampleTarget; } multisampleTarget;
protected: protected:
VkInstance instance; VkInstance instance;
VkPhysicalDevice physicalDevice; VkPhysicalDevice physicalDevice;
@ -87,7 +94,7 @@ protected:
VkPhysicalDeviceFeatures deviceFeatures; VkPhysicalDeviceFeatures deviceFeatures;
VkPhysicalDeviceMemoryProperties deviceMemoryProperties; VkPhysicalDeviceMemoryProperties deviceMemoryProperties;
VkDevice device; VkDevice device;
vks::VulkanDevice *vulkanDevice; VulkanBase::VulkanDevice *vulkanDevice;
VkQueue queue; VkQueue queue;
VkFormat depthFormat; VkFormat depthFormat;
VkCommandPool cmdPool; VkCommandPool cmdPool;
@ -100,6 +107,7 @@ protected:
std::string title = "Vulkan Example"; std::string title = "Vulkan Example";
std::string name = "vulkanExample"; std::string name = "vulkanExample";
void windowResize(); void windowResize();
public: public:
static std::vector<const char *> args; static std::vector<const char *> args;
uint32_t selectedPhysicalDeviceIndex = 0; uint32_t selectedPhysicalDeviceIndex = 0;
@ -112,7 +120,8 @@ public:
bool paused = false; bool paused = false;
uint32_t lastFPS = 0; uint32_t lastFPS = 0;
struct Settings { struct Settings
{
bool validation = false; // 校验层开关 bool validation = false; // 校验层开关
bool fullscreen = false; // 全屏开关 bool fullscreen = false; // 全屏开关
bool vsync = false; // 垂直同步开关 bool vsync = false; // 垂直同步开关
@ -130,18 +139,21 @@ public:
VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_4_BIT; // 多重采样倍率 VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_4_BIT; // 多重采样倍率
} settings; } settings;
struct DepthStencil { struct DepthStencil
{
VkImage image; VkImage image;
VkDeviceMemory mem; VkDeviceMemory mem;
VkImageView view; VkImageView view;
} depthStencil; } depthStencil;
struct GamePadState { struct GamePadState
{
glm::vec2 axisLeft = glm::vec2(0.0f); glm::vec2 axisLeft = glm::vec2(0.0f);
glm::vec2 axisRight = glm::vec2(0.0f); glm::vec2 axisRight = glm::vec2(0.0f);
} gamePadState; } gamePadState;
struct MouseButtons { struct MouseButtons
{
bool left = false; bool left = false;
bool right = false; bool right = false;
bool middle = false; bool middle = false;
@ -155,7 +167,8 @@ public:
// true if application has focused, false if moved to background // true if application has focused, false if moved to background
bool focused = false; bool focused = false;
std::string androidProduct; std::string androidProduct;
struct TouchPoint { struct TouchPoint
{
int32_t id; int32_t id;
float x; float x;
float y; float y;

View File

@ -1,6 +1,6 @@
#include "glTFMainModel.h" #include "glTFMainModel.h"
#include <iostream>
#include <VulkanTools.h> #include <VulkanTools.h>
#include <iostream>
GLTFLOADER_NAMESPACE_BEGIN GLTFLOADER_NAMESPACE_BEGIN
@ -12,24 +12,37 @@ glTFMainModel::~glTFMainModel()
{ {
} }
ModelBuffer &glTFMainModel::getModelVertex()
{
return m_vertices;
}
ModelBuffer &glTFMainModel::getModelIndex()
{
return m_indices;
}
void glTFMainModel::destroy(VkDevice device) void glTFMainModel::destroy(VkDevice device)
{ {
if (m_vertices.buffer != VK_NULL_HANDLE) { if (m_vertices.buffer != VK_NULL_HANDLE)
{
vkDestroyBuffer(device, m_vertices.buffer, nullptr); vkDestroyBuffer(device, m_vertices.buffer, nullptr);
vkFreeMemory(device, m_vertices.memory, nullptr); vkFreeMemory(device, m_vertices.memory, nullptr);
m_vertices.buffer = VK_NULL_HANDLE; m_vertices.buffer = VK_NULL_HANDLE;
} }
if (m_indices.buffer != VK_NULL_HANDLE) { if (m_indices.buffer != VK_NULL_HANDLE)
{
vkDestroyBuffer(device, m_indices.buffer, nullptr); vkDestroyBuffer(device, m_indices.buffer, nullptr);
vkFreeMemory(device, m_indices.memory, nullptr); vkFreeMemory(device, m_indices.memory, nullptr);
m_indices.buffer = VK_NULL_HANDLE; m_indices.buffer = VK_NULL_HANDLE;
} }
for (glTFTexture texture : m_textures) { for (glTFTexture texture : m_textures)
{
texture.destroy(); texture.destroy();
} }
m_textures.resize(0); m_textures.resize(0);
for (glTFNode* node : m_nodes) { for (glTFNode *node : m_nodes)
{
delete node; delete node;
} }
m_nodes.resize(0); m_nodes.resize(0);
@ -40,27 +53,32 @@ void glTFMainModel::destroy(VkDevice device)
m_linearNodes.resize(0); m_linearNodes.resize(0);
m_extensions.resize(0); m_extensions.resize(0);
for (glTFSkin* skin : m_skins) { for (glTFSkin *skin : m_skins)
{
delete skin; delete skin;
} }
m_skins.resize(0); m_skins.resize(0);
} }
void glTFMainModel::getNodeProperty(const tinygltf::Node &node, const tinygltf::Model &model, size_t &vertexCount, size_t &indexCount) void glTFMainModel::getNodeProperty(const tinygltf::Node &node, const tinygltf::Model &model, size_t &vertexCount, size_t &indexCount)
{ {
if (node.children.size() > 0) { if (node.children.size() > 0)
for (size_t i = 0; i < node.children.size(); i++) { {
for (size_t i = 0; i < node.children.size(); i++)
{
getNodeProperty(model.nodes[node.children[i]], model, vertexCount, indexCount); getNodeProperty(model.nodes[node.children[i]], model, vertexCount, indexCount);
} }
} }
if (node.mesh > -1) { if (node.mesh > -1)
{
const tinygltf::Mesh mesh = model.meshes[node.mesh]; const tinygltf::Mesh mesh = model.meshes[node.mesh];
for (size_t i = 0; i < mesh.primitives.size(); i++) { for (size_t i = 0; i < mesh.primitives.size(); i++)
{
auto primitive = mesh.primitives[i]; auto primitive = mesh.primitives[i];
vertexCount += model.accessors[primitive.attributes.find("POSITION")->second].count; vertexCount += model.accessors[primitive.attributes.find("POSITION")->second].count;
if (primitive.indices > -1) { if (primitive.indices > -1)
{
indexCount += model.accessors[primitive.indices].count; indexCount += model.accessors[primitive.indices].count;
} }
} }
@ -70,16 +88,19 @@ void glTFMainModel::getNodeProperty(const tinygltf::Node& node, const tinygltf::
void glTFMainModel::getSceneDimensions() void glTFMainModel::getSceneDimensions()
{ {
// Calculate binary volume hierarchy for all nodes in the scene // Calculate binary volume hierarchy for all nodes in the scene
for (glTFNode* node : m_linearNodes) { for (glTFNode *node : m_linearNodes)
{
calculateBoundingBox(node, nullptr); calculateBoundingBox(node, nullptr);
} }
m_dimensions.min = glm::vec3(FLT_MAX); m_dimensions.min = glm::vec3(FLT_MAX);
m_dimensions.max = glm::vec3(-FLT_MAX); m_dimensions.max = glm::vec3(-FLT_MAX);
for (auto node : m_linearNodes) { for (auto node : m_linearNodes)
{
glTFBoundingBox bvh = node->getBvh(); glTFBoundingBox bvh = node->getBvh();
if (bvh.isValid()) { if (bvh.isValid())
{
m_dimensions.min = glm::min(m_dimensions.min, bvh.getMin()); m_dimensions.min = glm::min(m_dimensions.min, bvh.getMin());
m_dimensions.max = glm::max(m_dimensions.max, bvh.getMax()); m_dimensions.max = glm::max(m_dimensions.max, bvh.getMax());
} }
@ -94,7 +115,8 @@ void glTFMainModel::getSceneDimensions()
VkSamplerAddressMode glTFMainModel::getVkWrapMode(int32_t wrapMode) VkSamplerAddressMode glTFMainModel::getVkWrapMode(int32_t wrapMode)
{ {
switch (wrapMode) { switch (wrapMode)
{
case -1: case -1:
case 10497: case 10497:
return VK_SAMPLER_ADDRESS_MODE_REPEAT; return VK_SAMPLER_ADDRESS_MODE_REPEAT;
@ -110,7 +132,8 @@ VkSamplerAddressMode glTFMainModel::getVkWrapMode(int32_t wrapMode)
VkFilter glTFMainModel::getVkFilterMode(int32_t filterMode) VkFilter glTFMainModel::getVkFilterMode(int32_t filterMode)
{ {
switch (filterMode) { switch (filterMode)
{
case -1: case -1:
case 9728: case 9728:
return VK_FILTER_NEAREST; return VK_FILTER_NEAREST;
@ -141,36 +164,44 @@ void glTFMainModel::loadNode(glTFNode* parent, const tinygltf::Node& node, uint3
// Generate local node matrix // Generate local node matrix
glm::vec3 translation = glm::vec3(0.0f); glm::vec3 translation = glm::vec3(0.0f);
if (node.translation.size() == 3) { if (node.translation.size() == 3)
{
translation = glm::make_vec3(node.translation.data()); translation = glm::make_vec3(node.translation.data());
newNode->setTranslation(translation); newNode->setTranslation(translation);
} }
glm::mat4 rotation = glm::mat4(1.0f); glm::mat4 rotation = glm::mat4(1.0f);
if (node.rotation.size() == 4) { if (node.rotation.size() == 4)
{
glm::quat q = glm::make_quat(node.rotation.data()); glm::quat q = glm::make_quat(node.rotation.data());
newNode->setRotation(glm::mat4(q)); newNode->setRotation(glm::mat4(q));
} }
glm::vec3 scale = glm::vec3(1.0f); glm::vec3 scale = glm::vec3(1.0f);
if (node.scale.size() == 3) { if (node.scale.size() == 3)
{
scale = glm::make_vec3(node.scale.data()); scale = glm::make_vec3(node.scale.data());
newNode->setScale(scale); newNode->setScale(scale);
} }
if (node.matrix.size() == 16) { if (node.matrix.size() == 16)
{
newNode->setMatrix(glm::make_mat4x4(node.matrix.data())); newNode->setMatrix(glm::make_mat4x4(node.matrix.data()));
}; };
// Node with children // Node with children
if (node.children.size() > 0) { if (node.children.size() > 0)
for (size_t i = 0; i < node.children.size(); i++) { {
for (size_t i = 0; i < node.children.size(); i++)
{
loadNode(newNode, model.nodes[node.children[i]], node.children[i], model, loaderInfo, globalscale); loadNode(newNode, model.nodes[node.children[i]], node.children[i], model, loaderInfo, globalscale);
} }
} }
// Node contains mesh data // Node contains mesh data
if (node.mesh > -1) { if (node.mesh > -1)
{
const tinygltf::Mesh mesh = model.meshes[node.mesh]; const tinygltf::Mesh mesh = model.meshes[node.mesh];
glTFMesh *newMesh = new glTFMesh(m_device, newNode->getMatrix()); glTFMesh *newMesh = new glTFMesh(m_device, newNode->getMatrix());
for (size_t j = 0; j < mesh.primitives.size(); j++) { for (size_t j = 0; j < mesh.primitives.size(); j++)
{
const tinygltf::Primitive &primitive = mesh.primitives[j]; const tinygltf::Primitive &primitive = mesh.primitives[j];
uint32_t vertexStart = static_cast<uint32_t>(loaderInfo.vertexPos); uint32_t vertexStart = static_cast<uint32_t>(loaderInfo.vertexPos);
uint32_t indexStart = static_cast<uint32_t>(loaderInfo.indexPos); uint32_t indexStart = static_cast<uint32_t>(loaderInfo.indexPos);
@ -211,7 +242,8 @@ void glTFMainModel::loadNode(glTFNode* parent, const tinygltf::Node& node, uint3
vertexCount = static_cast<uint32_t>(posAccessor.count); vertexCount = static_cast<uint32_t>(posAccessor.count);
posByteStride = posAccessor.ByteStride(posView) ? (posAccessor.ByteStride(posView) / sizeof(float)) : tinygltf::GetNumComponentsInType(TINYGLTF_TYPE_VEC3); posByteStride = posAccessor.ByteStride(posView) ? (posAccessor.ByteStride(posView) / sizeof(float)) : tinygltf::GetNumComponentsInType(TINYGLTF_TYPE_VEC3);
if (primitive.attributes.find("NORMAL") != primitive.attributes.end()) { if (primitive.attributes.find("NORMAL") != primitive.attributes.end())
{
const tinygltf::Accessor &normAccessor = model.accessors[primitive.attributes.find("NORMAL")->second]; const tinygltf::Accessor &normAccessor = model.accessors[primitive.attributes.find("NORMAL")->second];
const tinygltf::BufferView &normView = model.bufferViews[normAccessor.bufferView]; const tinygltf::BufferView &normView = model.bufferViews[normAccessor.bufferView];
bufferNormals = reinterpret_cast<const float *>(&(model.buffers[normView.buffer].data[normAccessor.byteOffset + normView.byteOffset])); bufferNormals = reinterpret_cast<const float *>(&(model.buffers[normView.buffer].data[normAccessor.byteOffset + normView.byteOffset]));
@ -219,13 +251,15 @@ void glTFMainModel::loadNode(glTFNode* parent, const tinygltf::Node& node, uint3
} }
// UVs // UVs
if (primitive.attributes.find("TEXCOORD_0") != primitive.attributes.end()) { if (primitive.attributes.find("TEXCOORD_0") != primitive.attributes.end())
{
const tinygltf::Accessor &uvAccessor = model.accessors[primitive.attributes.find("TEXCOORD_0")->second]; const tinygltf::Accessor &uvAccessor = model.accessors[primitive.attributes.find("TEXCOORD_0")->second];
const tinygltf::BufferView &uvView = model.bufferViews[uvAccessor.bufferView]; const tinygltf::BufferView &uvView = model.bufferViews[uvAccessor.bufferView];
bufferTexCoordSet0 = reinterpret_cast<const float *>(&(model.buffers[uvView.buffer].data[uvAccessor.byteOffset + uvView.byteOffset])); bufferTexCoordSet0 = reinterpret_cast<const float *>(&(model.buffers[uvView.buffer].data[uvAccessor.byteOffset + uvView.byteOffset]));
uv0ByteStride = uvAccessor.ByteStride(uvView) ? (uvAccessor.ByteStride(uvView) / sizeof(float)) : tinygltf::GetNumComponentsInType(TINYGLTF_TYPE_VEC2); uv0ByteStride = uvAccessor.ByteStride(uvView) ? (uvAccessor.ByteStride(uvView) / sizeof(float)) : tinygltf::GetNumComponentsInType(TINYGLTF_TYPE_VEC2);
} }
if (primitive.attributes.find("TEXCOORD_1") != primitive.attributes.end()) { if (primitive.attributes.find("TEXCOORD_1") != primitive.attributes.end())
{
const tinygltf::Accessor &uvAccessor = model.accessors[primitive.attributes.find("TEXCOORD_1")->second]; const tinygltf::Accessor &uvAccessor = model.accessors[primitive.attributes.find("TEXCOORD_1")->second];
const tinygltf::BufferView &uvView = model.bufferViews[uvAccessor.bufferView]; const tinygltf::BufferView &uvView = model.bufferViews[uvAccessor.bufferView];
bufferTexCoordSet1 = reinterpret_cast<const float *>(&(model.buffers[uvView.buffer].data[uvAccessor.byteOffset + uvView.byteOffset])); bufferTexCoordSet1 = reinterpret_cast<const float *>(&(model.buffers[uvView.buffer].data[uvAccessor.byteOffset + uvView.byteOffset]));
@ -233,7 +267,8 @@ void glTFMainModel::loadNode(glTFNode* parent, const tinygltf::Node& node, uint3
} }
// Vertex colors // Vertex colors
if (primitive.attributes.find("COLOR_0") != primitive.attributes.end()) { if (primitive.attributes.find("COLOR_0") != primitive.attributes.end())
{
const tinygltf::Accessor &accessor = model.accessors[primitive.attributes.find("COLOR_0")->second]; const tinygltf::Accessor &accessor = model.accessors[primitive.attributes.find("COLOR_0")->second];
const tinygltf::BufferView &view = model.bufferViews[accessor.bufferView]; const tinygltf::BufferView &view = model.bufferViews[accessor.bufferView];
bufferColorSet0 = reinterpret_cast<const float *>(&(model.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset])); bufferColorSet0 = reinterpret_cast<const float *>(&(model.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset]));
@ -242,7 +277,8 @@ void glTFMainModel::loadNode(glTFNode* parent, const tinygltf::Node& node, uint3
// Skinning // Skinning
// Joints // Joints
if (primitive.attributes.find("JOINTS_0") != primitive.attributes.end()) { if (primitive.attributes.find("JOINTS_0") != primitive.attributes.end())
{
const tinygltf::Accessor &jointAccessor = model.accessors[primitive.attributes.find("JOINTS_0")->second]; const tinygltf::Accessor &jointAccessor = model.accessors[primitive.attributes.find("JOINTS_0")->second];
const tinygltf::BufferView &jointView = model.bufferViews[jointAccessor.bufferView]; const tinygltf::BufferView &jointView = model.bufferViews[jointAccessor.bufferView];
bufferJoints = &(model.buffers[jointView.buffer].data[jointAccessor.byteOffset + jointView.byteOffset]); bufferJoints = &(model.buffers[jointView.buffer].data[jointAccessor.byteOffset + jointView.byteOffset]);
@ -250,7 +286,8 @@ void glTFMainModel::loadNode(glTFNode* parent, const tinygltf::Node& node, uint3
jointByteStride = jointAccessor.ByteStride(jointView) ? (jointAccessor.ByteStride(jointView) / tinygltf::GetComponentSizeInBytes(jointComponentType)) : tinygltf::GetNumComponentsInType(TINYGLTF_TYPE_VEC4); jointByteStride = jointAccessor.ByteStride(jointView) ? (jointAccessor.ByteStride(jointView) / tinygltf::GetComponentSizeInBytes(jointComponentType)) : tinygltf::GetNumComponentsInType(TINYGLTF_TYPE_VEC4);
} }
if (primitive.attributes.find("WEIGHTS_0") != primitive.attributes.end()) { if (primitive.attributes.find("WEIGHTS_0") != primitive.attributes.end())
{
const tinygltf::Accessor &weightAccessor = model.accessors[primitive.attributes.find("WEIGHTS_0")->second]; const tinygltf::Accessor &weightAccessor = model.accessors[primitive.attributes.find("WEIGHTS_0")->second];
const tinygltf::BufferView &weightView = model.bufferViews[weightAccessor.bufferView]; const tinygltf::BufferView &weightView = model.bufferViews[weightAccessor.bufferView];
bufferWeights = reinterpret_cast<const float *>(&(model.buffers[weightView.buffer].data[weightAccessor.byteOffset + weightView.byteOffset])); bufferWeights = reinterpret_cast<const float *>(&(model.buffers[weightView.buffer].data[weightAccessor.byteOffset + weightView.byteOffset]));
@ -259,7 +296,8 @@ void glTFMainModel::loadNode(glTFNode* parent, const tinygltf::Node& node, uint3
hasSkin = (bufferJoints && bufferWeights); hasSkin = (bufferJoints && bufferWeights);
for (size_t v = 0; v < posAccessor.count; v++) { for (size_t v = 0; v < posAccessor.count; v++)
{
Vertex &vert = loaderInfo.vertexBuffer[loaderInfo.vertexPos]; Vertex &vert = loaderInfo.vertexBuffer[loaderInfo.vertexPos];
vert.pos = glm::vec4(glm::make_vec3(&bufferPos[v * posByteStride]), 1.0f); vert.pos = glm::vec4(glm::make_vec3(&bufferPos[v * posByteStride]), 1.0f);
vert.normal = glm::normalize(glm::vec3(bufferNormals ? glm::make_vec3(&bufferNormals[v * normByteStride]) : glm::vec3(0.0f))); vert.normal = glm::normalize(glm::vec3(bufferNormals ? glm::make_vec3(&bufferNormals[v * normByteStride]) : glm::vec3(0.0f)));
@ -269,13 +307,16 @@ void glTFMainModel::loadNode(glTFNode* parent, const tinygltf::Node& node, uint3
if (hasSkin) if (hasSkin)
{ {
switch (jointComponentType) { switch (jointComponentType)
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT: { {
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
{
const uint16_t *buf = static_cast<const uint16_t *>(bufferJoints); const uint16_t *buf = static_cast<const uint16_t *>(bufferJoints);
vert.joint0 = glm::vec4(glm::make_vec4(&buf[v * jointByteStride])); vert.joint0 = glm::vec4(glm::make_vec4(&buf[v * jointByteStride]));
break; break;
} }
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE: { case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE:
{
const uint8_t *buf = static_cast<const uint8_t *>(bufferJoints); const uint8_t *buf = static_cast<const uint8_t *>(bufferJoints);
vert.joint0 = glm::vec4(glm::make_vec4(&buf[v * jointByteStride])); vert.joint0 = glm::vec4(glm::make_vec4(&buf[v * jointByteStride]));
break; break;
@ -286,12 +327,14 @@ void glTFMainModel::loadNode(glTFNode* parent, const tinygltf::Node& node, uint3
break; break;
} }
} }
else { else
{
vert.joint0 = glm::vec4(0.0f); vert.joint0 = glm::vec4(0.0f);
} }
vert.weight0 = hasSkin ? glm::make_vec4(&bufferWeights[v * weightByteStride]) : glm::vec4(0.0f); vert.weight0 = hasSkin ? glm::make_vec4(&bufferWeights[v * weightByteStride]) : glm::vec4(0.0f);
// Fix for all zero weights // Fix for all zero weights
if (glm::length(vert.weight0) == 0.0f) { if (glm::length(vert.weight0) == 0.0f)
{
vert.weight0 = glm::vec4(1.0f, 0.0f, 0.0f, 0.0f); vert.weight0 = glm::vec4(1.0f, 0.0f, 0.0f, 0.0f);
} }
loaderInfo.vertexPos++; loaderInfo.vertexPos++;
@ -307,26 +350,33 @@ void glTFMainModel::loadNode(glTFNode* parent, const tinygltf::Node& node, uint3
indexCount = static_cast<uint32_t>(accessor.count); indexCount = static_cast<uint32_t>(accessor.count);
const void *dataPtr = &(buffer.data[accessor.byteOffset + bufferView.byteOffset]); const void *dataPtr = &(buffer.data[accessor.byteOffset + bufferView.byteOffset]);
switch (accessor.componentType) { switch (accessor.componentType)
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_INT: { {
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_INT:
{
const uint32_t *buf = static_cast<const uint32_t *>(dataPtr); const uint32_t *buf = static_cast<const uint32_t *>(dataPtr);
for (size_t index = 0; index < accessor.count; index++) { for (size_t index = 0; index < accessor.count; index++)
{
loaderInfo.indexBuffer[loaderInfo.indexPos] = buf[index] + vertexStart; loaderInfo.indexBuffer[loaderInfo.indexPos] = buf[index] + vertexStart;
loaderInfo.indexPos++; loaderInfo.indexPos++;
} }
break; break;
} }
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_SHORT: { case TINYGLTF_PARAMETER_TYPE_UNSIGNED_SHORT:
{
const uint16_t *buf = static_cast<const uint16_t *>(dataPtr); const uint16_t *buf = static_cast<const uint16_t *>(dataPtr);
for (size_t index = 0; index < accessor.count; index++) { for (size_t index = 0; index < accessor.count; index++)
{
loaderInfo.indexBuffer[loaderInfo.indexPos] = buf[index] + vertexStart; loaderInfo.indexBuffer[loaderInfo.indexPos] = buf[index] + vertexStart;
loaderInfo.indexPos++; loaderInfo.indexPos++;
} }
break; break;
} }
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_BYTE: { case TINYGLTF_PARAMETER_TYPE_UNSIGNED_BYTE:
{
const uint8_t *buf = static_cast<const uint8_t *>(dataPtr); const uint8_t *buf = static_cast<const uint8_t *>(dataPtr);
for (size_t index = 0; index < accessor.count; index++) { for (size_t index = 0; index < accessor.count; index++)
{
loaderInfo.indexBuffer[loaderInfo.indexPos] = buf[index] + vertexStart; loaderInfo.indexBuffer[loaderInfo.indexPos] = buf[index] + vertexStart;
loaderInfo.indexPos++; loaderInfo.indexPos++;
} }
@ -342,8 +392,10 @@ void glTFMainModel::loadNode(glTFNode* parent, const tinygltf::Node& node, uint3
newMesh->pushPrimitiveBack(newPrimitive); newMesh->pushPrimitiveBack(newPrimitive);
} }
// Mesh BB from BBs of primitives // Mesh BB from BBs of primitives
for (auto p : newMesh->getPrimitives()) { for (auto p : newMesh->getPrimitives())
if (p->getBoundingBox().isValid() && !newMesh->getBoundingBox().isValid()) { {
if (p->getBoundingBox().isValid() && !newMesh->getBoundingBox().isValid())
{
newMesh->setBoundingBox(p->getBoundingBox()); newMesh->setBoundingBox(p->getBoundingBox());
newMesh->getBoundingBox().setValid(true); newMesh->getBoundingBox().setValid(true);
} }
@ -352,10 +404,12 @@ void glTFMainModel::loadNode(glTFNode* parent, const tinygltf::Node& node, uint3
} }
newNode->setMesh(newMesh); newNode->setMesh(newMesh);
} }
if (parent) { if (parent)
{
parent->pushChildrenBack(newNode); parent->pushChildrenBack(newNode);
} }
else { else
{
m_nodes.push_back(newNode); m_nodes.push_back(newNode);
} }
m_linearNodes.push_back(newNode); m_linearNodes.push_back(newNode);
@ -363,25 +417,30 @@ void glTFMainModel::loadNode(glTFNode* parent, const tinygltf::Node& node, uint3
void glTFMainModel::loadSkins(tinygltf::Model &gltfModel) void glTFMainModel::loadSkins(tinygltf::Model &gltfModel)
{ {
for (tinygltf::Skin& source : gltfModel.skins) { for (tinygltf::Skin &source : gltfModel.skins)
{
glTFSkin *newSkin = new glTFSkin{}; glTFSkin *newSkin = new glTFSkin{};
newSkin->setName(source.name); newSkin->setName(source.name);
// Find skeleton root node // Find skeleton root node
if (source.skeleton > -1) { if (source.skeleton > -1)
{
newSkin->setSkeletonRoot(nodeFromIndex(source.skeleton)); newSkin->setSkeletonRoot(nodeFromIndex(source.skeleton));
} }
// Find joint nodes // Find joint nodes
for (int jointIndex : source.joints) { for (int jointIndex : source.joints)
{
glTFNode *node = nodeFromIndex(jointIndex); glTFNode *node = nodeFromIndex(jointIndex);
if (node) { if (node)
{
newSkin->pushJointsBack(nodeFromIndex(jointIndex)); newSkin->pushJointsBack(nodeFromIndex(jointIndex));
} }
} }
// Get inverse bind matrices from buffer // Get inverse bind matrices from buffer
if (source.inverseBindMatrices > -1) { if (source.inverseBindMatrices > -1)
{
const tinygltf::Accessor &accessor = gltfModel.accessors[source.inverseBindMatrices]; const tinygltf::Accessor &accessor = gltfModel.accessors[source.inverseBindMatrices];
const tinygltf::BufferView &bufferView = gltfModel.bufferViews[accessor.bufferView]; const tinygltf::BufferView &bufferView = gltfModel.bufferViews[accessor.bufferView];
const tinygltf::Buffer &buffer = gltfModel.buffers[bufferView.buffer]; const tinygltf::Buffer &buffer = gltfModel.buffers[bufferView.buffer];
@ -398,10 +457,12 @@ void glTFMainModel::loadSkins(tinygltf::Model& gltfModel)
void glTFMainModel::loadTextures(tinygltf::Model &gltfModel, VulkanBase::VulkanDevice *device, VkQueue transferQueue) void glTFMainModel::loadTextures(tinygltf::Model &gltfModel, VulkanBase::VulkanDevice *device, VkQueue transferQueue)
{ {
for (tinygltf::Texture& tex : gltfModel.textures) { for (tinygltf::Texture &tex : gltfModel.textures)
{
tinygltf::Image image = gltfModel.images[tex.source]; tinygltf::Image image = gltfModel.images[tex.source];
VulkanBase::VulkanTextureSampler textureSampler; VulkanBase::VulkanTextureSampler textureSampler;
if (tex.sampler == -1) { if (tex.sampler == -1)
{
// No sampler specified, use a default one // No sampler specified, use a default one
textureSampler.setMaxFilter(VK_FILTER_LINEAR); textureSampler.setMaxFilter(VK_FILTER_LINEAR);
textureSampler.setMinFilter(VK_FILTER_LINEAR); textureSampler.setMinFilter(VK_FILTER_LINEAR);
@ -409,7 +470,8 @@ void glTFMainModel::loadTextures(tinygltf::Model& gltfModel, VulkanBase::VulkanD
textureSampler.setAddressModeV(VK_SAMPLER_ADDRESS_MODE_REPEAT); textureSampler.setAddressModeV(VK_SAMPLER_ADDRESS_MODE_REPEAT);
textureSampler.setAddressModeW(VK_SAMPLER_ADDRESS_MODE_REPEAT); textureSampler.setAddressModeW(VK_SAMPLER_ADDRESS_MODE_REPEAT);
} }
else { else
{
textureSampler = m_textureSamplers[tex.sampler]; textureSampler = m_textureSamplers[tex.sampler];
} }
glTFTexture texture; glTFTexture texture;
@ -420,7 +482,8 @@ void glTFMainModel::loadTextures(tinygltf::Model& gltfModel, VulkanBase::VulkanD
void glTFMainModel::loadTextureSamplers(tinygltf::Model &gltfModel) void glTFMainModel::loadTextureSamplers(tinygltf::Model &gltfModel)
{ {
for (tinygltf::Sampler smpl : gltfModel.samplers) { for (tinygltf::Sampler smpl : gltfModel.samplers)
{
VulkanBase::VulkanTextureSampler sampler{}; VulkanBase::VulkanTextureSampler sampler{};
sampler.setMinFilter(getVkFilterMode(smpl.minFilter)); sampler.setMinFilter(getVkFilterMode(smpl.minFilter));
sampler.setMaxFilter(getVkFilterMode(smpl.magFilter)); sampler.setMaxFilter(getVkFilterMode(smpl.magFilter));
@ -433,83 +496,104 @@ void glTFMainModel::loadTextureSamplers(tinygltf::Model& gltfModel)
void glTFMainModel::loadMaterials(tinygltf::Model &gltfModel) void glTFMainModel::loadMaterials(tinygltf::Model &gltfModel)
{ {
for (tinygltf::Material& mat : gltfModel.materials) { for (tinygltf::Material &mat : gltfModel.materials)
{
glTFMaterial material{}; glTFMaterial material{};
material.setDoublesided(mat.doubleSided); material.setDoublesided(mat.doubleSided);
if (mat.values.find("baseColorTexture") != mat.values.end()) { if (mat.values.find("baseColorTexture") != mat.values.end())
{
material.getPbrBaseTexture()->setBaseColorTexture(&m_textures[mat.values["baseColorTexture"].TextureIndex()]); material.getPbrBaseTexture()->setBaseColorTexture(&m_textures[mat.values["baseColorTexture"].TextureIndex()]);
material.getTextureCoordSet()->setBaseColor(mat.values["baseColorTexture"].TextureTexCoord()); material.getTextureCoordSet()->setBaseColor(mat.values["baseColorTexture"].TextureTexCoord());
} }
if (mat.values.find("metallicRoughnessTexture") != mat.values.end()) { if (mat.values.find("metallicRoughnessTexture") != mat.values.end())
{
material.getPbrBaseTexture()->setMetallicRoughnessTexture(&m_textures[mat.values["metallicRoughnessTexture"].TextureIndex()]); material.getPbrBaseTexture()->setMetallicRoughnessTexture(&m_textures[mat.values["metallicRoughnessTexture"].TextureIndex()]);
material.getTextureCoordSet()->setMetallicRoughness(mat.values["metallicRoughnessTexture"].TextureTexCoord()); material.getTextureCoordSet()->setMetallicRoughness(mat.values["metallicRoughnessTexture"].TextureTexCoord());
} }
if (mat.values.find("roughnessFactor") != mat.values.end()) { if (mat.values.find("roughnessFactor") != mat.values.end())
{
material.getPbrBaseTexture()->setRoughnessFactor(static_cast<float>(mat.values["roughnessFactor"].Factor())); material.getPbrBaseTexture()->setRoughnessFactor(static_cast<float>(mat.values["roughnessFactor"].Factor()));
} }
if (mat.values.find("metallicFactor") != mat.values.end()) { if (mat.values.find("metallicFactor") != mat.values.end())
{
material.getPbrBaseTexture()->setMetallicFactor(static_cast<float>(mat.values["metallicFactor"].Factor())); material.getPbrBaseTexture()->setMetallicFactor(static_cast<float>(mat.values["metallicFactor"].Factor()));
} }
if (mat.values.find("baseColorFactor") != mat.values.end()) { if (mat.values.find("baseColorFactor") != mat.values.end())
{
material.getPbrBaseTexture()->setBaseColorFactor(glm::make_vec4(mat.values["baseColorFactor"].ColorFactor().data())); material.getPbrBaseTexture()->setBaseColorFactor(glm::make_vec4(mat.values["baseColorFactor"].ColorFactor().data()));
} }
if (mat.additionalValues.find("normalTexture") != mat.additionalValues.end()) { if (mat.additionalValues.find("normalTexture") != mat.additionalValues.end())
{
material.getPbrBaseTexture()->setNormalTexture(&m_textures[mat.additionalValues["normalTexture"].TextureIndex()]); material.getPbrBaseTexture()->setNormalTexture(&m_textures[mat.additionalValues["normalTexture"].TextureIndex()]);
material.getTextureCoordSet()->setNormal(mat.additionalValues["normalTexture"].TextureTexCoord()); material.getTextureCoordSet()->setNormal(mat.additionalValues["normalTexture"].TextureTexCoord());
} }
if (mat.additionalValues.find("emissiveTexture") != mat.additionalValues.end()) { if (mat.additionalValues.find("emissiveTexture") != mat.additionalValues.end())
{
material.getPbrBaseTexture()->setEmissiveTexture(&m_textures[mat.additionalValues["emissiveTexture"].TextureIndex()]); material.getPbrBaseTexture()->setEmissiveTexture(&m_textures[mat.additionalValues["emissiveTexture"].TextureIndex()]);
material.getTextureCoordSet()->setEmissive(mat.additionalValues["emissiveTexture"].TextureTexCoord()); material.getTextureCoordSet()->setEmissive(mat.additionalValues["emissiveTexture"].TextureTexCoord());
} }
if (mat.additionalValues.find("occlusionTexture") != mat.additionalValues.end()) { if (mat.additionalValues.find("occlusionTexture") != mat.additionalValues.end())
{
material.getPbrBaseTexture()->setOcclusionTexture(&m_textures[mat.additionalValues["occlusionTexture"].TextureIndex()]); material.getPbrBaseTexture()->setOcclusionTexture(&m_textures[mat.additionalValues["occlusionTexture"].TextureIndex()]);
material.getTextureCoordSet()->setOcclusion(mat.additionalValues["occlusionTexture"].TextureTexCoord()); material.getTextureCoordSet()->setOcclusion(mat.additionalValues["occlusionTexture"].TextureTexCoord());
} }
if (mat.additionalValues.find("alphaMode") != mat.additionalValues.end()) { if (mat.additionalValues.find("alphaMode") != mat.additionalValues.end())
{
tinygltf::Parameter param = mat.additionalValues["alphaMode"]; tinygltf::Parameter param = mat.additionalValues["alphaMode"];
if (param.string_value == "BLEND") { if (param.string_value == "BLEND")
{
material.setAlphaMode(AlphaMode::ALPHAMODE_BLEND); material.setAlphaMode(AlphaMode::ALPHAMODE_BLEND);
} }
if (param.string_value == "MASK") { if (param.string_value == "MASK")
{
material.setAlphaCutOff(0.5f); material.setAlphaCutOff(0.5f);
material.setAlphaMode(AlphaMode::ALPHAMODE_MASK); material.setAlphaMode(AlphaMode::ALPHAMODE_MASK);
} }
} }
if (mat.additionalValues.find("alphaCutoff") != mat.additionalValues.end()) { if (mat.additionalValues.find("alphaCutoff") != mat.additionalValues.end())
{
material.setAlphaCutOff(static_cast<float>(mat.additionalValues["alphaCutoff"].Factor())); material.setAlphaCutOff(static_cast<float>(mat.additionalValues["alphaCutoff"].Factor()));
} }
if (mat.additionalValues.find("emissiveFactor") != mat.additionalValues.end()) { if (mat.additionalValues.find("emissiveFactor") != mat.additionalValues.end())
{
material.getPbrBaseTexture()->setEmissiveFactor(glm::vec4(glm::make_vec3(mat.additionalValues["emissiveFactor"].ColorFactor().data()), 1.0)); material.getPbrBaseTexture()->setEmissiveFactor(glm::vec4(glm::make_vec3(mat.additionalValues["emissiveFactor"].ColorFactor().data()), 1.0));
} }
// Extensions // Extensions
if (mat.extensions.find("KHR_materials_pbrSpecularGlossiness") != mat.extensions.end()) { if (mat.extensions.find("KHR_materials_pbrSpecularGlossiness") != mat.extensions.end())
{
auto ext = mat.extensions.find("KHR_materials_pbrSpecularGlossiness"); auto ext = mat.extensions.find("KHR_materials_pbrSpecularGlossiness");
if (ext->second.Has("specularGlossinessTexture")) { if (ext->second.Has("specularGlossinessTexture"))
{
auto index = ext->second.Get("specularGlossinessTexture").Get("index"); auto index = ext->second.Get("specularGlossinessTexture").Get("index");
material.getTextureExtension()->setSpecularGlossinessTexture(&m_textures[index.Get<int>()]); material.getTextureExtension()->setSpecularGlossinessTexture(&m_textures[index.Get<int>()]);
auto texCoordSet = ext->second.Get("specularGlossinessTexture").Get("texCoord"); auto texCoordSet = ext->second.Get("specularGlossinessTexture").Get("texCoord");
material.getTextureCoordSet()->setSpecularGlossiness(texCoordSet.Get<int>()); material.getTextureCoordSet()->setSpecularGlossiness(texCoordSet.Get<int>());
material.getPbrWorkFlow()->setSpecularGlossiness(true); material.getPbrWorkFlow()->setSpecularGlossiness(true);
} }
if (ext->second.Has("diffuseTexture")) { if (ext->second.Has("diffuseTexture"))
{
auto index = ext->second.Get("diffuseTexture").Get("index"); auto index = ext->second.Get("diffuseTexture").Get("index");
material.getTextureExtension()->setDiffuseTexture(&m_textures[index.Get<int>()]); material.getTextureExtension()->setDiffuseTexture(&m_textures[index.Get<int>()]);
} }
if (ext->second.Has("diffuseFactor")) { if (ext->second.Has("diffuseFactor"))
{
auto factor = ext->second.Get("diffuseFactor"); auto factor = ext->second.Get("diffuseFactor");
glm::vec4 diffuseFactor(0.0); glm::vec4 diffuseFactor(0.0);
for (uint32_t i = 0; i < factor.ArrayLen(); i++) { for (uint32_t i = 0; i < factor.ArrayLen(); i++)
{
auto val = factor.Get(i); auto val = factor.Get(i);
diffuseFactor[i] = val.IsNumber() ? (float)val.Get<double>() : (float)val.Get<int>(); diffuseFactor[i] = val.IsNumber() ? (float)val.Get<double>() : (float)val.Get<int>();
} }
material.getTextureExtension()->setDiffuseFactor(diffuseFactor); material.getTextureExtension()->setDiffuseFactor(diffuseFactor);
} }
if (ext->second.Has("specularFactor")) { if (ext->second.Has("specularFactor"))
{
auto factor = ext->second.Get("specularFactor"); auto factor = ext->second.Get("specularFactor");
glm::vec3 specularFactor(0.0); glm::vec3 specularFactor(0.0);
for (uint32_t i = 0; i < factor.ArrayLen(); i++) { for (uint32_t i = 0; i < factor.ArrayLen(); i++)
{
auto val = factor.Get(i); auto val = factor.Get(i);
specularFactor[i] = val.IsNumber() ? (float)val.Get<double>() : (float)val.Get<int>(); specularFactor[i] = val.IsNumber() ? (float)val.Get<double>() : (float)val.Get<int>();
} }
@ -525,24 +609,30 @@ void glTFMainModel::loadMaterials(tinygltf::Model& gltfModel)
void glTFMainModel::loadAnimations(tinygltf::Model &gltfModel) void glTFMainModel::loadAnimations(tinygltf::Model &gltfModel)
{ {
for (tinygltf::Animation& anim : gltfModel.animations) { for (tinygltf::Animation &anim : gltfModel.animations)
{
glTFAnimation animation{}; glTFAnimation animation{};
animation.setName(anim.name); animation.setName(anim.name);
if (anim.name.empty()) { if (anim.name.empty())
{
animation.setName(std::to_string(m_animations.size())); animation.setName(std::to_string(m_animations.size()));
} }
// Samplers // Samplers
for (auto& samp : anim.samplers) { for (auto &samp : anim.samplers)
{
glTFAnimationSampler sampler{}; glTFAnimationSampler sampler{};
if (samp.interpolation == "LINEAR") { if (samp.interpolation == "LINEAR")
{
sampler.setAnimationInterpolationType(AnimationInterpolationType::LINEAR); sampler.setAnimationInterpolationType(AnimationInterpolationType::LINEAR);
} }
if (samp.interpolation == "STEP") { if (samp.interpolation == "STEP")
{
sampler.setAnimationInterpolationType(AnimationInterpolationType::STEP); sampler.setAnimationInterpolationType(AnimationInterpolationType::STEP);
} }
if (samp.interpolation == "CUBICSPLINE") { if (samp.interpolation == "CUBICSPLINE")
{
sampler.setAnimationInterpolationType(AnimationInterpolationType::CUBICSPLINE); sampler.setAnimationInterpolationType(AnimationInterpolationType::CUBICSPLINE);
} }
@ -556,17 +646,20 @@ void glTFMainModel::loadAnimations(tinygltf::Model& gltfModel)
const void *dataPtr = &buffer.data[accessor.byteOffset + bufferView.byteOffset]; const void *dataPtr = &buffer.data[accessor.byteOffset + bufferView.byteOffset];
const float *buf = static_cast<const float *>(dataPtr); const float *buf = static_cast<const float *>(dataPtr);
for (size_t index = 0; index < accessor.count; index++) { for (size_t index = 0; index < accessor.count; index++)
{
sampler.pushInputBack(buf[index]); sampler.pushInputBack(buf[index]);
} }
for (auto input : sampler.getInputs()) { for (auto input : sampler.getInputs())
if (input < animation.getStart()) { {
if (input < animation.getStart())
{
animation.setStart(input); animation.setStart(input);
}; };
if (input > animation.getEnd()) { if (input > animation.getEnd())
{
animation.setEnd(input); animation.setEnd(input);
} }
} }
@ -582,26 +675,30 @@ void glTFMainModel::loadAnimations(tinygltf::Model& gltfModel)
const void *dataPtr = &buffer.data[accessor.byteOffset + bufferView.byteOffset]; const void *dataPtr = &buffer.data[accessor.byteOffset + bufferView.byteOffset];
switch (accessor.type) { switch (accessor.type)
case TINYGLTF_TYPE_VEC3: { {
case TINYGLTF_TYPE_VEC3:
{
const glm::vec3 *buf = static_cast<const glm::vec3 *>(dataPtr); const glm::vec3 *buf = static_cast<const glm::vec3 *>(dataPtr);
for (size_t index = 0; index < accessor.count; index++) { for (size_t index = 0; index < accessor.count; index++)
{
sampler.pushOutputsVec4Back(glm::vec4(buf[index], 0.0f)); sampler.pushOutputsVec4Back(glm::vec4(buf[index], 0.0f));
} }
break; break;
} }
case TINYGLTF_TYPE_VEC4: { case TINYGLTF_TYPE_VEC4:
{
const glm::vec4 *buf = static_cast<const glm::vec4 *>(dataPtr); const glm::vec4 *buf = static_cast<const glm::vec4 *>(dataPtr);
for (size_t index = 0; index < accessor.count; index++) { for (size_t index = 0; index < accessor.count; index++)
{
sampler.pushOutputsVec4Back(buf[index]); sampler.pushOutputsVec4Back(buf[index]);
} }
break; break;
} }
default: { default:
{
std::cout << "unknown type" << std::endl; std::cout << "unknown type" << std::endl;
break; break;
} }
@ -609,29 +706,34 @@ void glTFMainModel::loadAnimations(tinygltf::Model& gltfModel)
} }
animation.pushSamplersBack(sampler); animation.pushSamplersBack(sampler);
} }
// Channels // Channels
for (auto& source : anim.channels) { for (auto &source : anim.channels)
{
glTFAnimationChannel channel{}; glTFAnimationChannel channel{};
if (source.target_path == "rotation") { if (source.target_path == "rotation")
{
channel.setAnimationPathType(AnimationPathType::ROTATION); channel.setAnimationPathType(AnimationPathType::ROTATION);
} }
if (source.target_path == "translation") { if (source.target_path == "translation")
{
channel.setAnimationPathType(AnimationPathType::TRANSLATION); channel.setAnimationPathType(AnimationPathType::TRANSLATION);
} }
if (source.target_path == "scale") { if (source.target_path == "scale")
{
channel.setAnimationPathType(AnimationPathType::SCALE); channel.setAnimationPathType(AnimationPathType::SCALE);
} }
if (source.target_path == "weights") { if (source.target_path == "weights")
{
std::cout << "weights not yet supported, skipping channel" << std::endl; std::cout << "weights not yet supported, skipping channel" << std::endl;
continue; continue;
} }
channel.setSamplerIndex(source.sampler); channel.setSamplerIndex(source.sampler);
channel.setNode(nodeFromIndex(source.target_node)); channel.setNode(nodeFromIndex(source.target_node));
if (!channel.getNode()) { if (!channel.getNode())
{
continue; continue;
} }
@ -654,7 +756,8 @@ void glTFMainModel::loadFromFile(std::string filename, VulkanBase::VulkanDevice*
bool binary = false; bool binary = false;
size_t extpos = filename.rfind('.', filename.length()); size_t extpos = filename.rfind('.', filename.length());
if (extpos != std::string::npos) { if (extpos != std::string::npos)
{
binary = (filename.substr(extpos + 1, filename.length() - extpos) == "glb"); binary = (filename.substr(extpos + 1, filename.length() - extpos) == "glb");
} }
@ -664,7 +767,8 @@ void glTFMainModel::loadFromFile(std::string filename, VulkanBase::VulkanDevice*
size_t vertexCount = 0; size_t vertexCount = 0;
size_t indexCount = 0; size_t indexCount = 0;
if (fileLoaded) { if (fileLoaded)
{
loadTextureSamplers(gltfModel); loadTextureSamplers(gltfModel);
loadTextures(gltfModel, device, transferQueue); loadTextures(gltfModel, device, transferQueue);
loadMaterials(gltfModel); loadMaterials(gltfModel);
@ -672,34 +776,41 @@ void glTFMainModel::loadFromFile(std::string filename, VulkanBase::VulkanDevice*
const tinygltf::Scene &scene = gltfModel.scenes[gltfModel.defaultScene > -1 ? gltfModel.defaultScene : 0]; const tinygltf::Scene &scene = gltfModel.scenes[gltfModel.defaultScene > -1 ? gltfModel.defaultScene : 0];
// Get vertex and index buffer sizes up-front // Get vertex and index buffer sizes up-front
for (size_t i = 0; i < scene.nodes.size(); i++) { for (size_t i = 0; i < scene.nodes.size(); i++)
{
getNodeProperty(gltfModel.nodes[scene.nodes[i]], gltfModel, vertexCount, indexCount); getNodeProperty(gltfModel.nodes[scene.nodes[i]], gltfModel, vertexCount, indexCount);
} }
loaderInfo.vertexBuffer = new Vertex[vertexCount]; loaderInfo.vertexBuffer = new Vertex[vertexCount];
loaderInfo.indexBuffer = new uint32_t[indexCount]; loaderInfo.indexBuffer = new uint32_t[indexCount];
// TODO: scene handling with no default scene // TODO: scene handling with no default scene
for (size_t i = 0; i < scene.nodes.size(); i++) { for (size_t i = 0; i < scene.nodes.size(); i++)
{
const tinygltf::Node node = gltfModel.nodes[scene.nodes[i]]; const tinygltf::Node node = gltfModel.nodes[scene.nodes[i]];
loadNode(nullptr, node, scene.nodes[i], gltfModel, loaderInfo, scale); loadNode(nullptr, node, scene.nodes[i], gltfModel, loaderInfo, scale);
} }
if (gltfModel.animations.size() > 0) { if (gltfModel.animations.size() > 0)
{
loadAnimations(gltfModel); loadAnimations(gltfModel);
} }
loadSkins(gltfModel); loadSkins(gltfModel);
for (auto node : m_linearNodes) { for (auto node : m_linearNodes)
{
// Assign skins // Assign skins
if (node->getSkinIndex() > -1) { if (node->getSkinIndex() > -1)
{
node->setSkin(m_skins[node->getSkinIndex()]); node->setSkin(m_skins[node->getSkinIndex()]);
} }
// Initial pose // Initial pose
if (node->getMesh()) { if (node->getMesh())
{
node->update(); node->update();
} }
} }
} }
else { else
{
// TODO: throw // TODO: throw
std::cerr << "Could not load gltf file: " << error << std::endl; std::cerr << "Could not load gltf file: " << error << std::endl;
return; return;
@ -712,7 +823,8 @@ void glTFMainModel::loadFromFile(std::string filename, VulkanBase::VulkanDevice*
assert(vertexBufferSize > 0); assert(vertexBufferSize > 0);
struct StagingBuffer { struct StagingBuffer
{
VkBuffer buffer; VkBuffer buffer;
VkDeviceMemory memory; VkDeviceMemory memory;
} vertexStaging, indexStaging; } vertexStaging, indexStaging;
@ -727,7 +839,8 @@ void glTFMainModel::loadFromFile(std::string filename, VulkanBase::VulkanDevice*
&vertexStaging.memory, &vertexStaging.memory,
loaderInfo.vertexBuffer)); loaderInfo.vertexBuffer));
// Index data // Index data
if (indexBufferSize > 0) { if (indexBufferSize > 0)
{
VK_CHECK_RESULT(device->createBuffer( VK_CHECK_RESULT(device->createBuffer(
VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
@ -746,7 +859,8 @@ void glTFMainModel::loadFromFile(std::string filename, VulkanBase::VulkanDevice*
&m_vertices.buffer, &m_vertices.buffer,
&m_vertices.memory)); &m_vertices.memory));
// Index buffer // Index buffer
if (indexBufferSize > 0) { if (indexBufferSize > 0)
{
VK_CHECK_RESULT(device->createBuffer( VK_CHECK_RESULT(device->createBuffer(
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
@ -763,7 +877,8 @@ void glTFMainModel::loadFromFile(std::string filename, VulkanBase::VulkanDevice*
copyRegion.size = vertexBufferSize; copyRegion.size = vertexBufferSize;
vkCmdCopyBuffer(copyCmd, vertexStaging.buffer, m_vertices.buffer, 1, &copyRegion); vkCmdCopyBuffer(copyCmd, vertexStaging.buffer, m_vertices.buffer, 1, &copyRegion);
if (indexBufferSize > 0) { if (indexBufferSize > 0)
{
copyRegion.size = indexBufferSize; copyRegion.size = indexBufferSize;
vkCmdCopyBuffer(copyCmd, indexStaging.buffer, m_indices.buffer, 1, &copyRegion); vkCmdCopyBuffer(copyCmd, indexStaging.buffer, m_indices.buffer, 1, &copyRegion);
} }
@ -772,7 +887,8 @@ void glTFMainModel::loadFromFile(std::string filename, VulkanBase::VulkanDevice*
vkDestroyBuffer(device->getLogicalDevice(), vertexStaging.buffer, nullptr); vkDestroyBuffer(device->getLogicalDevice(), vertexStaging.buffer, nullptr);
vkFreeMemory(device->getLogicalDevice(), vertexStaging.memory, nullptr); vkFreeMemory(device->getLogicalDevice(), vertexStaging.memory, nullptr);
if (indexBufferSize > 0) { if (indexBufferSize > 0)
{
vkDestroyBuffer(device->getLogicalDevice(), indexStaging.buffer, nullptr); vkDestroyBuffer(device->getLogicalDevice(), indexStaging.buffer, nullptr);
vkFreeMemory(device->getLogicalDevice(), indexStaging.memory, nullptr); vkFreeMemory(device->getLogicalDevice(), indexStaging.memory, nullptr);
} }
@ -785,12 +901,15 @@ void glTFMainModel::loadFromFile(std::string filename, VulkanBase::VulkanDevice*
void glTFMainModel::drawNode(glTFNode *node, VkCommandBuffer commandBuffer) void glTFMainModel::drawNode(glTFNode *node, VkCommandBuffer commandBuffer)
{ {
if (node->getMesh()) { if (node->getMesh())
for (glTFPrimitive* primitive : node->getMesh()->getPrimitives()) { {
for (glTFPrimitive *primitive : node->getMesh()->getPrimitives())
{
vkCmdDrawIndexed(commandBuffer, primitive->getIndexCount(), 1, primitive->getFirstIndex(), 0, 0); vkCmdDrawIndexed(commandBuffer, primitive->getIndexCount(), 1, primitive->getFirstIndex(), 0, 0);
} }
} }
for (auto& child : node->getChildren()) { for (auto &child : node->getChildren())
{
drawNode(child, commandBuffer); drawNode(child, commandBuffer);
} }
} }
@ -800,7 +919,8 @@ void glTFMainModel::draw(VkCommandBuffer commandBuffer)
const VkDeviceSize offsets[1] = {0}; const VkDeviceSize offsets[1] = {0};
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &m_vertices.buffer, offsets); vkCmdBindVertexBuffers(commandBuffer, 0, 1, &m_vertices.buffer, offsets);
vkCmdBindIndexBuffer(commandBuffer, m_indices.buffer, 0, VK_INDEX_TYPE_UINT32); vkCmdBindIndexBuffer(commandBuffer, m_indices.buffer, 0, VK_INDEX_TYPE_UINT32);
for (auto& node : m_nodes) { for (auto &node : m_nodes)
{
drawNode(node, commandBuffer); drawNode(node, commandBuffer);
} }
} }
@ -811,11 +931,14 @@ void glTFMainModel::calculateBoundingBox(glTFNode* node, glTFNode* parent)
glTFMesh *nodeMesh = node->getMesh(); glTFMesh *nodeMesh = node->getMesh();
if (nodeMesh) { if (nodeMesh)
if (nodeMesh->getBoundingBox().isValid()) { {
if (nodeMesh->getBoundingBox().isValid())
{
node->setAxisAlignedBoundingBox(nodeMesh->getBoundingBox().getAABB(node->getMatrix())); node->setAxisAlignedBoundingBox(nodeMesh->getBoundingBox().getAABB(node->getMatrix()));
if (node->getChildren().size() == 0) { if (node->getChildren().size() == 0)
{
glTFBoundingBox nodeAABB = node->getAxisAlignedBoundingBox(); glTFBoundingBox nodeAABB = node->getAxisAlignedBoundingBox();
nodeAABB.setValid(true); nodeAABB.setValid(true);
node->setBvh(nodeAABB); node->setBvh(nodeAABB);
@ -826,36 +949,44 @@ void glTFMainModel::calculateBoundingBox(glTFNode* node, glTFNode* parent)
parentBvh.setMin(glm::min(parentBvh.getMin(), node->getBvh().getMin())); parentBvh.setMin(glm::min(parentBvh.getMin(), node->getBvh().getMin()));
parentBvh.setMax(glm::min(parentBvh.getMax(), node->getBvh().getMax())); parentBvh.setMax(glm::min(parentBvh.getMax(), node->getBvh().getMax()));
for (auto& child : node->getChildren()) { for (auto &child : node->getChildren())
{
calculateBoundingBox(child, node); calculateBoundingBox(child, node);
} }
} }
void glTFMainModel::updateAnimation(uint32_t index, float time) void glTFMainModel::updateAnimation(uint32_t index, float time)
{ {
if (m_animations.empty()) { if (m_animations.empty())
{
std::cout << ".glTF does not contain animation." << std::endl; std::cout << ".glTF does not contain animation." << std::endl;
return; return;
} }
if (index > static_cast<uint32_t>(m_animations.size()) - 1) { if (index > static_cast<uint32_t>(m_animations.size()) - 1)
{
std::cout << "No animation with index " << index << std::endl; std::cout << "No animation with index " << index << std::endl;
return; return;
} }
glTFAnimation &animation = m_animations[index]; glTFAnimation &animation = m_animations[index];
bool updated = false; bool updated = false;
for (auto& channel : animation.getChannels()) { for (auto &channel : animation.getChannels())
{
glTFAnimationSampler &sampler = animation.getSampler()[channel.getSamplerIndex()]; glTFAnimationSampler &sampler = animation.getSampler()[channel.getSamplerIndex()];
if (sampler.getInputs().size() > sampler.getOutputsVec4().size()) { if (sampler.getInputs().size() > sampler.getOutputsVec4().size())
{
continue; continue;
} }
std::vector<float> samplerInputs = sampler.getInputs(); std::vector<float> samplerInputs = sampler.getInputs();
for (size_t i = 0; i < sampler.getInputs().size() - 1; i++) { for (size_t i = 0; i < sampler.getInputs().size() - 1; i++)
if ((time >= samplerInputs[i]) && (time <= samplerInputs[i + 1])) { {
if ((time >= samplerInputs[i]) && (time <= samplerInputs[i + 1]))
{
float u = std::max(0.0f, time - samplerInputs[i]) / (samplerInputs[i + 1] - samplerInputs[i]); float u = std::max(0.0f, time - samplerInputs[i]) / (samplerInputs[i + 1] - samplerInputs[i]);
if (u <= 1.0f) if (u <= 1.0f)
{ {
switch (channel.getAnimationPathType()) { switch (channel.getAnimationPathType())
{
case glTFLoader::AnimationPathType::TRANSLATION: case glTFLoader::AnimationPathType::TRANSLATION:
{ {
std::vector<glm::vec4> samplerOutPutVec4 = sampler.getOutputsVec4(); std::vector<glm::vec4> samplerOutPutVec4 = sampler.getOutputsVec4();
@ -899,8 +1030,10 @@ void glTFMainModel::updateAnimation(uint32_t index, float time)
} }
} }
} }
if (updated) { if (updated)
for (auto& node : m_nodes) { {
for (auto &node : m_nodes)
{
node->update(); node->update();
} }
} }
@ -909,12 +1042,15 @@ void glTFMainModel::updateAnimation(uint32_t index, float time)
glTFNode *glTFMainModel::findNode(glTFNode *parent, uint32_t index) glTFNode *glTFMainModel::findNode(glTFNode *parent, uint32_t index)
{ {
glTFNode *nodeFound = nullptr; glTFNode *nodeFound = nullptr;
if (parent->getIndex() == index) { if (parent->getIndex() == index)
{
return parent; return parent;
} }
for (auto& child : parent->getChildren()) { for (auto &child : parent->getChildren())
{
nodeFound = findNode(child, index); nodeFound = findNode(child, index);
if (nodeFound) { if (nodeFound)
{
break; break;
} }
} }
@ -924,9 +1060,11 @@ glTFNode* glTFMainModel::findNode(glTFNode* parent, uint32_t index)
glTFNode *glTFMainModel::nodeFromIndex(uint32_t index) glTFNode *glTFMainModel::nodeFromIndex(uint32_t index)
{ {
glTFNode *nodeFound = nullptr; glTFNode *nodeFound = nullptr;
for (auto& node : m_nodes) { for (auto &node : m_nodes)
{
nodeFound = findNode(node, index); nodeFound = findNode(node, index);
if (nodeFound) { if (nodeFound)
{
break; break;
} }
} }
@ -934,5 +1072,3 @@ glTFNode* glTFMainModel::nodeFromIndex(uint32_t index)
} }
GLTFLOADER_NAMESPACE_END GLTFLOADER_NAMESPACE_END

View File

@ -1,15 +1,21 @@
#ifndef GLTFMAINMODEL_H #ifndef GLTFMAINMODEL_H
#define GLTFMAINMODEL_H #define GLTFMAINMODEL_H
#ifndef TINYGLTF_NO_STB_IMAGE_WRITE
#define TINYGLTF_NO_STB_IMAGE_WRITE
#endif
#include "glTFModel_Marco.h" #include "glTFModel_Marco.h"
#include "glTFModel_common.h" #include "glTFModel_common.h"
#include "VulkanDevice.h" #include "VulkanDevice.h"
#include "glTFAnimation.h"
#include "glTFNode.h" #include "glTFNode.h"
#include "glTFSkin.h" #include "glTFSkin.h"
#include "glTFTexture.h" #include "glTFTexture.h"
#include "glTFAnimation.h"
#include <tiny_gltf.h>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <string> #include <string>
@ -17,6 +23,18 @@
GLTFLOADER_NAMESPACE_BEGIN GLTFLOADER_NAMESPACE_BEGIN
struct ModelBuffer
{
VkBuffer buffer = VK_NULL_HANDLE;
VkDeviceMemory memory;
};
struct AABBDimensions
{
glm::vec3 min = glm::vec3(FLT_MAX);
glm::vec3 max = glm::vec3(-FLT_MAX);
};
class glTFMainModel class glTFMainModel
{ {
public: public:
@ -27,6 +45,10 @@ public:
VkFilter getVkFilterMode(int32_t filterMode); VkFilter getVkFilterMode(int32_t filterMode);
void getNodeProperty(const tinygltf::Node &node, const tinygltf::Model &model, size_t &vertexCount, size_t &indexCount); void getNodeProperty(const tinygltf::Node &node, const tinygltf::Model &model, size_t &vertexCount, size_t &indexCount);
void getSceneDimensions(); void getSceneDimensions();
ModelBuffer &getModelVertex();
ModelBuffer &getModelIndex();
void destroy(VkDevice device); void destroy(VkDevice device);
void loadNode(glTFNode *parent, const tinygltf::Node &node, uint32_t nodeIndex, const tinygltf::Model &model, LoaderInfo &loaderInfo, float globalscale); void loadNode(glTFNode *parent, const tinygltf::Node &node, uint32_t nodeIndex, const tinygltf::Model &model, LoaderInfo &loaderInfo, float globalscale);
@ -46,17 +68,10 @@ public:
glTFNode *nodeFromIndex(uint32_t index); glTFNode *nodeFromIndex(uint32_t index);
private: private:
VulkanBase::VulkanDevice *m_device; VulkanBase::VulkanDevice *m_device;
struct Vertices { ModelBuffer m_vertices;
VkBuffer buffer = VK_NULL_HANDLE; ModelBuffer m_indices;
VkDeviceMemory memory;
} m_vertices;
struct Indices {
VkBuffer buffer = VK_NULL_HANDLE;
VkDeviceMemory memory;
} m_indices;
glm::mat4 m_aabb; glm::mat4 m_aabb;
@ -71,14 +86,9 @@ private:
std::vector<glTFAnimation> m_animations; std::vector<glTFAnimation> m_animations;
std::vector<std::string> m_extensions; std::vector<std::string> m_extensions;
struct Dimensions { AABBDimensions m_dimensions;
glm::vec3 min = glm::vec3(FLT_MAX);
glm::vec3 max = glm::vec3(-FLT_MAX);
} m_dimensions;
}; };
GLTFLOADER_NAMESPACE_END GLTFLOADER_NAMESPACE_END
#endif // !GLTFMAINMODEL_h #endif // !GLTFMAINMODEL_h

View File

@ -1,6 +1,5 @@
#include "glTFMaterial.h" #include "glTFMaterial.h"
GLTFLOADER_NAMESPACE_BEGIN GLTFLOADER_NAMESPACE_BEGIN
glTFMaterial::glTFMaterial() glTFMaterial::glTFMaterial()
@ -51,34 +50,43 @@ void glTFMaterial::setTextureCoordSet(TextureCoordSet* value)
m_texCoordSets = value; m_texCoordSets = value;
} }
PbrTextureExtension* glTFMaterial::getTextureExtension() PBR::PbrTextureExtension *glTFMaterial::getTextureExtension()
{ {
return m_textureExtension; return m_textureExtension;
} }
void glTFMaterial::setPbrTextureExtension(PbrTextureExtension* value) void glTFMaterial::setPbrTextureExtension(PBR::PbrTextureExtension *value)
{ {
m_textureExtension = value; m_textureExtension = value;
} }
PbrBaseTexture* glTFMaterial::getPbrBaseTexture() PBR::PbrBaseTexture *glTFMaterial::getPbrBaseTexture()
{ {
return m_pbrBaseTexture; return m_pbrBaseTexture;
} }
void glTFMaterial::setPbrBaseTexture(PbrBaseTexture* value) void glTFMaterial::setPbrBaseTexture(PBR::PbrBaseTexture *value)
{ {
m_pbrBaseTexture = value; m_pbrBaseTexture = value;
} }
PbrWorkFlow* glTFMaterial::getPbrWorkFlow() PBR::PbrWorkFlow *glTFMaterial::getPbrWorkFlow()
{ {
return m_pbrWorkFlow; return m_pbrWorkFlow;
} }
void glTFMaterial::setPbrWorkFlow() void glTFMaterial::setPbrWorkFlow(PBR::PbrWorkFlow *value)
{ {
m_pbrWorkFlow; m_pbrWorkFlow = value;
}
void glTFMaterial::setDescriptorSet(VkDescriptorSet value)
{
m_descriptorSet = value;
}
VkDescriptorSet glTFMaterial::getDescriptorSet()
{
return m_descriptorSet;
} }
GLTFLOADER_NAMESPACE_END GLTFLOADER_NAMESPACE_END

View File

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

View File

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

View File

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

View File

@ -3,12 +3,11 @@
#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
@ -27,20 +26,24 @@ public:
void setFirstIndex(unsigned int firstIndex); void setFirstIndex(unsigned int firstIndex);
unsigned int getFirstIndex(); unsigned int getFirstIndex();
private: void setGltfMaterial(glTFMaterial &material);
glTFMaterial &getGltfMaterial();
void setHasIndices(bool hasIndices);
bool getHasIndices();
void setVertexCount(unsigned int vertexCount);
unsigned int getVertexCount();
private:
unsigned int m_firstIndex; unsigned int m_firstIndex;
unsigned int m_indexCount; unsigned int m_indexCount;
unsigned int m_vertexCount; unsigned int m_vertexCount;
glTFMaterial &m_material; glTFMaterial &m_material;
bool m_hasIndices; bool m_hasIndices;
glTFBoundingBox m_boundingBox; glTFBoundingBox m_boundingBox;
}; };
GLTFLOADER_NAMESPACE_END GLTFLOADER_NAMESPACE_END
#endif // !GLTFPRIMITIVE_H #endif // !GLTFPRIMITIVE_H

View File

@ -8,7 +8,6 @@
#include <tiny_gltf.h> #include <tiny_gltf.h>
GLTFLOADER_NAMESPACE_BEGIN GLTFLOADER_NAMESPACE_BEGIN
/// @brief gltf模型的贴图 /// @brief gltf模型的贴图
@ -25,7 +24,6 @@ public:
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;
@ -38,13 +36,6 @@ private:
VkSampler m_sampler; VkSampler m_sampler;
}; };
GLTFLOADER_NAMESPACE_END GLTFLOADER_NAMESPACE_END
#endif // !GLTFTEXTURE_H #endif // !GLTFTEXTURE_H

View File

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

View File

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

34
src/pbr/PbrMarco.h 100644
View File

@ -0,0 +1,34 @@
#pragma once
#define MAX_NUM_JOINTS 128u
/// 命名空间宏
#define PBR_NAMESPACE_BEGIN \
namespace PBR \
{
#define PBR_NAMESPACE_END }
/// windows 导入导出宏PBR_EXPORTS将在cmake中定义
/// unix-like 下提供符号可见性控制
#ifdef PBR_STATIC_BUILD
#define PBR_API
#define PBR_LOCAL
#else
#ifdef _WIN32
#ifdef PBR_EXPORTS
#define PBR_API __declspec(dllexport)
#define PBR_LOCAL
#else
#define PBR_API __declspec(dllimport)
#define PBR_LOCAL
#endif
#else
#if __GNUC__ >= 4 || defined(__clang__)
#define PBR_API __attribute__((visibility("default")))
#define PBR_LOCAL __attribute__((visibility("hidden")))
#else
#define PBR_API
#define PBR_LOCAL
#endif
#endif
#endif

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,147 @@
#include "ShaderLoader.h"
#include <cassert>
#include <fstream>
#include <iostream>
ShaderLoader::ShaderLoader()
{
}
ShaderLoader::~ShaderLoader()
{
}
VkPipelineShaderStageCreateInfo ShaderLoader::loadShader(VkDevice device, std::string filename, VkShaderStageFlagBits stage)
{
VkPipelineShaderStageCreateInfo shaderStage{};
shaderStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
shaderStage.stage = stage;
shaderStage.pName = "main";
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
std::string assetpath = "shaders/" + filename;
AAsset *asset = AAssetManager_open(androidApp->activity->assetManager, assetpath.c_str(), AASSET_MODE_STREAMING);
assert(asset);
size_t size = AAsset_getLength(asset);
assert(size > 0);
char *shaderCode = new char[size];
AAsset_read(asset, shaderCode, size);
AAsset_close(asset);
VkShaderModule shaderModule;
VkShaderModuleCreateInfo moduleCreateInfo;
moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
moduleCreateInfo.pNext = NULL;
moduleCreateInfo.codeSize = size;
moduleCreateInfo.pCode = (uint32_t *)shaderCode;
moduleCreateInfo.flags = 0;
VK_CHECK_RESULT(vkCreateShaderModule(device, &moduleCreateInfo, NULL, &shaderStage.module));
delete[] shaderCode;
#else
std::ifstream is(filename, std::ios::binary | std::ios::in | std::ios::ate);
if (is.is_open())
{
size_t size = is.tellg();
is.seekg(0, std::ios::beg);
char *shaderCode = new char[size];
is.read(shaderCode, size);
is.close();
assert(size > 0);
VkShaderModuleCreateInfo moduleCreateInfo{};
moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
moduleCreateInfo.codeSize = size;
moduleCreateInfo.pCode = (uint32_t *)shaderCode;
vkCreateShaderModule(device, &moduleCreateInfo, NULL, &shaderStage.module);
delete[] shaderCode;
}
else
{
std::cerr << "Error: Could not open shader file \"" << filename << "\"" << std::endl;
shaderStage.module = VK_NULL_HANDLE;
}
#endif
return shaderStage;
}
void ShaderLoader::readDirectory(const std::string &directory, const std::string &pattern, std::map<std::string, std::string> &filelist, bool recursive)
{
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
AAssetDir *assetDir = AAssetManager_openDir(androidApp->activity->assetManager, directory.c_str());
AAssetDir_rewind(assetDir);
const char *assetName;
while ((assetName = AAssetDir_getNextFileName(assetDir)) != 0)
{
std::string filename(assetName);
filename.erase(filename.find_last_of("."), std::string::npos);
filelist[filename] = directory + "/" + assetName;
}
AAssetDir_close(assetDir);
#elif defined(VK_USE_PLATFORM_WIN32_KHR)
std::string searchpattern(directory + "/" + pattern);
WIN32_FIND_DATA data;
HANDLE hFind;
if ((hFind = FindFirstFile(searchpattern.c_str(), &data)) != INVALID_HANDLE_VALUE)
{
do
{
std::string filename(data.cFileName);
filename.erase(filename.find_last_of("."), std::string::npos);
filelist[filename] = directory + "/" + data.cFileName;
} while (FindNextFile(hFind, &data) != 0);
FindClose(hFind);
}
if (recursive)
{
std::string dirpattern = directory + "/*";
if ((hFind = FindFirstFile(dirpattern.c_str(), &data)) != INVALID_HANDLE_VALUE)
{
do
{
if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
char subdir[MAX_PATH];
strcpy(subdir, directory.c_str());
strcat(subdir, "/");
strcat(subdir, data.cFileName);
if ((strcmp(data.cFileName, ".") != 0) && (strcmp(data.cFileName, "..") != 0))
{
readDirectory(subdir, pattern, filelist, recursive);
}
}
} while (FindNextFile(hFind, &data) != 0);
FindClose(hFind);
}
}
#elif defined(__linux__)
std::string patternExt = pattern;
patternExt.erase(0, pattern.find_last_of("."));
struct dirent *entry;
DIR *dir = opendir(directory.c_str());
if (dir == NULL)
{
return;
}
while ((entry = readdir(dir)) != NULL)
{
if (entry->d_type == DT_REG)
{
std::string filename(entry->d_name);
if (filename.find(patternExt) != std::string::npos)
{
filename.erase(filename.find_last_of("."), std::string::npos);
filelist[filename] = directory + "/" + entry->d_name;
}
}
if (recursive && (entry->d_type == DT_DIR))
{
std::string subdir = directory + "/" + entry->d_name;
if ((strcmp(entry->d_name, ".") != 0) && (strcmp(entry->d_name, "..") != 0))
{
readDirectory(subdir, pattern, filelist, recursive);
}
}
}
closedir(dir);
#endif
}

View File

@ -0,0 +1,17 @@
#ifndef SHADERLOADER_H
#define SHADERLOADER_H
#include <map>
#include <string>
#include <vulkan/vulkan.h>
class ShaderLoader
{
public:
ShaderLoader();
~ShaderLoader();
static VkPipelineShaderStageCreateInfo loadShader(VkDevice device, std::string filename, VkShaderStageFlagBits stage);
static void readDirectory(const std::string &directory, const std::string &pattern, std::map<std::string, std::string> &filelist, bool recursive);
};
#endif

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,7 @@
#pragma once #ifndef RENDER_UNIFORM_BUFFER_SET_H
#define RENDER_UNIFORM_BUFFER_SET_H
#include "VulkanUtils.hpp" #include "VulkanBuffer.h"
class RenderUniformBufferSet class RenderUniformBufferSet
{ {
@ -9,17 +10,19 @@ public:
~RenderUniformBufferSet(); ~RenderUniformBufferSet();
// Getter methods // Getter methods
Buffer &getScene(); VulkanBase::Buffer &getScene();
Buffer &getSkybox(); VulkanBase::Buffer &getSkybox();
Buffer &getParams(); VulkanBase::Buffer &getParams();
// Setter methods // Setter methods
void setScene(Buffer &buffer); void setScene(VulkanBase::Buffer &buffer);
void setSkybox(Buffer &buffer); void setSkybox(VulkanBase::Buffer &buffer);
void setParams(Buffer &buffer); void setParams(VulkanBase::Buffer &buffer);
private: private:
Buffer scene; VulkanBase::Buffer scene;
Buffer skybox; VulkanBase::Buffer skybox;
Buffer params; VulkanBase::Buffer params;
}; };
#endif

404
src/render/ui.hpp 100644
View File

@ -0,0 +1,404 @@

#include <io.h>
#if defined(__ANDROID__)
#include <android/asset_manager.h>
#endif
#include <vulkan/vulkan.h>
#include <backends/imgui_impl_glfw.h>
#include <backends/imgui_impl_vulkan.h>
#include <imgui.h>
#define GLM_FORCE_RADIANS
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <array>
#include <map>
#include <vector>
#include "ShaderLoader.h"
#include "VulkanBuffer.h"
#include "VulkanDevice.h"
#include "VulkanTexture.h"
#include "VulkanTools.h"
struct UI
{
private:
VkDevice device;
std::string getAssetPath() const
{
if (_access("./../data/", 0) != -1)
{
return "./../data/";
}
else if (_access("./data/", 0) != -1)
{
return "./data/";
}
else if (_access("./../../data/", 0) != -1)
{
return "../../data/";
}
else
{
return VK_EXAMPLE_DATA_DIR;
}
}
public:
VulkanBase::Buffer vertexBuffer, indexBuffer;
VulkanBase::Texture2D fontTexture;
VkPipelineLayout pipelineLayout;
VkPipeline pipeline;
VkDescriptorPool descriptorPool;
VkDescriptorSetLayout descriptorSetLayout;
VkDescriptorSet descriptorSet;
struct PushConstBlock
{
glm::vec2 scale;
glm::vec2 translate;
} pushConstBlock;
UI(VulkanBase::VulkanDevice *vulkanDevice, VkRenderPass renderPass, VkQueue queue, VkPipelineCache pipelineCache, VkSampleCountFlagBits multiSampleCount)
{
this->device = vulkanDevice->getLogicalDevice();
ImGui::CreateContext();
/*
Font texture loading
*/
ImGuiIO &io = ImGui::GetIO();
/// enable keyborad and gamepad input
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
unsigned char *fontData;
int texWidth, texHeight;
std::string ttfFilePath = getAssetPath() + "/STXINWEI.TTF";
io.Fonts->AddFontFromFileTTF(ttfFilePath.data(), 16.0f, NULL, io.Fonts->GetGlyphRangesChineseSimplifiedCommon());
io.Fonts->GetTexDataAsRGBA32(&fontData, &texWidth, &texHeight);
fontTexture.loadFromBuffer(fontData, texWidth * texHeight * 4 * sizeof(char), VK_FORMAT_R8G8B8A8_UNORM, texWidth, texHeight, vulkanDevice, queue);
/*
Setup
*/
ImGuiStyle &style = ImGui::GetStyle();
style.FrameBorderSize = 0.0f;
style.WindowBorderSize = 0.0f;
/*
Descriptor pool
*/
std::vector<VkDescriptorPoolSize> poolSizes = {
{VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1}};
VkDescriptorPoolCreateInfo descriptorPoolCI{};
descriptorPoolCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
descriptorPoolCI.poolSizeCount = 1;
descriptorPoolCI.pPoolSizes = poolSizes.data();
descriptorPoolCI.maxSets = 1;
VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolCI, nullptr, &descriptorPool));
/*
Descriptor set layout
*/
VkDescriptorSetLayoutBinding setLayoutBinding{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr};
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI{};
descriptorSetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
descriptorSetLayoutCI.pBindings = &setLayoutBinding;
descriptorSetLayoutCI.bindingCount = 1;
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorSetLayout));
/*
Descriptor set
*/
VkDescriptorSetAllocateInfo descriptorSetAllocInfo{};
descriptorSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
descriptorSetAllocInfo.descriptorPool = descriptorPool;
descriptorSetAllocInfo.pSetLayouts = &descriptorSetLayout;
descriptorSetAllocInfo.descriptorSetCount = 1;
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocInfo, &descriptorSet));
VkWriteDescriptorSet writeDescriptorSet{};
writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
writeDescriptorSet.descriptorCount = 1;
writeDescriptorSet.dstSet = descriptorSet;
writeDescriptorSet.dstBinding = 0;
writeDescriptorSet.pImageInfo = &fontTexture.descriptor;
vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr);
/*
Pipeline layout
*/
VkPushConstantRange pushConstantRange{VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(PushConstBlock)};
VkPipelineLayoutCreateInfo pipelineLayoutCI{};
pipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutCI.pushConstantRangeCount = 1;
pipelineLayoutCI.pPushConstantRanges = &pushConstantRange;
pipelineLayoutCI.setLayoutCount = 1;
pipelineLayoutCI.pSetLayouts = &descriptorSetLayout;
pipelineLayoutCI.pushConstantRangeCount = 1;
pipelineLayoutCI.pPushConstantRanges = &pushConstantRange;
VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelineLayout));
/*
Pipeline
*/
VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI{};
inputAssemblyStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
inputAssemblyStateCI.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
VkPipelineRasterizationStateCreateInfo rasterizationStateCI{};
rasterizationStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizationStateCI.polygonMode = VK_POLYGON_MODE_FILL;
rasterizationStateCI.cullMode = VK_CULL_MODE_NONE;
rasterizationStateCI.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
rasterizationStateCI.lineWidth = 1.0f;
VkPipelineColorBlendAttachmentState blendAttachmentState{};
blendAttachmentState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
blendAttachmentState.blendEnable = VK_TRUE;
blendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
blendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
blendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD;
blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD;
VkPipelineColorBlendStateCreateInfo colorBlendStateCI{};
colorBlendStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
colorBlendStateCI.attachmentCount = 1;
colorBlendStateCI.pAttachments = &blendAttachmentState;
VkPipelineDepthStencilStateCreateInfo depthStencilStateCI{};
depthStencilStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
depthStencilStateCI.depthTestEnable = VK_FALSE;
depthStencilStateCI.depthWriteEnable = VK_FALSE;
depthStencilStateCI.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
depthStencilStateCI.front = depthStencilStateCI.back;
depthStencilStateCI.back.compareOp = VK_COMPARE_OP_ALWAYS;
VkPipelineViewportStateCreateInfo viewportStateCI{};
viewportStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportStateCI.viewportCount = 1;
viewportStateCI.scissorCount = 1;
VkPipelineMultisampleStateCreateInfo multisampleStateCI{};
multisampleStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
if (multiSampleCount > VK_SAMPLE_COUNT_1_BIT)
{
multisampleStateCI.rasterizationSamples = multiSampleCount;
}
std::vector<VkDynamicState> dynamicStateEnables = {
VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_SCISSOR};
VkPipelineDynamicStateCreateInfo dynamicStateCI{};
dynamicStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamicStateCI.pDynamicStates = dynamicStateEnables.data();
dynamicStateCI.dynamicStateCount = static_cast<uint32_t>(dynamicStateEnables.size());
VkVertexInputBindingDescription vertexInputBinding = {0, 20, VK_VERTEX_INPUT_RATE_VERTEX};
std::vector<VkVertexInputAttributeDescription> vertexInputAttributes = {
{0, 0, VK_FORMAT_R32G32_SFLOAT, 0},
{1, 0, VK_FORMAT_R32G32_SFLOAT, sizeof(float) * 2},
{2, 0, VK_FORMAT_R8G8B8A8_UNORM, sizeof(float) * 4},
};
VkPipelineVertexInputStateCreateInfo vertexInputStateCI{};
vertexInputStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertexInputStateCI.vertexBindingDescriptionCount = 1;
vertexInputStateCI.pVertexBindingDescriptions = &vertexInputBinding;
vertexInputStateCI.vertexAttributeDescriptionCount = static_cast<uint32_t>(vertexInputAttributes.size());
vertexInputStateCI.pVertexAttributeDescriptions = vertexInputAttributes.data();
std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages;
VkGraphicsPipelineCreateInfo pipelineCI{};
pipelineCI.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipelineCI.layout = pipelineLayout;
pipelineCI.renderPass = renderPass;
pipelineCI.pInputAssemblyState = &inputAssemblyStateCI;
pipelineCI.pVertexInputState = &vertexInputStateCI;
pipelineCI.pRasterizationState = &rasterizationStateCI;
pipelineCI.pColorBlendState = &colorBlendStateCI;
pipelineCI.pMultisampleState = &multisampleStateCI;
pipelineCI.pViewportState = &viewportStateCI;
pipelineCI.pDepthStencilState = &depthStencilStateCI;
pipelineCI.pDynamicState = &dynamicStateCI;
pipelineCI.stageCount = static_cast<uint32_t>(shaderStages.size());
pipelineCI.pStages = shaderStages.data();
pipelineCI.layout = pipelineLayout;
std::string uiVertShaderPath = getAssetPath() + "shaders/ui.vert.spv";
std::string uiFragShaderPath = getAssetPath() + "shaders/ui.frag.spv";
shaderStages = {
ShaderLoader::loadShader(device, uiVertShaderPath.data(), VK_SHADER_STAGE_VERTEX_BIT),
ShaderLoader::loadShader(device, uiFragShaderPath.data(), VK_SHADER_STAGE_FRAGMENT_BIT)};
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipeline));
for (auto shaderStage : shaderStages)
{
vkDestroyShaderModule(device, shaderStage.module, nullptr);
}
}
~UI()
{
ImGui::DestroyContext();
vertexBuffer.destroy();
indexBuffer.destroy();
vkDestroyPipeline(device, pipeline, nullptr);
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
vkDestroyDescriptorPool(device, descriptorPool, nullptr);
}
void draw(VkCommandBuffer cmdBuffer)
{
vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
vkCmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr);
const VkDeviceSize offsets[1] = {0};
vkCmdBindVertexBuffers(cmdBuffer, 0, 1, &vertexBuffer.buffer, offsets);
vkCmdBindIndexBuffer(cmdBuffer, indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT16);
vkCmdPushConstants(cmdBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(UI::PushConstBlock), &pushConstBlock);
ImDrawData *imDrawData = ImGui::GetDrawData();
int32_t vertexOffset = 0;
int32_t indexOffset = 0;
for (int32_t j = 0; j < imDrawData->CmdListsCount; j++)
{
const ImDrawList *cmd_list = imDrawData->CmdLists[j];
for (int32_t k = 0; k < cmd_list->CmdBuffer.Size; k++)
{
const ImDrawCmd *pcmd = &cmd_list->CmdBuffer[k];
VkRect2D scissorRect;
scissorRect.offset.x = std::max((int32_t)(pcmd->ClipRect.x), 0);
scissorRect.offset.y = std::max((int32_t)(pcmd->ClipRect.y), 0);
scissorRect.extent.width = (uint32_t)(pcmd->ClipRect.z - pcmd->ClipRect.x);
scissorRect.extent.height = (uint32_t)(pcmd->ClipRect.w - pcmd->ClipRect.y);
vkCmdSetScissor(cmdBuffer, 0, 1, &scissorRect);
vkCmdDrawIndexed(cmdBuffer, pcmd->ElemCount, 1, indexOffset, vertexOffset, 0);
indexOffset += pcmd->ElemCount;
}
vertexOffset += cmd_list->VtxBuffer.Size;
}
}
template <typename T>
bool checkbox(const char *caption, T *value)
{
bool val = (*value == 1);
bool res = ImGui::Checkbox(caption, &val);
*value = val;
return res;
}
bool header(const char *caption)
{
return ImGui::CollapsingHeader(caption, ImGuiTreeNodeFlags_DefaultOpen);
}
bool slider(const char *caption, float *value, float min, float max)
{
return ImGui::SliderFloat(caption, value, min, max);
}
bool combo(const char *caption, int32_t *itemindex, std::vector<std::string> items)
{
if (items.empty())
{
return false;
}
std::vector<const char *> charitems;
charitems.reserve(items.size());
for (size_t i = 0; i < items.size(); i++)
{
charitems.push_back(items[i].c_str());
}
uint32_t itemCount = static_cast<uint32_t>(charitems.size());
return ImGui::Combo(caption, itemindex, &charitems[0], itemCount, itemCount);
}
bool combo(const char *caption, std::string &selectedkey, std::map<std::string, std::string> items)
{
bool selectionChanged = false;
if (ImGui::BeginCombo(caption, selectedkey.c_str()))
{
for (auto it = items.begin(); it != items.end(); ++it)
{
const bool isSelected = it->first == selectedkey;
if (ImGui::Selectable(it->first.c_str(), isSelected))
{
selectionChanged = it->first != selectedkey;
selectedkey = it->first;
}
if (isSelected)
{
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
return selectionChanged;
}
bool button(const char *caption)
{
return ImGui::Button(caption);
}
bool beginChild(const char *caption, ImVec2 size, bool border)
{
return ImGui::BeginChild(caption, size, border);
}
void endChild()
{
return ImGui::EndChild();
}
// menu GUI
bool beginMainMenuBar()
{
return ImGui::BeginMainMenuBar();
}
bool beginMenu(const char *caption)
{
return ImGui::BeginMenu(caption);
}
bool menuItem(const char *caption)
{
return ImGui::MenuItem(caption);
}
void endMenu()
{
return ImGui::EndMenu();
}
void endMainMenuBar()
{
return ImGui::EndMainMenuBar();
}
void text(const char *formatstr, ...)
{
va_list args;
va_start(args, formatstr);
ImGui::TextV(formatstr, args);
va_end(args);
}
};