1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "common/vsoc/lib/screen_region_view.h" 18 19 #include <memory> 20 21 #include "common/libs/glog/logging.h" 22 #include "common/vsoc/lib/lock_guard.h" 23 24 using vsoc::layout::screen::CompositionStats; 25 using vsoc::screen::ScreenRegionView; 26 27 const uint8_t* ScreenRegionView::first_buffer() const { 28 // TODO(jemoreira): Add alignments? 29 return &(this->data().buffer[0]); 30 } 31 32 int ScreenRegionView::number_of_buffers() const { 33 auto offset_of_first_buffer = 34 const_cast<ScreenRegionView*>(this)->pointer_to_region_offset( 35 this->first_buffer()); 36 size_t total_buffer_size = control_->region_size() - offset_of_first_buffer; 37 return total_buffer_size / buffer_size(); 38 } 39 40 void* ScreenRegionView::GetBuffer(int buffer_idx) { 41 uint8_t* buffer = const_cast<uint8_t*>(this->first_buffer()); 42 return buffer + buffer_idx * this->buffer_size(); 43 } 44 45 // We can use a locking protocol because we decided that the streamer should 46 // have more priority than the hwcomposer, so it's OK to block the hwcomposer 47 // waiting for the streamer to complete, while the streamer will only block on 48 // the hwcomposer when it has ran out of work to do and needs to get more from 49 // the hwcomposer. 50 void ScreenRegionView::BroadcastNewFrame(int buffer_idx, 51 const CompositionStats* stats) { 52 { 53 if (buffer_idx < 0 || buffer_idx >= number_of_buffers()) { 54 LOG(ERROR) << "Attempting to broadcast an invalid buffer index: " 55 << buffer_idx; 56 return; 57 } 58 auto lock_guard(make_lock_guard(&data()->bcast_lock)); 59 data()->seq_num++; 60 data()->buffer_index = static_cast<int32_t>(buffer_idx); 61 if (stats) { 62 data()->stats = *stats; 63 } 64 } 65 // Signaling after releasing the lock may cause spurious wake ups. 66 // Signaling while holding the lock may cause the just-awaken listener to 67 // block immediately trying to acquire the lock. 68 // The former is less costly and slightly less likely to happen. 69 SendSignal(layout::Sides::Both, &data()->seq_num); 70 } 71 72 int ScreenRegionView::WaitForNewFrameSince(uint32_t* last_seq_num, 73 CompositionStats* stats) { 74 static std::unique_ptr<RegionWorker> worker = StartWorker(); 75 // It's ok to read seq_num here without holding the lock because the lock will 76 // be acquired immediately after so we'll block if necessary to wait for the 77 // critical section in BroadcastNewFrame to complete. 78 // Also, the call to WaitForSignal receives a pointer to seq_num (so the 79 // compiler should not optimize it out) and includes a memory barrier 80 // (FUTEX_WAIT). 81 while (data()->seq_num == *last_seq_num) { 82 // Don't hold the lock when waiting for a signal, will deadlock. 83 WaitForSignal(&data()->seq_num, *last_seq_num); 84 } 85 86 { 87 auto lock_guard(make_lock_guard(&data()->bcast_lock)); 88 *last_seq_num = data()->seq_num; 89 if (stats) { 90 *stats = data()->stats; 91 } 92 return static_cast<int>(data()->buffer_index); 93 } 94 } 95