/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "common/vsoc/lib/screen_region_view.h" #include <memory> #include "common/libs/glog/logging.h" #include "common/vsoc/lib/lock_guard.h" using vsoc::layout::screen::CompositionStats; using vsoc::screen::ScreenRegionView; const uint8_t* ScreenRegionView::first_buffer() const { // TODO(jemoreira): Add alignments? return &(this->data().buffer[0]); } int ScreenRegionView::number_of_buffers() const { auto offset_of_first_buffer = const_cast<ScreenRegionView*>(this)->pointer_to_region_offset( this->first_buffer()); size_t total_buffer_size = control_->region_size() - offset_of_first_buffer; return total_buffer_size / buffer_size(); } void* ScreenRegionView::GetBuffer(int buffer_idx) { uint8_t* buffer = const_cast<uint8_t*>(this->first_buffer()); return buffer + buffer_idx * this->buffer_size(); } // We can use a locking protocol because we decided that the streamer should // have more priority than the hwcomposer, so it's OK to block the hwcomposer // waiting for the streamer to complete, while the streamer will only block on // the hwcomposer when it has ran out of work to do and needs to get more from // the hwcomposer. void ScreenRegionView::BroadcastNewFrame(int buffer_idx, const CompositionStats* stats) { { if (buffer_idx < 0 || buffer_idx >= number_of_buffers()) { LOG(ERROR) << "Attempting to broadcast an invalid buffer index: " << buffer_idx; return; } auto lock_guard(make_lock_guard(&data()->bcast_lock)); data()->seq_num++; data()->buffer_index = static_cast<int32_t>(buffer_idx); if (stats) { data()->stats = *stats; } } // Signaling after releasing the lock may cause spurious wake ups. // Signaling while holding the lock may cause the just-awaken listener to // block immediately trying to acquire the lock. // The former is less costly and slightly less likely to happen. SendSignal(layout::Sides::Both, &data()->seq_num); } int ScreenRegionView::WaitForNewFrameSince(uint32_t* last_seq_num, CompositionStats* stats) { static std::unique_ptr<RegionWorker> worker = StartWorker(); // It's ok to read seq_num here without holding the lock because the lock will // be acquired immediately after so we'll block if necessary to wait for the // critical section in BroadcastNewFrame to complete. // Also, the call to WaitForSignal receives a pointer to seq_num (so the // compiler should not optimize it out) and includes a memory barrier // (FUTEX_WAIT). while (data()->seq_num == *last_seq_num) { // Don't hold the lock when waiting for a signal, will deadlock. WaitForSignal(&data()->seq_num, *last_seq_num); } { auto lock_guard(make_lock_guard(&data()->bcast_lock)); *last_seq_num = data()->seq_num; if (stats) { *stats = data()->stats; } return static_cast<int>(data()->buffer_index); } }