Skip to content

Commit

Permalink
graphicsdriver/opengl: Fix suspicious GL function calls
Browse files Browse the repository at this point in the history
Before this change, the pixel object buffer is unbound just after
getting a pointer by glMapBuffer. This seemed suspicious.

This change fixes to do all pixel manipulations once between
glMapBuffer and glUnmapBuffer without changing a bound buffer.

This might fix a wrong rendering on some machines, but I am not
sure.

Updates #993
  • Loading branch information
hajimehoshi committed Nov 19, 2019
1 parent 8243c18 commit 52f6be2
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 29 deletions.
2 changes: 0 additions & 2 deletions internal/graphicsdriver/opengl/context_desktop.go
Original file line number Diff line number Diff line change
Expand Up @@ -530,15 +530,13 @@ func (c *context) mapPixelBuffer(buffer buffer) unsafe.Pointer {
_ = c.t.Call(func() error {
gl.BindBuffer(gl.PIXEL_UNPACK_BUFFER, uint32(buffer))
ptr = gl.MapBuffer(gl.PIXEL_UNPACK_BUFFER, gl.WRITE_ONLY)
gl.BindBuffer(gl.PIXEL_UNPACK_BUFFER, 0)
return nil
})
return ptr
}

func (c *context) unmapPixelBuffer(buffer buffer, t textureNative, width, height int) {
_ = c.t.Call(func() error {
gl.BindBuffer(gl.PIXEL_UNPACK_BUFFER, uint32(buffer))
gl.UnmapBuffer(gl.PIXEL_UNPACK_BUFFER)
return nil
})
Expand Down
55 changes: 45 additions & 10 deletions internal/graphicsdriver/opengl/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ import (
"github.com/hajimehoshi/ebiten/internal/graphics"
)

type bufferedRP struct {
pixels []byte
x int
y int
width int
height int
}

type Image struct {
driver *Driver
textureNative textureNative
Expand All @@ -26,14 +34,15 @@ type Image struct {
width int
height int
screen bool

bufferedRPs []bufferedRP
}

func (i *Image) IsInvalidated() bool {
return !i.driver.context.isTexture(i.textureNative)
}

func (i *Image) Dispose() {
thePBOState.ensurePBOUnmapped()
if i.pbo != *new(buffer) {
i.driver.context.deleteBuffer(i.pbo)
}
Expand All @@ -46,6 +55,7 @@ func (i *Image) Dispose() {
}

func (i *Image) SetAsDestination() {
i.resolveReplacePixels()
i.driver.state.destination = i
}

Expand All @@ -58,7 +68,7 @@ func (i *Image) setViewport() error {
}

func (i *Image) Pixels() ([]byte, error) {
thePBOState.ensurePBOUnmapped()
i.resolveReplacePixels()
if err := i.ensureFramebuffer(); err != nil {
return nil, err
}
Expand Down Expand Up @@ -96,21 +106,46 @@ func (i *Image) ReplacePixels(p []byte, x, y, width, height int) {
panic("opengl: ReplacePixels cannot be called on the screen, that doesn't have a texture")
}

i.bufferedRPs = append(i.bufferedRPs, bufferedRP{
pixels: p,
x: x,
y: y,
width: width,
height: height,
})
}

func (i *Image) SetAsSource() {
i.resolveReplacePixels()
i.driver.state.source = i
}

func (i *Image) resolveReplacePixels() {
if len(i.bufferedRPs) == 0 {
return
}

defer func() {
i.bufferedRPs = nil
}()

// glFlush is necessary on Android.
// glTexSubImage2D didn't work without this hack at least on Nexus 5x and NuAns NEO [Reloaded] (#211).
if i.driver.drawCalled {
i.driver.context.flush()
}
i.driver.drawCalled = false

if canUsePBO {
thePBOState.mapPBOIfNecessary(i)
thePBOState.draw(p, x, y, width, height)
} else {
i.driver.context.texSubImage2D(i.textureNative, p, x, y, width, height)
if !canUsePBO {
for _, rp := range i.bufferedRPs {
i.driver.context.texSubImage2D(i.textureNative, rp.pixels, rp.x, rp.y, rp.width, rp.height)
}
return
}
}

func (i *Image) SetAsSource() {
i.driver.state.source = i
thePBOState.mapPBO(i)
for _, rp := range i.bufferedRPs {
thePBOState.draw(rp.pixels, rp.x, rp.y, rp.width, rp.height)
}
thePBOState.unmapPBO()
}
14 changes: 2 additions & 12 deletions internal/graphicsdriver/opengl/pbo_desktop.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,7 @@ type pboState struct {

var thePBOState pboState

func (s *pboState) mapPBOIfNecessary(img *Image) {
if s.image == img {
return
}

s.ensurePBOUnmapped()

func (s *pboState) mapPBO(img *Image) {
if img.pbo == *new(buffer) {
w, h := graphics.InternalImageSize(img.width), graphics.InternalImageSize(img.height)
img.pbo = img.driver.context.newPixelBufferObject(w, h)
Expand Down Expand Up @@ -73,11 +67,7 @@ func (s *pboState) draw(pix []byte, x, y, width, height int) {
runtime.KeepAlive(mapped)
}

func (s *pboState) ensurePBOUnmapped() {
if s.mappedPBO == nil {
return
}

func (s *pboState) unmapPBO() {
i := s.image
w, h := graphics.InternalImageSize(i.width), graphics.InternalImageSize(i.height)
i.driver.context.unmapPixelBuffer(i.pbo, i.textureNative, w, h)
Expand Down
6 changes: 3 additions & 3 deletions internal/graphicsdriver/opengl/pbo_notdesktop.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ type pboState struct{}

var thePBOState pboState

func (s *pboState) mapPBOIfNecessary(img *Image) {
func (s *pboState) mapPBO(img *Image) {
panic("opengl: PBO is not available in this environment")
}

func (s *pboState) draw(pix []byte, x, y, width, height int) {
panic("opengl: PBO is not available in this environment")
}

func (s *pboState) ensurePBOUnmapped() {
// Do nothing
func (s *pboState) unmapPBO() {
panic("opengl: PBO is not available in this environment")
}
2 changes: 0 additions & 2 deletions internal/graphicsdriver/opengl/program.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,8 +265,6 @@ func (d *Driver) useProgram(mode driver.CompositeMode, colorM *affine.ColorM, fi
panic("source image is not set")
}

thePBOState.ensurePBOUnmapped()

if err := destination.setViewport(); err != nil {
return err
}
Expand Down

0 comments on commit 52f6be2

Please sign in to comment.