ebiten: Bug fix: Draw commands with EvenOdd should not be merged

Updates #1684
This commit is contained in:
Hajime Hoshi 2021-07-05 18:08:52 +09:00
parent daa883d799
commit 674802d2f5
3 changed files with 45 additions and 11 deletions

View File

@ -2332,7 +2332,7 @@ func TestImageEvenOdd(t *testing.T) {
} }
} }
// Do the same thing with a little shift. This confirms that the underlying stencil buffer is cleared correctly. // Do the same thing but with a little shift. This confirms that the underlying stencil buffer is cleared correctly.
for i := range vs0 { for i := range vs0 {
vs0[i].DstX++ vs0[i].DstX++
vs0[i].DstY++ vs0[i].DstY++
@ -2366,4 +2366,42 @@ func TestImageEvenOdd(t *testing.T) {
} }
} }
} }
// Do the same thing but with split DrawTriangle calls. This confirms that the even-odd rule is applied for one call.
for i := range vs0 {
vs0[i].DstX--
vs0[i].DstY--
}
for i := range vs1 {
vs1[i].DstX--
vs1[i].DstY--
}
for i := range vs2 {
vs2[i].DstX--
vs2[i].DstY--
}
dst.Clear()
// Use the first indices set.
dst.DrawTriangles(vs0, is0, emptySubImage, op)
dst.DrawTriangles(vs1, is0, emptySubImage, op)
dst.DrawTriangles(vs2, is0, emptySubImage, op)
for j := 0; j < 16; j++ {
for i := 0; i < 16; i++ {
got := dst.At(i, j)
var want color.RGBA
switch {
case 3 <= i && i < 13 && 3 <= j && j < 13:
want = color.RGBA{0, 0, 0xff, 0xff}
case 2 <= i && i < 14 && 2 <= j && j < 14:
want = color.RGBA{0, 0xff, 0, 0xff}
case 1 <= i && i < 15 && 1 <= j && j < 15:
want = color.RGBA{0xff, 0, 0, 0xff}
default:
want = color.RGBA{0, 0, 0, 0}
}
if got != want {
t.Errorf("dst.At(%d, %d): got: %v, want: %v", i, j, got, want)
}
}
}
} }

View File

@ -482,7 +482,7 @@ func (c *drawTrianglesCommand) CanMergeWithDrawTrianglesCommand(dst *Image, srcs
if c.srcRegion != srcRegion { if c.srcRegion != srcRegion {
return false return false
} }
if c.evenOdd != evenOdd { if c.evenOdd || evenOdd {
return false return false
} }
return true return true

View File

@ -316,7 +316,6 @@ type Graphics struct {
screenDrawable ca.MetalDrawable screenDrawable ca.MetalDrawable
lastDstTexture mtl.Texture lastDstTexture mtl.Texture
lastStencilUse bool
vb mtl.Buffer vb mtl.Buffer
ib mtl.Buffer ib mtl.Buffer
@ -345,10 +344,6 @@ const (
noStencil noStencil
) )
func (s stencilMode) useStencil() bool {
return s != noStencil
}
var theGraphics Graphics var theGraphics Graphics
func Get() *Graphics { func Get() *Graphics {
@ -645,11 +640,13 @@ func (g *Graphics) flushRenderCommandEncoderIfNeeded() {
g.rce.EndEncoding() g.rce.EndEncoding()
g.rce = mtl.RenderCommandEncoder{} g.rce = mtl.RenderCommandEncoder{}
g.lastDstTexture = mtl.Texture{} g.lastDstTexture = mtl.Texture{}
g.lastStencilUse = false
} }
func (g *Graphics) draw(rps mtl.RenderPipelineState, dst *Image, dstRegion driver.Region, srcs [graphics.ShaderImageNum]*Image, indexLen int, indexOffset int, uniforms []interface{}, stencilMode stencilMode) error { func (g *Graphics) draw(rps mtl.RenderPipelineState, dst *Image, dstRegion driver.Region, srcs [graphics.ShaderImageNum]*Image, indexLen int, indexOffset int, uniforms []interface{}, stencilMode stencilMode) error {
if g.lastDstTexture != dst.mtlTexture() || g.lastStencilUse != stencilMode.useStencil() { // When prepareing a stencil buffer, flush the current render command encoder
// to make sure the stencil buffer is cleared when loading.
// TODO: What about clearing the stencil buffer by vertices?
if g.lastDstTexture != dst.mtlTexture() || stencilMode == prepareStencil {
g.flushRenderCommandEncoderIfNeeded() g.flushRenderCommandEncoderIfNeeded()
} }
@ -668,7 +665,7 @@ func (g *Graphics) draw(rps mtl.RenderPipelineState, dst *Image, dstRegion drive
rpd.ColorAttachments[0].Texture = t rpd.ColorAttachments[0].Texture = t
rpd.ColorAttachments[0].ClearColor = mtl.ClearColor{} rpd.ColorAttachments[0].ClearColor = mtl.ClearColor{}
if stencilMode.useStencil() { if stencilMode == prepareStencil {
dst.ensureStencil() dst.ensureStencil()
rpd.StencilAttachment.LoadAction = mtl.LoadActionClear rpd.StencilAttachment.LoadAction = mtl.LoadActionClear
rpd.StencilAttachment.StoreAction = mtl.StoreActionDontCare rpd.StencilAttachment.StoreAction = mtl.StoreActionDontCare
@ -680,7 +677,6 @@ func (g *Graphics) draw(rps mtl.RenderPipelineState, dst *Image, dstRegion drive
} }
g.rce = g.cb.MakeRenderCommandEncoder(rpd) g.rce = g.cb.MakeRenderCommandEncoder(rpd)
} }
g.lastStencilUse = stencilMode.useStencil()
g.rce.SetRenderPipelineState(rps) g.rce.SetRenderPipelineState(rps)