#include "include/dvr/dvr_hardware_composer_client.h" #include #include #include #include #include #include #include #include struct DvrHwcFrame { android::dvr::ComposerView::Frame frame; }; namespace { class HwcCallback : public android::dvr::BnVrComposerCallback { public: using CallbackFunction = std::function; 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 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 guard(mutex_); callback_ = nullptr; } android::binder::Status HwcCallback::onNewFrame( const android::dvr::ParcelableComposerFrame& frame, android::dvr::ParcelableUniqueFd* fence) { std::lock_guard guard(mutex_); if (!callback_) { fence->set_fence(android::base::unique_fd()); return android::binder::Status::ok(); } std::unique_ptr 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 composer; android::sp callback; }; DvrHwcClient* dvrHwcClientCreate(DvrHwcOnFrameCallback callback, void* data) { std::unique_ptr client(new DvrHwcClient()); android::sp sm(android::defaultServiceManager()); client->composer = android::interface_cast( 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(frame->frame.active_config); } uint32_t dvrHwcFrameGetColorMode(DvrHwcFrame* frame) { return static_cast(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(frame->frame.power_mode); } uint32_t dvrHwcFrameGetVsyncEnabled(DvrHwcFrame* frame) { return static_cast(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( 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(color.g) << 8) | (static_cast(color.b) << 16) | (static_cast(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, }; }