blob: fa062d9d1fec515c0eafffd7d4a46a0407dec241 [file] [log] [blame]
// 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.
#ifndef CC_TREES_PRESENTATION_TIME_CALLBACK_BUFFER_H_
#define CC_TREES_PRESENTATION_TIME_CALLBACK_BUFFER_H_
#include <vector>
#include "base/callback_forward.h"
#include "base/containers/circular_deque.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "cc/cc_export.h"
#include "ui/gfx/presentation_feedback.h"
namespace cc {
// Maintains a queue of callbacks and compositor frame times that we want to
// buffer until a relevant frame is presented.
//
// Callbacks are queued through `RegisterMainThreadCallbacks()` or
// `RegisterMainThreadSuccessfulCallbacks()` if the they are to be run on the
// main thread and `RegisterCompositorThreadSuccessfulCallbacks()` if they are
// to be run on the compositor thread.
//
// Once a frame is presented, users of this class can call
// `PopPendingCallbacks()` to get their callbacks back. This class never runs
// callbacks itself so it's up to calling code to `PostTask()` or call `Run()`
// as needed.
//
// This class is thread unsafe so concurrent access would require external
// synchronization. In practice, however, instances of this class are only used
// on the compositor thread even though some of the buffered callbacks are
// intended to be run on the renderer main thread.
//
// CC_EXPORT is only needed for testing.
class CC_EXPORT PresentationTimeCallbackBuffer {
public:
// Maximum expected buffer size for presentation callbacks. We generally
// don't expect many frames waiting for a presentation feedback, hence we
// don't expect many presentation callbacks waiting for a frame presentation.
static constexpr size_t kMaxBufferSize = 60u;
using Callback = base::OnceCallback<void(const gfx::PresentationFeedback&)>;
using SuccessfulCallback = base::OnceCallback<void(base::TimeTicks)>;
PresentationTimeCallbackBuffer();
PresentationTimeCallbackBuffer(const PresentationTimeCallbackBuffer&) =
delete;
PresentationTimeCallbackBuffer(PresentationTimeCallbackBuffer&&);
PresentationTimeCallbackBuffer& operator=(
const PresentationTimeCallbackBuffer&) = delete;
PresentationTimeCallbackBuffer& operator=(PresentationTimeCallbackBuffer&&);
~PresentationTimeCallbackBuffer();
// Buffers the given `callbacks` in preparation for a presentation at or after
// the given `frame_token`. The presentation is not necessarily successful.
// Calling code posts these callbacks to the main thread once they're popped.
void RegisterMainThreadCallbacks(uint32_t frame_token,
std::vector<Callback> callbacks);
// Buffers the given `callbacks` in preparation for a successful presentation
// at or after the given `frame_token`. Calling code posts these callbacks to
// the main thread once they're popped.
void RegisterMainThreadSuccessfulCallbacks(
uint32_t frame_token,
std::vector<SuccessfulCallback> callbacks);
// Buffers the given `callbacks` in preparation for a successful presentation
// at or after the given `frame_token`. Calling code invokes these callbacks
// on the compositor thread once they're popped.
void RegisterCompositorThreadSuccessfulCallbacks(
uint32_t frame_token,
std::vector<SuccessfulCallback> callbacks);
// Structured return value for |PopPendingCallbacks|. CC_EXPORT is only
// needed for testing.
struct CC_EXPORT PendingCallbacks {
PendingCallbacks();
PendingCallbacks(const PendingCallbacks&) = delete;
PendingCallbacks(PendingCallbacks&&);
PendingCallbacks& operator=(const PendingCallbacks&) = delete;
PendingCallbacks& operator=(PendingCallbacks&&);
~PendingCallbacks();
// Holds callbacks registered through
// `RegisterMainThreadPresentationCallbacks()`.
std::vector<Callback> main_callbacks;
// Holds callbacks registered through
// `RegisterMainThreadSuccessfulPresentationCallbacks()`.
std::vector<SuccessfulCallback> main_successful_callbacks;
// Holds callbacks registered through
// `RegisterCompositorThreadSuccessfulPresentationCallbacks()`.
std::vector<SuccessfulCallback> compositor_successful_callbacks;
};
// Call this once the presentation for the given `frame_token` has completed.
// Yields any pending callbacks that were registered against a frame token
// that was less than or equal to the given `frame_token`. If
// `presentation_failed` is true, successful presentation time callbacks are
// not returned. They are only returned on successful presentations. Note that
// since failed presentation feedbacks can arrive out of order (i.e. earlier
// than previous frames that might get presented successfully), when called on
// a failed presentation, this might return callbacks for previous frames that
// are still in flight. This is okay for now as we aim to only allow
// registering callbacks for successful presentations which will make this a
// non-issue.
// It is the caller's responsibility to run the callbacks on the right
// threads/sequences.
PendingCallbacks PopPendingCallbacks(uint32_t frame_token,
bool presentation_failed);
private:
// Stores information needed once we get a response for a particular
// presentation token.
struct FrameTokenInfo {
explicit FrameTokenInfo(uint32_t token);
FrameTokenInfo(const FrameTokenInfo&) = delete;
FrameTokenInfo(FrameTokenInfo&&);
FrameTokenInfo& operator=(const FrameTokenInfo&) = delete;
FrameTokenInfo& operator=(FrameTokenInfo&&);
~FrameTokenInfo();
// A |CompositorFrameMetadata::frame_token| that we use to associate
// presentation feedback with the relevant compositor frame.
uint32_t token;
// The presentation callbacks to send back to the main thread.
std::vector<Callback> main_callbacks;
// The successful presentation callbacks to send back to the main thread.
std::vector<SuccessfulCallback> main_successful_callbacks;
// The successful presentation callbacks to invoke on the compositor thread.
std::vector<SuccessfulCallback> compositor_successful_callbacks;
};
// Returns a reference to a |FrameTokenInfo| with the given |frame_token|.
// The instance is created if necessary and occupies the appropriate place in
// |frame_token_infos_|.
FrameTokenInfo& GetOrMakeRegistration(uint32_t frame_token);
// Queue of pending registrations ordered by |token|. We can use a deque
// because we require callers to use non-decreasing tokens when registering.
base::circular_deque<FrameTokenInfo> frame_token_infos_;
// When DCHECK is enabled, check that instances of this class aren't being
// used concurrently.
SEQUENCE_CHECKER(sequence_checker_);
};
} // namespace cc
#endif // CC_TREES_PRESENTATION_TIME_CALLBACK_BUFFER_H_