blob: 4e87cf6b8fd08158450fb0ab382eb233564c1fb9 [file] [log] [blame]
#include "include/dvr/dvr_hardware_composer_client.h"
#include <android/dvr/IVrComposer.h>
#include <android/dvr/BnVrComposerCallback.h>
#include <android/hardware_buffer.h>
#include <binder/IServiceManager.h>
#include <private/android/AHardwareBufferHelpers.h>
#include <functional>
#include <memory>
#include <mutex>
struct DvrHwcFrame {
android::dvr::ComposerView::Frame frame;
};
namespace {
class HwcCallback : public android::dvr::BnVrComposerCallback {
public:
using CallbackFunction = std::function<int(DvrHwcFrame*)>;
explicit HwcCallback(const CallbackFunction& callback);
~HwcCallback() override;
// Reset the callback. This needs to be done early to avoid use after free
// accesses from binder thread callbacks.
void Shutdown();
std::unique_ptr<DvrHwcFrame> DequeueFrame();
private:
// android::dvr::BnVrComposerCallback:
android::binder::Status onNewFrame(
const android::dvr::ParcelableComposerFrame& frame,
android::dvr::ParcelableUniqueFd* fence) override;
// Protects the |callback_| from uses from multiple threads. During shutdown
// there may be in-flight frame update events. In those cases the callback
// access needs to be protected otherwise binder threads may access an invalid
// callback.
std::mutex mutex_;
CallbackFunction callback_;
HwcCallback(const HwcCallback&) = delete;
void operator=(const HwcCallback&) = delete;
};
HwcCallback::HwcCallback(const CallbackFunction& callback)
: callback_(callback) {}
HwcCallback::~HwcCallback() {}
void HwcCallback::Shutdown() {
std::lock_guard<std::mutex> guard(mutex_);
callback_ = nullptr;
}
android::binder::Status HwcCallback::onNewFrame(
const android::dvr::ParcelableComposerFrame& frame,
android::dvr::ParcelableUniqueFd* fence) {
std::lock_guard<std::mutex> guard(mutex_);
if (!callback_) {
fence->set_fence(android::base::unique_fd());
return android::binder::Status::ok();
}
std::unique_ptr<DvrHwcFrame> dvr_frame(new DvrHwcFrame());
dvr_frame->frame = frame.frame();
fence->set_fence(android::base::unique_fd(callback_(dvr_frame.release())));
return android::binder::Status::ok();
}
} // namespace
struct DvrHwcClient {
android::sp<android::dvr::IVrComposer> composer;
android::sp<HwcCallback> callback;
};
DvrHwcClient* dvrHwcClientCreate(DvrHwcOnFrameCallback callback, void* data) {
std::unique_ptr<DvrHwcClient> client(new DvrHwcClient());
android::sp<android::IServiceManager> sm(android::defaultServiceManager());
client->composer = android::interface_cast<android::dvr::IVrComposer>(
sm->getService(android::dvr::IVrComposer::SERVICE_NAME()));
if (!client->composer.get())
return nullptr;
client->callback = new HwcCallback(std::bind(callback, data,
std::placeholders::_1));
android::binder::Status status = client->composer->registerObserver(
client->callback);
if (!status.isOk())
return nullptr;
return client.release();
}
void dvrHwcClientDestroy(DvrHwcClient* client) {
client->composer->clearObserver();
// NOTE: Deleting DvrHwcClient* isn't enough since DvrHwcClient::callback is a
// shared pointer that could be referenced from a binder thread. But the
// client callback isn't valid past this calls so that needs to be reset.
client->callback->Shutdown();
delete client;
}
void dvrHwcFrameDestroy(DvrHwcFrame* frame) {
delete frame;
}
DvrHwcDisplay dvrHwcFrameGetDisplayId(DvrHwcFrame* frame) {
return frame->frame.display_id;
}
int32_t dvrHwcFrameGetDisplayWidth(DvrHwcFrame* frame) {
return frame->frame.display_width;
}
int32_t dvrHwcFrameGetDisplayHeight(DvrHwcFrame* frame) {
return frame->frame.display_height;
}
bool dvrHwcFrameGetDisplayRemoved(DvrHwcFrame* frame) {
return frame->frame.removed;
}
size_t dvrHwcFrameGetLayerCount(DvrHwcFrame* frame) {
return frame->frame.layers.size();
}
uint32_t dvrHwcFrameGetActiveConfig(DvrHwcFrame* frame) {
return static_cast<uint32_t>(frame->frame.active_config);
}
uint32_t dvrHwcFrameGetColorMode(DvrHwcFrame* frame) {
return static_cast<uint32_t>(frame->frame.color_mode);
}
void dvrHwcFrameGetColorTransform(DvrHwcFrame* frame, float* out_matrix,
int32_t* out_hint) {
*out_hint = frame->frame.color_transform_hint;
memcpy(out_matrix, frame->frame.color_transform,
sizeof(frame->frame.color_transform));
}
uint32_t dvrHwcFrameGetPowerMode(DvrHwcFrame* frame) {
return static_cast<uint32_t>(frame->frame.power_mode);
}
uint32_t dvrHwcFrameGetVsyncEnabled(DvrHwcFrame* frame) {
return static_cast<uint32_t>(frame->frame.vsync_enabled);
}
DvrHwcLayer dvrHwcFrameGetLayerId(DvrHwcFrame* frame, size_t layer_index) {
return frame->frame.layers[layer_index].id;
}
AHardwareBuffer* dvrHwcFrameGetLayerBuffer(DvrHwcFrame* frame,
size_t layer_index) {
AHardwareBuffer* buffer = android::AHardwareBuffer_from_GraphicBuffer(
frame->frame.layers[layer_index].buffer.get());
AHardwareBuffer_acquire(buffer);
return buffer;
}
int dvrHwcFrameGetLayerFence(DvrHwcFrame* frame, size_t layer_index) {
return frame->frame.layers[layer_index].fence->dup();
}
DvrHwcRecti dvrHwcFrameGetLayerDisplayFrame(DvrHwcFrame* frame,
size_t layer_index) {
return DvrHwcRecti{
frame->frame.layers[layer_index].display_frame.left,
frame->frame.layers[layer_index].display_frame.top,
frame->frame.layers[layer_index].display_frame.right,
frame->frame.layers[layer_index].display_frame.bottom,
};
}
DvrHwcRectf dvrHwcFrameGetLayerCrop(DvrHwcFrame* frame, size_t layer_index) {
return DvrHwcRectf{
frame->frame.layers[layer_index].crop.left,
frame->frame.layers[layer_index].crop.top,
frame->frame.layers[layer_index].crop.right,
frame->frame.layers[layer_index].crop.bottom,
};
}
DvrHwcBlendMode dvrHwcFrameGetLayerBlendMode(DvrHwcFrame* frame,
size_t layer_index) {
return static_cast<DvrHwcBlendMode>(
frame->frame.layers[layer_index].blend_mode);
}
float dvrHwcFrameGetLayerAlpha(DvrHwcFrame* frame, size_t layer_index) {
return frame->frame.layers[layer_index].alpha;
}
uint32_t dvrHwcFrameGetLayerType(DvrHwcFrame* frame, size_t layer_index) {
return frame->frame.layers[layer_index].type;
}
uint32_t dvrHwcFrameGetLayerApplicationId(DvrHwcFrame* frame,
size_t layer_index) {
return frame->frame.layers[layer_index].app_id;
}
uint32_t dvrHwcFrameGetLayerZOrder(DvrHwcFrame* frame, size_t layer_index) {
return frame->frame.layers[layer_index].z_order;
}
void dvrHwcFrameGetLayerCursor(DvrHwcFrame* frame, size_t layer_index,
int32_t* out_x, int32_t* out_y) {
*out_x = frame->frame.layers[layer_index].cursor_x;
*out_y = frame->frame.layers[layer_index].cursor_y;
}
uint32_t dvrHwcFrameGetLayerTransform(DvrHwcFrame* frame, size_t layer_index) {
return frame->frame.layers[layer_index].transform;
}
uint32_t dvrHwcFrameGetLayerDataspace(DvrHwcFrame* frame, size_t layer_index) {
return frame->frame.layers[layer_index].dataspace;
}
uint32_t dvrHwcFrameGetLayerColor(DvrHwcFrame* frame, size_t layer_index) {
const auto& color = frame->frame.layers[layer_index].color;
return color.r | (static_cast<uint32_t>(color.g) << 8) |
(static_cast<uint32_t>(color.b) << 16) |
(static_cast<uint32_t>(color.a) << 24);
}
uint32_t dvrHwcFrameGetLayerNumVisibleRegions(DvrHwcFrame* frame,
size_t layer_index) {
return frame->frame.layers[layer_index].visible_regions.size();
}
DvrHwcRecti dvrHwcFrameGetLayerVisibleRegion(DvrHwcFrame* frame,
size_t layer_index, size_t index) {
return DvrHwcRecti{
frame->frame.layers[layer_index].visible_regions[index].left,
frame->frame.layers[layer_index].visible_regions[index].top,
frame->frame.layers[layer_index].visible_regions[index].right,
frame->frame.layers[layer_index].visible_regions[index].bottom,
};
}
uint32_t dvrHwcFrameGetLayerNumDamagedRegions(DvrHwcFrame* frame,
size_t layer_index) {
return frame->frame.layers[layer_index].damaged_regions.size();
}
DvrHwcRecti dvrHwcFrameGetLayerDamagedRegion(DvrHwcFrame* frame,
size_t layer_index, size_t index) {
return DvrHwcRecti{
frame->frame.layers[layer_index].damaged_regions[index].left,
frame->frame.layers[layer_index].damaged_regions[index].top,
frame->frame.layers[layer_index].damaged_regions[index].right,
frame->frame.layers[layer_index].damaged_regions[index].bottom,
};
}