diff --git a/Common/Vulkan/VulkanImage.cpp b/Common/Vulkan/VulkanImage.cpp index 4c4d2fcff1..5c5e513948 100644 --- a/Common/Vulkan/VulkanImage.cpp +++ b/Common/Vulkan/VulkanImage.cpp @@ -30,7 +30,7 @@ static bool IsDepthStencilFormat(VkFormat format) { } } -bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage, const VkComponentMapping *mapping) { +bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, VulkanDeviceAllocator *allocator, int w, int h, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage, const VkComponentMapping *mapping) { Wipe(); width_ = w; @@ -75,7 +75,8 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips, bool dedicatedAllocation = false; vulkan_->GetImageMemoryRequirements(image_, &mem_reqs, &dedicatedAllocation); - if (allocator_ && !dedicatedAllocation) { + if (allocator && !dedicatedAllocation) { + allocator_ = allocator; offset_ = allocator_->Allocate(mem_reqs, &mem_, Tag()); if (offset_ == VulkanDeviceAllocator::ALLOCATE_FAILED) { ELOG("Image memory allocation failed (mem_reqs.size=%d, typebits=%08x", (int)mem_reqs.size, (int)mem_reqs.memoryTypeBits); @@ -231,10 +232,13 @@ void VulkanTexture::Destroy() { if (image_ != VK_NULL_HANDLE) { vulkan_->Delete().QueueDeleteImage(image_); } - if (mem_ != VK_NULL_HANDLE && !allocator_) { - vulkan_->Delete().QueueDeleteDeviceMemory(mem_); - } else if (mem_ != VK_NULL_HANDLE) { - allocator_->Free(mem_, offset_); - mem_ = VK_NULL_HANDLE; + if (mem_ != VK_NULL_HANDLE) { + if (allocator_) { + allocator_->Free(mem_, offset_); + mem_ = VK_NULL_HANDLE; + allocator_ = nullptr; + } else { + vulkan_->Delete().QueueDeleteDeviceMemory(mem_); + } } } diff --git a/Common/Vulkan/VulkanImage.h b/Common/Vulkan/VulkanImage.h index 9a23d91784..64f84a8997 100644 --- a/Common/Vulkan/VulkanImage.h +++ b/Common/Vulkan/VulkanImage.h @@ -8,8 +8,8 @@ class VulkanDeviceAllocator; // Not very optimal - if you have many small textures you should use other strategies. class VulkanTexture { public: - VulkanTexture(VulkanContext *vulkan, VulkanDeviceAllocator *allocator) - : vulkan_(vulkan), allocator_(allocator) { + VulkanTexture(VulkanContext *vulkan) + : vulkan_(vulkan) { } ~VulkanTexture() { Destroy(); @@ -18,7 +18,7 @@ public: // Fast uploads from buffer. Mipmaps supported. // Usage must at least include VK_IMAGE_USAGE_TRANSFER_DST_BIT in order to use UploadMip. // When using UploadMip, initialLayout should be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL. - bool CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, const VkComponentMapping *mapping = nullptr); + bool CreateDirect(VkCommandBuffer cmd, VulkanDeviceAllocator *allocator, int w, int h, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, const VkComponentMapping *mapping = nullptr); void UploadMip(VkCommandBuffer cmd, int mip, int mipWidth, int mipHeight, VkBuffer buffer, uint32_t offset, size_t rowLength); // rowLength is in pixels void GenerateMip(VkCommandBuffer cmd, int mip); void EndCreate(VkCommandBuffer cmd, bool vertexTexture = false); @@ -55,7 +55,7 @@ private: int32_t height_ = 0; int32_t numMips_ = 1; VkFormat format_ = VK_FORMAT_UNDEFINED; - VulkanDeviceAllocator *allocator_; + VulkanDeviceAllocator *allocator_ = nullptr; // If set, memory is from this allocator. size_t offset_ = 0; std::string tag_; }; diff --git a/GPU/Vulkan/DepalettizeShaderVulkan.cpp b/GPU/Vulkan/DepalettizeShaderVulkan.cpp index 57e61fef65..b759882ad7 100644 --- a/GPU/Vulkan/DepalettizeShaderVulkan.cpp +++ b/GPU/Vulkan/DepalettizeShaderVulkan.cpp @@ -129,16 +129,18 @@ VulkanTexture *DepalShaderCacheVulkan::GetClutTexture(GEPaletteFormat clutFormat VkFormat destFormat = GetClutDestFormat(clutFormat, &componentMapping); int texturePixels = clutFormat == GE_CMODE_32BIT_ABGR8888 ? 256 : 512; + VulkanTexture *vktex = new VulkanTexture(vulkan_); + vktex->SetTag("DepalClut"); + VkCommandBuffer cmd = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::INIT_COMMANDBUFFER); + if (!vktex->CreateDirect(cmd, alloc_, texturePixels, 1, 1, destFormat, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, &componentMapping)) { + ERROR_LOG(G3D, "Failed to create texture for CLUT"); + return nullptr; + } + VkBuffer pushBuffer; uint32_t pushOffset = push_->PushAligned(rawClut, 1024, 4, &pushBuffer); - VulkanTexture *vktex = new VulkanTexture(vulkan_, alloc_); - vktex->SetTag("DepalClut"); - VkCommandBuffer cmd = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::INIT_COMMANDBUFFER); - if (!vktex->CreateDirect(cmd, texturePixels, 1, 1, destFormat, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, &componentMapping)) { - Crash(); - } vktex->UploadMip(cmd, 0, texturePixels, 1, pushBuffer, pushOffset, texturePixels); vktex->EndCreate(cmd); diff --git a/GPU/Vulkan/DrawEngineVulkan.h b/GPU/Vulkan/DrawEngineVulkan.h index cece2c08c6..9065c94611 100644 --- a/GPU/Vulkan/DrawEngineVulkan.h +++ b/GPU/Vulkan/DrawEngineVulkan.h @@ -194,7 +194,7 @@ public: void SetLineWidth(float lineWidth); void SetDepalTexture(VkImageView depal) { - if (boundDepal_ != depal) { + if (boundDepal_ != depal && depal) { boundDepal_ = depal; gstate_c.Dirty(DIRTY_FRAGMENTSHADER_STATE); } diff --git a/GPU/Vulkan/FramebufferVulkan.cpp b/GPU/Vulkan/FramebufferVulkan.cpp index 2e87b65390..3282a812b9 100644 --- a/GPU/Vulkan/FramebufferVulkan.cpp +++ b/GPU/Vulkan/FramebufferVulkan.cpp @@ -195,9 +195,9 @@ void FramebufferManagerVulkan::MakePixelTexture(const u8 *srcPixels, GEBufferFor VkCommandBuffer initCmd = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::INIT_COMMANDBUFFER); // There's only ever a few of these alive, don't need to stress the allocator with these big ones. - drawPixelsTex_ = new VulkanTexture(vulkan_, nullptr); + drawPixelsTex_ = new VulkanTexture(vulkan_); drawPixelsTex_->SetTag("DrawPixels"); - if (!drawPixelsTex_->CreateDirect(initCmd, width, height, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT)) { + if (!drawPixelsTex_->CreateDirect(initCmd, nullptr, width, height, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT)) { // out of memory? delete drawPixelsTex_; drawPixelsTex_ = nullptr; diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index 0eb056af6c..d092893d40 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -351,7 +351,7 @@ void TextureCacheVulkan::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFr depalShaderCache_->SetPushBuffer(drawEngine_->GetPushBufferForTextureData()); const GEPaletteFormat clutFormat = gstate.getClutPaletteFormat(); VulkanTexture *clutTexture = depalShaderCache_->GetClutTexture(clutFormat, clutHash_, clutBuf_); - drawEngine_->SetDepalTexture(clutTexture->GetImageView()); + drawEngine_->SetDepalTexture(clutTexture ? clutTexture->GetImageView() : VK_NULL_HANDLE); // Only point filtering enabled. samplerKey.magFilt = false; samplerKey.minFilt = false; @@ -599,7 +599,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { { delete entry->vkTex; - entry->vkTex = new VulkanTexture(vulkan_, allocator_); + entry->vkTex = new VulkanTexture(vulkan_); VulkanTexture *image = entry->vkTex; const VkComponentMapping *mapping; @@ -625,7 +625,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { snprintf(texName, sizeof(texName), "Texture%08x", entry->addr); image->SetTag(texName); - bool allocSuccess = image->CreateDirect(cmdInit, w * scaleFactor, h * scaleFactor, maxLevel + 1, actualFmt, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, mapping); + bool allocSuccess = image->CreateDirect(cmdInit, allocator_, w * scaleFactor, h * scaleFactor, maxLevel + 1, actualFmt, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, mapping); if (!allocSuccess && !lowMemoryMode_) { WARN_LOG_REPORT(G3D, "Texture cache ran out of GPU memory; switching to low memory mode"); lowMemoryMode_ = true; @@ -644,7 +644,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { scaleFactor = 1; actualFmt = dstFmt; - allocSuccess = image->CreateDirect(cmdInit, w * scaleFactor, h * scaleFactor, maxLevel + 1, actualFmt, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, mapping); + allocSuccess = image->CreateDirect(cmdInit, allocator_, w * scaleFactor, h * scaleFactor, maxLevel + 1, actualFmt, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, mapping); } if (!allocSuccess) { diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index 1ff74d1d5a..17dda0da30 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -630,11 +630,11 @@ static inline VkSamplerAddressMode AddressModeToVulkan(Draw::TextureAddressMode VulkanTexture *VKContext::GetNullTexture() { if (!nullTexture_) { VkCommandBuffer cmdInit = renderManager_.GetInitCmd(); - nullTexture_ = new VulkanTexture(vulkan_, allocator_); + nullTexture_ = new VulkanTexture(vulkan_); nullTexture_->SetTag("Null"); int w = 8; int h = 8; - nullTexture_->CreateDirect(cmdInit, w, h, 1, VK_FORMAT_A8B8G8R8_UNORM_PACK32, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + nullTexture_->CreateDirect(cmdInit, allocator_, w, h, 1, VK_FORMAT_A8B8G8R8_UNORM_PACK32, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); uint32_t bindOffset; VkBuffer bindBuf; @@ -713,7 +713,7 @@ bool VKTexture::Create(VkCommandBuffer cmd, VulkanPushBuffer *push, const Textur width_ = desc.width; height_ = desc.height; depth_ = desc.depth; - vkTex_ = new VulkanTexture(vulkan_, alloc); + vkTex_ = new VulkanTexture(vulkan_); vkTex_->SetTag(desc.tag); VkFormat vulkanFormat = DataFormatToVulkan(format_); int bpp = GetBpp(vulkanFormat); @@ -723,7 +723,7 @@ bool VKTexture::Create(VkCommandBuffer cmd, VulkanPushBuffer *push, const Textur // Gonna have to generate some, which requires TRANSFER_SRC usageBits |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; } - if (!vkTex_->CreateDirect(cmd, width_, height_, mipLevels_, vulkanFormat, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, usageBits)) { + if (!vkTex_->CreateDirect(cmd, alloc, width_, height_, mipLevels_, vulkanFormat, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, usageBits)) { ELOG("Failed to create VulkanTexture: %dx%dx%d fmt %d, %d levels", width_, height_, depth_, (int)vulkanFormat, mipLevels_); return false; }