From 09a7d398744ea832a6a31bd87915e31a20d173fb Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sat, 15 Oct 2022 18:58:56 +0900 Subject: [PATCH] internal/graphicsdriver: add Blend struct This is a preparation to specify blend factors and blend operators. Updates #2382 --- graphics.go | 77 +++++++++++++--- image.go | 16 ++-- internal/atlas/image.go | 12 +-- internal/atlas/image_test.go | 34 +++---- internal/atlas/shader_test.go | 8 +- internal/buffered/image.go | 6 +- internal/graphicscommand/command.go | 57 ++++-------- internal/graphicscommand/image.go | 4 +- internal/graphicscommand/image_test.go | 10 +-- internal/graphicsdriver/blend.go | 71 +++++++++++++++ internal/graphicsdriver/compositemode.go | 88 ------------------- .../directx/graphics_windows.go | 24 ++--- .../directx/pipeline_windows.go | 32 ++++--- internal/graphicsdriver/graphics.go | 2 +- .../graphicsdriver/metal/graphics_darwin.go | 19 ++-- .../graphicsdriver/metal/mtl/mtl_darwin.go | 16 ++++ .../graphicsdriver/metal/shader_darwin.go | 26 +++--- internal/graphicsdriver/opengl/context.go | 23 ++++- internal/graphicsdriver/opengl/context_gl.go | 23 +++-- .../graphicsdriver/opengl/context_gles.go | 21 +++-- internal/graphicsdriver/opengl/context_js.go | 22 +++-- .../opengl/gl/package_notpurego.go | 31 +++++-- .../opengl/gl/package_purego.go | 21 +++-- internal/graphicsdriver/opengl/gl_js.go | 6 +- .../graphicsdriver/opengl/gles/default.go | 8 +- .../graphicsdriver/opengl/gles/gomobile.go | 8 +- .../graphicsdriver/opengl/gles/interface.go | 3 +- internal/graphicsdriver/opengl/graphics.go | 4 +- internal/mipmap/mipmap.go | 6 +- internal/restorable/image.go | 18 ++-- internal/restorable/images_test.go | 54 ++++++------ internal/restorable/shader_test.go | 12 +-- internal/ui/image.go | 8 +- 33 files changed, 440 insertions(+), 330 deletions(-) create mode 100644 internal/graphicsdriver/blend.go delete mode 100644 internal/graphicsdriver/compositemode.go diff --git a/graphics.go b/graphics.go index d1a7b1e76..6d0886f05 100644 --- a/graphics.go +++ b/graphics.go @@ -15,6 +15,8 @@ package ebiten import ( + "fmt" + "github.com/hajimehoshi/ebiten/v2/internal/builtinshader" "github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver" "github.com/hajimehoshi/ebiten/v2/internal/ui" @@ -41,50 +43,97 @@ type CompositeMode int const ( // Regular alpha blending // c_out = c_src + c_dst × (1 - α_src) - CompositeModeSourceOver CompositeMode = CompositeMode(graphicsdriver.CompositeModeSourceOver) + CompositeModeSourceOver CompositeMode = iota // c_out = 0 - CompositeModeClear CompositeMode = CompositeMode(graphicsdriver.CompositeModeClear) + CompositeModeClear // c_out = c_src - CompositeModeCopy CompositeMode = CompositeMode(graphicsdriver.CompositeModeCopy) + CompositeModeCopy // c_out = c_dst - CompositeModeDestination CompositeMode = CompositeMode(graphicsdriver.CompositeModeDestination) + CompositeModeDestination // c_out = c_src × (1 - α_dst) + c_dst - CompositeModeDestinationOver CompositeMode = CompositeMode(graphicsdriver.CompositeModeDestinationOver) + CompositeModeDestinationOver // c_out = c_src × α_dst - CompositeModeSourceIn CompositeMode = CompositeMode(graphicsdriver.CompositeModeSourceIn) + CompositeModeSourceIn // c_out = c_dst × α_src - CompositeModeDestinationIn CompositeMode = CompositeMode(graphicsdriver.CompositeModeDestinationIn) + CompositeModeDestinationIn // c_out = c_src × (1 - α_dst) - CompositeModeSourceOut CompositeMode = CompositeMode(graphicsdriver.CompositeModeSourceOut) + CompositeModeSourceOut // c_out = c_dst × (1 - α_src) - CompositeModeDestinationOut CompositeMode = CompositeMode(graphicsdriver.CompositeModeDestinationOut) + CompositeModeDestinationOut // c_out = c_src × α_dst + c_dst × (1 - α_src) - CompositeModeSourceAtop CompositeMode = CompositeMode(graphicsdriver.CompositeModeSourceAtop) + CompositeModeSourceAtop // c_out = c_src × (1 - α_dst) + c_dst × α_src - CompositeModeDestinationAtop CompositeMode = CompositeMode(graphicsdriver.CompositeModeDestinationAtop) + CompositeModeDestinationAtop // c_out = c_src × (1 - α_dst) + c_dst × (1 - α_src) - CompositeModeXor CompositeMode = CompositeMode(graphicsdriver.CompositeModeXor) + CompositeModeXor // Sum of source and destination (a.k.a. 'plus' or 'additive') // c_out = c_src + c_dst - CompositeModeLighter CompositeMode = CompositeMode(graphicsdriver.CompositeModeLighter) + CompositeModeLighter // The product of source and destination (a.k.a 'multiply blend mode') // c_out = c_src * c_dst - CompositeModeMultiply CompositeMode = CompositeMode(graphicsdriver.CompositeModeMultiply) + CompositeModeMultiply ) +func (c CompositeMode) blend() graphicsdriver.Blend { + src, dst := c.blendFactors() + return graphicsdriver.Blend{ + BlendFactorSourceColor: src, + BlendFactorSourceAlpha: src, + BlendFactorDestinationColor: dst, + BlendFactorDestinationAlpha: dst, + BlendOperationColor: graphicsdriver.BlendOperationAdd, + BlendOperationAlpha: graphicsdriver.BlendOperationAdd, + } +} + +func (c CompositeMode) blendFactors() (src graphicsdriver.BlendFactor, dst graphicsdriver.BlendFactor) { + switch c { + case CompositeModeSourceOver: + return graphicsdriver.BlendFactorOne, graphicsdriver.BlendFactorOneMinusSourceAlpha + case CompositeModeClear: + return graphicsdriver.BlendFactorZero, graphicsdriver.BlendFactorZero + case CompositeModeCopy: + return graphicsdriver.BlendFactorOne, graphicsdriver.BlendFactorZero + case CompositeModeDestination: + return graphicsdriver.BlendFactorZero, graphicsdriver.BlendFactorOne + case CompositeModeDestinationOver: + return graphicsdriver.BlendFactorOneMinusDestinationAlpha, graphicsdriver.BlendFactorOne + case CompositeModeSourceIn: + return graphicsdriver.BlendFactorDestinationAlpha, graphicsdriver.BlendFactorZero + case CompositeModeDestinationIn: + return graphicsdriver.BlendFactorZero, graphicsdriver.BlendFactorSourceAlpha + case CompositeModeSourceOut: + return graphicsdriver.BlendFactorOneMinusDestinationAlpha, graphicsdriver.BlendFactorZero + case CompositeModeDestinationOut: + return graphicsdriver.BlendFactorZero, graphicsdriver.BlendFactorOneMinusSourceAlpha + case CompositeModeSourceAtop: + return graphicsdriver.BlendFactorDestinationAlpha, graphicsdriver.BlendFactorOneMinusSourceAlpha + case CompositeModeDestinationAtop: + return graphicsdriver.BlendFactorOneMinusDestinationAlpha, graphicsdriver.BlendFactorSourceAlpha + case CompositeModeXor: + return graphicsdriver.BlendFactorOneMinusDestinationAlpha, graphicsdriver.BlendFactorOneMinusSourceAlpha + case CompositeModeLighter: + return graphicsdriver.BlendFactorOne, graphicsdriver.BlendFactorOne + case CompositeModeMultiply: + return graphicsdriver.BlendFactorDestinationColor, graphicsdriver.BlendFactorZero + default: + panic(fmt.Sprintf("ebiten: invalid composite mode: %d", c)) + } +} + // GraphicsLibrary represets graphics libraries supported by the engine. type GraphicsLibrary = ui.GraphicsLibrary diff --git a/image.go b/image.go index 925a37b7a..9f4552234 100644 --- a/image.go +++ b/image.go @@ -215,7 +215,7 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) { options = &DrawImageOptions{} } - mode := graphicsdriver.CompositeMode(options.CompositeMode) + blend := options.CompositeMode.blend() filter := builtinshader.Filter(options.Filter) if offsetX, offsetY := i.adjustPosition(0, 0); offsetX != 0 || offsetY != 0 { @@ -245,7 +245,7 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) { }) } - i.image.DrawTriangles(srcs, vs, is, mode, i.adjustedRegion(), graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, shader.shader, uniforms, false, canSkipMipmap(options.GeoM, filter)) + i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedRegion(), graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, shader.shader, uniforms, false, canSkipMipmap(options.GeoM, filter)) } // Vertex represents a vertex passed to DrawTriangles. @@ -396,7 +396,7 @@ func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, o options = &DrawTrianglesOptions{} } - mode := graphicsdriver.CompositeMode(options.CompositeMode) + blend := options.CompositeMode.blend() address := builtinshader.Address(options.Address) var sr graphicsdriver.Region @@ -455,7 +455,7 @@ func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, o }) } - i.image.DrawTriangles(srcs, vs, is, mode, i.adjustedRegion(), sr, [graphics.ShaderImageCount - 1][2]float32{}, shader.shader, uniforms, options.FillRule == EvenOdd, filter != builtinshader.FilterLinear) + i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedRegion(), sr, [graphics.ShaderImageCount - 1][2]float32{}, shader.shader, uniforms, options.FillRule == EvenOdd, filter != builtinshader.FilterLinear) } // DrawTrianglesShaderOptions represents options for DrawTrianglesShader. @@ -525,7 +525,7 @@ func (i *Image) DrawTrianglesShader(vertices []Vertex, indices []uint16, shader options = &DrawTrianglesShaderOptions{} } - mode := graphicsdriver.CompositeMode(options.CompositeMode) + blend := options.CompositeMode.blend() vs := graphics.Vertices(len(vertices)) dst := i @@ -589,7 +589,7 @@ func (i *Image) DrawTrianglesShader(vertices []Vertex, indices []uint16, shader offsets[i][1] = float32(y - sy) } - i.image.DrawTriangles(imgs, vs, is, mode, i.adjustedRegion(), sr, offsets, shader.shader, shader.convertUniforms(options.Uniforms), options.FillRule == EvenOdd, true) + i.image.DrawTriangles(imgs, vs, is, blend, i.adjustedRegion(), sr, offsets, shader.shader, shader.convertUniforms(options.Uniforms), options.FillRule == EvenOdd, true) } // DrawRectShaderOptions represents options for DrawRectShader. @@ -645,7 +645,7 @@ func (i *Image) DrawRectShader(width, height int, shader *Shader, options *DrawR options = &DrawRectShaderOptions{} } - mode := graphicsdriver.CompositeMode(options.CompositeMode) + blend := options.CompositeMode.blend() var imgs [graphics.ShaderImageCount]*ui.Image for i, img := range options.Images { @@ -690,7 +690,7 @@ func (i *Image) DrawRectShader(width, height int, shader *Shader, options *DrawR offsets[i][1] = float32(y - sy) } - i.image.DrawTriangles(imgs, vs, is, mode, i.adjustedRegion(), sr, offsets, shader.shader, shader.convertUniforms(options.Uniforms), false, true) + i.image.DrawTriangles(imgs, vs, is, blend, i.adjustedRegion(), sr, offsets, shader.shader, shader.convertUniforms(options.Uniforms), false, true) } // SubImage returns an image representing the portion of the image p visible through r. diff --git a/internal/atlas/image.go b/internal/atlas/image.go index fc7f78c35..71c43cfc1 100644 --- a/internal/atlas/image.go +++ b/internal/atlas/image.go @@ -309,7 +309,7 @@ func (i *Image) ensureIsolated() { Width: float32(w - 2*i.paddingSize()), Height: float32(h - 2*i.paddingSize()), } - newImg.DrawTriangles(srcs, offsets, vs, is, graphicsdriver.CompositeModeCopy, dstRegion, graphicsdriver.Region{}, NearestFilterShader.shader, nil, false) + newImg.DrawTriangles(srcs, offsets, vs, is, graphicsdriver.BlendCopy, dstRegion, graphicsdriver.Region{}, NearestFilterShader.shader, nil, false) i.dispose(false) i.backend = &backend{ @@ -348,7 +348,7 @@ func (i *Image) putOnAtlas(graphicsDriver graphicsdriver.Graphics) error { Width: w, Height: h, } - newI.drawTriangles([graphics.ShaderImageCount]*Image{i}, vs, is, graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, NearestFilterShader, nil, false, true) + newI.drawTriangles([graphics.ShaderImageCount]*Image{i}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, NearestFilterShader, nil, false, true) newI.moveTo(i) i.usedAsSourceCount = 0 @@ -395,13 +395,13 @@ func (i *Image) processSrc(src *Image) { // 5: Color G // 6: Color B // 7: Color Y -func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, mode graphicsdriver.CompositeMode, dstRegion, srcRegion graphicsdriver.Region, subimageOffsets [graphics.ShaderImageCount - 1][2]float32, shader *Shader, uniforms [][]float32, evenOdd bool) { +func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion, srcRegion graphicsdriver.Region, subimageOffsets [graphics.ShaderImageCount - 1][2]float32, shader *Shader, uniforms [][]float32, evenOdd bool) { backendsM.Lock() defer backendsM.Unlock() - i.drawTriangles(srcs, vertices, indices, mode, dstRegion, srcRegion, subimageOffsets, shader, uniforms, evenOdd, false) + i.drawTriangles(srcs, vertices, indices, blend, dstRegion, srcRegion, subimageOffsets, shader, uniforms, evenOdd, false) } -func (i *Image) drawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, mode graphicsdriver.CompositeMode, dstRegion, srcRegion graphicsdriver.Region, subimageOffsets [graphics.ShaderImageCount - 1][2]float32, shader *Shader, uniforms [][]float32, evenOdd bool, keepOnAtlas bool) { +func (i *Image) drawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion, srcRegion graphicsdriver.Region, subimageOffsets [graphics.ShaderImageCount - 1][2]float32, shader *Shader, uniforms [][]float32, evenOdd bool, keepOnAtlas bool) { if i.disposed { panic("atlas: the drawing target image must not be disposed (DrawTriangles)") } @@ -472,7 +472,7 @@ func (i *Image) drawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [ imgs[i] = src.backend.restorable } - i.backend.restorable.DrawTriangles(imgs, offsets, vertices, indices, mode, dstRegion, srcRegion, shader.shader, uniforms, evenOdd) + i.backend.restorable.DrawTriangles(imgs, offsets, vertices, indices, blend, dstRegion, srcRegion, shader.shader, uniforms, evenOdd) for _, src := range srcs { if src == nil { diff --git a/internal/atlas/image_test.go b/internal/atlas/image_test.go index ba459be78..d6bf33c05 100644 --- a/internal/atlas/image_test.go +++ b/internal/atlas/image_test.go @@ -106,7 +106,7 @@ func TestEnsureIsolated(t *testing.T) { Width: size, Height: size, } - img4.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + img4.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) if got, want := img4.IsOnAtlasForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -119,7 +119,7 @@ func TestEnsureIsolated(t *testing.T) { Width: size / 2, Height: size / 2, } - img3.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img5}, vs, is, graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + img3.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img5}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) if got, want := img3.IsOnAtlasForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -148,7 +148,7 @@ func TestEnsureIsolated(t *testing.T) { // Check further drawing doesn't cause panic. // This bug was fixed by 03dcd948. - img4.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + img4.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) } func TestReputOnAtlas(t *testing.T) { @@ -195,7 +195,7 @@ func TestReputOnAtlas(t *testing.T) { Width: size, Height: size, } - img1.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img2}, vs, is, graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + img1.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img2}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) if got, want := img1.IsOnAtlasForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -207,7 +207,7 @@ func TestReputOnAtlas(t *testing.T) { if err := atlas.PutImagesOnAtlasForTesting(ui.GraphicsDriverForTesting()); err != nil { t.Fatal(err) } - img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) if got, want := img1.IsOnAtlasForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -235,7 +235,7 @@ func TestReputOnAtlas(t *testing.T) { } // img1 is on an atlas again. - img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) if got, want := img1.IsOnAtlasForTesting(), true; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -259,7 +259,7 @@ func TestReputOnAtlas(t *testing.T) { } // Use img1 as a render target again. - img1.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img2}, vs, is, graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + img1.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img2}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) if got, want := img1.IsOnAtlasForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -271,7 +271,7 @@ func TestReputOnAtlas(t *testing.T) { t.Fatal(err) } img1.WritePixels(make([]byte, 4*size*size), 0, 0, size, size) - img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) if got, want := img1.IsOnAtlasForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -281,7 +281,7 @@ func TestReputOnAtlas(t *testing.T) { } // img1 is not on an atlas due to WritePixels. - img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) if got, want := img1.IsOnAtlasForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -291,7 +291,7 @@ func TestReputOnAtlas(t *testing.T) { if err := atlas.PutImagesOnAtlasForTesting(ui.GraphicsDriverForTesting()); err != nil { t.Fatal(err) } - img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) if got, want := img3.IsOnAtlasForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -391,7 +391,7 @@ func TestWritePixelsAfterDrawTriangles(t *testing.T) { Width: w, Height: h, } - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) dst.WritePixels(pix, 0, 0, w, h) pix = make([]byte, 4*w*h) @@ -439,7 +439,7 @@ func TestSmallImages(t *testing.T) { Width: w, Height: h, } - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.CompositeModeSourceOver, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) pix = make([]byte, 4*w*h) if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), pix); err != nil { @@ -487,7 +487,7 @@ func TestLongImages(t *testing.T) { Width: dstW, Height: dstH, } - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.CompositeModeSourceOver, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) pix = make([]byte, 4*dstW*dstH) if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), pix); err != nil { @@ -604,7 +604,7 @@ func TestDisposedAndReputOnAtlas(t *testing.T) { Width: size, Height: size, } - src.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src2}, vs, is, graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + src.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src2}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) if got, want := src.IsOnAtlasForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -614,7 +614,7 @@ func TestDisposedAndReputOnAtlas(t *testing.T) { if err := atlas.PutImagesOnAtlasForTesting(ui.GraphicsDriverForTesting()); err != nil { t.Fatal(err) } - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) if got, want := src.IsOnAtlasForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -654,7 +654,7 @@ func TestImageIsNotReputOnAtlasWithoutUsingAsSource(t *testing.T) { } // Use src2 as a rendering target, and make src2 an independent image. - src2.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + src2.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) if got, want := src2.IsOnAtlasForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -675,7 +675,7 @@ func TestImageIsNotReputOnAtlasWithoutUsingAsSource(t *testing.T) { if err := atlas.PutImagesOnAtlasForTesting(ui.GraphicsDriverForTesting()); err != nil { t.Fatal(err) } - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src2}, vs, is, graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src2}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) if got, want := src2.IsOnAtlasForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } diff --git a/internal/atlas/shader_test.go b/internal/atlas/shader_test.go index 1886bd4ec..7f9336515 100644 --- a/internal/atlas/shader_test.go +++ b/internal/atlas/shader_test.go @@ -40,12 +40,12 @@ func TestShaderFillTwice(t *testing.T) { } g := ui.GraphicsDriverForTesting() s0 := atlas.NewShader(etesting.ShaderProgramFill(0xff, 0xff, 0xff, 0xff)) - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{}, vs, is, graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, s0, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, s0, nil, false) // Vertices must be recreated (#1755) vs = quadVertices(w, h, 0, 0, 1) s1 := atlas.NewShader(etesting.ShaderProgramFill(0x80, 0x80, 0x80, 0xff)) - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{}, vs, is, graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, s1, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, s1, nil, false) pix := make([]byte, 4*w*h) if err := dst.ReadPixels(g, pix); err != nil { @@ -73,11 +73,11 @@ func TestImageDrawTwice(t *testing.T) { Width: w, Height: h, } - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src0}, vs, is, graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src0}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) // Vertices must be recreated (#1755) vs = quadVertices(w, h, 0, 0, 1) - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src1}, vs, is, graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src1}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) pix := make([]byte, 4*w*h) if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), pix); err != nil { diff --git a/internal/buffered/image.go b/internal/buffered/image.go index 9c4f07c74..81da57b11 100644 --- a/internal/buffered/image.go +++ b/internal/buffered/image.go @@ -140,7 +140,7 @@ func (i *Image) WritePixels(pix []byte, x, y, width, height int) { // DrawTriangles draws the src image with the given vertices. // // Copying vertices and indices is the caller's responsibility. -func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, mode graphicsdriver.CompositeMode, dstRegion, srcRegion graphicsdriver.Region, subimageOffsets [graphics.ShaderImageCount - 1][2]float32, shader *Shader, uniforms [][]float32, evenOdd bool) { +func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion, srcRegion graphicsdriver.Region, subimageOffsets [graphics.ShaderImageCount - 1][2]float32, shader *Shader, uniforms [][]float32, evenOdd bool) { for _, src := range srcs { if i == src { panic("buffered: Image.DrawTriangles: source images must be different from the receiver") @@ -150,7 +150,7 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [ if maybeCanAddDelayedCommand() { if tryAddDelayedCommand(func() { // Arguments are not copied. Copying is the caller's responsibility. - i.DrawTriangles(srcs, vertices, indices, mode, dstRegion, srcRegion, subimageOffsets, shader, uniforms, evenOdd) + i.DrawTriangles(srcs, vertices, indices, blend, dstRegion, srcRegion, subimageOffsets, shader, uniforms, evenOdd) }) { return } @@ -165,7 +165,7 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [ } i.invalidatePixels() - i.img.DrawTriangles(imgs, vertices, indices, mode, dstRegion, srcRegion, subimageOffsets, shader.shader, uniforms, evenOdd) + i.img.DrawTriangles(imgs, vertices, indices, blend, dstRegion, srcRegion, subimageOffsets, shader.shader, uniforms, evenOdd) } type Shader struct { diff --git a/internal/graphicscommand/command.go b/internal/graphicscommand/command.go index beba5ed4c..d12fa362c 100644 --- a/internal/graphicscommand/command.go +++ b/internal/graphicscommand/command.go @@ -89,7 +89,7 @@ func mustUseDifferentVertexBuffer(nextNumVertexFloats, nextNumIndices int) bool } // EnqueueDrawTrianglesCommand enqueues a drawing-image command. -func (q *commandQueue) EnqueueDrawTrianglesCommand(dst *Image, srcs [graphics.ShaderImageCount]*Image, offsets [graphics.ShaderImageCount - 1][2]float32, vertices []float32, indices []uint16, mode graphicsdriver.CompositeMode, dstRegion, srcRegion graphicsdriver.Region, shader *Shader, uniforms [][]float32, evenOdd bool) { +func (q *commandQueue) EnqueueDrawTrianglesCommand(dst *Image, srcs [graphics.ShaderImageCount]*Image, offsets [graphics.ShaderImageCount - 1][2]float32, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion, srcRegion graphicsdriver.Region, shader *Shader, uniforms [][]float32, evenOdd bool) { if len(indices) > graphics.IndicesCount { panic(fmt.Sprintf("graphicscommand: len(indices) must be <= graphics.IndicesCount but not at EnqueueDrawTrianglesCommand: len(indices): %d, graphics.IndicesCount: %d", len(indices), graphics.IndicesCount)) } @@ -123,7 +123,7 @@ func (q *commandQueue) EnqueueDrawTrianglesCommand(dst *Image, srcs [graphics.Sh // TODO: If dst is the screen, reorder the command to be the last. if !split && 0 < len(q.commands) { if last, ok := q.commands[len(q.commands)-1].(*drawTrianglesCommand); ok { - if last.CanMergeWithDrawTrianglesCommand(dst, srcs, vertices, mode, dstRegion, srcRegion, shader, uniforms, evenOdd) { + if last.CanMergeWithDrawTrianglesCommand(dst, srcs, vertices, blend, dstRegion, srcRegion, shader, uniforms, evenOdd) { last.setVertices(q.lastVertices(len(vertices) + last.numVertices())) last.addNumIndices(len(indices)) return @@ -137,7 +137,7 @@ func (q *commandQueue) EnqueueDrawTrianglesCommand(dst *Image, srcs [graphics.Sh c.offsets = offsets c.vertices = q.lastVertices(len(vertices)) c.nindices = len(indices) - c.mode = mode + c.blend = blend c.dstRegion = dstRegion c.srcRegion = srcRegion c.shader = shader @@ -259,7 +259,7 @@ type drawTrianglesCommand struct { offsets [graphics.ShaderImageCount - 1][2]float32 vertices []float32 nindices int - mode graphicsdriver.CompositeMode + blend graphicsdriver.Blend dstRegion graphicsdriver.Region srcRegion graphicsdriver.Region shader *Shader @@ -268,39 +268,14 @@ type drawTrianglesCommand struct { } func (c *drawTrianglesCommand) String() string { - mode := "" - switch c.mode { - case graphicsdriver.CompositeModeSourceOver: - mode = "source-over" - case graphicsdriver.CompositeModeClear: - mode = "clear" - case graphicsdriver.CompositeModeCopy: - mode = "copy" - case graphicsdriver.CompositeModeDestination: - mode = "destination" - case graphicsdriver.CompositeModeDestinationOver: - mode = "destination-over" - case graphicsdriver.CompositeModeSourceIn: - mode = "source-in" - case graphicsdriver.CompositeModeDestinationIn: - mode = "destination-in" - case graphicsdriver.CompositeModeSourceOut: - mode = "source-out" - case graphicsdriver.CompositeModeDestinationOut: - mode = "destination-out" - case graphicsdriver.CompositeModeSourceAtop: - mode = "source-atop" - case graphicsdriver.CompositeModeDestinationAtop: - mode = "destination-atop" - case graphicsdriver.CompositeModeXor: - mode = "xor" - case graphicsdriver.CompositeModeLighter: - mode = "lighter" - case graphicsdriver.CompositeModeMultiply: - mode = "multiply" - default: - panic(fmt.Sprintf("graphicscommand: invalid composite mode: %d", c.mode)) - } + // TODO: Improve readability + blend := fmt.Sprintf("{src-color: %d, src-alpha: %d, dst-color: %d, dst-alpha: %d, op-color: %d, op-alpha: %d}", + c.blend.BlendFactorSourceColor, + c.blend.BlendFactorSourceAlpha, + c.blend.BlendFactorDestinationColor, + c.blend.BlendFactorDestinationAlpha, + c.blend.BlendOperationColor, + c.blend.BlendOperationAlpha) dst := fmt.Sprintf("%d", c.dst.id) if c.dst.screen { @@ -321,7 +296,7 @@ func (c *drawTrianglesCommand) String() string { r := fmt.Sprintf("(x:%d, y:%d, width:%d, height:%d)", int(c.dstRegion.X), int(c.dstRegion.Y), int(c.dstRegion.Width), int(c.dstRegion.Height)) - return fmt.Sprintf("draw-triangles: dst: %s <- src: [%s], dst region: %s, num of indices: %d, mode: %s, even-odd: %t", dst, strings.Join(srcstrs[:], ", "), r, c.nindices, mode, c.evenOdd) + return fmt.Sprintf("draw-triangles: dst: %s <- src: [%s], dst region: %s, num of indices: %d, blend: %s, even-odd: %t", dst, strings.Join(srcstrs[:], ", "), r, c.nindices, blend, c.evenOdd) } // Exec executes the drawTrianglesCommand. @@ -340,7 +315,7 @@ func (c *drawTrianglesCommand) Exec(graphicsDriver graphicsdriver.Graphics, inde imgs[i] = src.image.ID() } - return graphicsDriver.DrawTriangles(c.dst.image.ID(), imgs, c.offsets, c.shader.shader.ID(), c.nindices, indexOffset, c.mode, c.dstRegion, c.srcRegion, c.uniforms, c.evenOdd) + return graphicsDriver.DrawTriangles(c.dst.image.ID(), imgs, c.offsets, c.shader.shader.ID(), c.nindices, indexOffset, c.blend, c.dstRegion, c.srcRegion, c.uniforms, c.evenOdd) } func (c *drawTrianglesCommand) numVertices() int { @@ -361,7 +336,7 @@ func (c *drawTrianglesCommand) addNumIndices(n int) { // CanMergeWithDrawTrianglesCommand returns a boolean value indicating whether the other drawTrianglesCommand can be merged // with the drawTrianglesCommand c. -func (c *drawTrianglesCommand) CanMergeWithDrawTrianglesCommand(dst *Image, srcs [graphics.ShaderImageCount]*Image, vertices []float32, mode graphicsdriver.CompositeMode, dstRegion, srcRegion graphicsdriver.Region, shader *Shader, uniforms [][]float32, evenOdd bool) bool { +func (c *drawTrianglesCommand) CanMergeWithDrawTrianglesCommand(dst *Image, srcs [graphics.ShaderImageCount]*Image, vertices []float32, blend graphicsdriver.Blend, dstRegion, srcRegion graphicsdriver.Region, shader *Shader, uniforms [][]float32, evenOdd bool) bool { if c.shader != shader { return false } @@ -384,7 +359,7 @@ func (c *drawTrianglesCommand) CanMergeWithDrawTrianglesCommand(dst *Image, srcs if c.srcs != srcs { return false } - if c.mode != mode { + if c.blend != blend { return false } if c.dstRegion != dstRegion { diff --git a/internal/graphicscommand/image.go b/internal/graphicscommand/image.go index a900597b6..6eb761dd3 100644 --- a/internal/graphicscommand/image.go +++ b/internal/graphicscommand/image.go @@ -127,7 +127,7 @@ func (i *Image) InternalSize() (int, int) { // // If the source image is not specified, i.e., src is nil and there is no image in the uniform variables, the // elements for the source image are not used. -func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, offsets [graphics.ShaderImageCount - 1][2]float32, vertices []float32, indices []uint16, mode graphicsdriver.CompositeMode, dstRegion, srcRegion graphicsdriver.Region, shader *Shader, uniforms [][]float32, evenOdd bool) { +func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, offsets [graphics.ShaderImageCount - 1][2]float32, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion, srcRegion graphicsdriver.Region, shader *Shader, uniforms [][]float32, evenOdd bool) { for _, src := range srcs { if src == nil { continue @@ -139,7 +139,7 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, offsets [g } i.resolveBufferedWritePixels() - theCommandQueue.EnqueueDrawTrianglesCommand(i, srcs, offsets, vertices, indices, mode, dstRegion, srcRegion, shader, uniforms, evenOdd) + theCommandQueue.EnqueueDrawTrianglesCommand(i, srcs, offsets, vertices, indices, blend, dstRegion, srcRegion, shader, uniforms, evenOdd) } // ReadPixels reads the image's pixels. diff --git a/internal/graphicscommand/image_test.go b/internal/graphicscommand/image_test.go index 3fa3ab0b5..676033a91 100644 --- a/internal/graphicscommand/image_test.go +++ b/internal/graphicscommand/image_test.go @@ -65,7 +65,7 @@ func TestClear(t *testing.T) { Width: w, Height: h, } - dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.CompositeModeClear, dr, graphicsdriver.Region{}, nearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendClear, dr, graphicsdriver.Region{}, nearestFilterShader, nil, false) pix := make([]byte, 4*w*h) if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), pix, 0, 0, w, h); err != nil { @@ -96,8 +96,8 @@ func TestWritePixelsPartAfterDrawTriangles(t *testing.T) { Width: w, Height: h, } - dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{clr}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.CompositeModeClear, dr, graphicsdriver.Region{}, nearestFilterShader, nil, false) - dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.CompositeModeSourceOver, dr, graphicsdriver.Region{}, nearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{clr}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendClear, dr, graphicsdriver.Region{}, nearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, nearestFilterShader, nil, false) dst.WritePixels(make([]byte, 4), 0, 0, 1, 1) // TODO: Check the result. @@ -115,11 +115,11 @@ func TestShader(t *testing.T) { Width: w, Height: h, } - dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{clr}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.CompositeModeClear, dr, graphicsdriver.Region{}, nearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{clr}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendClear, dr, graphicsdriver.Region{}, nearestFilterShader, nil, false) g := ui.GraphicsDriverForTesting() s := graphicscommand.NewShader(etesting.ShaderProgramFill(0xff, 0, 0, 0xff)) - dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.CompositeModeSourceOver, dr, graphicsdriver.Region{}, s, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, s, nil, false) pix := make([]byte, 4*w*h) if err := dst.ReadPixels(g, pix, 0, 0, w, h); err != nil { diff --git a/internal/graphicsdriver/blend.go b/internal/graphicsdriver/blend.go new file mode 100644 index 000000000..e0f337935 --- /dev/null +++ b/internal/graphicsdriver/blend.go @@ -0,0 +1,71 @@ +// 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. + +package graphicsdriver + +type Blend struct { + BlendFactorSourceColor BlendFactor + BlendFactorSourceAlpha BlendFactor + BlendFactorDestinationColor BlendFactor + BlendFactorDestinationAlpha BlendFactor + BlendOperationColor BlendOperation + BlendOperationAlpha BlendOperation +} + +type BlendFactor int + +const ( + BlendFactorZero BlendFactor = iota + BlendFactorOne + BlendFactorSourceAlpha + BlendFactorDestinationAlpha + BlendFactorOneMinusSourceAlpha + BlendFactorOneMinusDestinationAlpha + BlendFactorDestinationColor +) + +type BlendOperation int + +const ( + BlendOperationAdd BlendOperation = iota + + // TODO: Add more operators +) + +var BlendSourceOver = Blend{ + BlendFactorSourceColor: BlendFactorOne, + BlendFactorSourceAlpha: BlendFactorOne, + BlendFactorDestinationColor: BlendFactorOneMinusSourceAlpha, + BlendFactorDestinationAlpha: BlendFactorOneMinusSourceAlpha, + BlendOperationColor: BlendOperationAdd, + BlendOperationAlpha: BlendOperationAdd, +} + +var BlendClear = Blend{ + BlendFactorSourceColor: BlendFactorZero, + BlendFactorSourceAlpha: BlendFactorZero, + BlendFactorDestinationColor: BlendFactorZero, + BlendFactorDestinationAlpha: BlendFactorZero, + BlendOperationColor: BlendOperationAdd, + BlendOperationAlpha: BlendOperationAdd, +} + +var BlendCopy = Blend{ + BlendFactorSourceColor: BlendFactorOne, + BlendFactorSourceAlpha: BlendFactorOne, + BlendFactorDestinationColor: BlendFactorZero, + BlendFactorDestinationAlpha: BlendFactorZero, + BlendOperationColor: BlendOperationAdd, + BlendOperationAlpha: BlendOperationAdd, +} diff --git a/internal/graphicsdriver/compositemode.go b/internal/graphicsdriver/compositemode.go deleted file mode 100644 index c45fccedd..000000000 --- a/internal/graphicsdriver/compositemode.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2018 The Ebiten 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. - -package graphicsdriver - -import ( - "fmt" -) - -type CompositeMode int - -const ( - CompositeModeUnknown CompositeMode = iota - 1 - CompositeModeSourceOver // This value must be 0 (= initial value) - CompositeModeClear - CompositeModeCopy - CompositeModeDestination - CompositeModeDestinationOver - CompositeModeSourceIn - CompositeModeDestinationIn - CompositeModeSourceOut - CompositeModeDestinationOut - CompositeModeSourceAtop - CompositeModeDestinationAtop - CompositeModeXor - CompositeModeLighter - CompositeModeMultiply - - CompositeModeMax = CompositeModeMultiply -) - -type BlendFactor int - -const ( - BlendFactorZero BlendFactor = iota - BlendFactorOne - BlendFactorSourceAlpha - BlendFactorDestinationAlpha - BlendFactorOneMinusSourceAlpha - BlendFactorOneMinusDestinationAlpha - BlendFactorDestinationColor -) - -func (c CompositeMode) BlendFactors() (src BlendFactor, dst BlendFactor) { - switch c { - case CompositeModeSourceOver: - return BlendFactorOne, BlendFactorOneMinusSourceAlpha - case CompositeModeClear: - return BlendFactorZero, BlendFactorZero - case CompositeModeCopy: - return BlendFactorOne, BlendFactorZero - case CompositeModeDestination: - return BlendFactorZero, BlendFactorOne - case CompositeModeDestinationOver: - return BlendFactorOneMinusDestinationAlpha, BlendFactorOne - case CompositeModeSourceIn: - return BlendFactorDestinationAlpha, BlendFactorZero - case CompositeModeDestinationIn: - return BlendFactorZero, BlendFactorSourceAlpha - case CompositeModeSourceOut: - return BlendFactorOneMinusDestinationAlpha, BlendFactorZero - case CompositeModeDestinationOut: - return BlendFactorZero, BlendFactorOneMinusSourceAlpha - case CompositeModeSourceAtop: - return BlendFactorDestinationAlpha, BlendFactorOneMinusSourceAlpha - case CompositeModeDestinationAtop: - return BlendFactorOneMinusDestinationAlpha, BlendFactorSourceAlpha - case CompositeModeXor: - return BlendFactorOneMinusDestinationAlpha, BlendFactorOneMinusSourceAlpha - case CompositeModeLighter: - return BlendFactorOne, BlendFactorOne - case CompositeModeMultiply: - return BlendFactorDestinationColor, BlendFactorZero - default: - panic(fmt.Sprintf("graphicsdriver: invalid composite mode: %d", c)) - } -} diff --git a/internal/graphicsdriver/directx/graphics_windows.go b/internal/graphicsdriver/directx/graphics_windows.go index efab4c390..ac7bfb0a8 100644 --- a/internal/graphicsdriver/directx/graphics_windows.go +++ b/internal/graphicsdriver/directx/graphics_windows.go @@ -1190,7 +1190,7 @@ func (g *Graphics) NewShader(program *shaderir.Program) (graphicsdriver.Shader, return s, nil } -func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcs [graphics.ShaderImageCount]graphicsdriver.ImageID, offsets [graphics.ShaderImageCount - 1][2]float32, shaderID graphicsdriver.ShaderID, indexLen int, indexOffset int, mode graphicsdriver.CompositeMode, dstRegion, srcRegion graphicsdriver.Region, uniforms [][]float32, evenOdd bool) error { +func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcs [graphics.ShaderImageCount]graphicsdriver.ImageID, offsets [graphics.ShaderImageCount - 1][2]float32, shaderID graphicsdriver.ShaderID, indexLen int, indexOffset int, blend graphicsdriver.Blend, dstRegion, srcRegion graphicsdriver.Region, uniforms [][]float32, evenOdd bool) error { if shaderID == graphicsdriver.InvalidShaderID { return fmt.Errorf("directx: shader ID is invalid") } @@ -1315,7 +1315,7 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcs [graphics.Sh }) if evenOdd { - s, err := shader.pipelineState(mode, prepareStencil, dst.screen) + s, err := shader.pipelineState(blend, prepareStencil, dst.screen) if err != nil { return err } @@ -1323,7 +1323,7 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcs [graphics.Sh return err } - s, err = shader.pipelineState(mode, drawWithStencil, dst.screen) + s, err = shader.pipelineState(blend, drawWithStencil, dst.screen) if err != nil { return err } @@ -1331,7 +1331,7 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcs [graphics.Sh return err } } else { - s, err := shader.pipelineState(mode, noStencil, dst.screen) + s, err := shader.pipelineState(blend, noStencil, dst.screen) if err != nil { return err } @@ -1773,9 +1773,9 @@ const ( ) type pipelineStateKey struct { - compositeMode graphicsdriver.CompositeMode - stencilMode stencilMode - screen bool + blend graphicsdriver.Blend + stencilMode stencilMode + screen bool } type Shader struct { @@ -1812,17 +1812,17 @@ func (s *Shader) disposeImpl() { } } -func (s *Shader) pipelineState(compositeMode graphicsdriver.CompositeMode, stencilMode stencilMode, screen bool) (*_ID3D12PipelineState, error) { +func (s *Shader) pipelineState(blend graphicsdriver.Blend, stencilMode stencilMode, screen bool) (*_ID3D12PipelineState, error) { key := pipelineStateKey{ - compositeMode: compositeMode, - stencilMode: stencilMode, - screen: screen, + blend: blend, + stencilMode: stencilMode, + screen: screen, } if state, ok := s.pipelineStates[key]; ok { return state, nil } - state, err := s.graphics.pipelineStates.newPipelineState(s.graphics.device, s.vertexShader, s.pixelShader, compositeMode, stencilMode, screen) + state, err := s.graphics.pipelineStates.newPipelineState(s.graphics.device, s.vertexShader, s.pixelShader, blend, stencilMode, screen) if err != nil { return nil, err } diff --git a/internal/graphicsdriver/directx/pipeline_windows.go b/internal/graphicsdriver/directx/pipeline_windows.go index 15e7a6a8e..d75927363 100644 --- a/internal/graphicsdriver/directx/pipeline_windows.go +++ b/internal/graphicsdriver/directx/pipeline_windows.go @@ -25,8 +25,8 @@ import ( const numDescriptorsPerFrame = 32 -func blendFactorToBlend(c graphicsdriver.BlendFactor, alpha bool) _D3D12_BLEND { - switch c { +func blendFactorToBlend(f graphicsdriver.BlendFactor, alpha bool) _D3D12_BLEND { + switch f { case graphicsdriver.BlendFactorZero: return _D3D12_BLEND_ZERO case graphicsdriver.BlendFactorOne: @@ -40,12 +40,23 @@ func blendFactorToBlend(c graphicsdriver.BlendFactor, alpha bool) _D3D12_BLEND { case graphicsdriver.BlendFactorOneMinusDestinationAlpha: return _D3D12_BLEND_INV_DEST_ALPHA case graphicsdriver.BlendFactorDestinationColor: + // D3D12_RENDER_TARGET_BLEND_DESC's *BlendAlpha members don't allow *_COLOR values. + // See https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ns-d3d12-d3d12_render_target_blend_desc. if alpha { return _D3D12_BLEND_DEST_ALPHA } return _D3D12_BLEND_DEST_COLOR default: - panic(fmt.Sprintf("directx: invalid blend factor: %d", c)) + panic(fmt.Sprintf("directx: invalid blend factor: %d", f)) + } +} + +func blendOperationToBlendOp(o graphicsdriver.BlendOperation) _D3D12_BLEND_OP { + switch o { + case graphicsdriver.BlendOperationAdd: + return _D3D12_BLEND_OP_ADD + default: + panic(fmt.Sprintf("directx: invalid blend operation: %d", o)) } } @@ -336,7 +347,7 @@ func newShader(source []byte, defs []_D3D_SHADER_MACRO) (vsh, psh *_ID3DBlob, fe return v, p, nil } -func (p *pipelineStates) newPipelineState(device *_ID3D12Device, vsh, psh *_ID3DBlob, compositeMode graphicsdriver.CompositeMode, stencilMode stencilMode, screen bool) (state *_ID3D12PipelineState, ferr error) { +func (p *pipelineStates) newPipelineState(device *_ID3D12Device, vsh, psh *_ID3DBlob, blend graphicsdriver.Blend, stencilMode stencilMode, screen bool) (state *_ID3D12PipelineState, ferr error) { rootSignature, err := p.ensureRootSignature(device) if err != nil { return nil, err @@ -391,7 +402,6 @@ func (p *pipelineStates) newPipelineState(device *_ID3D12Device, vsh, psh *_ID3D } // Create a pipeline state. - srcOp, dstOp := compositeMode.BlendFactors() psoDesc := _D3D12_GRAPHICS_PIPELINE_STATE_DESC{ pRootSignature: rootSignature, VS: _D3D12_SHADER_BYTECODE{ @@ -409,12 +419,12 @@ func (p *pipelineStates) newPipelineState(device *_ID3D12Device, vsh, psh *_ID3D { BlendEnable: 1, LogicOpEnable: 0, - SrcBlend: blendFactorToBlend(srcOp, false), - DestBlend: blendFactorToBlend(dstOp, false), - BlendOp: _D3D12_BLEND_OP_ADD, - SrcBlendAlpha: blendFactorToBlend(srcOp, true), - DestBlendAlpha: blendFactorToBlend(dstOp, true), - BlendOpAlpha: _D3D12_BLEND_OP_ADD, + SrcBlend: blendFactorToBlend(blend.BlendFactorSourceColor, false), + DestBlend: blendFactorToBlend(blend.BlendFactorDestinationColor, false), + BlendOp: blendOperationToBlendOp(blend.BlendOperationColor), + SrcBlendAlpha: blendFactorToBlend(blend.BlendFactorSourceAlpha, true), + DestBlendAlpha: blendFactorToBlend(blend.BlendFactorDestinationAlpha, true), + BlendOpAlpha: blendOperationToBlendOp(blend.BlendOperationAlpha), LogicOp: _D3D12_LOGIC_OP_NOOP, RenderTargetWriteMask: writeMask, }, diff --git a/internal/graphicsdriver/graphics.go b/internal/graphicsdriver/graphics.go index 7830abe5f..f30613ec0 100644 --- a/internal/graphicsdriver/graphics.go +++ b/internal/graphicsdriver/graphics.go @@ -52,7 +52,7 @@ type Graphics interface { NewShader(program *shaderir.Program) (Shader, error) // DrawTriangles draws an image onto another image with the given parameters. - DrawTriangles(dst ImageID, srcs [graphics.ShaderImageCount]ImageID, offsets [graphics.ShaderImageCount - 1][2]float32, shader ShaderID, indexLen int, indexOffset int, mode CompositeMode, dstRegion, srcRegion Region, uniforms [][]float32, evenOdd bool) error + DrawTriangles(dst ImageID, srcs [graphics.ShaderImageCount]ImageID, offsets [graphics.ShaderImageCount - 1][2]float32, shader ShaderID, indexLen int, indexOffset int, blend Blend, dstRegion, srcRegion Region, uniforms [][]float32, evenOdd bool) error } // GraphicsNotReady represents that the graphics driver is not ready for recovering from the context lost. diff --git a/internal/graphicsdriver/metal/graphics_darwin.go b/internal/graphicsdriver/metal/graphics_darwin.go index 44db1b693..7ea1ded59 100644 --- a/internal/graphicsdriver/metal/graphics_darwin.go +++ b/internal/graphicsdriver/metal/graphics_darwin.go @@ -317,7 +317,16 @@ func blendFactorToMetalBlendFactor(c graphicsdriver.BlendFactor) mtl.BlendFactor case graphicsdriver.BlendFactorDestinationColor: return mtl.BlendFactorDestinationColor default: - panic(fmt.Sprintf("metal: invalid operation: %d", c)) + panic(fmt.Sprintf("metal: invalid blend factor: %d", c)) + } +} + +func blendOperationToMetalBlendOperation(o graphicsdriver.BlendOperation) mtl.BlendOperation { + switch o { + case graphicsdriver.BlendOperationAdd: + return mtl.BlendOperationAdd + default: + panic(fmt.Sprintf("metal: invalid blend operation: %d", o)) } } @@ -478,7 +487,7 @@ func (g *Graphics) draw(rps mtl.RenderPipelineState, dst *Image, dstRegion graph return nil } -func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.ShaderImageCount]graphicsdriver.ImageID, offsets [graphics.ShaderImageCount - 1][2]float32, shaderID graphicsdriver.ShaderID, indexLen int, indexOffset int, mode graphicsdriver.CompositeMode, dstRegion, srcRegion graphicsdriver.Region, uniforms [][]float32, evenOdd bool) error { +func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.ShaderImageCount]graphicsdriver.ImageID, offsets [graphics.ShaderImageCount - 1][2]float32, shaderID graphicsdriver.ShaderID, indexLen int, indexOffset int, blend graphicsdriver.Blend, dstRegion, srcRegion graphicsdriver.Region, uniforms [][]float32, evenOdd bool) error { if shaderID == graphicsdriver.InvalidShaderID { return fmt.Errorf("metal: shader ID is invalid") } @@ -575,14 +584,14 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics. } if evenOdd { - prepareStencilRpss, err := g.shaders[shaderID].RenderPipelineState(&g.view, mode, prepareStencil, dst.screen) + prepareStencilRpss, err := g.shaders[shaderID].RenderPipelineState(&g.view, blend, prepareStencil, dst.screen) if err != nil { return err } if err := g.draw(prepareStencilRpss, dst, dstRegion, srcs, indexLen, indexOffset, uniformVars, prepareStencil); err != nil { return err } - drawWithStencilRpss, err := g.shaders[shaderID].RenderPipelineState(&g.view, mode, drawWithStencil, dst.screen) + drawWithStencilRpss, err := g.shaders[shaderID].RenderPipelineState(&g.view, blend, drawWithStencil, dst.screen) if err != nil { return err } @@ -590,7 +599,7 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics. return err } } else { - rpss, err := g.shaders[shaderID].RenderPipelineState(&g.view, mode, noStencil, dst.screen) + rpss, err := g.shaders[shaderID].RenderPipelineState(&g.view, blend, noStencil, dst.screen) if err != nil { return err } diff --git a/internal/graphicsdriver/metal/mtl/mtl_darwin.go b/internal/graphicsdriver/metal/mtl/mtl_darwin.go index 49ecf9aa5..99bddbd0b 100644 --- a/internal/graphicsdriver/metal/mtl/mtl_darwin.go +++ b/internal/graphicsdriver/metal/mtl/mtl_darwin.go @@ -290,6 +290,16 @@ const ( BlendFactorOneMinusSource1Alpha BlendFactor = 18 ) +type BlendOperation uint8 + +const ( + BlendOperationAdd BlendOperation = 0 + BlendOperationSubtract BlendOperation = 1 + BlendOperationReverseSubtract BlendOperation = 2 + BlendOperationMin BlendOperation = 3 + BlendOperationMax BlendOperation = 4 +) + type ColorWriteMask uint8 const ( @@ -383,6 +393,8 @@ type RenderPipelineColorAttachmentDescriptor struct { DestinationRGBBlendFactor BlendFactor SourceAlphaBlendFactor BlendFactor SourceRGBBlendFactor BlendFactor + AlphaBlendOperation BlendOperation + RGBBlendOperation BlendOperation WriteMask ColorWriteMask } @@ -492,6 +504,8 @@ var ( sel_setDestinationRGBBlendFactor = objc.RegisterName("setDestinationRGBBlendFactor:") sel_setSourceAlphaBlendFactor = objc.RegisterName("setSourceAlphaBlendFactor:") sel_setSourceRGBBlendFactor = objc.RegisterName("setSourceRGBBlendFactor:") + sel_setAlphaBlendOperation = objc.RegisterName("setAlphaBlendOperation:") + sel_setRgbBlendOperation = objc.RegisterName("setRgbBlendOperation:") sel_setWriteMask = objc.RegisterName("setWriteMask:") sel_setStencilAttachmentPixelFormat = objc.RegisterName("setStencilAttachmentPixelFormat:") sel_newRenderPipelineStateWithDescriptor_error = objc.RegisterName("newRenderPipelineStateWithDescriptor:error:") @@ -624,6 +638,8 @@ func (d Device) MakeRenderPipelineState(rpd RenderPipelineDescriptor) (RenderPip colorAttachments0.Send(sel_setDestinationRGBBlendFactor, uintptr(rpd.ColorAttachments[0].DestinationRGBBlendFactor)) colorAttachments0.Send(sel_setSourceAlphaBlendFactor, uintptr(rpd.ColorAttachments[0].SourceAlphaBlendFactor)) colorAttachments0.Send(sel_setSourceRGBBlendFactor, uintptr(rpd.ColorAttachments[0].SourceRGBBlendFactor)) + colorAttachments0.Send(sel_setAlphaBlendOperation, uintptr(rpd.ColorAttachments[0].AlphaBlendOperation)) + colorAttachments0.Send(sel_setRgbBlendOperation, uintptr(rpd.ColorAttachments[0].RGBBlendOperation)) colorAttachments0.Send(sel_setWriteMask, uintptr(rpd.ColorAttachments[0].WriteMask)) renderPipelineDescriptor.Send(sel_setStencilAttachmentPixelFormat, uintptr(rpd.StencilAttachmentPixelFormat)) var err cocoa.NSError diff --git a/internal/graphicsdriver/metal/shader_darwin.go b/internal/graphicsdriver/metal/shader_darwin.go index 65e4ac0a6..ca5113603 100644 --- a/internal/graphicsdriver/metal/shader_darwin.go +++ b/internal/graphicsdriver/metal/shader_darwin.go @@ -24,9 +24,9 @@ import ( ) type shaderRpsKey struct { - compositeMode graphicsdriver.CompositeMode - stencilMode stencilMode - screen bool + blend graphicsdriver.Blend + stencilMode stencilMode + screen bool } type Shader struct { @@ -86,11 +86,11 @@ func (s *Shader) init(device mtl.Device) error { return nil } -func (s *Shader) RenderPipelineState(view *view, compositeMode graphicsdriver.CompositeMode, stencilMode stencilMode, screen bool) (mtl.RenderPipelineState, error) { +func (s *Shader) RenderPipelineState(view *view, blend graphicsdriver.Blend, stencilMode stencilMode, screen bool) (mtl.RenderPipelineState, error) { key := shaderRpsKey{ - compositeMode: compositeMode, - stencilMode: stencilMode, - screen: screen, + blend: blend, + stencilMode: stencilMode, + screen: screen, } if rps, ok := s.rpss[key]; ok { return rps, nil @@ -112,11 +112,13 @@ func (s *Shader) RenderPipelineState(view *view, compositeMode graphicsdriver.Co rpld.ColorAttachments[0].PixelFormat = pix rpld.ColorAttachments[0].BlendingEnabled = true - src, dst := compositeMode.BlendFactors() - rpld.ColorAttachments[0].DestinationAlphaBlendFactor = blendFactorToMetalBlendFactor(dst) - rpld.ColorAttachments[0].DestinationRGBBlendFactor = blendFactorToMetalBlendFactor(dst) - rpld.ColorAttachments[0].SourceAlphaBlendFactor = blendFactorToMetalBlendFactor(src) - rpld.ColorAttachments[0].SourceRGBBlendFactor = blendFactorToMetalBlendFactor(src) + rpld.ColorAttachments[0].DestinationAlphaBlendFactor = blendFactorToMetalBlendFactor(blend.BlendFactorDestinationAlpha) + rpld.ColorAttachments[0].DestinationRGBBlendFactor = blendFactorToMetalBlendFactor(blend.BlendFactorDestinationColor) + rpld.ColorAttachments[0].SourceAlphaBlendFactor = blendFactorToMetalBlendFactor(blend.BlendFactorSourceAlpha) + rpld.ColorAttachments[0].SourceRGBBlendFactor = blendFactorToMetalBlendFactor(blend.BlendFactorSourceColor) + rpld.ColorAttachments[0].AlphaBlendOperation = blendOperationToMetalBlendOperation(blend.BlendOperationAlpha) + rpld.ColorAttachments[0].RGBBlendOperation = blendOperationToMetalBlendOperation(blend.BlendOperationColor) + if stencilMode == prepareStencil { rpld.ColorAttachments[0].WriteMask = mtl.ColorWriteMaskNone } else { diff --git a/internal/graphicsdriver/opengl/context.go b/internal/graphicsdriver/opengl/context.go index 3cdbc6c58..549be01fa 100644 --- a/internal/graphicsdriver/opengl/context.go +++ b/internal/graphicsdriver/opengl/context.go @@ -33,8 +33,14 @@ const ( glZero blendFactor = 0 ) -func convertBlendFactor(op graphicsdriver.BlendFactor) blendFactor { - switch op { +type blendOperation int + +const ( + glAdd blendOperation = 0x104 +) + +func convertBlendFactor(f graphicsdriver.BlendFactor) blendFactor { + switch f { case graphicsdriver.BlendFactorZero: return glZero case graphicsdriver.BlendFactorOne: @@ -50,7 +56,16 @@ func convertBlendFactor(op graphicsdriver.BlendFactor) blendFactor { case graphicsdriver.BlendFactorDestinationColor: return glDstColor default: - panic(fmt.Sprintf("opengl: invalid blend factor %d at convertBlendFactor", op)) + panic(fmt.Sprintf("opengl: invalid blend factor %d", f)) + } +} + +func convertBlendOperation(o graphicsdriver.BlendOperation) blendOperation { + switch o { + case graphicsdriver.BlendOperationAdd: + return glAdd + default: + panic(fmt.Sprintf("opengl: invalid blend operation %d", o)) } } @@ -62,7 +77,7 @@ type context struct { lastRenderbuffer renderbufferNative lastViewportWidth int lastViewportHeight int - lastCompositeMode graphicsdriver.CompositeMode + lastBlend graphicsdriver.Blend maxTextureSize int maxTextureSizeOnce sync.Once highp bool diff --git a/internal/graphicsdriver/opengl/context_gl.go b/internal/graphicsdriver/opengl/context_gl.go index 347362595..48c883040 100644 --- a/internal/graphicsdriver/opengl/context_gl.go +++ b/internal/graphicsdriver/opengl/context_gl.go @@ -100,11 +100,11 @@ func (c *context) reset() error { c.lastFramebuffer = invalidFramebuffer c.lastViewportWidth = 0 c.lastViewportHeight = 0 - c.lastCompositeMode = graphicsdriver.CompositeModeUnknown gl.Enable(gl.BLEND) gl.Enable(gl.SCISSOR_TEST) - c.blendFunc(graphicsdriver.CompositeModeSourceOver) + // Set the source over blending. + c.blend(graphicsdriver.BlendSourceOver) f := int32(0) gl.GetIntegerv(gl.FRAMEBUFFER_BINDING, &f) @@ -112,14 +112,21 @@ func (c *context) reset() error { return nil } -func (c *context) blendFunc(mode graphicsdriver.CompositeMode) { - if c.lastCompositeMode == mode { +func (c *context) blend(blend graphicsdriver.Blend) { + if c.lastBlend == blend { return } - c.lastCompositeMode = mode - s, d := mode.BlendFactors() - s2, d2 := convertBlendFactor(s), convertBlendFactor(d) - gl.BlendFunc(uint32(s2), uint32(d2)) + c.lastBlend = blend + gl.BlendFuncSeparate( + uint32(convertBlendFactor(blend.BlendFactorSourceColor)), + uint32(convertBlendFactor(blend.BlendFactorDestinationColor)), + uint32(convertBlendFactor(blend.BlendFactorSourceAlpha)), + uint32(convertBlendFactor(blend.BlendFactorDestinationAlpha)), + ) + gl.BlendEquationSeparate( + uint32(convertBlendOperation(blend.BlendOperationColor)), + uint32(convertBlendOperation(blend.BlendOperationAlpha)), + ) } func (c *context) scissor(x, y, width, height int) { diff --git a/internal/graphicsdriver/opengl/context_gles.go b/internal/graphicsdriver/opengl/context_gles.go index 123f75501..57d0f135f 100644 --- a/internal/graphicsdriver/opengl/context_gles.go +++ b/internal/graphicsdriver/opengl/context_gles.go @@ -93,10 +93,9 @@ func (c *context) reset() error { c.lastFramebuffer = invalidFramebuffer c.lastViewportWidth = 0 c.lastViewportHeight = 0 - c.lastCompositeMode = graphicsdriver.CompositeModeUnknown c.ctx.Enable(gles.BLEND) c.ctx.Enable(gles.SCISSOR_TEST) - c.blendFunc(graphicsdriver.CompositeModeSourceOver) + c.blend(graphicsdriver.BlendSourceOver) f := make([]int32, 1) c.ctx.GetIntegerv(f, gles.FRAMEBUFFER_BINDING) c.screenFramebuffer = framebufferNative(f[0]) @@ -104,14 +103,20 @@ func (c *context) reset() error { return nil } -func (c *context) blendFunc(mode graphicsdriver.CompositeMode) { - if c.lastCompositeMode == mode { +func (c *context) blend(blend graphicsdriver.Blend) { + if c.lastBlend == blend { return } - c.lastCompositeMode = mode - s, d := mode.BlendFactors() - s2, d2 := convertBlendFactor(s), convertBlendFactor(d) - c.ctx.BlendFunc(uint32(s2), uint32(d2)) + c.ctx.BlendFuncSeparate( + uint32(convertBlendFactor(blend.BlendFactorSourceColor)), + uint32(convertBlendFactor(blend.BlendFactorDestinationColor)), + uint32(convertBlendFactor(blend.BlendFactorSourceAlpha)), + uint32(convertBlendFactor(blend.BlendFactorDestinationAlpha)), + ) + c.ctx.BlendEquationSeparate( + uint32(convertBlendOperation(blend.BlendOperationColor)), + uint32(convertBlendOperation(blend.BlendOperationAlpha)), + ) } func (c *context) scissor(x, y, width, height int) { diff --git a/internal/graphicsdriver/opengl/context_js.go b/internal/graphicsdriver/opengl/context_js.go index 30a2d754c..359598233 100644 --- a/internal/graphicsdriver/opengl/context_js.go +++ b/internal/graphicsdriver/opengl/context_js.go @@ -163,7 +163,6 @@ func (c *context) reset() error { c.lastFramebuffer = framebufferNative(js.Null()) c.lastViewportWidth = 0 c.lastViewportHeight = 0 - c.lastCompositeMode = graphicsdriver.CompositeModeUnknown if err := c.initGL(); err != nil { return err @@ -175,7 +174,7 @@ func (c *context) reset() error { gl := c.gl gl.enable.Invoke(gles.BLEND) gl.enable.Invoke(gles.SCISSOR_TEST) - c.blendFunc(graphicsdriver.CompositeModeSourceOver) + c.blend(graphicsdriver.BlendSourceOver) f := gl.getParameter.Invoke(gles.FRAMEBUFFER_BINDING) c.screenFramebuffer = framebufferNative(f) @@ -185,15 +184,22 @@ func (c *context) reset() error { return nil } -func (c *context) blendFunc(mode graphicsdriver.CompositeMode) { - if c.lastCompositeMode == mode { +func (c *context) blend(blend graphicsdriver.Blend) { + if c.lastBlend == blend { return } - c.lastCompositeMode = mode - s, d := mode.BlendFactors() - s2, d2 := convertBlendFactor(s), convertBlendFactor(d) + c.lastBlend = blend gl := c.gl - gl.blendFunc.Invoke(int(s2), int(d2)) + gl.blendFuncSeparate.Invoke( + int(convertBlendFactor(blend.BlendFactorSourceColor)), + int(convertBlendFactor(blend.BlendFactorDestinationColor)), + int(convertBlendFactor(blend.BlendFactorSourceAlpha)), + int(convertBlendFactor(blend.BlendFactorDestinationAlpha)), + ) + gl.blendEquationSeparate.Invoke( + int(convertBlendOperation(blend.BlendOperationColor)), + int(convertBlendOperation(blend.BlendOperationAlpha)), + ) } func (c *context) scissor(x, y, width, height int) { diff --git a/internal/graphicsdriver/opengl/gl/package_notpurego.go b/internal/graphicsdriver/opengl/gl/package_notpurego.go index 0615b96d3..f77fe6e24 100644 --- a/internal/graphicsdriver/opengl/gl/package_notpurego.go +++ b/internal/graphicsdriver/opengl/gl/package_notpurego.go @@ -102,7 +102,8 @@ package gl // typedef void (APIENTRYP GPBINDFRAMEBUFFEREXT)(GLenum target, GLuint framebuffer); // typedef void (APIENTRYP GPBINDRENDERBUFFEREXT)(GLenum target, GLuint renderbuffer); // typedef void (APIENTRYP GPBINDTEXTURE)(GLenum target, GLuint texture); -// typedef void (APIENTRYP GPBLENDFUNC)(GLenum sfactor, GLenum dfactor); +// typedef void (APIENTRYP GPBLENDEQUATIONSEPARATE)(GLenum modeRGB, GLenum modeAlpha); +// typedef void (APIENTRYP GPBLENDFUNCSEPARATE)(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); // typedef void (APIENTRYP GPBUFFERDATA)(GLenum target, GLsizeiptr size, const void * data, GLenum usage); // typedef void (APIENTRYP GPBUFFERSUBDATA)(GLenum target, GLintptr offset, GLsizeiptr size, const void * data); // typedef GLenum (APIENTRYP GPCHECKFRAMEBUFFERSTATUSEXT)(GLenum target); @@ -197,8 +198,11 @@ package gl // static void glowBindTexture(GPBINDTEXTURE fnptr, GLenum target, GLuint texture) { // (*fnptr)(target, texture); // } -// static void glowBlendFunc(GPBLENDFUNC fnptr, GLenum sfactor, GLenum dfactor) { -// (*fnptr)(sfactor, dfactor); +// static void glowBlendEquationSeparate(GPBLENDEQUATIONSEPARATE fnptr, GLenum modeRGB, GLenum modeAlpha) { +// (*fnptr)(modeRGB, modeAlpha); +// } +// static void glowBlendFuncSeparate(GPBLENDFUNCSEPARATE fnptr, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) { +// (*fnptr)(srcRGB, dstRGB, srcAlpha, dstAlpha); // } // static void glowBufferData(GPBUFFERDATA fnptr, GLenum target, GLsizeiptr size, const void * data, GLenum usage) { // (*fnptr)(target, size, data, usage); @@ -431,7 +435,8 @@ var ( gpBindFramebufferEXT C.GPBINDFRAMEBUFFEREXT gpBindRenderbufferEXT C.GPBINDRENDERBUFFEREXT gpBindTexture C.GPBINDTEXTURE - gpBlendFunc C.GPBLENDFUNC + gpBlendEquationSeparate C.GPBLENDEQUATIONSEPARATE + gpBlendFuncSeparate C.GPBLENDFUNCSEPARATE gpBufferData C.GPBUFFERDATA gpBufferSubData C.GPBUFFERSUBDATA gpCheckFramebufferStatusEXT C.GPCHECKFRAMEBUFFERSTATUSEXT @@ -541,8 +546,12 @@ func BindTexture(target uint32, texture uint32) { C.glowBindTexture(gpBindTexture, (C.GLenum)(target), (C.GLuint)(texture)) } -func BlendFunc(sfactor uint32, dfactor uint32) { - C.glowBlendFunc(gpBlendFunc, (C.GLenum)(sfactor), (C.GLenum)(dfactor)) +func BlendEquationSeparate(modeRGB uint32, modeAlpha uint32) { + C.glowBlendEquationSeparate(gpBlendEquationSeparate, (C.GLenum)(modeRGB), (C.GLenum)(modeAlpha)) +} + +func BlendFuncSeparate(srcRGB uint32, dstRGB uint32, srcAlpha uint32, dstAlpha uint32) { + C.glowBlendFuncSeparate(gpBlendFuncSeparate, (C.GLenum)(srcRGB), (C.GLenum)(dstRGB), (C.GLenum)(srcAlpha), (C.GLenum)(dstAlpha)) } func BufferData(target uint32, size int, data unsafe.Pointer, usage uint32) { @@ -861,9 +870,13 @@ func InitWithProcAddrFunc(getProcAddr func(name string) unsafe.Pointer) error { if gpBindTexture == nil { return errors.New("gl: glBindTexture is missing") } - gpBlendFunc = (C.GPBLENDFUNC)(getProcAddr("glBlendFunc")) - if gpBlendFunc == nil { - return errors.New("gl: glBlendFunc is missing") + gpBlendEquationSeparate = (C.GPBLENDEQUATIONSEPARATE)(getProcAddr("glBlendEquationSeparate")) + if gpBlendEquationSeparate == nil { + return errors.New("gl: glBlendEquationSeparate is missing") + } + gpBlendFuncSeparate = (C.GPBLENDFUNCSEPARATE)(getProcAddr("glBlendFuncSeparate")) + if gpBlendFuncSeparate == nil { + return errors.New("gl: glBlendFuncSeparate is missing") } gpBufferData = (C.GPBUFFERDATA)(getProcAddr("glBufferData")) if gpBufferData == nil { diff --git a/internal/graphicsdriver/opengl/gl/package_purego.go b/internal/graphicsdriver/opengl/gl/package_purego.go index 0f6c75956..da37a3efc 100644 --- a/internal/graphicsdriver/opengl/gl/package_purego.go +++ b/internal/graphicsdriver/opengl/gl/package_purego.go @@ -20,7 +20,8 @@ var ( gpBindFramebufferEXT uintptr gpBindRenderbufferEXT uintptr gpBindTexture uintptr - gpBlendFunc uintptr + gpBlendEquationSeparate uintptr + gpBlendFuncSeparate uintptr gpBufferData uintptr gpBufferSubData uintptr gpCheckFramebufferStatusEXT uintptr @@ -130,8 +131,12 @@ func BindTexture(target uint32, texture uint32) { purego.SyscallN(gpBindTexture, uintptr(target), uintptr(texture)) } -func BlendFunc(sfactor uint32, dfactor uint32) { - purego.SyscallN(gpBlendFunc, uintptr(sfactor), uintptr(dfactor)) +func BlendEquationSeparate(modeRGB uint32, modeAlpha uint32) { + purego.SyscallN(gpBlendEquationSeparate, uintptr(modeRGB), uintptr(modeAlpha)) +} + +func BlendFuncSeparate(srcRGB uint32, dstRGB uint32, srcAlpha uint32, dstAlpha uint32) { + purego.SyscallN(gpBlendFuncSeparate, uintptr(srcRGB), uintptr(dstRGB), uintptr(srcAlpha), uintptr(dstAlpha)) } func BufferData(target uint32, size int, data unsafe.Pointer, usage uint32) { @@ -450,9 +455,13 @@ func InitWithProcAddrFunc(getProcAddr func(name string) uintptr) error { if gpBindTexture == 0 { return errors.New("gl: glBindTexture is missing") } - gpBlendFunc = getProcAddr("glBlendFunc") - if gpBlendFunc == 0 { - return errors.New("gl: glBlendFunc is missing") + gpBlendEquationSeparate = getProcAddr("glBlendEquationSeparate") + if gpBlendEquationSeparate == 0 { + return errors.New("gl: glBlendEquationSeparate is missing") + } + gpBlendFuncSeparate = getProcAddr("glBlendFuncSeparate") + if gpBlendFuncSeparate == 0 { + return errors.New("gl: glBlendFuncSeparate is missing") } gpBufferData = getProcAddr("glBufferData") if gpBufferData == 0 { diff --git a/internal/graphicsdriver/opengl/gl_js.go b/internal/graphicsdriver/opengl/gl_js.go index 19fea4eef..96ec82be6 100644 --- a/internal/graphicsdriver/opengl/gl_js.go +++ b/internal/graphicsdriver/opengl/gl_js.go @@ -26,7 +26,8 @@ type gl struct { bindFramebuffer js.Value bindRenderbuffer js.Value bindTexture js.Value - blendFunc js.Value + blendEquationSeparate js.Value + blendFuncSeparate js.Value bufferData js.Value bufferSubData js.Value checkFramebufferStatus js.Value @@ -103,7 +104,8 @@ func (c *context) newGL(v js.Value) *gl { bindFramebuffer: v.Get("bindFramebuffer").Call("bind", v), bindRenderbuffer: v.Get("bindRenderbuffer").Call("bind", v), bindTexture: v.Get("bindTexture").Call("bind", v), - blendFunc: v.Get("blendFunc").Call("bind", v), + blendEquationSeparate: v.Get("blendEquationSeparate").Call("bind", v), + blendFuncSeparate: v.Get("blendFuncSeparate").Call("bind", v), bufferData: v.Get("bufferData").Call("bind", v), bufferSubData: v.Get("bufferSubData").Call("bind", v), checkFramebufferStatus: v.Get("checkFramebufferStatus").Call("bind", v), diff --git a/internal/graphicsdriver/opengl/gles/default.go b/internal/graphicsdriver/opengl/gles/default.go index ba57fb96b..58282c514 100644 --- a/internal/graphicsdriver/opengl/gles/default.go +++ b/internal/graphicsdriver/opengl/gles/default.go @@ -78,8 +78,12 @@ func (DefaultContext) BindTexture(target uint32, texture uint32) { C.glBindTexture(C.GLenum(target), C.GLuint(texture)) } -func (DefaultContext) BlendFunc(sfactor uint32, dfactor uint32) { - C.glBlendFunc(C.GLenum(sfactor), C.GLenum(dfactor)) +func (DefaultContext) BlendEquationSeparate(modeRGB uint32, modeAlpha uint32) { + C.glBlendEquationSeparate(C.GLenum(modeRGB), C.GLenum(modeAlpha)) +} + +func (DefaultContext) BlendFuncSeparate(srcRGB uint32, dstRGB uint32, srcAlpha uint32, dstAlpha uint32) { + C.glBlendFuncSeparate(C.GLenum(srcRGB), C.GLenum(dstRGB), C.GLenum(srcAlpha), C.GLenum(dstAlpha)) } func (DefaultContext) BufferData(target uint32, size int, data []byte, usage uint32) { diff --git a/internal/graphicsdriver/opengl/gles/gomobile.go b/internal/graphicsdriver/opengl/gles/gomobile.go index 09b55d971..08e8ca0dd 100644 --- a/internal/graphicsdriver/opengl/gles/gomobile.go +++ b/internal/graphicsdriver/opengl/gles/gomobile.go @@ -64,8 +64,12 @@ func (g *GomobileContext) BindTexture(target uint32, texture uint32) { g.ctx.BindTexture(gl.Enum(target), gl.Texture{Value: texture}) } -func (g *GomobileContext) BlendFunc(sfactor uint32, dfactor uint32) { - g.ctx.BlendFunc(gl.Enum(sfactor), gl.Enum(dfactor)) +func (g *GomobileContext) BlendEquationSeparate(modeRGB uint32, modeAlpha uint32) { + g.ctx.BlendEquationSeparate(gl.Enum(modeRGB), gl.Enum(modeAlpha)) +} + +func (g *GomobileContext) BlendFuncSeparate(srcRGB uint32, dstRGB uint32, srcAlpha uint32, dstAlpha uint32) { + g.ctx.BlendFuncSeparate(gl.Enum(srcRGB), gl.Enum(dstRGB), gl.Enum(srcAlpha), gl.Enum(dstAlpha)) } func (g *GomobileContext) BufferData(target uint32, size int, data []byte, usage uint32) { diff --git a/internal/graphicsdriver/opengl/gles/interface.go b/internal/graphicsdriver/opengl/gles/interface.go index 6258fe625..aafa47497 100644 --- a/internal/graphicsdriver/opengl/gles/interface.go +++ b/internal/graphicsdriver/opengl/gles/interface.go @@ -22,7 +22,8 @@ type Context interface { BindFramebuffer(target uint32, framebuffer uint32) BindRenderbuffer(target uint32, renderbuffer uint32) BindTexture(target uint32, texture uint32) - BlendFunc(sfactor uint32, dfactor uint32) + BlendEquationSeparate(modeRGB uint32, modeAlpha uint32) + BlendFuncSeparate(srcRGB uint32, dstRGB uint32, srcAlpha uint32, dstAlpha uint32) BufferData(target uint32, size int, data []byte, usage uint32) BufferSubData(target uint32, offset int, data []byte) CheckFramebufferStatus(target uint32) uint32 diff --git a/internal/graphicsdriver/opengl/graphics.go b/internal/graphicsdriver/opengl/graphics.go index 411d0cf56..834e7a593 100644 --- a/internal/graphicsdriver/opengl/graphics.go +++ b/internal/graphicsdriver/opengl/graphics.go @@ -180,7 +180,7 @@ func (g *Graphics) uniformVariableName(idx int) string { return name } -func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.ShaderImageCount]graphicsdriver.ImageID, offsets [graphics.ShaderImageCount - 1][2]float32, shaderID graphicsdriver.ShaderID, indexLen int, indexOffset int, mode graphicsdriver.CompositeMode, dstRegion, srcRegion graphicsdriver.Region, uniforms [][]float32, evenOdd bool) error { +func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.ShaderImageCount]graphicsdriver.ImageID, offsets [graphics.ShaderImageCount - 1][2]float32, shaderID graphicsdriver.ShaderID, indexLen int, indexOffset int, blend graphicsdriver.Blend, dstRegion, srcRegion graphicsdriver.Region, uniforms [][]float32, evenOdd bool) error { if shaderID == graphicsdriver.InvalidShaderID { return fmt.Errorf("opengl: shader ID is invalid") } @@ -198,7 +198,7 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics. int(dstRegion.Width), int(dstRegion.Height), ) - g.context.blendFunc(mode) + g.context.blend(blend) shader := g.shaders[shaderID] program := shader.p diff --git a/internal/mipmap/mipmap.go b/internal/mipmap/mipmap.go index 06a7b3315..c33194283 100644 --- a/internal/mipmap/mipmap.go +++ b/internal/mipmap/mipmap.go @@ -65,7 +65,7 @@ func (m *Mipmap) ReadPixels(graphicsDriver graphicsdriver.Graphics, pixels []byt return m.orig.ReadPixels(graphicsDriver, pixels, x, y, width, height) } -func (m *Mipmap) DrawTriangles(srcs [graphics.ShaderImageCount]*Mipmap, vertices []float32, indices []uint16, mode graphicsdriver.CompositeMode, dstRegion, srcRegion graphicsdriver.Region, subimageOffsets [graphics.ShaderImageCount - 1][2]float32, shader *Shader, uniforms [][]float32, evenOdd bool, canSkipMipmap bool) { +func (m *Mipmap) DrawTriangles(srcs [graphics.ShaderImageCount]*Mipmap, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion, srcRegion graphicsdriver.Region, subimageOffsets [graphics.ShaderImageCount - 1][2]float32, shader *Shader, uniforms [][]float32, evenOdd bool, canSkipMipmap bool) { if len(indices) == 0 { return } @@ -123,7 +123,7 @@ func (m *Mipmap) DrawTriangles(srcs [graphics.ShaderImageCount]*Mipmap, vertices imgs[i] = src.orig } - m.orig.DrawTriangles(imgs, vertices, indices, mode, dstRegion, srcRegion, subimageOffsets, shader.shader, uniforms, evenOdd) + m.orig.DrawTriangles(imgs, vertices, indices, blend, dstRegion, srcRegion, subimageOffsets, shader.shader, uniforms, evenOdd) m.disposeMipmaps() } @@ -192,7 +192,7 @@ func (m *Mipmap) level(level int) *buffered.Image { Width: float32(w2), Height: float32(h2), } - s.DrawTriangles([graphics.ShaderImageCount]*buffered.Image{src}, vs, is, graphicsdriver.CompositeModeCopy, dstRegion, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, shader.shader, nil, false) + s.DrawTriangles([graphics.ShaderImageCount]*buffered.Image{src}, vs, is, graphicsdriver.BlendCopy, dstRegion, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, shader.shader, nil, false) m.setImg(level, s) return m.imgs[level] diff --git a/internal/restorable/image.go b/internal/restorable/image.go index 184b4659f..65e45dca5 100644 --- a/internal/restorable/image.go +++ b/internal/restorable/image.go @@ -76,7 +76,7 @@ type drawTrianglesHistoryItem struct { offsets [graphics.ShaderImageCount - 1][2]float32 vertices []float32 indices []uint16 - mode graphicsdriver.CompositeMode + blend graphicsdriver.Blend dstRegion graphicsdriver.Region srcRegion graphicsdriver.Region shader *Shader @@ -218,7 +218,7 @@ func (i *Image) Extend(width, height int) *Image { Width: float32(sw), Height: float32(sh), } - newImg.DrawTriangles(srcs, offsets, vs, is, graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, NearestFilterShader, nil, false) + newImg.DrawTriangles(srcs, offsets, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, NearestFilterShader, nil, false) // Overwrite the history as if the image newImg is created only by WritePixels. newImg.clearDrawTrianglesHistory() @@ -264,7 +264,7 @@ func clearImage(i *graphicscommand.Image) { Width: float32(dw), Height: float32(dh), } - i.DrawTriangles(srcs, offsets, vs, is, graphicsdriver.CompositeModeClear, dstRegion, graphicsdriver.Region{}, NearestFilterShader.shader, nil, false) + i.DrawTriangles(srcs, offsets, vs, is, graphicsdriver.BlendClear, dstRegion, graphicsdriver.Region{}, NearestFilterShader.shader, nil, false) } // BasePixelsForTesting returns the image's basePixels for testing. @@ -371,7 +371,7 @@ func (i *Image) WritePixels(pixels []byte, x, y, width, height int) { // 5: Color G // 6: Color B // 7: Color Y -func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, offsets [graphics.ShaderImageCount - 1][2]float32, vertices []float32, indices []uint16, mode graphicsdriver.CompositeMode, dstRegion, srcRegion graphicsdriver.Region, shader *Shader, uniforms [][]float32, evenOdd bool) { +func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, offsets [graphics.ShaderImageCount - 1][2]float32, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion, srcRegion graphicsdriver.Region, shader *Shader, uniforms [][]float32, evenOdd bool) { if i.priority { panic("restorable: DrawTriangles cannot be called on a priority image") } @@ -395,7 +395,7 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, offsets [g if srcstale || !needsRestoring() || !i.needsRestoring() { i.makeStale(image.Rect(0, 0, i.width, i.height)) } else { - i.appendDrawTrianglesHistory(srcs, offsets, vertices, indices, mode, dstRegion, srcRegion, shader, uniforms, evenOdd) + i.appendDrawTrianglesHistory(srcs, offsets, vertices, indices, blend, dstRegion, srcRegion, shader, uniforms, evenOdd) } var imgs [graphics.ShaderImageCount]*graphicscommand.Image @@ -405,11 +405,11 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, offsets [g } imgs[i] = src.image } - i.image.DrawTriangles(imgs, offsets, vertices, indices, mode, dstRegion, srcRegion, shader.shader, uniforms, evenOdd) + i.image.DrawTriangles(imgs, offsets, vertices, indices, blend, dstRegion, srcRegion, shader.shader, uniforms, evenOdd) } // appendDrawTrianglesHistory appends a draw-image history item to the image. -func (i *Image) appendDrawTrianglesHistory(srcs [graphics.ShaderImageCount]*Image, offsets [graphics.ShaderImageCount - 1][2]float32, vertices []float32, indices []uint16, mode graphicsdriver.CompositeMode, dstRegion, srcRegion graphicsdriver.Region, shader *Shader, uniforms [][]float32, evenOdd bool) { +func (i *Image) appendDrawTrianglesHistory(srcs [graphics.ShaderImageCount]*Image, offsets [graphics.ShaderImageCount - 1][2]float32, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion, srcRegion graphicsdriver.Region, shader *Shader, uniforms [][]float32, evenOdd bool) { if i.stale || !i.needsRestoring() { return } @@ -434,7 +434,7 @@ func (i *Image) appendDrawTrianglesHistory(srcs [graphics.ShaderImageCount]*Imag offsets: offsets, vertices: vs, indices: is, - mode: mode, + blend: blend, dstRegion: dstRegion, srcRegion: srcRegion, shader: shader, @@ -620,7 +620,7 @@ func (i *Image) restore(graphicsDriver graphicsdriver.Graphics) error { } imgs[i] = img.image } - gimg.DrawTriangles(imgs, c.offsets, c.vertices, c.indices, c.mode, c.dstRegion, c.srcRegion, c.shader.shader, c.uniforms, c.evenOdd) + gimg.DrawTriangles(imgs, c.offsets, c.vertices, c.indices, c.blend, c.dstRegion, c.srcRegion, c.shader.shader, c.uniforms, c.evenOdd) } if len(i.drawTrianglesHistory) > 0 { diff --git a/internal/restorable/images_test.go b/internal/restorable/images_test.go index 40475b3e8..f8b22a73e 100644 --- a/internal/restorable/images_test.go +++ b/internal/restorable/images_test.go @@ -145,7 +145,7 @@ func TestRestoreChain(t *testing.T) { Width: 1, Height: 1, } - imgs[i+1].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[i]}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + imgs[i+1].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[i]}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) } if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting(), false); err != nil { t.Fatal(err) @@ -193,10 +193,10 @@ func TestRestoreChain2(t *testing.T) { Width: w, Height: h, } - imgs[8].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[7]}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(imgs[7], w, h, 0, 0), is, graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) - imgs[9].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[8]}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(imgs[8], w, h, 0, 0), is, graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + imgs[8].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[7]}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(imgs[7], w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + imgs[9].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[8]}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(imgs[8], w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) for i := 0; i < 7; i++ { - imgs[i+1].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[i]}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(imgs[i], w, h, 0, 0), is, graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + imgs[i+1].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[i]}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(imgs[i], w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) } if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting(), false); err != nil { @@ -242,10 +242,10 @@ func TestRestoreOverrideSource(t *testing.T) { Width: w, Height: h, } - img2.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(img1, w, h, 0, 0), is, graphicsdriver.CompositeModeSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) - img3.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(img2, w, h, 0, 0), is, graphicsdriver.CompositeModeSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img2.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(img1, w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img3.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(img2, w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) img0.WritePixels([]byte{clr1.R, clr1.G, clr1.B, clr1.A}, 0, 0, w, h) - img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(img0, w, h, 0, 0), is, graphicsdriver.CompositeModeSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(img0, w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting(), false); err != nil { t.Fatal(err) } @@ -331,23 +331,23 @@ func TestRestoreComplexGraph(t *testing.T) { } var offsets [graphics.ShaderImageCount - 1][2]float32 vs := quadVertices(img0, w, h, 0, 0) - img3.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, offsets, vs, is, graphicsdriver.CompositeModeSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img3.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, offsets, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) vs = quadVertices(img1, w, h, 1, 0) - img3.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, offsets, vs, is, graphicsdriver.CompositeModeSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img3.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, offsets, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) vs = quadVertices(img1, w, h, 1, 0) - img4.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, offsets, vs, is, graphicsdriver.CompositeModeSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img4.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, offsets, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) vs = quadVertices(img2, w, h, 2, 0) - img4.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, offsets, vs, is, graphicsdriver.CompositeModeSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img4.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, offsets, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) vs = quadVertices(img3, w, h, 0, 0) - img5.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img3}, offsets, vs, is, graphicsdriver.CompositeModeSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img5.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img3}, offsets, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) vs = quadVertices(img3, w, h, 0, 0) - img6.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img3}, offsets, vs, is, graphicsdriver.CompositeModeSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img6.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img3}, offsets, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) vs = quadVertices(img4, w, h, 1, 0) - img6.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img4}, offsets, vs, is, graphicsdriver.CompositeModeSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img6.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img4}, offsets, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) vs = quadVertices(img2, w, h, 0, 0) - img7.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, offsets, vs, is, graphicsdriver.CompositeModeSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img7.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, offsets, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) vs = quadVertices(img3, w, h, 2, 0) - img7.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img3}, offsets, vs, is, graphicsdriver.CompositeModeSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img7.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img3}, offsets, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting(), false); err != nil { t.Fatal(err) } @@ -445,8 +445,8 @@ func TestRestoreRecursive(t *testing.T) { Width: w, Height: h, } - img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(img0, w, h, 1, 0), is, graphicsdriver.CompositeModeSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) - img0.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(img1, w, h, 1, 0), is, graphicsdriver.CompositeModeSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(img0, w, h, 1, 0), is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img0.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(img1, w, h, 1, 0), is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting(), false); err != nil { t.Fatal(err) } @@ -549,7 +549,7 @@ func TestDrawTrianglesAndWritePixels(t *testing.T) { Width: 2, Height: 1, } - img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) img1.WritePixels([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 0, 0, 2, 1) if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting(), false); err != nil { @@ -592,8 +592,8 @@ func TestDispose(t *testing.T) { Width: 1, Height: 1, } - img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(img2, 1, 1, 0, 0), is, graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) - img0.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(img1, 1, 1, 0, 0), is, graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(img2, 1, 1, 0, 0), is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img0.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(img1, 1, 1, 0, 0), is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) img1.Dispose() if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting(), false); err != nil { @@ -707,7 +707,7 @@ func TestWritePixelsOnly(t *testing.T) { Width: 1, Height: 1, } - img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) img0.WritePixels([]byte{5, 6, 7, 8}, 0, 0, 1, 1) // BasePixelsForTesting is available without GPU accessing. @@ -766,7 +766,7 @@ func TestReadPixelsFromVolatileImage(t *testing.T) { Width: w, Height: h, } - dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) // Read the pixels. If the implementation is correct, dst tries to read its pixels from GPU due to being // stale. @@ -795,7 +795,7 @@ func TestAllowWritePixelsAfterDrawTriangles(t *testing.T) { Width: w, Height: h, } - dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.CompositeModeSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) dst.WritePixels(make([]byte, 4*w*h), 0, 0, w, h) // WritePixels for a whole image doesn't panic. } @@ -819,7 +819,7 @@ func TestAllowWritePixelsForPartAfterDrawTriangles(t *testing.T) { Width: w, Height: h, } - dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.CompositeModeSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) dst.WritePixels(make([]byte, 4*2*2), 0, 0, 2, 2) // WritePixels for a part of image doesn't panic. @@ -922,7 +922,7 @@ func TestMutateSlices(t *testing.T) { Width: w, Height: h, } - dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.CompositeModeSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) for i := range vs { vs[i] = 0 } @@ -1119,7 +1119,7 @@ func TestDrawTrianglesAndReadPixels(t *testing.T) { Width: w, Height: h, } - dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.CompositeModeSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) pix := make([]byte, 4*w*h) if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), pix, 0, 0, w, h); err != nil { diff --git a/internal/restorable/shader_test.go b/internal/restorable/shader_test.go index a7dd8ff21..82666db20 100644 --- a/internal/restorable/shader_test.go +++ b/internal/restorable/shader_test.go @@ -50,7 +50,7 @@ func clearImage(img *restorable.Image, w, h int) { Width: float32(w), Height: float32(h), } - img.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{emptyImage}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.CompositeModeClear, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{emptyImage}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendClear, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) } func TestShader(t *testing.T) { @@ -64,7 +64,7 @@ func TestShader(t *testing.T) { Width: 1, Height: 1, } - img.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(nil, 1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, s, nil, false) + img.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(nil, 1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, s, nil, false) if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting(), false); err != nil { t.Fatal(err) @@ -99,7 +99,7 @@ func TestShaderChain(t *testing.T) { Width: 1, Height: 1, } - imgs[i+1].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[i]}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(imgs[i], 1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, s, nil, false) + imgs[i+1].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[i]}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(imgs[i], 1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, s, nil, false) } if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting(), false); err != nil { @@ -137,7 +137,7 @@ func TestShaderMultipleSources(t *testing.T) { Width: 1, Height: 1, } - dst.DrawTriangles(srcs, offsets, quadVertices(srcs[0], 1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, s, nil, false) + dst.DrawTriangles(srcs, offsets, quadVertices(srcs[0], 1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, s, nil, false) // Clear one of the sources after DrawTriangles. dst should not be affected. clearImage(srcs[0], 1, 1) @@ -178,7 +178,7 @@ func TestShaderMultipleSourcesOnOneTexture(t *testing.T) { Width: 1, Height: 1, } - dst.DrawTriangles(srcs, offsets, quadVertices(srcs[0], 1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, s, nil, false) + dst.DrawTriangles(srcs, offsets, quadVertices(srcs[0], 1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, s, nil, false) // Clear one of the sources after DrawTriangles. dst should not be affected. clearImage(srcs[0], 3, 1) @@ -208,7 +208,7 @@ func TestShaderDispose(t *testing.T) { Width: 1, Height: 1, } - img.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(nil, 1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, s, nil, false) + img.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(nil, 1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, s, nil, false) // Dispose the shader. This should invalidates all the images using this shader i.e., all the images become // stale. diff --git a/internal/ui/image.go b/internal/ui/image.go index e68245d28..d60467fbf 100644 --- a/internal/ui/image.go +++ b/internal/ui/image.go @@ -56,7 +56,7 @@ func (i *Image) MarkDisposed() { i.dotsCache = nil } -func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, mode graphicsdriver.CompositeMode, dstRegion, srcRegion graphicsdriver.Region, subimageOffsets [graphics.ShaderImageCount - 1][2]float32, shader *Shader, uniforms [][]float32, evenOdd bool, canSkipMipmap bool) { +func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion, srcRegion graphicsdriver.Region, subimageOffsets [graphics.ShaderImageCount - 1][2]float32, shader *Shader, uniforms [][]float32, evenOdd bool, canSkipMipmap bool) { i.flushCacheIfNeeded() var srcMipmaps [graphics.ShaderImageCount]*mipmap.Mipmap @@ -68,7 +68,7 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [ srcMipmaps[i] = src.mipmap } - i.mipmap.DrawTriangles(srcMipmaps, vertices, indices, mode, dstRegion, srcRegion, subimageOffsets, shader.shader, uniforms, evenOdd, canSkipMipmap) + i.mipmap.DrawTriangles(srcMipmaps, vertices, indices, blend, dstRegion, srcRegion, subimageOffsets, shader.shader, uniforms, evenOdd, canSkipMipmap) } func (i *Image) WritePixels(pix []byte, x, y, width, height int) { @@ -190,7 +190,7 @@ func (i *Image) flushCacheIfNeeded() { Width: float32(i.width), Height: float32(i.height), } - i.mipmap.DrawTriangles(srcs, vs, is, graphicsdriver.CompositeModeCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, NearestFilterShader.shader, nil, false, true) + i.mipmap.DrawTriangles(srcs, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, NearestFilterShader.shader, nil, false, true) } func DumpImages(dir string) (string, error) { @@ -230,5 +230,5 @@ func (i *Image) Fill(r, g, b, a float32, x, y, width, height int) { srcs := [graphics.ShaderImageCount]*Image{emptyImage} - i.DrawTriangles(srcs, vs, is, graphicsdriver.CompositeModeCopy, dstRegion, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, NearestFilterShader, nil, false, true) + i.DrawTriangles(srcs, vs, is, graphicsdriver.BlendCopy, dstRegion, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, NearestFilterShader, nil, false, true) }