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