Add Swappy & Pre-Transformed Swapchain

- Adds Swappy for Android for stable frame pacing
- Implements pre-transformed Swapchain so that Godot's compositor is in
charge of rotating the screen instead of Android's compositor
(performance optimization for phones that don't have HW rotator)

============================

The work was performed by collaboration of TheForge and Google. I am
merely splitting it up into smaller PRs and cleaning it up.

Changes from original PR:

- Removed "display/window/frame_pacing/android/target_frame_rate" option
to use Engine::get_max_fps instead.
- Target framerate can be changed at runtime using Engine::set_max_fps.
- Swappy is enabled by default.
- Added documentation.
- enable_auto_swap setting is replaced with swappy_mode.
This commit is contained in:
Matias N. Goldberg
2024-05-05 19:15:56 -03:00
parent 92e51fca72
commit aaa0e2fddf
23 changed files with 1064 additions and 14 deletions

View File

@ -0,0 +1,41 @@
/*
* Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* This is the main interface to the Android Performance Tuner library, also
* known as Tuning Fork.
*
* It is part of the Android Games SDK and produces best results when integrated
* with the Swappy Frame Pacing Library.
*
* See the documentation at
* https://developer.android.com/games/sdk/performance-tuner/custom-engine for
* more information on using this library in a native Android game.
*
*/
#pragma once
// There are separate versions for each GameSDK component that use this format:
#define ANDROID_GAMESDK_PACKED_VERSION(MAJOR, MINOR, BUGFIX) \
((MAJOR << 16) | (MINOR << 8) | (BUGFIX))
// Accessors
#define ANDROID_GAMESDK_MAJOR_VERSION(PACKED) ((PACKED) >> 16)
#define ANDROID_GAMESDK_MINOR_VERSION(PACKED) (((PACKED) >> 8) & 0xff)
#define ANDROID_GAMESDK_BUGFIX_VERSION(PACKED) ((PACKED) & 0xff)
#define AGDK_STRING_VERSION(MAJOR, MINOR, BUGFIX, GIT) \
#MAJOR "." #MINOR "." #BUGFIX "." #GIT

View File

@ -0,0 +1,420 @@
/*
* Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @defgroup swappyVk Swappy for Vulkan
* Vulkan part of Swappy.
* @{
*/
#pragma once
#include "jni.h"
#include "swappy_common.h"
#ifndef VK_NO_PROTOTYPES
#define VK_NO_PROTOTYPES 1
#endif
#include <vulkan/vulkan.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Determine any Vulkan device extensions that must be enabled for a new
* VkDevice.
*
* Swappy-for-Vulkan (SwappyVk) benefits from certain Vulkan device extensions
* (e.g. VK_GOOGLE_display_timing). Before the application calls
* vkCreateDevice, SwappyVk needs to look at the list of available extensions
* (returned by vkEnumerateDeviceExtensionProperties) and potentially identify
* one or more extensions that the application must add to:
*
* - VkDeviceCreateInfo::enabledExtensionCount
* - VkDeviceCreateInfo::ppEnabledExtensionNames
*
* before the application calls vkCreateDevice. For each VkPhysicalDevice that
* the application will call vkCreateDevice for, the application must call this
* function, and then must add the identified extension(s) to the list that are
* enabled for the VkDevice. Similar to many Vulkan functions, this function
* can be called twice, once to identify the number of required extensions, and
* again with application-allocated memory that the function can write into.
*
* @param[in] physicalDevice - The VkPhysicalDevice associated with
* the available extensions.
* @param[in] availableExtensionCount - This is the returned value of
* pPropertyCount from vkEnumerateDeviceExtensionProperties.
* @param[in] pAvailableExtensions - This is the returned value of
* pProperties from vkEnumerateDeviceExtensionProperties.
* @param[inout] pRequiredExtensionCount - If pRequiredExtensions is nullptr,
* the function sets this to the number of extensions that are required. If
* pRequiredExtensions is non-nullptr, this is the number of required extensions
* that the function should write into pRequiredExtensions.
* @param[inout] pRequiredExtensions - If non-nullptr, this is
* application-allocated memory into which the function will write the names of
* required extensions. It is a pointer to an array of
* char* strings (i.e. the same as
* VkDeviceCreateInfo::ppEnabledExtensionNames).
*/
void SwappyVk_determineDeviceExtensions(
VkPhysicalDevice physicalDevice, uint32_t availableExtensionCount,
VkExtensionProperties* pAvailableExtensions,
uint32_t* pRequiredExtensionCount, char** pRequiredExtensions);
/**
* @brief Tell Swappy the queueFamilyIndex used to create a specific VkQueue
*
* Swappy needs to know the queueFamilyIndex used for creating a specific
* VkQueue so it can use it when presenting.
*
* @param[in] device - The VkDevice associated with the queue
* @param[in] queue - A device queue.
* @param[in] queueFamilyIndex - The queue family index used to create the
* VkQueue.
*
*/
void SwappyVk_setQueueFamilyIndex(VkDevice device, VkQueue queue,
uint32_t queueFamilyIndex);
// TBD: For now, SwappyVk assumes only one VkSwapchainKHR per VkDevice, and that
// applications don't re-create swapchains. Is this long-term sufficient?
/**
* Internal init function. Do not call directly.
* See SwappyVk_initAndGetRefreshCycleDuration instead.
* @private
*/
bool SwappyVk_initAndGetRefreshCycleDuration_internal(
JNIEnv* env, jobject jactivity, VkPhysicalDevice physicalDevice,
VkDevice device, VkSwapchainKHR swapchain, uint64_t* pRefreshDuration);
/**
* @brief Initialize SwappyVk for a given device and swapchain, and obtain the
* approximate time duration between vertical-blanking periods.
*
* Uses JNI to query AppVsyncOffset and PresentationDeadline.
*
* If your application presents to more than one swapchain at a time, you must
* call this for each swapchain before calling swappyVkSetSwapInterval() for it.
*
* The duration between vertical-blanking periods (an interval) is expressed as
* the approximate number of nanoseconds between vertical-blanking periods of
* the swapchains physical display.
*
* If the application converts this number to a fraction (e.g. 16,666,666 nsec
* to 0.016666666) and divides one by that fraction, it will be the approximate
* refresh rate of the display (e.g. 16,666,666 nanoseconds corresponds to a
* 60Hz display, 11,111,111 nsec corresponds to a 90Hz display).
*
* @param[in] env - JNIEnv that is assumed to be from AttachCurrentThread
* function
* @param[in] jactivity - NativeActivity object handle, used for JNI
* @param[in] physicalDevice - The VkPhysicalDevice associated with the
* swapchain
* @param[in] device - The VkDevice associated with the swapchain
* @param[in] swapchain - The VkSwapchainKHR the application wants Swappy to
* swap
* @param[out] pRefreshDuration - The returned refresh cycle duration
*
* @return bool - true if the value returned by pRefreshDuration is
* valid, otherwise false if an error.
*/
bool SwappyVk_initAndGetRefreshCycleDuration(JNIEnv* env, jobject jactivity,
VkPhysicalDevice physicalDevice,
VkDevice device,
VkSwapchainKHR swapchain,
uint64_t* pRefreshDuration);
/**
* @brief Tell Swappy which ANativeWindow to use when calling to ANativeWindow_*
* API.
* @param[in] device - The VkDevice associated with the swapchain
* @param[in] swapchain - The VkSwapchainKHR the application wants Swappy to
* swap
* @param[in] window - The ANativeWindow that was used to create the
* VkSwapchainKHR
*/
void SwappyVk_setWindow(VkDevice device, VkSwapchainKHR swapchain,
ANativeWindow* window);
/**
* @brief Tell Swappy the duration of that each presented image should be
* visible.
*
* If your application presents to more than one swapchain at a time, you must
* call this for each swapchain before presenting to it.
*
* @param[in] device - The VkDevice associated with the swapchain
* @param[in] swapchain - The VkSwapchainKHR the application wants Swappy to
* swap
* @param[in] swap_ns - The duration of that each presented image should be
* visible in nanoseconds
*/
void SwappyVk_setSwapIntervalNS(VkDevice device, VkSwapchainKHR swapchain,
uint64_t swap_ns);
/**
* @brief Tell Swappy to present one or more images to corresponding swapchains.
*
* Swappy will call vkQueuePresentKHR for your application. Swappy may insert a
* struct to the pNext-chain of VkPresentInfoKHR, or it may insert other Vulkan
* commands in order to attempt to honor the desired swap interval.
*
* @note If your application presents to more than one swapchain at a time, and
* if you use a different swap interval for each swapchain, Swappy will attempt
* to honor the swap interval for each swapchain (being more successful on
* devices that support an underlying presentation-timing extension, such as
* VK_GOOGLE_display_timing).
*
* @param[in] queue - The VkQueue associated with the device and swapchain
* @param[in] pPresentInfo - A pointer to the VkPresentInfoKHR containing the
* information about what image(s) to present on which
* swapchain(s).
*/
VkResult SwappyVk_queuePresent(VkQueue queue,
const VkPresentInfoKHR* pPresentInfo);
/**
* @brief Destroy the SwappyVk instance associated with a swapchain.
*
* This API is expected to be called before calling vkDestroySwapchainKHR()
* so Swappy can cleanup its internal state.
*
* @param[in] device - The VkDevice associated with SwappyVk
* @param[in] swapchain - The VkSwapchainKHR the application wants Swappy to
* destroy
*/
void SwappyVk_destroySwapchain(VkDevice device, VkSwapchainKHR swapchain);
/**
* @brief Destroy any swapchains associated with the device and clean up the
* device's resources
*
* This function should be called after SwappyVk_destroySwapchain if you no
* longer need the device.
*
* @param[in] device - The VkDevice associated with SwappyVk
*/
void SwappyVk_destroyDevice(VkDevice device);
/**
* @brief Enables Auto-Swap-Interval feature for all instances.
*
* By default this feature is enabled. Changing it is completely
* optional for fine-tuning swappy behaviour.
*
* @param[in] enabled - True means enable, false means disable
*/
void SwappyVk_setAutoSwapInterval(bool enabled);
/**
* @brief Enables Auto-Pipeline-Mode feature for all instances.
*
* By default this feature is enabled. Changing it is completely
* optional for fine-tuning swappy behaviour.
*
* @param[in] enabled - True means enable, false means disable
*/
void SwappyVk_setAutoPipelineMode(bool enabled);
/**
* @brief Sets the maximal swap duration for all instances.
*
* Sets the maximal duration for Auto-Swap-Interval in milliseconds.
* If SwappyVk is operating in Auto-Swap-Interval and the frame duration is
* longer than the provided duration, SwappyVk will not do any pacing and just
* submit the frame as soon as possible.
*
* @param[in] max_swap_ns - maximal swap duration in milliseconds.
*/
void SwappyVk_setMaxAutoSwapIntervalNS(uint64_t max_swap_ns);
/**
* @brief The fence timeout parameter can be set for devices with faulty
* drivers. Its default value is 50,000,000.
*/
void SwappyVk_setFenceTimeoutNS(uint64_t fence_timeout_ns);
/**
* @brief Get the fence timeout parameter, for devices with faulty
* drivers. Its default value is 50,000,000.
*/
uint64_t SwappyVk_getFenceTimeoutNS();
/**
* @brief Inject callback functions to be called each frame.
*
* @param[in] tracer - Collection of callback functions
*/
void SwappyVk_injectTracer(const SwappyTracer* tracer);
/**
* @brief Remove callbacks that were previously added using
* SwappyVk_injectTracer.
*
* Only removes callbacks that were previously added using
* SwappyVK_injectTracer. If SwappyVK_injectTracker was not called with the
* tracer, then there is no effect.
*
* @param[in] tracer - Collection of callback functions
*/
void SwappyVk_uninjectTracer(const SwappyTracer* tracer);
/**
* @brief A structure enabling you to provide your own Vulkan function wrappers
* by calling ::SwappyVk_setFunctionProvider.
*
* Usage of this functionality is optional.
*/
typedef struct SwappyVkFunctionProvider {
/**
* @brief Callback to initialize the function provider.
*
* This function is called by Swappy before any functions are requested.
* E.g. so you can call dlopen on the Vulkan library.
*/
bool (*init)();
/**
* @brief Callback to get the address of a function.
*
* This function is called by Swappy to get the address of a Vulkan
* function.
* @param name The null-terminated name of the function.
*/
void* (*getProcAddr)(const char* name);
/**
* @brief Callback to close any resources owned by the function provider.
*
* This function is called by Swappy when no more functions will be
* requested, e.g. so you can call dlclose on the Vulkan library.
*/
void (*close)();
} SwappyVkFunctionProvider;
/**
* @brief Set the Vulkan function provider.
*
* This enables you to provide an object that will be used to look up Vulkan
* functions, e.g. to hook usage of these functions.
*
* To use this functionality, you *must* call this function before any others.
*
* Usage of this function is entirely optional. If you do not use it, the Vulkan
* functions required by Swappy will be dynamically loaded from libvulkan.so.
*
* @param[in] provider - provider object
*/
void SwappyVk_setFunctionProvider(
const SwappyVkFunctionProvider* pSwappyVkFunctionProvider);
/**
* @brief Get the swap interval value, in nanoseconds, for a given swapchain.
*
* @param[in] swapchain - the swapchain to query
*/
uint64_t SwappyVk_getSwapIntervalNS(VkSwapchainKHR swapchain);
/**
* @brief Get the supported refresh periods of this device. Call once with
* out_refreshrates set to nullptr to get the number of supported refresh
* periods, then call again passing that number as allocated_entries and
* an array of size equal to allocated_entries that will be filled with the
* refresh periods.
*/
int SwappyVk_getSupportedRefreshPeriodsNS(uint64_t* out_refreshrates,
int allocated_entries,
VkSwapchainKHR swapchain);
/**
* @brief Check if Swappy is enabled for the specified swapchain.
*
* @return false if SwappyVk_initAndGetRefreshCycleDuration was not
* called for the specified swapchain, true otherwise.
*/
bool SwappyVk_isEnabled(VkSwapchainKHR swapchain, bool* isEnabled);
/**
* @brief Toggle statistics collection on/off
*
* By default, stats collection is off and there is no overhead related to
* stats. An app can turn on stats collection by calling
* `SwappyVk_enableStats(swapchain, true)`. Then, the app is expected to call
* ::SwappyVk_recordFrameStart for each frame before starting to do any CPU
* related work. Stats will be logged to logcat with a 'FrameStatistics' tag. An
* app can get the stats by calling ::SwappyVk_getStats.
*
* SwappyVk_initAndGetRefreshCycleDuration must have been called successfully
* before for this swapchain, otherwise there is no effect in this call. Frame
* stats are only available if the platform supports VK_GOOGLE_display_timing
* extension.
*
* @param[in] swapchain - The swapchain for which frame stat collection is
* configured.
* @param enabled - Whether to enable/disable frame stat collection.
*/
void SwappyVk_enableStats(VkSwapchainKHR swapchain, bool enabled);
/**
* @brief Should be called if stats have been enabled with SwappyVk_enableStats.
*
* When stats collection is enabled with SwappyVk_enableStats, the app is
* expected to call this function for each frame before starting to do any CPU
* related work. It is assumed that this function will be called after a
* successful call to vkAcquireNextImageKHR. See ::SwappyVk_enableStats for more
* conditions.
*
* @param[in] queue - The VkQueue associated with the device and swapchain
* @param[in] swapchain - The swapchain where the frame is presented to.
* @param[in] image - The image in swapchain that corresponds to the frame.
* @see SwappyVk_enableStats.
*/
void SwappyVk_recordFrameStart(VkQueue queue, VkSwapchainKHR swapchain, uint32_t image);
/**
* @brief Returns the stats collected, if statistics collection was toggled on.
*
* Given that this API uses VkSwapchainKHR and the potential for this call to be
* done on different threads, all calls to ::SwappyVk_getStats
* must be externally synchronized with other SwappyVk calls. Unsynchronized
* calls may lead to undefined behavior. See ::SwappyVk_enableStats for more
* conditions.
*
* @param[in] swapchain - The swapchain for which stats are being queried.
* @param swappyStats - Pointer to a SwappyStats that will be populated with
* the collected stats. Cannot be NULL.
* @see SwappyStats
*/
void SwappyVk_getStats(VkSwapchainKHR swapchain, SwappyStats *swappyStats);
/**
* @brief Clears the frame statistics collected so far.
*
* All the frame statistics collected are reset to 0, frame statistics are
* collected normally after this call. See ::SwappyVk_enableStats for more
* conditions.
*
* @param[in] swapchain - The swapchain for which stats are being cleared.
*/
void SwappyVk_clearStats(VkSwapchainKHR swapchain);
#ifdef __cplusplus
} // extern "C"
#endif
/** @} */

View File

@ -0,0 +1,278 @@
/*
* Copyright 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @defgroup swappy_common Swappy common tools
* Tools to be used with Swappy for OpenGL or Swappy for Vulkan.
* @{
*/
#pragma once
#include <android/native_window.h>
#include <stdint.h>
#include "common/gamesdk_common.h"
/** @brief Swap interval for 60fps, in nanoseconds. */
#define SWAPPY_SWAP_60FPS (16666667L)
/** @brief Swap interval for 30fps, in nanoseconds. */
#define SWAPPY_SWAP_30FPS (33333333L)
/** @brief Swap interval for 20fps, in nanoseconds. */
#define SWAPPY_SWAP_20FPS (50000000L)
/**
* The longest duration, in refresh periods, represented by the statistics.
* @see SwappyStats
*/
#define MAX_FRAME_BUCKETS 6
/** @cond INTERNAL */
#define SWAPPY_SYSTEM_PROP_KEY_DISABLE "swappy.disable"
// Internal macros to track Swappy version, do not use directly.
#define SWAPPY_MAJOR_VERSION 2
#define SWAPPY_MINOR_VERSION 0
#define SWAPPY_BUGFIX_VERSION 0
#define SWAPPY_PACKED_VERSION \
ANDROID_GAMESDK_PACKED_VERSION(SWAPPY_MAJOR_VERSION, SWAPPY_MINOR_VERSION, \
SWAPPY_BUGFIX_VERSION)
// Internal macros to generate a symbol to track Swappy version, do not use
// directly.
#define SWAPPY_VERSION_CONCAT_NX(PREFIX, MAJOR, MINOR, BUGFIX, GITCOMMIT) \
PREFIX##_##MAJOR##_##MINOR##_##BUGFIX##_##GITCOMMIT
#define SWAPPY_VERSION_CONCAT(PREFIX, MAJOR, MINOR, BUGFIX, GITCOMMIT) \
SWAPPY_VERSION_CONCAT_NX(PREFIX, MAJOR, MINOR, BUGFIX, GITCOMMIT)
#define SWAPPY_VERSION_SYMBOL \
SWAPPY_VERSION_CONCAT(Swappy_version, SWAPPY_MAJOR_VERSION, \
SWAPPY_MINOR_VERSION, SWAPPY_BUGFIX_VERSION, \
AGDK_GIT_COMMIT)
// Define this to 1 to enable all logging from Swappy, by default it is
// disabled in a release build and enabled in a debug build.
#ifndef ENABLE_SWAPPY_LOGGING
#define ENABLE_SWAPPY_LOGGING 0
#endif
/** @endcond */
/** @brief Id of a thread returned by an external thread manager. */
typedef uint64_t SwappyThreadId;
/**
* @brief A structure enabling you to set how Swappy starts and joins threads by
* calling
* ::Swappy_setThreadFunctions.
*
* Usage of this functionality is optional.
*/
typedef struct SwappyThreadFunctions {
/** @brief Thread start callback.
*
* This function is called by Swappy to start thread_func on a new thread.
* @param user_data A value to be passed the thread function.
* If the thread was started, this function should set the thread_id and
* return 0. If the thread was not started, this function should return a
* non-zero value.
*/
int (*start)(SwappyThreadId* thread_id, void* (*thread_func)(void*),
void* user_data);
/** @brief Thread join callback.
*
* This function is called by Swappy to join the thread with given id.
*/
void (*join)(SwappyThreadId thread_id);
/** @brief Thread joinable callback.
*
* This function is called by Swappy to discover whether the thread with the
* given id is joinable.
*/
bool (*joinable)(SwappyThreadId thread_id);
} SwappyThreadFunctions;
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Return the version of the Swappy library at runtime.
*/
uint32_t Swappy_version();
/**
* @brief Call this before any other functions in order to use a custom thread
* manager.
*
* Usage of this function is entirely optional. Swappy uses std::thread by
* default.
*
*/
void Swappy_setThreadFunctions(const SwappyThreadFunctions* thread_functions);
/**
* @brief Return the full version of the Swappy library at runtime, e.g.
* "1.9.0_8a85ab7c46"
*/
const char* Swappy_versionString();
/**
* @brief Swappy frame statistics, collected if toggled on with
* ::SwappyGL_enableStats or ::SwappyVk_enableStats.
*/
typedef struct SwappyStats {
/** @brief Total frames swapped by swappy */
uint64_t totalFrames;
/** @brief Histogram of the number of screen refreshes a frame waited in the
* compositor queue after rendering was completed.
*
* For example:
* if a frame waited 2 refresh periods in the compositor queue after
* rendering was done, the frame will be counted in idleFrames[2]
*/
uint64_t idleFrames[MAX_FRAME_BUCKETS];
/** @brief Histogram of the number of screen refreshes passed between the
* requested presentation time and the actual present time.
*
* For example:
* if a frame was presented 2 refresh periods after the requested
* timestamp swappy set, the frame will be counted in lateFrames[2]
*/
uint64_t lateFrames[MAX_FRAME_BUCKETS];
/** @brief Histogram of the number of screen refreshes passed between two
* consecutive frames
*
* For example:
* if frame N was presented 2 refresh periods after frame N-1
* frame N will be counted in offsetFromPreviousFrame[2]
*/
uint64_t offsetFromPreviousFrame[MAX_FRAME_BUCKETS];
/** @brief Histogram of the number of screen refreshes passed between the
* call to Swappy_recordFrameStart and the actual present time.
*
* For example:
* if a frame was presented 2 refresh periods after the call to
* `Swappy_recordFrameStart` the frame will be counted in latencyFrames[2]
*/
uint64_t latencyFrames[MAX_FRAME_BUCKETS];
} SwappyStats;
#ifdef __cplusplus
} // extern "C"
#endif
/**
* Pointer to a function that can be attached to SwappyTracer::preWait
* @param userData Pointer to arbitrary data, see SwappyTracer::userData.
*/
typedef void (*SwappyPreWaitCallback)(void*);
/**
* Pointer to a function that can be attached to SwappyTracer::postWait.
* @param userData Pointer to arbitrary data, see SwappyTracer::userData.
* @param cpu_time_ns Time for CPU processing of this frame in nanoseconds.
* @param gpu_time_ns Time for GPU processing of previous frame in nanoseconds.
*/
typedef void (*SwappyPostWaitCallback)(void*, int64_t cpu_time_ns,
int64_t gpu_time_ns);
/**
* Pointer to a function that can be attached to SwappyTracer::preSwapBuffers.
* @param userData Pointer to arbitrary data, see SwappyTracer::userData.
*/
typedef void (*SwappyPreSwapBuffersCallback)(void*);
/**
* Pointer to a function that can be attached to SwappyTracer::postSwapBuffers.
* @param userData Pointer to arbitrary data, see SwappyTracer::userData.
* @param desiredPresentationTimeMillis The target time, in milliseconds, at
* which the frame would be presented on screen.
*/
typedef void (*SwappyPostSwapBuffersCallback)(
void*, int64_t desiredPresentationTimeMillis);
/**
* Pointer to a function that can be attached to SwappyTracer::startFrame.
* @param userData Pointer to arbitrary data, see SwappyTracer::userData.
* @param desiredPresentationTimeMillis The time, in milliseconds, at which the
* frame is scheduled to be presented.
*/
typedef void (*SwappyStartFrameCallback)(void*, int currentFrame,
int64_t desiredPresentationTimeMillis);
/**
* Pointer to a function that can be attached to
* SwappyTracer::swapIntervalChanged. Call ::SwappyGL_getSwapIntervalNS or
* ::SwappyVk_getSwapIntervalNS to get the latest swapInterval.
* @param userData Pointer to arbitrary data, see SwappyTracer::userData.
*/
typedef void (*SwappySwapIntervalChangedCallback)(void*);
/**
* @brief Collection of callbacks to be called each frame to trace execution.
*
* Injection of these is optional.
*/
typedef struct SwappyTracer {
/**
* Callback called before waiting to queue the frame to the composer.
*/
SwappyPreWaitCallback preWait;
/**
* Callback called after wait to queue the frame to the composer is done.
*/
SwappyPostWaitCallback postWait;
/**
* Callback called before calling the function to queue the frame to the
* composer.
*/
SwappyPreSwapBuffersCallback preSwapBuffers;
/**
* Callback called after calling the function to queue the frame to the
* composer.
*/
SwappyPostSwapBuffersCallback postSwapBuffers;
/**
* Callback called at the start of a frame.
*/
SwappyStartFrameCallback startFrame;
/**
* Pointer to some arbitrary data that will be passed as the first argument
* of callbacks.
*/
void* userData;
/**
* Callback called when the swap interval was changed.
*/
SwappySwapIntervalChangedCallback swapIntervalChanged;
} SwappyTracer;
/** @} */