Skip to content

Commit de165a3

Browse files
authored
fix(🗑️): slightly adjusted heuristics about native Skia resources to the GC (#3499)
1 parent 1ff4de3 commit de165a3

File tree

9 files changed

+124
-17
lines changed

9 files changed

+124
-17
lines changed

packages/skia/cpp/api/JsiSkAnimatedImage.h

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
#pragma once
22

3+
#include <algorithm>
4+
#include <cmath>
5+
#include <limits>
36
#include <memory>
47
#include <string>
58
#include <utility>
@@ -63,7 +66,72 @@ class JsiSkAnimatedImage
6366
: JsiSkWrappingSkPtrHostObject<SkAnimatedImage>(std::move(context),
6467
std::move(image)) {}
6568

66-
size_t getMemoryPressure() const override { return 8192; }
69+
size_t getMemoryPressure() const override {
70+
auto animation = getObject();
71+
if (!animation) {
72+
return 0;
73+
}
74+
75+
const auto safeMul = [](size_t a, size_t b) {
76+
if (a == 0 || b == 0) {
77+
return static_cast<size_t>(0);
78+
}
79+
if (std::numeric_limits<size_t>::max() / a < b) {
80+
return std::numeric_limits<size_t>::max();
81+
}
82+
return a * b;
83+
};
84+
85+
const auto safeAdd = [](size_t a, size_t b) {
86+
if (std::numeric_limits<size_t>::max() - a < b) {
87+
return std::numeric_limits<size_t>::max();
88+
}
89+
return a + b;
90+
};
91+
92+
SkRect bounds = animation->getBounds();
93+
auto width = std::max<SkScalar>(0, bounds.width());
94+
auto height = std::max<SkScalar>(0, bounds.height());
95+
size_t frameWidth =
96+
static_cast<size_t>(std::ceil(static_cast<double>(width)));
97+
size_t frameHeight =
98+
static_cast<size_t>(std::ceil(static_cast<double>(height)));
99+
100+
size_t frameBytes = safeMul(safeMul(frameWidth, frameHeight),
101+
static_cast<size_t>(4)); // RGBA bytes
102+
if (frameBytes == 0) {
103+
if (auto frame = animation->getCurrentFrame()) {
104+
auto frameInfo = frame->imageInfo();
105+
size_t bytesPerPixel = static_cast<size_t>(frameInfo.bytesPerPixel());
106+
if (bytesPerPixel == 0) {
107+
bytesPerPixel = 4;
108+
}
109+
frameBytes =
110+
safeMul(safeMul(static_cast<size_t>(frame->width()),
111+
static_cast<size_t>(frame->height())),
112+
bytesPerPixel);
113+
}
114+
}
115+
116+
if (frameBytes == 0) {
117+
return 0;
118+
}
119+
120+
int frameCount = animation->getFrameCount();
121+
if (frameCount <= 0) {
122+
frameCount = 1;
123+
}
124+
125+
// Animated images keep display, decoding, and restore frames resident.
126+
size_t cachedFrames =
127+
static_cast<size_t>(std::min(frameCount, 3)); // triple buffering
128+
size_t estimated = safeMul(frameBytes, cachedFrames);
129+
130+
// Include codec/metadata overhead.
131+
estimated = safeAdd(estimated, 256 * 1024);
132+
133+
return estimated;
134+
}
67135

68136
std::string getObjectType() const override { return "JsiSkAnimatedImage"; }
69137
};

packages/skia/cpp/api/JsiSkImageFilter.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class JsiSkImageFilter : public JsiSkWrappingSkPtrHostObject<SkImageFilter> {
2525
: JsiSkWrappingSkPtrHostObject<SkImageFilter>(std::move(context),
2626
std::move(imageFilter)) {}
2727

28-
size_t getMemoryPressure() const override { return 4096; }
28+
size_t getMemoryPressure() const override { return 1024 * 1024; }
2929

3030
std::string getObjectType() const override { return "JsiSkImageFilter"; }
3131

packages/skia/cpp/api/JsiSkParagraph.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ class JsiSkParagraph
171171
JSI_EXPORT_FUNC(JsiSkParagraph, getLineMetrics),
172172
JSI_EXPORT_FUNC(JsiSkParagraph, dispose))
173173

174-
size_t getMemoryPressure() const override { return 8192; }
174+
size_t getMemoryPressure() const override { return 1024 * 1024; }
175175

176176
std::string getObjectType() const override { return "JsiSkParagraph"; }
177177

packages/skia/cpp/api/JsiSkParagraphBuilder.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ class JsiSkParagraphBuilder : public JsiSkHostObject {
110110
JSI_EXPORT_FUNC(JsiSkParagraphBuilder, pushStyle),
111111
JSI_EXPORT_FUNC(JsiSkParagraphBuilder, pop))
112112

113-
size_t getMemoryPressure() const override { return 4096; }
113+
size_t getMemoryPressure() const override { return 1024 * 1024; }
114114

115115
std::string getObjectType() const override { return "JsiSkParagraphBuilder"; }
116116

packages/skia/cpp/api/JsiSkParagraphBuilderFactory.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class JsiSkParagraphBuilderFactory : public JsiSkHostObject {
4747

4848
JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkParagraphBuilderFactory, Make))
4949

50-
size_t getMemoryPressure() const override { return 3072; }
50+
size_t getMemoryPressure() const override { return 1024 * 1024; }
5151

5252
std::string getObjectType() const override {
5353
return "JsiSkParagraphBuilderFactory";

packages/skia/cpp/api/JsiSkPictureRecorder.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,7 @@ class JsiSkPictureRecorder
5757
finishRecordingAsPicture),
5858
JSI_EXPORT_FUNC(JsiSkPictureRecorder, dispose))
5959

60-
size_t getMemoryPressure() const override {
61-
return sizeof(SkPictureRecorder);
62-
}
60+
size_t getMemoryPressure() const override { return 1024 * 1024; }
6361

6462
std::string getObjectType() const override { return "JsiSkPictureRecorder"; }
6563

packages/skia/cpp/api/JsiSkShader.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class JsiSkShader : public JsiSkWrappingSkPtrHostObject<SkShader> {
2626
: JsiSkWrappingSkPtrHostObject<SkShader>(std::move(context),
2727
std::move(shader)) {}
2828

29-
size_t getMemoryPressure() const override { return 4096; }
29+
size_t getMemoryPressure() const override { return 1024 * 1024; }
3030

3131
std::string getObjectType() const override { return "JsiSkShader"; }
3232

packages/skia/cpp/api/JsiSkSurface.h

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#pragma once
22

3+
#include <algorithm>
4+
#include <limits>
35
#include <memory>
46
#include <utility>
57

@@ -116,15 +118,54 @@ class JsiSkSurface : public JsiSkWrappingSkPtrHostObject<SkSurface> {
116118

117119
size_t getMemoryPressure() const override {
118120
auto surface = getObject();
119-
if (!surface)
121+
if (!surface) {
120122
return 0;
123+
}
124+
125+
const auto safeAdd = [](size_t a, size_t b) {
126+
if (std::numeric_limits<size_t>::max() - a < b) {
127+
return std::numeric_limits<size_t>::max();
128+
}
129+
return a + b;
130+
};
131+
132+
SkImageInfo info = surface->imageInfo();
133+
size_t pixelBytes = info.computeMinByteSize();
134+
if (pixelBytes == 0) {
135+
auto width = std::max(info.width(), surface->width());
136+
auto height = std::max(info.height(), surface->height());
137+
int bytesPerPixel = info.bytesPerPixel();
138+
if (bytesPerPixel <= 0) {
139+
bytesPerPixel = 4;
140+
}
141+
if (width > 0 && height > 0) {
142+
pixelBytes = static_cast<size_t>(width) * static_cast<size_t>(height) *
143+
static_cast<size_t>(bytesPerPixel);
144+
}
145+
}
146+
147+
if (pixelBytes == 0) {
148+
return 0;
149+
}
150+
151+
size_t estimated = pixelBytes;
152+
153+
auto canvas = surface->getCanvas();
154+
const bool isGpuBacked =
155+
surface->recordingContext() != nullptr || surface->recorder() != nullptr ||
156+
(canvas && (canvas->recordingContext() != nullptr ||
157+
canvas->recorder() != nullptr));
158+
159+
if (isGpuBacked) {
160+
// Account for a resolved texture and depth/stencil attachments.
161+
estimated = safeAdd(estimated, pixelBytes); // resolve/texture copy
162+
estimated = safeAdd(estimated, pixelBytes / 2); // depth-stencil buffers
163+
}
164+
165+
// Add a small overhead buffer for bookkeeping allocations.
166+
estimated = safeAdd(estimated, 128 * 1024);
121167

122-
// Surface memory is primarily the pixel buffer: width × height × bytes per
123-
// pixel
124-
int width = surface->width();
125-
int height = surface->height();
126-
// Assume 4 bytes per pixel (RGBA) for most surfaces
127-
return width * height * 4;
168+
return estimated;
128169
}
129170

130171
std::string getObjectType() const override { return "JsiSkSurface"; }

packages/skia/cpp/api/JsiSkiaContext.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class JsiSkiaContext : public JsiSkWrappingSharedPtrHostObject<WindowContext> {
5555
std::shared_ptr<WindowContext> ctx)
5656
: JsiSkWrappingSharedPtrHostObject(std::move(context), std::move(ctx)) {}
5757

58-
size_t getMemoryPressure() const override { return 8192; }
58+
size_t getMemoryPressure() const override { return 10 * 1024 * 1024; }
5959

6060
std::string getObjectType() const override { return "JsiSkiaContext"; }
6161

0 commit comments

Comments
 (0)