Merge "gralloc: Add UBWC support for Camera"
diff --git a/displayengine/include/utils/locker.h b/displayengine/include/utils/locker.h
index 2c1ef9a..549a282 100644
--- a/displayengine/include/utils/locker.h
+++ b/displayengine/include/utils/locker.h
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+* Copyright (c) 2014 - 2015, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
@@ -28,7 +28,11 @@
#include <stdint.h>
#include <pthread.h>
-#define SCOPE_LOCK(locker) Locker::ScopeLock scopeLock(locker)
+#define SCOPE_LOCK(locker) Locker::ScopeLock lock(locker)
+#define SEQUENCE_ENTRY_SCOPE_LOCK(locker) Locker::SequenceEntryScopeLock lock(locker)
+#define SEQUENCE_EXIT_SCOPE_LOCK(locker) Locker::SequenceExitScopeLock lock(locker)
+#define SEQUENCE_WAIT_SCOPE_LOCK(locker) Locker::SequenceWaitScopeLock lock(locker)
+#define SEQUENCE_CANCEL_SCOPE_LOCK(locker) Locker::SequenceCancelScopeLock lock(locker)
namespace sde {
@@ -48,7 +52,78 @@
Locker &locker_;
};
- Locker() {
+ class SequenceEntryScopeLock {
+ public:
+ explicit SequenceEntryScopeLock(Locker& locker) : locker_(locker) {
+ locker_.Lock();
+ locker_.sequence_wait_ = 1;
+ }
+
+ ~SequenceEntryScopeLock() {
+ locker_.Unlock();
+ }
+
+ private:
+ Locker &locker_;
+ };
+
+ class SequenceExitScopeLock {
+ public:
+ explicit SequenceExitScopeLock(Locker& locker) : locker_(locker) {
+ locker_.Lock();
+ locker_.sequence_wait_ = 0;
+ }
+
+ ~SequenceExitScopeLock() {
+ locker_.Broadcast();
+ locker_.Unlock();
+ }
+
+ private:
+ Locker &locker_;
+ };
+
+ class SequenceWaitScopeLock {
+ public:
+ explicit SequenceWaitScopeLock(Locker& locker) : locker_(locker), error_(false) {
+ locker_.Lock();
+
+ if (locker_.sequence_wait_ == 1) {
+ locker_.Wait();
+ error_ = (locker_.sequence_wait_ == -1);
+ }
+ }
+
+ ~SequenceWaitScopeLock() {
+ locker_.Unlock();
+ }
+
+ bool IsError() {
+ return error_;
+ }
+
+ private:
+ Locker &locker_;
+ bool error_;
+ };
+
+ class SequenceCancelScopeLock {
+ public:
+ explicit SequenceCancelScopeLock(Locker& locker) : locker_(locker) {
+ locker_.Lock();
+ locker_.sequence_wait_ = -1;
+ }
+
+ ~SequenceCancelScopeLock() {
+ locker_.Broadcast();
+ locker_.Unlock();
+ }
+
+ private:
+ Locker &locker_;
+ };
+
+ Locker() : sequence_wait_(0) {
pthread_mutex_init(&mutex_, 0);
pthread_cond_init(&condition_, 0);
}
@@ -63,7 +138,7 @@
void Signal() { pthread_cond_signal(&condition_); }
void Broadcast() { pthread_cond_broadcast(&condition_); }
void Wait() { pthread_cond_wait(&condition_, &mutex_); }
- int WaitFinite(long int ms) {
+ int WaitFinite(int ms) {
struct timespec ts;
struct timeval tv;
gettimeofday(&tv, NULL);
@@ -77,6 +152,11 @@
private:
pthread_mutex_t mutex_;
pthread_cond_t condition_;
+ int sequence_wait_; // This flag is set to 1 on sequence entry, 0 on exit, and -1 on cancel.
+ // Some routines will wait for sequence of function calls to finish
+ // so that capturing a transitionary snapshot of context is prevented.
+ // If flag is set to -1, these routines will exit without doing any
+ // further processing.
};
} // namespace sde
diff --git a/displayengine/libs/core/comp_manager.cpp b/displayengine/libs/core/comp_manager.cpp
index c759ebb..7e888ee 100644
--- a/displayengine/libs/core/comp_manager.cpp
+++ b/displayengine/libs/core/comp_manager.cpp
@@ -125,9 +125,11 @@
SET_BIT(registered_displays_, type);
display_comp_ctx->display_type = type;
*display_ctx = display_comp_ctx;
- // New display device has been added, so move the composition mode to safe mode until unless
+ // New non-primary display device has been added, so move the composition mode to safe mode until
// resources for the added display is configured properly.
- safe_mode_ = true;
+ if (type != kPrimary) {
+ safe_mode_ = true;
+ }
DLOGV_IF(kTagCompManager, "registered display bit mask 0x%x, configured display bit mask 0x%x, " \
"display type %d", registered_displays_, configured_displays_,
diff --git a/displayengine/libs/core/hw_framebuffer.cpp b/displayengine/libs/core/hw_framebuffer.cpp
index 306857b..5d1f725 100644
--- a/displayengine/libs/core/hw_framebuffer.cpp
+++ b/displayengine/libs/core/hw_framebuffer.cpp
@@ -172,6 +172,10 @@
goto CleanupOnError;
}
+ // Disable HPD at start if HDMI is external, it will be enabled later when the display powers on
+ // This helps for framework reboot or adb shell stop/start
+ EnableHotPlugDetection(0);
+
return kErrorNone;
CleanupOnError:
diff --git a/displayengine/libs/hwc/hwc_display.cpp b/displayengine/libs/hwc/hwc_display.cpp
index d8c8a64..452bff1 100644
--- a/displayengine/libs/hwc/hwc_display.cpp
+++ b/displayengine/libs/hwc/hwc_display.cpp
@@ -31,6 +31,7 @@
#include <gralloc_priv.h>
#include <utils/constants.h>
#include <qdMetaData.h>
+#include <sync/sync.h>
#include "hwc_display.h"
#include "hwc_debugger.h"
@@ -42,7 +43,8 @@
HWCDisplay::HWCDisplay(CoreInterface *core_intf, hwc_procs_t const **hwc_procs, DisplayType type,
int id)
: core_intf_(core_intf), hwc_procs_(hwc_procs), type_(type), id_(id), display_intf_(NULL),
- flush_(false), output_buffer_(NULL) {
+ flush_(false), output_buffer_(NULL), dump_frame_count_(0), dump_frame_index_(0),
+ dump_input_layers_(false) {
}
int HWCDisplay::Init() {
@@ -198,6 +200,14 @@
return 0;
}
+void HWCDisplay::SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type) {
+ dump_frame_count_ = count;
+ dump_frame_index_ = 0;
+ dump_input_layers_ = ((bit_mask_layer_type & (1 << INPUT_LAYER_DUMP)) != 0);
+
+ DLOGI("num_frame_dump %d, input_layer_dump_enable %d", dump_frame_count_, dump_input_layers_);
+}
+
DisplayError HWCDisplay::VSync(const DisplayEventVSync &vsync) {
if (*hwc_procs_) {
(*hwc_procs_)->vsync(*hwc_procs_, id_, vsync.timestamp);
@@ -406,6 +416,8 @@
size_t num_hw_layers = content_list->numHwLayers;
+ DumpInputBuffers(content_list);
+
if (!flush_) {
for (size_t i = 0; i < num_hw_layers; i++) {
hwc_layer_1_t &hwc_layer = content_list->hwLayers[i];
@@ -431,13 +443,18 @@
}
}
+ return status;
+}
+
+int HWCDisplay::PostCommitLayerStack(hwc_display_contents_1_t *content_list) {
+ size_t num_hw_layers = content_list->numHwLayers;
+ int status = 0;
+
if (flush_) {
DisplayError error = display_intf_->Flush();
if (error != kErrorNone) {
DLOGE("Flush failed. Error = %d", error);
}
-
- flush_ = false;
}
for (size_t i = 0; i < num_hw_layers; i++) {
@@ -445,7 +462,7 @@
Layer &layer = layer_stack_.layers[i];
LayerBuffer *layer_buffer = layer_stack_.layers[i].input_buffer;
- if ((status == 0) && (layer.composition == kCompositionSDE ||
+ if (!flush_ && (layer.composition == kCompositionSDE ||
layer.composition == kCompositionGPUTarget)) {
hwc_layer.releaseFenceFd = layer_buffer->release_fence_fd;
}
@@ -455,9 +472,21 @@
}
}
+ if (!flush_) {
+ content_list->retireFenceFd = layer_stack_.retire_fence_fd;
+
+ if (dump_frame_count_) {
+ dump_frame_count_--;
+ dump_frame_index_++;
+ }
+ }
+
+ flush_ = false;
+
return status;
}
+
bool HWCDisplay::NeedsFrameBufferRefresh(hwc_display_contents_1_t *content_list) {
uint32_t layer_count = layer_stack_.layer_count;
@@ -587,5 +616,119 @@
return format;
}
+void HWCDisplay::DumpInputBuffers(hwc_display_contents_1_t *content_list) {
+ size_t num_hw_layers = content_list->numHwLayers;
+ char dir_path[PATH_MAX];
+
+ if (!dump_frame_count_ || flush_ || !dump_input_layers_) {
+ return;
+ }
+
+ snprintf(dir_path, sizeof(dir_path), "/data/misc/display/frame_dump_%s", GetDisplayString());
+
+ if (mkdir(dir_path, 0777) != 0 && errno != EEXIST) {
+ DLOGW("Failed to create %s directory errno = %d, desc = %s", dir_path, errno, strerror(errno));
+ return;
+ }
+
+ // if directory exists already, need to explicitly change the permission.
+ if (errno == EEXIST && chmod(dir_path, 0777) != 0) {
+ DLOGW("Failed to change permissions on %s directory", dir_path);
+ return;
+ }
+
+ for (uint32_t i = 0; i < num_hw_layers; i++) {
+ hwc_layer_1_t &hwc_layer = content_list->hwLayers[i];
+ const private_handle_t *pvt_handle = static_cast<const private_handle_t *>(hwc_layer.handle);
+
+ if (hwc_layer.acquireFenceFd >= 0) {
+ int error = sync_wait(hwc_layer.acquireFenceFd, 1000);
+ if (error < 0) {
+ DLOGW("sync_wait error errno = %d, desc = %s", errno, strerror(errno));
+ return;
+ }
+ }
+
+ if (pvt_handle && pvt_handle->base) {
+ char dump_file_name[PATH_MAX];
+ size_t result = 0;
+
+ snprintf(dump_file_name, sizeof(dump_file_name), "%s/input_layer%d_%dx%d_%s_frame%d.raw",
+ dir_path, i, pvt_handle->width, pvt_handle->height,
+ GetHALPixelFormatString(pvt_handle->format), dump_frame_index_);
+
+ FILE* fp = fopen(dump_file_name, "w+");
+ if (fp) {
+ result = fwrite(reinterpret_cast<void *>(pvt_handle->base), pvt_handle->size, 1, fp);
+ fclose(fp);
+ }
+
+ DLOGI("Frame Dump %s: is %s", dump_file_name, result ? "Successful" : "Failed");
+ }
+ }
+}
+
+const char *HWCDisplay::GetHALPixelFormatString(int format) {
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ return "RGBA_8888";
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ return "RGBX_8888";
+ case HAL_PIXEL_FORMAT_RGB_888:
+ return "RGB_888";
+ case HAL_PIXEL_FORMAT_RGB_565:
+ return "RGB_565";
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ return "BGRA_8888";
+ case HAL_PIXEL_FORMAT_RGBA_5551:
+ return "RGBA_5551";
+ case HAL_PIXEL_FORMAT_RGBA_4444:
+ return "RGBA_4444";
+ case HAL_PIXEL_FORMAT_YV12:
+ return "YV12";
+ case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+ return "YCbCr_422_SP_NV16";
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+ return "YCrCb_420_SP_NV21";
+ case HAL_PIXEL_FORMAT_YCbCr_422_I:
+ return "YCbCr_422_I_YUY2";
+ case HAL_PIXEL_FORMAT_YCrCb_422_I:
+ return "YCrCb_422_I_YVYU";
+ case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:
+ return "NV12_ENCODEABLE";
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
+ return "YCbCr_420_SP_TILED_TILE_4x2";
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP:
+ return "YCbCr_420_SP";
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO:
+ return "YCrCb_420_SP_ADRENO";
+ case HAL_PIXEL_FORMAT_YCrCb_422_SP:
+ return "YCrCb_422_SP";
+ case HAL_PIXEL_FORMAT_R_8:
+ return "R_8";
+ case HAL_PIXEL_FORMAT_RG_88:
+ return "RG_88";
+ case HAL_PIXEL_FORMAT_INTERLACE:
+ return "INTERLACE";
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
+ return "YCbCr_420_SP_VENUS";
+ default:
+ return "Unknown pixel format";
+ }
+}
+
+const char *HWCDisplay::GetDisplayString() {
+ switch (type_) {
+ case kPrimary:
+ return "primary";
+ case kHDMI:
+ return "hdmi";
+ case kVirtual:
+ return "virtual";
+ default:
+ return "invalid";
+ }
+}
+
} // namespace sde
diff --git a/displayengine/libs/hwc/hwc_display.h b/displayengine/libs/hwc/hwc_display.h
index 9956504..3934078 100644
--- a/displayengine/libs/hwc/hwc_display.h
+++ b/displayengine/libs/hwc/hwc_display.h
@@ -44,6 +44,7 @@
virtual int SetActiveConfig(int index);
virtual void SetIdleTimeoutMs(uint32_t timeout_ms);
virtual int SetActiveConfig(hwc_display_contents_1_t *content_list);
+ virtual void SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type);
protected:
// Maximum number of layers supported by display engine.
@@ -82,6 +83,7 @@
virtual int AllocateLayerStack(hwc_display_contents_1_t *content_list);
virtual int PrepareLayerStack(hwc_display_contents_1_t *content_list);
virtual int CommitLayerStack(hwc_display_contents_1_t *content_list);
+ virtual int PostCommitLayerStack(hwc_display_contents_1_t *content_list);
bool NeedsFrameBufferRefresh(hwc_display_contents_1_t *content_list);
void CacheLayerStackInfo(hwc_display_contents_1_t *content_list);
inline void SetRect(const hwc_rect_t &source, LayerRect *target);
@@ -91,6 +93,14 @@
inline void SetBlending(const int32_t &source, LayerBlending *target);
int SetFormat(const int32_t &source, const int flags, LayerBufferFormat *target);
LayerBufferFormat GetSDEFormat(const int32_t &source, const int flags);
+ void DumpInputBuffers(hwc_display_contents_1_t *content_list);
+ const char *GetHALPixelFormatString(int format);
+ const char *GetDisplayString();
+
+ enum {
+ INPUT_LAYER_DUMP,
+ OUTPUT_LAYER_DUMP,
+ };
CoreInterface *core_intf_;
hwc_procs_t const **hwc_procs_;
@@ -102,6 +112,9 @@
LayerStackCache layer_stack_cache_;
bool flush_;
LayerBuffer *output_buffer_;
+ uint32_t dump_frame_count_;
+ uint32_t dump_frame_index_;
+ bool dump_input_layers_;
};
} // namespace sde
diff --git a/displayengine/libs/hwc/hwc_display_external.cpp b/displayengine/libs/hwc/hwc_display_external.cpp
index da5ea4d..2758e3a 100644
--- a/displayengine/libs/hwc/hwc_display_external.cpp
+++ b/displayengine/libs/hwc/hwc_display_external.cpp
@@ -64,7 +64,10 @@
return status;
}
- content_list->retireFenceFd = layer_stack_.retire_fence_fd;
+ status = HWCDisplay::PostCommitLayerStack(content_list);
+ if (status) {
+ return status;
+ }
return 0;
}
diff --git a/displayengine/libs/hwc/hwc_display_primary.cpp b/displayengine/libs/hwc/hwc_display_primary.cpp
index aeb56f4..6dbb723 100644
--- a/displayengine/libs/hwc/hwc_display_primary.cpp
+++ b/displayengine/libs/hwc/hwc_display_primary.cpp
@@ -64,7 +64,10 @@
return status;
}
- content_list->retireFenceFd = layer_stack_.retire_fence_fd;
+ status = HWCDisplay::PostCommitLayerStack(content_list);
+ if (status) {
+ return status;
+ }
return 0;
}
diff --git a/displayengine/libs/hwc/hwc_display_virtual.cpp b/displayengine/libs/hwc/hwc_display_virtual.cpp
index a6d0f63..9601e63 100644
--- a/displayengine/libs/hwc/hwc_display_virtual.cpp
+++ b/displayengine/libs/hwc/hwc_display_virtual.cpp
@@ -29,6 +29,7 @@
#include <utils/constants.h>
#include <gralloc_priv.h>
+#include <sync/sync.h>
#include "hwc_display_virtual.h"
#include "hwc_debugger.h"
@@ -38,7 +39,8 @@
namespace sde {
HWCDisplayVirtual::HWCDisplayVirtual(CoreInterface *core_intf, hwc_procs_t const **hwc_procs)
- : HWCDisplay(core_intf, hwc_procs, kVirtual, HWC_DISPLAY_VIRTUAL) {
+ : HWCDisplay(core_intf, hwc_procs, kVirtual, HWC_DISPLAY_VIRTUAL),
+ dump_output_layer_(false) {
}
int HWCDisplayVirtual::Init() {
@@ -95,13 +97,18 @@
return status;
}
+ DumpOutputBuffer(content_list);
+
+ status = HWCDisplay::PostCommitLayerStack(content_list);
+ if (status) {
+ return status;
+ }
+
if (content_list->outbufAcquireFenceFd >= 0) {
close(content_list->outbufAcquireFenceFd);
content_list->outbufAcquireFenceFd = -1;
}
- content_list->retireFenceFd = layer_stack_.retire_fence_fd;
-
return 0;
}
@@ -173,5 +180,59 @@
return status;
}
+void HWCDisplayVirtual::DumpOutputBuffer(hwc_display_contents_1_t *content_list) {
+ const private_handle_t *output_handle = (const private_handle_t *)(content_list->outbuf);
+ char dir_path[PATH_MAX];
+
+ if (!dump_frame_count_ || flush_ || !dump_output_layer_) {
+ return;
+ }
+
+ snprintf(dir_path, sizeof(dir_path), "/data/misc/display/frame_dump_%s", GetDisplayString());
+
+ if (mkdir(dir_path, 777) != 0 && errno != EEXIST) {
+ DLOGW("Failed to create %s directory errno = %d, desc = %s", dir_path, errno, strerror(errno));
+ return;
+ }
+
+ // if directory exists already, need to explicitly change the permission.
+ if (errno == EEXIST && chmod(dir_path, 0777) != 0) {
+ DLOGW("Failed to change permissions on %s directory", dir_path);
+ return;
+ }
+
+ if (output_handle && output_handle->base) {
+ char dump_file_name[PATH_MAX];
+ size_t result = 0;
+
+ if (content_list->outbufAcquireFenceFd >= 0) {
+ int error = sync_wait(content_list->outbufAcquireFenceFd, 1000);
+ if (error < 0) {
+ DLOGW("sync_wait error errno = %d, desc = %s", errno, strerror(errno));
+ return;
+ }
+ }
+
+ snprintf(dump_file_name, sizeof(dump_file_name), "%s/output_layer_%dx%d_%s_frame%d.raw",
+ dir_path, output_handle->width, output_handle->height,
+ GetHALPixelFormatString(output_handle->format), dump_frame_index_);
+
+ FILE* fp = fopen(dump_file_name, "w+");
+ if (fp) {
+ result = fwrite(reinterpret_cast<void *>(output_handle->base), output_handle->size, 1, fp);
+ fclose(fp);
+ }
+
+ DLOGI("Frame Dump of %s is %s", dump_file_name, result ? "Successful" : "Failed");
+ }
+}
+
+void HWCDisplayVirtual::SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type) {
+ HWCDisplay::SetFrameDumpConfig(count, bit_mask_layer_type);
+ dump_output_layer_ = ((bit_mask_layer_type & (1 << OUTPUT_LAYER_DUMP)) != 0);
+
+ DLOGI("output_layer_dump_enable %d", dump_output_layer_);
+}
+
} // namespace sde
diff --git a/displayengine/libs/hwc/hwc_display_virtual.h b/displayengine/libs/hwc/hwc_display_virtual.h
index 775852a..7ac7c22 100644
--- a/displayengine/libs/hwc/hwc_display_virtual.h
+++ b/displayengine/libs/hwc/hwc_display_virtual.h
@@ -37,9 +37,13 @@
virtual int Prepare(hwc_display_contents_1_t *content_list);
virtual int Commit(hwc_display_contents_1_t *content_list);
virtual int SetActiveConfig(hwc_display_contents_1_t *content_list);
+ virtual void SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type);
private:
int SetOutputBuffer(hwc_display_contents_1_t *content_list);
+ void DumpOutputBuffer(hwc_display_contents_1_t *content_list);
+
+ bool dump_output_layer_;
};
} // namespace sde
diff --git a/displayengine/libs/hwc/hwc_session.cpp b/displayengine/libs/hwc/hwc_session.cpp
index 0b2f484..3bc4fd1 100644
--- a/displayengine/libs/hwc/hwc_session.cpp
+++ b/displayengine/libs/hwc/hwc_session.cpp
@@ -210,7 +210,7 @@
hwc_display_contents_1_t **displays) {
DTRACE_SCOPED();
- SCOPE_LOCK(locker_);
+ SEQUENCE_ENTRY_SCOPE_LOCK(locker_);
if (!device || !displays) {
return -EINVAL;
@@ -254,7 +254,7 @@
hwc_display_contents_1_t **displays) {
DTRACE_SCOPED();
- SCOPE_LOCK(locker_);
+ SEQUENCE_EXIT_SCOPE_LOCK(locker_);
if (!device || !displays) {
return -EINVAL;
@@ -289,7 +289,7 @@
}
int HWCSession::EventControl(hwc_composer_device_1 *device, int disp, int event, int enable) {
- SCOPE_LOCK(locker_);
+ SEQUENCE_WAIT_SCOPE_LOCK(locker_);
if (!device) {
return -EINVAL;
@@ -317,7 +317,7 @@
}
int HWCSession::SetPowerMode(hwc_composer_device_1 *device, int disp, int mode) {
- SCOPE_LOCK(locker_);
+ SEQUENCE_WAIT_SCOPE_LOCK(locker_);
if (!device) {
return -EINVAL;
@@ -348,6 +348,8 @@
}
int HWCSession::Query(hwc_composer_device_1 *device, int param, int *value) {
+ SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
if (!device || !value) {
return -EINVAL;
}
@@ -365,7 +367,7 @@
}
void HWCSession::Dump(hwc_composer_device_1 *device, char *buffer, int length) {
- SCOPE_LOCK(locker_);
+ SEQUENCE_WAIT_SCOPE_LOCK(locker_);
if (!device || !buffer || !length) {
return;
@@ -376,6 +378,8 @@
int HWCSession::GetDisplayConfigs(hwc_composer_device_1 *device, int disp, uint32_t *configs,
size_t *num_configs) {
+ SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
if (!device || !configs || !num_configs) {
return -EINVAL;
}
@@ -406,6 +410,8 @@
int HWCSession::GetDisplayAttributes(hwc_composer_device_1 *device, int disp, uint32_t config,
const uint32_t *attributes, int32_t *values) {
+ SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
if (!device || !attributes || !values) {
return -EINVAL;
}
@@ -435,6 +441,8 @@
}
int HWCSession::GetActiveConfig(hwc_composer_device_1 *device, int disp) {
+ SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
if (!device) {
return -1;
}
@@ -464,6 +472,8 @@
}
int HWCSession::SetActiveConfig(hwc_composer_device_1 *device, int disp, int index) {
+ SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
if (!device) {
return -EINVAL;
}
@@ -549,6 +559,8 @@
android::status_t HWCSession::notifyCallback(uint32_t command, const android::Parcel *input_parcel,
android::Parcel */*output_parcel*/) {
+ SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
switch (command) {
case qService::IQService::DYNAMIC_DEBUG:
DynamicDebug(input_parcel);
@@ -564,6 +576,11 @@
display_primary_->SetIdleTimeoutMs(timeout);
}
break;
+
+ case qService::IQService::SET_FRAME_DUMP_CONFIG:
+ SetFrameDumpConfig(input_parcel);
+ break;
+
default:
DLOGW("QService command = %d is not supported", command);
return -EINVAL;
@@ -572,6 +589,30 @@
return 0;
}
+void HWCSession::SetFrameDumpConfig(const android::Parcel *input_parcel) {
+ uint32_t frame_dump_count = UINT32(input_parcel->readInt32());
+ uint32_t bit_mask_display_type = UINT32(input_parcel->readInt32());
+ uint32_t bit_mask_layer_type = UINT32(input_parcel->readInt32());
+
+ if (bit_mask_display_type & (1 << qService::IQService::DUMP_PRIMARY_DISPLAY)) {
+ if (display_primary_) {
+ display_primary_->SetFrameDumpConfig(frame_dump_count, bit_mask_layer_type);
+ }
+ }
+
+ if (bit_mask_display_type & (1 << qService::IQService::DUMP_HDMI_DISPLAY)) {
+ if (display_external_) {
+ display_external_->SetFrameDumpConfig(frame_dump_count, bit_mask_layer_type);
+ }
+ }
+
+ if (bit_mask_display_type & (1 << qService::IQService::DUMP_VIRTUAL_DISPLAY)) {
+ if (display_virtual_) {
+ display_virtual_->SetFrameDumpConfig(frame_dump_count, bit_mask_layer_type);
+ }
+ }
+}
+
void HWCSession::DynamicDebug(const android::Parcel *input_parcel) {
int type = input_parcel->readInt32();
bool enable = (input_parcel->readInt32() > 0);
@@ -666,7 +707,7 @@
}
if (connected) {
- SCOPE_LOCK(locker_);
+ SEQUENCE_WAIT_SCOPE_LOCK(locker_);
if (display_external_) {
DLOGE("HDMI already connected");
return -1;
@@ -683,7 +724,7 @@
return -1;
}
} else {
- SCOPE_LOCK(locker_);
+ SEQUENCE_WAIT_SCOPE_LOCK(locker_);
if (!display_external_) {
DLOGE("HDMI not connected");
return -1;
diff --git a/displayengine/libs/hwc/hwc_session.h b/displayengine/libs/hwc/hwc_session.h
index 2a7fe62..4b8c8ce 100644
--- a/displayengine/libs/hwc/hwc_session.h
+++ b/displayengine/libs/hwc/hwc_session.h
@@ -84,6 +84,7 @@
virtual android::status_t notifyCallback(uint32_t command, const android::Parcel *input_parcel,
android::Parcel *output_parcel);
void DynamicDebug(const android::Parcel *input_parcel);
+ void SetFrameDumpConfig(const android::Parcel *input_parcel);
static Locker locker_;
CoreInterface *core_intf_;
diff --git a/libhwcomposer/hwc_copybit.cpp b/libhwcomposer/hwc_copybit.cpp
index ee5b3b7..f1edf5d 100644
--- a/libhwcomposer/hwc_copybit.cpp
+++ b/libhwcomposer/hwc_copybit.cpp
@@ -131,6 +131,21 @@
return renderArea;
}
+bool CopyBit::isLayerChanging(hwc_display_contents_1_t *list, int k) {
+ if((mLayerCache.hnd[k] != list->hwLayers[k].handle) ||
+ (mLayerCache.displayFrame[k].left !=
+ list->hwLayers[k].displayFrame.left) ||
+ (mLayerCache.displayFrame[k].top !=
+ list->hwLayers[k].displayFrame.top) ||
+ (mLayerCache.displayFrame[k].right !=
+ list->hwLayers[k].displayFrame.right) ||
+ (mLayerCache.displayFrame[k].bottom !=
+ list->hwLayers[k].displayFrame.bottom)) {
+ return 1;
+ }
+ return 0;
+}
+
int CopyBit::getLayersChanging(hwc_context_t *ctx,
hwc_display_contents_1_t *list,
int dpy){
@@ -146,7 +161,7 @@
int updatingLayerCount = 0;
for (int k = ctx->listStats[dpy].numAppLayers-1; k >= 0 ; k--){
//swap rect will kick in only for single updating layer
- if(mLayerCache.hnd[k] != list->hwLayers[k].handle){
+ if(isLayerChanging(list, k)) {
updatingLayerCount ++;
if(updatingLayerCount == 1)
changingLayerIndex = k;
@@ -163,19 +178,20 @@
dirtyRect = list->hwLayers[changingLayerIndex].dirtyRect;
#endif
- for (int k = ctx->listStats[dpy].numAppLayers-1; k >= 0 ; k--){
- //disable swap rect for overlapping visible layer(s)
- hwc_rect_t displayFrame = list->hwLayers[k].displayFrame;
- hwc_rect_t result = getIntersection(displayFrame,dirtyRect);
- if((k != changingLayerIndex) && isValidRect(result)){
- return -1;
+ for (int k = ctx->listStats[dpy].numAppLayers-1; k >= 0 ; k--) {
+ //disable swap rect in case of scaling and video .
+ private_handle_t *hnd =(private_handle_t *)list->hwLayers[k].handle;
+ if(needsScaling(&list->hwLayers[k])||( hnd && isYuvBuffer(hnd))) {
+ mFbCache.reset();
+ return -1;
}
}
- mFbCache.insertAndUpdateFbCache(dirtyRect);
if(mFbCache.getUnchangedFbDRCount(dirtyRect) <
- NUM_RENDER_BUFFERS)
+ NUM_RENDER_BUFFERS) {
+ mFbCache.insertAndUpdateFbCache(dirtyRect);
changingLayerIndex = -1;
- }else {
+ }
+ } else {
mFbCache.reset();
changingLayerIndex = -1;
}
@@ -189,23 +205,11 @@
//dirty rect will enable only if
//1.Only single layer is updating.
- //2.No overlapping
- //3.No scaling
- //4.No video layer
+ //2.No scaling
+ //3.No video layer
if(mSwapRectEnable == false)
return -1;
- int changingLayerIndex = getLayersChanging(ctx, list, dpy);
- //swap rect will kick in only for single updating layer
- if(changingLayerIndex == -1){
- return -1;
- }
- if(!needsScaling(&list->hwLayers[changingLayerIndex])){
- private_handle_t *hnd =
- (private_handle_t *)list->hwLayers[changingLayerIndex].handle;
- if( hnd && !isYuvBuffer(hnd))
- return changingLayerIndex;
- }
- return -1;
+ return getLayersChanging(ctx, list, dpy);
}
bool CopyBit::prepareOverlap(hwc_context_t *ctx,
@@ -472,6 +476,7 @@
list->hwLayers[abcRenderBufIdx].acquireFenceFd);
}
for(int i = abcRenderBufIdx + 1; i < layerCount; i++){
+ mDirtyLayerIndex = -1;
int retVal = drawLayerUsingCopybit(ctx,
&(list->hwLayers[i]),renderBuffer, 0);
if(retVal < 0) {
@@ -480,8 +485,8 @@
}
// Get Release Fence FD of copybit for the App layer(s)
copybit->flush_get_fence(copybit, copybitFd);
- close(list->hwLayers[abcRenderBufIdx].acquireFenceFd);
- list->hwLayers[abcRenderBufIdx].acquireFenceFd = -1;
+ close(list->hwLayers[last].acquireFenceFd);
+ list->hwLayers[last].acquireFenceFd = -1;
return true;
}
}
@@ -533,21 +538,16 @@
}
mDirtyLayerIndex = checkDirtyRect(ctx, list, dpy);
+ ALOGD_IF (DEBUG_COPYBIT, "%s:Dirty Layer Index: %d",
+ __FUNCTION__, mDirtyLayerIndex);
hwc_rect_t clearRegion = {0,0,0,0};
- if (CBUtils::getuiClearRegion(list, clearRegion, layerProp)){
- if (mDirtyLayerIndex != -1){
- hwc_layer_1_t *layer = &list->hwLayers[mDirtyLayerIndex];
-#ifdef QCOM_BSP
- hwc_rect_t result = getIntersection(layer->dirtyRect,clearRegion);
- if(isValidRect(result))
- clear(renderBuffer,result);
-#else
- clear(renderBuffer,clearRegion);
-#endif
- } else {
+ mDirtyRect = list->hwLayers[last].displayFrame;
+ if (mDirtyLayerIndex != -1)
+ mDirtyRect = list->hwLayers[mDirtyLayerIndex].displayFrame;
+
+ if (CBUtils::getuiClearRegion(list, clearRegion, layerProp,
+ mDirtyLayerIndex))
clear(renderBuffer, clearRegion);
- }
- }
// numAppLayers-1, as we iterate from 0th layer index with HWC_COPYBIT flag
for (int i = 0; i <= (ctx->listStats[dpy].numAppLayers-1); i++) {
if(!(layerProp[i].mFlags & HWC_COPYBIT)) {
@@ -557,9 +557,6 @@
if(ctx->copybitDrop[i]) {
continue;
}
- //skip non updating layers
- if((mDirtyLayerIndex != -1) && (mDirtyLayerIndex != i) )
- continue;
int ret = -1;
if (list->hwLayers[i].acquireFenceFd != -1
&& ctx->mMDP.version >= qdutils::MDP_V4_0) {
@@ -859,11 +856,18 @@
#ifdef QCOM_BSP
//change src and dst with dirtyRect
if(mDirtyLayerIndex != -1) {
- srcRect.l = layer->dirtyRect.left;
- srcRect.t = layer->dirtyRect.top;
- srcRect.r = layer->dirtyRect.right;
- srcRect.b = layer->dirtyRect.bottom;
- dstRect = srcRect;
+ hwc_rect_t result = getIntersection(displayFrame, mDirtyRect);
+ if(!isValidRect(result))
+ return true;
+ dstRect.l = result.left;
+ dstRect.t = result.top;
+ dstRect.r = result.right;
+ dstRect.b = result.bottom;
+
+ srcRect.l += (result.left - displayFrame.left);
+ srcRect.t += (result.top - displayFrame.top);
+ srcRect.r -= (displayFrame.right - result.right);
+ srcRect.b -= (displayFrame.bottom - result.bottom);
}
#endif
// Copybit dst
@@ -1215,6 +1219,7 @@
layerCount = ctx->listStats[dpy].numAppLayers;
for (int i=0; i<ctx->listStats[dpy].numAppLayers; i++){
hnd[i] = list->hwLayers[i].handle;
+ displayFrame[i] = list->hwLayers[i].displayFrame;
}
}
diff --git a/libhwcomposer/hwc_copybit.h b/libhwcomposer/hwc_copybit.h
index a7ce43e..6ead4a7 100644
--- a/libhwcomposer/hwc_copybit.h
+++ b/libhwcomposer/hwc_copybit.h
@@ -60,6 +60,7 @@
struct LayerCache {
int layerCount;
buffer_handle_t hnd[MAX_NUM_APP_LAYERS];
+ hwc_rect_t displayFrame[MAX_NUM_APP_LAYERS];
/* c'tor */
LayerCache();
/* clear caching info*/
@@ -129,10 +130,12 @@
int mDirtyLayerIndex;
LayerCache mLayerCache;
FbCache mFbCache;
+ hwc_rect_t mDirtyRect;
int getLayersChanging(hwc_context_t *ctx, hwc_display_contents_1_t *list,
int dpy);
int checkDirtyRect(hwc_context_t *ctx, hwc_display_contents_1_t *list,
int dpy);
+ bool isLayerChanging(hwc_display_contents_1_t *list, int k);
};
}; //namespace qhwc
diff --git a/liboverlay/overlay.cpp b/liboverlay/overlay.cpp
index ca599ed..a34e599 100644
--- a/liboverlay/overlay.cpp
+++ b/liboverlay/overlay.cpp
@@ -306,14 +306,20 @@
if(leftType == rightType) {
//Safe. Onus on driver to assign correct pipes within same type
return false;
- } else if(leftType == OV_MDP_PIPE_DMA or rightType == OV_MDP_PIPE_VG) {
- //If we are here, right is definitely a higher prio type.
+ } else {
//This check takes advantage of having only 3 types and avoids 3
//different failure combination checks.
- return true;
- } else {
- //Types are correct priority-wise
- return false;
+ // Swap IF:
+ // ----------------
+ // | Left | Right |
+ // ================
+ // | DMA | ViG |
+ // ----------------
+ // | DMA | RGB |
+ // ----------------
+ // | RGB | ViG |
+ // ----------------
+ return (leftType == OV_MDP_PIPE_DMA or rightType == OV_MDP_PIPE_VG);
}
} else if(pipe1Id < 0) {
//LEFT needs new allocation.
@@ -321,8 +327,7 @@
// If RIGHT has highest priority(lowest id), swap it.
return (pipe2Id == PipeBook::pipeMinID[leftType]);
} else {
- // Swap if needs lowest priority type pipe.
- return (leftType == OV_MDP_PIPE_DMA);
+ return (leftType == OV_MDP_PIPE_DMA or rightType == OV_MDP_PIPE_VG);
}
} else { /* if (pipe2Id < 0) */
// RIGHT needs new allocation.
@@ -330,8 +335,7 @@
// If LEFT has lowest priority(highest id), swap it.
return (pipe1Id == PipeBook::pipeMaxID[leftType]);
} else {
- // Swap if needs highest priority type pipe.
- return (rightType == OV_MDP_PIPE_VG);
+ return (leftType == OV_MDP_PIPE_DMA or rightType == OV_MDP_PIPE_VG);
}
}
}
diff --git a/libqdutils/cb_utils.cpp b/libqdutils/cb_utils.cpp
index ef66ac6..c17842a 100644
--- a/libqdutils/cb_utils.cpp
+++ b/libqdutils/cb_utils.cpp
@@ -41,13 +41,36 @@
namespace qdutils {
int CBUtils::getuiClearRegion(hwc_display_contents_1_t* list,
- hwc_rect_t &clearWormholeRect, LayerProp *layerProp) {
+ hwc_rect_t &clearWormholeRect, LayerProp *layerProp, int dirtyIndex) {
size_t last = list->numHwLayers - 1;
hwc_rect_t fbFrame = list->hwLayers[last].displayFrame;
Rect fbFrameRect(fbFrame.left,fbFrame.top,fbFrame.right,fbFrame.bottom);
Region wormholeRegion(fbFrameRect);
+ if (dirtyIndex != -1) {
+#ifdef QCOM_BSP
+ /*
+ * 1. Map dirty rect of updating layer to its display frame.
+ * 2. Use this display frame as wormholeRegion instead of full Frame
+ * */
+ hwc_rect_t dirtyRect = list->hwLayers[dirtyIndex].dirtyRect;
+ hwc_rect_t displayFrame = list->hwLayers[dirtyIndex].displayFrame;
+ hwc_frect_t sCropF = list->hwLayers[dirtyIndex].sourceCropf;
+ hwc_rect_t srcRect = {int(ceilf(sCropF.left)), int(ceilf(sCropF.top)),
+ int(ceilf(sCropF.right)), int(ceilf(sCropF.bottom))};
+
+ displayFrame.left += dirtyRect.left - srcRect.left;
+ displayFrame.top += dirtyRect.top - srcRect.top;
+ displayFrame.right -= srcRect.right - dirtyRect.right;
+ displayFrame.bottom -= srcRect.bottom - dirtyRect.bottom;
+
+ Rect tmpRect(displayFrame.left,displayFrame.top,displayFrame.right,
+ displayFrame.bottom);
+ Region tmpRegion(tmpRect);
+ wormholeRegion = wormholeRegion.intersect(tmpRegion);
+#endif
+ }
if(cb_swap_rect::getInstance().checkSwapRectFeature_on() == true){
wormholeRegion.set(0,0);
for(size_t i = 0 ; i < last; i++) {
diff --git a/libqdutils/cb_utils.h b/libqdutils/cb_utils.h
index 85dd78f..59f452b 100644
--- a/libqdutils/cb_utils.h
+++ b/libqdutils/cb_utils.h
@@ -38,7 +38,7 @@
public:
static int getuiClearRegion(hwc_display_contents_1_t* list,
hwc_rect_t &clearWormholeRec,
- LayerProp *layerProp);
+ LayerProp *layerProp, int dirtyIndex = -1);
};
}//namespace qdutils
#endif /* end of include guard: CB_UTIL_H*/
diff --git a/libqservice/IQService.h b/libqservice/IQService.h
index e5fc2a8..cd2d116 100644
--- a/libqservice/IQService.h
+++ b/libqservice/IQService.h
@@ -59,6 +59,7 @@
CONFIGURE_DYN_REFRESH_RATE = 18,
SET_PARTIAL_UPDATE = 19, // Preference on partial update feature
TOGGLE_SCREEN_UPDATE = 20, // Provides ability to disable screen updates
+ SET_FRAME_DUMP_CONFIG = 21, // Provides ability to set the frame dump config
COMMAND_LIST_END = 400,
};
@@ -77,6 +78,12 @@
DEBUG_ROTATOR,
};
+ enum {
+ DUMP_PRIMARY_DISPLAY,
+ DUMP_HDMI_DISPLAY,
+ DUMP_VIRTUAL_DISPLAY,
+ };
+
// Register a client that can be notified
virtual void connect(const android::sp<qClient::IQClient>& client) = 0;
// Generic function to dispatch binder commands