Skip to content

Commit ba1db84

Browse files
authored
fix(🤖): Remove internal draw loop (#2763)
On Android it removes the need to use JNI back and forth for each frame.
1 parent 1352eca commit ba1db84

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+256
-766
lines changed

‎apps/paper/ios/paper.xcodeproj/project.pbxproj

+65-65
Large diffs are not rendered by default.

‎packages/skia/android/CMakeLists.txt

-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ add_library(
8787

8888
"${PROJECT_SOURCE_DIR}/../cpp/rnskia/RNSkManager.cpp"
8989
"${PROJECT_SOURCE_DIR}/../cpp/rnskia/RNSkDomView.cpp"
90-
"${PROJECT_SOURCE_DIR}/../cpp/rnskia/RNSkDispatchQueue.cpp"
9190

9291
"${PROJECT_SOURCE_DIR}/../cpp/rnskia/dom/base/DrawingContext.cpp"
9392
"${PROJECT_SOURCE_DIR}/../cpp/rnskia/dom/base/ConcatablePaint.cpp"

‎packages/skia/android/cpp/jni/JniPlatformContext.cpp

-49
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,6 @@ using TSelf = jni::local_ref<JniPlatformContext::jhybriddata>;
6363
void JniPlatformContext::registerNatives() {
6464
registerHybrid({
6565
makeNativeMethod("initHybrid", JniPlatformContext::initHybrid),
66-
makeNativeMethod("notifyDrawLoop",
67-
JniPlatformContext::notifyDrawLoopExternal),
68-
makeNativeMethod("notifyTaskReady",
69-
JniPlatformContext::notifyTaskReadyExternal),
7066
});
7167
}
7268

@@ -134,51 +130,6 @@ sk_sp<SkImage> JniPlatformContext::takeScreenshotFromViewTag(size_t tag) {
134130
return skImage;
135131
}
136132

137-
void JniPlatformContext::startDrawLoop() {
138-
jni::ThreadScope ts;
139-
// Start drawing loop
140-
static auto method =
141-
javaPart_->getClass()->getMethod<void(void)>("beginDrawLoop");
142-
method(javaPart_.get());
143-
}
144-
145-
void JniPlatformContext::stopDrawLoop() {
146-
jni::ThreadScope ts;
147-
// Stop drawing loop
148-
static auto method =
149-
javaPart_->getClass()->getMethod<void(void)>("endDrawLoop");
150-
method(javaPart_.get());
151-
}
152-
153-
void JniPlatformContext::notifyDrawLoopExternal() {
154-
jni::ThreadScope ts;
155-
_onNotifyDrawLoop();
156-
}
157-
158-
void JniPlatformContext::runTaskOnMainThread(std::function<void()> task) {
159-
_taskMutex->lock();
160-
_taskCallbacks.push(task);
161-
_taskMutex->unlock();
162-
163-
// Notify Java that task is ready
164-
static auto method = javaPart_->getClass()->getMethod<void(void)>(
165-
"notifyTaskReadyOnMainThread");
166-
method(javaPart_.get());
167-
}
168-
169-
void JniPlatformContext::notifyTaskReadyExternal() {
170-
jni::ThreadScope ts;
171-
_taskMutex->lock();
172-
auto task = _taskCallbacks.front();
173-
if (task != nullptr) {
174-
_taskCallbacks.pop();
175-
_taskMutex->unlock();
176-
task();
177-
} else {
178-
_taskMutex->unlock();
179-
}
180-
}
181-
182133
void JniPlatformContext::performStreamOperation(
183134
const std::string &sourceUri,
184135
const std::function<void(std::unique_ptr<SkStreamAsset>)> &op) {

‎packages/skia/android/cpp/jni/include/JniPlatformContext.h

+1-17
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,6 @@ class JniPlatformContext : public jni::HybridClass<JniPlatformContext> {
3333

3434
void raiseError(const std::exception &err);
3535

36-
void startDrawLoop();
37-
void stopDrawLoop();
38-
39-
void notifyDrawLoopExternal();
40-
4136
void notifyTaskReadyExternal();
4237

4338
void runTaskOnMainThread(std::function<void()> task);
@@ -46,10 +41,6 @@ class JniPlatformContext : public jni::HybridClass<JniPlatformContext> {
4641

4742
sk_sp<SkImage> takeScreenshotFromViewTag(size_t tag);
4843

49-
void setOnNotifyDrawLoop(const std::function<void(void)> &callback) {
50-
_onNotifyDrawLoop = callback;
51-
}
52-
5344
jni::global_ref<jobject> createVideo(const std::string &url);
5445

5546
private:
@@ -58,16 +49,9 @@ class JniPlatformContext : public jni::HybridClass<JniPlatformContext> {
5849

5950
float _pixelDensity;
6051

61-
std::function<void(void)> _onNotifyDrawLoop;
62-
63-
std::queue<std::function<void()>> _taskCallbacks;
64-
65-
std::shared_ptr<std::mutex> _taskMutex;
66-
6752
explicit JniPlatformContext(
6853
jni::alias_ref<JniPlatformContext::jhybridobject> jThis,
6954
const float pixelDensity)
70-
: _taskMutex(std::make_shared<std::mutex>()),
71-
javaPart_(jni::make_global(jThis)), _pixelDensity(pixelDensity) {}
55+
: javaPart_(jni::make_global(jThis)), _pixelDensity(pixelDensity) {}
7256
};
7357
} // namespace RNSkia

‎packages/skia/android/cpp/jni/include/JniSkiaBaseView.h

-2
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@ class JniSkiaBaseView {
3939

4040
virtual void surfaceDestroyed() { _skiaAndroidView->surfaceDestroyed(); }
4141

42-
virtual void setMode(std::string mode) { _skiaAndroidView->setMode(mode); }
43-
4442
virtual void setDebugMode(bool show) {
4543
_skiaAndroidView->setShowDebugInfo(show);
4644
}

‎packages/skia/android/cpp/jni/include/JniSkiaDomView.h

-3
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ class JniSkiaDomView : public jni::HybridClass<JniSkiaDomView>,
4040
makeNativeMethod("surfaceDestroyed", JniSkiaDomView::surfaceDestroyed),
4141
makeNativeMethod("surfaceSizeChanged",
4242
JniSkiaDomView::surfaceSizeChanged),
43-
makeNativeMethod("setMode", JniSkiaDomView::setMode),
4443
makeNativeMethod("setDebugMode", JniSkiaDomView::setDebugMode),
4544
makeNativeMethod("registerView", JniSkiaDomView::registerView),
4645
makeNativeMethod("unregisterView", JniSkiaDomView::unregisterView)});
@@ -57,8 +56,6 @@ class JniSkiaDomView : public jni::HybridClass<JniSkiaDomView>,
5756

5857
void surfaceDestroyed() override { JniSkiaBaseView::surfaceDestroyed(); }
5958

60-
void setMode(std::string mode) override { JniSkiaBaseView::setMode(mode); }
61-
6259
void setDebugMode(bool show) override { JniSkiaBaseView::setDebugMode(show); }
6360

6461
void registerView(int nativeId) override {

‎packages/skia/android/cpp/jni/include/JniSkiaManager.h

-2
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,6 @@ class JniSkiaManager : public jni::HybridClass<JniSkiaManager> {
5353
std::shared_ptr<RNSkManager> getSkiaManager() { return _skManager; }
5454

5555
void invalidate() {
56-
_context->stopDrawLoop();
57-
_context->notifyDrawLoop(true);
5856
_skManager = nullptr;
5957
_context = nullptr;
6058
}

‎packages/skia/android/cpp/jni/include/JniSkiaPictureView.h

-3
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ class JniSkiaPictureView : public jni::HybridClass<JniSkiaPictureView>,
4141
JniSkiaPictureView::surfaceDestroyed),
4242
makeNativeMethod("surfaceSizeChanged",
4343
JniSkiaPictureView::surfaceSizeChanged),
44-
makeNativeMethod("setMode", JniSkiaPictureView::setMode),
4544
makeNativeMethod("setDebugMode", JniSkiaPictureView::setDebugMode),
4645
makeNativeMethod("registerView", JniSkiaPictureView::registerView),
4746
makeNativeMethod("unregisterView",
@@ -59,8 +58,6 @@ class JniSkiaPictureView : public jni::HybridClass<JniSkiaPictureView>,
5958

6059
void surfaceDestroyed() override { JniSkiaBaseView::surfaceDestroyed(); }
6160

62-
void setMode(std::string mode) override { JniSkiaBaseView::setMode(mode); }
63-
6461
void setDebugMode(bool show) override { JniSkiaBaseView::setDebugMode(show); }
6562

6663
void registerView(int nativeId) override {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#pragma once
2+
3+
#include <android/looper.h>
4+
#include <unistd.h>
5+
6+
class MainThreadDispatcher {
7+
private:
8+
ALooper *mainLooper;
9+
int messagePipe[2];
10+
std::queue<std::function<void()>> taskQueue;
11+
std::mutex queueMutex;
12+
13+
static constexpr int LOOPER_ID_MAIN = 1;
14+
15+
void processMessages() {
16+
std::lock_guard<std::mutex> lock(queueMutex);
17+
while (!taskQueue.empty()) {
18+
auto task = taskQueue.front();
19+
taskQueue.pop();
20+
task();
21+
}
22+
}
23+
24+
public:
25+
static MainThreadDispatcher &getInstance() {
26+
static MainThreadDispatcher instance;
27+
return instance;
28+
}
29+
30+
void post(std::function<void()> task) {
31+
// TODO: this is disabled for now but we can clean this up
32+
// if (ALooper_forThread() == mainLooper) {
33+
// task();
34+
// } else {
35+
{
36+
std::lock_guard<std::mutex> lock(queueMutex);
37+
taskQueue.push(std::move(task));
38+
}
39+
char wake = 1;
40+
write(messagePipe[1], &wake, 1);
41+
// }
42+
}
43+
44+
~MainThreadDispatcher() {
45+
close(messagePipe[0]);
46+
close(messagePipe[1]);
47+
}
48+
49+
private:
50+
MainThreadDispatcher() {
51+
mainLooper = ALooper_forThread();
52+
if (!mainLooper) {
53+
mainLooper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
54+
}
55+
56+
pipe(messagePipe);
57+
58+
ALooper_addFd(
59+
mainLooper, messagePipe[0], LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT,
60+
[](int fd, int events, void *data) -> int {
61+
char buf[1];
62+
read(fd, buf, 1);
63+
auto dispatcher = static_cast<MainThreadDispatcher *>(data);
64+
dispatcher->processMessages();
65+
return 1;
66+
},
67+
this);
68+
}
69+
};

‎packages/skia/android/cpp/rnskia-android/RNSkAndroidPlatformContext.h

+4-11
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include "AHardwareBufferUtils.h"
1919
#include "JniPlatformContext.h"
20+
#include "MainThreadDispatcher.h"
2021
#include "RNSkAndroidVideo.h"
2122
#include "RNSkPlatformContext.h"
2223

@@ -37,13 +38,9 @@ class RNSkAndroidPlatformContext : public RNSkPlatformContext {
3738
std::shared_ptr<facebook::react::CallInvoker> jsCallInvoker)
3839
: RNSkPlatformContext(runtime, jsCallInvoker,
3940
jniPlatformContext->getPixelDensity()),
40-
_jniPlatformContext(jniPlatformContext) {
41-
// Hook onto the notify draw loop callback in the platform context
42-
jniPlatformContext->setOnNotifyDrawLoop(
43-
[this]() { notifyDrawLoop(false); });
44-
}
41+
_jniPlatformContext(jniPlatformContext) {}
4542

46-
~RNSkAndroidPlatformContext() { stopDrawLoop(); }
43+
~RNSkAndroidPlatformContext() {}
4744

4845
void performStreamOperation(
4946
const std::string &sourceUri,
@@ -163,17 +160,13 @@ class RNSkAndroidPlatformContext : public RNSkPlatformContext {
163160
}
164161

165162
void runOnMainThread(std::function<void()> task) override {
166-
_jniPlatformContext->runTaskOnMainThread(task);
163+
MainThreadDispatcher::getInstance().post(std::move(task));
167164
}
168165

169166
sk_sp<SkImage> takeScreenshotFromViewTag(size_t tag) override {
170167
return _jniPlatformContext->takeScreenshotFromViewTag(tag);
171168
}
172169

173-
void startDrawLoop() override { _jniPlatformContext->startDrawLoop(); }
174-
175-
void stopDrawLoop() override { _jniPlatformContext->stopDrawLoop(); }
176-
177170
private:
178171
JniPlatformContext *_jniPlatformContext;
179172
};

‎packages/skia/android/cpp/rnskia-android/RNSkAndroidView.h

+3-13
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ class RNSkBaseAndroidView {
1919

2020
virtual float getPixelDensity() = 0;
2121

22-
virtual void setMode(std::string mode) = 0;
23-
2422
virtual void setShowDebugInfo(bool show) = 0;
2523

2624
virtual void viewDidUnmount() = 0;
@@ -42,7 +40,7 @@ class RNSkAndroidView : public T, public RNSkBaseAndroidView {
4240

4341
// Try to render directly when the surface has been set so that
4442
// we don't have to wait until the draw loop returns.
45-
RNSkView::renderImmediate();
43+
RNSkView::redraw();
4644
}
4745

4846
void surfaceDestroyed() override {
@@ -55,24 +53,16 @@ class RNSkAndroidView : public T, public RNSkBaseAndroidView {
5553
->surfaceSizeChanged(surface, width, height);
5654
// This is only need for the first time to frame, this renderImmediate call
5755
// will invoke updateTexImage for the previous frame
58-
RNSkView::renderImmediate();
56+
RNSkView::redraw();
5957
}
6058

6159
float getPixelDensity() override {
6260
return T::getPlatformContext()->getPixelDensity();
6361
}
6462

65-
void setMode(std::string mode) override {
66-
if (mode.compare("continuous") == 0) {
67-
T::setDrawingMode(RNSkDrawingMode::Continuous);
68-
} else {
69-
T::setDrawingMode(RNSkDrawingMode::Default);
70-
}
71-
}
72-
7363
void setShowDebugInfo(bool show) override { T::setShowDebugOverlays(show); }
7464

75-
void viewDidUnmount() override { T::endDrawingLoop(); }
65+
void viewDidUnmount() override {}
7666

7767
std::shared_ptr<RNSkView> getSkiaView() override {
7868
return T::shared_from_this();

‎packages/skia/android/cpp/rnskia-android/RNSkOpenGLCanvasProvider.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ bool RNSkOpenGLCanvasProvider::renderToCanvas(
6464

6565
// Swap buffers and show on screen
6666
_surfaceHolder->present();
67-
6867
return true;
6968
} else {
7069
// the render context did not provide a surface

0 commit comments

Comments
 (0)