[D3D12] Delayed ImmediateTexture releasing
This commit is contained in:
parent
d437555036
commit
f5f8714c3f
|
@ -29,12 +29,14 @@ namespace d3d12 {
|
|||
#include "xenia/ui/d3d12/shaders/dxbc/immediate_vs.h"
|
||||
|
||||
D3D12ImmediateDrawer::D3D12ImmediateTexture::D3D12ImmediateTexture(
|
||||
uint32_t width, uint32_t height, ID3D12Resource* resource_if_exists,
|
||||
ImmediateTextureFilter filter, bool is_repeated)
|
||||
uint32_t width, uint32_t height, ID3D12Resource* resource,
|
||||
SamplerIndex sampler_index, D3D12ImmediateDrawer* immediate_drawer,
|
||||
size_t immediate_drawer_index)
|
||||
: ImmediateTexture(width, height),
|
||||
resource_(resource_if_exists),
|
||||
filter_(filter),
|
||||
is_repeated_(is_repeated) {
|
||||
resource_(resource),
|
||||
sampler_index_(sampler_index),
|
||||
immediate_drawer_(immediate_drawer),
|
||||
immediate_drawer_index_(immediate_drawer_index) {
|
||||
if (resource_) {
|
||||
resource_->AddRef();
|
||||
}
|
||||
|
@ -42,14 +44,20 @@ D3D12ImmediateDrawer::D3D12ImmediateTexture::D3D12ImmediateTexture(
|
|||
}
|
||||
|
||||
D3D12ImmediateDrawer::D3D12ImmediateTexture::~D3D12ImmediateTexture() {
|
||||
if (immediate_drawer_) {
|
||||
immediate_drawer_->OnImmediateTextureDestroyed(*this);
|
||||
}
|
||||
if (resource_) {
|
||||
resource_->Release();
|
||||
// TODO(Triang3l): Track last usage submission because it turns out that
|
||||
// deletion in the ImGui and the profiler actually happens before after
|
||||
// awaiting submission completion.
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12ImmediateDrawer::D3D12ImmediateTexture::OnImmediateDrawerShutdown() {
|
||||
immediate_drawer_ = nullptr;
|
||||
// Lifetime is not managed anymore, so don't keep the resource either.
|
||||
util::ReleaseAndNull(resource_);
|
||||
}
|
||||
|
||||
D3D12ImmediateDrawer::D3D12ImmediateDrawer(D3D12Context& graphics_context)
|
||||
: ImmediateDrawer(&graphics_context), context_(graphics_context) {}
|
||||
|
||||
|
@ -233,6 +241,11 @@ bool D3D12ImmediateDrawer::Initialize() {
|
|||
}
|
||||
|
||||
void D3D12ImmediateDrawer::Shutdown() {
|
||||
for (auto& deleted_texture : textures_deleted_) {
|
||||
deleted_texture.first->Release();
|
||||
}
|
||||
textures_deleted_.clear();
|
||||
|
||||
for (auto& texture_upload : texture_uploads_submitted_) {
|
||||
texture_upload.buffer->Release();
|
||||
texture_upload.texture->Release();
|
||||
|
@ -245,6 +258,11 @@ void D3D12ImmediateDrawer::Shutdown() {
|
|||
}
|
||||
texture_uploads_pending_.clear();
|
||||
|
||||
for (D3D12ImmediateTexture* texture : textures_) {
|
||||
texture->OnImmediateDrawerShutdown();
|
||||
}
|
||||
textures_.clear();
|
||||
|
||||
texture_descriptor_pool_.reset();
|
||||
vertex_buffer_pool_.reset();
|
||||
|
||||
|
@ -257,8 +275,8 @@ void D3D12ImmediateDrawer::Shutdown() {
|
|||
}
|
||||
|
||||
std::unique_ptr<ImmediateTexture> D3D12ImmediateDrawer::CreateTexture(
|
||||
uint32_t width, uint32_t height, ImmediateTextureFilter filter, bool repeat,
|
||||
const uint8_t* data) {
|
||||
uint32_t width, uint32_t height, ImmediateTextureFilter filter,
|
||||
bool is_repeated, const uint8_t* data) {
|
||||
const D3D12Provider& provider = context_.GetD3D12Provider();
|
||||
ID3D12Device* device = provider.GetDevice();
|
||||
D3D12_HEAP_FLAGS heap_flag_create_not_zeroed =
|
||||
|
@ -347,10 +365,22 @@ std::unique_ptr<ImmediateTexture> D3D12ImmediateDrawer::CreateTexture(
|
|||
resource = nullptr;
|
||||
}
|
||||
|
||||
SamplerIndex sampler_index;
|
||||
if (filter == ImmediateTextureFilter::kLinear) {
|
||||
sampler_index =
|
||||
is_repeated ? SamplerIndex::kLinearRepeat : SamplerIndex::kLinearClamp;
|
||||
} else {
|
||||
sampler_index = is_repeated ? SamplerIndex::kNearestRepeat
|
||||
: SamplerIndex::kNearestClamp;
|
||||
}
|
||||
|
||||
// Manage by this immediate drawer if successfully created a resource.
|
||||
std::unique_ptr<D3D12ImmediateTexture> texture =
|
||||
std::make_unique<D3D12ImmediateTexture>(width, height, resource, filter,
|
||||
repeat);
|
||||
std::make_unique<D3D12ImmediateTexture>(
|
||||
width, height, resource, sampler_index, resource ? this : nullptr,
|
||||
textures_.size());
|
||||
if (resource) {
|
||||
textures_.push_back(texture.get());
|
||||
// D3D12ImmediateTexture now holds a reference.
|
||||
resource->Release();
|
||||
}
|
||||
|
@ -368,7 +398,19 @@ void D3D12ImmediateDrawer::Begin(int render_target_width,
|
|||
current_command_list_ = context_.GetSwapCommandList();
|
||||
|
||||
uint64_t completed_fence_value = context_.GetSwapCompletedFenceValue();
|
||||
uint64_t current_fence_value = context_.GetSwapCurrentFenceValue();
|
||||
|
||||
// Release deleted textures.
|
||||
for (auto it = textures_deleted_.begin(); it != textures_deleted_.end();) {
|
||||
if (it->second > completed_fence_value) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
it->first->Release();
|
||||
if (std::next(it) != textures_deleted_.end()) {
|
||||
*it = textures_deleted_.back();
|
||||
}
|
||||
textures_deleted_.pop_back();
|
||||
}
|
||||
|
||||
// Release upload buffers for completed texture uploads.
|
||||
auto erase_uploads_end = texture_uploads_submitted_.begin();
|
||||
|
@ -501,17 +543,20 @@ void D3D12ImmediateDrawer::Draw(const ImmediateDraw& draw) {
|
|||
// Bind the texture. If this is the first draw in a frame, the descriptor heap
|
||||
// index will be invalid initially, and the texture will be bound regardless
|
||||
// of what's in current_texture_.
|
||||
uint64_t current_fence_value = context_.GetSwapCurrentFenceValue();
|
||||
auto texture = reinterpret_cast<D3D12ImmediateTexture*>(draw.texture_handle);
|
||||
ID3D12Resource* texture_resource = texture ? texture->resource() : nullptr;
|
||||
bool bind_texture = current_texture_ != texture_resource;
|
||||
uint32_t texture_descriptor_index;
|
||||
uint64_t texture_heap_index = texture_descriptor_pool_->Request(
|
||||
context_.GetSwapCurrentFenceValue(),
|
||||
current_texture_descriptor_heap_index_, bind_texture ? 1 : 0, 1,
|
||||
texture_descriptor_index);
|
||||
current_fence_value, current_texture_descriptor_heap_index_,
|
||||
bind_texture ? 1 : 0, 1, texture_descriptor_index);
|
||||
if (texture_heap_index == D3D12DescriptorHeapPool::kHeapIndexInvalid) {
|
||||
return;
|
||||
}
|
||||
if (texture_resource) {
|
||||
texture->SetLastUsageFenceValue(current_fence_value);
|
||||
}
|
||||
if (current_texture_descriptor_heap_index_ != texture_heap_index) {
|
||||
current_texture_descriptor_heap_index_ = texture_heap_index;
|
||||
bind_texture = true;
|
||||
|
@ -555,19 +600,10 @@ void D3D12ImmediateDrawer::Draw(const ImmediateDraw& draw) {
|
|||
texture_descriptor_index));
|
||||
}
|
||||
|
||||
// Bind the sampler.
|
||||
SamplerIndex sampler_index;
|
||||
if (texture != nullptr) {
|
||||
if (texture->filter() == ImmediateTextureFilter::kLinear) {
|
||||
sampler_index = texture->is_repeated() ? SamplerIndex::kLinearRepeat
|
||||
: SamplerIndex::kLinearClamp;
|
||||
} else {
|
||||
sampler_index = texture->is_repeated() ? SamplerIndex::kNearestRepeat
|
||||
: SamplerIndex::kNearestClamp;
|
||||
}
|
||||
} else {
|
||||
sampler_index = SamplerIndex::kNearestClamp;
|
||||
}
|
||||
// Bind the sampler. If the resource doesn't exist (solid color drawing), use
|
||||
// nearest-neighbor and clamp so fetching is simpler.
|
||||
SamplerIndex sampler_index =
|
||||
texture_resource ? texture->sampler_index() : SamplerIndex::kNearestClamp;
|
||||
if (current_sampler_index_ != sampler_index) {
|
||||
current_sampler_index_ = sampler_index;
|
||||
current_command_list_->SetGraphicsRootDescriptorTable(
|
||||
|
@ -618,6 +654,27 @@ void D3D12ImmediateDrawer::End() {
|
|||
}
|
||||
}
|
||||
|
||||
void D3D12ImmediateDrawer::OnImmediateTextureDestroyed(
|
||||
D3D12ImmediateTexture& texture) {
|
||||
// Remove from the texture list.
|
||||
size_t texture_index = texture.immediate_drawer_index();
|
||||
assert_true(texture_index != SIZE_MAX);
|
||||
D3D12ImmediateTexture*& texture_at_index = textures_[texture_index];
|
||||
texture_at_index = textures_.back();
|
||||
texture_at_index->SetImmediateDrawerIndex(texture_index);
|
||||
textures_.pop_back();
|
||||
|
||||
// Queue for delayed release.
|
||||
ID3D12Resource* resource = texture.resource();
|
||||
uint64_t last_usage_fence_value = texture.last_usage_fence_value();
|
||||
if (resource &&
|
||||
last_usage_fence_value > context_.GetSwapCompletedFenceValue()) {
|
||||
resource->AddRef();
|
||||
textures_deleted_.push_back(
|
||||
std::make_pair(resource, last_usage_fence_value));
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12ImmediateDrawer::UploadTextures() {
|
||||
assert_not_null(current_command_list_);
|
||||
if (texture_uploads_pending_.empty()) {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "xenia/ui/d3d12/d3d12_api.h"
|
||||
|
@ -46,23 +47,51 @@ class D3D12ImmediateDrawer : public ImmediateDrawer {
|
|||
void End() override;
|
||||
|
||||
private:
|
||||
enum class SamplerIndex {
|
||||
kNearestClamp,
|
||||
kLinearClamp,
|
||||
kNearestRepeat,
|
||||
kLinearRepeat,
|
||||
|
||||
kCount,
|
||||
kInvalid = kCount
|
||||
};
|
||||
|
||||
class D3D12ImmediateTexture : public ImmediateTexture {
|
||||
public:
|
||||
static constexpr DXGI_FORMAT kFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
D3D12ImmediateTexture(uint32_t width, uint32_t height,
|
||||
ID3D12Resource* resource_if_exists,
|
||||
ImmediateTextureFilter filter, bool is_repeated);
|
||||
ID3D12Resource* resource, SamplerIndex sampler_index,
|
||||
D3D12ImmediateDrawer* immediate_drawer,
|
||||
size_t immediate_drawer_index);
|
||||
~D3D12ImmediateTexture() override;
|
||||
|
||||
ID3D12Resource* resource() const { return resource_; }
|
||||
ImmediateTextureFilter filter() const { return filter_; }
|
||||
bool is_repeated() const { return is_repeated_; }
|
||||
SamplerIndex sampler_index() const { return sampler_index_; }
|
||||
|
||||
size_t immediate_drawer_index() const { return immediate_drawer_index_; }
|
||||
void SetImmediateDrawerIndex(size_t index) {
|
||||
immediate_drawer_index_ = index;
|
||||
}
|
||||
void OnImmediateDrawerShutdown();
|
||||
|
||||
uint64_t last_usage_fence_value() const { return last_usage_fence_value_; }
|
||||
void SetLastUsageFenceValue(uint64_t fence_value) {
|
||||
last_usage_fence_value_ = fence_value;
|
||||
}
|
||||
|
||||
private:
|
||||
ID3D12Resource* resource_;
|
||||
ImmediateTextureFilter filter_;
|
||||
bool is_repeated_;
|
||||
SamplerIndex sampler_index_;
|
||||
|
||||
D3D12ImmediateDrawer* immediate_drawer_;
|
||||
size_t immediate_drawer_index_;
|
||||
|
||||
uint64_t last_usage_fence_value_ = 0;
|
||||
};
|
||||
|
||||
void OnImmediateTextureDestroyed(D3D12ImmediateTexture& texture);
|
||||
|
||||
void UploadTextures();
|
||||
|
||||
D3D12Context& context_;
|
||||
|
@ -79,15 +108,6 @@ class D3D12ImmediateDrawer : public ImmediateDrawer {
|
|||
ID3D12PipelineState* pipeline_state_triangle_ = nullptr;
|
||||
ID3D12PipelineState* pipeline_state_line_ = nullptr;
|
||||
|
||||
enum class SamplerIndex {
|
||||
kNearestClamp,
|
||||
kLinearClamp,
|
||||
kNearestRepeat,
|
||||
kLinearRepeat,
|
||||
|
||||
kCount,
|
||||
kInvalid = kCount
|
||||
};
|
||||
ID3D12DescriptorHeap* sampler_heap_ = nullptr;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE sampler_heap_cpu_start_;
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE sampler_heap_gpu_start_;
|
||||
|
@ -95,6 +115,9 @@ class D3D12ImmediateDrawer : public ImmediateDrawer {
|
|||
std::unique_ptr<D3D12UploadBufferPool> vertex_buffer_pool_;
|
||||
std::unique_ptr<D3D12DescriptorHeapPool> texture_descriptor_pool_;
|
||||
|
||||
// Only with non-null resources.
|
||||
std::vector<D3D12ImmediateTexture*> textures_;
|
||||
|
||||
struct PendingTextureUpload {
|
||||
ID3D12Resource* texture;
|
||||
ID3D12Resource* buffer;
|
||||
|
@ -108,6 +131,8 @@ class D3D12ImmediateDrawer : public ImmediateDrawer {
|
|||
};
|
||||
std::deque<SubmittedTextureUpload> texture_uploads_submitted_;
|
||||
|
||||
std::vector<std::pair<ID3D12Resource*, uint64_t>> textures_deleted_;
|
||||
|
||||
ID3D12GraphicsCommandList* current_command_list_ = nullptr;
|
||||
int current_render_target_width_, current_render_target_height_;
|
||||
bool batch_open_ = false;
|
||||
|
|
Loading…
Reference in New Issue