xref: /aosp_15_r20/external/swiftshader/src/WSI/MetalSurface.mm (revision 03ce13f70fcc45d86ee91b7ee4cab1936a95046e)
1*03ce13f7SAndroid Build Coastguard Worker// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
2*03ce13f7SAndroid Build Coastguard Worker//
3*03ce13f7SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*03ce13f7SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*03ce13f7SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*03ce13f7SAndroid Build Coastguard Worker//
7*03ce13f7SAndroid Build Coastguard Worker//    http://www.apache.org/licenses/LICENSE-2.0
8*03ce13f7SAndroid Build Coastguard Worker//
9*03ce13f7SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*03ce13f7SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*03ce13f7SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*03ce13f7SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*03ce13f7SAndroid Build Coastguard Worker// limitations under the License.
14*03ce13f7SAndroid Build Coastguard Worker
15*03ce13f7SAndroid Build Coastguard Worker#include "MetalSurface.hpp"
16*03ce13f7SAndroid Build Coastguard Worker#include "Vulkan/VkDeviceMemory.hpp"
17*03ce13f7SAndroid Build Coastguard Worker#include "Vulkan/VkImage.hpp"
18*03ce13f7SAndroid Build Coastguard Worker
19*03ce13f7SAndroid Build Coastguard Worker#include <Metal/Metal.h>
20*03ce13f7SAndroid Build Coastguard Worker#include <QuartzCore/CAMetalLayer.h>
21*03ce13f7SAndroid Build Coastguard Worker#include <AppKit/NSView.h>
22*03ce13f7SAndroid Build Coastguard Worker
23*03ce13f7SAndroid Build Coastguard Workernamespace vk {
24*03ce13f7SAndroid Build Coastguard Worker
25*03ce13f7SAndroid Build Coastguard Workerclass MetalLayer
26*03ce13f7SAndroid Build Coastguard Worker{
27*03ce13f7SAndroid Build Coastguard Workerpublic:
28*03ce13f7SAndroid Build Coastguard Worker    void initWithLayer(const void* pLayer) API_AVAILABLE(macosx(10.11))
29*03ce13f7SAndroid Build Coastguard Worker    {
30*03ce13f7SAndroid Build Coastguard Worker        view = nullptr;
31*03ce13f7SAndroid Build Coastguard Worker        layer = nullptr;
32*03ce13f7SAndroid Build Coastguard Worker
33*03ce13f7SAndroid Build Coastguard Worker        id<NSObject> obj = (id<NSObject>)pLayer;
34*03ce13f7SAndroid Build Coastguard Worker
35*03ce13f7SAndroid Build Coastguard Worker        if(!NSThread.isMainThread)
36*03ce13f7SAndroid Build Coastguard Worker        {
37*03ce13f7SAndroid Build Coastguard Worker            UNREACHABLE("MetalLayer::init(): not called from main thread");
38*03ce13f7SAndroid Build Coastguard Worker        }
39*03ce13f7SAndroid Build Coastguard Worker        if([obj isKindOfClass: [CAMetalLayer class]])
40*03ce13f7SAndroid Build Coastguard Worker        {
41*03ce13f7SAndroid Build Coastguard Worker            layer = (CAMetalLayer*)[obj retain];
42*03ce13f7SAndroid Build Coastguard Worker            layer.framebufferOnly = false;
43*03ce13f7SAndroid Build Coastguard Worker            layer.device = MTLCreateSystemDefaultDevice();
44*03ce13f7SAndroid Build Coastguard Worker        }
45*03ce13f7SAndroid Build Coastguard Worker        else
46*03ce13f7SAndroid Build Coastguard Worker        {
47*03ce13f7SAndroid Build Coastguard Worker            UNREACHABLE("MetalLayer::init(): view doesn't have metal backed layer");
48*03ce13f7SAndroid Build Coastguard Worker        }
49*03ce13f7SAndroid Build Coastguard Worker    }
50*03ce13f7SAndroid Build Coastguard Worker
51*03ce13f7SAndroid Build Coastguard Worker    void initWithView(const void* pView) API_AVAILABLE(macosx(10.11))
52*03ce13f7SAndroid Build Coastguard Worker    {
53*03ce13f7SAndroid Build Coastguard Worker        view = nullptr;
54*03ce13f7SAndroid Build Coastguard Worker        layer = nullptr;
55*03ce13f7SAndroid Build Coastguard Worker
56*03ce13f7SAndroid Build Coastguard Worker        id<NSObject> obj = (id<NSObject>)pView;
57*03ce13f7SAndroid Build Coastguard Worker
58*03ce13f7SAndroid Build Coastguard Worker        if([obj isKindOfClass: [NSView class]])
59*03ce13f7SAndroid Build Coastguard Worker        {
60*03ce13f7SAndroid Build Coastguard Worker            NSView* objView = (NSView*)[obj retain];
61*03ce13f7SAndroid Build Coastguard Worker
62*03ce13f7SAndroid Build Coastguard Worker            initWithLayer(objView.layer);
63*03ce13f7SAndroid Build Coastguard Worker
64*03ce13f7SAndroid Build Coastguard Worker            view = objView;
65*03ce13f7SAndroid Build Coastguard Worker        }
66*03ce13f7SAndroid Build Coastguard Worker    }
67*03ce13f7SAndroid Build Coastguard Worker
68*03ce13f7SAndroid Build Coastguard Worker    void release() API_AVAILABLE(macosx(10.11))
69*03ce13f7SAndroid Build Coastguard Worker    {
70*03ce13f7SAndroid Build Coastguard Worker        if(layer)
71*03ce13f7SAndroid Build Coastguard Worker        {
72*03ce13f7SAndroid Build Coastguard Worker            [layer.device release];
73*03ce13f7SAndroid Build Coastguard Worker            [layer release];
74*03ce13f7SAndroid Build Coastguard Worker        }
75*03ce13f7SAndroid Build Coastguard Worker        if(view)
76*03ce13f7SAndroid Build Coastguard Worker        {
77*03ce13f7SAndroid Build Coastguard Worker            [view release];
78*03ce13f7SAndroid Build Coastguard Worker        }
79*03ce13f7SAndroid Build Coastguard Worker    }
80*03ce13f7SAndroid Build Coastguard Worker
81*03ce13f7SAndroid Build Coastguard Worker    // Synchronizes the drawableSize to layer.bounds.size * layer.contentsScale and returns the new value of
82*03ce13f7SAndroid Build Coastguard Worker    // drawableSize.
83*03ce13f7SAndroid Build Coastguard Worker    VkExtent2D syncExtent() const API_AVAILABLE(macosx(10.11))
84*03ce13f7SAndroid Build Coastguard Worker    {
85*03ce13f7SAndroid Build Coastguard Worker        if(layer)
86*03ce13f7SAndroid Build Coastguard Worker        {
87*03ce13f7SAndroid Build Coastguard Worker            CGSize drawSize = layer.bounds.size;
88*03ce13f7SAndroid Build Coastguard Worker            CGFloat scaleFactor = layer.contentsScale;
89*03ce13f7SAndroid Build Coastguard Worker            drawSize.width = trunc(drawSize.width * scaleFactor);
90*03ce13f7SAndroid Build Coastguard Worker            drawSize.height = trunc(drawSize.height * scaleFactor);
91*03ce13f7SAndroid Build Coastguard Worker
92*03ce13f7SAndroid Build Coastguard Worker            [layer setDrawableSize: drawSize];
93*03ce13f7SAndroid Build Coastguard Worker
94*03ce13f7SAndroid Build Coastguard Worker            return { static_cast<uint32_t>(drawSize.width), static_cast<uint32_t>(drawSize.height) };
95*03ce13f7SAndroid Build Coastguard Worker        }
96*03ce13f7SAndroid Build Coastguard Worker        else
97*03ce13f7SAndroid Build Coastguard Worker        {
98*03ce13f7SAndroid Build Coastguard Worker            return { 0, 0 };
99*03ce13f7SAndroid Build Coastguard Worker        }
100*03ce13f7SAndroid Build Coastguard Worker    }
101*03ce13f7SAndroid Build Coastguard Worker
102*03ce13f7SAndroid Build Coastguard Worker    id<CAMetalDrawable> getNextDrawable() const API_AVAILABLE(macosx(10.11))
103*03ce13f7SAndroid Build Coastguard Worker    {
104*03ce13f7SAndroid Build Coastguard Worker        if(layer)
105*03ce13f7SAndroid Build Coastguard Worker        {
106*03ce13f7SAndroid Build Coastguard Worker            return [layer nextDrawable];
107*03ce13f7SAndroid Build Coastguard Worker        }
108*03ce13f7SAndroid Build Coastguard Worker
109*03ce13f7SAndroid Build Coastguard Worker        return nil;
110*03ce13f7SAndroid Build Coastguard Worker    }
111*03ce13f7SAndroid Build Coastguard Worker
112*03ce13f7SAndroid Build Coastguard Worker    VkExtent2D getDrawableSize() const API_AVAILABLE(macosx(10.11)) {
113*03ce13f7SAndroid Build Coastguard Worker        if (layer) {
114*03ce13f7SAndroid Build Coastguard Worker            return {
115*03ce13f7SAndroid Build Coastguard Worker                static_cast<uint32_t>([layer drawableSize].width),
116*03ce13f7SAndroid Build Coastguard Worker                static_cast<uint32_t>([layer drawableSize].height),
117*03ce13f7SAndroid Build Coastguard Worker            };
118*03ce13f7SAndroid Build Coastguard Worker        }
119*03ce13f7SAndroid Build Coastguard Worker        return {0, 0};
120*03ce13f7SAndroid Build Coastguard Worker    }
121*03ce13f7SAndroid Build Coastguard Worker
122*03ce13f7SAndroid Build Coastguard Workerprivate:
123*03ce13f7SAndroid Build Coastguard Worker    NSView* view;
124*03ce13f7SAndroid Build Coastguard Worker    CAMetalLayer* layer API_AVAILABLE(macosx(10.11));
125*03ce13f7SAndroid Build Coastguard Worker};
126*03ce13f7SAndroid Build Coastguard Worker
127*03ce13f7SAndroid Build Coastguard WorkerMetalSurface::MetalSurface(const void *pCreateInfo, void *mem) : metalLayer(reinterpret_cast<MetalLayer*>(mem))
128*03ce13f7SAndroid Build Coastguard Worker{
129*03ce13f7SAndroid Build Coastguard Worker
130*03ce13f7SAndroid Build Coastguard Worker}
131*03ce13f7SAndroid Build Coastguard Worker
132*03ce13f7SAndroid Build Coastguard Workervoid MetalSurface::destroySurface(const VkAllocationCallbacks *pAllocator) API_AVAILABLE(macosx(10.11))
133*03ce13f7SAndroid Build Coastguard Worker{
134*03ce13f7SAndroid Build Coastguard Worker    if(metalLayer)
135*03ce13f7SAndroid Build Coastguard Worker    {
136*03ce13f7SAndroid Build Coastguard Worker        metalLayer->release();
137*03ce13f7SAndroid Build Coastguard Worker    }
138*03ce13f7SAndroid Build Coastguard Worker
139*03ce13f7SAndroid Build Coastguard Worker    vk::freeHostMemory(metalLayer, pAllocator);
140*03ce13f7SAndroid Build Coastguard Worker}
141*03ce13f7SAndroid Build Coastguard Worker
142*03ce13f7SAndroid Build Coastguard Workersize_t MetalSurface::ComputeRequiredAllocationSize(const void *pCreateInfo) API_AVAILABLE(macosx(10.11))
143*03ce13f7SAndroid Build Coastguard Worker{
144*03ce13f7SAndroid Build Coastguard Worker    return sizeof(MetalLayer);
145*03ce13f7SAndroid Build Coastguard Worker}
146*03ce13f7SAndroid Build Coastguard Worker
147*03ce13f7SAndroid Build Coastguard WorkerVkResult MetalSurface::getSurfaceCapabilities(const void *pSurfaceInfoPNext,
148*03ce13f7SAndroid Build Coastguard Worker                                              VkSurfaceCapabilitiesKHR *pSurfaceCapabilities,
149*03ce13f7SAndroid Build Coastguard Worker                                              void *pSurfaceCapabilitiesPNext) const
150*03ce13f7SAndroid Build Coastguard Worker    API_AVAILABLE(macosx(10.11))
151*03ce13f7SAndroid Build Coastguard Worker{
152*03ce13f7SAndroid Build Coastguard Worker    // The value of drawableSize in CAMetalLayer is set the first time a drawable is queried but after that it is the
153*03ce13f7SAndroid Build Coastguard Worker    // (Metal) application's responsibility to resize the drawable when the window is resized. The best time for Swiftshader
154*03ce13f7SAndroid Build Coastguard Worker    // to resize the drawable is when querying the capabilities of the swapchain as that's done when the Vulkan application
155*03ce13f7SAndroid Build Coastguard Worker    // is trying to handle a window resize.
156*03ce13f7SAndroid Build Coastguard Worker    VkExtent2D extent = metalLayer->syncExtent();
157*03ce13f7SAndroid Build Coastguard Worker    pSurfaceCapabilities->currentExtent = extent;
158*03ce13f7SAndroid Build Coastguard Worker    pSurfaceCapabilities->minImageExtent = extent;
159*03ce13f7SAndroid Build Coastguard Worker    pSurfaceCapabilities->maxImageExtent = extent;
160*03ce13f7SAndroid Build Coastguard Worker
161*03ce13f7SAndroid Build Coastguard Worker    setCommonSurfaceCapabilities(pSurfaceInfoPNext, pSurfaceCapabilities,
162*03ce13f7SAndroid Build Coastguard Worker                                 pSurfaceCapabilitiesPNext);
163*03ce13f7SAndroid Build Coastguard Worker    return VK_SUCCESS;
164*03ce13f7SAndroid Build Coastguard Worker}
165*03ce13f7SAndroid Build Coastguard Worker
166*03ce13f7SAndroid Build Coastguard WorkerVkResult MetalSurface::present(PresentImage* image) API_AVAILABLE(macosx(10.11))
167*03ce13f7SAndroid Build Coastguard Worker{
168*03ce13f7SAndroid Build Coastguard Worker    @autoreleasepool
169*03ce13f7SAndroid Build Coastguard Worker    {
170*03ce13f7SAndroid Build Coastguard Worker        auto drawable = metalLayer->getNextDrawable();
171*03ce13f7SAndroid Build Coastguard Worker        if(drawable)
172*03ce13f7SAndroid Build Coastguard Worker        {
173*03ce13f7SAndroid Build Coastguard Worker            const VkExtent3D &extent = image->getImage()->getExtent();
174*03ce13f7SAndroid Build Coastguard Worker            VkExtent2D drawableExtent = metalLayer->getDrawableSize();
175*03ce13f7SAndroid Build Coastguard Worker
176*03ce13f7SAndroid Build Coastguard Worker            if(drawableExtent.width != extent.width || drawableExtent.height != extent.height)
177*03ce13f7SAndroid Build Coastguard Worker            {
178*03ce13f7SAndroid Build Coastguard Worker                return VK_ERROR_OUT_OF_DATE_KHR;
179*03ce13f7SAndroid Build Coastguard Worker            }
180*03ce13f7SAndroid Build Coastguard Worker
181*03ce13f7SAndroid Build Coastguard Worker            [drawable.texture replaceRegion:MTLRegionMake2D(0, 0, extent.width, extent.height)
182*03ce13f7SAndroid Build Coastguard Worker                              mipmapLevel:0
183*03ce13f7SAndroid Build Coastguard Worker                              withBytes:image->getImageMemory()->getOffsetPointer(0)
184*03ce13f7SAndroid Build Coastguard Worker                              bytesPerRow:image->getImage()->rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0)];
185*03ce13f7SAndroid Build Coastguard Worker            [drawable present];
186*03ce13f7SAndroid Build Coastguard Worker
187*03ce13f7SAndroid Build Coastguard Worker        }
188*03ce13f7SAndroid Build Coastguard Worker    }
189*03ce13f7SAndroid Build Coastguard Worker    return VK_SUCCESS;
190*03ce13f7SAndroid Build Coastguard Worker}
191*03ce13f7SAndroid Build Coastguard Worker
192*03ce13f7SAndroid Build Coastguard Worker#ifdef VK_USE_PLATFORM_METAL_EXT
193*03ce13f7SAndroid Build Coastguard WorkerMetalSurfaceEXT::MetalSurfaceEXT(const VkMetalSurfaceCreateInfoEXT *pCreateInfo, void *mem) API_AVAILABLE(macosx(10.11))
194*03ce13f7SAndroid Build Coastguard Worker : MetalSurface(pCreateInfo, mem)
195*03ce13f7SAndroid Build Coastguard Worker{
196*03ce13f7SAndroid Build Coastguard Worker    metalLayer->initWithLayer(pCreateInfo->pLayer);
197*03ce13f7SAndroid Build Coastguard Worker}
198*03ce13f7SAndroid Build Coastguard Worker#endif
199*03ce13f7SAndroid Build Coastguard Worker
200*03ce13f7SAndroid Build Coastguard Worker#ifdef VK_USE_PLATFORM_MACOS_MVK
201*03ce13f7SAndroid Build Coastguard WorkerMacOSSurfaceMVK::MacOSSurfaceMVK(const VkMacOSSurfaceCreateInfoMVK *pCreateInfo, void *mem) API_AVAILABLE(macosx(10.11))
202*03ce13f7SAndroid Build Coastguard Worker : MetalSurface(pCreateInfo, mem)
203*03ce13f7SAndroid Build Coastguard Worker{
204*03ce13f7SAndroid Build Coastguard Worker    metalLayer->initWithView(pCreateInfo->pView);
205*03ce13f7SAndroid Build Coastguard Worker}
206*03ce13f7SAndroid Build Coastguard Worker#endif
207*03ce13f7SAndroid Build Coastguard Worker
208*03ce13f7SAndroid Build Coastguard Worker}
209