blob: 090cc2070ef0de00cd85dfe24213b767b081b4af [file] [log] [blame]
Alexis Hetu0662a4a2019-07-08 15:06:40 -04001// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "MacOSSurfaceMVK.h"
16#include "Vulkan/VkDeviceMemory.hpp"
17#include "Vulkan/VkImage.hpp"
18
19#include <Metal/Metal.h>
20#include <QuartzCore/CAMetalLayer.h>
21#include <AppKit/NSView.h>
22
23namespace vk {
24
25class MetalLayer
26{
27public:
28 void init(const void* pView)
29 {
30 view = nullptr;
31 layer = nullptr;
32
33 id<NSObject> obj = (id<NSObject>)pView;
34
35 if([obj isKindOfClass: [NSView class]])
36 {
37 if(!NSThread.isMainThread)
38 {
39 UNREACHABLE("MetalLayer::init(): not called from main thread");
40 }
41 view = (NSView*)[obj retain];
42
43 obj = view.layer;
44 if ([obj isKindOfClass: [CAMetalLayer class]])
45 {
46 layer = (CAMetalLayer*)[obj retain];
47 }
48 else
49 {
50 UNREACHABLE("MetalLayer::init(): view doesn't have metal backed layer");
51 }
52 }
53 }
54
55 void release()
56 {
57 if(layer)
58 {
59 [layer release];
60 }
61
62 if(view)
63 {
64 [view release];
65 }
66 }
67
68 VkExtent2D getExtent() const
69 {
70 if(layer)
71 {
72 CGSize drawSize = layer.bounds.size;
73 CGFloat scaleFactor = layer.contentsScale;
74 drawSize.width = trunc(drawSize.width * scaleFactor);
75 drawSize.height = trunc(drawSize.height * scaleFactor);
76 return { static_cast<uint32_t>(drawSize.width), static_cast<uint32_t>(drawSize.height) };
77 }
78 else
79 {
80 return { 0, 0 };
81 }
82 }
83
84 id<CAMetalDrawable> getNextDrawable() const
85 {
86 if(layer)
87 {
88 return [layer nextDrawable];
89 }
90
91 return nil;
92 }
93
94private:
95 NSView* view;
96 CAMetalLayer* layer;
97};
98
99MacOSSurfaceMVK::MacOSSurfaceMVK(const VkMacOSSurfaceCreateInfoMVK *pCreateInfo, void *mem) :
100 metalLayer(reinterpret_cast<MetalLayer*>(mem))
101{
102 metalLayer->init(pCreateInfo->pView);
103}
104
105void MacOSSurfaceMVK::destroySurface(const VkAllocationCallbacks *pAllocator)
106{
107 if(metalLayer)
108 {
109 metalLayer->release();
110 }
111
112 vk::deallocate(metalLayer, pAllocator);
113}
114
115size_t MacOSSurfaceMVK::ComputeRequiredAllocationSize(const VkMacOSSurfaceCreateInfoMVK *pCreateInfo)
116{
117 return sizeof(MetalLayer);
118}
119
120void MacOSSurfaceMVK::getSurfaceCapabilities(VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) const
121{
122 SurfaceKHR::getSurfaceCapabilities(pSurfaceCapabilities);
123
124 VkExtent2D extent = metalLayer->getExtent();
125 pSurfaceCapabilities->currentExtent = extent;
126 pSurfaceCapabilities->minImageExtent = extent;
127 pSurfaceCapabilities->maxImageExtent = extent;
128}
129
130void MacOSSurfaceMVK::present(PresentImage* image)
131{
132 auto drawable = metalLayer->getNextDrawable();
133 if(drawable)
134 {
135 VkExtent3D extent = image->getImage()->getMipLevelExtent(VK_IMAGE_ASPECT_COLOR_BIT, 0);
136 [drawable.texture replaceRegion:MTLRegionMake2D(0, 0, extent.width, extent.height)
137 mipmapLevel:0
138 withBytes:image->getImageMemory()->getOffsetPointer(0)
139 bytesPerRow:image->getImage()->rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0)];
140 [drawable present];
141 }
142}
143
144}