React Native - Android/OpenGL + Skia not rendering correct on device

594 views
Skip to first unread message

Christian Falch

unread,
Sep 7, 2021, 7:45:22 AM9/7/21
to skia-discuss
Hi,

We're working on a Skia binding for React Native on iOS / Android.

(more info here if anyone is interested: https://twitter.com/chrfalch/status/1434880480650932232)

On iOS we're using Metal and everything seems to be working fine on both device and simulator.

On Android everything works fine on the Emulator, but on a real device (this is tested on a Samsung A20 and a Nokia 6.2) only shaders are working correctly. So blurring an image or creating a color shader works fine - but none of the regular drawing operations on the canvas works at all. No circles, paths, rects, text or colors show up. 

We have made an example where we can see some colors (although the wrong ones) in part of a path, but this is probably because it is rendered on top of a shape with a shader.

I've compared our OpenGL setup with SkiaSharp, Flutter and other sample android configurations and they seem to be fine. We're using a TextureView on Android to render (to support transparency and multiple Skia views at the same time).

My initial thought is that this is related to the color space (since all colors ends up being drawn black) - but I'm not able to understand where this is originating from.

Had hoped that someone would know something about this - or have seen something similar before.

Regards,
Christian

Christian Falch

unread,
Sep 14, 2021, 4:43:04 PM9/14/21
to skia-discuss
Bumping this with some more information:

Here is how we're configuring OpenGL in Android:

EGLint att[] = {
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_ALPHA_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_RED_SIZE, 8,
EGL_DEPTH_SIZE, 0,
EGL_STENCIL_SIZE, 0,
EGL_NONE
};

This is how we're configuring the Skia surface

GLint buffer;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &buffer);

GLint stencil;
glGetIntegerv(GL_STENCIL_BITS, &stencil);

GLint samples;
glGetIntegerv(GL_SAMPLES, &samples);

auto maxSamples = _skContext->maxSurfaceSampleCountForColorType(kRGBA_8888_SkColorType);
if (samples > maxSamples)
samples = maxSamples;

GrGLFramebufferInfo fbInfo;
fbInfo.fFBOID = buffer;
fbInfo.fFormat = 0x8058;

_skRenderTarget = GrBackendRenderTarget(_width, _height, samples, stencil, fbInfo);

_skSurface = SkSurface::MakeFromBackendRenderTarget(
_skContext.get(), _skRenderTarget, kBottomLeft_GrSurfaceOrigin,
kRGBA_8888_SkColorType, nullptr, nullptr);


When testing clearing the screen with OpenGL we get the correct colors on the screen.

Drawing shaders with Skia works correctly, while using drawing primitives like canvas.drawPaint renders only black colors.

Any idea why this is happening?

Christian

Brian Salomon

unread,
Sep 14, 2021, 5:27:10 PM9/14/21
to skia-d...@googlegroups.com
Hi Christian,

Sorry for the late reply. We've recently discovered that many of the threads on this list have been incorrectly going to spam.

Unless you're creating a multisampled framebuffer (which it doesn't look like from the EGL attributes) you can just pass 1 for the sample count to GrBackendRenderTarget.

I'm wondering if there is a GL state issue. Have you tried calling GrDirectContext::resetContext() before Skia runs each frame? That's the signal to Skia that some other code used the GL context and left it in a state unknown to Skia.

Brian


--
You received this message because you are subscribed to the Google Groups "skia-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to skia-discuss...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/skia-discuss/37448ad0-eb9b-418a-a416-3996ef4abae9n%40googlegroups.com.

Christian Falch

unread,
Sep 15, 2021, 2:14:11 AM9/15/21
to skia-discuss
Hi Brian,

Thanks so much for replying - no worries about the delay :) 

I'm getting 0 samples when reading GL_SAMPLES value, tried changing it to 1 when creating the GrBackendRenderTarget without any luck.

I'm already resetting the GrDirectContext before I start drawing. 

Our frame drawing code runs in a separate thread where OpenGL/Skia is also set up where the call to reset it done on the line before we perform the Skia drawing.

Skia drawing ends by flushing the canvas and then flushing the context (removed error checking for readability):

// Clear with transparency
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
_skContext->resetContext();

// Draw in surface calls SkCanvas->flush()
drawInSurface(_skSurface, _width, _height, _wrapperContext);

_skContext->flush();
eglSwapBuffers(_glDisplay, _glSurface))

Here is a screenshot of how this looks - simulator on the left, device on the right - The circle is rendered using a shader, while everything else is rendered using drawing operations and paths. As you might be able to see on the device part, there are some indications of some of the paths drawn.

screenshots.png

Christian

Brian Salomon

unread,
Sep 15, 2021, 10:21:04 AM9/15/21
to skia-d...@googlegroups.com
From Skia's perspective specifying 0 and 1 samples is the same. We assume it is a non-MSAA single sampled target either way,.

Are those other widgets each in their own TextureViews? I'm wondering if the rendering is going to the wrong place. I don't know enough about TextureView but I'd expect you'd want to extract (or set?) a GL texture ID for the TextureView and then use SkSurface::MakeFromBackendTexture rather than SkSurface::MakeFromBackendRenderTarget.

Brian

Christian Falch

unread,
Sep 15, 2021, 11:38:58 AM9/15/21
to skia-discuss
Hi,

Thanks again for replying. 

When setting up our rendering pipeline on Android we've tried to follow how the Mono project's SkiaSharp is set up. They're also supporting multiple TextureViews at the same time on Android and are setting up in the same way as we do.

This is where they're using the SurfaceTexture to create an OpenGL surface:


And this is the corresponding setup for the Skia part where they use GRBackendRenderTarget to create the Skia Surface using the frame buffer binding of the current context.

So it seems like the model we've gone for should be valid although the colors are still getting messed up for all regular drawing operations.

I've tested rendering multiple TextureViews to the same screen using shaders, and that works out without any issues.

Any other ideas would be appreciated! :) :) 

Christian

Christian Falch

unread,
Sep 15, 2021, 11:55:27 AM9/15/21
to skia-discuss
OK! Found the issue - it was when colors where converted from Javascript through React Native that things went wrong do to a specific platform constraint on Android / React Native. 

Thanks so much for trying to help out, and sorry for using your time.

Christian

Reply all
Reply to author
Forward
0 new messages