mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 21:01:52 +00:00
Render basic geometry
Added GraphicsContext, SwapChain, Buffer, VertexBuffer, IndexBuffer and a basic DX11 implementation.
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user