Add DirectFB support for Vulkan WSI

Bug: b/162574690
Change-Id: I825af0494737ec9090da9580dfd876db88e3c289
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/47368
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Tested-by: Nicolas Caramelli <caramelli.devel@gmail.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a966fc6..87a5dba 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -89,6 +89,10 @@
 if(SWIFTSHADER_BUILD_WSI_WAYLAND)
     find_library(WAYLAND wayland-client)
 endif(SWIFTSHADER_BUILD_WSI_WAYLAND)
+if(SWIFTSHADER_BUILD_WSI_DIRECTFB)
+    find_library(DIRECTFB directfb)
+    find_path(DIRECTFB_INCLUDE_DIR directfb/directfb.h)
+endif(SWIFTSHADER_BUILD_WSI_DIRECTFB)
 
 ###########################################################
 # Options
@@ -116,6 +120,7 @@
 option_if_not_defined(SWIFTSHADER_BUILD_GLES_CM "Build the OpenGL ES 1.1 library" TRUE)
 option_if_not_defined(SWIFTSHADER_BUILD_VULKAN "Build the Vulkan library" TRUE)
 option_if_not_defined(SWIFTSHADER_BUILD_WSI_WAYLAND "Build the Wayland WSI support" FALSE)
+option_if_not_defined(SWIFTSHADER_BUILD_WSI_DIRECTFB "Build the DirectFB WSI support" FALSE)
 option_if_not_defined(SWIFTSHADER_BUILD_PVR "Build the PowerVR examples" TRUE)
 option_if_not_defined(SWIFTSHADER_GET_PVR "Check out the PowerVR submodule" FALSE)
 option_if_not_defined(SWIFTSHADER_BUILD_ANGLE "Build angle" FALSE)
@@ -647,6 +652,10 @@
     if(SWIFTSHADER_BUILD_WSI_WAYLAND)
         list(APPEND OS_LIBS "${WAYLAND}")
     endif(SWIFTSHADER_BUILD_WSI_WAYLAND)
+    if(SWIFTSHADER_BUILD_WSI_DIRECTFB)
+        list(APPEND OS_LIBS "${DIRECTFB}")
+        include_directories(${DIRECTFB_INCLUDE_DIR}/directfb)
+    endif(SWIFTSHADER_BUILD_WSI_DIRECTFB)
 elseif(FUCHSIA)
     set(OS_LIBS zircon)
 elseif(APPLE)
@@ -732,6 +741,11 @@
                 target_compile_definitions(vk_base INTERFACE "VK_USE_PLATFORM_WAYLAND_KHR")
             endif()
         endif(SWIFTSHADER_BUILD_WSI_WAYLAND)
+        if(SWIFTSHADER_BUILD_WSI_DIRECTFB)
+            if(DIRECTFB AND DIRECTFB_INCLUDE_DIR)
+                target_compile_definitions(vk_base INTERFACE "VK_USE_PLATFORM_DIRECTFB_EXT")
+            endif()
+        endif(SWIFTSHADER_BUILD_WSI_DIRECTFB)
     elseif(APPLE)
         target_compile_definitions(vk_base INTERFACE "VK_USE_PLATFORM_MACOS_MVK")
     elseif(FUCHSIA)
diff --git a/src/Vulkan/VkGetProcAddress.cpp b/src/Vulkan/VkGetProcAddress.cpp
index dfa3bb8..49784ac 100644
--- a/src/Vulkan/VkGetProcAddress.cpp
+++ b/src/Vulkan/VkGetProcAddress.cpp
@@ -119,6 +119,11 @@
 	MAKE_VULKAN_INSTANCE_ENTRY(vkCreateWaylandSurfaceKHR),
 	MAKE_VULKAN_INSTANCE_ENTRY(vkGetPhysicalDeviceWaylandPresentationSupportKHR),
 #endif
+#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
+	// VK_EXT_directfb_surface
+	MAKE_VULKAN_INSTANCE_ENTRY(vkCreateDirectFBSurfaceEXT),
+	MAKE_VULKAN_INSTANCE_ENTRY(vkGetPhysicalDeviceDirectFBPresentationSupportEXT),
+#endif
 #ifdef VK_USE_PLATFORM_MACOS_MVK
 	// VK_MVK_macos_surface
 	MAKE_VULKAN_INSTANCE_ENTRY(vkCreateMacOSSurfaceMVK),
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index efb2bf4..b630658 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -61,6 +61,10 @@
 #	include "WSI/WaylandSurfaceKHR.hpp"
 #endif
 
+#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
+#	include "WSI/DirectFBSurfaceEXT.hpp"
+#endif
+
 #ifdef VK_USE_PLATFORM_WIN32_KHR
 #	include "WSI/Win32SurfaceKHR.hpp"
 #endif
@@ -308,6 +312,9 @@
 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
 	{ VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, VK_KHR_WAYLAND_SURFACE_SPEC_VERSION },
 #endif
+#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
+	{ VK_EXT_DIRECTFB_SURFACE_EXTENSION_NAME, VK_EXT_DIRECTFB_SURFACE_SPEC_VERSION },
+#endif
 #ifdef VK_USE_PLATFORM_MACOS_MVK
 	{ VK_MVK_MACOS_SURFACE_EXTENSION_NAME, VK_MVK_MACOS_SURFACE_SPEC_VERSION },
 #endif
@@ -3478,6 +3485,24 @@
 }
 #endif
 
+#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateDirectFBSurfaceEXT(VkInstance instance, const VkDirectFBSurfaceCreateInfoEXT *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface)
+{
+	TRACE("(VkInstance instance = %p, VkDirectFBSurfaceCreateInfoEXT* pCreateInfo = %p, VkAllocationCallbacks* pAllocator = %p, VkSurface* pSurface = %p)",
+	      instance, pCreateInfo, pAllocator, pSurface);
+
+	return vk::DirectFBSurfaceEXT::Create(pAllocator, pCreateInfo, pSurface);
+}
+
+VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceDirectFBPresentationSupportEXT(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, IDirectFB *dfb)
+{
+	TRACE("(VkPhysicalDevice physicalDevice = %p, uint32_t queueFamilyIndex = %d, IDirectFB* dfb = %p)",
+	      physicalDevice, int(queueFamilyIndex), dfb);
+
+	return VK_TRUE;
+}
+#endif
+
 #ifdef VK_USE_PLATFORM_MACOS_MVK
 VKAPI_ATTR VkResult VKAPI_CALL vkCreateMacOSSurfaceMVK(VkInstance instance, const VkMacOSSurfaceCreateInfoMVK *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface)
 {
diff --git a/src/WSI/CMakeLists.txt b/src/WSI/CMakeLists.txt
index d161c5a..1f7025e 100644
--- a/src/WSI/CMakeLists.txt
+++ b/src/WSI/CMakeLists.txt
@@ -52,6 +52,13 @@
             WaylandSurfaceKHR.hpp
         )
     endif()
+
+    if(DIRECTFB)
+        list(APPEND WSI_SRC_FILES
+            DirectFBSurfaceEXT.cpp
+            DirectFBSurfaceEXT.hpp
+        )
+    endif()
 elseif(APPLE)
     list(APPEND WSI_SRC_FILES
         MetalSurface.mm
diff --git a/src/WSI/DirectFBSurfaceEXT.cpp b/src/WSI/DirectFBSurfaceEXT.cpp
new file mode 100644
index 0000000..f9f0a22
--- /dev/null
+++ b/src/WSI/DirectFBSurfaceEXT.cpp
@@ -0,0 +1,89 @@
+// Copyright 2020 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 "DirectFBSurfaceEXT.hpp"
+
+#include "Vulkan/VkDeviceMemory.hpp"
+#include "Vulkan/VkImage.hpp"
+
+namespace vk {
+
+DirectFBSurfaceEXT::DirectFBSurfaceEXT(const VkDirectFBSurfaceCreateInfoEXT *pCreateInfo, void *mem)
+    : dfb(pCreateInfo->dfb)
+    , surface(pCreateInfo->surface)
+{
+}
+
+void DirectFBSurfaceEXT::destroySurface(const VkAllocationCallbacks *pAllocator)
+{
+}
+
+size_t DirectFBSurfaceEXT::ComputeRequiredAllocationSize(const VkDirectFBSurfaceCreateInfoEXT *pCreateInfo)
+{
+	return 0;
+}
+
+void DirectFBSurfaceEXT::getSurfaceCapabilities(VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) const
+{
+	SurfaceKHR::getSurfaceCapabilities(pSurfaceCapabilities);
+
+	int width, height;
+	surface->GetSize(surface, &width, &height);
+	VkExtent2D extent = { static_cast<uint32_t>(width), static_cast<uint32_t>(height) };
+
+	pSurfaceCapabilities->currentExtent = extent;
+	pSurfaceCapabilities->minImageExtent = extent;
+	pSurfaceCapabilities->maxImageExtent = extent;
+}
+
+void DirectFBSurfaceEXT::attachImage(PresentImage *image)
+{
+	DFBSurfaceDescription desc;
+	desc.flags = static_cast<DFBSurfaceDescriptionFlags>(DSDESC_PIXELFORMAT | DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PREALLOCATED);
+	desc.pixelformat = DSPF_RGB32;
+	const VkExtent3D &extent = image->getImage()->getExtent();
+	desc.width = extent.width;
+	desc.height = extent.height;
+	desc.preallocated[0].data = image->getImageMemory()->getOffsetPointer(0);
+	desc.preallocated[0].pitch = image->getImage()->rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0);
+	IDirectFBSurface *dfbImage;
+	dfb->CreateSurface(dfb, &desc, &dfbImage);
+	imageMap[image] = dfbImage;
+}
+
+void DirectFBSurfaceEXT::detachImage(PresentImage *image)
+{
+	auto it = imageMap.find(image);
+	if(it != imageMap.end())
+	{
+		IDirectFBSurface *dfbImage = it->second;
+		dfbImage->Release(dfbImage);
+		imageMap.erase(it);
+	}
+}
+
+VkResult DirectFBSurfaceEXT::present(PresentImage *image)
+{
+	auto it = imageMap.find(image);
+	if(it != imageMap.end())
+	{
+		IDirectFBSurface *dfbImage = it->second;
+		surface->Blit(surface, dfbImage, NULL, 0, 0);
+		surface->Flip(surface, NULL, DSFLIP_WAITFORSYNC);
+	}
+
+	return VK_SUCCESS;
+}
+
+}  // namespace vk
diff --git a/src/WSI/DirectFBSurfaceEXT.hpp b/src/WSI/DirectFBSurfaceEXT.hpp
new file mode 100644
index 0000000..07cd600
--- /dev/null
+++ b/src/WSI/DirectFBSurfaceEXT.hpp
@@ -0,0 +1,50 @@
+// Copyright 2020 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_DIRECTFBSURFACEEXT_HPP
+#define SWIFTSHADER_DIRECTFBSURFACEEXT_HPP
+
+#include "VkSurfaceKHR.hpp"
+#include "Vulkan/VkObject.hpp"
+
+#include <directfb.h>
+#include <vulkan/vulkan_directfb.h>
+
+#include <unordered_map>
+
+namespace vk {
+
+class DirectFBSurfaceEXT : public SurfaceKHR, public ObjectBase<DirectFBSurfaceEXT, VkSurfaceKHR>
+{
+public:
+	DirectFBSurfaceEXT(const VkDirectFBSurfaceCreateInfoEXT *pCreateInfo, void *mem);
+
+	void destroySurface(const VkAllocationCallbacks *pAllocator) override;
+
+	static size_t ComputeRequiredAllocationSize(const VkDirectFBSurfaceCreateInfoEXT *pCreateInfo);
+
+	void getSurfaceCapabilities(VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) const override;
+
+	virtual void attachImage(PresentImage *image) override;
+	virtual void detachImage(PresentImage *image) override;
+	VkResult present(PresentImage *image) override;
+
+private:
+	IDirectFB *dfb;
+	IDirectFBSurface *surface;
+	std::unordered_map<PresentImage *, IDirectFBSurface *> imageMap;
+};
+
+}  // namespace vk
+#endif  //SWIFTSHADER_DIRECTFBSURFACEEXT_HPP