Render basic geometry

Added GraphicsContext, SwapChain, Buffer, VertexBuffer, IndexBuffer and a basic DX11 implementation.
This commit is contained in:
Simon Lübeß
2020-11-25 13:03:40 +01:00
parent 0237e0b38d
commit 5954fbc411
20 changed files with 1219 additions and 180 deletions
@@ -0,0 +1,135 @@
using System.Diagnostics;
using System;
using DirectX.D3D11;
using internal GlitchyEngine.Renderer;
namespace GlitchyEngine.Renderer
{
extension CPUAccessFlags
{
public static explicit operator DirectX.D3D11.CpuAccessFlags(Self cpuAccessFlags)
{
DirectX.D3D11.CpuAccessFlags flags = .None;
if(cpuAccessFlags.HasFlag(.Read))
flags |= .Read;
if(cpuAccessFlags.HasFlag(.Write))
flags |= .Write;
return flags;
}
}
extension BufferDescription
{
public static operator DirectX.D3D11.BufferDescription(Self desc)
{
DirectX.D3D11.BufferDescription result;
result.ByteWidth = desc.Size;
result.Usage = (.)desc.Usage;
result.CpuAccessFlags = (.)desc.CPUAccess;
result.BindFlags = .None;
if(desc.BindFlags.HasFlag(.Constant))
{
result.BindFlags |= .ConstantBuffer;
}
if(desc.BindFlags.HasFlag(.Index))
{
result.BindFlags |= .IndexBuffer;
}
if(desc.BindFlags.HasFlag(.Vertex))
{
result.BindFlags |= .VertexBuffer;
}
result.MiscFlags = .None;
result.StructureByteStride = 0;
return result;
}
}
public extension MapType
{
public static explicit operator DirectX.D3D11.MapType(Self mapType)
{
return (.)(uint32)mapType;
}
}
public extension Buffer
{
// Todo: nativeBuffer contains exactly that!
internal DirectX.D3D11.BufferDescription nativeDescription;
internal ID3D11Buffer* nativeBuffer ~ _?.Release();
private Result<void> InternalCreateBuffer(void* data, uint32 byteLength, uint32 dstByteOffset)
{
nativeDescription = (.)_description;
uint8* byteData = (.)data;
if(dstByteOffset == 0)
{
byteData = new uint8[nativeDescription.ByteWidth]*;
defer:: delete byteData;
Internal.MemCpy(byteData + dstByteOffset, data, byteLength);
}
SubresourceData srData = .(byteData, byteLength, 0);
var result = _context.nativeDevice.CreateBuffer(ref nativeDescription, &srData, &nativeBuffer);
if(result.Failed)
{
Log.EngineLogger.Error("Failed to create buffer. Message({}):{}", (int)result, result);
return .Err;
}
return .Ok;
}
protected override Result<void> PlatformSetData(void* data, uint32 byteLength, uint32 dstByteOffset, GlitchyEngine.Renderer.MapType mapType)
{
if(nativeBuffer == null)
{
// We can pass the data while creating the buffer, so we can return here.
return InternalCreateBuffer(data, byteLength, dstByteOffset);
}
Debug.Assert(dstByteOffset + byteLength <= _description.Size, "The destination offset and byte length are too long for the target buffer.");
switch(nativeDescription.Usage)
{
case .Default:
Box dataBox = .(dstByteOffset, 0, 0, dstByteOffset + byteLength, 1, 1);
_context.nativeContext.UpdateSubresource(nativeBuffer, 0, &dataBox, data, byteLength, byteLength);
case .Dynamic:
Debug.Assert(mapType.CanWrite, "The map type has to have write access.");
// Todo: DoNotWaitFlag
MappedSubresource map = ?;
_context.nativeContext.Map(nativeBuffer, 0, (.)mapType, .None, &map);
Internal.MemCpy(((uint8*)map.Data) + dstByteOffset, data, byteLength);
_context.nativeContext.Unmap(nativeBuffer, 0);
Runtime.NotImplemented();
case .Immutable:
Log.EngineLogger.Error("Can't set the data of an immutable resource.");
return .Err;
default:
Log.EngineLogger.Error("Unknown resource usage: engine={}, native={}", _description.Usage, nativeDescription.Usage);
return .Err;
}
return .Ok;
}
}
public extension VertexBuffer<T>
{
}
}
@@ -0,0 +1,159 @@
using System;
using System.Diagnostics;
using DirectX.Common;
using DirectX.D3D11;
using DirectX.D3D11.SDKLayers;
using DirectX.DXGI.DXGI1_2;
using GlitchyEngine.Renderer;
using GlitchyEngine.Math;
using GlitchyEngine.Platform.DX11;
using internal GlitchyEngine.Renderer;
//using internal GlitchyEngine.Platform.DX11.Renderer;
namespace GlitchyEngine.Renderer
//namespace GlitchyEngine.Platform.DX11.Renderer
{
/// DirectX 11 specific implementation of the GraphicsContext
extension GraphicsContext
//public class Dx11Context : GraphicsContext
{
//private Dx11SwapChain _swapChain;
private SwapChain _swapChain;
internal Windows.HWnd nativeWindowHandle;
internal ID3D11Device* nativeDevice;
internal ID3D11DeviceContext* nativeContext;
private ID3D11Debug* _debugDevice;
public override SwapChain SwapChain => _swapChain;
private const uint32 MaxRTVCount = DirectX.D3D11.D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT;
//public static override uint32 MaxRenderTargetCount() => MaxRTVCount;
public this(Windows.HWnd windowHandle)
{
nativeWindowHandle = windowHandle;
_swapChain = new SwapChain(this);
//_swapChain = new Dx11SwapChain(this);
}
public ~this()
{
delete _swapChain;
nativeDevice?.Release();
nativeContext?.Release();
_debugDevice.ReportLiveDeviceObjects(.Detail);
_debugDevice?.Release();
}
public override void Init()
{
InitDevice();
SwapChain.Init();
}
/**
* Initializes the Device and ImmediateContext.
*/
void InitDevice()
{
nativeDevice?.Release();
nativeContext?.Release();
Log.EngineLogger.Trace("Creating D3D11 Device and Context...");
DeviceCreationFlags deviceFlags = .None;
#if DEBUG
deviceFlags |= .Debug;
#endif
FeatureLevel[] levels = scope .(.Level_11_0);
var deviceResult = D3D11.CreateDevice(null, .Hardware, 0, deviceFlags, levels, &nativeDevice, let deviceLevel, &nativeContext);
Debug.Assert(deviceResult.Succeeded, scope $"Failed to create D3D11 Device. Message(0x{(int32)deviceResult}): {deviceResult}");
#if DEBUG
if(nativeDevice.QueryInterface<ID3D11Debug>(out _debugDevice).Succeeded)
{
ID3D11InfoQueue* infoQueue;
if(nativeDevice.QueryInterface<ID3D11InfoQueue>(out infoQueue).Succeeded)
{
infoQueue.SetBreakOnSeverity(.Corruption, true);
infoQueue.SetBreakOnSeverity(.Error, true);
infoQueue.Release();
}
}
#endif
Dx11Cheater.Device = nativeDevice;
Dx11Cheater.ImmediateContext = nativeContext;
Log.EngineLogger.Trace("D3D11 Device and Context created (Feature level: {})", deviceLevel);
}
private ID3D11RenderTargetView*[MaxRTVCount] _renderTargets;
public override void SetRenderTarget(RenderTarget renderTarget, int slot = 0)
{
if(renderTarget == null)
{
_renderTargets[slot] = _swapChain.nativeBackBufferTarget;
//_immediateContext.OutputMerger.SetRenderTargets(1, &_swapChain._backBufferTarget, null);
}
else
{
Runtime.NotImplemented();
}
}
public override void BindRenderTargets()
{
nativeContext.OutputMerger.SetRenderTargets(MaxRTVCount, &_renderTargets, null);
}
public override void ClearRenderTarget(RenderTarget renderTarget, ColorRGBA color)
{
if(renderTarget == null)
{
nativeContext.ClearRenderTargetView(_swapChain.nativeBackBufferTarget, color);
}
else
{
Runtime.NotImplemented();
}
}
public override void SetVertexBuffer(uint32 slot, Buffer buffer, uint32 stride, uint32 offset = 0)
{
// make stride and offset mutable so that we can take their pointers.
var stride, offset;
nativeContext.InputAssembler.SetVertexBuffers(slot, 1, &buffer.nativeBuffer, &stride, &offset);
}
public override void Draw(uint32 vertexCount, uint32 startVertexIndex = 0)
{
nativeContext.Draw(vertexCount, startVertexIndex);
}
public override void DrawIndexed(uint32 indexCount, uint32 startIndexLocation = 0, int32 vertexOffset = 0)
{
nativeContext.DrawIndexed(indexCount, startIndexLocation, vertexOffset);
}
public override void SetIndexBuffer(Buffer buffer, IndexFormat indexFormat = .Index16Bit, uint32 byteOffset = 0)
{
nativeContext.InputAssembler.SetIndexBuffer(buffer.nativeBuffer, indexFormat == .Index32Bit ? .R32_UInt : .R16_UInt, byteOffset);
}
}
}
@@ -0,0 +1,155 @@
using DirectX.D3D11;
using DirectX.DXGI.DXGI1_2;
using GlitchyEngine.Platform.DX11;
using System.Diagnostics;
using internal GlitchyEngine.Renderer;
namespace GlitchyEngine.Renderer
{
public extension SwapChain
{
private GraphicsContext _context;
private bool _changed;
private uint32 _width, _height;
internal DirectX.DXGI.IDXGIDevice* nativeDxgiDevice;
internal IDXGISwapChain1* nativeSwapChain;
internal ID3D11RenderTargetView* nativeBackBufferTarget;
private DirectX.D3D11.Viewport _backBufferViewport;
public override uint32 Width
{
get => _width;
set
{
if(_width == value)
return;
_width = value;
_changed = true;
}
}
public override uint32 Height
{
get => _height;
set
{
if(_height == value)
return;
_height = value;
_changed = true;
}
}
public override GraphicsContext Context => _context;
//public this(Dx11Context context)
public this(GraphicsContext context)
{
_context = context;
SetResolutionFromWindow();
}
public ~this()
{
nativeDxgiDevice?.Release();
nativeSwapChain?.Release();
nativeBackBufferTarget?.Release();
}
void SetResolutionFromWindow()
{
DirectX.Windows.Winuser.GetClientRect(_context.nativeWindowHandle, let rect);
Width = (.)(rect.Right - rect.Left);
Height = (.)(rect.Bottom - rect.Top);
}
public override void Init()
{
ApplyChanges();
}
public override void ApplyChanges()
{
if(!_changed)
return;
UpdateSwapchain();
}
/**
* Initializes the swapchain.
*/
public void UpdateSwapchain()
{
Log.EngineLogger.Trace("Updating swap chain ({}, {})", _width, _height);
uint32 backBufferCount = 2;
Format backBufferFormat = .R8G8B8A8_UNorm;
Format backBufferViewFormat = .R8G8B8A8_UNorm; // _SRGB
if(nativeSwapChain != null)
{
nativeBackBufferTarget.Release();
var resizeResult = nativeSwapChain.ResizeBuffers(backBufferCount, _width, _height, backBufferFormat, .None);
Debug.Assert(resizeResult.Succeeded, scope $"Failed to resize swap chain. Message({(int32)resizeResult}):{resizeResult}");
}
else
{
_context.nativeDevice.QueryInterface(out nativeDxgiDevice);
nativeDxgiDevice.GetAdapter(let adapter);
adapter.GetParent<DirectX.DXGI.IDXGIFactory2>(let factory);
adapter.Release();
SwapChainDescription1 swDesc = .();
swDesc.Width = _width;
swDesc.Height = _height;
swDesc.Format = backBufferFormat;
swDesc.SampleDescription = .(1, 0);
swDesc.BufferUsage = .RenderTargetOutput;
swDesc.BufferCount = backBufferCount;
swDesc.SwapEffect = .FlipDiscard;
SwapChainFullscreenDescription fsSwapChainDesc = .();
fsSwapChainDesc.Windowed = true;
var createResult = factory.CreateSwapChainForHwnd((.)_context.nativeDevice, _context.nativeWindowHandle, ref swDesc, &fsSwapChainDesc, null, &nativeSwapChain);
Debug.Assert(createResult.Succeeded, scope $"Failed to create swap chain. Message({(int32)createResult}):{createResult}");
factory.Release();
Dx11Cheater.SwapChain = nativeSwapChain;
}
nativeSwapChain.GetBuffer<ID3D11Texture2D>(0, let backBuffer);
RenderTargetViewDescription rtvDesc = .(backBuffer, .Texture2D, backBufferViewFormat);
_context.nativeDevice.CreateRenderTargetView(backBuffer, &rtvDesc, &nativeBackBufferTarget);
Dx11Cheater.BackbufferTarget = nativeBackBufferTarget;
_backBufferViewport = DirectX.D3D11.Viewport(0, 0, _width, _height, 0.0f, 1.0f);
Dx11Cheater.BackbufferViewport = _backBufferViewport;
backBuffer.Release();
}
public override void Present()
{
nativeSwapChain.Present(Application.Get().Window.IsVSync ? 1 : 0, .None);
}
}
}