Update rive-cpp to 2.0 version
[platform/core/uifw/rive-tizen.git] / submodule / skia / tools / sk_app / MetalWindowContext.mm
1 /*
2  * Copyright 2019 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7
8 #include "include/core/SkCanvas.h"
9 #include "include/core/SkSurface.h"
10 #include "include/gpu/GrBackendSurface.h"
11 #include "include/gpu/GrDirectContext.h"
12 #include "include/gpu/mtl/GrMtlBackendContext.h"
13 #include "include/gpu/mtl/GrMtlTypes.h"
14 #include "src/core/SkMathPriv.h"
15 #include "src/gpu/ganesh/GrCaps.h"
16 #include "src/gpu/ganesh/GrDirectContextPriv.h"
17 #include "src/image/SkImage_Base.h"
18 #include "tools/sk_app/MetalWindowContext.h"
19
20 using sk_app::DisplayParams;
21 using sk_app::MetalWindowContext;
22
23 namespace sk_app {
24
25 MetalWindowContext::MetalWindowContext(const DisplayParams& params)
26         : WindowContext(params)
27         , fValid(false)
28         , fDrawableHandle(nil) {
29     fDisplayParams.fMSAASampleCount = GrNextPow2(fDisplayParams.fMSAASampleCount);
30 }
31
32 NSURL* MetalWindowContext::CacheURL() {
33     NSArray *paths = [[NSFileManager defaultManager] URLsForDirectory:NSCachesDirectory
34                                                             inDomains:NSUserDomainMask];
35     NSURL* cachePath = [paths objectAtIndex:0];
36     return [cachePath URLByAppendingPathComponent:@"binaryArchive.metallib"];
37 }
38
39 void MetalWindowContext::initializeContext() {
40     SkASSERT(!fContext);
41
42     fDevice.reset(MTLCreateSystemDefaultDevice());
43     fQueue.reset([*fDevice newCommandQueue]);
44
45     if (fDisplayParams.fMSAASampleCount > 1) {
46         if (@available(macOS 10.11, iOS 9.0, *)) {
47             if (![*fDevice supportsTextureSampleCount:fDisplayParams.fMSAASampleCount]) {
48                 return;
49             }
50         } else {
51             return;
52         }
53     }
54     fSampleCount = fDisplayParams.fMSAASampleCount;
55     fStencilBits = 8;
56
57     fValid = this->onInitializeContext();
58
59 #if GR_METAL_SDK_VERSION >= 230
60     if (fDisplayParams.fEnableBinaryArchive) {
61         if (@available(macOS 11.0, iOS 14.0, *)) {
62             sk_cfp<MTLBinaryArchiveDescriptor*> desc([MTLBinaryArchiveDescriptor new]);
63             (*desc).url = CacheURL(); // try to load
64             NSError* error;
65             fPipelineArchive = [*fDevice newBinaryArchiveWithDescriptor:*desc error:&error];
66             if (!fPipelineArchive) {
67                 (*desc).url = nil; // create new
68                 fPipelineArchive = [*fDevice newBinaryArchiveWithDescriptor:*desc error:&error];
69                 if (!fPipelineArchive) {
70                     SkDebugf("Error creating MTLBinaryArchive:\n%s\n",
71                              error.debugDescription.UTF8String);
72                 }
73             }
74         }
75     } else {
76         if (@available(macOS 11.0, iOS 14.0, *)) {
77             fPipelineArchive = nil;
78         }
79     }
80 #endif
81
82     GrMtlBackendContext backendContext = {};
83     backendContext.fDevice.retain((GrMTLHandle)fDevice.get());
84     backendContext.fQueue.retain((GrMTLHandle)fQueue.get());
85 #if GR_METAL_SDK_VERSION >= 230
86     if (@available(macOS 11.0, iOS 14.0, *)) {
87         backendContext.fBinaryArchive.retain((__bridge GrMTLHandle)fPipelineArchive);
88     }
89 #endif
90     fContext = GrDirectContext::MakeMetal(backendContext, fDisplayParams.fGrContextOptions);
91     if (!fContext && fDisplayParams.fMSAASampleCount > 1) {
92         fDisplayParams.fMSAASampleCount /= 2;
93         this->initializeContext();
94         return;
95     }
96 }
97
98 void MetalWindowContext::destroyContext() {
99     if (fContext) {
100         // in case we have outstanding refs to this (lua?)
101         fContext->abandonContext();
102         fContext.reset();
103     }
104
105     this->onDestroyContext();
106
107     fMetalLayer = nil;
108     fValid = false;
109
110 #if GR_METAL_SDK_VERSION >= 230
111     if (@available(macOS 11.0, iOS 14.0, *)) {
112         [fPipelineArchive release];
113     }
114 #endif
115     fQueue.reset();
116     fDevice.reset();
117 }
118
119 sk_sp<SkSurface> MetalWindowContext::getBackbufferSurface() {
120     sk_sp<SkSurface> surface;
121     if (fContext) {
122         if (fDisplayParams.fDelayDrawableAcquisition) {
123             surface = SkSurface::MakeFromCAMetalLayer(fContext.get(),
124                                                       (__bridge GrMTLHandle)fMetalLayer,
125                                                       kTopLeft_GrSurfaceOrigin, fSampleCount,
126                                                       kBGRA_8888_SkColorType,
127                                                       fDisplayParams.fColorSpace,
128                                                       &fDisplayParams.fSurfaceProps,
129                                                       &fDrawableHandle);
130         } else {
131             id<CAMetalDrawable> currentDrawable = [fMetalLayer nextDrawable];
132
133             GrMtlTextureInfo fbInfo;
134             fbInfo.fTexture.retain(currentDrawable.texture);
135
136             GrBackendRenderTarget backendRT(fWidth,
137                                             fHeight,
138                                             fSampleCount,
139                                             fbInfo);
140
141             surface = SkSurface::MakeFromBackendRenderTarget(fContext.get(), backendRT,
142                                                              kTopLeft_GrSurfaceOrigin,
143                                                              kBGRA_8888_SkColorType,
144                                                              fDisplayParams.fColorSpace,
145                                                              &fDisplayParams.fSurfaceProps);
146
147             fDrawableHandle = CFRetain((GrMTLHandle) currentDrawable);
148         }
149     }
150
151     return surface;
152 }
153
154 void MetalWindowContext::swapBuffers() {
155     id<CAMetalDrawable> currentDrawable = (id<CAMetalDrawable>)fDrawableHandle;
156
157     id<MTLCommandBuffer> commandBuffer([*fQueue commandBuffer]);
158     commandBuffer.label = @"Present";
159
160     [commandBuffer presentDrawable:currentDrawable];
161     [commandBuffer commit];
162     // ARC is off in sk_app, so we need to release the CF ref manually
163     CFRelease(fDrawableHandle);
164     fDrawableHandle = nil;
165 }
166
167 void MetalWindowContext::setDisplayParams(const DisplayParams& params) {
168     this->destroyContext();
169     fDisplayParams = params;
170     this->initializeContext();
171 }
172
173 void MetalWindowContext::activate(bool isActive) {
174     // serialize pipeline archive
175     if (!isActive) {
176 #if GR_METAL_SDK_VERSION >= 230
177         if (@available(macOS 11.0, iOS 14.0, *)) {
178             if (fPipelineArchive) {
179                 NSError* error;
180                 [fPipelineArchive serializeToURL:CacheURL() error:&error];
181                 if (error) {
182                     SkDebugf("Error storing MTLBinaryArchive:\n%s\n",
183                              error.debugDescription.UTF8String);
184                 }
185             }
186         }
187 #endif
188     }
189 }
190
191 }   //namespace sk_app