chromium/components/exo/wayland/wp_presentation.cc

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/exo/wayland/wp_presentation.h"

#include <presentation-time-server-protocol.h>

#include <memory>
#include <utility>

#include "base/functional/bind.h"
#include "base/time/time.h"
#include "components/exo/wayland/server_util.h"
#include "ui/gfx/presentation_feedback.h"

namespace exo {
namespace wayland {
namespace {

////////////////////////////////////////////////////////////////////////////////
// presentation_interface:

void HandleSurfacePresentationCallback(
    wl_resource* resource,
    const gfx::PresentationFeedback& feedback) {
  if (feedback.timestamp.is_null()) {
    wp_presentation_feedback_send_discarded(resource);
  } else {
    int64_t presentation_time_us = feedback.timestamp.ToInternalValue();
    int64_t seconds = presentation_time_us / base::Time::kMicrosecondsPerSecond;
    int64_t microseconds =
        presentation_time_us % base::Time::kMicrosecondsPerSecond;
    static_assert(
        static_cast<uint32_t>(gfx::PresentationFeedback::Flags::kVSync) ==
            static_cast<uint32_t>(WP_PRESENTATION_FEEDBACK_KIND_VSYNC),
        "gfx::PresentationFlags::VSync don't match!");
    static_assert(
        static_cast<uint32_t>(gfx::PresentationFeedback::Flags::kHWClock) ==
            static_cast<uint32_t>(WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK),
        "gfx::PresentationFlags::HWClock don't match!");
    static_assert(
        static_cast<uint32_t>(
            gfx::PresentationFeedback::Flags::kHWCompletion) ==
            static_cast<uint32_t>(WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION),
        "gfx::PresentationFlags::HWCompletion don't match!");
    static_assert(
        static_cast<uint32_t>(gfx::PresentationFeedback::Flags::kZeroCopy) ==
            static_cast<uint32_t>(WP_PRESENTATION_FEEDBACK_KIND_ZERO_COPY),
        "gfx::PresentationFlags::ZeroCopy don't match!");
    wp_presentation_feedback_send_presented(
        resource, seconds >> 32, seconds & 0xffffffff,
        microseconds * base::Time::kNanosecondsPerMicrosecond,
        feedback.interval.InMicroseconds() *
            base::Time::kNanosecondsPerMicrosecond,
        0, 0, feedback.flags);
  }
  wl_client_flush(wl_resource_get_client(resource));
  wl_resource_destroy(resource);
}

void presentation_destroy(wl_client* client, wl_resource* resource) {
  wl_resource_destroy(resource);
}

void presentation_feedback(wl_client* client,
                           wl_resource* resource,
                           wl_resource* surface_resource,
                           uint32_t id) {
  wl_resource* presentation_feedback_resource =
      wl_resource_create(client, &wp_presentation_feedback_interface,
                         wl_resource_get_version(resource), id);

  // base::Unretained is safe as the resource owns the callback.
  auto cancelable_callback = std::make_unique<base::CancelableRepeatingCallback<
      void(const gfx::PresentationFeedback&)>>(
      base::BindRepeating(&HandleSurfacePresentationCallback,
                          base::Unretained(presentation_feedback_resource)));

  GetUserDataAs<Surface>(surface_resource)
      ->RequestPresentationCallback(cancelable_callback->callback());

  SetImplementation(presentation_feedback_resource, nullptr,
                    std::move(cancelable_callback));
}

const struct wp_presentation_interface presentation_implementation = {
    presentation_destroy, presentation_feedback};

}  // namespace

void bind_presentation(wl_client* client,
                       void* data,
                       uint32_t version,
                       uint32_t id) {
  wl_resource* resource =
      wl_resource_create(client, &wp_presentation_interface, 1, id);

  wl_resource_set_implementation(resource, &presentation_implementation, data,
                                 nullptr);

  wp_presentation_send_clock_id(resource, CLOCK_MONOTONIC);
}

}  // namespace wayland
}  // namespace exo