-
Notifications
You must be signed in to change notification settings - Fork 483
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add per-thread shared Skia contextes on iOS (#1775)
Offscreen and onscreen surfaces created on the same thread share the same Skia context. Code has been refactored to have somewhat of a symmetry with our OpenGL integration on Android.
- Loading branch information
1 parent
c6b9fd7
commit 14fb038
Showing
9 changed files
with
167 additions
and
150 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
#import <MetalKit/MetalKit.h> | ||
|
||
#pragma clang diagnostic push | ||
#pragma clang diagnostic ignored "-Wdocumentation" | ||
|
||
#import "SkCanvas.h" | ||
#import <include/gpu/GrDirectContext.h> | ||
|
||
#pragma clang diagnostic pop | ||
|
||
using SkiaMetalContext = struct SkiaMetalContext { | ||
id<MTLCommandQueue> commandQueue = nullptr; | ||
sk_sp<GrDirectContext> skContext = nullptr; | ||
}; | ||
|
||
class ThreadContextHolder { | ||
public: | ||
static thread_local SkiaMetalContext ThreadSkiaMetalContext; | ||
}; | ||
|
||
class SkiaMetalSurfaceFactory { | ||
public: | ||
static sk_sp<SkSurface> makeWindowedSurface(id<MTLTexture> texture, int width, | ||
int height); | ||
static sk_sp<SkSurface> makeOffscreenSurface(int width, int height); | ||
|
||
private: | ||
static id<MTLDevice> device; | ||
static bool | ||
createSkiaDirectContextIfNecessary(SkiaMetalContext *threadContext); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
#import <RNSkLog.h> | ||
|
||
#include <SkiaMetalSurfaceFactory.h> | ||
|
||
#pragma clang diagnostic push | ||
#pragma clang diagnostic ignored "-Wdocumentation" | ||
|
||
#import "SkCanvas.h" | ||
#import "SkColorSpace.h" | ||
#import "SkSurface.h" | ||
|
||
#import <include/gpu/GrBackendSurface.h> | ||
#import <include/gpu/GrDirectContext.h> | ||
#import <include/gpu/ganesh/SkSurfaceGanesh.h> | ||
|
||
#pragma clang diagnostic pop | ||
|
||
thread_local SkiaMetalContext ThreadContextHolder::ThreadSkiaMetalContext; | ||
|
||
struct OffscreenRenderContext { | ||
id<MTLTexture> texture; | ||
|
||
OffscreenRenderContext(id<MTLDevice> device, | ||
sk_sp<GrDirectContext> skiaContext, | ||
id<MTLCommandQueue> commandQueue, int width, | ||
int height) { | ||
// Create a Metal texture descriptor | ||
MTLTextureDescriptor *textureDescriptor = [MTLTextureDescriptor | ||
texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm | ||
width:width | ||
height:height | ||
mipmapped:NO]; | ||
textureDescriptor.usage = | ||
MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead; | ||
texture = [device newTextureWithDescriptor:textureDescriptor]; | ||
} | ||
}; | ||
|
||
id<MTLDevice> SkiaMetalSurfaceFactory::device = MTLCreateSystemDefaultDevice(); | ||
|
||
bool SkiaMetalSurfaceFactory::createSkiaDirectContextIfNecessary( | ||
SkiaMetalContext *skiaMetalContext) { | ||
if (skiaMetalContext->skContext == nullptr) { | ||
skiaMetalContext->commandQueue = | ||
id<MTLCommandQueue>(CFRetain((GrMTLHandle)[device newCommandQueue])); | ||
skiaMetalContext->skContext = GrDirectContext::MakeMetal( | ||
(__bridge void *)device, | ||
(__bridge void *)skiaMetalContext->commandQueue); | ||
if (skiaMetalContext->skContext == nullptr) { | ||
RNSkia::RNSkLogger::logToConsole("Couldn't create a Skia Metal Context"); | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
|
||
sk_sp<SkSurface> | ||
SkiaMetalSurfaceFactory::makeWindowedSurface(id<MTLTexture> texture, int width, | ||
int height) { | ||
// Get render context for current thread | ||
if (!SkiaMetalSurfaceFactory::createSkiaDirectContextIfNecessary( | ||
&ThreadContextHolder::ThreadSkiaMetalContext)) { | ||
return nullptr; | ||
} | ||
GrMtlTextureInfo fbInfo; | ||
fbInfo.fTexture.retain((__bridge void *)texture); | ||
|
||
GrBackendRenderTarget backendRT(width, height, 1, fbInfo); | ||
|
||
auto skSurface = SkSurfaces::WrapBackendRenderTarget( | ||
ThreadContextHolder::ThreadSkiaMetalContext.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(int width, | ||
int height) { | ||
if (!SkiaMetalSurfaceFactory::createSkiaDirectContextIfNecessary( | ||
&ThreadContextHolder::ThreadSkiaMetalContext)) { | ||
return nullptr; | ||
} | ||
auto ctx = new OffscreenRenderContext( | ||
device, ThreadContextHolder::ThreadSkiaMetalContext.skContext, | ||
ThreadContextHolder::ThreadSkiaMetalContext.commandQueue, width, height); | ||
|
||
// Create a GrBackendTexture from the Metal texture | ||
GrMtlTextureInfo info; | ||
info.fTexture.retain((__bridge void *)ctx->texture); | ||
GrBackendTexture backendTexture(width, height, GrMipMapped::kNo, info); | ||
|
||
// Create a SkSurface from the GrBackendTexture | ||
auto surface = SkSurfaces::WrapBackendTexture( | ||
ThreadContextHolder::ThreadSkiaMetalContext.skContext.get(), | ||
backendTexture, kTopLeft_GrSurfaceOrigin, 0, kBGRA_8888_SkColorType, | ||
nullptr, nullptr, | ||
[](void *addr) { delete (OffscreenRenderContext *)addr; }, ctx); | ||
|
||
return surface; | ||
} |
Oops, something went wrong.