blob: 2a2233580b11f05a2745fecaad065ccf88617cd5 [file] [log] [blame]
/*
* 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);
}
}