#include "D3D12RHI.h" #include #include #include #include #include void EngineLog(const char* msg, ...) { char buffer[1024]; va_list args; va_start(args, msg); vsnprintf(buffer, sizeof(buffer), msg, args); va_end(args); FILE* f = nullptr; fopen_s(&f, "D:\\xcengine_debug.log", "a"); if (f) { fprintf(f, "%s\n", buffer); fclose(f); } printf("%s\n", buffer); OutputDebugStringA(buffer); OutputDebugStringA("\n"); } namespace XCEngine { namespace RHI { D3D12Device::D3D12Device() { } D3D12Device::~D3D12Device() { Shutdown(); } bool D3D12Device::CreateDXGIDevice(void* windowHandle) { UINT dxgiFactoryFlags = 0; #ifdef _DEBUG ID3D12Debug* debugController = nullptr; if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) { debugController->EnableDebugLayer(); dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG; } #endif HRESULT hr = CreateDXGIFactory2(dxgiFactoryFlags, IID_PPV_ARGS(&m_dxgiFactory)); if (FAILED(hr)) { return false; } Microsoft::WRL::ComPtr adapter; int adapterIndex = 0; bool adapterFound = false; while (m_dxgiFactory->EnumAdapters1(adapterIndex, &adapter) != DXGI_ERROR_NOT_FOUND) { DXGI_ADAPTER_DESC1 desc; adapter->GetDesc1(&desc); if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) { adapterIndex++; continue; } hr = D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), nullptr); if (SUCCEEDED(hr)) { adapterFound = true; break; } adapterIndex++; } if (!adapterFound) { return false; } m_adapter = adapter; hr = D3D12CreateDevice(m_adapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device)); if (FAILED(hr)) { return false; } return true; } bool D3D12Device::Initialize(void* windowHandle, uint32_t width, uint32_t height) { if (!CreateDXGIDevice(windowHandle)) { return false; } D3D12_COMMAND_QUEUE_DESC queueDesc = {}; queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; queueDesc.Priority = 0; queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; Microsoft::WRL::ComPtr commandQueue; HRESULT hr = m_device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&commandQueue)); if (FAILED(hr)) { return false; } m_commandQueue = new D3D12CommandQueue(this, commandQueue.Get()); SwapChainDesc swapChainDesc = {}; swapChainDesc.width = width; swapChainDesc.height = height; swapChainDesc.format = Format::R8G8B8A8_UNorm; swapChainDesc.bufferCount = 2; swapChainDesc.vsync = false; swapChainDesc.fullscreen = false; ISwapChain* swapChain = nullptr; if (!CreateSwapChain(&swapChain, swapChainDesc, windowHandle)) { return false; } m_swapChain = static_cast(swapChain); return true; } void D3D12Device::Shutdown() { if (m_commandQueue) { delete m_commandQueue; m_commandQueue = nullptr; } if (m_swapChain) { delete m_swapChain; m_swapChain = nullptr; } } bool D3D12Device::CreateCommandQueue(ICommandQueue** queue, const CommandQueueDesc& desc) { D3D12_COMMAND_QUEUE_DESC queueDesc = {}; queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; queueDesc.Priority = desc.priority; queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; Microsoft::WRL::ComPtr commandQueue; HRESULT hr = m_device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&commandQueue)); if (FAILED(hr)) { return false; } *queue = new D3D12CommandQueue(this, commandQueue.Get()); return true; } bool D3D12Device::CreateCommandAllocator(ICommandAllocator** allocator) { Microsoft::WRL::ComPtr commandAllocator; HRESULT hr = m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&commandAllocator)); if (FAILED(hr)) { return false; } *allocator = new D3D12CommandAllocator(this, commandAllocator.Get()); return true; } bool D3D12Device::CreateCommandList(ICommandList** list, ICommandAllocator* allocator) { D3D12CommandAllocator* d3d12Allocator = static_cast(allocator); Microsoft::WRL::ComPtr commandList; HRESULT hr = m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, d3d12Allocator->GetNativeAllocator(), nullptr, IID_PPV_ARGS(&commandList)); if (FAILED(hr)) { return false; } *list = new D3D12CommandList(this, commandList.Get()); return true; } bool D3D12Device::CreateFence(IFence** fence) { Microsoft::WRL::ComPtr d3dFence; HRESULT hr = m_device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&d3dFence)); if (FAILED(hr)) { return false; } *fence = new D3D12Fence(this, d3dFence.Get()); return true; } bool D3D12Device::CreateDescriptorHeap(IDescriptorHeap** heap, const DescriptorHeapDesc& desc) { D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {}; heapDesc.NumDescriptors = desc.count; heapDesc.Flags = desc.shaderVisible ? D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE : D3D12_DESCRIPTOR_HEAP_FLAG_NONE; switch (desc.type) { case DescriptorHeapType::CBV_SRV_UAV: heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; break; case DescriptorHeapType::Sampler: heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; break; case DescriptorHeapType::RTV: heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; break; case DescriptorHeapType::DSV: heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV; break; } Microsoft::WRL::ComPtr descriptorHeap; HRESULT hr = m_device->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&descriptorHeap)); if (FAILED(hr)) { return false; } *heap = new D3D12DescriptorHeap(this, descriptorHeap.Get(), desc.type); return true; } bool D3D12Device::CreateRootSignature(IRootSignature** signature, const RootSignatureDesc& desc) { *signature = new D3D12RootSignature(this); return (*signature)->Initialize(desc); } bool D3D12Device::CreatePipelineState(IPipelineState** pso, const PipelineDesc& desc) { *pso = new D3D12PipelineState(this); return static_cast(*pso)->Initialize(desc); } bool D3D12Device::CreateSwapChain(ISwapChain** swapChain, const SwapChainDesc& desc, void* windowHandle) { *swapChain = new D3D12SwapChain(this); bool result = (*swapChain)->Initialize(desc, windowHandle); return result; } D3D12CommandQueue::D3D12CommandQueue(D3D12Device* device, ID3D12CommandQueue* queue) : m_device(device), m_commandQueue(queue) { } D3D12CommandQueue::~D3D12CommandQueue() { } void D3D12CommandQueue::ExecuteCommandLists(void** lists, uint32_t count) { ID3D12CommandList** d3dLists = reinterpret_cast(lists); m_commandQueue->ExecuteCommandLists(count, d3dLists); } void D3D12CommandQueue::Signal(void* fence, uint64_t value) { ID3D12Fence* d3dFence = static_cast(fence); m_commandQueue->Signal(d3dFence, value); } void D3D12CommandQueue::Wait(void* fence, uint64_t value) { ID3D12Fence* d3dFence = static_cast(fence); m_commandQueue->Wait(d3dFence, value); } uint64_t D3D12CommandQueue::GetTimestampFrequency() const { uint64_t frequency = 0; m_commandQueue->GetTimestampFrequency(&frequency); return frequency; } D3D12CommandAllocator::D3D12CommandAllocator(D3D12Device* device, ID3D12CommandAllocator* allocator) : m_device(device), m_commandAllocator(allocator) { } D3D12CommandAllocator::~D3D12CommandAllocator() { } void D3D12CommandAllocator::Reset() { m_commandAllocator->Reset(); } D3D12Fence::D3D12Fence(D3D12Device* device, ID3D12Fence* fence) : m_device(device), m_fence(fence) { m_fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); } D3D12Fence::~D3D12Fence() { if (m_fenceEvent) { CloseHandle(m_fenceEvent); m_fenceEvent = nullptr; } } uint64_t D3D12Fence::GetCompletedValue() const { return m_fence->GetCompletedValue(); } void D3D12Fence::Signal(uint64_t value) { m_fence->Signal(value); } void D3D12Fence::Wait(uint64_t value) { if (m_fence->GetCompletedValue() < value) { m_fence->SetEventOnCompletion(value, m_fenceEvent); WaitForSingleObject(m_fenceEvent, INFINITE); } } void D3D12Fence::Wait(uint64_t value, uint64_t timeoutMs) { if (m_fence->GetCompletedValue() < value) { m_fence->SetEventOnCompletion(value, m_fenceEvent); WaitForSingleObject(m_fenceEvent, (DWORD)timeoutMs); } } D3D12DescriptorHeap::D3D12DescriptorHeap(D3D12Device* device, ID3D12DescriptorHeap* heap, DescriptorHeapType type) : m_device(device), m_descriptorHeap(heap), m_type(type) { m_descriptorCount = heap->GetDesc().NumDescriptors; m_descriptorSize = device->GetD3D12Device()->GetDescriptorHandleIncrementSize( type == DescriptorHeapType::CBV_SRV_UAV ? D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV : type == DescriptorHeapType::Sampler ? D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER : type == DescriptorHeapType::RTV ? D3D12_DESCRIPTOR_HEAP_TYPE_RTV : D3D12_DESCRIPTOR_HEAP_TYPE_DSV); } D3D12DescriptorHeap::~D3D12DescriptorHeap() { } void* D3D12DescriptorHeap::GetCPUDescriptorHandle(uint32_t index) const { D3D12_CPU_DESCRIPTOR_HANDLE handle = m_descriptorHeap->GetCPUDescriptorHandleForHeapStart(); handle.ptr += index * m_descriptorSize; return (void*)handle.ptr; } uint64_t D3D12DescriptorHeap::GetGPUDescriptorHandle(uint32_t index) const { D3D12_GPU_DESCRIPTOR_HANDLE handle = m_descriptorHeap->GetGPUDescriptorHandleForHeapStart(); handle.ptr += index * m_descriptorSize; return handle.ptr; } void D3D12DescriptorHeap::SetName(const char* name) { if (name) { m_descriptorHeap->SetName(std::wstring(name, name + strlen(name)).c_str()); } } D3D12SwapChain::D3D12SwapChain(D3D12Device* device) : m_device(device) { } D3D12SwapChain::~D3D12SwapChain() { Shutdown(); } bool D3D12SwapChain::Initialize(const SwapChainDesc& desc, void* windowHandle) { m_bufferCount = desc.bufferCount; m_vsync = desc.vsync; m_fullscreen = desc.fullscreen; DXGI_SWAP_CHAIN_DESC swapChainDesc = {}; swapChainDesc.BufferCount = desc.bufferCount; swapChainDesc.BufferDesc.Width = desc.width; swapChainDesc.BufferDesc.Height = desc.height; swapChainDesc.BufferDesc.Format = FormatToDXGIFormat(desc.format); swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.OutputWindow = (HWND)windowHandle; swapChainDesc.SampleDesc.Count = 1; swapChainDesc.Windowed = !desc.fullscreen; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; Microsoft::WRL::ComPtr swapChain; ID3D12CommandQueue* cmdQueue = (ID3D12CommandQueue*)m_device->GetCommandQueue()->GetNativeQueue(); HRESULT hr = m_device->GetDXGIFactory()->CreateSwapChain( cmdQueue, &swapChainDesc, &swapChain); if (FAILED(hr)) { return false; } hr = swapChain.As(&m_swapChain); DescriptorHeapDesc rtvDesc = {}; rtvDesc.type = DescriptorHeapType::RTV; rtvDesc.count = desc.bufferCount; rtvDesc.shaderVisible = false; if (!m_device->CreateDescriptorHeap((IDescriptorHeap**)&m_rtvHeap, rtvDesc)) { return false; } D3D12_CPU_DESCRIPTOR_HANDLE rtvHeapStart; rtvHeapStart.ptr = (UINT64)m_rtvHeap->GetCPUDescriptorHandle(0); UINT rtvDescriptorSize = m_device->GetD3D12Device()->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); for (uint32_t i = 0; i < desc.bufferCount; i++) { hr = m_swapChain->GetBuffer(i, IID_PPV_ARGS(&m_buffers[i])); if (FAILED(hr)) { return false; } D3D12_CPU_DESCRIPTOR_HANDLE rtvPointer; rtvPointer.ptr = rtvHeapStart.ptr + i * rtvDescriptorSize; m_device->GetD3D12Device()->CreateRenderTargetView(m_buffers[i].Get(), nullptr, rtvPointer); } return true; } void D3D12SwapChain::Shutdown() { m_buffers[0].Reset(); if (m_rtvHeap) { delete m_rtvHeap; m_rtvHeap = nullptr; } m_swapChain.Reset(); } bool D3D12SwapChain::Present() { HRESULT hr = m_swapChain->Present(m_vsync ? 1 : 0, 0); return SUCCEEDED(hr); } bool D3D12SwapChain::Resize(uint32_t width, uint32_t height) { for (uint32_t i = 0; i < m_bufferCount; i++) { m_buffers[i].Reset(); } HRESULT hr = m_swapChain->ResizeBuffers(m_bufferCount, width, height, DXGI_FORMAT_UNKNOWN, 0); if (FAILED(hr)) { return false; } D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = *(D3D12_CPU_DESCRIPTOR_HANDLE*)m_rtvHeap->GetCPUDescriptorHandle(0); for (uint32_t i = 0; i < m_bufferCount; i++) { hr = m_swapChain->GetBuffer(i, IID_PPV_ARGS(&m_buffers[i])); if (FAILED(hr)) { return false; } m_device->GetD3D12Device()->CreateRenderTargetView(m_buffers[i].Get(), nullptr, rtvHandle); rtvHandle.ptr += m_rtvHeap->GetDescriptorSize(); } return true; } uint32_t D3D12SwapChain::GetCurrentBufferIndex() const { return m_swapChain->GetCurrentBackBufferIndex(); } void* D3D12SwapChain::GetBuffer(uint32_t index) { return GetBufferResource(index); } void D3D12SwapChain::SetFullscreen(bool fullscreen) { m_fullscreen = fullscreen; m_swapChain->SetFullscreenState(fullscreen, nullptr); } bool D3D12SwapChain::IsFullscreen() const { return m_fullscreen; } D3D12RootSignature::D3D12RootSignature(D3D12Device* device) : m_device(device) { } D3D12RootSignature::~D3D12RootSignature() { } bool D3D12RootSignature::Initialize(const RootSignatureDesc& desc) { EngineLog("RootSignature: Start init, paramCount=%u", desc.parameterCount); D3D12_ROOT_PARAMETER rootParameters[16] = {}; D3D12_DESCRIPTOR_RANGE descriptorRanges[16] = {}; for (uint32_t i = 0; i < desc.parameterCount && i < 16; i++) { const RootParameter& param = desc.parameters[i]; switch (param.type) { case RootParameterType::CBV: rootParameters[i].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; rootParameters[i].ShaderVisibility = (D3D12_SHADER_VISIBILITY)param.visibility; rootParameters[i].Descriptor.RegisterSpace = param.registerSpace; rootParameters[i].Descriptor.ShaderRegister = param.shaderRegister; break; case RootParameterType::SRV: rootParameters[i].ParameterType = D3D12_ROOT_PARAMETER_TYPE_SRV; rootParameters[i].ShaderVisibility = (D3D12_SHADER_VISIBILITY)param.visibility; rootParameters[i].Descriptor.RegisterSpace = param.registerSpace; rootParameters[i].Descriptor.ShaderRegister = param.shaderRegister; break; case RootParameterType::Constants: rootParameters[i].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; rootParameters[i].ShaderVisibility = (D3D12_SHADER_VISIBILITY)param.visibility; rootParameters[i].Constants.RegisterSpace = param.registerSpace; rootParameters[i].Constants.ShaderRegister = param.shaderRegister; rootParameters[i].Constants.Num32BitValues = param.num32BitValues; break; case RootParameterType::DescriptorTable: rootParameters[i].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; rootParameters[i].ShaderVisibility = (D3D12_SHADER_VISIBILITY)param.visibility; rootParameters[i].DescriptorTable.pDescriptorRanges = &descriptorRanges[i]; rootParameters[i].DescriptorTable.NumDescriptorRanges = 1; descriptorRanges[i].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; descriptorRanges[i].RegisterSpace = param.registerSpace; descriptorRanges[i].BaseShaderRegister = 0; descriptorRanges[i].NumDescriptors = 1; descriptorRanges[i].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; break; default: rootParameters[i].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; break; } EngineLog("RootParam[%d]: type=%d, visibility=%d, reg=%d, space=%d", i, (int)param.type, (int)param.visibility, param.shaderRegister, param.registerSpace); } D3D12_STATIC_SAMPLER_DESC samplerDesc = {}; samplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR; samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; samplerDesc.MaxLOD = D3D12_FLOAT32_MAX; samplerDesc.RegisterSpace = 0; samplerDesc.ShaderRegister = 0; samplerDesc.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc = {}; rootSignatureDesc.NumParameters = desc.parameterCount; rootSignatureDesc.pParameters = rootParameters; rootSignatureDesc.NumStaticSamplers = 1; rootSignatureDesc.pStaticSamplers = &samplerDesc; rootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; Microsoft::WRL::ComPtr signature; Microsoft::WRL::ComPtr errorBlob; HRESULT hr = D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &errorBlob); if (FAILED(hr)) { if (errorBlob) { OutputDebugStringA((const char*)errorBlob->GetBufferPointer()); } EngineLog("RootSignature: Serialize FAILED"); return false; } EngineLog("RootSignature: Serialize SUCCESS, size=%llu", (unsigned long long)signature->GetBufferSize()); hr = m_device->GetD3D12Device()->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature)); if (SUCCEEDED(hr)) { EngineLog("RootSignature: SUCCESS"); } else { EngineLog("RootSignature: FAILED"); } return SUCCEEDED(hr); } void D3D12RootSignature::SetName(const char* name) { if (name && m_rootSignature) { m_rootSignature->SetName(std::wstring(name, name + strlen(name)).c_str()); } } void* D3D12RootSignature::GetNativeRootSignature() const { return m_rootSignature.Get(); } D3D12PipelineState::D3D12PipelineState(D3D12Device* device) : m_device(device) { } D3D12PipelineState::~D3D12PipelineState() { } bool D3D12PipelineState::Initialize(const PipelineDesc& desc) { EngineLog("PipelineState: Start init"); D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; if (desc.rootSignature) { EngineLog("PipelineState: has rootSignature"); D3D12RootSignature* rs = static_cast(desc.rootSignature); psoDesc.pRootSignature = rs->GetNative(); EngineLog("PipelineState: rootSignature ptr=%p", psoDesc.pRootSignature); } else { EngineLog("PipelineState: NO rootSignature!"); } if (desc.vertexShader.size > 0 && desc.vertexShader.bytecode != nullptr) { psoDesc.VS.pShaderBytecode = desc.vertexShader.bytecode; psoDesc.VS.BytecodeLength = desc.vertexShader.size; } if (desc.pixelShader.size > 0 && desc.pixelShader.bytecode != nullptr) { psoDesc.PS.pShaderBytecode = desc.pixelShader.bytecode; psoDesc.PS.BytecodeLength = desc.pixelShader.size; } if (desc.geometryShader.size > 0 && desc.geometryShader.bytecode != nullptr) { psoDesc.GS.pShaderBytecode = desc.geometryShader.bytecode; psoDesc.GS.BytecodeLength = desc.geometryShader.size; } D3D12_INPUT_ELEMENT_DESC d3d12Elements[16] = {}; for (uint32_t i = 0; i < desc.inputLayout.elementCount && i < 16; i++) { const InputElementDesc& src = desc.inputLayout.elements[i]; d3d12Elements[i].SemanticName = src.semanticName; d3d12Elements[i].SemanticIndex = src.semanticIndex; d3d12Elements[i].Format = FormatToDXGIFormat(src.format); d3d12Elements[i].InputSlot = src.inputSlot; d3d12Elements[i].AlignedByteOffset = src.alignedByteOffset; d3d12Elements[i].InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA; d3d12Elements[i].InstanceDataStepRate = 0; } psoDesc.InputLayout.NumElements = desc.inputLayout.elementCount; psoDesc.InputLayout.pInputElementDescs = d3d12Elements; psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; psoDesc.NumRenderTargets = 1; psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; psoDesc.DSVFormat = DXGI_FORMAT_D24_UNORM_S8_UINT; psoDesc.SampleDesc.Count = 1; psoDesc.SampleDesc.Quality = 0; psoDesc.SampleMask = 0xffffffff; psoDesc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID; psoDesc.RasterizerState.CullMode = D3D12_CULL_MODE_BACK; psoDesc.RasterizerState.DepthClipEnable = TRUE; psoDesc.DepthStencilState.DepthEnable = TRUE; psoDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL; psoDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL; psoDesc.BlendState = { 0 }; D3D12_RENDER_TARGET_BLEND_DESC rtBlendDesc = { FALSE,FALSE, D3D12_BLEND_SRC_ALPHA,D3D12_BLEND_INV_SRC_ALPHA,D3D12_BLEND_OP_ADD, D3D12_BLEND_SRC_ALPHA,D3D12_BLEND_INV_SRC_ALPHA,D3D12_BLEND_OP_ADD, D3D12_LOGIC_OP_NOOP, D3D12_COLOR_WRITE_ENABLE_ALL, }; for (UINT i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) psoDesc.BlendState.RenderTarget[i] = rtBlendDesc; EngineLog("PSO: VS=%p(%u), PS=%p(%u), RTV=%d, DSV=%d", psoDesc.VS.pShaderBytecode, psoDesc.VS.BytecodeLength, psoDesc.PS.pShaderBytecode, psoDesc.PS.BytecodeLength, psoDesc.RTVFormats[0], psoDesc.DSVFormat); HRESULT hr = m_device->GetD3D12Device()->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineState)); if (FAILED(hr)) { EngineLog("PipelineState: FAILED with HRESULT=%08lx", (unsigned long)hr); return false; } EngineLog("PipelineState: SUCCESS"); return true; } void D3D12PipelineState::SetName(const char* name) { if (name && m_pipelineState) { m_pipelineState->SetName(std::wstring(name, name + strlen(name)).c_str()); } } void* D3D12PipelineState::GetNativePipelineState() const { return m_pipelineState.Get(); } D3D12CommandList::D3D12CommandList(D3D12Device* device, ID3D12GraphicsCommandList* list) : m_device(device), m_commandList(list) { } D3D12CommandList::~D3D12CommandList() { } void D3D12CommandList::Reset(void* allocator) { ID3D12CommandAllocator* d3dAllocator = static_cast(allocator); m_commandList->Reset(d3dAllocator, nullptr); } void D3D12CommandList::Close() { m_commandList->Close(); } void D3D12CommandList::SetPipelineState(IPipelineState* pso) { if (pso) { D3D12PipelineState* d3dPso = static_cast(pso); m_commandList->SetPipelineState(d3dPso->GetNative()); } } void D3D12CommandList::SetRootSignature(IRootSignature* signature) { if (signature) { D3D12RootSignature* d3dRs = static_cast(signature); m_commandList->SetGraphicsRootSignature(d3dRs->GetNative()); } } void D3D12CommandList::SetPrimitiveTopology(PrimitiveTopology topology) { D3D12_PRIMITIVE_TOPOLOGY d3dTopology; switch (topology) { case PrimitiveTopology::TriangleList: d3dTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; break; case PrimitiveTopology::TriangleStrip: d3dTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; break; case PrimitiveTopology::LineList: d3dTopology = D3D_PRIMITIVE_TOPOLOGY_LINELIST; break; default: d3dTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; break; } m_commandList->IASetPrimitiveTopology(d3dTopology); } void D3D12CommandList::SetVertexBuffer(uint32_t slot, IResource* buffer, uint32_t offset, uint32_t stride) { if (buffer) { D3D12Resource* d3dBuffer = static_cast(buffer); D3D12_VERTEX_BUFFER_VIEW vbView = {}; vbView.BufferLocation = d3dBuffer->GetNative()->GetGPUVirtualAddress() + offset; vbView.SizeInBytes = (UINT)stride; vbView.StrideInBytes = stride; m_commandList->IASetVertexBuffers(slot, 1, &vbView); } } void D3D12CommandList::SetIndexBuffer(IResource* buffer, uint32_t offset) { if (buffer) { D3D12Resource* d3dBuffer = static_cast(buffer); D3D12_INDEX_BUFFER_VIEW ibView = {}; ibView.BufferLocation = d3dBuffer->GetNative()->GetGPUVirtualAddress() + offset; ibView.Format = DXGI_FORMAT_R32_UINT; ibView.SizeInBytes = 0; m_commandList->IASetIndexBuffer(&ibView); } } void D3D12CommandList::SetDescriptorHeap(IDescriptorHeap* heap) { if (heap) { D3D12DescriptorHeap* d3dHeap = static_cast(heap); ID3D12DescriptorHeap* heaps[] = { d3dHeap->GetNativeHeap() }; m_commandList->SetDescriptorHeaps(1, heaps); } } void D3D12CommandList::SetGraphicsDescriptorTable(uint32_t rootParameterIndex, uint64_t baseDescriptor) { m_commandList->SetGraphicsRootDescriptorTable(rootParameterIndex, D3D12_GPU_DESCRIPTOR_HANDLE{ baseDescriptor }); } void D3D12CommandList::SetComputeDescriptorTable(uint32_t rootParameterIndex, uint64_t baseDescriptor) { m_commandList->SetComputeRootDescriptorTable(rootParameterIndex, D3D12_GPU_DESCRIPTOR_HANDLE{ baseDescriptor }); } void D3D12CommandList::DrawInstanced(uint32_t vertexCountPerInstance, uint32_t instanceCount, uint32_t startVertex, uint32_t startInstance) { m_commandList->DrawInstanced(vertexCountPerInstance, instanceCount, startVertex, startInstance); } void D3D12CommandList::DrawIndexedInstanced(uint32_t indexCountPerInstance, uint32_t instanceCount, uint32_t startIndex, int32_t baseVertex, uint32_t startInstance) { m_commandList->DrawIndexedInstanced(indexCountPerInstance, instanceCount, startIndex, baseVertex, startInstance); } void D3D12CommandList::Dispatch(uint32_t x, uint32_t y, uint32_t z) { m_commandList->Dispatch(x, y, z); } void D3D12CommandList::SetViewports(const Viewport* viewports, uint32_t count) { D3D12_VIEWPORT d3dViewports[16] = {}; for (uint32_t i = 0; i < count && i < 16; i++) { d3dViewports[i].TopLeftX = viewports[i].topLeftX; d3dViewports[i].TopLeftY = viewports[i].topLeftY; d3dViewports[i].Width = viewports[i].width; d3dViewports[i].Height = viewports[i].height; d3dViewports[i].MinDepth = viewports[i].minDepth; d3dViewports[i].MaxDepth = viewports[i].maxDepth; } m_commandList->RSSetViewports(count, d3dViewports); } void D3D12CommandList::SetScissorRects(const Rect* rects, uint32_t count) { D3D12_RECT d3dRects[16] = {}; for (uint32_t i = 0; i < count && i < 16; i++) { d3dRects[i].left = rects[i].left; d3dRects[i].top = rects[i].top; d3dRects[i].right = rects[i].right; d3dRects[i].bottom = rects[i].bottom; } m_commandList->RSSetScissorRects(count, d3dRects); } void D3D12CommandList::SetRenderTargets(void** targets, uint32_t count, void* depthStencil) { D3D12_CPU_DESCRIPTOR_HANDLE rtvHandles[8] = {}; for (uint32_t i = 0; i < count && i < 8; i++) { rtvHandles[i].ptr = (UINT64)targets[i]; } D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = {}; if (depthStencil) { dsvHandle.ptr = (UINT64)depthStencil; } m_commandList->OMSetRenderTargets(count, rtvHandles, FALSE, depthStencil ? &dsvHandle : nullptr); } void D3D12CommandList::ClearRenderTargetView(void* target, const float color[4]) { D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = { (UINT64)target }; m_commandList->ClearRenderTargetView(rtvHandle, color, 0, nullptr); } void D3D12CommandList::ClearDepthStencilView(void* depth, float depthValue, uint8_t stencil) { D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = { (UINT64)depth }; m_commandList->ClearDepthStencilView(dsvHandle, D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, depthValue, stencil, 0, nullptr); } void D3D12CommandList::CopyResource(IResource* dst, const IResource* src) { D3D12Resource* d3dDst = static_cast(dst); D3D12Resource* d3dSrc = static_cast(const_cast(src)); m_commandList->CopyResource(d3dDst->GetNative(), d3dSrc->GetNative()); } void D3D12CommandList::CopyBuffer(IResource* dst, uint64_t dstOffset, const IResource* src, uint64_t srcOffset, uint64_t size) { D3D12Resource* d3dDst = static_cast(dst); D3D12Resource* d3dSrc = static_cast(const_cast(src)); m_commandList->CopyBufferRegion(d3dDst->GetNative(), dstOffset, d3dSrc->GetNative(), srcOffset, size); } void D3D12CommandList::ResourceBarrier(IResource* resource, ResourceStateFlag before, ResourceStateFlag after) { D3D12Resource* d3dResource = static_cast(resource); D3D12_RESOURCE_STATES beforeState = D3D12_RESOURCE_STATE_COMMON; D3D12_RESOURCE_STATES afterState = D3D12_RESOURCE_STATE_COMMON; if (static_cast(before) & static_cast(ResourceStateFlag::RenderTarget)) beforeState = D3D12_RESOURCE_STATE_RENDER_TARGET; else if (static_cast(before) & static_cast(ResourceStateFlag::DepthWrite)) beforeState = D3D12_RESOURCE_STATE_DEPTH_WRITE; else if (static_cast(before) & static_cast(ResourceStateFlag::DepthRead)) beforeState = D3D12_RESOURCE_STATE_DEPTH_READ; else if (static_cast(before) & static_cast(ResourceStateFlag::ShaderResource)) beforeState = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; else if (static_cast(before) & static_cast(ResourceStateFlag::CopyDest)) beforeState = D3D12_RESOURCE_STATE_COPY_DEST; else if (static_cast(before) & static_cast(ResourceStateFlag::CopySource)) beforeState = D3D12_RESOURCE_STATE_COPY_SOURCE; else if (static_cast(before) & static_cast(ResourceStateFlag::Present)) beforeState = D3D12_RESOURCE_STATE_PRESENT; if (static_cast(after) & static_cast(ResourceStateFlag::RenderTarget)) afterState = D3D12_RESOURCE_STATE_RENDER_TARGET; else if (static_cast(after) & static_cast(ResourceStateFlag::DepthWrite)) afterState = D3D12_RESOURCE_STATE_DEPTH_WRITE; else if (static_cast(after) & static_cast(ResourceStateFlag::DepthRead)) afterState = D3D12_RESOURCE_STATE_DEPTH_READ; else if (static_cast(after) & static_cast(ResourceStateFlag::ShaderResource)) afterState = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; else if (static_cast(after) & static_cast(ResourceStateFlag::CopyDest)) afterState = D3D12_RESOURCE_STATE_COPY_DEST; else if (static_cast(after) & static_cast(ResourceStateFlag::CopySource)) afterState = D3D12_RESOURCE_STATE_COPY_SOURCE; else if (static_cast(after) & static_cast(ResourceStateFlag::Present)) afterState = D3D12_RESOURCE_STATE_PRESENT; D3D12_RESOURCE_BARRIER barrier = {}; barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; barrier.Transition.pResource = d3dResource->GetNative(); barrier.Transition.StateBefore = beforeState; barrier.Transition.StateAfter = afterState; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; m_commandList->ResourceBarrier(1, &barrier); } void* D3D12CommandList::GetNativeCommandList() const { return m_commandList.Get(); } D3D12Resource::D3D12Resource(D3D12Device* device, ID3D12Resource* resource) : m_device(device), m_resource(resource) { } D3D12Resource::~D3D12Resource() { m_resource.Reset(); } } // namespace RHI } // namespace XCEngine