[Vulkan] Delayed ImmediateTexture destruction

This commit is contained in:
Triang3l
2020-09-27 15:06:10 +03:00
parent 886129cefa
commit 183269ba16
2 changed files with 202 additions and 201 deletions

View File

@@ -13,7 +13,7 @@
#include <cstddef>
#include <deque>
#include <memory>
#include <unordered_set>
#include <utility>
#include <vector>
#include "xenia/ui/immediate_drawer.h"
@@ -54,24 +54,28 @@ class VulkanImmediateDrawer : public ImmediateDrawer {
class VulkanImmediateTexture : public ImmediateTexture {
public:
VulkanImmediateTexture(uint32_t width, uint32_t height,
VulkanImmediateDrawer* immediate_drawer,
uintptr_t immediate_drawer_handle)
: ImmediateTexture(width, height), immediate_drawer_(immediate_drawer) {
handle = immediate_drawer_handle;
}
~VulkanImmediateTexture() {
if (immediate_drawer_) {
immediate_drawer_->HandleImmediateTextureDestroyed(handle);
}
}
void DetachFromImmediateDrawer() {
immediate_drawer_ = nullptr;
handle = 0;
}
struct Resource {
VkImage image;
VkDeviceMemory memory;
VkImageView image_view;
uint32_t descriptor_index;
};
private:
VulkanImmediateTexture(uint32_t width, uint32_t height)
: ImmediateTexture(width, height), immediate_drawer_(nullptr) {
handle = reinterpret_cast<uintptr_t>(this);
}
~VulkanImmediateTexture() override;
// If null, this is either a blank texture, or the immediate drawer has been
// destroyed.
VulkanImmediateDrawer* immediate_drawer_;
size_t immediate_drawer_index_;
// Invalid if immediate_drawer_ is null, since it's managed by the immediate
// drawer.
Resource resource_;
size_t pending_upload_index_;
uint64_t last_usage_submission_ = 0;
};
struct TextureDescriptorPool {
@@ -86,19 +90,6 @@ class VulkanImmediateDrawer : public ImmediateDrawer {
TextureDescriptorPool* recycled_next;
};
// Tracked separately from VulkanImmediateTexture because copying may take
// additional references.
struct Texture {
// Null for the white texture, reference held by the drawer itself instead
// of immediate textures.
VulkanImmediateTexture* immediate_texture;
VkImage image;
VkDeviceMemory memory;
VkImageView image_view;
uint32_t descriptor_index;
uint32_t reference_count;
};
bool EnsurePipelinesCreated();
// Allocates a combined image sampler in a pool and returns its index, or
@@ -107,31 +98,15 @@ class VulkanImmediateDrawer : public ImmediateDrawer {
VkDescriptorSet GetTextureDescriptor(uint32_t descriptor_index) const;
void FreeTextureDescriptor(uint32_t descriptor_index);
// Returns SIZE_MAX in case of failure. The created texture will have a
// reference count of 1 plus references needed for uploading, but will not be
// attached to a VulkanImmediateTexture (will return the reference to the
// caller, in short). If data is null, a (1, 1, 1, 1) image will be created,
// which can be used as a replacement when drawing without a real texture.
size_t CreateVulkanTexture(uint32_t width, uint32_t height,
// If data is null, a (1, 1, 1, 1) image will be created, which can be used as
// a replacement when drawing without a real texture.
bool CreateTextureResource(uint32_t width, uint32_t height,
ImmediateTextureFilter filter, bool is_repeated,
const uint8_t* data);
void ReleaseTexture(size_t index);
uintptr_t GetTextureHandleForIndex(size_t index) const {
return index != white_texture_index_ ? uintptr_t(index + 1) : 0;
}
size_t GetTextureIndexForHandle(uintptr_t handle) const {
// 0 is a special value for no texture.
return handle ? size_t(handle - 1) : white_texture_index_;
}
// For calling from VulkanImmediateTexture.
void HandleImmediateTextureDestroyed(uintptr_t handle) {
size_t index = GetTextureIndexForHandle(handle);
if (index == white_texture_index_) {
return;
}
textures_[index].immediate_texture = nullptr;
ReleaseTexture(index);
}
const uint8_t* data,
VulkanImmediateTexture::Resource& resource_out,
size_t& pending_upload_index_out);
void DestroyTextureResource(VulkanImmediateTexture::Resource& resource);
void OnImmediateTextureDestroyed(VulkanImmediateTexture& texture);
VulkanContext& context_;
@@ -141,26 +116,28 @@ class VulkanImmediateDrawer : public ImmediateDrawer {
TextureDescriptorPool* texture_descriptor_pool_unallocated_first_ = nullptr;
TextureDescriptorPool* texture_descriptor_pool_recycled_first_ = nullptr;
std::vector<Texture> textures_;
std::vector<size_t> textures_free_;
VulkanImmediateTexture::Resource white_texture_ = {};
std::vector<VulkanImmediateTexture*> textures_;
struct PendingTextureUpload {
size_t texture_index;
uint32_t width;
uint32_t height;
// Null for internal resources such as the white texture.
VulkanImmediateTexture* texture;
// VK_NULL_HANDLE if need to clear rather than to copy.
VkBuffer buffer;
VkDeviceMemory buffer_memory;
VkImage image;
uint32_t width;
uint32_t height;
};
std::vector<PendingTextureUpload> texture_uploads_pending_;
struct SubmittedTextureUpload {
size_t texture_index;
// VK_NULL_HANDLE if cleared rather than copied.
struct SubmittedTextureUploadBuffer {
VkBuffer buffer;
VkDeviceMemory buffer_memory;
uint64_t submission_index;
};
std::deque<SubmittedTextureUpload> texture_uploads_submitted_;
size_t white_texture_index_;
std::deque<SubmittedTextureUploadBuffer> texture_upload_buffers_submitted_;
// Resource and last usage submission pairs.
std::vector<std::pair<VulkanImmediateTexture::Resource, uint64_t>>
textures_deleted_;
VkPipelineLayout pipeline_layout_ = VK_NULL_HANDLE;