You're breathtaking!

This commit is contained in:
Wojtek Figat
2020-12-07 23:40:54 +01:00
commit 6fb9eee74c
5143 changed files with 1153594 additions and 0 deletions

View File

@@ -0,0 +1,165 @@
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
#if GRAPHICS_API_DIRECTX11
#include "GPUBufferDX11.h"
#include "../RenderToolsDX.h"
#include "Engine/Graphics/PixelFormatExtensions.h"
#include "Engine/Threading/Threading.h"
GPUBufferDX11::GPUBufferDX11(GPUDeviceDX11* device, const StringView& name)
: GPUResourceDX11(device, name)
{
}
GPUBufferView* GPUBufferDX11::View() const
{
return (GPUBufferView*)&_view;
}
void* GPUBufferDX11::Map(GPUResourceMapMode mode)
{
if (!IsInMainThread())
_device->Locker.Lock();
D3D11_MAPPED_SUBRESOURCE map;
map.pData = nullptr;
D3D11_MAP mapType;
switch (mode)
{
case GPUResourceMapMode::Read:
mapType = D3D11_MAP_READ;
break;
case GPUResourceMapMode::Write:
mapType = D3D11_MAP_WRITE_DISCARD;
break;
case GPUResourceMapMode::ReadWrite:
mapType = D3D11_MAP_READ_WRITE;
break;
default:
CRASH;
return nullptr;
}
const HRESULT result = _device->GetIM()->Map(_resource, 0, mapType, 0, &map);
LOG_DIRECTX_RESULT(result);
return map.pData;
}
void GPUBufferDX11::Unmap()
{
_device->GetIM()->Unmap(_resource, 0);
if (!IsInMainThread())
_device->Locker.Unlock();
}
bool GPUBufferDX11::OnInit()
{
bool useSRV = IsShaderResource();
bool useUAV = IsUnorderedAccess();
// Create buffer description
D3D11_BUFFER_DESC bufferDesc;
bufferDesc.ByteWidth = _desc.Size;
bufferDesc.Usage = RenderToolsDX::ToD3D11Usage(_desc.Usage);
bufferDesc.BindFlags = 0;
bufferDesc.CPUAccessFlags = RenderToolsDX::GetDX11CpuAccessFlagsFromUsage(_desc.Usage);
bufferDesc.MiscFlags = 0;
bufferDesc.StructureByteStride = 0;
//
if (_desc.Flags & GPUBufferFlags::VertexBuffer)
bufferDesc.BindFlags |= D3D11_BIND_VERTEX_BUFFER;
if (_desc.Flags & GPUBufferFlags::IndexBuffer)
bufferDesc.BindFlags |= D3D11_BIND_INDEX_BUFFER;
if (useSRV)
bufferDesc.BindFlags |= D3D11_BIND_SHADER_RESOURCE;
if (useUAV)
bufferDesc.BindFlags |= D3D11_BIND_UNORDERED_ACCESS;
//
if (_desc.Flags & GPUBufferFlags::Argument)
bufferDesc.MiscFlags |= D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS;
if (_desc.Flags & GPUBufferFlags::RawBuffer)
bufferDesc.MiscFlags |= D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS;
if (_desc.Flags & GPUBufferFlags::Structured)
{
bufferDesc.MiscFlags |= D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
bufferDesc.StructureByteStride = _desc.Stride;
}
// Create resource
D3D11_SUBRESOURCE_DATA data;
if (_desc.InitData)
{
data.pSysMem = _desc.InitData;
data.SysMemPitch = bufferDesc.ByteWidth;
data.SysMemSlicePitch = 0;
}
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateBuffer(&bufferDesc, _desc.InitData ? &data : nullptr, &_resource));
// Set state
DX_SET_DEBUG_NAME(_resource, GetName());
_memoryUsage = _desc.Size;
int32 numElements = _desc.GetElementsCount();
// Create views
if (useSRV)
{
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
if (_desc.Flags & GPUBufferFlags::RawBuffer)
{
srvDesc.Format = DXGI_FORMAT_R32_TYPELESS;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFEREX;
srvDesc.BufferEx.FirstElement = 0;
srvDesc.BufferEx.NumElements = numElements;
srvDesc.BufferEx.Flags = D3D11_BUFFEREX_SRV_FLAG_RAW;
}
else
{
if (_desc.Flags & GPUBufferFlags::Structured)
srvDesc.Format = DXGI_FORMAT_UNKNOWN;
else
srvDesc.Format = RenderToolsDX::ToDxgiFormat(PixelFormatExtensions::FindShaderResourceFormat(_desc.Format, false));
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
srvDesc.Buffer.FirstElement = 0;
srvDesc.Buffer.NumElements = numElements;
}
ID3D11ShaderResourceView* srv;
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateShaderResourceView(_resource, &srvDesc, &srv));
_view.SetSRV(srv);
}
if (useUAV)
{
D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc;
uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
uavDesc.Buffer.FirstElement = 0;
uavDesc.Buffer.NumElements = numElements;
uavDesc.Buffer.Flags = 0;
if (_desc.Flags & GPUBufferFlags::RawBuffer)
uavDesc.Buffer.Flags |= D3D11_BUFFER_UAV_FLAG_RAW;
if (_desc.Flags & GPUBufferFlags::Append)
uavDesc.Buffer.Flags |= D3D11_BUFFER_UAV_FLAG_APPEND;
if (_desc.Flags & GPUBufferFlags::Counter)
uavDesc.Buffer.Flags |= D3D11_BUFFER_UAV_FLAG_COUNTER;
if (_desc.Flags & GPUBufferFlags::Structured)
uavDesc.Format = DXGI_FORMAT_UNKNOWN;
else
uavDesc.Format = RenderToolsDX::ToDxgiFormat(PixelFormatExtensions::FindUnorderedAccessFormat(_desc.Format));
ID3D11UnorderedAccessView* uav;
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateUnorderedAccessView(_resource, &uavDesc, &uav));
_view.SetUAV(uav);
}
return false;
}
void GPUBufferDX11::OnReleaseGPU()
{
_view.Release();
DX_SAFE_RELEASE_CHECK(_resource, 0);
// Base
GPUBuffer::OnReleaseGPU();
}
#endif

View File

@@ -0,0 +1,145 @@
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
#pragma once
#if GRAPHICS_API_DIRECTX11
#include "Engine/Graphics/GPUBuffer.h"
#include "GPUDeviceDX11.h"
#include "../IncludeDirectXHeaders.h"
#include "IShaderResourceDX11.h"
/// <summary>
/// The buffer view for DirectX 11 backend.
/// </summary>
/// <seealso cref="GPUBufferView" />
/// <seealso cref="IShaderResourceDX11" />
class GPUBufferViewDX11 : public GPUBufferView, public IShaderResourceDX11
{
private:
ID3D11ShaderResourceView* _srv = nullptr;
ID3D11UnorderedAccessView* _uav = nullptr;
public:
/// <summary>
/// Initializes a new instance of the <see cref="GPUBufferViewDX11"/> class.
/// </summary>
GPUBufferViewDX11()
{
}
/// <summary>
/// Finalizes an instance of the <see cref="GPUBufferViewDX11"/> class.
/// </summary>
~GPUBufferViewDX11()
{
Release();
}
public:
/// <summary>
/// Release the view.
/// </summary>
void Release()
{
DX_SAFE_RELEASE_CHECK(_srv, 0);
DX_SAFE_RELEASE_CHECK(_uav, 0);
}
public:
/// <summary>
/// Sets new shader resource view.
/// </summary>
/// <param name="srv">A new shader resource view.</param>
void SetSRV(ID3D11ShaderResourceView* srv)
{
DX_SAFE_RELEASE_CHECK(_srv, 0);
_srv = srv;
}
/// <summary>
/// Sets new unordered access view.
/// </summary>
/// <param name="uav">A new unordered access view.</param>
void SetUAV(ID3D11UnorderedAccessView* uav)
{
DX_SAFE_RELEASE_CHECK(_uav, 0);
_uav = uav;
}
public:
// [GPUResourceView]
void* GetNativePtr() const override
{
return (void*)(IShaderResourceDX11*)this;
}
// [IShaderResourceDX11]
ID3D11ShaderResourceView* SRV() const override
{
return _srv;
}
ID3D11UnorderedAccessView* UAV() const override
{
return _uav;
}
};
/// <summary>
/// GPU buffer for DirectX 11 backend.
/// </summary>
/// <seealso cref="GPUResourceDX11" />
class GPUBufferDX11 : public GPUResourceDX11<GPUBuffer>
{
private:
ID3D11Buffer* _resource = nullptr;
GPUBufferViewDX11 _view;
public:
/// <summary>
/// Initializes a new instance of the <see cref="GPUBufferDX11"/> class.
/// </summary>
/// <param name="device">The graphics device.</param>
/// <param name="name">The resource name.</param>
GPUBufferDX11(GPUDeviceDX11* device, const StringView& name);
public:
/// <summary>
/// Gets DirectX 11 buffer object handle
/// </summary>
/// <returns>Buffer</returns>
FORCE_INLINE ID3D11Buffer* GetBuffer() const
{
return _resource;
}
public:
// [GPUBuffer]
GPUBufferView* View() const override;
void* Map(GPUResourceMapMode mode) override;
void Unmap() override;
// [GPUResourceDX11]
ID3D11Resource* GetResource() override
{
return _resource;
}
protected:
// [GPUBuffer]
bool OnInit() override;
void OnReleaseGPU() override;
};
#endif

View File

@@ -0,0 +1,880 @@
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
#include "GPUShaderDX11.h"
#if GRAPHICS_API_DIRECTX11
#include "GPUContextDX11.h"
#include "Engine/Core/Math/Viewport.h"
#include "Engine/Core/Math/Rectangle.h"
#include "GPUShaderProgramDX11.h"
#include "GPUPipelineStateDX11.h"
#include "GPUTextureDX11.h"
#include "GPUBufferDX11.h"
#include "Engine/GraphicsDevice/DirectX/RenderToolsDX.h"
#include "Engine/Profiler/RenderStats.h"
#define DX11_CLEAR_SR_ON_STAGE_DISABLE 0
#if DX11_CLEAR_SR_ON_STAGE_DISABLE
ID3D11ShaderResourceView* EmptySRHandles[GPU_MAX_SR_BINDED] = {};
#endif
// Ensure to match the indirect commands arguments layout
static_assert(sizeof(GPUDispatchIndirectArgs) == sizeof(uint32) * 3, "Wrong size of GPUDrawIndirectArgs.");
static_assert(OFFSET_OF(GPUDispatchIndirectArgs, ThreadGroupCountX) == sizeof(uint32) * 0, "Wrong offset for GPUDrawIndirectArgs::ThreadGroupCountX");
static_assert(OFFSET_OF(GPUDispatchIndirectArgs, ThreadGroupCountY) == sizeof(uint32) * 1,"Wrong offset for GPUDrawIndirectArgs::ThreadGroupCountY");
static_assert(OFFSET_OF(GPUDispatchIndirectArgs, ThreadGroupCountZ) == sizeof(uint32) * 2, "Wrong offset for GPUDrawIndirectArgs::ThreadGroupCountZ");
//
static_assert(sizeof(GPUDrawIndirectArgs) == sizeof(D3D11_DRAW_INSTANCED_INDIRECT_ARGS), "Wrong size of GPUDrawIndirectArgs.");
static_assert(OFFSET_OF(GPUDrawIndirectArgs, VerticesCount) == OFFSET_OF(D3D11_DRAW_INSTANCED_INDIRECT_ARGS, VertexCountPerInstance), "Wrong offset for GPUDrawIndirectArgs::VerticesCount");
static_assert(OFFSET_OF(GPUDrawIndirectArgs, InstanceCount) == OFFSET_OF(D3D11_DRAW_INSTANCED_INDIRECT_ARGS, InstanceCount),"Wrong offset for GPUDrawIndirectArgs::InstanceCount");
static_assert(OFFSET_OF(GPUDrawIndirectArgs, StartVertex) == OFFSET_OF(D3D11_DRAW_INSTANCED_INDIRECT_ARGS, StartVertexLocation), "Wrong offset for GPUDrawIndirectArgs::StartVertex");
static_assert(OFFSET_OF(GPUDrawIndirectArgs, StartInstance) == OFFSET_OF(D3D11_DRAW_INSTANCED_INDIRECT_ARGS, StartInstanceLocation), "Wrong offset for GPUDrawIndirectArgs::StartInstance");
//
static_assert(sizeof(GPUDrawIndexedIndirectArgs) == sizeof(D3D11_DRAW_INDEXED_INSTANCED_INDIRECT_ARGS), "Wrong size of GPUDrawIndexedIndirectArgs.");
static_assert(OFFSET_OF(GPUDrawIndexedIndirectArgs, IndicesCount) == OFFSET_OF(D3D11_DRAW_INDEXED_INSTANCED_INDIRECT_ARGS, IndexCountPerInstance), "Wrong offset for GPUDrawIndexedIndirectArgs::IndicesCount");
static_assert(OFFSET_OF(GPUDrawIndexedIndirectArgs, InstanceCount) == OFFSET_OF(D3D11_DRAW_INDEXED_INSTANCED_INDIRECT_ARGS, InstanceCount),"Wrong offset for GPUDrawIndexedIndirectArgs::InstanceCount");
static_assert(OFFSET_OF(GPUDrawIndexedIndirectArgs, StartIndex) == OFFSET_OF(D3D11_DRAW_INDEXED_INSTANCED_INDIRECT_ARGS, StartIndexLocation), "Wrong offset for GPUDrawIndexedIndirectArgs::StartIndex");
static_assert(OFFSET_OF(GPUDrawIndexedIndirectArgs, StartVertex) == OFFSET_OF(D3D11_DRAW_INDEXED_INSTANCED_INDIRECT_ARGS, BaseVertexLocation), "Wrong offset for GPUDrawIndexedIndirectArgs::StartVertex");
static_assert(OFFSET_OF(GPUDrawIndexedIndirectArgs, StartInstance) == OFFSET_OF(D3D11_DRAW_INDEXED_INSTANCED_INDIRECT_ARGS, StartInstanceLocation), "Wrong offset for GPUDrawIndexedIndirectArgs::StartInstance");
GPUContextDX11::GPUContextDX11(GPUDeviceDX11* device, ID3D11DeviceContext* context)
: GPUContext(device)
, _device(device)
, _context(context)
#if GPU_ALLOW_PROFILE_EVENTS
, _userDefinedAnnotations(nullptr)
#endif
, _omDirtyFlag(false)
, _rtCount(0)
, _rtDepth(nullptr)
, _uaOutput(nullptr)
, _srDirtyFlag(false)
, _uaDirtyFlag(false)
, _cbDirtyFlag(false)
, _currentState(nullptr)
{
ASSERT(_context);
#if GPU_ALLOW_PROFILE_EVENTS
_context->QueryInterface(IID_PPV_ARGS(&_userDefinedAnnotations));
#endif
// Only DirectX 11 supports more than 1 UAV
_maxUASlotsForCS = GPU_MAX_UA_BINDED;
if (_device->GetRendererType() != RendererType::DirectX11)
_maxUASlotsForCS = 1;
}
GPUContextDX11::~GPUContextDX11()
{
#if GPU_ALLOW_PROFILE_EVENTS
SAFE_RELEASE(_userDefinedAnnotations);
#endif
}
void GPUContextDX11::FrameBegin()
{
// Base
GPUContext::FrameBegin();
// Setup
_omDirtyFlag = false;
_uaDirtyFlag = false;
_srDirtyFlag = false;
_cbDirtyFlag = false;
_rtCount = 0;
_currentState = nullptr;
_rtDepth = nullptr;
_uaOutput = nullptr;
Platform::MemoryClear(_rtHandles, sizeof(_rtHandles));
Platform::MemoryClear(_srHandles, sizeof(_srHandles));
Platform::MemoryClear(_uaHandles, sizeof(_uaHandles));
Platform::MemoryClear(_cbHandles, sizeof(_cbHandles));
Platform::MemoryClear(_vbHandles, sizeof(_vbHandles));
Platform::MemoryClear(_vbStrides, sizeof(_vbStrides));
Platform::MemoryClear(_vbOffsets, sizeof(_vbOffsets));
_ibHandle = nullptr;
CurrentBlendState = nullptr;
CurrentRasterizerState = nullptr;
CurrentDepthStencilState = nullptr;
CurrentVS = nullptr;
CurrentHS = nullptr;
CurrentDS = nullptr;
CurrentGS = nullptr;
CurrentPS = nullptr;
CurrentCS = nullptr;
CurrentPrimitiveTopology = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED;
// Bind static samplers
ID3D11SamplerState* samplers[] =
{
_device->_samplerLinearClamp,
_device->_samplerPointClamp,
_device->_samplerLinearWrap,
_device->_samplerPointWrap,
_device->_samplerShadow,
_device->_samplerShadowPCF
};
_context->VSSetSamplers(0, ARRAY_COUNT(samplers), samplers);
_context->DSSetSamplers(0, ARRAY_COUNT(samplers), samplers);
_context->PSSetSamplers(0, ARRAY_COUNT(samplers), samplers);
_context->CSSetSamplers(0, ARRAY_COUNT(samplers), samplers); // TODO: maybe we don't want to bind those static sampler always?
}
#if GPU_ALLOW_PROFILE_EVENTS
void GPUContextDX11::EventBegin(const Char* name)
{
if (_userDefinedAnnotations)
_userDefinedAnnotations->BeginEvent(name);
}
void GPUContextDX11::EventEnd()
{
if (_userDefinedAnnotations)
_userDefinedAnnotations->EndEvent();
}
#endif
void* GPUContextDX11::GetNativePtr() const
{
return (void*)_context;
}
bool GPUContextDX11::IsDepthBufferBinded()
{
return _rtDepth != nullptr;
}
void GPUContextDX11::Clear(GPUTextureView* rt, const Color& color)
{
auto rtDX11 = static_cast<GPUTextureViewDX11*>(rt);
if (rtDX11)
{
_context->ClearRenderTargetView(rtDX11->RTV(), color.Raw);
}
}
void GPUContextDX11::ClearDepth(GPUTextureView* depthBuffer, float depthValue)
{
auto depthBufferDX11 = static_cast<GPUTextureViewDX11*>(depthBuffer);
if (depthBufferDX11)
{
ASSERT(depthBufferDX11->DSV());
_context->ClearDepthStencilView(depthBufferDX11->DSV(), D3D11_CLEAR_DEPTH, depthValue, 0xff);
}
}
void GPUContextDX11::ClearUA(GPUBuffer* buf, const Vector4& value)
{
ASSERT(buf != nullptr && buf->IsUnorderedAccess());
auto uav = ((GPUBufferViewDX11*)buf->View())->UAV();
_context->ClearUnorderedAccessViewFloat(uav, value.Raw);
}
void GPUContextDX11::ResetRenderTarget()
{
if (_rtCount > 0 || _uaOutput || _rtDepth)
{
_omDirtyFlag = true;
_rtCount = 0;
_rtDepth = nullptr;
_uaOutput = nullptr;
Platform::MemoryClear(_rtHandles, sizeof(_rtHandles));
flushOM();
}
}
void GPUContextDX11::SetRenderTarget(GPUTextureView* rt)
{
auto rtDX11 = reinterpret_cast<GPUTextureViewDX11*>(rt);
ID3D11RenderTargetView* rtv = rtDX11 ? rtDX11->RTV() : nullptr;
int32 newRtCount = rtv ? 1 : 0;
if (_rtCount != newRtCount || _rtHandles[0] != rtv || _rtDepth != nullptr || _uaOutput)
{
_omDirtyFlag = true;
_rtCount = newRtCount;
_rtDepth = nullptr;
_rtHandles[0] = rtv;
_uaOutput = nullptr;
}
}
void GPUContextDX11::SetRenderTarget(GPUTextureView* depthBuffer, GPUTextureView* rt)
{
auto rtDX11 = reinterpret_cast<GPUTextureViewDX11*>(rt);
auto depthBufferDX11 = static_cast<GPUTextureViewDX11*>(depthBuffer);
ID3D11RenderTargetView* rtv = rtDX11 ? rtDX11->RTV() : nullptr;
ID3D11DepthStencilView* dsv = depthBufferDX11 ? depthBufferDX11->DSV() : nullptr;
int32 newRtCount = rtv ? 1 : 0;
if (_rtCount != newRtCount || _rtHandles[0] != rtv || _rtDepth != dsv || _uaOutput)
{
_omDirtyFlag = true;
_rtCount = newRtCount;
_rtDepth = dsv;
_rtHandles[0] = rtv;
_uaOutput = nullptr;
}
}
void GPUContextDX11::SetRenderTarget(GPUTextureView* depthBuffer, const Span<GPUTextureView*>& rts)
{
ASSERT(Math::IsInRange(rts.Length(), 1, GPU_MAX_RT_BINDED));
auto depthBufferDX11 = static_cast<GPUTextureViewDX11*>(depthBuffer);
ID3D11DepthStencilView* dsv = depthBufferDX11 ? depthBufferDX11->DSV() : nullptr;
ID3D11RenderTargetView* rtvs[GPU_MAX_RT_BINDED];
for (int32 i = 0; i < rts.Length(); i++)
{
auto rtDX11 = reinterpret_cast<GPUTextureViewDX11*>(rts[i]);
rtvs[i] = rtDX11 ? rtDX11->RTV() : nullptr;
}
int32 rtvsSize = sizeof(ID3D11RenderTargetView*) * rts.Length();
if (_rtCount != rts.Length() || _rtDepth != dsv || _uaOutput || Platform::MemoryCompare(_rtHandles, rtvs, rtvsSize) != 0)
{
_omDirtyFlag = true;
_rtCount = rts.Length();
_rtDepth = dsv;
_uaOutput = nullptr;
Platform::MemoryCopy(_rtHandles, rtvs, rtvsSize);
}
}
void GPUContextDX11::SetRenderTarget(GPUTextureView* rt, GPUBuffer* uaOutput)
{
auto rtDX11 = reinterpret_cast<GPUTextureViewDX11*>(rt);
auto uaOutputDX11 = reinterpret_cast<GPUBufferDX11*>(uaOutput);
ID3D11RenderTargetView* rtv = rtDX11 ? rtDX11->RTV() : nullptr;
ID3D11UnorderedAccessView* uav = uaOutputDX11 ? ((GPUBufferViewDX11*)uaOutputDX11->View())->UAV() : nullptr;
int32 newRtCount = rtv ? 1 : 0;
if (_rtCount != newRtCount || _rtHandles[0] != rtv || _rtDepth != nullptr || _uaOutput != uav)
{
_omDirtyFlag = true;
_rtCount = newRtCount;
_rtDepth = nullptr;
_rtHandles[0] = rtv;
_uaOutput = uav;
}
}
void GPUContextDX11::ResetSR()
{
_srDirtyFlag = false;
Platform::MemoryClear(_srHandles, sizeof(_srHandles));
_context->VSSetShaderResources(0, ARRAY_COUNT(_srHandles), _srHandles);
_context->HSSetShaderResources(0, ARRAY_COUNT(_srHandles), _srHandles);
_context->DSSetShaderResources(0, ARRAY_COUNT(_srHandles), _srHandles);
_context->GSSetShaderResources(0, ARRAY_COUNT(_srHandles), _srHandles);
_context->PSSetShaderResources(0, ARRAY_COUNT(_srHandles), _srHandles);
_context->CSSetShaderResources(0, ARRAY_COUNT(_srHandles), _srHandles);
}
void GPUContextDX11::ResetUA()
{
_uaDirtyFlag = false;
Platform::MemoryClear(_uaHandles, sizeof(_uaHandles));
_context->CSSetUnorderedAccessViews(0, _maxUASlotsForCS, _uaHandles, nullptr);
}
void GPUContextDX11::ResetCB()
{
_cbDirtyFlag = false;
Platform::MemoryClear(_cbHandles, sizeof(_cbHandles));
_context->VSSetConstantBuffers(0, ARRAY_COUNT(_cbHandles), _cbHandles);
_context->HSSetConstantBuffers(0, ARRAY_COUNT(_cbHandles), _cbHandles);
_context->DSSetConstantBuffers(0, ARRAY_COUNT(_cbHandles), _cbHandles);
_context->GSSetConstantBuffers(0, ARRAY_COUNT(_cbHandles), _cbHandles);
_context->PSSetConstantBuffers(0, ARRAY_COUNT(_cbHandles), _cbHandles);
_context->CSSetConstantBuffers(0, ARRAY_COUNT(_cbHandles), _cbHandles);
}
void GPUContextDX11::BindCB(int32 slot, GPUConstantBuffer* cb)
{
ASSERT(slot >= 0 && slot < GPU_MAX_CB_BINDED);
ID3D11Buffer* buffer = nullptr;
if (cb && cb->GetSize() > 0)
{
auto cbDX11 = static_cast<GPUConstantBufferDX11*>(cb);
buffer = cbDX11->GetBuffer();
}
if (_cbHandles[slot] != buffer)
{
_cbDirtyFlag = true;
_cbHandles[slot] = buffer;
}
}
void GPUContextDX11::BindSR(int32 slot, GPUResourceView* view)
{
ASSERT(slot >= 0 && slot < GPU_MAX_SR_BINDED);
auto handle = view ? ((IShaderResourceDX11*)view->GetNativePtr())->SRV() : nullptr;
if (_srHandles[slot] != handle)
{
_srDirtyFlag = true;
_srHandles[slot] = handle;
}
}
void GPUContextDX11::BindUA(int32 slot, GPUResourceView* view)
{
ASSERT(slot >= 0 && slot < GPU_MAX_UA_BINDED);
auto handle = view ? ((IShaderResourceDX11*)view->GetNativePtr())->UAV() : nullptr;
if (_uaHandles[slot] != handle)
{
_uaDirtyFlag = true;
_uaHandles[slot] = handle;
}
}
void GPUContextDX11::BindVB(const Span<GPUBuffer*>& vertexBuffers, const uint32* vertexBuffersOffsets)
{
ASSERT(vertexBuffers.Length() >= 0 && vertexBuffers.Length() <= GPU_MAX_VB_BINDED);
bool vbEdited = false;
for (int32 i = 0; i < vertexBuffers.Length(); i++)
{
const auto vbDX11 = static_cast<GPUBufferDX11*>(vertexBuffers[i]);
const auto vb = vbDX11 ? vbDX11->GetBuffer() : nullptr;
vbEdited |= vb != _vbHandles[i];
_vbHandles[i] = vb;
const UINT stride = vbDX11 ? vbDX11->GetStride() : 0;
vbEdited |= stride != _vbStrides[i];
_vbStrides[i] = stride;
const UINT offset = vertexBuffersOffsets ? vertexBuffersOffsets[i] : 0;
vbEdited |= offset != _vbOffsets[i];
_vbOffsets[i] = offset;
}
if (vbEdited)
{
_context->IASetVertexBuffers(0, vertexBuffers.Length(), _vbHandles, _vbStrides, _vbOffsets);
}
}
void GPUContextDX11::BindIB(GPUBuffer* indexBuffer)
{
const auto ibDX11 = static_cast<GPUBufferDX11*>(indexBuffer);
if (ibDX11 != _ibHandle)
{
_ibHandle = ibDX11;
_context->IASetIndexBuffer(ibDX11->GetBuffer(), RenderToolsDX::ToDxgiFormat(ibDX11->GetFormat()), 0);
}
}
void GPUContextDX11::UpdateCB(GPUConstantBuffer* cb, const void* data)
{
ASSERT(data && cb);
auto cbDX11 = static_cast<GPUConstantBufferDX11*>(cb);
const uint32 size = cbDX11->GetSize();
if (size == 0)
return;
_context->UpdateSubresource(cbDX11->GetBuffer(), 0, nullptr, data, size, 1);
}
void GPUContextDX11::Dispatch(GPUShaderProgramCS* shader, uint32 threadGroupCountX, uint32 threadGroupCountY, uint32 threadGroupCountZ)
{
CurrentCS = (GPUShaderProgramCSDX11*)shader;
// Flush
flushCBs();
flushSRVs();
flushUAVs();
flushOM();
// Dispatch
_context->CSSetShader((ID3D11ComputeShader*)shader->GetBufferHandle(), nullptr, 0);
_context->Dispatch(threadGroupCountX, threadGroupCountY, threadGroupCountZ);
RENDER_STAT_DISPATCH_CALL();
CurrentCS = nullptr;
}
void GPUContextDX11::DispatchIndirect(GPUShaderProgramCS* shader, GPUBuffer* bufferForArgs, uint32 offsetForArgs)
{
CurrentCS = (GPUShaderProgramCSDX11*)shader;
auto bufferForArgsDX11 = (GPUBufferDX11*)bufferForArgs;
// Flush
flushCBs();
flushSRVs();
flushUAVs();
flushOM();
// Dispatch
_context->CSSetShader((ID3D11ComputeShader*)shader->GetBufferHandle(), nullptr, 0);
_context->DispatchIndirect(bufferForArgsDX11->GetBuffer(), offsetForArgs);
RENDER_STAT_DISPATCH_CALL();
CurrentCS = nullptr;
}
void GPUContextDX11::ResolveMultisample(GPUTexture* sourceMultisampleTexture, GPUTexture* destTexture, int32 sourceSubResource, int32 destSubResource, PixelFormat format)
{
ASSERT(sourceMultisampleTexture && sourceMultisampleTexture->IsMultiSample());
ASSERT(destTexture && !destTexture->IsMultiSample());
auto dstResourceDX11 = static_cast<GPUTextureDX11*>(destTexture);
auto srcResourceDX11 = static_cast<GPUTextureDX11*>(sourceMultisampleTexture);
const auto formatDXGI = RenderToolsDX::ToDxgiFormat(format == PixelFormat::Unknown ? destTexture->Format() : format);
_context->ResolveSubresource(dstResourceDX11->GetResource(), destSubResource, srcResourceDX11->GetResource(), destSubResource, formatDXGI);
}
void GPUContextDX11::DrawInstanced(uint32 verticesCount, uint32 instanceCount, int32 startInstance, int32 startVertex)
{
onDrawCall();
if (instanceCount > 1)
_context->DrawInstanced(verticesCount, instanceCount, startVertex, startInstance);
else
_context->Draw(verticesCount, startVertex);
RENDER_STAT_DRAW_CALL(verticesCount * instanceCount, verticesCount * instanceCount / 3);
}
void GPUContextDX11::DrawIndexedInstanced(uint32 indicesCount, uint32 instanceCount, int32 startInstance, int32 startVertex, int32 startIndex)
{
onDrawCall();
if (instanceCount > 1)
_context->DrawIndexedInstanced(indicesCount, instanceCount, startIndex, startVertex, startInstance);
else
_context->DrawIndexed(indicesCount, startIndex, startVertex);
RENDER_STAT_DRAW_CALL(0, indicesCount / 3 * instanceCount);
}
void GPUContextDX11::DrawInstancedIndirect(GPUBuffer* bufferForArgs, uint32 offsetForArgs)
{
ASSERT(bufferForArgs && bufferForArgs->GetFlags() & GPUBufferFlags::Argument);
const auto bufferForArgsDX11 = static_cast<GPUBufferDX11*>(bufferForArgs);
onDrawCall();
_context->DrawInstancedIndirect(bufferForArgsDX11->GetBuffer(), offsetForArgs);
RENDER_STAT_DRAW_CALL(0, 0);
}
void GPUContextDX11::DrawIndexedInstancedIndirect(GPUBuffer* bufferForArgs, uint32 offsetForArgs)
{
ASSERT(bufferForArgs && bufferForArgs->GetFlags() & GPUBufferFlags::Argument);
const auto bufferForArgsDX11 = static_cast<GPUBufferDX11*>(bufferForArgs);
onDrawCall();
_context->DrawIndexedInstancedIndirect(bufferForArgsDX11->GetBuffer(), offsetForArgs);
RENDER_STAT_DRAW_CALL(0, 0);
}
void GPUContextDX11::SetViewport(const Viewport& viewport)
{
_context->RSSetViewports(1, (D3D11_VIEWPORT*)&viewport);
}
void GPUContextDX11::SetScissor(const Rectangle& scissorRect)
{
D3D11_RECT rect;
rect.left = (LONG)scissorRect.GetLeft();
rect.right = (LONG)scissorRect.GetRight();
rect.top = (LONG)scissorRect.GetTop();
rect.bottom = (LONG)scissorRect.GetBottom();
_context->RSSetScissorRects(1, &rect);
}
GPUPipelineState* GPUContextDX11::GetState() const
{
return _currentState;
}
void GPUContextDX11::SetState(GPUPipelineState* state)
{
if (_currentState != state)
{
_currentState = static_cast<GPUPipelineStateDX11*>(state);
ID3D11BlendState* blendState = nullptr;
ID3D11RasterizerState* rasterizerState = nullptr;
ID3D11DepthStencilState* depthStencilState = nullptr;
GPUShaderProgramVSDX11* vs = nullptr;
GPUShaderProgramHSDX11* hs = nullptr;
GPUShaderProgramDSDX11* ds = nullptr;
GPUShaderProgramGSDX11* gs = nullptr;
GPUShaderProgramPSDX11* ps = nullptr;
D3D11_PRIMITIVE_TOPOLOGY primitiveTopology = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED;
if (state)
{
ASSERT(_currentState->IsValid());
blendState = _currentState->BlendState;
rasterizerState = _device->RasterizerStates[_currentState->RasterizerStateIndex];
depthStencilState = _device->DepthStencilStates[_currentState->DepthStencilStateIndex];
ASSERT(_currentState->VS != nullptr);
vs = _currentState->VS;
hs = _currentState->HS;
ds = _currentState->DS;
gs = _currentState->GS;
ps = _currentState->PS;
primitiveTopology = _currentState->PrimitiveTopology;
}
// Per pipeline stage state caching
if (CurrentDepthStencilState != depthStencilState)
{
CurrentDepthStencilState = depthStencilState;
_context->OMSetDepthStencilState(depthStencilState, 0);
}
if (CurrentRasterizerState != rasterizerState)
{
CurrentRasterizerState = rasterizerState;
_context->RSSetState(rasterizerState);
}
if (CurrentBlendState != blendState)
{
CurrentBlendState = blendState;
FLOAT blendFactor[4] = { 1, 1, 1, 1 };
_context->OMSetBlendState(blendState, blendFactor, D3D11_DEFAULT_SAMPLE_MASK);
}
if (CurrentVS != vs)
{
#if DX11_CLEAR_SR_ON_STAGE_DISABLE
if (CurrentVS && !vs)
{
_context->VSSetShaderResources(0, ARRAY_COUNT(EmptySRHandles), EmptySRHandles);
}
#endif
CurrentVS = vs;
_context->VSSetShader(vs ? vs->GetBufferHandleDX11() : nullptr, nullptr, 0);
_context->IASetInputLayout(vs ? vs->GetInputLayoutDX11() : nullptr);
}
if (CurrentHS != hs)
{
#if DX11_CLEAR_SR_ON_STAGE_DISABLE
if (CurrentHS && !hs)
{
_context->HSSetShaderResources(0, ARRAY_COUNT(EmptySRHandles), EmptySRHandles);
}
#endif
CurrentHS = hs;
_context->HSSetShader(hs ? hs->GetBufferHandleDX11() : nullptr, nullptr, 0);
}
if (CurrentDS != ds)
{
#if DX11_CLEAR_SR_ON_STAGE_DISABLE
if (CurrentDS && !ds)
{
_context->DSSetShaderResources(0, ARRAY_COUNT(EmptySRHandles), EmptySRHandles);
}
#endif
CurrentDS = ds;
_context->DSSetShader(ds ? ds->GetBufferHandleDX11() : nullptr, nullptr, 0);
}
if (CurrentGS != gs)
{
#if DX11_CLEAR_SR_ON_STAGE_DISABLE
if (CurrentGS && !gs)
{
_context->GSSetShaderResources(0, ARRAY_COUNT(EmptySRHandles), EmptySRHandles);
}
#endif
CurrentGS = gs;
_context->GSSetShader(gs ? gs->GetBufferHandleDX11() : nullptr, nullptr, 0);
}
if (CurrentPS != ps)
{
#if DX11_CLEAR_SR_ON_STAGE_DISABLE
if (CurrentPS && !ps)
{
_context->PSSetShaderResources(0, ARRAY_COUNT(EmptySRHandles), EmptySRHandles);
}
#endif
CurrentPS = ps;
_context->PSSetShader(ps ? ps->GetBufferHandleDX11() : nullptr, nullptr, 0);
}
if (CurrentPrimitiveTopology != primitiveTopology)
{
CurrentPrimitiveTopology = primitiveTopology;
_context->IASetPrimitiveTopology(primitiveTopology);
}
RENDER_STAT_PS_STATE_CHANGE();
}
}
void GPUContextDX11::ClearState()
{
if (!_context)
return;
ResetRenderTarget();
ResetSR();
ResetUA();
ResetCB();
SetState(nullptr);
FlushState();
//_context->ClearState();
}
void GPUContextDX11::FlushState()
{
// Flush
flushCBs();
flushSRVs();
flushUAVs();
flushOM();
}
void GPUContextDX11::Flush()
{
if (_context)
_context->Flush();
}
void GPUContextDX11::UpdateBuffer(GPUBuffer* buffer, const void* data, uint32 size, uint32 offset)
{
ASSERT(data);
ASSERT(buffer && buffer->GetSize() >= size);
auto bufferDX11 = (GPUBufferDX11*)buffer;
// Use map/unmap for dynamic buffers
if (buffer->IsDynamic())
{
D3D11_MAPPED_SUBRESOURCE map;
const HRESULT result = _context->Map(bufferDX11->GetResource(), 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
if (FAILED(result))
{
LOG_DIRECTX_RESULT(result);
return;
}
Platform::MemoryCopy(map.pData, data, size);
_context->Unmap(bufferDX11->GetResource(), 0);
}
else
{
D3D11_BOX box;
box.left = offset;
box.right = offset + size;
box.front = 0;
box.back = 1;
box.top = 0;
box.bottom = 1;
_context->UpdateSubresource(bufferDX11->GetResource(), 0, &box, data, size, 0);
}
}
void GPUContextDX11::CopyBuffer(GPUBuffer* dstBuffer, GPUBuffer* srcBuffer, uint32 size, uint32 dstOffset, uint32 srcOffset)
{
ASSERT(dstBuffer && srcBuffer);
auto dstBufferDX11 = static_cast<GPUBufferDX11*>(dstBuffer);
auto srcBufferDX11 = static_cast<GPUBufferDX11*>(srcBuffer);
D3D11_BOX box;
box.left = srcOffset;
box.right = srcOffset + size;
box.top = 0;
box.bottom = 1;
box.front = 0;
box.back = 1;
_context->CopySubresourceRegion(dstBufferDX11->GetResource(), 0, dstOffset, 0, 0, srcBufferDX11->GetResource(), 0, &box);
}
void GPUContextDX11::UpdateTexture(GPUTexture* texture, int32 arrayIndex, int32 mipIndex, const void* data, uint32 rowPitch, uint32 slicePitch)
{
ASSERT(texture && texture->IsAllocated() && data);
auto textureDX11 = static_cast<GPUTextureDX11*>(texture);
const int32 subresourceIndex = RenderToolsDX::CalcSubresourceIndex(mipIndex, arrayIndex, texture->MipLevels());
_context->UpdateSubresource(textureDX11->GetResource(), subresourceIndex, nullptr, data, static_cast<UINT>(rowPitch), slicePitch);
//D3D11_MAPPED_SUBRESOURCE mapped;
//_device->GetIM()->Map(_resource, textureMipIndex, D3D11_MAP_WRITE_DISCARD, 0, &mapped);
//Platform::MemoryCopy(mapped.pData, data, size);
//_device->GetIM()->Unmap(_resource, textureMipIndex);
}
void GPUContextDX11::CopyTexture(GPUTexture* dstResource, uint32 dstSubresource, uint32 dstX, uint32 dstY, uint32 dstZ, GPUTexture* srcResource, uint32 srcSubresource)
{
ASSERT(dstResource && srcResource);
auto dstResourceDX11 = static_cast<GPUTextureDX11*>(dstResource);
auto srcResourceDX11 = static_cast<GPUTextureDX11*>(srcResource);
_context->CopySubresourceRegion(dstResourceDX11->GetResource(), dstSubresource, dstX, dstY, dstZ, srcResourceDX11->GetResource(), srcSubresource, nullptr);
}
void GPUContextDX11::ResetCounter(GPUBuffer* buffer)
{
}
void GPUContextDX11::CopyCounter(GPUBuffer* dstBuffer, uint32 dstOffset, GPUBuffer* srcBuffer)
{
ASSERT(dstBuffer && srcBuffer);
auto dstBufferDX11 = static_cast<GPUBufferDX11*>(dstBuffer);
auto srvUavView = ((GPUBufferViewDX11*)srcBuffer->View())->UAV();
_context->CopyStructureCount(dstBufferDX11->GetBuffer(), dstOffset, srvUavView);
}
void GPUContextDX11::CopyResource(GPUResource* dstResource, GPUResource* srcResource)
{
ASSERT(dstResource && srcResource);
auto dstResourceDX11 = dynamic_cast<IGPUResourceDX11*>(dstResource);
auto srcResourceDX11 = dynamic_cast<IGPUResourceDX11*>(srcResource);
_context->CopyResource(dstResourceDX11->GetResource(), srcResourceDX11->GetResource());
}
void GPUContextDX11::CopySubresource(GPUResource* dstResource, uint32 dstSubresource, GPUResource* srcResource, uint32 srcSubresource)
{
ASSERT(dstResource && srcResource);
auto dstResourceDX11 = dynamic_cast<IGPUResourceDX11*>(dstResource);
auto srcResourceDX11 = dynamic_cast<IGPUResourceDX11*>(srcResource);
_context->CopySubresourceRegion(dstResourceDX11->GetResource(), dstSubresource, 0, 0, 0, srcResourceDX11->GetResource(), srcSubresource, nullptr);
}
void GPUContextDX11::flushSRVs()
{
// Check if need to flush shader resources
if (_srDirtyFlag)
{
// Clear flag
_srDirtyFlag = false;
// Flush with the driver
// TODO: don't bind SRV to all stages and all slots (use mask for bind diff?)
#define FLUSH_STAGE(STAGE) \
if (Current##STAGE) \
{ \
_context->STAGE##SetShaderResources(0, ARRAY_COUNT(_srHandles), _srHandles); \
}
FLUSH_STAGE(VS);
FLUSH_STAGE(HS);
FLUSH_STAGE(DS);
FLUSH_STAGE(GS);
FLUSH_STAGE(PS);
FLUSH_STAGE(CS);
#undef FLUSH_STAGE
}
}
void GPUContextDX11::flushUAVs()
{
// Check if need to flush unordered access
if (_uaDirtyFlag)
{
// Clear flag
_uaDirtyFlag = false;
// Flush with the driver
uint32 initialCounts[GPU_MAX_UA_BINDED] = { 0 };
_context->CSSetUnorderedAccessViews(0, _maxUASlotsForCS, _uaHandles, initialCounts);
}
}
void GPUContextDX11::flushCBs()
{
// Check if need to flush constant buffers
if (_cbDirtyFlag)
{
// Clear flag
_cbDirtyFlag = false;
// Flush with the driver
// TODO: don't bind CBV to all stages and all slots (use mask for bind diff? eg. cache mask from last flush and check if there is a diff + include mask from diff slots?)
#define FLUSH_STAGE(STAGE) \
if (Current##STAGE) \
{ \
_context->STAGE##SetConstantBuffers(0, ARRAY_COUNT(_cbHandles), _cbHandles); \
}
FLUSH_STAGE(VS);
FLUSH_STAGE(HS);
FLUSH_STAGE(DS);
FLUSH_STAGE(GS);
FLUSH_STAGE(PS);
FLUSH_STAGE(CS);
#undef FLUSH_STAGE
}
}
void GPUContextDX11::flushOM()
{
// Check if need to flush output merger state or/and unordered access views
if (_omDirtyFlag)
{
#if _DEBUG
// Validate binded render targets amount
int32 rtCount = 0;
for (int i = 0; i < ARRAY_COUNT(_rtHandles) && i < _rtCount; i++)
{
if (_rtHandles[i] != nullptr)
rtCount++;
else
break;
}
ASSERT(rtCount == _rtCount);
#endif
// Check if don't use UAVs and set output merger render targets table
if (_uaOutput == nullptr)
{
_context->OMSetRenderTargets(_rtCount, _rtHandles, _rtDepth);
}
else
{
// Note: current dx11 content implementation assumes that there must be one or more render targets binded in order to use uav output
ASSERT(_rtCount > 0);
uint32 initialCounts[1] = { 0 };
// TODO: set -1 if buffer had no ResetCounter call since last time
_context->OMSetRenderTargetsAndUnorderedAccessViews(_rtCount, _rtHandles, _rtDepth, _rtCount, 1, &_uaOutput, initialCounts);
}
// Clear flag
_omDirtyFlag = false;
}
}
void GPUContextDX11::onDrawCall()
{
ASSERT(_currentState);
// Flush
flushCBs();
flushSRVs();
flushUAVs();
flushOM();
}
#endif

View File

@@ -0,0 +1,150 @@
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Graphics/GPUContext.h"
#include "GPUDeviceDX11.h"
#include "GPUPipelineStateDX11.h"
#include "../IncludeDirectXHeaders.h"
#if GRAPHICS_API_DIRECTX11
class GPUBufferDX11;
/// <summary>
/// GPU Context for DirectX 11 backend.
/// </summary>
class GPUContextDX11 : public GPUContext
{
private:
GPUDeviceDX11* _device;
ID3D11DeviceContext* _context;
#if GPU_ALLOW_PROFILE_EVENTS
ID3DUserDefinedAnnotation* _userDefinedAnnotations;
#endif
int32 _maxUASlotsForCS;
// Output Merger
bool _omDirtyFlag;
int32 _rtCount;
ID3D11DepthStencilView* _rtDepth;
ID3D11RenderTargetView* _rtHandles[GPU_MAX_RT_BINDED];
ID3D11UnorderedAccessView* _uaOutput;
// Shader Resources
bool _srDirtyFlag;
ID3D11ShaderResourceView* _srHandles[GPU_MAX_SR_BINDED];
// Unordered Access
bool _uaDirtyFlag;
ID3D11UnorderedAccessView* _uaHandles[GPU_MAX_UA_BINDED];
// Constant Buffers
bool _cbDirtyFlag;
ID3D11Buffer* _cbHandles[GPU_MAX_CB_BINDED];
// Vertex Buffers
GPUBufferDX11* _ibHandle;
ID3D11Buffer* _vbHandles[GPU_MAX_VB_BINDED];
UINT _vbStrides[GPU_MAX_VB_BINDED];
UINT _vbOffsets[GPU_MAX_VB_BINDED];
// Pipeline State
GPUPipelineStateDX11* _currentState;
ID3D11BlendState* CurrentBlendState;
ID3D11RasterizerState* CurrentRasterizerState;
ID3D11DepthStencilState* CurrentDepthStencilState;
GPUShaderProgramVSDX11* CurrentVS;
GPUShaderProgramHSDX11* CurrentHS;
GPUShaderProgramDSDX11* CurrentDS;
GPUShaderProgramGSDX11* CurrentGS;
GPUShaderProgramPSDX11* CurrentPS;
GPUShaderProgramCSDX11* CurrentCS;
D3D11_PRIMITIVE_TOPOLOGY CurrentPrimitiveTopology;
public:
/// <summary>
/// Initializes a new instance of the <see cref="GPUContextDX11"/> class.
/// </summary>
/// <param name="device">The graphics device.</param>
/// <param name="context">The context.</param>
GPUContextDX11(GPUDeviceDX11* device, ID3D11DeviceContext* context);
/// <summary>
/// Finalizes an instance of the <see cref="GPUContextDX11"/> class.
/// </summary>
~GPUContextDX11();
public:
/// <summary>
/// Gets DirectX 11 device context used by this context
/// </summary>
/// <returns>GPU context</returns>
FORCE_INLINE ID3D11DeviceContext* GetContext() const
{
return _context;
}
private:
void flushSRVs();
void flushUAVs();
void flushCBs();
void flushOM();
void onDrawCall();
public:
// [GPUContext]
void FrameBegin() override;
#if GPU_ALLOW_PROFILE_EVENTS
void EventBegin(const Char* name) override;
void EventEnd() override;
#endif
void* GetNativePtr() const override;
bool IsDepthBufferBinded() override;
void Clear(GPUTextureView* rt, const Color& color) override;
void ClearDepth(GPUTextureView* depthBuffer, float depthValue) override;
void ClearUA(GPUBuffer* buf, const Vector4& value) override;
void ResetRenderTarget() override;
void SetRenderTarget(GPUTextureView* rt) override;
void SetRenderTarget(GPUTextureView* depthBuffer, GPUTextureView* rt) override;
void SetRenderTarget(GPUTextureView* depthBuffer, const Span<GPUTextureView*>& rts) override;
void SetRenderTarget(GPUTextureView* rt, GPUBuffer* uaOutput) override;
void ResetSR() override;
void ResetUA() override;
void ResetCB() override;
void BindCB(int32 slot, GPUConstantBuffer* cb) override;
void BindSR(int32 slot, GPUResourceView* view) override;
void BindUA(int32 slot, GPUResourceView* view) override;
void BindVB(const Span<GPUBuffer*>& vertexBuffers, const uint32* vertexBuffersOffsets = nullptr) override;
void BindIB(GPUBuffer* indexBuffer) override;
void UpdateCB(GPUConstantBuffer* cb, const void* data) override;
void Dispatch(GPUShaderProgramCS* shader, uint32 threadGroupCountX, uint32 threadGroupCountY, uint32 threadGroupCountZ) override;
void DispatchIndirect(GPUShaderProgramCS* shader, GPUBuffer* bufferForArgs, uint32 offsetForArgs) override;
void ResolveMultisample(GPUTexture* sourceMultisampleTexture, GPUTexture* destTexture, int32 sourceSubResource, int32 destSubResource, PixelFormat format) override;
void DrawInstanced(uint32 verticesCount, uint32 instanceCount, int32 startInstance, int32 startVertex) override;
void DrawIndexedInstanced(uint32 indicesCount, uint32 instanceCount, int32 startInstance, int32 startVertex, int32 startIndex) override;
void DrawInstancedIndirect(GPUBuffer* bufferForArgs, uint32 offsetForArgs) override;
void DrawIndexedInstancedIndirect(GPUBuffer* bufferForArgs, uint32 offsetForArgs) override;
void SetViewport(const Viewport& viewport) override;
void SetScissor(const Rectangle& scissorRect) override;
GPUPipelineState* GetState() const override;
void SetState(GPUPipelineState* state) override;
void ClearState() override;
void FlushState() override;
void Flush() override;
void UpdateBuffer(GPUBuffer* buffer, const void* data, uint32 size, uint32 offset) override;
void CopyBuffer(GPUBuffer* dstBuffer, GPUBuffer* srcBuffer, uint32 size, uint32 dstOffset, uint32 srcOffset) override;
void UpdateTexture(GPUTexture* texture, int32 arrayIndex, int32 mipIndex, const void* data, uint32 rowPitch, uint32 slicePitch) override;
void CopyTexture(GPUTexture* dstResource, uint32 dstSubresource, uint32 dstX, uint32 dstY, uint32 dstZ, GPUTexture* srcResource, uint32 srcSubresource) override;
void ResetCounter(GPUBuffer* buffer) override;
void CopyCounter(GPUBuffer* dstBuffer, uint32 dstOffset, GPUBuffer* srcBuffer) override;
void CopyResource(GPUResource* dstResource, GPUResource* srcResource) override;
void CopySubresource(GPUResource* dstResource, uint32 dstSubresource, GPUResource* srcResource, uint32 srcSubresource) override;
};
#endif

View File

@@ -0,0 +1,711 @@
// Copyright (c) 2012-2020 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 "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* outFeatureLevel)
{
// Temporary data
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
D3D_FEATURE_LEVEL requestedFeatureLevels[] =
{
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
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 to create device
if (SUCCEEDED(D3D11CreateDevice(
adapter,
D3D_DRIVER_TYPE_UNKNOWN,
NULL,
deviceFlags,
&requestedFeatureLevels[firstAllowedFeatureLevel],
numAllowedFeatureLevels,
D3D11_SDK_VERSION,
&device,
outFeatureLevel,
&context
)))
{
// Release created stuff
device->Release();
context->Release();
return true;
}
return false;
}
GPUDevice* GPUDeviceDX11::Create()
{
// Configuration
#if PLATFORM_XBOX_ONE
D3D_FEATURE_LEVEL maxAllowedFeatureLevel = D3D_FEATURE_LEVEL_10_0;
#elif 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::Instance();
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);
// 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;
// Verify compute shader is supported on DirectX 11
if (createdFeatureLevel >= D3D_FEATURE_LEVEL_11_0)
{
D3D11_FEATURE_DATA_D3D10_X_HARDWARE_OPTIONS options = { 0 };
_device->CheckFeatureSupport(D3D11_FEATURE_D3D10_X_HARDWARE_OPTIONS, &options, sizeof(options));
if (!options.ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x)
{
_device->Release();
_device = nullptr;
LOG(Fatal, "DirectCompute is not supported by this device (DirectX 11 level).");
return true;
}
}
// Init device limits
{
auto& limits = Limits;
if (createdFeatureLevel >= D3D_FEATURE_LEVEL_11_0)
{
limits.HasCompute = true;
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.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;
}
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.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 = D3D11_REQ_TEXTURECUBE_DIMENSION;
}
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(depthTextEnable, depthWrite) \
dsDesc.DepthEnable = depthTextEnable; \
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 + (depthTextEnable ? 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);
}
GPUSwapChain* GPUDeviceDX11::CreateSwapChain(Window* window)
{
return New<GPUSwapChainDX11>(this, window);
}
#endif

View File

@@ -0,0 +1,152 @@
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Graphics/GPUDevice.h"
#include "Engine/Graphics/GPUResource.h"
#include "../GPUDeviceDX.h"
#include "../IncludeDirectXHeaders.h"
#if GRAPHICS_API_DIRECTX11
class Engine;
class GPUContextDX11;
class GPUSwapChainDX11;
/// <summary>
/// Implementation of Graphics Device for DirectX 11 backend.
/// </summary>
class GPUDeviceDX11 : public GPUDeviceDX
{
friend GPUContextDX11;
friend GPUSwapChainDX11;
private:
// Private Stuff
ID3D11Device* _device;
ID3D11DeviceContext* _imContext;
IDXGIFactory* _factoryDXGI;
GPUContextDX11* _mainContext;
// Static Samplers
ID3D11SamplerState* _samplerLinearClamp;
ID3D11SamplerState* _samplerPointClamp;
ID3D11SamplerState* _samplerLinearWrap;
ID3D11SamplerState* _samplerPointWrap;
ID3D11SamplerState* _samplerShadow;
ID3D11SamplerState* _samplerShadowPCF;
// Shared data for pipeline states
CriticalSection BlendStatesWriteLocker;
Dictionary<BlendingMode, ID3D11BlendState*> BlendStates;
ID3D11RasterizerState* RasterizerStates[3 * 2 * 2]; // Index = CullMode[0-2] + Wireframe[0?3] + DepthClipEnable[0?6]
ID3D11DepthStencilState* DepthStencilStates[9 * 2 * 2]; // Index = ComparisonFunc[0-8] + DepthTestEnable[0?9] + DepthWriteEnable[0?18]
public:
// Create new graphics device (returns null if failed)
// @returns Created device or null
static GPUDevice* Create();
/// <summary>
/// Initializes a new instance of the <see cref="GPUDeviceDX11"/> class.
/// </summary>
/// <param name="dxgiFactory">The DXGI factory handle.</param>
/// <param name="adapter">The GPU device adapter.</param>
GPUDeviceDX11(IDXGIFactory* dxgiFactory, GPUAdapterDX* adapter);
/// <summary>
/// Finalizes an instance of the <see cref="GPUDeviceDX11"/> class.
/// </summary>
~GPUDeviceDX11();
public:
// Gets DX11 device
ID3D11Device* GetDevice() const
{
return _device;
}
// Gets DXGI factory
IDXGIFactory* GetDXGIFactory() const
{
return _factoryDXGI;
}
// Gets immediate context
ID3D11DeviceContext* GetIM() const
{
return _imContext;
}
GPUContextDX11* GetMainContextDX11()
{
return _mainContext;
}
public:
ID3D11BlendState* GetBlendState(const BlendingMode& blending);
public:
// [GPUDeviceDX]
GPUContext* GetMainContext() override
{
return reinterpret_cast<GPUContext*>(_mainContext);
}
void* GetNativePtr() const override
{
return _device;
}
bool Init() override;
void Dispose() override;
void WaitForGPU() override;
void DrawEnd() override;
GPUTexture* CreateTexture(const StringView& name) override;
GPUShader* CreateShader(const StringView& name) override;
GPUPipelineState* CreatePipelineState() override;
GPUTimerQuery* CreateTimerQuery() override;
GPUBuffer* CreateBuffer(const StringView& name) override;
GPUSwapChain* CreateSwapChain(Window* window) override;
};
/// <summary>
/// Base interface for GPU resources on DirectX 11
/// </summary>
class IGPUResourceDX11
{
public:
/// <summary>
/// Gets DirectX 11 resource object handle
/// </summary>
/// <returns>DirectX 11 resource object handle</returns>
virtual ID3D11Resource* GetResource() = 0;
};
/// <summary>
/// GPU resource implementation for DirectX 11 backend.
/// </summary>
template<class BaseType>
class GPUResourceDX11 : public GPUResourceBase<GPUDeviceDX11, BaseType>, public IGPUResourceDX11
{
public:
/// <summary>
/// Initializes a new instance of the <see cref="GPUResourceDX11"/> class.
/// </summary>
/// <param name="device">The graphics device.</param>
/// <param name="name">The resource name.</param>
GPUResourceDX11(GPUDeviceDX11* device, const StringView& name) noexcept
: GPUResourceBase(device, name)
{
}
};
extern GPUDevice* CreateGPUDeviceDX11();
#endif

View File

@@ -0,0 +1,61 @@
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
#if GRAPHICS_API_DIRECTX11
#include "GPUPipelineStateDX11.h"
void GPUPipelineStateDX11::OnReleaseGPU()
{
BlendState = nullptr;
VS = nullptr;
HS = nullptr;
DS = nullptr;
GS = nullptr;
PS = nullptr;
}
ID3D11Resource* GPUPipelineStateDX11::GetResource()
{
return nullptr;
}
bool GPUPipelineStateDX11::IsValid() const
{
return !!_memoryUsage;
}
bool GPUPipelineStateDX11::Init(const Description& desc)
{
ASSERT(!IsValid());
// Cache shaders
VS = (GPUShaderProgramVSDX11*)desc.VS;
HS = desc.HS ? (GPUShaderProgramHSDX11*)desc.HS : nullptr;
DS = desc.DS ? (GPUShaderProgramDSDX11*)desc.DS : nullptr;
GS = desc.GS ? (GPUShaderProgramGSDX11*)desc.GS : nullptr;
PS = desc.PS ? (GPUShaderProgramPSDX11*)desc.PS : nullptr;
// Primitive Topology
const static D3D11_PRIMITIVE_TOPOLOGY D3D11_primTypes[] =
{
D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED,
D3D11_PRIMITIVE_TOPOLOGY_POINTLIST,
D3D11_PRIMITIVE_TOPOLOGY_LINELIST,
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST,
};
PrimitiveTopology = D3D11_primTypes[static_cast<int32>(desc.PrimitiveTopologyType)];
if (HS)
PrimitiveTopology = (D3D11_PRIMITIVE_TOPOLOGY)((int32)D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + (HS->GetControlPointsCount() - 1));
// States
DepthStencilStateIndex = static_cast<int32>(desc.DepthFunc) + (desc.DepthTestEnable ? 0 : 9) + (desc.DepthWriteEnable ? 0 : 18);
RasterizerStateIndex = static_cast<int32>(desc.CullMode) + (desc.Wireframe ? 0 : 3) + (desc.DepthClipEnable ? 0 : 6);
BlendState = _device->GetBlendState(desc.BlendMode);
// Calculate approx. memory usage (just to set sth)
_memoryUsage = sizeof(D3D11_DEPTH_STENCIL_DESC) + sizeof(D3D11_RASTERIZER_DESC) + sizeof(D3D11_BLEND_DESC);
return GPUPipelineState::Init(desc);
}
#endif

View File

@@ -0,0 +1,54 @@
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Graphics/GPUPipelineState.h"
#include "GPUShaderProgramDX11.h"
#include "GPUDeviceDX11.h"
#if GRAPHICS_API_DIRECTX11
/// <summary>
/// Graphics pipeline state object for DirectX 11 backend.
/// </summary>
class GPUPipelineStateDX11 : public GPUResourceDX11<GPUPipelineState>
{
public:
int32 DepthStencilStateIndex;
int32 RasterizerStateIndex;
ID3D11BlendState* BlendState = nullptr;
GPUShaderProgramVSDX11* VS = nullptr;
GPUShaderProgramHSDX11* HS = nullptr;
GPUShaderProgramDSDX11* DS = nullptr;
GPUShaderProgramGSDX11* GS = nullptr;
GPUShaderProgramPSDX11* PS = nullptr;
D3D11_PRIMITIVE_TOPOLOGY PrimitiveTopology;
public:
/// <summary>
/// Initializes a new instance of the <see cref="GPUPipelineStateDX11"/> class.
/// </summary>
/// <param name="device">The device.</param>
GPUPipelineStateDX11(GPUDeviceDX11* device)
: GPUResourceDX11<GPUPipelineState>(device, StringView::Empty)
{
}
public:
// [GPUResourceDX11]
ID3D11Resource* GetResource() final override;
// [GPUPipelineState]
bool IsValid() const override;
bool Init(const Description& desc) override;
protected:
// [GPUResourceDX11]
void OnReleaseGPU() final override;
};
#endif

View File

@@ -0,0 +1,195 @@
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
#if GRAPHICS_API_DIRECTX11
#include "GPUShaderDX11.h"
#include "GPUShaderProgramDX11.h"
#include "Engine/Serialization/MemoryReadStream.h"
#include "../RenderToolsDX.h"
GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, byte* cacheBytes, uint32 cacheSize, MemoryReadStream& stream)
{
GPUShaderProgram* shader = nullptr;
switch (type)
{
case ShaderStage::Vertex:
{
D3D11_INPUT_ELEMENT_DESC inputLayoutDesc[VERTEX_SHADER_MAX_INPUT_ELEMENTS];
// Temporary variables
byte Type, Format, Index, InputSlot, InputSlotClass;
uint32 AlignedByteOffset, InstanceDataStepRate;
// Load Input Layout (it may be empty)
byte inputLayoutSize;
stream.ReadByte(&inputLayoutSize);
ASSERT(inputLayoutSize <= VERTEX_SHADER_MAX_INPUT_ELEMENTS);
for (int32 a = 0; a < inputLayoutSize; a++)
{
// Read description
// TODO: maybe use struct and load at once?
stream.ReadByte(&Type);
stream.ReadByte(&Index);
stream.ReadByte(&Format);
stream.ReadByte(&InputSlot);
stream.ReadUint32(&AlignedByteOffset);
stream.ReadByte(&InputSlotClass);
stream.ReadUint32(&InstanceDataStepRate);
// Get semantic name
const char* semanticName = nullptr;
// TODO: maybe use enum+mapping ?
switch (Type)
{
case 1:
semanticName = "POSITION";
break;
case 2:
semanticName = "COLOR";
break;
case 3:
semanticName = "TEXCOORD";
break;
case 4:
semanticName = "NORMAL";
break;
case 5:
semanticName = "TANGENT";
break;
case 6:
semanticName = "BITANGENT";
break;
case 7:
semanticName = "ATTRIBUTE";
break;
case 8:
semanticName = "BLENDINDICES";
break;
case 9:
semanticName = "BLENDWEIGHT";
break;
default:
LOG(Fatal, "Invalid vertex shader element semantic type: {0}", Type);
break;
}
// Set data
inputLayoutDesc[a] =
{
semanticName,
static_cast<UINT>(Index),
static_cast<DXGI_FORMAT>(Format),
static_cast<UINT>(InputSlot),
static_cast<UINT>(AlignedByteOffset),
static_cast<D3D11_INPUT_CLASSIFICATION>(InputSlotClass),
static_cast<UINT>(InstanceDataStepRate)
};
}
ID3D11InputLayout* inputLayout = nullptr;
if (inputLayoutSize > 0)
{
// Create input layout
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateInputLayout(inputLayoutDesc, inputLayoutSize, cacheBytes, cacheSize, &inputLayout));
}
// Create shader
ID3D11VertexShader* buffer = nullptr;
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateVertexShader(cacheBytes, cacheSize, nullptr, &buffer));
// Create object
shader = New<GPUShaderProgramVSDX11>(initializer, buffer, inputLayout, inputLayoutSize);
break;
}
case ShaderStage::Hull:
{
// Read control points
int32 controlPointsCount;
stream.ReadInt32(&controlPointsCount);
// Create shader
ID3D11HullShader* buffer = nullptr;
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateHullShader(cacheBytes, cacheSize, nullptr, &buffer));
// Create object
shader = New<GPUShaderProgramHSDX11>(initializer, buffer, controlPointsCount);
break;
}
case ShaderStage::Domain:
{
// Create shader
ID3D11DomainShader* buffer = nullptr;
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateDomainShader(cacheBytes, cacheSize, nullptr, &buffer));
// Create object
shader = New<GPUShaderProgramDSDX11>(initializer, buffer);
break;
}
case ShaderStage::Geometry:
{
// Create shader
ID3D11GeometryShader* buffer = nullptr;
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateGeometryShader(cacheBytes, cacheSize, nullptr, &buffer));
// Create object
shader = New<GPUShaderProgramGSDX11>(initializer, buffer);
break;
}
case ShaderStage::Pixel:
{
// Create shader
ID3D11PixelShader* buffer = nullptr;
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreatePixelShader(cacheBytes, cacheSize, nullptr, &buffer));
// Create object
shader = New<GPUShaderProgramPSDX11>(initializer, buffer);
break;
}
case ShaderStage::Compute:
{
// Create shader
ID3D11ComputeShader* buffer = nullptr;
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateComputeShader(cacheBytes, cacheSize, nullptr, &buffer));
// Create object
shader = New<GPUShaderProgramCSDX11>(initializer, buffer);
break;
}
}
return shader;
}
GPUConstantBuffer* GPUShaderDX11::CreateCB(const String& name, uint32 size, MemoryReadStream& stream)
{
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->GetDevice()->CreateBuffer(&cbDesc, nullptr, &buffer);
if (FAILED(result))
{
LOG_DIRECTX_RESULT(result);
return nullptr;
}
memorySize = cbDesc.ByteWidth;
}
return new(_cbs) GPUConstantBufferDX11(_device, name, size, memorySize, buffer);
}
void GPUShaderDX11::OnReleaseGPU()
{
_cbs.Clear();
GPUShader::OnReleaseGPU();
}
#endif

View File

@@ -0,0 +1,112 @@
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
#pragma once
#if GRAPHICS_API_DIRECTX11
#include "Engine/Graphics/Shaders/GPUShader.h"
#include "Engine/Graphics/Shaders/GPUConstantBuffer.h"
#include "GPUDeviceDX11.h"
/// <summary>
/// Constant Buffer for DirectX 11 backend.
/// </summary>
class GPUConstantBufferDX11 : public GPUResourceDX11<GPUConstantBuffer>
{
private:
ID3D11Buffer* _resource;
public:
/// <summary>
/// Initializes a new instance of the <see cref="GPUConstantBufferDX11"/> class.
/// </summary>
/// <param name="device">The graphics device.</param>
/// <param name="name">The resource name.</param>
/// <param name="size">The buffer size (in bytes).</param>
/// <param name="memorySize">The buffer memory size (in bytes).</param>
/// <param name="buffer">The buffer.</param>
GPUConstantBufferDX11(GPUDeviceDX11* device, const String& name, uint32 size, uint32 memorySize, ID3D11Buffer* buffer) noexcept
: GPUResourceDX11(device, name)
, _resource(buffer)
{
_size = size;
_memoryUsage = memorySize;
}
/// <summary>
/// Finalizes an instance of the <see cref="GPUConstantBufferDX11"/> class.
/// </summary>
~GPUConstantBufferDX11()
{
DX_SAFE_RELEASE_CHECK(_resource, 0);
_memoryUsage = 0;
}
public:
/// <summary>
/// Gets the constant buffer object.
/// </summary>
/// <returns>The DirectX buffer object.</returns>
FORCE_INLINE ID3D11Buffer* GetBuffer() const
{
return _resource;
}
public:
// [GPUResourceDX11]
ID3D11Resource* GetResource() override
{
return _resource;
}
public:
// [GPUResourceDX11]
void OnReleaseGPU() final override
{
DX_SAFE_RELEASE_CHECK(_resource, 0);
}
};
/// <summary>
/// Shader for DirectX 11 backend.
/// </summary>
class GPUShaderDX11 : public GPUResourceDX11<GPUShader>
{
private:
Array<GPUConstantBufferDX11, FixedAllocation<MAX_CONSTANT_BUFFER_SLOTS>> _cbs;
public:
/// <summary>
/// Initializes a new instance of the <see cref="GPUShaderDX11"/> class.
/// </summary>
/// <param name="device">The device.</param>
/// <param name="name">The resource name.</param>
GPUShaderDX11(GPUDeviceDX11* device, const StringView& name)
: GPUResourceDX11(device, name)
{
}
protected:
// [GPUShader]
GPUShaderProgram* CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, byte* cacheBytes, uint32 cacheSize, MemoryReadStream& stream) override;
GPUConstantBuffer* CreateCB(const String& name, uint32 size, MemoryReadStream& stream) override;
void OnReleaseGPU() override;
public:
// [GPUResourceDX11]
ID3D11Resource* GetResource() final override
{
return nullptr;
}
};
#endif

View File

@@ -0,0 +1,217 @@
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Graphics/Shaders/GPUShaderProgram.h"
#include "../IncludeDirectXHeaders.h"
#if GRAPHICS_API_DIRECTX11
/// <summary>
/// Shaders base class for DirectX 11 backend.
/// </summary>
template<typename BaseType, typename BufferType>
class GPUShaderProgramDX11 : public BaseType
{
protected:
BufferType* _buffer;
public:
/// <summary>
/// Initializes a new instance of the <see cref="GPUShaderProgramDX11"/> class.
/// </summary>
/// <param name="initializer">The program initialization data.</param>
/// <param name="buffer">The shader buffer object.</param>
GPUShaderProgramDX11(const GPUShaderProgramInitializer& initializer, BufferType* buffer)
: _buffer(buffer)
{
BaseType::Init(initializer);
}
/// <summary>
/// Finalizes an instance of the <see cref="GPUShaderProgramDX11"/> class.
/// </summary>
~GPUShaderProgramDX11()
{
DX_SAFE_RELEASE_CHECK(_buffer, 0);
}
public:
/// <summary>
/// Gets DirectX 11 buffer handle.
/// </summary>
/// <returns>The DirectX 11 buffer.</returns>
FORCE_INLINE BufferType* GetBufferHandleDX11() const
{
return _buffer;
}
public:
// [BaseType]
uint32 GetBufferSize() const override
{
return 0;
}
void* GetBufferHandle() const override
{
return _buffer;
}
};
/// <summary>
/// Vertex Shader for DirectX 11 backend.
/// </summary>
class GPUShaderProgramVSDX11 : public GPUShaderProgramDX11<GPUShaderProgramVS, ID3D11VertexShader>
{
private:
byte _inputLayoutSize;
ID3D11InputLayout* _inputLayout;
public:
/// <summary>
/// Initializes a new instance of the <see cref="GPUShaderProgramVSDX11"/> class.
/// </summary>
/// <param name="initializer">The program initialization data.</param>
/// <param name="buffer">The shader buffer object.</param>
/// <param name="inputLayout">The input layout.</param>
/// <param name="inputLayoutSize">Size of the input layout.</param>
GPUShaderProgramVSDX11(const GPUShaderProgramInitializer& initializer, ID3D11VertexShader* buffer, ID3D11InputLayout* inputLayout, byte inputLayoutSize)
: GPUShaderProgramDX11(initializer, buffer)
, _inputLayoutSize(inputLayoutSize)
, _inputLayout(inputLayout)
{
}
/// <summary>
/// Finalizes an instance of the <see cref="GPUShaderProgramVSDX11"/> class.
/// </summary>
~GPUShaderProgramVSDX11()
{
DX_SAFE_RELEASE_CHECK(_inputLayout, 0);
}
public:
/// <summary>
/// Gets the DirectX 11 input layout handle
/// </summary>
/// <returns>DirectX 11 input layout</returns>
FORCE_INLINE ID3D11InputLayout* GetInputLayoutDX11() const
{
return _inputLayout;
}
public:
// [GPUShaderProgramDX11]
void* GetInputLayout() const override
{
return (void*)_inputLayout;
}
byte GetInputLayoutSize() const override
{
return _inputLayoutSize;
}
};
/// <summary>
/// Hull Shader for DirectX 11 backend.
/// </summary>
class GPUShaderProgramHSDX11 : public GPUShaderProgramDX11<GPUShaderProgramHS, ID3D11HullShader>
{
public:
/// <summary>
/// Initializes a new instance of the <see cref="GPUShaderProgramHSDX11"/> class.
/// </summary>
/// <param name="initializer">The program initialization data.</param>
/// <param name="buffer">The shader buffer object.</param>
/// <param name="controlPointsCount">The control points used by the hull shader for processing.</param>
GPUShaderProgramHSDX11(const GPUShaderProgramInitializer& initializer, ID3D11HullShader* buffer, int32 controlPointsCount)
: GPUShaderProgramDX11(initializer, buffer)
{
_controlPointsCount = controlPointsCount;
}
};
/// <summary>
/// Domain Shader for DirectX 11 backend.
/// </summary>
class GPUShaderProgramDSDX11 : public GPUShaderProgramDX11<GPUShaderProgramDS, ID3D11DomainShader>
{
public:
/// <summary>
/// Initializes a new instance of the <see cref="GPUShaderProgramDSDX11"/> class.
/// </summary>
/// <param name="initializer">The program initialization data.</param>
/// <param name="buffer">The shader buffer object.</param>
GPUShaderProgramDSDX11(const GPUShaderProgramInitializer& initializer, ID3D11DomainShader* buffer)
: GPUShaderProgramDX11(initializer, buffer)
{
}
};
/// <summary>
/// Geometry Shader for DirectX 11 backend.
/// </summary>
class GPUShaderProgramGSDX11 : public GPUShaderProgramDX11<GPUShaderProgramGS, ID3D11GeometryShader>
{
public:
/// <summary>
/// Initializes a new instance of the <see cref="GPUShaderProgramGSDX11"/> class.
/// </summary>
/// <param name="initializer">The program initialization data.</param>
/// <param name="buffer">The shader buffer object.</param>
GPUShaderProgramGSDX11(const GPUShaderProgramInitializer& initializer, ID3D11GeometryShader* buffer)
: GPUShaderProgramDX11(initializer, buffer)
{
}
};
/// <summary>
/// Pixel Shader for DirectX 11 backend.
/// </summary>
class GPUShaderProgramPSDX11 : public GPUShaderProgramDX11<GPUShaderProgramPS, ID3D11PixelShader>
{
public:
/// <summary>
/// Initializes a new instance of the <see cref="GPUShaderProgramPSDX11"/> class.
/// </summary>
/// <param name="initializer">The program initialization data.</param>
/// <param name="buffer">The shader buffer object.</param>
GPUShaderProgramPSDX11(const GPUShaderProgramInitializer& initializer, ID3D11PixelShader* buffer)
: GPUShaderProgramDX11(initializer, buffer)
{
}
};
/// <summary>
/// Compute Shader for DirectX 11 backend.
/// </summary>
class GPUShaderProgramCSDX11 : public GPUShaderProgramDX11<GPUShaderProgramCS, ID3D11ComputeShader>
{
public:
/// <summary>
/// Initializes a new instance of the <see cref="GPUShaderProgramCSDX11"/> class.
/// </summary>
/// <param name="initializer">The program initialization data.</param>
/// <param name="buffer">The shader buffer object.</param>
GPUShaderProgramCSDX11(const GPUShaderProgramInitializer& initializer, ID3D11ComputeShader* buffer)
: GPUShaderProgramDX11(initializer, buffer)
{
}
};
#endif

View File

@@ -0,0 +1,256 @@
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
#if GRAPHICS_API_DIRECTX11
#include "GPUSwapChainDX11.h"
#include "Engine/Platform/Window.h"
#include "Engine/Graphics/RenderTools.h"
#include "Engine/GraphicsDevice/DirectX/RenderToolsDX.h"
#include "GPUContextDX11.h"
GPUSwapChainDX11::GPUSwapChainDX11(GPUDeviceDX11* device, Window* window)
: GPUResourceDX11(device, StringView::Empty)
#if PLATFORM_WINDOWS
, _windowHandle(static_cast<HWND>(window->GetNativePtr()))
#else
, _windowHandle(static_cast<IUnknown*>(window->GetNativePtr()))
#endif
, _swapChain(nullptr)
, _backBuffer(nullptr)
{
ASSERT(_windowHandle);
_window = window;
}
void GPUSwapChainDX11::getBackBuffer()
{
VALIDATE_DIRECTX_RESULT(_swapChain->GetBuffer(0, __uuidof(_backBuffer), reinterpret_cast<void**>(&_backBuffer)));
ID3D11RenderTargetView* rtv;
ID3D11ShaderResourceView* srv;
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateRenderTargetView(_backBuffer, nullptr, &rtv));
#if GPU_USE_WINDOW_SRV
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateShaderResourceView(_backBuffer, nullptr, &srv));
#else
srv = nullptr;
#endif
_backBufferHandle.Init(this, rtv, srv, nullptr, nullptr, _format, MSAALevel::None);
}
void GPUSwapChainDX11::releaseBackBuffer()
{
// Release data
_backBufferHandle.Release();
DX_SAFE_RELEASE_CHECK(_backBuffer, 0);
}
void GPUSwapChainDX11::OnReleaseGPU()
{
#if PLATFORM_WINDOWS
// Disable fullscreen mode
if (_swapChain)
{
VALIDATE_DIRECTX_RESULT(_swapChain->SetFullscreenState(false, nullptr));
}
#endif
// Release data
releaseBackBuffer();
DX_SAFE_RELEASE_CHECK(_swapChain, 0);
_width = _height = 0;
}
ID3D11Resource* GPUSwapChainDX11::GetResource()
{
return _backBuffer;
}
bool GPUSwapChainDX11::IsFullscreen()
{
// Check if has swap chain created
if (_swapChain == nullptr)
return false;
// Get state
BOOL state;
VALIDATE_DIRECTX_RESULT(_swapChain->GetFullscreenState(&state, nullptr));
return state == TRUE;
}
void GPUSwapChainDX11::SetFullscreen(bool isFullscreen)
{
#if PLATFORM_WINDOWS
if (_swapChain && isFullscreen != IsFullscreen())
{
_device->WaitForGPU();
GPUDeviceLock lock(_device);
DXGI_SWAP_CHAIN_DESC swapChainDesc;
_swapChain->GetDesc(&swapChainDesc);
// Setup target for fullscreen mode
IDXGIOutput* output = nullptr;
if (isFullscreen && _device->Outputs.HasItems())
{
const uint32 outputIdx = 0;
auto& outputDX = _device->Outputs[outputIdx];
output = outputDX.Output.Get();
swapChainDesc.BufferDesc = outputDX.DesktopViewMode;
}
releaseBackBuffer();
if (FAILED(_swapChain->ResizeTarget(&swapChainDesc.BufferDesc)))
{
LOG(Warning, "Swapchain resize failed.");
}
if (FAILED(_swapChain->SetFullscreenState(isFullscreen, output)))
{
LOG(Warning, "Cannot change fullscreen mode for '{0}' to {1}.", ToString(), isFullscreen);
}
VALIDATE_DIRECTX_RESULT(_swapChain->ResizeBuffers(swapChainDesc.BufferCount, _width, _height, swapChainDesc.BufferDesc.Format, swapChainDesc.Flags));
getBackBuffer();
}
#else
LOG(Info, "Cannot change fullscreen mode on this platform");
#endif
}
GPUTextureView* GPUSwapChainDX11::GetBackBufferView()
{
return &_backBufferHandle;
}
void GPUSwapChainDX11::Present(bool vsync)
{
// Present frame
ASSERT(_swapChain);
const HRESULT result = _swapChain->Present(vsync ? 1 : 0, 0);
LOG_DIRECTX_RESULT(result);
// Base
GPUSwapChain::Present(vsync);
}
bool GPUSwapChainDX11::Resize(int32 width, int32 height)
{
// Check if size won't change
if (width == _width && height == _height)
{
return false;
}
_device->WaitForGPU();
GPUDeviceLock lock(_device);
_format = GPU_BACK_BUFFER_PIXEL_FORMAT;
#if PLATFORM_WINDOWS
DXGI_SWAP_CHAIN_DESC swapChainDesc;
#else
DXGI_SWAP_CHAIN_DESC1 swapChainDesc;
#endif
if (_swapChain == nullptr)
{
ReleaseGPU();
// Create swap chain description
#if PLATFORM_WINDOWS
if (_device->Outputs.HasItems())
{
const uint32 outputIdx = 0;
auto& output = _device->Outputs[outputIdx];
swapChainDesc.BufferDesc = output.DesktopViewMode;
}
else
{
swapChainDesc.BufferDesc.RefreshRate.Numerator = 0;
swapChainDesc.BufferDesc.RefreshRate.Denominator = 0;
swapChainDesc.BufferDesc.Format = RenderToolsDX::ToDxgiFormat(_format);
swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
}
swapChainDesc.BufferDesc.Width = width;
swapChainDesc.BufferDesc.Height = height;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 2;
swapChainDesc.OutputWindow = _windowHandle;
swapChainDesc.Windowed = TRUE;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
#else
swapChainDesc.Width = width;
swapChainDesc.Height = height;
swapChainDesc.Format = RenderToolsDX::ToDxgiFormat(_format);
swapChainDesc.Stereo = false;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 2;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
swapChainDesc.Scaling = DXGI_SCALING_NONE;
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
#endif
#if GPU_USE_WINDOW_SRV
swapChainDesc.BufferUsage |= DXGI_USAGE_SHADER_INPUT;
#endif
// Create swap chain
#if PLATFORM_WINDOWS
auto dxgi = _device->GetDXGIFactory();
VALIDATE_DIRECTX_RESULT(dxgi->CreateSwapChain(_device->GetDevice(), &swapChainDesc, &_swapChain));
ASSERT(_swapChain);
// Disable DXGI changes to the window
VALIDATE_DIRECTX_RESULT(dxgi->MakeWindowAssociation(_windowHandle, DXGI_MWA_NO_WINDOW_CHANGES | DXGI_MWA_NO_ALT_ENTER));
#else
auto dxgiFactory = (IDXGIFactory2*)_device->GetDXGIFactory();
VALIDATE_DIRECTX_RESULT(dxgiFactory->CreateSwapChainForCoreWindow(_device->GetDevice(), static_cast<IUnknown*>(_windowHandle), &swapChainDesc, nullptr, &_swapChain));
ASSERT(_swapChain);
// Ensure that DXGI does not queue more than one frame at a time. This both reduces latency and
// ensures that the application will only render after each VSync, minimizing power consumption.
ComPtr<IDXGIDevice2> dxgiDevice;
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->QueryInterface(IID_PPV_ARGS(&dxgiDevice)));
VALIDATE_DIRECTX_RESULT(dxgiDevice->SetMaximumFrameLatency(1));
#endif
}
else
{
releaseBackBuffer();
#if PLATFORM_WINDOWS
_swapChain->GetDesc(&swapChainDesc);
VALIDATE_DIRECTX_RESULT(_swapChain->ResizeBuffers(swapChainDesc.BufferCount, width, height, swapChainDesc.BufferDesc.Format, swapChainDesc.Flags));
#else
_swapChain->GetDesc1(&swapChainDesc);
VALIDATE_DIRECTX_RESULT(_swapChain->ResizeBuffers(swapChainDesc.BufferCount, width, height, swapChainDesc.Format, swapChainDesc.Flags));
#endif
}
_width = width;
_height = height;
#if PLATFORM_WINDOWS
_memoryUsage = CalculateTextureMemoryUsage(RenderToolsDX::ToPixelFormat(swapChainDesc.BufferDesc.Format), _width, _height, 1) * swapChainDesc.BufferCount;
#else
_memoryUsage = CalculateTextureMemoryUsage(RenderToolsDX::ToPixelFormat(swapChainDesc.Format), _width, _height, 1) * swapChainDesc.BufferCount;
#endif
getBackBuffer();
return false;
}
void GPUSwapChainDX11::CopyBackbuffer(GPUContext* context, GPUTexture* dst)
{
const auto contextDX11 = (GPUContextDX11*)context;
contextDX11->GetContext()->CopyResource((ID3D11Resource*)dst->GetNativePtr(), _backBuffer);
}
#endif

View File

@@ -0,0 +1,61 @@
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
#pragma once
#include "GPUDeviceDX11.h"
#include "GPUTextureDX11.h"
#include "Engine/Graphics/GPUSwapChain.h"
#include "../IncludeDirectXHeaders.h"
#if GRAPHICS_API_DIRECTX11
/// <summary>
/// Graphics Device rendering output for DirectX 11 backend.
/// </summary>
class GPUSwapChainDX11 : public GPUResourceDX11<GPUSwapChain>
{
friend class WindowsWindow;
friend class GPUContextDX11;
friend GPUDeviceDX11;
private:
#if PLATFORM_WINDOWS
HWND _windowHandle;
IDXGISwapChain* _swapChain;
#else
IUnknown* _windowHandle;
IDXGISwapChain1* _swapChain;
#endif
ID3D11Texture2D* _backBuffer;
GPUTextureViewDX11 _backBufferHandle;
public:
GPUSwapChainDX11(GPUDeviceDX11* device, Window* window);
private:
void getBackBuffer();
void releaseBackBuffer();
public:
// [GPUResourceDX11]
ID3D11Resource* GetResource() override;
// [GPUSwapChain]
bool IsFullscreen() override;
void SetFullscreen(bool isFullscreen) override;
GPUTextureView* GetBackBufferView() override;
void Present(bool vsync) override;
bool Resize(int32 width, int32 height) override;
void CopyBackbuffer(GPUContext* context, GPUTexture* dst) override;
protected:
// [GPUResourceDX11]
void OnReleaseGPU() final override;
};
#endif

View File

@@ -0,0 +1,604 @@
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
#if GRAPHICS_API_DIRECTX11
#include "GPUTextureDX11.h"
#include "Engine/Graphics/PixelFormatExtensions.h"
#include "Engine/Graphics/Textures/TextureData.h"
#include "Engine/GraphicsDevice/DirectX/RenderToolsDX.h"
bool GPUTextureDX11::OnInit()
{
// Cache formats
const PixelFormat format = Format();
const PixelFormat typelessFormat = PixelFormatExtensions::MakeTypeless(format);
const DXGI_FORMAT dxgiFormat = RenderToolsDX::ToDxgiFormat(typelessFormat);
_dxgiFormatDSV = RenderToolsDX::ToDxgiFormat(PixelFormatExtensions::FindDepthStencilFormat(format));
_dxgiFormatSRV = RenderToolsDX::ToDxgiFormat(PixelFormatExtensions::FindShaderResourceFormat(format, _sRGB));
_dxgiFormatRTV = _dxgiFormatSRV;
_dxgiFormatUAV = RenderToolsDX::ToDxgiFormat(PixelFormatExtensions::FindUnorderedAccessFormat(format));
// Cache properties
auto device = _device->GetDevice();
bool useSRV = IsShaderResource();
bool useDSV = IsDepthStencil();
bool useRTV = IsRenderTarget();
bool useUAV = IsUnorderedAccess();
// Create resource
HRESULT result;
if (IsVolume())
{
// Create texture description
D3D11_TEXTURE3D_DESC textureDesc;
textureDesc.MipLevels = MipLevels();
textureDesc.Format = dxgiFormat;
textureDesc.Width = Width();
textureDesc.Height = Height();
textureDesc.Depth = Depth();
textureDesc.BindFlags = 0;
textureDesc.CPUAccessFlags = RenderToolsDX::GetDX11CpuAccessFlagsFromUsage(_desc.Usage);
textureDesc.MiscFlags = 0;
textureDesc.Usage = RenderToolsDX::ToD3D11Usage(_desc.Usage);
if (useSRV)
textureDesc.BindFlags |= D3D11_BIND_SHADER_RESOURCE;
if (useRTV)
textureDesc.BindFlags |= D3D11_BIND_RENDER_TARGET;
if (useDSV)
textureDesc.BindFlags |= D3D11_BIND_DEPTH_STENCIL;
if (useUAV)
textureDesc.BindFlags |= D3D11_BIND_UNORDERED_ACCESS;
// Create texture
ID3D11Texture3D* texture;
result = device->CreateTexture3D(&textureDesc, nullptr, &texture);
_resource = texture;
}
else
{
// Create texture description
D3D11_TEXTURE2D_DESC textureDesc;
textureDesc.MipLevels = MipLevels();
textureDesc.Format = dxgiFormat;
textureDesc.Width = Width();
textureDesc.Height = Height();
textureDesc.Usage = RenderToolsDX::ToD3D11Usage(_desc.Usage);
textureDesc.BindFlags = 0;
textureDesc.CPUAccessFlags = RenderToolsDX::GetDX11CpuAccessFlagsFromUsage(_desc.Usage);
textureDesc.ArraySize = ArraySize();
textureDesc.SampleDesc.Count = static_cast<UINT>(_desc.MultiSampleLevel);
textureDesc.SampleDesc.Quality = 0;
textureDesc.MiscFlags = 0;
if (useSRV)
textureDesc.BindFlags |= D3D11_BIND_SHADER_RESOURCE;
if (useRTV)
textureDesc.BindFlags |= D3D11_BIND_RENDER_TARGET;
if (useDSV)
textureDesc.BindFlags |= D3D11_BIND_DEPTH_STENCIL;
if (useUAV)
textureDesc.BindFlags |= D3D11_BIND_UNORDERED_ACCESS;
if (_device->GetFeatureLevel() >= FeatureLevel::SM5 && IsMultiSample())
textureDesc.SampleDesc.Quality = D3D11_STANDARD_MULTISAMPLE_PATTERN;
if (IsCubeMap())
textureDesc.MiscFlags |= D3D11_RESOURCE_MISC_TEXTURECUBE;
// Create texture
ID3D11Texture2D* texture;
result = device->CreateTexture2D(&textureDesc, nullptr, &texture);
_resource = texture;
}
LOG_DIRECTX_RESULT_WITH_RETURN(result);
ASSERT(_resource != nullptr);
DX_SET_DEBUG_NAME(_resource, GetName());
// Update memory usage
_memoryUsage = calculateMemoryUsage();
// Initialize handles to the resource
if (IsRegularTexture())
{
// 'Regular' texture is using only one handle (texture/cubemap)
_handlesPerSlice.Resize(1, false);
}
else
{
// Create all handles
initHandles();
}
return false;
}
void GPUTextureDX11::onResidentMipsChanged()
{
// We support changing resident mip maps only for regular textures (render targets and depth buffers don't use that feature at all)
ASSERT(IsRegularTexture() && _handlesPerSlice.Count() == 1);
ASSERT(!IsVolume());
// Fill description
D3D11_SHADER_RESOURCE_VIEW_DESC srDesc;
srDesc.Format = _dxgiFormatSRV;
if (IsCubeMap())
{
srDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
srDesc.TextureCube.MostDetailedMip = MipLevels() - ResidentMipLevels();
srDesc.TextureCube.MipLevels = ResidentMipLevels();
}
else
{
srDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srDesc.Texture2D.MostDetailedMip = MipLevels() - ResidentMipLevels();
srDesc.Texture2D.MipLevels = ResidentMipLevels();
}
// Create new view
ID3D11ShaderResourceView* srView;
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateShaderResourceView(_resource, &srDesc, &srView));
// Change view
if (_handlesPerSlice[0].GetParent() == nullptr)
_handlesPerSlice[0].Init(this, nullptr, srView, nullptr, nullptr, Format(), MultiSampleLevel());
else
_handlesPerSlice[0].SetSRV(srView);
}
void GPUTextureDX11::OnReleaseGPU()
{
_handlesPerMip.Resize(0, false);
_handlesPerSlice.Resize(0, false);
_handleArray.Release();
_handleVolume.Release();
_handleReadOnlyDepth.Release();
DX_SAFE_RELEASE_CHECK(_resource, 0);
// Base
GPUTexture::OnReleaseGPU();
}
#define CLEAR_VIEWS() rtView = nullptr; srView = nullptr; dsView = nullptr; uaView = nullptr
void GPUTextureDX11::initHandles()
{
ID3D11RenderTargetView* rtView;
ID3D11ShaderResourceView* srView;
ID3D11DepthStencilView* dsView;
ID3D11UnorderedAccessView* uaView;
D3D11_RENDER_TARGET_VIEW_DESC rtDesc;
D3D11_SHADER_RESOURCE_VIEW_DESC srDesc;
D3D11_DEPTH_STENCIL_VIEW_DESC dsDesc;
D3D11_UNORDERED_ACCESS_VIEW_DESC uaDesc;
CLEAR_VIEWS();
rtDesc.Format = _dxgiFormatRTV;
srDesc.Format = _dxgiFormatSRV;
dsDesc.Format = _dxgiFormatDSV;
dsDesc.Flags = 0;
uaDesc.Format = _dxgiFormatUAV;
// Cache properties
auto device = _device->GetDevice();
bool useSRV = IsShaderResource();
bool useDSV = IsDepthStencil();
bool useRTV = IsRenderTarget();
bool useUAV = IsUnorderedAccess();
int32 arraySize = ArraySize();
int32 mipLevels = MipLevels();
bool isArray = arraySize > 1;
bool isCubeMap = IsCubeMap();
bool isMsaa = IsMultiSample();
bool isVolume = IsVolume();
auto format = Format();
auto msaa = MultiSampleLevel();
// Create resource views
if (isVolume)
{
// Create handle for whole 3d texture
if (useSRV)
{
srDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
srDesc.Texture3D.MostDetailedMip = 0;
srDesc.Texture3D.MipLevels = mipLevels;
VALIDATE_DIRECTX_RESULT(device->CreateShaderResourceView(_resource, &srDesc, &srView));
}
if (useRTV)
{
rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D;
rtDesc.Texture3D.MipSlice = 0;
rtDesc.Texture3D.FirstWSlice = 0;
rtDesc.Texture3D.WSize = Depth();
VALIDATE_DIRECTX_RESULT(device->CreateRenderTargetView(_resource, &rtDesc, &rtView));
}
if (useUAV)
{
uaDesc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE3D;
uaDesc.Texture3D.MipSlice = 0;
uaDesc.Texture3D.WSize = Depth();
uaDesc.Texture3D.FirstWSlice = 0;
VALIDATE_DIRECTX_RESULT(device->CreateUnorderedAccessView(_resource, &uaDesc, &uaView));
}
_handleVolume.Init(this, rtView, srView, nullptr, uaView, format, msaa);
// Init per slice views
_handlesPerSlice.Resize(Depth(), false);
if (_desc.HasPerSliceViews() && useRTV)
{
rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D;
rtDesc.Texture3D.MipSlice = 0;
rtDesc.Texture3D.WSize = 1;
for (int32 sliceIndex = 0; sliceIndex < Depth(); sliceIndex++)
{
rtDesc.Texture3D.FirstWSlice = sliceIndex;
VALIDATE_DIRECTX_RESULT(device->CreateRenderTargetView(_resource, &rtDesc, &rtView));
_handlesPerSlice[sliceIndex].Init(this, rtView, nullptr, nullptr, nullptr, format, msaa);
}
}
}
else if (isArray)
{
// Resize handles
_handlesPerSlice.Resize(ArraySize(), false);
// Create per array slice handles
for (int32 arrayIndex = 0; arrayIndex < arraySize; arrayIndex++)
{
CLEAR_VIEWS();
if (useDSV)
{
/*if (isCubeMap)
{
dsDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
dsDesc.Texture2DArray.ArraySize = 6;
dsDesc.Texture2DArray.FirstArraySlice = arrayIndex * 6;
dsDesc.Texture2DArray.MipSlice = 0;
}
else*/
{
dsDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
dsDesc.Texture2DArray.ArraySize = 1;
dsDesc.Texture2DArray.FirstArraySlice = arrayIndex;
dsDesc.Texture2DArray.MipSlice = 0;
}
VALIDATE_DIRECTX_RESULT(device->CreateDepthStencilView(_resource, &dsDesc, &dsView));
}
if (useRTV)
{
/*if (isCubeMap)
{
rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
rtDesc.Texture2DArray.ArraySize = 6;
rtDesc.Texture2DArray.FirstArraySlice = arrayIndex * 6;
rtDesc.Texture2DArray.MipSlice = 0;
}
else*/
{
rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
rtDesc.Texture2DArray.ArraySize = 1;
rtDesc.Texture2DArray.FirstArraySlice = arrayIndex;
rtDesc.Texture2DArray.MipSlice = 0;
}
VALIDATE_DIRECTX_RESULT(device->CreateRenderTargetView(_resource, &rtDesc, &rtView));
}
if (useSRV)
{
// When GetFeatureLevel returns D3D_FEATURE_LEVEL_10_0 or less, Resources created with D3D11_RESOURCE_MISC_TEXTURECUBE may only be treated as cubemap ShaderResourceViews.
// (ViewDimension must be D3D11_SRV_DIMENSION_TEXTURECUBE) [ STATE_CREATION ERROR #126: CREATESHADERRESOURCEVIEW_INVALIDDESC]
if (isCubeMap && _device->GetRendererType() != RendererType::DirectX10)
{
RendererType aa = _device->GetRendererType();
/*if (isCubeMap)
{
srDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBEARRAY;
srDesc.TextureCubeArray.First2DArrayFace = arrayIndex * 6;
srDesc.TextureCubeArray.NumCubes = 1;
srDesc.TextureCubeArray.MipLevels = mipLevels;
srDesc.TextureCubeArray.MostDetailedMip = 0;
}
else*/
{
srDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
srDesc.Texture2DArray.ArraySize = 1;
srDesc.Texture2DArray.FirstArraySlice = arrayIndex;
srDesc.Texture2DArray.MipLevels = mipLevels;
srDesc.Texture2DArray.MostDetailedMip = 0;
}
VALIDATE_DIRECTX_RESULT(device->CreateShaderResourceView(_resource, &srDesc, &srView));
}
}
_handlesPerSlice[arrayIndex].Init(this, rtView, srView, dsView, nullptr, format, msaa);
}
// Create whole array handle
{
CLEAR_VIEWS();
if (useDSV)
{
dsDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
dsDesc.Texture2DArray.ArraySize = arraySize;
dsDesc.Texture2DArray.FirstArraySlice = 0;
dsDesc.Texture2DArray.MipSlice = 0;
VALIDATE_DIRECTX_RESULT(device->CreateDepthStencilView(_resource, &dsDesc, &dsView));
}
if (useRTV)
{
rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
rtDesc.Texture2DArray.ArraySize = arraySize;
rtDesc.Texture2DArray.FirstArraySlice = 0;
rtDesc.Texture2DArray.MipSlice = 0;
VALIDATE_DIRECTX_RESULT(device->CreateRenderTargetView(_resource, &rtDesc, &rtView));
}
if (useSRV)
{
if (isCubeMap)
{
srDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
srDesc.TextureCube.MostDetailedMip = 0;
srDesc.TextureCube.MipLevels = mipLevels;
}
else
{
srDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
srDesc.Texture2DArray.ArraySize = arraySize;
srDesc.Texture2DArray.FirstArraySlice = 0;
srDesc.Texture2DArray.MipLevels = mipLevels;
srDesc.Texture2DArray.MostDetailedMip = 0;
}
VALIDATE_DIRECTX_RESULT(device->CreateShaderResourceView(_resource, &srDesc, &srView));
}
if (useUAV)
{
uaDesc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2DARRAY;
uaDesc.Texture2DArray.MipSlice = 0;
uaDesc.Texture2DArray.ArraySize = arraySize;
uaDesc.Texture2DArray.FirstArraySlice = 0;
VALIDATE_DIRECTX_RESULT(device->CreateUnorderedAccessView(_resource, &uaDesc, &uaView));
}
_handleArray.Init(this, rtView, srView, dsView, uaView, format, msaa);
}
}
else
{
// Resize handles
_handlesPerSlice.Resize(1, false);
CLEAR_VIEWS();
// Create single handle for the whole texture
if (useDSV)
{
if (isCubeMap)
{
dsDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
dsDesc.Texture2DArray.MipSlice = 0;
dsDesc.Texture2DArray.FirstArraySlice = 0;
dsDesc.Texture2DArray.ArraySize = arraySize * 6;
}
else if (isMsaa)
{
dsDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS;
}
else
{
dsDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
dsDesc.Texture2D.MipSlice = 0;
}
VALIDATE_DIRECTX_RESULT(device->CreateDepthStencilView(_resource, &dsDesc, &dsView));
}
if (useRTV)
{
if (isCubeMap)
{
rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
rtDesc.Texture2DArray.MipSlice = 0;
rtDesc.Texture2DArray.FirstArraySlice = 0;
rtDesc.Texture2DArray.ArraySize = arraySize * 6;
}
else if (isMsaa)
{
rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS;
}
else
{
rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
rtDesc.Texture2D.MipSlice = 0;
}
VALIDATE_DIRECTX_RESULT(device->CreateRenderTargetView(_resource, &rtDesc, &rtView));
}
if (useSRV)
{
if (isCubeMap)
{
srDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
srDesc.TextureCube.MostDetailedMip = 0;
srDesc.TextureCube.MipLevels = mipLevels;
}
else if (isMsaa)
{
srDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMS;
}
else
{
srDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srDesc.Texture2D.MostDetailedMip = 0;
srDesc.Texture2D.MipLevels = mipLevels;
}
VALIDATE_DIRECTX_RESULT(device->CreateShaderResourceView(_resource, &srDesc, &srView));
}
if (useUAV)
{
uaDesc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D;
uaDesc.Texture2D.MipSlice = 0;
VALIDATE_DIRECTX_RESULT(device->CreateUnorderedAccessView(_resource, &uaDesc, &uaView));
}
_handlesPerSlice[0].Init(this, rtView, srView, dsView, uaView, format, msaa);
}
// Init per mip map handles
if (HasPerMipViews())
{
// Init handles
_handlesPerMip.Resize(arraySize, false);
for (int32 arrayIndex = 0; arrayIndex < arraySize; arrayIndex++)
{
auto& slice = _handlesPerMip[arrayIndex];
slice.Resize(mipLevels, false);
for (int32 mipIndex = 0; mipIndex < mipLevels; mipIndex++)
{
dsView = nullptr;
rtView = nullptr;
srView = nullptr;
// DSV
if (useDSV)
{
dsDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
dsDesc.Texture2DArray.ArraySize = 1;
dsDesc.Texture2DArray.FirstArraySlice = arrayIndex;
dsDesc.Texture2DArray.MipSlice = mipIndex;
_device->GetDevice()->CreateDepthStencilView(_resource, &dsDesc, &dsView);
}
// RTV
if (useRTV)
{
rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
rtDesc.Texture2DArray.ArraySize = 1;
rtDesc.Texture2DArray.FirstArraySlice = arrayIndex;
rtDesc.Texture2DArray.MipSlice = mipIndex;
_device->GetDevice()->CreateRenderTargetView(_resource, &rtDesc, &rtView);
}
// SRV
if (useSRV)
{
// When GetFeatureLevel returns D3D_FEATURE_LEVEL_10_0 or less, Resources created with D3D11_RESOURCE_MISC_TEXTURECUBE may only be treated as cubemap ShaderResourceViews.
// (ViewDimension must be D3D11_SRV_DIMENSION_TEXTURECUBE) [ STATE_CREATION ERROR #126: CREATESHADERRESOURCEVIEW_INVALIDDESC]
if ((isCubeMap && _device->GetRendererType() == RendererType::DirectX10) == false)
{
srDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
srDesc.Texture2DArray.ArraySize = 1;
srDesc.Texture2DArray.FirstArraySlice = arrayIndex;
srDesc.Texture2DArray.MipLevels = 1;
srDesc.Texture2DArray.MostDetailedMip = mipIndex;
_device->GetDevice()->CreateShaderResourceView(_resource, &srDesc, &srView);
}
}
slice[mipIndex].Init(this, rtView, srView, dsView, nullptr, format, msaa);
}
}
}
// Read-only depth-stencil
if (_desc.Flags & GPUTextureFlags::ReadOnlyDepthView)
{
CLEAR_VIEWS();
// Create single handle for the whole texture
if (useDSV)
{
if (isCubeMap)
{
dsDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
dsDesc.Texture2DArray.MipSlice = 0;
dsDesc.Texture2DArray.FirstArraySlice = 0;
dsDesc.Texture2DArray.ArraySize = arraySize * 6;
}
else if (isMsaa)
{
dsDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS;
}
else
{
dsDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
dsDesc.Texture2D.MipSlice = 0;
}
dsDesc.Flags = D3D11_DSV_READ_ONLY_DEPTH;
if (PixelFormatExtensions::HasStencil(format))
dsDesc.Flags |= D3D11_DSV_READ_ONLY_STENCIL;
VALIDATE_DIRECTX_RESULT(device->CreateDepthStencilView(_resource, &dsDesc, &dsView));
}
ASSERT(!useRTV);
rtView = nullptr;
if (useSRV)
{
if (isCubeMap)
{
srDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
srDesc.TextureCube.MostDetailedMip = 0;
srDesc.TextureCube.MipLevels = mipLevels;
}
else if (isMsaa)
{
srDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMS;
}
else
{
srDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srDesc.Texture2D.MostDetailedMip = 0;
srDesc.Texture2D.MipLevels = mipLevels;
}
VALIDATE_DIRECTX_RESULT(device->CreateShaderResourceView(_resource, &srDesc, &srView));
}
_handleReadOnlyDepth.Init(this, rtView, srView, dsView, nullptr, format, msaa);
}
}
bool GPUTextureDX11::GetData(int32 arrayOrDepthSliceIndex, int32 mipMapIndex, TextureMipData& data, uint32 mipRowPitch)
{
if (!IsStaging())
{
LOG(Warning, "Texture::GetData is valid only for staging resources.");
return true;
}
GPUDeviceLock lock(_device);
// Map the staging resource mip map for reading
const uint32 subresource = RenderToolsDX::CalcSubresourceIndex(mipMapIndex, arrayOrDepthSliceIndex, MipLevels());
D3D11_MAPPED_SUBRESOURCE mapped;
const HRESULT mapResult = _device->GetIM()->Map(_resource, subresource, D3D11_MAP_READ, 0, &mapped);
if (FAILED(mapResult))
{
LOG_DIRECTX_RESULT(mapResult);
return true;
}
// Check if target row pitch is the same
if (mipRowPitch == mapped.RowPitch || mipRowPitch == 0)
{
// Init mip info
data.Lines = mapped.DepthPitch / mapped.RowPitch;
data.DepthPitch = mapped.DepthPitch;
data.RowPitch = mapped.RowPitch;
// Copy data
data.Data.Copy((byte*)mapped.pData, mapped.DepthPitch);
}
else
{
// Init mip info
data.Lines = mapped.DepthPitch / mapped.RowPitch;
data.DepthPitch = mipRowPitch * data.Lines;
data.RowPitch = mipRowPitch;
// Copy data
data.Data.Allocate(data.DepthPitch);
for (uint32 i = 0; i < data.Lines; i++)
{
Platform::MemoryCopy(data.Data.Get() + data.RowPitch * i, ((byte*)mapped.pData) + mapped.RowPitch * i, data.RowPitch);
}
}
// Unmap texture
_device->GetIM()->Unmap(_resource, subresource);
return false;
}
#endif

View File

@@ -0,0 +1,284 @@
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Core/Collections/Array.h"
#include "Engine/Graphics/Textures/GPUTexture.h"
#include "GPUDeviceDX11.h"
#include "IShaderResourceDX11.h"
#if GRAPHICS_API_DIRECTX11
/// <summary>
/// The texture view for DirectX 11 backend.
/// </summary>
/// <seealso cref="GPUTextureView" />
/// <seealso cref="IShaderResourceDX11" />
class GPUTextureViewDX11 : public GPUTextureView, public IShaderResourceDX11
{
private:
ID3D11RenderTargetView* _rtv = nullptr;
ID3D11ShaderResourceView* _srv = nullptr;
ID3D11DepthStencilView* _dsv = nullptr;
ID3D11UnorderedAccessView* _uav = nullptr;
public:
/// <summary>
/// Initializes a new instance of the <see cref="GPUTextureViewDX11"/> class.
/// </summary>
GPUTextureViewDX11()
{
}
GPUTextureViewDX11(const GPUTextureViewDX11& other)
: GPUTextureViewDX11()
{
#if !BUILD_RELEASE
CRASH; // Not used
#endif
}
GPUTextureViewDX11& operator=(const GPUTextureViewDX11& other)
{
#if !BUILD_RELEASE
CRASH; // Not used
#endif
return *this;
}
/// <summary>
/// Finalizes an instance of the <see cref="GPUTextureViewDX11"/> class.
/// </summary>
~GPUTextureViewDX11()
{
Release();
}
public:
/// <summary>
/// Init
/// </summary>
/// <param name="parent">Resource that owns that handle</param>
/// <param name="rtv">Render Target View</param>
/// <param name="srv">Shader Resource view</param>
/// <param name="dsv">Depth Stencil View</param>
/// <param name="uav">Unordered Access View</param>
/// <param name="format">Parent texture format</param>
/// <param name="msaa">Parent texture multi-sample level</param>
void Init(GPUResource* parent, ID3D11RenderTargetView* rtv, ID3D11ShaderResourceView* srv, ID3D11DepthStencilView* dsv, ID3D11UnorderedAccessView* uav, PixelFormat format, MSAALevel msaa)
{
GPUTextureView::Init(parent, format, msaa);
_rtv = rtv;
_srv = srv;
_dsv = dsv;
_uav = uav;
}
/// <summary>
/// Release the view.
/// </summary>
void Release()
{
DX_SAFE_RELEASE_CHECK(_rtv, 0);
DX_SAFE_RELEASE_CHECK(_srv, 0);
DX_SAFE_RELEASE_CHECK(_dsv, 0);
DX_SAFE_RELEASE_CHECK(_uav, 0);
}
public:
/// <summary>
/// Sets new render target view.
/// </summary>
/// <param name="rtv">A new render target view.</param>
void SetRTV(ID3D11RenderTargetView* rtv)
{
DX_SAFE_RELEASE_CHECK(_rtv, 0);
_rtv = rtv;
}
/// <summary>
/// Sets new shader resource view.
/// </summary>
/// <param name="srv">A new shader resource view.</param>
void SetSRV(ID3D11ShaderResourceView* srv)
{
DX_SAFE_RELEASE_CHECK(_srv, 0);
_srv = srv;
}
/// <summary>
/// Sets new depth stencil view.
/// </summary>
/// <param name="dsv">A new depth stencil view.</param>
void SetDSV(ID3D11DepthStencilView* dsv)
{
DX_SAFE_RELEASE_CHECK(_dsv, 0);
_dsv = dsv;
}
/// <summary>
/// Sets new unordered access view.
/// </summary>
/// <param name="uav">A new unordered access view.</param>
void SetUAV(ID3D11UnorderedAccessView* uav)
{
DX_SAFE_RELEASE_CHECK(_uav, 0);
_uav = uav;
}
public:
/// <summary>
/// Gets the render target view.
/// </summary>
/// <returns>The render target view.</returns>
ID3D11RenderTargetView* RTV() const
{
return _rtv;
}
/// <summary>
/// Gets the depth stencil view.
/// </summary>
/// <returns>The depth stencil view.</returns>
ID3D11DepthStencilView* DSV() const
{
return _dsv;
}
public:
// [GPUResourceView]
void* GetNativePtr() const override
{
return (void*)(IShaderResourceDX11*)this;
}
// [IShaderResourceDX11]
ID3D11ShaderResourceView* SRV() const override
{
return _srv;
}
ID3D11UnorderedAccessView* UAV() const override
{
return _uav;
}
};
/// <summary>
/// Texture object for DirectX 11 backend.
/// </summary>
class GPUTextureDX11 : public GPUResourceDX11<GPUTexture>
{
private:
ID3D11Resource* _resource = nullptr;
GPUTextureViewDX11 _handleArray;
GPUTextureViewDX11 _handleVolume;
GPUTextureViewDX11 _handleReadOnlyDepth;
Array<GPUTextureViewDX11> _handlesPerSlice; // [slice]
Array<Array<GPUTextureViewDX11>> _handlesPerMip; // [slice][mip]
DXGI_FORMAT _dxgiFormatDSV;
DXGI_FORMAT _dxgiFormatSRV;
DXGI_FORMAT _dxgiFormatRTV;
DXGI_FORMAT _dxgiFormatUAV;
public:
/// <summary>
/// Initializes a new instance of the <see cref="GPUTextureDX11"/> class.
/// </summary>
/// <param name="device">The device.</param>
/// <param name="name">The name.</param>
GPUTextureDX11(GPUDeviceDX11* device, const StringView& name)
: GPUResourceDX11<GPUTexture>(device, name)
{
}
public:
/// <summary>
/// Gets DX11 texture resource.
/// </summary>
/// <returns>DX11 texture resource.</returns>
FORCE_INLINE ID3D11Resource* GetResource() const
{
return _resource;
}
private:
void initHandles();
ID3D11Texture2D* GetTexture2D() const
{
ASSERT(_desc.Dimensions == TextureDimensions::Texture || _desc.Dimensions == TextureDimensions::CubeTexture);
return (ID3D11Texture2D*)_resource;
}
ID3D11Texture3D* GetTexture3D() const
{
ASSERT(_desc.Dimensions == TextureDimensions::VolumeTexture);
return (ID3D11Texture3D*)_resource;
}
public:
// [GPUTexture]
GPUTextureView* View(int32 arrayOrDepthIndex) const override
{
return (GPUTextureView*)&_handlesPerSlice[arrayOrDepthIndex];
}
GPUTextureView* View(int32 arrayOrDepthIndex, int32 mipMapIndex) const override
{
return (GPUTextureView*)&_handlesPerMip[arrayOrDepthIndex][mipMapIndex];
}
GPUTextureView* ViewArray() const override
{
ASSERT(ArraySize() > 1);
return (GPUTextureView*)&_handleArray;
}
GPUTextureView* ViewVolume() const override
{
ASSERT(IsVolume());
return (GPUTextureView*)&_handleVolume;
}
GPUTextureView* ViewReadOnlyDepth() const override
{
ASSERT(_desc.Flags & GPUTextureFlags::ReadOnlyDepthView);
return (GPUTextureView*)&_handleReadOnlyDepth;
}
void* GetNativePtr() const override
{
return static_cast<void*>(_resource);
}
bool GetData(int32 arrayOrDepthSliceIndex, int32 mipMapIndex, TextureMipData& data, uint32 mipRowPitch) override;
// [GPUResourceDX11]
ID3D11Resource* GetResource() override
{
return _resource;
}
protected:
// [GPUTexture]
bool OnInit() override;
void onResidentMipsChanged() override;
void OnReleaseGPU() override;
};
#endif

View File

@@ -0,0 +1,124 @@
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
#if GRAPHICS_API_DIRECTX11
#include "GPUTimerQueryDX11.h"
GPUTimerQueryDX11::GPUTimerQueryDX11(GPUDeviceDX11* device)
: GPUResourceDX11<GPUTimerQuery>(device, String::Empty)
{
D3D11_QUERY_DESC queryDesc;
queryDesc.Query = D3D11_QUERY_TIMESTAMP_DISJOINT;
queryDesc.MiscFlags = 0;
HRESULT hr = device->GetDevice()->CreateQuery(&queryDesc, &_disjointQuery);
if (hr != S_OK)
{
LOG(Fatal, "Failed to create a timer query.");
}
queryDesc.Query = D3D11_QUERY_TIMESTAMP;
hr = device->GetDevice()->CreateQuery(&queryDesc, &_beginQuery);
if (hr != S_OK)
{
LOG(Fatal, "Failed to create a timer query.");
}
hr = device->GetDevice()->CreateQuery(&queryDesc, &_endQuery);
if (hr != S_OK)
{
LOG(Fatal, "Failed to create a timer query.");
}
// Set non-zero mem usage (fake)
_memoryUsage = sizeof(D3D11_QUERY_DESC) * 3;
}
GPUTimerQueryDX11::~GPUTimerQueryDX11()
{
if (_beginQuery)
_beginQuery->Release();
if (_endQuery)
_endQuery->Release();
if (_disjointQuery)
_disjointQuery->Release();
}
void GPUTimerQueryDX11::OnReleaseGPU()
{
SAFE_RELEASE(_beginQuery);
SAFE_RELEASE(_endQuery);
SAFE_RELEASE(_disjointQuery);
}
ID3D11Resource* GPUTimerQueryDX11::GetResource()
{
return nullptr;
}
void GPUTimerQueryDX11::Begin()
{
auto context = _device->GetIM();
context->Begin(_disjointQuery);
context->End(_beginQuery);
_endCalled = false;
}
void GPUTimerQueryDX11::End()
{
if (_endCalled)
return;
auto context = _device->GetIM();
context->End(_endQuery);
context->End(_disjointQuery);
_endCalled = true;
_finalized = false;
}
bool GPUTimerQueryDX11::HasResult()
{
if (!_endCalled)
return false;
D3D11_QUERY_DATA_TIMESTAMP_DISJOINT disjointData;
return _device->GetIM()->GetData(_disjointQuery, &disjointData, sizeof(disjointData), 0) == S_OK;
}
float GPUTimerQueryDX11::GetResult()
{
if (!_finalized)
{
#if BUILD_DEBUG
ASSERT(HasResult());
#endif
UINT64 timeStart, timeEnd;
auto context = _device->GetIM();
context->GetData(_beginQuery, &timeStart, sizeof(timeStart), 0);
context->GetData(_endQuery, &timeEnd, sizeof(timeEnd), 0);
D3D11_QUERY_DATA_TIMESTAMP_DISJOINT disjointData;
context->GetData(_disjointQuery, &disjointData, sizeof(disjointData), 0);
if (disjointData.Disjoint == FALSE)
{
const float frequency = static_cast<float>(disjointData.Frequency);
const UINT64 delta = timeEnd - timeStart;
_timeDelta = (float)((delta / frequency) * 1000.0);
}
else
{
LOG(Warning, "Unrealiable GPU timer query detected.");
}
_finalized = true;
}
return _timeDelta;
}
#endif

View File

@@ -0,0 +1,55 @@
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Graphics/GPUTimerQuery.h"
#include "GPUDeviceDX11.h"
#if GRAPHICS_API_DIRECTX11
/// <summary>
/// GPU timer query object for DirectX 11 backend.
/// </summary>
class GPUTimerQueryDX11 : public GPUResourceDX11<GPUTimerQuery>
{
private:
bool _finalized = false;
bool _endCalled = false;
float _timeDelta = 0.0f;
ID3D11Query* _beginQuery = nullptr;
ID3D11Query* _endQuery = nullptr;
ID3D11Query* _disjointQuery = nullptr;
public:
/// <summary>
/// Initializes a new instance of the <see cref="GPUTimerQueryDX11"/> class.
/// </summary>
/// <param name="device">The graphics device.</param>
GPUTimerQueryDX11(GPUDeviceDX11* device);
/// <summary>
/// Finalizes an instance of the <see cref="GPUTimerQueryDX11"/> class.
/// </summary>
~GPUTimerQueryDX11();
public:
// [GPUResourceDX11]
ID3D11Resource* GetResource() final override;
// [GPUTimerQuery]
void Begin() override;
void End() override;
bool HasResult() override;
float GetResult() override;
protected:
// [GPUResource]
void OnReleaseGPU() override;
};
#endif

View File

@@ -0,0 +1,18 @@
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
using Flax.Build.NativeCpp;
/// <summary>
/// DirectX 11 graphics backend module.
/// </summary>
public class GraphicsDeviceDX11 : GraphicsDeviceBaseModule
{
/// <inheritdoc />
public override void Setup(BuildOptions options)
{
base.Setup(options);
options.PublicDefinitions.Add("GRAPHICS_API_DIRECTX11");
options.OutputFiles.Add("d3d11.lib");
}
}

View File

@@ -0,0 +1,35 @@
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
#pragma once
#include "../IncludeDirectXHeaders.h"
#if GRAPHICS_API_DIRECTX11
/// <summary>
/// Interface for objects that can be bound to the shader slots in DirectX 11.
/// </summary>
class IShaderResourceDX11
{
public:
IShaderResourceDX11()
{
}
public:
/// <summary>
/// Gets handle to the shader resource view object.
/// </summary>
/// <returns>SRV</returns>
virtual ID3D11ShaderResourceView* SRV() const = 0;
/// <summary>
/// Gets CPU to the unordered access view object.
/// </summary>
/// <returns>UAV</returns>
virtual ID3D11UnorderedAccessView* UAV() const = 0;
};
#endif