Use the following functions to use Android Frame Pacing with a rendering engine based on the Vulkan API.
Identify required extensions for creation
To gather the set of extensions necessary to create an instance of Android Frame Pacing when using Vulkan, complete the steps shown in the following code snippet:
VkPhysicalDevice physicalDevice; uint32_t availableExtensionCount; VkExtensionProperties* pAvailableExtensions; uint32_t requiredExtensionCount; char** pRequiredExtensions; // Determine the number of extensions available for this device. vkEnumerateDeviceExtensionProperties(physicalDevice, layerName, &availableExtensionCount, pAvailableExtensions); // Determine the number of required extensions. SwappyVk_determineDeviceExtensions(physicalDevice, availableExtensionCount, pAvailableExtensions, &requiredExtensionCount, nullptr); // Determine the required extensions. pRequiredExtensions = (char**)malloc(requiredExtensionCount * sizeof(char*)); pRequiredExtensionsData = (char*)malloc(requiredExtensionCount * (VK_MAX_EXTENSION_NAME_SIZE + 1)); for (uint32_t i = 0; i < requiredExtensionCount; i++) { pRequiredExtensions[i] = &pRequiredExtensionsData[i * (VK_MAX_EXTENSION_NAME_SIZE + 1)]; } SwappyVk_determineDeviceExtensions(physicalDevice, availableExtensionCount, pAvailableExtensions, &requiredExtensionCount, pRequiredExtensions);
You can then start Android Frame Pacing by calling vkCreateDevice()
. The 2nd
argument, a struct of type VkDeviceCreateInfo*
, should have its
enabledExtensionCount
member set to the number of required extensions.
Identify queue family
To present the correct display queue, Android Frame Pacing needs to know which queue family Vulkan is using. To determine the correct family, complete the steps shown in the following code snippet:
// Reusing local variables from previous snippets: // VkPhysicalDevice physicalDevice; const VkDeviceCreateInfo createInfo; const VkAllocationCallbacks allocator; VkDevice device; uint32_t queueFamilyIndex; uint32_t queueIndex; VkQueue deviceQueue; // Values of "device" and "deviceQueue" set in the 1st and 2nd function // calls, respectively. vkCreateDevice(physicalDevice, &createInfo, &allocator, &device); vkGetDeviceQueue(device, queueFamilyIndex, queueIndex, &deviceQueue); SwappyVk_setQueueFamilyIndex(device, deviceQueue, queueFamilyIndex);
Define framerate for swapchain
To initialize Android Frame Pacing for a given physical device and swapchain, complete the steps shown in the following code snippet:
// Reusing local variables from previous snippets: // VkPhysicalDevice physicalDevice; // VkDevice device; // Assume that the JNI environment is available in: // JNIEnv *env; // jobject jactivity; // Assume that swapchain is already known. VkSwapchainKHR swapchain; uint64_t refreshDuration; // in nanoseconds // Determine duration between vertical-blanking periods. // Example: 60 FPS sets "refreshDuration" to 16,666,666. SwappyVk_initAndGetRefreshCycleDuration(env, jactivity, physicalDevice, device, swapchain, &refreshDuration);
This determines the swap duration in nanoseconds. There are helper macros
defined in swappy_common.h
for common swap durations (for example,
SWAPPY_SWAP_60FPS
).
Next, you need to supply the swap duration in nanoseconds.
// Declare the periods in nanoseconds that should elapse before refreshing one // image with the next image. There are helper macros defined in swappy_common.h // for common swap durations. // This example shows what to do when you want to render your game at 30 FPS. SwappyVk_setSwapIntervalNS(device, swapchain, SWAPPY_SWAP_30FPS);
Setting the ANativeWindow
Swappy needs the handle of ANativeWindow
in order to perform
ANativeWindow
-specific operation, such as calling
ANativeWindow_setFrameRate()
.
Call
SwappyVk_setWindow()
when your Android display surface has changed and you have a new ANativeWindow
handle (see the Cube sample for an example).
Auto Modes
Android Frame Pacing adjusts the swap duration and pipeline mode based on the average duration of previous frames. You can control this behavior with the following functions:
void SwappyVk_setAutoSwapInterval(bool enabled);
void SwappyVk_setMaxAutoSwapIntervalNS(uint64_t max_swap_ns);
void SwappyVk_setAutoPipelineMode(bool enabled);
Present a frame
To present a frame of your game to Android Frame Pacing, call
SwappyVk_queuePresent()
.
This function calls vkQueuePresentKHR()
on behalf of your game.
Destroy the swapchain
To destroy the SwappyVk
data associated with a given swapchain, complete the
steps shown in the following code snippet:
// Reusing local variables from previous snippets: // VkDevice device; // VkSwapchainKHR swapchain; // const VkAllocationCallbacks allocator; SwappyVk_destroySwapchain(device, swapchain); vkDestroySwapchainKHR(device, swapchain, &allocator);