From 27a5697a96563f5a21d199441533e3c3d7c9b7c8 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 26 Mar 2016 18:22:21 -0700 Subject: [PATCH] Vulkan: Use the slab allocator for textures. --- Common/Vulkan/VulkanImage.cpp | 35 +++++++++++++++++++++---------- Common/Vulkan/VulkanImage.h | 9 ++++++-- GPU/Vulkan/TextureCacheVulkan.cpp | 14 ++++++++++--- GPU/Vulkan/TextureCacheVulkan.h | 2 ++ 4 files changed, 44 insertions(+), 16 deletions(-) diff --git a/Common/Vulkan/VulkanImage.cpp b/Common/Vulkan/VulkanImage.cpp index 86484b0547..7c403cf9f3 100644 --- a/Common/Vulkan/VulkanImage.cpp +++ b/Common/Vulkan/VulkanImage.cpp @@ -1,4 +1,5 @@ #include "Common/Vulkan/VulkanImage.h" +#include "Common/Vulkan/VulkanMemory.h" VkResult VulkanTexture::Create(int w, int h, VkFormat format) { tex_width = w; @@ -234,9 +235,12 @@ void VulkanTexture::Wipe() { vulkan_->Delete().QueueDeleteImageView(view); view = VK_NULL_HANDLE; } - if (mem) { + if (mem && !allocator_) { vulkan_->Delete().QueueDeleteDeviceMemory(mem); mem = VK_NULL_HANDLE; + } else if (mem) { + allocator_->Free(mem, offset_); + mem = VK_NULL_HANDLE; } } @@ -267,18 +271,25 @@ void VulkanTexture::CreateDirect(int w, int h, int numMips, VkFormat format, VkI assert(res == VK_SUCCESS); vkGetImageMemoryRequirements(vulkan_->GetDevice(), image, &mem_reqs); - VkMemoryAllocateInfo mem_alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; - mem_alloc.memoryTypeIndex = 0; - mem_alloc.allocationSize = mem_reqs.size; - // Find memory type - don't specify any mapping requirements - bool pass = vulkan_->MemoryTypeFromProperties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &mem_alloc.memoryTypeIndex); - assert(pass); + if (allocator_) { + offset_ = allocator_->Allocate(mem_reqs, &mem); + } else { + VkMemoryAllocateInfo mem_alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; + mem_alloc.memoryTypeIndex = 0; + mem_alloc.allocationSize = mem_reqs.size; - res = vkAllocateMemory(vulkan_->GetDevice(), &mem_alloc, NULL, &mem); - assert(res == VK_SUCCESS); + // Find memory type - don't specify any mapping requirements + bool pass = vulkan_->MemoryTypeFromProperties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &mem_alloc.memoryTypeIndex); + assert(pass); - res = vkBindImageMemory(vulkan_->GetDevice(), image, mem, 0); + res = vkAllocateMemory(vulkan_->GetDevice(), &mem_alloc, NULL, &mem); + assert(res == VK_SUCCESS); + + offset_ = 0; + } + + res = vkBindImageMemory(vulkan_->GetDevice(), image, mem, offset_); assert(res == VK_SUCCESS); // Since we're going to blit to the target, set its layout to TRANSFER_DST @@ -347,11 +358,13 @@ void VulkanTexture::Destroy() { mappableImage = VK_NULL_HANDLE; } } - if (mem) { + if (mem && !allocator_) { vulkan_->Delete().QueueDeleteDeviceMemory(mem); if (mappableMemory == mem) { mappableMemory = VK_NULL_HANDLE; } + } else if (mem) { + allocator_->Free(mem, offset_); } view = VK_NULL_HANDLE; diff --git a/Common/Vulkan/VulkanImage.h b/Common/Vulkan/VulkanImage.h index 3b0a3ece81..9b8af3179f 100644 --- a/Common/Vulkan/VulkanImage.h +++ b/Common/Vulkan/VulkanImage.h @@ -2,14 +2,17 @@ #include "Common/Vulkan/VulkanContext.h" +class VulkanDeviceAllocator; + // Wrapper around what you need to use a texture. // Not very optimal - if you have many small textures you should use other strategies. class VulkanTexture { public: - VulkanTexture(VulkanContext *vulkan) + VulkanTexture(VulkanContext *vulkan, VulkanDeviceAllocator *allocator = nullptr) : vulkan_(vulkan), image(VK_NULL_HANDLE), mem(VK_NULL_HANDLE), view(VK_NULL_HANDLE), tex_width(0), tex_height(0), numMips_(1), format_(VK_FORMAT_UNDEFINED), - mappableImage(VK_NULL_HANDLE), mappableMemory(VK_NULL_HANDLE), needStaging(false) { + mappableImage(VK_NULL_HANDLE), mappableMemory(VK_NULL_HANDLE), needStaging(false), + allocator_(allocator), offset_(0) { memset(&mem_reqs, 0, sizeof(mem_reqs)); } ~VulkanTexture() { @@ -47,4 +50,6 @@ private: VkDeviceMemory mappableMemory; VkMemoryRequirements mem_reqs; bool needStaging; + VulkanDeviceAllocator *allocator_; + size_t offset_; }; diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index e2b4fa0fe2..66f608c3ce 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -66,8 +66,11 @@ #define TEXCACHE_MAX_TEXELS_SCALED (256*256) // Per frame -#define TEXCACHE_MIN_PRESSURE 16 * 1024 * 1024 // Total in GL -#define TEXCACHE_SECOND_MIN_PRESSURE 4 * 1024 * 1024 +#define TEXCACHE_MIN_PRESSURE (16 * 1024 * 1024) // Total in GL +#define TEXCACHE_SECOND_MIN_PRESSURE (4 * 1024 * 1024) + +#define TEXCACHE_MIN_SLAB_SIZE (4 * 1024 * 1024) +#define TEXCACHE_MAX_SLAB_SIZE (32 * 1024 * 1024) // Note: some drivers prefer B4G4R4A4_UNORM_PACK16 over R4G4B4A4_UNORM_PACK16. #define VULKAN_4444_FORMAT VK_FORMAT_B4G4R4A4_UNORM_PACK16 @@ -137,6 +140,7 @@ TextureCacheVulkan::TextureCacheVulkan(VulkanContext *vulkan) timesInvalidatedAllThisFrame_ = 0; lastBoundTexture = nullptr; decimationCounter_ = TEXCACHE_DECIMATION_INTERVAL; + allocator_ = new VulkanDeviceAllocator(vulkan_, TEXCACHE_MIN_SLAB_SIZE, TEXCACHE_MAX_SLAB_SIZE); SetupTextureDecoder(); @@ -559,6 +563,8 @@ void TextureCacheVulkan::SetFramebufferSamplingParams(u16 bufferWidth, u16 buffe } void TextureCacheVulkan::StartFrame() { + // TODO: Better place? + allocator_->End(); lastBoundTexture = nullptr; timesInvalidatedAllThisFrame_ = 0; @@ -572,6 +578,8 @@ void TextureCacheVulkan::StartFrame() { } else { Decimate(); } + + allocator_->Begin(); } static inline u32 MiniHash(const u32 *ptr) { @@ -1318,7 +1326,7 @@ void TextureCacheVulkan::SetTexture(VulkanPushBuffer *uploadBuffer) { } } else { entry->vkTex = new CachedTextureVulkan(); - entry->vkTex->texture_ = new VulkanTexture(vulkan_); + entry->vkTex->texture_ = new VulkanTexture(vulkan_, allocator_); VulkanTexture *image = entry->vkTex->texture_; const VkComponentMapping *mapping; diff --git a/GPU/Vulkan/TextureCacheVulkan.h b/GPU/Vulkan/TextureCacheVulkan.h index 590ae4edbc..f47164d77a 100644 --- a/GPU/Vulkan/TextureCacheVulkan.h +++ b/GPU/Vulkan/TextureCacheVulkan.h @@ -35,6 +35,7 @@ class DrawEngineVulkan; class VulkanContext; class VulkanTexture; class VulkanPushBuffer; +class VulkanDeviceAllocator; struct SamplerCacheKey { SamplerCacheKey() : fullKey(0) {} @@ -140,6 +141,7 @@ private: void SetFramebufferSamplingParams(u16 bufferWidth, u16 bufferHeight, SamplerCacheKey &key); VulkanContext *vulkan_; + VulkanDeviceAllocator *allocator_; TexCache secondCache; u32 secondCacheSizeEstimate_;