Skip to content

Hardware abstract layer for modern gpu based on Metal/Vulkan/DirectX12 backend.

License

Notifications You must be signed in to change notification settings

haolange/SharpGPU

Folders and files

NameName
Last commit message
Last commit date

Latest commit

06bacfa · Nov 28, 2024
Oct 30, 2024
Oct 30, 2024
Oct 30, 2024
Oct 30, 2024
Apr 11, 2023
Dec 19, 2023
Dec 12, 2023
Nov 8, 2024
Nov 28, 2024

Repository files navigation

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();

About

Hardware abstract layer for modern gpu based on Metal/Vulkan/DirectX12 backend.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages