blob: a50e06b2968f47cfbd51f2e2468a4fc89c915b75 [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/fb_bcast_region_view.h"
#include "common/libs/glog/logging.h"
#include "common/vsoc/lib/lock_guard.h"
using vsoc::framebuffer::FBBroadcastRegionView;
using vsoc::layout::framebuffer::CompositionStats;
uint32_t FBBroadcastRegionView::GetAndSetNextAvailableBufferBit(
uint32_t filter) {
auto lock_guard(make_lock_guard(&data()->bcast_lock));
uint32_t bit = data()->buffer_bits & filter;
if (bit == filter) {
// All bits from the filter are already set.
return 0LU;
}
// Set available bits to 1
bit = (bit ^ filter);
// Isolate first available bit
bit &= ~bit + 1LU;
// Set it on bit set on shared memory
data()->buffer_bits |= bit;
return bit;
}
void FBBroadcastRegionView::UnsetBufferBits(uint32_t bits) {
auto lock_guard(make_lock_guard(&data()->bcast_lock));
data()->buffer_bits &= ~bits;
}
// 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's ran out of work to do and needs to get more from the
// hwcomposer.
void FBBroadcastRegionView::BroadcastNewFrame(vsoc_reg_off_t frame_offset,
const CompositionStats* stats) {
{
auto lock_guard(make_lock_guard(&data()->bcast_lock));
data()->seq_num++;
data()->frame_offset = frame_offset;
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.
layout::Sides side;
side.value_ = layout::Sides::Both;
SendSignal(side, &data()->seq_num);
}
vsoc_reg_off_t FBBroadcastRegionView::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 data()->frame_offset;
}
}
#if defined(CUTTLEFISH_HOST)
std::shared_ptr<FBBroadcastRegionView> FBBroadcastRegionView::GetInstance(
const char* domain) {
return RegionView::GetInstanceImpl<FBBroadcastRegionView>(
[](std::shared_ptr<FBBroadcastRegionView> region, const char* domain) {
return region->Open(domain);
},
domain);
}
#else
std::shared_ptr<FBBroadcastRegionView> FBBroadcastRegionView::GetInstance() {
return RegionView::GetInstanceImpl<FBBroadcastRegionView>(
std::mem_fn(&FBBroadcastRegionView::Open));
}
#endif