Awesome
SharpGPU
Hardware Abstract Layer for modern gpus based on Metal/Vulkan/DirectX12 backend.
Basic Example
Shader context
That is the example shader source
std::string computeHLSL
{@"
[[vk::binding(0, 0)]]
RWTexture2D<float4> _ResultTexture[1] : register(u0, space0);
[numthreads(8, 8, 1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
float2 UV = (id.xy + 0.5) / float2(1600, 900);
float IDMod7 = saturate(((id.x & 7) / 7) + ((id.y & 7) / 7));
_ResultTexture[0][id.xy] = float4(id.x & id.y, IDMod7, UV);
}"};
std::string rasterHLSL
{@"
[[vk::binding(0, 0)]]
Texture2D _DiffuseTexture[1] : register(t0, space0);
[[vk::binding(1, 0)]]
SamplerState _DiffuseSampler[1] : register(s1, space0);
struct Attributes
{
[[vk::location(0)]]
float4 color : COLOR1;
[[vk::location(1)]]
float4 vertexOS : POSITION0;
};
struct Varyings
{
[[vk::location(0)]]
float2 uv0 : TEXCOORD0;
[[vk::location(1)]]
float4 color : COLOR1;
};
Varyings VSMain(Attributes input, out float4 vertexCS : SV_POSITION)
{
vertexCS = input.vertexOS;
Varyings output = (Varyings)0;
output.uv0 = input.vertexOS.xy;
output.color = input.color;
return output;
}
float4 FSMain(Varyings input) : SV_TARGET
{
return input.color * _DiffuseTexture[0].Sample(_DiffuseSampler[0], input.uv0);
}"};
Creating the Direct3D_12 Instance //Or Metal/Vulkan/OpenGL/Direct3D 11
The first step after we include the RHI headers and libraries into your project is to create a instance wrapper.
#include <rhi/d3d12.h>
...
rhi::RHIInstanceDescriptor descriptor;
{
descriptor.Backend = ERHIBackend::DirectX12;
descriptor.EnableDebugLayer = false;
descriptor.EnableValidatior = false;
}
rhi::RHIInstance* instance = rhi::CreateInstance(descriptor);
Get the Device
That select device form instance use index
#include <rhi/d3d12.h>
...
rhi::RHIDevice* device = instance->GetDevice(0);
Get the CommandQueue
Create command queue for execution gpu task
#include <rhi/d3d12.h>
...
uint32 computeQueueCount = device->QueryQueueCount(ERHIPipelineType.Compute);
uint32 transferQueueCount = device->QueryQueueCount(ERHIPipelineType.Transfer);
uint32 graphicsQueueCount = device->QueryQueueCount(ERHIPipelineType.Graphics);
rhi::RHICommandQueue* computeQueue = device->GetCommandQueue(ERHIPipelineType.Compute, 0);
rhi::RHICommandQueue* transferQueue = device->GetCommandQueue(ERHIPipelineType.Transfer, 0);
rhi::RHICommandQueue* graphicsQueue = device->GetCommandQueue(ERHIPipelineType.Graphics, 0);
Creating the Fence
Create frame fence for render loop sync
#include <rhi/d3d12.h>
...
rhi::RHIFence* fence = device->CreateFence();
Creating the SwapChain
Create swap chain for window display
#include <rhi/d3d12.h>
...
rhi::RHISwapChainDescriptor swapChainDescriptor;
{
swapChainDescriptor.FPS = 60;
swapChainDescriptor.Count = 3;
swapChainDescriptor.Extent = screenSize;
swapChainDescriptor.Format = ERHISwapChainFormat::R8G8B8A8_UNorm;
swapChainDescriptor.Surface = hwdnPtr;
swapChainDescriptor.PresentMode = ERHIPresentMode.VSync;
swapChainDescriptor.PresentQueue = graphicsQueue;
swapChainDescriptor.FrameBufferOnly = true;
}
rhi::SwapChain* swapChain = device->CreateSwapChain(swapChainDescriptor);
Creating the texture
Create a texture and sampler
#include <rhi/d3d12.h>
...
rhi::RHISamplerDescriptor samplerInfo;
{
samplerInfo.LodMin = -1000;
samplerInfo.LodMax = 1000;
samplerInfo.MipLODBias = 0;
samplerInfo.Anisotropy = 8;
samplerInfo.MinFilter = ERHIFilterMode::Linear;
samplerInfo.MagFilter = ERHIFilterMode::Linear;
samplerInfo.MipFilter = ERHIFilterMode::Linear;
samplerInfo.AddressModeU = ERHIAddressMode::Repeat;
samplerInfo.AddressModeV = ERHIAddressMode::Repeat;
samplerInfo.AddressModeW = ERHIAddressMode::Repeat;
samplerInfo.ComparisonMode = ERHIComparisonMode::Never;
}
rhi::RHISampler* sampler = device->CreateSampler(samplerInfo);
rhi::RHITextureDescriptor textureInfo;
{
textureInfo.Extent = uint3(screenSize.xy, 1);
textureInfo.MipCount = 1;
textureInfo.SampleCount = ERHISampleCount::None;
textureInfo.Format = ERHIPixelFormat::R8G8B8A8_UNorm;
textureInfo.UsageFlag = ERHITextureUsage::ShaderResource | ERHITextureUsage::UnorderedAccess;
textureInfo.Dimension = ERHITextureDimension::Texture2D;
textureInfo.StorageMode = ERHIStorageMode::GPULocal;
}
rhi::RHITexture* texture = device->CreateTexture(textureInfo);
Creating the texture view
Create textureView for compute or raster
#include <rhi/d3d12.h>
...
rhi::RHITextureViewDescriptor computeOutputViewInfo;
{
computeOutputViewInfo.MipCount = 1;
computeOutputViewInfo.BaseMipLevel = 0;
computeOutputViewInfo.ArrayCount = 1;
computeOutputViewInfo.BaseArraySlice = 0;
computeOutputViewInfo.ViewType = ERHITextureViewType::UnorderedAccess;
}
rhi::TextureView* textureUAV = texture->CreateTextureView(computeOutputViewInfo);
rhi::RHITextureViewDescriptor rasterInputViewInfo;
{
rasterInputViewInfo.MipCount = 1;
rasterInputViewInfo.BaseMipLevel = 0;
rasterInputViewInfo.ArrayCount = 1;
rasterInputViewInfo.BaseArraySlice = 0;
rasterInputViewInfo.ViewType = ERHITextureViewType::ShaderResource;
}
rhi::TextureView* textureSRV = texture->CreateTextureView(rasterInputViewInfo);
Creating the Compute resource table
Create a compute resourceTable
#include <rhi/d3d12.h>
...
rhi::RHIResourceTableLayoutElement computeResourceTableLayoutElements[1];
{
computeResourceTableLayoutElements[0].Slot = 0;
computeResourceTableLayoutElements[0].Type = ERHIBindType::StorageTexture2D;
computeResourceTableLayoutElements[0].Stage = ERHIShaderStage::Compute;
}
rhi::RHIResourceTableLayoutDescriptor computeResourceTableLayoutInfo;
{
computeResourceTableLayoutInfo.Index = 0;
computeResourceTableLayoutInfo.Elements = computeResourceTableLayoutElements;
computeResourceTableLayoutInfo.NumElements = 1;
}
rhi::RHIResourceTableLayout* computeResourceTableLayout = device->CreateResourceTableLayout(computeResourceTableLayoutInfo);
rhi::RHIResourceTableElement computeResourceTableElements[1];
{
computeResourceTableElements[0].TextureView = textureUAV;
}
rhi::RHIResourceTableDescriptor computeResourceTableInfo;
{
computeResourceTableInfo.Layout = computeResourceTableLayout;
computeResourceTableInfo.Elements = computeResourceTableElements;
computeResourceTableInfo.NumElements = 1;
}
rhi::RHIResourceTable* computeResourceTable = device->CreateResourceTable(computeResourceTableInfo);
Creating the Compute Pass
Create a compute pipelineState for compute pass
#include <rhi/d3d12.h>
...
rhi::RHIFunctionDescriptor computeFunctionInfo;
{
computeFunctionInfo.Type = ERHIFunctionType::Compute;
computeFunctionInfo.ByteSize = computeBlob.Size;
computeFunctionInfo.ByteCode = computeBlob.Data;
computeFunctionInfo.EntryName = "CSMain";
}
rhi::RHIFunction* computeFunction = device->CreateFunction(computeFunctionInfo);
rhi::RHIPipelineLayoutDescriptor computePipelienLayoutInfo;
{
computePipelienLayoutInfo.bLocalSignature = false;
computePipelienLayoutInfo.bUseVertexLayout = false;
computePipelienLayoutInfo.StaticSamplers = nullptr;
computePipelienLayoutInfo.NumStaticSamplers = 0;
computePipelienLayoutInfo.ResourceTableLayouts = computeResourceTableLayout;
computePipelienLayoutInfo.NumResourceTableLayouts = 1;
}
rhi::RHIPipelineLayout* computePipelineLayout = device->CreatePipelineLayout(computePipelienLayoutInfo);
rhi::RHIComputePipelineDescriptor computePipelineInfo;
{
computePipelineInfo.ThreadSize = uint3(8, 8, 1);
computePipelineInfo.ComputeFunction = computeFunction;
computePipelineInfo.PipelineLayout = computePipelineLayout;
}
rhi::RHIPipeline* computePipeline = device->CreateComputePipeline(computePipelineInfo);
Creating the UniformBuffer
Create a uniform buffer for any pipelineState to read constant data
#include <rhi/d3d12.h>
...
UniformInfo uniformArray[1] = // ......;
rhi::RHIBufferDescriptor uniformBufferInfo;
{
uniformBufferInfo.ByteSize = uniformArray.Length * ((sizeof(UniformInfo) + 255) & ~255);
uniformBufferInfo.UsageFlag = ERHIBufferUsage::UniformBuffer;
uniformBufferInfo.StorageMode = ERHIStorageMode::HostUpload;
}
rhi::RHIBuffer* uniformBuffer = device->CreateBuffer(uniformBufferInfo);
void* uniformData = uniformBuffer->Map(0, uniformBufferInfo.ByteSize);
MemoryUtility::MemCpy(&uniformArray, uniformData, uniformBufferInfo.ByteSize);
rhiIndexBuffer->Unmap(0, uniformBufferInfo.ByteSize);
rhi::RHIBufferViewDescriptor uniformBufferViewInfo;
{
uniformBufferViewInfo.Offset = 0;
uniformBufferViewInfo.Type = ERHIBufferViewType.UniformBuffer;
uniformBufferViewInfo.Count = uniformArray.Length;
uniformBufferViewInfo.Stride = (sizeof(UniformInfo) + 255) & ~255;
}
rhi::RHIBufferView* uniformBufferView = uniformBuffer->CreateBufferView(bufferViewDescriptor);
Creating the Vertex Stream
Create indexBuffer and vertexBuffer
#include <rhi/d3d12.h>
...
//index buffer
uint16 indices[3] = {0, 1, 2};
rhi::RHIBufferDescriptor indexBufferInfo;
{
indexBufferInfo.ByteSize = indices.Length * sizeof(uint16);
indexBufferInfo.UsageFlag = ERHIBufferUsage::IndexBuffer;
indexBufferInfo.StorageMode = ERHIStorageMode::HostUpload;
}
rhi::RHIBuffer* indexBufferCPU = device->CreateBuffer(indexBufferInfo);
void* indexData = indexBufferCPU->Map(0, indexBufferInfo.ByteSize);
MemoryUtility::MemCpy(&indices, indexData, indexBufferInfo.ByteSize);
indexBufferCPU->Unmap(0, indexBufferInfo.ByteSize);
indexBufferInfo.StorageMode = ERHIStorageMode.GPULocal;
rhi::RHIBuffer* indexBufferGPU = device->CreateBuffer(indexBufferInfo);
//vertex buffer
Vertex vertices[3];
{
vertices[0].color = float4(1, 0, 0, 1);
vertices[0].position = float4(-0.5f, -0.5f, 0, 1);
vertices[1].color = float4(0, 1, 0, 1);
vertices[1].position = float4(0, 0.5f, 0, 1);
vertices[2].color = float4(0, 0, 1, 1);
vertices[2].position = float4(0.5f, -0.5f, 0, 1);
}
rhi::RHIBufferDescriptor vertexBufferInfo;
{
vertexBufferInfo.ByteSize = vertices.Length * sizeof(Vertex);
vertexBufferInfo.UsageFlag = ERHIBufferUsage::VertexBuffer;
vertexBufferInfo.StorageMode = ERHIStorageMode::HostUpload;
}
rhi::RHIBuffer* vertexBufferCPU = device->CreateBuffer(vertexBufferInfo);
void* vertexData = vertexBufferCPU->Map(vertexBufferInfo.ByteSize, 0);
MemoryUtility::MemCpy(&vertices, vertexData, vertexBufferInfo.ByteSize);
vertexBufferCPU->Unmap();
vertexBufferInfo.StorageMode = ERHIStorageMode.GPULocal;
rhi::RHIBuffer* vertexBufferGPU = device->CreateBuffer(vertexBufferInfo);
Creating the Raster resource table
Create a raster resourceTable
#include <rhi/d3d12.h>
...
rhi::RHIResourceTableLayoutElement rasterResourceTableLayoutElements[2];
{
rasterResourceTableLayoutElements[0].Slot = 0;
rasterResourceTableLayoutElements[0].Type = ERHIBindType::Texture2D;
rasterResourceTableLayoutElements[0].Stage = ERHIShaderStage::Fragment;
rasterResourceTableLayoutElements[1].Slot = 1;
rasterResourceTableLayoutElements[1].Type = ERHIBindType::Sampler;
rasterResourceTableLayoutElements[1].Stage = ERHIShaderStage::Fragment;
}
rhi::RHIResourceTableLayoutDescriptor rasterResourceTableLayoutInfo;
{
rasterResourceTableLayoutInfo.Index = 0;
rasterResourceTableLayoutInfo.Elements = &rasterResourceTableLayoutElements;
rasterResourceTableLayoutInfo.NumElements = 2;
}
rhi::RHIResourceTableLayout* rasterResourceTableLayout = device->CreateResourceTableLayout(rasterResourceTableLayoutInfo);
rhi::RHIResourceTableElement rasterResourceTableElements[2];
{
rasterResourceTableElements[0].TextureView = textureSRV;
rasterResourceTableElements[1].Sampler = sampler;
}
rhi::RHIResourceTableDescriptor rasterResourceTableInfo;
{
rasterResourceTableInfo.Layout = rasterResourceTableLayout;
rasterResourceTableInfo.Elements = &rasterResourceTableElements;
rasterResourceTableInfo.NumElements = 2;
}
rhi::RHIResourceTable* rasterResourceTable = device->CreateResourceTable(rasterResourceTableInfo);
Creating the Raster Pass
Create a raster pipelineState for raster pass
#include <rhi/d3d12.h>
...
rhi::RHIOutputStateDescriptor outputStateInfo;
{
outputStateInfo.SampleCount = ERHISampleCount::None;
outputStateInfo.DepthFormat = ERHIPixelFormat::D32_Float_S8_UInt;
outputStateInfo.ColorFormat0 = ERHIPixelFormat::R8G8B8A8_UNorm;
outputStateInfo.ColorFormat1 = outputStateInfo.ColorFormat0;
outputStateInfo.ColorFormat2 = outputStateInfo.ColorFormat0;
outputStateInfo.ColorFormat3 = outputStateInfo.ColorFormat0;
outputStateInfo.ColorFormat4 = outputStateInfo.ColorFormat0;
outputStateInfo.ColorFormat5 = outputStateInfo.ColorFormat0;
outputStateInfo.ColorFormat6 = outputStateInfo.ColorFormat0;
outputStateInfo.ColorFormat7 = outputStateInfo.ColorFormat0;
}
rhi::RHIBlendStateDescriptor blendStateInfo;
{
blendStateInfo.AlphaToCoverage = false;
blendStateInfo.IndependentBlend = false;
blendStateInfo.BlendDescriptor0.BlendEnable = false;
blendStateInfo.BlendDescriptor0.BlendOpColor = ERHIBlendOp::Add;
blendStateInfo.BlendDescriptor0.BlendOpAlpha = ERHIBlendOp::Add;
blendStateInfo.BlendDescriptor0.SrcBlendColor = ERHIBlendMode::One;
blendStateInfo.BlendDescriptor0.SrcBlendAlpha = ERHIBlendMode::One;
blendStateInfo.BlendDescriptor0.DstBlendColor = ERHIBlendMode::Zero;
blendStateInfo.BlendDescriptor0.DstBlendAlpha = ERHIBlendMode::Zero;
blendStateInfo.BlendDescriptor0.ColorWriteChannel = ERHIColorWriteChannel::All;
blendStateInfo.BlendDescriptor1 = blendStateInfo.BlendDescriptor0;
blendStateInfo.BlendDescriptor2 = blendStateInfo.BlendDescriptor0;
blendStateInfo.BlendDescriptor3 = blendStateInfo.BlendDescriptor0;
blendStateInfo.BlendDescriptor4 = blendStateInfo.BlendDescriptor0;
blendStateInfo.BlendDescriptor5 = blendStateInfo.BlendDescriptor0;
blendStateInfo.BlendDescriptor6 = blendStateInfo.BlendDescriptor0;
blendStateInfo.BlendDescriptor7 = blendStateInfo.BlendDescriptor0;
}
rhi::RHIRasterizerStateDescriptor rasterizerStateInfo;
{
rasterizerStateInfo.CullMode = ERHICullMode::Back;
rasterizerStateInfo.FillMode = ERHIFillMode::Solid;
rasterizerStateInfo.DepthBias = 0;
rasterizerStateInfo.DepthBiasClamp = 0;
rasterizerStateInfo.SlopeScaledDepthBias = 0;
rasterizerStateInfo.DepthClipEnable = true;
rasterizerStateInfo.ConservativeRaster = false;
rasterizerStateInfo.AntialiasedLineEnable = false;
rasterizerStateInfo.FrontCounterClockwise = false;
}
rhi::RHIDepthStencilStateDescriptor depthStencilStateInfo;
{
depthStencilStateInfo.DepthEnable = true;
depthStencilStateInfo.DepthWriteMask = true;
depthStencilStateInfo.ComparisonMode = ERHIComparisonMode::LessEqual;
depthStencilStateInfo.StencilEnable = false;
depthStencilStateInfo.StencilReadMask = 255;
depthStencilStateInfo.StencilWriteMask = 255;
depthStencilStateInfo.BackFace.ComparisonMode = ERHIComparisonMode::Always;
depthStencilStateInfo.BackFace.StencilPassOp = ERHIStencilOp::Keep;
depthStencilStateInfo.BackFace.StencilFailOp = ERHIStencilOp::Keep;
depthStencilStateInfo.BackFace.StencilDepthFailOp = ERHIStencilOp::Keep;
depthStencilStateInfo.FrontFace.ComparisonMode = ERHIComparisonMode::Always;
depthStencilStateInfo.FrontFace.StencilPassOp = ERHIStencilOp::Keep;
depthStencilStateInfo.FrontFace.StencilFailOp = ERHIStencilOp::Keep;
depthStencilStateInfo.FrontFace.StencilDepthFailOp = ERHIStencilOp::Keep;
}
rhi::RHIRenderStateDescriptor renderStateInfo;
{
renderStateInfo.SampleMask = 0;
renderStateInfo.BlendState = blendStateInfo;
renderStateInfo.RasterizerState = rasterizerStateInfo;
renderStateInfo.DepthStencilState = depthStencilStateInfo;
}
rhi::RHIVertexElementDescriptor vertexElementInfos[2];
{
vertexElementInfos[0].Slot = 1;
vertexElementInfos[0].Offset = 0;
vertexElementInfos[0].Type = ERHISemanticType::Color;
vertexElementInfos[0].Format = ERHISemanticFormat::Float4;
vertexElementInfos[1].Slot = 0;
vertexElementInfos[1].Offset = 16;
vertexElementInfos[1].Type = ERHISemanticType::Position;
vertexElementInfos[1].Format = ERHISemanticFormat::Float4;
}
rhi::RHIVertexLayoutDescriptor vertexLayoutInfos[1];
{
vertexLayoutInfos[0].Index = 0;
vertexLayoutInfos[0].Stride = sizeOf(Vertex);
vertexLayoutInfos[0].StepMode = ERHIVertexStepMode::PerVertex;
vertexLayoutInfos[0].VertexElements = &vertexElementInfos;
vertexLayoutInfos[0].VertexElementLength = vertexElementInfos.length;
}
rhi::RHIPipelineLayoutDescriptor rasterPipelienLayoutInfo;
{
rasterPipelienLayoutInfo.bLocalSignature = false;
rasterPipelienLayoutInfo.bUseVertexLayout = true;
rasterPipelienLayoutInfo.StaticSamplers = nullptr;
rasterPipelienLayoutInfo.NumStaticSamplers = 0;
rasterPipelienLayoutInfo.ResourceTableLayouts = rhirasterResourceTableLayout;
rasterPipelienLayoutInfo.NumResourceTableLayouts = 1;
}
rhi::RHIPipelineLayout* rasterPipelineLayout = device->CreatePipelineLayout(rasterPipelienLayoutInfo);
rhi::RHIFunctionDescriptor vertexFunctionInfo;
{
vertexFunctionInfo.Type = ERHIFunctionType::Vertex;
vertexFunctionInfo.ByteSize = vertexBlob.Size;
vertexFunctionInfo.ByteCode = vertexBlob.Data;
vertexFunctionInfo.EntryName = "VSMain";
}
rhi::RHIFunction* vertexFunction = device->CreateFunction(vertexFunctionInfo);
rhi::RHIFunctionDescriptor fragmentFunctionInfo;
{
fragmentFunctionInfo.Type = ERHIFunctionType::Fragment;
fragmentFunctionInfo.ByteSize = fragmentBlob.Size;
fragmentFunctionInfo.ByteCode = fragmentBlob.Data;
fragmentFunctionInfo.EntryName = "FSMain";
}
rhi::RHIFunction* vertexFunction = device->CreateFunction(fragmentFunctionInfo);
rhi::RHIRasterPipelineDescriptor rasterPipelineInfo;
{
rasterPipelineInfo.OutputState = outputStateInfo;
rasterPipelineInfo.RenderState = renderStateInfo;
rasterPipelineInfo.VertexLayouts = &vertexLayoutInfos;
rasterPipelineInfo.NumVertexLayouts = vertexLayoutInfos.length;
rasterPipelineInfo.VertexFunction = vertexFunction;
rasterPipelineInfo.FragmentFunction = vertexFunction;
rasterPipelineInfo.PipelineLayout = rasterPipelineLayout;
rasterPipelineInfo.PrimitiveTopology = ERHIPrimitiveTopology::TriangleList;
}
rhi::RHIPipeline* rasterPipeline = device->CreateRasterPipeline(rasterPipelineInfo);
Frame Begin Logic
Create commandbuffer and encoder for init
#include <rhi/d3d12.h>
...
rhi::RHICommandBuffer* cmdBuffer = graphicsQueue->CreateCommandBuffer(); //if renderer use async upload it's sould be use TransferQueue to record upload command and use Fence to sync CPU event
cmdBuffer.Begin("FrameInit");
{
cmdBuffer->ResourceBarrier(RHIBarrier::Transition(indexBufferGPU, ERHITextureState::Undefine, ERHITextureState::CopyDst, ERHIPipelineType::Graphics, ERHIPipelineType::Graphics));
cmdBuffer->ResourceBarrier(RHIBarrier::Transition(vertexBufferGPU, ERHITextureState::Undefine, ERHITextureState::CopyDst, ERHIPipelineType::Graphics, ERHIPipelineType::Graphics));
rhi::RHITransferEncoder* transferEncoder = cmdBuffer.BeginTransferPass(RHITransferPassDescriptor("Upload VertexStream"));
{
transferEncoder->CopyBufferToBuffer(indexBufferCPU, 0, indexBufferGPU, 0, indexBufferInfo.ByteSize);
transferEncoder->CopyBufferToBuffer(vertexBufferCPU, 0, vertexBufferGPU, 0, vertexBufferInfo.ByteSize);
}
transferEncoder->EndPass();
cmdBuffer->ResourceBarrier(RHIBarrier::Transition(indexBufferGPU, ERHITextureState::CopyDst, ERHITextureState::IndexBuffer, ERHIPipelineType::Graphics, ERHIPipelineType::Graphics));
cmdBuffer->ResourceBarrier(RHIBarrier::Transition(vertexBufferGPU, ERHITextureState::CopyDst, ERHITextureState::VertexBuffer, ERHIPipelineType::Graphics, ERHIPipelineType::Graphics));
}
cmdBuffer.End("FrameInit");
graphicsQueue->Submit(cmdBuffer, 1, fence, nullptr, 0, nullptr, 0); //cmdBuffers, cmdBufferCount, fence, waitSemaphores, waitSemaphoreCount, signalSemaphores, signalSemaphoreCount
Frame RenderLoop Logic
Create commandbuffer and encoder for rendering
#include <rhi/d3d12.h>
...
rhi::RHICommandBuffer* cmdBuffer = graphicsQueue->CreateCommandBuffer();
cmdBuffer.Begin("FrameRendering");
{
cmdBuffer->ResourceBarrier(RHIBarrier::Transition(texture, ERHITextureState::Undefine, ERHITextureState::UnorderedAccess, ERHIPipelineStage.Common, ERHIPipelineStage.Compute, ERHIPipelineType::Graphics, ERHIPipelineType::Graphics));
// run compute pass
rhi::RHIComputeEncoder* computeEncoder = cmdBuffer->BeginComputePass(RHIComputePassDescriptor("ComputePass"));
{
computeEncoder->PushDebugGroup("GenereteIndex");
computeEncoder->SetPipeline(computePipeline);
computeEncoder->SetResourceTable(computeResourceTable, 0);
computeEncoder->Dispatch(math::ceil(screenSize.x / 8), math::ceil(screenSize.y / 8), 1);
computeEncoder->PopDebugGroup();
}
computeEncoder->EndPass();
//run raster pass
rhi::RHIColorAttachmentDescriptor colorAttachmentInfos[1];
{
colorAttachmentInfos[0].MipLevel = 0;
colorAttachmentInfos[0].ArraySlice = 0;
colorAttachmentInfos[0].ClearValue = float4(0.5f, 0.5f, 1, 1);
colorAttachmentInfos[0].LoadAction = ERHILoadAction::Clear;
colorAttachmentInfos[0].StoreAction = ERHIStoreAction::Store;
colorAttachmentInfos[0].RenderTarget = swapChain->AcquireBackBufferTexture();
colorAttachmentInfos[0].ResolveTarget = nullptr;
colorAttachmentInfos[0].ResolveMipLevel = 0;
colorAttachmentInfos[0].ResolveArraySlice = 0;
}
RHISubPassDescriptor subPassDescriptors[1];
{
subPassDescriptors[0].Flags = ERHISubPassFlags::None;
subPassDescriptors[0].ColorInputs = RHIAttachmentIndexArray::Emtpy;
subPassDescriptors[0].ColorOutputs = RHIAttachmentIndexArray(1);
}
rhi::RHIRasterPassDescriptor rasterPassInfo;
{
rasterPassInfo.Name = "RasterPassInfo";
rasterPassInfo.ArrayLength = 1;
rasterPassInfo.SampleCount = 1;
rasterPassInfo.MultiViewCount = 0;
rasterPassInfo.Occlusion = nullptr;
rasterPassInfo.Timestamp = nullptr;
rasterPassInfo.Statistics = nullptr;
rasterPassInfo.ShadingRateTexture = nullptr;
rasterPassInfo.ColorAttachments = colorAttachmentInfos;
rasterPassInfo.DepthStencilAttachment = nullptr;
rasterPassInfo.SubPassDescriptors = subPassDescriptors;
}
cmdBuffer->ResourceBarrier(RHIBarrier::Transition(texture, ERHITextureState::UnorderedAccess, ERHITextureState::ShaderResource, ERHIPipelineStage.Compute, ERHIPipelineStage.Fragment, ERHIPipelineType::Graphics, ERHIPipelineType::Graphics));
cmdBuffer->ResourceBarrier(RHIBarrier::Transition(swapChain->AcquireBackBufferTexture(), ERHITextureState::Present, ERHITextureState::RenderTarget, ERHIPipelineStage.Common, ERHIPipelineStage.Fragment, ERHIPipelineType::Graphics, ERHIPipelineType::Graphics));
rhi::RHIRasterEncoder* rasterEncoder = cmdBuffer->BeginRasterPass(rasterPassInfo);
{
rasterEncoder->SetScissor(Rect(0, 0, screenSize.x, screenSize.y));
rasterEncoder->SetViewport(Viewport(0, 0, screenSize.x, screenSize.y, 0, 1));
rasterEncoder->SetBlendFactor(1);
rasterEncoder->PushDebugGroup("DrawTriange");
rasterEncoder->SetPipeline(rasterPipeline);
rasterEncoder->SetResourceTable(rasterResourceTable, 0);
rasterEncoder->SetIndexBuffer(indexBufferGPU, 0, ERHIIndexFormat::UInt16);
rasterEncoder->SetVertexBuffer(vertexBufferGPU, 0, 0);
rasterEncoder->SetShadingRate(ERHIShadingRate.Rate2x1, ERHIShadingRateCombiner.Passthrough);
rasterEncoder->DrawIndexed(3, 1, 0, 0, 0);
rasterEncoder->PopDebugGroup();
}
rasterEncoder->EndPass();
cmdBuffer->ResourceBarrier(RHIBarrier::Transition(texture, ERHITextureState.ShaderResource, ERHITextureState.Undefine, ERHIPipelineStage.Fragment, ERHIPipelineStage.Common, ERHIPipelineType.Graphics, ERHIPipelineType.Graphics));
cmdBuffer->ResourceBarrier(RHIBarrier::Transition(swapChain->AcquireBackBufferTexture(), ERHITextureState.RenderTarget, ERHITextureState.Present, ERHIPipelineStage.Fragment, ERHIPipelineStage.Common, ERHIPipelineType.Graphics, ERHIPipelineType.Graphics));
}
cmdBuffer.End("FrameRendering");
graphicsQueue->Submit(cmdBuffer, 1, fence, nullptr, 0, nullptr, 0); //cmdBuffers, cmdBufferCount, fence, waitSemaphores, waitSemaphoreCount, signalSemaphores, signalSemaphoreCount
swapChain->Present();
fence->Wait();
Release Resource
Release every resource on end
#include <rhi/d3d12.h>
...
indexBufferCPU->Release();
vertexBufferCPU->Release();
indexBufferGPU->Release();
vertexBufferGPU->Release();
sampler->Release();
texture->Release();
textureSRV->Release();
textureUAV->Release();
computeFunction->Release();
computeResourceTableLayout->Release();
computeResourceTable->Release();
computePipelineLayout->Release();
computePipeline->Release();
vertexFunction->Release();
fragmentFunction->Release();
rasterResourceTableLayout->Release();
rasterResourceTable->Release();
rasterPipelineLayout->Release();
rasterPipeline->Release();
cmdBuffer->Release();
transferQueue->Release();
computeQueue->Release();
graphicsQueue->Release();
fence->Release();
swapChain->Release();
instance->Release();