Files
FlaxEngine/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp

730 lines
26 KiB
C++

// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
#if GRAPHICS_API_DIRECTX11
#include "GPUDeviceDX11.h"
#include "GPUShaderDX11.h"
#include "GPUContextDX11.h"
#include "GPUPipelineStateDX11.h"
#include "GPUTextureDX11.h"
#include "GPUTimerQueryDX11.h"
#include "GPUBufferDX11.h"
#include "GPUSamplerDX11.h"
#include "GPUSwapChainDX11.h"
#include "Engine/Core/Log.h"
#include "Engine/Core/Utilities.h"
#include "Engine/Threading/Threading.h"
#include "Engine/GraphicsDevice/DirectX/RenderToolsDX.h"
#include "Engine/Engine/CommandLine.h"
#if !USE_EDITOR && PLATFORM_WINDOWS
#include "Engine/Core/Config/PlatformSettings.h"
#endif
#define DX11_FORCE_USE_DX10 0
#define DX11_FORCE_USE_DX10_1 0
static bool TryCreateDevice(IDXGIAdapter* adapter, D3D_FEATURE_LEVEL maxFeatureLevel, D3D_FEATURE_LEVEL* featureLevel)
{
ID3D11Device* device = nullptr;
ID3D11DeviceContext* context = nullptr;
uint32 deviceFlags = D3D11_CREATE_DEVICE_SINGLETHREADED | D3D11_CREATE_DEVICE_BGRA_SUPPORT;
#if GPU_ENABLE_DIAGNOSTICS
deviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
// Pick the first level
D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0
};
int32 levelIndex = 0;
while (levelIndex < ARRAY_COUNT(featureLevels))
{
if (featureLevels[levelIndex] == maxFeatureLevel)
break;
levelIndex++;
}
if (levelIndex >= ARRAY_COUNT(featureLevels))
{
return false;
}
// Try to create device
if (SUCCEEDED(D3D11CreateDevice(
adapter,
D3D_DRIVER_TYPE_UNKNOWN,
NULL,
deviceFlags,
&featureLevels[levelIndex],
ARRAY_COUNT(featureLevels) - levelIndex,
D3D11_SDK_VERSION,
&device,
featureLevel,
&context
)))
{
device->Release();
context->Release();
return true;
}
return false;
}
GPUDevice* GPUDeviceDX11::Create()
{
// Configuration
#if DX11_FORCE_USE_DX10
D3D_FEATURE_LEVEL maxAllowedFeatureLevel = D3D_FEATURE_LEVEL_10_0;
#elif DX11_FORCE_USE_DX10_1
D3D_FEATURE_LEVEL maxAllowedFeatureLevel = D3D_FEATURE_LEVEL_10_1;
#else
D3D_FEATURE_LEVEL maxAllowedFeatureLevel = D3D_FEATURE_LEVEL_11_0;
#endif
if (CommandLine::Options.D3D10)
maxAllowedFeatureLevel = D3D_FEATURE_LEVEL_10_0;
else if (CommandLine::Options.D3D11)
maxAllowedFeatureLevel = D3D_FEATURE_LEVEL_11_0;
#if !USE_EDITOR && PLATFORM_WINDOWS
auto winSettings = WindowsPlatformSettings::Get();
if (!winSettings->SupportDX11 && !winSettings->SupportDX10)
{
// Skip if there is no support
LOG(Warning, "Cannot use DirectX (support disabled).");
return nullptr;
}
if (!winSettings->SupportDX11 && maxAllowedFeatureLevel == D3D_FEATURE_LEVEL_11_0)
{
// Downgrade if there is no SM5 support
maxAllowedFeatureLevel = D3D_FEATURE_LEVEL_10_0;
LOG(Warning, "Cannot use DirectX 11 (support disabled).");
}
if (!winSettings->SupportDX10 && maxAllowedFeatureLevel == D3D_FEATURE_LEVEL_10_0)
{
// Upgrade if there is no SM4 support
maxAllowedFeatureLevel = D3D_FEATURE_LEVEL_11_0;
LOG(Warning, "Cannot use DirectX 10 (support disabled).");
}
#endif
// Create DXGI factory
#if PLATFORM_WINDOWS
IDXGIFactory1* dxgiFactory;
HRESULT hr = CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory));
#else
IDXGIFactory2* dxgiFactory;
HRESULT hr = CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory));
#endif
if (hr != S_OK)
{
LOG(Error, "Cannot create DXGI adapter. Error code: {0:x}.", hr);
return nullptr;
}
// Enumerate the DXGIFactory's adapters
Array<GPUAdapterDX> adapters;
IDXGIAdapter* tmpAdapter;
for (uint32 index = 0; dxgiFactory->EnumAdapters(index, &tmpAdapter) != DXGI_ERROR_NOT_FOUND; index++)
{
GPUAdapterDX adapter;
if (tmpAdapter && TryCreateDevice(tmpAdapter, maxAllowedFeatureLevel, &adapter.MaxFeatureLevel))
{
adapter.Index = index;
VALIDATE_DIRECTX_RESULT(tmpAdapter->GetDesc(&adapter.Description));
uint32 outputs = RenderToolsDX::CountAdapterOutputs(tmpAdapter);
LOG(Info, "Adapter {1}: '{0}', DirectX {2}", adapter.Description.Description, index, RenderToolsDX::GetFeatureLevelString(adapter.MaxFeatureLevel));
LOG(Info, " Dedicated Video Memory: {0}, Dedicated System Memory: {1}, Shared System Memory: {2}, Output(s): {3}", Utilities::BytesToText(adapter.Description.DedicatedVideoMemory), Utilities::BytesToText(adapter.Description.DedicatedSystemMemory), Utilities::BytesToText(adapter.Description.SharedSystemMemory), outputs);
adapters.Add(adapter);
}
}
// Select the adapter to use
GPUAdapterDX selectedAdapter = adapters[0];
uint32 vendorId = 0;
if (CommandLine::Options.NVIDIA)
vendorId = GPU_VENDOR_ID_NVIDIA;
else if (CommandLine::Options.AMD)
vendorId = GPU_VENDOR_ID_AMD;
else if (CommandLine::Options.Intel)
vendorId = GPU_VENDOR_ID_INTEL;
if (vendorId != 0)
{
for (const auto& adapter : adapters)
{
if (adapter.GetVendorId() == vendorId)
{
selectedAdapter = adapter;
break;
}
}
}
// Validate adapter
if (!selectedAdapter.IsValid())
{
LOG(Error, "Failed to choose valid DirectX adapter!");
return nullptr;
}
// Create device
auto device = New<GPUDeviceDX11>(dxgiFactory, New<GPUAdapterDX>(selectedAdapter));
if (device->Init())
{
LOG(Warning, "Graphics Device init failed");
Delete(device);
return nullptr;
}
return device;
}
GPUDeviceDX11::GPUDeviceDX11(IDXGIFactory* dxgiFactory, GPUAdapterDX* adapter)
: GPUDeviceDX(getRendererType(adapter), getShaderProfile(adapter), adapter)
, _device(nullptr)
, _imContext(nullptr)
, _factoryDXGI(dxgiFactory)
, _mainContext(nullptr)
, _samplerLinearClamp(nullptr)
, _samplerPointClamp(nullptr)
, _samplerLinearWrap(nullptr)
, _samplerPointWrap(nullptr)
, _samplerShadow(nullptr)
, _samplerShadowPCF(nullptr)
{
Platform::MemoryClear(RasterizerStates, sizeof(RasterizerStates));
Platform::MemoryClear(DepthStencilStates, sizeof(DepthStencilStates));
}
ID3D11BlendState* GPUDeviceDX11::GetBlendState(const BlendingMode& blending)
{
// Use lookup
ID3D11BlendState* blendState = nullptr;
if (BlendStates.TryGet(blending, blendState))
return blendState;
// Make it safe
ScopeLock lock(BlendStatesWriteLocker);
// Try again to prevent race condition with double-adding the same thing
if (BlendStates.TryGet(blending, blendState))
return blendState;
// Prepare description
D3D11_BLEND_DESC desc;
desc.AlphaToCoverageEnable = blending.AlphaToCoverageEnable ? TRUE : FALSE;
desc.IndependentBlendEnable = FALSE;
desc.RenderTarget[0].BlendEnable = blending.BlendEnable ? TRUE : FALSE;
desc.RenderTarget[0].SrcBlend = (D3D11_BLEND)blending.SrcBlend;
desc.RenderTarget[0].DestBlend = (D3D11_BLEND)blending.DestBlend;
desc.RenderTarget[0].BlendOp = (D3D11_BLEND_OP)blending.BlendOp;
desc.RenderTarget[0].SrcBlendAlpha = (D3D11_BLEND)blending.SrcBlendAlpha;
desc.RenderTarget[0].DestBlendAlpha = (D3D11_BLEND)blending.DestBlendAlpha;
desc.RenderTarget[0].BlendOpAlpha = (D3D11_BLEND_OP)blending.BlendOpAlpha;
desc.RenderTarget[0].RenderTargetWriteMask = (UINT8)blending.RenderTargetWriteMask;
#if BUILD_DEBUG
for (byte i = 1; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++)
desc.RenderTarget[i] = desc.RenderTarget[0];
#endif
// Create object
VALIDATE_DIRECTX_RESULT(_device->CreateBlendState(&desc, &blendState));
// Cache blend state
BlendStates.Add(blending, blendState);
return blendState;
}
static MSAALevel GetMaximumMultisampleCount(ID3D11Device* device, DXGI_FORMAT dxgiFormat)
{
int32 maxCount = 1;
UINT numQualityLevels;
for (int32 i = 2; i <= 8; i *= 2)
{
if (SUCCEEDED(device->CheckMultisampleQualityLevels(dxgiFormat, i, &numQualityLevels)) && numQualityLevels > 0)
maxCount = i;
}
return static_cast<MSAALevel>(maxCount);
}
bool GPUDeviceDX11::Init()
{
HRESULT result;
// Get DXGI adapter
ComPtr<IDXGIAdapter> adapter;
if (_factoryDXGI->EnumAdapters(_adapter->Index, &adapter) == DXGI_ERROR_NOT_FOUND || adapter == nullptr)
{
LOG(Warning, "Cannot get the adapter.");
return true;
}
UpdateOutputs(adapter);
ComPtr<IDXGIFactory5> factory5;
_factoryDXGI->QueryInterface(IID_PPV_ARGS(&factory5));
if (factory5)
{
BOOL allowTearing;
if (SUCCEEDED(factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing, sizeof(allowTearing)))
&& allowTearing
#if PLATFORM_WINDOWS
&& GetModuleHandleA("renderdoc.dll") == nullptr // Disable tearing with RenderDoc (prevents crashing)
#endif
)
{
_allowTearing = true;
}
}
// Get flags and device type base on current configuration
uint32 flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
#if GPU_ENABLE_DIAGNOSTICS
flags |= D3D11_CREATE_DEVICE_DEBUG;
LOG(Info, "DirectX debugging layer enabled");
#endif
// Create DirectX device
D3D_FEATURE_LEVEL createdFeatureLevel = static_cast<D3D_FEATURE_LEVEL>(0);
auto targetFeatureLevel = GetD3DFeatureLevel();
VALIDATE_DIRECTX_RESULT(D3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, flags, &targetFeatureLevel, 1, D3D11_SDK_VERSION, &_device, &createdFeatureLevel, &_imContext));
// Validate result
ASSERT(_device);
ASSERT(_imContext);
ASSERT(createdFeatureLevel == targetFeatureLevel);
_state = DeviceState::Created;
// Init device limits
{
auto& limits = Limits;
if (createdFeatureLevel >= D3D_FEATURE_LEVEL_11_0)
{
D3D11_FEATURE_DATA_D3D10_X_HARDWARE_OPTIONS d3D10XHardwareOptions = {};
_device->CheckFeatureSupport(D3D11_FEATURE_D3D10_X_HARDWARE_OPTIONS, &d3D10XHardwareOptions, sizeof(d3D10XHardwareOptions));
D3D11_FEATURE_DATA_D3D11_OPTIONS2 featureDataD3D11Options2 = {};
_device->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS2, &featureDataD3D11Options2, sizeof(featureDataD3D11Options2));
limits.HasCompute = d3D10XHardwareOptions.ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x != 0;
limits.HasTessellation = true;
limits.HasGeometryShaders = true;
limits.HasInstancing = true;
limits.HasVolumeTextureRendering = true;
limits.HasDrawIndirect = true;
limits.HasAppendConsumeBuffers = true;
limits.HasSeparateRenderTargetBlendState = true;
limits.HasDepthAsSRV = true;
limits.HasReadOnlyDepth = true;
limits.HasMultisampleDepthAsSRV = true;
limits.HasTypedUAVLoad = featureDataD3D11Options2.TypedUAVLoadAdditionalFormats != 0;
limits.MaximumMipLevelsCount = D3D11_REQ_MIP_LEVELS;
limits.MaximumTexture1DSize = D3D11_REQ_TEXTURE1D_U_DIMENSION;
limits.MaximumTexture1DArraySize = D3D11_REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION;
limits.MaximumTexture2DSize = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
limits.MaximumTexture2DArraySize = D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION;
limits.MaximumTexture3DSize = D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION;
limits.MaximumTextureCubeSize = D3D11_REQ_TEXTURECUBE_DIMENSION;
limits.MaximumSamplerAnisotropy = D3D11_DEFAULT_MAX_ANISOTROPY;
}
else
{
limits.HasCompute = false;
limits.HasTessellation = false;
limits.HasGeometryShaders = true;
limits.HasInstancing = true;
limits.HasVolumeTextureRendering = false;
limits.HasDrawIndirect = false;
limits.HasAppendConsumeBuffers = false;
limits.HasSeparateRenderTargetBlendState = false;
limits.HasDepthAsSRV = false;
limits.HasReadOnlyDepth = createdFeatureLevel == D3D_FEATURE_LEVEL_10_1;
limits.HasMultisampleDepthAsSRV = false;
limits.HasTypedUAVLoad = false;
limits.MaximumMipLevelsCount = D3D10_REQ_MIP_LEVELS;
limits.MaximumTexture1DSize = D3D10_REQ_TEXTURE1D_U_DIMENSION;
limits.MaximumTexture1DArraySize = D3D10_REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION;
limits.MaximumTexture2DSize = D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION;
limits.MaximumTexture2DArraySize = D3D10_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION;
limits.MaximumTexture3DSize = D3D10_REQ_TEXTURE3D_U_V_OR_W_DIMENSION;
limits.MaximumTextureCubeSize = D3D10_REQ_TEXTURECUBE_DIMENSION;
limits.MaximumSamplerAnisotropy = D3D10_DEFAULT_MAX_ANISOTROPY;
}
for (int32 i = 0; i < static_cast<int32>(PixelFormat::MAX); i++)
{
auto format = static_cast<PixelFormat>(i);
auto dxgiFormat = RenderToolsDX::ToDxgiFormat(format);
auto maximumMultisampleCount = GetMaximumMultisampleCount(_device, dxgiFormat);
UINT formatSupport = 0;
_device->CheckFormatSupport(dxgiFormat, &formatSupport);
FeaturesPerFormat[i] = FormatFeatures(format, maximumMultisampleCount, (FormatSupport)formatSupport);
}
}
// Init debug layer
#if GPU_ENABLE_DIAGNOSTICS
ComPtr<ID3D11InfoQueue> infoQueue;
VALIDATE_DIRECTX_RESULT(_device->QueryInterface(IID_PPV_ARGS(&infoQueue)));
if (infoQueue)
{
D3D11_INFO_QUEUE_FILTER filter;
Platform::MemoryClear(&filter, sizeof(filter));
D3D11_MESSAGE_SEVERITY denySeverity = D3D11_MESSAGE_SEVERITY_INFO;
filter.DenyList.NumSeverities = 1;
filter.DenyList.pSeverityList = &denySeverity;
D3D11_MESSAGE_ID disabledMessages[] =
{
D3D11_MESSAGE_ID_OMSETRENDERTARGETS_INVALIDVIEW,
D3D11_MESSAGE_ID_QUERY_BEGIN_ABANDONING_PREVIOUS_RESULTS,
D3D11_MESSAGE_ID_QUERY_END_ABANDONING_PREVIOUS_RESULTS,
D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_EMPTY_LAYOUT,
D3D11_MESSAGE_ID_DEVICE_DRAW_INDEX_BUFFER_TOO_SMALL,
D3D11_MESSAGE_ID_DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET,
D3D11_MESSAGE_ID_SETPRIVATEDATA_CHANGINGPARAMS,
};
filter.DenyList.NumIDs = ARRAY_COUNT(disabledMessages);
filter.DenyList.pIDList = disabledMessages;
infoQueue->PushStorageFilter(&filter);
infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, TRUE);
infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, TRUE);
//infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_WARNING, TRUE);
}
#endif
// Create main context from Immediate Context
_mainContext = New<GPUContextDX11>(this, _imContext);
// Static Samplers
{
D3D11_SAMPLER_DESC samplerDesc;
Platform::MemoryClear(&samplerDesc, sizeof(samplerDesc));
// Linear Clamp
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.MinLOD = 0;
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
result = _device->CreateSamplerState(&samplerDesc, &_samplerLinearClamp);
LOG_DIRECTX_RESULT_WITH_RETURN(result);
// Point Clamp
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.MinLOD = 0;
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
result = _device->CreateSamplerState(&samplerDesc, &_samplerPointClamp);
LOG_DIRECTX_RESULT_WITH_RETURN(result);
// Linear Wrap
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.MinLOD = 0;
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
result = _device->CreateSamplerState(&samplerDesc, &_samplerLinearWrap);
LOG_DIRECTX_RESULT_WITH_RETURN(result);
// Point Wrap
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.MinLOD = 0;
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
result = _device->CreateSamplerState(&samplerDesc, &_samplerPointWrap);
LOG_DIRECTX_RESULT_WITH_RETURN(result);
// Shadow
samplerDesc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_MIP_POINT;
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.MipLODBias = 0.0f;
samplerDesc.MaxAnisotropy = 1;
samplerDesc.ComparisonFunc = D3D11_COMPARISON_LESS_EQUAL;
samplerDesc.MinLOD = 0;
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
result = _device->CreateSamplerState(&samplerDesc, &_samplerShadow);
LOG_DIRECTX_RESULT_WITH_RETURN(result);
// Shadow PCF
samplerDesc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR;
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.MipLODBias = 0.0f;
samplerDesc.MaxAnisotropy = 1;
samplerDesc.ComparisonFunc = D3D11_COMPARISON_LESS_EQUAL;
samplerDesc.BorderColor[0] = samplerDesc.BorderColor[1] = samplerDesc.BorderColor[2] = samplerDesc.BorderColor[3] = 0;
samplerDesc.MinLOD = 0;
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
result = _device->CreateSamplerState(&samplerDesc, &_samplerShadowPCF);
LOG_DIRECTX_RESULT_WITH_RETURN(result);
}
// Rasterizer States
{
D3D11_RASTERIZER_DESC rDesc;
rDesc.ScissorEnable = TRUE;
rDesc.MultisampleEnable = TRUE;
rDesc.FrontCounterClockwise = FALSE;
rDesc.DepthBias = 0;
rDesc.DepthBiasClamp = 0.0f;
rDesc.SlopeScaledDepthBias = 0.0f;
int32 index;
#define CREATE_RASTERIZER_STATE(cullMode, dxCullMode, wireframe, depthClip) \
index = (int32)cullMode + (wireframe ? 0 : 3) + (depthClip ? 0 : 6); \
rDesc.CullMode = dxCullMode; \
rDesc.FillMode = wireframe ? D3D11_FILL_WIREFRAME : D3D11_FILL_SOLID; \
rDesc.AntialiasedLineEnable = !!wireframe; \
rDesc.DepthClipEnable = !!depthClip; \
result = _device->CreateRasterizerState(&rDesc, &RasterizerStates[index]); \
LOG_DIRECTX_RESULT_WITH_RETURN(result)
CREATE_RASTERIZER_STATE(CullMode::Normal, D3D11_CULL_BACK, false, false);
CREATE_RASTERIZER_STATE(CullMode::Inverted, D3D11_CULL_FRONT, false, false);
CREATE_RASTERIZER_STATE(CullMode::TwoSided, D3D11_CULL_NONE, false, false);
CREATE_RASTERIZER_STATE(CullMode::Normal, D3D11_CULL_BACK, true, false);
CREATE_RASTERIZER_STATE(CullMode::Inverted, D3D11_CULL_FRONT, true, false);
CREATE_RASTERIZER_STATE(CullMode::TwoSided, D3D11_CULL_NONE, true, false);
//
CREATE_RASTERIZER_STATE(CullMode::Normal, D3D11_CULL_BACK, false, true);
CREATE_RASTERIZER_STATE(CullMode::Inverted, D3D11_CULL_FRONT, false, true);
CREATE_RASTERIZER_STATE(CullMode::TwoSided, D3D11_CULL_NONE, false, true);
CREATE_RASTERIZER_STATE(CullMode::Normal, D3D11_CULL_BACK, true, true);
CREATE_RASTERIZER_STATE(CullMode::Inverted, D3D11_CULL_FRONT, true, true);
CREATE_RASTERIZER_STATE(CullMode::TwoSided, D3D11_CULL_NONE, true, true);
#undef CREATE_RASTERIZER_STATE
}
// Depth Stencil States
{
D3D11_DEPTH_STENCIL_DESC dsDesc;
dsDesc.StencilEnable = FALSE;
dsDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
dsDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
const D3D11_DEPTH_STENCILOP_DESC defaultStencilOp = { D3D11_STENCIL_OP_KEEP, D3D11_STENCIL_OP_KEEP, D3D11_STENCIL_OP_KEEP, D3D11_COMPARISON_ALWAYS };
dsDesc.FrontFace = defaultStencilOp;
dsDesc.BackFace = defaultStencilOp;
int32 index;
#define CREATE_DEPTH_STENCIL_STATE(depthEnable, depthWrite) \
dsDesc.DepthEnable = depthEnable; \
dsDesc.DepthWriteMask = depthWrite ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; \
for(int32 depthFunc = 1; depthFunc <= 8; depthFunc++) { \
dsDesc.DepthFunc = (D3D11_COMPARISON_FUNC)depthFunc; \
index = (int32)depthFunc + (depthEnable ? 0 : 9) + (depthWrite ? 0 : 18); \
HRESULT result = _device->CreateDepthStencilState(&dsDesc, &DepthStencilStates[index]); \
LOG_DIRECTX_RESULT_WITH_RETURN(result); }
CREATE_DEPTH_STENCIL_STATE(false, false);
CREATE_DEPTH_STENCIL_STATE(false, true);
CREATE_DEPTH_STENCIL_STATE(true, true);
CREATE_DEPTH_STENCIL_STATE(true, false);
#undef CREATE_DEPTH_STENCIL_STATE
}
_state = DeviceState::Ready;
return GPUDeviceDX::Init();
}
GPUDeviceDX11::~GPUDeviceDX11()
{
// Ensure to be disposed
GPUDeviceDX11::Dispose();
}
GPUDevice* CreateGPUDeviceDX11()
{
return GPUDeviceDX11::Create();
}
void GPUDeviceDX11::Dispose()
{
GPUDeviceLock lock(this);
// Check if has been disposed already
if (_state == DeviceState::Disposed)
return;
// Set current state
_state = DeviceState::Disposing;
// Wait for rendering end
WaitForGPU();
// Pre dispose
preDispose();
// Clear device resources
SAFE_RELEASE(_samplerLinearClamp);
SAFE_RELEASE(_samplerPointClamp);
SAFE_RELEASE(_samplerLinearWrap);
SAFE_RELEASE(_samplerPointWrap);
SAFE_RELEASE(_samplerShadow);
SAFE_RELEASE(_samplerShadowPCF);
//
for (auto i = BlendStates.Begin(); i.IsNotEnd(); ++i)
{
i->Value->Release();
}
BlendStates.Clear();
for (uint32 i = 0; i < ARRAY_COUNT(RasterizerStates); i++)
{
SAFE_RELEASE(RasterizerStates[i]);
}
for (uint32 i = 0; i < ARRAY_COUNT(DepthStencilStates); i++)
{
SAFE_RELEASE(DepthStencilStates[i]);
}
// Clear DirectX stuff
SAFE_DELETE(_mainContext);
SAFE_DELETE(_adapter);
SAFE_RELEASE(_imContext);
#if GPU_ENABLE_DIAGNOSTICS && 0
ID3D11Debug* debugLayer = nullptr;
_device->QueryInterface(IID_PPV_ARGS(&debugLayer));
if (debugLayer)
{
// Report any DirectX object leaks
debugLayer->ReportLiveDeviceObjects(D3D11_RLDO_DETAIL | D3D11_RLDO_IGNORE_INTERNAL);
debugLayer->Release();
}
#endif
SAFE_RELEASE(_device);
SAFE_RELEASE(_factoryDXGI);
// Base
GPUDeviceDX::Dispose();
// Set current state
_state = DeviceState::Disposed;
}
void GPUDeviceDX11::WaitForGPU()
{
// In DirectX 11 driver manages CPU/GPU work synchronization and work submission
}
void GPUDeviceDX11::DrawEnd()
{
GPUDeviceDX::DrawEnd();
#if GPU_ENABLE_DIAGNOSTICS
// Flush debug messages queue
ComPtr<ID3D11InfoQueue> infoQueue;
VALIDATE_DIRECTX_RESULT(_device->QueryInterface(IID_PPV_ARGS(&infoQueue)));
if (infoQueue)
{
Array<uint8> data;
const uint64 messagesCount = infoQueue->GetNumStoredMessagesAllowedByRetrievalFilter();
for (uint64 i = 0; i < messagesCount; i++)
{
SIZE_T length = 0;
if (SUCCEEDED(infoQueue->GetMessage(i, nullptr, &length)))
{
data.Resize((int32)length);
auto messageData = (D3D11_MESSAGE*)data.Get();
if (SUCCEEDED(infoQueue->GetMessage(i, messageData, &length)))
{
LogType logType;
switch (messageData->Severity)
{
case D3D11_MESSAGE_SEVERITY_CORRUPTION:
logType = LogType::Fatal;
break;
case D3D11_MESSAGE_SEVERITY_ERROR:
logType = LogType::Error;
break;
case D3D11_MESSAGE_SEVERITY_WARNING:
logType = LogType::Warning;
break;
case D3D11_MESSAGE_SEVERITY_INFO:
case D3D11_MESSAGE_SEVERITY_MESSAGE:
default:
logType = LogType::Info;
break;
}
Log::Logger::Write(logType, String(messageData->pDescription));
}
}
}
infoQueue->ClearStoredMessages();
}
#endif
}
GPUTexture* GPUDeviceDX11::CreateTexture(const StringView& name)
{
return New<GPUTextureDX11>(this, name);
}
GPUShader* GPUDeviceDX11::CreateShader(const StringView& name)
{
return New<GPUShaderDX11>(this, name);
}
GPUPipelineState* GPUDeviceDX11::CreatePipelineState()
{
return New<GPUPipelineStateDX11>(this);
}
GPUTimerQuery* GPUDeviceDX11::CreateTimerQuery()
{
return New<GPUTimerQueryDX11>(this);
}
GPUBuffer* GPUDeviceDX11::CreateBuffer(const StringView& name)
{
return New<GPUBufferDX11>(this, name);
}
GPUSampler* GPUDeviceDX11::CreateSampler()
{
return New<GPUSamplerDX11>(this);
}
GPUSwapChain* GPUDeviceDX11::CreateSwapChain(Window* window)
{
return New<GPUSwapChainDX11>(this, window);
}
GPUConstantBuffer* GPUDeviceDX11::CreateConstantBuffer(uint32 size, const StringView& name)
{
ID3D11Buffer* buffer = nullptr;
uint32 memorySize = 0;
if (size)
{
// Create buffer
D3D11_BUFFER_DESC cbDesc;
cbDesc.ByteWidth = Math::AlignUp<uint32>(size, 16);
cbDesc.Usage = D3D11_USAGE_DEFAULT;
cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
cbDesc.CPUAccessFlags = 0;
cbDesc.MiscFlags = 0;
cbDesc.StructureByteStride = 0;
const HRESULT result = _device->CreateBuffer(&cbDesc, nullptr, &buffer);
if (FAILED(result))
{
LOG_DIRECTX_RESULT(result);
return nullptr;
}
memorySize = cbDesc.ByteWidth;
}
return New<GPUConstantBufferDX11>(this, size, memorySize, buffer, name);
}
#endif