Screenshot from within CX

Jimmy

Active member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
878
I've been debugging my screenshot routine for a few weeks now and finally found the source what happens. I'm not sure where to go from here or just give up because it might be hardware I'm not sure.

I'll explan with some source and pictures. Becuase this is one of those buggie things that you need a lot of devices to test, it does not show up on many.
The code will make the screen green if okay, and dark dots where it has this problem (you won't see it if you don't have a particular Android devices, it might be 24-bit devices, it might special hardware, I'm not sure yet, it can be 32-bit CPU and some rounding error in the chain? I'm not sure yet.

EDIT
Put in a green for okay pixels, so you see something is hapepning on all devices.
When screen is filled , it WILL go black as the second time.. no pixel is the "correct", its green. This is supposed to happen.

What you don't want is a sparse grid of pixels, these will show up quickly in the first round if there is any problem.

Code:
' This might be a hardware-level, OS-level or anything in-between. I don't think it's a Cerberus-X problem.
' You have to be aware of this when developing for a bigger market though and are dependent on technical details such as this.

Strict                ' Tests pixels for unusual content after we've drawn a solid rectangle. All pixels are expected to be the same.
Import mojo2            ' This will only be interesting on the Android platform, other platforms have no issue.
Import brl.databuffer    ' The Android this show a problem that exist with a few devices;
                    ' e.g. Samsung Note2 (32-bit, 1280x720, 24-bit graphics)
Function Main:Int()    ' On those devices, when draw anything solid colour on the screen, it won't have a solid colour at all.
    New Game            ' Every 4:th pixel in both directions will  create a sparse grid of unusual pixel content. The RGBA will be abit different there.
    Return 0             ' As all blendmodes gives the same result we do not set any in this example
End

Class Game Extends App

    Field checkred:Int = 206, checkgreen:Int = 246, checkblue:Int = 4, checkalpha:Int = 255 ' << Good test
    Field xxx:Int, yyy:Int,screen2:Image, r:Int, g:Int, b:Int, a:Int, sprite:Canvas, canvas:Canvas
    Field cc:Float[4], pixels:DataBuffer = New DataBuffer(4*320*200), ptr:Int = 0

    Method OnCreate:Int()
        canvas=New Canvas
        SetSwapInterval 1 ; SetUpdateRate 0
        screen2=New Image(320,200,0,0,0) ; sprite=New Canvas(screen2)
        cc[0] = checkred/255.0 ; cc[1] = checkgreen/255.0 ; cc[2] = checkblue/255.0 ; cc[3] = checkalpha/255.0
        sprite.SetColor cc[0],cc[1],cc[2],cc[3]
        sprite.DrawRect 0,0,320,200 ; sprite.Flush
        Return 0
    End

    Method OnRender:Int()
        canvas.Clear 0,0,0,0
        canvas.SetColor 1,1,1,1
         For Local temp:Int = 0 To 100 ' x100 faster test
             yyy= Int(ptr/320) ; xxx= ptr-(yyy*320) ; ptr = ptr + 1 ; If ptr > (320*200) Then ptr = 0       
            sprite.ReadPixels(xxx,yyy,1,1, pixels)
            Local pixel:Int[] = ColorToRgb(pixels.PeekInt(Int(Int(0)*4+Int(0)*320*4)))
            r = pixel[3] ; g = pixel[2] ; b = pixel[1] ; a = pixel[0]             
            If r <> checkred Or g <> checkgreen Or  b <> checkblue Or a <> checkalpha Then sprite.SetColor 0,0,0,1 ; sprite.DrawRect xxx,yyy,1,1
            If r = checkred And g = checkgreen And b = checkblue And a = checkalpha Then sprite.SetColor 0,0,0,1 ; sprite.DrawRect xxx,yyy,1,1 ' Green if okay
        Next

        ' Draw image on display
        sprite.Flush ;     canvas.SetColor 1,1,1,1 ; canvas.DrawRect 0,0,640,400,screen2,0,0,320,200 
         canvas.Flush
         Return 0
    End
 
    Function ColorToRgb:Int[](value:Int)
            Local resp:Int[] ;  resp = resp.Resize(4)
            Local v:Int = value ;  resp[3] = v & 255 ; v = v Shr 8 ; resp[2] = v & 255 ; v = v Shr 8 ;  resp[1] = v & 255 ; v = v Shr 8 ;  resp[0] = v & 255
            Return resp
    End
 
End

This is of course what it should be and what it DOES look like on many Androids, and also 100% on all other platforms.


correct.jpeg


But looking more carefully on we can find Android devices that gives you this, every 4:th pixel is a little bit off, and here this program makes them visible bby marking them with something a lot stronger.

Been digging into thousands and thousand lines of game code that this was a bit-rounding error, because as happens exactly every 4th pixel. It was a really hard nut to comes this far and being able to understand it.

How to go from here? I'm not sure. I'm gonna check Android documentation and hardware of course.


buggynote2.jpeg
 
Last edited:

Jimmy

Active member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
878
I did my research and the problem is that dithering is on by default on e.g. the Samsung Galaxy series, Mali 400 etc.
It might be a problem with more modern devices too I'm not sure.

This disturbs Cerberus readpixels because it reads what the device says it should.

You can use GLES11.glDisable(GLES11.GL_DITHER)

But what about disable dithering on GLES2?
I need to check if GLES20.glDisable(GLES20.GL_DITHER) is all that it takes.

Screenshot 2021-08-02 at 14.37.50.png
 

Phil7

Administrator
CX Code Contributor
3rd Party Tool Dev
Joined
Jun 26, 2017
Messages
636
May I ask you, for what purpose you are trying to get a screenshot from within Cerberus?
 

Jimmy

Active member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
878
I'm working on a lot of things. You know what? I solved it this very minute. It's fixed.

Mojo2/graphics.cxs, line 2295
Method Render:Void( op:DrawOp,index:Int,count:Int )

glDisable GL_DITHER ' < add this one


I might move it to somewhere else if it is not needed every frame.
 

Jimmy

Active member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
878
I'm reading to check my GUI on all devices on the market for that I need pixelperfect checks for my Unitests.

I can do that now. All models work ranging the year 2011-2021 all works. One line of code. (I use 8+8+8+8 graphics and I don't need dithering , that's useful for 16bit graphis).

Some 24/32bit devices forget to have dither off as default, and makes a terible mess.
 
Last edited:
Top Bottom