Skip to content

Commit a2c6a3e

Browse files
Preparation to prefetch image requests in batch mode (#53490)
Summary: Pull Request resolved: #53490 Changelog: [Internal] Sending individual image prefetch request on Android over JNI is causing measurable performance regression. The idea here is batch all image prefetch request for a given shadowNodeTree and then flush it all at once - **DONE** in the next change. Another optimization we should consider is to execute the batch on `n imagePrefetchRequest` off the JavaScript thread `mqt_v_js` and instead on e.g. the UiThread (on which currently Android Image UI initiates image resource downloads) Reviewed By: lenaic Differential Revision: D81186916 fbshipit-source-id: f8b24e70f2ded237be96bdb973b72acbbb8b1c20
1 parent b2d25c8 commit a2c6a3e

File tree

7 files changed

+50
-40
lines changed

7 files changed

+50
-40
lines changed

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -984,10 +984,9 @@ public void runGuarded() {
984984
* by an ImageView.
985985
*/
986986
@UnstableReactNativeAPI
987-
public void experimental_prefetchResource(
988-
String componentName, int surfaceId, int reactTag, ReadableMapBuffer params) {
989-
mMountingManager.experimental_prefetchResource(
990-
mReactApplicationContext, componentName, surfaceId, reactTag, params);
987+
public void experimental_prefetchResources(String componentName, ReadableMapBuffer params) {
988+
mMountingManager.experimental_prefetchResources(
989+
mReactApplicationContext, componentName, params);
991990
}
992991

993992
void setBinding(FabricUIManagerBinding binding) {

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.kt

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -331,23 +331,19 @@ internal class MountingManager(
331331
*
332332
* @param reactContext
333333
* @param componentName
334-
* @param surfaceId surface ID
335-
* @param reactTag reactTag that should be set as ID of the view instance
336334
* @param params prefetch request params defined in C++
337335
*/
338336
@Suppress("FunctionName")
339337
@AnyThread
340338
@UnstableReactNativeAPI
341-
fun experimental_prefetchResource(
339+
fun experimental_prefetchResources(
342340
reactContext: ReactContext?,
343341
componentName: String?,
344-
surfaceId: Int,
345-
reactTag: Int,
346342
params: MapBuffer?,
347343
) {
348344
viewManagerRegistry
349345
.get(checkNotNull(componentName))
350-
.experimental_prefetchResource(reactContext, surfaceId, reactTag, params)
346+
.experimental_prefetchResources(reactContext, params)
351347
}
352348

353349
fun enqueuePendingEvent(

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -488,13 +488,10 @@ public void onSurfaceStopped(int surfaceId) {
488488
* ViewManager.
489489
*
490490
* @param reactContext {@link com.facebook.react.bridge.ReactContext} used for the view.
491-
* @param surfaceId {@link int} surface ID
492-
* @param reactTag reactTag that should be set as ID of the view instance
493491
* @param params {@link MapBuffer} prefetch request params defined in C++
494492
*/
495493
@UnstableReactNativeAPI
496-
public void experimental_prefetchResource(
497-
ReactContext reactContext, int surfaceId, int reactTag, MapBuffer params) {
494+
public void experimental_prefetchResources(ReactContext reactContext, MapBuffer params) {
498495
return;
499496
}
500497

packages/react-native/ReactCommon/react/renderer/imagemanager/platform/android/react/renderer/imagemanager/ImageFetcher.cpp

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,35 +9,31 @@
99

1010
#include <react/common/mapbuffer/JReadableMapBuffer.h>
1111
#include <react/renderer/imagemanager/conversions.h>
12-
#include <utility>
1312

1413
namespace facebook::react {
1514

1615
ImageRequest ImageFetcher::requestImage(
1716
const ImageSource& imageSource,
1817
SurfaceId surfaceId,
1918
const ImageRequestParams& imageRequestParams,
20-
Tag tag) const {
19+
Tag tag) {
20+
items_.emplace_back(ImageRequestItem{
21+
.imageSource = imageSource,
22+
.surfaceId = surfaceId,
23+
.imageRequestParams = imageRequestParams,
24+
.tag = tag});
25+
2126
auto fabricUIManager_ =
2227
contextContainer_->at<jni::global_ref<jobject>>("FabricUIManager");
23-
static auto requestImage =
28+
static auto prefetchResources =
2429
fabricUIManager_->getClass()
25-
->getMethod<void(
26-
std::string, SurfaceId, Tag, JReadableMapBuffer::javaobject)>(
27-
"experimental_prefetchResource");
28-
29-
auto serializedImageRequest =
30-
serializeImageRequest(imageSource, imageRequestParams);
30+
->getMethod<void(std::string, JReadableMapBuffer::javaobject)>(
31+
"experimental_prefetchResources");
3132

3233
auto readableMapBuffer =
33-
JReadableMapBuffer::createWithContents(std::move(serializedImageRequest));
34-
35-
requestImage(
36-
fabricUIManager_,
37-
"RCTImageView",
38-
surfaceId,
39-
tag,
40-
readableMapBuffer.get());
34+
JReadableMapBuffer::createWithContents(serializeImageRequests(items_));
35+
items_.clear();
36+
prefetchResources(fabricUIManager_, "RCTImageView", readableMapBuffer.get());
4137

4238
auto telemetry = std::make_shared<ImageTelemetry>(surfaceId);
4339

packages/react-native/ReactCommon/react/renderer/imagemanager/platform/android/react/renderer/imagemanager/ImageFetcher.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,10 @@ class ImageFetcher {
2222
const ImageSource& imageSource,
2323
SurfaceId surfaceId,
2424
const ImageRequestParams& imageRequestParams,
25-
Tag tag) const;
25+
Tag tag);
2626

2727
private:
28+
std::vector<ImageRequestItem> items_;
2829
std::shared_ptr<const ContextContainer> contextContainer_;
2930
};
3031
} // namespace facebook::react

packages/react-native/ReactCommon/react/renderer/imagemanager/platform/android/react/renderer/imagemanager/ImageRequestParams.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,11 @@ class ImageRequestParams {
9191
}
9292
};
9393

94+
struct ImageRequestItem {
95+
ImageSource imageSource;
96+
SurfaceId surfaceId{};
97+
ImageRequestParams imageRequestParams;
98+
Tag tag{};
99+
};
100+
94101
} // namespace facebook::react

packages/react-native/ReactCommon/react/renderer/imagemanager/platform/android/react/renderer/imagemanager/conversions.h

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77

88
#pragma once
99

10-
#include <string>
11-
1210
#include <react/renderer/core/graphicsConversions.h>
1311
#include <react/renderer/imagemanager/ImageRequestParams.h>
1412
#include <react/renderer/imagemanager/primitives.h>
1513
#include <react/renderer/mapbuffer/MapBuffer.h>
1614
#include <react/renderer/mapbuffer/MapBufferBuilder.h>
15+
#include <string>
16+
#include <vector>
1717

1818
namespace facebook::react {
1919

@@ -51,6 +51,8 @@ constexpr MapBuffer::Key IS_KEY_FADE_DURATION = 11;
5151
constexpr MapBuffer::Key IS_KEY_PROGRESSIVE_RENDERING_ENABLED = 12;
5252
constexpr MapBuffer::Key IS_KEY_LOADING_INDICATOR_SRC = 13;
5353
constexpr MapBuffer::Key IS_KEY_ANALYTIC_TAG = 14;
54+
constexpr MapBuffer::Key IS_KEY_SURFACE_ID = 15;
55+
constexpr MapBuffer::Key IS_KEY_TAG = 16;
5456

5557
inline void serializeImageSource(
5658
MapBufferBuilder& builder,
@@ -91,14 +93,26 @@ inline void serializeImageRequestParams(
9193
builder.putString(IS_KEY_ANALYTIC_TAG, imageRequestParams.analyticTag);
9294
}
9395

96+
inline MapBuffer serializeImageRequest(const ImageRequestItem& item) {
97+
auto builder = MapBufferBuilder();
98+
serializeImageSource(builder, item.imageSource);
99+
serializeImageRequestParams(builder, item.imageRequestParams);
100+
builder.putInt(IS_KEY_SURFACE_ID, item.surfaceId);
101+
builder.putInt(IS_KEY_TAG, item.tag);
102+
return builder.build();
103+
}
104+
94105
} // namespace
95106

96-
inline MapBuffer serializeImageRequest(
97-
const ImageSource& imageSource,
98-
const ImageRequestParams& imageRequestParams) {
99-
auto builder = MapBufferBuilder();
100-
serializeImageSource(builder, imageSource);
101-
serializeImageRequestParams(builder, imageRequestParams);
107+
inline MapBuffer serializeImageRequests(
108+
const std::vector<ImageRequestItem>& items) {
109+
std::vector<MapBuffer> mapBufferList;
110+
mapBufferList.reserve(items.size());
111+
for (const auto& item : items) {
112+
mapBufferList.emplace_back(serializeImageRequest(item));
113+
}
114+
MapBufferBuilder builder;
115+
builder.putMapBufferList(0, mapBufferList);
102116
return builder.build();
103117
}
104118

0 commit comments

Comments
 (0)