blob: 807b1bb9bfb229892393658736c9f75443964b0d [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/ui/scenic/lib/gfx/engine/image_pipe_updater.h"
#include "lib/trace/internal/event_common.h"
#include "src/ui/scenic/lib/gfx/resources/image_pipe_base.h"
#include "src/ui/scenic/lib/scheduling/frame_scheduler.h"
namespace scenic_impl {
namespace gfx {
ImagePipeUpdater::ImagePipeUpdater(
const std::shared_ptr<scheduling::FrameScheduler>& frame_scheduler)
: scheduling_id_(scheduling::GetNextSessionId()),
frame_scheduler_(frame_scheduler),
weak_factory_(this) {
FXL_DCHECK(frame_scheduler);
frame_scheduler->AddSessionUpdater(weak_factory_.GetWeakPtr());
frame_scheduler->SetOnUpdateFailedCallbackForSession(scheduling_id_, [] {
// ImagePipe updates currently can not fail.
FXL_CHECK(false);
});
}
ImagePipeUpdater::ImagePipeUpdater()
: scheduling_id_(scheduling::GetNextSessionId()), weak_factory_(this){};
ImagePipeUpdater::~ImagePipeUpdater() {
if (auto scheduler = frame_scheduler_.lock()) {
scheduler->RemoveSession(scheduling_id_);
}
}
scheduling::PresentId ImagePipeUpdater::ScheduleImagePipeUpdate(
zx::time presentation_time, fxl::WeakPtr<ImagePipeBase> image_pipe,
std::vector<zx::event> acquire_fences, std::vector<zx::event> release_fences,
fuchsia::images::ImagePipe::PresentImageCallback callback) {
TRACE_DURATION("gfx", "ImagePipeUpdater::ScheduleImagePipeUpdate", "scheduling_id",
scheduling_id_);
scheduling::PresentId present_id = 0;
// This gets reset to the same value on every frame. Should probably only be set once (per pipe).
// TODO(45362): Optimize this for either one or several image pipes.
image_pipes_[scheduling_id_] = std::move(image_pipe);
if (auto scheduler = frame_scheduler_.lock()) {
present_id =
scheduler->RegisterPresent(scheduling_id_, std::move(callback), std::move(release_fences));
scheduling::SchedulingIdPair id_pair{scheduling_id_, present_id};
auto [it, success] = fence_listeners_.emplace(id_pair, std::move(acquire_fences));
FXL_DCHECK(success);
const auto trace_id = SESSION_TRACE_ID(scheduling_id_, present_id);
TRACE_FLOW_BEGIN("gfx", "wait_for_fences", trace_id);
// Set callback for the acquire fence listener.
auto& fence_listener = it->second;
fence_listener.WaitReadyAsync(
[weak = weak_factory_.GetWeakPtr(), id_pair, presentation_time, trace_id]() mutable {
if (!weak)
return;
TRACE_DURATION("gfx", "ImagePipeUpdater::ScheduleImagePipeUpdate::fences_ready");
TRACE_FLOW_END("gfx", "wait_for_fences", trace_id);
if (auto locked_frame_scheduler = weak->frame_scheduler_.lock()) {
locked_frame_scheduler->ScheduleUpdateForSession(presentation_time, id_pair);
}
// Release fences have been moved into frame scheduler. Delete the remaining fence
// listener.
weak->fence_listeners_.erase(id_pair);
});
}
return present_id;
}
ImagePipeUpdater::UpdateResults ImagePipeUpdater::UpdateSessions(
const std::unordered_map<scheduling::SessionId, scheduling::PresentId>& sessions_to_update,
uint64_t trace_id) {
UpdateResults results{};
if (sessions_to_update.find(scheduling_id_) == sessions_to_update.end()) {
return results;
}
const scheduling::SessionId session_id = scheduling_id_;
const scheduling::PresentId present_id = sessions_to_update.at(session_id);
// Destroy all unsignalled acquire fence listeners older than |present_id|.
{
auto begin_it = fence_listeners_.lower_bound({session_id, 0});
auto end_it = fence_listeners_.upper_bound({session_id, present_id});
FXL_DCHECK(std::distance(begin_it, end_it) >= 0);
fence_listeners_.erase(begin_it, end_it);
}
// Apply update for |present_id|.
FXL_DCHECK(image_pipes_.find(session_id) != image_pipes_.end());
if (auto image_pipe = image_pipes_[session_id]) {
auto image_pipe_update_results = image_pipe->Update(present_id);
}
return results;
}
} // namespace gfx
} // namespace scenic_impl