#ifndef ANDROID_DVR_SERVICES_DISPLAYD_HARDWARE_COMPOSER_H_ #define ANDROID_DVR_SERVICES_DISPLAYD_HARDWARE_COMPOSER_H_ #include #include "DisplayHardware/ComposerHal.h" #include "hwc_types.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "DisplayHardware/DisplayIdentification.h" #include "acquired_buffer.h" #include "display_surface.h" // Hardware composer HAL doesn't define HWC_TRANSFORM_NONE as of this writing. #ifndef HWC_TRANSFORM_NONE #define HWC_TRANSFORM_NONE static_cast(0) #endif namespace android { namespace dvr { // Basic display metrics for physical displays. struct DisplayParams { hwc2_display_t id; bool is_primary; int width; int height; struct { int x; int y; } dpi; int vsync_period_ns; }; // Layer represents the connection between a hardware composer layer and the // source supplying buffers for the layer's contents. class Layer { public: Layer() = default; // Sets up the layer to use a display surface as its content source. The Layer // automatically handles ACQUIRE/RELEASE phases for the surface's buffer train // every frame. // // |composer| The composer instance. // |display_params| Info about the display to use. // |blending| receives HWC_BLENDING_* values. // |composition_type| receives either HWC_FRAMEBUFFER for most layers or // HWC_FRAMEBUFFER_TARGET (unless you know what you are doing). // |index| is the index of this surface in the DirectDisplaySurface array. Layer(Hwc2::Composer* composer, const DisplayParams& display_params, const std::shared_ptr& surface, HWC::BlendMode blending, HWC::Composition composition_type, size_t z_order); // Sets up the layer to use a direct buffer as its content source. No special // handling of the buffer is performed; responsibility for updating or // changing the buffer each frame is on the caller. // // |composer| The composer instance. // |display_params| Info about the display to use. // |blending| receives HWC_BLENDING_* values. // |composition_type| receives either HWC_FRAMEBUFFER for most layers or // HWC_FRAMEBUFFER_TARGET (unless you know what you are doing). Layer(Hwc2::Composer* composer, const DisplayParams& display_params, const std::shared_ptr& buffer, HWC::BlendMode blending, HWC::Composition composition_type, size_t z_order); Layer(Layer&&) noexcept; Layer& operator=(Layer&&) noexcept; ~Layer(); // Releases any shared pointers and fence handles held by this instance. void Reset(); // Layers that use a direct IonBuffer should call this each frame to update // which buffer will be used for the next PostLayers. void UpdateBuffer(const std::shared_ptr& buffer); // Sets up the hardware composer layer for the next frame. When the layer is // associated with a display surface, this method automatically ACQUIRES a new // buffer if one is available. void Prepare(); // After calling prepare, if this frame is to be dropped instead of passing // along to the HWC, call Drop to close the contained fence(s). void Drop(); // Performs fence bookkeeping after the frame has been posted to hardware // composer. void Finish(int release_fence_fd); // Sets the blending for the layer. |blending| receives HWC_BLENDING_* values. void SetBlending(HWC::BlendMode blending); // Sets the z-order of this layer void SetZOrder(size_t z_order); // Gets the current IonBuffer associated with this layer. Ownership of the // buffer DOES NOT pass to the caller and the pointer is not guaranteed to // remain valid across calls to Layer::Setup(), Layer::Prepare(), or // Layer::Reset(). YOU HAVE BEEN WARNED. IonBuffer* GetBuffer(); HWC::Composition GetCompositionType() const { return composition_type_; } HWC::Layer GetLayerHandle() const { return hardware_composer_layer_; } bool IsLayerSetup() const { return !source_.empty(); } int GetSurfaceId() const { int surface_id = -1; pdx::rpc::IfAnyOf::Call( &source_, [&surface_id](const SourceSurface& surface_source) { surface_id = surface_source.GetSurfaceId(); }); return surface_id; } int GetBufferId() const { int buffer_id = -1; pdx::rpc::IfAnyOf::Call( &source_, [&buffer_id](const SourceSurface& surface_source) { buffer_id = surface_source.GetBufferId(); }); return buffer_id; } // Compares Layers by surface id. bool operator<(const Layer& other) const { return GetSurfaceId() < other.GetSurfaceId(); } bool operator<(int surface_id) const { return GetSurfaceId() < surface_id; } void IgnoreBadDisplayErrorsOnDestroy(bool ignore) { ignore_bad_display_errors_on_destroy_ = ignore; } private: void CommonLayerSetup(); // Applies all of the settings to this layer using the hwc functions void UpdateLayerSettings(); // Applies visibility settings that may have changed. void UpdateVisibilitySettings(); // Checks whether the buffer, given by id, is associated with the given slot // in the HWC buffer cache. If the slot is not associated with the given // buffer the cache is updated to establish the association and the buffer // should be sent to HWC using setLayerBuffer. Returns true if the association // was already established, false if not. A buffer_id of -1 is never // associated and always returns false. bool CheckAndUpdateCachedBuffer(std::size_t slot, int buffer_id); // Composer instance. Hwc2::Composer* composer_ = nullptr; // Parameters of the display to use for this layer. DisplayParams display_params_; // The hardware composer layer and metrics to use during the prepare cycle. hwc2_layer_t hardware_composer_layer_ = 0; // Layer properties used to setup the hardware composer layer during the // Prepare phase. size_t z_order_ = 0; HWC::BlendMode blending_ = HWC::BlendMode::None; HWC::Composition composition_type_ = HWC::Composition::Invalid; HWC::Composition target_composition_type_ = HWC::Composition::Device; // State when the layer is connected to a surface. Provides the same interface // as SourceBuffer to simplify internal use by Layer. struct SourceSurface { std::shared_ptr surface; AcquiredBuffer acquired_buffer; pdx::LocalHandle release_fence; explicit SourceSurface(const std::shared_ptr& surface) : surface(surface) {} // Attempts to acquire a new buffer from the surface and return a tuple with // width, height, buffer handle, and fence. If a new buffer is not available // the previous buffer is returned or an empty value if no buffer has ever // been posted. When a new buffer is acquired the previous buffer's release // fence is passed out automatically. std::tuple, pdx::LocalHandle, std::size_t> Acquire() { if (surface->IsBufferAvailable()) { acquired_buffer.Release(std::move(release_fence)); acquired_buffer = surface->AcquireCurrentBuffer(); ATRACE_ASYNC_END("BufferPost", acquired_buffer.buffer()->id()); } if (!acquired_buffer.IsEmpty()) { return std::make_tuple( acquired_buffer.buffer()->width(), acquired_buffer.buffer()->height(), acquired_buffer.buffer()->id(), acquired_buffer.buffer()->buffer()->buffer(), acquired_buffer.ClaimAcquireFence(), acquired_buffer.slot()); } else { return std::make_tuple(0, 0, -1, nullptr, pdx::LocalHandle{}, 0); } } void Finish(pdx::LocalHandle fence) { release_fence = std::move(fence); } // Gets a pointer to the current acquired buffer or returns nullptr if there // isn't one. IonBuffer* GetBuffer() { if (acquired_buffer.IsAvailable()) return acquired_buffer.buffer()->buffer(); else return nullptr; } // Returns the surface id of the surface. int GetSurfaceId() const { return surface->surface_id(); } // Returns the buffer id for the current buffer. int GetBufferId() const { if (acquired_buffer.IsAvailable()) return acquired_buffer.buffer()->id(); else return -1; } }; // State when the layer is connected to a buffer. Provides the same interface // as SourceSurface to simplify internal use by Layer. struct SourceBuffer { std::shared_ptr buffer; std::tuple, pdx::LocalHandle, std::size_t> Acquire() { if (buffer) return std::make_tuple(buffer->width(), buffer->height(), -1, buffer->buffer(), pdx::LocalHandle{}, 0); else return std::make_tuple(0, 0, -1, nullptr, pdx::LocalHandle{}, 0); } void Finish(pdx::LocalHandle /*fence*/) {} IonBuffer* GetBuffer() { return buffer.get(); } int GetSurfaceId() const { return -1; } int GetBufferId() const { return -1; } }; // The underlying hardware composer layer is supplied buffers either from a // surface buffer train or from a buffer directly. pdx::rpc::Variant source_; pdx::LocalHandle acquire_fence_; bool surface_rect_functions_applied_ = false; bool pending_visibility_settings_ = true; // Map of buffer slot assignments that have already been established with HWC: // slot -> buffer_id. When this map contains a matching slot and buffer_id the // buffer argument to setLayerBuffer may be nullptr to avoid the cost of // importing a buffer HWC already knows about. std::map cached_buffer_map_; // When calling destroyLayer() on an external display that's been removed we // typically get HWC2_ERROR_BAD_DISPLAY errors. If // ignore_bad_display_errors_on_destroy_ is true, don't log the bad display // errors, since they're expected. bool ignore_bad_display_errors_on_destroy_ = false; Layer(const Layer&) = delete; void operator=(const Layer&) = delete; }; // HardwareComposer encapsulates the hardware composer HAL, exposing a // simplified API to post buffers to the display. // // HardwareComposer is accessed by both the vr flinger dispatcher thread and the // surface flinger main thread, in addition to internally running a separate // thread for compositing/EDS and posting layers to the HAL. When changing how // variables are used or adding new state think carefully about which threads // will access the state and whether it needs to be synchronized. class HardwareComposer { public: using RequestDisplayCallback = std::function; HardwareComposer(); ~HardwareComposer(); bool Initialize(Hwc2::Composer* composer, hwc2_display_t primary_display_id, RequestDisplayCallback request_display_callback); bool IsInitialized() const { return initialized_; } // Start the post thread if there's work to do (i.e. visible layers). This // should only be called from surface flinger's main thread. void Enable(); // Pause the post thread, blocking until the post thread has signaled that // it's paused. This should only be called from surface flinger's main thread. void Disable(); // Called on a binder thread. void OnBootFinished(); std::string Dump(); const DisplayParams& GetPrimaryDisplayParams() const { return primary_display_; } // Sets the display surfaces to compose the hardware layer stack. void SetDisplaySurfaces( std::vector> surfaces); int OnNewGlobalBuffer(DvrGlobalBufferKey key, IonBuffer& ion_buffer); void OnDeletedGlobalBuffer(DvrGlobalBufferKey key); // Gets the edid data for the current active display (internal or external) DisplayIdentificationData GetCurrentDisplayIdentificationData() { return display_identification_data_; } // Gets the edid port for the current active display (internal or external) uint8_t GetCurrentDisplayPort() { return display_port_; } private: DisplayParams GetDisplayParams(Hwc2::Composer* composer, hwc2_display_t display, bool is_primary); // Turn display vsync on/off. Returns true on success, false on failure. bool EnableVsync(const DisplayParams& display, bool enabled); // Turn display power on/off. Returns true on success, false on failure. bool SetPowerMode(const DisplayParams& display, bool active); // Convenience function to turn a display on/off. Turns both power and vsync // on/off. Returns true on success, false on failure. bool EnableDisplay(const DisplayParams& display, bool enabled); class VsyncService : public BnVsyncService { public: status_t registerCallback(const sp callback) override; status_t unregisterCallback(const sp callback) override; void OnVsync(int64_t vsync_timestamp); private: std::vector>::const_iterator FindCallback( const sp& callback) const; std::mutex mutex_; std::vector> callbacks_; }; class ComposerCallback : public Hwc2::IComposerCallback { public: ComposerCallback() = default; hardware::Return onHotplug(Hwc2::Display display, Connection conn) override; hardware::Return onRefresh(Hwc2::Display display) override; hardware::Return onVsync(Hwc2::Display display, int64_t timestamp) override; hardware::Return onVsync_2_4( Hwc2::Display display, int64_t timestamp, Hwc2::VsyncPeriodNanos vsyncPeriodNanos) override; hardware::Return onVsyncPeriodTimingChanged( Hwc2::Display display, const Hwc2::VsyncPeriodChangeTimeline& updatedTimeline) override; hardware::Return onSeamlessPossible(Hwc2::Display display) override; bool GotFirstHotplug() { return got_first_hotplug_; } void SetVsyncService(const sp& vsync_service); struct Displays { hwc2_display_t primary_display = 0; std::optional external_display; bool external_display_was_hotplugged = false; }; Displays GetDisplays(); pdx::Status GetVsyncTime(hwc2_display_t display); private: struct DisplayInfo { hwc2_display_t id = 0; pdx::LocalHandle driver_vsync_event_fd; int64_t callback_vsync_timestamp{0}; }; DisplayInfo* GetDisplayInfo(hwc2_display_t display); std::mutex mutex_; bool got_first_hotplug_ = false; DisplayInfo primary_display_; std::optional external_display_; bool external_display_was_hotplugged_ = false; sp vsync_service_; }; HWC::Error Validate(hwc2_display_t display); HWC::Error Present(hwc2_display_t display); void PostLayers(hwc2_display_t display); void PostThread(); // The post thread has two controlling states: // 1. Idle: no work to do (no visible surfaces). // 2. Suspended: explicitly halted (system is not in VR mode). // When either #1 or #2 is true then the post thread is quiescent, otherwise // it is active. using PostThreadStateType = uint32_t; struct PostThreadState { enum : PostThreadStateType { Active = 0, Idle = (1 << 0), Suspended = (1 << 1), Quit = (1 << 2), }; }; void UpdatePostThreadState(uint32_t state, bool suspend); // Blocks until either event_fd becomes readable, or we're interrupted by a // control thread, or timeout_ms is reached before any events occur. Any // errors are returned as negative errno values, with -ETIMEDOUT returned in // the case of a timeout. If we're interrupted, kPostThreadInterrupted will be // returned. int PostThreadPollInterruptible(const pdx::LocalHandle& event_fd, int requested_events, int timeout_ms); // WaitForPredictedVSync and SleepUntil are blocking calls made on the post // thread that can be interrupted by a control thread. If interrupted, these // calls return kPostThreadInterrupted. int ReadWaitPPState(); pdx::Status WaitForPredictedVSync(); int SleepUntil(int64_t wakeup_timestamp); // Initialize any newly connected displays, and set target_display_ to the // display we should render to. Returns true if target_display_ // changed. Called only from the post thread. bool UpdateTargetDisplay(); // Reconfigures the layer stack if the display surfaces changed since the last // frame. Called only from the post thread. void UpdateLayerConfig(); // Called on the post thread to create the Composer instance. void CreateComposer(); // Called on the post thread when the post thread is resumed. void OnPostThreadResumed(); // Called on the post thread when the post thread is paused or quits. void OnPostThreadPaused(); // Use post_thread_wait_ to wait for a specific condition, specified by pred. // timeout_sec < 0 means wait indefinitely, otherwise it specifies the timeout // in seconds. // The lock must be held when this function is called. // Returns true if the wait was interrupted because the post thread was asked // to quit. bool PostThreadCondWait(std::unique_lock& lock, int timeout_sec, const std::function& pred); // Map the given shared memory buffer to our broadcast ring to track updates // to the config parameters. int MapConfigBuffer(IonBuffer& ion_buffer); void ConfigBufferDeleted(); // Poll for config udpates. void UpdateConfigBuffer(); bool initialized_; bool is_standalone_device_; std::unique_ptr composer_; sp composer_callback_; RequestDisplayCallback request_display_callback_; DisplayParams primary_display_; std::optional external_display_; DisplayParams* target_display_ = &primary_display_; // The list of surfaces we should draw. Set by the display service when // DirectSurfaces are added, removed, or change visibility. Written by the // message dispatch thread and read by the post thread. std::vector> surfaces_; // Set to true by the dispatch thread whenever surfaces_ changes. Set to false // by the post thread when the new list of surfaces is processed. bool surfaces_changed_ = false; std::vector> current_surfaces_; // Layer set for handling buffer flow into hardware composer layers. This // vector must be sorted by surface_id in ascending order. std::vector layers_; // The layer posting thread. This thread wakes up a short time before vsync to // hand buffers to hardware composer. std::thread post_thread_; // Post thread state machine and synchronization primitives. PostThreadStateType post_thread_state_{PostThreadState::Idle | PostThreadState::Suspended}; std::atomic post_thread_quiescent_{true}; bool post_thread_resumed_{false}; pdx::LocalHandle post_thread_event_fd_; std::mutex post_thread_mutex_; std::condition_variable post_thread_wait_; std::condition_variable post_thread_ready_; // When boot is finished this will be set to true and the post thread will be // notified via post_thread_wait_. bool boot_finished_ = false; // VSync sleep timerfd. pdx::LocalHandle vsync_sleep_timer_fd_; // The timestamp of the last vsync. int64_t last_vsync_timestamp_ = 0; // The number of vsync intervals to predict since the last vsync. int vsync_prediction_interval_ = 1; // Vsync count since display on. uint32_t vsync_count_ = 0; // Counter tracking the number of skipped frames. int frame_skip_count_ = 0; // Fd array for tracking retire fences that are returned by hwc. This allows // us to detect when the display driver begins queuing frames. std::vector retire_fence_fds_; // If we are publishing vsync data, we will put it here. std::unique_ptr> vsync_ring_; // Broadcast ring for receiving config data from the DisplayManager. DvrConfigRing shared_config_ring_; uint32_t shared_config_ring_sequence_{0}; // Config buffer for reading from the post thread. DvrConfig post_thread_config_; std::mutex shared_config_mutex_; bool vsync_trace_parity_ = false; sp vsync_service_; // Edid section. void UpdateEdidData(Hwc2::Composer* composer, hwc2_display_t hw_id); DisplayIdentificationData display_identification_data_; uint8_t display_port_; static constexpr int kPostThreadInterrupted = 1; HardwareComposer(const HardwareComposer&) = delete; void operator=(const HardwareComposer&) = delete; }; } // namespace dvr } // namespace android #endif // ANDROID_DVR_SERVICES_DISPLAYD_HARDWARE_COMPOSER_H_