MacOS WSI
This cl implements the VK_MVK_macos_surface extension, which
adds the vkCreateMacOSSurfaceMVK function on MacOS.
According to the spec:
"The VK_MVK_macos_surface extension is an instance extension.
It provides a mechanism to create a VkSurfaceKHR object
(defined by the VK_KHR_surface extension) that refers to an
NSView, the native surface type of macOS, which is
underpinned by a CAMetalLayer, to support rendering to the
surface using Apple’s Metal framework."
Bug b/137673628
Change-Id: Iacf7696b1d9e52d7349ea4efa01f0acdd09a6c8f
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/33848
Reviewed-by: Hernan Liatis <hliatis@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Chris Forbes <chrisforbes@google.com>
Tested-by: Alexis Hétu <sugoi@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cc702b2..166049e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -394,9 +394,13 @@
set_cpp_flag("-fPIC")
endif()
- if(LINUX)
+ if(WIN32)
+ set_cpp_flag("-DVK_USE_PLATFORM_WIN32_KHR")
+ elseif(LINUX)
set_cpp_flag("-DUSE_X11=1")
set_cpp_flag("-DVK_USE_PLATFORM_XLIB_KHR")
+ elseif(APPLE)
+ set_cpp_flag("-DVK_USE_PLATFORM_MACOS_MVK")
endif()
# Use -g3 to have even more debug info
@@ -1812,6 +1816,11 @@
list(APPEND OPENGL_COMPILER_LIST
${OPENGL_COMPILER_DIR}/ossource_posix.cpp
)
+
+ list(APPEND VULKAN_LIST
+ ${SOURCE_DIR}/WSI/MacOSSurfaceMVK.mm
+ ${SOURCE_DIR}/WSI/MacOSSurfaceMVK.h
+ )
elseif(ANDROID)
list(APPEND SWIFTSHADER_LIST
${SOURCE_DIR}/Main/FrameBufferAndroid.cpp
diff --git a/src/Vulkan/VkGetProcAddress.cpp b/src/Vulkan/VkGetProcAddress.cpp
index 4bfb07e..c132e7f 100644
--- a/src/Vulkan/VkGetProcAddress.cpp
+++ b/src/Vulkan/VkGetProcAddress.cpp
@@ -93,6 +93,10 @@
MAKE_VULKAN_INSTANCE_ENTRY(vkCreateXlibSurfaceKHR),
MAKE_VULKAN_INSTANCE_ENTRY(vkGetPhysicalDeviceXlibPresentationSupportKHR),
#endif
+#ifdef VK_USE_PLATFORM_MACOS_MVK
+ // VK_MVK_macos_surface
+ MAKE_VULKAN_INSTANCE_ENTRY(vkCreateMacOSSurfaceMVK),
+#endif
};
#undef MAKE_VULKAN_INSTANCE_ENTRY
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index 2450b54..ef70b3f 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -42,6 +42,10 @@
#include "VkShaderModule.hpp"
#include "VkRenderPass.hpp"
+#ifdef VK_USE_PLATFORM_MACOS_MVK
+#include "WSI/MacOSSurfaceMVK.h"
+#endif
+
#ifdef VK_USE_PLATFORM_XLIB_KHR
#include "WSI/XlibSurfaceKHR.hpp"
#endif
@@ -135,6 +139,9 @@
#ifdef VK_USE_PLATFORM_XLIB_KHR
{ VK_KHR_XLIB_SURFACE_EXTENSION_NAME, VK_KHR_XLIB_SURFACE_SPEC_VERSION },
#endif
+#ifdef VK_USE_PLATFORM_MACOS_MVK
+ { VK_MVK_MACOS_SURFACE_EXTENSION_NAME, VK_MVK_MACOS_SURFACE_SPEC_VERSION },
+#endif
};
static const VkExtensionProperties deviceExtensionProperties[] =
@@ -2611,6 +2618,16 @@
}
#endif
+#ifdef VK_USE_PLATFORM_MACOS_MVK
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateMacOSSurfaceMVK(VkInstance instance, const VkMacOSSurfaceCreateInfoMVK* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface)
+{
+ TRACE("(VkInstance instance = %p, VkMacOSSurfaceCreateInfoMVK* pCreateInfo = %p, VkAllocationCallbacks* pAllocator = %p, VkSurface* pSurface = %p)",
+ instance, pCreateInfo, pAllocator, pSurface);
+
+ return vk::MacOSSurfaceMVK::Create(pAllocator, pCreateInfo, pSurface);
+}
+#endif
+
#ifndef __ANDROID__
VKAPI_ATTR void VKAPI_CALL vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator)
{
diff --git a/src/WSI/MacOSSurfaceMVK.h b/src/WSI/MacOSSurfaceMVK.h
new file mode 100644
index 0000000..7822fb6
--- /dev/null
+++ b/src/WSI/MacOSSurfaceMVK.h
@@ -0,0 +1,45 @@
+// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SWIFTSHADER_MACOSSURFACEMVK_HPP
+#define SWIFTSHADER_MACOSSURFACEMVK_HPP
+
+#include "Vulkan/VkObject.hpp"
+#include "VkSurfaceKHR.hpp"
+#include "vulkan/vulkan_macos.h"
+
+namespace vk {
+
+class MetalLayer;
+
+class MacOSSurfaceMVK : public SurfaceKHR, public ObjectBase<MacOSSurfaceMVK, VkSurfaceKHR> {
+public:
+ MacOSSurfaceMVK(const VkMacOSSurfaceCreateInfoMVK *pCreateInfo, void *mem);
+
+ void destroySurface(const VkAllocationCallbacks *pAllocator) override;
+
+ static size_t ComputeRequiredAllocationSize(const VkMacOSSurfaceCreateInfoMVK *pCreateInfo);
+
+ void getSurfaceCapabilities(VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) const override;
+
+ virtual void attachImage(PresentImage* image) override {}
+ virtual void detachImage(PresentImage* image) override {}
+ void present(PresentImage* image) override;
+
+private:
+ MetalLayer* metalLayer = nullptr;
+};
+
+}
+#endif //SWIFTSHADER_MACOSSURFACEMVK_HPP
diff --git a/src/WSI/MacOSSurfaceMVK.mm b/src/WSI/MacOSSurfaceMVK.mm
new file mode 100644
index 0000000..090cc20
--- /dev/null
+++ b/src/WSI/MacOSSurfaceMVK.mm
@@ -0,0 +1,144 @@
+// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "MacOSSurfaceMVK.h"
+#include "Vulkan/VkDeviceMemory.hpp"
+#include "Vulkan/VkImage.hpp"
+
+#include <Metal/Metal.h>
+#include <QuartzCore/CAMetalLayer.h>
+#include <AppKit/NSView.h>
+
+namespace vk {
+
+class MetalLayer
+{
+public:
+ void init(const void* pView)
+ {
+ view = nullptr;
+ layer = nullptr;
+
+ id<NSObject> obj = (id<NSObject>)pView;
+
+ if([obj isKindOfClass: [NSView class]])
+ {
+ if(!NSThread.isMainThread)
+ {
+ UNREACHABLE("MetalLayer::init(): not called from main thread");
+ }
+ view = (NSView*)[obj retain];
+
+ obj = view.layer;
+ if ([obj isKindOfClass: [CAMetalLayer class]])
+ {
+ layer = (CAMetalLayer*)[obj retain];
+ }
+ else
+ {
+ UNREACHABLE("MetalLayer::init(): view doesn't have metal backed layer");
+ }
+ }
+ }
+
+ void release()
+ {
+ if(layer)
+ {
+ [layer release];
+ }
+
+ if(view)
+ {
+ [view release];
+ }
+ }
+
+ VkExtent2D getExtent() const
+ {
+ if(layer)
+ {
+ CGSize drawSize = layer.bounds.size;
+ CGFloat scaleFactor = layer.contentsScale;
+ drawSize.width = trunc(drawSize.width * scaleFactor);
+ drawSize.height = trunc(drawSize.height * scaleFactor);
+ return { static_cast<uint32_t>(drawSize.width), static_cast<uint32_t>(drawSize.height) };
+ }
+ else
+ {
+ return { 0, 0 };
+ }
+ }
+
+ id<CAMetalDrawable> getNextDrawable() const
+ {
+ if(layer)
+ {
+ return [layer nextDrawable];
+ }
+
+ return nil;
+ }
+
+private:
+ NSView* view;
+ CAMetalLayer* layer;
+};
+
+MacOSSurfaceMVK::MacOSSurfaceMVK(const VkMacOSSurfaceCreateInfoMVK *pCreateInfo, void *mem) :
+ metalLayer(reinterpret_cast<MetalLayer*>(mem))
+{
+ metalLayer->init(pCreateInfo->pView);
+}
+
+void MacOSSurfaceMVK::destroySurface(const VkAllocationCallbacks *pAllocator)
+{
+ if(metalLayer)
+ {
+ metalLayer->release();
+ }
+
+ vk::deallocate(metalLayer, pAllocator);
+}
+
+size_t MacOSSurfaceMVK::ComputeRequiredAllocationSize(const VkMacOSSurfaceCreateInfoMVK *pCreateInfo)
+{
+ return sizeof(MetalLayer);
+}
+
+void MacOSSurfaceMVK::getSurfaceCapabilities(VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) const
+{
+ SurfaceKHR::getSurfaceCapabilities(pSurfaceCapabilities);
+
+ VkExtent2D extent = metalLayer->getExtent();
+ pSurfaceCapabilities->currentExtent = extent;
+ pSurfaceCapabilities->minImageExtent = extent;
+ pSurfaceCapabilities->maxImageExtent = extent;
+}
+
+void MacOSSurfaceMVK::present(PresentImage* image)
+{
+ auto drawable = metalLayer->getNextDrawable();
+ if(drawable)
+ {
+ VkExtent3D extent = image->getImage()->getMipLevelExtent(VK_IMAGE_ASPECT_COLOR_BIT, 0);
+ [drawable.texture replaceRegion:MTLRegionMake2D(0, 0, extent.width, extent.height)
+ mipmapLevel:0
+ withBytes:image->getImageMemory()->getOffsetPointer(0)
+ bytesPerRow:image->getImage()->rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0)];
+ [drawable present];
+ }
+}
+
+}