internal/graphicsdriver: add Blend struct

This is a preparation to specify blend factors and blend operators.

Updates #2382
This commit is contained in:
Hajime Hoshi 2022-10-15 18:58:56 +09:00
parent 2f146d5e4f
commit 09a7d39874
33 changed files with 440 additions and 330 deletions

View File

@ -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

View File

@ -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.

View File

@ -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 {

View File

@ -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)
}

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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.

View File

@ -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 {

View File

@ -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,
}

View File

@ -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))
}
}

View File

@ -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
}

View File

@ -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,
},

View File

@ -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.

View File

@ -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
}

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -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) {

View File

@ -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) {

View File

@ -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) {

View File

@ -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 {

View File

@ -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 {

View File

@ -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),

View File

@ -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) {

View File

@ -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) {

View File

@ -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

View File

@ -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

View File

@ -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]

View File

@ -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 {

View File

@ -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 {

View File

@ -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.

View File

@ -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)
}