diff --git a/image_test.go b/image_test.go index 38797af0b..de421d296 100644 --- a/image_test.go +++ b/image_test.go @@ -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 { vs0[i].DstX++ 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) + } + } + } } diff --git a/internal/graphicscommand/command.go b/internal/graphicscommand/command.go index b9d9cbd45..d21163a14 100644 --- a/internal/graphicscommand/command.go +++ b/internal/graphicscommand/command.go @@ -482,7 +482,7 @@ func (c *drawTrianglesCommand) CanMergeWithDrawTrianglesCommand(dst *Image, srcs if c.srcRegion != srcRegion { return false } - if c.evenOdd != evenOdd { + if c.evenOdd || evenOdd { return false } return true diff --git a/internal/graphicsdriver/metal/graphics.go b/internal/graphicsdriver/metal/graphics.go index 86a0c7682..affaa7ea8 100644 --- a/internal/graphicsdriver/metal/graphics.go +++ b/internal/graphicsdriver/metal/graphics.go @@ -316,7 +316,6 @@ type Graphics struct { screenDrawable ca.MetalDrawable lastDstTexture mtl.Texture - lastStencilUse bool vb mtl.Buffer ib mtl.Buffer @@ -345,10 +344,6 @@ const ( noStencil ) -func (s stencilMode) useStencil() bool { - return s != noStencil -} - var theGraphics Graphics func Get() *Graphics { @@ -645,11 +640,13 @@ func (g *Graphics) flushRenderCommandEncoderIfNeeded() { g.rce.EndEncoding() g.rce = mtl.RenderCommandEncoder{} 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 { - 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() } @@ -668,7 +665,7 @@ func (g *Graphics) draw(rps mtl.RenderPipelineState, dst *Image, dstRegion drive rpd.ColorAttachments[0].Texture = t rpd.ColorAttachments[0].ClearColor = mtl.ClearColor{} - if stencilMode.useStencil() { + if stencilMode == prepareStencil { dst.ensureStencil() rpd.StencilAttachment.LoadAction = mtl.LoadActionClear 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.lastStencilUse = stencilMode.useStencil() g.rce.SetRenderPipelineState(rps)