添加帧速率调节功能

使用以下函数可以结合基于 Vulkan API 的渲染引擎使用 Android 帧速率同步。

识别创建所需的扩展

要收集使用 Vulkan 创建 Android 帧速率同步实例所需的扩展集,请完成以下代码片段中显示的步骤

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 帧速率同步。第二个参数(类型为VkDeviceCreateInfo*的结构体)的enabledExtensionCount成员应设置为所需扩展的数量。

识别队列族

为了呈现正确的显示队列,Android 帧速率同步需要知道 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 帧速率同步,请完成以下代码片段中显示的步骤

// 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 显示界面发生更改并且您有新的ANativeWindow句柄时,请调用SwappyVk_setWindow()(有关示例,请参阅Cube 示例)。

自动模式

Android 帧速率同步会根据先前帧的平均持续时间调整交换持续时间和管道模式。您可以使用以下函数控制此行为

呈现帧

要将游戏的帧呈现给 Android 帧速率同步,请调用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);