Replaced gli with libktx for 2D texture loading sample

This commit is contained in:
Sascha Willems 2019-08-03 09:46:41 +02:00
parent 1a6042e82d
commit 87042dc358
2 changed files with 36 additions and 21 deletions

View file

@ -320,7 +320,7 @@ namespace vks
VK_CHECK_RESULT(vkMapMemory(device->logicalDevice, mappableMemory, 0, memReqs.size, 0, &data)); VK_CHECK_RESULT(vkMapMemory(device->logicalDevice, mappableMemory, 0, memReqs.size, 0, &data));
// Copy image data into memory // Copy image data into memory
memcpy(data, ktxTextureData, ktxTextureSize); memcpy(data, ktxTextureData, memReqs.size);
vkUnmapMemory(device->logicalDevice, mappableMemory); vkUnmapMemory(device->logicalDevice, mappableMemory);

View file

@ -15,13 +15,13 @@
#define GLM_FORCE_RADIANS #define GLM_FORCE_RADIANS
#define GLM_FORCE_DEPTH_ZERO_TO_ONE #define GLM_FORCE_DEPTH_ZERO_TO_ONE
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <gli/gli.hpp>
#include <vulkan/vulkan.h> #include <vulkan/vulkan.h>
#include "vulkanexamplebase.h" #include "vulkanexamplebase.h"
#include "VulkanDevice.hpp" #include "VulkanDevice.hpp"
#include "VulkanBuffer.hpp" #include "VulkanBuffer.hpp"
#include <ktx.h>
#include <ktxvulkan.h>
#define VERTEX_BUFFER_BIND_ID 0 #define VERTEX_BUFFER_BIND_ID 0
#define ENABLE_VALIDATION false #define ENABLE_VALIDATION false
@ -133,11 +133,16 @@ public:
// Texture data contains 4 channels (RGBA) with unnormalized 8-bit values, this is the most commonly supported format // Texture data contains 4 channels (RGBA) with unnormalized 8-bit values, this is the most commonly supported format
VkFormat format = VK_FORMAT_R8G8B8A8_UNORM; VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
ktxResult result;
ktxTexture* ktxTexture;
#if defined(__ANDROID__) #if defined(__ANDROID__)
// Textures are stored inside the apk on Android (compressed) // Textures are stored inside the apk on Android (compressed)
// So they need to be loaded via the asset manager // So they need to be loaded via the asset manager
AAsset* asset = AAssetManager_open(androidApp->activity->assetManager, filename.c_str(), AASSET_MODE_STREAMING); AAsset* asset = AAssetManager_open(androidApp->activity->assetManager, filename.c_str(), AASSET_MODE_STREAMING);
assert(asset); if (!asset) {
vks::tools::exitFatal("Could not load texture from " + filename + "\n\nThe file may be part of the additional asset pack.\n\nRun \"download_assets.py\" in the repository root to download the latest version.", -1);
}
size_t size = AAsset_getLength(asset); size_t size = AAsset_getLength(asset);
assert(size > 0); assert(size > 0);
@ -145,19 +150,26 @@ public:
AAsset_read(asset, textureData, size); AAsset_read(asset, textureData, size);
AAsset_close(asset); AAsset_close(asset);
gli::texture2d tex2D(gli::load((const char*)textureData, size)); result = ktxTexture_CreateFromMemory(textureData, size, KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT, target);
free(textureData);
#else #else
gli::texture2d tex2D(gli::load(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, &ktxTexture);
#endif #endif
assert(result == KTX_SUCCESS);
assert(!tex2D.empty()); // Get properties required for using and upload texture data from the ktx texture object
texture.width = ktxTexture->baseWidth;
texture.width = static_cast<uint32_t>(tex2D[0].extent().x); texture.height = ktxTexture->baseHeight;
texture.height = static_cast<uint32_t>(tex2D[0].extent().y); texture.mipLevels = ktxTexture->numLevels;
texture.mipLevels = static_cast<uint32_t>(tex2D.levels()); ktx_uint8_t *ktxTextureData = ktxTexture_GetData(ktxTexture);
ktx_size_t ktxTextureSize = ktxTexture_GetSize(ktxTexture);
// We prefer using staging to copy the texture data to a device local optimal image // We prefer using staging to copy the texture data to a device local optimal image
VkBool32 useStaging = true; VkBool32 useStaging = false;
// Only use linear tiling if forced // Only use linear tiling if forced
bool forceLinearTiling = false; bool forceLinearTiling = false;
@ -182,7 +194,7 @@ public:
VkDeviceMemory stagingMemory; VkDeviceMemory stagingMemory;
VkBufferCreateInfo bufferCreateInfo = vks::initializers::bufferCreateInfo(); VkBufferCreateInfo bufferCreateInfo = vks::initializers::bufferCreateInfo();
bufferCreateInfo.size = tex2D.size(); bufferCreateInfo.size = ktxTextureSize;
// This buffer is used as a transfer source for the buffer copy // This buffer is used as a transfer source for the buffer copy
bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
@ -199,7 +211,7 @@ public:
// Copy texture data into host local staging buffer // Copy texture data into host local staging buffer
uint8_t *data; uint8_t *data;
VK_CHECK_RESULT(vkMapMemory(device, stagingMemory, 0, memReqs.size, 0, (void **)&data)); VK_CHECK_RESULT(vkMapMemory(device, stagingMemory, 0, memReqs.size, 0, (void **)&data));
memcpy(data, tex2D.data(), tex2D.size()); memcpy(data, ktxTextureData, ktxTextureSize);
vkUnmapMemory(device, stagingMemory); vkUnmapMemory(device, stagingMemory);
// Setup buffer copy regions for each mip level // Setup buffer copy regions for each mip level
@ -207,19 +219,20 @@ public:
uint32_t offset = 0; uint32_t offset = 0;
for (uint32_t i = 0; i < texture.mipLevels; i++) { for (uint32_t i = 0; i < texture.mipLevels; i++) {
// Calculate offset into staging buffer for the current mip lavel
ktx_size_t offset;
assert(ktxTexture_GetImageOffset(ktxTexture, i, 0, 0, &offset) == KTX_SUCCESS);
// Setup a buffer image copy structure for the current mip lavel
VkBufferImageCopy bufferCopyRegion = {}; VkBufferImageCopy bufferCopyRegion = {};
bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
bufferCopyRegion.imageSubresource.mipLevel = i; bufferCopyRegion.imageSubresource.mipLevel = i;
bufferCopyRegion.imageSubresource.baseArrayLayer = 0; bufferCopyRegion.imageSubresource.baseArrayLayer = 0;
bufferCopyRegion.imageSubresource.layerCount = 1; bufferCopyRegion.imageSubresource.layerCount = 1;
bufferCopyRegion.imageExtent.width = static_cast<uint32_t>(tex2D[i].extent().x); bufferCopyRegion.imageExtent.width = ktxTexture->baseWidth >> i;
bufferCopyRegion.imageExtent.height = static_cast<uint32_t>(tex2D[i].extent().y); bufferCopyRegion.imageExtent.height = ktxTexture->baseHeight >> i;
bufferCopyRegion.imageExtent.depth = 1; bufferCopyRegion.imageExtent.depth = 1;
bufferCopyRegion.bufferOffset = offset; bufferCopyRegion.bufferOffset = offset;
bufferCopyRegions.push_back(bufferCopyRegion); bufferCopyRegions.push_back(bufferCopyRegion);
offset += static_cast<uint32_t>(tex2D[i].size());
} }
// Create optimal tiled target image on the device // Create optimal tiled target image on the device
@ -347,7 +360,7 @@ public:
void *data; void *data;
VK_CHECK_RESULT(vkMapMemory(device, mappableMemory, 0, memReqs.size, 0, &data)); VK_CHECK_RESULT(vkMapMemory(device, mappableMemory, 0, memReqs.size, 0, &data));
// Copy image data of the first mip level into memory // Copy image data of the first mip level into memory
memcpy(data, tex2D[0].data(), tex2D[0].size()); memcpy(data, ktxTextureData, memReqs.size);
vkUnmapMemory(device, mappableMemory); vkUnmapMemory(device, mappableMemory);
// Linear tiled images don't need to be staged and can be directly used as textures // Linear tiled images don't need to be staged and can be directly used as textures
@ -389,6 +402,8 @@ public:
VulkanExampleBase::flushCommandBuffer(copyCmd, queue, true); VulkanExampleBase::flushCommandBuffer(copyCmd, queue, true);
} }
ktxTexture_Destroy(ktxTexture);
// Create a texture sampler // Create a texture sampler
// In Vulkan textures are accessed by samplers // In Vulkan textures are accessed by samplers
// This separates all the sampling information from the texture data. This means you could have multiple sampler objects for the same texture with different settings // This separates all the sampling information from the texture data. This means you could have multiple sampler objects for the same texture with different settings