Implement VK_KHR_win32_surface

Bug: b/139184291
Change-Id: Iab77a5ac5894aec60fc70f2630b6d2a2b232d253
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/30435
Reviewed-by: Ben Clayton <bclayton@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d2efade..bbe06ab 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -394,15 +394,6 @@
         set_cpp_flag("-fPIC")
     endif()
 
-    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
     set_cpp_flag("-g -g3" DEBUG)
     set_cpp_flag("-g -g3" RELWITHDEBINFO)
@@ -1779,7 +1770,11 @@
     list(APPEND EGL_LIST ${OPENGL_DIR}/libEGL/libEGL.rc)
     list(APPEND GLES2_LIST ${OPENGL_DIR}/libGLESv2/libGLESv2.rc)
     list(APPEND GLES_CM_LIST ${OPENGL_DIR}/libGLES_CM/libGLES_CM.rc)
-    list(APPEND VULKAN_LIST ${VULKAN_DIR}/Vulkan.rc)
+    list(APPEND VULKAN_LIST
+        ${VULKAN_DIR}/Vulkan.rc
+        ${SOURCE_DIR}/WSI/Win32SurfaceKHR.cpp
+        ${SOURCE_DIR}/WSI/Win32SurfaceKHR.hpp
+    )
 elseif(LINUX)
     list(APPEND SWIFTSHADER_LIST
         ${SOURCE_DIR}/Main/FrameBufferX11.cpp
@@ -1927,6 +1922,9 @@
         COMPILE_DEFINITIONS "EGL_EGLEXT_PROTOTYPES; EGLAPI=; NO_SANITIZE_FUNCTION=;$<$<CONFIG:Debug>:DEBUGGER_WAIT_DIALOG>"
         PREFIX ""
     )
+    if(LINUX)
+        set_property(TARGET libEGL APPEND PROPERTY COMPILE_DEFINITIONS "USE_X11=1")
+    endif()
     if (ANDROID)
         set_target_properties(libEGL PROPERTIES SUFFIX "_swiftshader.so")
     endif ()
@@ -2005,6 +2003,18 @@
         COMPILE_DEFINITIONS "VK_EXPORT=;NO_SANITIZE_FUNCTION=;$<$<CONFIG:Debug>:DEBUGGER_WAIT_DIALOG>"
         PREFIX ""
     )
+
+    if(WIN32)
+        set_property(TARGET libvk_swiftshader APPEND
+                     PROPERTY COMPILE_DEFINITIONS "VK_USE_PLATFORM_WIN32_KHR")
+    elseif(LINUX)
+        set_property(TARGET libvk_swiftshader APPEND
+                     PROPERTY COMPILE_DEFINITIONS "VK_USE_PLATFORM_XLIB_KHR")
+    elseif(APPLE)
+        set_property(TARGET libvk_swiftshader APPEND
+                     PROPERTY COMPILE_DEFINITIONS "VK_USE_PLATFORM_MACOS_MVK")
+    endif()
+
     set_shared_library_export_map(libvk_swiftshader ${SOURCE_DIR}/Vulkan)
     target_link_libraries(libvk_swiftshader ${Reactor} ${OS_LIBS} SPIRV-Tools SPIRV-Tools-opt)
     add_custom_command(
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index 2c78203..2d06679 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -41,6 +41,8 @@
 #include <unordered_set>
 #include <vector>
 
+#undef Yield // b/127920555
+
 namespace vk
 {
 	class PipelineLayout;
diff --git a/src/Vulkan/VkGetProcAddress.cpp b/src/Vulkan/VkGetProcAddress.cpp
index c132e7f..c8e5ace 100644
--- a/src/Vulkan/VkGetProcAddress.cpp
+++ b/src/Vulkan/VkGetProcAddress.cpp
@@ -97,6 +97,10 @@
     // VK_MVK_macos_surface
     MAKE_VULKAN_INSTANCE_ENTRY(vkCreateMacOSSurfaceMVK),
 #endif
+#ifdef VK_USE_PLATFORM_WIN32_KHR
+	// VK_KHR_win32_surface
+	MAKE_VULKAN_INSTANCE_ENTRY(vkCreateWin32SurfaceKHR),
+#endif
 };
 #undef MAKE_VULKAN_INSTANCE_ENTRY
 
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index dbd2644..2a843b2 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -50,6 +50,10 @@
 #include "WSI/XlibSurfaceKHR.hpp"
 #endif
 
+#ifdef VK_USE_PLATFORM_WIN32_KHR
+#include "WSI/Win32SurfaceKHR.hpp"
+#endif
+
 #ifdef __ANDROID__
 #include <vulkan/vk_android_native_buffer.h>
 #include "System/GrallocAndroid.hpp"
@@ -142,6 +146,9 @@
 #ifdef VK_USE_PLATFORM_MACOS_MVK
     { VK_MVK_MACOS_SURFACE_EXTENSION_NAME, VK_MVK_MACOS_SURFACE_SPEC_VERSION },
 #endif
+#ifdef VK_USE_PLATFORM_WIN32_KHR
+	{ VK_KHR_WIN32_SURFACE_EXTENSION_NAME, VK_KHR_WIN32_SURFACE_SPEC_VERSION },
+#endif
 };
 
 static const VkExtensionProperties deviceExtensionProperties[] =
@@ -2628,6 +2635,16 @@
 }
 #endif
 
+#ifdef VK_USE_PLATFORM_WIN32_KHR
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateWin32SurfaceKHR(VkInstance instance, const VkWin32SurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface)
+{
+	TRACE("(VkInstance instance = %p, VkWin32SurfaceCreateInfoKHR* pCreateInfo = %p, VkAllocationCallbacks* pAllocator = %p, VkSurface* pSurface = %p)",
+			instance, pCreateInfo, pAllocator, pSurface);
+
+	return vk::Win32SurfaceKHR::Create(pAllocator, pCreateInfo, pSurface);
+}
+#endif
+
 #ifndef __ANDROID__
 VKAPI_ATTR void VKAPI_CALL vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator)
 {
diff --git a/src/Vulkan/libvk_swiftshader.def b/src/Vulkan/libvk_swiftshader.def
index cfa6d81..f0de6a5 100644
--- a/src/Vulkan/libvk_swiftshader.def
+++ b/src/Vulkan/libvk_swiftshader.def
@@ -213,4 +213,6 @@
 	vkGetPhysicalDeviceSurfaceSupportKHR

 	vkGetPhysicalDeviceSurfaceCapabilitiesKHR

 	vkGetPhysicalDeviceSurfaceFormatsKHR

-	vkGetPhysicalDeviceSurfacePresentModesKHR
\ No newline at end of file
+	vkGetPhysicalDeviceSurfacePresentModesKHR

+	; VK_KHR_win32_surface

+	vkCreateWin32SurfaceKHR
\ No newline at end of file
diff --git a/src/Vulkan/vulkan.vcxproj b/src/Vulkan/vulkan.vcxproj
index 162f3f2..5a1fac8 100644
--- a/src/Vulkan/vulkan.vcxproj
+++ b/src/Vulkan/vulkan.vcxproj
@@ -62,7 +62,7 @@
       <IntrinsicFunctions>true</IntrinsicFunctions>

       <SDLCheck>true</SDLCheck>

       <AdditionalIncludeDirectories>$(SolutionDir)include;$(SolutionDir)third_party\SPIRV-Headers\include;$(SolutionDir)third_party\SPIRV-Tools\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

-      <PreprocessorDefinitions>VK_EXPORT=;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;_SECURE_SCL=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <PreprocessorDefinitions>VK_USE_PLATFORM_WIN32_KHR;VK_EXPORT=;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;_SECURE_SCL=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>

       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>

       <AdditionalOptions>/permissive- %(AdditionalOptions)</AdditionalOptions>

       <TreatSpecificWarningsAsErrors>4018;5038;4838</TreatSpecificWarningsAsErrors>

@@ -89,7 +89,7 @@
       <Optimization>Disabled</Optimization>

       <SDLCheck>true</SDLCheck>

       <AdditionalIncludeDirectories>$(SolutionDir)include;$(SolutionDir)third_party\SPIRV-Headers\include;$(SolutionDir)third_party\SPIRV-Tools\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

-      <PreprocessorDefinitions>VK_EXPORT=;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;DEBUGGER_WAIT_DIALOG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <PreprocessorDefinitions>VK_USE_PLATFORM_WIN32_KHR;VK_EXPORT=;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;DEBUGGER_WAIT_DIALOG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>

       <AdditionalOptions>/permissive- %(AdditionalOptions)</AdditionalOptions>

       <TreatSpecificWarningsAsErrors>4018;5038;4838</TreatSpecificWarningsAsErrors>

@@ -109,6 +109,7 @@
     </PostBuildEvent>

   </ItemDefinitionGroup>

   <ItemGroup>

+    <ClCompile Include="..\WSI\Win32SurfaceKHR.cpp" />

     <ClCompile Include="libVulkan.cpp" />

     <ClCompile Include="main.cpp" />

     <ClCompile Include="VkBuffer.cpp" />

@@ -189,6 +190,7 @@
     </ClCompile>

   </ItemGroup>

   <ItemGroup>

+    <ClInclude Include="..\WSI\Win32SurfaceKHR.hpp" />

     <ClInclude Include="resource.h" />

     <ClInclude Include="Version.h" />

     <ClInclude Include="VkBuffer.hpp" />

diff --git a/src/Vulkan/vulkan.vcxproj.filters b/src/Vulkan/vulkan.vcxproj.filters
index 4f325dc..68eea69 100644
--- a/src/Vulkan/vulkan.vcxproj.filters
+++ b/src/Vulkan/vulkan.vcxproj.filters
@@ -252,6 +252,9 @@
     <ClCompile Include="..\WSI\VkSwapchainKHR.cpp">

       <Filter>Source Files\WSI</Filter>

     </ClCompile>

+    <ClCompile Include="..\WSI\Win32SurfaceKHR.cpp">

+      <Filter>Source Files\WSI</Filter>

+    </ClCompile>

   </ItemGroup>

   <ItemGroup>

     <ClInclude Include="resource.h">

@@ -510,6 +513,9 @@
     <ClInclude Include="..\WSI\VkSwapchainKHR.hpp">

       <Filter>Header Files\WSI</Filter>

     </ClInclude>

+    <ClInclude Include="..\WSI\Win32SurfaceKHR.hpp">

+      <Filter>Header Files\WSI</Filter>

+    </ClInclude>

   </ItemGroup>

   <ItemGroup>

     <None Include="libvk_swiftshader.def" />

diff --git a/src/WSI/VkSurfaceKHR.hpp b/src/WSI/VkSurfaceKHR.hpp
index e25e95d..2badec7 100644
--- a/src/WSI/VkSurfaceKHR.hpp
+++ b/src/WSI/VkSurfaceKHR.hpp
@@ -16,7 +16,9 @@
 #define SWIFTSHADER_VKSURFACEKHR_HPP_
 
 #include "Vulkan/VkObject.hpp"
+#include "Vulkan/VkImage.hpp"
 #include <Vulkan/VulkanPlatform.h>
+
 #include <vector>
 
 namespace vk
@@ -24,7 +26,7 @@
 
 enum PresentImageStatus
 {
-	NONEXISTENT, //  Image wasn't made
+	NONEXISTENT,  // Image wasn't created
 	AVAILABLE,
 	DRAWING,
 	PRESENTING,
diff --git a/src/WSI/Win32SurfaceKHR.cpp b/src/WSI/Win32SurfaceKHR.cpp
new file mode 100644
index 0000000..81073e9
--- /dev/null
+++ b/src/WSI/Win32SurfaceKHR.cpp
@@ -0,0 +1,110 @@
+// 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 "Win32SurfaceKHR.hpp"
+
+#include "Vulkan/VkDeviceMemory.hpp"
+#include "Vulkan/VkDebug.hpp"
+
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+#include <string.h>
+
+namespace vk {
+
+Win32SurfaceKHR::Win32SurfaceKHR(const VkWin32SurfaceCreateInfoKHR *pCreateInfo, void *mem) :
+		hinstance(pCreateInfo->hinstance),
+		hwnd(pCreateInfo->hwnd)
+{
+	ASSERT(IsWindow(hwnd) == TRUE);
+
+	RECT clientRect = {};
+	BOOL status = GetClientRect(hwnd, &clientRect);
+	ASSERT(status != 0);
+
+	windowContext = GetDC(hwnd);
+	bitmapContext = CreateCompatibleDC(windowContext);
+
+	BITMAPINFO bitmapInfo = {};
+	bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFO);
+	bitmapInfo.bmiHeader.biBitCount = 32;
+	bitmapInfo.bmiHeader.biPlanes = 1;
+	bitmapInfo.bmiHeader.biHeight = clientRect.top - clientRect.bottom;
+	bitmapInfo.bmiHeader.biWidth = clientRect.right - clientRect.left;
+	bitmapInfo.bmiHeader.biCompression = BI_RGB;
+
+	bitmap = CreateDIBSection(bitmapContext, &bitmapInfo, DIB_RGB_COLORS, &framebuffer, 0, 0);
+	ASSERT(bitmap != NULL);
+	SelectObject(bitmapContext, bitmap);
+}
+
+void Win32SurfaceKHR::destroySurface(const VkAllocationCallbacks *pAllocator)
+{
+	SelectObject(bitmapContext, NULL);
+	DeleteObject(bitmap);
+	ReleaseDC(hwnd, windowContext);
+	DeleteDC(bitmapContext);
+}
+
+size_t Win32SurfaceKHR::ComputeRequiredAllocationSize(const VkWin32SurfaceCreateInfoKHR *pCreateInfo)
+{
+	return 0;
+}
+
+void Win32SurfaceKHR::getSurfaceCapabilities(VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) const
+{
+	SurfaceKHR::getSurfaceCapabilities(pSurfaceCapabilities);
+
+	RECT clientRect = {};
+	BOOL status = GetClientRect(hwnd, &clientRect);
+	ASSERT(status != 0);
+
+	int windowWidth = clientRect.right - clientRect.left;
+	int windowHeight = clientRect.bottom - clientRect.top;
+
+	VkExtent2D extent = {static_cast<uint32_t>(windowWidth), static_cast<uint32_t>(windowHeight)};
+	pSurfaceCapabilities->currentExtent = extent;
+	pSurfaceCapabilities->minImageExtent = extent;
+	pSurfaceCapabilities->maxImageExtent = extent;
+}
+
+void Win32SurfaceKHR::attachImage(PresentImage* image)
+{
+	// Nothing to do here, the current implementation based on GDI blits on
+	// present instead of associating the image with the surface.
+}
+
+void Win32SurfaceKHR::detachImage(PresentImage* image)
+{
+	// Nothing to do here, the current implementation based on GDI blits on
+	// present instead of associating the image with the surface.
+}
+
+void Win32SurfaceKHR::present(PresentImage* image)
+{
+	if(!framebuffer)
+	{
+		return;
+	}
+
+	VkExtent3D extent = image->getImage()->getMipLevelExtent(VK_IMAGE_ASPECT_COLOR_BIT, 0);
+
+	// FIXME(b/139184291): Assumes B8G8R8A8 surface without stride padding.
+	size_t bytes = extent.width * extent.height * 4;
+	memcpy(framebuffer, image->getImageMemory()->getOffsetPointer(0), bytes);
+
+	StretchBlt(windowContext, 0, 0, extent.width, extent.height, bitmapContext, 0, 0, extent.width, extent.height, SRCCOPY);
+}
+
+}
\ No newline at end of file
diff --git a/src/WSI/Win32SurfaceKHR.hpp b/src/WSI/Win32SurfaceKHR.hpp
new file mode 100644
index 0000000..8a28a71
--- /dev/null
+++ b/src/WSI/Win32SurfaceKHR.hpp
@@ -0,0 +1,56 @@
+// 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_WIN32SURFACEKHR_HPP
+#define SWIFTSHADER_WIN32SURFACEKHR_HPP
+
+#include "Vulkan/VkObject.hpp"
+#include "Vulkan/VkImage.hpp"
+#include "VkSurfaceKHR.hpp"
+
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+#include "vulkan/vulkan_win32.h"
+
+#include <map>
+
+namespace vk {
+
+class Win32SurfaceKHR : public SurfaceKHR, public ObjectBase<Win32SurfaceKHR, VkSurfaceKHR> {
+public:
+	Win32SurfaceKHR(const VkWin32SurfaceCreateInfoKHR *pCreateInfo, void *mem);
+
+	void destroySurface(const VkAllocationCallbacks *pAllocator) override;
+
+	static size_t ComputeRequiredAllocationSize(const VkWin32SurfaceCreateInfoKHR *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:
+	const HINSTANCE hinstance;
+	const HWND hwnd;
+
+	HDC windowContext = {};
+	HDC bitmapContext = {};
+
+	HBITMAP bitmap = {};
+	void *framebuffer = nullptr;
+};
+
+}
+#endif //SWIFTSHADER_WIN32SURFACEKHR_HPP
diff --git a/src/WSI/XlibSurfaceKHR.cpp b/src/WSI/XlibSurfaceKHR.cpp
index 0891c22..a193c23 100644
--- a/src/WSI/XlibSurfaceKHR.cpp
+++ b/src/WSI/XlibSurfaceKHR.cpp
@@ -1,3 +1,6 @@
+// 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
 //
diff --git a/src/WSI/XlibSurfaceKHR.hpp b/src/WSI/XlibSurfaceKHR.hpp
index c923a32..0dcb5e4 100644
--- a/src/WSI/XlibSurfaceKHR.hpp
+++ b/src/WSI/XlibSurfaceKHR.hpp
@@ -39,8 +39,8 @@
 	void present(PresentImage* image) override;
 
 private:
-	Display *pDisplay;
-	Window window;
+	Display *const pDisplay;
+	const Window window;
 	GC gc;
 	Visual *visual = nullptr;
 	std::map<PresentImage*, XImage*> imageMap;