[D3D12] Immediate drawer
This commit is contained in:
parent
e572f65d11
commit
bf0f20df9b
|
@ -256,6 +256,10 @@ void D3D12Context::BeginSwap() {
|
|||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
|
||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||
graphics_command_list->ResourceBarrier(1, &barrier);
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE back_buffer_rtv = GetSwapChainBackBufferRTV();
|
||||
graphics_command_list->OMSetRenderTargets(1, &back_buffer_rtv, TRUE,
|
||||
nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,11 @@
|
|||
|
||||
#include "xenia/ui/d3d12/d3d12_immediate_drawer.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/math.h"
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
|
@ -21,10 +25,87 @@ namespace d3d12 {
|
|||
|
||||
class D3D12ImmediateTexture : public ImmediateTexture {
|
||||
public:
|
||||
D3D12ImmediateTexture(uint32_t width, uint32_t height)
|
||||
: ImmediateTexture(width, height) {}
|
||||
static constexpr DXGI_FORMAT kFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
|
||||
D3D12ImmediateTexture(uint32_t width, uint32_t height,
|
||||
ImmediateTextureFilter filter, bool repeat);
|
||||
|
||||
bool Initialize(ID3D12Device* device);
|
||||
void Shutdown();
|
||||
|
||||
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:
|
||||
ID3D12Resource* resource_ = nullptr;
|
||||
D3D12_RESOURCE_STATES state_;
|
||||
ImmediateTextureFilter filter_;
|
||||
bool repeat_;
|
||||
};
|
||||
|
||||
D3D12ImmediateTexture::D3D12ImmediateTexture(uint32_t width, uint32_t height,
|
||||
ImmediateTextureFilter filter,
|
||||
bool repeat)
|
||||
: ImmediateTexture(width, height), filter_(filter), repeat_(repeat) {
|
||||
handle = reinterpret_cast<uintptr_t>(this);
|
||||
}
|
||||
|
||||
bool D3D12ImmediateTexture::Initialize(ID3D12Device* device) {
|
||||
// The first operation will likely be copying the contents.
|
||||
state_ = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||
|
||||
D3D12_HEAP_PROPERTIES heap_properties = {};
|
||||
heap_properties.Type = D3D12_HEAP_TYPE_DEFAULT;
|
||||
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(device->CreateCommittedResource(
|
||||
&heap_properties, D3D12_HEAP_FLAG_NONE, &resource_desc, state_,
|
||||
nullptr, IID_PPV_ARGS(&resource_)))) {
|
||||
XELOGE("Failed to create a %ux%u texture for immediate drawing", width,
|
||||
height);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void D3D12ImmediateTexture::Shutdown() {
|
||||
if (resource_ != nullptr) {
|
||||
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)
|
||||
: ImmediateDrawer(graphics_context), context_(graphics_context) {}
|
||||
|
||||
|
@ -37,6 +118,15 @@ bool D3D12ImmediateDrawer::Initialize() {
|
|||
// Create the root signature.
|
||||
D3D12_ROOT_PARAMETER root_parameters[size_t(RootParameter::kCount)];
|
||||
D3D12_DESCRIPTOR_RANGE descriptor_range_texture, descriptor_range_sampler;
|
||||
{
|
||||
auto& root_parameter =
|
||||
root_parameters[size_t(RootParameter::kRestrictTextureSamples)];
|
||||
root_parameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
|
||||
root_parameter.Constants.ShaderRegister = 0;
|
||||
root_parameter.Constants.RegisterSpace = 0;
|
||||
root_parameter.Constants.Num32BitValues = 1;
|
||||
root_parameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
||||
}
|
||||
{
|
||||
auto& root_parameter = root_parameters[size_t(RootParameter::kTexture)];
|
||||
root_parameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
||||
|
@ -63,15 +153,6 @@ bool D3D12ImmediateDrawer::Initialize() {
|
|||
descriptor_range_sampler.OffsetInDescriptorsFromTableStart = 0;
|
||||
root_parameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
||||
}
|
||||
{
|
||||
auto& root_parameter =
|
||||
root_parameters[size_t(RootParameter::kRestrictTextureSamples)];
|
||||
root_parameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
|
||||
root_parameter.Constants.ShaderRegister = 0;
|
||||
root_parameter.Constants.RegisterSpace = 0;
|
||||
root_parameter.Constants.Num32BitValues = 1;
|
||||
root_parameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
||||
}
|
||||
{
|
||||
auto& root_parameter =
|
||||
root_parameters[size_t(RootParameter::kViewportInvSize)];
|
||||
|
@ -89,13 +170,22 @@ bool D3D12ImmediateDrawer::Initialize() {
|
|||
root_signature_desc.Flags =
|
||||
D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
|
||||
ID3DBlob* root_signature_blob;
|
||||
if (FAILED(D3D12SerializeRootSignature(&root_signature_desc,
|
||||
D3D_ROOT_SIGNATURE_VERSION_1,
|
||||
&root_signature_blob, nullptr))) {
|
||||
ID3DBlob* root_signature_error_blob = nullptr;
|
||||
if (FAILED(D3D12SerializeRootSignature(
|
||||
&root_signature_desc, D3D_ROOT_SIGNATURE_VERSION_1,
|
||||
&root_signature_blob, &root_signature_error_blob))) {
|
||||
XELOGE("Failed to serialize immediate drawer root signature");
|
||||
if (root_signature_error_blob != nullptr) {
|
||||
XELOGE("%s", reinterpret_cast<const char*>(
|
||||
root_signature_error_blob->GetBufferPointer()));
|
||||
root_signature_error_blob->Release();
|
||||
}
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
if (root_signature_error_blob != nullptr) {
|
||||
root_signature_error_blob->Release();
|
||||
}
|
||||
if (FAILED(device->CreateRootSignature(
|
||||
0, root_signature_blob->GetBufferPointer(),
|
||||
root_signature_blob->GetBufferSize(),
|
||||
|
@ -107,6 +197,58 @@ bool D3D12ImmediateDrawer::Initialize() {
|
|||
}
|
||||
root_signature_blob->Release();
|
||||
|
||||
// Create the pipelines.
|
||||
D3D12_GRAPHICS_PIPELINE_STATE_DESC pipeline_desc = {};
|
||||
pipeline_desc.pRootSignature = root_signature_;
|
||||
pipeline_desc.VS.pShaderBytecode = immediate_vs;
|
||||
pipeline_desc.VS.BytecodeLength = sizeof(immediate_vs);
|
||||
pipeline_desc.PS.pShaderBytecode = immediate_ps;
|
||||
pipeline_desc.PS.BytecodeLength = sizeof(immediate_ps);
|
||||
D3D12_RENDER_TARGET_BLEND_DESC& pipeline_blend_desc =
|
||||
pipeline_desc.BlendState.RenderTarget[0];
|
||||
pipeline_blend_desc.BlendEnable = TRUE;
|
||||
pipeline_blend_desc.SrcBlend = D3D12_BLEND_SRC_ALPHA;
|
||||
pipeline_blend_desc.DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
|
||||
pipeline_blend_desc.BlendOp = D3D12_BLEND_OP_ADD;
|
||||
pipeline_blend_desc.SrcBlendAlpha = D3D12_BLEND_SRC_ALPHA;
|
||||
pipeline_blend_desc.DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA;
|
||||
pipeline_blend_desc.BlendOpAlpha = D3D12_BLEND_OP_ADD;
|
||||
pipeline_blend_desc.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
|
||||
pipeline_desc.SampleMask = UINT_MAX;
|
||||
pipeline_desc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
|
||||
pipeline_desc.RasterizerState.CullMode = D3D12_CULL_MODE_BACK;
|
||||
pipeline_desc.RasterizerState.DepthClipEnable = TRUE;
|
||||
D3D12_INPUT_ELEMENT_DESC pipeline_input_elements[3] = {};
|
||||
pipeline_input_elements[0].SemanticName = "POSITION";
|
||||
pipeline_input_elements[0].Format = DXGI_FORMAT_R32G32_FLOAT;
|
||||
pipeline_input_elements[0].AlignedByteOffset = 0;
|
||||
pipeline_input_elements[1].SemanticName = "TEXCOORD";
|
||||
pipeline_input_elements[1].Format = DXGI_FORMAT_R32G32_FLOAT;
|
||||
pipeline_input_elements[1].AlignedByteOffset = 8;
|
||||
pipeline_input_elements[2].SemanticName = "COLOR";
|
||||
pipeline_input_elements[2].Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
pipeline_input_elements[2].AlignedByteOffset = 16;
|
||||
pipeline_desc.InputLayout.pInputElementDescs = pipeline_input_elements;
|
||||
pipeline_desc.InputLayout.NumElements =
|
||||
UINT(xe::countof(pipeline_input_elements));
|
||||
pipeline_desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
pipeline_desc.NumRenderTargets = 1;
|
||||
pipeline_desc.RTVFormats[0] = D3D12Context::kSwapChainFormat;
|
||||
pipeline_desc.SampleDesc.Count = 1;
|
||||
if (FAILED(device->CreateGraphicsPipelineState(
|
||||
&pipeline_desc, IID_PPV_ARGS(&pipeline_triangle_)))) {
|
||||
XELOGE("Failed to create immediate drawer triangle pipeline state");
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
pipeline_desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
|
||||
if (FAILED(device->CreateGraphicsPipelineState(
|
||||
&pipeline_desc, IID_PPV_ARGS(&pipeline_line_)))) {
|
||||
XELOGE("Failed to create immediate drawer line pipeline state");
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create the samplers.
|
||||
D3D12_DESCRIPTOR_HEAP_DESC sampler_heap_desc;
|
||||
sampler_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER;
|
||||
|
@ -160,6 +302,12 @@ bool D3D12ImmediateDrawer::Initialize() {
|
|||
uint32_t(SamplerIndex::kLinearRepeat) * sampler_size;
|
||||
device->CreateSampler(&sampler_desc, sampler_handle);
|
||||
|
||||
// Create pools for draws.
|
||||
vertex_buffer_pool_ =
|
||||
std::make_unique<UploadBufferPool>(context_, 2 * 1024 * 1024);
|
||||
texture_descriptor_pool_ = std::make_unique<DescriptorHeapPool>(
|
||||
context_, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 2048);
|
||||
|
||||
// Reset the current state.
|
||||
current_command_list_ = nullptr;
|
||||
|
||||
|
@ -168,15 +316,32 @@ bool D3D12ImmediateDrawer::Initialize() {
|
|||
|
||||
void D3D12ImmediateDrawer::Shutdown() {
|
||||
for (auto& texture_upload : texture_uploads_submitted_) {
|
||||
texture_upload.data_resource->Release();
|
||||
texture_upload.buffer->Release();
|
||||
}
|
||||
texture_uploads_submitted_.clear();
|
||||
|
||||
for (auto& texture_upload : texture_uploads_pending_) {
|
||||
texture_upload.buffer->Release();
|
||||
}
|
||||
texture_uploads_pending_.clear();
|
||||
|
||||
texture_descriptor_pool_.reset();
|
||||
vertex_buffer_pool_.reset();
|
||||
|
||||
if (sampler_heap_ != nullptr) {
|
||||
sampler_heap_->Release();
|
||||
sampler_heap_ = nullptr;
|
||||
}
|
||||
|
||||
if (pipeline_line_ != nullptr) {
|
||||
pipeline_line_->Release();
|
||||
pipeline_line_ = nullptr;
|
||||
}
|
||||
if (pipeline_triangle_ != nullptr) {
|
||||
pipeline_triangle_->Release();
|
||||
pipeline_triangle_ = nullptr;
|
||||
}
|
||||
|
||||
if (root_signature_ != nullptr) {
|
||||
root_signature_->Release();
|
||||
root_signature_ = nullptr;
|
||||
|
@ -186,22 +351,112 @@ void D3D12ImmediateDrawer::Shutdown() {
|
|||
std::unique_ptr<ImmediateTexture> D3D12ImmediateDrawer::CreateTexture(
|
||||
uint32_t width, uint32_t height, ImmediateTextureFilter filter, bool repeat,
|
||||
const uint8_t* data) {
|
||||
// TODO(Triang3l): Implement CreateTexture.
|
||||
auto texture = std::make_unique<D3D12ImmediateTexture>(width, height);
|
||||
auto texture =
|
||||
std::make_unique<D3D12ImmediateTexture>(width, height, filter, repeat);
|
||||
texture->Initialize(context_->GetD3D12Provider()->GetDevice());
|
||||
if (data != nullptr) {
|
||||
UpdateTexture(texture.get(), data);
|
||||
}
|
||||
return std::unique_ptr<ImmediateTexture>(texture.release());
|
||||
}
|
||||
|
||||
void D3D12ImmediateDrawer::UpdateTexture(ImmediateTexture* texture,
|
||||
const uint8_t* data) {
|
||||
// TODO(Triang3l): Implement UpdateTexture.
|
||||
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 device = context_->GetD3D12Provider()->GetDevice();
|
||||
|
||||
// Create and fill the upload buffer.
|
||||
D3D12_RESOURCE_DESC texture_desc = texture_resource->GetDesc();
|
||||
D3D12_PLACED_SUBRESOURCE_FOOTPRINT upload_footprint;
|
||||
UINT64 upload_size;
|
||||
device->GetCopyableFootprints(&texture_desc, 0, 1, 0, &upload_footprint,
|
||||
nullptr, nullptr, &upload_size);
|
||||
D3D12_HEAP_PROPERTIES heap_properties = {};
|
||||
heap_properties.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||
D3D12_RESOURCE_DESC buffer_desc;
|
||||
buffer_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||
buffer_desc.Alignment = 0;
|
||||
buffer_desc.Width = upload_size;
|
||||
buffer_desc.Height = 1;
|
||||
buffer_desc.DepthOrArraySize = 1;
|
||||
buffer_desc.MipLevels = 1;
|
||||
buffer_desc.Format = DXGI_FORMAT_UNKNOWN;
|
||||
buffer_desc.SampleDesc.Count = 1;
|
||||
buffer_desc.SampleDesc.Quality = 0;
|
||||
buffer_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||
buffer_desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||
ID3D12Resource* buffer;
|
||||
if (FAILED(device->CreateCommittedResource(
|
||||
&heap_properties, D3D12_HEAP_FLAG_NONE, &buffer_desc,
|
||||
D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&buffer)))) {
|
||||
XELOGE(
|
||||
"Failed to create an upload buffer for a %ux%u texture for "
|
||||
"immediate drawing",
|
||||
width, height);
|
||||
return;
|
||||
}
|
||||
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 %ux%u 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.frame = context_->GetCurrentFrame();
|
||||
texture_uploads_submitted_.push_back(submitted_upload);
|
||||
} else {
|
||||
// Defer uploading to the next frame when there's a command list.
|
||||
PendingTextureUpload pending_upload;
|
||||
pending_upload.texture = texture;
|
||||
pending_upload.buffer = buffer;
|
||||
texture_uploads_pending_.push_back(pending_upload);
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12ImmediateDrawer::Begin(int render_target_width,
|
||||
int render_target_height) {
|
||||
auto device = context_->GetD3D12Provider()->GetDevice();
|
||||
|
||||
// Use the compositing command list.
|
||||
current_command_list_ = context_->GetSwapCommandList();
|
||||
|
||||
uint32_t queue_frame = context_->GetCurrentQueueFrame();
|
||||
uint64_t current_frame = context_->GetCurrentFrame();
|
||||
uint64_t last_completed_frame = context_->GetLastCompletedFrame();
|
||||
|
||||
// Remove temporary buffers for completed texture uploads.
|
||||
|
@ -212,26 +467,261 @@ void D3D12ImmediateDrawer::Begin(int render_target_width,
|
|||
++erase_uploads_end;
|
||||
break;
|
||||
}
|
||||
erase_uploads_end->data_resource->Release();
|
||||
erase_uploads_end->buffer->Release();
|
||||
++erase_uploads_end;
|
||||
}
|
||||
texture_uploads_submitted_.erase(texture_uploads_submitted_.begin(),
|
||||
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.frame = current_frame;
|
||||
texture_uploads_submitted_.push_back(submitted_upload);
|
||||
texture_uploads_pending_.pop_back();
|
||||
}
|
||||
|
||||
vertex_buffer_pool_->BeginFrame();
|
||||
texture_descriptor_pool_->BeginFrame();
|
||||
texture_descriptor_pool_full_update_ = 0;
|
||||
|
||||
current_render_target_width_ = render_target_width;
|
||||
current_render_target_height_ = render_target_height;
|
||||
D3D12_VIEWPORT viewport;
|
||||
viewport.TopLeftX = 0.0f;
|
||||
viewport.TopLeftY = 0.0f;
|
||||
viewport.Width = float(render_target_width);
|
||||
viewport.Height = float(render_target_height);
|
||||
viewport.MinDepth = 0.0f;
|
||||
viewport.MaxDepth = 1.0f;
|
||||
current_command_list_->RSSetViewports(1, &viewport);
|
||||
|
||||
current_command_list_->SetGraphicsRootSignature(root_signature_);
|
||||
float viewport_inv_scale[2];
|
||||
viewport_inv_scale[0] = 1.0f / viewport.Width;
|
||||
viewport_inv_scale[1] = 1.0f / viewport.Height;
|
||||
current_command_list_->SetGraphicsRoot32BitConstants(
|
||||
UINT(RootParameter::kViewportInvSize), 2, viewport_inv_scale, 0);
|
||||
}
|
||||
|
||||
void D3D12ImmediateDrawer::BeginDrawBatch(const ImmediateDrawBatch& batch) {
|
||||
// TODO(Triang3l): Implement BeginDrawBatch.
|
||||
assert_not_null(current_command_list_);
|
||||
if (current_command_list_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
batch_open_ = false;
|
||||
|
||||
// Bind the vertices.
|
||||
D3D12_VERTEX_BUFFER_VIEW vertex_buffer_view;
|
||||
vertex_buffer_view.StrideInBytes = UINT(sizeof(ImmediateVertex));
|
||||
vertex_buffer_view.SizeInBytes =
|
||||
batch.vertex_count * uint32_t(sizeof(ImmediateVertex));
|
||||
void* vertex_buffer_mapping = vertex_buffer_pool_->RequestFull(
|
||||
vertex_buffer_view.SizeInBytes, nullptr, nullptr,
|
||||
&vertex_buffer_view.BufferLocation);
|
||||
if (vertex_buffer_mapping == nullptr) {
|
||||
XELOGE("Failed to get a buffer for %u vertices in the immediate drawer",
|
||||
batch.vertex_count);
|
||||
return;
|
||||
}
|
||||
std::memcpy(vertex_buffer_mapping, batch.vertices,
|
||||
vertex_buffer_view.SizeInBytes);
|
||||
current_command_list_->IASetVertexBuffers(0, 1, &vertex_buffer_view);
|
||||
|
||||
// Bind the indices.
|
||||
batch_has_index_buffer_ = batch.indices != nullptr;
|
||||
if (batch_has_index_buffer_) {
|
||||
D3D12_INDEX_BUFFER_VIEW index_buffer_view;
|
||||
index_buffer_view.SizeInBytes = batch.index_count * sizeof(uint16_t);
|
||||
index_buffer_view.Format = DXGI_FORMAT_R16_UINT;
|
||||
void* index_buffer_mapping = vertex_buffer_pool_->RequestFull(
|
||||
index_buffer_view.SizeInBytes, nullptr, nullptr,
|
||||
&index_buffer_view.BufferLocation);
|
||||
if (index_buffer_mapping == nullptr) {
|
||||
XELOGE("Failed to get a buffer for %u indices in the immediate drawer",
|
||||
batch.index_count);
|
||||
return;
|
||||
}
|
||||
std::memcpy(index_buffer_mapping, batch.indices,
|
||||
index_buffer_view.SizeInBytes);
|
||||
current_command_list_->IASetIndexBuffer(&index_buffer_view);
|
||||
}
|
||||
|
||||
batch_open_ = true;
|
||||
current_primitive_topology_ = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;
|
||||
current_texture_ = nullptr;
|
||||
current_sampler_index_ = SamplerIndex::kInvalid;
|
||||
}
|
||||
|
||||
void D3D12ImmediateDrawer::Draw(const ImmediateDraw& draw) {
|
||||
// TODO(Triang3l): Implement Draw.
|
||||
assert_not_null(current_command_list_);
|
||||
if (current_command_list_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!batch_open_) {
|
||||
// Could be an error while obtaining the vertex and index buffers.
|
||||
return;
|
||||
}
|
||||
|
||||
auto provider = context_->GetD3D12Provider();
|
||||
auto device = provider->GetDevice();
|
||||
|
||||
// Bind the texture.
|
||||
auto texture = reinterpret_cast<D3D12ImmediateTexture*>(draw.texture_handle);
|
||||
ID3D12Resource* texture_resource;
|
||||
if (texture != nullptr) {
|
||||
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;
|
||||
uint64_t texture_full_update = texture_descriptor_pool_->Request(
|
||||
texture_descriptor_pool_full_update_, bind_texture ? 1 : 0, 1,
|
||||
texture_descriptor_index);
|
||||
if (texture_full_update == 0) {
|
||||
return;
|
||||
}
|
||||
if (texture_descriptor_pool_full_update_ != texture_full_update) {
|
||||
bind_texture = true;
|
||||
texture_descriptor_pool_full_update_ = texture_full_update;
|
||||
ID3D12DescriptorHeap* descriptor_heaps[] = {
|
||||
texture_descriptor_pool_->GetLastRequestHeap(), sampler_heap_};
|
||||
current_command_list_->SetDescriptorHeaps(2, descriptor_heaps);
|
||||
}
|
||||
if (bind_texture) {
|
||||
auto descriptor_size_view = provider->GetDescriptorSizeView();
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC texture_view_desc;
|
||||
texture_view_desc.Format = D3D12ImmediateTexture::kFormat;
|
||||
texture_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
||||
texture_view_desc.Shader4ComponentMapping =
|
||||
D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||
texture_view_desc.Texture2D.MostDetailedMip = 0;
|
||||
texture_view_desc.Texture2D.MipLevels = 1;
|
||||
texture_view_desc.Texture2D.PlaneSlice = 0;
|
||||
texture_view_desc.Texture2D.ResourceMinLODClamp = 0.0f;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE texture_view_cpu_handle;
|
||||
texture_view_cpu_handle.ptr =
|
||||
texture_descriptor_pool_->GetLastRequestHeapCPUStart().ptr +
|
||||
texture_descriptor_index * descriptor_size_view;
|
||||
device->CreateShaderResourceView(texture_resource, &texture_view_desc,
|
||||
texture_view_cpu_handle);
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE texture_view_gpu_handle;
|
||||
texture_view_gpu_handle.ptr =
|
||||
texture_descriptor_pool_->GetLastRequestHeapGPUStart().ptr +
|
||||
texture_descriptor_index * descriptor_size_view;
|
||||
current_command_list_->SetGraphicsRootDescriptorTable(
|
||||
UINT(RootParameter::kTexture), texture_view_gpu_handle);
|
||||
current_texture_ = texture;
|
||||
}
|
||||
|
||||
// Bind the sampler.
|
||||
SamplerIndex sampler_index;
|
||||
if (texture != nullptr) {
|
||||
if (texture->GetFilter() == ImmediateTextureFilter::kLinear) {
|
||||
sampler_index = texture->IsRepeated() ? SamplerIndex::kLinearRepeat
|
||||
: SamplerIndex::kLinearClamp;
|
||||
} else {
|
||||
sampler_index = texture->IsRepeated() ? SamplerIndex::kNearestRepeat
|
||||
: SamplerIndex::kNearestClamp;
|
||||
}
|
||||
} else {
|
||||
sampler_index = SamplerIndex::kNearestClamp;
|
||||
}
|
||||
if (current_sampler_index_ != sampler_index) {
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE sampler_gpu_handle;
|
||||
sampler_gpu_handle.ptr =
|
||||
sampler_heap_gpu_start_.ptr +
|
||||
UINT(sampler_index) * provider->GetDescriptorSizeSampler();
|
||||
current_command_list_->SetGraphicsRootDescriptorTable(
|
||||
UINT(RootParameter::kSampler), sampler_gpu_handle);
|
||||
current_sampler_index_ = sampler_index;
|
||||
}
|
||||
|
||||
// Set whether texture coordinates need to be restricted.
|
||||
uint32_t restrict_texture_samples = draw.restrict_texture_samples ? 1 : 0;
|
||||
current_command_list_->SetGraphicsRoot32BitConstants(
|
||||
UINT(RootParameter::kRestrictTextureSamples), 1,
|
||||
&restrict_texture_samples, 0);
|
||||
|
||||
// Set the primitive type and the pipeline for it.
|
||||
D3D_PRIMITIVE_TOPOLOGY primitive_topology;
|
||||
ID3D12PipelineState* pipeline;
|
||||
switch (draw.primitive_type) {
|
||||
case ImmediatePrimitiveType::kLines:
|
||||
primitive_topology = D3D_PRIMITIVE_TOPOLOGY_LINELIST;
|
||||
pipeline = pipeline_line_;
|
||||
break;
|
||||
case ImmediatePrimitiveType::kTriangles:
|
||||
primitive_topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||
pipeline = pipeline_triangle_;
|
||||
break;
|
||||
default:
|
||||
assert_unhandled_case(draw.primitive_type);
|
||||
return;
|
||||
}
|
||||
if (current_primitive_topology_ != primitive_topology) {
|
||||
current_command_list_->IASetPrimitiveTopology(primitive_topology);
|
||||
current_command_list_->SetPipelineState(pipeline);
|
||||
current_primitive_topology_ = primitive_topology;
|
||||
}
|
||||
|
||||
// Set the scissor rectangle if enabled.
|
||||
D3D12_RECT scissor;
|
||||
if (draw.scissor) {
|
||||
scissor.left = draw.scissor_rect[0];
|
||||
scissor.top = current_render_target_height_ -
|
||||
(draw.scissor_rect[1] + draw.scissor_rect[3]);
|
||||
scissor.right = scissor.left + draw.scissor_rect[2];
|
||||
scissor.bottom = scissor.top + draw.scissor_rect[3];
|
||||
} else {
|
||||
scissor.left = 0;
|
||||
scissor.top = 0;
|
||||
scissor.right = current_render_target_width_;
|
||||
scissor.bottom = current_render_target_height_;
|
||||
}
|
||||
current_command_list_->RSSetScissorRects(1, &scissor);
|
||||
|
||||
// Draw.
|
||||
if (batch_has_index_buffer_) {
|
||||
current_command_list_->DrawIndexedInstanced(
|
||||
draw.count, 1, draw.index_offset, draw.base_vertex, 0);
|
||||
} else {
|
||||
current_command_list_->DrawInstanced(draw.count, 1, draw.base_vertex, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12ImmediateDrawer::EndDrawBatch() {
|
||||
// TODO(Triang3l): Implement EndDrawBatch.
|
||||
}
|
||||
void D3D12ImmediateDrawer::EndDrawBatch() { batch_open_ = false; }
|
||||
|
||||
void D3D12ImmediateDrawer::End() { current_command_list_ = nullptr; }
|
||||
void D3D12ImmediateDrawer::End() {
|
||||
texture_descriptor_pool_->EndFrame();
|
||||
vertex_buffer_pool_->EndFrame();
|
||||
|
||||
current_command_list_ = nullptr;
|
||||
}
|
||||
|
||||
} // namespace d3d12
|
||||
} // namespace ui
|
||||
|
|
|
@ -12,10 +12,12 @@
|
|||
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "xenia/ui/d3d12/command_list.h"
|
||||
#include "xenia/ui/d3d12/d3d12_api.h"
|
||||
#include "xenia/ui/d3d12/d3d12_context.h"
|
||||
#include "xenia/ui/d3d12/pools.h"
|
||||
#include "xenia/ui/immediate_drawer.h"
|
||||
|
||||
namespace xe {
|
||||
|
@ -48,33 +50,53 @@ class D3D12ImmediateDrawer : public ImmediateDrawer {
|
|||
|
||||
ID3D12RootSignature* root_signature_ = nullptr;
|
||||
enum class RootParameter {
|
||||
kRestrictTextureSamples,
|
||||
kTexture,
|
||||
kSampler,
|
||||
kRestrictTextureSamples,
|
||||
kViewportInvSize,
|
||||
|
||||
kCount
|
||||
};
|
||||
|
||||
ID3D12PipelineState* pipeline_triangle_ = nullptr;
|
||||
ID3D12PipelineState* pipeline_line_ = nullptr;
|
||||
|
||||
enum class SamplerIndex {
|
||||
kNearestClamp,
|
||||
kLinearClamp,
|
||||
kNearestRepeat,
|
||||
kLinearRepeat,
|
||||
|
||||
kCount
|
||||
kCount,
|
||||
kInvalid = kCount
|
||||
};
|
||||
ID3D12DescriptorHeap* sampler_heap_ = nullptr;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE sampler_heap_cpu_start_;
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE sampler_heap_gpu_start_;
|
||||
|
||||
ID3D12GraphicsCommandList* current_command_list_ = nullptr;
|
||||
std::unique_ptr<UploadBufferPool> vertex_buffer_pool_ = nullptr;
|
||||
std::unique_ptr<DescriptorHeapPool> texture_descriptor_pool_ = nullptr;
|
||||
|
||||
struct PendingTextureUpload {
|
||||
ImmediateTexture* texture;
|
||||
ID3D12Resource* buffer;
|
||||
};
|
||||
std::vector<PendingTextureUpload> texture_uploads_pending_;
|
||||
|
||||
struct SubmittedTextureUpload {
|
||||
ID3D12Resource* data_resource;
|
||||
ID3D12Resource* buffer;
|
||||
uint64_t frame;
|
||||
};
|
||||
std::deque<SubmittedTextureUpload> texture_uploads_submitted_;
|
||||
|
||||
ID3D12GraphicsCommandList* current_command_list_ = nullptr;
|
||||
int current_render_target_width_, current_render_target_height_;
|
||||
bool batch_open_ = false;
|
||||
bool batch_has_index_buffer_;
|
||||
uint64_t texture_descriptor_pool_full_update_;
|
||||
D3D_PRIMITIVE_TOPOLOGY current_primitive_topology_;
|
||||
ImmediateTexture* current_texture_;
|
||||
SamplerIndex current_sampler_index_;
|
||||
};
|
||||
|
||||
} // namespace d3d12
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
Texture2D<float4> immediate_texture : register(t0);
|
||||
SamplerState immediate_sampler : register(s0);
|
||||
bool restrict_texture_samples : register(b0);
|
||||
Texture2D<float4> xe_immediate_texture : register(t0);
|
||||
SamplerState xe_immediate_sampler : register(s0);
|
||||
bool xe_restrict_texture_samples : register(b0);
|
||||
|
||||
struct ps_input {
|
||||
float2 uv : TEXCOORD0;
|
||||
struct XePixelShaderInput {
|
||||
float2 texcoord : TEXCOORD0;
|
||||
float4 color : TEXCOORD1;
|
||||
};
|
||||
|
||||
float4 main(ps_input input) : SV_Target {
|
||||
float4 main(XePixelShaderInput input) : SV_Target {
|
||||
float4 output = input.color;
|
||||
if (!restrict_texture_samples || input.uv.x <= 1.0) {
|
||||
output *= immediate_texture.Sample(immediate_sampler, input.uv);
|
||||
if (!xe_restrict_texture_samples || input.texcoord.x <= 1.0) {
|
||||
output *= xe_immediate_texture.Sample(xe_immediate_sampler, input.texcoord);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
|
|
@ -1,21 +1,23 @@
|
|||
float2 viewport_inv_size : register(b0);
|
||||
float2 xe_viewport_inv_size : register(b0);
|
||||
|
||||
struct vs_input {
|
||||
float2 pos : POSITION;
|
||||
float2 uv : TEXCOORD;
|
||||
struct XeVertexShaderInput {
|
||||
float2 position : POSITION;
|
||||
float2 texcoord : TEXCOORD;
|
||||
float4 color : COLOR;
|
||||
};
|
||||
|
||||
struct vs_output {
|
||||
float4 pos : SV_Position;
|
||||
float2 uv : TEXCOORD0;
|
||||
struct XeVertexShaderOutput {
|
||||
float2 texcoord : TEXCOORD0;
|
||||
float4 color : TEXCOORD1;
|
||||
float4 position : SV_Position;
|
||||
};
|
||||
|
||||
vs_output main(vs_input input) {
|
||||
vs_output output;
|
||||
output.pos = float4(viewport_inv_size * input.pos, 0.0, 1.0);
|
||||
output.uv = input.uv;
|
||||
XeVertexShaderOutput main(XeVertexShaderInput input) {
|
||||
XeVertexShaderOutput output;
|
||||
output.position = float4(
|
||||
input.position * xe_viewport_inv_size * float2(2.0, -2.0) +
|
||||
float2(-1.0, 1.0), 0.0, 1.0);
|
||||
output.texcoord = input.texcoord;
|
||||
output.color = input.color;
|
||||
return output;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue