mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 03:08:54 +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.state.lastActiveTexture = 0
|
||||||
g.context.ctx.ActiveTexture(gl.TEXTURE0)
|
g.context.ctx.ActiveTexture(gl.TEXTURE0)
|
||||||
|
g.context.lastTexture = 0 // Make sure next bindTexture call actually does something.
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, u := range uniforms {
|
for _, u := range uniforms {
|
||||||
@ -267,6 +268,7 @@ loop:
|
|||||||
if g.state.lastActiveTexture != idx {
|
if g.state.lastActiveTexture != idx {
|
||||||
g.context.ctx.ActiveTexture(uint32(gl.TEXTURE0 + idx))
|
g.context.ctx.ActiveTexture(uint32(gl.TEXTURE0 + idx))
|
||||||
g.state.lastActiveTexture = 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.
|
// 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) {
|
func TestShaderFillWithDrawTriangles(t *testing.T) {
|
||||||
const w, h = 16, 16
|
const w, h = 16, 16
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user