1
2/*
3 * Copyright 2019 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9#include "vk/GrVkVulkan.h"
10
11#include "vk/GrVkInterface.h"
12#include "vk/GrVkUtil.h"
13
14#include "vk/VkTestUtils.h"
15
16#include "WindowContextFactory_mac.h"
17#include "../VulkanWindowContext.h"
18#include "vulkan/vulkan_macos.h"
19
20#import <MetalKit/MetalKit.h>
21
22namespace sk_app {
23
24class VulkanWindowContext_mac : public VulkanWindowContext {
25public:
26    VulkanWindowContext_mac(MTKView* mtkView,
27                            const DisplayParams& params,
28                            CreateVkSurfaceFn createVkSurface,
29                            CanPresentFn canPresent,
30                            PFN_vkGetInstanceProcAddr instProc,
31                            PFN_vkGetDeviceProcAddr devProc);
32
33    ~VulkanWindowContext_mac() override;
34
35    void resize(int w, int h) override;
36
37private:
38    MTKView*              fMTKView;
39
40    typedef VulkanWindowContext INHERITED;
41};
42
43VulkanWindowContext_mac::VulkanWindowContext_mac(MTKView* mtkView,
44                                                 const DisplayParams& params,
45                                                 CreateVkSurfaceFn createVkSurface,
46                                                 CanPresentFn canPresent,
47                                                 PFN_vkGetInstanceProcAddr instProc,
48                                                 PFN_vkGetDeviceProcAddr devProc)
49    : INHERITED(params, createVkSurface, canPresent, instProc, devProc)
50    , fMTKView(mtkView) {
51
52    // any config code here (particularly for msaa)?
53}
54
55VulkanWindowContext_mac::~VulkanWindowContext_mac() {
56    [fMTKView removeFromSuperview];
57    [fMTKView release];
58    fMTKView = nil;
59}
60
61void VulkanWindowContext_mac::resize(int w, int h) {
62    CGSize newSize;
63    newSize.width = w;
64    newSize.height = h;
65    fMTKView.drawableSize = newSize;
66    this->INHERITED::resize(w, h);
67}
68
69namespace window_context_factory {
70
71WindowContext* NewVulkanForMac(const MacWindowInfo& info, const DisplayParams& displayParams) {
72    PFN_vkGetInstanceProcAddr instProc;
73    PFN_vkGetDeviceProcAddr devProc;
74    if (!sk_gpu_test::LoadVkLibraryAndGetProcAddrFuncs(&instProc, &devProc)) {
75        return nullptr;
76    }
77
78    // Create mtkview
79    NSRect rect = info.fMainView.frame;
80    MTKView* mtkView = [[MTKView alloc] initWithFrame:rect device:nil];
81    if (nil == mtkView) {
82        return nullptr;
83    }
84
85    mtkView.autoResizeDrawable = NO;
86    mtkView.colorPixelFormat = MTLPixelFormatBGRA8Unorm;
87    mtkView.drawableSize = rect.size;
88
89//    if (fDisplayParams.fMSAASampleCount > 1) {
90//        if (![fDevice supportsTextureSampleCount:fDisplayParams.fMSAASampleCount]) {
91//            return nullptr;
92//        }
93//    }
94//    mtkView.sampleCount = fDisplayParams.fMSAASampleCount;
95
96    // attach Metal view to main view
97    [mtkView setTranslatesAutoresizingMaskIntoConstraints:NO];
98
99    [info.fMainView addSubview:mtkView];
100    NSDictionary *views = NSDictionaryOfVariableBindings(mtkView);
101
102    [info.fMainView addConstraints:
103     [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[mtkView]|"
104                                             options:0
105                                             metrics:nil
106                                               views:views]];
107
108    [info.fMainView addConstraints:
109     [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[mtkView]|"
110                                             options:0
111                                             metrics:nil
112                                               views:views]];
113
114    auto createVkSurface = [mtkView, instProc](VkInstance instance) -> VkSurfaceKHR {
115        static PFN_vkCreateMacOSSurfaceMVK createMacOSSurfaceMVK = nullptr;
116        if (!createMacOSSurfaceMVK) {
117            createMacOSSurfaceMVK =
118                    (PFN_vkCreateMacOSSurfaceMVK) instProc(instance, "vkCreateMacOSSurfaceMVK");
119        }
120
121        VkSurfaceKHR surface;
122
123        VkMacOSSurfaceCreateInfoMVK surfaceCreateInfo;
124        memset(&surfaceCreateInfo, 0, sizeof(VkMacOSSurfaceCreateInfoMVK));
125        surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
126        surfaceCreateInfo.pNext = nullptr;
127        surfaceCreateInfo.flags = 0;
128        surfaceCreateInfo.pView = (__bridge void*)mtkView;
129
130        VkResult res = createMacOSSurfaceMVK(instance, &surfaceCreateInfo, nullptr, &surface);
131        if (VK_SUCCESS != res) {
132            return VK_NULL_HANDLE;
133        }
134
135        return surface;
136    };
137
138    auto canPresent = [](VkInstance instance, VkPhysicalDevice physDev, uint32_t queueFamilyIndex) {
139        return true;
140    };
141    WindowContext* context = new VulkanWindowContext_mac(mtkView, displayParams, createVkSurface,
142                                                         canPresent, instProc, devProc);
143    if (!context->isValid()) {
144        delete context;
145        [mtkView removeFromSuperview];
146        [mtkView release];
147        return nullptr;
148    }
149    return context;
150}
151
152}  // namespace VulkanWindowContextFactory
153
154}  // namespace sk_app
155