完成gltfTexture重构

reconstruct-gltfLoader
InkSoul 2025-04-05 21:07:56 +08:00
parent e43f2e1aac
commit 7f3056d2fe
12 changed files with 807 additions and 16 deletions

View File

@ -1,4 +1,4 @@

SET(PLUMAGE_RENDER "${CMAKE_CURRENT_SOURCE_DIR}/render") SET(PLUMAGE_RENDER "${CMAKE_CURRENT_SOURCE_DIR}/render")
message("working path ${PLUMAGE_RENDER}") message("working path ${PLUMAGE_RENDER}")
@ -11,6 +11,18 @@ set(MAIN_FILE
set(GLTF_MODEL_LOADER set(GLTF_MODEL_LOADER
"${PLUMAGE_RENDER}/glTFBoundingBox.h" "${PLUMAGE_RENDER}/glTFBoundingBox.h"
"${PLUMAGE_RENDER}/glTFBoundingBox.cpp" "${PLUMAGE_RENDER}/glTFBoundingBox.cpp"
"${PLUMAGE_RENDER}/glTFTexture.h"
"${PLUMAGE_RENDER}/glTFTexture.cpp"
"render/glTFModel.h"
"render/glTFModel.cpp"
)
set(VULKAN_BASE
"render/VulkanBase_Common.h"
"render/VulkanDevice.h"
"render/VulkanDevice.cpp"
"render/VulkanTextureSampler.h"
"render/VulkanTextureSampler.cpp"
) )
# wayland requires additional source files # wayland requires additional source files
@ -27,6 +39,8 @@ ENDIF()
# Add optional readme / tutorial # Add optional readme / tutorial
#file(GLOB README_FILES "${HOMEWORK_FOLDER}/*.md") #file(GLOB README_FILES "${HOMEWORK_FOLDER}/*.md")
include_directories(${3rdParty_gli_path}) include_directories(${3rdParty_gli_path})
include_directories(${3rdParty_glm_path}) include_directories(${3rdParty_glm_path})
include_directories(${3rdParty_imgui_path}) include_directories(${3rdParty_imgui_path})
@ -43,10 +57,11 @@ if(WIN32)
add_executable(${RenderName} WIN32 ${SHADERS_GLSL} ${SHADERS_HLSL} add_executable(${RenderName} WIN32 ${SHADERS_GLSL} ${SHADERS_HLSL}
${MAIN_FILE} ${MAIN_FILE}
${GLTF_MODEL_LOADER} ${GLTF_MODEL_LOADER}
"render/glTFModel.h" ${VULKAN_BASE}
"render/glTFModel.cpp"
"render/renderFoundation.h" "render/renderFoundation.h"
"render/renderFoundation.cpp" ) "render/renderFoundation.cpp"
)
target_link_libraries(${RenderName} base ${Vulkan_LIBRARY} ${WINLIBS}) target_link_libraries(${RenderName} base ${Vulkan_LIBRARY} ${WINLIBS})
endif() endif()
set_target_properties(${RenderName} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/bin) set_target_properties(${RenderName} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
@ -56,13 +71,14 @@ if(RESOURCE_INSTALL_DIR)
install(TARGETS ${RenderName} DESTINATION ${CMAKE_INSTALL_BINDIR}) install(TARGETS ${RenderName} DESTINATION ${CMAKE_INSTALL_BINDIR})
endif() endif()
#
#if(WIN32) if(WIN32)
# target_compile_definitions(MyLib PRIVATE MYLIB_EXPORTS) target_compile_definitions(${RenderName} PRIVATE VULKANBASE_STATIC_BUILD)
#endif(UNIX AND NOT APPLE) # Linux target_compile_definitions(${RenderName} PRIVATE GLTFLOADER_STATIC_BUILD)
# add_compile_options(-fvisibility=hidden) elseif(UNIX AND NOT APPLE) # Linux
# add_compile_options(-fvisibility-inlines-hidden) add_compile_options(-fvisibility=hidden)
#endif() add_compile_options(-fvisibility-inlines-hidden)
endif()

View File

@ -1,4 +1,4 @@
file(GLOB BASE_SRC "*.cpp" "*.h" "${3rdParty_imgui_path}/*.cpp" ) file(GLOB BASE_SRC "*.cpp" "*.h" "${3rdParty_imgui_path}/*.cpp" )
include_directories(${3rdParty_ktx_path}) include_directories(${3rdParty_ktx_path})

View File

@ -1,4 +1,4 @@
/* /*
* Vulkan device class * Vulkan device class
* *
* Encapsulates a physical Vulkan device and it's logical representation * Encapsulates a physical Vulkan device and it's logical representation
@ -27,6 +27,8 @@
#include "VulkanTools.h" #include "VulkanTools.h"
/// @brief 已单独剥离,等待删除
namespace vks namespace vks
{ {
struct VulkanDevice struct VulkanDevice

View File

@ -1,4 +1,4 @@

#pragma once #pragma once
#include "vulkan/vulkan.h" #include "vulkan/vulkan.h"

View File

@ -0,0 +1,30 @@
#pragma once
/// 命名空间宏
#define VULKANBASE_NAMESPACE_BEGIN namespace VulkanBase {
#define VULKANBASE_NAMESPACE_END }
/// windows 导入导出宏GLTFLOADER_EXPORTS将在cmake中定义
/// unix-like 下提供符号可见性控制
#ifdef VULKANBASE_STATIC_BUILD
#define VULKANBASE_API
#define VULKANBASE_LOCAL
#else
#ifdef _WIN32
#ifdef VULKANBASE_EXPORTS
#define VULKANBASE_API __declspec(dllexport)
#define VULKANBASE_LOCAL
#else
#define VULKANBASE_API __declspec(dllimport)
#define VULKANBASE_LOCAL
#endif
#else
#if __GNUC__ >= 4 || defined(__clang__)
#define VULKANBASE_API __attribute__ ((visibility ("default")))
#define VULKANBASE_LOCAL __attribute__ ((visibility ("hidden")))
#else
#define VULKANBASE_API
#define VULKANBASE_LOCAL
#endif
#endif
#endif

View File

@ -0,0 +1,213 @@
#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 = nullptr)
{
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 = nullptr)
{
// 创建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 = 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(m_logicalDevice, &cmdPoolInfo, nullptr, &cmdPool));
return cmdPool;
}
VkCommandBuffer VulkanDevice::createCommandBuffer(VkCommandBufferLevel level, bool begin = false)
{
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 = true)
{
VK_CHECK_RESULT(vkEndCommandBuffer(commandBuffer));
VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBuffer;
//创建同步栅栏确保命令buffer执行完毕
VkFenceCreateInfo fenceInfo{};
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
VkFence fence;
VK_CHECK_RESULT(vkCreateFence(m_logicalDevice, &fenceInfo, nullptr, &fence));
// 提交队列
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, fence));
// 等待栅栏发出信号说明命令buffer执行完毕
VK_CHECK_RESULT(vkWaitForFences(m_logicalDevice, 1, &fence, VK_TRUE, 100000000000));
// 同步栅栏使命结束,销毁
vkDestroyFence(m_logicalDevice, fence, nullptr);
// 需要的时候销毁命令buffer
if (free) {
vkFreeCommandBuffers(m_logicalDevice, m_commandPool, 1, &commandBuffer);
}
}
VULKANBASE_NAMESPACE_END

View File

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

View File

@ -0,0 +1,68 @@
#include "VulkanTextureSampler.h"
VULKANBASE_NAMESPACE_BEGIN
VulkanTextureSampler::VulkanTextureSampler()
{
}
VulkanTextureSampler::~VulkanTextureSampler()
{
}
VkFilter VulkanTextureSampler::getMaxFilter()
{
return m_maxFilter;
}
void VulkanTextureSampler::setMaxFilter(VkFilter maxFilter)
{
m_maxFilter = maxFilter;
}
VkFilter VulkanTextureSampler::getMinFilter()
{
return m_minFilter;
}
void VulkanTextureSampler::setMinFilter(VkFilter minFilter)
{
m_minFilter = minFilter;
}
VkSamplerAddressMode VulkanTextureSampler::getAddressModeU()
{
return m_addressModeU;
}
void VulkanTextureSampler::setAddressModeU(VkSamplerAddressMode samplerAddresMode)
{
m_addressModeU = samplerAddresMode;
}
VkSamplerAddressMode VulkanTextureSampler::getAddressModeV()
{
return m_addressModeV;
}
void VulkanTextureSampler::setAddressModeV(VkSamplerAddressMode samplerAddresMode)
{
m_addressModeV = samplerAddresMode;
}
VkSamplerAddressMode VulkanTextureSampler::getAddressModeW()
{
return m_addressModeW;
}
void VulkanTextureSampler::setAddressModeW(VkSamplerAddressMode samplerAddresMode)
{
m_addressModeW = samplerAddresMode;
}
VULKANBASE_NAMESPACE_END

View File

@ -0,0 +1,45 @@
#ifndef VULKANTEXTURESAMPLER_H
#define VULKANTEXTURESAMPLER_H
#include "VulkanBase_Common.h"
#include <vulkan/vulkan.h>
VULKANBASE_NAMESPACE_BEGIN
/// @brief 贴图采样器暂时适用于gltf模型贴图
class VulkanTextureSampler
{
public:
VulkanTextureSampler();
~VulkanTextureSampler();
VkFilter getMaxFilter();
void setMaxFilter(VkFilter maxFilter);
VkFilter getMinFilter();
void setMinFilter(VkFilter minFilter);
VkSamplerAddressMode getAddressModeU();
void setAddressModeU(VkSamplerAddressMode samplerAddresMode);
VkSamplerAddressMode getAddressModeV();
void setAddressModeV(VkSamplerAddressMode samplerAddresMode);
VkSamplerAddressMode getAddressModeW();
void setAddressModeW(VkSamplerAddressMode samplerAddresMode);
private:
VkFilter m_maxFilter;
VkFilter m_minFilter;
VkSamplerAddressMode m_addressModeU;
VkSamplerAddressMode m_addressModeV;
VkSamplerAddressMode m_addressModeW;
};
VULKANBASE_NAMESPACE_END
#endif // !VULKANTEXTURESAMPLER_H

View File

@ -1,4 +1,4 @@
#include "glTFBoundingBox.h" #include "glTFBoundingBox.h"
GLTFLOADER_NAMESPACE_BEGIN GLTFLOADER_NAMESPACE_BEGIN

View File

@ -0,0 +1,270 @@
#include "glTFTexture.h"
#include <VulkanTools.h>
GLTFLOADER_NAMESPACE_BEGIN
glTFTexture::glTFTexture()
{
}
glTFTexture::~glTFTexture()
{
}
void glTFTexture::updateDescriptor()
{
m_descriptor.sampler = m_sampler;
m_descriptor.imageView = m_view;
m_descriptor.imageLayout = m_imageLayout;
}
void glTFTexture::destroy()
{
VkDevice logicalDevice = m_device->getLogicalDevice();
vkDestroyImageView(logicalDevice, m_view, nullptr);
vkDestroyImage(logicalDevice, m_image, nullptr);
vkFreeMemory(logicalDevice, m_deviceMemory, nullptr);
vkDestroySampler(logicalDevice, m_sampler, nullptr);
}
void glTFTexture::fromglTfImage(tinygltf::Image& gltfimage, VulkanBase::VulkanTextureSampler textureSampler, VulkanBase::VulkanDevice* device, VkQueue copyQueue)
{
VkDevice logicalDevice = device->getLogicalDevice();
unsigned char* buffer = nullptr;
VkDeviceSize bufferSize = 0;
bool deleteBuffer = false;
if (gltfimage.component == 3) {
/// 即使创建为24bit的rgb硬件上依旧是rgba因此填充alpha值但带宽压力上升25%
/// 可选todo采用计算着色器将rgb写入uniform buffer
bufferSize = gltfimage.width * gltfimage.height * 4;
buffer = new unsigned char[bufferSize];
unsigned char* rgba = buffer;
unsigned char* rgb = &gltfimage.image[0];
for (int32_t i = 0; i < gltfimage.width * gltfimage.height; ++i) {
for (int32_t j = 0; j < 3; ++j) {
rgba[j] = rgb[j];
}
rgba += 4;
rgb += 3;
}
deleteBuffer = true;
}
else {
buffer = &gltfimage.image[0];
bufferSize = gltfimage.image.size();
}
VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
VkFormatProperties formatProperties;
m_width = gltfimage.width;
m_height = gltfimage.height;
m_mipLevels = static_cast<uint32_t>(floor(log2(std::max(m_width, m_height))) + 1.0);
vkGetPhysicalDeviceFormatProperties(device->getPhysicalDevice(), format, &formatProperties);
assert(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT);
assert(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT);
/// 分配存放缓冲区的设备内存
VkMemoryAllocateInfo memAllocInfo{};
memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
VkMemoryRequirements memReqs{};
VkBuffer stagingBuffer;
VkDeviceMemory stagingMemory;
VkBufferCreateInfo bufferCreateInfo{};
bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferCreateInfo.size = bufferSize;
bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VK_CHECK_RESULT(vkCreateBuffer(logicalDevice, &bufferCreateInfo, nullptr, &stagingBuffer));
vkGetBufferMemoryRequirements(logicalDevice, stagingBuffer, &memReqs);
memAllocInfo.allocationSize = memReqs.size;
memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
VK_CHECK_RESULT(vkAllocateMemory(logicalDevice, &memAllocInfo, nullptr, &stagingMemory));
VK_CHECK_RESULT(vkBindBufferMemory(logicalDevice, stagingBuffer, stagingMemory, 0));
// 向设备内存中写入缓冲区
uint8_t* data;
VK_CHECK_RESULT(vkMapMemory(logicalDevice, stagingMemory, 0, memReqs.size, 0, (void**)&data));
memcpy(data, buffer, bufferSize);
vkUnmapMemory(logicalDevice, stagingMemory);
/// 创建图片类型设备内存
VkImageCreateInfo imageCreateInfo{};
imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
imageCreateInfo.format = format;
imageCreateInfo.mipLevels = m_mipLevels;
imageCreateInfo.arrayLayers = 1;
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageCreateInfo.extent = { m_width, m_height, 1 };
imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
VK_CHECK_RESULT(vkCreateImage(logicalDevice, &imageCreateInfo, nullptr, &m_image));
vkGetImageMemoryRequirements(logicalDevice, m_image, &memReqs);
memAllocInfo.allocationSize = memReqs.size;
memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VK_CHECK_RESULT(vkAllocateMemory(logicalDevice, &memAllocInfo, nullptr, &m_deviceMemory));
VK_CHECK_RESULT(vkBindImageMemory(logicalDevice, m_image, m_deviceMemory, 0));
/// 分配复制命令缓冲区
VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
VkImageSubresourceRange subresourceRange = {};
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
subresourceRange.levelCount = 1;
subresourceRange.layerCount = 1;
{
/// 插入barrier强制管线等待上方指令完成
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 = m_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 = m_width;
bufferCopyRegion.imageExtent.height = m_height;
bufferCopyRegion.imageExtent.depth = 1;
vkCmdCopyBufferToImage(copyCmd, stagingBuffer, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &bufferCopyRegion);
{
/// 插入barrier管线等待copy操作完成
VkImageMemoryBarrier imageMemoryBarrier{};
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
imageMemoryBarrier.image = m_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, true);
/// 销毁图片buffer存储的设备内存
vkFreeMemory(logicalDevice, stagingMemory, nullptr);
/// 销毁图片buffer存储的设备缓冲区
vkDestroyBuffer(logicalDevice, stagingBuffer, nullptr);
// 生成mip-map链 (glTF 使用 jpg 和 png 格式, 需要当场生成mip-map)
VkCommandBuffer blitCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
for (uint32_t i = 1; i < m_mipLevels; i++) {
VkImageBlit imageBlit{};
imageBlit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageBlit.srcSubresource.layerCount = 1;
imageBlit.srcSubresource.mipLevel = i - 1;
imageBlit.srcOffsets[1].x = int32_t(m_width >> (i - 1));
imageBlit.srcOffsets[1].y = int32_t(m_height >> (i - 1));
imageBlit.srcOffsets[1].z = 1;
imageBlit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageBlit.dstSubresource.layerCount = 1;
imageBlit.dstSubresource.mipLevel = i;
imageBlit.dstOffsets[1].x = int32_t(m_width >> i);
imageBlit.dstOffsets[1].y = int32_t(m_height >> i);
imageBlit.dstOffsets[1].z = 1;
VkImageSubresourceRange mipSubRange = {};
mipSubRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
mipSubRange.baseMipLevel = i;
mipSubRange.levelCount = 1;
mipSubRange.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 = m_image;
imageMemoryBarrier.subresourceRange = mipSubRange;
vkCmdPipelineBarrier(blitCmd, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
}
vkCmdBlitImage(blitCmd, m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &imageBlit, VK_FILTER_LINEAR);
{
VkImageMemoryBarrier imageMemoryBarrier{};
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
imageMemoryBarrier.image = m_image;
imageMemoryBarrier.subresourceRange = mipSubRange;
vkCmdPipelineBarrier(blitCmd, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
}
}
subresourceRange.levelCount = m_mipLevels;
m_imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
{
VkImageMemoryBarrier imageMemoryBarrier{};
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
imageMemoryBarrier.image = m_image;
imageMemoryBarrier.subresourceRange = subresourceRange;
vkCmdPipelineBarrier(blitCmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
}
m_device->flushCommandBuffer(blitCmd, copyQueue, true);
/// 创建贴图采样器
VkSamplerCreateInfo samplerInfo{};
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
samplerInfo.magFilter = textureSampler.getMaxFilter();
samplerInfo.minFilter = textureSampler.getMinFilter();
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
samplerInfo.addressModeU = textureSampler.getAddressModeU();
samplerInfo.addressModeV = textureSampler.getAddressModeV();
samplerInfo.addressModeW = textureSampler.getAddressModeW();
samplerInfo.compareOp = VK_COMPARE_OP_NEVER;
samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
samplerInfo.maxAnisotropy = 1.0;
samplerInfo.anisotropyEnable = VK_FALSE;
samplerInfo.maxLod = (float)m_mipLevels;
samplerInfo.maxAnisotropy = 8.0f;
samplerInfo.anisotropyEnable = VK_TRUE;
VK_CHECK_RESULT(vkCreateSampler(logicalDevice, &samplerInfo, nullptr, &m_sampler));
/// 创建图片的数据视图,用于读写图片
VkImageViewCreateInfo viewInfo{};
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewInfo.image = m_image;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.format = format;
viewInfo.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
viewInfo.subresourceRange.layerCount = 1;
viewInfo.subresourceRange.levelCount = m_mipLevels;
VK_CHECK_RESULT(vkCreateImageView(logicalDevice, &viewInfo, nullptr, &m_view));
updateDescriptor();
if (deleteBuffer)
delete[] buffer;
}
GLTFLOADER_NAMESPACE_END

View File

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