/* * Copyright 2011-2023 Branimir Karadzic. All rights reserved. * License: https://github.com/bkaradzic/bgfx/blob/master/LICENSE */ #ifndef BGFX_RENDERER_D3D12_H_HEADER_GUARD #define BGFX_RENDERER_D3D12_H_HEADER_GUARD #define USE_D3D12_DYNAMIC_LIB (BX_PLATFORM_WINDOWS || BX_PLATFORM_LINUX) #include #include #if BX_PLATFORM_LINUX || BX_PLATFORM_WINDOWS || BX_PLATFORM_WINRT # include #else # if !BGFX_CONFIG_DEBUG # define D3DCOMPILE_NO_DEBUG 1 # endif // !BGFX_CONFIG_DEBUG # include #endif // BX_PLATFORM_XBOXONE #if defined(__MINGW32__) // BK - temp workaround for MinGW until I nuke d3dx12 usage. extern "C++" { # if defined(__cpp_constexpr) && __cpp_constexpr >= 200704L \ && defined(__cpp_inline_variables) && __cpp_inline_variables >= 201606L __extension__ template constexpr const GUID& __mingw_uuidof(); # else __extension__ template const GUID& __mingw_uuidof(); # endif // __cpp_* template<> const GUID& __mingw_uuidof() { static const GUID IID_ID3D12Device0 = { 0x189819f1, 0x1db6, 0x4b57, { 0xbe, 0x54, 0x18, 0x21, 0x33, 0x9b, 0x85, 0xf7 } }; return IID_ID3D12Device0; } } #endif // defined(__MINGW32__) #include "renderer.h" #include "renderer_d3d.h" #include "shader_dxbc.h" #include "debug_renderdoc.h" #include "nvapi.h" #include "dxgi.h" #if BGFX_CONFIG_DEBUG_ANNOTATION && !BX_PLATFORM_LINUX # if BX_PLATFORM_WINDOWS || BX_PLATFORM_WINRT typedef struct PIXEventsThreadInfo* (WINAPI* PFN_PIX_GET_THREAD_INFO)(); typedef uint64_t (WINAPI* PFN_PIX_EVENTS_REPLACE_BLOCK)(bool _getEarliestTime); extern PFN_PIX_GET_THREAD_INFO bgfx_PIXGetThreadInfo; extern PFN_PIX_EVENTS_REPLACE_BLOCK bgfx_PIXEventsReplaceBlock; # define PIXGetThreadInfo bgfx_PIXGetThreadInfo # define PIXEventsReplaceBlock bgfx_PIXEventsReplaceBlock # else extern "C" struct PIXEventsThreadInfo* WINAPI bgfx_PIXGetThreadInfo(); extern "C" uint64_t WINAPI bgfx_PIXEventsReplaceBlock(bool _getEarliestTime); # endif // BX_PLATFORM_WINDOWS # include # define _PIX3_BEGINEVENT(_commandList, _color, _name) PIXBeginEvent(_commandList, _color, _name) # define _PIX3_SETMARKER(_commandList, _color, _name) PIXSetMarker(_commandList, _color, _name) # define _PIX3_ENDEVENT(_commandList) PIXEndEvent(_commandList) # define PIX3_BEGINEVENT(_commandList, _color, _name) _PIX3_BEGINEVENT(_commandList, _color, _name) # define PIX3_SETMARKER(_commandList, _color, _name) _PIX3_SETMARKER(_commandList, _color, _name) # define PIX3_ENDEVENT(_commandList) _PIX3_ENDEVENT(_commandList) #else # define PIX3_BEGINEVENT(_commandList, _color, _name) BX_UNUSED(_commandList, _color, _name) # define PIX3_SETMARKER(_commandList, _color, _name) BX_UNUSED(_commandList, _color, _name) # define PIX3_ENDEVENT(_commandList) BX_UNUSED(_commandList) #endif // BGFX_CONFIG_DEBUG_ANNOTATION #define BGFX_D3D12_PROFILER_BEGIN(_view, _abgr) \ BX_MACRO_BLOCK_BEGIN \ PIX3_BEGINEVENT(m_commandList, _abgr, s_viewName[_view]); \ BGFX_PROFILER_BEGIN(s_viewName[view], _abgr); \ BX_MACRO_BLOCK_END #define BGFX_D3D12_PROFILER_BEGIN_LITERAL(_name, _abgr) \ BX_MACRO_BLOCK_BEGIN \ PIX3_BEGINEVENT(m_commandList, _abgr, "" _name); \ BGFX_PROFILER_BEGIN_LITERAL("" _name, _abgr); \ BX_MACRO_BLOCK_END #define BGFX_D3D12_PROFILER_END() \ BX_MACRO_BLOCK_BEGIN \ BGFX_PROFILER_END(); \ PIX3_ENDEVENT(m_commandList); \ BX_MACRO_BLOCK_END namespace bgfx { namespace d3d12 { typedef HRESULT (WINAPI* PFN_D3D12_ENABLE_EXPERIMENTAL_FEATURES)(uint32_t _numFeatures, const IID* _iids, void* _configurationStructs, uint32_t* _configurationStructSizes); struct Rdt { enum Enum { Sampler, SRV, CBV, UAV, Count }; }; class ScratchBufferD3D12 { public: ScratchBufferD3D12() { } ~ScratchBufferD3D12() { } void create(uint32_t _size, uint32_t _maxDescriptors); void destroy(); void reset(D3D12_GPU_DESCRIPTOR_HANDLE& _gpuHandle); void allocEmpty(D3D12_GPU_DESCRIPTOR_HANDLE& _gpuHandle); void* allocCbv(D3D12_GPU_VIRTUAL_ADDRESS& _gpuAddress, uint32_t _size); void allocSrv(D3D12_GPU_DESCRIPTOR_HANDLE& _gpuHandle, struct TextureD3D12& _texture, uint8_t _mip = 0); void allocSrv(D3D12_GPU_DESCRIPTOR_HANDLE& _gpuHandle, struct BufferD3D12& _buffer); void allocUav(D3D12_GPU_DESCRIPTOR_HANDLE& _gpuHandle, struct TextureD3D12& _texture, uint8_t _mip = 0); void allocUav(D3D12_GPU_DESCRIPTOR_HANDLE& _gpuHandle, struct BufferD3D12& _buffer); ID3D12DescriptorHeap* getHeap() { return m_heap; } private: ID3D12DescriptorHeap* m_heap; ID3D12Resource* m_upload; D3D12_GPU_VIRTUAL_ADDRESS m_gpuVA; D3D12_CPU_DESCRIPTOR_HANDLE m_cpuHandle; D3D12_GPU_DESCRIPTOR_HANDLE m_gpuHandle; uint32_t m_incrementSize; uint8_t* m_data; uint32_t m_size; uint32_t m_pos; }; class DescriptorAllocatorD3D12 { public: DescriptorAllocatorD3D12() : m_numDescriptorsPerBlock(1) { } ~DescriptorAllocatorD3D12() { } void create(D3D12_DESCRIPTOR_HEAP_TYPE _type, uint16_t _maxDescriptors, uint16_t _numDescriptorsPerBlock = 1); void destroy(); uint16_t alloc(ID3D12Resource* _ptr, const D3D12_SHADER_RESOURCE_VIEW_DESC* _desc); uint16_t alloc(const uint32_t* _flags, uint32_t _num, const float _palette[][4]); void free(uint16_t _handle); void reset(); D3D12_GPU_DESCRIPTOR_HANDLE get(uint16_t _handle); ID3D12DescriptorHeap* getHeap() { return m_heap; } private: ID3D12DescriptorHeap* m_heap; bx::HandleAlloc* m_handleAlloc; D3D12_CPU_DESCRIPTOR_HANDLE m_cpuHandle; D3D12_GPU_DESCRIPTOR_HANDLE m_gpuHandle; uint32_t m_incrementSize; uint16_t m_numDescriptorsPerBlock; }; struct BufferD3D12 { BufferD3D12() : m_ptr(NULL) , m_state(D3D12_RESOURCE_STATE_COMMON) , m_size(0) , m_flags(BGFX_BUFFER_NONE) , m_dynamic(false) { } void create(uint32_t _size, void* _data, uint16_t _flags, bool _vertex, uint32_t _stride = 0); void update(ID3D12GraphicsCommandList* _commandList, uint32_t _offset, uint32_t _size, void* _data, bool _discard = false); void destroy(); D3D12_RESOURCE_STATES setState(ID3D12GraphicsCommandList* _commandList, D3D12_RESOURCE_STATES _state); D3D12_SHADER_RESOURCE_VIEW_DESC m_srvd; D3D12_UNORDERED_ACCESS_VIEW_DESC m_uavd; ID3D12Resource* m_ptr; D3D12_GPU_VIRTUAL_ADDRESS m_gpuVA; D3D12_RESOURCE_STATES m_state; uint32_t m_size; uint16_t m_flags; bool m_dynamic; }; struct VertexBufferD3D12 : public BufferD3D12 { void create(uint32_t _size, void* _data, VertexLayoutHandle _layoutHandle, uint16_t _flags); VertexLayoutHandle m_layoutHandle; }; struct ShaderD3D12 { ShaderD3D12() : m_code(NULL) , m_constantBuffer(NULL) , m_hash(0) , m_numUniforms(0) , m_numPredefined(0) { } void create(const Memory* _mem); void destroy() { if (NULL != m_constantBuffer) { UniformBuffer::destroy(m_constantBuffer); m_constantBuffer = NULL; } m_numPredefined = 0; if (NULL != m_code) { release(m_code); m_code = NULL; m_hash = 0; } } const Memory* m_code; UniformBuffer* m_constantBuffer; PredefinedUniform m_predefined[PredefinedUniform::Count]; uint16_t m_attrMask[Attrib::Count]; uint32_t m_hash; uint16_t m_numUniforms; uint16_t m_size; uint8_t m_numPredefined; }; struct ProgramD3D12 { ProgramD3D12() : m_vsh(NULL) , m_fsh(NULL) { } void create(const ShaderD3D12* _vsh, const ShaderD3D12* _fsh) { BX_ASSERT(NULL != _vsh->m_code, "Vertex shader doesn't exist."); m_vsh = _vsh; bx::memCopy(&m_predefined[0], _vsh->m_predefined, _vsh->m_numPredefined*sizeof(PredefinedUniform)); m_numPredefined = _vsh->m_numPredefined; if (NULL != _fsh) { BX_ASSERT(NULL != _fsh->m_code, "Fragment shader doesn't exist."); m_fsh = _fsh; bx::memCopy(&m_predefined[m_numPredefined], _fsh->m_predefined, _fsh->m_numPredefined*sizeof(PredefinedUniform)); m_numPredefined += _fsh->m_numPredefined; } } void destroy() { m_numPredefined = 0; m_vsh = NULL; m_fsh = NULL; } const ShaderD3D12* m_vsh; const ShaderD3D12* m_fsh; PredefinedUniform m_predefined[PredefinedUniform::Count * 2]; uint8_t m_numPredefined; }; struct TextureD3D12 { enum Enum { Texture2D, Texture3D, TextureCube, }; TextureD3D12() : m_ptr(NULL) , m_singleMsaa(NULL) , m_directAccessPtr(NULL) , m_state(D3D12_RESOURCE_STATE_COMMON) , m_numMips(0) { bx::memSet(&m_srvd, 0, sizeof(m_srvd) ); bx::memSet(&m_uavd, 0, sizeof(m_uavd) ); } void* create(const Memory* _mem, uint64_t _flags, uint8_t _skip); void destroy(); void overrideInternal(uintptr_t _ptr); void update(ID3D12GraphicsCommandList* _commandList, uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, uint16_t _pitch, const Memory* _mem); void resolve(ID3D12GraphicsCommandList* _commandList, uint8_t _resolve, uint32_t _layer, uint32_t _numLayers, uint32_t _mip); D3D12_RESOURCE_STATES setState(ID3D12GraphicsCommandList* _commandList, D3D12_RESOURCE_STATES _state); D3D12_SHADER_RESOURCE_VIEW_DESC m_srvd; D3D12_UNORDERED_ACCESS_VIEW_DESC m_uavd; ID3D12Resource* m_ptr; ID3D12Resource* m_singleMsaa; void* m_directAccessPtr; D3D12_RESOURCE_STATES m_state; uint64_t m_flags; uint32_t m_width; uint32_t m_height; uint32_t m_depth; uint32_t m_numLayers; uint16_t m_samplerIdx; uint8_t m_type; uint8_t m_requestedFormat; uint8_t m_textureFormat; uint8_t m_numMips; }; struct FrameBufferD3D12 { FrameBufferD3D12() : m_swapChain(NULL) , m_nwh(NULL) , m_width(0) , m_height(0) , m_denseIdx(UINT16_MAX) , m_num(0) , m_numTh(0) , m_state(D3D12_RESOURCE_STATE_PRESENT) , m_needPresent(false) { m_depth.idx = bgfx::kInvalidHandle; } void create(uint8_t _num, const Attachment* _attachment); void create(uint16_t _denseIdx, void* _nwh, uint32_t _width, uint32_t _height, TextureFormat::Enum _format, TextureFormat::Enum _depthFormat); uint16_t destroy(); HRESULT present(uint32_t _syncInterval, uint32_t _flags); void preReset(); void postReset(); void resolve(); void clear(ID3D12GraphicsCommandList* _commandList, const Clear& _clear, const float _palette[][4], const D3D12_RECT* _rect = NULL, uint32_t _num = 0); D3D12_RESOURCE_STATES setState(ID3D12GraphicsCommandList* _commandList, uint8_t _idx, D3D12_RESOURCE_STATES _state); TextureHandle m_texture[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS]; TextureHandle m_depth; Dxgi::SwapChainI* m_swapChain; void* m_nwh; uint32_t m_width; uint32_t m_height; uint16_t m_denseIdx; uint8_t m_num; uint8_t m_numTh; Attachment m_attachment[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS]; D3D12_RESOURCE_STATES m_state; bool m_needPresent; }; struct CommandQueueD3D12 { CommandQueueD3D12() : m_currentFence(0) , m_completedFence(0) , m_control(BX_COUNTOF(m_commandList) ) { BX_STATIC_ASSERT(BX_COUNTOF(m_commandList) == BX_COUNTOF(m_release) ); } void init(ID3D12Device* _device); void shutdown(); ID3D12GraphicsCommandList* alloc(); uint64_t kick(); void finish(uint64_t _waitFence = UINT64_MAX, bool _finishAll = false); bool tryFinish(uint64_t _waitFence); void release(ID3D12Resource* _ptr); bool consume(uint32_t _ms = UINT32_MAX); struct CommandList { ID3D12GraphicsCommandList* m_commandList; ID3D12CommandAllocator* m_commandAllocator; HANDLE m_event; }; ID3D12CommandQueue* m_commandQueue; uint64_t m_currentFence; uint64_t m_completedFence; ID3D12Fence* m_fence; CommandList m_commandList[256]; typedef stl::vector ResourceArray; ResourceArray m_release[256]; bx::RingBufferControl m_control; }; struct BatchD3D12 { enum Enum { Draw, DrawIndexed, Count }; BatchD3D12() : m_currIndirect(0) , m_maxDrawPerBatch(0) , m_minIndirect(0) , m_flushPerBatch(0) { bx::memSet(m_num, 0, sizeof(m_num) ); } ~BatchD3D12() { } void create(uint32_t _maxDrawPerBatch); void destroy(); template Ty& getCmd(Enum _type); uint32_t draw(ID3D12GraphicsCommandList* _commandList, D3D12_GPU_VIRTUAL_ADDRESS _cbv, const RenderDraw& _draw); void flush(ID3D12GraphicsCommandList* _commandList, Enum _type); void flush(ID3D12GraphicsCommandList* _commandList, bool _clean = false); void begin(); void end(ID3D12GraphicsCommandList* _commandList); void setSeqMode(bool _enabled) { m_flushPerBatch = _enabled ? 1 : m_maxDrawPerBatch; } void setIndirectMode(bool _enabled) { m_minIndirect = _enabled ? 64 : UINT32_MAX; } ID3D12CommandSignature* m_commandSignature[Count]; uint32_t m_num[Count]; void* m_cmds[Count]; struct DrawIndirectCommand { D3D12_VERTEX_BUFFER_VIEW vbv[BGFX_CONFIG_MAX_VERTEX_STREAMS + 1 /* instanced buffer */]; D3D12_GPU_VIRTUAL_ADDRESS cbv; D3D12_DRAW_ARGUMENTS args; }; struct DrawIndexedIndirectCommand { D3D12_VERTEX_BUFFER_VIEW vbv[BGFX_CONFIG_MAX_VERTEX_STREAMS + 1 /* instanced buffer */]; D3D12_INDEX_BUFFER_VIEW ibv; D3D12_GPU_VIRTUAL_ADDRESS cbv; D3D12_DRAW_INDEXED_ARGUMENTS args; }; struct Stats { uint32_t m_numImmediate[Count]; uint32_t m_numIndirect[Count]; }; BufferD3D12 m_indirect[32]; uint32_t m_currIndirect; DrawIndexedIndirectCommand m_current; Stats m_stats; uint32_t m_maxDrawPerBatch; uint32_t m_minIndirect; uint32_t m_flushPerBatch; }; struct TimerQueryD3D12 { TimerQueryD3D12() : m_control(BX_COUNTOF(m_query) ) { } void init(); void shutdown(); uint32_t begin(uint32_t _resultIdx, uint32_t _frameNum); void end(uint32_t _idx); bool update(); struct Query { uint32_t m_resultIdx; uint32_t m_frameNum; uint64_t m_fence; bool m_ready; }; struct Result { void reset() { m_begin = 0; m_end = 0; m_pending = 0; m_frameNum = 0; } uint64_t m_begin; uint64_t m_end; uint32_t m_pending; uint32_t m_frameNum; }; uint64_t m_frequency; Result m_result[BGFX_CONFIG_MAX_VIEWS+1]; Query m_query[BGFX_CONFIG_MAX_VIEWS*4]; ID3D12Resource* m_readback; ID3D12QueryHeap* m_queryHeap; uint64_t* m_queryResult; bx::RingBufferControl m_control; }; struct OcclusionQueryD3D12 { OcclusionQueryD3D12() : m_control(BX_COUNTOF(m_handle) ) { } void init(); void shutdown(); void begin(ID3D12GraphicsCommandList* _commandList, Frame* _render, OcclusionQueryHandle _handle); void end(ID3D12GraphicsCommandList* _commandList); void invalidate(OcclusionQueryHandle _handle); ID3D12Resource* m_readback; ID3D12QueryHeap* m_queryHeap; OcclusionQueryHandle m_handle[BGFX_CONFIG_MAX_OCCLUSION_QUERIES]; uint64_t* m_result; bx::RingBufferControl m_control; }; } /* namespace d3d12 */ } // namespace bgfx #endif // BGFX_RENDERER_D3D12_H_HEADER_GUARD