1179 lines
36 KiB
C++
1179 lines
36 KiB
C++
/*
|
|
* Copyright 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 "impl/vr_hwc.h"
|
|
|
|
#include "android-base/stringprintf.h"
|
|
#include <binder/IServiceManager.h>
|
|
#include <cutils/properties.h>
|
|
#include <private/dvr/display_client.h>
|
|
#include <ui/Fence.h>
|
|
#include <utils/Trace.h>
|
|
|
|
#include <mutex>
|
|
|
|
#include "vr_composer_client.h"
|
|
|
|
using namespace android::hardware::graphics::common::V1_0;
|
|
using namespace android::hardware::graphics::composer::V2_3;
|
|
|
|
using android::base::StringPrintf;
|
|
using android::hardware::hidl_handle;
|
|
using android::hardware::hidl_string;
|
|
using android::hardware::hidl_vec;
|
|
using android::hardware::Return;
|
|
using android::hardware::Void;
|
|
|
|
namespace types = android::hardware::graphics::common;
|
|
|
|
namespace android {
|
|
namespace dvr {
|
|
namespace {
|
|
|
|
const Display kDefaultDisplayId = 1;
|
|
const Config kDefaultConfigId = 1;
|
|
|
|
sp<GraphicBuffer> CreateGraphicBuffer(
|
|
const native_handle_t* handle,
|
|
const IVrComposerClient::BufferMetadata& metadata) {
|
|
sp<GraphicBuffer> buffer = new GraphicBuffer(
|
|
handle, GraphicBuffer::CLONE_HANDLE, metadata.width, metadata.height,
|
|
static_cast<int32_t>(metadata.format), metadata.layerCount,
|
|
metadata.usage, metadata.stride);
|
|
if (buffer->initCheck() != OK) {
|
|
ALOGE("Failed to create graphic buffer");
|
|
return nullptr;
|
|
}
|
|
|
|
return buffer;
|
|
}
|
|
|
|
void GetPrimaryDisplaySize(int32_t* width, int32_t* height) {
|
|
*width = 1080;
|
|
*height = 1920;
|
|
|
|
int error = 0;
|
|
auto display_client = display::DisplayClient::Create(&error);
|
|
if (!display_client) {
|
|
ALOGE("Could not connect to display service : %s(%d)", strerror(error),
|
|
error);
|
|
return;
|
|
}
|
|
|
|
auto status = display_client->GetDisplayMetrics();
|
|
if (!status) {
|
|
ALOGE("Could not get display metrics from display service : %s(%d)",
|
|
status.GetErrorMessage().c_str(), status.error());
|
|
return;
|
|
}
|
|
|
|
*width = status.get().display_width;
|
|
*height = status.get().display_height;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
HwcDisplay::HwcDisplay(int32_t width, int32_t height)
|
|
: width_(width), height_(height) {}
|
|
|
|
HwcDisplay::~HwcDisplay() {}
|
|
|
|
bool HwcDisplay::SetClientTarget(const native_handle_t* handle,
|
|
base::unique_fd fence) {
|
|
if (handle)
|
|
buffer_ = CreateGraphicBuffer(handle, buffer_metadata_);
|
|
|
|
fence_ = new Fence(fence.release());
|
|
return true;
|
|
}
|
|
|
|
void HwcDisplay::SetClientTargetMetadata(
|
|
const IVrComposerClient::BufferMetadata& metadata) {
|
|
buffer_metadata_ = metadata;
|
|
}
|
|
|
|
HwcLayer* HwcDisplay::CreateLayer() {
|
|
uint64_t layer_id = layer_ids_++;
|
|
layers_.push_back(HwcLayer(layer_id));
|
|
return &layers_.back();
|
|
}
|
|
|
|
HwcLayer* HwcDisplay::GetLayer(Layer id) {
|
|
for (size_t i = 0; i < layers_.size(); ++i)
|
|
if (layers_[i].info.id == id)
|
|
return &layers_[i];
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
bool HwcDisplay::DestroyLayer(Layer id) {
|
|
for (auto it = layers_.begin(); it != layers_.end(); ++it) {
|
|
if (it->info.id == id) {
|
|
layers_.erase(it);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void HwcDisplay::GetChangedCompositionTypes(
|
|
std::vector<Layer>* layer_ids,
|
|
std::vector<IComposerClient::Composition>* types) {
|
|
std::sort(layers_.begin(), layers_.end(),
|
|
[](const auto& lhs, const auto& rhs) {
|
|
return lhs.info.z_order < rhs.info.z_order;
|
|
});
|
|
|
|
const size_t no_layer = std::numeric_limits<size_t>::max();
|
|
size_t first_client_layer = no_layer, last_client_layer = no_layer;
|
|
for (size_t i = 0; i < layers_.size(); ++i) {
|
|
switch (layers_[i].composition_type) {
|
|
case IComposerClient::Composition::SOLID_COLOR:
|
|
case IComposerClient::Composition::CURSOR:
|
|
case IComposerClient::Composition::SIDEBAND:
|
|
if (first_client_layer == no_layer)
|
|
first_client_layer = i;
|
|
|
|
last_client_layer = i;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (size_t i = 0; i < layers_.size(); ++i) {
|
|
if (i >= first_client_layer && i <= last_client_layer) {
|
|
if (layers_[i].composition_type != IComposerClient::Composition::CLIENT) {
|
|
layer_ids->push_back(layers_[i].info.id);
|
|
types->push_back(IComposerClient::Composition::CLIENT);
|
|
layers_[i].composition_type = IComposerClient::Composition::CLIENT;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if (layers_[i].composition_type != IComposerClient::Composition::DEVICE) {
|
|
layer_ids->push_back(layers_[i].info.id);
|
|
types->push_back(IComposerClient::Composition::DEVICE);
|
|
layers_[i].composition_type = IComposerClient::Composition::DEVICE;
|
|
}
|
|
}
|
|
}
|
|
|
|
Error HwcDisplay::GetFrame(
|
|
std::vector<ComposerView::ComposerLayer>* out_frames) {
|
|
bool queued_client_target = false;
|
|
std::vector<ComposerView::ComposerLayer> frame;
|
|
for (const auto& layer : layers_) {
|
|
if (layer.composition_type == IComposerClient::Composition::CLIENT) {
|
|
if (queued_client_target)
|
|
continue;
|
|
|
|
if (!buffer_.get()) {
|
|
ALOGE("Client composition requested but no client target buffer");
|
|
return Error::BAD_LAYER;
|
|
}
|
|
|
|
ComposerView::ComposerLayer client_target_layer = {
|
|
.buffer = buffer_,
|
|
.fence = fence_.get() ? fence_ : new Fence(-1),
|
|
.display_frame = {0, 0, static_cast<int32_t>(buffer_->getWidth()),
|
|
static_cast<int32_t>(buffer_->getHeight())},
|
|
.crop = {0.0f, 0.0f, static_cast<float>(buffer_->getWidth()),
|
|
static_cast<float>(buffer_->getHeight())},
|
|
.blend_mode = IComposerClient::BlendMode::NONE,
|
|
};
|
|
|
|
frame.push_back(client_target_layer);
|
|
queued_client_target = true;
|
|
} else {
|
|
if (!layer.info.buffer.get() || !layer.info.fence.get()) {
|
|
ALOGV("Layer requested without valid buffer");
|
|
continue;
|
|
}
|
|
|
|
frame.push_back(layer.info);
|
|
}
|
|
}
|
|
|
|
out_frames->swap(frame);
|
|
return Error::NONE;
|
|
}
|
|
|
|
std::vector<Layer> HwcDisplay::UpdateLastFrameAndGetLastFrameLayers() {
|
|
std::vector<Layer> last_frame_layers;
|
|
last_frame_layers.swap(last_frame_layers_ids_);
|
|
|
|
for (const auto& layer : layers_)
|
|
last_frame_layers_ids_.push_back(layer.info.id);
|
|
|
|
return last_frame_layers;
|
|
}
|
|
|
|
void HwcDisplay::SetColorTransform(const float* matrix, int32_t hint) {
|
|
color_transform_hint_ = hint;
|
|
if (matrix)
|
|
memcpy(color_transform_, matrix, sizeof(color_transform_));
|
|
}
|
|
|
|
void HwcDisplay::dumpDebugInfo(std::string* result) const {
|
|
if (!result) {
|
|
return;
|
|
}
|
|
*result += StringPrintf("HwcDisplay: width: %d, height: %d, layers size: %zu, colormode: %d\
|
|
, config: %d\n", width_, height_, layers_.size(), color_mode_, active_config_);
|
|
*result += StringPrintf("HwcDisplay buffer metadata: width: %d, height: %d, stride: %d,\
|
|
layerCount: %d, pixelFormat: %d\n", buffer_metadata_.width, buffer_metadata_.height,
|
|
buffer_metadata_.stride, buffer_metadata_.layerCount, buffer_metadata_.format);
|
|
for (const auto& layer : layers_) {
|
|
layer.dumpDebugInfo(result);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// VrHwcClient
|
|
|
|
VrHwc::VrHwc() {
|
|
vsync_callback_ = new VsyncCallback;
|
|
}
|
|
|
|
VrHwc::~VrHwc() {
|
|
vsync_callback_->SetEventCallback(nullptr);
|
|
}
|
|
|
|
bool VrHwc::hasCapability(hwc2_capability_t /* capability */) { return false; }
|
|
|
|
void VrHwc::registerEventCallback(EventCallback* callback) {
|
|
std::unique_lock<std::mutex> lock(mutex_);
|
|
event_callback_ = callback;
|
|
int32_t width, height;
|
|
GetPrimaryDisplaySize(&width, &height);
|
|
// Create the primary display late to avoid initialization issues between
|
|
// VR HWC and SurfaceFlinger.
|
|
displays_[kDefaultDisplayId].reset(new HwcDisplay(width, height));
|
|
|
|
// Surface flinger will make calls back into vr_hwc when it receives the
|
|
// onHotplug() call, so it's important to release mutex_ here.
|
|
lock.unlock();
|
|
event_callback_->onHotplug(kDefaultDisplayId,
|
|
hardware::graphics::composer::V2_1::
|
|
IComposerCallback::Connection::CONNECTED);
|
|
lock.lock();
|
|
UpdateVsyncCallbackEnabledLocked();
|
|
}
|
|
|
|
void VrHwc::unregisterEventCallback() {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
event_callback_ = nullptr;
|
|
UpdateVsyncCallbackEnabledLocked();
|
|
}
|
|
|
|
uint32_t VrHwc::getMaxVirtualDisplayCount() { return 1; }
|
|
|
|
Error VrHwc::destroyVirtualDisplay(Display display) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
if (display == kDefaultDisplayId || displays_.erase(display) == 0)
|
|
return Error::BAD_DISPLAY;
|
|
ComposerView::Frame frame;
|
|
frame.display_id = display;
|
|
frame.removed = true;
|
|
if (observer_)
|
|
observer_->OnNewFrame(frame);
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::createLayer(Display display, Layer* outLayer) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
auto display_ptr = FindDisplay(display);
|
|
if (!display_ptr)
|
|
return Error::BAD_DISPLAY;
|
|
|
|
HwcLayer* layer = display_ptr->CreateLayer();
|
|
*outLayer = layer->info.id;
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::destroyLayer(Display display, Layer layer) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
auto display_ptr = FindDisplay(display);
|
|
if (!display_ptr) {
|
|
return Error::BAD_DISPLAY;
|
|
}
|
|
|
|
return display_ptr->DestroyLayer(layer) ? Error::NONE : Error::BAD_LAYER;
|
|
}
|
|
|
|
Error VrHwc::getActiveConfig(Display display, Config* outConfig) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
if (!FindDisplay(display))
|
|
return Error::BAD_DISPLAY;
|
|
*outConfig = kDefaultConfigId;
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::getDisplayAttribute(Display display, Config config,
|
|
IComposerClient::Attribute attribute,
|
|
int32_t* outValue) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
auto display_ptr = FindDisplay(display);
|
|
if (!display_ptr) {
|
|
return Error::BAD_DISPLAY;
|
|
}
|
|
if (config != kDefaultConfigId) {
|
|
return Error::BAD_CONFIG;
|
|
}
|
|
|
|
switch (attribute) {
|
|
case IComposerClient::Attribute::WIDTH:
|
|
*outValue = display_ptr->width();
|
|
break;
|
|
case IComposerClient::Attribute::HEIGHT:
|
|
*outValue = display_ptr->height();
|
|
break;
|
|
case IComposerClient::Attribute::VSYNC_PERIOD:
|
|
{
|
|
int error = 0;
|
|
auto display_client = display::DisplayClient::Create(&error);
|
|
if (!display_client) {
|
|
ALOGE("Could not connect to display service : %s(%d)",
|
|
strerror(error), error);
|
|
// Return a default value of 30 fps
|
|
*outValue = 1000 * 1000 * 1000 / 30;
|
|
} else {
|
|
auto metrics = display_client->GetDisplayMetrics();
|
|
*outValue = metrics.get().vsync_period_ns;
|
|
}
|
|
}
|
|
break;
|
|
case IComposerClient::Attribute::DPI_X:
|
|
case IComposerClient::Attribute::DPI_Y:
|
|
{
|
|
constexpr int32_t kDefaultDPI = 300;
|
|
int32_t dpi = property_get_int32("ro.vr.hwc.dpi", kDefaultDPI);
|
|
if (dpi <= 0) {
|
|
dpi = kDefaultDPI;
|
|
}
|
|
*outValue = 1000 * dpi;
|
|
}
|
|
break;
|
|
default:
|
|
return Error::BAD_PARAMETER;
|
|
}
|
|
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::getDisplayConfigs(Display display, hidl_vec<Config>* outConfigs) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
if (!FindDisplay(display))
|
|
return Error::BAD_DISPLAY;
|
|
std::vector<Config> configs(1, kDefaultConfigId);
|
|
*outConfigs = hidl_vec<Config>(configs);
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::getDisplayName(Display /* display */, hidl_string* outName) {
|
|
*outName = hidl_string();
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::getDisplayType(Display display,
|
|
IComposerClient::DisplayType* outType) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
auto display_ptr = FindDisplay(display);
|
|
if (!display_ptr) {
|
|
*outType = IComposerClient::DisplayType::INVALID;
|
|
return Error::BAD_DISPLAY;
|
|
}
|
|
|
|
if (display == kDefaultDisplayId)
|
|
*outType = IComposerClient::DisplayType::PHYSICAL;
|
|
else
|
|
*outType = IComposerClient::DisplayType::VIRTUAL;
|
|
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::getDozeSupport(Display display, bool* outSupport) {
|
|
*outSupport = false;
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
if (!FindDisplay(display))
|
|
return Error::BAD_DISPLAY;
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::setActiveConfig(Display display, Config config) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
auto display_ptr = FindDisplay(display);
|
|
if (!display_ptr)
|
|
return Error::BAD_DISPLAY;
|
|
if (config != kDefaultConfigId)
|
|
return Error::BAD_CONFIG;
|
|
|
|
display_ptr->set_active_config(config);
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::setVsyncEnabled(Display display, IComposerClient::Vsync enabled) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
auto display_ptr = FindDisplay(display);
|
|
if (!display_ptr)
|
|
return Error::BAD_DISPLAY;
|
|
|
|
if (enabled != IComposerClient::Vsync::ENABLE &&
|
|
enabled != IComposerClient::Vsync::DISABLE) {
|
|
return Error::BAD_PARAMETER;
|
|
}
|
|
|
|
Error set_vsync_result = Error::NONE;
|
|
if (display == kDefaultDisplayId) {
|
|
sp<IVsyncService> vsync_service = interface_cast<IVsyncService>(
|
|
defaultServiceManager()->getService(
|
|
String16(IVsyncService::GetServiceName())));
|
|
if (vsync_service == nullptr) {
|
|
ALOGE("Failed to get vsync service");
|
|
return Error::NO_RESOURCES;
|
|
}
|
|
|
|
if (enabled == IComposerClient::Vsync::ENABLE) {
|
|
ALOGI("Enable vsync");
|
|
display_ptr->set_vsync_enabled(true);
|
|
status_t result = vsync_service->registerCallback(vsync_callback_);
|
|
if (result != OK) {
|
|
ALOGE("%s service registerCallback() failed: %s (%d)",
|
|
IVsyncService::GetServiceName(), strerror(-result), result);
|
|
set_vsync_result = Error::NO_RESOURCES;
|
|
}
|
|
} else if (enabled == IComposerClient::Vsync::DISABLE) {
|
|
ALOGI("Disable vsync");
|
|
display_ptr->set_vsync_enabled(false);
|
|
status_t result = vsync_service->unregisterCallback(vsync_callback_);
|
|
if (result != OK) {
|
|
ALOGE("%s service unregisterCallback() failed: %s (%d)",
|
|
IVsyncService::GetServiceName(), strerror(-result), result);
|
|
set_vsync_result = Error::NO_RESOURCES;
|
|
}
|
|
}
|
|
|
|
UpdateVsyncCallbackEnabledLocked();
|
|
}
|
|
|
|
return set_vsync_result;
|
|
}
|
|
|
|
Error VrHwc::setColorTransform(Display display, const float* matrix,
|
|
int32_t hint) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
auto display_ptr = FindDisplay(display);
|
|
if (!display_ptr)
|
|
return Error::BAD_DISPLAY;
|
|
|
|
display_ptr->SetColorTransform(matrix, hint);
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::setClientTarget(Display display, buffer_handle_t target,
|
|
int32_t acquireFence, int32_t /* dataspace */,
|
|
const std::vector<hwc_rect_t>& /* damage */) {
|
|
base::unique_fd fence(acquireFence);
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
auto display_ptr = FindDisplay(display);
|
|
if (!display_ptr)
|
|
return Error::BAD_DISPLAY;
|
|
|
|
if (target == nullptr)
|
|
return Error::NONE;
|
|
|
|
if (!display_ptr->SetClientTarget(target, std::move(fence)))
|
|
return Error::BAD_PARAMETER;
|
|
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::setOutputBuffer(Display display, buffer_handle_t /* buffer */,
|
|
int32_t releaseFence) {
|
|
base::unique_fd fence(releaseFence);
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
auto display_ptr = FindDisplay(display);
|
|
if (!display_ptr)
|
|
return Error::BAD_DISPLAY;
|
|
|
|
// TODO(dnicoara): Is it necessary to do anything here?
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::validateDisplay(
|
|
Display display, std::vector<Layer>* outChangedLayers,
|
|
std::vector<IComposerClient::Composition>* outCompositionTypes,
|
|
uint32_t* /* outDisplayRequestMask */,
|
|
std::vector<Layer>* /* outRequestedLayers */,
|
|
std::vector<uint32_t>* /* outRequestMasks */) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
auto display_ptr = FindDisplay(display);
|
|
if (!display_ptr)
|
|
return Error::BAD_DISPLAY;
|
|
|
|
display_ptr->GetChangedCompositionTypes(outChangedLayers,
|
|
outCompositionTypes);
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::acceptDisplayChanges(Display /* display */) { return Error::NONE; }
|
|
|
|
Error VrHwc::presentDisplay(Display display, int32_t* outPresentFence,
|
|
std::vector<Layer>* outLayers,
|
|
std::vector<int32_t>* outReleaseFences) {
|
|
*outPresentFence = -1;
|
|
outLayers->clear();
|
|
outReleaseFences->clear();
|
|
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
auto display_ptr = FindDisplay(display);
|
|
|
|
if (!display_ptr)
|
|
return Error::BAD_DISPLAY;
|
|
|
|
ComposerView::Frame frame;
|
|
std::vector<Layer> last_frame_layers;
|
|
Error status = display_ptr->GetFrame(&frame.layers);
|
|
frame.display_id = display;
|
|
frame.display_width = display_ptr->width();
|
|
frame.display_height = display_ptr->height();
|
|
frame.active_config = display_ptr->active_config();
|
|
frame.power_mode = display_ptr->power_mode();
|
|
frame.vsync_enabled = display_ptr->vsync_enabled() ?
|
|
IComposerClient::Vsync::ENABLE : IComposerClient::Vsync::DISABLE;
|
|
frame.color_transform_hint = display_ptr->color_transform_hint();
|
|
frame.color_mode = display_ptr->color_mode();
|
|
memcpy(frame.color_transform, display_ptr->color_transform(),
|
|
sizeof(frame.color_transform));
|
|
if (status != Error::NONE)
|
|
return status;
|
|
|
|
last_frame_layers = display_ptr->UpdateLastFrameAndGetLastFrameLayers();
|
|
|
|
base::unique_fd fence;
|
|
if (observer_)
|
|
fence = observer_->OnNewFrame(frame);
|
|
|
|
if (fence.get() < 0)
|
|
return Error::NONE;
|
|
|
|
*outPresentFence = dup(fence.get());
|
|
outLayers->swap(last_frame_layers);
|
|
for (size_t i = 0; i < outLayers->size(); ++i)
|
|
outReleaseFences->push_back(dup(fence.get()));
|
|
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::setLayerCursorPosition(Display display, Layer layer, int32_t x,
|
|
int32_t y) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
auto display_ptr = FindDisplay(display);
|
|
if (!display_ptr)
|
|
return Error::BAD_DISPLAY;
|
|
|
|
HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
|
|
if (!hwc_layer)
|
|
return Error::BAD_LAYER;
|
|
|
|
hwc_layer->info.cursor_x = x;
|
|
hwc_layer->info.cursor_y = y;
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::setLayerBuffer(Display display, Layer layer,
|
|
buffer_handle_t buffer, int32_t acquireFence) {
|
|
base::unique_fd fence(acquireFence);
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
auto display_ptr = FindDisplay(display);
|
|
if (!display_ptr)
|
|
return Error::BAD_DISPLAY;
|
|
|
|
HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
|
|
if (!hwc_layer)
|
|
return Error::BAD_LAYER;
|
|
|
|
hwc_layer->info.buffer = CreateGraphicBuffer(
|
|
buffer, hwc_layer->buffer_metadata);
|
|
hwc_layer->info.fence = new Fence(fence.release());
|
|
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::setLayerSurfaceDamage(Display display, Layer layer,
|
|
const std::vector<hwc_rect_t>& damage) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
auto display_ptr = FindDisplay(display);
|
|
if (!display_ptr)
|
|
return Error::BAD_DISPLAY;
|
|
|
|
HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
|
|
if (!hwc_layer)
|
|
return Error::BAD_LAYER;
|
|
|
|
hwc_layer->info.damaged_regions = damage;
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::setLayerBlendMode(Display display, Layer layer, int32_t mode) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
auto display_ptr = FindDisplay(display);
|
|
if (!display_ptr)
|
|
return Error::BAD_DISPLAY;
|
|
|
|
HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
|
|
if (!hwc_layer)
|
|
return Error::BAD_LAYER;
|
|
|
|
hwc_layer->info.blend_mode =
|
|
static_cast<ComposerView::ComposerLayer::BlendMode>(mode);
|
|
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::setLayerColor(Display display, Layer layer,
|
|
IComposerClient::Color color) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
auto display_ptr = FindDisplay(display);
|
|
if (!display_ptr)
|
|
return Error::BAD_DISPLAY;
|
|
|
|
HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
|
|
if (!hwc_layer)
|
|
return Error::BAD_LAYER;
|
|
|
|
hwc_layer->info.color = color;
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::setLayerCompositionType(Display display, Layer layer,
|
|
int32_t type) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
auto display_ptr = FindDisplay(display);
|
|
if (!display_ptr)
|
|
return Error::BAD_DISPLAY;
|
|
|
|
HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
|
|
if (!hwc_layer)
|
|
return Error::BAD_LAYER;
|
|
|
|
hwc_layer->composition_type = static_cast<HwcLayer::Composition>(type);
|
|
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::setLayerDataspace(Display display, Layer layer,
|
|
int32_t dataspace) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
auto display_ptr = FindDisplay(display);
|
|
if (!display_ptr)
|
|
return Error::BAD_DISPLAY;
|
|
|
|
HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
|
|
if (!hwc_layer)
|
|
return Error::BAD_LAYER;
|
|
|
|
hwc_layer->info.dataspace = dataspace;
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::setLayerDisplayFrame(Display display, Layer layer,
|
|
const hwc_rect_t& frame) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
auto display_ptr = FindDisplay(display);
|
|
if (!display_ptr)
|
|
return Error::BAD_DISPLAY;
|
|
|
|
HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
|
|
if (!hwc_layer)
|
|
return Error::BAD_LAYER;
|
|
|
|
hwc_layer->info.display_frame =
|
|
{frame.left, frame.top, frame.right, frame.bottom};
|
|
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::setLayerPlaneAlpha(Display display, Layer layer, float alpha) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
auto display_ptr = FindDisplay(display);
|
|
if (!display_ptr)
|
|
return Error::BAD_DISPLAY;
|
|
|
|
HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
|
|
if (!hwc_layer)
|
|
return Error::BAD_LAYER;
|
|
|
|
hwc_layer->info.alpha = alpha;
|
|
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::setLayerSidebandStream(Display display, Layer /* layer */,
|
|
buffer_handle_t /* stream */) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
if (!FindDisplay(display))
|
|
return Error::BAD_DISPLAY;
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::setLayerSourceCrop(Display display, Layer layer,
|
|
const hwc_frect_t& crop) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
auto display_ptr = FindDisplay(display);
|
|
if (!display_ptr)
|
|
return Error::BAD_DISPLAY;
|
|
|
|
HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
|
|
if (!hwc_layer)
|
|
return Error::BAD_LAYER;
|
|
|
|
hwc_layer->info.crop = {crop.left, crop.top, crop.right, crop.bottom};
|
|
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::setLayerTransform(Display display, Layer layer,
|
|
int32_t transform) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
auto display_ptr = FindDisplay(display);
|
|
if (!display_ptr)
|
|
return Error::BAD_DISPLAY;
|
|
|
|
HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
|
|
if (!hwc_layer)
|
|
return Error::BAD_LAYER;
|
|
|
|
hwc_layer->info.transform = transform;
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::setLayerVisibleRegion(Display display, Layer layer,
|
|
const std::vector<hwc_rect_t>& visible) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
auto display_ptr = FindDisplay(display);
|
|
if (!display_ptr)
|
|
return Error::BAD_DISPLAY;
|
|
|
|
HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
|
|
if (!hwc_layer)
|
|
return Error::BAD_LAYER;
|
|
|
|
hwc_layer->info.visible_regions = visible;
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::setLayerZOrder(Display display, Layer layer, uint32_t z) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
auto display_ptr = FindDisplay(display);
|
|
if (!display_ptr)
|
|
return Error::BAD_DISPLAY;
|
|
|
|
HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
|
|
if (!hwc_layer)
|
|
return Error::BAD_LAYER;
|
|
|
|
hwc_layer->info.z_order = z;
|
|
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::setLayerInfo(Display display, Layer layer, uint32_t type,
|
|
uint32_t appId) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
auto display_ptr = FindDisplay(display);
|
|
if (!display_ptr)
|
|
return Error::BAD_DISPLAY;
|
|
|
|
HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
|
|
if (!hwc_layer)
|
|
return Error::BAD_LAYER;
|
|
|
|
hwc_layer->info.type = type;
|
|
hwc_layer->info.app_id = appId;
|
|
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::setClientTargetMetadata(
|
|
Display display, const IVrComposerClient::BufferMetadata& metadata) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
auto display_ptr = FindDisplay(display);
|
|
if (!display_ptr)
|
|
return Error::BAD_DISPLAY;
|
|
|
|
display_ptr->SetClientTargetMetadata(metadata);
|
|
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::setLayerBufferMetadata(
|
|
Display display, Layer layer,
|
|
const IVrComposerClient::BufferMetadata& metadata) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
auto display_ptr = FindDisplay(display);
|
|
if (!display_ptr)
|
|
return Error::BAD_DISPLAY;
|
|
|
|
HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
|
|
if (!hwc_layer)
|
|
return Error::BAD_LAYER;
|
|
|
|
hwc_layer->buffer_metadata = metadata;
|
|
|
|
return Error::NONE;
|
|
}
|
|
|
|
Return<void> VrHwc::getCapabilities(getCapabilities_cb hidl_cb) {
|
|
hidl_cb(hidl_vec<Capability>());
|
|
return Void();
|
|
}
|
|
|
|
Return<void> VrHwc::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) {
|
|
std::string result;
|
|
|
|
{
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
result = "\nVrHwc states:\n";
|
|
for (const auto& pair : displays_) {
|
|
result += StringPrintf("Display id: %lu\n", (unsigned long)pair.first);
|
|
pair.second->dumpDebugInfo(&result);
|
|
}
|
|
result += "\n";
|
|
}
|
|
|
|
hidl_cb(hidl_string(result));
|
|
return Void();
|
|
}
|
|
|
|
Return<void> VrHwc::createClient(createClient_cb hidl_cb) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
|
|
Error status = Error::NONE;
|
|
sp<VrComposerClient> client;
|
|
if (!client_.promote().get()) {
|
|
client = new VrComposerClient(*this);
|
|
} else {
|
|
ALOGE("Already have a client");
|
|
status = Error::NO_RESOURCES;
|
|
}
|
|
|
|
client_ = client;
|
|
hidl_cb(status, client);
|
|
return Void();
|
|
}
|
|
|
|
Return<void> VrHwc::createClient_2_3(IComposer::createClient_2_3_cb hidl_cb) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
|
|
Error status = Error::NONE;
|
|
sp<VrComposerClient> client;
|
|
if (!client_.promote().get()) {
|
|
client = new VrComposerClient(*this);
|
|
} else {
|
|
ALOGE("Already have a client");
|
|
status = Error::NO_RESOURCES;
|
|
}
|
|
|
|
client_ = client;
|
|
hidl_cb(status, client);
|
|
return Void();
|
|
}
|
|
|
|
void VrHwc::ForceDisplaysRefresh() {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
if (event_callback_ != nullptr) {
|
|
for (const auto& pair : displays_)
|
|
event_callback_->onRefresh(pair.first);
|
|
}
|
|
}
|
|
|
|
void VrHwc::RegisterObserver(Observer* observer) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
if (observer_)
|
|
ALOGE("Overwriting observer");
|
|
else
|
|
observer_ = observer;
|
|
}
|
|
|
|
void VrHwc::UnregisterObserver(Observer* observer) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
if (observer != observer_)
|
|
ALOGE("Trying to unregister unknown observer");
|
|
else
|
|
observer_ = nullptr;
|
|
}
|
|
|
|
HwcDisplay* VrHwc::FindDisplay(Display display) {
|
|
auto iter = displays_.find(display);
|
|
return iter == displays_.end() ? nullptr : iter->second.get();
|
|
}
|
|
|
|
void VrHwc::UpdateVsyncCallbackEnabledLocked() {
|
|
auto primary_display = FindDisplay(kDefaultDisplayId);
|
|
LOG_ALWAYS_FATAL_IF(event_callback_ != nullptr && primary_display == nullptr,
|
|
"Should have created the primary display by now");
|
|
bool send_vsync =
|
|
event_callback_ != nullptr && primary_display->vsync_enabled();
|
|
vsync_callback_->SetEventCallback(send_vsync ? event_callback_ : nullptr);
|
|
}
|
|
|
|
Return<void> VrHwc::debug(const hidl_handle& fd,
|
|
const hidl_vec<hidl_string>& args) {
|
|
std::string result;
|
|
|
|
{
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
for (const auto& pair : displays_) {
|
|
result += StringPrintf("Display id: %d\n", static_cast<int>(pair.first));
|
|
pair.second->dumpDebugInfo(&result);
|
|
}
|
|
result += "\n";
|
|
}
|
|
|
|
FILE* out = fdopen(dup(fd->data[0]), "w");
|
|
fprintf(out, "%s", result.c_str());
|
|
fclose(out);
|
|
|
|
return Void();
|
|
}
|
|
|
|
void HwcLayer::dumpDebugInfo(std::string* result) const {
|
|
if (!result) {
|
|
return;
|
|
}
|
|
*result += StringPrintf("Layer: composition_type: %d, type: %d, app_id: %d, z_order: %d,\
|
|
cursor_x: %d, cursor_y: %d, color(rgba): (%d,%d,%d,%d), dataspace: %d, transform: %d,\
|
|
display_frame(LTRB): (%d,%d,%d,%d), crop(LTRB): (%.1f,%.1f,%.1f,%.1f), blend_mode: %d\n",
|
|
composition_type, info.type, info.app_id, info.z_order, info.cursor_x, info.cursor_y,
|
|
info.color.r, info.color.g, info.color.b, info.color.a, info.dataspace, info.transform,
|
|
info.display_frame.left, info.display_frame.top, info.display_frame.right,
|
|
info.display_frame.bottom, info.crop.left, info.crop.top, info.crop.right,
|
|
info.crop.bottom, info.blend_mode);
|
|
*result += StringPrintf("Layer buffer metadata: width: %d, height: %d, stride: %d, layerCount: %d\
|
|
, pixelFormat: %d\n", buffer_metadata.width, buffer_metadata.height, buffer_metadata.stride,
|
|
buffer_metadata.layerCount, buffer_metadata.format);
|
|
}
|
|
|
|
status_t VrHwc::VsyncCallback::onVsync(int64_t vsync_timestamp) {
|
|
ATRACE_NAME("vr_hwc onVsync");
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
if (callback_ != nullptr)
|
|
callback_->onVsync(kDefaultDisplayId, vsync_timestamp);
|
|
return OK;
|
|
}
|
|
|
|
void VrHwc::VsyncCallback::SetEventCallback(EventCallback* callback) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
callback_ = callback;
|
|
}
|
|
|
|
// composer::V2_2::ComposerHal
|
|
Error VrHwc::setReadbackBuffer(Display display,
|
|
const native_handle_t* bufferHandle,
|
|
android::base::unique_fd fenceFd) {
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::getReadbackBufferFence(Display display,
|
|
android::base::unique_fd* outFenceFd) {
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::createVirtualDisplay_2_2(uint32_t width, uint32_t height,
|
|
types::V1_1::PixelFormat* format,
|
|
Display* outDisplay) {
|
|
*format = types::V1_1::PixelFormat::RGBA_8888;
|
|
*outDisplay = display_count_;
|
|
displays_[display_count_].reset(new HwcDisplay(width, height));
|
|
display_count_++;
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::setPowerMode_2_2(Display display,
|
|
IComposerClient::PowerMode mode) {
|
|
bool dozeSupported = false;
|
|
|
|
Error dozeSupportError = getDozeSupport(display, &dozeSupported);
|
|
|
|
if (dozeSupportError != Error::NONE)
|
|
return dozeSupportError;
|
|
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
auto display_ptr = FindDisplay(display);
|
|
if (!display_ptr)
|
|
return Error::BAD_DISPLAY;
|
|
|
|
if (mode < IComposerClient::PowerMode::OFF ||
|
|
mode > IComposerClient::PowerMode::DOZE_SUSPEND) {
|
|
return Error::BAD_PARAMETER;
|
|
}
|
|
|
|
if (!dozeSupported && (mode == IComposerClient::PowerMode::DOZE ||
|
|
mode == IComposerClient::PowerMode::DOZE_SUSPEND)) {
|
|
return Error::UNSUPPORTED;
|
|
}
|
|
|
|
display_ptr->set_power_mode(mode);
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::setLayerFloatColor(Display display, Layer layer,
|
|
IComposerClient::FloatColor color) {
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::getRenderIntents(Display display, types::V1_1::ColorMode mode,
|
|
std::vector<RenderIntent>* outIntents) {
|
|
return Error::NONE;
|
|
}
|
|
|
|
std::array<float, 16> VrHwc::getDataspaceSaturationMatrix(
|
|
types::V1_1::Dataspace dataspace) {
|
|
return {};
|
|
}
|
|
|
|
// composer::V2_3::ComposerHal
|
|
Error VrHwc::getHdrCapabilities_2_3(Display /*display*/,
|
|
hidl_vec<Hdr>* /*outTypes*/,
|
|
float* outMaxLuminance,
|
|
float* outMaxAverageLuminance,
|
|
float* outMinLuminance) {
|
|
*outMaxLuminance = 0;
|
|
*outMaxAverageLuminance = 0;
|
|
*outMinLuminance = 0;
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::setLayerPerFrameMetadata_2_3(
|
|
Display display, Layer layer,
|
|
const std::vector<IComposerClient::PerFrameMetadata>& metadata) {
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::getPerFrameMetadataKeys_2_3(
|
|
Display display,
|
|
std::vector<IComposerClient::PerFrameMetadataKey>* outKeys) {
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::setColorMode_2_3(Display display, ColorMode mode,
|
|
RenderIntent intent) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
auto display_ptr = FindDisplay(display);
|
|
if (!display_ptr)
|
|
return Error::BAD_DISPLAY;
|
|
|
|
if (mode < ColorMode::NATIVE || mode > ColorMode::DISPLAY_P3)
|
|
return Error::BAD_PARAMETER;
|
|
|
|
display_ptr->set_color_mode(mode);
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::getRenderIntents_2_3(Display display, ColorMode mode,
|
|
std::vector<RenderIntent>* outIntents) {
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::getColorModes_2_3(Display display, hidl_vec<ColorMode>* outModes) {
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::getClientTargetSupport_2_3(Display display, uint32_t width,
|
|
uint32_t height, PixelFormat format,
|
|
Dataspace dataspace) {
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::getReadbackBufferAttributes_2_3(Display display,
|
|
PixelFormat* outFormat,
|
|
Dataspace* outDataspace) {
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::getDisplayIdentificationData(Display display, uint8_t* outPort,
|
|
std::vector<uint8_t>* outData) {
|
|
int error = 0;
|
|
auto display_client = display::DisplayClient::Create(&error);
|
|
if (!display_client) {
|
|
ALOGE("Could not connect to display service : %s(%d)", strerror(error),
|
|
error);
|
|
return Error::BAD_CONFIG;
|
|
}
|
|
auto edid_data = display_client->GetConfigurationData(
|
|
display::ConfigFileType::kDeviceEdid);
|
|
auto display_identification_port =
|
|
display_client->GetDisplayIdentificationPort();
|
|
*outPort = display_identification_port.get();
|
|
|
|
std::copy(edid_data.get().begin(), edid_data.get().end(),
|
|
std::back_inserter(*outData));
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::setLayerColorTransform(Display display, Layer layer,
|
|
const float* matrix) {
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::getDisplayedContentSamplingAttributes(
|
|
Display display, PixelFormat& format, Dataspace& dataspace,
|
|
hidl_bitfield<IComposerClient::FormatColorComponent>& componentMask) {
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::setDisplayedContentSamplingEnabled(
|
|
Display display, IComposerClient::DisplayedContentSampling enable,
|
|
hidl_bitfield<IComposerClient::FormatColorComponent> componentMask,
|
|
uint64_t maxFrames) {
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::getDisplayedContentSample(Display display, uint64_t maxFrames,
|
|
uint64_t timestamp, uint64_t& frameCount,
|
|
hidl_vec<uint64_t>& sampleComponent0,
|
|
hidl_vec<uint64_t>& sampleComponent1,
|
|
hidl_vec<uint64_t>& sampleComponent2,
|
|
hidl_vec<uint64_t>& sampleComponent3) {
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::getDisplayCapabilities(
|
|
Display display,
|
|
std::vector<IComposerClient::DisplayCapability>* outCapabilities) {
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::setLayerPerFrameMetadataBlobs(
|
|
Display display, Layer layer,
|
|
std::vector<IComposerClient::PerFrameMetadataBlob>& blobs) {
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::getDisplayBrightnessSupport(Display display, bool* outSupport) {
|
|
return Error::NONE;
|
|
}
|
|
|
|
Error VrHwc::setDisplayBrightness(Display display, float brightness) {
|
|
return Error::NONE;
|
|
}
|
|
|
|
} // namespace dvr
|
|
} // namespace android
|