Skip to content

Commit

Permalink
fix(🤖): bug fixes in OpenGL renderer (#2759)
Browse files Browse the repository at this point in the history
This fixes a couple of issues where the OpenGL renderer could get in an inconsistent state.
  • Loading branch information
wcandillon authored Nov 21, 2024
1 parent 516bdb5 commit d314745
Show file tree
Hide file tree
Showing 16 changed files with 85 additions and 117 deletions.
14 changes: 10 additions & 4 deletions apps/paper/src/Examples/API/Data.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React from "react";
import { useWindowDimensions } from "react-native";
import {
AlphaType,
Canvas,
Expand Down Expand Up @@ -28,12 +27,19 @@ const img = Skia.Image.MakeImage(
256 * 4
)!;

const surface = Skia.Surface.MakeOffscreen(256, 256)!;
const canvas = surface.getCanvas();
canvas.drawColor(Skia.Color("cyan"));
const paint = Skia.Paint();
paint.setColor(Skia.Color("magenta"));
canvas.drawCircle(128, 128, 128, paint);
const img1 = surface.makeImageSnapshot().makeNonTextureImage();

export const Data = () => {
const { width } = useWindowDimensions();
const SIZE = width;
return (
<Canvas style={{ width: SIZE, height: SIZE }}>
<Canvas style={{ width: 256, height: 512 }}>
<Image image={img} x={0} y={0} width={256} height={256} fit="cover" />
<Image image={img1} x={0} y={256} width={256} height={256} fit="cover" />
</Canvas>
);
};
4 changes: 2 additions & 2 deletions packages/skia/android/cpp/jni/include/JniSkiaBaseView.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ class JniSkiaBaseView {
_skiaAndroidView->surfaceAvailable(surface, width, height);
}

virtual void surfaceSizeChanged(int width, int height) {
_skiaAndroidView->surfaceSizeChanged(width, height);
virtual void surfaceSizeChanged(jobject surface, int width, int height) {
_skiaAndroidView->surfaceSizeChanged(surface, width, height);
}

virtual void surfaceDestroyed() { _skiaAndroidView->surfaceDestroyed(); }
Expand Down
4 changes: 2 additions & 2 deletions packages/skia/android/cpp/jni/include/JniSkiaDomView.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ class JniSkiaDomView : public jni::HybridClass<JniSkiaDomView>,
JniSkiaBaseView::surfaceAvailable(surface, width, height);
}

void surfaceSizeChanged(int width, int height) override {
JniSkiaBaseView::surfaceSizeChanged(width, height);
void surfaceSizeChanged(jobject surface, int width, int height) override {
JniSkiaBaseView::surfaceSizeChanged(surface, width, height);
}

void surfaceDestroyed() override { JniSkiaBaseView::surfaceDestroyed(); }
Expand Down
4 changes: 2 additions & 2 deletions packages/skia/android/cpp/jni/include/JniSkiaPictureView.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ class JniSkiaPictureView : public jni::HybridClass<JniSkiaPictureView>,
JniSkiaBaseView::surfaceAvailable(surface, width, height);
}

void surfaceSizeChanged(int width, int height) override {
JniSkiaBaseView::surfaceSizeChanged(width, height);
void surfaceSizeChanged(jobject surface, int width, int height) override {
JniSkiaBaseView::surfaceSizeChanged(surface, width, height);
}

void surfaceDestroyed() override { JniSkiaBaseView::surfaceDestroyed(); }
Expand Down
4 changes: 3 additions & 1 deletion packages/skia/android/cpp/rnskia-android/OpenGLContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,11 @@ class OpenGLContext {
#endif
}

// TODO: remove width, height
std::unique_ptr<WindowContext> MakeWindow(ANativeWindow *window, int width,
int height) {
return std::make_unique<OpenGLWindowContext>(this, window, width, height);
return std::make_unique<OpenGLWindowContext>(
_directContext, _glDisplay.get(), _glContext.get(), window);
}

private:
Expand Down
69 changes: 20 additions & 49 deletions packages/skia/android/cpp/rnskia-android/OpenGLWindowContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,74 +16,45 @@ namespace RNSkia {

sk_sp<SkSurface> OpenGLWindowContext::getSurface() {
if (_skSurface == nullptr) {

struct ReleaseContext {
std::unique_ptr<gl::Surface> surface = nullptr;
};

if (!_window) {
throw std::runtime_error("No native window provided");
}
auto releaseCtx = new ReleaseContext();
releaseCtx->surface =
_context->_glDisplay->makeWindowSurface(_context->_glConfig, _window);
if (!releaseCtx->surface) {
throw std::runtime_error("Failed to create window surface");
}
_glSurface = releaseCtx->surface.get();

// Now make this one current
auto success = _context->_glContext->makeCurrent(releaseCtx->surface.get());
if (!success) {
throw std::runtime_error("Failed to make window surface current");
}

// Set up parameters for the render target so that it
// matches the underlying OpenGL context.
GrGLFramebufferInfo fboInfo;

// We pass 0 as the framebuffer id, since the
// underlying Skia GrGlGpu will read this when wrapping the context in the
// render target and the GrGlGpu object.
fboInfo.fFBOID = 0;
fboInfo.fFormat = 0x8058; // GL_RGBA8

_glContext->makeCurrent(_glSurface.get());
GLint stencil;
glGetIntegerv(GL_STENCIL_BITS, &stencil);

GLint samples;
glGetIntegerv(GL_SAMPLES, &samples);

auto colorType = kN32_SkColorType;
auto colorType = kRGBA_8888_SkColorType;

auto maxSamples =
_context->_directContext->maxSurfaceSampleCountForColorType(colorType);
_directContext->maxSurfaceSampleCountForColorType(colorType);

if (samples > maxSamples) {
samples = maxSamples;
}

auto renderTarget = GrBackendRenderTargets::MakeGL(_width, _height, samples,
stencil, fboInfo);

SkSurfaceProps props(0, kUnknown_SkPixelGeometry);

// Create surface object
GrGLFramebufferInfo fbInfo;
fbInfo.fFBOID = 0;
fbInfo.fFormat = GR_GL_RGBA8;
// fbInfo.fProtected =
// skgpu::Protected(fDisplayParams.fCreateProtectedNativeBackend);

auto width = ANativeWindow_getWidth(_window);
auto height = ANativeWindow_getHeight(_window);
auto backendRT =
GrBackendRenderTargets::MakeGL(width, height, samples, stencil, fbInfo);
sk_sp<SkColorSpace> colorSpace(nullptr);
SkSurfaceProps surfaceProps(0, kRGB_H_SkPixelGeometry);
_skSurface = SkSurfaces::WrapBackendRenderTarget(
_context->_directContext.get(), renderTarget,
kBottomLeft_GrSurfaceOrigin, colorType, nullptr, &props,
[](void *addr) {
auto releaseCtx = reinterpret_cast<ReleaseContext *>(addr);
delete releaseCtx;
},
reinterpret_cast<void *>(releaseCtx));
_directContext.get(), backendRT, kBottomLeft_GrSurfaceOrigin,
kRGBA_8888_SkColorType, colorSpace, &surfaceProps);
}
return _skSurface;
}

void OpenGLWindowContext::present() {
_context->_glContext->makeCurrent(_glSurface);
_context->_directContext->flushAndSubmit();
_glContext->makeCurrent(_glSurface.get());
// TODO: is flushAndSubmit needed here?
_directContext->flushAndSubmit();
_glSurface->present();
}

Expand Down
30 changes: 14 additions & 16 deletions packages/skia/android/cpp/rnskia-android/OpenGLWindowContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,16 @@

namespace RNSkia {

class OpenGLContext;

class OpenGLWindowContext : public WindowContext {
public:
OpenGLWindowContext(OpenGLContext *context, ANativeWindow *window, int width,
int height)
: _context(context), _window(window), _width(width), _height(height) {
OpenGLWindowContext(sk_sp<GrDirectContext> directContext,
gl::Display *display, gl::Context *glContext,
ANativeWindow *window)
: _directContext(directContext), _display(display), _glContext(glContext),
_window(window) {
ANativeWindow_acquire(_window);
auto config = display->chooseConfig();
_glSurface = display->makeWindowSurface(config, _window);
}

~OpenGLWindowContext() {
Expand All @@ -51,23 +53,19 @@ class OpenGLWindowContext : public WindowContext {

void present() override;

void resize(int width, int height) override {
_skSurface = nullptr;
_width = width;
_height = height;
}
int getWidth() override { return ANativeWindow_getWidth(_window); };

int getWidth() override { return _width; };
int getHeight() override { return ANativeWindow_getHeight(_window); };

int getHeight() override { return _height; };
void resize(int width, int height) override { _skSurface = nullptr; }

private:
OpenGLContext *_context;
sk_sp<GrDirectContext> _directContext;
gl::Display *_display;
ANativeWindow *_window;
sk_sp<SkSurface> _skSurface = nullptr;
gl::Surface *_glSurface = nullptr;
int _width = 0;
int _height = 0;
gl::Context *_glContext = nullptr;
std::unique_ptr<gl::Surface> _glSurface = nullptr;
};

} // namespace RNSkia
6 changes: 3 additions & 3 deletions packages/skia/android/cpp/rnskia-android/RNSkAndroidView.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class RNSkBaseAndroidView {

virtual void surfaceDestroyed() = 0;

virtual void surfaceSizeChanged(int width, int height) = 0;
virtual void surfaceSizeChanged(jobject surface, int width, int height) = 0;

virtual float getPixelDensity() = 0;

Expand Down Expand Up @@ -50,9 +50,9 @@ class RNSkAndroidView : public T, public RNSkBaseAndroidView {
->surfaceDestroyed();
}

void surfaceSizeChanged(int width, int height) override {
void surfaceSizeChanged(jobject surface, int width, int height) override {
std::static_pointer_cast<RNSkOpenGLCanvasProvider>(T::getCanvasProvider())
->surfaceSizeChanged(width, height);
->surfaceSizeChanged(surface, width, height);
// This is only need for the first time to frame, this renderImmediate call
// will invoke updateTexImage for the previous frame
RNSkView::renderImmediate();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ bool RNSkOpenGLCanvasProvider::renderToCanvas(

void RNSkOpenGLCanvasProvider::surfaceAvailable(jobject jSurfaceTexture,
int width, int height) {
// If the surface is 0, we can skip it
if (width == 0 && height == 0) {
return;
}
// Create renderer!
JNIEnv *env = facebook::jni::Environment::current();

Expand Down Expand Up @@ -118,17 +122,22 @@ void RNSkOpenGLCanvasProvider::surfaceDestroyed() {
}
}

void RNSkOpenGLCanvasProvider::surfaceSizeChanged(int width, int height) {
void RNSkOpenGLCanvasProvider::surfaceSizeChanged(jobject jSurfaceTexture,
int width, int height) {
if (width == 0 && height == 0) {
// Setting width/height to zero is nothing we need to care about when
// it comes to invalidating the surface.
return;
}

// Recreate RenderContext surface based on size change???
_surfaceHolder->resize(width, height);
if (_surfaceHolder == nullptr) {
_surfaceHolder = nullptr;
surfaceAvailable(jSurfaceTexture, width, height);
} else {
_surfaceHolder->resize(width, height);
}

// Redraw after size change
_requestRedraw();
}
} // namespace RNSkia
} // namespace RNSkia
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class RNSkOpenGLCanvasProvider

void surfaceDestroyed();

void surfaceSizeChanged(int width, int height);
void surfaceSizeChanged(jobject jSurface, int width, int height);

private:
std::unique_ptr<WindowContext> _surfaceHolder = nullptr;
Expand Down
4 changes: 4 additions & 0 deletions packages/skia/android/cpp/rnskia-android/gl/Display.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ class Display {

bool isValid() const { return _display != EGL_NO_DISPLAY; }

void clearContext() {
eglMakeCurrent(_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}

EGLConfig chooseConfig() {

EGLint att[] = {EGL_RENDERABLE_TYPE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int h
return;
}
Log.i(tag, "onSurfaceTextureSizeChanged " + width + "/" + height);
surfaceSizeChanged(width, height);
surfaceSizeChanged(surface, width, height);
}

@Override
Expand All @@ -82,18 +82,18 @@ public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return false;
}

//private long _prevTimestamp = 0;
private long _prevTimestamp = 0;
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
// long timestamp = surface.getTimestamp();
// long frameDuration = (timestamp - _prevTimestamp)/1000000;
// Log.i(tag, "onSurfaceTextureUpdated "+frameDuration+"ms");
// _prevTimestamp = timestamp;
long timestamp = surface.getTimestamp();
long frameDuration = (timestamp - _prevTimestamp)/1000000;
Log.i(tag, "onSurfaceTextureUpdated "+frameDuration+"ms");
_prevTimestamp = timestamp;
}

protected abstract void surfaceAvailable(Object surface, int width, int height);

protected abstract void surfaceSizeChanged(int width, int height);
protected abstract void surfaceSizeChanged(Object surface, int width, int height);

protected abstract void surfaceDestroyed();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ protected void finalize() throws Throwable {

protected native void surfaceAvailable(Object surface, int width, int height);

protected native void surfaceSizeChanged(int width, int height);
protected native void surfaceSizeChanged(Object surface, int width, int height);

protected native void surfaceDestroyed();

Expand All @@ -37,8 +37,6 @@ protected void finalize() throws Throwable {

protected native void setDebugMode(boolean show);

protected native void updateTouchPoints(double[] points);

protected native void registerView(int nativeId);

protected native void unregisterView();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ protected void finalize() throws Throwable {

protected native void surfaceAvailable(Object surface, int width, int height);

protected native void surfaceSizeChanged(int width, int height);
protected native void surfaceSizeChanged(Object surface, int width, int height);

protected native void surfaceDestroyed();

Expand All @@ -36,8 +36,6 @@ protected void finalize() throws Throwable {

protected native void setDebugMode(boolean show);

protected native void updateTouchPoints(double[] points);

protected native void registerView(int nativeId);

protected native void unregisterView();
Expand Down

This file was deleted.

Loading

0 comments on commit d314745

Please sign in to comment.