调整结构
parent
98335c7edc
commit
907b94dcdd
|
|
@ -3,6 +3,7 @@ AccessModifierOffset: -4
|
|||
AlignConsecutiveMacros: true
|
||||
AlignTrailingComments: true
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortIfStatementsOnASingleLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
BreakBeforeBraces: Allman
|
||||
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/glTFTexture.h"
|
||||
"gltf/glTFTexture.cpp"
|
||||
#"gltf/glTFModel.h"
|
||||
#"gltf/glTFModel.cpp"
|
||||
"gltf/glTFMaterial.h"
|
||||
"gltf/glTFMaterial.cpp"
|
||||
"gltf/glTFPrimitive.h"
|
||||
|
|
@ -35,12 +33,12 @@ set(GLTF_MODEL_LOADER
|
|||
"gltf/glTFAnimation.cpp"
|
||||
"gltf/glTFMainModel.h"
|
||||
"gltf/glTFMainModel.cpp"
|
||||
|
||||
)
|
||||
|
||||
|
||||
|
||||
aux_source_directory(${PROJECT_SOURCE_DIR}/src/render VULKAN_BASE)
|
||||
aux_source_directory(${PROJECT_SOURCE_DIR}/src/pbr PBR)
|
||||
|
||||
#include_directories(${3rdParty_gli_path})
|
||||
include_directories(${3rdParty_glm_path})
|
||||
|
|
@ -65,6 +63,7 @@ if(WIN32)
|
|||
${MAIN_FILE}
|
||||
${GLTF_MODEL_LOADER}
|
||||
${VULKAN_BASE}
|
||||
${PBR}
|
||||
|
||||
"render/renderFoundation.h"
|
||||
"render/renderFoundation.cpp"
|
||||
|
|
|
|||
|
|
@ -4,12 +4,10 @@ file(GLOB BASE_SRC "*.cpp" "*.h" "${3rdParty_imgui_path}/*.cpp" )
|
|||
include_directories(${3rdParty_ktx_path})
|
||||
include_directories(${3rdParty_ktx_otherInclude_path})
|
||||
include_directories(${3rdParty_glm_path})
|
||||
include_directories(${3rdParty_gli_path})
|
||||
include_directories(${3rdParty_stb_path})
|
||||
include_directories(${3rdParty_vulkan_path})
|
||||
include_directories(${3rdParty_imgui_path})
|
||||
|
||||
message("======================debug=====================")
|
||||
message(${BASE_SRC})
|
||||
|
||||
add_library(base STATIC ${BASE_SRC} ${KTX_SOURCES})
|
||||
if(WIN32)
|
||||
|
|
|
|||
|
|
@ -1,18 +1,8 @@
|
|||
/*
|
||||
* Vulkan buffer class
|
||||
*
|
||||
* Encapsulates a Vulkan buffer
|
||||
*
|
||||
* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
|
||||
*
|
||||
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
|
||||
#include "VulkanBuffer.h"
|
||||
#include "VulkanTools.h"
|
||||
|
||||
namespace vks
|
||||
{
|
||||
/**
|
||||
VULKANBASE_NAMESPACE_BEGIN
|
||||
/**
|
||||
* Map a memory range of this buffer. If successful, mapped points to the specified buffer range.
|
||||
*
|
||||
* @param size (Optional) Size of the memory range to map. Pass VK_WHOLE_SIZE to map the complete buffer range.
|
||||
|
|
@ -20,65 +10,65 @@ namespace vks
|
|||
*
|
||||
* @return VkResult of the buffer mapping call
|
||||
*/
|
||||
VkResult Buffer::map(VkDeviceSize size, VkDeviceSize offset)
|
||||
{
|
||||
VkResult Buffer::map(VkDeviceSize size, VkDeviceSize offset)
|
||||
{
|
||||
return vkMapMemory(device, memory, offset, size, 0, &mapped);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Unmap a mapped memory range
|
||||
*
|
||||
* @note Does not return a result as vkUnmapMemory can't fail
|
||||
*/
|
||||
void Buffer::unmap()
|
||||
{
|
||||
void Buffer::unmap()
|
||||
{
|
||||
if (mapped)
|
||||
{
|
||||
vkUnmapMemory(device, memory);
|
||||
mapped = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Attach the allocated memory block to the buffer
|
||||
*
|
||||
* @param offset (Optional) Byte offset (from the beginning) for the memory region to bind
|
||||
*
|
||||
* @return VkResult of the bindBufferMemory call
|
||||
*/
|
||||
VkResult Buffer::bind(VkDeviceSize offset)
|
||||
{
|
||||
VkResult Buffer::bind(VkDeviceSize offset)
|
||||
{
|
||||
return vkBindBufferMemory(device, buffer, memory, offset);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Setup the default descriptor for this buffer
|
||||
*
|
||||
* @param size (Optional) Size of the memory range of the descriptor
|
||||
* @param offset (Optional) Byte offset from beginning
|
||||
*
|
||||
*/
|
||||
void Buffer::setupDescriptor(VkDeviceSize size, VkDeviceSize offset)
|
||||
{
|
||||
void Buffer::setupDescriptor(VkDeviceSize size, VkDeviceSize offset)
|
||||
{
|
||||
descriptor.offset = offset;
|
||||
descriptor.buffer = buffer;
|
||||
descriptor.range = size;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Copies the specified data to the mapped buffer
|
||||
*
|
||||
* @param data Pointer to the data to copy
|
||||
* @param size Size of the data to copy in machine units
|
||||
*
|
||||
*/
|
||||
void Buffer::copyTo(void* data, VkDeviceSize size)
|
||||
{
|
||||
void Buffer::copyTo(void *data, VkDeviceSize size)
|
||||
{
|
||||
assert(mapped);
|
||||
memcpy(mapped, data, size);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Flush a memory range of the buffer to make it visible to the device
|
||||
*
|
||||
* @note Only required for non-coherent memory
|
||||
|
|
@ -88,17 +78,17 @@ namespace vks
|
|||
*
|
||||
* @return VkResult of the flush call
|
||||
*/
|
||||
VkResult Buffer::flush(VkDeviceSize size, VkDeviceSize offset)
|
||||
{
|
||||
VkResult Buffer::flush(VkDeviceSize size, VkDeviceSize offset)
|
||||
{
|
||||
VkMappedMemoryRange mappedRange = {};
|
||||
mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
|
||||
mappedRange.memory = memory;
|
||||
mappedRange.offset = offset;
|
||||
mappedRange.size = size;
|
||||
return vkFlushMappedMemoryRanges(device, 1, &mappedRange);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Invalidate a memory range of the buffer to make it visible to the host
|
||||
*
|
||||
* @note Only required for non-coherent memory
|
||||
|
|
@ -108,28 +98,40 @@ namespace vks
|
|||
*
|
||||
* @return VkResult of the invalidate call
|
||||
*/
|
||||
VkResult Buffer::invalidate(VkDeviceSize size, VkDeviceSize offset)
|
||||
{
|
||||
VkResult Buffer::invalidate(VkDeviceSize size, VkDeviceSize offset)
|
||||
{
|
||||
VkMappedMemoryRange mappedRange = {};
|
||||
mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
|
||||
mappedRange.memory = memory;
|
||||
mappedRange.offset = offset;
|
||||
mappedRange.size = size;
|
||||
return vkInvalidateMappedMemoryRanges(device, 1, &mappedRange);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Release all Vulkan resources held by this buffer
|
||||
*/
|
||||
void Buffer::destroy()
|
||||
{
|
||||
if (buffer)
|
||||
void Buffer::destroy()
|
||||
{
|
||||
if (mapped)
|
||||
{
|
||||
unmap();
|
||||
}
|
||||
vkDestroyBuffer(device, buffer, nullptr);
|
||||
}
|
||||
if (memory)
|
||||
{
|
||||
vkFreeMemory(device, memory, nullptr);
|
||||
buffer = VK_NULL_HANDLE;
|
||||
memory = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
void Buffer::create(VulkanBase::VulkanDevice *device, VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkDeviceSize size, bool map)
|
||||
{
|
||||
VkDevice logicalDevice = device->getLogicalDevice();
|
||||
device->createBuffer(usageFlags, memoryPropertyFlags, size, &buffer, &memory);
|
||||
descriptor = {buffer, 0, size};
|
||||
if (map)
|
||||
{
|
||||
VK_CHECK_RESULT(vkMapMemory(logicalDevice, memory, 0, size, 0, &mapped));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
VULKANBASE_NAMESPACE_END
|
||||
|
|
@ -1,46 +1,43 @@
|
|||
/*
|
||||
* Vulkan buffer class
|
||||
*
|
||||
* Encapsulates a Vulkan buffer
|
||||
*
|
||||
* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
|
||||
*
|
||||
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef VULKANBUFFER_H
|
||||
#define VULKANBUFFER_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "vulkan/vulkan.h"
|
||||
#include "VulkanTools.h"
|
||||
#include "VulkanBase_Marco.h"
|
||||
#include "VulkanDevice.h"
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
namespace vks
|
||||
{
|
||||
/**
|
||||
VULKANBASE_NAMESPACE_BEGIN
|
||||
/**
|
||||
* @brief Encapsulates access to a Vulkan buffer backed up by device memory
|
||||
* @note To be filled by an external source like the VulkanDevice
|
||||
*/
|
||||
struct Buffer
|
||||
{
|
||||
struct Buffer
|
||||
{
|
||||
VkDevice device;
|
||||
VkBuffer buffer = VK_NULL_HANDLE;
|
||||
VkDeviceMemory memory = VK_NULL_HANDLE;
|
||||
VkDescriptorBufferInfo descriptor;
|
||||
VkDeviceSize size = 0;
|
||||
VkDeviceSize alignment = 0;
|
||||
void* mapped = nullptr;
|
||||
int32_t count = 0;
|
||||
void *mapped = nullptr;
|
||||
/** @brief Usage flags to be filled by external source at buffer creation (to query at some later point) */
|
||||
VkBufferUsageFlags usageFlags;
|
||||
/** @brief Memory property flags to be filled by external source at buffer creation (to query at some later point) */
|
||||
VkMemoryPropertyFlags memoryPropertyFlags;
|
||||
void create(VulkanDevice *device, VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkDeviceSize size, bool map = true);
|
||||
VkResult map(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0);
|
||||
void unmap();
|
||||
VkResult bind(VkDeviceSize offset = 0);
|
||||
void setupDescriptor(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0);
|
||||
void copyTo(void* data, VkDeviceSize size);
|
||||
void copyTo(void *data, VkDeviceSize size);
|
||||
VkResult flush(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0);
|
||||
VkResult invalidate(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0);
|
||||
void destroy();
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
VULKANBASE_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -1,39 +1,42 @@
|
|||
/*
|
||||
* Vulkan texture loader
|
||||
*
|
||||
* Copyright(C) by Sascha Willems - www.saschawillems.de
|
||||
*
|
||||
* This code is licensed under the MIT license(MIT) (http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
* Vulkan texture loader
|
||||
*
|
||||
* Copyright(C) by Sascha Willems - www.saschawillems.de
|
||||
*
|
||||
* This code is licensed under the MIT license(MIT) (http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
|
||||
#include "VulkanTexture.h"
|
||||
#include "vulkan/vulkan_core.h"
|
||||
|
||||
namespace vks
|
||||
namespace VulkanBase
|
||||
{
|
||||
void Texture::updateDescriptor()
|
||||
{
|
||||
void Texture::updateDescriptor()
|
||||
{
|
||||
descriptor.sampler = sampler;
|
||||
descriptor.imageView = view;
|
||||
descriptor.imageLayout = imageLayout;
|
||||
}
|
||||
}
|
||||
|
||||
void Texture::destroy()
|
||||
{
|
||||
vkDestroyImageView(device->logicalDevice, view, nullptr);
|
||||
vkDestroyImage(device->logicalDevice, image, nullptr);
|
||||
void Texture::destroy()
|
||||
{
|
||||
VkDevice logicalDevice = device->getLogicalDevice();
|
||||
vkDestroyImageView(logicalDevice, view, nullptr);
|
||||
vkDestroyImage(logicalDevice, image, nullptr);
|
||||
if (sampler)
|
||||
{
|
||||
vkDestroySampler(device->logicalDevice, sampler, nullptr);
|
||||
}
|
||||
vkFreeMemory(device->logicalDevice, deviceMemory, nullptr);
|
||||
vkDestroySampler(logicalDevice, sampler, nullptr);
|
||||
}
|
||||
vkFreeMemory(logicalDevice, deviceMemory, nullptr);
|
||||
}
|
||||
|
||||
ktxResult Texture::loadKTXFile(std::string filename, ktxTexture **target)
|
||||
{
|
||||
ktxResult Texture::loadKTXFile(std::string filename, ktxTexture **target)
|
||||
{
|
||||
ktxResult result = KTX_SUCCESS;
|
||||
#if defined(__ANDROID__)
|
||||
AAsset* asset = AAssetManager_open(androidApp->activity->assetManager, filename.c_str(), AASSET_MODE_STREAMING);
|
||||
if (!asset) {
|
||||
AAsset *asset = AAssetManager_open(androidApp->activity->assetManager, filename.c_str(), AASSET_MODE_STREAMING);
|
||||
if (!asset)
|
||||
{
|
||||
vks::tools::exitFatal("Could not load texture from " + filename + "\n\nThe file may be part of the additional asset pack.\n\nRun \"download_assets.py\" in the repository root to download the latest version.", -1);
|
||||
}
|
||||
size_t size = AAsset_getLength(asset);
|
||||
|
|
@ -44,15 +47,16 @@ namespace vks
|
|||
result = ktxTexture_CreateFromMemory(textureData, size, KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT, target);
|
||||
delete[] textureData;
|
||||
#else
|
||||
if (!vks::tools::fileExists(filename)) {
|
||||
if (!vks::tools::fileExists(filename))
|
||||
{
|
||||
vks::tools::exitFatal("Could not load texture from " + filename + "\n\nThe file may be part of the additional asset pack.\n\nRun \"download_assets.py\" in the repository root to download the latest version.", -1);
|
||||
}
|
||||
result = ktxTexture_CreateFromNamedFile(filename.c_str(), KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT, target);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Load a 2D texture including all mip levels
|
||||
*
|
||||
* @param filename File to load (supports .ktx)
|
||||
|
|
@ -64,13 +68,14 @@ namespace vks
|
|||
* @param (Optional) forceLinear Force linear tiling (not advised, defaults to false)
|
||||
*
|
||||
*/
|
||||
void Texture2D::loadFromFile(std::string filename, VkFormat format, vks::VulkanDevice *device, VkQueue copyQueue, VkImageUsageFlags imageUsageFlags, VkImageLayout imageLayout, bool forceLinear)
|
||||
{
|
||||
ktxTexture* ktxTexture;
|
||||
void Texture2D::loadFromFile(std::string filename, VkFormat format, VulkanBase::VulkanDevice *device, VkQueue copyQueue, VkImageUsageFlags imageUsageFlags, VkImageLayout imageLayout, bool forceLinear)
|
||||
{
|
||||
ktxTexture *ktxTexture;
|
||||
ktxResult result = loadKTXFile(filename, &ktxTexture);
|
||||
assert(result == KTX_SUCCESS);
|
||||
|
||||
this->device = device;
|
||||
VkDevice logicalDevice = device->getLogicalDevice();
|
||||
width = ktxTexture->baseWidth;
|
||||
height = ktxTexture->baseHeight;
|
||||
mipLevels = ktxTexture->numLevels;
|
||||
|
|
@ -80,7 +85,7 @@ namespace vks
|
|||
|
||||
// Get device properties for the requested texture format
|
||||
VkFormatProperties formatProperties;
|
||||
vkGetPhysicalDeviceFormatProperties(device->physicalDevice, format, &formatProperties);
|
||||
vkGetPhysicalDeviceFormatProperties(device->getPhysicalDevice(), format, &formatProperties);
|
||||
|
||||
// Only use linear tiling if requested (and supported by the device)
|
||||
// Support for linear tiling is mostly limited, so prefer to use
|
||||
|
|
@ -107,23 +112,23 @@ namespace vks
|
|||
bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
|
||||
VK_CHECK_RESULT(vkCreateBuffer(device->logicalDevice, &bufferCreateInfo, nullptr, &stagingBuffer));
|
||||
VK_CHECK_RESULT(vkCreateBuffer(logicalDevice, &bufferCreateInfo, nullptr, &stagingBuffer));
|
||||
|
||||
// Get memory requirements for the staging buffer (alignment, memory type bits)
|
||||
vkGetBufferMemoryRequirements(device->logicalDevice, stagingBuffer, &memReqs);
|
||||
vkGetBufferMemoryRequirements(logicalDevice, stagingBuffer, &memReqs);
|
||||
|
||||
memAllocInfo.allocationSize = memReqs.size;
|
||||
// Get memory type index for a host visible buffer
|
||||
memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
|
||||
VK_CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &stagingMemory));
|
||||
VK_CHECK_RESULT(vkBindBufferMemory(device->logicalDevice, stagingBuffer, stagingMemory, 0));
|
||||
VK_CHECK_RESULT(vkAllocateMemory(logicalDevice, &memAllocInfo, nullptr, &stagingMemory));
|
||||
VK_CHECK_RESULT(vkBindBufferMemory(logicalDevice, stagingBuffer, stagingMemory, 0));
|
||||
|
||||
// Copy texture data into staging buffer
|
||||
uint8_t *data;
|
||||
VK_CHECK_RESULT(vkMapMemory(device->logicalDevice, stagingMemory, 0, memReqs.size, 0, (void **)&data));
|
||||
VK_CHECK_RESULT(vkMapMemory(logicalDevice, stagingMemory, 0, memReqs.size, 0, (void **)&data));
|
||||
memcpy(data, ktxTextureData, ktxTextureSize);
|
||||
vkUnmapMemory(device->logicalDevice, stagingMemory);
|
||||
vkUnmapMemory(logicalDevice, stagingMemory);
|
||||
|
||||
// Setup buffer copy regions for each mip level
|
||||
std::vector<VkBufferImageCopy> bufferCopyRegions;
|
||||
|
|
@ -157,22 +162,22 @@ namespace vks
|
|||
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
imageCreateInfo.extent = { width, height, 1 };
|
||||
imageCreateInfo.extent = {width, height, 1};
|
||||
imageCreateInfo.usage = imageUsageFlags;
|
||||
// Ensure that the TRANSFER_DST bit is set for staging
|
||||
if (!(imageCreateInfo.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT))
|
||||
{
|
||||
imageCreateInfo.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||
}
|
||||
VK_CHECK_RESULT(vkCreateImage(device->logicalDevice, &imageCreateInfo, nullptr, &image));
|
||||
VK_CHECK_RESULT(vkCreateImage(logicalDevice, &imageCreateInfo, nullptr, &image));
|
||||
|
||||
vkGetImageMemoryRequirements(device->logicalDevice, image, &memReqs);
|
||||
vkGetImageMemoryRequirements(logicalDevice, image, &memReqs);
|
||||
|
||||
memAllocInfo.allocationSize = memReqs.size;
|
||||
|
||||
memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
VK_CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &deviceMemory));
|
||||
VK_CHECK_RESULT(vkBindImageMemory(device->logicalDevice, image, deviceMemory, 0));
|
||||
VK_CHECK_RESULT(vkAllocateMemory(logicalDevice, &memAllocInfo, nullptr, &deviceMemory));
|
||||
VK_CHECK_RESULT(vkBindImageMemory(logicalDevice, image, deviceMemory, 0));
|
||||
|
||||
VkImageSubresourceRange subresourceRange = {};
|
||||
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
|
|
@ -196,8 +201,7 @@ namespace vks
|
|||
image,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
static_cast<uint32_t>(bufferCopyRegions.size()),
|
||||
bufferCopyRegions.data()
|
||||
);
|
||||
bufferCopyRegions.data());
|
||||
|
||||
// Change texture image layout to shader read after all mip levels have been copied
|
||||
this->imageLayout = imageLayout;
|
||||
|
|
@ -211,8 +215,8 @@ namespace vks
|
|||
device->flushCommandBuffer(copyCmd, copyQueue);
|
||||
|
||||
// Clean up staging resources
|
||||
vkFreeMemory(device->logicalDevice, stagingMemory, nullptr);
|
||||
vkDestroyBuffer(device->logicalDevice, stagingBuffer, nullptr);
|
||||
vkFreeMemory(logicalDevice, stagingMemory, nullptr);
|
||||
vkDestroyBuffer(logicalDevice, stagingBuffer, nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -229,7 +233,7 @@ namespace vks
|
|||
VkImageCreateInfo imageCreateInfo = vks::initializers::imageCreateInfo();
|
||||
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||
imageCreateInfo.format = format;
|
||||
imageCreateInfo.extent = { width, height, 1 };
|
||||
imageCreateInfo.extent = {width, height, 1};
|
||||
imageCreateInfo.mipLevels = 1;
|
||||
imageCreateInfo.arrayLayers = 1;
|
||||
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
|
|
@ -239,11 +243,11 @@ namespace vks
|
|||
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
|
||||
// Load mip map level 0 to linear tiling image
|
||||
VK_CHECK_RESULT(vkCreateImage(device->logicalDevice, &imageCreateInfo, nullptr, &mappableImage));
|
||||
VK_CHECK_RESULT(vkCreateImage(logicalDevice, &imageCreateInfo, nullptr, &mappableImage));
|
||||
|
||||
// Get memory requirements for this image
|
||||
// like size and alignment
|
||||
vkGetImageMemoryRequirements(device->logicalDevice, mappableImage, &memReqs);
|
||||
vkGetImageMemoryRequirements(logicalDevice, mappableImage, &memReqs);
|
||||
// Set memory allocation size to required memory size
|
||||
memAllocInfo.allocationSize = memReqs.size;
|
||||
|
||||
|
|
@ -251,10 +255,10 @@ namespace vks
|
|||
memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
|
||||
// Allocate host memory
|
||||
VK_CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &mappableMemory));
|
||||
VK_CHECK_RESULT(vkAllocateMemory(logicalDevice, &memAllocInfo, nullptr, &mappableMemory));
|
||||
|
||||
// Bind allocated image for use
|
||||
VK_CHECK_RESULT(vkBindImageMemory(device->logicalDevice, mappableImage, mappableMemory, 0));
|
||||
VK_CHECK_RESULT(vkBindImageMemory(logicalDevice, mappableImage, mappableMemory, 0));
|
||||
|
||||
// Get sub resource layout
|
||||
// Mip map count, array layer, etc.
|
||||
|
|
@ -267,15 +271,15 @@ namespace vks
|
|||
|
||||
// Get sub resources layout
|
||||
// Includes row pitch, size offsets, etc.
|
||||
vkGetImageSubresourceLayout(device->logicalDevice, mappableImage, &subRes, &subResLayout);
|
||||
vkGetImageSubresourceLayout(logicalDevice, mappableImage, &subRes, &subResLayout);
|
||||
|
||||
// Map image memory
|
||||
VK_CHECK_RESULT(vkMapMemory(device->logicalDevice, mappableMemory, 0, memReqs.size, 0, &data));
|
||||
VK_CHECK_RESULT(vkMapMemory(logicalDevice, mappableMemory, 0, memReqs.size, 0, &data));
|
||||
|
||||
// Copy image data into memory
|
||||
memcpy(data, ktxTextureData, memReqs.size);
|
||||
|
||||
vkUnmapMemory(device->logicalDevice, mappableMemory);
|
||||
vkUnmapMemory(logicalDevice, mappableMemory);
|
||||
|
||||
// Linear tiled images don't need to be staged
|
||||
// and can be directly used as textures
|
||||
|
|
@ -306,10 +310,19 @@ namespace vks
|
|||
// Max level-of-detail should match mip level count
|
||||
samplerCreateInfo.maxLod = (useStaging) ? (float)mipLevels : 0.0f;
|
||||
// Only enable anisotropic filtering if enabled on the device
|
||||
samplerCreateInfo.maxAnisotropy = device->enabledFeatures.samplerAnisotropy ? device->properties.limits.maxSamplerAnisotropy : 1.0f;
|
||||
samplerCreateInfo.anisotropyEnable = device->enabledFeatures.samplerAnisotropy;
|
||||
|
||||
if (device->getPhysicalDeviceFeatures().samplerAnisotropy)
|
||||
{
|
||||
samplerCreateInfo.maxAnisotropy = device->getPhysicalDeviceProperties().limits.maxSamplerAnisotropy;
|
||||
}
|
||||
else
|
||||
{
|
||||
samplerCreateInfo.maxAnisotropy = 1.0;
|
||||
}
|
||||
|
||||
samplerCreateInfo.anisotropyEnable = device->getPhysicalDeviceFeatures().samplerAnisotropy;
|
||||
samplerCreateInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
|
||||
VK_CHECK_RESULT(vkCreateSampler(device->logicalDevice, &samplerCreateInfo, nullptr, &sampler));
|
||||
VK_CHECK_RESULT(vkCreateSampler(logicalDevice, &samplerCreateInfo, nullptr, &sampler));
|
||||
|
||||
// Create image view
|
||||
// Textures are not directly accessed by the shaders and
|
||||
|
|
@ -319,18 +332,18 @@ namespace vks
|
|||
viewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewCreateInfo.format = format;
|
||||
viewCreateInfo.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
|
||||
viewCreateInfo.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
|
||||
// Linear tiling usually won't support mip maps
|
||||
// Only set mip map count if optimal tiling is used
|
||||
viewCreateInfo.subresourceRange.levelCount = (useStaging) ? mipLevels : 1;
|
||||
viewCreateInfo.image = image;
|
||||
VK_CHECK_RESULT(vkCreateImageView(device->logicalDevice, &viewCreateInfo, nullptr, &view));
|
||||
VK_CHECK_RESULT(vkCreateImageView(logicalDevice, &viewCreateInfo, nullptr, &view));
|
||||
|
||||
// Update descriptor image info member that can be used for setting up descriptor sets
|
||||
updateDescriptor();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Creates a 2D texture from a buffer
|
||||
*
|
||||
* @param buffer Buffer containing texture data to upload
|
||||
|
|
@ -344,8 +357,8 @@ namespace vks
|
|||
* @param (Optional) imageUsageFlags Usage flags for the texture's image (defaults to VK_IMAGE_USAGE_SAMPLED_BIT)
|
||||
* @param (Optional) imageLayout Usage layout for the texture (defaults VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||
*/
|
||||
void Texture2D::fromBuffer(void* buffer, VkDeviceSize bufferSize, VkFormat format, uint32_t texWidth, uint32_t texHeight, vks::VulkanDevice *device, VkQueue copyQueue, VkFilter filter, VkImageUsageFlags imageUsageFlags, VkImageLayout imageLayout)
|
||||
{
|
||||
void Texture2D::loadFromBuffer(void *buffer, VkDeviceSize bufferSize, VkFormat format, uint32_t texWidth, uint32_t texHeight, VulkanBase::VulkanDevice *device, VkQueue copyQueue, VkFilter filter, VkImageUsageFlags imageUsageFlags, VkImageLayout imageLayout)
|
||||
{
|
||||
assert(buffer);
|
||||
|
||||
this->device = device;
|
||||
|
|
@ -353,6 +366,8 @@ namespace vks
|
|||
height = texHeight;
|
||||
mipLevels = 1;
|
||||
|
||||
VkDevice logicalDevice = device->getLogicalDevice();
|
||||
|
||||
VkMemoryAllocateInfo memAllocInfo = vks::initializers::memoryAllocateInfo();
|
||||
VkMemoryRequirements memReqs;
|
||||
|
||||
|
|
@ -369,23 +384,23 @@ namespace vks
|
|||
bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
|
||||
VK_CHECK_RESULT(vkCreateBuffer(device->logicalDevice, &bufferCreateInfo, nullptr, &stagingBuffer));
|
||||
VK_CHECK_RESULT(vkCreateBuffer(logicalDevice, &bufferCreateInfo, nullptr, &stagingBuffer));
|
||||
|
||||
// Get memory requirements for the staging buffer (alignment, memory type bits)
|
||||
vkGetBufferMemoryRequirements(device->logicalDevice, stagingBuffer, &memReqs);
|
||||
vkGetBufferMemoryRequirements(logicalDevice, stagingBuffer, &memReqs);
|
||||
|
||||
memAllocInfo.allocationSize = memReqs.size;
|
||||
// Get memory type index for a host visible buffer
|
||||
memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
|
||||
VK_CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &stagingMemory));
|
||||
VK_CHECK_RESULT(vkBindBufferMemory(device->logicalDevice, stagingBuffer, stagingMemory, 0));
|
||||
VK_CHECK_RESULT(vkAllocateMemory(logicalDevice, &memAllocInfo, nullptr, &stagingMemory));
|
||||
VK_CHECK_RESULT(vkBindBufferMemory(logicalDevice, stagingBuffer, stagingMemory, 0));
|
||||
|
||||
// Copy texture data into staging buffer
|
||||
uint8_t *data;
|
||||
VK_CHECK_RESULT(vkMapMemory(device->logicalDevice, stagingMemory, 0, memReqs.size, 0, (void **)&data));
|
||||
VK_CHECK_RESULT(vkMapMemory(logicalDevice, stagingMemory, 0, memReqs.size, 0, (void **)&data));
|
||||
memcpy(data, buffer, bufferSize);
|
||||
vkUnmapMemory(device->logicalDevice, stagingMemory);
|
||||
vkUnmapMemory(logicalDevice, stagingMemory);
|
||||
|
||||
VkBufferImageCopy bufferCopyRegion = {};
|
||||
bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
|
|
@ -407,22 +422,22 @@ namespace vks
|
|||
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
imageCreateInfo.extent = { width, height, 1 };
|
||||
imageCreateInfo.extent = {width, height, 1};
|
||||
imageCreateInfo.usage = imageUsageFlags;
|
||||
// Ensure that the TRANSFER_DST bit is set for staging
|
||||
if (!(imageCreateInfo.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT))
|
||||
{
|
||||
imageCreateInfo.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||
}
|
||||
VK_CHECK_RESULT(vkCreateImage(device->logicalDevice, &imageCreateInfo, nullptr, &image));
|
||||
VK_CHECK_RESULT(vkCreateImage(logicalDevice, &imageCreateInfo, nullptr, &image));
|
||||
|
||||
vkGetImageMemoryRequirements(device->logicalDevice, image, &memReqs);
|
||||
vkGetImageMemoryRequirements(logicalDevice, image, &memReqs);
|
||||
|
||||
memAllocInfo.allocationSize = memReqs.size;
|
||||
|
||||
memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
VK_CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &deviceMemory));
|
||||
VK_CHECK_RESULT(vkBindImageMemory(device->logicalDevice, image, deviceMemory, 0));
|
||||
VK_CHECK_RESULT(vkAllocateMemory(logicalDevice, &memAllocInfo, nullptr, &deviceMemory));
|
||||
VK_CHECK_RESULT(vkBindImageMemory(logicalDevice, image, deviceMemory, 0));
|
||||
|
||||
VkImageSubresourceRange subresourceRange = {};
|
||||
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
|
|
@ -446,8 +461,7 @@ namespace vks
|
|||
image,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
1,
|
||||
&bufferCopyRegion
|
||||
);
|
||||
&bufferCopyRegion);
|
||||
|
||||
// Change texture image layout to shader read after all mip levels have been copied
|
||||
this->imageLayout = imageLayout;
|
||||
|
|
@ -461,8 +475,8 @@ namespace vks
|
|||
device->flushCommandBuffer(copyCmd, copyQueue);
|
||||
|
||||
// Clean up staging resources
|
||||
vkFreeMemory(device->logicalDevice, stagingMemory, nullptr);
|
||||
vkDestroyBuffer(device->logicalDevice, stagingBuffer, nullptr);
|
||||
vkFreeMemory(logicalDevice, stagingMemory, nullptr);
|
||||
vkDestroyBuffer(logicalDevice, stagingBuffer, nullptr);
|
||||
|
||||
// Create sampler
|
||||
VkSamplerCreateInfo samplerCreateInfo = {};
|
||||
|
|
@ -478,7 +492,7 @@ namespace vks
|
|||
samplerCreateInfo.minLod = 0.0f;
|
||||
samplerCreateInfo.maxLod = 0.0f;
|
||||
samplerCreateInfo.maxAnisotropy = 1.0f;
|
||||
VK_CHECK_RESULT(vkCreateSampler(device->logicalDevice, &samplerCreateInfo, nullptr, &sampler));
|
||||
VK_CHECK_RESULT(vkCreateSampler(logicalDevice, &samplerCreateInfo, nullptr, &sampler));
|
||||
|
||||
// Create image view
|
||||
VkImageViewCreateInfo viewCreateInfo = {};
|
||||
|
|
@ -486,16 +500,16 @@ namespace vks
|
|||
viewCreateInfo.pNext = NULL;
|
||||
viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewCreateInfo.format = format;
|
||||
viewCreateInfo.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
|
||||
viewCreateInfo.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
|
||||
viewCreateInfo.subresourceRange.levelCount = 1;
|
||||
viewCreateInfo.image = image;
|
||||
VK_CHECK_RESULT(vkCreateImageView(device->logicalDevice, &viewCreateInfo, nullptr, &view));
|
||||
VK_CHECK_RESULT(vkCreateImageView(logicalDevice, &viewCreateInfo, nullptr, &view));
|
||||
|
||||
// Update descriptor image info member that can be used for setting up descriptor sets
|
||||
updateDescriptor();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Load a 2D texture array including all mip levels
|
||||
*
|
||||
* @param filename File to load (supports .ktx)
|
||||
|
|
@ -506,9 +520,9 @@ namespace vks
|
|||
* @param (Optional) imageLayout Usage layout for the texture (defaults VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||
*
|
||||
*/
|
||||
void Texture2DArray::loadFromFile(std::string filename, VkFormat format, vks::VulkanDevice *device, VkQueue copyQueue, VkImageUsageFlags imageUsageFlags, VkImageLayout imageLayout)
|
||||
{
|
||||
ktxTexture* ktxTexture;
|
||||
void Texture2DArray::loadFromFile(std::string filename, VkFormat format, VulkanBase::VulkanDevice *device, VkQueue copyQueue, VkImageUsageFlags imageUsageFlags, VkImageLayout imageLayout)
|
||||
{
|
||||
ktxTexture *ktxTexture;
|
||||
ktxResult result = loadKTXFile(filename, &ktxTexture);
|
||||
assert(result == KTX_SUCCESS);
|
||||
|
||||
|
|
@ -521,6 +535,8 @@ namespace vks
|
|||
ktx_uint8_t *ktxTextureData = ktxTexture_GetData(ktxTexture);
|
||||
ktx_size_t ktxTextureSize = ktxTexture_GetSize(ktxTexture);
|
||||
|
||||
VkDevice logicalDevice = device->getLogicalDevice();
|
||||
|
||||
VkMemoryAllocateInfo memAllocInfo = vks::initializers::memoryAllocateInfo();
|
||||
VkMemoryRequirements memReqs;
|
||||
|
||||
|
|
@ -534,23 +550,23 @@ namespace vks
|
|||
bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
|
||||
VK_CHECK_RESULT(vkCreateBuffer(device->logicalDevice, &bufferCreateInfo, nullptr, &stagingBuffer));
|
||||
VK_CHECK_RESULT(vkCreateBuffer(logicalDevice, &bufferCreateInfo, nullptr, &stagingBuffer));
|
||||
|
||||
// Get memory requirements for the staging buffer (alignment, memory type bits)
|
||||
vkGetBufferMemoryRequirements(device->logicalDevice, stagingBuffer, &memReqs);
|
||||
vkGetBufferMemoryRequirements(logicalDevice, stagingBuffer, &memReqs);
|
||||
|
||||
memAllocInfo.allocationSize = memReqs.size;
|
||||
// Get memory type index for a host visible buffer
|
||||
memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
|
||||
VK_CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &stagingMemory));
|
||||
VK_CHECK_RESULT(vkBindBufferMemory(device->logicalDevice, stagingBuffer, stagingMemory, 0));
|
||||
VK_CHECK_RESULT(vkAllocateMemory(logicalDevice, &memAllocInfo, nullptr, &stagingMemory));
|
||||
VK_CHECK_RESULT(vkBindBufferMemory(logicalDevice, stagingBuffer, stagingMemory, 0));
|
||||
|
||||
// Copy texture data into staging buffer
|
||||
uint8_t *data;
|
||||
VK_CHECK_RESULT(vkMapMemory(device->logicalDevice, stagingMemory, 0, memReqs.size, 0, (void **)&data));
|
||||
VK_CHECK_RESULT(vkMapMemory(logicalDevice, stagingMemory, 0, memReqs.size, 0, (void **)&data));
|
||||
memcpy(data, ktxTextureData, ktxTextureSize);
|
||||
vkUnmapMemory(device->logicalDevice, stagingMemory);
|
||||
vkUnmapMemory(logicalDevice, stagingMemory);
|
||||
|
||||
// Setup buffer copy regions for each layer including all of its miplevels
|
||||
std::vector<VkBufferImageCopy> bufferCopyRegions;
|
||||
|
|
@ -585,7 +601,7 @@ namespace vks
|
|||
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
imageCreateInfo.extent = { width, height, 1 };
|
||||
imageCreateInfo.extent = {width, height, 1};
|
||||
imageCreateInfo.usage = imageUsageFlags;
|
||||
// Ensure that the TRANSFER_DST bit is set for staging
|
||||
if (!(imageCreateInfo.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT))
|
||||
|
|
@ -595,15 +611,15 @@ namespace vks
|
|||
imageCreateInfo.arrayLayers = layerCount;
|
||||
imageCreateInfo.mipLevels = mipLevels;
|
||||
|
||||
VK_CHECK_RESULT(vkCreateImage(device->logicalDevice, &imageCreateInfo, nullptr, &image));
|
||||
VK_CHECK_RESULT(vkCreateImage(logicalDevice, &imageCreateInfo, nullptr, &image));
|
||||
|
||||
vkGetImageMemoryRequirements(device->logicalDevice, image, &memReqs);
|
||||
vkGetImageMemoryRequirements(logicalDevice, image, &memReqs);
|
||||
|
||||
memAllocInfo.allocationSize = memReqs.size;
|
||||
memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
|
||||
VK_CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &deviceMemory));
|
||||
VK_CHECK_RESULT(vkBindImageMemory(device->logicalDevice, image, deviceMemory, 0));
|
||||
VK_CHECK_RESULT(vkAllocateMemory(logicalDevice, &memAllocInfo, nullptr, &deviceMemory));
|
||||
VK_CHECK_RESULT(vkBindImageMemory(logicalDevice, image, deviceMemory, 0));
|
||||
|
||||
// Use a separate command buffer for texture loading
|
||||
VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
||||
|
|
@ -652,34 +668,42 @@ namespace vks
|
|||
samplerCreateInfo.addressModeV = samplerCreateInfo.addressModeU;
|
||||
samplerCreateInfo.addressModeW = samplerCreateInfo.addressModeU;
|
||||
samplerCreateInfo.mipLodBias = 0.0f;
|
||||
samplerCreateInfo.maxAnisotropy = device->enabledFeatures.samplerAnisotropy ? device->properties.limits.maxSamplerAnisotropy : 1.0f;
|
||||
samplerCreateInfo.anisotropyEnable = device->enabledFeatures.samplerAnisotropy;
|
||||
if (device->getPhysicalDeviceFeatures().samplerAnisotropy)
|
||||
{
|
||||
samplerCreateInfo.maxAnisotropy = device->getPhysicalDeviceProperties().limits.maxSamplerAnisotropy;
|
||||
}
|
||||
else
|
||||
{
|
||||
samplerCreateInfo.maxAnisotropy = 1.0;
|
||||
}
|
||||
|
||||
samplerCreateInfo.anisotropyEnable = device->getPhysicalDeviceFeatures().samplerAnisotropy;
|
||||
samplerCreateInfo.compareOp = VK_COMPARE_OP_NEVER;
|
||||
samplerCreateInfo.minLod = 0.0f;
|
||||
samplerCreateInfo.maxLod = (float)mipLevels;
|
||||
samplerCreateInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
|
||||
VK_CHECK_RESULT(vkCreateSampler(device->logicalDevice, &samplerCreateInfo, nullptr, &sampler));
|
||||
VK_CHECK_RESULT(vkCreateSampler(logicalDevice, &samplerCreateInfo, nullptr, &sampler));
|
||||
|
||||
// Create image view
|
||||
VkImageViewCreateInfo viewCreateInfo = vks::initializers::imageViewCreateInfo();
|
||||
viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewCreateInfo.format = format;
|
||||
viewCreateInfo.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
|
||||
viewCreateInfo.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
|
||||
viewCreateInfo.subresourceRange.layerCount = layerCount;
|
||||
viewCreateInfo.subresourceRange.levelCount = mipLevels;
|
||||
viewCreateInfo.image = image;
|
||||
VK_CHECK_RESULT(vkCreateImageView(device->logicalDevice, &viewCreateInfo, nullptr, &view));
|
||||
VK_CHECK_RESULT(vkCreateImageView(logicalDevice, &viewCreateInfo, nullptr, &view));
|
||||
|
||||
// Clean up staging resources
|
||||
ktxTexture_Destroy(ktxTexture);
|
||||
vkFreeMemory(device->logicalDevice, stagingMemory, nullptr);
|
||||
vkDestroyBuffer(device->logicalDevice, stagingBuffer, nullptr);
|
||||
vkFreeMemory(logicalDevice, stagingMemory, nullptr);
|
||||
vkDestroyBuffer(logicalDevice, stagingBuffer, nullptr);
|
||||
|
||||
// Update descriptor image info member that can be used for setting up descriptor sets
|
||||
updateDescriptor();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Load a cubemap texture including all mip levels from a single file
|
||||
*
|
||||
* @param filename File to load (supports .ktx)
|
||||
|
|
@ -690,9 +714,9 @@ namespace vks
|
|||
* @param (Optional) imageLayout Usage layout for the texture (defaults VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||
*
|
||||
*/
|
||||
void TextureCubeMap::loadFromFile(std::string filename, VkFormat format, vks::VulkanDevice *device, VkQueue copyQueue, VkImageUsageFlags imageUsageFlags, VkImageLayout imageLayout)
|
||||
{
|
||||
ktxTexture* ktxTexture;
|
||||
void TextureCubeMap::loadFromFile(std::string filename, VkFormat format, VulkanBase::VulkanDevice *device, VkQueue copyQueue, VkImageUsageFlags imageUsageFlags, VkImageLayout imageLayout)
|
||||
{
|
||||
ktxTexture *ktxTexture;
|
||||
ktxResult result = loadKTXFile(filename, &ktxTexture);
|
||||
assert(result == KTX_SUCCESS);
|
||||
|
||||
|
|
@ -704,6 +728,8 @@ namespace vks
|
|||
ktx_uint8_t *ktxTextureData = ktxTexture_GetData(ktxTexture);
|
||||
ktx_size_t ktxTextureSize = ktxTexture_GetSize(ktxTexture);
|
||||
|
||||
VkDevice logicalDevice = device->getLogicalDevice();
|
||||
|
||||
VkMemoryAllocateInfo memAllocInfo = vks::initializers::memoryAllocateInfo();
|
||||
VkMemoryRequirements memReqs;
|
||||
|
||||
|
|
@ -717,23 +743,23 @@ namespace vks
|
|||
bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
|
||||
VK_CHECK_RESULT(vkCreateBuffer(device->logicalDevice, &bufferCreateInfo, nullptr, &stagingBuffer));
|
||||
VK_CHECK_RESULT(vkCreateBuffer(logicalDevice, &bufferCreateInfo, nullptr, &stagingBuffer));
|
||||
|
||||
// Get memory requirements for the staging buffer (alignment, memory type bits)
|
||||
vkGetBufferMemoryRequirements(device->logicalDevice, stagingBuffer, &memReqs);
|
||||
vkGetBufferMemoryRequirements(logicalDevice, stagingBuffer, &memReqs);
|
||||
|
||||
memAllocInfo.allocationSize = memReqs.size;
|
||||
// Get memory type index for a host visible buffer
|
||||
memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
|
||||
VK_CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &stagingMemory));
|
||||
VK_CHECK_RESULT(vkBindBufferMemory(device->logicalDevice, stagingBuffer, stagingMemory, 0));
|
||||
VK_CHECK_RESULT(vkAllocateMemory(logicalDevice, &memAllocInfo, nullptr, &stagingMemory));
|
||||
VK_CHECK_RESULT(vkBindBufferMemory(logicalDevice, stagingBuffer, stagingMemory, 0));
|
||||
|
||||
// Copy texture data into staging buffer
|
||||
uint8_t *data;
|
||||
VK_CHECK_RESULT(vkMapMemory(device->logicalDevice, stagingMemory, 0, memReqs.size, 0, (void **)&data));
|
||||
VK_CHECK_RESULT(vkMapMemory(logicalDevice, stagingMemory, 0, memReqs.size, 0, (void **)&data));
|
||||
memcpy(data, ktxTextureData, ktxTextureSize);
|
||||
vkUnmapMemory(device->logicalDevice, stagingMemory);
|
||||
vkUnmapMemory(logicalDevice, stagingMemory);
|
||||
|
||||
// Setup buffer copy regions for each face including all of its mip levels
|
||||
std::vector<VkBufferImageCopy> bufferCopyRegions;
|
||||
|
|
@ -769,7 +795,7 @@ namespace vks
|
|||
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
imageCreateInfo.extent = { width, height, 1 };
|
||||
imageCreateInfo.extent = {width, height, 1};
|
||||
imageCreateInfo.usage = imageUsageFlags;
|
||||
// Ensure that the TRANSFER_DST bit is set for staging
|
||||
if (!(imageCreateInfo.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT))
|
||||
|
|
@ -781,16 +807,15 @@ namespace vks
|
|||
// This flag is required for cube map images
|
||||
imageCreateInfo.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
|
||||
|
||||
VK_CHECK_RESULT(vkCreateImage(logicalDevice, &imageCreateInfo, nullptr, &image));
|
||||
|
||||
VK_CHECK_RESULT(vkCreateImage(device->logicalDevice, &imageCreateInfo, nullptr, &image));
|
||||
|
||||
vkGetImageMemoryRequirements(device->logicalDevice, image, &memReqs);
|
||||
vkGetImageMemoryRequirements(logicalDevice, image, &memReqs);
|
||||
|
||||
memAllocInfo.allocationSize = memReqs.size;
|
||||
memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
|
||||
VK_CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &deviceMemory));
|
||||
VK_CHECK_RESULT(vkBindImageMemory(device->logicalDevice, image, deviceMemory, 0));
|
||||
VK_CHECK_RESULT(vkAllocateMemory(logicalDevice, &memAllocInfo, nullptr, &deviceMemory));
|
||||
VK_CHECK_RESULT(vkBindImageMemory(logicalDevice, image, deviceMemory, 0));
|
||||
|
||||
// Use a separate command buffer for texture loading
|
||||
VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
||||
|
|
@ -839,31 +864,39 @@ namespace vks
|
|||
samplerCreateInfo.addressModeV = samplerCreateInfo.addressModeU;
|
||||
samplerCreateInfo.addressModeW = samplerCreateInfo.addressModeU;
|
||||
samplerCreateInfo.mipLodBias = 0.0f;
|
||||
samplerCreateInfo.maxAnisotropy = device->enabledFeatures.samplerAnisotropy ? device->properties.limits.maxSamplerAnisotropy : 1.0f;
|
||||
samplerCreateInfo.anisotropyEnable = device->enabledFeatures.samplerAnisotropy;
|
||||
if (device->getPhysicalDeviceFeatures().samplerAnisotropy)
|
||||
{
|
||||
samplerCreateInfo.maxAnisotropy = device->getPhysicalDeviceProperties().limits.maxSamplerAnisotropy;
|
||||
}
|
||||
else
|
||||
{
|
||||
samplerCreateInfo.maxAnisotropy = 1.0;
|
||||
}
|
||||
|
||||
samplerCreateInfo.anisotropyEnable = device->getPhysicalDeviceFeatures().samplerAnisotropy;
|
||||
samplerCreateInfo.compareOp = VK_COMPARE_OP_NEVER;
|
||||
samplerCreateInfo.minLod = 0.0f;
|
||||
samplerCreateInfo.maxLod = (float)mipLevels;
|
||||
samplerCreateInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
|
||||
VK_CHECK_RESULT(vkCreateSampler(device->logicalDevice, &samplerCreateInfo, nullptr, &sampler));
|
||||
VK_CHECK_RESULT(vkCreateSampler(logicalDevice, &samplerCreateInfo, nullptr, &sampler));
|
||||
|
||||
// Create image view
|
||||
VkImageViewCreateInfo viewCreateInfo = vks::initializers::imageViewCreateInfo();
|
||||
viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_CUBE;
|
||||
viewCreateInfo.format = format;
|
||||
viewCreateInfo.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
|
||||
viewCreateInfo.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
|
||||
viewCreateInfo.subresourceRange.layerCount = 6;
|
||||
viewCreateInfo.subresourceRange.levelCount = mipLevels;
|
||||
viewCreateInfo.image = image;
|
||||
VK_CHECK_RESULT(vkCreateImageView(device->logicalDevice, &viewCreateInfo, nullptr, &view));
|
||||
VK_CHECK_RESULT(vkCreateImageView(logicalDevice, &viewCreateInfo, nullptr, &view));
|
||||
|
||||
// Clean up staging resources
|
||||
ktxTexture_Destroy(ktxTexture);
|
||||
vkFreeMemory(device->logicalDevice, stagingMemory, nullptr);
|
||||
vkDestroyBuffer(device->logicalDevice, stagingBuffer, nullptr);
|
||||
vkFreeMemory(logicalDevice, stagingMemory, nullptr);
|
||||
vkDestroyBuffer(logicalDevice, stagingBuffer, nullptr);
|
||||
|
||||
// Update descriptor image info member that can be used for setting up descriptor sets
|
||||
updateDescriptor();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace VulkanBase
|
||||
|
|
|
|||
|
|
@ -1,37 +1,27 @@
|
|||
/*
|
||||
* Vulkan texture loader
|
||||
*
|
||||
* Copyright(C) by Sascha Willems - www.saschawillems.de
|
||||
*
|
||||
* This code is licensed under the MIT license(MIT) (http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#ifndef VULKANTEXTURE_H
|
||||
#define VULKANTEXTURE_H
|
||||
|
||||
#pragma once
|
||||
#include "VulkanBase_Marco.h"
|
||||
|
||||
#include "VulkanBuffer.h"
|
||||
#include "VulkanDevice.h"
|
||||
#include "VulkanTools.h"
|
||||
|
||||
#include <ktx.h>
|
||||
#include <ktxvulkan.h>
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "vulkan/vulkan.h"
|
||||
VULKANBASE_NAMESPACE_BEGIN
|
||||
|
||||
#include <ktx.h>
|
||||
#include <ktxvulkan.h>
|
||||
|
||||
#include "VulkanBuffer.h"
|
||||
#include "VulkanDevice.hpp"
|
||||
//#include "VulkanTools.h"
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
# include <android/asset_manager.h>
|
||||
#endif
|
||||
|
||||
namespace vks
|
||||
{
|
||||
class Texture
|
||||
{
|
||||
public:
|
||||
vks::VulkanDevice * device;
|
||||
public:
|
||||
VulkanBase::VulkanDevice *device;
|
||||
VkImage image;
|
||||
VkImageLayout imageLayout;
|
||||
VkDeviceMemory deviceMemory;
|
||||
|
|
@ -49,22 +39,22 @@ class Texture
|
|||
|
||||
class Texture2D : public Texture
|
||||
{
|
||||
public:
|
||||
public:
|
||||
void loadFromFile(
|
||||
std::string filename,
|
||||
VkFormat format,
|
||||
vks::VulkanDevice *device,
|
||||
VulkanBase::VulkanDevice *device,
|
||||
VkQueue copyQueue,
|
||||
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
|
||||
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
bool forceLinear = false);
|
||||
void fromBuffer(
|
||||
void * buffer,
|
||||
void loadFromBuffer(
|
||||
void *buffer,
|
||||
VkDeviceSize bufferSize,
|
||||
VkFormat format,
|
||||
uint32_t texWidth,
|
||||
uint32_t texHeight,
|
||||
vks::VulkanDevice *device,
|
||||
VulkanBase::VulkanDevice *device,
|
||||
VkQueue copyQueue,
|
||||
VkFilter filter = VK_FILTER_LINEAR,
|
||||
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
|
||||
|
|
@ -73,11 +63,11 @@ class Texture2D : public Texture
|
|||
|
||||
class Texture2DArray : public Texture
|
||||
{
|
||||
public:
|
||||
public:
|
||||
void loadFromFile(
|
||||
std::string filename,
|
||||
VkFormat format,
|
||||
vks::VulkanDevice *device,
|
||||
VulkanBase::VulkanDevice *device,
|
||||
VkQueue copyQueue,
|
||||
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
|
||||
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
|
|
@ -85,13 +75,16 @@ class Texture2DArray : public Texture
|
|||
|
||||
class TextureCubeMap : public Texture
|
||||
{
|
||||
public:
|
||||
public:
|
||||
void loadFromFile(
|
||||
std::string filename,
|
||||
VkFormat format,
|
||||
vks::VulkanDevice *device,
|
||||
VulkanBase::VulkanDevice *device,
|
||||
VkQueue copyQueue,
|
||||
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
|
||||
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
};
|
||||
} // namespace vks
|
||||
|
||||
VULKANBASE_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
#include "vulkan/vulkan.h"
|
||||
#include "VulkanInitializers.hpp"
|
||||
#include "vulkan/vulkan.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
|
||||
#include <algorithm>
|
||||
#include <assert.h>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <math.h>
|
||||
#include <stdexcept>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
#include <windows.h>
|
||||
|
||||
#elif defined(__ANDROID__)
|
||||
#include "VulkanAndroid.h"
|
||||
#include <android/asset_manager.h>
|
||||
|
|
@ -33,70 +35,70 @@
|
|||
// Macro to check and display Vulkan return results
|
||||
#if defined(__ANDROID__)
|
||||
#define VK_CHECK_RESULT(f) \
|
||||
{ \
|
||||
{ \
|
||||
VkResult res = (f); \
|
||||
if (res != VK_SUCCESS) \
|
||||
{ \
|
||||
LOGE("Fatal : VkResult is \" %s \" in %s at line %d", vks::tools::errorString(res).c_str(), __FILE__, __LINE__); \
|
||||
assert(res == VK_SUCCESS); \
|
||||
} \
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define VK_CHECK_RESULT(f) \
|
||||
{ \
|
||||
{ \
|
||||
VkResult res = (f); \
|
||||
if (res != VK_SUCCESS) \
|
||||
{ \
|
||||
std::cout << "Fatal : VkResult is \"" << vks::tools::errorString(res) << "\" in " << __FILE__ << " at line " << __LINE__ << "\n"; \
|
||||
assert(res == VK_SUCCESS); \
|
||||
} \
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#define GET_INSTANCE_PROC_ADDR(inst, entrypoint) \
|
||||
{ \
|
||||
fp##entrypoint = reinterpret_cast<PFN_vk##entrypoint>(vkGetInstanceProcAddr(inst, "vk"#entrypoint)); \
|
||||
{ \
|
||||
fp##entrypoint = reinterpret_cast<PFN_vk##entrypoint>(vkGetInstanceProcAddr(inst, "vk" #entrypoint)); \
|
||||
if (fp##entrypoint == NULL) \
|
||||
{ \
|
||||
exit(1); \
|
||||
} \
|
||||
}
|
||||
}
|
||||
|
||||
#define GET_DEVICE_PROC_ADDR(dev, entrypoint) \
|
||||
{ \
|
||||
fp##entrypoint = reinterpret_cast<PFN_vk##entrypoint>(vkGetDeviceProcAddr(dev, "vk"#entrypoint)); \
|
||||
{ \
|
||||
fp##entrypoint = reinterpret_cast<PFN_vk##entrypoint>(vkGetDeviceProcAddr(dev, "vk" #entrypoint)); \
|
||||
if (fp##entrypoint == NULL) \
|
||||
{ \
|
||||
exit(1); \
|
||||
} \
|
||||
}
|
||||
}
|
||||
|
||||
const std::string getAssetPath();
|
||||
|
||||
namespace vks
|
||||
{
|
||||
namespace tools
|
||||
{
|
||||
/** @brief Disable message boxes on fatal errors */
|
||||
extern bool errorModeSilent;
|
||||
namespace tools
|
||||
{
|
||||
/** @brief Disable message boxes on fatal errors */
|
||||
extern bool errorModeSilent;
|
||||
|
||||
/** @brief Returns an error code as a string */
|
||||
std::string errorString(VkResult errorCode);
|
||||
/** @brief Returns an error code as a string */
|
||||
std::string errorString(VkResult errorCode);
|
||||
|
||||
/** @brief Returns the device type as a string */
|
||||
std::string physicalDeviceTypeString(VkPhysicalDeviceType type);
|
||||
/** @brief Returns the device type as a string */
|
||||
std::string physicalDeviceTypeString(VkPhysicalDeviceType type);
|
||||
|
||||
// Selected a suitable supported depth format starting with 32 bit down to 16 bit
|
||||
// Returns false if none of the depth formats in the list is supported by the device
|
||||
VkBool32 getSupportedDepthFormat(VkPhysicalDevice physicalDevice, VkFormat *depthFormat);
|
||||
// Selected a suitable supported depth format starting with 32 bit down to 16 bit
|
||||
// Returns false if none of the depth formats in the list is supported by the device
|
||||
VkBool32 getSupportedDepthFormat(VkPhysicalDevice physicalDevice, VkFormat *depthFormat);
|
||||
|
||||
// Returns tru a given format support LINEAR filtering
|
||||
VkBool32 formatIsFilterable(VkPhysicalDevice physicalDevice, VkFormat format, VkImageTiling tiling);
|
||||
// Returns true if a given format has a stencil part
|
||||
VkBool32 formatHasStencil(VkFormat format);
|
||||
// Returns tru a given format support LINEAR filtering
|
||||
VkBool32 formatIsFilterable(VkPhysicalDevice physicalDevice, VkFormat format, VkImageTiling tiling);
|
||||
// Returns true if a given format has a stencil part
|
||||
VkBool32 formatHasStencil(VkFormat format);
|
||||
|
||||
// Put an image memory barrier for setting an image layout on the sub resource into the given command buffer
|
||||
void setImageLayout(
|
||||
// Put an image memory barrier for setting an image layout on the sub resource into the given command buffer
|
||||
void setImageLayout(
|
||||
VkCommandBuffer cmdbuffer,
|
||||
VkImage image,
|
||||
VkImageLayout oldImageLayout,
|
||||
|
|
@ -104,8 +106,8 @@ namespace vks
|
|||
VkImageSubresourceRange subresourceRange,
|
||||
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
|
||||
// Uses a fixed sub resource layout with first mip level and layer
|
||||
void setImageLayout(
|
||||
// Uses a fixed sub resource layout with first mip level and layer
|
||||
void setImageLayout(
|
||||
VkCommandBuffer cmdbuffer,
|
||||
VkImage image,
|
||||
VkImageAspectFlags aspectMask,
|
||||
|
|
@ -114,8 +116,8 @@ namespace vks
|
|||
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
|
||||
|
||||
/** @brief Insert an image memory barrier into the command buffer */
|
||||
void insertImageMemoryBarrier(
|
||||
/** @brief Insert an image memory barrier into the command buffer */
|
||||
void insertImageMemoryBarrier(
|
||||
VkCommandBuffer cmdbuffer,
|
||||
VkImage image,
|
||||
VkAccessFlags srcAccessMask,
|
||||
|
|
@ -126,20 +128,20 @@ namespace vks
|
|||
VkPipelineStageFlags dstStageMask,
|
||||
VkImageSubresourceRange subresourceRange);
|
||||
|
||||
// Display error message and exit on fatal error
|
||||
void exitFatal(const std::string& message, int32_t exitCode);
|
||||
void exitFatal(const std::string& message, VkResult resultCode);
|
||||
// Display error message and exit on fatal error
|
||||
void exitFatal(const std::string &message, int32_t exitCode);
|
||||
void exitFatal(const std::string &message, VkResult resultCode);
|
||||
|
||||
// Load a SPIR-V shader (binary)
|
||||
// Load a SPIR-V shader (binary)
|
||||
#if defined(__ANDROID__)
|
||||
VkShaderModule loadShader(AAssetManager* assetManager, const char *fileName, VkDevice device);
|
||||
VkShaderModule loadShader(AAssetManager *assetManager, const char *fileName, VkDevice device);
|
||||
#else
|
||||
VkShaderModule loadShader(const char *fileName, VkDevice device);
|
||||
VkShaderModule loadShader(const char *fileName, VkDevice device);
|
||||
#endif
|
||||
|
||||
/** @brief Checks if a file exists */
|
||||
bool fileExists(const std::string &filename);
|
||||
/** @brief Checks if a file exists */
|
||||
bool fileExists(const std::string &filename);
|
||||
|
||||
uint32_t alignedSize(uint32_t value, uint32_t alignment);
|
||||
}
|
||||
}
|
||||
uint32_t alignedSize(uint32_t value, uint32_t alignment);
|
||||
} // namespace tools
|
||||
} // namespace vks
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,24 +1,26 @@
|
|||
/*
|
||||
* Vulkan Example base class
|
||||
*
|
||||
* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
|
||||
*
|
||||
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
* Vulkan Example base class
|
||||
*
|
||||
* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
|
||||
*
|
||||
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma comment(linker, "/subsystem:windows")
|
||||
#include <windows.h>
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
#include <windows.h>
|
||||
|
||||
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
|
||||
#include <android/native_activity.h>
|
||||
#include "VulkanAndroid.h"
|
||||
#include <android/asset_manager.h>
|
||||
#include <android/native_activity.h>
|
||||
#include <android_native_app_glue.h>
|
||||
#include <sys/system_properties.h>
|
||||
#include "VulkanAndroid.h"
|
||||
|
||||
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||
#include <wayland-client.h>
|
||||
#elif defined(_DIRECT2DISPLAY)
|
||||
|
|
@ -26,24 +28,25 @@
|
|||
#elif defined(VK_USE_PLATFORM_XCB_KHR)
|
||||
#include <xcb/xcb.h>
|
||||
#elif defined(VK_USE_PLATFORM_MACOS_MVK)
|
||||
#include <Cocoa/Cocoa.h>
|
||||
#include <Carbon/Carbon.h>
|
||||
#include <QuartzCore/CAMetalLayer.h>
|
||||
#include <Cocoa/Cocoa.h>
|
||||
#include <CoreVideo/CVDisplayLink.h>
|
||||
#include <QuartzCore/CAMetalLayer.h>
|
||||
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define GLM_FORCE_RADIANS
|
||||
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
|
||||
#define GLM_ENABLE_EXPERIMENTAL
|
||||
#include <glm/glm.hpp>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <array>
|
||||
#include <glm/glm.hpp>
|
||||
#include <numeric>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "vulkan/vulkan.h"
|
||||
|
||||
|
|
@ -51,7 +54,7 @@
|
|||
#include "camera.hpp"
|
||||
#include "keycodes.hpp"
|
||||
|
||||
#include "VulkanDevice.hpp"
|
||||
#include "VulkanDevice.h"
|
||||
#include "VulkanSwapChain.hpp"
|
||||
|
||||
#include "imgui.h"
|
||||
|
|
@ -68,18 +71,22 @@ private:
|
|||
PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallback;
|
||||
PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallback;
|
||||
VkDebugReportCallbackEXT debugReportCallback;
|
||||
struct MultisampleTarget {
|
||||
struct {
|
||||
struct MultisampleTarget
|
||||
{
|
||||
struct
|
||||
{
|
||||
VkImage image;
|
||||
VkImageView view;
|
||||
VkDeviceMemory memory;
|
||||
} color;
|
||||
struct {
|
||||
struct
|
||||
{
|
||||
VkImage image;
|
||||
VkImageView view;
|
||||
VkDeviceMemory memory;
|
||||
} depth;
|
||||
} multisampleTarget;
|
||||
|
||||
protected:
|
||||
VkInstance instance;
|
||||
VkPhysicalDevice physicalDevice;
|
||||
|
|
@ -87,12 +94,12 @@ protected:
|
|||
VkPhysicalDeviceFeatures deviceFeatures;
|
||||
VkPhysicalDeviceMemoryProperties deviceMemoryProperties;
|
||||
VkDevice device;
|
||||
vks::VulkanDevice *vulkanDevice;
|
||||
VulkanBase::VulkanDevice *vulkanDevice;
|
||||
VkQueue queue;
|
||||
VkFormat depthFormat;
|
||||
VkCommandPool cmdPool;
|
||||
VkRenderPass renderPass;
|
||||
std::vector<VkFramebuffer>frameBuffers;
|
||||
std::vector<VkFramebuffer> frameBuffers;
|
||||
uint32_t currentBuffer = 0;
|
||||
VkDescriptorPool descriptorPool;
|
||||
VkPipelineCache pipelineCache;
|
||||
|
|
@ -100,8 +107,9 @@ protected:
|
|||
std::string title = "Vulkan Example";
|
||||
std::string name = "vulkanExample";
|
||||
void windowResize();
|
||||
|
||||
public:
|
||||
static std::vector<const char*> args;
|
||||
static std::vector<const char *> args;
|
||||
uint32_t selectedPhysicalDeviceIndex = 0;
|
||||
bool prepared = false;
|
||||
uint32_t width = 1280;
|
||||
|
|
@ -112,7 +120,8 @@ public:
|
|||
bool paused = false;
|
||||
uint32_t lastFPS = 0;
|
||||
|
||||
struct Settings {
|
||||
struct Settings
|
||||
{
|
||||
bool validation = false; // 校验层开关
|
||||
bool fullscreen = false; // 全屏开关
|
||||
bool vsync = false; // 垂直同步开关
|
||||
|
|
@ -130,18 +139,21 @@ public:
|
|||
VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_4_BIT; // 多重采样倍率
|
||||
} settings;
|
||||
|
||||
struct DepthStencil {
|
||||
struct DepthStencil
|
||||
{
|
||||
VkImage image;
|
||||
VkDeviceMemory mem;
|
||||
VkImageView view;
|
||||
} depthStencil;
|
||||
|
||||
struct GamePadState {
|
||||
struct GamePadState
|
||||
{
|
||||
glm::vec2 axisLeft = glm::vec2(0.0f);
|
||||
glm::vec2 axisRight = glm::vec2(0.0f);
|
||||
} gamePadState;
|
||||
|
||||
struct MouseButtons {
|
||||
struct MouseButtons
|
||||
{
|
||||
bool left = false;
|
||||
bool right = false;
|
||||
bool middle = false;
|
||||
|
|
@ -155,7 +167,8 @@ public:
|
|||
// true if application has focused, false if moved to background
|
||||
bool focused = false;
|
||||
std::string androidProduct;
|
||||
struct TouchPoint {
|
||||
struct TouchPoint
|
||||
{
|
||||
int32_t id;
|
||||
float x;
|
||||
float y;
|
||||
|
|
@ -184,15 +197,15 @@ public:
|
|||
xcb_window_t window;
|
||||
xcb_intern_atom_reply_t *atom_wm_delete_window;
|
||||
#elif defined(VK_USE_PLATFORM_MACOS_MVK)
|
||||
NSWindow* window;
|
||||
NSWindow *window;
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
HWND setupWindow(HINSTANCE hinstance, WNDPROC wndproc);
|
||||
void handleMessages(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
|
||||
static int32_t handleAppInput(struct android_app* app, AInputEvent* event);
|
||||
static void handleAppCommand(android_app* app, int32_t cmd);
|
||||
static int32_t handleAppInput(struct android_app *app, AInputEvent *event);
|
||||
static void handleAppCommand(android_app *app, int32_t cmd);
|
||||
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||
wl_shell_surface *setupWindow();
|
||||
void initWaylandConnection();
|
||||
|
|
@ -242,7 +255,7 @@ public:
|
|||
void initxcbConnection();
|
||||
void handleEvent(const xcb_generic_event_t *event);
|
||||
#elif defined(VK_USE_PLATFORM_MACOS_MVK)
|
||||
NSWindow* setupWindow();
|
||||
NSWindow *setupWindow();
|
||||
void mouseDragged(float x, float y);
|
||||
void windowWillResize(float x, float y);
|
||||
void windowDidResize();
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,15 +1,21 @@
|
|||
#ifndef GLTFMAINMODEL_H
|
||||
#define GLTFMAINMODEL_H
|
||||
|
||||
#ifndef TINYGLTF_NO_STB_IMAGE_WRITE
|
||||
#define TINYGLTF_NO_STB_IMAGE_WRITE
|
||||
#endif
|
||||
|
||||
#include "glTFModel_Marco.h"
|
||||
#include "glTFModel_common.h"
|
||||
|
||||
#include "VulkanDevice.h"
|
||||
|
||||
#include "glTFAnimation.h"
|
||||
#include "glTFNode.h"
|
||||
#include "glTFSkin.h"
|
||||
#include "glTFTexture.h"
|
||||
#include "glTFAnimation.h"
|
||||
|
||||
#include <tiny_gltf.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <string>
|
||||
|
|
@ -17,6 +23,18 @@
|
|||
|
||||
GLTFLOADER_NAMESPACE_BEGIN
|
||||
|
||||
struct ModelBuffer
|
||||
{
|
||||
VkBuffer buffer = VK_NULL_HANDLE;
|
||||
VkDeviceMemory memory;
|
||||
};
|
||||
|
||||
struct AABBDimensions
|
||||
{
|
||||
glm::vec3 min = glm::vec3(FLT_MAX);
|
||||
glm::vec3 max = glm::vec3(-FLT_MAX);
|
||||
};
|
||||
|
||||
class glTFMainModel
|
||||
{
|
||||
public:
|
||||
|
|
@ -25,45 +43,42 @@ public:
|
|||
|
||||
VkSamplerAddressMode getVkWrapMode(int32_t wrapMode);
|
||||
VkFilter getVkFilterMode(int32_t filterMode);
|
||||
void getNodeProperty(const tinygltf::Node& node, const tinygltf::Model& model, size_t& vertexCount, size_t& indexCount);
|
||||
void getNodeProperty(const tinygltf::Node &node, const tinygltf::Model &model, size_t &vertexCount, size_t &indexCount);
|
||||
void getSceneDimensions();
|
||||
|
||||
ModelBuffer &getModelVertex();
|
||||
ModelBuffer &getModelIndex();
|
||||
|
||||
void destroy(VkDevice device);
|
||||
|
||||
void loadNode(glTFNode* parent, const tinygltf::Node& node, uint32_t nodeIndex, const tinygltf::Model& model, LoaderInfo& loaderInfo, float globalscale);
|
||||
void loadSkins(tinygltf::Model& gltfModel);
|
||||
void loadTextures(tinygltf::Model& gltfModel, VulkanBase::VulkanDevice* device, VkQueue transferQueue);
|
||||
void loadTextureSamplers(tinygltf::Model& gltfModel);
|
||||
void loadMaterials(tinygltf::Model& gltfModel);
|
||||
void loadAnimations(tinygltf::Model& gltfModel);
|
||||
void loadFromFile(std::string filename, VulkanBase::VulkanDevice* device, VkQueue transferQueue, float scale = 1.0f);
|
||||
void loadNode(glTFNode *parent, const tinygltf::Node &node, uint32_t nodeIndex, const tinygltf::Model &model, LoaderInfo &loaderInfo, float globalscale);
|
||||
void loadSkins(tinygltf::Model &gltfModel);
|
||||
void loadTextures(tinygltf::Model &gltfModel, VulkanBase::VulkanDevice *device, VkQueue transferQueue);
|
||||
void loadTextureSamplers(tinygltf::Model &gltfModel);
|
||||
void loadMaterials(tinygltf::Model &gltfModel);
|
||||
void loadAnimations(tinygltf::Model &gltfModel);
|
||||
void loadFromFile(std::string filename, VulkanBase::VulkanDevice *device, VkQueue transferQueue, float scale = 1.0f);
|
||||
|
||||
void drawNode(glTFNode* node, VkCommandBuffer commandBuffer);
|
||||
void drawNode(glTFNode *node, VkCommandBuffer commandBuffer);
|
||||
void draw(VkCommandBuffer commandBuffer);
|
||||
|
||||
void calculateBoundingBox(glTFNode* node, glTFNode* parent);
|
||||
void calculateBoundingBox(glTFNode *node, glTFNode *parent);
|
||||
void updateAnimation(uint32_t index, float time);
|
||||
glTFNode* findNode(glTFNode* parent, uint32_t index);
|
||||
glTFNode* nodeFromIndex(uint32_t index);
|
||||
glTFNode *findNode(glTFNode *parent, uint32_t index);
|
||||
glTFNode *nodeFromIndex(uint32_t index);
|
||||
|
||||
private:
|
||||
VulkanBase::VulkanDevice *m_device;
|
||||
|
||||
VulkanBase::VulkanDevice* m_device;
|
||||
|
||||
struct Vertices {
|
||||
VkBuffer buffer = VK_NULL_HANDLE;
|
||||
VkDeviceMemory memory;
|
||||
} m_vertices;
|
||||
struct Indices {
|
||||
VkBuffer buffer = VK_NULL_HANDLE;
|
||||
VkDeviceMemory memory;
|
||||
} m_indices;
|
||||
ModelBuffer m_vertices;
|
||||
ModelBuffer m_indices;
|
||||
|
||||
glm::mat4 m_aabb;
|
||||
|
||||
std::vector<glTFNode*> m_nodes;
|
||||
std::vector<glTFNode*> m_linearNodes;
|
||||
std::vector<glTFNode *> m_nodes;
|
||||
std::vector<glTFNode *> m_linearNodes;
|
||||
|
||||
std::vector<glTFSkin*> m_skins;
|
||||
std::vector<glTFSkin *> m_skins;
|
||||
|
||||
std::vector<glTFTexture> m_textures;
|
||||
std::vector<VulkanBase::VulkanTextureSampler> m_textureSamplers;
|
||||
|
|
@ -71,14 +86,9 @@ private:
|
|||
std::vector<glTFAnimation> m_animations;
|
||||
std::vector<std::string> m_extensions;
|
||||
|
||||
struct Dimensions {
|
||||
glm::vec3 min = glm::vec3(FLT_MAX);
|
||||
glm::vec3 max = glm::vec3(-FLT_MAX);
|
||||
} m_dimensions;
|
||||
|
||||
AABBDimensions m_dimensions;
|
||||
};
|
||||
|
||||
|
||||
GLTFLOADER_NAMESPACE_END
|
||||
|
||||
#endif // !GLTFMAINMODEL_h
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
#include "glTFMaterial.h"
|
||||
|
||||
|
||||
GLTFLOADER_NAMESPACE_BEGIN
|
||||
|
||||
glTFMaterial::glTFMaterial()
|
||||
|
|
@ -41,44 +40,53 @@ float glTFMaterial::getAlphaCutOff()
|
|||
return m_alphaCutoff;
|
||||
}
|
||||
|
||||
TextureCoordSet* glTFMaterial::getTextureCoordSet()
|
||||
TextureCoordSet *glTFMaterial::getTextureCoordSet()
|
||||
{
|
||||
return m_texCoordSets;
|
||||
}
|
||||
|
||||
void glTFMaterial::setTextureCoordSet(TextureCoordSet* value)
|
||||
void glTFMaterial::setTextureCoordSet(TextureCoordSet *value)
|
||||
{
|
||||
m_texCoordSets = value;
|
||||
}
|
||||
|
||||
PbrTextureExtension* glTFMaterial::getTextureExtension()
|
||||
PBR::PbrTextureExtension *glTFMaterial::getTextureExtension()
|
||||
{
|
||||
return m_textureExtension;
|
||||
}
|
||||
|
||||
void glTFMaterial::setPbrTextureExtension(PbrTextureExtension* value)
|
||||
void glTFMaterial::setPbrTextureExtension(PBR::PbrTextureExtension *value)
|
||||
{
|
||||
m_textureExtension = value;
|
||||
}
|
||||
|
||||
PbrBaseTexture* glTFMaterial::getPbrBaseTexture()
|
||||
PBR::PbrBaseTexture *glTFMaterial::getPbrBaseTexture()
|
||||
{
|
||||
return m_pbrBaseTexture;
|
||||
}
|
||||
|
||||
void glTFMaterial::setPbrBaseTexture(PbrBaseTexture* value)
|
||||
void glTFMaterial::setPbrBaseTexture(PBR::PbrBaseTexture *value)
|
||||
{
|
||||
m_pbrBaseTexture = value;
|
||||
}
|
||||
|
||||
PbrWorkFlow* glTFMaterial::getPbrWorkFlow()
|
||||
PBR::PbrWorkFlow *glTFMaterial::getPbrWorkFlow()
|
||||
{
|
||||
return m_pbrWorkFlow;
|
||||
}
|
||||
|
||||
void glTFMaterial::setPbrWorkFlow()
|
||||
void glTFMaterial::setPbrWorkFlow(PBR::PbrWorkFlow *value)
|
||||
{
|
||||
m_pbrWorkFlow;
|
||||
m_pbrWorkFlow = value;
|
||||
}
|
||||
|
||||
void glTFMaterial::setDescriptorSet(VkDescriptorSet value)
|
||||
{
|
||||
m_descriptorSet = value;
|
||||
}
|
||||
VkDescriptorSet glTFMaterial::getDescriptorSet()
|
||||
{
|
||||
return m_descriptorSet;
|
||||
}
|
||||
|
||||
GLTFLOADER_NAMESPACE_END
|
||||
|
|
@ -4,11 +4,11 @@
|
|||
#include "glTFModel_Marco.h"
|
||||
#include "glTFModel_common.h"
|
||||
|
||||
#include "glTFTexture.h"
|
||||
#include "PbrBaseTexture.h"
|
||||
#include "PbrTextureCoordSet.h"
|
||||
#include "PbrTextureExtension.h"
|
||||
#include "PbrBaseTexture.h"
|
||||
#include "PbrWorkFlow.h"
|
||||
#include "glTFTexture.h"
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
|
|
@ -29,38 +29,34 @@ public:
|
|||
void setAlphaCutOff(float value);
|
||||
float getAlphaCutOff();
|
||||
|
||||
void setDescriptorSet(VkDescriptorSet value);
|
||||
VkDescriptorSet getDescriptorSet();
|
||||
|
||||
TextureCoordSet* getTextureCoordSet();
|
||||
void setTextureCoordSet(TextureCoordSet* value);
|
||||
TextureCoordSet *getTextureCoordSet();
|
||||
void setTextureCoordSet(TextureCoordSet *value);
|
||||
|
||||
PbrTextureExtension* getTextureExtension();
|
||||
void setPbrTextureExtension(PbrTextureExtension* value);
|
||||
PBR::PbrTextureExtension *getTextureExtension();
|
||||
void setPbrTextureExtension(PBR::PbrTextureExtension *value);
|
||||
|
||||
PbrBaseTexture* getPbrBaseTexture();
|
||||
void setPbrBaseTexture(PbrBaseTexture* value);
|
||||
PBR::PbrBaseTexture *getPbrBaseTexture();
|
||||
void setPbrBaseTexture(PBR::PbrBaseTexture *value);
|
||||
|
||||
PbrWorkFlow* getPbrWorkFlow();
|
||||
void setPbrWorkFlow();
|
||||
PBR::PbrWorkFlow *getPbrWorkFlow();
|
||||
void setPbrWorkFlow(PBR::PbrWorkFlow *value);
|
||||
|
||||
private:
|
||||
|
||||
AlphaMode m_alphaMode = ALPHAMODE_OPAQUE;
|
||||
float m_alphaCutoff = 1.0f;
|
||||
|
||||
PbrBaseTexture* m_pbrBaseTexture;
|
||||
PBR::PbrBaseTexture *m_pbrBaseTexture;
|
||||
bool m_doubleSided = false;
|
||||
TextureCoordSet* m_texCoordSets;
|
||||
PbrTextureExtension* m_textureExtension;
|
||||
PbrWorkFlow* m_pbrWorkFlow;
|
||||
TextureCoordSet *m_texCoordSets;
|
||||
PBR::PbrTextureExtension *m_textureExtension;
|
||||
PBR::PbrWorkFlow *m_pbrWorkFlow;
|
||||
|
||||
VkDescriptorSet m_descriptorSet = VK_NULL_HANDLE;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
GLTFLOADER_NAMESPACE_END
|
||||
|
||||
#endif // !GLTFMATERIAL_H
|
||||
|
|
|
|||
|
|
@ -32,9 +32,9 @@
|
|||
|
||||
|
||||
#include "tiny_gltf.h"
|
||||
#include "VulkanDevice.hpp"
|
||||
#include "VulkanDevice.h"
|
||||
//#include "VulkanUtils.hpp"
|
||||
#include "vulkan/vulkan.h"
|
||||
|
||||
|
||||
#define ENABLE_VALIDATION false
|
||||
#define MAX_NUM_JOINTS 128u
|
||||
|
|
@ -64,7 +64,7 @@ namespace glTFModel
|
|||
};
|
||||
|
||||
struct Texture {
|
||||
vks::VulkanDevice* device;
|
||||
VulkanBase::VulkanDevice* device;
|
||||
VkImage image;
|
||||
VkImageLayout imageLayout;
|
||||
VkDeviceMemory deviceMemory;
|
||||
|
|
@ -77,7 +77,7 @@ namespace glTFModel
|
|||
void updateDescriptor();
|
||||
void destroy();
|
||||
// Load a texture from a glTF image (stored as vector of chars loaded via stb_image) and generate a full mip chaing for it
|
||||
void fromglTfImage(tinygltf::Image& gltfimage, glTFModel::TextureSampler textureSampler, vks::VulkanDevice* device, VkQueue copyQueue);
|
||||
void fromglTfImage(tinygltf::Image& gltfimage, glTFModel::TextureSampler textureSampler, VulkanBase::VulkanDevice* device, VkQueue copyQueue);
|
||||
};
|
||||
|
||||
struct Material {
|
||||
|
|
@ -127,7 +127,7 @@ namespace glTFModel
|
|||
};
|
||||
|
||||
struct Mesh {
|
||||
vks::VulkanDevice* device;
|
||||
VulkanBase::VulkanDevice* device;
|
||||
std::vector<Primitive*> primitives;
|
||||
BoundingBox bb;
|
||||
BoundingBox aabb;
|
||||
|
|
@ -143,7 +143,7 @@ namespace glTFModel
|
|||
glm::mat4 jointMatrix[128]{};
|
||||
float jointcount{ 0 };
|
||||
} uniformBlock;
|
||||
Mesh(vks::VulkanDevice* device, glm::mat4 matrix);
|
||||
Mesh(VulkanBase::VulkanDevice* device, glm::mat4 matrix);
|
||||
~Mesh();
|
||||
void setBoundingBox(glm::vec3 min, glm::vec3 max);
|
||||
};
|
||||
|
|
@ -199,7 +199,7 @@ namespace glTFModel
|
|||
|
||||
struct Model {
|
||||
|
||||
vks::VulkanDevice* device;
|
||||
VulkanBase::VulkanDevice* device;
|
||||
|
||||
struct Vertex {
|
||||
glm::vec3 pos;
|
||||
|
|
@ -249,13 +249,13 @@ namespace glTFModel
|
|||
void loadNode(glTFModel::Node* parent, const tinygltf::Node& node, uint32_t nodeIndex, const tinygltf::Model& model, LoaderInfo& loaderInfo, float globalscale);
|
||||
void getNodeProps(const tinygltf::Node& node, const tinygltf::Model& model, size_t& vertexCount, size_t& indexCount);
|
||||
void loadSkins(tinygltf::Model& gltfModel);
|
||||
void loadTextures(tinygltf::Model& gltfModel, vks::VulkanDevice* device, VkQueue transferQueue);
|
||||
void loadTextures(tinygltf::Model& gltfModel, VulkanBase::VulkanDevice* device, VkQueue transferQueue);
|
||||
VkSamplerAddressMode getVkWrapMode(int32_t wrapMode);
|
||||
VkFilter getVkFilterMode(int32_t filterMode);
|
||||
void loadTextureSamplers(tinygltf::Model& gltfModel);
|
||||
void loadMaterials(tinygltf::Model& gltfModel);
|
||||
void loadAnimations(tinygltf::Model& gltfModel);
|
||||
void loadFromFile(std::string filename, vks::VulkanDevice* device, VkQueue transferQueue, float scale = 1.0f);
|
||||
void loadFromFile(std::string filename, VulkanBase::VulkanDevice* device, VkQueue transferQueue, float scale = 1.0f);
|
||||
void drawNode(Node* node, VkCommandBuffer commandBuffer);
|
||||
void draw(VkCommandBuffer commandBuffer);
|
||||
void calculateBoundingBox(Node* node, Node* parent);
|
||||
|
|
|
|||
|
|
@ -2,13 +2,8 @@
|
|||
|
||||
GLTFLOADER_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
|
||||
glTFPrimitive::glTFPrimitive(uint32_t firstIndex, uint32_t indexCount, uint32_t vertexCount, glTFMaterial& material)
|
||||
:m_firstIndex(firstIndex)
|
||||
,m_indexCount(indexCount)
|
||||
,m_vertexCount(vertexCount)
|
||||
,m_material(material)
|
||||
glTFPrimitive::glTFPrimitive(uint32_t firstIndex, uint32_t indexCount, uint32_t vertexCount, glTFMaterial &material)
|
||||
: m_firstIndex(firstIndex), m_indexCount(indexCount), m_vertexCount(vertexCount), m_material(material)
|
||||
{
|
||||
m_hasIndices = indexCount > 0;
|
||||
}
|
||||
|
|
@ -47,5 +42,32 @@ unsigned int glTFPrimitive::getFirstIndex()
|
|||
return m_firstIndex;
|
||||
}
|
||||
|
||||
void glTFPrimitive::setGltfMaterial(glTFMaterial &material)
|
||||
{
|
||||
m_material = material;
|
||||
}
|
||||
|
||||
glTFMaterial &glTFPrimitive::getGltfMaterial()
|
||||
{
|
||||
return m_material;
|
||||
}
|
||||
|
||||
void glTFPrimitive::setHasIndices(bool hasIndices)
|
||||
{
|
||||
m_hasIndices = hasIndices;
|
||||
}
|
||||
bool glTFPrimitive::getHasIndices()
|
||||
{
|
||||
return m_hasIndices;
|
||||
}
|
||||
|
||||
void glTFPrimitive::setVertexCount(unsigned int vertexCount)
|
||||
{
|
||||
m_vertexCount = vertexCount;
|
||||
}
|
||||
unsigned int glTFPrimitive::getVertexCount()
|
||||
{
|
||||
return m_vertexCount;
|
||||
}
|
||||
|
||||
GLTFLOADER_NAMESPACE_END
|
||||
|
|
@ -3,18 +3,17 @@
|
|||
|
||||
#include "glTFModel_Marco.h"
|
||||
|
||||
#include "glTFMaterial.h"
|
||||
#include "glTFBoundingBox.h"
|
||||
#include "glTFMaterial.h"
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
|
||||
GLTFLOADER_NAMESPACE_BEGIN
|
||||
|
||||
class GLTFLOADER_API glTFPrimitive
|
||||
{
|
||||
public:
|
||||
glTFPrimitive(uint32_t firstIndex, uint32_t indexCount, uint32_t vertexCount, glTFMaterial& material);
|
||||
glTFPrimitive(uint32_t firstIndex, uint32_t indexCount, uint32_t vertexCount, glTFMaterial &material);
|
||||
|
||||
~glTFPrimitive();
|
||||
|
||||
|
|
@ -27,20 +26,24 @@ public:
|
|||
void setFirstIndex(unsigned int firstIndex);
|
||||
unsigned int getFirstIndex();
|
||||
|
||||
private:
|
||||
void setGltfMaterial(glTFMaterial &material);
|
||||
glTFMaterial &getGltfMaterial();
|
||||
|
||||
void setHasIndices(bool hasIndices);
|
||||
bool getHasIndices();
|
||||
|
||||
void setVertexCount(unsigned int vertexCount);
|
||||
unsigned int getVertexCount();
|
||||
|
||||
private:
|
||||
unsigned int m_firstIndex;
|
||||
unsigned int m_indexCount;
|
||||
unsigned int m_vertexCount;
|
||||
glTFMaterial& m_material;
|
||||
glTFMaterial &m_material;
|
||||
bool m_hasIndices;
|
||||
glTFBoundingBox m_boundingBox;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
GLTFLOADER_NAMESPACE_END
|
||||
|
||||
#endif // !GLTFPRIMITIVE_H
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
#include <tiny_gltf.h>
|
||||
|
||||
|
||||
GLTFLOADER_NAMESPACE_BEGIN
|
||||
|
||||
/// @brief gltf模型的贴图
|
||||
|
|
@ -22,11 +21,10 @@ public:
|
|||
|
||||
void destroy();
|
||||
|
||||
void fromglTfImage(tinygltf::Image& gltfimage, VulkanBase::VulkanTextureSampler textureSampler, VulkanBase::VulkanDevice* device, VkQueue copyQueue);
|
||||
void fromglTfImage(tinygltf::Image &gltfimage, VulkanBase::VulkanTextureSampler textureSampler, VulkanBase::VulkanDevice *device, VkQueue copyQueue);
|
||||
|
||||
private:
|
||||
|
||||
VulkanBase::VulkanDevice* m_device;
|
||||
VulkanBase::VulkanDevice *m_device;
|
||||
VkImage m_image;
|
||||
VkImageLayout m_imageLayout;
|
||||
VkDeviceMemory m_deviceMemory;
|
||||
|
|
@ -38,13 +36,6 @@ private:
|
|||
VkSampler m_sampler;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
GLTFLOADER_NAMESPACE_END
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // !GLTFTEXTURE_H
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include "PbrBaseTexture.h"
|
||||
|
||||
GLTFLOADER_NAMESPACE_BEGIN
|
||||
PBR_NAMESPACE_BEGIN
|
||||
|
||||
PbrBaseTexture::PbrBaseTexture()
|
||||
{
|
||||
|
|
@ -10,12 +10,12 @@ PbrBaseTexture::~PbrBaseTexture()
|
|||
{
|
||||
}
|
||||
|
||||
void PbrBaseTexture::setBaseColorTexture(glTFTexture* value)
|
||||
void PbrBaseTexture::setBaseColorTexture(glTFLoader::glTFTexture *value)
|
||||
{
|
||||
m_baseColorTexture = value;
|
||||
}
|
||||
|
||||
glTFTexture* PbrBaseTexture::getBaseColorTexture()
|
||||
glTFLoader::glTFTexture *PbrBaseTexture::getBaseColorTexture()
|
||||
{
|
||||
return m_baseColorTexture;
|
||||
}
|
||||
|
|
@ -30,22 +30,22 @@ glm::vec4 PbrBaseTexture::getBaseColorFactor()
|
|||
return m_baseColorFactor;
|
||||
}
|
||||
|
||||
void PbrBaseTexture::setNormalTexture(glTFTexture* value)
|
||||
void PbrBaseTexture::setNormalTexture(glTFLoader::glTFTexture *value)
|
||||
{
|
||||
m_normalTexture = value;
|
||||
}
|
||||
|
||||
glTFTexture* PbrBaseTexture::getNormalTexture()
|
||||
glTFLoader::glTFTexture *PbrBaseTexture::getNormalTexture()
|
||||
{
|
||||
return m_normalTexture;
|
||||
}
|
||||
|
||||
void PbrBaseTexture::setMetallicRoughnessTexture(glTFTexture* value)
|
||||
void PbrBaseTexture::setMetallicRoughnessTexture(glTFLoader::glTFTexture *value)
|
||||
{
|
||||
m_metallicRoughnessTexture = value;
|
||||
}
|
||||
|
||||
glTFTexture* PbrBaseTexture::getMetalicRoughnessTexture()
|
||||
glTFLoader::glTFTexture *PbrBaseTexture::getMetalicRoughnessTexture()
|
||||
{
|
||||
return m_metallicRoughnessTexture;
|
||||
}
|
||||
|
|
@ -70,17 +70,16 @@ float PbrBaseTexture::getRoughnessFactor()
|
|||
return m_roughnessFactor;
|
||||
}
|
||||
|
||||
void PbrBaseTexture::setEmissiveTexture(glTFTexture* value)
|
||||
void PbrBaseTexture::setEmissiveTexture(glTFLoader::glTFTexture *value)
|
||||
{
|
||||
m_emissiveTexture = value;
|
||||
}
|
||||
|
||||
glTFTexture* PbrBaseTexture::getEmissiveTexture()
|
||||
glTFLoader::glTFTexture *PbrBaseTexture::getEmissiveTexture()
|
||||
{
|
||||
return m_emissiveTexture;
|
||||
}
|
||||
|
||||
|
||||
void PbrBaseTexture::setEmissiveFactor(glm::vec4 value)
|
||||
{
|
||||
m_emissiveFactor = value;
|
||||
|
|
@ -91,14 +90,14 @@ glm::vec4 PbrBaseTexture::getEmissiveFactor()
|
|||
return m_emissiveFactor;
|
||||
}
|
||||
|
||||
void PbrBaseTexture::setOcclusionTexture(glTFTexture* value)
|
||||
void PbrBaseTexture::setOcclusionTexture(glTFLoader::glTFTexture *value)
|
||||
{
|
||||
m_occlusionTexture = value;
|
||||
}
|
||||
|
||||
glTFTexture* PbrBaseTexture::getOcclusionTexture()
|
||||
glTFLoader::glTFTexture *PbrBaseTexture::getOcclusionTexture()
|
||||
{
|
||||
return m_occlusionTexture;
|
||||
}
|
||||
|
||||
GLTFLOADER_NAMESPACE_END
|
||||
PBR_NAMESPACE_END
|
||||
|
|
@ -1,14 +1,13 @@
|
|||
#ifndef PBRBASETEXTURE_H
|
||||
#define PBRBASETEXTURE_H
|
||||
|
||||
/// todo: 分离为单独的PBR命名空间
|
||||
#include "glTFModel_Marco.h"
|
||||
#include "PbrMarco.h"
|
||||
|
||||
#include "glTFTexture.h"
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
GLTFLOADER_NAMESPACE_BEGIN
|
||||
PBR_NAMESPACE_BEGIN
|
||||
|
||||
/// @brief todo:拆分texture基类摆脱gltf限制
|
||||
class PbrBaseTexture
|
||||
|
|
@ -17,17 +16,17 @@ public:
|
|||
PbrBaseTexture();
|
||||
~PbrBaseTexture();
|
||||
|
||||
void setBaseColorTexture(glTFTexture* value);
|
||||
glTFTexture* getBaseColorTexture();
|
||||
void setBaseColorTexture(glTFLoader::glTFTexture *value);
|
||||
glTFLoader::glTFTexture *getBaseColorTexture();
|
||||
|
||||
void setBaseColorFactor(glm::vec4 value);
|
||||
glm::vec4 getBaseColorFactor();
|
||||
|
||||
void setNormalTexture(glTFTexture* value);
|
||||
glTFTexture* getNormalTexture();
|
||||
void setNormalTexture(glTFLoader::glTFTexture *value);
|
||||
glTFLoader::glTFTexture *getNormalTexture();
|
||||
|
||||
void setMetallicRoughnessTexture(glTFTexture* value);
|
||||
glTFTexture* getMetalicRoughnessTexture();
|
||||
void setMetallicRoughnessTexture(glTFLoader::glTFTexture *value);
|
||||
glTFLoader::glTFTexture *getMetalicRoughnessTexture();
|
||||
|
||||
void setMetallicFactor(float value);
|
||||
float getMetallicFactor();
|
||||
|
|
@ -35,35 +34,31 @@ public:
|
|||
void setRoughnessFactor(float value);
|
||||
float getRoughnessFactor();
|
||||
|
||||
void setEmissiveTexture(glTFTexture* value);
|
||||
glTFTexture* getEmissiveTexture();
|
||||
void setEmissiveTexture(glTFLoader::glTFTexture *value);
|
||||
glTFLoader::glTFTexture *getEmissiveTexture();
|
||||
|
||||
void setEmissiveFactor(glm::vec4 value);
|
||||
glm::vec4 getEmissiveFactor();
|
||||
|
||||
void setOcclusionTexture(glTFTexture* value);
|
||||
glTFTexture* getOcclusionTexture();
|
||||
void setOcclusionTexture(glTFLoader::glTFTexture *value);
|
||||
glTFLoader::glTFTexture *getOcclusionTexture();
|
||||
|
||||
private:
|
||||
|
||||
glTFTexture* m_baseColorTexture = nullptr;
|
||||
glTFLoader::glTFTexture *m_baseColorTexture = nullptr;
|
||||
glm::vec4 m_baseColorFactor = glm::vec4(1.0f);
|
||||
|
||||
glTFTexture* m_normalTexture = nullptr;
|
||||
glTFLoader::glTFTexture *m_normalTexture = nullptr;
|
||||
|
||||
glTFTexture* m_metallicRoughnessTexture = nullptr;
|
||||
glTFLoader::glTFTexture *m_metallicRoughnessTexture = nullptr;
|
||||
float m_metallicFactor = 1.0f;
|
||||
float m_roughnessFactor = 1.0f;
|
||||
|
||||
glTFTexture* m_emissiveTexture = nullptr;
|
||||
glTFLoader::glTFTexture *m_emissiveTexture = nullptr;
|
||||
glm::vec4 m_emissiveFactor = glm::vec4(1.0f);
|
||||
|
||||
glTFTexture* m_occlusionTexture = nullptr;
|
||||
|
||||
glTFLoader::glTFTexture *m_occlusionTexture = nullptr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
GLTFLOADER_NAMESPACE_END
|
||||
PBR_NAMESPACE_END
|
||||
|
||||
#endif // !PBRBASETEXTURE_H
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
GLTFLOADER_NAMESPACE_BEGIN
|
||||
PBR_NAMESPACE_BEGIN
|
||||
|
||||
PbrTextureExtension::PbrTextureExtension()
|
||||
{
|
||||
|
|
@ -10,22 +10,22 @@ PbrTextureExtension::~PbrTextureExtension()
|
|||
{
|
||||
}
|
||||
|
||||
void PbrTextureExtension::setSpecularGlossinessTexture(glTFTexture* _texture)
|
||||
void PbrTextureExtension::setSpecularGlossinessTexture(glTFLoader::glTFTexture *_texture)
|
||||
{
|
||||
m_specularGlossinessTexture = _texture;
|
||||
}
|
||||
|
||||
glTFTexture* PbrTextureExtension::getSpecularGlossinessTexture()
|
||||
glTFLoader::glTFTexture *PbrTextureExtension::getSpecularGlossinessTexture()
|
||||
{
|
||||
return m_specularGlossinessTexture;
|
||||
}
|
||||
|
||||
void PbrTextureExtension::setDiffuseTexture(glTFTexture* _texture)
|
||||
void PbrTextureExtension::setDiffuseTexture(glTFLoader::glTFTexture *_texture)
|
||||
{
|
||||
m_diffuseTexture = _texture;
|
||||
}
|
||||
|
||||
glTFTexture* PbrTextureExtension::getDiffuseTexture()
|
||||
glTFLoader::glTFTexture *PbrTextureExtension::getDiffuseTexture()
|
||||
{
|
||||
return m_diffuseTexture;
|
||||
}
|
||||
|
|
@ -50,6 +50,4 @@ glm::vec3 PbrTextureExtension::getSpecularFactor()
|
|||
return m_specularFactor;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GLTFLOADER_NAMESPACE_END
|
||||
PBR_NAMESPACE_END
|
||||
|
|
@ -1,14 +1,13 @@
|
|||
#ifndef PBRTEXTUREEXTENSION_H
|
||||
#define PBRTEXTUREEXTENSION_H
|
||||
|
||||
#include "glTFModel_Marco.h"
|
||||
#include "PbrMarco.h"
|
||||
|
||||
#include "glTFTexture.h"
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
|
||||
GLTFLOADER_NAMESPACE_BEGIN
|
||||
PBR_NAMESPACE_BEGIN
|
||||
|
||||
class PbrTextureExtension
|
||||
{
|
||||
|
|
@ -16,11 +15,11 @@ public:
|
|||
PbrTextureExtension();
|
||||
~PbrTextureExtension();
|
||||
|
||||
void setSpecularGlossinessTexture(glTFTexture* _texture);
|
||||
glTFTexture* getSpecularGlossinessTexture();
|
||||
void setSpecularGlossinessTexture(glTFLoader::glTFTexture *_texture);
|
||||
glTFLoader::glTFTexture *getSpecularGlossinessTexture();
|
||||
|
||||
void setDiffuseTexture(glTFTexture* _texture);
|
||||
glTFTexture* getDiffuseTexture();
|
||||
void setDiffuseTexture(glTFLoader::glTFTexture *_texture);
|
||||
glTFLoader::glTFTexture *getDiffuseTexture();
|
||||
|
||||
void setDiffuseFactor(glm::vec4 value);
|
||||
glm::vec4 getDiffuseFactor();
|
||||
|
|
@ -28,24 +27,13 @@ public:
|
|||
void setSpecularFactor(glm::vec3 value);
|
||||
glm::vec3 getSpecularFactor();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
glTFTexture* m_specularGlossinessTexture = nullptr;
|
||||
glTFTexture* m_diffuseTexture = nullptr;
|
||||
glTFLoader::glTFTexture *m_specularGlossinessTexture = nullptr;
|
||||
glTFLoader::glTFTexture *m_diffuseTexture = nullptr;
|
||||
glm::vec4 m_diffuseFactor = glm::vec4(1.0f);
|
||||
glm::vec3 m_specularFactor = glm::vec3(0.0f);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
GLTFLOADER_NAMESPACE_END
|
||||
|
||||
|
||||
|
||||
PBR_NAMESPACE_END
|
||||
|
||||
#endif // !PbrTextureExtension_h
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include "PbrWorkFlow.h"
|
||||
|
||||
GLTFLOADER_NAMESPACE_BEGIN
|
||||
PBR_NAMESPACE_BEGIN
|
||||
|
||||
PbrWorkFlow::PbrWorkFlow()
|
||||
{
|
||||
|
|
@ -32,4 +32,4 @@ bool PbrWorkFlow::getSpecularGlossiness()
|
|||
|
||||
|
||||
|
||||
GLTFLOADER_NAMESPACE_END
|
||||
PBR_NAMESPACE_END
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
#ifndef PBRWORKFLOW_H
|
||||
#define PBRWORKFLOW_H
|
||||
|
||||
#include "glTFModel_Marco.h"
|
||||
#include "PbrMarco.h"
|
||||
|
||||
GLTFLOADER_NAMESPACE_BEGIN
|
||||
PBR_NAMESPACE_BEGIN
|
||||
|
||||
class PbrWorkFlow
|
||||
{
|
||||
|
|
@ -18,16 +18,10 @@ public:
|
|||
bool getSpecularGlossiness();
|
||||
|
||||
private:
|
||||
|
||||
bool m_metallicRoughness = true;
|
||||
bool m_specularGlossiness = false;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
GLTFLOADER_NAMESPACE_END
|
||||
|
||||
PBR_NAMESPACE_END
|
||||
|
||||
#endif // !PBRWORKFLOW_H
|
||||
|
|
|
|||
|
|
@ -1,5 +1,12 @@
|
|||
#include "IrradiancePushBlock.h"
|
||||
|
||||
IrradiancePushBlock::IrradiancePushBlock()
|
||||
{
|
||||
}
|
||||
IrradiancePushBlock::~IrradiancePushBlock()
|
||||
{
|
||||
}
|
||||
|
||||
// Getter method definitions
|
||||
float IrradiancePushBlock::getDeltaPhi() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,45 +1,45 @@
|
|||
#include "RenderSceneTextures.h"
|
||||
|
||||
// Getters
|
||||
vks::TextureCubeMap &RenderSceneTextures::getEnvironmentCube()
|
||||
VulkanBase::TextureCubeMap &RenderSceneTextures::getEnvironmentCube()
|
||||
{
|
||||
return m_environmentCube;
|
||||
}
|
||||
vks::Texture2D &RenderSceneTextures::getEmpty()
|
||||
VulkanBase::Texture2D &RenderSceneTextures::getEmpty()
|
||||
{
|
||||
return m_empty;
|
||||
}
|
||||
vks::Texture2D &RenderSceneTextures::getLutBrdf()
|
||||
VulkanBase::Texture2D &RenderSceneTextures::getLutBrdf()
|
||||
{
|
||||
return m_lutBrdf;
|
||||
}
|
||||
vks::TextureCubeMap &RenderSceneTextures::getIrradianceCube()
|
||||
VulkanBase::TextureCubeMap &RenderSceneTextures::getIrradianceCube()
|
||||
{
|
||||
return m_irradianceCube;
|
||||
}
|
||||
vks::TextureCubeMap &RenderSceneTextures::getPrefilteredCube()
|
||||
VulkanBase::TextureCubeMap &RenderSceneTextures::getPrefilteredCube()
|
||||
{
|
||||
return m_prefilteredCube;
|
||||
}
|
||||
|
||||
// Setters
|
||||
void RenderSceneTextures::setEnvironmentCube(const vks::TextureCubeMap &texture)
|
||||
void RenderSceneTextures::setEnvironmentCube(const VulkanBase::TextureCubeMap &texture)
|
||||
{
|
||||
m_environmentCube = texture;
|
||||
}
|
||||
void RenderSceneTextures::setEmpty(const vks::Texture2D &texture)
|
||||
void RenderSceneTextures::setEmpty(const VulkanBase::Texture2D &texture)
|
||||
{
|
||||
m_empty = texture;
|
||||
}
|
||||
void RenderSceneTextures::setLutBrdf(const vks::Texture2D &texture)
|
||||
void RenderSceneTextures::setLutBrdf(const VulkanBase::Texture2D &texture)
|
||||
{
|
||||
m_lutBrdf = texture;
|
||||
}
|
||||
void RenderSceneTextures::setIrradianceCube(const vks::TextureCubeMap &texture)
|
||||
void RenderSceneTextures::setIrradianceCube(const VulkanBase::TextureCubeMap &texture)
|
||||
{
|
||||
m_irradianceCube = texture;
|
||||
}
|
||||
void RenderSceneTextures::setPrefilteredCube(const vks::TextureCubeMap &texture)
|
||||
void RenderSceneTextures::setPrefilteredCube(const VulkanBase::TextureCubeMap &texture)
|
||||
{
|
||||
m_prefilteredCube = texture;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <VulkanTexture.hpp>
|
||||
#include <VulkanTexture.h>
|
||||
|
||||
class RenderSceneTextures
|
||||
{
|
||||
|
|
@ -9,18 +9,18 @@ public:
|
|||
~RenderSceneTextures();
|
||||
|
||||
// Getters
|
||||
vks::TextureCubeMap &getEnvironmentCube();
|
||||
vks::Texture2D &getEmpty();
|
||||
vks::Texture2D &getLutBrdf();
|
||||
vks::TextureCubeMap &getIrradianceCube();
|
||||
vks::TextureCubeMap &getPrefilteredCube();
|
||||
VulkanBase::TextureCubeMap &getEnvironmentCube();
|
||||
VulkanBase::Texture2D &getEmpty();
|
||||
VulkanBase::Texture2D &getLutBrdf();
|
||||
VulkanBase::TextureCubeMap &getIrradianceCube();
|
||||
VulkanBase::TextureCubeMap &getPrefilteredCube();
|
||||
|
||||
// Setters
|
||||
void setEnvironmentCube(const vks::TextureCubeMap &texture);
|
||||
void setEmpty(const vks::Texture2D &texture);
|
||||
void setLutBrdf(const vks::Texture2D &texture);
|
||||
void setIrradianceCube(const vks::TextureCubeMap &texture);
|
||||
void setPrefilteredCube(const vks::TextureCubeMap &texture);
|
||||
void setEnvironmentCube(const VulkanBase::TextureCubeMap &texture);
|
||||
void setEmpty(const VulkanBase::Texture2D &texture);
|
||||
void setLutBrdf(const VulkanBase::Texture2D &texture);
|
||||
void setIrradianceCube(const VulkanBase::TextureCubeMap &texture);
|
||||
void setPrefilteredCube(const VulkanBase::TextureCubeMap &texture);
|
||||
|
||||
// destroy
|
||||
void destroyEnvironmentCube();
|
||||
|
|
@ -30,9 +30,9 @@ public:
|
|||
void destroyPrefilteredCube();
|
||||
|
||||
private:
|
||||
vks::TextureCubeMap m_environmentCube;
|
||||
vks::Texture2D m_empty;
|
||||
vks::Texture2D m_lutBrdf;
|
||||
vks::TextureCubeMap m_irradianceCube;
|
||||
vks::TextureCubeMap m_prefilteredCube;
|
||||
VulkanBase::TextureCubeMap m_environmentCube;
|
||||
VulkanBase::Texture2D m_empty;
|
||||
VulkanBase::Texture2D m_lutBrdf;
|
||||
VulkanBase::TextureCubeMap m_irradianceCube;
|
||||
VulkanBase::TextureCubeMap m_prefilteredCube;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
#define TINYGLTF_IMPLEMENTATION
|
||||
#include "render.h"
|
||||
|
||||
#include "PbrBaseTexture.h"
|
||||
#include "PbrTextureCoordSet.h"
|
||||
#include "glTFMainModel.h"
|
||||
|
||||
#include "PushConstBlockMaterial.h"
|
||||
#include "VulkanTexture.hpp"
|
||||
#include "glTFModel.h"
|
||||
#include "ShaderLoader.h"
|
||||
#include "VulkanTexture.h"
|
||||
|
||||
#include "glTFMaterial.h"
|
||||
#include "glTFPrimitive.h"
|
||||
#include "glTFSkin.h"
|
||||
#include "glTFTexture.h"
|
||||
#include "glm/gtc/matrix_transform.hpp"
|
||||
#include "renderUniformBufferSet.h"
|
||||
#include "vulkan/vulkan_core.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
#endif
|
||||
#ifndef STB_IMAGE_IMPLEMENTATION
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#endif
|
||||
|
|
@ -21,7 +29,6 @@
|
|||
#define TINYGLTF_NO_STB_IMAGE_WRITE
|
||||
#endif
|
||||
|
||||
#include "render.h"
|
||||
// #include "VulkanUtils.hpp"
|
||||
// #include "assetLoader.h"
|
||||
|
||||
|
|
@ -30,21 +37,21 @@ PlumageRender::PlumageRender()
|
|||
title = "plumage render";
|
||||
}
|
||||
|
||||
void PlumageRender::renderNode(glTFModel::Node *node, uint32_t cbIndex, glTFModel::Material::AlphaMode alphaMode)
|
||||
void PlumageRender::renderNode(glTFLoader::glTFNode *node, uint32_t cbIndex, glTFLoader::AlphaMode alphaMode)
|
||||
{
|
||||
if (node->mesh)
|
||||
if (node->getMesh())
|
||||
{
|
||||
// Render mesh primitives
|
||||
for (glTFModel::Primitive *primitive : node->mesh->primitives)
|
||||
for (glTFLoader::glTFPrimitive *primitive : node->getMesh()->getPrimitives())
|
||||
{
|
||||
if (primitive->material.alphaMode == alphaMode)
|
||||
if (primitive->getGltfMaterial().getAlphaMode() == alphaMode)
|
||||
{
|
||||
VkPipeline pipeline = VK_NULL_HANDLE;
|
||||
switch (alphaMode)
|
||||
{
|
||||
case glTFModel::Material::ALPHAMODE_OPAQUE:
|
||||
case glTFModel::Material::ALPHAMODE_MASK:
|
||||
if (primitive->material.doubleSided)
|
||||
case glTFLoader::ALPHAMODE_OPAQUE:
|
||||
case glTFLoader::ALPHAMODE_MASK:
|
||||
if (primitive->getGltfMaterial().getDoublesided())
|
||||
{
|
||||
pipeline = m_pipelineList.getPbrDoubleSided();
|
||||
}
|
||||
|
|
@ -53,7 +60,7 @@ void PlumageRender::renderNode(glTFModel::Node *node, uint32_t cbIndex, glTFMode
|
|||
pipeline = m_pipelineList.getPbr();
|
||||
}
|
||||
break;
|
||||
case glTFModel::Material::ALPHAMODE_BLEND:
|
||||
case glTFLoader::ALPHAMODE_BLEND:
|
||||
pipeline = m_pipelineList.getPbrAlphaBlend();
|
||||
break;
|
||||
}
|
||||
|
|
@ -66,78 +73,81 @@ void PlumageRender::renderNode(glTFModel::Node *node, uint32_t cbIndex, glTFMode
|
|||
|
||||
const std::vector<VkDescriptorSet> descriptorsets = {
|
||||
descriptorSets[cbIndex].getScene(),
|
||||
primitive->material.descriptorSet,
|
||||
node->mesh->uniformBuffer.descriptorSet,
|
||||
primitive->getGltfMaterial().getDescriptorSet(),
|
||||
node->getMesh()->getUniformBuffer().descriptorSet,
|
||||
};
|
||||
vkCmdBindDescriptorSets(commandBuffers[cbIndex], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, static_cast<uint32_t>(descriptorsets.size()), descriptorsets.data(), 0, NULL);
|
||||
|
||||
// Pass material parameters as push constants
|
||||
PushConstBlockMaterial m_pushConstBlockMaterial;
|
||||
m_pushConstBlockMaterial.setEmissiveFactor(primitive->material.emissiveFactor);
|
||||
PBR::PbrBaseTexture *pbrBaseTexture = primitive->getGltfMaterial().getPbrBaseTexture();
|
||||
glTFLoader::TextureCoordSet *texCoordSet = primitive->getGltfMaterial().getTextureCoordSet();
|
||||
m_pushConstBlockMaterial.setEmissiveFactor(pbrBaseTexture->getEmissiveFactor());
|
||||
// To save push constant space, availabilty and texture coordiante set are combined
|
||||
// -1 = texture not used for this material, >= 0 texture used and index of texture coordinate set
|
||||
if (primitive->material.baseColorTexture != nullptr)
|
||||
if (pbrBaseTexture->getBaseColorTexture() != nullptr)
|
||||
{
|
||||
|
||||
m_pushConstBlockMaterial.setColorTextureSet(primitive->material.texCoordSets.baseColor);
|
||||
m_pushConstBlockMaterial.setColorTextureSet(texCoordSet->getBaseColor());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pushConstBlockMaterial.setColorTextureSet(-1);
|
||||
}
|
||||
|
||||
if (primitive->material.normalTexture != nullptr)
|
||||
if (pbrBaseTexture->getNormalTexture() != nullptr)
|
||||
{
|
||||
m_pushConstBlockMaterial.setNormalTextureSet(primitive->material.texCoordSets.normal);
|
||||
m_pushConstBlockMaterial.setNormalTextureSet(texCoordSet->getNormal());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pushConstBlockMaterial.setNormalTextureSet(-1);
|
||||
}
|
||||
if (primitive->material.occlusionTexture != nullptr)
|
||||
if (pbrBaseTexture->getOcclusionTexture() != nullptr)
|
||||
{
|
||||
m_pushConstBlockMaterial.setOcclusionTextureSet(primitive->material.texCoordSets.occlusion);
|
||||
m_pushConstBlockMaterial.setOcclusionTextureSet(texCoordSet->getOcclusion());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pushConstBlockMaterial.setOcclusionTextureSet(-1);
|
||||
}
|
||||
|
||||
if (primitive->material.emissiveTexture != nullptr)
|
||||
if (pbrBaseTexture->getEmissiveTexture() != nullptr)
|
||||
{
|
||||
m_pushConstBlockMaterial.setEmissiveTextureSet(primitive->material.texCoordSets.emissive);
|
||||
m_pushConstBlockMaterial.setEmissiveTextureSet(texCoordSet->getEmissive());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pushConstBlockMaterial.setEmissiveTextureSet(-1);
|
||||
}
|
||||
if (primitive->material.alphaMode == glTFModel::Material::ALPHAMODE_MASK)
|
||||
if (primitive->getGltfMaterial().getAlphaMode() == glTFLoader::ALPHAMODE_MASK)
|
||||
{
|
||||
m_pushConstBlockMaterial.setAlphaMask(static_cast<float>(primitive->material.alphaMode));
|
||||
m_pushConstBlockMaterial.setAlphaMask(static_cast<float>(primitive->getGltfMaterial().getAlphaMode()));
|
||||
}
|
||||
m_pushConstBlockMaterial.setAlphaMaskCutoff(primitive->material.alphaCutoff);
|
||||
m_pushConstBlockMaterial.setAlphaMaskCutoff(primitive->getGltfMaterial().getAlphaCutOff());
|
||||
|
||||
// TODO: glTF specs states that metallic roughness should be preferred, even if specular glosiness is present
|
||||
|
||||
if (primitive->material.pbrWorkflows.metallicRoughness)
|
||||
glTFLoader::glTFMaterial *material = &primitive->getGltfMaterial();
|
||||
if (material->getPbrWorkFlow()->getMetallicRoughness())
|
||||
{
|
||||
// Metallic roughness workflow
|
||||
m_pushConstBlockMaterial.setWorkflow(static_cast<float>(PBR_WORKFLOW_METALLIC_ROUGHNESS));
|
||||
m_pushConstBlockMaterial.setBaseColorFactor(primitive->material.baseColorFactor);
|
||||
m_pushConstBlockMaterial.setMetallicFactor(primitive->material.metallicFactor);
|
||||
m_pushConstBlockMaterial.setRoughnessFactor(primitive->material.roughnessFactor);
|
||||
if (primitive->material.metallicRoughnessTexture != nullptr)
|
||||
m_pushConstBlockMaterial.setBaseColorFactor(pbrBaseTexture->getBaseColorFactor());
|
||||
m_pushConstBlockMaterial.setMetallicFactor(pbrBaseTexture->getMetallicFactor());
|
||||
m_pushConstBlockMaterial.setRoughnessFactor(pbrBaseTexture->getRoughnessFactor());
|
||||
if (pbrBaseTexture->getMetalicRoughnessTexture() != nullptr)
|
||||
{
|
||||
m_pushConstBlockMaterial.setPhysicalDescriptorTextureSet(primitive->material.texCoordSets.metallicRoughness);
|
||||
m_pushConstBlockMaterial.setPhysicalDescriptorTextureSet(texCoordSet->getMetallicRoughness());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pushConstBlockMaterial.setPhysicalDescriptorTextureSet(-1);
|
||||
}
|
||||
|
||||
if (primitive->material.baseColorTexture != nullptr)
|
||||
if (pbrBaseTexture->getBaseColorTexture() != nullptr)
|
||||
{
|
||||
m_pushConstBlockMaterial.setColorTextureSet(primitive->material.texCoordSets.baseColor);
|
||||
m_pushConstBlockMaterial.setColorTextureSet(texCoordSet->getBaseColor());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -145,47 +155,49 @@ void PlumageRender::renderNode(glTFModel::Node *node, uint32_t cbIndex, glTFMode
|
|||
}
|
||||
}
|
||||
|
||||
if (primitive->material.pbrWorkflows.specularGlossiness)
|
||||
if (material->getPbrWorkFlow()->getSpecularGlossiness())
|
||||
{
|
||||
|
||||
// Specular glossiness workflow
|
||||
m_pushConstBlockMaterial.setWorkflow(static_cast<float>(PBR_WORKFLOW_SPECULAR_GLOSINESS));
|
||||
if (primitive->material.extension.specularGlossinessTexture != nullptr)
|
||||
if (material->getTextureExtension()->getSpecularGlossinessTexture() != nullptr)
|
||||
{
|
||||
m_pushConstBlockMaterial.setPhysicalDescriptorTextureSet(primitive->material.texCoordSets.specularGlossiness);
|
||||
m_pushConstBlockMaterial.setPhysicalDescriptorTextureSet(texCoordSet->getSpecularGlossiness());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pushConstBlockMaterial.setPhysicalDescriptorTextureSet(-1);
|
||||
}
|
||||
|
||||
if (primitive->material.extension.diffuseTexture != nullptr)
|
||||
if (material->getTextureExtension()->getDiffuseTexture() != nullptr)
|
||||
{
|
||||
m_pushConstBlockMaterial.setColorTextureSet(primitive->material.texCoordSets.baseColor);
|
||||
m_pushConstBlockMaterial.setColorTextureSet(texCoordSet->getBaseColor());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pushConstBlockMaterial.setColorTextureSet(-1);
|
||||
}
|
||||
|
||||
m_pushConstBlockMaterial.setDiffuseFactor(primitive->material.extension.diffuseFactor);
|
||||
m_pushConstBlockMaterial.setSpecularFactor(glm::vec4(primitive->material.extension.specularFactor, 1.0f));
|
||||
m_pushConstBlockMaterial.setDiffuseFactor(material->getTextureExtension()->getDiffuseFactor());
|
||||
m_pushConstBlockMaterial.setSpecularFactor(glm::vec4(material->getTextureExtension()->getSpecularFactor(), 1.0f));
|
||||
}
|
||||
|
||||
vkCmdPushConstants(commandBuffers[cbIndex], pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstBlockMaterial), &m_pushConstBlockMaterial);
|
||||
|
||||
if (primitive->hasIndices)
|
||||
if (primitive->getHasIndices())
|
||||
{
|
||||
vkCmdDrawIndexed(commandBuffers[cbIndex], primitive->indexCount, 1, primitive->firstIndex, 0, 0);
|
||||
vkCmdDrawIndexed(commandBuffers[cbIndex], primitive->getIndexCount(), 1, primitive->getFirstIndex(), 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
vkCmdDraw(commandBuffers[cbIndex], primitive->vertexCount, 1, 0, 0);
|
||||
vkCmdDraw(commandBuffers[cbIndex], primitive->getVertexCount(), 1, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
for (auto child : node->children)
|
||||
|
||||
std::vector<glTFLoader::glTFNode *> nodeChildren = node->getChildren();
|
||||
for (auto child : nodeChildren)
|
||||
{
|
||||
renderNode(child, cbIndex, alphaMode);
|
||||
}
|
||||
|
|
@ -249,12 +261,12 @@ void PlumageRender::buildCommandBuffers()
|
|||
m_sceneModel.getSkyBox().draw(currentCB);
|
||||
}
|
||||
|
||||
glTFModel::Model &model = m_sceneModel.getScene();
|
||||
glTFLoader::glTFMainModel &model = m_sceneModel.getScene();
|
||||
|
||||
vkCmdBindVertexBuffers(currentCB, 0, 1, &model.vertices.buffer, offsets);
|
||||
if (model.indices.buffer != VK_NULL_HANDLE)
|
||||
vkCmdBindVertexBuffers(currentCB, 0, 1, &model.getModelVertex().buffer, offsets);
|
||||
if (model.getModelIndex().buffer != VK_NULL_HANDLE)
|
||||
{
|
||||
vkCmdBindIndexBuffer(currentCB, model.indices.buffer, 0, VK_INDEX_TYPE_UINT32);
|
||||
vkCmdBindIndexBuffer(currentCB, model.getModelIndex().buffer, 0, VK_INDEX_TYPE_UINT32);
|
||||
}
|
||||
|
||||
boundPipeline = VK_NULL_HANDLE;
|
||||
|
|
@ -329,7 +341,7 @@ void PlumageRender::loadAssets()
|
|||
std::cout << msg << std::endl;
|
||||
}
|
||||
|
||||
readDirectory(assetpath + "environments", "*.ktx", environments, false);
|
||||
ShaderLoader::readDirectory(assetpath + "environments", "*.ktx", environments, false);
|
||||
|
||||
m_sceneTextures.getEmpty().loadFromFile(PlumageRender::m_configFilePath.getEmptyEnvmapFilePath(), VK_FORMAT_R8G8B8A8_UNORM, vulkanDevice, queue);
|
||||
|
||||
|
|
@ -459,7 +471,7 @@ void PlumageRender::setupDescriptors()
|
|||
VkDescriptorSetLayout sceneDescriptorSetLayout = m_descriptorSetLayoutList.getScene();
|
||||
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &sceneDescriptorSetLayout));
|
||||
|
||||
vks::TextureCubeMap refIrradianceCube = m_sceneTextures.getIrradianceCube();
|
||||
VulkanBase::TextureCubeMap refIrradianceCube = m_sceneTextures.getIrradianceCube();
|
||||
for (auto i = 0; i < descriptorSets.size(); i++)
|
||||
{
|
||||
|
||||
|
|
@ -605,7 +617,7 @@ void PlumageRender::setupDescriptors()
|
|||
}
|
||||
}
|
||||
|
||||
vks::TextureCubeMap refPrefilterCube = m_sceneTextures.getPrefilteredCube();
|
||||
VulkanBase::TextureCubeMap refPrefilterCube = m_sceneTextures.getPrefilteredCube();
|
||||
// Skybox (fixed set)
|
||||
for (auto i = 0; i < uniformBuffers.size(); i++)
|
||||
{
|
||||
|
|
@ -752,8 +764,8 @@ void PlumageRender::preparePipelines()
|
|||
|
||||
// Skybox pipeline (background cube)
|
||||
shaderStages = {
|
||||
loadShader(device, m_configFilePath.getSkyboxVertShaderPath(), VK_SHADER_STAGE_VERTEX_BIT),
|
||||
loadShader(device, m_configFilePath.getSkyboxFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT)};
|
||||
ShaderLoader::loadShader(device, m_configFilePath.getSkyboxVertShaderPath(), VK_SHADER_STAGE_VERTEX_BIT),
|
||||
ShaderLoader::loadShader(device, m_configFilePath.getSkyboxFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT)};
|
||||
VkPipeline skyboxPipeline = m_pipelineList.getSkybox();
|
||||
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &skyboxPipeline));
|
||||
for (auto shaderStage : shaderStages)
|
||||
|
|
@ -763,8 +775,8 @@ void PlumageRender::preparePipelines()
|
|||
|
||||
// PBR pipeline
|
||||
shaderStages = {
|
||||
loadShader(device, m_configFilePath.getPbrVertShaderPath(), VK_SHADER_STAGE_VERTEX_BIT),
|
||||
loadShader(device, m_configFilePath.getPbrFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT)};
|
||||
ShaderLoader::loadShader(device, m_configFilePath.getPbrVertShaderPath(), VK_SHADER_STAGE_VERTEX_BIT),
|
||||
ShaderLoader::loadShader(device, m_configFilePath.getPbrFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT)};
|
||||
depthStencilStateCI.depthWriteEnable = VK_TRUE;
|
||||
depthStencilStateCI.depthTestEnable = VK_TRUE;
|
||||
VkPipeline pbrPipeline = m_pipelineList.getPbr();
|
||||
|
|
@ -807,7 +819,7 @@ void PlumageRender::generateCubemaps()
|
|||
for (uint32_t target = 0; target < PREFILTEREDENV + 1; target++)
|
||||
{
|
||||
|
||||
vks::TextureCubeMap cubemap;
|
||||
VulkanBase::TextureCubeMap cubemap;
|
||||
|
||||
auto tStart = std::chrono::high_resolution_clock::now();
|
||||
|
||||
|
|
@ -1132,14 +1144,14 @@ void PlumageRender::generateCubemaps()
|
|||
pipelineCI.pStages = shaderStages.data();
|
||||
pipelineCI.renderPass = renderpass;
|
||||
|
||||
shaderStages[0] = loadShader(device, m_configFilePath.getFilterVertShaderPath(), VK_SHADER_STAGE_VERTEX_BIT);
|
||||
shaderStages[0] = ShaderLoader::loadShader(device, m_configFilePath.getFilterVertShaderPath(), VK_SHADER_STAGE_VERTEX_BIT);
|
||||
switch (target)
|
||||
{
|
||||
case IRRADIANCE:
|
||||
shaderStages[1] = loadShader(device, m_configFilePath.getIrradianceFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
shaderStages[1] = ShaderLoader::loadShader(device, m_configFilePath.getIrradianceFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
break;
|
||||
case PREFILTEREDENV:
|
||||
shaderStages[1] = loadShader(device, m_configFilePath.getPrefilterEnvmapFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
shaderStages[1] = ShaderLoader::loadShader(device, m_configFilePath.getPrefilterEnvmapFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
break;
|
||||
};
|
||||
VkPipeline pipeline;
|
||||
|
|
@ -1360,7 +1372,7 @@ void PlumageRender::generateBRDFLUT()
|
|||
|
||||
const VkFormat format = VK_FORMAT_R16G16_SFLOAT;
|
||||
const int32_t dim = 2048;
|
||||
vks::Texture2D RefLutBrdfTex = m_sceneTextures.getLutBrdf();
|
||||
VulkanBase::Texture2D RefLutBrdfTex = m_sceneTextures.getLutBrdf();
|
||||
|
||||
// Image
|
||||
VkImageCreateInfo imageCI{};
|
||||
|
|
@ -1553,8 +1565,8 @@ void PlumageRender::generateBRDFLUT()
|
|||
|
||||
// Look-up-table (from BRDF) pipeline
|
||||
shaderStages = {
|
||||
loadShader(device, m_configFilePath.getBrdfVertShaderPath(), VK_SHADER_STAGE_VERTEX_BIT),
|
||||
loadShader(device, m_configFilePath.getBrdfFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT)};
|
||||
ShaderLoader::loadShader(device, m_configFilePath.getBrdfVertShaderPath(), VK_SHADER_STAGE_VERTEX_BIT),
|
||||
ShaderLoader::loadShader(device, m_configFilePath.getBrdfFragShaderPath(), VK_SHADER_STAGE_FRAGMENT_BIT)};
|
||||
VkPipeline pipeline;
|
||||
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipeline));
|
||||
for (auto shaderStage : shaderStages)
|
||||
|
|
@ -2264,9 +2276,8 @@ void PlumageRender::updateUIOverlay()
|
|||
if (!filename.empty())
|
||||
{
|
||||
vkDeviceWaitIdle(device);
|
||||
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
|
||||
std::string stringFilename = std::filesystem::path(filename).string();
|
||||
|
||||
std::string stringFilename = converter.to_bytes(filename);
|
||||
loadScene(stringFilename);
|
||||
setupDescriptors();
|
||||
updateCBs = true;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
#include "RenderOffScreen.h"
|
||||
#include "RenderPipelineList.h"
|
||||
#include "RenderSceneTextures.h"
|
||||
#include "glTFMaterial.h"
|
||||
#include "glTFSkin.h"
|
||||
#include "renderShaderData.h"
|
||||
#if defined(_WIN32)
|
||||
#include <direct.h>
|
||||
|
|
@ -36,8 +38,7 @@
|
|||
#include "VulkanExampleBase.h"
|
||||
#include "glTFModel.h"
|
||||
#include "ui.hpp"
|
||||
#include <VulkanTexture.hpp>
|
||||
#include <VulkanUtils.hpp>
|
||||
#include <VulkanTexture.h>
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#define ENABLE_VALIDATION false
|
||||
|
|
@ -55,6 +56,7 @@
|
|||
#include "RenderPipelineList.h"
|
||||
#include "RenderSceneTextures.h"
|
||||
#include "SceneUBOMatrices.h"
|
||||
#include "ShaderLoader.h"
|
||||
#include "SkyboxUBOMatrices.h"
|
||||
#include "VertexStagingBuffer.h"
|
||||
#include "renderEffectState.h"
|
||||
|
|
@ -184,7 +186,7 @@ public:
|
|||
delete gui;
|
||||
}
|
||||
|
||||
void renderNode(glTFModel::Node *node, uint32_t cbIndex, glTFModel::Material::AlphaMode alphaMode);
|
||||
void renderNode(glTFLoader::glTFNode *node, uint32_t cbIndex, glTFLoader::AlphaMode alphaMode);
|
||||
void loadScene(std::string filename);
|
||||
void loadEnvironment(std::string filename);
|
||||
void buildCommandBuffers();
|
||||
|
|
|
|||
|
|
@ -9,22 +9,22 @@ RenderSceneModel::~RenderSceneModel()
|
|||
{
|
||||
}
|
||||
|
||||
void RenderSceneModel::setScene(glTFModel::Model value)
|
||||
void RenderSceneModel::setScene(glTFLoader::glTFMainModel value)
|
||||
{
|
||||
m_scene = value;
|
||||
}
|
||||
|
||||
glTFModel::Model &RenderSceneModel::getScene()
|
||||
glTFLoader::glTFMainModel &RenderSceneModel::getScene()
|
||||
{
|
||||
return m_scene;
|
||||
}
|
||||
|
||||
void RenderSceneModel::setSkyBox(glTFModel::Model value)
|
||||
void RenderSceneModel::setSkyBox(glTFLoader::glTFMainModel value)
|
||||
{
|
||||
m_skybox = value;
|
||||
}
|
||||
|
||||
glTFModel::Model &RenderSceneModel::getSkyBox()
|
||||
glTFLoader::glTFMainModel &RenderSceneModel::getSkyBox()
|
||||
{
|
||||
return m_skybox;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "glTFModel.h"
|
||||
#include "vulkan/vulkan.h"
|
||||
#include "glTFMainModel.h"
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
class RenderSceneModel
|
||||
{
|
||||
|
|
@ -9,16 +9,16 @@ public:
|
|||
RenderSceneModel();
|
||||
~RenderSceneModel();
|
||||
|
||||
void setScene(glTFModel::Model value);
|
||||
glTFModel::Model &getScene();
|
||||
void setScene(glTFLoader::glTFMainModel value);
|
||||
glTFLoader::glTFMainModel &getScene();
|
||||
|
||||
void setSkyBox(glTFModel::Model value);
|
||||
glTFModel::Model &getSkyBox();
|
||||
void setSkyBox(glTFLoader::glTFMainModel value);
|
||||
glTFLoader::glTFMainModel &getSkyBox();
|
||||
|
||||
void destroyScene(VkDevice device);
|
||||
void destroySkyBox(VkDevice device);
|
||||
|
||||
private:
|
||||
glTFModel::Model m_scene;
|
||||
glTFModel::Model m_skybox;
|
||||
glTFLoader::glTFMainModel m_scene;
|
||||
glTFLoader::glTFMainModel m_skybox;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -9,33 +9,33 @@ RenderUniformBufferSet::~RenderUniformBufferSet()
|
|||
}
|
||||
|
||||
// Getter method definitions
|
||||
Buffer &RenderUniformBufferSet::getScene()
|
||||
VulkanBase::Buffer &RenderUniformBufferSet::getScene()
|
||||
{
|
||||
return scene;
|
||||
}
|
||||
|
||||
Buffer &RenderUniformBufferSet::getSkybox()
|
||||
VulkanBase::Buffer &RenderUniformBufferSet::getSkybox()
|
||||
{
|
||||
return skybox;
|
||||
}
|
||||
|
||||
Buffer &RenderUniformBufferSet::getParams()
|
||||
VulkanBase::Buffer &RenderUniformBufferSet::getParams()
|
||||
{
|
||||
return params;
|
||||
}
|
||||
|
||||
// Setter method definitions
|
||||
void RenderUniformBufferSet::setScene(Buffer &buffer)
|
||||
void RenderUniformBufferSet::setScene(VulkanBase::Buffer &buffer)
|
||||
{
|
||||
scene = buffer;
|
||||
}
|
||||
|
||||
void RenderUniformBufferSet::setSkybox(Buffer &buffer)
|
||||
void RenderUniformBufferSet::setSkybox(VulkanBase::Buffer &buffer)
|
||||
{
|
||||
skybox = buffer;
|
||||
}
|
||||
|
||||
void RenderUniformBufferSet::setParams(Buffer &buffer)
|
||||
void RenderUniformBufferSet::setParams(VulkanBase::Buffer &buffer)
|
||||
{
|
||||
params = buffer;
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
#ifndef RENDER_UNIFORM_BUFFER_SET_H
|
||||
#define RENDER_UNIFORM_BUFFER_SET_H
|
||||
|
||||
#include "VulkanUtils.hpp"
|
||||
#include "VulkanBuffer.h"
|
||||
|
||||
class RenderUniformBufferSet
|
||||
{
|
||||
|
|
@ -9,17 +10,19 @@ public:
|
|||
~RenderUniformBufferSet();
|
||||
|
||||
// Getter methods
|
||||
Buffer &getScene();
|
||||
Buffer &getSkybox();
|
||||
Buffer &getParams();
|
||||
VulkanBase::Buffer &getScene();
|
||||
VulkanBase::Buffer &getSkybox();
|
||||
VulkanBase::Buffer &getParams();
|
||||
|
||||
// Setter methods
|
||||
void setScene(Buffer &buffer);
|
||||
void setSkybox(Buffer &buffer);
|
||||
void setParams(Buffer &buffer);
|
||||
void setScene(VulkanBase::Buffer &buffer);
|
||||
void setSkybox(VulkanBase::Buffer &buffer);
|
||||
void setParams(VulkanBase::Buffer &buffer);
|
||||
|
||||
private:
|
||||
Buffer scene;
|
||||
Buffer skybox;
|
||||
Buffer params;
|
||||
VulkanBase::Buffer scene;
|
||||
VulkanBase::Buffer skybox;
|
||||
VulkanBase::Buffer params;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -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