blob: 1056f8a1dd33e216a20a80e826d59d238462188f [file] [log] [blame] [edit]
// Copyright 2018 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/graphics/display/drivers/coordinator/fence.h"
#include <lib/async/cpp/wait.h>
#include <lib/async/dispatcher.h>
#include <lib/driver/logging/cpp/logger.h>
#include <lib/fdf/cpp/dispatcher.h>
#include <lib/trace/event.h>
#include <lib/zx/event.h>
#include <lib/zx/result.h>
#include <zircon/assert.h>
#include <zircon/errors.h>
#include <zircon/status.h>
#include <zircon/types.h>
#include <utility>
#include <fbl/alloc_checker.h>
#include <fbl/intrusive_single_list.h>
#include <fbl/ref_ptr.h>
#include "src/graphics/display/lib/api-types/cpp/event-id.h"
namespace display_coordinator {
void Fence::Signal() {
ZX_DEBUG_ASSERT(fdf::Dispatcher::GetCurrent()->async_dispatcher() ==
dispatcher_->async_dispatcher());
event_.signal(/*clear_mask=*/0, /*set_mask=*/ZX_EVENT_SIGNALED);
}
zx::result<> Fence::Wait() {
ZX_DEBUG_ASSERT(fdf::Dispatcher::GetCurrent()->async_dispatcher() ==
dispatcher_->async_dispatcher());
if (signal_waiter_.is_pending()) {
return zx::ok();
}
zx_status_t wait_status = signal_waiter_.Begin(dispatcher_->async_dispatcher());
if (wait_status != ZX_OK) {
return zx::error(wait_status);
}
ZX_DEBUG_ASSERT(signal_waiter_.is_pending());
return zx::ok();
}
void Fence::OnEventSignaled(async_dispatcher_t* dispatcher, async::WaitBase* self,
zx_status_t status, const zx_packet_signal_t* signal) {
ZX_DEBUG_ASSERT_MSG(status == ZX_OK, "Fence::OnReady failed: %s", zx_status_get_string(status));
ZX_DEBUG_ASSERT(dispatcher != nullptr);
ZX_DEBUG_ASSERT((signal->observed & ZX_EVENT_SIGNALED) != 0);
ZX_DEBUG_ASSERT(fdf::Dispatcher::GetCurrent()->async_dispatcher() ==
dispatcher_->async_dispatcher());
ZX_DEBUG_ASSERT(dispatcher == dispatcher_->async_dispatcher());
TRACE_DURATION("gfx", "Display::Fence::OnReady");
TRACE_FLOW_END("gfx", "event_signal", koid_);
ZX_DEBUG_ASSERT(!signal_waiter_.is_pending());
event_.signal(/*clear_mask=*/ZX_EVENT_SIGNALED, /*set_mask=*/0);
listener_.OnFenceSignaled(*this);
}
Fence::Fence(FenceListener* listener, fdf::UnownedSynchronizedDispatcher dispatcher,
display::EventId fence_id, zx::event event)
: IdMappable(fence_id),
listener_(*listener),
dispatcher_(std::move(dispatcher)),
event_(std::move(event)),
signal_waiter_(this, event_.get(), /*trigger=*/ZX_EVENT_SIGNALED, /*options=*/0) {
ZX_DEBUG_ASSERT(listener != nullptr);
ZX_DEBUG_ASSERT(dispatcher_->get() != nullptr);
ZX_DEBUG_ASSERT(fence_id != display::kInvalidEventId);
ZX_DEBUG_ASSERT(event_.is_valid());
ZX_DEBUG_ASSERT(fdf::Dispatcher::GetCurrent()->async_dispatcher() ==
dispatcher_->async_dispatcher());
zx_info_handle_basic_t info;
zx_status_t status = event_.get_info(ZX_INFO_HANDLE_BASIC, &info, sizeof(info), nullptr, nullptr);
ZX_DEBUG_ASSERT(status == ZX_OK);
koid_ = info.koid;
}
Fence::~Fence() {
ZX_DEBUG_ASSERT(fdf::Dispatcher::GetCurrent()->async_dispatcher() ==
dispatcher_->async_dispatcher());
}
FenceCollection::FenceCollection(FenceListener* listener,
fdf::UnownedSynchronizedDispatcher dispatcher)
: listener_(*listener), dispatcher_(std::move(dispatcher)) {
ZX_DEBUG_ASSERT(listener != nullptr);
ZX_DEBUG_ASSERT(dispatcher_->get() != nullptr);
ZX_DEBUG_ASSERT(fdf::Dispatcher::GetCurrent()->async_dispatcher() ==
dispatcher_->async_dispatcher());
}
void FenceCollection::Clear() {
ZX_DEBUG_ASSERT(fdf::Dispatcher::GetCurrent()->async_dispatcher() ==
dispatcher_->async_dispatcher());
imported_fences_.clear();
}
zx::result<> FenceCollection::ImportEvent(zx::event event, display::EventId id) {
ZX_DEBUG_ASSERT(event.is_valid());
ZX_DEBUG_ASSERT(id != display::kInvalidEventId);
ZX_DEBUG_ASSERT(fdf::Dispatcher::GetCurrent()->async_dispatcher() ==
dispatcher_->async_dispatcher());
auto imported_fences_it = imported_fences_.find(id);
if (imported_fences_it.IsValid()) {
fdf::error("Refused to import an event with existing ID: {}", id.value());
return zx::error(ZX_ERR_ALREADY_EXISTS);
}
fbl::AllocChecker alloc_checker;
fbl::RefPtr<Fence> fence = fbl::AdoptRef(
new (&alloc_checker) Fence(&listener_, dispatcher_->borrow(), id, std::move(event)));
if (!alloc_checker.check()) {
fdf::error("Failed to allocate Fence for event ID: {}", id.value());
return zx::error(ZX_ERR_NO_MEMORY);
}
bool successfully_inserted = imported_fences_.insert_or_find(std::move(fence));
ZX_DEBUG_ASSERT(successfully_inserted);
return zx::ok();
}
void FenceCollection::ReleaseEvent(display::EventId id) {
ZX_DEBUG_ASSERT(fdf::Dispatcher::GetCurrent()->async_dispatcher() ==
dispatcher_->async_dispatcher());
auto imported_fences_it = imported_fences_.find(id);
if (!imported_fences_it.IsValid()) {
return;
}
imported_fences_.erase(imported_fences_it);
}
fbl::RefPtr<Fence> FenceCollection::GetFence(display::EventId id) {
ZX_DEBUG_ASSERT(fdf::Dispatcher::GetCurrent()->async_dispatcher() ==
dispatcher_->async_dispatcher());
if (id == display::kInvalidEventId) {
return nullptr;
}
auto imported_fences_it = imported_fences_.find(id);
return imported_fences_it.IsValid() ? imported_fences_it.CopyPointer() : nullptr;
}
} // namespace display_coordinator