Directx 12 mrt working - 1st iteration

This commit is contained in:
Zyko 2024-04-13 01:11:48 +02:00
parent 2faf8a551d
commit 7dd4aa9150
4 changed files with 211 additions and 27 deletions

View File

@ -127,7 +127,7 @@ func main() {
ebiten.SetVsyncEnabled(false)
ebiten.SetWindowTitle("MRT (Ebitengine Demo)")
if err := ebiten.RunGameWithOptions(&Game{}, &ebiten.RunGameOptions{
GraphicsLibrary: ebiten.GraphicsLibraryOpenGL,
GraphicsLibrary: ebiten.GraphicsLibraryDirectX,
}); err != nil {
log.Fatal(err)
}

View File

@ -625,6 +625,7 @@ func (g *graphics11) DrawTriangles(dstIDs [graphics.ShaderDstImageCount]graphics
if targetCount > 1 || firstTarget > 0 {
targetCount = graphics.ShaderDstImageCount
}
g.deviceContext.RSSetViewports(viewports[:targetCount])
if err := g.setAsRenderTargets(dsts[:targetCount], fillRule != graphicsdriver.FillAll); err != nil {

View File

@ -1082,7 +1082,78 @@ func (g *graphics12) NewShader(program *shaderir.Program) (graphicsdriver.Shader
return s, nil
}
func (g *graphics12) DrawTriangles(dstIDs [graphics.ShaderDstImageCount]graphicsdriver.ImageID, srcs [graphics.ShaderSrcImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms []uint32, fillRule graphicsdriver.FillRule) error {
func (g *graphics12) setAsRenderTargets(dsts []*image12, useStencil bool) error {
var rtvs []_D3D12_CPU_DESCRIPTOR_HANDLE
var dsvPtr *_D3D12_CPU_DESCRIPTOR_HANDLE
for i, img := range dsts {
// Ignore a nil image in case of MRT
if img == nil {
_ = i
rtvBase, err := g.rtvDescriptorHeap.GetCPUDescriptorHandleForHeapStart()
if err != nil {
return err
}
rtv := rtvBase
rtv.Offset(int32(g.frameIndex), g.rtvDescriptorSize)
rtvs = append(rtvs, rtv)
continue
}
if err := img.ensureRenderTargetView(g.device); err != nil {
return err
}
if img.screen {
if useStencil {
return fmt.Errorf("directx: stencils are not available on the screen framebuffer")
}
rtvBase, err := g.rtvDescriptorHeap.GetCPUDescriptorHandleForHeapStart()
if err != nil {
return err
}
rtv := rtvBase
rtv.Offset(int32(g.frameIndex), g.rtvDescriptorSize)
rtvs = append(rtvs, rtv)
continue
}
rtvBase, err := img.rtvDescriptorHeap.GetCPUDescriptorHandleForHeapStart()
if err != nil {
return err
}
rtv := rtvBase
rtvs = append(rtvs, rtv)
if !useStencil || dsvPtr != nil {
continue
}
if err := img.ensureDepthStencilView(g.device); err != nil {
return err
}
dsv, err := img.dsvDescriptorHeap.GetCPUDescriptorHandleForHeapStart()
if err != nil {
return err
}
dsvPtr = &dsv
}
if !useStencil {
g.drawCommandList.OMSetRenderTargets(rtvs, false, nil)
return nil
}
g.drawCommandList.OMSetStencilRef(0)
g.drawCommandList.OMSetRenderTargets(rtvs, false, dsvPtr)
g.drawCommandList.ClearDepthStencilView(*dsvPtr, _D3D12_CLEAR_FLAG_STENCIL, 0, 0, nil)
return nil
}
func (g *graphics12) DrawTriangles(dstIDs [graphics.ShaderDstImageCount]graphicsdriver.ImageID, srcIDs [graphics.ShaderSrcImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms []uint32, fillRule graphicsdriver.FillRule) error {
if shaderID == graphicsdriver.InvalidShaderID {
return fmt.Errorf("directx: shader ID is invalid")
}
@ -1103,20 +1174,46 @@ func (g *graphics12) DrawTriangles(dstIDs [graphics.ShaderDstImageCount]graphics
g.pipelineStates.releaseConstantBuffers(g.frameIndex)
}
dst := g.images[dstIDs[0]] // TODO: handle array
var resourceBarriers []_D3D12_RESOURCE_BARRIER_Transition
if rb, ok := dst.transiteState(_D3D12_RESOURCE_STATE_RENDER_TARGET); ok {
resourceBarriers = append(resourceBarriers, rb)
}
var srcImages [graphics.ShaderSrcImageCount]*image12
for i, srcID := range srcs {
src := g.images[srcID]
if src == nil {
var dsts [graphics.ShaderDstImageCount]*image12
var viewports [graphics.ShaderDstImageCount]_D3D12_VIEWPORT
var targetCount int
firstTarget := -1
for i, id := range dstIDs {
img := g.images[id]
if img == nil {
continue
}
srcImages[i] = src
if rb, ok := src.transiteState(_D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); ok {
if firstTarget == -1 {
firstTarget = i
}
dsts[i] = img
w, h := img.internalSize()
viewports[i] = _D3D12_VIEWPORT{
TopLeftX: 0,
TopLeftY: 0,
Width: float32(w),
Height: float32(h),
MinDepth: _D3D12_MIN_DEPTH,
MaxDepth: _D3D12_MAX_DEPTH,
}
if rb, ok := img.transiteState(_D3D12_RESOURCE_STATE_RENDER_TARGET); ok {
resourceBarriers = append(resourceBarriers, rb)
}
targetCount++
}
var srcs [graphics.ShaderSrcImageCount]*image12
for i, srcID := range srcIDs {
img := g.images[srcID]
if img == nil {
continue
}
srcs[i] = img
if rb, ok := img.transiteState(_D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); ok {
resourceBarriers = append(resourceBarriers, rb)
}
}
@ -1125,25 +1222,26 @@ func (g *graphics12) DrawTriangles(dstIDs [graphics.ShaderDstImageCount]graphics
g.drawCommandList.ResourceBarrier(resourceBarriers)
}
if err := dst.setAsRenderTarget(g.drawCommandList, g.device, fillRule != graphicsdriver.FillAll); err != nil {
// If the number of targets is more than one, or if the only target is the first one, then
// it is safe to assume that MRT is used.
// Also, it only matters in order to specify empty targets/viewports when not all slots are
// being filled.
usesMRT := targetCount > 1 || firstTarget > 0
if usesMRT {
targetCount = graphics.ShaderDstImageCount
}
g.drawCommandList.RSSetViewports(viewports[:targetCount])
if err := g.setAsRenderTargets(dsts[:targetCount], fillRule != graphicsdriver.FillAll); err != nil {
return err
}
shader := g.shaders[shaderID]
adjustedUniforms := adjustUniforms(shader.uniformTypes, shader.uniformOffsets, uniforms)
w, h := dst.internalSize()
g.needFlushDrawCommandList = true
g.drawCommandList.RSSetViewports([]_D3D12_VIEWPORT{
{
TopLeftX: 0,
TopLeftY: 0,
Width: float32(w),
Height: float32(h),
MinDepth: _D3D12_MIN_DEPTH,
MaxDepth: _D3D12_MAX_DEPTH,
},
})
g.drawCommandList.IASetPrimitiveTopology(_D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST)
g.drawCommandList.IASetVertexBuffers(0, []_D3D12_VERTEX_BUFFER_VIEW{
{
@ -1158,7 +1256,7 @@ func (g *graphics12) DrawTriangles(dstIDs [graphics.ShaderDstImageCount]graphics
Format: _DXGI_FORMAT_R32_UINT,
})
if err := g.pipelineStates.drawTriangles(g.device, g.drawCommandList, g.frameIndex, dst.screen, srcImages, shader, dstRegions, adjustedUniforms, blend, indexOffset, fillRule); err != nil {
if err := g.pipelineStates.drawTriangles(g.device, g.drawCommandList, g.frameIndex, !usesMRT && dsts[firstTarget].screen, srcs, shader, dstRegions, adjustedUniforms, blend, indexOffset, fillRule); err != nil {
return err
}

View File

@ -510,6 +510,90 @@ func (p *pipelineStates) newPipelineState(device *_ID3D12Device, vsh, psh *_ID3D
LogicOp: _D3D12_LOGIC_OP_NOOP,
RenderTargetWriteMask: writeMask,
},
{
BlendEnable: 1,
LogicOpEnable: 0,
SrcBlend: blendFactorToBlend12(blend.BlendFactorSourceRGB, false),
DestBlend: blendFactorToBlend12(blend.BlendFactorDestinationRGB, false),
BlendOp: blendOperationToBlendOp12(blend.BlendOperationRGB),
SrcBlendAlpha: blendFactorToBlend12(blend.BlendFactorSourceAlpha, true),
DestBlendAlpha: blendFactorToBlend12(blend.BlendFactorDestinationAlpha, true),
BlendOpAlpha: blendOperationToBlendOp12(blend.BlendOperationAlpha),
LogicOp: _D3D12_LOGIC_OP_NOOP,
RenderTargetWriteMask: writeMask,
},
{
BlendEnable: 1,
LogicOpEnable: 0,
SrcBlend: blendFactorToBlend12(blend.BlendFactorSourceRGB, false),
DestBlend: blendFactorToBlend12(blend.BlendFactorDestinationRGB, false),
BlendOp: blendOperationToBlendOp12(blend.BlendOperationRGB),
SrcBlendAlpha: blendFactorToBlend12(blend.BlendFactorSourceAlpha, true),
DestBlendAlpha: blendFactorToBlend12(blend.BlendFactorDestinationAlpha, true),
BlendOpAlpha: blendOperationToBlendOp12(blend.BlendOperationAlpha),
LogicOp: _D3D12_LOGIC_OP_NOOP,
RenderTargetWriteMask: writeMask,
},
{
BlendEnable: 1,
LogicOpEnable: 0,
SrcBlend: blendFactorToBlend12(blend.BlendFactorSourceRGB, false),
DestBlend: blendFactorToBlend12(blend.BlendFactorDestinationRGB, false),
BlendOp: blendOperationToBlendOp12(blend.BlendOperationRGB),
SrcBlendAlpha: blendFactorToBlend12(blend.BlendFactorSourceAlpha, true),
DestBlendAlpha: blendFactorToBlend12(blend.BlendFactorDestinationAlpha, true),
BlendOpAlpha: blendOperationToBlendOp12(blend.BlendOperationAlpha),
LogicOp: _D3D12_LOGIC_OP_NOOP,
RenderTargetWriteMask: writeMask,
},
{
BlendEnable: 1,
LogicOpEnable: 0,
SrcBlend: blendFactorToBlend12(blend.BlendFactorSourceRGB, false),
DestBlend: blendFactorToBlend12(blend.BlendFactorDestinationRGB, false),
BlendOp: blendOperationToBlendOp12(blend.BlendOperationRGB),
SrcBlendAlpha: blendFactorToBlend12(blend.BlendFactorSourceAlpha, true),
DestBlendAlpha: blendFactorToBlend12(blend.BlendFactorDestinationAlpha, true),
BlendOpAlpha: blendOperationToBlendOp12(blend.BlendOperationAlpha),
LogicOp: _D3D12_LOGIC_OP_NOOP,
RenderTargetWriteMask: writeMask,
},
{
BlendEnable: 1,
LogicOpEnable: 0,
SrcBlend: blendFactorToBlend12(blend.BlendFactorSourceRGB, false),
DestBlend: blendFactorToBlend12(blend.BlendFactorDestinationRGB, false),
BlendOp: blendOperationToBlendOp12(blend.BlendOperationRGB),
SrcBlendAlpha: blendFactorToBlend12(blend.BlendFactorSourceAlpha, true),
DestBlendAlpha: blendFactorToBlend12(blend.BlendFactorDestinationAlpha, true),
BlendOpAlpha: blendOperationToBlendOp12(blend.BlendOperationAlpha),
LogicOp: _D3D12_LOGIC_OP_NOOP,
RenderTargetWriteMask: writeMask,
},
{
BlendEnable: 1,
LogicOpEnable: 0,
SrcBlend: blendFactorToBlend12(blend.BlendFactorSourceRGB, false),
DestBlend: blendFactorToBlend12(blend.BlendFactorDestinationRGB, false),
BlendOp: blendOperationToBlendOp12(blend.BlendOperationRGB),
SrcBlendAlpha: blendFactorToBlend12(blend.BlendFactorSourceAlpha, true),
DestBlendAlpha: blendFactorToBlend12(blend.BlendFactorDestinationAlpha, true),
BlendOpAlpha: blendOperationToBlendOp12(blend.BlendOperationAlpha),
LogicOp: _D3D12_LOGIC_OP_NOOP,
RenderTargetWriteMask: writeMask,
},
{
BlendEnable: 1,
LogicOpEnable: 0,
SrcBlend: blendFactorToBlend12(blend.BlendFactorSourceRGB, false),
DestBlend: blendFactorToBlend12(blend.BlendFactorDestinationRGB, false),
BlendOp: blendOperationToBlendOp12(blend.BlendOperationRGB),
SrcBlendAlpha: blendFactorToBlend12(blend.BlendFactorSourceAlpha, true),
DestBlendAlpha: blendFactorToBlend12(blend.BlendFactorDestinationAlpha, true),
BlendOpAlpha: blendOperationToBlendOp12(blend.BlendOperationAlpha),
LogicOp: _D3D12_LOGIC_OP_NOOP,
RenderTargetWriteMask: writeMask,
},
},
},
SampleMask: math.MaxUint32,
@ -532,9 +616,10 @@ func (p *pipelineStates) newPipelineState(device *_ID3D12Device, vsh, psh *_ID3D
NumElements: uint32(len(inputElementDescsForDX12)),
},
PrimitiveTopologyType: _D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
NumRenderTargets: 1,
NumRenderTargets: graphics.ShaderDstImageCount,
RTVFormats: [8]_DXGI_FORMAT{
rtvFormat,
rtvFormat, rtvFormat, rtvFormat, rtvFormat,
rtvFormat, rtvFormat, rtvFormat, rtvFormat,
},
DSVFormat: dsvFormat,
SampleDesc: _DXGI_SAMPLE_DESC{