Add MTLBinaryArchive support to iOS Metal build

Change-Id: I7a4f58e4fc1fc18c42de372dd480e0681000e2f2
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/333758
Commit-Queue: Jim Van Verth <jvanverth@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Reviewed-by: Chinmay Garde <chinmaygarde@google.com>
Reviewed-by: Adlai Holler <adlai@google.com>
This commit is contained in:
Jim Van Verth 2020-11-19 12:59:06 -05:00 committed by Skia Commit-Bot
parent 133724cc02
commit 9e64047a04
8 changed files with 127 additions and 6 deletions

View File

@ -7,6 +7,12 @@ This file includes a list of high level updates for each milestone release.
Milestone 89
------------
* Add MTLBinaryArchive parameter to GrMtlBackendContext. This allows
Skia to cache PipelineStates in the given archive for faster
shader compiles on future runs. The client must handle loading and
saving of the archive.
https://review.skia.org/333758
* Deprecated enum SkYUVAInfo::PlanarConfig has been removed.
https://review.skia.org/334161

View File

@ -15,6 +15,7 @@
struct SK_API GrMtlBackendContext {
sk_cf_obj<GrMTLHandle> fDevice;
sk_cf_obj<GrMTLHandle> fQueue;
sk_cf_obj<GrMTLHandle> fBinaryArchive;
};
#endif

View File

@ -29,6 +29,28 @@ typedef const void* GrMTLHandle;
#define SK_API_AVAILABLE_CA_METAL_LAYER SK_API_AVAILABLE(macos(10.11), ios(8.0))
#endif // TARGET_OS_SIMULATOR
#if defined(SK_BUILD_FOR_MAC)
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 110000
#define GR_METAL_SDK_VERSION 230
#elif __MAC_OS_X_VERSION_MAX_ALLOWED >= 101500
#define GR_METAL_SDK_VERSION 220
#elif __MAC_OS_X_VERSION_MAX_ALLOWED >= 101400
#define GR_METAL_SDK_VERSION 210
#else
#error Must use at least 10.14 SDK to build Metal backend for MacOS
#endif
#else
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 || __TV_OS_VERSION_MAX_ALLOWED >= 140000
#define GR_METAL_SDK_VERSION 230
#elif __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 || __TV_OS_VERSION_MAX_ALLOWED >= 130000
#define GR_METAL_SDK_VERSION 220
#elif __IPHONE_OS_VERSION_MAX_ALLOWED >= 120000 || __TV_OS_VERSION_MAX_ALLOWED >= 120000
#define GR_METAL_SDK_VERSION 210
#else
#error Must use at least 12.00 SDK to build Metal backend for iOS
#endif
#endif
/**
* Types for interacting with Metal resources created externally to Skia.
* This is used by GrBackendObjects.
@ -43,6 +65,7 @@ public:
return fTexture == that.fTexture;
}
};
#endif
#endif

View File

@ -84,6 +84,11 @@ public:
const SkIPoint& dstPoint) override;
SkSL::Compiler* shaderCompiler() const { return fCompiler.get(); }
#if GR_METAL_SDK_VERSION >= 230
id<MTLBinaryArchive> binaryArchive() const SK_API_AVAILABLE(macos(11.0), ios(14.0)) {
return fBinaryArchive;
}
#endif
void submit(GrOpsRenderPass* renderPass) override;
@ -112,7 +117,7 @@ public:
private:
GrMtlGpu(GrDirectContext*, const GrContextOptions&, id<MTLDevice>,
id<MTLCommandQueue>, MTLFeatureSet);
id<MTLCommandQueue>, GrMTLHandle binaryArchive, MTLFeatureSet);
void destroyResources();
@ -282,6 +287,9 @@ private:
SkDeque fOutstandingCommandBuffers;
std::unique_ptr<SkSL::Compiler> fCompiler;
#if GR_METAL_SDK_VERSION >= 230
id<MTLBinaryArchive> fBinaryArchive SK_API_AVAILABLE(macos(11.0), ios(14.0));
#endif
GrMtlResourceProvider fResourceProvider;
GrStagingBufferManager fStagingBufferManager;

View File

@ -123,7 +123,8 @@ sk_sp<GrGpu> GrMtlGpu::Make(const GrMtlBackendContext& context, const GrContextO
if (!get_feature_set(device, &featureSet)) {
return nullptr;
}
return sk_sp<GrGpu>(new GrMtlGpu(direct, options, device, queue, featureSet));
return sk_sp<GrGpu>(new GrMtlGpu(direct, options, device, queue, context.fBinaryArchive.get(),
featureSet));
}
// This constant determines how many OutstandingCommandBuffers are allocated together as a block in
@ -133,7 +134,8 @@ sk_sp<GrGpu> GrMtlGpu::Make(const GrMtlBackendContext& context, const GrContextO
static const int kDefaultOutstandingAllocCnt = 8;
GrMtlGpu::GrMtlGpu(GrDirectContext* direct, const GrContextOptions& options,
id<MTLDevice> device, id<MTLCommandQueue> queue, MTLFeatureSet featureSet)
id<MTLDevice> device, id<MTLCommandQueue> queue, GrMTLHandle binaryArchive,
MTLFeatureSet featureSet)
: INHERITED(direct)
, fDevice(device)
, fQueue(queue)
@ -145,6 +147,11 @@ GrMtlGpu::GrMtlGpu(GrDirectContext* direct, const GrContextOptions& options,
fCaps = fMtlCaps;
fCompiler.reset(new SkSL::Compiler(fMtlCaps->shaderCaps()));
fCurrentCmdBuffer = GrMtlCommandBuffer::Make(fQueue);
#if GR_METAL_SDK_VERSION >= 230
if (@available(macOS 11.0, iOS 14.0, *)) {
fBinaryArchive = (__bridge id<MTLBinaryArchive>)(binaryArchive);
}
#endif
}
GrMtlGpu::~GrMtlGpu() {

View File

@ -506,14 +506,37 @@ GrMtlPipelineState* GrMtlPipelineStateBuilder::finalize(GrRenderTarget* renderTa
SkASSERT(pipelineDescriptor.colorAttachments[0]);
NSError* error = nil;
#if GR_METAL_SDK_VERSION >= 230
if (@available(macOS 11.0, iOS 14.0, *)) {
id<MTLBinaryArchive> archive = fGpu->binaryArchive();
if (archive) {
NSArray* archiveArray = [NSArray arrayWithObjects:archive, nil];
pipelineDescriptor.binaryArchives = archiveArray;
BOOL result;
{
TRACE_EVENT0("skia.gpu", "addRenderPipelineFunctionsWithDescriptor");
result = [archive addRenderPipelineFunctionsWithDescriptor: pipelineDescriptor
error: &error];
}
if (!result && error) {
SkDebugf("Error storing pipeline: %s\n",
[[error localizedDescription] cStringUsingEncoding: NSASCIIStringEncoding]);
}
}
}
#endif
id<MTLRenderPipelineState> pipelineState;
{
TRACE_EVENT0("skia.gpu", "newRenderPipelineStateWithDescriptor");
#if defined(SK_BUILD_FOR_MAC)
id<MTLRenderPipelineState> pipelineState = GrMtlNewRenderPipelineStateWithDescriptor(
pipelineState = GrMtlNewRenderPipelineStateWithDescriptor(
fGpu->device(), pipelineDescriptor, &error);
#else
id<MTLRenderPipelineState> pipelineState =
pipelineState =
[fGpu->device() newRenderPipelineStateWithDescriptor: pipelineDescriptor
error: &error];
#endif
}
if (error) {
SkDebugf("Error creating pipeline: %s\n",
[[error localizedDescription] cStringUsingEncoding: NSASCIIStringEncoding]);

View File

@ -30,6 +30,8 @@ public:
void activate(bool isActive) override;
protected:
static NSURL* CacheURL();
MetalWindowContext(const DisplayParams&);
// This should be called by subclass constructor. It is also called when window/display
// parameters change. This will in turn call onInitializeContext().
@ -47,6 +49,9 @@ protected:
id<MTLCommandQueue> fQueue;
CAMetalLayer* fMetalLayer;
GrMTLHandle fDrawableHandle;
#if GR_METAL_SDK_VERSION >= 230
id<MTLBinaryArchive> fPipelineArchive SK_API_AVAILABLE(macos(11.0), ios(14.0));
#endif
};
} // namespace sk_app

View File

@ -29,6 +29,13 @@ MetalWindowContext::MetalWindowContext(const DisplayParams& params)
fDisplayParams.fMSAASampleCount = GrNextPow2(fDisplayParams.fMSAASampleCount);
}
NSURL* MetalWindowContext::CacheURL() {
NSArray *paths = [[NSFileManager defaultManager] URLsForDirectory:NSCachesDirectory
inDomains:NSUserDomainMask];
NSURL* cachePath = [paths objectAtIndex:0];
return [cachePath URLByAppendingPathComponent:@"binaryArchive.metallib"];
}
void MetalWindowContext::initializeContext() {
SkASSERT(!fContext);
@ -49,9 +56,33 @@ void MetalWindowContext::initializeContext() {
fValid = this->onInitializeContext();
#if GR_METAL_SDK_VERSION >= 230
if (@available(macOS 11.0, iOS 14.0, *)) {
MTLBinaryArchiveDescriptor* desc = [MTLBinaryArchiveDescriptor new];
desc.url = CacheURL(); // try to load
NSError* error;
fPipelineArchive = [fDevice newBinaryArchiveWithDescriptor:desc error:&error];
if (!fPipelineArchive) {
desc.url = nil; // create new
NSError* error;
fPipelineArchive = [fDevice newBinaryArchiveWithDescriptor:desc error:&error];
if (!fPipelineArchive) {
SkDebugf("Error creating MTLBinaryArchive:\n%s\n",
error.debugDescription.UTF8String);
}
}
[desc release];
}
#endif
GrMtlBackendContext backendContext = {};
backendContext.fDevice.retain((__bridge GrMTLHandle)fDevice);
backendContext.fQueue.retain((__bridge GrMTLHandle)fQueue);
#if GR_METAL_SDK_VERSION >= 230
if (@available(macOS 11.0, iOS 14.0, *)) {
backendContext.fBinaryArchive.retain((__bridge GrMTLHandle)fPipelineArchive);
}
#endif
fContext = GrDirectContext::MakeMetal(backendContext, fDisplayParams.fGrContextOptions);
if (!fContext && fDisplayParams.fMSAASampleCount > 1) {
fDisplayParams.fMSAASampleCount /= 2;
@ -72,6 +103,11 @@ void MetalWindowContext::destroyContext() {
fMetalLayer = nil;
fValid = false;
#if GR_METAL_SDK_VERSION >= 230
if (@available(macOS 11.0, iOS 14.0, *)) {
[fPipelineArchive release];
}
#endif
[fQueue release];
[fDevice release];
}
@ -131,7 +167,19 @@ void MetalWindowContext::setDisplayParams(const DisplayParams& params) {
}
void MetalWindowContext::activate(bool isActive) {
// save/restore here
// serialize pipeline archive
if (!isActive) {
#if GR_METAL_SDK_VERSION >= 230
if (@available(macOS 11.0, iOS 14.0, *)) {
NSError* error;
[fPipelineArchive serializeToURL:CacheURL() error:&error];
if (error) {
SkDebugf("Error storing MTLBinaryArchive:\n%s\n",
error.debugDescription.UTF8String);
}
}
#endif
}
}
} //namespace sk_app