blob: a1f1597ee48cd68af29ed38632ce2e51c7a9131d [file] [log] [blame]
/*
* Copyright (C) 2016 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 "base_composer.h"
#include <string.h>
#include <cutils/properties.h>
#include <hardware/gralloc.h>
#include <log/log.h>
#include <common/libs/utils/size_utils.h>
#include "guest/hals/gralloc/legacy/gralloc_vsoc_priv.h"
namespace cvd {
BaseComposer::BaseComposer(int64_t vsync_base_timestamp)
: vsync_base_timestamp_(vsync_base_timestamp) {
vsync_period_ns_ = 1000000000 / frame_buffer_.refresh_rate();
hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
reinterpret_cast<const hw_module_t**>(&gralloc_module_));
}
BaseComposer::~BaseComposer() {}
void BaseComposer::Dump(char* buff __unused, int buff_len __unused) {}
int BaseComposer::PostFrameBufferTarget(buffer_handle_t buffer_handle) {
int fb_index = frame_buffer_.NextScreenBuffer();
void* frame_buffer = frame_buffer_.GetBuffer(fb_index);
const private_handle_t* p_handle =
reinterpret_cast<const private_handle_t*>(buffer_handle);
void* buffer;
int retval = gralloc_module_->lock(gralloc_module_, buffer_handle,
GRALLOC_USAGE_SW_READ_OFTEN, 0, 0,
p_handle->x_res, p_handle->y_res, &buffer);
if (retval != 0) {
ALOGE("Got error code %d from lock function", retval);
return -1;
}
memcpy(frame_buffer, buffer, frame_buffer_.buffer_size());
frame_buffer_.Broadcast(fb_index);
return 0;
} // namespace cvd
int BaseComposer::PrepareLayers(size_t num_layers, vsoc_hwc_layer* layers) {
// find unsupported overlays
for (size_t i = 0; i < num_layers; i++) {
if (IS_TARGET_FRAMEBUFFER(layers[i].compositionType)) {
continue;
}
layers[i].compositionType = HWC_FRAMEBUFFER;
}
return 0;
}
int BaseComposer::SetLayers(size_t num_layers, vsoc_hwc_layer* layers) {
for (size_t idx = 0; idx < num_layers; idx++) {
if (IS_TARGET_FRAMEBUFFER(layers[idx].compositionType)) {
return PostFrameBufferTarget(layers[idx].handle);
}
}
return -1;
}
FrameBuffer::FrameBuffer()
: broadcast_thread_([this]() { BroadcastLoop(); }) {
auto vsock_frames_port = property_get_int32("ro.boot.vsock_frames_port", -1);
if (vsock_frames_port > 0) {
screen_server_ = cvd::SharedFD::VsockClient(2, vsock_frames_port,
SOCK_STREAM);
if (screen_server_->IsOpen()) {
// TODO(b/128842613): Get this info from the configuration server
int32_t screen_params[4];
auto res = screen_server_->Read(screen_params, sizeof(screen_params));
if (res == sizeof(screen_params)) {
x_res_ = screen_params[0];
y_res_ = screen_params[1];
dpi_ = screen_params[2];
refresh_rate_ = screen_params[3];
} else {
LOG(ERROR) << "Unable to get screen configuration parameters from screen "
<< "server (" << res << "): " << screen_server_->StrError();
}
} else {
LOG(ERROR) << "Unable to connect to screen server: "
<< screen_server_->StrError();
}
} else {
LOG(INFO) << "No screen server configured, operating on headless mode";
}
// This needs to happen no matter what, otherwise there won't be a buffer for
// the set calls to compose on.
inner_buffer_ = std::vector<char>(buffer_size() * 8);
}
FrameBuffer::~FrameBuffer() {
running_ = false;
broadcast_thread_.join();
}
int FrameBuffer::NextScreenBuffer() {
int num_buffers = inner_buffer_.size() / buffer_size();
last_frame_buffer_ =
num_buffers > 0 ? (last_frame_buffer_ + 1) % num_buffers : -1;
return last_frame_buffer_;
}
void FrameBuffer::BroadcastLoop() {
if (!screen_server_->IsOpen()) {
LOG(ERROR) << "Broadcaster thread exiting due to no connection to screen"
<< " server. Compositions will occur, but frames won't be sent"
<< " anywhere";
return;
}
int32_t current_seq = 0;
int32_t current_offset;
while (running_) {
{
std::unique_lock<std::mutex> lock(mutex_);
while (current_seq == current_seq_) {
cond_var_.wait(lock);
}
current_offset = current_offset_;
current_seq = current_seq_;
}
int32_t size = buffer_size();
screen_server_->Write(&size, sizeof(size));
auto buff = static_cast<char*>(GetBuffer(current_offset));
while (size > 0) {
auto written = screen_server_->Write(buff, size);
size -= written;
buff += written;
}
}
}
void FrameBuffer::Broadcast(int32_t offset) {
std::lock_guard<std::mutex> lock(mutex_);
current_offset_ = offset;
current_seq_++;
cond_var_.notify_all();
}
void* FrameBuffer::GetBuffer(int fb_index) {
return &inner_buffer_[buffer_size() * fb_index];
}
size_t FrameBuffer::buffer_size() {
return (line_length() * y_res()) + 4;
}
int32_t FrameBuffer::x_res() { return x_res_; }
int32_t FrameBuffer::y_res() { return y_res_; }
int32_t FrameBuffer::line_length() {
return cvd::AlignToPowerOf2(x_res() * bytes_per_pixel(), 4);
}
int32_t FrameBuffer::bytes_per_pixel() { return 4; }
int32_t FrameBuffer::dpi() { return dpi_; }
int32_t FrameBuffer::refresh_rate() { return refresh_rate_; }
} // namespace cvd