添加帧同步函数

使用以下函数将 Android Frame Pacing 与基于 Vulkan API 的渲染引擎结合使用。

确定创建实例所需的扩展

如需在使用 Vulkan 时收集创建 Android Frame Pacing 实例所需的扩展集,请完成以下代码段中所示的步骤:

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);

然后,您可以通过调用 vkCreateDevice() 启动 Android Frame Pacing。第二个参数(类型为 VkDeviceCreateInfo* 的结构体)应将其 enabledExtensionCount 成员设置为所需扩展的数量。

确定队列系列

为了呈现正确的显示队列,Android Frame Pacing 需要知道 Vulkan 使用的是哪个队列系列。如需确定正确的系列,请完成以下代码段中所示的步骤:

// 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);

定义交换链的帧速率

如需初始化指定物理设备和交换链的 Android Frame Pacing,请完成以下代码段中所示的步骤:

// 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);

这决定了以纳秒为单位的交换时长。swappy_common.h 中定义了用于确定通用交换时长的帮助程序宏(例如 SWAPPY_SWAP_60FPS)。

接着,您需要提供以纳秒为单位的交换时长。

// 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);

设置 ANativeWindow

Swappy 需要 ANativeWindow 的句柄才能执行特定于 ANativeWindow 的操作,例如调用 ANativeWindow_setFrameRate()。如果您的 Android 显示 Surface 发生变化,并且您有新的 ANativeWindow 句柄,请调用 SwappyVk_setWindow()(请参阅 Cube 示例)。

自动模式

Android Frame Pacing 会基于先前帧的平均时长调整交换时长和流水线模式。您可以使用以下函数控制此行为:

呈现帧

如需向 Android Frame Pacing 呈现游戏帧,请调用 SwappyVk_queuePresent()。此函数将代表您的游戏调用 vkQueuePresentKHR()

销毁交换链

如需销毁与给定交换链相关联的 SwappyVk 数据,请完成以下代码段中所示的步骤:

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

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