From f2556ab35c0eecdfd93c02f7c226a5c94316d143 Mon Sep 17 00:00:00 2001 From: Alexander Vestin Date: Fri, 25 Mar 2022 13:18:46 +0000 Subject: [PATCH] Initial Android surface Bug: dawn:286 Change-Id: I50b45706f031254ac5beba5c07c3c4c3d7f9ea12 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/84200 Reviewed-by: Austin Eng Commit-Queue: Corentin Wallez --- CMakeLists.txt | 5 +- dawn_wire.json | 3 +- src/dawn/native/Surface.cpp | 26 +++++++- src/dawn/native/Surface.h | 15 ++++- src/dawn/native/SwapChain.cpp | 14 +++-- src/dawn/native/vulkan/SwapChainVk.cpp | 69 ++++++++++++++++----- src/dawn/native/vulkan/VulkanExtensions.cpp | 2 + src/dawn/native/vulkan/VulkanExtensions.h | 1 + src/dawn/native/vulkan/VulkanFunctions.cpp | 6 ++ src/dawn/native/vulkan/VulkanFunctions.h | 4 ++ src/dawn/utils/CMakeLists.txt | 1 - third_party/CMakeLists.txt | 2 +- 12 files changed, 123 insertions(+), 25 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3813bfebbb..6dd0b0261b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -88,6 +88,9 @@ if (WIN32) endif() elseif(APPLE) set(ENABLE_METAL ON) +elseif(ANDROID) + set(ENABLE_VULKAN ON) + set(ENABLE_OPENGLES ON) elseif(UNIX) set(ENABLE_OPENGLES ON) set(ENABLE_DESKTOP_GL ON) @@ -96,7 +99,7 @@ elseif(UNIX) endif() # GLFW is not supported in UWP -if((WIN32 AND NOT WINDOWS_STORE) OR UNIX) +if((WIN32 AND NOT WINDOWS_STORE) OR UNIX AND NOT ANDROID) set(DAWN_SUPPORTS_GLFW_FOR_WINDOWING ON) endif() diff --git a/dawn_wire.json b/dawn_wire.json index 58ef049024..2e2318efb1 100644 --- a/dawn_wire.json +++ b/dawn_wire.json @@ -176,7 +176,8 @@ "SurfaceDescriptorFromWindowsHWND", "SurfaceDescriptorFromXlibWindow", "SurfaceDescriptorFromWindowsCoreWindow", - "SurfaceDescriptorFromWindowsSwapChainPanel" + "SurfaceDescriptorFromWindowsSwapChainPanel", + "SurfaceDescriptorFromAndroidNativeWindow" ], "client_side_commands": [ "AdapterCreateDevice", diff --git a/src/dawn/native/Surface.cpp b/src/dawn/native/Surface.cpp index bede05f09e..378a2756b7 100644 --- a/src/dawn/native/Surface.cpp +++ b/src/dawn/native/Surface.cpp @@ -50,6 +50,9 @@ namespace dawn::native { case Surface::Type::Xlib: s->Append("Xlib"); break; + case Surface::Type::AndroidWindow: + s->Append("AndroidWindow"); + break; } return {true}; } @@ -65,6 +68,7 @@ namespace dawn::native { descriptor); DAWN_TRY(ValidateSingleSType(descriptor->nextInChain, + wgpu::SType::SurfaceDescriptorFromAndroidNativeWindow, wgpu::SType::SurfaceDescriptorFromMetalLayer, wgpu::SType::SurfaceDescriptorFromWindowsHWND, wgpu::SType::SurfaceDescriptorFromWindowsCoreWindow, @@ -82,6 +86,17 @@ namespace dawn::native { } #endif // defined(DAWN_ENABLE_BACKEND_METAL) +#if defined(DAWN_PLATFORM_ANDROID) + const SurfaceDescriptorFromAndroidNativeWindow* androidDesc = nullptr; + FindInChain(descriptor->nextInChain, &androidDesc); + // Currently the best validation we can do since it's not possible to check if the pointer + // to a ANativeWindow is valid. + if (androidDesc) { + DAWN_INVALID_IF(androidDesc->window == nullptr, "Android window is not set."); + return {}; + } +#endif // defined(DAWN_PLATFORM_ANDROID) + #if defined(DAWN_PLATFORM_WINDOWS) # if defined(DAWN_PLATFORM_WIN32) const SurfaceDescriptorFromWindowsHWND* hwndDesc = nullptr; @@ -142,20 +157,24 @@ namespace dawn::native { Surface::Surface(InstanceBase* instance, const SurfaceDescriptor* descriptor) : mInstance(instance) { ASSERT(descriptor->nextInChain != nullptr); + const SurfaceDescriptorFromAndroidNativeWindow* androidDesc = nullptr; const SurfaceDescriptorFromMetalLayer* metalDesc = nullptr; const SurfaceDescriptorFromWindowsHWND* hwndDesc = nullptr; const SurfaceDescriptorFromWindowsCoreWindow* coreWindowDesc = nullptr; const SurfaceDescriptorFromWindowsSwapChainPanel* swapChainPanelDesc = nullptr; const SurfaceDescriptorFromXlibWindow* xDesc = nullptr; + FindInChain(descriptor->nextInChain, &androidDesc); FindInChain(descriptor->nextInChain, &metalDesc); FindInChain(descriptor->nextInChain, &hwndDesc); FindInChain(descriptor->nextInChain, &coreWindowDesc); FindInChain(descriptor->nextInChain, &swapChainPanelDesc); FindInChain(descriptor->nextInChain, &xDesc); - ASSERT(metalDesc || hwndDesc || xDesc); if (metalDesc) { mType = Type::MetalLayer; mMetalLayer = metalDesc->layer; + } else if (androidDesc) { + mType = Type::AndroidWindow; + mAndroidNativeWindow = androidDesc->window; } else if (hwndDesc) { mType = Type::WindowsHWND; mHInstance = hwndDesc->hinstance; @@ -202,6 +221,11 @@ namespace dawn::native { return mType; } + void* Surface::GetAndroidNativeWindow() const { + ASSERT(mType == Type::AndroidWindow); + return mAndroidNativeWindow; + } + void* Surface::GetMetalLayer() const { ASSERT(mType == Type::MetalLayer); return mMetalLayer; diff --git a/src/dawn/native/Surface.h b/src/dawn/native/Surface.h index c6320af71c..367a2985af 100644 --- a/src/dawn/native/Surface.h +++ b/src/dawn/native/Surface.h @@ -50,13 +50,23 @@ namespace dawn::native { NewSwapChainBase* GetAttachedSwapChain(); // These are valid to call on all Surfaces. - enum class Type { MetalLayer, WindowsHWND, WindowsCoreWindow, WindowsSwapChainPanel, Xlib }; + enum class Type { + AndroidWindow, + MetalLayer, + WindowsHWND, + WindowsCoreWindow, + WindowsSwapChainPanel, + Xlib + }; Type GetType() const; InstanceBase* GetInstance(); // Valid to call if the type is MetalLayer void* GetMetalLayer() const; + // Valid to call if the type is Android + void* GetAndroidNativeWindow() const; + // Valid to call if the type is WindowsHWND void* GetHInstance() const; void* GetHWND() const; @@ -83,6 +93,9 @@ namespace dawn::native { // MetalLayer void* mMetalLayer = nullptr; + // ANativeWindow + void* mAndroidNativeWindow = nullptr; + // WindowsHwnd void* mHInstance = nullptr; void* mHWND = nullptr; diff --git a/src/dawn/native/SwapChain.cpp b/src/dawn/native/SwapChain.cpp index 6b4c331a30..5fffc09db1 100644 --- a/src/dawn/native/SwapChain.cpp +++ b/src/dawn/native/SwapChain.cpp @@ -74,11 +74,17 @@ namespace dawn::native { DAWN_TRY(ValidatePresentMode(descriptor->presentMode)); - // TODO(crbug.com/dawn/160): Lift this restriction once - // wgpu::Instance::GetPreferredSurfaceFormat is implemented. - DAWN_INVALID_IF(descriptor->format != wgpu::TextureFormat::BGRA8Unorm, +// TODO(crbug.com/dawn/160): Lift this restriction once wgpu::Instance::GetPreferredSurfaceFormat is +// implemented. +// TODO(dawn:286): +#if defined(DAWN_PLATFORM_ANDROID) + constexpr wgpu::TextureFormat kRequireSwapChainFormat = wgpu::TextureFormat::RGBA8Unorm; +#else + constexpr wgpu::TextureFormat kRequireSwapChainFormat = wgpu::TextureFormat::BGRA8Unorm; +#endif // !defined(DAWN_PLATFORM_ANDROID) + DAWN_INVALID_IF(descriptor->format != kRequireSwapChainFormat, "Format (%s) is not %s, which is (currently) the only accepted format.", - descriptor->format, wgpu::TextureFormat::BGRA8Unorm); + descriptor->format, kRequireSwapChainFormat); DAWN_INVALID_IF(descriptor->usage != wgpu::TextureUsage::RenderAttachment, "Usage (%s) is not %s, which is (currently) the only accepted usage.", diff --git a/src/dawn/native/vulkan/SwapChainVk.cpp b/src/dawn/native/vulkan/SwapChainVk.cpp index d0750e6709..2c80d06f0a 100644 --- a/src/dawn/native/vulkan/SwapChainVk.cpp +++ b/src/dawn/native/vulkan/SwapChainVk.cpp @@ -134,6 +134,30 @@ namespace dawn::native::vulkan { break; #endif // defined(DAWN_PLATFORM_WINDOWS) +#if defined(DAWN_PLATFORM_ANDROID) + case Surface::Type::AndroidWindow: { + if (info.HasExt(InstanceExt::AndroidSurface)) { + ASSERT(surface->GetAndroidNativeWindow() != nullptr); + + VkAndroidSurfaceCreateInfoKHR createInfo; + createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR; + createInfo.pNext = nullptr; + createInfo.flags = 0; + createInfo.window = + static_cast(surface->GetAndroidNativeWindow()); + + VkSurfaceKHR vkSurface = VK_NULL_HANDLE; + DAWN_TRY(CheckVkSuccess( + fn.CreateAndroidSurfaceKHR(instance, &createInfo, nullptr, &*vkSurface), + "CreateAndroidSurfaceKHR")); + return vkSurface; + } + + break; + } + +#endif // defined(DAWN_PLATFORM_ANDROID) + #if defined(DAWN_USE_X11) case Surface::Type::Xlib: { if (info.HasExt(InstanceExt::XlibSurface)) { @@ -382,22 +406,22 @@ namespace dawn::native::vulkan { config.wgpuUsage = GetUsage(); } - // Only support BGRA8Unorm with SRGB color space for now. - bool hasBGRA8Unorm = false; + // Only support BGRA8Unorm (and RGBA8Unorm on android) with SRGB color space for now. + config.wgpuFormat = GetFormat(); + config.format = VulkanImageFormat(ToBackend(GetDevice()), config.wgpuFormat); + config.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; + + bool formatIsSupported = false; for (const VkSurfaceFormatKHR& format : surfaceInfo.formats) { - if (format.format == VK_FORMAT_B8G8R8A8_UNORM && - format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - hasBGRA8Unorm = true; + if (format.format == config.format && format.colorSpace == config.colorSpace) { + formatIsSupported = true; break; } } - if (!hasBGRA8Unorm) { - return DAWN_INTERNAL_ERROR( - "Vulkan SwapChain must support BGRA8Unorm with sRGB colorspace."); + if (!formatIsSupported) { + return DAWN_INTERNAL_ERROR(absl::StrFormat( + "Vulkan SwapChain must support %s with sRGB colorspace.", config.wgpuFormat)); } - config.format = VK_FORMAT_B8G8R8A8_UNORM; - config.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; - config.wgpuFormat = wgpu::TextureFormat::BGRA8Unorm; // Only the identity transform with opaque alpha is supported for now. DAWN_INVALID_IF((surfaceInfo.capabilities.supportedTransforms & @@ -406,11 +430,26 @@ namespace dawn::native::vulkan { config.transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; - DAWN_INVALID_IF((surfaceInfo.capabilities.supportedCompositeAlpha & - VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) == 0, - "Vulkan SwapChain must support opaque alpha."); - config.alphaMode = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; +#if !defined(DAWN_PLATFORM_ANDROID) + DAWN_INVALID_IF((surfaceInfo.capabilities.supportedCompositeAlpha & + VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) == 0, + "Vulkan SwapChain must support opaque alpha."); +#else + // TODO(dawn:286): investigate composite alpha for WebGPU native + VkCompositeAlphaFlagBitsKHR compositeAlphaFlags[4] = { + VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR, + VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR, + VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR, + }; + for (uint32_t i = 0; i < 4; i++) { + if (surfCapabilities.supportedCompositeAlpha & compositeAlphaFlags[i]) { + config.alphaMode = compositeAlphaFlags[i]; + break; + } + } +#endif // #if !defined(DAWN_PLATFORM_ANDROID) // Choose the number of images for the swapchain= and clamp it to the min and max from the // surface capabilities. maxImageCount = 0 means there is no limit. diff --git a/src/dawn/native/vulkan/VulkanExtensions.cpp b/src/dawn/native/vulkan/VulkanExtensions.cpp index e34736e061..3f54e546fc 100644 --- a/src/dawn/native/vulkan/VulkanExtensions.cpp +++ b/src/dawn/native/vulkan/VulkanExtensions.cpp @@ -47,6 +47,7 @@ namespace dawn::native::vulkan { {InstanceExt::Win32Surface, "VK_KHR_win32_surface", NeverPromoted}, {InstanceExt::XcbSurface, "VK_KHR_xcb_surface", NeverPromoted}, {InstanceExt::XlibSurface, "VK_KHR_xlib_surface", NeverPromoted}, + {InstanceExt::AndroidSurface, "VK_KHR_android_surface", NeverPromoted}, {InstanceExt::DebugUtils, "VK_EXT_debug_utils", NeverPromoted}, {InstanceExt::ValidationFeatures, "VK_EXT_validation_features", NeverPromoted}, @@ -99,6 +100,7 @@ namespace dawn::native::vulkan { hasDependencies = HasDep(InstanceExt::GetPhysicalDeviceProperties2); break; + case InstanceExt::AndroidSurface: case InstanceExt::FuchsiaImagePipeSurface: case InstanceExt::MetalSurface: case InstanceExt::WaylandSurface: diff --git a/src/dawn/native/vulkan/VulkanExtensions.h b/src/dawn/native/vulkan/VulkanExtensions.h index 4e3cf19936..d58c35e0b8 100644 --- a/src/dawn/native/vulkan/VulkanExtensions.h +++ b/src/dawn/native/vulkan/VulkanExtensions.h @@ -37,6 +37,7 @@ namespace dawn::native::vulkan { Win32Surface, XcbSurface, XlibSurface, + AndroidSurface, // Others DebugUtils, diff --git a/src/dawn/native/vulkan/VulkanFunctions.cpp b/src/dawn/native/vulkan/VulkanFunctions.cpp index 782cd5a698..48e970994a 100644 --- a/src/dawn/native/vulkan/VulkanFunctions.cpp +++ b/src/dawn/native/vulkan/VulkanFunctions.cpp @@ -147,6 +147,12 @@ namespace dawn::native::vulkan { } #endif // defined(DAWN_PLATFORM_WINDOWS) +#if defined(DAWN_PLATFORM_ANDROID) + if (globalInfo.HasExt(InstanceExt::AndroidSurface)) { + GET_INSTANCE_PROC(CreateAndroidSurfaceKHR); + } +#endif // defined(DAWN_PLATFORM_ANDROID) + #if defined(DAWN_USE_X11) if (globalInfo.HasExt(InstanceExt::XlibSurface)) { GET_INSTANCE_PROC(CreateXlibSurfaceKHR); diff --git a/src/dawn/native/vulkan/VulkanFunctions.h b/src/dawn/native/vulkan/VulkanFunctions.h index 07b8b39dc0..0de5192b68 100644 --- a/src/dawn/native/vulkan/VulkanFunctions.h +++ b/src/dawn/native/vulkan/VulkanFunctions.h @@ -132,6 +132,10 @@ namespace dawn::native::vulkan { GetPhysicalDeviceWin32PresentationSupportKHR = nullptr; #endif // defined(DAWN_PLATFORM_WINDOWS) +#if defined(DAWN_PLATFORM_ANDROID) + PFN_vkCreateAndroidSurfaceKHR CreateAndroidSurfaceKHR = nullptr; +#endif // defined(DAWN_PLATFORM_ANDROID) + #if defined(DAWN_USE_X11) // KHR_xlib_surface PFN_vkCreateXlibSurfaceKHR CreateXlibSurfaceKHR = nullptr; diff --git a/src/dawn/utils/CMakeLists.txt b/src/dawn/utils/CMakeLists.txt index 3ed0994f2f..6e4d6f7c36 100644 --- a/src/dawn/utils/CMakeLists.txt +++ b/src/dawn/utils/CMakeLists.txt @@ -43,7 +43,6 @@ target_link_libraries(dawn_utils dawn_proc dawn_wire SPIRV-Tools-opt - glfw ) if(WIN32 AND NOT WINDOWS_STORE) diff --git a/third_party/CMakeLists.txt b/third_party/CMakeLists.txt index 7c8619f2fb..136c848ff0 100644 --- a/third_party/CMakeLists.txt +++ b/third_party/CMakeLists.txt @@ -32,7 +32,7 @@ if (NOT TARGET SPIRV-Tools) add_subdirectory(${DAWN_SPIRV_TOOLS_DIR} "${CMAKE_CURRENT_BINARY_DIR}/spirv-tools") endif() -if (NOT TARGET glfw) +if (NOT TARGET glfw AND DAWN_SUPPORTS_GLFW_FOR_WINDOWING) set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE) set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE) set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)