#include "GraphicsApi.h" #include "Globals.h" #include "DLLRegister.h" #include "Fenster.h" #include #include #include using namespace Framework; DirectX12::DirectX12() : GraphicsApi( DIRECTX12 ), device( 0 ), infoQueue( 0 ), directCommandQueue( 0 ), swapChain( 0 ), rtvHeap( 0 ), directCommandList( 0 ), backBufferIndex( 0 ), tearing( 0 ), fence( 0 ), fenceEvent( 0 ) { for( int i = 0; i < 2; i++ ) { fenceValue[ i ] = 0; backBuffer[ i ] = 0; directCommandAllocator[ i ] = 0; } } DirectX12::~DirectX12() { if( directCommandQueue && fence && fenceEvent ) { unsigned __int64 val = ++fenceValue[ backBufferIndex ]; directCommandQueue->Signal( fence, val ); if( fence->GetCompletedValue() < val ) { fence->SetEventOnCompletion( val, fenceEvent ); WaitForSingleObject( fenceEvent, INFINITE ); } } if( fence ) fence->Release(); if( directCommandList ) directCommandList->Release(); for( int i = 0; i < 2; i++ ) { if( directCommandAllocator[ i ] ) directCommandAllocator[ i ]->Release(); if( backBuffer[ i ] ) backBuffer[ i ]->Release(); } if( rtvHeap ) rtvHeap->Release(); if( swapChain ) swapChain->Release(); if( directCommandQueue ) directCommandQueue->Release(); if( infoQueue ) infoQueue->Release(); if( device ) { device->Release(); getDLLRegister()->releaseDLL( "dxgi.dll" ); getDLLRegister()->releaseDLL( "d3d12.dll" ); } } typedef HRESULT( *CreateDXGIFactory2Function )( UINT, REFIID, void ** ); typedef HRESULT( *D3D12CreateDeviceFunction )( IDXGIAdapter *, D3D_FEATURE_LEVEL, REFIID, void ** ); void DirectX12::initialize( WFenster * fenster, Vec2 backBufferSize, bool fullScreen ) { if( device ) return GraphicsApi::initialize( fenster, backBufferSize, fullScreen ); GraphicsApi::initialize( fenster, backBufferSize, fullScreen ); HINSTANCE dxgiDLL = getDLLRegister()->ladeDLL( "dxgi.dll", "dxgi.dll" ); if( !dxgiDLL ) { WMessageBox( fenster->getFensterHandle(), new Text( "Fehler" ), new Text( "dxgi.dll konnte nicht gefunden werden." ), MB_ICONERROR ); return; } HINSTANCE d3d12DLL = getDLLRegister()->ladeDLL( "d3d12.dll", "d3d12.dll" ); if( !d3d12DLL ) { getDLLRegister()->releaseDLL( "dxgi.dll" ); WMessageBox( fenster->getFensterHandle(), new Text( "Fehler" ), new Text( "DirectX 12 konnte nicht gefunden werden." ), MB_ICONERROR ); return; } CreateDXGIFactory2Function createFactory = (CreateDXGIFactory2Function)GetProcAddress( dxgiDLL, "CreateDXGIFactory2" ); if( !createFactory ) { getDLLRegister()->releaseDLL( "dxgi.dll" ); getDLLRegister()->releaseDLL( "d3d12.dll" ); WMessageBox( fenster->getFensterHandle(), new Text( "Fehler" ), new Text( "Der Einstiegspunkt CreateDXGIFactory2 fon DXGI konnte nicht gefunden werden." ), MB_ICONERROR ); return; } D3D12CreateDeviceFunction createDevice = (D3D12CreateDeviceFunction)GetProcAddress( d3d12DLL, "D3D12CreateDevice" ); if( !createDevice ) { getDLLRegister()->releaseDLL( "dxgi.dll" ); getDLLRegister()->releaseDLL( "d3d12.dll" ); WMessageBox( fenster->getFensterHandle(), new Text( "Fehler" ), new Text( "Der Einstiegspunkt D3D12CreateDevice fon DirectX 12 konnte nicht gefunden werden." ), MB_ICONERROR ); return; } IDXGIFactory4 *factory; UINT createFactoryFlags = 0; #if defined(_DEBUG) createFactoryFlags = DXGI_CREATE_FACTORY_DEBUG; #endif HRESULT res = createFactory( createFactoryFlags, __uuidof( IDXGIFactory4 ), (void **)& factory ); if( FAILED( res ) ) { getDLLRegister()->releaseDLL( "dxgi.dll" ); getDLLRegister()->releaseDLL( "d3d12.dll" ); std::cout << "ERROR: createFactory returned " << res << "\n"; WMessageBox( fenster->getFensterHandle(), new Text( "Fehler" ), new Text( "createFactory ist Fehlgeschlagen." ), MB_ICONERROR ); return; } int index = 0; unsigned __int64 maxVideoMemory = 0; IDXGIAdapter1 *best = 0; do { IDXGIAdapter1 *current; res = factory->EnumAdapters1( index++, ¤t ); if( res == S_OK ) { DXGI_ADAPTER_DESC1 dxgiAdapterDesc1; current->GetDesc1( &dxgiAdapterDesc1 ); if( ( dxgiAdapterDesc1.Flags &DXGI_ADAPTER_FLAG_SOFTWARE ) == 0 && dxgiAdapterDesc1.DedicatedVideoMemory > maxVideoMemory && SUCCEEDED( createDevice( current, D3D_FEATURE_LEVEL_12_1, __uuidof( ID3D12Device2 ), 0 ) ) ) { if( best ) best->Release(); best = current; maxVideoMemory = dxgiAdapterDesc1.DedicatedVideoMemory; } else current->Release(); } } while( res != DXGI_ERROR_NOT_FOUND ); res = createDevice( best, D3D_FEATURE_LEVEL_12_1, __uuidof( ID3D12Device2 ), (void **)& device ); best->Release(); if( FAILED( res ) ) { factory->Release(); getDLLRegister()->releaseDLL( "dxgi.dll" ); getDLLRegister()->releaseDLL( "d3d12.dll" ); std::cout << "ERROR: createDevice returned " << res << "\n"; WMessageBox( fenster->getFensterHandle(), new Text( "Fehler" ), new Text( "createDevice ist Fehlgeschlagen." ), MB_ICONERROR ); return; } res = device->QueryInterface( __uuidof( ID3D12InfoQueue ), (void **)& infoQueue ); if( SUCCEEDED( res ) ) { infoQueue->SetBreakOnSeverity( D3D12_MESSAGE_SEVERITY_CORRUPTION, TRUE ); infoQueue->SetBreakOnSeverity( D3D12_MESSAGE_SEVERITY_ERROR, TRUE ); infoQueue->SetBreakOnSeverity( D3D12_MESSAGE_SEVERITY_WARNING, TRUE ); D3D12_MESSAGE_SEVERITY Severities[] = { D3D12_MESSAGE_SEVERITY_INFO }; // Suppress individual messages by their ID D3D12_MESSAGE_ID DenyIds[] = { D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE, // I'm really not sure how to avoid this message. D3D12_MESSAGE_ID_MAP_INVALID_NULLRANGE, // This warning occurs when using capture frame while graphics debugging. D3D12_MESSAGE_ID_UNMAP_INVALID_NULLRANGE, // This warning occurs when using capture frame while graphics debugging. }; D3D12_INFO_QUEUE_FILTER NewFilter = {}; NewFilter.DenyList.NumSeverities = _countof( Severities ); NewFilter.DenyList.pSeverityList = Severities; NewFilter.DenyList.NumIDs = _countof( DenyIds ); NewFilter.DenyList.pIDList = DenyIds; infoQueue->PushStorageFilter( &NewFilter ); } D3D12_COMMAND_QUEUE_DESC desc = {}; desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; desc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL; desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; desc.NodeMask = 0; res = device->CreateCommandQueue( &desc, __uuidof( ID3D12CommandQueue ), (void **)& directCommandQueue ); if( FAILED( res ) ) { factory->Release(); std::cout << "ERROR: CreateCommandQueue returned " << res << "\n"; WMessageBox( fenster->getFensterHandle(), new Text( "Fehler" ), new Text( "CreateCommandQueue ist Fehlgeschlagen." ), MB_ICONERROR ); return; } IDXGIFactory5 *fac5 = 0; factory->QueryInterface( __uuidof( IDXGIFactory5 ), (void **)& fac5 ); if( fac5 ) { res = fac5->CheckFeatureSupport( DXGI_FEATURE_PRESENT_ALLOW_TEARING, &tearing, sizeof( tearing ) ); if( FAILED( res ) ) tearing = 0; fac5->Release(); } DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {}; swapChainDesc.Width = backBufferSize.x; swapChainDesc.Height = backBufferSize.y; swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; swapChainDesc.Stereo = FALSE; swapChainDesc.SampleDesc = { 1, 0 }; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.BufferCount = 2; swapChainDesc.Scaling = DXGI_SCALING_STRETCH; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED; swapChainDesc.Flags = tearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0; IDXGISwapChain1 *tmpSwapChain; res = factory->CreateSwapChainForHwnd( directCommandQueue, fenster->getFensterHandle(), &swapChainDesc, 0, 0, &tmpSwapChain ); if( FAILED( res ) ) { factory->Release(); std::cout << "ERROR: CreateSwapChainForHwnd returned " << res << "\n"; WMessageBox( fenster->getFensterHandle(), new Text( "Fehler" ), new Text( "CreateSwapChainForHwnd ist Fehlgeschlagen." ), MB_ICONERROR ); return; } res = tmpSwapChain->QueryInterface( __uuidof( IDXGISwapChain4 ), (void**)&swapChain ); tmpSwapChain->Release(); if( FAILED( res ) ) { factory->Release(); std::cout << "ERROR: QueryInterface returned " << res << "\n"; WMessageBox( fenster->getFensterHandle(), new Text( "Fehler" ), new Text( "QueryInterface ist Fehlgeschlagen." ), MB_ICONERROR ); return; } factory->MakeWindowAssociation( fenster->getFensterHandle(), DXGI_MWA_NO_ALT_ENTER ); D3D12_DESCRIPTOR_HEAP_DESC rtvhdesc = {}; rtvhdesc.NumDescriptors = 2; rtvhdesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; res = device->CreateDescriptorHeap( &rtvhdesc, __uuidof( ID3D12DescriptorHeap ), (void **)& rtvHeap ); if( FAILED( res ) ) { factory->Release(); std::cout << "ERROR: CreateDescriptorHeap returned " << res << "\n"; WMessageBox( fenster->getFensterHandle(), new Text( "Fehler" ), new Text( "CreateDescriptorHeap ist Fehlgeschlagen." ), MB_ICONERROR ); return; } auto rtvDescriptorSize = device->GetDescriptorHandleIncrementSize( D3D12_DESCRIPTOR_HEAP_TYPE_RTV ); D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle( rtvHeap->GetCPUDescriptorHandleForHeapStart() ); for( int i = 0; i < 2; i++ ) { ID3D12Resource *backBuffer; res = swapChain->GetBuffer( i, __uuidof( ID3D12Resource ), (void **)& backBuffer ); if( FAILED( res ) ) { factory->Release(); std::cout << "ERROR: GetBuffer returned " << res << "\n"; WMessageBox( fenster->getFensterHandle(), new Text( "Fehler" ), new Text( "GetBuffer ist Fehlgeschlagen." ), MB_ICONERROR ); return; } device->CreateRenderTargetView( backBuffer, nullptr, rtvHandle ); this->backBuffer[ i ] = backBuffer; rtvHandle.ptr += rtvDescriptorSize; } res = device->CreateCommandAllocator( D3D12_COMMAND_LIST_TYPE_DIRECT, __uuidof( ID3D12CommandAllocator ), (void **)& directCommandAllocator[ 0 ] ); if( FAILED( res ) ) { factory->Release(); std::cout << "ERROR: CreateCommandAllocator returned " << res << "\n"; WMessageBox( fenster->getFensterHandle(), new Text( "Fehler" ), new Text( "CreateCommandAllocator ist Fehlgeschlagen." ), MB_ICONERROR ); return; } res = device->CreateCommandAllocator( D3D12_COMMAND_LIST_TYPE_DIRECT, __uuidof( ID3D12CommandAllocator ), (void **)& directCommandAllocator[ 1 ] ); if( FAILED( res ) ) { factory->Release(); std::cout << "ERROR: CreateCommandAllocator returned " << res << "\n"; WMessageBox( fenster->getFensterHandle(), new Text( "Fehler" ), new Text( "CreateCommandAllocator ist Fehlgeschlagen." ), MB_ICONERROR ); return; } res = device->CreateCommandList( 0, D3D12_COMMAND_LIST_TYPE_DIRECT, directCommandAllocator[ 0 ], nullptr, __uuidof( ID3D12GraphicsCommandList ), (void **)& directCommandList ); if( FAILED( res ) ) { factory->Release(); std::cout << "ERROR: CreateCommandList returned " << res << "\n"; WMessageBox( fenster->getFensterHandle(), new Text( "Fehler" ), new Text( "CreateCommandList ist Fehlgeschlagen." ), MB_ICONERROR ); return; } device->CreateFence( 0, D3D12_FENCE_FLAG_NONE, __uuidof( ID3D12Fence ), (void **)&fence ); fenceEvent = CreateEvent( 0, 0, 0, 0 ); if( !fenceEvent ) { factory->Release(); std::cout << "ERROR: CreateEvent returned 0\n"; WMessageBox( fenster->getFensterHandle(), new Text( "Fehler" ), new Text( "CreateEvent ist Fehlgeschlagen." ), MB_ICONERROR ); return; } factory->Release(); } void DirectX12::update() { if( !device || !swapChain || !fence || !directCommandQueue || !fenceEvent ) return; unsigned __int64 val = ++fenceValue[ backBufferIndex ]; directCommandQueue->Signal( fence, val ); if( fence->GetCompletedValue() < val ) { fence->SetEventOnCompletion( val, fenceEvent ); WaitForSingleObject( fenceEvent, INFINITE ); } HINSTANCE dxgiDLL = getDLLRegister()->ladeDLL( "dxgi.dll", "dxgi.dll" ); if( !dxgiDLL ) { WMessageBox( fenster->getFensterHandle(), new Text( "Fehler" ), new Text( "dxgi.dll konnte nicht gefunden werden." ), MB_ICONERROR ); return; } CreateDXGIFactory2Function createFactory = (CreateDXGIFactory2Function)GetProcAddress( dxgiDLL, "CreateDXGIFactory2" ); if( !createFactory ) { getDLLRegister()->releaseDLL( "dxgi.dll" ); WMessageBox( fenster->getFensterHandle(), new Text( "Fehler" ), new Text( "Der Einstiegspunkt CreateDXGIFactory2 fon DXGI konnte nicht gefunden werden." ), MB_ICONERROR ); return; } DXGI_SWAP_CHAIN_DESC swapChainDesc = {}; HRESULT res = swapChain->GetDesc( &swapChainDesc ); if( FAILED( res ) ) { getDLLRegister()->releaseDLL( "dxgi.dll" ); std::cout << "ERROR: GetDesc returned " << res << "\n"; WMessageBox( fenster->getFensterHandle(), new Text( "Fehler" ), new Text( "GetDesc ist Fehlgeschlagen." ), MB_ICONERROR ); return; } IDXGIFactory4 *factory; UINT createFactoryFlags = 0; #if defined(_DEBUG) createFactoryFlags = DXGI_CREATE_FACTORY_DEBUG; #endif res = createFactory( createFactoryFlags, __uuidof( IDXGIFactory4 ), (void **)& factory ); if( FAILED( res ) ) { getDLLRegister()->releaseDLL( "dxgi.dll" ); std::cout << "ERROR: createFactory returned " << res << "\n"; WMessageBox( fenster->getFensterHandle(), new Text( "Fehler" ), new Text( "createFactory ist Fehlgeschlagen." ), MB_ICONERROR ); return; } for( int i = 0; i < 2; ++i ) { backBuffer[ i ]->Release(); backBuffer[ i ] = 0; } res = swapChain->ResizeBuffers( 2, backBufferSize.x, backBufferSize.y, swapChainDesc.BufferDesc.Format, swapChainDesc.Flags ); backBufferIndex = swapChain->GetCurrentBackBufferIndex(); auto rtvDescriptorSize = device->GetDescriptorHandleIncrementSize( D3D12_DESCRIPTOR_HEAP_TYPE_RTV ); D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle( rtvHeap->GetCPUDescriptorHandleForHeapStart() ); for( int i = 0; i < 2; i++ ) { ID3D12Resource *backBuffer; res = swapChain->GetBuffer( i, __uuidof( ID3D12Resource ), (void **)& backBuffer ); if( FAILED( res ) ) { getDLLRegister()->releaseDLL( "dxgi.dll" ); factory->Release(); std::cout << "ERROR: GetBuffer returned " << res << "\n"; WMessageBox( fenster->getFensterHandle(), new Text( "Fehler" ), new Text( "GetBuffer ist Fehlgeschlagen." ), MB_ICONERROR ); return; } device->CreateRenderTargetView( backBuffer, nullptr, rtvHandle ); this->backBuffer[ i ] = backBuffer; rtvHandle.ptr += rtvDescriptorSize; } getDLLRegister()->releaseDLL( "dxgi.dll" ); factory->Release(); } void DirectX12::beginFrame( bool fill2D, bool fill3D, int fillColor ) { D3D12_RESOURCE_BARRIER barrier; ZeroMemory( &barrier, sizeof( barrier ) ); barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; barrier.Transition.pResource = this->backBuffer[ backBufferIndex ]; barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT; barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; directCommandList->ResourceBarrier( 1, &barrier ); if( fill3D ) { float color[ 4 ]; // Setup the color to clear the buffer. color[ 0 ] = ( ( fillColor >> 16 ) & 0xFF ) / 255.f; // R color[ 1 ] = ( ( fillColor >> 8 ) & 0xFF ) / 255.f; // G color[ 2 ] = ( fillColor & 0xFF ) / 255.f; // B color[ 3 ] = ( ( fillColor >> 24 ) & 0xFF ) / 255.f; // A auto rtvDescriptorSize = device->GetDescriptorHandleIncrementSize( D3D12_DESCRIPTOR_HEAP_TYPE_RTV ); D3D12_CPU_DESCRIPTOR_HANDLE rtv = rtvHeap->GetCPUDescriptorHandleForHeapStart(); rtv.ptr += rtvDescriptorSize * backBufferIndex; directCommandList->ClearRenderTargetView( rtv, color, 0, 0 ); } } void DirectX12::renderKamera( Kam3D * zKamera ) { } void DirectX12::presentFrame() { directCommandList->Close(); directCommandQueue->ExecuteCommandLists( 1, (ID3D12CommandList**)&directCommandList ); // TODO: Render Framework GUI swapChain->Present( 0, tearing ? DXGI_PRESENT_ALLOW_TEARING : 0 ); directCommandQueue->Signal( fence, ++fenceValue[ backBufferIndex ] ); if( fence->GetCompletedValue() < fenceValue[ backBufferIndex ] ) { fence->SetEventOnCompletion( fenceValue[ backBufferIndex ], fenceEvent ); WaitForSingleObject( fenceEvent, INFINITE ); } backBufferIndex = swapChain->GetCurrentBackBufferIndex(); directCommandAllocator[ backBufferIndex ]->Reset(); directCommandList->Reset( directCommandAllocator[ backBufferIndex ], nullptr ); } Textur *DirectX12::createOrGetTextur( const char *name, Bild * b ) { return 0; } Bild *DirectX12::zUIRenderBild() const { return 0; } bool DirectX12::isAvailable() { HINSTANCE dxgiDLL = getDLLRegister()->ladeDLL( "dxgi.dll", "dxgi.dll" ); if( !dxgiDLL ) return 0; HINSTANCE d3d12DLL = getDLLRegister()->ladeDLL( "d3d12.dll", "d3d12.dll" ); if( !d3d12DLL ) { getDLLRegister()->releaseDLL( "dxgi.dll" ); return 0; } CreateDXGIFactory2Function createFactory = (CreateDXGIFactory2Function)GetProcAddress( dxgiDLL, "CreateDXGIFactory2" ); if( !createFactory ) { getDLLRegister()->releaseDLL( "dxgi.dll" ); getDLLRegister()->releaseDLL( "d3d12.dll" ); return 0; } D3D12CreateDeviceFunction createDevice = (D3D12CreateDeviceFunction)GetProcAddress( d3d12DLL, "D3D12CreateDevice" ); if( !createDevice ) { getDLLRegister()->releaseDLL( "dxgi.dll" ); getDLLRegister()->releaseDLL( "d3d12.dll" ); return 0; } IDXGIFactory4 *factory; UINT createFactoryFlags = 0; #if defined(_DEBUG) createFactoryFlags = DXGI_CREATE_FACTORY_DEBUG; #endif HRESULT res = createFactory( createFactoryFlags, __uuidof( IDXGIFactory4 ), (void **)& factory ); if( FAILED( res ) ) { getDLLRegister()->releaseDLL( "dxgi.dll" ); getDLLRegister()->releaseDLL( "d3d12.dll" ); return 0; } int index = 0; do { IDXGIAdapter1 *current; res = factory->EnumAdapters1( index++, ¤t ); if( res == S_OK ) { DXGI_ADAPTER_DESC1 dxgiAdapterDesc1; current->GetDesc1( &dxgiAdapterDesc1 ); if( ( dxgiAdapterDesc1.Flags &DXGI_ADAPTER_FLAG_SOFTWARE ) == 0 && SUCCEEDED( createDevice( current, D3D_FEATURE_LEVEL_12_1, __uuidof( ID3D12Device2 ), 0 ) ) ) { current->Release(); factory->Release(); getDLLRegister()->releaseDLL( "dxgi.dll" ); getDLLRegister()->releaseDLL( "d3d12.dll" ); return 1; } current->Release(); } } while( res != DXGI_ERROR_NOT_FOUND ); factory->Release(); getDLLRegister()->releaseDLL( "dxgi.dll" ); getDLLRegister()->releaseDLL( "d3d12.dll" ); return 0; }