1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "client.h"
6 #include "fence.h"
7 
8 #include <utility>
9 
10 namespace display {
11 
CreateRef()12 bool Fence::CreateRef() {
13     fbl::AllocChecker ac;
14     cur_ref_ = fbl::AdoptRef(new (&ac) FenceReference(fbl::RefPtr<Fence>(this)));
15     if (ac.check()) {
16         ref_count_++;
17     }
18 
19     return ac.check();
20 }
21 
ClearRef()22 void Fence::ClearRef() {
23     cur_ref_ = nullptr;
24 }
25 
GetReference()26 fbl::RefPtr<FenceReference> Fence::GetReference() {
27     return cur_ref_;
28 }
29 
Signal()30 void Fence::Signal() {
31     event_.signal(0, ZX_EVENT_SIGNALED);
32 }
33 
OnRefDead()34 bool Fence::OnRefDead() {
35     return --ref_count_ == 0;
36 }
37 
OnRefArmed(fbl::RefPtr<FenceReference> && ref)38 zx_status_t Fence::OnRefArmed(fbl::RefPtr<FenceReference>&& ref) {
39     if (armed_refs_.is_empty()) {
40         ready_wait_.set_object(event_.get());
41         ready_wait_.set_trigger(ZX_EVENT_SIGNALED);
42 
43         zx_status_t status = ready_wait_.Begin(dispatcher_);
44         if (status != ZX_OK) {
45             return status;
46         }
47     }
48 
49     armed_refs_.push_back(std::move(ref));
50     return ZX_OK;
51 }
52 
OnRefDisarmed(FenceReference * ref)53 void Fence::OnRefDisarmed(FenceReference* ref) {
54     armed_refs_.erase(*ref);
55     if (armed_refs_.is_empty()) {
56         ready_wait_.Cancel();
57     }
58 }
59 
OnReady(async_dispatcher_t * dispatcher,async::WaitBase * self,zx_status_t status,const zx_packet_signal_t * signal)60 void Fence::OnReady(async_dispatcher_t* dispatcher, async::WaitBase* self,
61                     zx_status_t status, const zx_packet_signal_t* signal) {
62     ZX_DEBUG_ASSERT(status == ZX_OK && (signal->observed & ZX_EVENT_SIGNALED));
63 
64     event_.signal(ZX_EVENT_SIGNALED, 0);
65 
66     fbl::RefPtr<FenceReference> ref = armed_refs_.pop_front();
67     ref->OnReady();
68     cb_->OnFenceFired(ref.get());
69 
70     if (!armed_refs_.is_empty()) {
71         ready_wait_.Begin(dispatcher_);
72     }
73 }
74 
Fence(FenceCallback * cb,async_dispatcher_t * dispatcher,uint64_t fence_id,zx::event && event)75 Fence::Fence(FenceCallback* cb, async_dispatcher_t* dispatcher, uint64_t fence_id, zx::event&& event)
76         : cb_(cb), dispatcher_(dispatcher), event_(std::move(event)) {
77     id = fence_id;
78 }
79 
~Fence()80 Fence::~Fence() {
81     ZX_DEBUG_ASSERT(armed_refs_.is_empty());
82     ZX_DEBUG_ASSERT(ref_count_ == 0);
83 }
84 
StartReadyWait()85 zx_status_t FenceReference::StartReadyWait() {
86     return fence_->OnRefArmed(fbl::RefPtr<FenceReference>(this));
87 }
88 
ResetReadyWait()89 void FenceReference::ResetReadyWait() {
90     fence_->OnRefDisarmed(this);
91 }
92 
SetImmediateRelease(fbl::RefPtr<FenceReference> && fence)93 void FenceReference::SetImmediateRelease(fbl::RefPtr<FenceReference>&& fence) {
94     release_fence_ = std::move(fence);
95 }
96 
OnReady()97 void FenceReference::OnReady() {
98     if (release_fence_) {
99         release_fence_->Signal();
100         release_fence_ = nullptr;
101     }
102 }
103 
Signal()104 void FenceReference::Signal() {
105     fence_->Signal();
106 }
107 
FenceReference(fbl::RefPtr<Fence> fence)108 FenceReference::FenceReference(fbl::RefPtr<Fence> fence) : fence_(std::move(fence)) { }
109 
~FenceReference()110 FenceReference::~FenceReference() {
111     fence_->cb_->OnRefForFenceDead(fence_.get());
112 }
113 
114 } // namespace display
115