From 2a5b64bf4d5804ebbb6e131d724ea39fc05190e0 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sat, 18 Jun 2022 18:42:08 +0900 Subject: [PATCH] internal/graphicsdriver/directx: suppress warnings for depth buffers Updates #2138 --- .../directx/graphics_windows.go | 69 +++++++++++--- .../directx/pipeline_windows.go | 6 +- internal/processtest/testdata/issue2138.go | 94 +++++++++++++++++++ 3 files changed, 156 insertions(+), 13 deletions(-) create mode 100644 internal/processtest/testdata/issue2138.go diff --git a/internal/graphicsdriver/directx/graphics_windows.go b/internal/graphicsdriver/directx/graphics_windows.go index 711fdfb64..97e65bdeb 100644 --- a/internal/graphicsdriver/directx/graphics_windows.go +++ b/internal/graphicsdriver/directx/graphics_windows.go @@ -1002,10 +1002,6 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcs [graphics.Sh shader = g.shaders[shaderID] } - if err := dst.setAsRenderTarget(g.device, evenOdd); err != nil { - return err - } - var srcImages [graphics.ShaderImageNum]*Image for i, srcID := range srcs { src := g.images[srcID] @@ -1126,7 +1122,6 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcs [graphics.Sh }, }) - g.drawCommandList.IASetPrimitiveTopology(_D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST) g.drawCommandList.IASetVertexBuffers(0, []_D3D12_VERTEX_BUFFER_VIEW{ { BufferLocation: g.vertices[g.frameIndex][len(g.vertices[g.frameIndex])-1].GetGPUVirtualAddress(), @@ -1134,11 +1129,15 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcs [graphics.Sh StrideInBytes: graphics.VertexFloatNum * uint32(unsafe.Sizeof(float32(0))), }, }) - g.drawCommandList.IASetIndexBuffer(&_D3D12_INDEX_BUFFER_VIEW{ - BufferLocation: g.indices[g.frameIndex][len(g.indices[g.frameIndex])-1].GetGPUVirtualAddress(), - SizeInBytes: graphics.IndicesNum * uint32(unsafe.Sizeof(uint16(0))), - Format: _DXGI_FORMAT_R16_UINT, - }) + + setIndices := func() { + g.drawCommandList.IASetPrimitiveTopology(_D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST) + g.drawCommandList.IASetIndexBuffer(&_D3D12_INDEX_BUFFER_VIEW{ + BufferLocation: g.indices[g.frameIndex][len(g.indices[g.frameIndex])-1].GetGPUVirtualAddress(), + SizeInBytes: graphics.IndicesNum * uint32(unsafe.Sizeof(uint16(0))), + Format: _DXGI_FORMAT_R16_UINT, + }) + } if shader == nil { key := builtinPipelineStatesKey{ @@ -1150,6 +1149,14 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcs [graphics.Sh } if evenOdd { + if err := dst.setAsRenderTarget(g.device, evenOdd); err != nil { + return err + } + if err := dst.clearStencilBuffer(g.device); err != nil { + return err + } + setIndices() + key.stencilMode = prepareStencil s, err := g.pipelineStates.builtinGraphicsPipelineState(g.device, key) if err != nil { @@ -1159,6 +1166,11 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcs [graphics.Sh return err } + if err := dst.setAsRenderTarget(g.device, evenOdd); err != nil { + return err + } + setIndices() + key.stencilMode = drawWithStencil s, err = g.pipelineStates.builtinGraphicsPipelineState(g.device, key) if err != nil { @@ -1168,6 +1180,11 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcs [graphics.Sh return err } } else { + if err := dst.setAsRenderTarget(g.device, evenOdd); err != nil { + return err + } + setIndices() + key.stencilMode = noStencil s, err := g.pipelineStates.builtinGraphicsPipelineState(g.device, key) if err != nil { @@ -1180,6 +1197,14 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcs [graphics.Sh } else { if evenOdd { + if err := dst.setAsRenderTarget(g.device, evenOdd); err != nil { + return err + } + if err := dst.clearStencilBuffer(g.device); err != nil { + return err + } + setIndices() + s, err := shader.pipelineState(mode, prepareStencil) if err != nil { return err @@ -1188,6 +1213,11 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcs [graphics.Sh return err } + if err := dst.setAsRenderTarget(g.device, evenOdd); err != nil { + return err + } + setIndices() + s, err = shader.pipelineState(mode, drawWithStencil) if err != nil { return err @@ -1196,6 +1226,11 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcs [graphics.Sh return err } } else { + if err := dst.setAsRenderTarget(g.device, evenOdd); err != nil { + return err + } + setIndices() + s, err := shader.pipelineState(mode, noStencil) if err != nil { return err @@ -1518,8 +1553,6 @@ func (i *Image) setAsRenderTarget(device *_ID3D12Device, useStencil bool) error return err } dsv = &v - - i.graphics.drawCommandList.ClearDepthStencilView(v, _D3D12_CLEAR_FLAG_STENCIL, 0, 0, nil) i.graphics.drawCommandList.OMSetStencilRef(0) } i.graphics.drawCommandList.OMSetRenderTargets([]_D3D12_CPU_DESCRIPTOR_HANDLE{rtv}, false, dsv) // TODO: Pass depth-stencil here! @@ -1527,6 +1560,18 @@ func (i *Image) setAsRenderTarget(device *_ID3D12Device, useStencil bool) error return nil } +func (i *Image) clearStencilBuffer(device *_ID3D12Device) error { + if err := i.ensureDepthStencilView(device); err != nil { + return err + } + dsv, err := i.dsvDescriptorHeap.GetCPUDescriptorHandleForHeapStart() + if err != nil { + return err + } + i.graphics.drawCommandList.ClearDepthStencilView(dsv, _D3D12_CLEAR_FLAG_STENCIL, 0, 0, nil) + return nil +} + func (i *Image) ensureRenderTargetView(device *_ID3D12Device) error { if i.screen { return nil diff --git a/internal/graphicsdriver/directx/pipeline_windows.go b/internal/graphicsdriver/directx/pipeline_windows.go index 9bf070e86..bc47daffe 100644 --- a/internal/graphicsdriver/directx/pipeline_windows.go +++ b/internal/graphicsdriver/directx/pipeline_windows.go @@ -619,6 +619,10 @@ func (p *pipelineStates) newPipelineState(device *_ID3D12Device, vsh, psh *_ID3D if screen { rtvFormat = _DXGI_FORMAT_B8G8R8A8_UNORM } + dsvFormat := _DXGI_FORMAT_UNKNOWN + if stencilMode != noStencil { + dsvFormat = _DXGI_FORMAT_D24_UNORM_S8_UINT + } // Create a pipeline state. srcOp, dstOp := compositeMode.Operations() @@ -674,7 +678,7 @@ func (p *pipelineStates) newPipelineState(device *_ID3D12Device, vsh, psh *_ID3D RTVFormats: [8]_DXGI_FORMAT{ rtvFormat, }, - DSVFormat: _DXGI_FORMAT_D24_UNORM_S8_UINT, + DSVFormat: dsvFormat, SampleDesc: _DXGI_SAMPLE_DESC{ Count: 1, Quality: 0, diff --git a/internal/processtest/testdata/issue2138.go b/internal/processtest/testdata/issue2138.go new file mode 100644 index 000000000..6358e4473 --- /dev/null +++ b/internal/processtest/testdata/issue2138.go @@ -0,0 +1,94 @@ +// Copyright 2022 The Ebitengine Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:build ignore +// +build ignore + +package main + +import ( + "errors" + "image" + "image/color" + "math" + + "github.com/hajimehoshi/ebiten/v2" + "github.com/hajimehoshi/ebiten/v2/text" + "github.com/hajimehoshi/ebiten/v2/vector" + "golang.org/x/image/font" + "golang.org/x/image/font/gofont/goregular" + "golang.org/x/image/font/opentype" +) + +var regularTermination = errors.New("regular termination") + +var ( + emptyImage = ebiten.NewImage(3, 3) + debugCircleImage *ebiten.Image + emptyTextureImage = emptyImage.SubImage(image.Rect(1, 1, 2, 2)).(*ebiten.Image) + face font.Face +) + +func init() { + emptyImage.Fill(color.White) + + img := image.NewRGBA(image.Rect(0, 0, 20, 20)) + debugCircleImage = ebiten.NewImageFromImage(img) + + emptyImage.Fill(color.Black) + + f, _ := opentype.Parse(goregular.TTF) + face, _ = opentype.NewFace(f, &opentype.FaceOptions{ + Size: 12, + DPI: 72, + }) +} + +type Game struct { + counter int +} + +func (g *Game) Update() error { + g.counter++ + if g.counter > 16 { + return regularTermination + } + return nil +} + +func (g *Game) Draw(screen *ebiten.Image) { + // Before the fix, some complex renderings with EvenOdd might cause a DirectX error like this (#2138): + // panic: directx: IDXGISwapChain4::Present failed: HRESULT(2289696773) + + screen.DrawImage(debugCircleImage, nil) + text.Draw(screen, "014678.,", face, 100, 100, color.White) + + p := vector.Path{} + p.Arc(100, 100, 6, 0, 2*math.Pi, vector.Clockwise) + filling, indicies := p.AppendVerticesAndIndicesForFilling(nil, nil) + screen.DrawTriangles(filling, indicies, emptyTextureImage, &ebiten.DrawTrianglesOptions{ + FillRule: ebiten.EvenOdd, + }) +} + +func (g *Game) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) { + return 800, 600 +} + +func main() { + if err := ebiten.RunGame(&Game{}); err != nil && !errors.Is(err, regularTermination) { + panic(err) + } + +}