Skip to content

Commit

Permalink
fix(🍏): Fix performance regression on iOS (#2744)
Browse files Browse the repository at this point in the history
fixes #2743

In v1.5.3, we introduced a regression where we would request the next frame twice leading to frame drop in half.
  • Loading branch information
wcandillon authored Nov 18, 2024
1 parent ef5d52e commit 53a8db5
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 75 deletions.
42 changes: 21 additions & 21 deletions packages/skia/cpp/rnskia/DawnContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ struct AsyncContext {
};

struct SharedTextureContext {
wgpu::SharedTextureMemory sharedTextureMemory;
wgpu::Texture texture;
wgpu::SharedTextureMemory sharedTextureMemory;
wgpu::Texture texture;
};

static void
Expand Down Expand Up @@ -111,7 +111,7 @@ class DawnContext {
int height = static_cast<int>(IOSurfaceGetHeight(ioSurface));
#else
wgpu::SharedTextureMemoryAHardwareBufferDescriptor platformDesc;
auto ahb = (AHardwareBuffer*)buffer;
auto ahb = (AHardwareBuffer *)buffer;
platformDesc.handle = ahb;
platformDesc.useExternalFormat = true;
AHardwareBuffer_Desc adesc;
Expand All @@ -122,13 +122,16 @@ class DawnContext {

wgpu::SharedTextureMemoryDescriptor desc = {};
desc.nextInChain = &platformDesc;
wgpu::SharedTextureMemory memory = backendContext.fDevice.ImportSharedTextureMemory(&desc);
wgpu::SharedTextureMemory memory =
backendContext.fDevice.ImportSharedTextureMemory(&desc);

wgpu::TextureDescriptor textureDesc;
textureDesc.format = DawnUtils::PreferredTextureFormat;
textureDesc.dimension = wgpu::TextureDimension::e2D;
textureDesc.usage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopySrc;
textureDesc.size = {static_cast<uint32_t>(width), static_cast<uint32_t>(height), 1};
textureDesc.usage =
wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopySrc;
textureDesc.size = {static_cast<uint32_t>(width),
static_cast<uint32_t>(height), 1};

wgpu::Texture texture = memory.CreateTexture(&textureDesc);

Expand All @@ -137,26 +140,23 @@ class DawnContext {
beginAccessDesc.fenceCount = 0;
bool success = memory.BeginAccess(texture, &beginAccessDesc);

if (success) {
skgpu::graphite::BackendTexture betFromView = skgpu::graphite::BackendTextures::MakeDawn(texture.Get());
auto result = SkImages::WrapTexture(
getRecorder(),
betFromView,
DawnUtils::PreferedColorType,
kPremul_SkAlphaType,
nullptr,
[](void* context) {
if (success) {
skgpu::graphite::BackendTexture betFromView =
skgpu::graphite::BackendTextures::MakeDawn(texture.Get());
auto result = SkImages::WrapTexture(
getRecorder(), betFromView, DawnUtils::PreferedColorType,
kPremul_SkAlphaType, nullptr,
[](void *context) {
auto ctx = static_cast<SharedTextureContext *>(context);
wgpu::SharedTextureMemoryEndAccessState endState = {};
ctx->sharedTextureMemory.EndAccess(ctx->texture, &endState);
delete ctx;
},
new SharedTextureContext{memory, texture}
);
return result;
}
},
new SharedTextureContext{memory, texture});
return result;
}
if (!success) {
return nullptr;
return nullptr;
}
return nullptr;
}
Expand Down
3 changes: 2 additions & 1 deletion packages/skia/cpp/rnskia/DawnUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ createDawnBackendContext(dawn::native::Instance *instance) {
features.push_back(wgpu::FeatureName::SharedTextureMemoryIOSurface);
}
#else
if (adapter.HasFeature(wgpu::FeatureName::SharedTextureMemoryAHardwareBuffer)) {
if (adapter.HasFeature(
wgpu::FeatureName::SharedTextureMemoryAHardwareBuffer)) {
features.push_back(wgpu::FeatureName::SharedTextureMemoryAHardwareBuffer);
}
#endif
Expand Down
3 changes: 1 addition & 2 deletions packages/skia/ios/RNSkia-iOS/RNSkMetalCanvasProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ class RNSkMetalCanvasProvider : public RNSkia::RNSkCanvasProvider {

private:
std::shared_ptr<RNSkia::RNSkPlatformContext> _context;
float _width = -1;
float _height = -1;
std::unique_ptr<RNSkia::WindowContext> _ctx = nullptr;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunguarded-availability-new"
CAMetalLayer *_layer;
Expand Down
41 changes: 18 additions & 23 deletions packages/skia/ios/RNSkia-iOS/RNSkMetalCanvasProvider.mm
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,23 @@
/**
Returns the scaled width of the view
*/
float RNSkMetalCanvasProvider::getScaledWidth() { return _width; };
float RNSkMetalCanvasProvider::getScaledWidth() {
return _ctx ? _ctx->getWidth() : -1;
};

/**
Returns the scaled height of the view
*/
float RNSkMetalCanvasProvider::getScaledHeight() { return _height; };
float RNSkMetalCanvasProvider::getScaledHeight() {
return _ctx ? _ctx->getHeight() : -1;
};

/**
Render to a canvas
*/
bool RNSkMetalCanvasProvider::renderToCanvas(
const std::function<void(SkCanvas *)> &cb) {
if (_width <= 0 || _height <= 0) {
if (!_ctx) {
return false;
}

Expand All @@ -72,33 +76,24 @@
// rendering and not wait until later - we've seen some example of memory
// usage growing very fast in the simulator without this.
@autoreleasepool {
id<CAMetalDrawable> currentDrawable = [_layer nextDrawable];
if (currentDrawable == nullptr) {
return false;
}
#if defined(SK_GRAPHITE)
auto ctx = RNSkia::DawnContext::getInstance().MakeWindow(
(__bridge void *)_layer, _width, _height);
#else
auto ctx = MetalContext::getInstance().MakeWindow(_layer, _width, _height);
#endif
auto skSurface = ctx->getSurface();
SkCanvas *canvas = skSurface->getCanvas();
auto surface = _ctx->getSurface();
auto canvas = surface->getCanvas();
cb(canvas);

if (auto dContext = GrAsDirectContext(skSurface->recordingContext())) {
dContext->flushAndSubmit();
}

ctx->present();
_ctx->present();
}
return true;
};

void RNSkMetalCanvasProvider::setSize(int width, int height) {
_layer.frame = CGRectMake(0, 0, width, height);
_width = width * _context->getPixelDensity();
_height = height * _context->getPixelDensity();
auto w = width * _context->getPixelDensity();
auto h = height * _context->getPixelDensity();
#if defined(SK_GRAPHITE)
_ctx = RNSkia::DawnContext::getInstance().MakeWindow((__bridge void *)_layer,
w, h);
#else
_ctx = MetalContext::getInstance().MakeWindow(_layer, w, h);
#endif
_requestRedraw();
}

Expand Down
30 changes: 22 additions & 8 deletions packages/skia/ios/RNSkia-iOS/SkiaMetalSurfaceFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,19 @@
#pragma clang diagnostic ignored "-Wdocumentation"

#import "include/core/SkCanvas.h"
#import "include/core/SkColorSpace.h"

#import <CoreMedia/CMSampleBuffer.h>
#import <CoreVideo/CVMetalTextureCache.h>

#import <include/gpu/ganesh/GrBackendSurface.h>
#import <include/gpu/ganesh/GrDirectContext.h>
#import <include/gpu/ganesh/SkImageGanesh.h>
#import <include/gpu/ganesh/SkSurfaceGanesh.h>
#import <include/gpu/ganesh/mtl/GrMtlBackendContext.h>
#import <include/gpu/ganesh/mtl/GrMtlBackendSurface.h>
#import <include/gpu/ganesh/mtl/GrMtlDirectContext.h>
#import <include/gpu/ganesh/mtl/SkSurfaceMetal.h>

#pragma clang diagnostic pop

Expand All @@ -26,9 +36,6 @@ class SkiaMetalSurfaceFactory {
friend class IOSSkiaContext;

public:
static sk_sp<SkSurface> makeWindowedSurface(SkiaMetalContext *context,
id<MTLTexture> texture, int width,
int height);
static sk_sp<SkSurface> makeOffscreenSurface(id<MTLDevice> device,
SkiaMetalContext *context,
int width, int height);
Expand Down Expand Up @@ -76,9 +83,16 @@ class IOSSkiaContext : public RNSkia::WindowContext {
}

// Get the texture from the drawable
_skSurface = SkiaMetalSurfaceFactory::makeWindowedSurface(
_context, _currentDrawable.texture, _layer.drawableSize.width,
_layer.drawableSize.height);
GrMtlTextureInfo fbInfo;
fbInfo.fTexture.retain((__bridge void *)_currentDrawable.texture);

GrBackendRenderTarget backendRT = GrBackendRenderTargets::MakeMtl(
_layer.drawableSize.width, _layer.drawableSize.height, fbInfo);

_skSurface = SkSurfaces::WrapBackendRenderTarget(
_context->skContext.get(), backendRT, kTopLeft_GrSurfaceOrigin,
kBGRA_8888_SkColorType, nullptr, nullptr);

return _skSurface;
}

Expand All @@ -95,9 +109,9 @@ class IOSSkiaContext : public RNSkia::WindowContext {

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

int getWidth() override { return _layer.frame.size.width; };
int getWidth() override { return _layer.frame.size.width * _layer.contentsScale; };

int getHeight() override { return _layer.frame.size.height; };
int getHeight() override { return _layer.frame.size.height * _layer.contentsScale; };

private:
SkiaMetalContext *_context;
Expand Down
20 changes: 0 additions & 20 deletions packages/skia/ios/RNSkia-iOS/SkiaMetalSurfaceFactory.mm
Original file line number Diff line number Diff line change
Expand Up @@ -46,26 +46,6 @@
return std::make_unique<IOSSkiaContext>(context, texture, width, height);
}

sk_sp<SkSurface> SkiaMetalSurfaceFactory::makeWindowedSurface(
SkiaMetalContext *context, id<MTLTexture> texture, int width, int height) {
GrMtlTextureInfo fbInfo;
fbInfo.fTexture.retain((__bridge void *)texture);

GrBackendRenderTarget backendRT =
GrBackendRenderTargets::MakeMtl(width, height, fbInfo);

auto skSurface = SkSurfaces::WrapBackendRenderTarget(
context->skContext.get(), backendRT, kTopLeft_GrSurfaceOrigin,
kBGRA_8888_SkColorType, nullptr, nullptr);

if (skSurface == nullptr || skSurface->getCanvas() == nullptr) {
RNSkia::RNSkLogger::logToConsole(
"Skia surface could not be created from parameters.");
return nullptr;
}
return skSurface;
}

sk_sp<SkSurface> SkiaMetalSurfaceFactory::makeOffscreenSurface(
id<MTLDevice> device, SkiaMetalContext *context, int width, int height) {

Expand Down

0 comments on commit 53a8db5

Please sign in to comment.