#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 #include #include #include #ifdef _DEBUG #include #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(ch)); } return result; } bool HasShaderPayload(const ShaderCompileDesc& desc) { return !desc.source.empty() || !desc.fileName.empty(); } bool CompileD3D12Shader(const ShaderCompileDesc& desc, D3D12Shader& shader) { 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()) { return shader.Compile(desc.source.data(), desc.source.size(), entryPointPtr, profilePtr); } if (!desc.fileName.empty()) { return shader.CompileFromFile(desc.fileName.c_str(), entryPointPtr, profilePtr); } 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(rawType); } uint16_t ResolveDepthOrArraySize(const TextureDesc& desc, TextureType textureType) { switch (textureType) { case TextureType::Texture3D: return static_cast(std::max(desc.depth, 1)); case TextureType::Texture2DArray: return static_cast(std::max(desc.arraySize, 1)); case TextureType::TextureCube: case TextureType::TextureCubeArray: return static_cast(std::max(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; } } 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); } } } // 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 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 D3D12Device::EnumerateAdapters() { std::vector adapters; if (!m_factory) { return adapters; } ComPtr 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& outRgba) { outRgba = {}; auto* d3d12Queue = static_cast(commandQueue); auto* d3d12Texture = static_cast(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(); D3D12_HEAP_TYPE heapType = D3D12_HEAP_TYPE_DEFAULT; if (desc.bufferType == static_cast(BufferType::ReadBack)) { heapType = D3D12_HEAP_TYPE_READBACK; } else if (desc.bufferType == static_cast(BufferType::Constant) || desc.bufferType == static_cast(BufferType::Vertex) || desc.bufferType == static_cast(BufferType::Index)) { heapType = D3D12_HEAP_TYPE_UPLOAD; } if (buffer->Initialize(m_device.Get(), desc.size, D3D12_RESOURCE_STATE_COMMON, heapType)) { buffer->SetStride(desc.stride); buffer->SetBufferType(static_cast(desc.bufferType)); return buffer; } delete buffer; return nullptr; } 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(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(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); } if (desc.textureType != static_cast(TextureType::Texture2D)) { return nullptr; } const Format format = static_cast(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(); ComPtr uploadBuffer; if (!texture->InitializeFromData( m_device.Get(), uploadCommandList.GetCommandList(), initialData, desc.width, desc.height, ToD3D12(format), resolvedRowPitch, &uploadBuffer)) { delete texture; uploadCommandList.Shutdown(); uploadAllocator.Shutdown(); uploadQueue.Shutdown(); return nullptr; } texture->SetState(ResourceStates::PixelShaderResource); 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(), 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(desc.filter)); d3d12Desc.AddressU = ToD3D12(static_cast(desc.addressU)); d3d12Desc.AddressV = ToD3D12(static_cast(desc.addressV)); d3d12Desc.AddressW = ToD3D12(static_cast(desc.addressW)); d3d12Desc.MipLODBias = desc.mipLodBias; d3d12Desc.MaxAnisotropy = desc.maxAnisotropy; d3d12Desc.ComparisonFunc = ToD3D12(static_cast(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(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(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(presentQueue->GetNativeHandle()); if (nativeQueue == nullptr) { return nullptr; } auto* swapChain = new D3D12SwapChain(); HWND hwnd = static_cast(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(); if (!allocator->Initialize(m_device.Get(), static_cast(desc.commandListType))) { return nullptr; } auto* cmdList = new D3D12CommandList(); if (!cmdList->Initialize(m_device.Get(), static_cast(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(desc.queueType))) { return queue; } delete queue; return nullptr; } RHIPipelineState* D3D12Device::CreatePipelineState(const GraphicsPipelineDesc& desc) { 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); 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(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 (rootSignature != nullptr) { rootSignature->Shutdown(); delete rootSignature; } delete pso; return nullptr; } pso->SetShaderBytecodes( vertexShader.GetD3D12Bytecode(), fragmentShader.GetD3D12Bytecode(), hasGeometryShader ? geometryShader.GetD3D12Bytecode() : D3D12_SHADER_BYTECODE{}); pso->EnsureValid(); if (rootSignature != nullptr) { rootSignature->Shutdown(); delete rootSignature; } if (!pso->IsValid()) { delete pso; return nullptr; } 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(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(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(); 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(texture); ID3D12Resource* resource = d3d12Texture->GetResource(); D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {}; const Format format = desc.format != 0 ? static_cast(desc.format) : texture->GetFormat(); dsvDesc.Format = ResolveD3D12DepthStencilViewFormat(format); dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; auto heap = std::make_unique(); 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(RHITexture* texture, const ResourceViewDesc& desc) { auto* view = new D3D12ResourceView(); auto* d3d12Texture = static_cast(texture); ID3D12Resource* resource = d3d12Texture->GetResource(); D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; const Format format = desc.format != 0 ? static_cast(desc.format) : texture->GetFormat(); srvDesc.Format = ResolveD3D12ShaderResourceViewFormat(format); srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; srvDesc.Texture2D.MostDetailedMip = desc.mipLevel; srvDesc.Texture2D.MipLevels = 1; srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; auto heap = std::make_unique(); 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); view->SetOwnedHeap(std::move(heap)); return view; } RHIResourceView* D3D12Device::CreateUnorderedAccessView(RHITexture* texture, const ResourceViewDesc& desc) { auto* view = new D3D12ResourceView(); auto* d3d12Texture = static_cast(texture); ID3D12Resource* resource = d3d12Texture->GetResource(); D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {}; uavDesc.Format = static_cast(desc.format); uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D; auto heap = std::make_unique(); 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(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(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