|
|
@ -10,6 +10,9 @@
|
|
|
|
#include "xenia/ui/d3d12/d3d12_immediate_drawer.h"
|
|
|
|
#include "xenia/ui/d3d12/d3d12_immediate_drawer.h"
|
|
|
|
|
|
|
|
|
|
|
|
#include <cstring>
|
|
|
|
#include <cstring>
|
|
|
|
|
|
|
|
#include <memory>
|
|
|
|
|
|
|
|
#include <utility>
|
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
|
|
|
|
#include "xenia/base/assert.h"
|
|
|
|
#include "xenia/base/assert.h"
|
|
|
|
#include "xenia/base/logging.h"
|
|
|
|
#include "xenia/base/logging.h"
|
|
|
@ -28,95 +31,48 @@ namespace d3d12 {
|
|
|
|
class D3D12ImmediateTexture : public ImmediateTexture {
|
|
|
|
class D3D12ImmediateTexture : public ImmediateTexture {
|
|
|
|
public:
|
|
|
|
public:
|
|
|
|
static constexpr DXGI_FORMAT kFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
|
|
static constexpr DXGI_FORMAT kFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
|
|
|
|
|
|
|
|
|
|
D3D12ImmediateTexture(uint32_t width, uint32_t height,
|
|
|
|
D3D12ImmediateTexture(uint32_t width, uint32_t height,
|
|
|
|
ImmediateTextureFilter filter, bool repeat);
|
|
|
|
ID3D12Resource* resource_if_exists,
|
|
|
|
|
|
|
|
ImmediateTextureFilter filter, bool is_repeated);
|
|
|
|
~D3D12ImmediateTexture() override;
|
|
|
|
~D3D12ImmediateTexture() override;
|
|
|
|
|
|
|
|
ID3D12Resource* resource() const { return resource_; }
|
|
|
|
bool Initialize(D3D12Provider& provider);
|
|
|
|
ImmediateTextureFilter filter() const { return filter_; }
|
|
|
|
void Shutdown();
|
|
|
|
bool is_repeated() const { return is_repeated_; }
|
|
|
|
|
|
|
|
|
|
|
|
ID3D12Resource* GetResource() const { return resource_; }
|
|
|
|
|
|
|
|
void Transition(D3D12_RESOURCE_STATES new_state,
|
|
|
|
|
|
|
|
ID3D12GraphicsCommandList* command_list);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ImmediateTextureFilter GetFilter() const { return filter_; }
|
|
|
|
|
|
|
|
bool IsRepeated() const { return repeat_; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
private:
|
|
|
|
ID3D12Resource* resource_ = nullptr;
|
|
|
|
ID3D12Resource* resource_;
|
|
|
|
D3D12_RESOURCE_STATES state_;
|
|
|
|
|
|
|
|
ImmediateTextureFilter filter_;
|
|
|
|
ImmediateTextureFilter filter_;
|
|
|
|
bool repeat_;
|
|
|
|
bool is_repeated_;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
D3D12ImmediateTexture::D3D12ImmediateTexture(uint32_t width, uint32_t height,
|
|
|
|
D3D12ImmediateTexture::D3D12ImmediateTexture(uint32_t width, uint32_t height,
|
|
|
|
|
|
|
|
ID3D12Resource* resource_if_exists,
|
|
|
|
ImmediateTextureFilter filter,
|
|
|
|
ImmediateTextureFilter filter,
|
|
|
|
bool repeat)
|
|
|
|
bool is_repeated)
|
|
|
|
: ImmediateTexture(width, height), filter_(filter), repeat_(repeat) {
|
|
|
|
: ImmediateTexture(width, height),
|
|
|
|
|
|
|
|
resource_(resource_if_exists),
|
|
|
|
|
|
|
|
filter_(filter),
|
|
|
|
|
|
|
|
is_repeated_(is_repeated) {
|
|
|
|
|
|
|
|
if (resource_) {
|
|
|
|
|
|
|
|
resource_->AddRef();
|
|
|
|
|
|
|
|
}
|
|
|
|
handle = reinterpret_cast<uintptr_t>(this);
|
|
|
|
handle = reinterpret_cast<uintptr_t>(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
D3D12ImmediateTexture::~D3D12ImmediateTexture() { Shutdown(); }
|
|
|
|
D3D12ImmediateTexture::~D3D12ImmediateTexture() {
|
|
|
|
|
|
|
|
if (resource_) {
|
|
|
|
bool D3D12ImmediateTexture::Initialize(D3D12Provider& provider) {
|
|
|
|
|
|
|
|
// The first operation will likely be copying the contents.
|
|
|
|
|
|
|
|
state_ = D3D12_RESOURCE_STATE_COPY_DEST;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
D3D12_RESOURCE_DESC resource_desc;
|
|
|
|
|
|
|
|
resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
|
|
|
|
|
|
|
resource_desc.Alignment = 0;
|
|
|
|
|
|
|
|
resource_desc.Width = width;
|
|
|
|
|
|
|
|
resource_desc.Height = height;
|
|
|
|
|
|
|
|
resource_desc.DepthOrArraySize = 1;
|
|
|
|
|
|
|
|
resource_desc.MipLevels = 1;
|
|
|
|
|
|
|
|
resource_desc.Format = kFormat;
|
|
|
|
|
|
|
|
resource_desc.SampleDesc.Count = 1;
|
|
|
|
|
|
|
|
resource_desc.SampleDesc.Quality = 0;
|
|
|
|
|
|
|
|
resource_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
|
|
|
|
|
|
|
resource_desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
|
|
|
|
|
|
|
if (FAILED(provider.GetDevice()->CreateCommittedResource(
|
|
|
|
|
|
|
|
&util::kHeapPropertiesDefault, provider.GetHeapFlagCreateNotZeroed(),
|
|
|
|
|
|
|
|
&resource_desc, state_, nullptr, IID_PPV_ARGS(&resource_)))) {
|
|
|
|
|
|
|
|
XELOGE("Failed to create a {}x{} texture for immediate drawing", width,
|
|
|
|
|
|
|
|
height);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void D3D12ImmediateTexture::Shutdown() {
|
|
|
|
|
|
|
|
if (resource_ != nullptr) {
|
|
|
|
|
|
|
|
resource_->Release();
|
|
|
|
resource_->Release();
|
|
|
|
resource_ = nullptr;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void D3D12ImmediateTexture::Transition(
|
|
|
|
|
|
|
|
D3D12_RESOURCE_STATES new_state, ID3D12GraphicsCommandList* command_list) {
|
|
|
|
|
|
|
|
if (resource_ == nullptr || state_ == new_state) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
D3D12_RESOURCE_BARRIER barrier;
|
|
|
|
|
|
|
|
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
|
|
|
|
|
|
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
|
|
|
|
|
|
barrier.Transition.pResource = resource_;
|
|
|
|
|
|
|
|
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
|
|
|
|
|
|
|
barrier.Transition.StateBefore = state_;
|
|
|
|
|
|
|
|
barrier.Transition.StateAfter = new_state;
|
|
|
|
|
|
|
|
command_list->ResourceBarrier(1, &barrier);
|
|
|
|
|
|
|
|
state_ = new_state;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
D3D12ImmediateDrawer::D3D12ImmediateDrawer(D3D12Context& graphics_context)
|
|
|
|
D3D12ImmediateDrawer::D3D12ImmediateDrawer(D3D12Context& graphics_context)
|
|
|
|
: ImmediateDrawer(&graphics_context), context_(graphics_context) {}
|
|
|
|
: ImmediateDrawer(&graphics_context), context_(graphics_context) {}
|
|
|
|
|
|
|
|
|
|
|
|
D3D12ImmediateDrawer::~D3D12ImmediateDrawer() { Shutdown(); }
|
|
|
|
D3D12ImmediateDrawer::~D3D12ImmediateDrawer() { Shutdown(); }
|
|
|
|
|
|
|
|
|
|
|
|
bool D3D12ImmediateDrawer::Initialize() {
|
|
|
|
bool D3D12ImmediateDrawer::Initialize() {
|
|
|
|
auto& provider = context_.GetD3D12Provider();
|
|
|
|
const D3D12Provider& provider = context_.GetD3D12Provider();
|
|
|
|
auto device = provider.GetDevice();
|
|
|
|
ID3D12Device* device = provider.GetDevice();
|
|
|
|
|
|
|
|
|
|
|
|
// Create the root signature.
|
|
|
|
// Create the root signature.
|
|
|
|
D3D12_ROOT_PARAMETER root_parameters[size_t(RootParameter::kCount)];
|
|
|
|
D3D12_ROOT_PARAMETER root_parameters[size_t(RootParameter::kCount)];
|
|
|
@ -174,20 +130,20 @@ bool D3D12ImmediateDrawer::Initialize() {
|
|
|
|
D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
|
|
|
|
D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
|
|
|
|
root_signature_ = util::CreateRootSignature(provider, root_signature_desc);
|
|
|
|
root_signature_ = util::CreateRootSignature(provider, root_signature_desc);
|
|
|
|
if (root_signature_ == nullptr) {
|
|
|
|
if (root_signature_ == nullptr) {
|
|
|
|
XELOGE("Failed to create the immediate drawer root signature");
|
|
|
|
XELOGE("Failed to create the Direct3D 12 immediate drawer root signature");
|
|
|
|
Shutdown();
|
|
|
|
Shutdown();
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Create the pipeline states.
|
|
|
|
// Create the pipeline states.
|
|
|
|
D3D12_GRAPHICS_PIPELINE_STATE_DESC pipeline_desc = {};
|
|
|
|
D3D12_GRAPHICS_PIPELINE_STATE_DESC pipeline_state_desc = {};
|
|
|
|
pipeline_desc.pRootSignature = root_signature_;
|
|
|
|
pipeline_state_desc.pRootSignature = root_signature_;
|
|
|
|
pipeline_desc.VS.pShaderBytecode = immediate_vs;
|
|
|
|
pipeline_state_desc.VS.pShaderBytecode = immediate_vs;
|
|
|
|
pipeline_desc.VS.BytecodeLength = sizeof(immediate_vs);
|
|
|
|
pipeline_state_desc.VS.BytecodeLength = sizeof(immediate_vs);
|
|
|
|
pipeline_desc.PS.pShaderBytecode = immediate_ps;
|
|
|
|
pipeline_state_desc.PS.pShaderBytecode = immediate_ps;
|
|
|
|
pipeline_desc.PS.BytecodeLength = sizeof(immediate_ps);
|
|
|
|
pipeline_state_desc.PS.BytecodeLength = sizeof(immediate_ps);
|
|
|
|
D3D12_RENDER_TARGET_BLEND_DESC& pipeline_blend_desc =
|
|
|
|
D3D12_RENDER_TARGET_BLEND_DESC& pipeline_blend_desc =
|
|
|
|
pipeline_desc.BlendState.RenderTarget[0];
|
|
|
|
pipeline_state_desc.BlendState.RenderTarget[0];
|
|
|
|
pipeline_blend_desc.BlendEnable = TRUE;
|
|
|
|
pipeline_blend_desc.BlendEnable = TRUE;
|
|
|
|
pipeline_blend_desc.SrcBlend = D3D12_BLEND_SRC_ALPHA;
|
|
|
|
pipeline_blend_desc.SrcBlend = D3D12_BLEND_SRC_ALPHA;
|
|
|
|
pipeline_blend_desc.DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
|
|
|
|
pipeline_blend_desc.DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
|
|
|
@ -199,11 +155,11 @@ bool D3D12ImmediateDrawer::Initialize() {
|
|
|
|
pipeline_blend_desc.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_RED |
|
|
|
|
pipeline_blend_desc.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_RED |
|
|
|
|
D3D12_COLOR_WRITE_ENABLE_GREEN |
|
|
|
|
D3D12_COLOR_WRITE_ENABLE_GREEN |
|
|
|
|
D3D12_COLOR_WRITE_ENABLE_BLUE;
|
|
|
|
D3D12_COLOR_WRITE_ENABLE_BLUE;
|
|
|
|
pipeline_desc.SampleMask = UINT_MAX;
|
|
|
|
pipeline_state_desc.SampleMask = UINT_MAX;
|
|
|
|
pipeline_desc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
|
|
|
|
pipeline_state_desc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
|
|
|
|
pipeline_desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
|
|
|
|
pipeline_state_desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
|
|
|
|
pipeline_desc.RasterizerState.FrontCounterClockwise = FALSE;
|
|
|
|
pipeline_state_desc.RasterizerState.FrontCounterClockwise = FALSE;
|
|
|
|
pipeline_desc.RasterizerState.DepthClipEnable = TRUE;
|
|
|
|
pipeline_state_desc.RasterizerState.DepthClipEnable = TRUE;
|
|
|
|
D3D12_INPUT_ELEMENT_DESC pipeline_input_elements[3] = {};
|
|
|
|
D3D12_INPUT_ELEMENT_DESC pipeline_input_elements[3] = {};
|
|
|
|
pipeline_input_elements[0].SemanticName = "POSITION";
|
|
|
|
pipeline_input_elements[0].SemanticName = "POSITION";
|
|
|
|
pipeline_input_elements[0].Format = DXGI_FORMAT_R32G32_FLOAT;
|
|
|
|
pipeline_input_elements[0].Format = DXGI_FORMAT_R32G32_FLOAT;
|
|
|
@ -215,23 +171,29 @@ bool D3D12ImmediateDrawer::Initialize() {
|
|
|
|
pipeline_input_elements[2].Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
|
|
pipeline_input_elements[2].Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
|
|
pipeline_input_elements[2].AlignedByteOffset =
|
|
|
|
pipeline_input_elements[2].AlignedByteOffset =
|
|
|
|
offsetof(ImmediateVertex, color);
|
|
|
|
offsetof(ImmediateVertex, color);
|
|
|
|
pipeline_desc.InputLayout.pInputElementDescs = pipeline_input_elements;
|
|
|
|
pipeline_state_desc.InputLayout.pInputElementDescs = pipeline_input_elements;
|
|
|
|
pipeline_desc.InputLayout.NumElements =
|
|
|
|
pipeline_state_desc.InputLayout.NumElements =
|
|
|
|
UINT(xe::countof(pipeline_input_elements));
|
|
|
|
UINT(xe::countof(pipeline_input_elements));
|
|
|
|
pipeline_desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
|
|
|
pipeline_state_desc.PrimitiveTopologyType =
|
|
|
|
pipeline_desc.NumRenderTargets = 1;
|
|
|
|
D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
|
|
|
pipeline_desc.RTVFormats[0] = D3D12Context::kSwapChainFormat;
|
|
|
|
pipeline_state_desc.NumRenderTargets = 1;
|
|
|
|
pipeline_desc.SampleDesc.Count = 1;
|
|
|
|
pipeline_state_desc.RTVFormats[0] = D3D12Context::kSwapChainFormat;
|
|
|
|
|
|
|
|
pipeline_state_desc.SampleDesc.Count = 1;
|
|
|
|
if (FAILED(device->CreateGraphicsPipelineState(
|
|
|
|
if (FAILED(device->CreateGraphicsPipelineState(
|
|
|
|
&pipeline_desc, IID_PPV_ARGS(&pipeline_triangle_)))) {
|
|
|
|
&pipeline_state_desc, IID_PPV_ARGS(&pipeline_state_triangle_)))) {
|
|
|
|
XELOGE("Failed to create immediate drawer triangle pipeline state");
|
|
|
|
XELOGE(
|
|
|
|
|
|
|
|
"Failed to create the Direct3D 12 immediate drawer triangle pipeline "
|
|
|
|
|
|
|
|
"state");
|
|
|
|
Shutdown();
|
|
|
|
Shutdown();
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pipeline_desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
|
|
|
|
pipeline_state_desc.PrimitiveTopologyType =
|
|
|
|
|
|
|
|
D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
|
|
|
|
if (FAILED(device->CreateGraphicsPipelineState(
|
|
|
|
if (FAILED(device->CreateGraphicsPipelineState(
|
|
|
|
&pipeline_desc, IID_PPV_ARGS(&pipeline_line_)))) {
|
|
|
|
&pipeline_state_desc, IID_PPV_ARGS(&pipeline_state_line_)))) {
|
|
|
|
XELOGE("Failed to create immediate drawer line pipeline state");
|
|
|
|
XELOGE(
|
|
|
|
|
|
|
|
"Failed to create the Direct3D 12 immediate drawer line pipeline "
|
|
|
|
|
|
|
|
"state");
|
|
|
|
Shutdown();
|
|
|
|
Shutdown();
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -244,7 +206,9 @@ bool D3D12ImmediateDrawer::Initialize() {
|
|
|
|
sampler_heap_desc.NodeMask = 0;
|
|
|
|
sampler_heap_desc.NodeMask = 0;
|
|
|
|
if (FAILED(device->CreateDescriptorHeap(&sampler_heap_desc,
|
|
|
|
if (FAILED(device->CreateDescriptorHeap(&sampler_heap_desc,
|
|
|
|
IID_PPV_ARGS(&sampler_heap_)))) {
|
|
|
|
IID_PPV_ARGS(&sampler_heap_)))) {
|
|
|
|
XELOGE("Failed to create immediate drawer sampler descriptor heap");
|
|
|
|
XELOGE(
|
|
|
|
|
|
|
|
"Failed to create the Direct3D 12 immediate drawer sampler descriptor "
|
|
|
|
|
|
|
|
"heap");
|
|
|
|
Shutdown();
|
|
|
|
Shutdown();
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -293,8 +257,6 @@ bool D3D12ImmediateDrawer::Initialize() {
|
|
|
|
vertex_buffer_pool_ = std::make_unique<D3D12UploadBufferPool>(provider);
|
|
|
|
vertex_buffer_pool_ = std::make_unique<D3D12UploadBufferPool>(provider);
|
|
|
|
texture_descriptor_pool_ = std::make_unique<D3D12DescriptorHeapPool>(
|
|
|
|
texture_descriptor_pool_ = std::make_unique<D3D12DescriptorHeapPool>(
|
|
|
|
device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 2048);
|
|
|
|
device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 2048);
|
|
|
|
texture_descriptor_pool_heap_index_ =
|
|
|
|
|
|
|
|
D3D12DescriptorHeapPool::kHeapIndexInvalid;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Reset the current state.
|
|
|
|
// Reset the current state.
|
|
|
|
current_command_list_ = nullptr;
|
|
|
|
current_command_list_ = nullptr;
|
|
|
@ -306,11 +268,13 @@ bool D3D12ImmediateDrawer::Initialize() {
|
|
|
|
void D3D12ImmediateDrawer::Shutdown() {
|
|
|
|
void D3D12ImmediateDrawer::Shutdown() {
|
|
|
|
for (auto& texture_upload : texture_uploads_submitted_) {
|
|
|
|
for (auto& texture_upload : texture_uploads_submitted_) {
|
|
|
|
texture_upload.buffer->Release();
|
|
|
|
texture_upload.buffer->Release();
|
|
|
|
|
|
|
|
texture_upload.texture->Release();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
texture_uploads_submitted_.clear();
|
|
|
|
texture_uploads_submitted_.clear();
|
|
|
|
|
|
|
|
|
|
|
|
for (auto& texture_upload : texture_uploads_pending_) {
|
|
|
|
for (auto& texture_upload : texture_uploads_pending_) {
|
|
|
|
texture_upload.buffer->Release();
|
|
|
|
texture_upload.buffer->Release();
|
|
|
|
|
|
|
|
texture_upload.texture->Release();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
texture_uploads_pending_.clear();
|
|
|
|
texture_uploads_pending_.clear();
|
|
|
|
|
|
|
|
|
|
|
@ -319,8 +283,8 @@ void D3D12ImmediateDrawer::Shutdown() {
|
|
|
|
|
|
|
|
|
|
|
|
util::ReleaseAndNull(sampler_heap_);
|
|
|
|
util::ReleaseAndNull(sampler_heap_);
|
|
|
|
|
|
|
|
|
|
|
|
util::ReleaseAndNull(pipeline_line_);
|
|
|
|
util::ReleaseAndNull(pipeline_state_line_);
|
|
|
|
util::ReleaseAndNull(pipeline_triangle_);
|
|
|
|
util::ReleaseAndNull(pipeline_state_triangle_);
|
|
|
|
|
|
|
|
|
|
|
|
util::ReleaseAndNull(root_signature_);
|
|
|
|
util::ReleaseAndNull(root_signature_);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -328,93 +292,97 @@ void D3D12ImmediateDrawer::Shutdown() {
|
|
|
|
std::unique_ptr<ImmediateTexture> D3D12ImmediateDrawer::CreateTexture(
|
|
|
|
std::unique_ptr<ImmediateTexture> D3D12ImmediateDrawer::CreateTexture(
|
|
|
|
uint32_t width, uint32_t height, ImmediateTextureFilter filter, bool repeat,
|
|
|
|
uint32_t width, uint32_t height, ImmediateTextureFilter filter, bool repeat,
|
|
|
|
const uint8_t* data) {
|
|
|
|
const uint8_t* data) {
|
|
|
|
auto texture =
|
|
|
|
const D3D12Provider& provider = context_.GetD3D12Provider();
|
|
|
|
std::make_unique<D3D12ImmediateTexture>(width, height, filter, repeat);
|
|
|
|
ID3D12Device* device = provider.GetDevice();
|
|
|
|
texture->Initialize(context_.GetD3D12Provider());
|
|
|
|
D3D12_HEAP_FLAGS heap_flag_create_not_zeroed =
|
|
|
|
if (data != nullptr) {
|
|
|
|
provider.GetHeapFlagCreateNotZeroed();
|
|
|
|
UpdateTexture(texture.get(), data);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return std::unique_ptr<ImmediateTexture>(texture.release());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void D3D12ImmediateDrawer::UpdateTexture(ImmediateTexture* texture,
|
|
|
|
|
|
|
|
const uint8_t* data) {
|
|
|
|
|
|
|
|
D3D12ImmediateTexture* d3d_texture =
|
|
|
|
|
|
|
|
static_cast<D3D12ImmediateTexture*>(texture);
|
|
|
|
|
|
|
|
ID3D12Resource* texture_resource = d3d_texture->GetResource();
|
|
|
|
|
|
|
|
if (texture_resource == nullptr) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t width = d3d_texture->width, height = d3d_texture->height;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
auto& provider = context_.GetD3D12Provider();
|
|
|
|
|
|
|
|
auto device = provider.GetDevice();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
D3D12_RESOURCE_DESC resource_desc;
|
|
|
|
|
|
|
|
resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
|
|
|
|
|
|
|
resource_desc.Alignment = 0;
|
|
|
|
|
|
|
|
resource_desc.Width = width;
|
|
|
|
|
|
|
|
resource_desc.Height = height;
|
|
|
|
|
|
|
|
resource_desc.DepthOrArraySize = 1;
|
|
|
|
|
|
|
|
resource_desc.MipLevels = 1;
|
|
|
|
|
|
|
|
resource_desc.Format = D3D12ImmediateTexture::kFormat;
|
|
|
|
|
|
|
|
resource_desc.SampleDesc.Count = 1;
|
|
|
|
|
|
|
|
resource_desc.SampleDesc.Quality = 0;
|
|
|
|
|
|
|
|
resource_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
|
|
|
|
|
|
|
resource_desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
|
|
|
|
|
|
|
ID3D12Resource* resource;
|
|
|
|
|
|
|
|
if (SUCCEEDED(provider.GetDevice()->CreateCommittedResource(
|
|
|
|
|
|
|
|
&util::kHeapPropertiesDefault, heap_flag_create_not_zeroed,
|
|
|
|
|
|
|
|
&resource_desc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr,
|
|
|
|
|
|
|
|
IID_PPV_ARGS(&resource)))) {
|
|
|
|
// Create and fill the upload buffer.
|
|
|
|
// Create and fill the upload buffer.
|
|
|
|
D3D12_RESOURCE_DESC texture_desc = texture_resource->GetDesc();
|
|
|
|
|
|
|
|
D3D12_PLACED_SUBRESOURCE_FOOTPRINT upload_footprint;
|
|
|
|
D3D12_PLACED_SUBRESOURCE_FOOTPRINT upload_footprint;
|
|
|
|
UINT64 upload_size;
|
|
|
|
UINT64 upload_size;
|
|
|
|
device->GetCopyableFootprints(&texture_desc, 0, 1, 0, &upload_footprint,
|
|
|
|
device->GetCopyableFootprints(&resource_desc, 0, 1, 0, &upload_footprint,
|
|
|
|
nullptr, nullptr, &upload_size);
|
|
|
|
nullptr, nullptr, &upload_size);
|
|
|
|
D3D12_RESOURCE_DESC buffer_desc;
|
|
|
|
D3D12_RESOURCE_DESC upload_buffer_desc;
|
|
|
|
util::FillBufferResourceDesc(buffer_desc, upload_size,
|
|
|
|
util::FillBufferResourceDesc(upload_buffer_desc, upload_size,
|
|
|
|
D3D12_RESOURCE_FLAG_NONE);
|
|
|
|
D3D12_RESOURCE_FLAG_NONE);
|
|
|
|
ID3D12Resource* buffer;
|
|
|
|
ID3D12Resource* upload_buffer;
|
|
|
|
if (FAILED(device->CreateCommittedResource(
|
|
|
|
if (SUCCEEDED(device->CreateCommittedResource(
|
|
|
|
&util::kHeapPropertiesUpload, provider.GetHeapFlagCreateNotZeroed(),
|
|
|
|
&util::kHeapPropertiesUpload, heap_flag_create_not_zeroed,
|
|
|
|
&buffer_desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr,
|
|
|
|
&upload_buffer_desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr,
|
|
|
|
IID_PPV_ARGS(&buffer)))) {
|
|
|
|
IID_PPV_ARGS(&upload_buffer)))) {
|
|
|
|
|
|
|
|
D3D12_RANGE upload_buffer_read_range;
|
|
|
|
|
|
|
|
upload_buffer_read_range.Begin = 0;
|
|
|
|
|
|
|
|
upload_buffer_read_range.End = 0;
|
|
|
|
|
|
|
|
void* upload_buffer_mapping;
|
|
|
|
|
|
|
|
if (SUCCEEDED(upload_buffer->Map(0, &upload_buffer_read_range,
|
|
|
|
|
|
|
|
&upload_buffer_mapping))) {
|
|
|
|
|
|
|
|
uint8_t* upload_buffer_row =
|
|
|
|
|
|
|
|
reinterpret_cast<uint8_t*>(upload_buffer_mapping) +
|
|
|
|
|
|
|
|
upload_footprint.Offset;
|
|
|
|
|
|
|
|
const uint8_t* data_row = data;
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < height; ++i) {
|
|
|
|
|
|
|
|
std::memcpy(upload_buffer_row, data_row, width * 4);
|
|
|
|
|
|
|
|
data_row += width * 4;
|
|
|
|
|
|
|
|
upload_buffer_row += upload_footprint.Footprint.RowPitch;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
upload_buffer->Unmap(0, nullptr);
|
|
|
|
|
|
|
|
// Defer uploading and transition to the next draw.
|
|
|
|
|
|
|
|
PendingTextureUpload pending_upload;
|
|
|
|
|
|
|
|
// While the upload has not been yet completed, keep a reference to the
|
|
|
|
|
|
|
|
// resource because its lifetime is not tied to that of the
|
|
|
|
|
|
|
|
// ImmediateTexture (and thus to context's submissions) now.
|
|
|
|
|
|
|
|
resource->AddRef();
|
|
|
|
|
|
|
|
pending_upload.texture = resource;
|
|
|
|
|
|
|
|
pending_upload.buffer = upload_buffer;
|
|
|
|
|
|
|
|
texture_uploads_pending_.push_back(pending_upload);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
XELOGE(
|
|
|
|
XELOGE(
|
|
|
|
"Failed to create an upload buffer for a {}x{} texture for "
|
|
|
|
"Failed to map a Direct3D 12 upload buffer for a {}x{} texture for "
|
|
|
|
"immediate drawing",
|
|
|
|
"immediate drawing",
|
|
|
|
width, height);
|
|
|
|
width, height);
|
|
|
|
return;
|
|
|
|
upload_buffer->Release();
|
|
|
|
|
|
|
|
resource->Release();
|
|
|
|
|
|
|
|
resource = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
D3D12_RANGE buffer_read_range;
|
|
|
|
|
|
|
|
buffer_read_range.Begin = 0;
|
|
|
|
|
|
|
|
buffer_read_range.End = 0;
|
|
|
|
|
|
|
|
void* buffer_mapping;
|
|
|
|
|
|
|
|
if (FAILED(buffer->Map(0, &buffer_read_range, &buffer_mapping))) {
|
|
|
|
|
|
|
|
XELOGE(
|
|
|
|
|
|
|
|
"Failed to map an upload buffer for a {}x{} texture for immediate "
|
|
|
|
|
|
|
|
"drawing",
|
|
|
|
|
|
|
|
width, height);
|
|
|
|
|
|
|
|
buffer->Release();
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t* buffer_row =
|
|
|
|
|
|
|
|
reinterpret_cast<uint8_t*>(buffer_mapping) + upload_footprint.Offset;
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < height; ++i) {
|
|
|
|
|
|
|
|
std::memcpy(buffer_row, data, width * 4);
|
|
|
|
|
|
|
|
data += width * 4;
|
|
|
|
|
|
|
|
buffer_row += upload_footprint.Footprint.RowPitch;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer->Unmap(0, nullptr);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (current_command_list_ != nullptr) {
|
|
|
|
|
|
|
|
// Upload the texture right now if we can.
|
|
|
|
|
|
|
|
d3d_texture->Transition(D3D12_RESOURCE_STATE_COPY_DEST,
|
|
|
|
|
|
|
|
current_command_list_);
|
|
|
|
|
|
|
|
D3D12_TEXTURE_COPY_LOCATION location_source, location_dest;
|
|
|
|
|
|
|
|
location_source.pResource = buffer;
|
|
|
|
|
|
|
|
location_source.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
|
|
|
|
|
|
|
|
location_source.PlacedFootprint = upload_footprint;
|
|
|
|
|
|
|
|
location_dest.pResource = texture_resource;
|
|
|
|
|
|
|
|
location_dest.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
|
|
|
|
|
|
|
location_dest.SubresourceIndex = 0;
|
|
|
|
|
|
|
|
current_command_list_->CopyTextureRegion(&location_dest, 0, 0, 0,
|
|
|
|
|
|
|
|
&location_source, nullptr);
|
|
|
|
|
|
|
|
SubmittedTextureUpload submitted_upload;
|
|
|
|
|
|
|
|
submitted_upload.buffer = buffer;
|
|
|
|
|
|
|
|
submitted_upload.fence_value = context_.GetSwapCurrentFenceValue();
|
|
|
|
|
|
|
|
texture_uploads_submitted_.push_back(submitted_upload);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
// Defer uploading to the next frame when there's a command list.
|
|
|
|
XELOGE(
|
|
|
|
PendingTextureUpload pending_upload;
|
|
|
|
"Failed to create a Direct3D 12 upload buffer for a {}x{} texture "
|
|
|
|
pending_upload.texture = texture;
|
|
|
|
"for immediate drawing",
|
|
|
|
pending_upload.buffer = buffer;
|
|
|
|
width, height);
|
|
|
|
texture_uploads_pending_.push_back(pending_upload);
|
|
|
|
resource->Release();
|
|
|
|
|
|
|
|
resource = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
XELOGE("Failed to create a {}x{} Direct3D 12 texture for immediate drawing",
|
|
|
|
|
|
|
|
width, height);
|
|
|
|
|
|
|
|
resource = nullptr;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<D3D12ImmediateTexture> texture =
|
|
|
|
|
|
|
|
std::make_unique<D3D12ImmediateTexture>(width, height, resource, filter,
|
|
|
|
|
|
|
|
repeat);
|
|
|
|
|
|
|
|
if (resource) {
|
|
|
|
|
|
|
|
// D3D12ImmediateTexture now holds a reference.
|
|
|
|
|
|
|
|
resource->Release();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return std::move(texture);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void D3D12ImmediateDrawer::Begin(int render_target_width,
|
|
|
|
void D3D12ImmediateDrawer::Begin(int render_target_width,
|
|
|
@ -422,7 +390,7 @@ void D3D12ImmediateDrawer::Begin(int render_target_width,
|
|
|
|
assert_null(current_command_list_);
|
|
|
|
assert_null(current_command_list_);
|
|
|
|
assert_false(batch_open_);
|
|
|
|
assert_false(batch_open_);
|
|
|
|
|
|
|
|
|
|
|
|
auto device = context_.GetD3D12Provider().GetDevice();
|
|
|
|
ID3D12Device* device = context_.GetD3D12Provider().GetDevice();
|
|
|
|
|
|
|
|
|
|
|
|
// Use the compositing command list.
|
|
|
|
// Use the compositing command list.
|
|
|
|
current_command_list_ = context_.GetSwapCommandList();
|
|
|
|
current_command_list_ = context_.GetSwapCommandList();
|
|
|
@ -430,7 +398,7 @@ void D3D12ImmediateDrawer::Begin(int render_target_width,
|
|
|
|
uint64_t completed_fence_value = context_.GetSwapCompletedFenceValue();
|
|
|
|
uint64_t completed_fence_value = context_.GetSwapCompletedFenceValue();
|
|
|
|
uint64_t current_fence_value = context_.GetSwapCurrentFenceValue();
|
|
|
|
uint64_t current_fence_value = context_.GetSwapCurrentFenceValue();
|
|
|
|
|
|
|
|
|
|
|
|
// Remove temporary buffers for completed texture uploads.
|
|
|
|
// Release upload buffers for completed texture uploads.
|
|
|
|
auto erase_uploads_end = texture_uploads_submitted_.begin();
|
|
|
|
auto erase_uploads_end = texture_uploads_submitted_.begin();
|
|
|
|
while (erase_uploads_end != texture_uploads_submitted_.end()) {
|
|
|
|
while (erase_uploads_end != texture_uploads_submitted_.end()) {
|
|
|
|
uint64_t upload_fence_value = erase_uploads_end->fence_value;
|
|
|
|
uint64_t upload_fence_value = erase_uploads_end->fence_value;
|
|
|
@ -439,42 +407,15 @@ void D3D12ImmediateDrawer::Begin(int render_target_width,
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
erase_uploads_end->buffer->Release();
|
|
|
|
erase_uploads_end->buffer->Release();
|
|
|
|
|
|
|
|
// Release the texture reference held for uploading.
|
|
|
|
|
|
|
|
erase_uploads_end->texture->Release();
|
|
|
|
++erase_uploads_end;
|
|
|
|
++erase_uploads_end;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
texture_uploads_submitted_.erase(texture_uploads_submitted_.begin(),
|
|
|
|
texture_uploads_submitted_.erase(texture_uploads_submitted_.begin(),
|
|
|
|
erase_uploads_end);
|
|
|
|
erase_uploads_end);
|
|
|
|
|
|
|
|
|
|
|
|
// Submit texture updates that happened between frames.
|
|
|
|
|
|
|
|
while (!texture_uploads_pending_.empty()) {
|
|
|
|
|
|
|
|
const PendingTextureUpload& pending_upload =
|
|
|
|
|
|
|
|
texture_uploads_pending_.back();
|
|
|
|
|
|
|
|
D3D12ImmediateTexture* texture =
|
|
|
|
|
|
|
|
static_cast<D3D12ImmediateTexture*>(pending_upload.texture);
|
|
|
|
|
|
|
|
texture->Transition(D3D12_RESOURCE_STATE_COPY_DEST, current_command_list_);
|
|
|
|
|
|
|
|
ID3D12Resource* texture_resource = texture->GetResource();
|
|
|
|
|
|
|
|
D3D12_RESOURCE_DESC texture_desc = texture_resource->GetDesc();
|
|
|
|
|
|
|
|
D3D12_TEXTURE_COPY_LOCATION location_source, location_dest;
|
|
|
|
|
|
|
|
location_source.pResource = pending_upload.buffer;
|
|
|
|
|
|
|
|
location_source.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
|
|
|
|
|
|
|
|
device->GetCopyableFootprints(&texture_desc, 0, 1, 0,
|
|
|
|
|
|
|
|
&location_source.PlacedFootprint, nullptr,
|
|
|
|
|
|
|
|
nullptr, nullptr);
|
|
|
|
|
|
|
|
location_dest.pResource = texture_resource;
|
|
|
|
|
|
|
|
location_dest.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
|
|
|
|
|
|
|
location_dest.SubresourceIndex = 0;
|
|
|
|
|
|
|
|
current_command_list_->CopyTextureRegion(&location_dest, 0, 0, 0,
|
|
|
|
|
|
|
|
&location_source, nullptr);
|
|
|
|
|
|
|
|
SubmittedTextureUpload submitted_upload;
|
|
|
|
|
|
|
|
submitted_upload.buffer = pending_upload.buffer;
|
|
|
|
|
|
|
|
submitted_upload.fence_value = current_fence_value;
|
|
|
|
|
|
|
|
texture_uploads_submitted_.push_back(submitted_upload);
|
|
|
|
|
|
|
|
texture_uploads_pending_.pop_back();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vertex_buffer_pool_->Reclaim(completed_fence_value);
|
|
|
|
vertex_buffer_pool_->Reclaim(completed_fence_value);
|
|
|
|
texture_descriptor_pool_->Reclaim(completed_fence_value);
|
|
|
|
texture_descriptor_pool_->Reclaim(completed_fence_value);
|
|
|
|
texture_descriptor_pool_heap_index_ =
|
|
|
|
|
|
|
|
D3D12DescriptorHeapPool::kHeapIndexInvalid;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
current_render_target_width_ = render_target_width;
|
|
|
|
current_render_target_width_ = render_target_width;
|
|
|
|
current_render_target_height_ = render_target_height;
|
|
|
|
current_render_target_height_ = render_target_height;
|
|
|
@ -486,10 +427,6 @@ void D3D12ImmediateDrawer::Begin(int render_target_width,
|
|
|
|
viewport.MinDepth = 0.0f;
|
|
|
|
viewport.MinDepth = 0.0f;
|
|
|
|
viewport.MaxDepth = 1.0f;
|
|
|
|
viewport.MaxDepth = 1.0f;
|
|
|
|
current_command_list_->RSSetViewports(1, &viewport);
|
|
|
|
current_command_list_->RSSetViewports(1, &viewport);
|
|
|
|
current_scissor_.left = 0;
|
|
|
|
|
|
|
|
current_scissor_.top = 0;
|
|
|
|
|
|
|
|
current_scissor_.right = 0;
|
|
|
|
|
|
|
|
current_scissor_.bottom = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
current_command_list_->SetGraphicsRootSignature(root_signature_);
|
|
|
|
current_command_list_->SetGraphicsRootSignature(root_signature_);
|
|
|
|
float viewport_inv_size[2];
|
|
|
|
float viewport_inv_size[2];
|
|
|
@ -498,8 +435,15 @@ void D3D12ImmediateDrawer::Begin(int render_target_width,
|
|
|
|
current_command_list_->SetGraphicsRoot32BitConstants(
|
|
|
|
current_command_list_->SetGraphicsRoot32BitConstants(
|
|
|
|
UINT(RootParameter::kViewportSizeInv), 2, viewport_inv_size, 0);
|
|
|
|
UINT(RootParameter::kViewportSizeInv), 2, viewport_inv_size, 0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
current_scissor_.left = 0;
|
|
|
|
|
|
|
|
current_scissor_.top = 0;
|
|
|
|
|
|
|
|
current_scissor_.right = 0;
|
|
|
|
|
|
|
|
current_scissor_.bottom = 0;
|
|
|
|
|
|
|
|
|
|
|
|
current_primitive_topology_ = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;
|
|
|
|
current_primitive_topology_ = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;
|
|
|
|
current_texture_ = nullptr;
|
|
|
|
current_texture_ = nullptr;
|
|
|
|
|
|
|
|
current_texture_descriptor_heap_index_ =
|
|
|
|
|
|
|
|
D3D12DescriptorHeapPool::kHeapIndexInvalid;
|
|
|
|
current_sampler_index_ = SamplerIndex::kInvalid;
|
|
|
|
current_sampler_index_ = SamplerIndex::kInvalid;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -554,9 +498,6 @@ void D3D12ImmediateDrawer::Draw(const ImmediateDraw& draw) {
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
auto& provider = context_.GetD3D12Provider();
|
|
|
|
|
|
|
|
auto device = provider.GetDevice();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Set the scissor rectangle if enabled.
|
|
|
|
// Set the scissor rectangle if enabled.
|
|
|
|
D3D12_RECT scissor;
|
|
|
|
D3D12_RECT scissor;
|
|
|
|
if (draw.scissor) {
|
|
|
|
if (draw.scissor) {
|
|
|
@ -583,43 +524,56 @@ void D3D12ImmediateDrawer::Draw(const ImmediateDraw& draw) {
|
|
|
|
current_command_list_->RSSetScissorRects(1, &scissor);
|
|
|
|
current_command_list_->RSSetScissorRects(1, &scissor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Bind the texture.
|
|
|
|
// Ensure texture data is available if any texture is loaded, upload all in a
|
|
|
|
|
|
|
|
// batch, then transition all at once.
|
|
|
|
|
|
|
|
UploadTextures();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
auto texture = reinterpret_cast<D3D12ImmediateTexture*>(draw.texture_handle);
|
|
|
|
ID3D12Resource* texture_resource;
|
|
|
|
ID3D12Resource* texture_resource = texture ? texture->resource() : nullptr;
|
|
|
|
if (texture != nullptr) {
|
|
|
|
bool bind_texture = current_texture_ != texture_resource;
|
|
|
|
texture->Transition(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
|
|
|
|
|
|
|
|
current_command_list_);
|
|
|
|
|
|
|
|
texture_resource = texture->GetResource();
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
texture_resource = nullptr;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
bool bind_texture = current_texture_ != texture;
|
|
|
|
|
|
|
|
uint32_t texture_descriptor_index;
|
|
|
|
uint32_t texture_descriptor_index;
|
|
|
|
uint64_t texture_heap_index = texture_descriptor_pool_->Request(
|
|
|
|
uint64_t texture_heap_index = texture_descriptor_pool_->Request(
|
|
|
|
context_.GetSwapCurrentFenceValue(), texture_descriptor_pool_heap_index_,
|
|
|
|
context_.GetSwapCurrentFenceValue(),
|
|
|
|
bind_texture ? 1 : 0, 1, texture_descriptor_index);
|
|
|
|
current_texture_descriptor_heap_index_, bind_texture ? 1 : 0, 1,
|
|
|
|
|
|
|
|
texture_descriptor_index);
|
|
|
|
if (texture_heap_index == D3D12DescriptorHeapPool::kHeapIndexInvalid) {
|
|
|
|
if (texture_heap_index == D3D12DescriptorHeapPool::kHeapIndexInvalid) {
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (texture_descriptor_pool_heap_index_ != texture_heap_index) {
|
|
|
|
if (current_texture_descriptor_heap_index_ != texture_heap_index) {
|
|
|
|
|
|
|
|
current_texture_descriptor_heap_index_ = texture_heap_index;
|
|
|
|
bind_texture = true;
|
|
|
|
bind_texture = true;
|
|
|
|
texture_descriptor_pool_heap_index_ = texture_heap_index;
|
|
|
|
|
|
|
|
ID3D12DescriptorHeap* descriptor_heaps[] = {
|
|
|
|
ID3D12DescriptorHeap* descriptor_heaps[] = {
|
|
|
|
texture_descriptor_pool_->GetLastRequestHeap(), sampler_heap_};
|
|
|
|
texture_descriptor_pool_->GetLastRequestHeap(), sampler_heap_};
|
|
|
|
current_command_list_->SetDescriptorHeaps(2, descriptor_heaps);
|
|
|
|
current_command_list_->SetDescriptorHeaps(2, descriptor_heaps);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const D3D12Provider& provider = context_.GetD3D12Provider();
|
|
|
|
|
|
|
|
|
|
|
|
if (bind_texture) {
|
|
|
|
if (bind_texture) {
|
|
|
|
current_texture_ = texture;
|
|
|
|
current_texture_ = texture_resource;
|
|
|
|
D3D12_SHADER_RESOURCE_VIEW_DESC texture_view_desc;
|
|
|
|
D3D12_SHADER_RESOURCE_VIEW_DESC texture_view_desc;
|
|
|
|
texture_view_desc.Format = D3D12ImmediateTexture::kFormat;
|
|
|
|
texture_view_desc.Format = D3D12ImmediateTexture::kFormat;
|
|
|
|
texture_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
|
|
|
texture_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
|
|
|
|
|
|
|
if (texture_resource) {
|
|
|
|
texture_view_desc.Shader4ComponentMapping =
|
|
|
|
texture_view_desc.Shader4ComponentMapping =
|
|
|
|
D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
|
|
|
D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// No texture, solid color.
|
|
|
|
|
|
|
|
texture_view_desc.Shader4ComponentMapping =
|
|
|
|
|
|
|
|
D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(
|
|
|
|
|
|
|
|
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1,
|
|
|
|
|
|
|
|
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1,
|
|
|
|
|
|
|
|
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1,
|
|
|
|
|
|
|
|
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1);
|
|
|
|
|
|
|
|
}
|
|
|
|
texture_view_desc.Texture2D.MostDetailedMip = 0;
|
|
|
|
texture_view_desc.Texture2D.MostDetailedMip = 0;
|
|
|
|
texture_view_desc.Texture2D.MipLevels = 1;
|
|
|
|
texture_view_desc.Texture2D.MipLevels = 1;
|
|
|
|
texture_view_desc.Texture2D.PlaneSlice = 0;
|
|
|
|
texture_view_desc.Texture2D.PlaneSlice = 0;
|
|
|
|
texture_view_desc.Texture2D.ResourceMinLODClamp = 0.0f;
|
|
|
|
texture_view_desc.Texture2D.ResourceMinLODClamp = 0.0f;
|
|
|
|
device->CreateShaderResourceView(
|
|
|
|
provider.GetDevice()->CreateShaderResourceView(
|
|
|
|
texture_resource, &texture_view_desc,
|
|
|
|
texture_resource, &texture_view_desc,
|
|
|
|
provider.OffsetViewDescriptor(
|
|
|
|
provider.OffsetViewDescriptor(
|
|
|
|
texture_descriptor_pool_->GetLastRequestHeapCPUStart(),
|
|
|
|
texture_descriptor_pool_->GetLastRequestHeapCPUStart(),
|
|
|
@ -634,11 +588,11 @@ void D3D12ImmediateDrawer::Draw(const ImmediateDraw& draw) {
|
|
|
|
// Bind the sampler.
|
|
|
|
// Bind the sampler.
|
|
|
|
SamplerIndex sampler_index;
|
|
|
|
SamplerIndex sampler_index;
|
|
|
|
if (texture != nullptr) {
|
|
|
|
if (texture != nullptr) {
|
|
|
|
if (texture->GetFilter() == ImmediateTextureFilter::kLinear) {
|
|
|
|
if (texture->filter() == ImmediateTextureFilter::kLinear) {
|
|
|
|
sampler_index = texture->IsRepeated() ? SamplerIndex::kLinearRepeat
|
|
|
|
sampler_index = texture->is_repeated() ? SamplerIndex::kLinearRepeat
|
|
|
|
: SamplerIndex::kLinearClamp;
|
|
|
|
: SamplerIndex::kLinearClamp;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
sampler_index = texture->IsRepeated() ? SamplerIndex::kNearestRepeat
|
|
|
|
sampler_index = texture->is_repeated() ? SamplerIndex::kNearestRepeat
|
|
|
|
: SamplerIndex::kNearestClamp;
|
|
|
|
: SamplerIndex::kNearestClamp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
@ -658,17 +612,17 @@ void D3D12ImmediateDrawer::Draw(const ImmediateDraw& draw) {
|
|
|
|
UINT(RootParameter::kRestrictTextureSamples), 1,
|
|
|
|
UINT(RootParameter::kRestrictTextureSamples), 1,
|
|
|
|
&restrict_texture_samples, 0);
|
|
|
|
&restrict_texture_samples, 0);
|
|
|
|
|
|
|
|
|
|
|
|
// Set the primitive type and the pipeline for it.
|
|
|
|
// Set the primitive type and the pipeline state for it.
|
|
|
|
D3D_PRIMITIVE_TOPOLOGY primitive_topology;
|
|
|
|
D3D_PRIMITIVE_TOPOLOGY primitive_topology;
|
|
|
|
ID3D12PipelineState* pipeline;
|
|
|
|
ID3D12PipelineState* pipeline_state;
|
|
|
|
switch (draw.primitive_type) {
|
|
|
|
switch (draw.primitive_type) {
|
|
|
|
case ImmediatePrimitiveType::kLines:
|
|
|
|
case ImmediatePrimitiveType::kLines:
|
|
|
|
primitive_topology = D3D_PRIMITIVE_TOPOLOGY_LINELIST;
|
|
|
|
primitive_topology = D3D_PRIMITIVE_TOPOLOGY_LINELIST;
|
|
|
|
pipeline = pipeline_line_;
|
|
|
|
pipeline_state = pipeline_state_line_;
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
case ImmediatePrimitiveType::kTriangles:
|
|
|
|
case ImmediatePrimitiveType::kTriangles:
|
|
|
|
primitive_topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
|
|
|
primitive_topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
|
|
|
pipeline = pipeline_triangle_;
|
|
|
|
pipeline_state = pipeline_state_triangle_;
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|
assert_unhandled_case(draw.primitive_type);
|
|
|
|
assert_unhandled_case(draw.primitive_type);
|
|
|
@ -677,7 +631,7 @@ void D3D12ImmediateDrawer::Draw(const ImmediateDraw& draw) {
|
|
|
|
if (current_primitive_topology_ != primitive_topology) {
|
|
|
|
if (current_primitive_topology_ != primitive_topology) {
|
|
|
|
current_primitive_topology_ = primitive_topology;
|
|
|
|
current_primitive_topology_ = primitive_topology;
|
|
|
|
current_command_list_->IASetPrimitiveTopology(primitive_topology);
|
|
|
|
current_command_list_->IASetPrimitiveTopology(primitive_topology);
|
|
|
|
current_command_list_->SetPipelineState(pipeline);
|
|
|
|
current_command_list_->SetPipelineState(pipeline_state);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Draw.
|
|
|
|
// Draw.
|
|
|
@ -693,8 +647,66 @@ void D3D12ImmediateDrawer::EndDrawBatch() { batch_open_ = false; }
|
|
|
|
|
|
|
|
|
|
|
|
void D3D12ImmediateDrawer::End() {
|
|
|
|
void D3D12ImmediateDrawer::End() {
|
|
|
|
assert_false(batch_open_);
|
|
|
|
assert_false(batch_open_);
|
|
|
|
|
|
|
|
if (current_command_list_) {
|
|
|
|
|
|
|
|
// Don't keep upload buffers forever if nothing was drawn in this frame.
|
|
|
|
|
|
|
|
UploadTextures();
|
|
|
|
current_command_list_ = nullptr;
|
|
|
|
current_command_list_ = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void D3D12ImmediateDrawer::UploadTextures() {
|
|
|
|
|
|
|
|
assert_not_null(current_command_list_);
|
|
|
|
|
|
|
|
if (texture_uploads_pending_.empty()) {
|
|
|
|
|
|
|
|
// Called often - don't initialize anything.
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ID3D12Device* device = context_.GetD3D12Provider().GetDevice();
|
|
|
|
|
|
|
|
uint64_t current_fence_value = context_.GetSwapCurrentFenceValue();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Copy all at once, then transition all at once (not interleaving copying and
|
|
|
|
|
|
|
|
// pipeline barriers).
|
|
|
|
|
|
|
|
std::vector<D3D12_RESOURCE_BARRIER> barriers;
|
|
|
|
|
|
|
|
barriers.reserve(texture_uploads_pending_.size());
|
|
|
|
|
|
|
|
while (!texture_uploads_pending_.empty()) {
|
|
|
|
|
|
|
|
const PendingTextureUpload& pending_upload =
|
|
|
|
|
|
|
|
texture_uploads_pending_.back();
|
|
|
|
|
|
|
|
ID3D12Resource* texture = pending_upload.texture;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
D3D12_RESOURCE_DESC texture_desc = texture->GetDesc();
|
|
|
|
|
|
|
|
D3D12_TEXTURE_COPY_LOCATION location_source, location_dest;
|
|
|
|
|
|
|
|
location_source.pResource = pending_upload.buffer;
|
|
|
|
|
|
|
|
location_source.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
|
|
|
|
|
|
|
|
device->GetCopyableFootprints(&texture_desc, 0, 1, 0,
|
|
|
|
|
|
|
|
&location_source.PlacedFootprint, nullptr,
|
|
|
|
|
|
|
|
nullptr, nullptr);
|
|
|
|
|
|
|
|
location_dest.pResource = texture;
|
|
|
|
|
|
|
|
location_dest.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
|
|
|
|
|
|
|
location_dest.SubresourceIndex = 0;
|
|
|
|
|
|
|
|
current_command_list_->CopyTextureRegion(&location_dest, 0, 0, 0,
|
|
|
|
|
|
|
|
&location_source, nullptr);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
D3D12_RESOURCE_BARRIER& barrier = barriers.emplace_back();
|
|
|
|
|
|
|
|
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
|
|
|
|
|
|
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
|
|
|
|
|
|
barrier.Transition.pResource = texture;
|
|
|
|
|
|
|
|
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
|
|
|
|
|
|
|
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
|
|
|
|
|
|
|
|
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SubmittedTextureUpload submitted_upload;
|
|
|
|
|
|
|
|
// Transfer the reference to the texture - need to keep it until the upload
|
|
|
|
|
|
|
|
// is completed.
|
|
|
|
|
|
|
|
submitted_upload.texture = texture;
|
|
|
|
|
|
|
|
submitted_upload.buffer = pending_upload.buffer;
|
|
|
|
|
|
|
|
submitted_upload.fence_value = current_fence_value;
|
|
|
|
|
|
|
|
texture_uploads_submitted_.push_back(submitted_upload);
|
|
|
|
|
|
|
|
texture_uploads_pending_.pop_back();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
assert_false(barriers.empty());
|
|
|
|
|
|
|
|
current_command_list_->ResourceBarrier(UINT(barriers.size()),
|
|
|
|
|
|
|
|
barriers.data());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace d3d12
|
|
|
|
} // namespace d3d12
|
|
|
|
} // namespace ui
|
|
|
|
} // namespace ui
|
|
|
|