I was trying to setup a unscaled pixel fitted screen on mobile and saw a glitch. It should render a rotating pulsing image.
On Android there is a glitch:

On Desktop works as it should:

Project is here: https://github.com/egonelbre/ebiten-basic
It uses multiple transformations in a sequence and I think it is what why it's wasn't noticed before (https://github.com/egonelbre/ebiten-basic/blob/master/basic/single.go#L29):
op := &ebiten.DrawImageOptions{}
op.CompositeMode = ebiten.CompositeModeSourceOver
op.GeoM.Translate(imgsz.Scale(0.5).Neg().Float64())
op.GeoM.Rotate(float64(scene.Rotation))
op.GeoM.Scale(imgsz.Inv().Float64())
s := scene.Scale * 100
op.GeoM.Scale(float64(s), float64(s))
op.GeoM.Translate(frame.Screen.Size.Scale(0.5).Float64())
Thank you for reporting. I'll look at this.
This doesn't happen on my Nexus 5x. What machine are you using, and what resolution is this?
Galaxy S4-mini, GT-I9195, Android 6.0.1, Cyanogenmod 13.0-20161221
Resolution that is shown in top-left corner is 960x540.
I guess there is an interoperability problem in shaders but am not sure. Hmm...
Managed to make a video of the issue:
https://goo.gl/photos/ojuCyEBSN8k7A9jz7
I also modified the code to iterate over multiple transforms: https://github.com/egonelbre/ebiten-basic/blob/master/basic/single.go#L31
And it seems the issue is already visible with the first transform.
What Go version are you using currently? (I'm on 1.8.0)
Managed to make a video of the issue:
https://goo.gl/photos/ojuCyEBSN8k7A9jz7
Thanks, I appreciate it.
And it seems the issue is already visible with the first transform.
Well, in Ebiten, calculating GeoM is in Go. As this works on other platforms, I don't think there is a problem there. GeoMs data is passed as vertices data (*1), and there might be a bug in shaders.
(*1) GeoM is not passed as a uniform value in order to reduce gl calls.
What Go version are you using currently? (I'm on 1.8.0)
I'm also using 1.8.0.
Well, in Ebiten, calculating GeoM is in Go. As this works on other platforms, I don't think there is a problem there. GeoMs data is passed as vertices data (*1), and there might be a bug in shaders.
In addition, GeoM only changes quad vertices linearly so such glitch should never happen however GeoM calculation was wrong.
http://stackoverflow.com/questions/29731812/uniform-value-is-wrong-in-adreno-305-qualcom-device-but-right-in-adreno-profiler might be related (but unsolved)
Yeah, I'm currently trying to get Adreno Profiler running. Yeah, nothing to do with GeoM itself.
I was thinking maybe it's hitting some attribute limit (or some other limit), because actual limit is lower than the driver shows due to some bug.
It looks like I'm not getting anything useful out of Adreno Profiler. It doesn't seem to be able to trace Go GL.
I've created adreno-305 branch. This includes fix for shader problems, I am still not sure though. I'd be glad if you could test this when you are available.
Unfortunately, it doesn't help, still the same issue.
Thank you for testing. Hmm, I'm out of idea so far.
I bought ZenFone Go, which has the same GPU Adreno 305, so I can test this next week.
Thank you for all the effort... I'm out of good ideas as well. Let me know if I can help somehow.
Hmm, ZenFone Go is not delivered yet. Wait a little more sorry
Great news: This can be reproduced on ZenFone Go!
Fixed by the below println code:
diff --git a/vertices_notjs.go b/vertices_notjs.go
index 47b866a..f2b3726 100644
--- a/vertices_notjs.go
+++ b/vertices_notjs.go
@@ -78,7 +78,13 @@ func vertices(parts ImageParts, width, height int, geo *affine.GeoM) []float32 {
vs[n+16] = g2
vs[n+17] = g3
vs[n+18] = g4
- vs[n+19] = g5
+ if g5 < 1 {
+ println("A", int(g5))
+ vs[n+19] = g5
+ } else {
+ println("B", int(g5))
+ vs[n+19] = g5
+ }
vs[n+20] = x0
vs[n+21] = y1
This is very very very mysterious. Without println, this fix doesn't work. Even though g5 is bigger than 1, "A" is always chosen. What is happening??
Maybe arm compiler issue or timing issue?
It seems this is sufficient to fix it:
...
nop()
vs[n+19] = g5
...
//go:noinline
func nop() {}
I decompiled the code... https://gist.github.com/egonelbre/930b80ff0d27c7816adb5b0770d9ce3c, but alas, I'm not familiar enough with ARM to understand what is significant.
Maybe arm compiler issue or timing issue?
Well, IIUC,
So your guess seems right, ARM 32bit compiler might have a problem.
It seems this is sufficient to fix it:
Great! I'll try to make this cleaner way. I can fix this in a day anyway. Thank you for a great help!
I decompiled the code... https://gist.github.com/egonelbre/930b80ff0d27c7816adb5b0770d9ce3c, but alas, I'm not familiar enough with ARM to understand what is significant.
Thank you, but I'm not familiar with this neither.
It seems inevitable to insert the nop there. Fixed.
I'm now trying to create a minimum case to reproduce this problem. Actually I've succeeded to create an independent main module to reproduce this and now am trying to make this smaller. The condition to reproduce this seems very sensitive.
This issue might be visible on Rasperry Pi, so maybe it can be debugged there faster.
EDIT: yes, reproducible on Raspberry.
Most helpful comment
Reported https://github.com/golang/go/issues/19403