void FD3D11DynamicRHI::InitD3DDevice() { check( IsInGameThread() ); // Wait for the rendering thread to go idle. SCOPED_SUSPEND_RENDERING_THREAD(false); // If the device we were using has been removed, release it and the resources we created for it. if(bDeviceRemoved) { UE_LOG(LogD3D11RHI, Log, TEXT("bDeviceRemoved")); check(Direct3DDevice); HRESULT hRes = Direct3DDevice->GetDeviceRemovedReason(); const TCHAR* Reason = TEXT("?"); switch(hRes) { case DXGI_ERROR_DEVICE_HUNG: Reason = TEXT("HUNG"); break; case DXGI_ERROR_DEVICE_REMOVED: Reason = TEXT("REMOVED"); break; case DXGI_ERROR_DEVICE_RESET: Reason = TEXT("RESET"); break; case DXGI_ERROR_DRIVER_INTERNAL_ERROR: Reason = TEXT("INTERNAL_ERROR"); break; case DXGI_ERROR_INVALID_CALL: Reason = TEXT("INVALID_CALL"); break; } bDeviceRemoved = false; // Cleanup the D3D device. CleanupD3DDevice(); // We currently don't support removed devices because FTexture2DResource can't recreate its RHI resources from scratch. // We would also need to recreate the viewport swap chains from scratch. UE_LOG(LogD3D11RHI, Fatal, TEXT("The Direct3D 11 device that was being used has been removed (Error: %d '%s'). Please restart the game."), hRes, Reason); } // If we don't have a device yet, either because this is the first viewport, or the old device was removed, create a device. if(!Direct3DDevice) { UE_LOG(LogD3D11RHI, Log, TEXT("!Direct3DDevice")); check(!GIsRHIInitialized); // Clear shadowed shader resources. ClearState(); // Determine the adapter and device type to use. TRefCountPtr<IDXGIAdapter> Adapter; // In Direct3D 11, if you are trying to create a hardware or a software device, set pAdapter != NULL which constrains the other inputs to be: // DriverType must be D3D_DRIVER_TYPE_UNKNOWN // Software must be NULL. D3D_DRIVER_TYPE DriverType = D3D_DRIVER_TYPE_UNKNOWN; uint32 DeviceFlags = D3D11RHI_ShouldAllowAsyncResourceCreation() ? 0 : D3D11_CREATE_DEVICE_SINGLETHREADED; // Use a debug device if specified on the command line. const bool bWithD3DDebug = D3D11RHI_ShouldCreateWithD3DDebug(); if (bWithD3DDebug) { DeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; UE_LOG(LogD3D11RHI, Log, TEXT("InitD3DDevice: -D3DDebug = %s"), bWithD3DDebug ? TEXT("on") : TEXT("off")); } GTexturePoolSize = 0; TRefCountPtr<IDXGIAdapter> EnumAdapter; if(DXGIFactory1->EnumAdapters(ChosenAdapter,EnumAdapter.GetInitReference()) != DXGI_ERROR_NOT_FOUND) { if (EnumAdapter)// && EnumAdapter->CheckInterfaceSupport(__uuidof(ID3D11Device),NULL) == S_OK) { DXGI_ADAPTER_DESC AdapterDesc; if (SUCCEEDED(EnumAdapter->GetDesc(&AdapterDesc))) { Adapter = EnumAdapter; GRHIAdapterName = AdapterDesc.Description; GRHIVendorId = AdapterDesc.VendorId; // Issue: 32bit windows doesn't report 64bit value, we take what we get. FD3D11GlobalStats::GDedicatedVideoMemory = int64(AdapterDesc.DedicatedVideoMemory); FD3D11GlobalStats::GDedicatedSystemMemory = int64(AdapterDesc.DedicatedSystemMemory); FD3D11GlobalStats::GSharedSystemMemory = int64(AdapterDesc.SharedSystemMemory); // Total amount of system memory, clamped to 8 GB int64 TotalPhysicalMemory = FMath::Min(int64(FPlatformMemory::GetConstants().TotalPhysicalGB), 8ll) * (1024ll * 1024ll * 1024ll); // Consider 50% of the shared memory but max 25% of total system memory. int64 ConsideredSharedSystemMemory = FMath::Min( FD3D11GlobalStats::GSharedSystemMemory / 2ll, TotalPhysicalMemory / 4ll ); FD3D11GlobalStats::GTotalGraphicsMemory = 0; if ( IsRHIDeviceIntel() ) { // It's all system memory. FD3D11GlobalStats::GTotalGraphicsMemory = FD3D11GlobalStats::GDedicatedVideoMemory; FD3D11GlobalStats::GTotalGraphicsMemory += FD3D11GlobalStats::GDedicatedSystemMemory; FD3D11GlobalStats::GTotalGraphicsMemory += ConsideredSharedSystemMemory; } else if ( FD3D11GlobalStats::GDedicatedVideoMemory >= 200*1024*1024 ) { // Use dedicated video memory, if it's more than 200 MB FD3D11GlobalStats::GTotalGraphicsMemory = FD3D11GlobalStats::GDedicatedVideoMemory; } else if ( FD3D11GlobalStats::GDedicatedSystemMemory >= 200*1024*1024 ) { // Use dedicated system memory, if it's more than 200 MB FD3D11GlobalStats::GTotalGraphicsMemory = FD3D11GlobalStats::GDedicatedSystemMemory; } else if ( FD3D11GlobalStats::GSharedSystemMemory >= 400*1024*1024 ) { // Use some shared system memory, if it's more than 400 MB FD3D11GlobalStats::GTotalGraphicsMemory = ConsideredSharedSystemMemory; } else { // Otherwise consider 25% of total system memory for graphics. FD3D11GlobalStats::GTotalGraphicsMemory = TotalPhysicalMemory / 4ll; } if ( sizeof(SIZE_T) < 8 ) { // Clamp to 1 GB if we're less than 64-bit FD3D11GlobalStats::GTotalGraphicsMemory = FMath::Min( FD3D11GlobalStats::GTotalGraphicsMemory, 1024ll * 1024ll * 1024ll ); } else { // Clamp to 1.9 GB if we're 64-bit FD3D11GlobalStats::GTotalGraphicsMemory = FMath::Min( FD3D11GlobalStats::GTotalGraphicsMemory, 1945ll * 1024ll * 1024ll ); } if ( GPoolSizeVRAMPercentage > 0 ) { float PoolSize = float(GPoolSizeVRAMPercentage) * 0.01f * float(FD3D11GlobalStats::GTotalGraphicsMemory); // Truncate GTexturePoolSize to MB (but still counted in bytes) GTexturePoolSize = int64(FGenericPlatformMath::TruncToFloat(PoolSize / 1024.0f / 1024.0f)) * 1024 * 1024; UE_LOG(LogRHI,Log,TEXT("Texture pool is %llu MB (%d%% of %llu MB)"), GTexturePoolSize / 1024 / 1024, GPoolSizeVRAMPercentage, FD3D11GlobalStats::GTotalGraphicsMemory / 1024 / 1024); } const bool bIsPerfHUD = !FCString::Stricmp(AdapterDesc.Description,TEXT("NVIDIA PerfHUD")); if(bIsPerfHUD) { DriverType = D3D_DRIVER_TYPE_REFERENCE; } } else { check(!"Internal error, GetDesc() failed but before it worked") } } } else {
void FD3D11DynamicRHI::CleanupD3DDevice() { if(GIsRHIInitialized) { check(Direct3DDevice); check(Direct3DDeviceIMContext); // Reset the RHI initialized flag. GIsRHIInitialized = false; check(!GIsCriticalError); // Ask all initialized FRenderResources to release their RHI resources. for(TLinkedList<FRenderResource*>::TIterator ResourceIt(FRenderResource::GetResourceList());ResourceIt;ResourceIt.Next()) { FRenderResource* Resource = *ResourceIt; check(Resource->IsInitialized()); Resource->ReleaseRHI(); } for(TLinkedList<FRenderResource*>::TIterator ResourceIt(FRenderResource::GetResourceList());ResourceIt;ResourceIt.Next()) { ResourceIt->ReleaseDynamicRHI(); } extern void EmptyD3DSamplerStateCache(); EmptyD3DSamplerStateCache(); // release our dynamic VB and IB buffers DynamicVB = NULL; DynamicIB = NULL; // Release references to bound uniform buffers. for (int32 Frequency = 0; Frequency < SF_NumFrequencies; ++Frequency) { for (int32 BindIndex = 0; BindIndex < MAX_UNIFORM_BUFFERS_PER_SHADER_STAGE; ++BindIndex) { BoundUniformBuffers[Frequency][BindIndex].SafeRelease(); } } // Release the device and its IC StateCache.SetContext(nullptr); // Flush all pending deletes before destroying the device. FRHIResource::FlushPendingDeletes(); ReleasePooledUniformBuffers(); ReleasePooledTextures(); // When running with D3D debug, clear state and flush the device to get rid of spurious live objects in D3D11's report. if (D3D11RHI_ShouldCreateWithD3DDebug()) { Direct3DDeviceIMContext->ClearState(); Direct3DDeviceIMContext->Flush(); } Direct3DDeviceIMContext = NULL; Direct3DDevice = NULL; } }
/** * Attempts to create a D3D11 device for the adapter using at most MaxFeatureLevel. * If creation is successful, true is returned and the supported feature level is set in OutFeatureLevel. */ static bool SafeTestD3D11CreateDevice(IDXGIAdapter* Adapter,D3D_FEATURE_LEVEL MaxFeatureLevel,D3D_FEATURE_LEVEL* OutFeatureLevel) { ID3D11Device* D3DDevice = NULL; ID3D11DeviceContext* D3DDeviceContext = NULL; uint32 DeviceFlags = D3D11_CREATE_DEVICE_SINGLETHREADED; // Use a debug device if specified on the command line. if(D3D11RHI_ShouldCreateWithD3DDebug()) { DeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; } D3D_FEATURE_LEVEL RequestedFeatureLevels[] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_0 }; int32 FirstAllowedFeatureLevel = 0; int32 NumAllowedFeatureLevels = ARRAY_COUNT(RequestedFeatureLevels); while (FirstAllowedFeatureLevel < NumAllowedFeatureLevels) { if (RequestedFeatureLevels[FirstAllowedFeatureLevel] == MaxFeatureLevel) { break; } FirstAllowedFeatureLevel++; } NumAllowedFeatureLevels -= FirstAllowedFeatureLevel; if (NumAllowedFeatureLevels == 0) { return false; } __try { // We don't want software renderer. Ideally we specify D3D_DRIVER_TYPE_HARDWARE on creation but // when we specify an adapter we need to specify D3D_DRIVER_TYPE_UNKNOWN (otherwise the call fails). // We cannot check the device type later (seems this is missing functionality in D3D). if(SUCCEEDED(D3D11CreateDevice( Adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, DeviceFlags, &RequestedFeatureLevels[FirstAllowedFeatureLevel], NumAllowedFeatureLevels, D3D11_SDK_VERSION, &D3DDevice, OutFeatureLevel, &D3DDeviceContext ))) { D3DDevice->Release(); D3DDeviceContext->Release(); return true; } } __except(IsDelayLoadException(GetExceptionInformation())) { } return false; }