添加帧同步函数

请使用以下函数,通过基于 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 显示 surface 发生变化并且您有新的 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);