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:  

```c++
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:  

```c++
// 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:  

```c++
// 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.  

```c++
// 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()`](https://developer.android.com/ndk/reference/group/a-native-window#anativewindow_setframerate).
Call
[`SwappyVk_setWindow()`](https://developer.android.com/games/sdk/reference/frame-pacing/group/swappy-vk#swappyvk_setwindow)
when your Android display surface has changed and you have a new `ANativeWindow`
handle (see the [Cube sample](https://android.googlesource.com/platform/frameworks/opt/gamesdk/+/refs/heads/master/samples/cube/) 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);`](https://developer.android.com/games/sdk/reference/frame-pacing/group/swappy-vk#swappyvk_setautoswapinterval)
- [`void SwappyVk_setMaxAutoSwapIntervalNS(uint64_t max_swap_ns);`](https://developer.android.com/games/sdk/reference/frame-pacing/group/swappy-vk#group__swappy_vk_1ga250d3120ca0446f36be6a94975169013)
- [`void SwappyVk_setAutoPipelineMode(bool enabled);`](https://developer.android.com/games/sdk/reference/frame-pacing/group/swappy-vk#swappyvk_setautopipelinemode)

## Present a frame

To present a frame of your game to Android Frame Pacing, call
[`SwappyVk_queuePresent()`](https://developer.android.com/games/sdk/reference/frame-pacing/group/swappy-vk#swappyvk_queuepresent).
This function calls `vkQueuePresentKHR()` on behalf of your game.
| **Note:** To achieve proper frame pacing, the Android Frame Pacing API can insert Vulkan commands into the presentation queue.

## Destroy the swapchain

To destroy the `SwappyVk` data associated with a given swapchain, complete the
steps shown in the following code snippet:  

```c++
// Reusing local variables from previous snippets:
// VkDevice device;
// VkSwapchainKHR swapchain;
// const VkAllocationCallbacks allocator;

SwappyVk_destroySwapchain(device, swapchain);
vkDestroySwapchainKHR(device, swapchain, &allocator);
```