/* * Copyright (C) 2019 The Android Open Source Project * * 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 TNT_FILAMENT_BACKEND_PLATFORMS_VULKANPLATFORM_H #define TNT_FILAMENT_BACKEND_PLATFORMS_VULKANPLATFORM_H #include #include #include #include #include #include namespace filament::backend { using SwapChain = Platform::SwapChain; /** * Private implementation details for the provided vulkan platform. */ struct VulkanPlatformPrivate; /** * A Platform interface that creates a Vulkan backend. */ class VulkanPlatform : public Platform, utils::PrivateImplementation { public: /** * A collection of handles to objects and metadata that comprises a Vulkan context. The client * can instantiate this struct and pass to Engine::Builder::sharedContext if they wishes to * share their vulkan context. This is specifically necessary if the client wishes to override * the swapchain API. */ struct VulkanSharedContext { VkInstance instance = VK_NULL_HANDLE; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; VkDevice logicalDevice = VK_NULL_HANDLE; uint32_t graphicsQueueFamilyIndex = 0xFFFFFFFF; // In the usual case, the client needs to allocate at least one more graphics queue // for Filament, and this index is the param to pass into vkGetDeviceQueue. In the case // where the gpu only has one graphics queue. Then the client needs to ensure that no // concurrent access can occur. uint32_t graphicsQueueIndex = 0xFFFFFFFF; }; /** * Shorthand for the pointer to the Platform SwapChain struct, we use it also as a handle (i.e. * identifier for the swapchain). */ using SwapChainPtr = Platform::SwapChain*; /** * Collection of images, formats, and extent (width/height) that defines the swapchain. */ struct SwapChainBundle { utils::FixedCapacityVector colors; VkImage depth = VK_NULL_HANDLE; VkFormat colorFormat = VK_FORMAT_UNDEFINED; VkFormat depthFormat = VK_FORMAT_UNDEFINED; VkExtent2D extent = {0, 0}; }; VulkanPlatform(); ~VulkanPlatform() override; Driver* createDriver(void* sharedContext, Platform::DriverConfig const& driverConfig) noexcept override; int getOSVersion() const noexcept override { return 0; } // ---------------------------------------------------- // ---------- Platform Customization options ---------- /** * The client preference can be stored within the struct. We allow for two specification of * preference: * 1) A substring to match against `VkPhysicalDeviceProperties.deviceName`. * 2) Index of the device in the list as returned by vkEnumeratePhysicalDevices. */ struct GPUPreference { std::string deviceName; int8_t index = -1; }; /** * Client can provide a preference over the GPU to use in the vulkan instance * @return `GPUPreference` struct that indicates the client's preference */ virtual GPUPreference getPreferredGPU() noexcept { return {}; } // -------- End platform customization options -------- // ---------------------------------------------------- /** * Returns whether the platform supports sRGB swapchain. This is true by default, and the client * needs to override this method to specify otherwise. * @return Whether the platform supports sRGB swapchain. */ virtual bool isSRGBSwapChainSupported() const { return true; } /** * Get the images handles and format of the memory backing the swapchain. This should be called * after createSwapChain() or after recreateIfResized(). * @param swapchain The handle returned by createSwapChain() * @return An array of VkImages */ virtual SwapChainBundle getSwapChainBundle(SwapChainPtr handle); /** * Acquire the next image for rendering. The `index` will be written with an non-negative * integer that the backend can use to index into the `SwapChainBundle.colors` array. The * corresponding VkImage will be used as the output color attachment. The client should signal * the `clientSignal` semaphore when the image is ready to be used by the backend. * @param handle The handle returned by createSwapChain() * @param clientSignal The semaphore that the client will signal to indicate that the backend * may render into the image. * @param index Pointer to memory that will be filled with the index that corresponding * to an image in the `SwapChainBundle.colors` array. * @return Result of acquire */ virtual VkResult acquire(SwapChainPtr handle, VkSemaphore clientSignal, uint32_t* index); /** * Present the image corresponding to `index` to the display. The client should wait on * `finishedDrawing` before presenting. * @param handle The handle returned by createSwapChain() * @param index Index that corresponding to an image in the * `SwapChainBundle.colors` array. * @param finishedDrawing Backend passes in a semaphore that the client will signal to * indicate that the client may render into the image. * @return Result of present */ virtual VkResult present(SwapChainPtr handle, uint32_t index, VkSemaphore finishedDrawing); /** * Check if the surface size has changed. * @param handle The handle returned by createSwapChain() * @return Whether the swapchain has been resized */ virtual bool hasResized(SwapChainPtr handle); /** * Carry out a recreation of the swapchain. * @param handle The handle returned by createSwapChain() * @return Result of the recreation */ virtual VkResult recreate(SwapChainPtr handle); /** * Create a swapchain given a platform window, or if given a null `nativeWindow`, then we * try to create a headless swapchain with the given `extent`. * @param flags Optional parameters passed to the client as defined in * Filament::SwapChain.h. * @param extent Optional width and height that indicates the size of the headless swapchain. * @return Result of the operation */ virtual SwapChainPtr createSwapChain(void* nativeWindow, uint64_t flags = 0, VkExtent2D extent = {0, 0}); /** * Destroy the swapchain. * @param handle The handle returned by createSwapChain() */ virtual void destroy(SwapChainPtr handle); /** * Clean up any resources owned by the Platform. For example, if the Vulkan instance handle was * generated by the platform, we need to clean it up in this method. */ virtual void terminate(); /** * @return The instance (VkInstance) for the Vulkan backend. */ VkInstance getInstance() const noexcept; /** * @return The logical device (VkDevice) that was selected as the backend device. */ VkDevice getDevice() const noexcept; /** * @return The physical device (i.e gpu) that was selected as the backend physical device. */ VkPhysicalDevice getPhysicalDevice() const noexcept; /** * @return The family index of the graphics queue selected for the Vulkan backend. */ uint32_t getGraphicsQueueFamilyIndex() const noexcept; /** * @return The index of the graphics queue (if there are multiple graphics queues) * selected for the Vulkan backend. */ uint32_t getGraphicsQueueIndex() const noexcept; /** * @return The queue that was selected for the Vulkan backend. */ VkQueue getGraphicsQueue() const noexcept; private: // Platform dependent helper methods using ExtensionSet = std::unordered_set; static ExtensionSet getRequiredInstanceExtensions(); using SurfaceBundle = std::tuple; static SurfaceBundle createVkSurfaceKHR(void* nativeWindow, VkInstance instance, uint64_t flags) noexcept; friend struct VulkanPlatformPrivate; }; }// namespace filament::backend #endif// TNT_FILAMENT_BACKEND_PLATFORMS_VULKANPLATFORM_H