Merge branch 'master' into vulkan

This commit is contained in:
Triang3l 2020-09-27 16:43:33 +03:00
commit 377a8d790d
8 changed files with 136 additions and 69 deletions

View File

@ -29,27 +29,34 @@ namespace d3d12 {
#include "xenia/ui/shaders/bytecode/d3d12_5_1/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();
}
handle = reinterpret_cast<uintptr_t>(this);
}
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 +240,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 +257,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 +274,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 +364,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 +397,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 +542,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_.
auto texture = reinterpret_cast<D3D12ImmediateTexture*>(draw.texture_handle);
uint64_t current_fence_value = context_.GetSwapCurrentFenceValue();
auto texture = static_cast<D3D12ImmediateTexture*>(draw.texture);
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 +599,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 +653,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()) {

View File

@ -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;

View File

@ -163,7 +163,7 @@ void ImGuiDrawer::SetupFont() {
width, height, ImmediateTextureFilter::kLinear, true,
reinterpret_cast<uint8_t*>(pixels));
io.Fonts->TexID = reinterpret_cast<void*>(font_texture_->handle);
io.Fonts->TexID = reinterpret_cast<ImTextureID>(font_texture_.get());
}
void ImGuiDrawer::RenderDrawLists(ImDrawData* data) {
@ -198,11 +198,7 @@ void ImGuiDrawer::RenderDrawLists(ImDrawData* data) {
draw.primitive_type = ImmediatePrimitiveType::kTriangles;
draw.count = cmd.ElemCount;
draw.index_offset = index_offset;
draw.texture_handle =
reinterpret_cast<uintptr_t>(cmd.TextureId) & ~kIgnoreAlpha;
draw.alpha_blend =
reinterpret_cast<uintptr_t>(cmd.TextureId) & kIgnoreAlpha ? false
: true;
draw.texture = reinterpret_cast<ImmediateTexture*>(cmd.TextureId);
draw.scissor = true;
draw.scissor_rect[0] = static_cast<int>(cmd.ClipRect.x);
draw.scissor_rect[1] = static_cast<int>(height - cmd.ClipRect.w);

View File

@ -36,8 +36,6 @@ class ImGuiDrawer : public WindowListener {
ImGuiIO& GetIO();
void RenderDrawLists();
static const uint64_t kIgnoreAlpha = (1ull << 63);
protected:
void Initialize();
void SetupFont();

View File

@ -32,12 +32,10 @@ class ImmediateTexture {
uint32_t width;
// Texture height, in pixels.
uint32_t height;
// Internal handle. Can be passed with the ImmediateDrawBatch.
uintptr_t handle;
protected:
ImmediateTexture(uint32_t width, uint32_t height)
: width(width), height(height), handle(0ULL) {}
: width(width), height(height) {}
};
// Describes the primitive type used by a draw call.
@ -78,16 +76,12 @@ struct ImmediateDraw {
int base_vertex = 0;
// Texture used when drawing, or nullptr if color only.
// This is most commonly the handle of an ImmediateTexture.
uintptr_t texture_handle = 0;
ImmediateTexture* texture = nullptr;
// True to enable scissoring using the region defined by scissor_rect.
bool scissor = false;
// Scissoring region in framebuffer pixels as (x, y, w, h).
int scissor_rect[4] = {0};
// Blends this draw with the background depending on its alpha (if true).
bool alpha_blend = true;
};
class ImmediateDrawer {
@ -97,7 +91,7 @@ class ImmediateDrawer {
// Creates a new texture with the given attributes and R8G8B8A8 data.
virtual std::unique_ptr<ImmediateTexture> CreateTexture(
uint32_t width, uint32_t height, ImmediateTextureFilter filter,
bool repeat, const uint8_t* data) = 0;
bool is_repeated, const uint8_t* data) = 0;
// Begins drawing in immediate mode using the given projection matrix.
virtual void Begin(int render_target_width, int render_target_height) = 0;

View File

@ -216,7 +216,7 @@ void MicroprofileDrawer::Flush() {
ImmediateDraw draw;
draw.primitive_type = current_primitive_type_;
draw.count = vertex_count_;
draw.texture_handle = font_texture_->handle;
draw.texture = font_texture_.get();
drawer->Draw(draw);
drawer->EndDrawBatch();

View File

@ -364,7 +364,7 @@ void VulkanImmediateDrawer::Draw(const ImmediateDraw& draw) {
// Bind the texture.
uint32_t texture_descriptor_index;
VulkanImmediateTexture* texture =
reinterpret_cast<VulkanImmediateTexture*>(draw.texture_handle);
static_cast<VulkanImmediateTexture*>(draw.texture);
if (texture && texture->immediate_drawer_ == this) {
texture_descriptor_index = texture->resource_.descriptor_index;
texture->last_usage_submission_ = context_.swap_submission_current();

View File

@ -36,7 +36,7 @@ class VulkanImmediateDrawer : public ImmediateDrawer {
std::unique_ptr<ImmediateTexture> CreateTexture(uint32_t width,
uint32_t height,
ImmediateTextureFilter filter,
bool repeat,
bool is_repeated,
const uint8_t* data) override;
void Begin(int render_target_width, int render_target_height) override;
@ -62,9 +62,7 @@ class VulkanImmediateDrawer : public ImmediateDrawer {
};
VulkanImmediateTexture(uint32_t width, uint32_t height)
: ImmediateTexture(width, height), immediate_drawer_(nullptr) {
handle = reinterpret_cast<uintptr_t>(this);
}
: ImmediateTexture(width, height), immediate_drawer_(nullptr) {}
~VulkanImmediateTexture() override;
// If null, this is either a blank texture, or the immediate drawer has been