调整结构
parent
98335c7edc
commit
907b94dcdd
|
|
@ -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
|
||||||
|
|
@ -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}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,756 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
* vulkan 贴图基础封装类
|
||||||
|
* 普通贴图使用stbi加载
|
||||||
|
* ktx格式cubeMap贴图使用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
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
356
src/base/ui.hpp
356
src/base/ui.hpp
|
|
@ -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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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, ©Region);
|
vkCmdCopyBuffer(copyCmd, vertexStaging.buffer, m_vertices.buffer, 1, ©Region);
|
||||||
|
|
||||||
if (indexBufferSize > 0) {
|
if (indexBufferSize > 0)
|
||||||
|
{
|
||||||
copyRegion.size = indexBufferSize;
|
copyRegion.size = indexBufferSize;
|
||||||
vkCmdCopyBuffer(copyCmd, indexStaging.buffer, m_indices.buffer, 1, ©Region);
|
vkCmdCopyBuffer(copyCmd, indexStaging.buffer, m_indices.buffer, 1, ©Region);
|
||||||
}
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue