Merge "overlay: Reset display and mixer tags for unallocated pipes"
diff --git a/displayengine/include/core/dump_interface.h b/displayengine/include/core/dump_interface.h
index 674e60f..3a7d93d 100644
--- a/displayengine/include/core/dump_interface.h
+++ b/displayengine/include/core/dump_interface.h
@@ -47,17 +47,16 @@
@details Client shall use this method to get current snapshot of display engine context as a
formatted string for logging or dumping purposes.
- @param[inout] buffer String buffer allocated by the client. Filled with dump information upon
- return.
+ @param[inout] buffer String buffer allocated by the client. Filled with null terminated dump
+ information upon return.
@param[in] length Length of the string buffer. Length shall be offset adjusted if any.
- @param[in] filled Number of bytes filled into the string buffer.
@return \link DisplayError \endlink
@warning Client shall ensure that this interface is not used while a device is being either
created or destroyed through display core.
*/
- static DisplayError GetDump(uint8_t *buffer, uint32_t length, uint32_t *filled);
+ static DisplayError GetDump(char *buffer, uint32_t length);
protected:
virtual ~DumpInterface() { }
diff --git a/displayengine/include/core/layer_buffer.h b/displayengine/include/core/layer_buffer.h
index e6dcf1c..421ab87 100644
--- a/displayengine/include/core/layer_buffer.h
+++ b/displayengine/include/core/layer_buffer.h
@@ -106,7 +106,8 @@
struct LayerBufferFlags {
uint64_t secure : 1; //!< This flag shall be set by client to indicate that the buffer need
//!< to be handled securely.
-
+ uint64_t video : 1; //!< This flag shall be set by client to indicate that the buffer is
+ //!< video/ui buffer
LayerBufferFlags() : secure(0) { }
};
diff --git a/displayengine/include/core/layer_stack.h b/displayengine/include/core/layer_stack.h
index fddfa8e..74c1960 100644
--- a/displayengine/include/core/layer_stack.h
+++ b/displayengine/include/core/layer_stack.h
@@ -93,10 +93,13 @@
@sa LayerBuffer
*/
struct LayerFlags {
- uint64_t skip : 1; //!< This flag shall be set by client to indicate that this layer will be
- //!< handled by GPU. Device Device will not consider it for composition.
-
- LayerFlags() : skip(0) { }
+ uint64_t skip : 1; //!< This flag shall be set by client to indicate that this layer will be
+ //!< handled by GPU. Display Device will not consider it for composition.
+ uint64_t updating : 1; //!< This flag shall be set by client to indicate that this is updating/
+ //!< non-updating. so strategy manager will mark them for SDE/GPU
+ //!< composition respectively when the layer stack qualifies for cache
+ //!< based composition.
+ LayerFlags() : skip(0), updating(0) { }
};
/*! @brief This structure defines flags associated with a layer stack. The 1-bit flag can be set to
@@ -108,8 +111,14 @@
uint64_t geometry_changed : 1; //!< This flag shall be set by client to indicate that the layer
//!< set passed to Prepare() has changed by more than just the
//!< buffer handles and acquire fences.
+ uint64_t skip_present : 1; //!< This flag will be set to true, if the current layer stack
+ //!< contains skip layers
+ uint64_t video_present : 1; //!< This flag will be set to true, if current layer stack
+ //!< contains video
+ uint64_t secure_present : 1; //!< This flag will be set to true, if the current layer stack
+ //!< contains secure layers
- LayerStackFlags() : geometry_changed(0) { }
+ LayerStackFlags() : geometry_changed(0), skip_present(0), video_present(0), secure_present(0) { }
};
/*! @brief This structure defines a rectanglular area inside a display layer.
diff --git a/displayengine/include/private/strategy_interface.h b/displayengine/include/private/strategy_interface.h
index 7050929..23dea8e 100644
--- a/displayengine/include/private/strategy_interface.h
+++ b/displayengine/include/private/strategy_interface.h
@@ -67,7 +67,7 @@
/*! @brief Maximum number of layers that can be handled by hardware in a given layer stack.
*/
-const int kNumLayersMax = 16;
+const int kMaxSDELayers = 16;
/*! @brief This structure defines constraints and device properties that shall be considered for
deciding a composition strategy.
@@ -75,11 +75,13 @@
@sa GetNextStrategy
*/
struct StrategyConstraints {
- bool gpu_only; //!< Select GPU only composition for this layer stack.
+ bool safe_mode; //!< In this mode, strategy manager chooses the composition strategy
+ //!< that requires minimum number of pipe for the current frame. i.e.,
+ //!< video only composition, secure only composition or GPU composition
uint32_t max_layers; //!< Maximum number of layers that shall be programmed on hardware for the
//!< given layer stack.
- StrategyConstraints() : gpu_only(false), max_layers(kNumLayersMax) { }
+ StrategyConstraints() : safe_mode(false), max_layers(kMaxSDELayers) { }
};
/*! @brief Flag to denote that GPU composition is performed for the given layer stack.
@@ -94,7 +96,7 @@
struct HWLayersInfo {
LayerStack *stack; //!< Input layer stack. Set by the caller.
- uint32_t index[kNumLayersMax];
+ uint32_t index[kMaxSDELayers];
//!< Indexes of the layers from the layer stack which need to be
//!< programmed on hardware.
uint32_t count; //!< Total number of layers which need to be set on hardware.
diff --git a/displayengine/include/utils/constants.h b/displayengine/include/utils/constants.h
index 4b18ed6..7d7a39c 100644
--- a/displayengine/include/utils/constants.h
+++ b/displayengine/include/utils/constants.h
@@ -43,6 +43,9 @@
#define ROUND_UP(number, step) ((((number) + ((step) - 1)) / (step)) * (step))
+#define SET_BIT(value, bit) ((value) | (1 << (bit)))
+#define CLEAR_BIT(value, bit) ((value) & (~(1 << (bit))))
+
namespace sde {
const int kThreadPriorityUrgent = -9;
diff --git a/displayengine/include/utils/debug.h b/displayengine/include/utils/debug.h
index 10d5ea6..0691dfc 100644
--- a/displayengine/include/utils/debug.h
+++ b/displayengine/include/utils/debug.h
@@ -46,9 +46,9 @@
namespace sde {
enum LogTag {
- kTagNone = 0, //!< Log tag name is not specified.
- kTagCore, //!< Log is tagged for display core.
- kTagStrategy, //!< Log is tagged for composition strategy.
+ kTagNone = 0, // Log tag name is not specified.
+ kTagCore, // Log is tagged for display core.
+ kTagStrategy, // Log is tagged for composition strategy.
};
class Debug {
diff --git a/displayengine/libs/core/comp_manager.cpp b/displayengine/libs/core/comp_manager.cpp
index 560db52..42a28c2 100644
--- a/displayengine/libs/core/comp_manager.cpp
+++ b/displayengine/libs/core/comp_manager.cpp
@@ -34,7 +34,8 @@
namespace sde {
-CompManager::CompManager() : strategy_lib_(NULL), strategy_intf_(NULL) {
+CompManager::CompManager() : strategy_lib_(NULL), strategy_intf_(NULL), registered_displays_(0),
+ configured_displays_(0), safe_mode_(false) {
}
DisplayError CompManager::Init(const HWResourceInfo &hw_res_info) {
@@ -102,9 +103,12 @@
delete comp_mgr_device;
return error;
}
-
+ SET_BIT(registered_displays_, type);
comp_mgr_device->device_type = type;
*device = comp_mgr_device;
+ // New device has been added, so move the composition mode to safe mode until unless resources
+ // for the added display is configured properly.
+ safe_mode_ = true;
return kErrorNone;
}
@@ -115,11 +119,26 @@
CompManagerDevice *comp_mgr_device = reinterpret_cast<CompManagerDevice *>(device);
res_mgr_.UnregisterDevice(comp_mgr_device->res_mgr_device);
+ CLEAR_BIT(registered_displays_, comp_mgr_device->device_type);
+ CLEAR_BIT(configured_displays_, comp_mgr_device->device_type);
delete comp_mgr_device;
return kErrorNone;
}
+void CompManager::PrepareStrategyConstraints(Handle device, HWLayers *hw_layers) {
+ CompManagerDevice *comp_mgr_device = reinterpret_cast<CompManagerDevice *>(device);
+ StrategyConstraints *constraints = &comp_mgr_device->constraints;
+
+ constraints->safe_mode = safe_mode_;
+ // If validation for the best available composition strategy with driver has failed, just
+ // fallback to GPU composition.
+ if (UNLIKELY(hw_layers->info.flags)) {
+ constraints->safe_mode = true;
+ return;
+ }
+}
+
DisplayError CompManager::Prepare(Handle device, HWLayers *hw_layers) {
SCOPE_LOCK(locker_);
@@ -128,19 +147,7 @@
DisplayError error = kErrorNone;
- comp_mgr_device->constraints.gpu_only = false;
-
- // If validation for the best available composition strategy with driver has failed, just
- // fallback to GPU composition.
- if (UNLIKELY(hw_layers->info.flags)) {
- // Did driver reject GPU composition as well? This will never happen.
- if (UNLIKELY(hw_layers->info.flags & kFlagGPU)) {
- DLOGE("Unexpected error. GPU composition validation failed.");
- return kErrorHardware;
- }
-
- comp_mgr_device->constraints.gpu_only = true;
- }
+ PrepareStrategyConstraints(device, hw_layers);
// Select a composition strategy, and try to allocate resources for it.
res_mgr_.Start(res_mgr_device);
@@ -175,6 +182,10 @@
SCOPE_LOCK(locker_);
CompManagerDevice *comp_mgr_device = reinterpret_cast<CompManagerDevice *>(device);
+ SET_BIT(configured_displays_, comp_mgr_device->device_type);
+ if (configured_displays_ == registered_displays_) {
+ safe_mode_ = false;
+ }
res_mgr_.PostCommit(comp_mgr_device->res_mgr_device, hw_layers);
}
@@ -187,10 +198,8 @@
res_mgr_.Purge(comp_mgr_device->res_mgr_device);
}
-uint32_t CompManager::GetDump(uint8_t *buffer, uint32_t length) {
+void CompManager::AppendDump(char *buffer, uint32_t length) {
SCOPE_LOCK(locker_);
-
- return 0;
}
} // namespace sde
diff --git a/displayengine/libs/core/comp_manager.h b/displayengine/libs/core/comp_manager.h
index e6954a8..f9c9202 100644
--- a/displayengine/libs/core/comp_manager.h
+++ b/displayengine/libs/core/comp_manager.h
@@ -48,9 +48,10 @@
void Purge(Handle device);
// DumpImpl method
- virtual uint32_t GetDump(uint8_t *buffer, uint32_t length);
+ virtual void AppendDump(char *buffer, uint32_t length);
private:
+ void PrepareStrategyConstraints(Handle device, HWLayers *hw_layers);
struct CompManagerDevice {
StrategyConstraints constraints;
Handle res_mgr_device;
@@ -62,6 +63,11 @@
StrategyInterface *strategy_intf_;
StrategyDefault strategy_default_;
ResManager res_mgr_;
+ uint64_t registered_displays_; // Stores the bit mask of registered displays
+ uint64_t configured_displays_; // Stores the bit mask of sucessfully configured displays
+ bool safe_mode_; // Flag to notify all displays to be in resource crunch
+ // mode, where strategy manager chooses the best strategy
+ // that uses optimal number of pipes for each display
};
} // namespace sde
diff --git a/displayengine/libs/core/device_base.cpp b/displayengine/libs/core/device_base.cpp
index f991903..6dc3ebd 100644
--- a/displayengine/libs/core/device_base.cpp
+++ b/displayengine/libs/core/device_base.cpp
@@ -294,10 +294,59 @@
return kErrorNone;
}
-uint32_t DeviceBase::GetDump(uint8_t *buffer, uint32_t length) {
+void DeviceBase::AppendDump(char *buffer, uint32_t length) {
SCOPE_LOCK(locker_);
- return 0;
+ AppendString(buffer, length, "\n-----------------------");
+ AppendString(buffer, length, "\ndevice type: %u", device_type_);
+ AppendString(buffer, length, "\nstate: %u, vsync on: %u", state_, INT(vsync_enable_));
+ AppendString(buffer, length, "\nnum configs: %u, active config index: %u",
+ num_modes_, active_mode_index_);
+
+ DeviceConfigVariableInfo &info = device_attributes_[active_mode_index_];
+ AppendString(buffer, length, "\nres:%ux%u, dpi:%.2fx%.2f, fps:%.2f, vsync period: %u",
+ info.x_pixels, info.y_pixels, info.x_dpi, info.y_dpi, info.fps, info.vsync_period_ns);
+
+ uint32_t num_layers = 0;
+ uint32_t num_hw_layers = 0;
+ if (hw_layers_.info.stack) {
+ num_layers = hw_layers_.info.stack->layer_count;
+ num_hw_layers = hw_layers_.info.count;
+ }
+
+ AppendString(buffer, length, "\n\nnum actual layers: %u, num sde layers: %u",
+ num_layers, num_hw_layers);
+
+ for (uint32_t i = 0; i < num_hw_layers; i++) {
+ Layer &layer = hw_layers_.info.stack->layers[i];
+ LayerBuffer *input_buffer = layer.input_buffer;
+ HWLayerConfig &layer_config = hw_layers_.config[i];
+ HWPipeInfo &left_pipe = hw_layers_.config[i].left_pipe;
+ HWPipeInfo &right_pipe = hw_layers_.config[i].right_pipe;
+
+ AppendString(buffer, length, "\n\nsde idx: %u, actual idx: %u", i, hw_layers_.info.index[i]);
+ AppendString(buffer, length, "\nw: %u, h: %u, fmt: %u",
+ input_buffer->width, input_buffer->height, input_buffer->format);
+ AppendRect(buffer, length, "\nsrc_rect:", &layer.src_rect);
+ AppendRect(buffer, length, "\ndst_rect:", &layer.dst_rect);
+
+ AppendString(buffer, length, "\n\tleft split =>");
+ AppendString(buffer, length, "\n\t pipe id: 0x%x", left_pipe.pipe_id);
+ AppendRect(buffer, length, "\n\t src_roi:", &left_pipe.src_roi);
+ AppendRect(buffer, length, "\n\t dst_roi:", &left_pipe.dst_roi);
+
+ if (layer_config.is_right_pipe) {
+ AppendString(buffer, length, "\n\tright split =>");
+ AppendString(buffer, length, "\n\t pipe id: 0x%x", right_pipe.pipe_id);
+ AppendRect(buffer, length, "\n\t src_roi:", &right_pipe.src_roi);
+ AppendRect(buffer, length, "\n\t dst_roi:", &right_pipe.dst_roi);
+ }
+ }
+}
+
+void DeviceBase::AppendRect(char *buffer, uint32_t length, const char *rect_name, LayerRect *rect) {
+ AppendString(buffer, length, "%s %.1f, %.1f, %.1f, %.1f",
+ rect_name, rect->left, rect->top, rect->right, rect->bottom);
}
} // namespace sde
diff --git a/displayengine/libs/core/device_base.h b/displayengine/libs/core/device_base.h
index 458983c..a2ef93b 100644
--- a/displayengine/libs/core/device_base.h
+++ b/displayengine/libs/core/device_base.h
@@ -34,7 +34,7 @@
namespace sde {
-class DeviceBase : public DeviceInterface, DumpImpl, HWEventHandler {
+class DeviceBase : public DeviceInterface, HWEventHandler, DumpImpl {
public:
DeviceBase(DeviceType device_type, DeviceEventHandler *event_handler,
HWBlockType hw_block_type, HWInterface *hw_intf, CompManager *comp_manager);
@@ -52,13 +52,14 @@
virtual DisplayError SetConfig(uint32_t mode);
virtual DisplayError SetVSyncState(bool enable);
- // DumpImpl method
- virtual uint32_t GetDump(uint8_t *buffer, uint32_t length);
-
// Implement the HWEventHandlers
virtual DisplayError VSync(int64_t timestamp);
virtual DisplayError Blank(bool blank);
+ // DumpImpl method
+ virtual void AppendDump(char *buffer, uint32_t length);
+ void AppendRect(char *buffer, uint32_t length, const char *rect_name, LayerRect *rect);
+
protected:
Locker locker_;
DeviceType device_type_;
diff --git a/displayengine/libs/core/dump_impl.cpp b/displayengine/libs/core/dump_impl.cpp
index b15573c..b000ea7 100644
--- a/displayengine/libs/core/dump_impl.cpp
+++ b/displayengine/libs/core/dump_impl.cpp
@@ -27,6 +27,9 @@
#define SDE_MODULE_NAME "DumpInterface"
#include <utils/debug.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
#include <utils/constants.h>
#include "dump_impl.h"
@@ -36,12 +39,18 @@
DumpImpl* DumpImpl::dump_list_[] = { 0 };
uint32_t DumpImpl::dump_count_ = 0;
-DisplayError DumpInterface::GetDump(uint8_t *buffer, uint32_t length, uint32_t *filled) {
- if (!buffer || !length || !filled) {
+DisplayError DumpInterface::GetDump(char *buffer, uint32_t length) {
+ if (!buffer || !length) {
return kErrorParameters;
}
- DumpImpl::GetDump(buffer, length, filled);
+ buffer[0] = '\0';
+ DumpImpl::AppendString(buffer, length, "\n-------- Snapdragon Display Engine --------");
+ for (uint32_t i = 0; i < DumpImpl::dump_count_; i++) {
+ DumpImpl::dump_list_[i]->AppendDump(buffer, length);
+ }
+ DumpImpl::AppendString(buffer, length, "\n-------------------------------------------\n");
+
return kErrorNone;
}
@@ -53,12 +62,16 @@
Unregister(this);
}
-// Caller has to ensure that it does not create or destroy devices while using dump interface.
-void DumpImpl::GetDump(uint8_t *buffer, uint32_t length, uint32_t *filled) {
- *filled = 0;
- for (uint32_t i = 0; (i < DumpImpl::dump_count_) && (*filled < length); i++) {
- *filled += DumpImpl::dump_list_[i]->GetDump(buffer + *filled, length - *filled);
+void DumpImpl::AppendString(char *buffer, uint32_t length, const char *format, ...) {
+ uint32_t filled = UINT32(strlen(buffer));
+ if (filled >= length) {
+ return;
}
+ buffer += filled;
+
+ va_list list;
+ va_start(list, format);
+ vsnprintf(buffer, length - filled, format, list);
}
// Every object is created or destroyed through display core only, which itself protects the
diff --git a/displayengine/libs/core/dump_impl.h b/displayengine/libs/core/dump_impl.h
index 7d652ec..83197e5 100644
--- a/displayengine/libs/core/dump_impl.h
+++ b/displayengine/libs/core/dump_impl.h
@@ -33,8 +33,8 @@
public:
// To be implemented in the modules which will add dump information to final dump buffer.
// buffer address & length will be already adjusted before calling into these modules.
- virtual uint32_t GetDump(uint8_t *buffer, uint32_t length) = 0;
- static void GetDump(uint8_t *buffer, uint32_t length, uint32_t *filled);
+ virtual void AppendDump(char *buffer, uint32_t length) = 0;
+ static void AppendString(char *buffer, uint32_t length, const char *format, ...);
protected:
DumpImpl();
diff --git a/displayengine/libs/core/hw_framebuffer.cpp b/displayengine/libs/core/hw_framebuffer.cpp
index 3057fa2..8dc3330 100644
--- a/displayengine/libs/core/hw_framebuffer.cpp
+++ b/displayengine/libs/core/hw_framebuffer.cpp
@@ -25,12 +25,12 @@
// SDE_LOG_TAG definition must precede debug.h include.
#define SDE_LOG_TAG kTagCore
#define SDE_MODULE_NAME "HWFrameBuffer"
+#define __STDC_FORMAT_MACROS
#include <utils/debug.h>
-#include <stdio.h>
-#include <stdlib.h>
#include <math.h>
#include <fcntl.h>
+#include <inttypes.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
@@ -50,18 +50,26 @@
extern int virtual_close(int fd);
extern int virtual_poll(struct pollfd *fds, nfds_t num, int timeout);
extern ssize_t virtual_pread(int fd, void *data, size_t count, off_t offset);
+extern FILE* virtual_fopen(const char *fname, const char *mode);
+extern int virtual_fclose(FILE* fileptr);
+extern ssize_t virtual_getline(char **lineptr, size_t *linelen, FILE *stream);
+
+
#endif
namespace sde {
HWFrameBuffer::HWFrameBuffer() : event_thread_name_("SDE_EventThread"), fake_vsync_(false),
- exit_threads_(false) {
+ exit_threads_(false), fb_path_("/sys/class/graphics/fb") {
// Pointer to actual driver interfaces.
ioctl_ = ::ioctl;
open_ = ::open;
close_ = ::close;
poll_ = ::poll;
pread_ = ::pread;
+ fopen_ = ::fopen;
+ fclose_ = ::fclose;
+ getline_ = ::getline;
#ifdef DISPLAY_CORE_VIRTUAL_DRIVER
// If debug property to use virtual driver is set, point to virtual driver interfaces.
@@ -71,20 +79,39 @@
close_ = virtual_close;
poll_ = virtual_poll;
pread_ = virtual_pread;
+ fopen_ = virtual_fopen;
+ fclose_ = virtual_fclose;
+ getline_ = virtual_getline;
}
#endif
+ for (int i = 0; i < kHWBlockMax; i ++) {
+ fb_node_index_[i] = -1;
+ }
}
DisplayError HWFrameBuffer::Init() {
DisplayError error = kErrorNone;
-
- // TODO(user): Need to read the fbnode info, hw capabilities here
-
- // Open nodes for polling
char node_path[kMaxStringLength] = {0};
char data[kMaxStringLength] = {0};
const char* event_name[kNumDisplayEvents] = {"vsync_event", "show_blank_event"};
+ // Read the fb node index
+ PopulateFBNodeIndex();
+ if (fb_node_index_[kHWPrimary] == -1) {
+ DLOGE("HW Display Device Primary should be present");
+ error = kErrorHardware;
+ goto CleanupOnError;
+ }
+
+ // Populate Primary Panel Info(Used for Partial Update)
+ PopulatePanelInfo(fb_node_index_[kHWPrimary]);
+ // Populate HW Capabilities
+ error = PopulateHWCapabilities();
+ if (error != kErrorNone) {
+ goto CleanupOnError;
+ }
+
+ // Open nodes for polling
for (int display = 0; display < kNumPhysicalDisplays; display++) {
for (int event = 0; event < kNumDisplayEvents; event++) {
poll_fds_[display][event].fd = -1;
@@ -96,12 +123,12 @@
for (int event = 0; event < kNumDisplayEvents; event++) {
pollfd &poll_fd = poll_fds_[display][event];
- snprintf(node_path, sizeof(node_path), "/sys/class/graphics/fb%d/%s",
- (display == 0) ? 0 : 1/*TODO(user): HDMI fb node index*/, event_name[event]);
+ snprintf(node_path, sizeof(node_path), "%s%d/%s", fb_path_, fb_node_index_[display],
+ event_name[event]);
poll_fd.fd = open_(node_path, O_RDONLY);
if (poll_fd.fd < 0) {
- DLOGE("open failed for display=%d event=%zu, error=%s", display, event, strerror(errno));
+ DLOGE("open failed for display=%d event=%d, error=%s", display, event, strerror(errno));
error = kErrorHardware;
goto CleanupOnError;
}
@@ -150,19 +177,7 @@
}
DisplayError HWFrameBuffer::GetHWCapabilities(HWResourceInfo *hw_res_info) {
- // Hardcode for 8084 for now.
- hw_res_info->mdp_version = 500;
- hw_res_info->hw_revision = 0x10030001;
- hw_res_info->num_dma_pipe = 2;
- hw_res_info->num_vig_pipe = 4;
- hw_res_info->num_rgb_pipe = 4;
- hw_res_info->num_rotator = 2;
- hw_res_info->num_control = 5;
- hw_res_info->num_mixer_to_disp = 4;
- hw_res_info->max_scale_up = 20;
- hw_res_info->max_scale_down = 4;
- hw_res_info->has_non_scalar_rgb = true;
- hw_res_info->is_src_split = true;
+ *hw_res_info = hw_resource_;
return kErrorNone;
}
@@ -195,7 +210,10 @@
}
*device = hw_context;
- event_handler_[device_id] = eventhandler;
+
+ // Store EventHandlers for two Physical displays
+ if (device_id < kNumPhysicalDisplays)
+ event_handler_[device_id] = eventhandler;
return error;
}
@@ -498,7 +516,7 @@
ssize_t length = pread_(poll_fd.fd, data, kMaxStringLength, 0);
if (length < 0) {
// If the read was interrupted - it is not a fatal error, just continue.
- DLOGE("Failed to read event:%zu for display=%d : %s", event, display, strerror(errno));
+ DLOGE("Failed to read event:%d for display=%d: %s", event, display, strerror(errno));
continue;
}
@@ -528,4 +546,231 @@
return;
}
+void HWFrameBuffer::PopulateFBNodeIndex() {
+ char stringbuffer[kMaxStringLength];
+ DisplayError error = kErrorNone;
+ HWBlockType hwblock = kHWPrimary;
+ char *line = stringbuffer;
+ size_t len = kMaxStringLength;
+ ssize_t read;
+
+
+ for (int i = 0; i < kHWBlockMax; i++) {
+ snprintf(stringbuffer, sizeof(stringbuffer), "%s%d/msm_fb_type", fb_path_, i);
+ FILE* fileptr = fopen_(stringbuffer, "r");
+ if (fileptr == NULL) {
+ DLOGE("File not found %s", stringbuffer);
+ continue;
+ }
+ read = getline_(&line, &len, fileptr);
+ if (read ==-1) {
+ fclose_(fileptr);
+ continue;
+ }
+ // TODO(user): For now, assume primary to be cmd/video/lvds/edp mode panel only
+ // Need more concrete info from driver
+ if ((strncmp(line, "mipi dsi cmd panel", strlen("mipi dsi cmd panel")) == 0)) {
+ pri_panel_info_.type = kCommandModePanel;
+ hwblock = kHWPrimary;
+ } else if ((strncmp(line, "mipi dsi video panel", strlen("mipi dsi video panel")) == 0)) {
+ pri_panel_info_.type = kVideoModePanel;
+ hwblock = kHWPrimary;
+ } else if ((strncmp(line, "lvds panel", strlen("lvds panel")) == 0)) {
+ pri_panel_info_.type = kLVDSPanel;
+ hwblock = kHWPrimary;
+ } else if ((strncmp(line, "edp panel", strlen("edp panel")) == 0)) {
+ pri_panel_info_.type = kEDPPanel;
+ hwblock = kHWPrimary;
+ } else if ((strncmp(line, "dtv panel", strlen("dtv panel")) == 0)) {
+ hwblock = kHWHDMI;
+ } else if ((strncmp(line, "writeback panel", strlen("writeback panel")) == 0)) {
+ hwblock = kHWWriteback0;
+ } else {
+ DLOGE("Unknown panel type = %s index = %d", line, i);
+ }
+ fb_node_index_[hwblock] = i;
+ fclose_(fileptr);
+ }
+}
+
+void HWFrameBuffer::PopulatePanelInfo(int fb_index) {
+ char stringbuffer[kMaxStringLength];
+ FILE* fileptr = NULL;
+ snprintf(stringbuffer, sizeof(stringbuffer), "%s%d/msm_fb_panel_info", fb_path_, fb_index);
+ fileptr = fopen_(stringbuffer, "r");
+ if (fileptr == NULL) {
+ DLOGE("Failed to open msm_fb_panel_info node");
+ return;
+ }
+
+ size_t len = kMaxStringLength;
+ ssize_t read;
+ char *line = stringbuffer;
+ while ((read = getline_(&line, &len, fileptr)) != -1) {
+ int token_count = 0;
+ const int max_count = 10;
+ char *tokens[max_count] = { NULL };
+ if (!ParseLine(line, tokens, max_count, &token_count)) {
+ if (!strncmp(tokens[0], "pu_en", strlen("pu_en"))) {
+ pri_panel_info_.partial_update = atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "xstart", strlen("xstart"))) {
+ pri_panel_info_.left_align = atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "walign", strlen("walign"))) {
+ pri_panel_info_.width_align = atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "ystart", strlen("ystart"))) {
+ pri_panel_info_.top_align = atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "halign", strlen("halign"))) {
+ pri_panel_info_.height_align = atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "min_w", strlen("min_w"))) {
+ pri_panel_info_.min_roi_width = atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "min_h", strlen("min_h"))) {
+ pri_panel_info_.min_roi_height = atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "roi_merge", strlen("roi_merge"))) {
+ pri_panel_info_.needs_roi_merge = atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "dynamic_fps_en", strlen("dyn_fps_en"))) {
+ pri_panel_info_.dynamic_fps = atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "min_fps", strlen("min_fps"))) {
+ pri_panel_info_.min_fps = atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "max_fps", strlen("max_fps"))) {
+ pri_panel_info_.max_fps= atoi(tokens[1]);
+ }
+ }
+ }
+ fclose_(fileptr);
+}
+
+// Get SDE HWCapabalities from the sysfs
+DisplayError HWFrameBuffer::PopulateHWCapabilities() {
+ DisplayError error = kErrorNone;
+ FILE *fileptr = NULL;
+ char stringbuffer[kMaxStringLength];
+ int token_count = 0;
+ const int max_count = 10;
+ char *tokens[max_count] = { NULL };
+ snprintf(stringbuffer , sizeof(stringbuffer), "%s%d/mdp/caps", fb_path_,
+ fb_node_index_[kHWPrimary]);
+ fileptr = fopen_(stringbuffer, "rb");
+
+ if (fileptr == NULL) {
+ DLOGE("File '%s' not found", stringbuffer);
+ return kErrorHardware;
+ }
+
+ size_t len = kMaxStringLength;
+ ssize_t read;
+ char *line = stringbuffer;
+ hw_resource_.hw_version = kHWMdssVersion5;
+ while ((read = getline_(&line, &len, fileptr)) != -1) {
+ // parse the line and update information accordingly
+ if (!ParseLine(line, tokens, max_count, &token_count)) {
+ if (!strncmp(tokens[0], "hw_rev", strlen("hw_rev"))) {
+ hw_resource_.hw_revision = atoi(tokens[1]); // HW Rev, v1/v2
+ } else if (!strncmp(tokens[0], "rgb_pipes", strlen("rgb_pipes"))) {
+ hw_resource_.num_rgb_pipe = (uint8_t)atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "vig_pipes", strlen("vig_pipes"))) {
+ hw_resource_.num_vig_pipe = (uint8_t)atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "dma_pipes", strlen("dma_pipes"))) {
+ hw_resource_.num_dma_pipe = (uint8_t)atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "cursor_pipes", strlen("cursor_pipes"))) {
+ hw_resource_.num_cursor_pipe = (uint8_t)atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "blending_stages", strlen("blending_stages"))) {
+ hw_resource_.num_blending_stages = (uint8_t)atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "max_downscale_ratio", strlen("max_downscale_ratio"))) {
+ hw_resource_.max_scale_down = atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "max_upscale_ratio", strlen("max_upscale_ratio"))) {
+ hw_resource_.max_scale_up = atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "max_bandwidth_low", strlen("max_bandwidth_low"))) {
+ hw_resource_.max_bandwidth_low = atol(tokens[1]);
+ } else if (!strncmp(tokens[0], "max_bandwidth_high", strlen("max_bandwidth_high"))) {
+ hw_resource_.max_bandwidth_high = atol(tokens[1]);
+ } else if (!strncmp(tokens[0], "max_mixer_width", strlen("max_mixer_width"))) {
+ hw_resource_.max_mixer_width = atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "features", strlen("features"))) {
+ for (int i = 0; i < token_count; i++) {
+ if (!strncmp(tokens[i], "bwc", strlen("bwc"))) {
+ hw_resource_.has_bwc = true;
+ } else if (!strncmp(tokens[i], "decimation", strlen("decimation"))) {
+ hw_resource_.has_decimation = true;
+ } else if (!strncmp(tokens[i], "tile_format", strlen("tile_format"))) {
+ hw_resource_.has_macrotile = true;
+ } else if (!strncmp(tokens[i], "src_split", strlen("src_split"))) {
+ hw_resource_.is_src_split = true;
+ } else if (!strncmp(tokens[i], "non_scalar_rgb", strlen("non_scalar_rgb"))) {
+ hw_resource_.has_non_scalar_rgb = true;
+ } else if (!strncmp(tokens[i], "rotator_downscale", strlen("rotator_downscale"))) {
+ hw_resource_.has_rotator_downscale = true;
+ }
+ }
+ }
+ }
+ }
+ fclose_(fileptr);
+
+ // Split info - for MDSS Version 5 - No need to check version here
+ snprintf(stringbuffer , sizeof(stringbuffer), "%s%d/msm_fb_split", fb_path_,
+ fb_node_index_[kHWPrimary]);
+ fileptr = fopen_(stringbuffer, "r");
+ if (fileptr) {
+ // Format "left right" space as delimiter
+ read = getline_(&line, &len, fileptr);
+ if (read != -1) {
+ if (!ParseLine(line, tokens, max_count, &token_count)) {
+ hw_resource_.split_info.left_split = atoi(tokens[0]);
+ hw_resource_.split_info.right_split = atoi(tokens[1]);
+ }
+ }
+ fclose_(fileptr);
+ }
+
+ // SourceSplit enabled - Get More information
+ if (hw_resource_.is_src_split) {
+ snprintf(stringbuffer , sizeof(stringbuffer), "%s%d/msm_fb_src_split_info", fb_path_,
+ fb_node_index_[kHWPrimary]);
+ fileptr = fopen_(stringbuffer, "r");
+ if (fileptr) {
+ read = getline_(&line, &len, fileptr);
+ if (read != -1) {
+ if (!strncmp(line, "src_split_always", strlen("src_split_always"))) {
+ hw_resource_.always_src_split = true;
+ }
+ }
+ fclose_(fileptr);
+ }
+ }
+
+ DLOGI("SDE Version: %d SDE Revision: %x RGB : %d, VIG: %d DMA: %d Cursor: %d",
+ hw_resource_.hw_version, hw_resource_.hw_revision, hw_resource_.num_rgb_pipe,
+ hw_resource_.num_vig_pipe, hw_resource_.num_dma_pipe, hw_resource_.num_cursor_pipe);
+ DLOGI("Upscale Ratio: %d Downscale Ratio: %d Blending Stages: %d", hw_resource_.max_scale_up,
+ hw_resource_.max_scale_down, hw_resource_.num_blending_stages);
+ DLOGI("BWC: %d Decimation: %d Tile Format: %d: Rotator Downscale: %d", hw_resource_.has_bwc,
+ hw_resource_.has_decimation, hw_resource_.has_macrotile,
+ hw_resource_.has_rotator_downscale);
+ DLOGI("Left Split: %d Right Split: %d", hw_resource_.split_info.left_split,
+ hw_resource_.split_info.right_split);
+ DLOGI("SourceSplit: %d Always: %d", hw_resource_.is_src_split, hw_resource_.always_src_split);
+ DLOGI("MaxLowBw: %"PRIu64" MaxHighBw: %"PRIu64"", hw_resource_.max_bandwidth_low,
+ hw_resource_.max_bandwidth_high);
+
+ return error;
+}
+
+int HWFrameBuffer::ParseLine(char *input, char *tokens[], int max_token, int *count) {
+ char *tmp_token = NULL;
+ char *temp_ptr;
+ int index = 0;
+ const char *delim = ", =\n";
+ if (!input) {
+ return -1;
+ }
+ tmp_token = strtok_r(input, delim, &temp_ptr);
+ while (tmp_token && index < max_token) {
+ tokens[index++] = tmp_token;
+ tmp_token = strtok_r(NULL, delim, &temp_ptr);
+ }
+ *count = index;
+
+ return 0;
+}
+
} // namespace sde
diff --git a/displayengine/libs/core/hw_framebuffer.h b/displayengine/libs/core/hw_framebuffer.h
index b64e869..6b844af 100644
--- a/displayengine/libs/core/hw_framebuffer.h
+++ b/displayengine/libs/core/hw_framebuffer.h
@@ -25,9 +25,12 @@
#ifndef __HW_FRAMEBUFFER_H__
#define __HW_FRAMEBUFFER_H__
+#include <stdio.h>
+#include <stdlib.h>
#include <linux/msm_mdp.h>
#include <poll.h>
#include <pthread.h>
+
#include "hw_interface.h"
namespace sde {
@@ -57,14 +60,45 @@
int device_fd;
};
+ enum PanelType {
+ kNoPanel,
+ kCommandModePanel,
+ kVideoModePanel,
+ kDTvPanel,
+ kWriteBackPanel,
+ kLVDSPanel,
+ kEDPPanel,
+ };
+
enum {
kHWEventVSync,
kHWEventBlank,
};
+ // Maps to the msm_fb_panel_info
+ struct PanelInfo {
+ PanelType type; // Smart or Dumb
+ bool partial_update; // Partial update feature
+ int left_align; // ROI left alignment restriction
+ int width_align; // ROI width alignment restriction
+ int top_align;; // ROI top alignment restriction
+ int height_align; // ROI height alignment restriction
+ int min_roi_width; // Min width needed for ROI
+ int min_roi_height; // Min height needed for ROI
+ bool needs_roi_merge; // Merge ROI's of both the DSI's
+ bool dynamic_fps; // Panel Supports dynamic fps
+ uint32_t min_fps; // Min fps supported by panel
+ uint32_t max_fps; // Max fps supported by panel
+
+ PanelInfo() : type(kNoPanel), partial_update(false), left_align(false), width_align(false),
+ top_align(false), height_align(false), min_roi_width(0), min_roi_height(0),
+ needs_roi_merge(false), dynamic_fps(false), min_fps(0), max_fps(0) { }
+ };
+
static const int kMaxStringLength = 1024;
static const int kNumPhysicalDisplays = 2;
static const int kNumDisplayEvents = 2;
+ static const int kHWMdssVersion5 = 500; // MDSS_V5
inline void SetFormat(uint32_t *target, const LayerBufferFormat &source);
inline void SetBlending(uint32_t *target, const LayerBlending &source);
@@ -77,12 +111,23 @@
void HandleVSync(int display_id, char *data);
void HandleBlank(int display_id, char *data);
+ // Populates HW FrameBuffer Node Index
+ void PopulateFBNodeIndex();
+ // Populates the Panel Info based on node index
+ void PopulatePanelInfo(int fb_index);
+ // Populates HW Capabilities
+ DisplayError PopulateHWCapabilities();
+ int ParseLine(char *input, char *token[], int max_token, int *count);
+
// Pointers to system calls which are either mapped to actual system call or virtual driver.
int (*ioctl_)(int, int, ...);
int (*open_)(const char *, int, ...);
int (*close_)(int);
int (*poll_)(struct pollfd *, nfds_t, int);
ssize_t (*pread_)(int, void *, size_t, off_t);
+ FILE* (*fopen_)( const char *fname, const char *mode );;
+ int (*fclose_)(FILE* fileptr);
+ ssize_t (*getline_)(char **lineptr, size_t *linelen, FILE *stream);
// Store the Device EventHandlers - used for callback
HWEventHandler *event_handler_[kNumPhysicalDisplays];
@@ -91,6 +136,10 @@
const char *event_thread_name_;
bool fake_vsync_;
bool exit_threads_;
+ HWResourceInfo hw_resource_;
+ int fb_node_index_[kHWBlockMax];
+ const char* fb_path_;
+ PanelInfo pri_panel_info_;
};
} // namespace sde
diff --git a/displayengine/libs/core/hw_interface.h b/displayengine/libs/core/hw_interface.h
index ddf631e..bb2a8a9 100644
--- a/displayengine/libs/core/hw_interface.h
+++ b/displayengine/libs/core/hw_interface.h
@@ -41,11 +41,13 @@
};
struct HWResourceInfo {
- uint32_t mdp_version;
+ uint32_t hw_version;
uint32_t hw_revision;
uint32_t num_dma_pipe;
uint32_t num_vig_pipe;
uint32_t num_rgb_pipe;
+ uint32_t num_cursor_pipe;
+ uint32_t num_blending_stages;
uint32_t num_rotator;
uint32_t num_control;
uint32_t num_mixer_to_disp;
@@ -54,20 +56,29 @@
uint32_t num_smp_per_pipe;
uint32_t max_scale_up;
uint32_t max_scale_down;
- uint32_t max_bandwidth_low;
- uint32_t max_bandwidth_high;
+ uint64_t max_bandwidth_low;
+ uint64_t max_bandwidth_high;
+ uint32_t max_mixer_width;
+ struct SplitInfo {
+ uint32_t left_split;
+ uint32_t right_split;
+ SplitInfo() : left_split(0), right_split(0) { }
+ } split_info;
bool has_bwc;
bool has_decimation;
+ bool has_macrotile;
+ bool has_rotator_downscale;
bool has_non_scalar_rgb;
bool is_src_split;
- bool has_microtile;
+ bool always_src_split;
HWResourceInfo()
- : mdp_version(0), hw_revision(0), num_dma_pipe(0), num_vig_pipe(0),
- num_rgb_pipe(0), num_rotator(0), num_control(0), num_mixer_to_disp(0), smp_total(0),
- smp_size(0), num_smp_per_pipe(0), max_scale_up(0), max_scale_down(0), max_bandwidth_low(0),
- max_bandwidth_high(0), has_bwc(false), has_decimation(false), has_non_scalar_rgb(false),
- is_src_split(false), has_microtile(false) { }
+ : hw_version(0), hw_revision(0), num_dma_pipe(0), num_vig_pipe(0), num_rgb_pipe(0),
+ num_cursor_pipe(0), num_blending_stages(0), num_rotator(0), num_control(0),
+ num_mixer_to_disp(0), smp_total(0), smp_size(0), num_smp_per_pipe(0), max_scale_up(0),
+ max_scale_down(0), max_bandwidth_low(0), max_bandwidth_high(0), max_mixer_width(2048),
+ has_bwc(false), has_decimation(false), has_macrotile(false), has_rotator_downscale(false),
+ has_non_scalar_rgb(false), is_src_split(false), always_src_split(false) { }
};
struct HWPipeInfo {
@@ -89,7 +100,7 @@
struct HWLayers {
HWLayersInfo info;
- HWLayerConfig config[kNumLayersMax];
+ HWLayerConfig config[kMaxSDELayers];
};
struct HWDeviceAttributes : DeviceConfigVariableInfo {
diff --git a/displayengine/libs/core/res_manager.cpp b/displayengine/libs/core/res_manager.cpp
index 16060d8..de73437 100644
--- a/displayengine/libs/core/res_manager.cpp
+++ b/displayengine/libs/core/res_manager.cpp
@@ -441,10 +441,8 @@
((dst_roi.bottom - dst_roi.top) != (src_roi.bottom - src_roi.top));
}
-uint32_t ResManager::GetDump(uint8_t *buffer, uint32_t length) {
+void ResManager::AppendDump(char *buffer, uint32_t length) {
SCOPE_LOCK(locker_);
-
- return 0;
}
} // namespace sde
diff --git a/displayengine/libs/core/res_manager.h b/displayengine/libs/core/res_manager.h
index ccd6433..b2698c9 100644
--- a/displayengine/libs/core/res_manager.h
+++ b/displayengine/libs/core/res_manager.h
@@ -48,7 +48,7 @@
void Purge(Handle device);
// DumpImpl method
- virtual uint32_t GetDump(uint8_t *buffer, uint32_t length);
+ virtual void AppendDump(char *buffer, uint32_t length);
private:
enum PipeId {
diff --git a/displayengine/libs/hwc/hwc_session.cpp b/displayengine/libs/hwc/hwc_session.cpp
index 51b9a80..9dfa920 100644
--- a/displayengine/libs/hwc/hwc_session.cpp
+++ b/displayengine/libs/hwc/hwc_session.cpp
@@ -287,8 +287,7 @@
return;
}
- uint32_t filled = 0;
- DumpInterface::GetDump(reinterpret_cast<uint8_t *>(buffer), length, &filled);
+ DumpInterface::GetDump(buffer, length);
}
int HWCSession::GetDisplayConfigs(hwc_composer_device_1 *device, int disp, uint32_t *configs,
diff --git a/displayengine/libs/hwc/hwc_sink.cpp b/displayengine/libs/hwc/hwc_sink.cpp
index e5b07f5..0fb4b8c 100644
--- a/displayengine/libs/hwc/hwc_sink.cpp
+++ b/displayengine/libs/hwc/hwc_sink.cpp
@@ -226,6 +226,9 @@
return 0;
}
+ // Reset Layer stack flags
+ layer_stack_.flags = LayerStackFlags();
+
// Configure each layer
for (size_t i = 0; i < num_hw_layers; i++) {
hwc_layer_1_t &hwc_layer = content_list->hwLayers[i];
@@ -244,6 +247,12 @@
layer_buffer->planes[0].fd = pvt_handle->fd;
layer_buffer->planes[0].offset = pvt_handle->offset;
layer_buffer->planes[0].stride = pvt_handle->width;
+ if (pvt_handle->bufferType == BUFFER_TYPE_VIDEO) {
+ layer_stack_.flags.video_present = true;
+ }
+ if (pvt_handle->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) {
+ layer_stack_.flags.secure_present = true;
+ }
}
SetRect(&layer.dst_rect, hwc_layer.displayFrame);
@@ -252,7 +261,6 @@
SetRect(&layer.visible_regions.rect[j], hwc_layer.visibleRegionScreen.rects[j]);
}
SetRect(&layer.dirty_regions.rect[0], hwc_layer.dirtyRect);
-
SetComposition(&layer.composition, hwc_layer.compositionType);
SetBlending(&layer.blending, hwc_layer.blending);
@@ -264,6 +272,11 @@
layer.plane_alpha = hwc_layer.planeAlpha;
layer.flags.skip = ((hwc_layer.flags & HWC_SKIP_LAYER) > 0);
+ layer.flags.updating = (layer_stack_cache_.layer_cache[i].handle != hwc_layer.handle);
+
+ if (layer.flags.skip) {
+ layer_stack_.flags.skip_present = true;
+ }
}
// Configure layer stack
@@ -275,15 +288,61 @@
return -EINVAL;
}
+ bool needs_fb_refresh = NeedsFrameBufferRefresh(content_list);
+
for (size_t i = 0; i < num_hw_layers; i++) {
hwc_layer_1_t &hwc_layer = content_list->hwLayers[i];
Layer &layer = layer_stack_.layers[i];
- SetComposition(&hwc_layer.compositionType, layer.composition);
+ // if current frame does not need frame buffer redraw, then mark them for HWC_OVERLAY
+ LayerComposition composition = needs_fb_refresh ? layer.composition : kCompositionSDE;
+ SetComposition(&hwc_layer.compositionType, composition);
}
+ // Cache the current layer stack information like layer_count, composition type and layer handle
+ // for the future.
+ CacheLayerStackInfo(content_list);
return 0;
}
+void HWCSink::CacheLayerStackInfo(hwc_display_contents_1_t *content_list) {
+ uint32_t layer_count = layer_stack_.layer_count;
+
+ for (size_t i = 0; i < layer_count; i++) {
+ Layer &layer = layer_stack_.layers[i];
+ layer_stack_cache_.layer_cache[i].handle = content_list->hwLayers[i].handle;
+ layer_stack_cache_.layer_cache[i].composition = layer.composition;
+ }
+ layer_stack_cache_.layer_count = layer_count;
+}
+
+bool HWCSink::NeedsFrameBufferRefresh(hwc_display_contents_1_t *content_list) {
+ uint32_t layer_count = layer_stack_.layer_count;
+
+ // Frame buffer needs to be refreshed for the following reasons:
+ // 1. Any layer is marked skip in the current layer stack.
+ // 2. Any layer is added/removed/layer properties changes in the current layer stack.
+ // 3. Any layer handle is changed and it is marked for GPU composition
+ // 4. Any layer's current composition is different from previous composition.
+ if ((layer_stack_cache_.layer_count != layer_count) || layer_stack_.flags.skip_present ||
+ layer_stack_.flags.geometry_changed) {
+ return true;
+ }
+
+ for (size_t i = 0; i < layer_count; i++) {
+ hwc_layer_1_t &hwc_layer = content_list->hwLayers[i];
+ Layer &layer = layer_stack_.layers[i];
+ LayerCache &layer_cache = layer_stack_cache_.layer_cache[i];
+ if (layer_cache.composition != layer.composition) {
+ return true;
+ }
+ if ((layer.composition == kCompositionGPU) && (layer_cache.handle != hwc_layer.handle)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
int HWCSink::CommitLayerStack(hwc_display_contents_1_t *content_list) {
size_t num_hw_layers = content_list->numHwLayers;
if (UNLIKELY(num_hw_layers <= 1)) {
diff --git a/displayengine/libs/hwc/hwc_sink.h b/displayengine/libs/hwc/hwc_sink.h
index 340aabd..551a77b 100644
--- a/displayengine/libs/hwc/hwc_sink.h
+++ b/displayengine/libs/hwc/hwc_sink.h
@@ -43,6 +43,18 @@
int SetState(DeviceState state);
protected:
+ // Maximum number of layers supported by display engine.
+ static const uint32_t kMaxLayerCount = 32;
+
+ // Structure to track memory allocation for layer stack (layers, rectangles) object.
+ struct LayerStackMemory : LayerStack {
+ static const size_t kSizeSteps = 4096; // Default memory allocation.
+ uint8_t *raw; // Pointer to byte array.
+ size_t size; // Current number of allocated bytes.
+
+ LayerStackMemory() : raw(NULL), size(0) { }
+ };
+
HWCSink(CoreInterface *core_intf, hwc_procs_t const **hwc_procs, DeviceType type, int id);
virtual ~HWCSink() { }
@@ -60,18 +72,32 @@
inline void SetBlending(LayerBlending *target, const int32_t &source);
inline int SetFormat(LayerBufferFormat *target, const int &source);
- // Structure to track memory allocation for layer stack (layers, rectangles) object.
- struct LayerStackMemory : LayerStack {
- static const size_t kSizeSteps = 4096; // Default memory allocation.
- uint8_t *raw; // Pointer to byte array.
- size_t size; // Current number of allocated bytes.
- } layer_stack_;
-
+ LayerStackMemory layer_stack_;
CoreInterface *core_intf_;
hwc_procs_t const **hwc_procs_;
DeviceType type_;
int id_;
DeviceInterface *device_intf_;
+
+ private:
+ struct LayerCache {
+ buffer_handle_t handle;
+ LayerComposition composition;
+
+ LayerCache() : handle(NULL), composition(kCompositionGPU) { }
+ };
+
+ struct LayerStackCache {
+ LayerCache layer_cache[kMaxLayerCount];
+ uint32_t layer_count;
+
+ LayerStackCache() : layer_count(0) { }
+ };
+
+ bool NeedsFrameBufferRefresh(hwc_display_contents_1_t *content_list);
+ void CacheLayerStackInfo(hwc_display_contents_1_t *content_list);
+
+ LayerStackCache layer_stack_cache_;
};
} // namespace sde
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index 3e16072..58cf374 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -523,9 +523,15 @@
qdutils::MDPVersion::getInstance().isSrcSplitAlways();
const uint32_t lSplit = getLeftSplit(ctx, mDpy);
const uint32_t cropWidth = sourceCrop.right - sourceCrop.left;
+ const uint32_t cropHeight = sourceCrop.bottom - sourceCrop.top;
+ const uint32_t dstWidth = displayFrame.right - displayFrame.left;
+ const uint32_t dstHeight = displayFrame.bottom - displayFrame.top;
+ const uint32_t layerClock = getLayerClock(dstWidth, dstHeight, cropHeight);
+ const uint32_t mixerClock = lSplit;
if((cropWidth > qdutils::MDPVersion::getInstance().getMaxMixerWidth()) or
- (primarySplitAlways and cropWidth > lSplit)) {
+ (primarySplitAlways and
+ (cropWidth > lSplit or layerClock > mixerClock))) {
destR = ov.getPipe(pipeSpecs);
if(destR == ovutils::OV_INVALID) {
ALOGE("%s: No pipes available to configure fb for dpy %d's right"
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index a2a5f2d..aa7783c 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -532,7 +532,8 @@
}
/* deduct any opaque region from visibleRect */
- if (layer->blending == HWC_BLENDING_NONE)
+ if (layer->blending == HWC_BLENDING_NONE &&
+ layer->planeAlpha == 0xFF)
visibleRect = deductRect(visibleRect, res);
}
}
@@ -638,7 +639,8 @@
return false;
}
- if (layer->blending == HWC_BLENDING_NONE) {
+ if (layer->blending == HWC_BLENDING_NONE &&
+ layer->planeAlpha == 0xFF) {
visibleRectL = deductRect(visibleRectL, l_res);
visibleRectR = deductRect(visibleRectR, r_res);
}
@@ -2568,18 +2570,26 @@
MDPVersion& mdpHw = MDPVersion::getInstance();
bool primarySplitAlways = (mDpy == HWC_DISPLAY_PRIMARY) and
mdpHw.isSrcSplitAlways();
- int lSplit = getLeftSplit(ctx, mDpy);
- int dstWidth = dst.right - dst.left;
- int cropWidth = has90Transform(layer) ? crop.bottom - crop.top :
+ const uint32_t lSplit = getLeftSplit(ctx, mDpy);
+ const uint32_t dstWidth = dst.right - dst.left;
+ const uint32_t dstHeight = dst.bottom - dst.top;
+ const uint32_t cropWidth = has90Transform(layer) ? crop.bottom - crop.top :
crop.right - crop.left;
+ const uint32_t cropHeight = has90Transform(layer) ? crop.right - crop.left :
+ crop.bottom - crop.top;
+ //Approximation to actual clock, ignoring the common factors in pipe and
+ //mixer cases like line_time
+ const uint32_t layerClock = getLayerClock(dstWidth, dstHeight, cropHeight);
+ const uint32_t mixerClock = lSplit;
//TODO Even if a 4k video is going to be rot-downscaled to dimensions under
//pipe line length, we are still using 2 pipes. This is fine just because
//this is source split where destination doesn't matter. Evaluate later to
//see if going through all the calcs to save a pipe is worth it
- if(dstWidth > (int) mdpHw.getMaxMixerWidth() or
- cropWidth > (int) mdpHw.getMaxMixerWidth() or
- (primarySplitAlways and (cropWidth > lSplit))) {
+ if(dstWidth > mdpHw.getMaxMixerWidth() or
+ cropWidth > mdpHw.getMaxMixerWidth() or
+ (primarySplitAlways and
+ (cropWidth > lSplit or layerClock > mixerClock))) {
pipe_info.rIndex = ctx->mOverlay->getPipe(pipeSpecs);
if(pipe_info.rIndex == ovutils::OV_INVALID) {
return false;
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 51e23de..916fbc7 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -1383,7 +1383,8 @@
//see if there is no blending required.
//If it is opaque see if we can substract this region from below
//layers.
- if(list->hwLayers[i].blending == HWC_BLENDING_NONE) {
+ if(list->hwLayers[i].blending == HWC_BLENDING_NONE &&
+ list->hwLayers[i].planeAlpha == 0xFF) {
int j= i-1;
hwc_rect_t& topframe =
(hwc_rect_t&)list->hwLayers[i].displayFrame;
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 2da8512..741527c 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -674,6 +674,11 @@
return ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected;
}
+inline uint32_t getLayerClock(const uint32_t& dstW, const uint32_t& dstH,
+ const uint32_t& srcH) {
+ return max(dstW, (srcH * dstW) / dstH);
+}
+
};
#endif //HWC_UTILS_H