1845 lines
66 KiB
C++
1845 lines
66 KiB
C++
#include "XCEngine/RHI/D3D12/D3D12Device.h"
|
|
#include "XCEngine/RHI/D3D12/D3D12CommandQueue.h"
|
|
#include "XCEngine/RHI/D3D12/D3D12CommandList.h"
|
|
#include "XCEngine/RHI/D3D12/D3D12CommandAllocator.h"
|
|
#include "XCEngine/RHI/D3D12/D3D12Fence.h"
|
|
#include "XCEngine/RHI/D3D12/D3D12DescriptorHeap.h"
|
|
#include "XCEngine/RHI/D3D12/D3D12DescriptorSet.h"
|
|
#include "XCEngine/RHI/D3D12/D3D12QueryHeap.h"
|
|
#include "XCEngine/RHI/D3D12/D3D12RootSignature.h"
|
|
#include "XCEngine/RHI/D3D12/D3D12PipelineLayout.h"
|
|
#include "XCEngine/RHI/D3D12/D3D12PipelineState.h"
|
|
#include "XCEngine/RHI/D3D12/D3D12Sampler.h"
|
|
#include "XCEngine/RHI/D3D12/D3D12Texture.h"
|
|
#include "XCEngine/RHI/D3D12/D3D12Buffer.h"
|
|
#include "XCEngine/RHI/D3D12/D3D12SwapChain.h"
|
|
#include "XCEngine/RHI/D3D12/D3D12Shader.h"
|
|
#include "XCEngine/RHI/D3D12/D3D12ResourceView.h"
|
|
#include "XCEngine/RHI/D3D12/D3D12RenderPass.h"
|
|
#include "XCEngine/RHI/D3D12/D3D12Framebuffer.h"
|
|
#include "XCEngine/Debug/Logger.h"
|
|
#include <algorithm>
|
|
#include <chrono>
|
|
#include <cstring>
|
|
#include <stdio.h>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#ifdef _DEBUG
|
|
#include <dxgidebug.h>
|
|
#endif
|
|
|
|
namespace XCEngine {
|
|
namespace RHI {
|
|
|
|
namespace {
|
|
|
|
std::string NarrowAscii(const std::wstring& value) {
|
|
std::string result;
|
|
result.reserve(value.size());
|
|
for (wchar_t ch : value) {
|
|
result.push_back(static_cast<char>(ch));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
uint64_t GetVolumeTraceSteadyMs();
|
|
void LogVolumeTraceRendering(const std::string& message);
|
|
|
|
bool HasShaderPayload(const ShaderCompileDesc& desc) {
|
|
return !desc.source.empty() || !desc.fileName.empty();
|
|
}
|
|
|
|
bool ShouldTraceVolumetricShaderCompile(const ShaderCompileDesc& desc) {
|
|
const std::string fileName = NarrowAscii(desc.fileName);
|
|
if (fileName.find("volumetric") != std::string::npos) {
|
|
return true;
|
|
}
|
|
|
|
if (!desc.source.empty()) {
|
|
const std::string sourceText(desc.source.begin(), desc.source.end());
|
|
if (sourceText.find("PNANOVDB_HLSL") != std::string::npos ||
|
|
sourceText.find("VolumeData") != std::string::npos) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
std::string DescribeShaderCompileDesc(const ShaderCompileDesc& desc) {
|
|
std::string description =
|
|
"entry=" + NarrowAscii(desc.entryPoint) +
|
|
" profile=" + NarrowAscii(desc.profile) +
|
|
" source_bytes=" + std::to_string(desc.source.size()) +
|
|
" macro_count=" + std::to_string(desc.macros.size());
|
|
if (!desc.fileName.empty()) {
|
|
description += " file=" + NarrowAscii(desc.fileName);
|
|
}
|
|
return description;
|
|
}
|
|
|
|
bool CompileD3D12Shader(const ShaderCompileDesc& desc, D3D12Shader& shader) {
|
|
const bool traceShaderCompile = ShouldTraceVolumetricShaderCompile(desc);
|
|
const uint64_t compileStartMs = traceShaderCompile ? GetVolumeTraceSteadyMs() : 0u;
|
|
if (traceShaderCompile) {
|
|
LogVolumeTraceRendering(
|
|
"D3D12 shader compile begin steady_ms=" + std::to_string(compileStartMs) + " " +
|
|
DescribeShaderCompileDesc(desc));
|
|
}
|
|
|
|
const std::string entryPoint = NarrowAscii(desc.entryPoint);
|
|
const std::string profile = NarrowAscii(desc.profile);
|
|
const char* entryPointPtr = entryPoint.empty() ? nullptr : entryPoint.c_str();
|
|
const char* profilePtr = profile.empty() ? nullptr : profile.c_str();
|
|
|
|
if (!desc.source.empty()) {
|
|
std::vector<std::string> macroNames;
|
|
std::vector<std::string> macroDefinitions;
|
|
std::vector<D3D_SHADER_MACRO> macroTable;
|
|
if (!desc.macros.empty()) {
|
|
macroNames.reserve(desc.macros.size());
|
|
macroDefinitions.reserve(desc.macros.size());
|
|
macroTable.reserve(desc.macros.size() + 1u);
|
|
for (const ShaderCompileMacro& macro : desc.macros) {
|
|
macroNames.push_back(NarrowAscii(macro.name));
|
|
macroDefinitions.push_back(NarrowAscii(macro.definition));
|
|
}
|
|
|
|
for (size_t macroIndex = 0; macroIndex < desc.macros.size(); ++macroIndex) {
|
|
D3D_SHADER_MACRO d3dMacro = {};
|
|
d3dMacro.Name = macroNames[macroIndex].c_str();
|
|
d3dMacro.Definition = macroDefinitions[macroIndex].empty()
|
|
? "1"
|
|
: macroDefinitions[macroIndex].c_str();
|
|
macroTable.push_back(d3dMacro);
|
|
}
|
|
macroTable.push_back({ nullptr, nullptr });
|
|
}
|
|
|
|
const D3D_SHADER_MACRO* macroPtr = macroTable.empty() ? nullptr : macroTable.data();
|
|
const bool compiled = shader.Compile(
|
|
desc.source.data(),
|
|
desc.source.size(),
|
|
desc.fileName.empty() ? nullptr : desc.fileName.c_str(),
|
|
macroPtr,
|
|
entryPointPtr,
|
|
profilePtr);
|
|
if (traceShaderCompile) {
|
|
const uint64_t compileEndMs = GetVolumeTraceSteadyMs();
|
|
LogVolumeTraceRendering(
|
|
std::string("D3D12 shader compile ") + (compiled ? "end" : "failed") +
|
|
" steady_ms=" + std::to_string(compileEndMs) +
|
|
" total_ms=" + std::to_string(compileEndMs - compileStartMs) + " " +
|
|
DescribeShaderCompileDesc(desc));
|
|
}
|
|
return compiled;
|
|
}
|
|
|
|
if (!desc.fileName.empty()) {
|
|
const bool compiled = shader.CompileFromFile(desc.fileName.c_str(), entryPointPtr, profilePtr);
|
|
if (traceShaderCompile) {
|
|
const uint64_t compileEndMs = GetVolumeTraceSteadyMs();
|
|
LogVolumeTraceRendering(
|
|
std::string("D3D12 shader compile ") + (compiled ? "end" : "failed") +
|
|
" steady_ms=" + std::to_string(compileEndMs) +
|
|
" total_ms=" + std::to_string(compileEndMs - compileStartMs) + " " +
|
|
DescribeShaderCompileDesc(desc));
|
|
}
|
|
return compiled;
|
|
}
|
|
|
|
if (traceShaderCompile) {
|
|
const uint64_t compileEndMs = GetVolumeTraceSteadyMs();
|
|
LogVolumeTraceRendering(
|
|
"D3D12 shader compile failed steady_ms=" + std::to_string(compileEndMs) +
|
|
" total_ms=" + std::to_string(compileEndMs - compileStartMs) +
|
|
" reason=empty_shader_payload " + DescribeShaderCompileDesc(desc));
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool WaitForQueueIdle(
|
|
ID3D12Device* device,
|
|
ID3D12CommandQueue* commandQueue) {
|
|
if (device == nullptr || commandQueue == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
ID3D12Fence* fence = nullptr;
|
|
if (FAILED(device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence)))) {
|
|
return false;
|
|
}
|
|
|
|
HANDLE fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
|
if (fenceEvent == nullptr) {
|
|
fence->Release();
|
|
return false;
|
|
}
|
|
|
|
constexpr UINT64 kFenceValue = 1;
|
|
const HRESULT signalResult = commandQueue->Signal(fence, kFenceValue);
|
|
if (FAILED(signalResult)) {
|
|
CloseHandle(fenceEvent);
|
|
fence->Release();
|
|
return false;
|
|
}
|
|
|
|
if (fence->GetCompletedValue() < kFenceValue) {
|
|
if (FAILED(fence->SetEventOnCompletion(kFenceValue, fenceEvent))) {
|
|
CloseHandle(fenceEvent);
|
|
fence->Release();
|
|
return false;
|
|
}
|
|
WaitForSingleObject(fenceEvent, INFINITE);
|
|
}
|
|
|
|
CloseHandle(fenceEvent);
|
|
fence->Release();
|
|
return true;
|
|
}
|
|
|
|
uint32_t GetFormatBytesPerPixel(Format format) {
|
|
switch (format) {
|
|
case Format::R8_UNorm:
|
|
return 1;
|
|
case Format::R8G8_UNorm:
|
|
return 2;
|
|
case Format::R8G8B8A8_UNorm:
|
|
case Format::R8G8B8A8_SRGB:
|
|
return 4;
|
|
case Format::R16_Float:
|
|
return 2;
|
|
case Format::R16G16B16A16_Float:
|
|
return 8;
|
|
case Format::R32_Float:
|
|
return 4;
|
|
case Format::R32G32_Float:
|
|
return 8;
|
|
case Format::R32G32B32_Float:
|
|
return 12;
|
|
case Format::R32G32B32A32_Float:
|
|
return 16;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
TextureType ResolveTextureType(uint32_t rawType) {
|
|
return static_cast<TextureType>(rawType);
|
|
}
|
|
|
|
uint16_t ResolveDepthOrArraySize(const TextureDesc& desc, TextureType textureType) {
|
|
switch (textureType) {
|
|
case TextureType::Texture3D:
|
|
return static_cast<uint16_t>(std::max<uint32_t>(desc.depth, 1));
|
|
case TextureType::Texture2DArray:
|
|
return static_cast<uint16_t>(std::max<uint32_t>(desc.arraySize, 1));
|
|
case TextureType::TextureCube:
|
|
case TextureType::TextureCubeArray:
|
|
return static_cast<uint16_t>(std::max<uint32_t>(desc.arraySize, 6));
|
|
default:
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
std::string ShaderModelToString(D3D_SHADER_MODEL shaderModel) {
|
|
switch (shaderModel) {
|
|
case D3D_SHADER_MODEL_6_7: return "6.7";
|
|
case D3D_SHADER_MODEL_6_6: return "6.6";
|
|
case D3D_SHADER_MODEL_6_5: return "6.5";
|
|
case D3D_SHADER_MODEL_6_4: return "6.4";
|
|
case D3D_SHADER_MODEL_6_3: return "6.3";
|
|
case D3D_SHADER_MODEL_6_2: return "6.2";
|
|
case D3D_SHADER_MODEL_6_1: return "6.1";
|
|
case D3D_SHADER_MODEL_6_0: return "6.0";
|
|
case D3D_SHADER_MODEL_5_1: return "5.1";
|
|
default: return {};
|
|
}
|
|
}
|
|
|
|
D3D12_RTV_DIMENSION ResolveRTVDimension(const ResourceViewDesc& desc, TextureType textureType) {
|
|
switch (desc.dimension) {
|
|
case ResourceViewDimension::Texture1D:
|
|
return D3D12_RTV_DIMENSION_TEXTURE1D;
|
|
case ResourceViewDimension::Texture1DArray:
|
|
return D3D12_RTV_DIMENSION_TEXTURE1DARRAY;
|
|
case ResourceViewDimension::Texture2DArray:
|
|
case ResourceViewDimension::TextureCube:
|
|
case ResourceViewDimension::TextureCubeArray:
|
|
return D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
|
|
case ResourceViewDimension::Texture3D:
|
|
return D3D12_RTV_DIMENSION_TEXTURE3D;
|
|
case ResourceViewDimension::Texture2DMS:
|
|
return D3D12_RTV_DIMENSION_TEXTURE2DMS;
|
|
case ResourceViewDimension::Texture2DMSArray:
|
|
return D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY;
|
|
case ResourceViewDimension::Unknown:
|
|
break;
|
|
default:
|
|
return D3D12_RTV_DIMENSION_TEXTURE2D;
|
|
}
|
|
|
|
switch (textureType) {
|
|
case TextureType::Texture1D:
|
|
return D3D12_RTV_DIMENSION_TEXTURE1D;
|
|
case TextureType::Texture2DArray:
|
|
case TextureType::TextureCube:
|
|
case TextureType::TextureCubeArray:
|
|
return D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
|
|
case TextureType::Texture3D:
|
|
return D3D12_RTV_DIMENSION_TEXTURE3D;
|
|
default:
|
|
return D3D12_RTV_DIMENSION_TEXTURE2D;
|
|
}
|
|
}
|
|
|
|
D3D12_SRV_DIMENSION ResolveSRVDimension(const ResourceViewDesc& desc, TextureType textureType) {
|
|
switch (desc.dimension) {
|
|
case ResourceViewDimension::Texture1D:
|
|
return D3D12_SRV_DIMENSION_TEXTURE1D;
|
|
case ResourceViewDimension::Texture1DArray:
|
|
return D3D12_SRV_DIMENSION_TEXTURE1DARRAY;
|
|
case ResourceViewDimension::Texture2DArray:
|
|
return D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
|
|
case ResourceViewDimension::Texture3D:
|
|
return D3D12_SRV_DIMENSION_TEXTURE3D;
|
|
case ResourceViewDimension::TextureCube:
|
|
return D3D12_SRV_DIMENSION_TEXTURECUBE;
|
|
case ResourceViewDimension::TextureCubeArray:
|
|
return D3D12_SRV_DIMENSION_TEXTURECUBEARRAY;
|
|
case ResourceViewDimension::Texture2DMS:
|
|
return D3D12_SRV_DIMENSION_TEXTURE2DMS;
|
|
case ResourceViewDimension::Texture2DMSArray:
|
|
return D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY;
|
|
case ResourceViewDimension::Unknown:
|
|
break;
|
|
default:
|
|
return D3D12_SRV_DIMENSION_TEXTURE2D;
|
|
}
|
|
|
|
switch (textureType) {
|
|
case TextureType::Texture1D:
|
|
return D3D12_SRV_DIMENSION_TEXTURE1D;
|
|
case TextureType::Texture2DArray:
|
|
return D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
|
|
case TextureType::Texture3D:
|
|
return D3D12_SRV_DIMENSION_TEXTURE3D;
|
|
case TextureType::TextureCube:
|
|
return D3D12_SRV_DIMENSION_TEXTURECUBE;
|
|
case TextureType::TextureCubeArray:
|
|
return D3D12_SRV_DIMENSION_TEXTURECUBEARRAY;
|
|
default:
|
|
return D3D12_SRV_DIMENSION_TEXTURE2D;
|
|
}
|
|
}
|
|
|
|
bool IsDepthFormat(Format format) {
|
|
return format == Format::D16_UNorm ||
|
|
format == Format::D24_UNorm_S8_UInt ||
|
|
format == Format::D32_Float;
|
|
}
|
|
|
|
DXGI_FORMAT ResolveD3D12ResourceFormat(Format format) {
|
|
switch (format) {
|
|
case Format::D16_UNorm:
|
|
return DXGI_FORMAT_R16_TYPELESS;
|
|
case Format::D24_UNorm_S8_UInt:
|
|
return DXGI_FORMAT_R24G8_TYPELESS;
|
|
case Format::D32_Float:
|
|
return DXGI_FORMAT_R32_TYPELESS;
|
|
default:
|
|
return ToD3D12(format);
|
|
}
|
|
}
|
|
|
|
DXGI_FORMAT ResolveD3D12DepthStencilViewFormat(Format format) {
|
|
switch (format) {
|
|
case Format::D16_UNorm:
|
|
return DXGI_FORMAT_D16_UNORM;
|
|
case Format::D24_UNorm_S8_UInt:
|
|
return DXGI_FORMAT_D24_UNORM_S8_UINT;
|
|
case Format::D32_Float:
|
|
return DXGI_FORMAT_D32_FLOAT;
|
|
default:
|
|
return ToD3D12(format);
|
|
}
|
|
}
|
|
|
|
DXGI_FORMAT ResolveD3D12ShaderResourceViewFormat(Format format) {
|
|
switch (format) {
|
|
case Format::D16_UNorm:
|
|
return DXGI_FORMAT_R16_UNORM;
|
|
case Format::D24_UNorm_S8_UInt:
|
|
return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
|
|
case Format::D32_Float:
|
|
return DXGI_FORMAT_R32_FLOAT;
|
|
default:
|
|
return ToD3D12(format);
|
|
}
|
|
}
|
|
|
|
bool IsSupportedBufferViewDimension(ResourceViewDimension dimension) {
|
|
return dimension == ResourceViewDimension::Buffer ||
|
|
dimension == ResourceViewDimension::StructuredBuffer ||
|
|
dimension == ResourceViewDimension::RawBuffer;
|
|
}
|
|
|
|
uint64_t GetVolumeTraceSteadyMs() {
|
|
using Clock = std::chrono::steady_clock;
|
|
static const Clock::time_point s_start = Clock::now();
|
|
return static_cast<uint64_t>(std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
Clock::now() - s_start).count());
|
|
}
|
|
|
|
bool ShouldTraceLargeStorageBuffer(const BufferDesc& desc) {
|
|
return static_cast<BufferType>(desc.bufferType) == BufferType::Storage &&
|
|
desc.size >= 32ull * 1024ull * 1024ull;
|
|
}
|
|
|
|
void LogVolumeTraceRendering(const std::string& message) {
|
|
Containers::String entry("[VolumeTrace] ");
|
|
entry += message.c_str();
|
|
Debug::Logger::Get().Info(Debug::LogCategory::Rendering, entry);
|
|
}
|
|
|
|
uint32_t ResolveBufferViewElementStride(RHIBuffer* buffer, const ResourceViewDesc& desc) {
|
|
if (desc.dimension == ResourceViewDimension::RawBuffer) {
|
|
return 4u;
|
|
}
|
|
|
|
if (desc.structureByteStride > 0) {
|
|
return desc.structureByteStride;
|
|
}
|
|
|
|
if (desc.dimension == ResourceViewDimension::Buffer && desc.format != 0) {
|
|
return GetFormatBytesPerPixel(static_cast<Format>(desc.format));
|
|
}
|
|
|
|
return buffer != nullptr ? buffer->GetStride() : 0u;
|
|
}
|
|
|
|
bool TryResolveBufferViewFirstElement(
|
|
RHIBuffer* buffer,
|
|
const ResourceViewDesc& desc,
|
|
uint32_t& outFirstElement,
|
|
uint32_t& outElementStride) {
|
|
outFirstElement = 0;
|
|
outElementStride = ResolveBufferViewElementStride(buffer, desc);
|
|
if (outElementStride == 0) {
|
|
return false;
|
|
}
|
|
|
|
if ((desc.bufferLocation % outElementStride) != 0) {
|
|
return false;
|
|
}
|
|
|
|
outFirstElement =
|
|
desc.firstElement + static_cast<uint32_t>(desc.bufferLocation / outElementStride);
|
|
return true;
|
|
}
|
|
|
|
bool TryResolveBufferViewElementCount(
|
|
RHIBuffer* buffer,
|
|
const ResourceViewDesc& desc,
|
|
uint32_t elementStride,
|
|
uint32_t firstElement,
|
|
uint32_t& outElementCount) {
|
|
outElementCount = 0;
|
|
if (desc.elementCount > 0) {
|
|
outElementCount = desc.elementCount;
|
|
return true;
|
|
}
|
|
|
|
if (buffer == nullptr || elementStride == 0) {
|
|
return false;
|
|
}
|
|
|
|
const uint64_t byteOffset = static_cast<uint64_t>(firstElement) * elementStride;
|
|
if (byteOffset >= buffer->GetSize()) {
|
|
return false;
|
|
}
|
|
|
|
outElementCount = static_cast<uint32_t>((buffer->GetSize() - byteOffset) / elementStride);
|
|
return outElementCount > 0;
|
|
}
|
|
|
|
DXGI_FORMAT ResolveD3D12BufferViewFormat(const ResourceViewDesc& desc) {
|
|
if (desc.dimension == ResourceViewDimension::RawBuffer) {
|
|
return DXGI_FORMAT_R32_TYPELESS;
|
|
}
|
|
|
|
if (desc.dimension == ResourceViewDimension::StructuredBuffer) {
|
|
return DXGI_FORMAT_UNKNOWN;
|
|
}
|
|
|
|
if (desc.dimension == ResourceViewDimension::Buffer && desc.format != 0) {
|
|
return ToD3D12(static_cast<Format>(desc.format));
|
|
}
|
|
|
|
return DXGI_FORMAT_UNKNOWN;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
D3D12Device::D3D12Device()
|
|
: m_isDeviceRemoved(false)
|
|
, m_initialized(false)
|
|
{
|
|
}
|
|
|
|
D3D12Device::~D3D12Device() {
|
|
Shutdown();
|
|
}
|
|
|
|
bool D3D12Device::Initialize(const RHIDeviceDesc& desc) {
|
|
if (m_initialized) {
|
|
return true;
|
|
}
|
|
|
|
m_deviceDesc = desc;
|
|
|
|
if (!CreateDXGIFactory(desc.enableDebugLayer)) {
|
|
return false;
|
|
}
|
|
|
|
ComPtr<IDXGIAdapter1> adapter;
|
|
int adapterIndex = desc.adapterIndex;
|
|
bool adapterFound = false;
|
|
|
|
while (m_factory->EnumAdapters1(adapterIndex, &adapter) != DXGI_ERROR_NOT_FOUND) {
|
|
DXGI_ADAPTER_DESC1 descAdapter;
|
|
adapter->GetDesc1(&descAdapter);
|
|
|
|
if (descAdapter.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) {
|
|
adapterIndex++;
|
|
continue;
|
|
}
|
|
|
|
HRESULT hr = D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), nullptr);
|
|
if (SUCCEEDED(hr)) {
|
|
adapterFound = true;
|
|
m_adapter = adapter;
|
|
break;
|
|
}
|
|
adapterIndex++;
|
|
}
|
|
|
|
if (!adapterFound) {
|
|
return false;
|
|
}
|
|
|
|
if (!CreateDevice(m_adapter.Get())) {
|
|
return false;
|
|
}
|
|
|
|
QueryAdapterInfo();
|
|
m_initialized = true;
|
|
return true;
|
|
}
|
|
|
|
void D3D12Device::Shutdown() {
|
|
if (m_device) {
|
|
m_device.Reset();
|
|
}
|
|
if (m_factory) {
|
|
m_factory.Reset();
|
|
}
|
|
m_adapter.Reset();
|
|
m_initialized = false;
|
|
}
|
|
|
|
bool D3D12Device::CreateDXGIFactory(bool enableDebugLayer) {
|
|
UINT dxgiFactoryFlags = 0;
|
|
|
|
if (enableDebugLayer) {
|
|
ID3D12Debug* debugController = nullptr;
|
|
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) {
|
|
debugController->EnableDebugLayer();
|
|
dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
|
|
debugController->Release();
|
|
}
|
|
}
|
|
|
|
HRESULT hr = CreateDXGIFactory2(dxgiFactoryFlags, IID_PPV_ARGS(&m_factory));
|
|
return SUCCEEDED(hr);
|
|
}
|
|
|
|
bool D3D12Device::CreateDevice(IDXGIAdapter1* adapter) {
|
|
OutputDebugStringA("[DEBUG] CreateDevice: start\n");
|
|
HRESULT hr = D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device));
|
|
if (FAILED(hr)) {
|
|
char buf[256];
|
|
sprintf(buf, "[DEBUG] CreateDevice: D3D12CreateDevice failed! hr=%08X\n", hr);
|
|
OutputDebugStringA(buf);
|
|
}
|
|
return SUCCEEDED(hr);
|
|
}
|
|
|
|
void D3D12Device::QueryAdapterInfo() {
|
|
if (!m_adapter) {
|
|
return;
|
|
}
|
|
|
|
DXGI_ADAPTER_DESC1 desc;
|
|
m_adapter->GetDesc1(&desc);
|
|
|
|
m_adapterInfo.vendorId = desc.VendorId;
|
|
m_adapterInfo.deviceId = desc.DeviceId;
|
|
m_adapterInfo.dedicatedVideoMemory = desc.DedicatedVideoMemory;
|
|
m_adapterInfo.dedicatedSystemMemory = desc.DedicatedSystemMemory;
|
|
m_adapterInfo.sharedSystemMemory = desc.SharedSystemMemory;
|
|
m_adapterInfo.description = desc.Description;
|
|
m_adapterInfo.isSoftware = (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) != 0;
|
|
|
|
m_deviceInfo.description = desc.Description;
|
|
m_deviceInfo.vendorId = desc.VendorId;
|
|
m_deviceInfo.deviceId = desc.DeviceId;
|
|
m_deviceInfo.dedicatedVideoMemory = desc.DedicatedVideoMemory;
|
|
m_deviceInfo.dedicatedSystemMemory = desc.DedicatedSystemMemory;
|
|
m_deviceInfo.sharedSystemMemory = desc.SharedSystemMemory;
|
|
m_deviceInfo.isSoftware = (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) != 0;
|
|
|
|
switch (desc.VendorId) {
|
|
case 0x10DE: m_deviceInfo.vendor = L"NVIDIA"; break;
|
|
case 0x1002: m_deviceInfo.vendor = L"AMD"; break;
|
|
case 0x8086: m_deviceInfo.vendor = L"Intel"; break;
|
|
default: m_deviceInfo.vendor = L"Unknown"; break;
|
|
}
|
|
m_deviceInfo.renderer = desc.Description;
|
|
|
|
D3D12_FEATURE_DATA_D3D12_OPTIONS5 options5 = {};
|
|
if (SUCCEEDED(m_device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS5, &options5, sizeof(options5)))) {
|
|
m_capabilities.bSupportsRayTracing = options5.RaytracingTier != D3D12_RAYTRACING_TIER_NOT_SUPPORTED;
|
|
}
|
|
|
|
D3D12_FEATURE_DATA_D3D12_OPTIONS7 options7 = {};
|
|
if (SUCCEEDED(m_device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS7, &options7, sizeof(options7)))) {
|
|
m_capabilities.bSupportsMeshShaders = options7.MeshShaderTier != D3D12_MESH_SHADER_TIER_NOT_SUPPORTED;
|
|
}
|
|
|
|
D3D12_FEATURE_DATA_D3D12_OPTIONS options = {};
|
|
if (SUCCEEDED(m_device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options)))) {
|
|
m_capabilities.bSupportsConservativeRasterization = options.ConservativeRasterizationTier != D3D12_CONSERVATIVE_RASTERIZATION_TIER_NOT_SUPPORTED;
|
|
}
|
|
|
|
m_capabilities.bSupportsComputeShaders = true;
|
|
|
|
D3D12_FEATURE_DATA_SHADER_MODEL shaderModel = {};
|
|
const D3D_SHADER_MODEL shaderModelCandidates[] = {
|
|
D3D_SHADER_MODEL_6_7,
|
|
D3D_SHADER_MODEL_6_6,
|
|
D3D_SHADER_MODEL_6_5,
|
|
D3D_SHADER_MODEL_6_4,
|
|
D3D_SHADER_MODEL_6_3,
|
|
D3D_SHADER_MODEL_6_2,
|
|
D3D_SHADER_MODEL_6_1,
|
|
D3D_SHADER_MODEL_6_0,
|
|
D3D_SHADER_MODEL_5_1
|
|
};
|
|
for (D3D_SHADER_MODEL candidate : shaderModelCandidates) {
|
|
shaderModel.HighestShaderModel = candidate;
|
|
if (SUCCEEDED(m_device->CheckFeatureSupport(D3D12_FEATURE_SHADER_MODEL, &shaderModel, sizeof(shaderModel)))) {
|
|
m_capabilities.shaderModel = ShaderModelToString(shaderModel.HighestShaderModel);
|
|
break;
|
|
}
|
|
}
|
|
|
|
D3D12_FEATURE_DATA_D3D12_OPTIONS3 options3 = {};
|
|
if (SUCCEEDED(m_device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS3, &options3, sizeof(options3)))) {
|
|
}
|
|
|
|
D3D12_FEATURE_DATA_D3D12_OPTIONS4 options4 = {};
|
|
if (SUCCEEDED(m_device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS4, &options4, sizeof(options4)))) {
|
|
}
|
|
|
|
m_capabilities.maxRenderTargets = 8;
|
|
m_capabilities.maxViewports = 16;
|
|
m_capabilities.maxVertexAttribs = 8;
|
|
m_capabilities.maxColorAttachments = 8;
|
|
m_capabilities.maxConstantBufferSize = D3D12_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * 16;
|
|
m_capabilities.maxAnisotropy = D3D12_MAX_MAXANISOTROPY;
|
|
m_capabilities.maxTexture2DSize = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION;
|
|
m_capabilities.maxTexture3DSize = D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION;
|
|
m_capabilities.maxTextureCubeSize = D3D12_REQ_TEXTURECUBE_DIMENSION;
|
|
}
|
|
|
|
bool D3D12Device::CheckFeatureSupport(D3D12_FEATURE feature, void* featureSupportData, uint32_t featureSupportDataSize) {
|
|
return SUCCEEDED(m_device->CheckFeatureSupport(feature, featureSupportData, featureSupportDataSize));
|
|
}
|
|
|
|
std::vector<AdapterInfo> D3D12Device::EnumerateAdapters() {
|
|
std::vector<AdapterInfo> adapters;
|
|
|
|
if (!m_factory) {
|
|
return adapters;
|
|
}
|
|
|
|
ComPtr<IDXGIAdapter1> adapter;
|
|
int adapterIndex = 0;
|
|
|
|
while (m_factory->EnumAdapters1(adapterIndex, &adapter) != DXGI_ERROR_NOT_FOUND) {
|
|
DXGI_ADAPTER_DESC1 desc;
|
|
adapter->GetDesc1(&desc);
|
|
|
|
AdapterInfo info;
|
|
info.description = desc.Description;
|
|
info.dedicatedVideoMemory = desc.DedicatedVideoMemory;
|
|
info.dedicatedSystemMemory = desc.DedicatedSystemMemory;
|
|
info.sharedSystemMemory = desc.SharedSystemMemory;
|
|
info.vendorId = desc.VendorId;
|
|
info.deviceId = desc.DeviceId;
|
|
info.isSoftware = (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) != 0;
|
|
|
|
adapters.push_back(info);
|
|
adapterIndex++;
|
|
}
|
|
|
|
return adapters;
|
|
}
|
|
|
|
UINT D3D12Device::GetDescriptorHandleIncrementSize(DescriptorHeapType type) const {
|
|
return m_device->GetDescriptorHandleIncrementSize(ToD3D12(type));
|
|
}
|
|
|
|
void* D3D12Device::GetNativeHandle() const {
|
|
return m_device.Get();
|
|
}
|
|
|
|
void* D3D12Device::GetNativeDevice() {
|
|
return m_device.Get();
|
|
}
|
|
|
|
bool D3D12Device::ReadTexturePixelRGBA8(
|
|
RHICommandQueue* commandQueue,
|
|
RHITexture* texture,
|
|
ResourceStates sourceState,
|
|
uint32_t pixelX,
|
|
uint32_t pixelY,
|
|
std::array<uint8_t, 4>& outRgba) {
|
|
outRgba = {};
|
|
|
|
auto* d3d12Queue = static_cast<D3D12CommandQueue*>(commandQueue);
|
|
auto* d3d12Texture = static_cast<D3D12Texture*>(texture);
|
|
if (m_device == nullptr ||
|
|
d3d12Queue == nullptr ||
|
|
d3d12Texture == nullptr ||
|
|
d3d12Texture->GetResource() == nullptr ||
|
|
pixelX >= d3d12Texture->GetWidth() ||
|
|
pixelY >= d3d12Texture->GetHeight()) {
|
|
return false;
|
|
}
|
|
|
|
ID3D12CommandAllocator* commandAllocator = nullptr;
|
|
if (FAILED(m_device->CreateCommandAllocator(
|
|
D3D12_COMMAND_LIST_TYPE_DIRECT,
|
|
IID_PPV_ARGS(&commandAllocator)))) {
|
|
return false;
|
|
}
|
|
|
|
ID3D12GraphicsCommandList* commandList = nullptr;
|
|
if (FAILED(m_device->CreateCommandList(
|
|
0,
|
|
D3D12_COMMAND_LIST_TYPE_DIRECT,
|
|
commandAllocator,
|
|
nullptr,
|
|
IID_PPV_ARGS(&commandList)))) {
|
|
commandAllocator->Release();
|
|
return false;
|
|
}
|
|
|
|
constexpr UINT kRowPitch = D3D12_TEXTURE_DATA_PITCH_ALIGNMENT;
|
|
D3D12_HEAP_PROPERTIES heapProperties = {};
|
|
heapProperties.Type = D3D12_HEAP_TYPE_READBACK;
|
|
|
|
D3D12_RESOURCE_DESC readbackDesc = {};
|
|
readbackDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
|
readbackDesc.Width = kRowPitch;
|
|
readbackDesc.Height = 1;
|
|
readbackDesc.DepthOrArraySize = 1;
|
|
readbackDesc.MipLevels = 1;
|
|
readbackDesc.SampleDesc.Count = 1;
|
|
readbackDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
|
|
|
ID3D12Resource* readbackBuffer = nullptr;
|
|
if (FAILED(m_device->CreateCommittedResource(
|
|
&heapProperties,
|
|
D3D12_HEAP_FLAG_NONE,
|
|
&readbackDesc,
|
|
D3D12_RESOURCE_STATE_COPY_DEST,
|
|
nullptr,
|
|
IID_PPV_ARGS(&readbackBuffer)))) {
|
|
commandList->Release();
|
|
commandAllocator->Release();
|
|
return false;
|
|
}
|
|
|
|
ID3D12Resource* sourceResource = d3d12Texture->GetResource();
|
|
D3D12_RESOURCE_BARRIER barrier = {};
|
|
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
barrier.Transition.pResource = sourceResource;
|
|
barrier.Transition.StateBefore = ToD3D12(sourceState);
|
|
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE;
|
|
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
|
commandList->ResourceBarrier(1, &barrier);
|
|
|
|
D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
|
|
srcLocation.pResource = sourceResource;
|
|
srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
|
srcLocation.SubresourceIndex = 0;
|
|
|
|
D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
|
|
dstLocation.pResource = readbackBuffer;
|
|
dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
|
|
dstLocation.PlacedFootprint.Offset = 0;
|
|
dstLocation.PlacedFootprint.Footprint.Format = sourceResource->GetDesc().Format;
|
|
dstLocation.PlacedFootprint.Footprint.Width = 1;
|
|
dstLocation.PlacedFootprint.Footprint.Height = 1;
|
|
dstLocation.PlacedFootprint.Footprint.Depth = 1;
|
|
dstLocation.PlacedFootprint.Footprint.RowPitch = kRowPitch;
|
|
|
|
D3D12_BOX sourceBox = {};
|
|
sourceBox.left = pixelX;
|
|
sourceBox.top = pixelY;
|
|
sourceBox.front = 0;
|
|
sourceBox.right = pixelX + 1u;
|
|
sourceBox.bottom = pixelY + 1u;
|
|
sourceBox.back = 1;
|
|
commandList->CopyTextureRegion(&dstLocation, 0, 0, 0, &srcLocation, &sourceBox);
|
|
|
|
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_SOURCE;
|
|
barrier.Transition.StateAfter = ToD3D12(sourceState);
|
|
commandList->ResourceBarrier(1, &barrier);
|
|
|
|
if (FAILED(commandList->Close())) {
|
|
readbackBuffer->Release();
|
|
commandList->Release();
|
|
commandAllocator->Release();
|
|
return false;
|
|
}
|
|
|
|
ID3D12CommandList* commandLists[] = { commandList };
|
|
d3d12Queue->GetCommandQueue()->ExecuteCommandLists(1, commandLists);
|
|
if (!WaitForQueueIdle(m_device.Get(), d3d12Queue->GetCommandQueue())) {
|
|
readbackBuffer->Release();
|
|
commandList->Release();
|
|
commandAllocator->Release();
|
|
return false;
|
|
}
|
|
|
|
void* mappedData = nullptr;
|
|
D3D12_RANGE readRange = { 0, 4 };
|
|
if (FAILED(readbackBuffer->Map(0, &readRange, &mappedData))) {
|
|
readbackBuffer->Release();
|
|
commandList->Release();
|
|
commandAllocator->Release();
|
|
return false;
|
|
}
|
|
|
|
std::memcpy(outRgba.data(), mappedData, outRgba.size());
|
|
D3D12_RANGE writeRange = { 0, 0 };
|
|
readbackBuffer->Unmap(0, &writeRange);
|
|
|
|
readbackBuffer->Release();
|
|
commandList->Release();
|
|
commandAllocator->Release();
|
|
return true;
|
|
}
|
|
|
|
const RHICapabilities& D3D12Device::GetCapabilities() const {
|
|
return m_capabilities;
|
|
}
|
|
|
|
const RHIDeviceInfo& D3D12Device::GetDeviceInfo() const {
|
|
return m_deviceInfo;
|
|
}
|
|
|
|
RHIBuffer* D3D12Device::CreateBuffer(const BufferDesc& desc) {
|
|
auto* buffer = new D3D12Buffer();
|
|
const BufferType bufferType = static_cast<BufferType>(desc.bufferType);
|
|
const BufferFlags bufferFlags = static_cast<BufferFlags>(desc.flags);
|
|
D3D12_HEAP_TYPE heapType = D3D12_HEAP_TYPE_DEFAULT;
|
|
D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COMMON;
|
|
D3D12_RESOURCE_FLAGS resourceFlags = D3D12_RESOURCE_FLAG_NONE;
|
|
|
|
if (bufferType == BufferType::ReadBack) {
|
|
heapType = D3D12_HEAP_TYPE_READBACK;
|
|
initialState = D3D12_RESOURCE_STATE_COPY_DEST;
|
|
} else if (bufferType == BufferType::Constant ||
|
|
bufferType == BufferType::Vertex ||
|
|
bufferType == BufferType::Index) {
|
|
heapType = D3D12_HEAP_TYPE_UPLOAD;
|
|
initialState = D3D12_RESOURCE_STATE_GENERIC_READ;
|
|
} else if (bufferType == BufferType::Storage) {
|
|
const bool allowUnorderedAccess =
|
|
(bufferFlags & BufferFlags::AllowUnorderedAccess) == BufferFlags::AllowUnorderedAccess;
|
|
if (allowUnorderedAccess) {
|
|
resourceFlags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
|
} else {
|
|
heapType = D3D12_HEAP_TYPE_UPLOAD;
|
|
initialState = D3D12_RESOURCE_STATE_GENERIC_READ;
|
|
}
|
|
}
|
|
|
|
if (ShouldTraceLargeStorageBuffer(desc)) {
|
|
LogVolumeTraceRendering(
|
|
"D3D12 CreateBuffer legacy size_bytes=" + std::to_string(desc.size) +
|
|
" heap=" + std::to_string(static_cast<int>(heapType)) +
|
|
" flags=" + std::to_string(static_cast<unsigned long long>(desc.flags)));
|
|
}
|
|
|
|
if (buffer->Initialize(m_device.Get(), desc.size, initialState, heapType, resourceFlags)) {
|
|
buffer->SetStride(desc.stride);
|
|
buffer->SetBufferType(bufferType);
|
|
buffer->SetState(ResourceStates::Common);
|
|
return buffer;
|
|
}
|
|
delete buffer;
|
|
return nullptr;
|
|
}
|
|
|
|
RHIBuffer* D3D12Device::CreateBuffer(
|
|
const BufferDesc& desc,
|
|
const void* initialData,
|
|
size_t initialDataSize,
|
|
ResourceStates finalState) {
|
|
const bool traceLargeStorageBuffer = ShouldTraceLargeStorageBuffer(desc);
|
|
const uint64_t traceStartMs = traceLargeStorageBuffer ? GetVolumeTraceSteadyMs() : 0u;
|
|
if (traceLargeStorageBuffer) {
|
|
LogVolumeTraceRendering(
|
|
"D3D12 CreateBuffer(initialData) begin steady_ms=" + std::to_string(traceStartMs) +
|
|
" size_bytes=" + std::to_string(desc.size) +
|
|
" initial_bytes=" + std::to_string(initialDataSize));
|
|
}
|
|
|
|
if (initialData == nullptr || initialDataSize == 0u) {
|
|
return CreateBuffer(desc);
|
|
}
|
|
if (m_device == nullptr ||
|
|
desc.size == 0u ||
|
|
initialDataSize > desc.size ||
|
|
desc.size > static_cast<uint64_t>(SIZE_MAX)) {
|
|
if (traceLargeStorageBuffer) {
|
|
LogVolumeTraceRendering("D3D12 CreateBuffer(initialData) rejected invalid parameters");
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
const BufferType bufferType = static_cast<BufferType>(desc.bufferType);
|
|
if (bufferType == BufferType::ReadBack) {
|
|
if (traceLargeStorageBuffer) {
|
|
LogVolumeTraceRendering("D3D12 CreateBuffer(initialData) rejected readback buffer");
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
const BufferFlags bufferFlags = static_cast<BufferFlags>(desc.flags);
|
|
D3D12_RESOURCE_FLAGS resourceFlags = D3D12_RESOURCE_FLAG_NONE;
|
|
if ((bufferFlags & BufferFlags::AllowUnorderedAccess) == BufferFlags::AllowUnorderedAccess) {
|
|
resourceFlags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
|
}
|
|
|
|
D3D12CommandQueue uploadQueue;
|
|
if (!uploadQueue.Initialize(m_device.Get(), CommandQueueType::Direct)) {
|
|
if (traceLargeStorageBuffer) {
|
|
LogVolumeTraceRendering("D3D12 CreateBuffer(initialData) failed stage=init_queue");
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
D3D12CommandAllocator uploadAllocator;
|
|
if (!uploadAllocator.Initialize(m_device.Get(), CommandQueueType::Direct)) {
|
|
if (traceLargeStorageBuffer) {
|
|
LogVolumeTraceRendering("D3D12 CreateBuffer(initialData) failed stage=init_allocator");
|
|
}
|
|
uploadQueue.Shutdown();
|
|
return nullptr;
|
|
}
|
|
|
|
D3D12CommandList uploadCommandList;
|
|
if (!uploadCommandList.Initialize(m_device.Get(), CommandQueueType::Direct, uploadAllocator.GetCommandAllocator())) {
|
|
if (traceLargeStorageBuffer) {
|
|
LogVolumeTraceRendering("D3D12 CreateBuffer(initialData) failed stage=init_command_list");
|
|
}
|
|
uploadAllocator.Shutdown();
|
|
uploadQueue.Shutdown();
|
|
return nullptr;
|
|
}
|
|
|
|
auto shutdownUploadContext = [&]() {
|
|
uploadCommandList.Shutdown();
|
|
uploadAllocator.Shutdown();
|
|
uploadQueue.Shutdown();
|
|
};
|
|
|
|
uploadAllocator.Reset();
|
|
uploadCommandList.Reset();
|
|
const uint64_t commandSetupEndMs = traceLargeStorageBuffer ? GetVolumeTraceSteadyMs() : 0u;
|
|
|
|
auto* buffer = new D3D12Buffer();
|
|
if (!buffer->Initialize(
|
|
m_device.Get(),
|
|
desc.size,
|
|
D3D12_RESOURCE_STATE_COPY_DEST,
|
|
D3D12_HEAP_TYPE_DEFAULT,
|
|
resourceFlags)) {
|
|
if (traceLargeStorageBuffer) {
|
|
LogVolumeTraceRendering("D3D12 CreateBuffer(initialData) failed stage=create_default_buffer");
|
|
}
|
|
delete buffer;
|
|
shutdownUploadContext();
|
|
return nullptr;
|
|
}
|
|
const uint64_t defaultBufferEndMs = traceLargeStorageBuffer ? GetVolumeTraceSteadyMs() : 0u;
|
|
|
|
buffer->SetStride(desc.stride);
|
|
buffer->SetBufferType(bufferType);
|
|
buffer->SetState(ResourceStates::CopyDst);
|
|
|
|
D3D12_HEAP_PROPERTIES uploadHeapProperties = {};
|
|
uploadHeapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;
|
|
uploadHeapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
|
uploadHeapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
|
uploadHeapProperties.CreationNodeMask = 0;
|
|
uploadHeapProperties.VisibleNodeMask = 0;
|
|
|
|
D3D12_RESOURCE_DESC uploadBufferDesc = {};
|
|
uploadBufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
|
uploadBufferDesc.Alignment = 0;
|
|
uploadBufferDesc.Width = desc.size;
|
|
uploadBufferDesc.Height = 1;
|
|
uploadBufferDesc.DepthOrArraySize = 1;
|
|
uploadBufferDesc.MipLevels = 1;
|
|
uploadBufferDesc.Format = DXGI_FORMAT_UNKNOWN;
|
|
uploadBufferDesc.SampleDesc.Count = 1;
|
|
uploadBufferDesc.SampleDesc.Quality = 0;
|
|
uploadBufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
|
uploadBufferDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
|
|
|
ComPtr<ID3D12Resource> uploadBuffer;
|
|
if (FAILED(m_device->CreateCommittedResource(
|
|
&uploadHeapProperties,
|
|
D3D12_HEAP_FLAG_NONE,
|
|
&uploadBufferDesc,
|
|
D3D12_RESOURCE_STATE_GENERIC_READ,
|
|
nullptr,
|
|
IID_PPV_ARGS(&uploadBuffer)))) {
|
|
if (traceLargeStorageBuffer) {
|
|
LogVolumeTraceRendering("D3D12 CreateBuffer(initialData) failed stage=create_upload_buffer");
|
|
}
|
|
buffer->Shutdown();
|
|
delete buffer;
|
|
shutdownUploadContext();
|
|
return nullptr;
|
|
}
|
|
const uint64_t uploadBufferEndMs = traceLargeStorageBuffer ? GetVolumeTraceSteadyMs() : 0u;
|
|
|
|
void* mappedData = nullptr;
|
|
D3D12_RANGE readRange = { 0, 0 };
|
|
if (FAILED(uploadBuffer->Map(0, &readRange, &mappedData)) || mappedData == nullptr) {
|
|
if (traceLargeStorageBuffer) {
|
|
LogVolumeTraceRendering("D3D12 CreateBuffer(initialData) failed stage=map_upload_buffer");
|
|
}
|
|
buffer->Shutdown();
|
|
delete buffer;
|
|
shutdownUploadContext();
|
|
return nullptr;
|
|
}
|
|
|
|
std::memset(mappedData, 0, static_cast<size_t>(desc.size));
|
|
std::memcpy(mappedData, initialData, initialDataSize);
|
|
uploadBuffer->Unmap(0, nullptr);
|
|
const uint64_t cpuFillEndMs = traceLargeStorageBuffer ? GetVolumeTraceSteadyMs() : 0u;
|
|
|
|
ID3D12GraphicsCommandList* const commandList = uploadCommandList.GetCommandList();
|
|
commandList->CopyBufferRegion(
|
|
buffer->GetResource(),
|
|
0,
|
|
uploadBuffer.Get(),
|
|
0,
|
|
desc.size);
|
|
|
|
const D3D12_RESOURCE_STATES resolvedFinalState = ToD3D12(finalState);
|
|
if (resolvedFinalState != D3D12_RESOURCE_STATE_COPY_DEST) {
|
|
D3D12_RESOURCE_BARRIER barrier = {};
|
|
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
|
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
barrier.Transition.pResource = buffer->GetResource();
|
|
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
|
|
barrier.Transition.StateAfter = resolvedFinalState;
|
|
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
|
commandList->ResourceBarrier(1, &barrier);
|
|
}
|
|
const uint64_t recordCommandsEndMs = traceLargeStorageBuffer ? GetVolumeTraceSteadyMs() : 0u;
|
|
|
|
uploadCommandList.Close();
|
|
ID3D12CommandList* commandLists[] = { commandList };
|
|
uploadQueue.ExecuteCommandListsInternal(1, commandLists);
|
|
const uint64_t submitEndMs = traceLargeStorageBuffer ? GetVolumeTraceSteadyMs() : 0u;
|
|
if (traceLargeStorageBuffer) {
|
|
LogVolumeTraceRendering(
|
|
"D3D12 CreateBuffer(initialData) waiting_for_idle steady_ms=" + std::to_string(submitEndMs) +
|
|
" size_bytes=" + std::to_string(desc.size));
|
|
}
|
|
uploadQueue.WaitForIdle();
|
|
const uint64_t waitEndMs = traceLargeStorageBuffer ? GetVolumeTraceSteadyMs() : 0u;
|
|
|
|
buffer->SetState(finalState);
|
|
if (traceLargeStorageBuffer) {
|
|
LogVolumeTraceRendering(
|
|
"D3D12 CreateBuffer(initialData) end steady_ms=" + std::to_string(waitEndMs) +
|
|
" total_ms=" + std::to_string(waitEndMs - traceStartMs) +
|
|
" setup_ms=" + std::to_string(commandSetupEndMs - traceStartMs) +
|
|
" default_buffer_ms=" + std::to_string(defaultBufferEndMs - commandSetupEndMs) +
|
|
" upload_buffer_ms=" + std::to_string(uploadBufferEndMs - defaultBufferEndMs) +
|
|
" cpu_fill_ms=" + std::to_string(cpuFillEndMs - uploadBufferEndMs) +
|
|
" record_ms=" + std::to_string(recordCommandsEndMs - cpuFillEndMs) +
|
|
" submit_ms=" + std::to_string(submitEndMs - recordCommandsEndMs) +
|
|
" wait_ms=" + std::to_string(waitEndMs - submitEndMs));
|
|
}
|
|
shutdownUploadContext();
|
|
return buffer;
|
|
}
|
|
|
|
RHITexture* D3D12Device::CreateTexture(const TextureDesc& desc) {
|
|
auto* texture = new D3D12Texture();
|
|
D3D12_RESOURCE_DESC d3d12Desc = {};
|
|
|
|
const TextureType textureType = ResolveTextureType(desc.textureType);
|
|
const Format format = static_cast<Format>(desc.format);
|
|
const bool isDepthFormat = IsDepthFormat(format);
|
|
|
|
d3d12Desc.Dimension = ToD3D12(textureType);
|
|
d3d12Desc.Width = desc.width;
|
|
d3d12Desc.Height = desc.height;
|
|
d3d12Desc.DepthOrArraySize = ResolveDepthOrArraySize(desc, textureType);
|
|
d3d12Desc.MipLevels = desc.mipLevels > 0 ? desc.mipLevels : 1;
|
|
d3d12Desc.Format = ResolveD3D12ResourceFormat(format);
|
|
d3d12Desc.SampleDesc.Count = desc.sampleCount > 0 ? desc.sampleCount : 1;
|
|
d3d12Desc.SampleDesc.Quality = desc.sampleQuality;
|
|
d3d12Desc.Flags = static_cast<D3D12_RESOURCE_FLAGS>(desc.flags);
|
|
|
|
if (isDepthFormat) {
|
|
d3d12Desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
|
|
} else if (d3d12Desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D && desc.width > 0 && desc.height > 0) {
|
|
d3d12Desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
|
|
}
|
|
|
|
d3d12Desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
|
const D3D12_RESOURCE_STATES initialState =
|
|
isDepthFormat ? D3D12_RESOURCE_STATE_DEPTH_WRITE : D3D12_RESOURCE_STATE_COMMON;
|
|
if (texture->Initialize(m_device.Get(), d3d12Desc, initialState)) {
|
|
texture->SetFormat(format);
|
|
texture->SetTextureType(textureType);
|
|
if (isDepthFormat) {
|
|
texture->SetState(ResourceStates::DepthWrite);
|
|
}
|
|
return texture;
|
|
}
|
|
delete texture;
|
|
return nullptr;
|
|
}
|
|
|
|
RHITexture* D3D12Device::CreateTexture(const TextureDesc& desc, const void* initialData, size_t initialDataSize, uint32_t rowPitch) {
|
|
(void)initialDataSize;
|
|
|
|
if (initialData == nullptr) {
|
|
return CreateTexture(desc);
|
|
}
|
|
|
|
const Format format = static_cast<Format>(desc.format);
|
|
uint32_t resolvedRowPitch = rowPitch;
|
|
if (resolvedRowPitch == 0) {
|
|
const uint32_t bytesPerPixel = GetFormatBytesPerPixel(format);
|
|
if (bytesPerPixel == 0) {
|
|
return nullptr;
|
|
}
|
|
resolvedRowPitch = desc.width * bytesPerPixel;
|
|
}
|
|
|
|
D3D12CommandQueue uploadQueue;
|
|
if (!uploadQueue.Initialize(m_device.Get(), CommandQueueType::Direct)) {
|
|
return nullptr;
|
|
}
|
|
|
|
D3D12CommandAllocator uploadAllocator;
|
|
if (!uploadAllocator.Initialize(m_device.Get(), CommandQueueType::Direct)) {
|
|
uploadQueue.Shutdown();
|
|
return nullptr;
|
|
}
|
|
|
|
D3D12CommandList uploadCommandList;
|
|
if (!uploadCommandList.Initialize(m_device.Get(), CommandQueueType::Direct, uploadAllocator.GetCommandAllocator())) {
|
|
uploadAllocator.Shutdown();
|
|
uploadQueue.Shutdown();
|
|
return nullptr;
|
|
}
|
|
|
|
uploadAllocator.Reset();
|
|
uploadCommandList.Reset();
|
|
|
|
auto* texture = new D3D12Texture();
|
|
D3D12_RESOURCE_DESC textureDesc = {};
|
|
const TextureType textureType = ResolveTextureType(desc.textureType);
|
|
textureDesc.Dimension = ToD3D12(textureType);
|
|
textureDesc.Alignment = 0;
|
|
textureDesc.Width = desc.width;
|
|
textureDesc.Height = desc.height;
|
|
textureDesc.DepthOrArraySize = ResolveDepthOrArraySize(desc, textureType);
|
|
textureDesc.MipLevels = desc.mipLevels > 0 ? static_cast<uint16_t>(desc.mipLevels) : 1;
|
|
textureDesc.Format = ResolveD3D12ResourceFormat(format);
|
|
textureDesc.SampleDesc.Count = desc.sampleCount > 0 ? desc.sampleCount : 1;
|
|
textureDesc.SampleDesc.Quality = desc.sampleQuality;
|
|
textureDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
|
textureDesc.Flags = static_cast<D3D12_RESOURCE_FLAGS>(desc.flags);
|
|
ComPtr<ID3D12Resource> uploadBuffer;
|
|
if (!texture->InitializeFromData(
|
|
m_device.Get(),
|
|
uploadCommandList.GetCommandList(),
|
|
textureDesc,
|
|
textureType,
|
|
initialData,
|
|
initialDataSize,
|
|
resolvedRowPitch,
|
|
&uploadBuffer)) {
|
|
delete texture;
|
|
uploadCommandList.Shutdown();
|
|
uploadAllocator.Shutdown();
|
|
uploadQueue.Shutdown();
|
|
return nullptr;
|
|
}
|
|
|
|
texture->SetState(ResourceStates::PixelShaderResource);
|
|
texture->SetFormat(format);
|
|
texture->SetTextureType(textureType);
|
|
|
|
uploadCommandList.Close();
|
|
ID3D12CommandList* commandLists[] = { uploadCommandList.GetCommandList() };
|
|
uploadQueue.ExecuteCommandListsInternal(1, commandLists);
|
|
uploadQueue.WaitForIdle();
|
|
uploadBuffer.Reset();
|
|
|
|
uploadCommandList.Shutdown();
|
|
uploadAllocator.Shutdown();
|
|
uploadQueue.Shutdown();
|
|
return texture;
|
|
}
|
|
|
|
RHIShader* D3D12Device::CreateShader(const ShaderCompileDesc& desc) {
|
|
auto* shader = new D3D12Shader();
|
|
const std::string entryPoint = NarrowAscii(desc.entryPoint);
|
|
const std::string profile = NarrowAscii(desc.profile);
|
|
const char* entryPointPtr = entryPoint.empty() ? nullptr : entryPoint.c_str();
|
|
const char* profilePtr = profile.empty() ? nullptr : profile.c_str();
|
|
|
|
bool success = false;
|
|
if (!desc.source.empty()) {
|
|
success = shader->Compile(
|
|
desc.source.data(),
|
|
desc.source.size(),
|
|
desc.fileName.empty() ? nullptr : desc.fileName.c_str(),
|
|
nullptr,
|
|
entryPointPtr,
|
|
profilePtr);
|
|
} else if (!desc.fileName.empty()) {
|
|
success = shader->CompileFromFile(desc.fileName.c_str(), entryPointPtr, profilePtr);
|
|
}
|
|
|
|
if (success) {
|
|
return shader;
|
|
}
|
|
delete shader;
|
|
return nullptr;
|
|
}
|
|
|
|
RHISampler* D3D12Device::CreateSampler(const SamplerDesc& desc) {
|
|
auto* sampler = new D3D12Sampler();
|
|
D3D12_SAMPLER_DESC d3d12Desc = {};
|
|
d3d12Desc.Filter = ToD3D12(static_cast<FilterMode>(desc.filter));
|
|
d3d12Desc.AddressU = ToD3D12(static_cast<TextureAddressMode>(desc.addressU));
|
|
d3d12Desc.AddressV = ToD3D12(static_cast<TextureAddressMode>(desc.addressV));
|
|
d3d12Desc.AddressW = ToD3D12(static_cast<TextureAddressMode>(desc.addressW));
|
|
d3d12Desc.MipLODBias = desc.mipLodBias;
|
|
d3d12Desc.MaxAnisotropy = desc.maxAnisotropy;
|
|
d3d12Desc.ComparisonFunc = ToD3D12(static_cast<ComparisonFunc>(desc.comparisonFunc));
|
|
d3d12Desc.BorderColor[0] = desc.borderColorR;
|
|
d3d12Desc.BorderColor[1] = desc.borderColorG;
|
|
d3d12Desc.BorderColor[2] = desc.borderColorB;
|
|
d3d12Desc.BorderColor[3] = desc.borderColorA;
|
|
d3d12Desc.MinLOD = desc.minLod;
|
|
d3d12Desc.MaxLOD = desc.maxLod;
|
|
if (sampler->Initialize(m_device.Get(), d3d12Desc)) {
|
|
return sampler;
|
|
}
|
|
delete sampler;
|
|
return nullptr;
|
|
}
|
|
|
|
RHIDescriptorPool* D3D12Device::CreateDescriptorPool(const DescriptorPoolDesc& desc) {
|
|
auto* pool = new D3D12DescriptorHeap();
|
|
DescriptorPoolDesc poolDesc = desc;
|
|
poolDesc.device = m_device.Get();
|
|
if (pool->Initialize(poolDesc)) {
|
|
return pool;
|
|
}
|
|
delete pool;
|
|
return nullptr;
|
|
}
|
|
|
|
RHIRenderPass* D3D12Device::CreateRenderPass(
|
|
uint32_t colorAttachmentCount,
|
|
const AttachmentDesc* colorAttachments,
|
|
const AttachmentDesc* depthStencilAttachment) {
|
|
auto* renderPass = new D3D12RenderPass();
|
|
if (!renderPass->Initialize(colorAttachmentCount, colorAttachments, depthStencilAttachment)) {
|
|
delete renderPass;
|
|
return nullptr;
|
|
}
|
|
return renderPass;
|
|
}
|
|
|
|
RHIFramebuffer* D3D12Device::CreateFramebuffer(
|
|
class RHIRenderPass* renderPass,
|
|
uint32_t width, uint32_t height,
|
|
uint32_t colorAttachmentCount,
|
|
RHIResourceView** colorAttachments,
|
|
RHIResourceView* depthStencilAttachment) {
|
|
auto* framebuffer = new D3D12Framebuffer();
|
|
if (!framebuffer->Initialize(renderPass, width, height, colorAttachmentCount, colorAttachments, depthStencilAttachment)) {
|
|
delete framebuffer;
|
|
return nullptr;
|
|
}
|
|
return framebuffer;
|
|
}
|
|
|
|
RHIDescriptorSet* D3D12Device::CreateDescriptorSet(RHIDescriptorPool* pool, const DescriptorSetLayoutDesc& layout) {
|
|
if (pool == nullptr) {
|
|
return nullptr;
|
|
}
|
|
return pool->AllocateSet(layout);
|
|
}
|
|
|
|
RHIFence* D3D12Device::CreateFence(const FenceDesc& desc) {
|
|
auto* fence = new D3D12Fence();
|
|
if (fence->Initialize(m_device.Get(), desc.initialValue)) {
|
|
return fence;
|
|
}
|
|
delete fence;
|
|
return nullptr;
|
|
}
|
|
|
|
RHIResourceView* D3D12Device::CreateVertexBufferView(RHIBuffer* buffer, const ResourceViewDesc& desc) {
|
|
if (!buffer) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto* view = new D3D12ResourceView();
|
|
view->InitializeAsVertexBuffer(static_cast<D3D12Buffer*>(buffer), desc);
|
|
if (!view->IsValid()) {
|
|
delete view;
|
|
return nullptr;
|
|
}
|
|
|
|
return view;
|
|
}
|
|
|
|
RHIResourceView* D3D12Device::CreateIndexBufferView(RHIBuffer* buffer, const ResourceViewDesc& desc) {
|
|
if (!buffer) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto* view = new D3D12ResourceView();
|
|
view->InitializeAsIndexBuffer(static_cast<D3D12Buffer*>(buffer), desc);
|
|
if (!view->IsValid()) {
|
|
delete view;
|
|
return nullptr;
|
|
}
|
|
|
|
return view;
|
|
}
|
|
|
|
RHISwapChain* D3D12Device::CreateSwapChain(const SwapChainDesc& desc, RHICommandQueue* presentQueue) {
|
|
if (presentQueue == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto* nativeQueue = static_cast<ID3D12CommandQueue*>(presentQueue->GetNativeHandle());
|
|
if (nativeQueue == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto* swapChain = new D3D12SwapChain();
|
|
HWND hwnd = static_cast<HWND>(desc.windowHandle);
|
|
if (swapChain->Initialize(m_factory.Get(), nativeQueue, hwnd,
|
|
desc.width, desc.height, desc.bufferCount)) {
|
|
return swapChain;
|
|
}
|
|
delete swapChain;
|
|
return nullptr;
|
|
}
|
|
|
|
RHICommandList* D3D12Device::CreateCommandList(const CommandListDesc& desc) {
|
|
if (!m_device) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto allocator = std::make_unique<D3D12CommandAllocator>();
|
|
if (!allocator->Initialize(m_device.Get(), static_cast<CommandQueueType>(desc.commandListType))) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto* cmdList = new D3D12CommandList();
|
|
if (!cmdList->Initialize(m_device.Get(), static_cast<CommandQueueType>(desc.commandListType), allocator->GetCommandAllocator())) {
|
|
delete cmdList;
|
|
return nullptr;
|
|
}
|
|
|
|
return cmdList;
|
|
}
|
|
|
|
RHICommandQueue* D3D12Device::CreateCommandQueue(const CommandQueueDesc& desc) {
|
|
auto* queue = new D3D12CommandQueue();
|
|
if (queue->Initialize(m_device.Get(), static_cast<CommandQueueType>(desc.queueType))) {
|
|
return queue;
|
|
}
|
|
delete queue;
|
|
return nullptr;
|
|
}
|
|
|
|
RHIPipelineState* D3D12Device::CreatePipelineState(const GraphicsPipelineDesc& desc) {
|
|
const bool traceVolumetricPipeline =
|
|
ShouldTraceVolumetricShaderCompile(desc.vertexShader) ||
|
|
ShouldTraceVolumetricShaderCompile(desc.fragmentShader) ||
|
|
ShouldTraceVolumetricShaderCompile(desc.geometryShader);
|
|
const uint64_t pipelineStartMs = traceVolumetricPipeline ? GetVolumeTraceSteadyMs() : 0u;
|
|
if (traceVolumetricPipeline) {
|
|
LogVolumeTraceRendering(
|
|
"D3D12 CreatePipelineState begin steady_ms=" + std::to_string(pipelineStartMs) +
|
|
" has_vs=" + std::to_string(HasShaderPayload(desc.vertexShader) ? 1 : 0) +
|
|
" has_ps=" + std::to_string(HasShaderPayload(desc.fragmentShader) ? 1 : 0) +
|
|
" has_gs=" + std::to_string(HasShaderPayload(desc.geometryShader) ? 1 : 0));
|
|
}
|
|
|
|
auto* pso = new D3D12PipelineState(m_device.Get());
|
|
pso->SetInputLayout(desc.inputLayout);
|
|
pso->SetRasterizerState(desc.rasterizerState);
|
|
pso->SetBlendState(desc.blendState);
|
|
pso->SetDepthStencilState(desc.depthStencilState);
|
|
pso->SetTopology(desc.topologyType);
|
|
pso->SetRenderTargetFormats(desc.renderTargetCount, desc.renderTargetFormats, desc.depthStencilFormat);
|
|
pso->SetSampleCount(desc.sampleCount);
|
|
pso->SetSampleQuality(desc.sampleQuality);
|
|
|
|
const bool hasVertexShader = HasShaderPayload(desc.vertexShader);
|
|
const bool hasFragmentShader = HasShaderPayload(desc.fragmentShader);
|
|
const bool hasGeometryShader = HasShaderPayload(desc.geometryShader);
|
|
if (!hasVertexShader && !hasFragmentShader && !hasGeometryShader) {
|
|
return pso;
|
|
}
|
|
|
|
if (!hasVertexShader || !hasFragmentShader) {
|
|
delete pso;
|
|
return nullptr;
|
|
}
|
|
|
|
D3D12RootSignature* rootSignature = nullptr;
|
|
if (desc.pipelineLayout != nullptr) {
|
|
auto* pipelineLayout = static_cast<D3D12PipelineLayout*>(desc.pipelineLayout);
|
|
pso->SetRootSignature(pipelineLayout->GetRootSignature());
|
|
} else {
|
|
rootSignature = CreateRootSignature({});
|
|
if (rootSignature == nullptr) {
|
|
delete pso;
|
|
return nullptr;
|
|
}
|
|
pso->SetRootSignature(rootSignature->GetRootSignature());
|
|
}
|
|
|
|
D3D12Shader vertexShader;
|
|
D3D12Shader fragmentShader;
|
|
D3D12Shader geometryShader;
|
|
const bool vertexCompiled = CompileD3D12Shader(desc.vertexShader, vertexShader);
|
|
const bool fragmentCompiled = CompileD3D12Shader(desc.fragmentShader, fragmentShader);
|
|
const bool geometryCompiled = !hasGeometryShader || CompileD3D12Shader(desc.geometryShader, geometryShader);
|
|
|
|
if (!vertexCompiled || !fragmentCompiled || !geometryCompiled) {
|
|
if (traceVolumetricPipeline) {
|
|
const uint64_t failureMs = GetVolumeTraceSteadyMs();
|
|
LogVolumeTraceRendering(
|
|
"D3D12 CreatePipelineState failed steady_ms=" + std::to_string(failureMs) +
|
|
" total_ms=" + std::to_string(failureMs - pipelineStartMs) +
|
|
" vertex_ok=" + std::to_string(vertexCompiled ? 1 : 0) +
|
|
" fragment_ok=" + std::to_string(fragmentCompiled ? 1 : 0) +
|
|
" geometry_ok=" + std::to_string(geometryCompiled ? 1 : 0));
|
|
}
|
|
if (rootSignature != nullptr) {
|
|
rootSignature->Shutdown();
|
|
delete rootSignature;
|
|
}
|
|
delete pso;
|
|
return nullptr;
|
|
}
|
|
|
|
pso->SetShaderBytecodes(
|
|
vertexShader.GetD3D12Bytecode(),
|
|
fragmentShader.GetD3D12Bytecode(),
|
|
hasGeometryShader ? geometryShader.GetD3D12Bytecode() : D3D12_SHADER_BYTECODE{});
|
|
const uint64_t finalizeStartMs = traceVolumetricPipeline ? GetVolumeTraceSteadyMs() : 0u;
|
|
if (traceVolumetricPipeline) {
|
|
LogVolumeTraceRendering(
|
|
"D3D12 CreatePipelineState finalize begin steady_ms=" + std::to_string(finalizeStartMs));
|
|
}
|
|
pso->EnsureValid();
|
|
if (traceVolumetricPipeline) {
|
|
const uint64_t finalizeEndMs = GetVolumeTraceSteadyMs();
|
|
LogVolumeTraceRendering(
|
|
"D3D12 CreatePipelineState finalize end steady_ms=" + std::to_string(finalizeEndMs) +
|
|
" total_ms=" + std::to_string(finalizeEndMs - finalizeStartMs) +
|
|
" valid=" + std::to_string(pso->IsValid() ? 1 : 0));
|
|
}
|
|
|
|
if (rootSignature != nullptr) {
|
|
rootSignature->Shutdown();
|
|
delete rootSignature;
|
|
}
|
|
|
|
if (!pso->IsValid()) {
|
|
if (traceVolumetricPipeline) {
|
|
const uint64_t failureMs = GetVolumeTraceSteadyMs();
|
|
LogVolumeTraceRendering(
|
|
"D3D12 CreatePipelineState invalid steady_ms=" + std::to_string(failureMs) +
|
|
" total_ms=" + std::to_string(failureMs - pipelineStartMs));
|
|
}
|
|
delete pso;
|
|
return nullptr;
|
|
}
|
|
|
|
if (traceVolumetricPipeline) {
|
|
const uint64_t pipelineEndMs = GetVolumeTraceSteadyMs();
|
|
LogVolumeTraceRendering(
|
|
"D3D12 CreatePipelineState end steady_ms=" + std::to_string(pipelineEndMs) +
|
|
" total_ms=" + std::to_string(pipelineEndMs - pipelineStartMs));
|
|
}
|
|
return pso;
|
|
}
|
|
|
|
RHIPipelineLayout* D3D12Device::CreatePipelineLayout(const RHIPipelineLayoutDesc& desc) {
|
|
auto* pipelineLayout = new D3D12PipelineLayout();
|
|
if (!pipelineLayout->InitializeWithDevice(this, desc)) {
|
|
delete pipelineLayout;
|
|
return nullptr;
|
|
}
|
|
return pipelineLayout;
|
|
}
|
|
|
|
RHIResourceView* D3D12Device::CreateRenderTargetView(RHITexture* texture, const ResourceViewDesc& desc) {
|
|
if (!texture) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto* view = new D3D12ResourceView();
|
|
auto* d3d12Texture = static_cast<D3D12Texture*>(texture);
|
|
ID3D12Resource* resource = d3d12Texture->GetResource();
|
|
|
|
if (!resource) {
|
|
delete view;
|
|
return nullptr;
|
|
}
|
|
|
|
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
|
|
const Format format = desc.format != 0 ? static_cast<Format>(desc.format) : texture->GetFormat();
|
|
const TextureType textureType = texture->GetTextureType();
|
|
rtvDesc.Format = ToD3D12(format);
|
|
rtvDesc.ViewDimension = ResolveRTVDimension(desc, textureType);
|
|
if (rtvDesc.ViewDimension == D3D12_RTV_DIMENSION_TEXTURE2DARRAY) {
|
|
rtvDesc.Texture2DArray.MipSlice = desc.mipLevel;
|
|
rtvDesc.Texture2DArray.FirstArraySlice = desc.firstArraySlice;
|
|
rtvDesc.Texture2DArray.ArraySize = desc.arraySize > 0 ? desc.arraySize : 1;
|
|
rtvDesc.Texture2DArray.PlaneSlice = desc.planeSlice;
|
|
} else if (rtvDesc.ViewDimension == D3D12_RTV_DIMENSION_TEXTURE3D) {
|
|
rtvDesc.Texture3D.MipSlice = desc.mipLevel;
|
|
rtvDesc.Texture3D.FirstWSlice = desc.firstArraySlice;
|
|
rtvDesc.Texture3D.WSize = desc.arraySize > 0 ? desc.arraySize : 1;
|
|
} else {
|
|
rtvDesc.Texture2D.MipSlice = desc.mipLevel;
|
|
rtvDesc.Texture2D.PlaneSlice = desc.planeSlice;
|
|
}
|
|
|
|
auto heap = std::make_unique<D3D12DescriptorHeap>();
|
|
if (!heap->Initialize(m_device.Get(), DescriptorHeapType::RTV, 1, false)) {
|
|
delete view;
|
|
return nullptr;
|
|
}
|
|
|
|
view->InitializeAsRenderTarget(m_device.Get(), resource, &rtvDesc, heap.get(), 0);
|
|
view->SetOwnedHeap(std::move(heap));
|
|
|
|
return view;
|
|
}
|
|
|
|
RHIResourceView* D3D12Device::CreateDepthStencilView(RHITexture* texture, const ResourceViewDesc& desc) {
|
|
auto* view = new D3D12ResourceView();
|
|
auto* d3d12Texture = static_cast<D3D12Texture*>(texture);
|
|
ID3D12Resource* resource = d3d12Texture->GetResource();
|
|
|
|
D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
|
|
const Format format = desc.format != 0 ? static_cast<Format>(desc.format) : texture->GetFormat();
|
|
dsvDesc.Format = ResolveD3D12DepthStencilViewFormat(format);
|
|
dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
|
|
|
|
auto heap = std::make_unique<D3D12DescriptorHeap>();
|
|
if (!heap->Initialize(m_device.Get(), DescriptorHeapType::DSV, 1, false)) {
|
|
delete view;
|
|
return nullptr;
|
|
}
|
|
|
|
view->InitializeAsDepthStencil(m_device.Get(), resource, &dsvDesc, heap.get(), 0);
|
|
view->SetOwnedHeap(std::move(heap));
|
|
return view;
|
|
}
|
|
|
|
RHIResourceView* D3D12Device::CreateShaderResourceView(RHIBuffer* buffer, const ResourceViewDesc& desc) {
|
|
if (buffer == nullptr || m_device == nullptr || !IsSupportedBufferViewDimension(desc.dimension)) {
|
|
return nullptr;
|
|
}
|
|
if (desc.dimension == ResourceViewDimension::Buffer && desc.format == 0) {
|
|
return nullptr;
|
|
}
|
|
|
|
uint32_t firstElement = 0;
|
|
uint32_t elementStride = 0;
|
|
if (!TryResolveBufferViewFirstElement(buffer, desc, firstElement, elementStride)) {
|
|
return nullptr;
|
|
}
|
|
|
|
uint32_t elementCount = 0;
|
|
if (!TryResolveBufferViewElementCount(buffer, desc, elementStride, firstElement, elementCount)) {
|
|
return nullptr;
|
|
}
|
|
|
|
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
|
srvDesc.Format = ResolveD3D12BufferViewFormat(desc);
|
|
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
|
|
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
|
srvDesc.Buffer.FirstElement = firstElement;
|
|
srvDesc.Buffer.NumElements = elementCount;
|
|
srvDesc.Buffer.StructureByteStride =
|
|
desc.dimension == ResourceViewDimension::StructuredBuffer ? elementStride : 0u;
|
|
srvDesc.Buffer.Flags =
|
|
desc.dimension == ResourceViewDimension::RawBuffer
|
|
? D3D12_BUFFER_SRV_FLAG_RAW
|
|
: D3D12_BUFFER_SRV_FLAG_NONE;
|
|
|
|
auto heap = std::make_unique<D3D12DescriptorHeap>();
|
|
if (!heap->Initialize(m_device.Get(), DescriptorHeapType::CBV_SRV_UAV, 1, false)) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto* view = new D3D12ResourceView();
|
|
view->InitializeAsShaderResourceBuffer(
|
|
m_device.Get(),
|
|
static_cast<D3D12Buffer*>(buffer),
|
|
desc,
|
|
&srvDesc,
|
|
heap.get(),
|
|
0);
|
|
if (!view->IsValid()) {
|
|
delete view;
|
|
return nullptr;
|
|
}
|
|
|
|
view->SetOwnedHeap(std::move(heap));
|
|
return view;
|
|
}
|
|
|
|
RHIResourceView* D3D12Device::CreateShaderResourceView(RHITexture* texture, const ResourceViewDesc& desc) {
|
|
auto* view = new D3D12ResourceView();
|
|
auto* d3d12Texture = static_cast<D3D12Texture*>(texture);
|
|
ID3D12Resource* resource = d3d12Texture->GetResource();
|
|
|
|
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
|
const Format format = desc.format != 0 ? static_cast<Format>(desc.format) : texture->GetFormat();
|
|
const TextureType textureType = texture->GetTextureType();
|
|
srvDesc.Format = ResolveD3D12ShaderResourceViewFormat(format);
|
|
srvDesc.ViewDimension = ResolveSRVDimension(desc, textureType);
|
|
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
|
switch (srvDesc.ViewDimension) {
|
|
case D3D12_SRV_DIMENSION_TEXTURE1D:
|
|
srvDesc.Texture1D.MostDetailedMip = desc.mipLevel;
|
|
srvDesc.Texture1D.MipLevels = 1;
|
|
break;
|
|
case D3D12_SRV_DIMENSION_TEXTURE1DARRAY:
|
|
srvDesc.Texture1DArray.MostDetailedMip = desc.mipLevel;
|
|
srvDesc.Texture1DArray.MipLevels = 1;
|
|
srvDesc.Texture1DArray.FirstArraySlice = desc.firstArraySlice;
|
|
srvDesc.Texture1DArray.ArraySize = desc.arraySize > 0 ? desc.arraySize : 1;
|
|
break;
|
|
case D3D12_SRV_DIMENSION_TEXTURE2DARRAY:
|
|
srvDesc.Texture2DArray.MostDetailedMip = desc.mipLevel;
|
|
srvDesc.Texture2DArray.MipLevels = 1;
|
|
srvDesc.Texture2DArray.FirstArraySlice = desc.firstArraySlice;
|
|
srvDesc.Texture2DArray.ArraySize = desc.arraySize > 0 ? desc.arraySize : 1;
|
|
srvDesc.Texture2DArray.PlaneSlice = desc.planeSlice;
|
|
break;
|
|
case D3D12_SRV_DIMENSION_TEXTURE3D:
|
|
srvDesc.Texture3D.MostDetailedMip = desc.mipLevel;
|
|
srvDesc.Texture3D.MipLevels = 1;
|
|
break;
|
|
case D3D12_SRV_DIMENSION_TEXTURECUBE:
|
|
srvDesc.TextureCube.MostDetailedMip = desc.mipLevel;
|
|
srvDesc.TextureCube.MipLevels = 1;
|
|
break;
|
|
case D3D12_SRV_DIMENSION_TEXTURECUBEARRAY:
|
|
srvDesc.TextureCubeArray.MostDetailedMip = desc.mipLevel;
|
|
srvDesc.TextureCubeArray.MipLevels = 1;
|
|
srvDesc.TextureCubeArray.First2DArrayFace = desc.firstArraySlice;
|
|
srvDesc.TextureCubeArray.NumCubes = desc.arraySize > 0 ? std::max<uint32_t>(desc.arraySize / 6u, 1u) : 1u;
|
|
break;
|
|
case D3D12_SRV_DIMENSION_TEXTURE2DMS:
|
|
case D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY:
|
|
break;
|
|
case D3D12_SRV_DIMENSION_TEXTURE2D:
|
|
default:
|
|
srvDesc.Texture2D.MostDetailedMip = desc.mipLevel;
|
|
srvDesc.Texture2D.MipLevels = 1;
|
|
srvDesc.Texture2D.PlaneSlice = desc.planeSlice;
|
|
break;
|
|
}
|
|
|
|
auto heap = std::make_unique<D3D12DescriptorHeap>();
|
|
if (!heap->Initialize(m_device.Get(), DescriptorHeapType::CBV_SRV_UAV, 1, false)) {
|
|
delete view;
|
|
return nullptr;
|
|
}
|
|
|
|
view->InitializeAsShaderResource(m_device.Get(), resource, &srvDesc, heap.get(), 0);
|
|
if (IsDepthFormat(format)) {
|
|
view->SetFormat(format);
|
|
}
|
|
view->SetOwnedHeap(std::move(heap));
|
|
|
|
return view;
|
|
}
|
|
|
|
RHIResourceView* D3D12Device::CreateUnorderedAccessView(RHIBuffer* buffer, const ResourceViewDesc& desc) {
|
|
if (buffer == nullptr || m_device == nullptr || !IsSupportedBufferViewDimension(desc.dimension)) {
|
|
return nullptr;
|
|
}
|
|
if (desc.dimension == ResourceViewDimension::Buffer && desc.format == 0) {
|
|
return nullptr;
|
|
}
|
|
|
|
uint32_t firstElement = 0;
|
|
uint32_t elementStride = 0;
|
|
if (!TryResolveBufferViewFirstElement(buffer, desc, firstElement, elementStride)) {
|
|
return nullptr;
|
|
}
|
|
|
|
uint32_t elementCount = 0;
|
|
if (!TryResolveBufferViewElementCount(buffer, desc, elementStride, firstElement, elementCount)) {
|
|
return nullptr;
|
|
}
|
|
|
|
D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
|
|
uavDesc.Format = ResolveD3D12BufferViewFormat(desc);
|
|
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
|
|
uavDesc.Buffer.FirstElement = firstElement;
|
|
uavDesc.Buffer.NumElements = elementCount;
|
|
uavDesc.Buffer.StructureByteStride =
|
|
desc.dimension == ResourceViewDimension::StructuredBuffer ? elementStride : 0u;
|
|
uavDesc.Buffer.Flags =
|
|
desc.dimension == ResourceViewDimension::RawBuffer
|
|
? D3D12_BUFFER_UAV_FLAG_RAW
|
|
: D3D12_BUFFER_UAV_FLAG_NONE;
|
|
|
|
auto heap = std::make_unique<D3D12DescriptorHeap>();
|
|
if (!heap->Initialize(m_device.Get(), DescriptorHeapType::CBV_SRV_UAV, 1, false)) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto* view = new D3D12ResourceView();
|
|
view->InitializeAsUnorderedAccessBuffer(
|
|
m_device.Get(),
|
|
static_cast<D3D12Buffer*>(buffer),
|
|
desc,
|
|
&uavDesc,
|
|
heap.get(),
|
|
0);
|
|
if (!view->IsValid()) {
|
|
delete view;
|
|
return nullptr;
|
|
}
|
|
|
|
view->SetOwnedHeap(std::move(heap));
|
|
return view;
|
|
}
|
|
|
|
RHIResourceView* D3D12Device::CreateUnorderedAccessView(RHITexture* texture, const ResourceViewDesc& desc) {
|
|
auto* view = new D3D12ResourceView();
|
|
auto* d3d12Texture = static_cast<D3D12Texture*>(texture);
|
|
ID3D12Resource* resource = d3d12Texture->GetResource();
|
|
|
|
D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
|
|
uavDesc.Format = static_cast<DXGI_FORMAT>(desc.format);
|
|
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
|
|
|
|
auto heap = std::make_unique<D3D12DescriptorHeap>();
|
|
if (!heap->Initialize(m_device.Get(), DescriptorHeapType::CBV_SRV_UAV, 1, false)) {
|
|
delete view;
|
|
return nullptr;
|
|
}
|
|
|
|
view->InitializeAsUnorderedAccess(m_device.Get(), resource, &uavDesc, heap.get(), 0);
|
|
view->SetOwnedHeap(std::move(heap));
|
|
return view;
|
|
}
|
|
|
|
D3D12DescriptorHeap* D3D12Device::CreateDescriptorHeap(const DescriptorHeapDesc& desc) {
|
|
auto* heap = new D3D12DescriptorHeap();
|
|
if (!heap->Initialize(m_device.Get(),
|
|
static_cast<DescriptorHeapType>(desc.heapType),
|
|
desc.descriptorCount,
|
|
desc.shaderVisible)) {
|
|
delete heap;
|
|
return nullptr;
|
|
}
|
|
return heap;
|
|
}
|
|
|
|
D3D12QueryHeap* D3D12Device::CreateQueryHeap(const QueryHeapDesc& desc) {
|
|
auto* queryHeap = new D3D12QueryHeap();
|
|
if (!queryHeap->Initialize(m_device.Get(), static_cast<QueryType>(desc.queryType), desc.count)) {
|
|
delete queryHeap;
|
|
return nullptr;
|
|
}
|
|
return queryHeap;
|
|
}
|
|
|
|
D3D12RootSignature* D3D12Device::CreateRootSignature(const RootSignatureDesc& desc) {
|
|
auto* rootSig = new D3D12RootSignature();
|
|
|
|
D3D12_ROOT_SIGNATURE_DESC rootSigDesc = {};
|
|
rootSigDesc.NumParameters = 0;
|
|
rootSigDesc.NumStaticSamplers = 0;
|
|
rootSigDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
|
|
|
|
if (!rootSig->Initialize(m_device.Get(), rootSigDesc)) {
|
|
delete rootSig;
|
|
return nullptr;
|
|
}
|
|
|
|
return rootSig;
|
|
}
|
|
|
|
D3D12CommandQueue* D3D12Device::CreateCommandQueueImpl(const CommandQueueDesc& desc) {
|
|
return nullptr;
|
|
}
|
|
|
|
D3D12CommandList* D3D12Device::CreateCommandListImpl(const CommandListDesc& desc) {
|
|
return nullptr;
|
|
}
|
|
|
|
} // namespace RHI
|
|
} // namespace XCEngine
|