// 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