+ swapchain->timing.clear();
+}
+
+uint32_t get_num_ready_timings(Swapchain& swapchain) {
+ if (swapchain.timing.size() < MIN_NUM_FRAMES_AGO) {
+ return 0;
+ }
+
+ uint32_t num_ready = 0;
+ const size_t num_timings = swapchain.timing.size() - MIN_NUM_FRAMES_AGO + 1;
+ for (uint32_t i = 0; i < num_timings; i++) {
+ TimingInfo& ti = swapchain.timing.editItemAt(i);
+ if (ti.ready()) {
+ // This TimingInfo is ready to be reported to the user. Add it
+ // to the num_ready.
+ num_ready++;
+ continue;
+ }
+ // This TimingInfo is not yet ready to be reported to the user,
+ // and so we should look for any available timestamps that
+ // might make it ready.
+ int64_t desired_present_time = 0;
+ int64_t render_complete_time = 0;
+ int64_t composition_latch_time = 0;
+ int64_t actual_present_time = 0;
+ // Obtain timestamps:
+ int ret = native_window_get_frame_timestamps(
+ swapchain.surface.window.get(), ti.native_frame_id_,
+ &desired_present_time, &render_complete_time,
+ &composition_latch_time,
+ NULL, //&first_composition_start_time,
+ NULL, //&last_composition_start_time,
+ NULL, //&composition_finish_time,
+ // TODO(ianelliott): Maybe ask if this one is
+ // supported, at startup time (since it may not be
+ // supported):
+ &actual_present_time,
+ NULL, //&dequeue_ready_time,
+ NULL /*&reads_done_time*/);
+
+ if (ret != android::NO_ERROR) {
+ continue;
+ }
+
+ // Record the timestamp(s) we received, and then see if this TimingInfo
+ // is ready to be reported to the user:
+ ti.timestamp_desired_present_time_ = desired_present_time;
+ ti.timestamp_actual_present_time_ = actual_present_time;
+ ti.timestamp_render_complete_time_ = render_complete_time;
+ ti.timestamp_composition_latch_time_ = composition_latch_time;
+
+ if (ti.ready()) {
+ // The TimingInfo has received enough timestamps, and should now
+ // use those timestamps to calculate the info that should be
+ // reported to the user:
+ ti.calculate(swapchain.refresh_duration);
+ num_ready++;
+ }
+ }
+ return num_ready;
+}
+
+// TODO(ianelliott): DEAL WITH RETURN VALUE (e.g. VK_INCOMPLETE)!!!
+void copy_ready_timings(Swapchain& swapchain,
+ uint32_t* count,
+ VkPastPresentationTimingGOOGLE* timings) {
+ if (swapchain.timing.empty()) {
+ *count = 0;
+ return;
+ }
+
+ size_t last_ready = swapchain.timing.size() - 1;
+ while (!swapchain.timing[last_ready].ready()) {
+ if (last_ready == 0) {
+ *count = 0;
+ return;
+ }
+ last_ready--;
+ }
+
+ uint32_t num_copied = 0;
+ size_t num_to_remove = 0;
+ for (uint32_t i = 0; i <= last_ready && num_copied < *count; i++) {
+ const TimingInfo& ti = swapchain.timing[i];
+ if (ti.ready()) {
+ ti.get_values(&timings[num_copied]);
+ num_copied++;
+ }
+ num_to_remove++;
+ }
+
+ // Discard old frames that aren't ready if newer frames are ready.
+ // We don't expect to get the timing info for those old frames.
+ swapchain.timing.removeItemsAt(0, num_to_remove);
+
+ *count = num_copied;
+}
+
+android_pixel_format GetNativePixelFormat(VkFormat format) {
+ android_pixel_format native_format = HAL_PIXEL_FORMAT_RGBA_8888;
+ switch (format) {
+ case VK_FORMAT_R8G8B8A8_UNORM:
+ case VK_FORMAT_R8G8B8A8_SRGB:
+ native_format = HAL_PIXEL_FORMAT_RGBA_8888;
+ break;
+ case VK_FORMAT_R5G6B5_UNORM_PACK16:
+ native_format = HAL_PIXEL_FORMAT_RGB_565;
+ break;
+ case VK_FORMAT_R16G16B16A16_SFLOAT:
+ native_format = HAL_PIXEL_FORMAT_RGBA_FP16;
+ break;
+ case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
+ native_format = HAL_PIXEL_FORMAT_RGBA_1010102;
+ break;
+ default:
+ ALOGV("unsupported swapchain format %d", format);
+ break;
+ }
+ return native_format;
+}
+
+android_dataspace GetNativeDataspace(VkColorSpaceKHR colorspace) {
+ switch (colorspace) {
+ case VK_COLOR_SPACE_SRGB_NONLINEAR_KHR:
+ return HAL_DATASPACE_V0_SRGB;
+ case VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT:
+ return HAL_DATASPACE_DISPLAY_P3;
+ case VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT:
+ return HAL_DATASPACE_V0_SCRGB_LINEAR;
+ case VK_COLOR_SPACE_DCI_P3_LINEAR_EXT:
+ return HAL_DATASPACE_DCI_P3_LINEAR;
+ case VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT:
+ return HAL_DATASPACE_DCI_P3;
+ case VK_COLOR_SPACE_BT709_LINEAR_EXT:
+ return HAL_DATASPACE_V0_SRGB_LINEAR;
+ case VK_COLOR_SPACE_BT709_NONLINEAR_EXT:
+ return HAL_DATASPACE_V0_SRGB;
+ case VK_COLOR_SPACE_BT2020_LINEAR_EXT:
+ return HAL_DATASPACE_BT2020_LINEAR;
+ case VK_COLOR_SPACE_HDR10_ST2084_EXT:
+ return static_cast<android_dataspace>(
+ HAL_DATASPACE_STANDARD_BT2020 | HAL_DATASPACE_TRANSFER_ST2084 |
+ HAL_DATASPACE_RANGE_FULL);
+ case VK_COLOR_SPACE_DOLBYVISION_EXT:
+ return static_cast<android_dataspace>(
+ HAL_DATASPACE_STANDARD_BT2020 | HAL_DATASPACE_TRANSFER_ST2084 |
+ HAL_DATASPACE_RANGE_FULL);
+ case VK_COLOR_SPACE_HDR10_HLG_EXT:
+ return static_cast<android_dataspace>(
+ HAL_DATASPACE_STANDARD_BT2020 | HAL_DATASPACE_TRANSFER_HLG |
+ HAL_DATASPACE_RANGE_FULL);
+ case VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT:
+ return static_cast<android_dataspace>(
+ HAL_DATASPACE_STANDARD_ADOBE_RGB |
+ HAL_DATASPACE_TRANSFER_LINEAR | HAL_DATASPACE_RANGE_FULL);
+ case VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT:
+ return HAL_DATASPACE_ADOBE_RGB;
+
+ // Pass through is intended to allow app to provide data that is passed
+ // to the display system without modification.
+ case VK_COLOR_SPACE_PASS_THROUGH_EXT:
+ return HAL_DATASPACE_ARBITRARY;
+
+ default:
+ // This indicates that we don't know about the
+ // dataspace specified and we should indicate that
+ // it's unsupported
+ return HAL_DATASPACE_UNKNOWN;
+ }