return true;
}
+bool Compositor::DrawIdleState(DisplayPlaneStateList &comp_planes,
+ std::vector<OverlayLayer> &layers,
+ const std::vector<HwcRect<int>> &display_frame) {
+ CTRACE();
+ const DisplayPlaneState *comp = NULL;
+ std::vector<size_t> dedicated_layers;
+ ScopedIdleRendererState state(renderer_.get());
+ if (!state.IsValid()) {
+ ETRACE("Failed to draw as Renderer doesnt have a valid context.");
+ return false;
+ }
+
+ if (!gpu_resource_handler_->PrepareResources(layers)) {
+ ETRACE(
+ "Failed to prepare GPU resources for compositing the frame, "
+ "error: %s",
+ PRINTERROR());
+ return false;
+ }
+
+ for (DisplayPlaneState &plane : comp_planes) {
+ if (plane.GetCompositionState() == DisplayPlaneState::State::kScanout) {
+ dedicated_layers.insert(dedicated_layers.end(),
+ plane.source_layers().begin(),
+ plane.source_layers().end());
+ } else if (plane.GetCompositionState() ==
+ DisplayPlaneState::State::kRender) {
+ comp = &plane;
+ std::vector<CompositionRegion> &comp_regions =
+ plane.GetCompositionRegion();
+ if (comp_regions.empty()) {
+ SeparateLayers(dedicated_layers, comp->source_layers(), display_frame,
+ comp_regions);
+ }
+
+ std::vector<size_t>().swap(dedicated_layers);
+ if (comp_regions.empty())
+ continue;
+
+ if (!Render(layers, plane.GetOffScreenTarget(), comp_regions)) {
+ ETRACE("Failed to Render layer.");
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
void Compositor::InsertFence(uint64_t fence) {
renderer_->InsertFence(fence);
}
OverlayBufferManager *buffer_manager, uint32_t width,
uint32_t height, HWCNativeHandle output_handle,
int32_t *retire_fence);
+ bool DrawIdleState(DisplayPlaneStateList &comp_planes,
+ std::vector<OverlayLayer> &layers,
+ const std::vector<HwcRect<int>> &display_frame);
void InsertFence(uint64_t fence);
private:
EGLOffScreenContext::EGLOffScreenContext()
: egl_display_(EGL_NO_DISPLAY),
egl_ctx_(EGL_NO_CONTEXT),
+ egl_idle_display_(EGL_NO_DISPLAY),
+ egl_idle_ctx_(EGL_NO_CONTEXT),
restore_context_(false) {
}
if (egl_display_ != EGL_NO_DISPLAY && egl_ctx_ != EGL_NO_CONTEXT)
if (eglDestroyContext(egl_display_, egl_ctx_) == EGL_FALSE)
ETRACE("Failed to destroy OpenGL ES Context.");
+
+ if (egl_idle_display_ != EGL_NO_DISPLAY && egl_idle_ctx_ != EGL_NO_CONTEXT)
+ if (eglDestroyContext(egl_idle_display_, egl_idle_ctx_) == EGL_FALSE)
+ ETRACE("Failed to destroy Idle OpenGL ES Context.");
}
bool EGLOffScreenContext::Init() {
return true;
}
+bool EGLOffScreenContext::InitIdleContext() {
+ EGLint num_configs;
+ EGLConfig egl_config;
+ static const EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3,
+ EGL_NONE};
+
+ static const EGLint config_attribs[] = {EGL_SURFACE_TYPE, EGL_DONT_CARE,
+ EGL_NONE};
+
+ egl_idle_display_ = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ if (egl_idle_display_ == EGL_NO_DISPLAY) {
+ ETRACE("Failed to get egl display");
+ return false;
+ }
+
+ if (!eglInitialize(egl_idle_display_, NULL, NULL)) {
+ ETRACE("Egl Initialization failed.");
+ return false;
+ }
+
+ if (!eglChooseConfig(egl_idle_display_, config_attribs, &egl_config, 1,
+ &num_configs)) {
+ ETRACE("Failed to choose a valid EGLConfig.");
+ return false;
+ }
+
+ egl_idle_ctx_ = eglCreateContext(egl_idle_display_, egl_config,
+ EGL_NO_CONTEXT, context_attribs);
+
+ if (egl_idle_ctx_ == EGL_NO_CONTEXT) {
+ ETRACE("Failed to create EGL Context.");
+ return false;
+ }
+
+ if (!eglMakeCurrent(egl_idle_display_, EGL_NO_SURFACE, EGL_NO_SURFACE,
+ egl_idle_ctx_)) {
+ ETRACE("failed to make context current");
+ return false;
+ }
+
+ return true;
+}
+
bool EGLOffScreenContext::MakeCurrent() {
saved_egl_display_ = eglGetCurrentDisplay();
saved_egl_ctx_ = eglGetCurrentContext();
return true;
}
+bool EGLOffScreenContext::MakeCurrentIdle() {
+ if (egl_idle_display_ == EGL_NO_DISPLAY) {
+ return InitIdleContext();
+ }
+
+ return true;
+}
+
void EGLOffScreenContext::RestoreState() {
if (!restore_context_)
return;
bool MakeCurrent();
+ bool MakeCurrentIdle();
+
void RestoreState();
private:
+ bool InitIdleContext();
EGLDisplay egl_display_;
EGLContext egl_ctx_;
+ EGLDisplay egl_idle_display_;
+ EGLContext egl_idle_ctx_;
EGLDisplay saved_egl_display_ = EGL_NO_DISPLAY;
EGLContext saved_egl_ctx_ = EGL_NO_CONTEXT;
EGLSurface saved_egl_read_ = EGL_NO_SURFACE;
return context_.MakeCurrent();
}
+bool GLRenderer::MakeCurrentIdle() {
+ return context_.MakeCurrentIdle();
+}
+
void GLRenderer::InsertFence(uint64_t kms_fence) {
if (kms_fence > 0) {
EGLint attrib_list[] = {
bool MakeCurrent() override;
+ bool MakeCurrentIdle() override;
+
void SetExplicitSyncSupport(bool disable_explicit_sync) override;
private:
virtual bool MakeCurrent() = 0;
+ virtual bool MakeCurrentIdle() = 0;
+
virtual void SetExplicitSyncSupport(bool disable_explicit_sync) = 0;
};
renderer_->RestoreState();
}
+ScopedIdleRendererState::ScopedIdleRendererState(Renderer* renderer) {
+ is_valid_ = renderer->MakeCurrentIdle();
+}
+
+ScopedIdleRendererState::~ScopedIdleRendererState() {
+}
+
} // namespace hwcomposer
bool is_valid_;
};
+struct ScopedIdleRendererState {
+ ScopedIdleRendererState(Renderer* renderer);
+
+ ScopedIdleRendererState(const ScopedRendererState& rhs) = delete;
+
+ ~ScopedIdleRendererState();
+
+ ScopedIdleRendererState& operator=(const ScopedRendererState& rhs) = delete;
+
+ bool IsValid() const {
+ return is_valid_;
+ }
+
+ private:
+ bool is_valid_;
+};
+
} // namespace hwcomposer
#endif // SCOPED_RENDERER_STATE_H_
return true;
}
+bool VKRenderer::MakeCurrentIdle() {
+ return true;
+}
+
void VKRenderer::SetExplicitSyncSupport(bool disable_explicit_sync) {
}
void InsertFence(uint64_t kms_fence) override;
void RestoreState() override;
bool MakeCurrent() override;
+ bool MakeCurrentIdle() override;
void SetExplicitSyncSupport(bool disable_explicit_sync) override;
private:
int success =
drmModeAtomicAddProperty(property_set, id_, crtc_prop_.id, 0) < 0;
success |= drmModeAtomicAddProperty(property_set, id_, fb_prop_.id, 0) < 0;
+ success |=
+ drmModeAtomicAddProperty(property_set, id_, crtc_x_prop_.id, 0) < 0;
+ success |=
+ drmModeAtomicAddProperty(property_set, id_, crtc_y_prop_.id, 0) < 0;
+ success |=
+ drmModeAtomicAddProperty(property_set, id_, crtc_w_prop_.id, 0) < 0;
+ success |=
+ drmModeAtomicAddProperty(property_set, id_, crtc_h_prop_.id, 0) < 0;
+ success |= drmModeAtomicAddProperty(property_set, id_, src_x_prop_.id, 0) < 0;
+ success |= drmModeAtomicAddProperty(property_set, id_, src_y_prop_.id, 0) < 0;
+ success |= drmModeAtomicAddProperty(property_set, id_, src_w_prop_.id, 0) < 0;
+ success |= drmModeAtomicAddProperty(property_set, id_, src_h_prop_.id, 0) < 0;
if (success) {
- ETRACE("Failed to disable plane with id: %d", id_);
+ ETRACE("Could not update properties for plane with id: %d", id_);
return false;
}
std::vector<std::unique_ptr<NativeSurface>>().swap(surfaces_);
}
+void DisplayPlaneManager::ReleaseFreeOffScreenTargets() {
+ std::vector<std::unique_ptr<NativeSurface>> surfaces;
+ for (auto &fb : surfaces_) {
+ if (fb->InUse()) {
+ surfaces.emplace_back(fb.release());
+ }
+ }
+
+ surfaces.swap(surfaces_);
+}
+
bool DisplayPlaneManager::TestCommit(
const std::vector<OverlayPlane> &commit_planes) const {
ScopedDrmAtomicReqPtr pset(drmModeAtomicAlloc());
void EnsureOffScreenTarget(DisplayPlaneState &plane);
+ void ReleaseFreeOffScreenTargets();
+
protected:
struct OverlayPlane {
public:
display_plane_manager_.reset(
new DisplayPlaneManager(gpu_fd_, crtc_id_, buffer_manager_));
- vblank_handler_.reset(new VblankEventHandler());
+ vblank_handler_.reset(new VblankEventHandler(this));
kms_fence_handler_.reset(new KMSFenceEventHandler(this));
/* use 0x80 as default brightness for all colors */
case kOn:
needs_modeset_ = true;
needs_color_correction_ = true;
- flags_ = DRM_MODE_ATOMIC_ALLOW_MODESET;
+ flags_ = 0;
+ flags_ |= DRM_MODE_ATOMIC_ALLOW_MODESET;
drmModeConnectorSetProperty(gpu_fd_, connector_, dpms_prop_,
DRM_MODE_DPMS_ON);
bool DisplayQueue::QueueUpdate(std::vector<HwcLayer*>& source_layers,
int32_t* retire_fence) {
CTRACE();
+ ScopedIdleStateTracker tracker(idle_tracker_);
size_t size = source_layers.size();
size_t previous_size = previous_layers_.size();
std::vector<OverlayLayer> layers;
}
}
+ previous_layers_rects_.swap(layers_rects);
+
return true;
}
display_plane_manager_->DisablePipe(pset.get());
drmModeConnectorSetProperty(gpu_fd_, connector_, dpms_prop_,
DRM_MODE_DPMS_OFF);
+ buffer_manager_->UnRegisterLayerBuffers(previous_layers_);
std::vector<OverlayLayer>().swap(previous_layers_);
previous_plane_state_.clear();
+ std::vector<HwcRect<int>>().swap(previous_layers_rects_);
+ previous_plane_state_.clear();
compositor_.Reset();
vblank_handler_->SetPowerMode(kOff);
+ idle_tracker_.preparing_composition_ = false;
+ idle_tracker_.idle_frames_ = 0;
}
void DisplayQueue::GetDrmObjectProperty(const char* name,
vblank_handler_->VSyncControl(enabled);
}
+void DisplayQueue::HandleIdleCase() {
+ idle_tracker_.idle_lock_.lock();
+ if (idle_tracker_.preparing_composition_) {
+ idle_tracker_.idle_lock_.unlock();
+ return;
+ }
+
+ if (previous_plane_state_.size() <= 1) {
+ idle_tracker_.idle_lock_.unlock();
+ return;
+ }
+
+ if (idle_tracker_.idle_frames_ > 5) {
+ idle_tracker_.idle_lock_.unlock();
+ return;
+ }
+
+ if (idle_tracker_.idle_frames_ < 5) {
+ idle_tracker_.idle_frames_++;
+ idle_tracker_.idle_lock_.unlock();
+ return;
+ }
+
+ idle_tracker_.idle_frames_++;
+ DisplayPlaneStateList current_composition_planes;
+ bool render_layers;
+ std::tie(render_layers, current_composition_planes) =
+ display_plane_manager_->ValidateLayers(previous_layers_, false, true);
+
+ if (render_layers) {
+ if (!compositor_.BeginFrame(true)) {
+ ETRACE("Failed to initialize compositor.");
+ idle_tracker_.idle_lock_.unlock();
+ return;
+ }
+
+ // Prepare for final composition.
+ if (!compositor_.DrawIdleState(current_composition_planes, previous_layers_,
+ previous_layers_rects_)) {
+ ETRACE("Failed to prepare for the frame composition. ");
+ idle_tracker_.idle_lock_.unlock();
+ return;
+ }
+ }
+
+ // Do the actual commit.
+ ScopedDrmAtomicReqPtr pset(drmModeAtomicAlloc());
+
+ if (!pset) {
+ ETRACE("Failed to allocate property set %d", -ENOMEM);
+ idle_tracker_.idle_lock_.unlock();
+ return;
+ }
+
+ uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
+
+ kms_fence_handler_->EnsureReadyForNextFrame();
+
+ if (!display_plane_manager_->CommitFrame(current_composition_planes,
+ pset.get(), flags)) {
+ ETRACE("Failed to Commit layers.");
+ idle_tracker_.idle_lock_.unlock();
+ return;
+ }
+
+ for (NativeSurface* surface : in_flight_surfaces_) {
+ surface->SetInUse(false);
+ }
+
+ std::vector<NativeSurface*>().swap(in_flight_surfaces_);
+
+ for (DisplayPlaneState& plane_state : previous_plane_state_) {
+ if (plane_state.GetCompositionState() ==
+ DisplayPlaneState::State::kRender) {
+ in_flight_surfaces_.emplace_back(plane_state.GetOffScreenTarget());
+ }
+ }
+
+ display_plane_manager_->ReleaseFreeOffScreenTargets();
+ idle_tracker_.idle_lock_.unlock();
+}
+
} // namespace hwcomposer
void VSyncControl(bool enabled);
+ void HandleIdleCase();
+
private:
+ struct IdleFrameTracker {
+ uint32_t idle_frames_ = 0;
+ SpinLock idle_lock_;
+ bool preparing_composition_ = true;
+ };
+
+ struct ScopedIdleStateTracker {
+ ScopedIdleStateTracker(struct IdleFrameTracker& tracker)
+ : tracker_(tracker) {
+ tracker_.idle_lock_.lock();
+ tracker_.idle_frames_ = 0;
+ tracker_.preparing_composition_ = true;
+ tracker_.idle_lock_.unlock();
+ }
+
+ ~ScopedIdleStateTracker() {
+ tracker_.idle_lock_.lock();
+ tracker_.preparing_composition_ = false;
+ tracker_.idle_lock_.unlock();
+ }
+
+ private:
+ struct IdleFrameTracker& tracker_;
+ };
+
bool ApplyPendingModeset(drmModeAtomicReqPtr property_set);
void GetCachedLayers(const std::vector<OverlayLayer>& layers,
DisplayPlaneStateList* composition, bool* render_layers);
std::unique_ptr<KMSFenceEventHandler> kms_fence_handler_;
std::unique_ptr<DisplayPlaneManager> display_plane_manager_;
std::vector<OverlayLayer> previous_layers_;
+ std::vector<HwcRect<int>> previous_layers_rects_;
DisplayPlaneStateList previous_plane_state_;
OverlayBufferManager* buffer_manager_;
std::vector<NativeSurface*> in_flight_surfaces_;
+ IdleFrameTracker idle_tracker_;
SpinLock spin_lock_;
};
#include <memory>
+#include "displayqueue.h"
#include "hwctrace.h"
namespace hwcomposer {
static const int64_t kOneSecondNs = 1 * 1000 * 1000 * 1000;
-VblankEventHandler::VblankEventHandler()
+VblankEventHandler::VblankEventHandler(DisplayQueue* queue)
: HWCThread(-8, "VblankEventHandler"),
display_(0),
enabled_(false),
refresh_(0.0),
fd_(-1),
pipe_(-1),
- last_timestamp_(-1) {
+ last_timestamp_(-1),
+ queue_(queue) {
}
VblankEventHandler::~VblankEventHandler() {
refresh_ = refresh;
fd_ = fd;
pipe_ = pipe;
+
+ if (!InitWorker()) {
+ ETRACE("Failed to initalize thread for VblankEventHandler. %s",
+ PRINTERROR());
+ }
}
bool VblankEventHandler::SetPowerMode(uint32_t power_mode) {
- if (power_mode == kOn && enabled_) {
- VSyncControl(enabled_);
- } else {
+ if (power_mode != kOn) {
Exit();
}
ScopedSpinLock lock(spin_lock_);
enabled_ = enabled;
- if (enabled_ && callback_) {
- if (!InitWorker()) {
- ETRACE("Failed to initalize thread for VblankEventHandler. %s",
- PRINTERROR());
- }
- } else {
- Exit();
- }
-
last_timestamp_ = -1;
return 0;
spin_lock_.unlock();
+ queue_->HandleIdleCase();
+
if (!enabled)
return;
namespace hwcomposer {
+class DisplayQueue;
+
class VblankEventHandler : public HWCThread {
public:
- VblankEventHandler();
+ VblankEventHandler(DisplayQueue* queue);
~VblankEventHandler() override;
void Init(float refresh, int fd, int pipe);
int fd_;
int pipe_;
int64_t last_timestamp_;
+ DisplayQueue* queue_;
};
} // namespace hwcomposer
if (handle->handle_) {
gralloc_->unregisterBuffer(gralloc_, handle->handle_);
+ }
+
+ if (handle->buffer_.get()) {
handle->buffer_.clear();
}
}
#ifdef USE_MINIGBM
bool GrallocBufferHandler::ImportBuffer(HWCNativeHandle handle, HwcBuffer *bo) {
- auto gr_handle = (struct cros_gralloc_handle *)handle->handle_;
- if (!gr_handle) {
+ if (!handle->handle_) {
ETRACE("could not find gralloc drm handle");
return false;
}
+ auto gr_handle = (struct cros_gralloc_handle *)handle->handle_;
memset(bo, 0, sizeof(struct HwcBuffer));
bo->format = gr_handle->format;
bo->width = gr_handle->width;
#define PUBLIC_HWCBUFFER_H_
#include <stdint.h>
+#include <unistd.h>
struct HwcBuffer {
uint32_t width;
uint32_t pitches[4];
uint32_t offsets[4];
uint32_t gem_handles[4];
- uint32_t prime_fd;
+ uint32_t prime_fd = 0;
uint32_t usage;
};
--- /dev/null
+{
+ "power_mode":"dozesuspend",
+ "layers_parameters": [
+ {
+ "format": 25,
+ "frame": {
+ "height": 500,
+ "width": 500,
+ "x": 0,
+ "y": 0
+ },
+ "resource_path": "",
+ "source": {
+ "crop": {
+ "height": 1080,
+ "width": 1920,
+ "x": 0,
+ "y": 0
+ },
+ "height": 1080,
+ "width": 1920
+ },
+ "transform": 0,
+ "type": 0
+ },
+ {
+ "format": 25,
+ "frame": {
+ "height": 700,
+ "width": 900,
+ "x": 300,
+ "y": 100
+ },
+ "resource_path": "",
+ "source": {
+ "crop": {
+ "height": 1080,
+ "width": 1920,
+ "x": 0,
+ "y": 0
+ },
+ "height": 1080,
+ "width": 1920
+ },
+ "transform": 0,
+ "type": 3
+ },
+ {
+ "format": 25,
+ "frame": {
+ "height": 900,
+ "width": 1920,
+ "x": 1200,
+ "y": 400
+ },
+ "resource_path": "",
+ "source": {
+ "crop": {
+ "height": 1080,
+ "width": 1920,
+ "x": 0,
+ "y": 0
+ },
+ "height": 1080,
+ "width": 1920
+ },
+ "transform": 0,
+ "type": 3
+ }
+ ]
+}