From ae1196f29d014bd08e858fa4487b6b7452fe56c2 Mon Sep 17 00:00:00 2001 From: Triang3l Date: Wed, 25 Jul 2018 00:47:02 +0300 Subject: [PATCH] [D3D12] Shared memory - heap creation --- .../gpu/d3d12/d3d12_command_processor.cc | 6 + src/xenia/gpu/d3d12/d3d12_command_processor.h | 4 +- src/xenia/gpu/d3d12/shared_memory.cc | 124 ++++++++++++++++++ src/xenia/gpu/d3d12/shared_memory.h | 65 +++++++++ 4 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 src/xenia/gpu/d3d12/shared_memory.cc create mode 100644 src/xenia/gpu/d3d12/shared_memory.h diff --git a/src/xenia/gpu/d3d12/d3d12_command_processor.cc b/src/xenia/gpu/d3d12/d3d12_command_processor.cc index b253d0dbb..d26627229 100644 --- a/src/xenia/gpu/d3d12/d3d12_command_processor.cc +++ b/src/xenia/gpu/d3d12/d3d12_command_processor.cc @@ -51,6 +51,12 @@ bool D3D12CommandProcessor::SetupContext() { } } + shared_memory_ = std::make_unique(context); + if (!shared_memory_->Initialize()) { + XELOGE("Failed to initialize shared memory"); + return false; + } + pipeline_cache_ = std::make_unique(register_file_, context); return true; diff --git a/src/xenia/gpu/d3d12/d3d12_command_processor.h b/src/xenia/gpu/d3d12/d3d12_command_processor.h index d56cb62fd..49e7f958f 100644 --- a/src/xenia/gpu/d3d12/d3d12_command_processor.h +++ b/src/xenia/gpu/d3d12/d3d12_command_processor.h @@ -15,6 +15,7 @@ #include "xenia/gpu/command_processor.h" #include "xenia/gpu/d3d12/d3d12_graphics_system.h" #include "xenia/gpu/d3d12/pipeline_cache.h" +#include "xenia/gpu/d3d12/shared_memory.h" #include "xenia/gpu/xenos.h" #include "xenia/kernel/kernel_state.h" #include "xenia/ui/d3d12/command_list.h" @@ -65,7 +66,8 @@ class D3D12CommandProcessor : public CommandProcessor { std::unique_ptr command_lists_[ui::d3d12::D3D12Context::kQueuedFrames] = {}; - std::unique_ptr pipeline_cache_; + std::unique_ptr shared_memory_ = nullptr; + std::unique_ptr pipeline_cache_ = nullptr; uint32_t current_queue_frame_ = UINT32_MAX; }; diff --git a/src/xenia/gpu/d3d12/shared_memory.cc b/src/xenia/gpu/d3d12/shared_memory.cc new file mode 100644 index 000000000..be69bfb1b --- /dev/null +++ b/src/xenia/gpu/d3d12/shared_memory.cc @@ -0,0 +1,124 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2018 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/gpu/d3d12/shared_memory.h" + +#include + +#include "xenia/base/logging.h" +#include "xenia/base/math.h" +#include "xenia/base/memory.h" + +namespace xe { +namespace gpu { +namespace d3d12 { + +SharedMemory::SharedMemory(ui::d3d12::D3D12Context* context) + : context_(context) { + page_size_log2_ = xe::math::log2_ceil(xe::memory::page_size()); + pages_in_sync_.resize(kBufferSize >> page_size_log2_ >> 6); +} + +SharedMemory::~SharedMemory() { Shutdown(); } + +bool SharedMemory::Initialize() { + auto device = context_->GetD3D12Provider()->GetDevice(); + + buffer_state_ = D3D12_RESOURCE_STATE_COPY_DEST; + D3D12_RESOURCE_DESC buffer_desc; + buffer_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + buffer_desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT; + buffer_desc.Width = kBufferSize; + 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_ALLOW_UNORDERED_ACCESS; + if (FAILED(device->CreateReservedResource(&buffer_desc, buffer_state_, + nullptr, IID_PPV_ARGS(&buffer_)))) { + XELOGE("Failed to create the 512 MB shared memory tiled buffer"); + Shutdown(); + return false; + } + + std::memset(heaps_, 0, sizeof(heaps_)); + + std::memset(pages_in_sync_.data(), 0, + page_in_sync_.size() * sizeof(uint64_t)); + + return true; +} + +void SharedMemory::Shutdown() { + // First free the buffer to detach it from the heaps. + if (buffer_ != nullptr) { + buffer_->Release(); + buffer_ = nullptr; + } + + for (uint32_t i = 0; i < xe::countof(heaps_); ++i) { + if (heaps_[i] != nullptr) { + heaps_[i]->Release(); + heaps_[i] = nullptr; + } + } +} + +bool SharedMemory::EnsureRangeAllocated(uint32_t start, uint32_t length) { + if (length == 0) { + // Some texture is empty, for example - safe to draw in this case. + return true; + } + start &= kAddressMask; + if ((kBufferSize - start) < length) { + // Exceeds the physical address space. + return false; + } + uint32_t heap_first = start >> kHeapSizeLog2; + uint32_t heap_last = (start + length - 1) >> kHeapSizeLog2; + for (uint32_t i = heap_first; i <= heap_last; ++i) { + if (heaps_[i] != nullptr) { + continue; + } + // TODO(Triang3l): If heap creation has failed at least once in this frame, + // don't try to allocate heaps until the next frame. + auto provider = context_->GetD3D12Provider(); + auto device = provider->GetDevice(); + auto direct_queue = provider->GetDirectQueue(); + D3D12_HEAP_DESC heap_desc = {}; + heap_desc.SizeInBytes = kHeapSize; + heap_desc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT; + if (FAILED(device->CreateHeap(&heap_desc, IID_PPV_ARGS(&heaps_[i])))) { + return false; + } + D3D12_TILED_RESOURCE_COORDINATE region_start_coordinates; + region_start_coordinates.X = i << kHeapSize; + region_start_coordinates.Y = 0; + region_start_coordinates.Z = 0; + region_start_coordinates.Subresource = 0; + D3D12_TILE_REGION_SIZE region_size; + region_size.NumTiles = kHeapSize >> kTileSizeLog2; + region_size.UseBox = FALSE; + D3D12_TILE_RANGE_FLAGS range_flags = D3D12_TILE_RANGE_FLAG_NONE; + UINT heap_range_start_offset = 0; + UINT range_tile_count = kHeapSize >> kTileSizeLog2; + direct_queue->UpdateTileMappings( + buffer_, 1, ®ion_start_coordinates, ®ion_size, heaps_[i], 1, + &range_flags, &heap_range_start_offset, &range_tile_count, + D3D12_TILE_MAPPING_FLAG_NONE); + } + return true; +} + +} // namespace d3d12 +} // namespace gpu +} // namespace xe diff --git a/src/xenia/gpu/d3d12/shared_memory.h b/src/xenia/gpu/d3d12/shared_memory.h new file mode 100644 index 000000000..5ae300db5 --- /dev/null +++ b/src/xenia/gpu/d3d12/shared_memory.h @@ -0,0 +1,65 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2018 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_GPU_D3D12_SHARED_MEMORY_H_ +#define XENIA_GPU_D3D12_SHARED_MEMORY_H_ + +#include "xenia/ui/d3d12/d3d12_api.h" +#include "xenia/ui/d3d12/d3d12_context.h" + +namespace xe { +namespace gpu { +namespace d3d12 { + +// Manages memory for unconverted textures, resolve targets, vertex and index +// buffers that can be accessed from shaders with Xenon physical addresses, with +// 4 KB granularity. +class SharedMemory { + public: + SharedMemory(ui::d3d12::D3D12Context* context); + ~SharedMemory(); + + bool Initialize(); + void Shutdown(); + + // Ensures the backing memory for the address range is present in the tiled + // buffer, allocating if needed. If couldn't allocate, false is returned - + // it's unsafe to use this portion (on tiled resources tier 1 at least). + bool EnsureRangeAllocated(uint32_t start, uint32_t length); + + private: + ui::d3d12::D3D12Context* context_ = nullptr; + + // The 512 MB tiled buffer. + static constexpr uint32_t kBufferSizeLog2 = 29; + static constexpr uint32_t kBufferSize = 1 << kBufferSizeLog2; + static constexpr uint32_t kAddressMask = kBufferSize - 1; + ID3D12Resource* buffer_ = nullptr; + D3D12_RESOURCE_STATES buffer_state_ = D3D12_RESOURCE_STATE_COPY_DEST; + + // D3D resource tiles are 64 KB in size. + static constexpr uint32_t kTileSizeLog2 = 16; + static constexpr uint32_t kTileSize = 1 << kTileSizeLog2; + // Heaps are 4 MB, so not too many of them are allocated. + static constexpr uint32_t kHeapSizeLog2 = 22; + static constexpr uint32_t kHeapSize = 1 << kHeapSizeLog2; + // Resident portions of the tiled buffer. + ID3D12Heap* heaps_[kBufferSize >> kHeapSizeLog2] = {}; + + // Log2 of system page size. + uint32_t page_size_log2_; + // Bit vector containing whether physical memory system pages are up to date. + std::vector pages_in_sync_; +}; + +} // namespace d3d12 +} // namespace gpu +} // namespace xe + +#endif // XENIA_GPU_D3D12_SHARED_MEMORY_H_