From d706d38adafb56e4633d798d25984889a1594db2 Mon Sep 17 00:00:00 2001 From: Zyko <13394516+Zyko0@users.noreply.github.com> Date: Sat, 13 Apr 2024 13:56:13 +0200 Subject: [PATCH] Add test with empty locations + fix directx 11 && 12 nil first argument --- examples/mrt/main.go | 6 +-- image.go | 9 +++-- internal/atlas/image.go | 4 +- internal/graphicscommand/commandqueue.go | 9 ++++- .../directx/graphics11_windows.go | 17 +++++---- .../directx/graphics12_windows.go | 7 ++-- shader_test.go | 38 +++++++++++++++++-- 7 files changed, 65 insertions(+), 25 deletions(-) diff --git a/examples/mrt/main.go b/examples/mrt/main.go index 11c7d1b3e..2cdbce402 100644 --- a/examples/mrt/main.go +++ b/examples/mrt/main.go @@ -36,9 +36,9 @@ var ( ebiten.NewImage(dstSize, dstSize), ebiten.NewImage(dstSize, dstSize), ebiten.NewImage(dstSize, dstSize),*/ - ebiten.NewImageWithOptions(image.Rect(0, 0, dstSize, dstSize), &ebiten.NewImageOptions{ + nil,/*ebiten.NewImageWithOptions(image.Rect(0, 0, dstSize, dstSize), &ebiten.NewImageOptions{ Unmanaged: true, - }), + }),*/ ebiten.NewImageWithOptions(image.Rect(0, 0, dstSize, dstSize), &ebiten.NewImageOptions{ Unmanaged: true, }), @@ -101,7 +101,7 @@ func (g *Game) Draw(screen *ebiten.Image) { indices := []uint16{0, 1, 2, 1, 2, 3} ebiten.DrawTrianglesShaderMRT(dsts, vertices, indices, s, nil) // Dst 0 - screen.DrawImage(dsts[0], nil) + //screen.DrawImage(dsts[0], nil) // Dst 1 opts := &ebiten.DrawImageOptions{} opts.GeoM.Translate(dstSize, 0) diff --git a/image.go b/image.go index 27937d38c..c8d1143ce 100644 --- a/image.go +++ b/image.go @@ -711,10 +711,8 @@ func (i *Image) DrawTrianglesShader(vertices []Vertex, indices []uint16, shader // // When the image i is disposed, DrawTrianglesShader does nothing. func DrawTrianglesShaderMRT(dsts [graphics.ShaderDstImageCount]*Image, vertices []Vertex, indices []uint16, shader *Shader, options *DrawTrianglesShaderOptions) { - if dsts[0] == nil || dsts[0].isDisposed() { - panic("ebiten: the first destination image given to DrawTrianglesShaderMRT must not be nil or disposed") - } var dstImgs [graphics.ShaderDstImageCount]*ui.Image + var firstDst *Image for i, dst := range dsts { if dst == nil { continue @@ -723,6 +721,9 @@ func DrawTrianglesShaderMRT(dsts [graphics.ShaderDstImageCount]*Image, vertices if dst.isDisposed() { panic("ebiten: the destination images given to DrawTrianglesShaderMRT must not be disposed") } + if firstDst == nil { + firstDst = dst + } dstImgs[i] = dst.image } @@ -754,7 +755,7 @@ func DrawTrianglesShaderMRT(dsts [graphics.ShaderDstImageCount]*Image, vertices blend = options.CompositeMode.blend().internalBlend() } - dst := dsts[0] + dst := firstDst vs := dst.ensureTmpVertices(len(vertices) * graphics.VertexFloatCount) src := options.Images[0] for i, v := range vertices { diff --git a/internal/atlas/image.go b/internal/atlas/image.go index d7915d577..d446d8c4c 100644 --- a/internal/atlas/image.go +++ b/internal/atlas/image.go @@ -576,12 +576,14 @@ func drawTrianglesMRT(dsts [graphics.ShaderDstImageCount]*Image, srcs [graphics. src.backend.sourceInThisFrame = true } + var firstDst *Image var dstImgs [graphics.ShaderDstImageCount]*graphicscommand.Image for i, dst := range dsts { if dst == nil { continue } dst.ensureIsolatedFromSource(backends) + firstDst = dst dstImgs[i] = dst.backend.image } @@ -595,7 +597,7 @@ func drawTrianglesMRT(dsts [graphics.ShaderDstImageCount]*Image, srcs [graphics. } } - r := dsts[0].regionWithPadding() + r := firstDst.regionWithPadding() // TODO: Check if dstRegion does not to violate the region. dstRegion = dstRegion.Add(r.Min) diff --git a/internal/graphicscommand/commandqueue.go b/internal/graphicscommand/commandqueue.go index 7cadaba24..3d74c9a09 100644 --- a/internal/graphicscommand/commandqueue.go +++ b/internal/graphicscommand/commandqueue.go @@ -330,7 +330,14 @@ func (q *commandQueue) prependPreservedUniforms(uniforms []uint32, shader *Shade copy(uniforms[graphics.PreservedUniformUint32Count:], origUniforms) // Set the destination texture size. - dw, dh := dsts[0].InternalSize() + var firstDst *Image + for _, dst := range dsts { + if dst != nil { + firstDst = dst + break + } + } + dw, dh := firstDst.InternalSize() uniforms[0] = math.Float32bits(float32(dw)) uniforms[1] = math.Float32bits(float32(dh)) uniformIndex := 2 diff --git a/internal/graphicsdriver/directx/graphics11_windows.go b/internal/graphicsdriver/directx/graphics11_windows.go index 2b90cdc32..23778bb0e 100644 --- a/internal/graphicsdriver/directx/graphics11_windows.go +++ b/internal/graphicsdriver/directx/graphics11_windows.go @@ -517,6 +517,7 @@ func (g *graphics11) removeShader(s *shader11) { func (g *graphics11) setAsRenderTargets(dsts []*image11, useStencil bool) error { var rtvs []*_ID3D11RenderTargetView + var dsv *_ID3D11DepthStencilView for _, i := range dsts { // Ignore a nil image in case of MRT if i == nil { @@ -532,7 +533,7 @@ func (g *graphics11) setAsRenderTargets(dsts []*image11, useStencil bool) error } rtvs = append(rtvs, i.renderTargetView) - if !useStencil { + if !useStencil || dsv != nil { continue } @@ -567,12 +568,13 @@ func (g *graphics11) setAsRenderTargets(dsts []*image11, useStencil bool) error return err } i.stencilView = sv + dsv = sv } } - g.deviceContext.OMSetRenderTargets(rtvs, dsts[0].stencilView) + g.deviceContext.OMSetRenderTargets(rtvs, dsv) if useStencil { - g.deviceContext.ClearDepthStencilView(dsts[0].stencilView, uint8(_D3D11_CLEAR_STENCIL), 0, 0) + g.deviceContext.ClearDepthStencilView(dsv, uint8(_D3D11_CLEAR_STENCIL), 0, 0) } return nil @@ -585,7 +587,7 @@ func (g *graphics11) DrawTriangles(dstIDs [graphics.ShaderDstImageCount]graphics g.deviceContext.PSSetShaderResources(0, srvs[:]) var dsts [graphics.ShaderDstImageCount]*image11 - var viewports [graphics.ShaderDstImageCount]_D3D11_VIEWPORT + var vp _D3D11_VIEWPORT var targetCount int firstTarget := -1 for i, id := range dstIDs { @@ -598,7 +600,7 @@ func (g *graphics11) DrawTriangles(dstIDs [graphics.ShaderDstImageCount]graphics } dsts[i] = img w, h := img.internalSize() - viewports[i] = _D3D11_VIEWPORT{ + vp = _D3D11_VIEWPORT{ TopLeftX: 0, TopLeftY: 0, Width: float32(w), @@ -621,13 +623,12 @@ func (g *graphics11) DrawTriangles(dstIDs [graphics.ShaderDstImageCount]graphics // 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. + // being filled, even though it's not a MRT scenario. if targetCount > 1 || firstTarget > 0 { targetCount = graphics.ShaderDstImageCount } - - g.deviceContext.RSSetViewports(viewports[:targetCount]) + g.deviceContext.RSSetViewports([]_D3D11_VIEWPORT{vp}) if err := g.setAsRenderTargets(dsts[:targetCount], fillRule != graphicsdriver.FillAll); err != nil { return err } diff --git a/internal/graphicsdriver/directx/graphics12_windows.go b/internal/graphicsdriver/directx/graphics12_windows.go index 250c5b410..99129fafa 100644 --- a/internal/graphicsdriver/directx/graphics12_windows.go +++ b/internal/graphicsdriver/directx/graphics12_windows.go @@ -1177,7 +1177,7 @@ func (g *graphics12) DrawTriangles(dstIDs [graphics.ShaderDstImageCount]graphics var resourceBarriers []_D3D12_RESOURCE_BARRIER_Transition var dsts [graphics.ShaderDstImageCount]*image12 - var viewports [graphics.ShaderDstImageCount]_D3D12_VIEWPORT + var vp _D3D12_VIEWPORT var targetCount int firstTarget := -1 for i, id := range dstIDs { @@ -1190,7 +1190,7 @@ func (g *graphics12) DrawTriangles(dstIDs [graphics.ShaderDstImageCount]graphics } dsts[i] = img w, h := img.internalSize() - viewports[i] = _D3D12_VIEWPORT{ + vp = _D3D12_VIEWPORT{ TopLeftX: 0, TopLeftY: 0, Width: float32(w), @@ -1231,8 +1231,7 @@ func (g *graphics12) DrawTriangles(dstIDs [graphics.ShaderDstImageCount]graphics targetCount = graphics.ShaderDstImageCount } - g.drawCommandList.RSSetViewports(viewports[:targetCount]) - + g.drawCommandList.RSSetViewports([]_D3D12_VIEWPORT{vp}) if err := g.setAsRenderTargets(dsts[:targetCount], fillRule != graphicsdriver.FillAll); err != nil { return err } diff --git a/shader_test.go b/shader_test.go index 5f2f32a9e..b325bb8d7 100644 --- a/shader_test.go +++ b/shader_test.go @@ -2652,7 +2652,7 @@ func Fragment(dstPos vec4, srcPos vec2, color vec4) (vec4, vec4, vec4, vec4, vec }, } indices := []uint16{0, 1, 2, 1, 2, 3} - t.Run("8 slots", func(t *testing.T) { + t.Run("8 locations", func(t *testing.T) { wantColors := [8]color.RGBA{ {R: 0xff, G: 0, B: 0, A: 0xff}, {R: 0, G: 0xff, B: 0, A: 0xff}, @@ -2663,9 +2663,8 @@ func Fragment(dstPos vec4, srcPos vec2, color vec4) (vec4, vec4, vec4, vec4, vec {R: 0xff, G: 0xff, B: 0xff, A: 0xff}, {R: 0xff, G: 0xff, B: 0xff, A: 0}, } - dsts := imgs - ebiten.DrawTrianglesShaderMRT(dsts, vertices, indices, s, nil) - for k, dst := range dsts { + ebiten.DrawTrianglesShaderMRT(imgs, vertices, indices, s, nil) + for k, dst := range imgs { for j := 0; j < h; j++ { for i := 0; i < w; i++ { got := dst.At(i, j).(color.RGBA) @@ -2677,4 +2676,35 @@ func Fragment(dstPos vec4, srcPos vec2, color vec4) (vec4, vec4, vec4, vec4, vec } } }) + + for _, img := range imgs { + img.Clear() + } + t.Run("Empty locations", func(t *testing.T) { + wantColors := [8]color.RGBA{ + {}, + {R: 0, G: 0xff, B: 0, A: 0xff}, + {}, + {R: 0xff, G: 0, B: 0xff, A: 0xff}, + {}, + {R: 0, G: 0xff, B: 0xff, A: 0xff}, + {}, + {R: 0xff, G: 0xff, B: 0xff, A: 0}, + } + dsts := [8]*ebiten.Image{ + nil, imgs[1], nil, imgs[3], nil, imgs[5], nil, imgs[7], + } + ebiten.DrawTrianglesShaderMRT(dsts, vertices, indices, s, nil) + for k, dst := range imgs { + for j := 0; j < h; j++ { + for i := 0; i < w; i++ { + got := dst.At(i, j).(color.RGBA) + want := wantColors[k] + if !sameColors(got, want, 1) { + t.Errorf("%d dst.At(%d, %d): got: %v, want: %v", k, i, j, got, want) + } + } + } + } + }) }