mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-11-10 04:57:26 +01:00
internal/graphicsdriver/opengl: fix state tracking of glBindTexture / glActiveTexture interaction (#2526)
After switching texture units using glActiveTexture, a different texture may be bound. For now, let's just force the active texture state variable to zero so the next glBindTexture call isn't skipped. Closes #2525
This commit is contained in:
parent
95f1ef0fb9
commit
abece041f4
@ -219,6 +219,7 @@ func (g *Graphics) useProgram(program program, uniforms []uniformVariable, textu
|
||||
}
|
||||
g.state.lastActiveTexture = 0
|
||||
g.context.ctx.ActiveTexture(gl.TEXTURE0)
|
||||
g.context.lastTexture = 0 // Make sure next bindTexture call actually does something.
|
||||
}
|
||||
|
||||
for _, u := range uniforms {
|
||||
@ -267,6 +268,7 @@ loop:
|
||||
if g.state.lastActiveTexture != idx {
|
||||
g.context.ctx.ActiveTexture(uint32(gl.TEXTURE0 + idx))
|
||||
g.state.lastActiveTexture = idx
|
||||
g.context.lastTexture = 0 // Make sure next bindTexture call actually does something.
|
||||
}
|
||||
|
||||
// Apparently, a texture must be bound every time. The cache is not used here.
|
||||
|
@ -87,6 +87,76 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
|
||||
}
|
||||
}
|
||||
|
||||
// Issue #2525
|
||||
func TestShaderWithDrawImageDoesNotWreckTextureUnits(t *testing.T) {
|
||||
const w, h = 16, 16
|
||||
rect := image.Rectangle{Max: image.Point{X: w, Y: h}}
|
||||
|
||||
dst := ebiten.NewImageWithOptions(rect, &ebiten.NewImageOptions{Unmanaged: true})
|
||||
s, err := ebiten.NewShader([]byte(`package main
|
||||
|
||||
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
|
||||
return imageSrc0At(texCoord)
|
||||
}
|
||||
`))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
src0 := ebiten.NewImageWithOptions(rect, &ebiten.NewImageOptions{Unmanaged: true})
|
||||
src0.Fill(color.RGBA{25, 0xff, 25, 0xff})
|
||||
src1 := ebiten.NewImageWithOptions(rect, &ebiten.NewImageOptions{Unmanaged: true})
|
||||
src1.Fill(color.RGBA{0xff, 0, 0, 0xff})
|
||||
op := &ebiten.DrawRectShaderOptions{}
|
||||
op.CompositeMode = ebiten.CompositeModeCopy
|
||||
op.Images[0] = src0
|
||||
op.Images[1] = src1
|
||||
dst.DrawRectShader(w, h, s, op)
|
||||
op.Images[0] = src1
|
||||
op.Images[1] = nil
|
||||
dst.DrawRectShader(w, h, s, op) // dst should now be identical to src1.
|
||||
|
||||
// With issue #2525, instead, GL_TEXTURE0 is active but with src0 bound
|
||||
// while binding src1 gets skipped!
|
||||
// This means that src0, not src1, got copied to dst.
|
||||
|
||||
// Demonstrate the bug with a write to src1, which will actually end up on src0.
|
||||
// Validated later.
|
||||
var buf []byte
|
||||
for i := 0; i < w*h; i++ {
|
||||
buf = append(buf, 2, 5, 2, 5)
|
||||
}
|
||||
src1.WritePixels(buf)
|
||||
|
||||
// Verify that src1 was copied to dst.
|
||||
for j := 0; j < h; j++ {
|
||||
for i := 0; i < w; i++ {
|
||||
got := dst.At(i, j).(color.RGBA)
|
||||
want := color.RGBA{0xff, 0, 0, 0xff}
|
||||
if got != want {
|
||||
t.Errorf("dst.At(%d, %d): got: %v, want: %v", i, j, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fix up texture unit assignment by binding a different texture.
|
||||
op.Images[0] = src1
|
||||
dst.DrawRectShader(w, h, s, op)
|
||||
op.Images[0] = src0
|
||||
dst.DrawRectShader(w, h, s, op)
|
||||
|
||||
// Verify that src0 was copied to dst and not overwritten above.
|
||||
for j := 0; j < h; j++ {
|
||||
for i := 0; i < w; i++ {
|
||||
got := dst.At(i, j).(color.RGBA)
|
||||
want := color.RGBA{25, 0xff, 25, 0xff}
|
||||
if got != want {
|
||||
t.Errorf("dst.At(%d, %d): got: %v, want: %v", i, j, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestShaderFillWithDrawTriangles(t *testing.T) {
|
||||
const w, h = 16, 16
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user