Merge "hwc: Request RGB pipe only if layer needs scaling."
diff --git a/common.mk b/common.mk
index 47c455f..ae4ea61 100644
--- a/common.mk
+++ b/common.mk
@@ -36,8 +36,7 @@
common_flags += -DMDSS_TARGET
endif
-ifeq ($(call is-board-platform-in-list, mpq8092 msm_bronze msm8916), true)
- #XXX: Replace with check from MDP when available
+ifeq ($(call is-board-platform-in-list, mpq8092), true)
common_flags += -DVPU_TARGET
endif
diff --git a/libcopybit/copybit.cpp b/libcopybit/copybit.cpp
index 9558f69..c0246e3 100644
--- a/libcopybit/copybit.cpp
+++ b/libcopybit/copybit.cpp
@@ -573,7 +573,9 @@
int rel_fen_fd = -1;
int my_tmp_get_fence = -1;
+ list1.sync.acq_fen_fd = ctx->acqFence;
list1.sync.rel_fen_fd = &my_tmp_get_fence;
+ list1.sync.acq_fen_fd_cnt = ctx->list.sync.acq_fen_fd_cnt;
mdp_blit_req* req = &list1.req[0];
if(!req) {
@@ -607,6 +609,7 @@
req->flags = MDP_SOLID_FILL | MDP_MEMORY_ID_TYPE_FB | MDP_BLEND_FG_PREMULT;
int status = msm_copybit(ctx, &list1);
+ ctx->list.sync.acq_fen_fd_cnt = 0;
if (my_tmp_get_fence != -1)
close(my_tmp_get_fence);
diff --git a/libexternal/external.cpp b/libexternal/external.cpp
index d905e0d..e6395fb 100644
--- a/libexternal/external.cpp
+++ b/libexternal/external.cpp
@@ -493,7 +493,6 @@
void ExternalDisplay::setResolution(int ID)
{
- struct fb_var_screeninfo info;
int ret = 0;
ret = ioctl(mFd, FBIOGET_VSCREENINFO, &mVInfo);
if(ret < 0) {
diff --git a/libgralloc/Android.mk b/libgralloc/Android.mk
index a879c5c..ef10f54 100644
--- a/libgralloc/Android.mk
+++ b/libgralloc/Android.mk
@@ -27,7 +27,7 @@
LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) $(kernel_deps)
LOCAL_SRC_FILES := gpu.cpp gralloc.cpp framebuffer.cpp mapper.cpp
LOCAL_COPY_HEADERS_TO := $(common_header_export_path)
-LOCAL_COPY_HEADERS := gralloc_priv.h
+LOCAL_COPY_HEADERS := gralloc_priv.h gr.h
include $(BUILD_SHARED_LIBRARY)
@@ -41,5 +41,6 @@
LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdmemalloc\"
LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) $(kernel_deps)
LOCAL_SRC_FILES := ionalloc.cpp alloc_controller.cpp
+LOCAL_COPY_HEADERS := alloc_controller.h memalloc.h
include $(BUILD_SHARED_LIBRARY)
diff --git a/libgralloc/alloc_controller.cpp b/libgralloc/alloc_controller.cpp
index 33c4f32..a2c2f14 100644
--- a/libgralloc/alloc_controller.cpp
+++ b/libgralloc/alloc_controller.cpp
@@ -36,6 +36,7 @@
#include "ionalloc.h"
#include "gr.h"
#include "comptype.h"
+#include "mdp_version.h"
#ifdef VENUS_COLOR_FORMAT
#include <media/msm_media_info.h>
@@ -45,6 +46,9 @@
#define VENUS_BUFFER_SIZE(args...) 0
#endif
+#define ASTC_BLOCK_SIZE 16
+#define ASTC_IN_UNITS(n, unit_size) (((n) + (unit_size) -1) / (unit_size))
+
using namespace gralloc;
using namespace qdutils;
@@ -88,13 +92,16 @@
{
LINK_adreno_compute_aligned_width_and_height = NULL;
LINK_adreno_compute_padding = NULL;
+ LINK_adreno_isMacroTilingSupportedByGpu = NULL;
libadreno_utils = ::dlopen("libadreno_utils.so", RTLD_NOW);
if (libadreno_utils) {
*(void **)&LINK_adreno_compute_aligned_width_and_height =
- ::dlsym(libadreno_utils, "compute_aligned_width_and_height");
- *(void **)&LINK_adreno_compute_padding = ::dlsym(libadreno_utils,
- "compute_surface_padding");
+ ::dlsym(libadreno_utils, "compute_aligned_width_and_height");
+ *(void **)&LINK_adreno_compute_padding =
+ ::dlsym(libadreno_utils, "compute_surface_padding");
+ *(void **)&LINK_adreno_isMacroTilingSupportedByGpu =
+ ::dlsym(libadreno_utils, "isMacroTilingSupportedByGpu");
}
}
@@ -105,8 +112,19 @@
}
}
+int AdrenoMemInfo::isMacroTilingSupportedByGPU()
+{
+ if ((libadreno_utils)) {
+ if(LINK_adreno_isMacroTilingSupportedByGpu) {
+ return LINK_adreno_isMacroTilingSupportedByGpu();
+ }
+ }
+ return 0;
+}
+
+
void AdrenoMemInfo::getAlignedWidthAndHeight(int width, int height, int format,
- int& aligned_w, int& aligned_h)
+ int tile_enabled, int& aligned_w, int& aligned_h)
{
aligned_w = ALIGN(width, 32);
aligned_h = ALIGN(height, 32);
@@ -138,9 +156,8 @@
// the function below computes aligned width and aligned height
// based on linear or macro tile mode selected.
if(LINK_adreno_compute_aligned_width_and_height) {
- int tile_mode = 0; // Linear surface
- LINK_adreno_compute_aligned_width_and_height(width,
- height, bpp, tile_mode,
+ LINK_adreno_compute_aligned_width_and_height(width,
+ height, bpp, tile_enabled,
raster_mode, padding_threshold,
&aligned_w, &aligned_h);
@@ -185,6 +202,76 @@
case HAL_PIXEL_FORMAT_NV21_ZSL:
aligned_w = ALIGN(width, 64);
break;
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_4x4_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
+ aligned_w = ASTC_IN_UNITS(width, 4);
+ aligned_h = ASTC_IN_UNITS(height, 4);
+ break;
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_5x4_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:
+ aligned_w = ASTC_IN_UNITS(width, 5);
+ aligned_h = ASTC_IN_UNITS(height, 4);
+ break;
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_5x5_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:
+ aligned_w = ASTC_IN_UNITS(width, 5);
+ aligned_h = ASTC_IN_UNITS(height, 5);
+ break;
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_6x5_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:
+ aligned_w = ASTC_IN_UNITS(width, 6);
+ aligned_h = ASTC_IN_UNITS(height, 5);
+ break;
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_6x6_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:
+ aligned_w = ASTC_IN_UNITS(width, 6);
+ aligned_h = ASTC_IN_UNITS(height, 6);
+ break;
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_8x5_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:
+ aligned_w = ASTC_IN_UNITS(width, 8);
+ aligned_h = ASTC_IN_UNITS(height, 5);
+ break;
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_8x6_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:
+ aligned_w = ASTC_IN_UNITS(width, 8);
+ aligned_h = ASTC_IN_UNITS(height, 6);
+ break;
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_8x8_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
+ aligned_w = ASTC_IN_UNITS(width, 8);
+ aligned_h = ASTC_IN_UNITS(height, 8);
+ break;
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x5_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:
+ aligned_w = ASTC_IN_UNITS(width, 10);
+ aligned_h = ASTC_IN_UNITS(height, 5);
+ break;
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x6_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:
+ aligned_w = ASTC_IN_UNITS(width, 10);
+ aligned_h = ASTC_IN_UNITS(height, 6);
+ break;
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x8_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:
+ aligned_w = ASTC_IN_UNITS(width, 10);
+ aligned_h = ASTC_IN_UNITS(height, 8);
+ break;
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x10_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
+ aligned_w = ASTC_IN_UNITS(width, 10);
+ aligned_h = ASTC_IN_UNITS(height, 10);
+ break;
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_12x10_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
+ aligned_w = ASTC_IN_UNITS(width, 12);
+ aligned_h = ASTC_IN_UNITS(height, 10);
+ break;
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_12x12_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:
+ aligned_w = ASTC_IN_UNITS(width, 12);
+ aligned_h = ASTC_IN_UNITS(height, 12);
+ break;
default: break;
}
}
@@ -289,16 +376,42 @@
return memalloc;
}
-size_t getBufferSizeAndDimensions(int width, int height, int format,
- int& alignedw, int &alignedh)
+bool isMacroTileEnabled(int format, int usage)
+{
+ bool tileEnabled = false;
+
+ // Check whether GPU & MDSS supports MacroTiling feature
+ if(AdrenoMemInfo::getInstance().isMacroTilingSupportedByGPU() &&
+ qdutils::MDPVersion::getInstance().supportsMacroTile())
+ {
+ // check the format
+ switch(format)
+ {
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ {
+ tileEnabled = true;
+ // check the usage flags
+ if (usage & (GRALLOC_USAGE_SW_READ_MASK |
+ GRALLOC_USAGE_SW_WRITE_MASK)) {
+ // Application intends to use CPU for rendering
+ tileEnabled = false;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ return tileEnabled;
+}
+
+// helper function
+size_t getSize(int format, int width, int height, int alignedw, int alignedh)
{
size_t size;
- AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(width,
- height,
- format,
- alignedw,
- alignedh);
switch (format) {
case HAL_PIXEL_FORMAT_RGBA_8888:
case HAL_PIXEL_FORMAT_RGBX_8888:
@@ -372,14 +485,97 @@
alignedh = ALIGN(height, 64);
size = ALIGN((alignedw*alignedh) + (alignedw* alignedh)/2, 4096);
break;
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_4x4_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_5x4_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_5x5_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_6x5_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_6x6_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_8x5_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_8x6_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_8x8_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x5_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x6_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x8_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x10_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_12x10_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_12x12_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
+ size = alignedw * alignedh * ASTC_BLOCK_SIZE;
+ break;
default:
ALOGE("unrecognized pixel format: 0x%x", format);
return -EINVAL;
}
+ return size;
+}
+
+size_t getBufferSizeAndDimensions(int width, int height, int format,
+ int& alignedw, int &alignedh)
+{
+ size_t size;
+
+ AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(width,
+ height,
+ format,
+ false,
+ alignedw,
+ alignedh);
+
+ size = getSize(format, width, height, alignedw, alignedh);
return size;
}
+
+size_t getBufferSizeAndDimensions(int width, int height, int format, int usage,
+ int& alignedw, int &alignedh)
+{
+ size_t size;
+ int tileEnabled = isMacroTileEnabled(format, usage);
+
+ AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(width,
+ height,
+ format,
+ tileEnabled,
+ alignedw,
+ alignedh);
+
+ size = getSize(format, width, height, alignedw, alignedh);
+
+ return size;
+}
+
+
+void getBufferAttributes(int width, int height, int format, int usage,
+ int& alignedw, int &alignedh, int& tileEnabled, size_t& size)
+{
+ tileEnabled = isMacroTileEnabled(format, usage);
+
+ AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(width,
+ height,
+ format,
+ tileEnabled,
+ alignedw,
+ alignedh);
+
+ if(size)
+ size = getSize(format, width, height, alignedw, alignedh);
+}
+
+
+
// Allocate buffer from width, height and format into a
// private_handle_t. It is the responsibility of the caller
// to free the buffer using the free_buffer function
@@ -392,7 +588,9 @@
data.base = 0;
data.fd = -1;
data.offset = 0;
- data.size = getBufferSizeAndDimensions(w, h, format, alignedw, alignedh);
+ data.size = getBufferSizeAndDimensions(w, h, format, usage, alignedw,
+ alignedh);
+
data.align = getpagesize();
data.uncached = useUncached(usage);
int allocFlags = usage;
diff --git a/libgralloc/gpu.cpp b/libgralloc/gpu.cpp
index b4da363..da179f9 100644
--- a/libgralloc/gpu.cpp
+++ b/libgralloc/gpu.cpp
@@ -150,6 +150,10 @@
flags |= private_handle_t::PRIV_FLAGS_SECURE_DISPLAY;
}
+ if(isMacroTileEnabled(format, usage)) {
+ flags |= private_handle_t::PRIV_FLAGS_TILE_RENDERED;
+ }
+
flags |= data.allocType;
int eBaseAddr = int(eData.base) + eData.offset;
private_handle_t *hnd = new private_handle_t(data.fd, size, flags,
@@ -173,6 +177,9 @@
{
*bufferType = BUFFER_TYPE_VIDEO;
+ if (inputFormat == HAL_PIXEL_FORMAT_RGB_888)
+ return;
+
if (inputFormat <= HAL_PIXEL_FORMAT_sRGB_X_8888) {
// RGB formats
*bufferType = BUFFER_TYPE_UI;
@@ -285,7 +292,8 @@
}
getGrallocInformationFromFormat(grallocFormat, &bufferType);
- size = getBufferSizeAndDimensions(w, h, grallocFormat, alignedw, alignedh);
+ size = getBufferSizeAndDimensions(w, h, grallocFormat, usage, alignedw,
+ alignedh);
if ((ssize_t)size <= 0)
return -EINVAL;
diff --git a/libgralloc/gr.h b/libgralloc/gr.h
index 1949f45..8c68e16 100644
--- a/libgralloc/gr.h
+++ b/libgralloc/gr.h
@@ -51,9 +51,20 @@
int mapFrameBufferLocked(struct private_module_t* module);
int terminateBuffer(gralloc_module_t const* module, private_handle_t* hnd);
+size_t getBufferSizeAndDimensions(int width, int height, int format, int usage,
+ int& alignedw, int &alignedh);
size_t getBufferSizeAndDimensions(int width, int height, int format,
int& alignedw, int &alignedh);
+
+// Attributes include aligned width, aligned height, tileEnabled and size of the buffer
+void getBufferAttributes(int width, int height, int format, int usage,
+ int& alignedw, int &alignedh,
+ int& tileEnabled, size_t &size);
+
+
+bool isMacroTileEnabled(int format, int usage);
+
int decideBufferHandlingMechanism(int format, const char *compositionUsed,
int hasBlitEngine, int *needConversion,
int *useBufferDirectly);
@@ -95,7 +106,16 @@
* @return aligned width, aligned height
*/
void getAlignedWidthAndHeight(int width, int height, int format,
- int& alignedw, int &alignedh);
+ int tileEnabled, int& alignedw, int &alignedh);
+
+ /*
+ * Function to return whether GPU support MacroTile feature
+ *
+ * @return >0 : supported
+ * 0 : not supported
+ */
+ int isMacroTilingSupportedByGPU();
+
private:
// Pointer to the padding library.
void *libadreno_utils;
@@ -114,6 +134,8 @@
int padding_threshold,
int *aligned_w,
int *aligned_h);
+ // link to the surface padding library.
+ int (*LINK_adreno_isMacroTilingSupportedByGpu) (void);
};
#endif /* GR_H_ */
diff --git a/libgralloc/gralloc_priv.h b/libgralloc/gralloc_priv.h
index f6d244a..c56eca9 100644
--- a/libgralloc/gralloc_priv.h
+++ b/libgralloc/gralloc_priv.h
@@ -79,8 +79,12 @@
/* Gralloc perform enums
*/
GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER = 1,
+ // This will be deprecated from latest graphics drivers. This is kept
+ // for those backward compatibility i.e., newer Display HAL + older graphics
+ // libraries
GRALLOC_MODULE_PERFORM_GET_STRIDE,
GRALLOC_MODULE_PERFORM_GET_CUSTOM_STRIDE_FROM_HANDLE,
+ GRALLOC_MODULE_PERFORM_GET_ATTRIBUTES,
};
#define GRALLOC_HEAP_MASK (GRALLOC_USAGE_PRIVATE_UI_CONTIG_HEAP |\
@@ -110,6 +114,39 @@
HAL_PIXEL_FORMAT_INTERLACE = 0x180,
//v4l2_fourcc('Y', 'U', 'Y', 'L'). 24 bpp YUYV 4:2:2 10 bit per component
HAL_PIXEL_FORMAT_YCbCr_422_I_10BIT = 0x4C595559,
+ //v4l2_fourcc('Y', 'B', 'W', 'C'). 10 bit per component. This compressed
+ //format reduces the memory access bandwidth
+ HAL_PIXEL_FORMAT_YCbCr_422_I_10BIT_COMPRESSED = 0x43574259,
+
+ //Khronos ASTC formats
+ HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_4x4_KHR = 0x93B0,
+ HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_5x4_KHR = 0x93B1,
+ HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_5x5_KHR = 0x93B2,
+ HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_6x5_KHR = 0x93B3,
+ HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_6x6_KHR = 0x93B4,
+ HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_8x5_KHR = 0x93B5,
+ HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_8x6_KHR = 0x93B6,
+ HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_8x8_KHR = 0x93B7,
+ HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x5_KHR = 0x93B8,
+ HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x6_KHR = 0x93B9,
+ HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x8_KHR = 0x93BA,
+ HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x10_KHR = 0x93BB,
+ HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_12x10_KHR = 0x93BC,
+ HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_12x12_KHR = 0x93BD,
+ HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR = 0x93D0,
+ HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR = 0x93D1,
+ HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR = 0x93D2,
+ HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR = 0x93D3,
+ HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR = 0x93D4,
+ HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR = 0x93D5,
+ HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR = 0x93D6,
+ HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR = 0x93D7,
+ HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR = 0x93D8,
+ HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR = 0x93D9,
+ HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR = 0x93DA,
+ HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR = 0x93DB,
+ HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR = 0x93DC,
+ HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR = 0x93DD,
};
/* possible formats for 3D content*/
@@ -170,6 +207,8 @@
PRIV_FLAGS_ITU_R_601_FR = 0x00400000,
PRIV_FLAGS_ITU_R_709 = 0x00800000,
PRIV_FLAGS_SECURE_DISPLAY = 0x01000000,
+ // Buffer is rendered in Tile Format
+ PRIV_FLAGS_TILE_RENDERED = 0x02000000
};
// file-descriptors
diff --git a/libgralloc/mapper.cpp b/libgralloc/mapper.cpp
index a07bdc3..109c141 100644
--- a/libgralloc/mapper.cpp
+++ b/libgralloc/mapper.cpp
@@ -331,10 +331,11 @@
int *stride = va_arg(args, int *);
int alignedw = 0, alignedh = 0;
AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(width,
- 0, format, alignedw, alignedh);
+ 0, format, false, alignedw, alignedh);
*stride = alignedw;
res = 0;
} break;
+
case GRALLOC_MODULE_PERFORM_GET_CUSTOM_STRIDE_FROM_HANDLE:
{
private_handle_t* hnd = va_arg(args, private_handle_t*);
@@ -350,6 +351,23 @@
}
res = 0;
} break;
+
+ case GRALLOC_MODULE_PERFORM_GET_ATTRIBUTES:
+ {
+ int width = va_arg(args, int);
+ int height = va_arg(args, int);
+ int format = va_arg(args, int);
+ int usage = va_arg(args, int);
+ int *alignedWidth = va_arg(args, int *);
+ int *alignedHeight = va_arg(args, int *);
+ int *tileEnabled = va_arg(args,int *);
+ *tileEnabled = isMacroTileEnabled(format, usage);
+ AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(width,
+ height, format, *tileEnabled, *alignedWidth,
+ *alignedHeight);
+ res = 0;
+ } break;
+
default:
break;
}
diff --git a/libhwcomposer/Android.mk b/libhwcomposer/Android.mk
index 7b2092d..9749c69 100644
--- a/libhwcomposer/Android.mk
+++ b/libhwcomposer/Android.mk
@@ -23,11 +23,10 @@
hwc_copybit.cpp \
hwc_qclient.cpp \
hwc_dump_layers.cpp \
- hwc_ad.cpp
-
-ifeq ($(call is-board-platform-in-list, mpq8092 msm_bronze msm8916), true)
+ hwc_ad.cpp \
+ hwc_virtual.cpp
+ifeq ($(call is-board-platform-in-list, mpq8092), true)
LOCAL_SRC_FILES += hwc_vpuclient.cpp
endif
-
include $(BUILD_SHARED_LIBRARY)
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index eb999f7..431757d 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2010 The Android Open Source Project
- * Copyright (C) 2012-2013, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2012-2014, The Linux Foundation. All rights reserved.
*
* Not a Contribution, Apache license notifications and license are retained
* for attribution purposes only.
@@ -39,6 +39,7 @@
#include "hwc_ad.h"
#include "profiler.h"
#include "hwc_vpuclient.h"
+#include "hwc_virtual.h"
using namespace qhwc;
using namespace overlay;
@@ -104,17 +105,27 @@
//Helper
static void reset(hwc_context_t *ctx, int numDisplays,
hwc_display_contents_1_t** displays) {
+
+ ctx->numActiveDisplays = 0;
for(int i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) {
hwc_display_contents_1_t *list = displays[i];
// XXX:SurfaceFlinger no longer guarantees that this
// value is reset on every prepare. However, for the layer
// cache we need to reset it.
// We can probably rethink that later on
- if (LIKELY(list && list->numHwLayers > 1)) {
+ if (LIKELY(list && list->numHwLayers > 0)) {
for(uint32_t j = 0; j < list->numHwLayers; j++) {
if(list->hwLayers[j].compositionType != HWC_FRAMEBUFFER_TARGET)
list->hwLayers[j].compositionType = HWC_FRAMEBUFFER;
}
+
+ /* For display devices like SSD and screenrecord, we cannot
+ * rely on isActive and connected attributes of dpyAttr to
+ * determine if the displaydevice is active. Hence in case if
+ * the layer-list is non-null and numHwLayers > 0, we assume
+ * the display device to be active.
+ */
+ ctx->numActiveDisplays += 1;
}
if(ctx->mFBUpdate[i])
@@ -123,19 +134,45 @@
ctx->mCopyBit[i]->reset();
if(ctx->mLayerRotMap[i])
ctx->mLayerRotMap[i]->reset();
+
}
ctx->mAD->reset();
MDPComp::reset();
+ if(ctx->mHWCVirtual)
+ ctx->mHWCVirtual->destroy(ctx, numDisplays, displays);
}
-//clear prev layer prop flags and realloc for current frame
-static void reset_layer_prop(hwc_context_t* ctx, int dpy, int numAppLayers) {
- if(ctx->layerProp[dpy]) {
- delete[] ctx->layerProp[dpy];
- ctx->layerProp[dpy] = NULL;
+bool isEqual(float f1, float f2) {
+ return ((int)(f1*100) == (int)(f2*100)) ? true : false;
+}
+
+static void scaleDisplayFrame(hwc_context_t *ctx, int dpy,
+ hwc_display_contents_1_t *list) {
+ float origXres = ctx->dpyAttr[dpy].xres_orig;
+ float origYres = ctx->dpyAttr[dpy].yres_orig;
+ float fakeXres = ctx->dpyAttr[dpy].xres;
+ float fakeYres = ctx->dpyAttr[dpy].yres;
+ float xresRatio = origXres / fakeXres;
+ float yresRatio = origYres / fakeYres;
+ for (size_t i = 0; i < list->numHwLayers; i++) {
+ hwc_layer_1_t *layer = &list->hwLayers[i];
+ hwc_rect_t& displayFrame = layer->displayFrame;
+ hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
+ float layerWidth = displayFrame.right - displayFrame.left;
+ float layerHeight = displayFrame.bottom - displayFrame.top;
+ float sourceWidth = sourceCrop.right - sourceCrop.left;
+ float sourceHeight = sourceCrop.bottom - sourceCrop.top;
+
+ if (isEqual(layerWidth / sourceWidth, xresRatio) &&
+ isEqual(layerHeight / sourceHeight, yresRatio))
+ break;
+
+ displayFrame.left = xresRatio * displayFrame.left;
+ displayFrame.top = yresRatio * displayFrame.top;
+ displayFrame.right = displayFrame.left + layerWidth * xresRatio;
+ displayFrame.bottom = displayFrame.top + layerHeight * yresRatio;
}
- ctx->layerProp[dpy] = new LayerProp[numAppLayers];
}
static int hwc_prepare_primary(hwc_composer_device_1 *dev,
@@ -143,17 +180,28 @@
ATRACE_CALL();
hwc_context_t* ctx = (hwc_context_t*)(dev);
const int dpy = HWC_DISPLAY_PRIMARY;
+ bool fbComp = false;
if (LIKELY(list && list->numHwLayers > 1) &&
ctx->dpyAttr[dpy].isActive) {
+
+ if (ctx->dpyAttr[dpy].customFBSize)
+ scaleDisplayFrame(ctx, dpy, list);
+
reset_layer_prop(ctx, dpy, list->numHwLayers - 1);
setListStats(ctx, list, dpy);
+
+ if (ctx->mVPUClient == NULL)
+ fbComp = (ctx->mMDPComp[dpy]->prepare(ctx, list) < 0);
#ifdef VPU_TARGET
- ctx->mVPUClient->prepare(ctx, list);
+ else
+ fbComp = (ctx->mVPUClient->prepare(ctx, dpy, list) < 0);
#endif
- if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
+
+ if (fbComp) {
const int fbZ = 0;
ctx->mFBUpdate[dpy]->prepare(ctx, list, fbZ);
}
+
if (ctx->mMDP.version < qdutils::MDP_V4_0) {
if(ctx->mCopyBit[dpy])
ctx->mCopyBit[dpy]->prepare(ctx, list, dpy);
@@ -193,39 +241,6 @@
return 0;
}
-static int hwc_prepare_virtual(hwc_composer_device_1 *dev,
- hwc_display_contents_1_t *list) {
- ATRACE_CALL();
-
- hwc_context_t* ctx = (hwc_context_t*)(dev);
- const int dpy = HWC_DISPLAY_VIRTUAL;
-
- if (LIKELY(list && list->numHwLayers > 1) &&
- ctx->dpyAttr[dpy].isActive &&
- ctx->dpyAttr[dpy].connected) {
- reset_layer_prop(ctx, dpy, list->numHwLayers - 1);
- if(!ctx->dpyAttr[dpy].isPause) {
- ctx->dpyAttr[dpy].isConfiguring = false;
- setListStats(ctx, list, dpy);
- if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
- const int fbZ = 0;
- ctx->mFBUpdate[dpy]->prepare(ctx, list, fbZ);
- }
- } else {
- /* Virtual Display is in Pause state.
- * Mark all application layers as OVERLAY so that
- * GPU will not compose.
- */
- for(size_t i = 0 ;i < (size_t)(list->numHwLayers - 1); i++) {
- hwc_layer_1_t *layer = &list->hwLayers[i];
- layer->compositionType = HWC_OVERLAY;
- }
- }
- }
- return 0;
-}
-
-
static int hwc_prepare(hwc_composer_device_1 *dev, size_t numDisplays,
hwc_display_contents_1_t** displays)
{
@@ -245,7 +260,7 @@
ctx->mRotMgr->configBegin();
overlay::Writeback::configBegin();
- for (int32_t i = numDisplays; i >= 0; i--) {
+ for (int32_t i = (numDisplays-1); i >= 0; i--) {
hwc_display_contents_1_t *list = displays[i];
int dpy = getDpyforExternalDisplay(ctx, i);
switch(dpy) {
@@ -256,7 +271,8 @@
ret = hwc_prepare_external(dev, list);
break;
case HWC_DISPLAY_VIRTUAL:
- ret = hwc_prepare_virtual(dev, list);
+ if(ctx->mHWCVirtual)
+ ret = ctx->mHWCVirtual->prepare(dev, list);
break;
default:
ret = -EINVAL;
@@ -439,8 +455,11 @@
value[0] = 0;
break;
case HWC_DISPLAY_TYPES_SUPPORTED:
- if(ctx->mMDP.hasOverlay)
- supported |= HWC_DISPLAY_EXTERNAL_BIT;
+ if(ctx->mMDP.hasOverlay) {
+ supported |= HWC_DISPLAY_VIRTUAL_BIT;
+ if(!qdutils::MDPVersion::getInstance().is8x26())
+ supported |= HWC_DISPLAY_EXTERNAL_BIT;
+ }
value[0] = supported;
break;
case HWC_FORMAT_RB_SWAP:
@@ -475,13 +494,15 @@
if(ctx->mHwcDebug[dpy])
ctx->mHwcDebug[dpy]->dumpLayers(list);
- if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
+ if (ctx->mVPUClient != NULL) {
+#ifdef VPU_TARGET
+ ctx->mVPUClient->predraw(ctx, dpy, list);
+#endif
+ }
+ else if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
ALOGE("%s: MDPComp draw failed", __FUNCTION__);
ret = -1;
}
-#ifdef VPU_TARGET
- ctx->mVPUClient->draw(ctx, list);
-#endif
//TODO We dont check for SKIP flag on this layer because we need PAN
//always. Last layer is always FB
@@ -502,6 +523,11 @@
ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy);
ret = -1;
}
+
+#ifdef VPU_TARGET
+ if (ctx->mVPUClient != NULL)
+ ctx->mVPUClient->draw(ctx, dpy, list);
+#endif
}
closeAcquireFds(list);
@@ -567,82 +593,13 @@
return ret;
}
-static int hwc_set_virtual(hwc_context_t *ctx,
- hwc_display_contents_1_t* list)
-{
- ATRACE_CALL();
- int ret = 0;
-
- const int dpy = HWC_DISPLAY_VIRTUAL;
-
-
- if (LIKELY(list) && ctx->dpyAttr[dpy].isActive &&
- ctx->dpyAttr[dpy].connected &&
- !ctx->dpyAttr[dpy].isPause) {
- uint32_t last = list->numHwLayers - 1;
- hwc_layer_1_t *fbLayer = &list->hwLayers[last];
- int fd = -1; //FenceFD from the Copybit(valid in async mode)
- bool copybitDone = false;
- if(ctx->mCopyBit[dpy])
- copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd);
-
- if(list->numHwLayers > 1)
- hwc_sync(ctx, list, dpy, fd);
-
- // Dump the layers for virtual
- if(ctx->mHwcDebug[dpy])
- ctx->mHwcDebug[dpy]->dumpLayers(list);
-
- if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
- ALOGE("%s: MDPComp draw failed", __FUNCTION__);
- ret = -1;
- }
-
- int extOnlyLayerIndex =
- ctx->listStats[dpy].extOnlyLayerIndex;
-
- private_handle_t *hnd = (private_handle_t *)fbLayer->handle;
- if(extOnlyLayerIndex!= -1) {
- hwc_layer_1_t *extLayer = &list->hwLayers[extOnlyLayerIndex];
- hnd = (private_handle_t *)extLayer->handle;
- } else if(copybitDone) {
- hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer();
- }
-
- if(hnd && !isYuvBuffer(hnd)) {
- if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) {
- ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
- ret = -1;
- }
- }
-
- if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
- ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy);
- ret = -1;
- }
- }
-
- closeAcquireFds(list);
-
- if (list && !ctx->mVirtualonExtActive && (list->retireFenceFd < 0) ) {
- // SF assumes HWC waits for the acquire fence and returns a new fence
- // that signals when we're done. Since we don't wait, and also don't
- // touch the buffer, we can just handle the acquire fence back to SF
- // as the retire fence.
- list->retireFenceFd = list->outbufAcquireFenceFd;
- }
-
- return ret;
-}
-
-
static int hwc_set(hwc_composer_device_1 *dev,
size_t numDisplays,
hwc_display_contents_1_t** displays)
{
int ret = 0;
hwc_context_t* ctx = (hwc_context_t*)(dev);
- for (uint32_t i = 0; i <= numDisplays; i++) {
+ for (uint32_t i = 0; i < numDisplays; i++) {
hwc_display_contents_1_t* list = displays[i];
int dpy = getDpyforExternalDisplay(ctx, i);
switch(dpy) {
@@ -653,7 +610,8 @@
ret = hwc_set_external(ctx, list);
break;
case HWC_DISPLAY_VIRTUAL:
- ret = hwc_set_virtual(ctx, list);
+ if(ctx->mHWCVirtual)
+ ret = ctx->mHWCVirtual->set(ctx, list);
break;
default:
ret = -EINVAL;
diff --git a/libhwcomposer/hwc_ad.cpp b/libhwcomposer/hwc_ad.cpp
index 104ffce..929ccc4 100644
--- a/libhwcomposer/hwc_ad.cpp
+++ b/libhwcomposer/hwc_ad.cpp
@@ -157,7 +157,7 @@
const hwc_display_contents_1_t* list) {
mDoable = false;
if(mFeatureEnabled &&
- !ctx->mExtDisplay->isConnected() &&
+ !isSecondaryConnected(ctx) &&
ctx->listStats[HWC_DISPLAY_PRIMARY].yuvCount == 1) {
int nYuvIndex = ctx->listStats[HWC_DISPLAY_PRIMARY].yuvIndices[0];
const hwc_layer_1_t* layer = &list->hwLayers[nYuvIndex];
diff --git a/libhwcomposer/hwc_copybit.cpp b/libhwcomposer/hwc_copybit.cpp
index 47b9225..86cad8f 100644
--- a/libhwcomposer/hwc_copybit.cpp
+++ b/libhwcomposer/hwc_copybit.cpp
@@ -25,7 +25,7 @@
#include "comptype.h"
#include "gr.h"
#include "cb_utils.h"
-
+#include "cb_swap_rect.h"
using namespace qdutils;
namespace qhwc {
@@ -188,8 +188,15 @@
dst_h = layer->displayFrame.bottom - layer->displayFrame.top;
dst_w = layer->displayFrame.right - layer->displayFrame.left;
+ if(src_w <=0 || src_h<=0 ||dst_w<=0 || dst_h<=0 ) {
+ ALOGE("%s: wrong params for display screen_w=%d \
+ src_crop_width=%d screen_h=%d src_crop_height=%d",
+ __FUNCTION__, dst_w,src_w,dst_h,src_h);
+ return false;
+ }
dx = (float)dst_w/src_w;
dy = (float)dst_h/src_h;
+
if (dx > MAX_SCALE_FACTOR || dx < MIN_SCALE_FACTOR)
return false;
@@ -303,6 +310,9 @@
ALOGD_IF(DEBUG_COPYBIT, "%s: Not Marked for copybit", __FUNCTION__);
continue;
}
+ if(layer->flags & HWC_SKIP_HWC_COMPOSITION){
+ continue;
+ }
int ret = -1;
if (list->hwLayers[i].acquireFenceFd != -1
&& ctx->mMDP.version >= qdutils::MDP_V4_0) {
@@ -448,8 +458,8 @@
if(screen_w <=0 || screen_h<=0 ||src_crop_width<=0 || src_crop_height<=0 ) {
ALOGE("%s: wrong params for display screen_w=%d src_crop_width=%d \
- screen_w=%d src_crop_width=%d", __FUNCTION__, screen_w,
- src_crop_width,screen_w,src_crop_width);
+ screen_h=%d src_crop_height=%d", __FUNCTION__, screen_w,
+ src_crop_width,screen_h,src_crop_height);
return -1;
}
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index d601f8f..0123452 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2010 The Android Open Source Project
- * Copyright (C) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2012-2014, The Linux Foundation. All rights reserved.
*
* Not a Contribution, Apache license notifications and license are
* retained for attribution purposes only.
@@ -45,11 +45,14 @@
}
IFBUpdate::IFBUpdate(hwc_context_t *ctx, const int& dpy) : mDpy(dpy) {
- getBufferSizeAndDimensions(ctx->dpyAttr[dpy].xres,
- ctx->dpyAttr[dpy].yres,
+ size_t size;
+ getBufferAttributes(ctx->dpyAttr[mDpy].xres,
+ ctx->dpyAttr[mDpy].yres,
HAL_PIXEL_FORMAT_RGBA_8888,
+ 0,
mAlignedFBWidth,
- mAlignedFBHeight);
+ mAlignedFBHeight,
+ mTileEnabled, size);
}
void IFBUpdate::reset() {
@@ -121,9 +124,9 @@
}
overlay::Overlay& ov = *(ctx->mOverlay);
- ovutils::Whf info(mAlignedFBWidth,
- mAlignedFBHeight,
- ovutils::getMdpFormat(HAL_PIXEL_FORMAT_RGBA_8888));
+ ovutils::Whf info(mAlignedFBWidth, mAlignedFBHeight,
+ ovutils::getMdpFormat(HAL_PIXEL_FORMAT_RGBA_8888,
+ mTileEnabled));
//Request a pipe
ovutils::eMdpPipeType type = ovutils::OV_MDP_PIPE_ANY;
@@ -164,12 +167,12 @@
// Dont do wormhole calculation when extDownscale is enabled on External
if(ctx->listStats[mDpy].isDisplayAnimating && mDpy) {
sourceCrop = layer->displayFrame;
- displayFrame = sourceCrop;
} else if((!mDpy ||
- (mDpy && !extOrient
- && !ctx->dpyAttr[mDpy].mDownScaleMode))
- && (extOnlyLayerIndex == -1)) {
- if(!qdutils::MDPVersion::getInstance().is8x26()) {
+ (mDpy && !extOrient
+ && !ctx->dpyAttr[mDpy].mDownScaleMode))
+ && (extOnlyLayerIndex == -1)) {
+ if(!qdutils::MDPVersion::getInstance().is8x26() &&
+ !ctx->dpyAttr[mDpy].customFBSize) {
getNonWormholeRegion(list, sourceCrop);
displayFrame = sourceCrop;
}
@@ -269,8 +272,8 @@
ovutils::Whf info(mAlignedFBWidth,
mAlignedFBHeight,
- ovutils::getMdpFormat(HAL_PIXEL_FORMAT_RGBA_8888));
-
+ ovutils::getMdpFormat(HAL_PIXEL_FORMAT_RGBA_8888,
+ mTileEnabled));
//Request left pipe
ovutils::eDest destL = ov.nextPipe(ovutils::OV_MDP_PIPE_ANY, mDpy,
Overlay::MIXER_LEFT);
diff --git a/libhwcomposer/hwc_fbupdate.h b/libhwcomposer/hwc_fbupdate.h
index 355e429..4b449c8 100644
--- a/libhwcomposer/hwc_fbupdate.h
+++ b/libhwcomposer/hwc_fbupdate.h
@@ -53,6 +53,7 @@
overlay::Rotator *mRot;
int mAlignedFBWidth;
int mAlignedFBHeight;
+ int mTileEnabled;
};
//Non-Split panel handler.
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 8ecd322..dbd05ae 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -325,8 +325,8 @@
int crop_h = crop.bottom - crop.top;
int dst_w = dst.right - dst.left;
int dst_h = dst.bottom - dst.top;
- float w_dscale = ceilf((float)crop_w / (float)dst_w);
- float h_dscale = ceilf((float)crop_h / (float)dst_h);
+ float w_scale = ((float)crop_w / (float)dst_w);
+ float h_scale = ((float)crop_h / (float)dst_h);
/* Workaround for MDP HW limitation in DSI command mode panels where
* FPS will not go beyond 30 if buffers on RGB pipes are of width or height
@@ -337,9 +337,12 @@
if((crop_w < 5)||(crop_h < 5))
return false;
- if((w_dscale > 1.0f) || (h_dscale > 1.0f)) {
+ if((w_scale > 1.0f) || (h_scale > 1.0f)) {
const uint32_t downscale =
qdutils::MDPVersion::getInstance().getMaxMDPDownscale();
+ const float w_dscale = w_scale;
+ const float h_dscale = h_scale;
+
if(ctx->mMDP.version >= qdutils::MDSS_V5) {
/* Workaround for downscales larger than 4x.
* Will be removed once decimator block is enabled for MDSS
@@ -358,6 +361,16 @@
}
}
+ if((w_scale < 1.0f) || (h_scale < 1.0f)) {
+ const uint32_t upscale =
+ qdutils::MDPVersion::getInstance().getMaxMDPUpscale();
+ const float w_uscale = 1.0f / w_scale;
+ const float h_uscale = 1.0f / h_scale;
+
+ if(w_uscale > upscale || h_uscale > upscale)
+ return false;
+ }
+
return true;
}
@@ -400,13 +413,13 @@
ALOGD_IF(isDebug(),"%s: MDP Comp. not enabled.", __FUNCTION__);
ret = false;
} else if(qdutils::MDPVersion::getInstance().is8x26() &&
- ctx->mVideoTransFlag && ctx->mVirtualDisplay->isConnected()) {
+ ctx->mVideoTransFlag &&
+ isSecondaryConnected(ctx)) {
//1 Padding round to shift pipes across mixers
ALOGD_IF(isDebug(),"%s: MDP Comp. video transition padding round",
__FUNCTION__);
ret = false;
- } else if(ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isConfiguring ||
- ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isConfiguring) {
+ } else if(isSecondaryConfiguring(ctx)) {
ALOGD_IF( isDebug(),"%s: External Display connection is pending",
__FUNCTION__);
ret = false;
@@ -438,6 +451,7 @@
if(!isValidRect(visibleRect)) {
mCurrentFrame.drop[i] = true;
mCurrentFrame.dropCount++;
+ continue;
}
const hwc_layer_1_t* layer = &list->hwLayers[i];
@@ -459,17 +473,17 @@
}else {
/* Reset frame ROI when any layer which needs scaling also needs ROI
* cropping */
- if((res_w != dst_w || res_h != dst_h) &&
- needsScaling (layer)) {
+ if((res_w != dst_w || res_h != dst_h) && needsScaling (layer)) {
ALOGI("%s: Resetting ROI due to scaling", __FUNCTION__);
memset(&mCurrentFrame.drop, 0, sizeof(mCurrentFrame.drop));
mCurrentFrame.dropCount = 0;
return false;
}
- }
- if (layer->blending == HWC_BLENDING_NONE)
- visibleRect = deductRect(visibleRect, res);
+ /* deduct any opaque region from visibleRect */
+ if (layer->blending == HWC_BLENDING_NONE)
+ visibleRect = deductRect(visibleRect, res);
+ }
}
return true;
}
@@ -528,6 +542,7 @@
hwc_display_contents_1_t* list){
const int numAppLayers = ctx->listStats[mDpy].numAppLayers;
+ int priDispW = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
if(sIdleFallBack && !ctx->listStats[mDpy].secureUI) {
ALOGD_IF(isDebug(), "%s: Idle fallback dpy %d",__FUNCTION__, mDpy);
@@ -541,6 +556,24 @@
return false;
}
+ if(mDpy > HWC_DISPLAY_PRIMARY && (priDispW > MAX_DISPLAY_DIM) &&
+ (ctx->dpyAttr[mDpy].xres < MAX_DISPLAY_DIM)) {
+ // Disable MDP comp on Secondary when the primary is highres panel and
+ // the secondary is a normal 1080p, because, MDP comp on secondary under
+ // in such usecase, decimation gets used for downscale and there will be
+ // a quality mismatch when there will be a fallback to GPU comp
+ ALOGD_IF(isDebug(), "%s: Disable MDP Compositon for Secondary Disp",
+ __FUNCTION__);
+ return false;
+ }
+
+ // check for action safe flag and downscale mode which requires scaling.
+ if(ctx->dpyAttr[mDpy].mActionSafePresent
+ || ctx->dpyAttr[mDpy].mDownScaleMode) {
+ ALOGD_IF(isDebug(), "%s: Scaling needed for this frame",__FUNCTION__);
+ return false;
+ }
+
for(int i = 0; i < numAppLayers; ++i) {
hwc_layer_1_t* layer = &list->hwLayers[i];
private_handle_t *hnd = (private_handle_t *)layer->handle;
@@ -706,7 +739,8 @@
int stagesForMDP = min(sMaxPipesPerMixer, ctx->mOverlay->availablePipes(
mDpy, Overlay::MIXER_DEFAULT));
//If MDP has X possible stages, it can take X layers.
- const int batchSize = numAppLayers - (stagesForMDP - 1); //1 for FB
+ const int batchSize = (numAppLayers - mCurrentFrame.dropCount) -
+ (stagesForMDP - 1); //1 for FB
if(batchSize <= 0) {
ALOGD_IF(isDebug(), "%s: Not attempting", __FUNCTION__);
@@ -714,20 +748,50 @@
}
int minBatchStart = -1;
+ int minBatchEnd = -1;
size_t minBatchPixelCount = SIZE_MAX;
- for(int i = 0; i <= numAppLayers - batchSize; i++) {
+ /* Iterate through the layer list to find out a contigous batch of batchSize
+ * non-dropped layers with loweest pixel count */
+ for(int i = 0; i <= (numAppLayers - batchSize); i++) {
+ if(mCurrentFrame.drop[i])
+ continue;
+
+ int batchCount = batchSize;
uint32_t batchPixelCount = 0;
- for(int j = i; j < i + batchSize; j++) {
- hwc_layer_1_t* layer = &list->hwLayers[j];
- hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);
- batchPixelCount += (crop.right - crop.left) *
+ int j = i;
+ for(; j < numAppLayers && batchCount; j++){
+ if(!mCurrentFrame.drop[j]) {
+ hwc_layer_1_t* layer = &list->hwLayers[j];
+ hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);
+ hwc_rect_t dst = layer->displayFrame;
+
+ /* If we have a valid ROI, count pixels only for the MDP fetched
+ * region of the buffer */
+ if((ctx->listStats[mDpy].roi.w != ctx->dpyAttr[mDpy].xres) ||
+ (ctx->listStats[mDpy].roi.h != ctx->dpyAttr[mDpy].yres)) {
+ hwc_rect_t roi;
+ roi.left = ctx->listStats[mDpy].roi.x;
+ roi.top = ctx->listStats[mDpy].roi.y;
+ roi.right = roi.left + ctx->listStats[mDpy].roi.w;
+ roi.bottom = roi.top + ctx->listStats[mDpy].roi.h;
+
+ /* valid ROI means no scaling layer is composed. So check
+ * only intersection to find actual fetched pixels */
+ crop = getIntersection(roi, dst);
+ }
+
+ batchPixelCount += (crop.right - crop.left) *
(crop.bottom - crop.top);
+ batchCount--;
+ }
}
- if(batchPixelCount < minBatchPixelCount) {
+ /* we dont want to program any batch of size lesser than batchSize */
+ if(!batchCount && (batchPixelCount < minBatchPixelCount)) {
minBatchPixelCount = batchPixelCount;
minBatchStart = i;
+ minBatchEnd = j-1;
}
}
@@ -737,8 +801,10 @@
return false;
}
+ /* non-dropped layers falling ouside the selected batch will be marked for
+ * MDP */
for(int i = 0; i < numAppLayers; i++) {
- if(i < minBatchStart || i >= minBatchStart + batchSize) {
+ if((i < minBatchStart || i > minBatchEnd) && !mCurrentFrame.drop[i] ) {
hwc_layer_1_t* layer = &list->hwLayers[i];
if(not isSupportedForMDPComp(ctx, layer)) {
ALOGD_IF(isDebug(), "%s: MDP unsupported layer found at %d",
@@ -752,10 +818,12 @@
mCurrentFrame.fbZ = minBatchStart;
mCurrentFrame.fbCount = batchSize;
- mCurrentFrame.mdpCount = mCurrentFrame.layerCount - batchSize;
+ mCurrentFrame.mdpCount = mCurrentFrame.layerCount - mCurrentFrame.fbCount -
+ mCurrentFrame.dropCount;
- ALOGD_IF(isDebug(), "%s: fbZ %d batchSize %d",
- __FUNCTION__, mCurrentFrame.fbZ, batchSize);
+ ALOGD_IF(isDebug(), "%s: fbZ %d batchSize %d fbStart: %d fbEnd: %d",
+ __FUNCTION__, mCurrentFrame.fbZ, batchSize, minBatchStart,
+ minBatchEnd);
if(sEnable4k2kYUVSplit){
adjustForSourceSplit(ctx, list);
@@ -789,7 +857,9 @@
const int fullScreenLayers = bwLeft * 1000000000 / (ctx->dpyAttr[mDpy].xres
* ctx->dpyAttr[mDpy].yres * bpp * panelRefRate);
- const int fbBatchSize = numAppLayers - (fullScreenLayers - 1);
+ const int fbBatchSize = (numAppLayers - mCurrentFrame.dropCount)
+ - (fullScreenLayers - 1);
+
//If batch size is not at least 2, we aren't really preferring MDP, since
//only 1 layer going to GPU could actually translate into an entire FB
//needed to be fetched by MDP, thus needing more b/w rather than less.
@@ -798,28 +868,43 @@
return false;
}
- //Top-most layers constitute FB batch
- const int fbBatchStart = numAppLayers - fbBatchSize;
+ //Find top fbBatchSize non-dropped layers to get your batch
+ int fbStart = -1, fbEnd = -1, batchCount = fbBatchSize;
+ for(int i = numAppLayers - 1; i >= 0; i--) {
+ if(mCurrentFrame.drop[i])
+ continue;
- //Bottom-most layers constitute MDP batch
- for(int i = 0; i < fbBatchStart; i++) {
- hwc_layer_1_t* layer = &list->hwLayers[i];
- if(not isSupportedForMDPComp(ctx, layer)) {
- ALOGD_IF(isDebug(), "%s: MDP unsupported layer found at %d",
- __FUNCTION__, i);
- reset(ctx);
- return false;
+ if(fbEnd < 0)
+ fbEnd = i;
+
+ if(!(--batchCount)) {
+ fbStart = i;
+ break;
}
- mCurrentFrame.isFBComposed[i] = false;
}
- mCurrentFrame.fbZ = fbBatchStart;
- mCurrentFrame.fbCount = fbBatchSize;
- mCurrentFrame.mdpCount = mCurrentFrame.layerCount - fbBatchSize;
+ //Bottom layers constitute MDP batch
+ for(int i = 0; i < fbStart; i++) {
+ if((i < fbStart || i > fbEnd) && !mCurrentFrame.drop[i] ) {
+ hwc_layer_1_t* layer = &list->hwLayers[i];
+ if(not isSupportedForMDPComp(ctx, layer)) {
+ ALOGD_IF(isDebug(), "%s: MDP unsupported layer found at %d",
+ __FUNCTION__, i);
+ reset(ctx);
+ return false;
+ }
+ mCurrentFrame.isFBComposed[i] = false;
+ }
+ }
- ALOGD_IF(isDebug(), "%s: FB Z %d, num app layers %d, MDP Batch Size %d",
- __FUNCTION__, mCurrentFrame.fbZ, numAppLayers,
- numAppLayers - fbBatchSize);
+ mCurrentFrame.fbZ = fbStart;
+ mCurrentFrame.fbCount = fbBatchSize;
+ mCurrentFrame.mdpCount = mCurrentFrame.layerCount - mCurrentFrame.fbCount
+ - mCurrentFrame.dropCount;
+
+ ALOGD_IF(isDebug(), "%s: FB Z %d, app layers %d, non-dropped layers: %d, "
+ "MDP Batch Size %d",__FUNCTION__, mCurrentFrame.fbZ, numAppLayers,
+ numAppLayers - mCurrentFrame.dropCount, mCurrentFrame.mdpCount);
if(sEnable4k2kYUVSplit){
adjustForSourceSplit(ctx, list);
@@ -955,11 +1040,13 @@
int& maxBatchCount) {
int i = 0;
int fbZOrder =-1;
+ int droppedLayerCt = 0;
while (i < mCurrentFrame.layerCount) {
int batchCount = 0;
int batchStart = i;
int batchEnd = i;
- int fbZ = batchStart;
+ /* Adjust batch Z order with the dropped layers so far */
+ int fbZ = batchStart - droppedLayerCt;
int firstZReverseIndex = -1;
int updatingLayersAbove = 0;//Updating layer count in middle of batch
while(i < mCurrentFrame.layerCount) {
@@ -974,6 +1061,7 @@
} else {
if(mCurrentFrame.drop[i]) {
i++;
+ droppedLayerCt++;
continue;
} else if(updatingLayersAbove <= 0) {
batchCount++;
@@ -1597,7 +1685,7 @@
/* reset Invalidator */
if(idleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount)
- idleInvalidator->markForSleep();
+ idleInvalidator->handleUpdateEvent();
overlay::Overlay& ov = *ctx->mOverlay;
LayerProp *layerProp = ctx->layerProp[mDpy];
@@ -1944,7 +2032,7 @@
/* reset Invalidator */
if(idleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount)
- idleInvalidator->markForSleep();
+ idleInvalidator->handleUpdateEvent();
overlay::Overlay& ov = *ctx->mOverlay;
LayerProp *layerProp = ctx->layerProp[mDpy];
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index 05a560b..bc41bd9 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -25,7 +25,7 @@
#include <cutils/properties.h>
#include <overlay.h>
-#define DEFAULT_IDLE_TIME 2000
+#define DEFAULT_IDLE_TIME 70
#define MAX_PIPES_PER_MIXER 4
namespace overlay {
@@ -45,7 +45,7 @@
virtual bool draw(hwc_context_t *ctx, hwc_display_contents_1_t *list) = 0;
/* dumpsys */
void dump(android::String8& buf);
-
+ bool isGLESOnlyComp() { return (mCurrentFrame.mdpCount == 0); }
static MDPComp* getObject(hwc_context_t *ctx, const int& dpy);
/* Handler to invoke frame redraw on Idle Timer expiry */
static void timeout_handler(void *udata);
diff --git a/libhwcomposer/hwc_qclient.cpp b/libhwcomposer/hwc_qclient.cpp
index 50e94c9..8c5b079 100644
--- a/libhwcomposer/hwc_qclient.cpp
+++ b/libhwcomposer/hwc_qclient.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-14, 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
@@ -31,11 +31,13 @@
#include <IQService.h>
#include <hwc_utils.h>
#include <hwc_vpuclient.h>
+#include <mdp_version.h>
#define QCLIENT_DEBUG 0
using namespace android;
using namespace qService;
+using namespace qhwc;
namespace qClient {
@@ -93,16 +95,19 @@
return result;
}
+#ifdef VPU_TARGET
static android::status_t vpuCommand(hwc_context_t *ctx,
uint32_t command,
const Parcel* inParcel,
Parcel* outParcel) {
status_t result = NO_INIT;
-#ifdef VPU_TARGET
- result = ctx->mVPUClient->processCommand(command, inParcel, outParcel);
+#ifdef QCOM_BSP
+ if(qdutils::MDPVersion::getInstance().is8092())
+ result = ctx->mVPUClient->processCommand(command, inParcel, outParcel);
#endif
return result;
}
+#endif
static void setExtOrientation(hwc_context_t *ctx, uint32_t orientation) {
ctx->mExtOrientation = orientation;
@@ -165,14 +170,27 @@
}
}
+static void pauseWFD(hwc_context_t *ctx, uint32_t pause) {
+ int dpy = HWC_DISPLAY_VIRTUAL;
+ if(pause) {
+ //WFD Pause
+ handle_pause(ctx, dpy);
+ } else {
+ //WFD Resume
+ handle_resume(ctx, dpy);
+ }
+}
+
status_t QClient::notifyCallback(uint32_t command, const Parcel* inParcel,
Parcel* outParcel) {
status_t ret = NO_ERROR;
+#ifdef VPU_TARGET
if (command > IQService::VPU_COMMAND_LIST_START &&
command < IQService::VPU_COMMAND_LIST_END) {
return vpuCommand(mHwcContext, command, inParcel, outParcel);
}
+#endif
switch(command) {
case IQService::SECURING:
@@ -202,6 +220,8 @@
break;
case IQService::SET_HSIC_DATA:
setHSIC(mHwcContext, inParcel);
+ case IQService::PAUSE_WFD:
+ pauseWFD(mHwcContext, inParcel->readInt32());
break;
default:
ret = NO_ERROR;
diff --git a/libhwcomposer/hwc_uevents.cpp b/libhwcomposer/hwc_uevents.cpp
index 51e5526..e51a1a4 100644
--- a/libhwcomposer/hwc_uevents.cpp
+++ b/libhwcomposer/hwc_uevents.cpp
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2010 The Android Open Source Project
- * Copyright (C) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2012-14, The Linux Foundation. All rights reserved.
*
* Not a Contribution, Apache license notifications and license are
* retained for attribution purposes only.
@@ -50,13 +50,6 @@
{
ctx->mFBUpdate[dpy] = IFBUpdate::getObject(ctx, dpy);
ctx->mMDPComp[dpy] = MDPComp::getObject(ctx, dpy);
- int compositionType =
- qdutils::QCCompositionType::getInstance().getCompositionType();
- if (compositionType & (qdutils::COMPOSITION_TYPE_DYN |
- qdutils::COMPOSITION_TYPE_MDP |
- qdutils::COMPOSITION_TYPE_C2D)) {
- ctx->mCopyBit[dpy] = new CopyBit(ctx, dpy);
- }
}
static void clear(hwc_context_t* ctx, int dpy)
@@ -65,10 +58,6 @@
delete ctx->mFBUpdate[dpy];
ctx->mFBUpdate[dpy] = NULL;
}
- if(ctx->mCopyBit[dpy]){
- delete ctx->mCopyBit[dpy];
- ctx->mCopyBit[dpy] = NULL;
- }
if(ctx->mMDPComp[dpy]) {
delete ctx->mMDPComp[dpy];
ctx->mMDPComp[dpy] = NULL;
@@ -117,6 +106,87 @@
return -1;
}
+void handle_pause(hwc_context_t* ctx, int dpy) {
+ {
+ Locker::Autolock _l(ctx->mDrawLock);
+ ctx->dpyAttr[dpy].isActive = true;
+ ctx->dpyAttr[dpy].isPause = true;
+ ctx->proc->invalidate(ctx->proc);
+ }
+ usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
+ * 2 / 1000);
+ // At this point all the pipes used by External have been
+ // marked as UNSET.
+ {
+ Locker::Autolock _l(ctx->mDrawLock);
+ // Perform commit to unstage the pipes.
+ if (!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
+ ALOGE("%s: display commit fail! for %d dpy",
+ __FUNCTION__, dpy);
+ }
+ }
+ return;
+}
+
+void handle_resume(hwc_context_t* ctx, int dpy) {
+ //Treat Resume as Online event
+ //Since external didnt have any pipes, force primary to give up
+ //its pipes; we don't allow inter-mixer pipe transfers.
+ {
+ Locker::Autolock _l(ctx->mDrawLock);
+
+ // A dynamic resolution change (DRC) can be made for a WiFi
+ // display. In order to support the resolution change, we
+ // need to reconfigure the corresponding display attributes.
+ // Since DRC is only on WiFi display, we only need to call
+ // configure() on the VirtualDisplay device.
+ if(dpy == HWC_DISPLAY_VIRTUAL)
+ ctx->mVirtualDisplay->configure();
+
+ ctx->dpyAttr[dpy].isConfiguring = true;
+ ctx->dpyAttr[dpy].isActive = true;
+ ctx->proc->invalidate(ctx->proc);
+ }
+ usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
+ * 2 / 1000);
+ //At this point external has all the pipes it would need.
+ {
+ Locker::Autolock _l(ctx->mDrawLock);
+ ctx->dpyAttr[dpy].isPause = false;
+ ctx->proc->invalidate(ctx->proc);
+ }
+ return;
+}
+
+static void teardownWfd(hwc_context_t* ctx) {
+ // Teardown WFD display
+ ALOGD_IF(UEVENT_DEBUG,"Received HDMI connection request when WFD is "
+ "active");
+ {
+ Locker::Autolock _l(ctx->mDrawLock);
+ clear(ctx, HWC_DISPLAY_VIRTUAL);
+ ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected = false;
+ ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = false;
+ }
+
+ ctx->mVirtualDisplay->teardown();
+
+ /* Need to send hotplug only when connected WFD in proprietary path */
+ if(ctx->mVirtualonExtActive) {
+ ALOGE_IF(UEVENT_DEBUG,"%s: Sending EXTERNAL OFFLINE"
+ "hotplug event for wfd display", __FUNCTION__);
+ ctx->proc->hotplug(ctx->proc, HWC_DISPLAY_EXTERNAL,
+ EXTERNAL_OFFLINE);
+ {
+ Locker::Autolock _l(ctx->mDrawLock);
+ ctx->mVirtualonExtActive = false;
+ }
+ }
+ /* Wait for few frames for SF to tear down the WFD session. */
+ usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
+ * 2 / 1000);
+}
+
static void handle_uevent(hwc_context_t* ctx, const char* udata, int len)
{
bool bpanelReset = getPanelResetStatus(ctx, udata, len);
@@ -196,33 +266,22 @@
if(dpy == HWC_DISPLAY_EXTERNAL) {
if(ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected) {
- ALOGD_IF(UEVENT_DEBUG,"Received HDMI connection request"
- "when WFD is active");
- {
- Locker::Autolock _l(ctx->mDrawLock);
- clear(ctx, HWC_DISPLAY_VIRTUAL);
- ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected = false;
- ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = false;
+ // Triple Display is supported on 8084 target
+ // WFD can be initiated by Wfd-client or Settings app
+ // 1. wfd-client use hdmi hotplug mechanism.
+ // If wfd is connected via wfd-client and if HDMI is
+ // connected, we have to teardown wfd session.
+ // (as SF support only one active External display
+ // at a given time).
+ // (ToDo: Once wfd-client migrates using virtual display
+ // apis, second condition is redundant).
+ // 2. Settings app use virtual display mechanism.
+ // In this approach, there is no limitation of supporting
+ // triple display.
+ if(!(qdutils::MDPVersion::getInstance().is8084() &&
+ !ctx->mVirtualonExtActive)) {
+ teardownWfd(ctx);
}
-
- ctx->mVirtualDisplay->teardown();
-
- /* Need to send hotplug only when connected WFD in
- * proprietary path */
- if(ctx->mVirtualonExtActive) {
- ALOGE_IF(UEVENT_DEBUG,"%s: Sending EXTERNAL OFFLINE"
- "hotplug event", __FUNCTION__);
- ctx->proc->hotplug(ctx->proc, HWC_DISPLAY_EXTERNAL,
- EXTERNAL_OFFLINE);
- {
- Locker::Autolock _l(ctx->mDrawLock);
- ctx->mVirtualonExtActive = false;
- }
- }
- /* Wait for few frames for SF to tear down
- * the WFD session. */
- usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
- * 2 / 1000);
}
ctx->mExtDisplay->configure();
} else {
@@ -267,25 +326,8 @@
case EXTERNAL_PAUSE:
{ // pause case
ALOGD("%s Received Pause event",__FUNCTION__);
- {
- Locker::Autolock _l(ctx->mDrawLock);
- ctx->dpyAttr[dpy].isActive = true;
- ctx->dpyAttr[dpy].isPause = true;
- ctx->proc->invalidate(ctx->proc);
- }
- usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
- * 2 / 1000);
- // At this point all the pipes used by External have been
- // marked as UNSET.
- {
- Locker::Autolock _l(ctx->mDrawLock);
- // Perform commit to unstage the pipes.
- if (!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
- ALOGE("%s: display commit fail! for %d dpy",
- __FUNCTION__, dpy);
- }
- }
- break;
+ handle_pause(ctx, dpy);
+ break;
}
case EXTERNAL_RESUME:
{ // resume case
@@ -293,29 +335,7 @@
//Treat Resume as Online event
//Since external didnt have any pipes, force primary to give up
//its pipes; we don't allow inter-mixer pipe transfers.
- {
- Locker::Autolock _l(ctx->mDrawLock);
-
- // A dynamic resolution change (DRC) can be made for a WiFi
- // display. In order to support the resolution change, we
- // need to reconfigure the corresponding display attributes.
- // Since DRC is only on WiFi display, we only need to call
- // configure() on the VirtualDisplay device.
- if(dpy == HWC_DISPLAY_VIRTUAL)
- ctx->mVirtualDisplay->configure();
-
- ctx->dpyAttr[dpy].isConfiguring = true;
- ctx->dpyAttr[dpy].isActive = true;
- ctx->proc->invalidate(ctx->proc);
- }
- usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
- * 2 / 1000);
- //At this point external has all the pipes it would need.
- {
- Locker::Autolock _l(ctx->mDrawLock);
- ctx->dpyAttr[dpy].isPause = false;
- ctx->proc->invalidate(ctx->proc);
- }
+ handle_resume(ctx, dpy);
break;
}
default:
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 0663f67..f6476f5 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2010 The Android Open Source Project
- * Copyright (C) 2012-2013, The Linux Foundation All rights reserved.
+ * Copyright (C) 2012-2014, The Linux Foundation All rights reserved.
*
* Not a Contribution, Apache license notifications and license are retained
* for attribution purposes only.
@@ -43,6 +43,7 @@
#include "hwc_qclient.h"
#include "QService.h"
#include "comptype.h"
+#include "hwc_virtual.h"
using namespace qClient;
using namespace qService;
@@ -53,6 +54,34 @@
namespace qhwc {
+bool isValidResolution(hwc_context_t *ctx, uint32_t xres, uint32_t yres)
+{
+ return !((xres > qdutils::MAX_DISPLAY_DIM &&
+ !isDisplaySplit(ctx, HWC_DISPLAY_PRIMARY)) ||
+ (xres < MIN_DISPLAY_XRES || yres < MIN_DISPLAY_YRES));
+}
+
+void changeResolution(hwc_context_t *ctx, int xres_orig, int yres_orig) {
+ //Store original display resolution.
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres_orig = xres_orig;
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres_orig = yres_orig;
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].customFBSize = false;
+
+ char property[PROPERTY_VALUE_MAX] = {'\0'};
+ char *yptr = NULL;
+ if (property_get("debug.hwc.fbsize", property, NULL) > 0) {
+ yptr = strcasestr(property,"x");
+ int xres = atoi(property);
+ int yres = atoi(yptr + 1);
+ if (isValidResolution(ctx,xres,yres) &&
+ xres != xres_orig && yres != yres_orig) {
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres = xres;
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres = yres;
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].customFBSize = true;
+ }
+ }
+}
+
static int openFramebufferDevice(hwc_context_t *ctx)
{
struct fb_fix_screeninfo finfo;
@@ -116,6 +145,9 @@
ctx->dpyAttr[HWC_DISPLAY_PRIMARY].ydpi = ydpi;
ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period = 1000000000l / fps;
+ //To change resolution of primary display
+ changeResolution(ctx, info.xres, info.yres);
+
//Unblank primary on first boot
if(ioctl(fb_fd, FBIOBLANK,FB_BLANK_UNBLANK) < 0) {
ALOGE("%s: Failed to unblank display", __FUNCTION__);
@@ -142,16 +174,18 @@
ctx->mFBUpdate[HWC_DISPLAY_PRIMARY] =
IFBUpdate::getObject(ctx, HWC_DISPLAY_PRIMARY);
- // Check if the target supports copybit compostion (dyn/mdp/c2d) to
+ // Check if the target supports copybit compostion (dyn/mdp) to
// decide if we need to open the copybit module.
int compositionType =
qdutils::QCCompositionType::getInstance().getCompositionType();
- if (compositionType & (qdutils::COMPOSITION_TYPE_DYN |
- qdutils::COMPOSITION_TYPE_MDP |
- qdutils::COMPOSITION_TYPE_C2D)) {
- ctx->mCopyBit[HWC_DISPLAY_PRIMARY] = new CopyBit(ctx,
- HWC_DISPLAY_PRIMARY);
+ // Only MDP copybit is used
+ if ((compositionType & (qdutils::COMPOSITION_TYPE_DYN |
+ qdutils::COMPOSITION_TYPE_MDP)) &&
+ (qdutils::MDPVersion::getInstance().getMDPVersion() ==
+ qdutils::MDP_V3_0_4)) {
+ ctx->mCopyBit[HWC_DISPLAY_PRIMARY] = new CopyBit(ctx,
+ HWC_DISPLAY_PRIMARY);
}
ctx->mExtDisplay = new ExternalDisplay(ctx);
@@ -168,11 +202,15 @@
ctx->mMDPComp[HWC_DISPLAY_PRIMARY] =
MDPComp::getObject(ctx, HWC_DISPLAY_PRIMARY);
ctx->dpyAttr[HWC_DISPLAY_PRIMARY].connected = true;
+ ctx->mHWCVirtual = HWCVirtualBase::getObject();
for (uint32_t i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) {
ctx->mHwcDebug[i] = new HwcDebug(i);
ctx->mLayerRotMap[i] = new LayerRotMap();
ctx->mAnimationState[i] = ANIMATION_STOPPED;
+ ctx->dpyAttr[i].mActionSafePresent = false;
+ ctx->dpyAttr[i].mAsWidthRatio = 0;
+ ctx->dpyAttr[i].mAsHeightRatio = 0;
}
MDPComp::init(ctx);
@@ -181,6 +219,7 @@
ctx->vstate.enable = false;
ctx->vstate.fakevsync = false;
ctx->mExtOrientation = 0;
+ ctx->numActiveDisplays = 1;
//Right now hwc starts the service but anybody could do it, or it could be
//independent process as well.
@@ -193,8 +232,11 @@
// Initialize device orientation to its default orientation
ctx->deviceOrientation = 0;
ctx->mBufferMirrorMode = false;
+ ctx->mVPUClient = NULL;
+
#ifdef VPU_TARGET
- ctx->mVPUClient = new VPUClient();
+ if(qdutils::MDPVersion::getInstance().is8092())
+ ctx->mVPUClient = new VPUClient(ctx);
#endif
ALOGI("Initializing Qualcomm Hardware Composer");
@@ -231,9 +273,8 @@
}
#ifdef VPU_TARGET
- if(ctx->mVPUClient) {
+ if(ctx->mVPUClient != NULL)
delete ctx->mVPUClient;
- }
#endif
for(int i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) {
@@ -254,6 +295,10 @@
ctx->mLayerRotMap[i] = NULL;
}
}
+ if(ctx->mHWCVirtual) {
+ delete ctx->mHWCVirtual;
+ ctx->mHWCVirtual = NULL;
+ }
if(ctx->mAD) {
delete ctx->mAD;
ctx->mAD = NULL;
@@ -285,22 +330,11 @@
int w = rect.right - rect.left;
int h = rect.bottom - rect.top;
- // if external supports underscan, do nothing
- // it will be taken care in the driver
- if(ctx->mExtDisplay->isCEUnderscanSupported())
+ if(!ctx->dpyAttr[dpy].mActionSafePresent)
return;
-
- char value[PROPERTY_VALUE_MAX];
- // Read action safe properties
- property_get("persist.sys.actionsafe.width", value, "0");
- int asWidthRatio = atoi(value);
- property_get("persist.sys.actionsafe.height", value, "0");
- int asHeightRatio = atoi(value);
-
- if(!asWidthRatio && !asHeightRatio) {
- //No action safe ratio set, return
- return;
- }
+ // Read action safe properties
+ int asWidthRatio = ctx->dpyAttr[dpy].mAsWidthRatio;
+ int asHeightRatio = ctx->dpyAttr[dpy].mAsHeightRatio;
float wRatio = 1.0;
float hRatio = 1.0;
@@ -433,8 +467,8 @@
xRatio = (inPos.x - viewFrame.left)/actualWidth;
yRatio = (inPos.y - viewFrame.top)/actualHeight;
// Use viewframe width and height to compute wRatio and hRatio.
- wRatio = inPos.w/(viewFrame.right - viewFrame.left);
- hRatio = inPos.h/(viewFrame.bottom - viewFrame.top);
+ wRatio = (float)inPos.w/(float)(viewFrame.right - viewFrame.left);
+ hRatio = (float)inPos.h/(float)(viewFrame.bottom - viewFrame.top);
//Calculate the position...
@@ -626,7 +660,6 @@
}
bool needsScaling(hwc_layer_1_t const* layer) {
int dst_w, dst_h, src_w, src_h;
-
hwc_rect_t displayFrame = layer->displayFrame;
hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
@@ -763,6 +796,7 @@
ctx->listStats[dpy].secureUI = false;
ctx->listStats[dpy].yuv4k2kCount = 0;
ctx->mViewFrame[dpy] = (hwc_rect_t){0, 0, 0, 0};
+ ctx->dpyAttr[dpy].mActionSafePresent = isActionSafePresent(ctx, dpy);
trimList(ctx, list, dpy);
optimizeLayerRects(ctx, list, dpy);
@@ -920,6 +954,27 @@
return false;
}
+// returns true if Action safe dimensions are set and target supports Actionsafe
+bool isActionSafePresent(hwc_context_t *ctx, int dpy) {
+ // if external supports underscan, do nothing
+ // it will be taken care in the driver
+ if(!dpy || ctx->mExtDisplay->isCEUnderscanSupported())
+ return false;
+
+ char value[PROPERTY_VALUE_MAX];
+ // Read action safe properties
+ property_get("persist.sys.actionsafe.width", value, "0");
+ ctx->dpyAttr[dpy].mAsWidthRatio = atoi(value);
+ property_get("persist.sys.actionsafe.height", value, "0");
+ ctx->dpyAttr[dpy].mAsHeightRatio = atoi(value);
+
+ if(!ctx->dpyAttr[dpy].mAsWidthRatio && !ctx->dpyAttr[dpy].mAsHeightRatio) {
+ //No action safe ratio set, return
+ return false;
+ }
+ return true;
+}
+
int getBlending(int blending) {
switch(blending) {
case HWC_BLENDING_NONE:
@@ -1078,7 +1133,8 @@
if(!needsScaling(&list->hwLayers[j])) {
hwc_layer_1_t* layer = (hwc_layer_1_t*)&list->hwLayers[j];
hwc_rect_t& bottomframe = layer->displayFrame;
- hwc_rect_t& bottomCrop = layer->sourceCrop;
+ hwc_rect_t bottomCrop =
+ integerizeSourceCrop(layer->sourceCropf);
int transform =layer->transform;
hwc_rect_t irect = getIntersection(bottomframe, topframe);
@@ -1088,7 +1144,11 @@
dest_rect = deductRect(bottomframe, irect);
qhwc::calculate_crop_rects(bottomCrop, bottomframe,
dest_rect, transform);
-
+ //Update layer sourceCropf
+ layer->sourceCropf.left = bottomCrop.left;
+ layer->sourceCropf.top = bottomCrop.top;
+ layer->sourceCropf.right = bottomCrop.right;
+ layer->sourceCropf.bottom = bottomCrop.bottom;
}
}
j--;
@@ -1123,12 +1183,19 @@
}
void closeAcquireFds(hwc_display_contents_1_t* list) {
- for(uint32_t i = 0; list && i < list->numHwLayers; i++) {
- //Close the acquireFenceFds
- //HWC_FRAMEBUFFER are -1 already by SF, rest we close.
- if(list->hwLayers[i].acquireFenceFd >= 0) {
- close(list->hwLayers[i].acquireFenceFd);
- list->hwLayers[i].acquireFenceFd = -1;
+ if(LIKELY(list)) {
+ for(uint32_t i = 0; i < list->numHwLayers; i++) {
+ //Close the acquireFenceFds
+ //HWC_FRAMEBUFFER are -1 already by SF, rest we close.
+ if(list->hwLayers[i].acquireFenceFd >= 0) {
+ close(list->hwLayers[i].acquireFenceFd);
+ list->hwLayers[i].acquireFenceFd = -1;
+ }
+ }
+ //Writeback
+ if(list->outbufAcquireFenceFd >= 0) {
+ close(list->outbufAcquireFenceFd);
+ list->outbufAcquireFenceFd = -1;
}
}
}
@@ -1140,6 +1207,7 @@
int acquireFd[MAX_NUM_APP_LAYERS];
int count = 0;
int releaseFd = -1;
+ int retireFd = -1;
int fbFd = -1;
bool swapzero = false;
int mdpVersion = qdutils::MDPVersion::getInstance().getMDPVersion();
@@ -1148,6 +1216,8 @@
memset(&data, 0, sizeof(data));
data.acq_fen_fd = acquireFd;
data.rel_fen_fd = &releaseFd;
+ data.retire_fen_fd = &retireFd;
+ data.flags = MDP_BUF_SYNC_FLAG_RETIRE_FENCE;
char property[PROPERTY_VALUE_MAX];
if(property_get("debug.egl.swapinterval", property, "1") > 0) {
@@ -1187,6 +1257,11 @@
}
//Accumulate acquireFenceFds for MDP
+ if(list->outbufAcquireFenceFd >= 0) {
+ //Writeback output buffer
+ acquireFd[count++] = list->outbufAcquireFenceFd;
+ }
+
for(uint32_t i = 0; i < list->numHwLayers; i++) {
if((list->hwLayers[i].compositionType == HWC_OVERLAY ||
list->hwLayers[i].compositionType == HWC_BLIT) &&
@@ -1229,6 +1304,7 @@
dpy, list->numHwLayers);
}
+ LayerProp *layerProp = ctx->layerProp[dpy];
for(uint32_t i = 0; i < list->numHwLayers; i++) {
if(list->hwLayers[i].compositionType == HWC_OVERLAY ||
list->hwLayers[i].compositionType == HWC_BLIT ||
@@ -1240,8 +1316,10 @@
// Release all the app layer fds immediately,
// if animation is in progress.
list->hwLayers[i].releaseFenceFd = -1;
- } else if(list->hwLayers[i].releaseFenceFd < 0) {
- //If rotator has not already populated this field.
+ } else if(list->hwLayers[i].releaseFenceFd < 0 &&
+ !(layerProp[i].mFlags & HWC_VPUCOMP)) {
+ //If rotator has not already populated this field
+ // & if it's a not VPU layer
list->hwLayers[i].releaseFenceFd = dup(releaseFd);
}
}
@@ -1257,20 +1335,14 @@
//Signals when MDP finishes reading rotator buffers.
ctx->mLayerRotMap[dpy]->setReleaseFd(releaseFd);
+ close(releaseFd);
+ releaseFd = -1;
- // if external is animating, close the relaseFd
- if(isExtAnimating) {
- close(releaseFd);
- releaseFd = -1;
- }
-
- if(UNLIKELY(swapzero)){
+ if(UNLIKELY(swapzero)) {
list->retireFenceFd = -1;
- close(releaseFd);
} else {
- list->retireFenceFd = releaseFd;
+ list->retireFenceFd = retireFd;
}
-
return ret;
}
@@ -1285,13 +1357,19 @@
ovutils::OV_MDP_BLEND_FG_PREMULT);
}
+ if (layer->flags & HWC_VPU_PIPE) {
+ ovutils::setMdpFlags(mdpFlags, ovutils::OV_MDP_VPU_PIPE);
+ }
+
if(isYuvBuffer(hnd)) {
if(isSecureBuffer(hnd)) {
ovutils::setMdpFlags(mdpFlags,
ovutils::OV_MDP_SECURE_OVERLAY_SESSION);
}
+ // in mpq, deinterlacing is done in vpu
if(metadata && (metadata->operation & PP_PARAM_INTERLACED) &&
- metadata->interlaced) {
+ metadata->interlaced &&
+ (!qdutils::MDPVersion::getInstance().is8092())) {
ovutils::setMdpFlags(mdpFlags,
ovutils::OV_MDP_DEINTERLACE);
}
@@ -1476,8 +1554,19 @@
eTransform orient = static_cast<eTransform>(transform);
int downscale = 0;
int rotFlags = ovutils::ROT_FLAGS_NONE;
- Whf whf(getWidth(hnd), getHeight(hnd),
- getMdpFormat(hnd->format), hnd->size);
+ uint32_t format = ovutils::getMdpFormat(hnd->format, isTileRendered(hnd));
+ Whf whf(getWidth(hnd), getHeight(hnd), format, hnd->size);
+ LayerProp *layerProp = ctx->layerProp[dpy];
+
+#ifdef VPU_TARGET
+ if(ctx->mVPUClient != NULL &&
+ ctx->mVPUClient->supportedVPULayer(dpy, layer)) {
+ whf.format = getMdpFormat(
+ ctx->mVPUClient->getLayerFormat(dpy, layer));
+ whf.w = ctx->mVPUClient->getWidth(dpy, layer);
+ whf.h = ctx->mVPUClient->getHeight(dpy, layer);
+ }
+#endif
// Handle R/B swap
if (layer->flags & HWC_FORMAT_RB_SWAP) {
@@ -1583,9 +1672,19 @@
eTransform orient = static_cast<eTransform>(transform);
const int downscale = 0;
int rotFlags = ROT_FLAGS_NONE;
+ uint32_t format = ovutils::getMdpFormat(hnd->format, isTileRendered(hnd));
+ Whf whf(getWidth(hnd), getHeight(hnd), format, hnd->size);
+ LayerProp *layerProp = ctx->layerProp[dpy];
- Whf whf(getWidth(hnd), getHeight(hnd),
- getMdpFormat(hnd->format), hnd->size);
+#ifdef VPU_TARGET
+ if(ctx->mVPUClient != NULL &&
+ ctx->mVPUClient->supportedVPULayer(dpy, layer)) {
+ whf.format = getMdpFormat(
+ ctx->mVPUClient->getLayerFormat(dpy, layer));
+ whf.w = ctx->mVPUClient->getWidth(dpy, layer);
+ whf.h = ctx->mVPUClient->getHeight(dpy, layer);
+ }
+#endif
// Handle R/B swap
if (layer->flags & HWC_FORMAT_RB_SWAP) {
@@ -1828,7 +1927,7 @@
bool canUseRotator(hwc_context_t *ctx, int dpy) {
if(qdutils::MDPVersion::getInstance().is8x26() &&
- ctx->mVirtualDisplay->isConnected() &&
+ isSecondaryConnected(ctx) &&
!ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isPause) {
/* 8x26 mdss driver supports multiplexing of DMA pipe
* in LINE and BLOCK modes for writeback panels.
@@ -1864,6 +1963,41 @@
return false;
}
+//clear prev layer prop flags and realloc for current frame
+void reset_layer_prop(hwc_context_t* ctx, int dpy, int numAppLayers) {
+ if(ctx->layerProp[dpy]) {
+ delete[] ctx->layerProp[dpy];
+ ctx->layerProp[dpy] = NULL;
+ }
+ ctx->layerProp[dpy] = new LayerProp[numAppLayers];
+}
+
+/* Since we fake non-Hybrid WFD solution as external display, this
+ * function helps us in determining the priority between external
+ * (hdmi/non-Hybrid WFD display) and virtual display devices(SSD/
+ * screenrecord). This can be removed once wfd-client migrates to
+ * using virtual-display api's.
+ */
+bool canUseMDPforVirtualDisplay(hwc_context_t* ctx,
+ const hwc_display_contents_1_t *list) {
+
+ /* We rely on the fact that for pure virtual display solution
+ * list->outbuf will be a non-NULL handle.
+ *
+ * If there are three active displays (which means there is one
+ * primary, one external and one virtual active display)
+ * we give mdss/mdp hw resources(pipes,smp,etc) for external
+ * display(hdmi/non-Hybrid WFD display) rather than for virtual
+ * display(SSD/screenrecord)
+ */
+
+ if(list->outbuf and (ctx->numActiveDisplays == HWC_NUM_DISPLAY_TYPES)) {
+ return false;
+ }
+
+ return true;
+}
+
void BwcPM::setBwc(hwc_context_t *ctx, const hwc_rect_t& crop,
const hwc_rect_t& dst, const int& transform,
ovutils::eMdpFlags& mdpFlags) {
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index cd84f73..ce1abeb 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2010 The Android Open Source Project
- * Copyright (C)2012-2013, The Linux Foundation. All rights reserved.
+ * Copyright (C)2012-2014, The Linux Foundation. All rights reserved.
*
* Not a Contribution, Apache license notifications and license are retained
* for attribution purposes only.
@@ -35,6 +35,8 @@
#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
#define MAX_NUM_APP_LAYERS 32
+#define MIN_DISPLAY_XRES 200
+#define MIN_DISPLAY_YRES 200
//Fwrd decls
struct hwc_context_t;
@@ -59,6 +61,7 @@
class HwcDebug;
class AssertiveDisplay;
class VPUClient;
+class HWCVirtualBase;
struct MDPInfo {
@@ -89,6 +92,18 @@
bool mDownScaleMode;
// Ext dst Rect
hwc_rect_t mDstRect;
+ //Action safe attributes
+ // Flag to indicate the presence of action safe dimensions for external
+ bool mActionSafePresent;
+ int mAsWidthRatio;
+ int mAsHeightRatio;
+
+ //If property fbsize set via adb shell debug.hwc.fbsize = XRESxYRES
+ //following fields are used.
+ bool customFBSize;
+ uint32_t xres_orig;
+ uint32_t yres_orig;
+
};
struct ListStats {
@@ -130,12 +145,14 @@
enum {
HWC_MDPCOMP = 0x00000001,
HWC_COPYBIT = 0x00000002,
+ HWC_VPUCOMP = 0x00000004,
};
// HAL specific features
enum {
HWC_COLOR_FILL = 0x00000008,
HWC_FORMAT_RB_SWAP = 0x00000040,
+ HWC_VPU_PIPE = 0x00000200,
};
class LayerRotMap {
@@ -216,6 +233,11 @@
bool isAlphaPresent(hwc_layer_1_t const* layer);
int hwc_vsync_control(hwc_context_t* ctx, int dpy, int enable);
int getBlending(int blending);
+bool isGLESOnlyComp(hwc_context_t *ctx, const int& dpy);
+void reset_layer_prop(hwc_context_t* ctx, int dpy, int numAppLayers);
+
+bool canUseMDPforVirtualDisplay(hwc_context_t* ctx,
+ const hwc_display_contents_1_t *list);
//Helper function to dump logs
void dumpsys_log(android::String8& buf, const char* fmt, ...);
@@ -230,6 +252,9 @@
bool areLayersIntersecting(const hwc_layer_1_t* layer1,
const hwc_layer_1_t* layer2);
+// returns true if Action safe dimensions are set and target supports Actionsafe
+bool isActionSafePresent(hwc_context_t *ctx, int dpy);
+
/* Calculates the destination position based on the action safe rectangle */
void getActionSafePosition(hwc_context_t *ctx, int dpy, hwc_rect_t& dst);
@@ -255,6 +280,10 @@
// BufferMirrirMode(Sidesync)
int getMirrorModeOrientation(hwc_context_t *ctx);
+// Handles wfd Pause and resume events
+void handle_pause(hwc_context_t *ctx, int dpy);
+void handle_resume(hwc_context_t *ctx, int dpy);
+
//Close acquireFenceFds of all layers of incoming list
void closeAcquireFds(hwc_display_contents_1_t* list);
@@ -334,6 +363,11 @@
static inline bool isSecureBuffer(const private_handle_t* hnd) {
return (hnd && (private_handle_t::PRIV_FLAGS_SECURE_BUFFER & hnd->flags));
}
+
+static inline bool isTileRendered(const private_handle_t* hnd) {
+ return (hnd && (private_handle_t::PRIV_FLAGS_TILE_RENDERED & hnd->flags));
+}
+
//Return true if buffer is marked locked
static inline bool isBufferLocked(const private_handle_t* hnd) {
return (hnd && (private_handle_t::PRIV_FLAGS_HWC_LOCK & hnd->flags));
@@ -448,6 +482,7 @@
qhwc::AssertiveDisplay *mAD;
qhwc::VPUClient *mVPUClient;
eAnimationState mAnimationState[HWC_NUM_DISPLAY_TYPES];
+ qhwc::HWCVirtualBase *mHWCVirtual;
// stores the primary device orientation
int deviceOrientation;
@@ -465,15 +500,14 @@
int mExtOrientation;
//Flags the transition of a video session
bool mVideoTransFlag;
-
//Used for SideSync feature
//which overrides the mExtOrientation
bool mBufferMirrorMode;
-
qhwc::LayerRotMap *mLayerRotMap[HWC_NUM_DISPLAY_TYPES];
-
// Panel reset flag will be set if BTA check fails
bool mPanelResetStatus;
+ // number of active Displays
+ int numActiveDisplays;
};
namespace qhwc {
@@ -494,6 +528,16 @@
return ctx->listStats[dpy].isSecurePresent;
}
+static inline bool isSecondaryConfiguring(hwc_context_t* ctx) {
+ return (ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isConfiguring ||
+ ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isConfiguring);
+}
+
+static inline bool isSecondaryConnected(hwc_context_t* ctx) {
+ return (ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected ||
+ ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected);
+}
+
};
#endif //HWC_UTILS_H
diff --git a/libhwcomposer/hwc_virtual.cpp b/libhwcomposer/hwc_virtual.cpp
new file mode 100644
index 0000000..600ba8d
--- /dev/null
+++ b/libhwcomposer/hwc_virtual.cpp
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2012-2014, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <fcntl.h>
+#include <errno.h>
+
+#include <cutils/log.h>
+#include <utils/Trace.h>
+#include <overlayWriteback.h>
+#include "hwc_utils.h"
+#include "hwc_fbupdate.h"
+#include "hwc_mdpcomp.h"
+#include "hwc_dump_layers.h"
+#include "hwc_copybit.h"
+#include "hwc_virtual.h"
+
+#define HWCVIRTUAL_LOG 0
+
+using namespace qhwc;
+using namespace overlay;
+
+HWCVirtualBase* HWCVirtualBase::getObject() {
+ char property[PROPERTY_VALUE_MAX];
+
+ if((property_get("persist.hwc.enable_vds", property, NULL) > 0)) {
+ if(atoi(property) != 0) {
+ ALOGD_IF(HWCVIRTUAL_LOG, "%s: VDS is enabled for Virtual display",
+ __FUNCTION__);
+ return new HWCVirtualVDS();
+ }
+ }
+ ALOGD_IF(HWCVIRTUAL_LOG, "%s: V4L2 is enabled for Virtual display",
+ __FUNCTION__);
+ return new HWCVirtualV4L2();
+}
+
+void HWCVirtualVDS::init(hwc_context_t *ctx) {
+ const int dpy = HWC_DISPLAY_VIRTUAL;
+ ctx->mFBUpdate[dpy] =
+ IFBUpdate::getObject(ctx, dpy);
+ ctx->mMDPComp[dpy] = MDPComp::getObject(ctx, dpy);
+
+ if(ctx->mFBUpdate[dpy])
+ ctx->mFBUpdate[dpy]->reset();
+ if(ctx->mMDPComp[dpy])
+ ctx->mMDPComp[dpy]->reset();
+}
+
+void HWCVirtualVDS::destroy(hwc_context_t *ctx, size_t numDisplays,
+ hwc_display_contents_1_t** displays) {
+ int dpy = HWC_DISPLAY_VIRTUAL;
+
+ //Cleanup virtual display objs, since there is no explicit disconnect
+ if(ctx->dpyAttr[dpy].connected && (displays[dpy] == NULL)) {
+ ctx->dpyAttr[dpy].connected = false;
+
+ if(ctx->mFBUpdate[dpy]) {
+ delete ctx->mFBUpdate[dpy];
+ ctx->mFBUpdate[dpy] = NULL;
+ }
+ if(ctx->mMDPComp[dpy]) {
+ delete ctx->mMDPComp[dpy];
+ ctx->mMDPComp[dpy] = NULL;
+ }
+ }
+}
+
+int HWCVirtualVDS::prepare(hwc_composer_device_1 *dev,
+ hwc_display_contents_1_t *list) {
+ ATRACE_CALL();
+ //XXX: Fix when framework support is added
+ hwc_context_t* ctx = (hwc_context_t*)(dev);
+ const int dpy = HWC_DISPLAY_VIRTUAL;
+
+ if (list && list->outbuf && list->numHwLayers > 0) {
+ reset_layer_prop(ctx, dpy, list->numHwLayers - 1);
+ uint32_t last = list->numHwLayers - 1;
+ hwc_layer_1_t *fbLayer = &list->hwLayers[last];
+ int fbWidth = 0, fbHeight = 0;
+ getLayerResolution(fbLayer, fbWidth, fbHeight);
+ ctx->dpyAttr[dpy].xres = fbWidth;
+ ctx->dpyAttr[dpy].yres = fbHeight;
+
+ if(ctx->dpyAttr[dpy].connected == false) {
+ ctx->dpyAttr[dpy].connected = true;
+ init(ctx);
+ //First round, just setup and return so primary can free pipes
+ return 0;
+ }
+
+ ctx->dpyAttr[dpy].isConfiguring = false;
+ ctx->dpyAttr[dpy].fd = Writeback::getInstance()->getFbFd();
+ private_handle_t *ohnd = (private_handle_t *)list->outbuf;
+ Writeback::getInstance()->configureDpyInfo(ohnd->width, ohnd->height);
+ setListStats(ctx, list, dpy);
+
+ if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
+ const int fbZ = 0;
+ ctx->mFBUpdate[dpy]->prepare(ctx, list, fbZ);
+ }
+ }
+ return 0;
+}
+
+int HWCVirtualVDS::set(hwc_context_t *ctx, hwc_display_contents_1_t *list) {
+ ATRACE_CALL();
+ int ret = 0;
+ const int dpy = HWC_DISPLAY_VIRTUAL;
+
+ if (list && list->outbuf && list->numHwLayers > 0) {
+ uint32_t last = list->numHwLayers - 1;
+ hwc_layer_1_t *fbLayer = &list->hwLayers[last];
+
+ if(fbLayer->handle && !isSecondaryConfiguring(ctx) &&
+ !ctx->mMDPComp[dpy]->isGLESOnlyComp()) {
+ private_handle_t *ohnd = (private_handle_t *)list->outbuf;
+ int format = ohnd->format;
+ if (format == HAL_PIXEL_FORMAT_RGBA_8888)
+ format = HAL_PIXEL_FORMAT_RGBX_8888;
+ Writeback::getInstance()->setOutputFormat(
+ utils::getMdpFormat(format));
+
+ int fd = -1; //FenceFD from the Copybit
+ hwc_sync(ctx, list, dpy, fd);
+
+ if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
+ ALOGE("%s: MDPComp draw failed", __FUNCTION__);
+ ret = -1;
+ }
+ if (!ctx->mFBUpdate[dpy]->draw(ctx,
+ (private_handle_t *)fbLayer->handle)) {
+ ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
+ ret = -1;
+ }
+
+ Writeback::getInstance()->queueBuffer(ohnd->fd, ohnd->offset);
+ if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
+ ALOGE("%s: display commit fail!", __FUNCTION__);
+ ret = -1;
+ }
+
+ } else if(list->outbufAcquireFenceFd >= 0) {
+ //If we dont handle the frame, set retireFenceFd to outbufFenceFd,
+ //which will make sure, the framework waits on it and closes it.
+ //The other way is to wait on outbufFenceFd ourselves, close it and
+ //set retireFenceFd to -1. Since we want hwc to be async, choosing
+ //the former.
+ //Also dup because, the closeAcquireFds() will close the outbufFence
+ list->retireFenceFd = dup(list->outbufAcquireFenceFd);
+ }
+ }
+
+ closeAcquireFds(list);
+ return ret;
+}
+
+/* Implementation for HWCVirtualV4L2 class */
+
+int HWCVirtualV4L2::prepare(hwc_composer_device_1 *dev,
+ hwc_display_contents_1_t *list) {
+ ATRACE_CALL();
+
+ hwc_context_t* ctx = (hwc_context_t*)(dev);
+ const int dpy = HWC_DISPLAY_VIRTUAL;
+
+ if (LIKELY(list && list->numHwLayers > 1) &&
+ ctx->dpyAttr[dpy].isActive &&
+ ctx->dpyAttr[dpy].connected &&
+ canUseMDPforVirtualDisplay(ctx,list)) {
+ reset_layer_prop(ctx, dpy, list->numHwLayers - 1);
+ if(!ctx->dpyAttr[dpy].isPause) {
+ ctx->dpyAttr[dpy].isConfiguring = false;
+ setListStats(ctx, list, dpy);
+ if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
+ const int fbZ = 0;
+ ctx->mFBUpdate[dpy]->prepare(ctx, list, fbZ);
+ }
+ } else {
+ /* Virtual Display is in Pause state.
+ * Mark all application layers as OVERLAY so that
+ * GPU will not compose.
+ */
+ for(size_t i = 0 ;i < (size_t)(list->numHwLayers - 1); i++) {
+ hwc_layer_1_t *layer = &list->hwLayers[i];
+ layer->compositionType = HWC_OVERLAY;
+ }
+ }
+ }
+ return 0;
+}
+
+int HWCVirtualV4L2::set(hwc_context_t *ctx, hwc_display_contents_1_t *list) {
+ ATRACE_CALL();
+ int ret = 0;
+
+ const int dpy = HWC_DISPLAY_VIRTUAL;
+
+ if (LIKELY(list) && ctx->dpyAttr[dpy].isActive &&
+ ctx->dpyAttr[dpy].connected &&
+ (!ctx->dpyAttr[dpy].isPause) &&
+ canUseMDPforVirtualDisplay(ctx,list)) {
+ uint32_t last = list->numHwLayers - 1;
+ hwc_layer_1_t *fbLayer = &list->hwLayers[last];
+ int fd = -1; //FenceFD from the Copybit(valid in async mode)
+ bool copybitDone = false;
+ if(ctx->mCopyBit[dpy])
+ copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd);
+
+ if(list->numHwLayers > 1)
+ hwc_sync(ctx, list, dpy, fd);
+
+ // Dump the layers for virtual
+ if(ctx->mHwcDebug[dpy])
+ ctx->mHwcDebug[dpy]->dumpLayers(list);
+
+ if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
+ ALOGE("%s: MDPComp draw failed", __FUNCTION__);
+ ret = -1;
+ }
+
+ int extOnlyLayerIndex =
+ ctx->listStats[dpy].extOnlyLayerIndex;
+
+ private_handle_t *hnd = (private_handle_t *)fbLayer->handle;
+ if(extOnlyLayerIndex!= -1) {
+ hwc_layer_1_t *extLayer = &list->hwLayers[extOnlyLayerIndex];
+ hnd = (private_handle_t *)extLayer->handle;
+ } else if(copybitDone) {
+ hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer();
+ }
+
+ if(hnd && !isYuvBuffer(hnd)) {
+ if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) {
+ ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
+ ret = -1;
+ }
+ }
+
+ if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
+ ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy);
+ ret = -1;
+ }
+ }
+
+ closeAcquireFds(list);
+
+ if (list && !ctx->mVirtualonExtActive && (list->retireFenceFd < 0) ) {
+ // SF assumes HWC waits for the acquire fence and returns a new fence
+ // that signals when we're done. Since we don't wait, and also don't
+ // touch the buffer, we can just handle the acquire fence back to SF
+ // as the retire fence.
+ list->retireFenceFd = list->outbufAcquireFenceFd;
+ }
+
+ return ret;
+}
diff --git a/libhwcomposer/hwc_virtual.h b/libhwcomposer/hwc_virtual.h
new file mode 100644
index 0000000..502aa3b
--- /dev/null
+++ b/libhwcomposer/hwc_virtual.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2012-2014, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HWC_VIRTUAL
+#define HWC_VIRTUAL
+
+#include <hwc_utils.h>
+
+namespace qhwc {
+namespace ovutils = overlay::utils;
+
+// Base and abstract class for VDS and V4L2 wfd design.
+class HWCVirtualBase {
+public:
+ explicit HWCVirtualBase(){};
+ virtual ~HWCVirtualBase(){};
+ // instantiates and returns the pointer to VDS or V4L2 object.
+ static HWCVirtualBase* getObject();
+ virtual int prepare(hwc_composer_device_1 *dev,
+ hwc_display_contents_1_t* list) = 0;
+ virtual int set(hwc_context_t *ctx, hwc_display_contents_1_t *list) = 0;
+ virtual void init(hwc_context_t *ctx) = 0;
+ virtual void destroy(hwc_context_t *ctx, size_t numDisplays,
+ hwc_display_contents_1_t** displays) = 0;
+};
+
+class HWCVirtualVDS : public HWCVirtualBase {
+public:
+ explicit HWCVirtualVDS(){};
+ virtual ~HWCVirtualVDS(){};
+ // Chooses composition type and configures pipe for each layer in virtual
+ // display list
+ virtual int prepare(hwc_composer_device_1 *dev,
+ hwc_display_contents_1_t* list);
+ // Queues the buffer for each layer in virtual display list and call display
+ // commit.
+ virtual int set(hwc_context_t *ctx, hwc_display_contents_1_t *list);
+ // instantiates mdpcomp, copybit and fbupdate objects and initialize those
+ // objects for virtual display during virtual display connect.
+ virtual void init(hwc_context_t *ctx);
+ // Destroys mdpcomp, copybit and fbupdate objects and for virtual display
+ // during virtual display disconnect.
+ virtual void destroy(hwc_context_t *ctx, size_t numDisplays,
+ hwc_display_contents_1_t** displays);
+};
+
+class HWCVirtualV4L2 : public HWCVirtualBase {
+public:
+ explicit HWCVirtualV4L2(){};
+ virtual ~HWCVirtualV4L2(){};
+ // Chooses composition type and configures pipe for each layer in virtual
+ // display list
+ virtual int prepare(hwc_composer_device_1 *dev,
+ hwc_display_contents_1_t* list);
+ // Queues the buffer for each layer in virtual display list and call
+ // display commit.
+ virtual int set(hwc_context_t *ctx, hwc_display_contents_1_t *list);
+ // instantiates mdpcomp, copybit and fbupdate objects and initialize those
+ // objects for virtual display during virtual display connect. This function
+ // is no-op for V4L2 design
+ virtual void init(hwc_context_t *ctx) {};
+ // Destroys mdpcomp, copybit and fbupdate objects and for virtual display
+ // during virtual display disconnect. This function is no-op for V4L2 design
+ virtual void destroy(hwc_context_t *ctx, size_t numDisplays,
+ hwc_display_contents_1_t** displays){};
+};
+
+}; //namespace
+#endif
diff --git a/libhwcomposer/hwc_vpuclient.cpp b/libhwcomposer/hwc_vpuclient.cpp
index 23c6841..6904efc 100644
--- a/libhwcomposer/hwc_vpuclient.cpp
+++ b/libhwcomposer/hwc_vpuclient.cpp
@@ -1,93 +1,964 @@
/*
-* Copyright (c) 2013 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:
-* * Redistributions of source code must retain the above copyright
-* notice, this list of conditions and the following disclaimer.
-* * Redistributions in binary form must reproduce the above
-* copyright notice, this list of conditions and the following
-* disclaimer in the documentation and/or other materials provided
-* with the distribution.
-* * Neither the name of The Linux Foundation. nor the names of its
-* contributors may be used to endorse or promote products derived
-* from this software without specific prior written permission.
-*
-* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
-* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
-* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
-* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
-* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
-* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
+ * Copyright (c) 2013-2014 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:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. INNO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER INCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING INANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
#include <dlfcn.h>
#include "hwc_vpuclient.h"
-#include "hwc_utils.h"
-#include <vpu/vpu.h>
#include <binder/Parcel.h>
-
+#include "hwc_fbupdate.h"
+#include <vpu/vpu.h>
using namespace vpu;
using namespace android;
+using namespace overlay::utils;
+namespace ovutils = overlay::utils;
+
namespace qhwc {
-VPUClient::VPUClient()
+VPUClient::VPUClient(hwc_context_t *ctx)
{
mVPULib = dlopen("libvpu.so", RTLD_NOW);
- VPU* (*init)();
- *(void **) &init = dlsym(mVPULib, "getObject");
- if(init)
- mVPU = init();
- else
- mVPU = NULL;
+ VPU* (*getObject)();
+
+ mVPU = NULL;
+ if (mVPULib == NULL) {
+ ALOGE("%s: Cannot open libvpu.so object", __FUNCTION__);
+ return;
+ }
+
+ *(void **) &getObject = dlsym(mVPULib, "getObject");
+ if (getObject) {
+ mVPU = getObject();
+ ALOGI("Initializing VPU client..");
+
+ // calling vpu init
+ if (mVPU->init() == NO_ERROR) {
+ // passing display attributes to libvpu
+ ALOGD_IF(isDebug(), "%s: VFM init successful!", __FUNCTION__);
+
+ DispAttr_t attr;
+ attr.width = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
+ attr.height = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres;
+ attr.fp100s = (ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period) ?
+ 1000000000/(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period/100):0;
+ mVPU->setDisplayAttr((DISPLAY_ID)HWC_DISPLAY_PRIMARY, attr);
+
+ ALOGD_IF(isDebug(),"%s: Display attr: width:%d height:%d fp100s:%d",
+ __FUNCTION__, attr.width, attr.height, attr.fp100s);
+
+ // memsetting the pipe structure to 0
+ memset(mProp, 0, sizeof(mProp));
+
+ mDebugLogs = 0;
+ // enable logs
+ char property[PROPERTY_VALUE_MAX];
+ if ( property_get("debug.vpuclient.logs", property, NULL) > 0 )
+ mDebugLogs = atoi(property);
+
+ // allocating memory for LayerList
+ for (int i = 0; i < HWC_NUM_DISPLAY_TYPES; ++i)
+ vList[i] = (LayerList*) malloc(sizeof(LayerList));
+ }
+ else {
+ ALOGE("Error: VPU init failed!");
+ mVPU = NULL;
+ }
+ }
}
VPUClient::~VPUClient()
{
+ // freeing LayerList
+ for (int i = 0; i < HWC_NUM_DISPLAY_TYPES; ++i) {
+ if (vList[i])
+ free(vList[i]);
+ }
+
void (*destroy) (VPU*);
*(void **) &destroy = dlsym(mVPULib, "deleteObject");
dlclose(mVPULib);
}
-int VPUClient::prepare(hwc_context_t *ctx,
- hwc_display_contents_1_t* list)
+void setLayer(hwc_layer_1_t *layer, Layer *vLayer)
{
- int err = 0;
- if(!mVPU)
- return err;
- // * Check VPU status
- // * Check session availability
- // * Other individual checks
- // Do not pass hwc context/list
- // Mark buffers to be drawn for VPU
- return err;
+ // setting handle info in vLayer
+ vLayer->handle = (private_handle_t *)(layer->handle);
+
+ if (vLayer->handle) {
+ vLayer->srcStride.width = getWidth(vLayer->handle);
+ vLayer->srcStride.height = getHeight(vLayer->handle);
+ }
+
+ // setting source crop
+ hwc_rect_t sourceRect = integerizeSourceCrop(layer->sourceCropf);
+ vLayer->srcRect.left = sourceRect.left;
+ vLayer->srcRect.top = sourceRect.top;
+ vLayer->srcRect.right = sourceRect.right;
+ vLayer->srcRect.bottom = sourceRect.bottom;
+
+ // setting destination crop
+ vLayer->tgtRect.left = layer->displayFrame.left;
+ vLayer->tgtRect.top = layer->displayFrame.top;
+ vLayer->tgtRect.right = layer->displayFrame.right;
+ vLayer->tgtRect.bottom = layer->displayFrame.bottom;
+
+ if (layer->flags & HWC_GEOMETRY_CHANGED)
+ vLayer->inFlags |= GEOMETRY_CHANGED;
+
+ vLayer->acquireFenceFd = layer->acquireFenceFd;
+
+ if (layer->compositionType == HWC_FRAMEBUFFER_TARGET || isSkipLayer(layer))
+ vLayer->inFlags |= SKIP_LAYER;
}
-int VPUClient::draw(hwc_context_t *ctx,
- hwc_display_contents_1_t* list)
+int VPUClient::setupVpuSession(hwc_context_t *ctx, int display,
+ hwc_display_contents_1_t* list)
+{
+ memset(vList[display], 0, sizeof(LayerList));
+ memset(mProp, 0, sizeof(mProp));
+ mNumVpuLayers = 0;
+
+ // setting up the layer
+ LayerList *vpuList = vList[display];
+ vpuList->numLayers = list->numHwLayers;
+ for (unsigned int i=0; i<(list->numHwLayers); ++i) {
+ hwc_layer_1_t *layer = &list->hwLayers[i];
+ Layer *vLayer = &vpuList->layers[i];
+ VpuLayerProp* prop = &mProp[display][i];
+
+ // Storing the sourceCropf, as it's going to be changed for overlay Set
+ // will be restored after overlay set in prepare.
+ prop->sourceCropf = layer->sourceCropf;
+
+ // filling up the vpu list
+ setLayer(layer, vLayer);
+ ALOGD_IF(isDebug2(), "%s:Done setting lyr:%d for VFM", __FUNCTION__, i);
+ }
+
+ if (mVPU->setupVpuSession((DISPLAY_ID)display, vpuList) != NO_ERROR) {
+ //error in vpu prepare
+ ALOGE("%s: ERROR in VPU::setupVpuSession", __FUNCTION__);
+ return -1;
+ }
+ ALOGD_IF(isDebug2(), "%s: Done VFM: setupVpuSession", __FUNCTION__);
+
+ mGpuFallback = true;
+ LayerProp *layerProp = ctx->layerProp[display];
+ // check if the pipeID is already set for this layer, then will need to
+ // ensure that it is reserved in overlay
+ for (unsigned int i=0; i<(vpuList->numLayers); ++i) {
+ hwc_layer_1_t *layer = &list->hwLayers[i];
+ Layer *vLayer = &vpuList->layers[i];
+ VpuLayerProp* prop = &mProp[display][i];
+
+ if (vLayer->outFlags & VPU_LAYER) {
+ ALOGD_IF(isDebug(), "%s: VPU supported layer:%d", __FUNCTION__, i);
+
+ mNumVpuLayers++;
+ mGpuFallback = false;
+ // Reserving the pipe used in last iteration for the same layer
+ if ((vLayer->outFlags & RESERVE_PREV_PIPES) &&
+ vLayer->sDestPipes.numPipes > 0) {
+ prop->pipeCount = vLayer->sDestPipes.numPipes;
+ if (prop->pipeCount == 1) {
+ setPipeId(prop, vLayer->sDestPipes.pipe[0]);
+ ALOGD_IF(isDebug(), "%s: VPU: Reserved pipe:%d",
+ __FUNCTION__, prop->pipeID[0]);
+ }
+ else if (prop->pipeCount == 2) {
+ setPipeId(prop, vLayer->sDestPipes.pipe[0],
+ vLayer->sDestPipes.pipe[1]);
+ ALOGD_IF(isDebug(), "%s: VPU: Reserved lpipe:%d, rpipe:%d",
+ __FUNCTION__, prop->pipeID[0], prop->pipeID[1]);
+ }
+ else {
+ ALOGE("%s: Invalid pipeCount for resevation", __FUNCTION__);
+ }
+ }
+ else {
+ ALOGD_IF(isDebug(), "%s: 1st vid frame for VPU", __FUNCTION__);
+ prop->firstBuffer = true;
+ }
+
+ // marking the layer pipes for vpu.
+ prop->vpuLayer = true;
+ prop->layer = layer;
+ layer->flags |= HWC_VPU_PIPE;
+
+ // getting image width and height
+ prop->width = layer->displayFrame.right - layer->displayFrame.left;
+ prop->height = layer->displayFrame.bottom - layer->displayFrame.top;
+
+ //setting source crop = dest crop (only for layers drawn by vpu,
+ // since we know it will be scaled up/down by vpu)
+ layer->sourceCropf.left = 0.0;
+ layer->sourceCropf.top = 0.0;
+ layer->sourceCropf.right = (float) prop->width;
+ layer->sourceCropf.bottom = (float) prop->height;
+
+ // setting the flag so that mdpComp wont recognize it as the MDPCOMP
+ layerProp[i].mFlags |= HWC_VPUCOMP;
+
+ // TODO: need to get the proper solution for color fill
+
+ // storing locally the vpu supported format from VFM
+ prop->format = vLayer->vpuOutPixFmt;
+ ALOGD_IF(isDebug(), "%s: MDP: sourceCropf: w:%d h:%d format:%d",
+ __FUNCTION__, prop->width, prop->height, prop->format);
+ }
+ }
+ return 0;
+}
+
+bool VPUClient::allocResLayerPipes(hwc_context_t* ctx, int dpy,
+ hwc_display_contents_1_t* list)
+{
+ overlay::Overlay& ov = *ctx->mOverlay;
+ for (unsigned int i=0; i<(list->numHwLayers); ++i) {
+ int pipeid = -1;
+ VpuLayerProp* prop = &mProp[dpy][i];
+
+ // checking if there is already a reserved pipe for this layer
+ // then use the same allocated pipe for this layer
+ getPipeId(prop, pipeid);
+
+ if (pipeid != -1) {
+ // there is a reserved pipe for this layer.
+ ovutils::eDest dest = ov.reservePipe(pipeid);
+ if (dest == ovutils::OV_INVALID) {
+ ALOGE("%s: Unable to get reserved pipe: layer#%d",
+ __FUNCTION__, i);
+ return false;
+ }
+
+ // setting dest locally
+ setDest(prop, dest);
+ ALOGD_IF(isDebug(), "%s: Reserving pipe:%d, dest:%d ", __FUNCTION__,
+ pipeid, dest);
+ }
+ else {
+ ALOGD_IF(isDebug2(), "%s: No reserved pipe for layer:%d",
+ __FUNCTION__, i);
+ }
+ }
+ return true;
+}
+
+bool VPUClient::allocLayerPipes(hwc_context_t* ctx, int dpy,
+ hwc_display_contents_1_t* list)
+{
+ // checking if the pipes are reserved for any layer,
+ // if yes, then updating the index of the pipes
+ if (!allocResLayerPipes(ctx, dpy, list)) {
+ ALOGE("%s: Reserved pipe alloc failed", __FUNCTION__);
+ return false;
+ }
+
+ for (unsigned int i=0; i<(list->numHwLayers); ++i) {
+ hwc_layer_1_t* layer = &list->hwLayers[i];
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ VpuLayerProp* prop = &mProp[dpy][i];
+ int pipe = -1;
+ overlay::Overlay& ov = *ctx->mOverlay;
+
+ // only care about the layers supported by VPU
+ if (!prop->vpuLayer)
+ continue;
+
+ // continue if this layer has reserved pipe
+ getPipeId(prop, pipe);
+ if (pipe != -1)
+ continue;
+
+ ovutils::eDest dest = ov.nextPipe(ovutils::OV_MDP_PIPE_VG, dpy,
+ overlay::Overlay::MIXER_DEFAULT);
+ if (dest == ovutils::OV_INVALID) {
+ ALOGE("%s: Unable to allocate pipe for layer#%d", __FUNCTION__, i);
+ return false;
+ }
+
+ // setting dest locally
+ setDest(prop, dest);
+ ALOGD_IF(isDebug(), "%s: Newly allocated pipe_dest:%d", __FUNCTION__,
+ dest);
+ }
+ return true;
+}
+
+bool VPUClient::allocResLayerPipesSplit(hwc_context_t* ctx, int dpy,
+ hwc_display_contents_1_t* list)
+{
+ overlay::Overlay& ov = *ctx->mOverlay;
+ for (unsigned int i=0; i<(list->numHwLayers); ++i) {
+ int lpipeid = -1;
+ int rpipeid = -1;
+ VpuLayerProp* prop = &mProp[dpy][i];
+
+ // checking if there is already a reserved pipe for this layer
+ // then use the same allocated pipe for this layer
+ getPipeId(prop, lpipeid, rpipeid);
+
+ if (lpipeid != -1 && rpipeid != -1) {
+ ovutils::eDest ldest = ov.reservePipe(lpipeid);
+ if (ldest == ovutils::OV_INVALID) {
+ ALOGD_IF(isDebug(), "%s: Unable to get reserved pipe-lsplit: "
+ "layer#%d", __FUNCTION__, i);
+ return false;
+ }
+
+ ovutils::eDest rdest = ov.reservePipe(rpipeid);
+ if (rdest == ovutils::OV_INVALID) {
+ ALOGD_IF(isDebug(), "%s: Unable to get reserved pipe-rsplit: "
+ "layer#%d", __FUNCTION__, i);
+ return false;
+ }
+
+ setDest(prop, ldest, rdest);
+ ALOGD_IF(isDebug(), "%s: Reserve lpipe:%d, ldest:%d, rpipe:%d, "
+ "rdest:%d", __FUNCTION__, lpipeid, ldest, rpipeid, rdest);
+ }
+ else if (lpipeid != -1 || rpipeid != -1) {
+ ALOGE("%s: Bug: only one pipe reserved!", __FUNCTION__);
+ return false;
+ }
+ }
+ return true;
+}
+
+bool VPUClient::allocLayerPipesSplit(hwc_context_t* ctx, int dpy,
+ hwc_display_contents_1_t* list)
+{
+ // checking if the pipes are reserved for any layer,
+ // if yes, then updating the index of the pipes
+ if (!allocResLayerPipesSplit(ctx, dpy, list)) {
+ ALOGE("%s: Reserved pipe alloc failed", __FUNCTION__);
+ return false;
+ }
+
+ for (unsigned int i=0; i<(list->numHwLayers); ++i) {
+ hwc_layer_1_t* layer = &list->hwLayers[i];
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ VpuLayerProp* prop = &mProp[dpy][i];
+ int lpipe, rpipe;
+ overlay::Overlay& ov = *ctx->mOverlay;
+
+ // only care about the layers supported by VPU
+ if (!prop->vpuLayer)
+ continue;
+
+ // only care about the layers supported by VPU
+ getPipeId(prop, lpipe, rpipe);
+ if (lpipe != -1 && rpipe != -1)
+ continue;
+
+ ovutils::eDest ldest = ov.nextPipe(ovutils::OV_MDP_PIPE_VG, dpy,
+ overlay::Overlay::MIXER_LEFT);
+ if (ldest == ovutils::OV_INVALID) {
+ ALOGE("%s: Unable to allocate pipe for layer#%d", __FUNCTION__, i);
+ return false;
+ }
+
+ ovutils::eDest rdest = ov.nextPipe(ovutils::OV_MDP_PIPE_VG, dpy,
+ overlay::Overlay::MIXER_RIGHT);
+ if (rdest == ovutils::OV_INVALID) {
+ ALOGE("%s: Unable to allocate pipe for layer#%d", __FUNCTION__, i);
+ return false;
+ }
+
+ // setting dests locally
+ setDest(prop, ldest, rdest);
+ ALOGD_IF(isDebug(), "%s: Newly allocated ldest:%d rdest:%d",
+ __FUNCTION__, ldest, rdest);
+ }
+ return true;
+}
+
+bool VPUClient::configureLayers(hwc_context_t* ctx, int dpy,
+ hwc_display_contents_1_t* list)
+{
+ for (unsigned int i=0; i<(list->numHwLayers); ++i) {
+ VpuLayerProp* prop = &mProp[dpy][i];
+ hwc_layer_1_t* layer = &list->hwLayers[i];
+
+ if (!prop->vpuLayer)
+ continue;
+
+ eMdpFlags mdpFlags = OV_MDP_BACKEND_COMPOSITION;
+ eZorder zOrder = static_cast<eZorder>(i);
+ eIsFg isFg = IS_FG_OFF;
+ setPipeCount(prop, 1);
+ eDest dest = (eDest) getDest(prop, 0);
+
+ ALOGD_IF(isDebug(),"%s: configuring: layer:%p z_order:%d dest_pipe:%d",
+ __FUNCTION__, layer, zOrder, dest);
+
+ if (configureNonSplit(ctx, layer, dpy, mdpFlags, zOrder, isFg,
+ dest, NULL)) {
+ ALOGE("%s: Failed to configure overlay for layer %d",
+ __FUNCTION__, i);
+ return false;
+ }
+ ALOGD_IF(isDebug2(), "%s: layer:%d configured!", __FUNCTION__, i);
+
+ // Pipe is successfully allocated for this layer; retrieving it from
+ // overlay
+ int pipeId = ctx->mOverlay->getPipeId((eDest) getDest(prop, 0));
+ setPipeId(prop, pipeId);
+
+ ALOGD_IF(isDebug(), "%s: allocated pipe:%d layer:%d", __FUNCTION__,
+ pipeId, i);
+ }
+ return true;
+}
+
+bool VPUClient::configureLayersSplit(hwc_context_t* ctx, int dpy,
+ hwc_display_contents_1_t* list)
+{
+ for (unsigned int i=0; i<(list->numHwLayers); ++i) {
+ VpuLayerProp* prop = &mProp[dpy][i];
+ hwc_layer_1_t* layer = &list->hwLayers[i];
+
+ if (!prop->vpuLayer)
+ continue;
+
+ eMdpFlags mdpFlags = OV_MDP_BACKEND_COMPOSITION;
+ eZorder zOrder = static_cast<eZorder>(i);
+ eIsFg isFg = IS_FG_OFF;
+ setPipeCount(prop, 2);
+ eDest ldest = (eDest) getDest(prop, 0);
+ eDest rdest = (eDest) getDest(prop, 1);
+
+ ALOGD_IF(isDebug(),"%s: configuring: layer:%p z_order:%d dest_pipeL:%d"
+ "dest_pipeR:%d",__FUNCTION__, layer, zOrder, ldest, rdest);
+
+ if (configureSplit(ctx, layer, dpy, mdpFlags, zOrder, isFg, ldest,
+ rdest, NULL)) {
+ ALOGE("%s: Failed to configure overlay for layer %d",
+ __FUNCTION__, i);
+ return false;
+ }
+ ALOGD_IF(isDebug2(), "%s: layer:%d configured!", __FUNCTION__, i);
+
+ // Pipe is successfully allocated for this layer; retrieving it from
+ // overlay
+ int lpipeId = ctx->mOverlay->getPipeId((eDest) getDest(prop, 0));
+ int rpipeId = ctx->mOverlay->getPipeId((eDest) getDest(prop, 1));
+ setPipeId(prop, lpipeId, rpipeId);
+
+ ALOGD_IF(isDebug(), "%s: allocated l-pipe:%d - r-pipe:%d for layer:%d",
+ __FUNCTION__, lpipeId, rpipeId, i);
+ }
+ return true;
+}
+
+void VPUClient::setMDPCompLayerFlags(hwc_context_t *ctx, int dpy,
+ hwc_display_contents_1_t* list)
+{
+ LayerProp *layerProp = ctx->layerProp[dpy];
+
+ // disableGpu only disables gpu for video layer. The expected behavior is to
+ // show a blank screen in case VPU doesnt support a video layer, and gpu
+ // fallback is disabled by the user.
+ bool disableGpu = false;
+ char property[PROPERTY_VALUE_MAX];
+ if ((property_get("persist.hwc.noGpuFallback", property, NULL) > 0) &&
+ (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
+ (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
+ ALOGD_IF(isDebug(), "%s: GPU fallback is disabled through prop",
+ __FUNCTION__);
+ disableGpu = true;
+ }
+
+ // no layers are supported by vpu
+ if (mGpuFallback && !disableGpu) {
+ ALOGD_IF(isDebug(), "%s: No VPU supported layers - Falling back to GPU",
+ __FUNCTION__);
+ return;
+ }
+
+ for (unsigned int i=0; i<(list->numHwLayers); ++i) {
+ hwc_layer_1_t* layer = &(list->hwLayers[i]);
+ VpuLayerProp* prop = &mProp[dpy][i];
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+
+ // mark vpu layers as HWC_OVERLAY, and those video layers that
+ // are not supported by vpu and gpu fallback is disabled by the
+ // user.
+ if (prop->vpuLayer || (isYuvBuffer(hnd) && disableGpu)) {
+ layer->compositionType = HWC_OVERLAY;
+ layer->hints |= HWC_HINT_CLEAR_FB;
+ ALOGD_IF(isDebug(), "%s: Marking layer:%d as overlay",
+ __FUNCTION__, i);
+ }
+ }
+}
+
+int VPUClient::prepare(hwc_context_t *ctx, int display,
+ hwc_display_contents_1_t* list)
+{
+ if (!mVPU) {
+ return -1;
+ }
+
+ const int numLayers = ctx->listStats[display].numAppLayers;
+ //number of app layers exceeds MAX_NUM_APP_LAYERS fall back to GPU
+ //do not cache the information for next draw cycle.
+ if (numLayers > MAX_NUM_APP_LAYERS) {
+ ALOGE("%s: Number of App layers exceeded the limit ",__FUNCTION__);
+ return -1;
+ }
+
+ if (setupVpuSession(ctx, display, list)) {
+ ALOGD_IF(isDebug(), "%s: Vpu session setup failed! ",__FUNCTION__);
+ return -1;
+ }
+
+ LayerProp *layerProp = ctx->layerProp[display];
+ bool isSplit = isDisplaySplit(ctx, display);
+ ALOGD_IF(isDebug2(), "%s: Split Pipe:%d ", __FUNCTION__,
+ isSplit ? 1 : 0);
+
+ // setting up the layer
+ LayerList *vpuList = vList[display];
+ vpuList->numLayers = list->numHwLayers;
+
+ // Prepare FB Update at z-0
+ if (numLayers > mNumVpuLayers) {
+ if (!ctx->mFBUpdate[display]->prepare(ctx, list, mNumVpuLayers)) {
+ ALOGD_IF(isDebug(), "%s configure framebuffer failed",
+ __FUNCTION__);
+ return -1;
+ }
+ }
+
+ // Allocate pipe for layers
+ if (!isSplit ? !allocLayerPipes(ctx, display, list) :
+ !allocLayerPipesSplit(ctx, display, list)) {
+ ALOGD_IF(isDebug(), "%s: Unable to allocate MDP pipes", __FUNCTION__);
+ return -1;
+ }
+
+ // Configure layers
+ if (!isSplit ? !configureLayers(ctx, display, list) :
+ !configureLayersSplit(ctx, display, list)) {
+ ALOGD_IF(isDebug(), "%s: Unable to configure MDP pipes", __FUNCTION__);
+ return -1;
+ }
+
+ // Set layer flags for MDP/VPU composition
+ setMDPCompLayerFlags(ctx, display, list);
+
+ for (unsigned int i=0; i<(list->numHwLayers); ++i) {
+ VpuLayerProp* prop = &mProp[display][i];
+
+ if (!prop->vpuLayer)
+ continue;
+
+ hwc_layer_1_t *layer = &list->hwLayers[i];
+ Layer *vLayer = &vpuList->layers[i];
+
+ // re-storing the sourceCropf, as it was changed in setVpuSession for
+ // overlay set
+ layer->sourceCropf = prop->sourceCropf;
+
+ // updating the pipe info inside vfm list
+ if ( prop->pipeCount > 0 && prop->pipeCount <= MAX_PIPES_PER_LAYER ) {
+ vLayer->sDestPipes.numPipes = prop->pipeCount;
+
+ for (int j=0; j < prop->pipeCount; ++j) {
+ // Setting pipe for VPU
+ vLayer->sDestPipes.pipe[j] = prop->pipeID[j];
+ }
+ }
+ }
+
+ if (mVPU->prepare((DISPLAY_ID)display, vpuList) != NO_ERROR) {
+ //error in vpu prepare
+ ALOGE("%s: ERROR in VPU::prepare", __func__);
+ return -1;
+ }
+ return 0;
+}
+
+bool VPUClient::queueHandle(hwc_context_t* ctx, VpuLayerProp* prop,
+ private_handle_t* hnd)
+{
+ overlay::Overlay& ov = *ctx->mOverlay;
+ ovutils::eDest dest = (eDest) getDest(prop, 0);
+
+ int fd = hnd->fd;
+ uint32_t offset = hnd->offset;
+
+ if (dest != ovutils::OV_INVALID) {
+ if (!ov.queueBuffer(fd, offset, dest)) {
+ ALOGE("%s: queueBuffer failed", __FUNCTION__);
+ return false;
+ }
+ else {
+ ALOGD_IF(isDebug(), "%s: Queue handle successful: hnd:0x%x "
+ "dest:%d", __FUNCTION__, (unsigned int) hnd, dest);
+ }
+ }
+ else {
+ ALOGE("%s: Invalid Dest: dest:%d", __FUNCTION__, dest);
+ return false;
+ }
+ return true;
+}
+
+bool VPUClient::queueHandleSplit(hwc_context_t* ctx, VpuLayerProp* prop,
+ private_handle_t* hnd)
+{
+ overlay::Overlay& ov = *ctx->mOverlay;
+ ovutils::eDest ldest = (eDest) getDest(prop, 0);
+ ovutils::eDest rdest = (eDest) getDest(prop, 1);
+
+ int fd = hnd->fd;
+ uint32_t offset = hnd->offset;
+
+ // play left mixer
+ if (ldest != ovutils::OV_INVALID) {
+ ALOGD_IF(isDebug(), "%s: Queuing left mixer", __FUNCTION__);
+ if (!ov.queueBuffer(fd, offset, ldest)) {
+ ALOGE("%s: queueBuffer failed for left mixer ", __FUNCTION__);
+ return false;
+ }
+ else {
+ ALOGD_IF(isDebug(), "%s: Queue left-handle successful: hnd:0x%x "
+ "ldest:%d", __FUNCTION__, (unsigned int) hnd, ldest);
+ }
+ }
+ else {
+ ALOGE("%s: Invalid l-Split Dest", __FUNCTION__);
+ return false;
+ }
+
+ // play right mixer
+ if (rdest != ovutils::OV_INVALID) {
+ ALOGD_IF(isDebug(), "%s: Queuing right mixer", __FUNCTION__);
+ if (!ov.queueBuffer(fd, offset, rdest)) {
+ ALOGE("%s: queueBuffer failed for right mixer ", __FUNCTION__);
+ return false;
+ }
+ else {
+ ALOGD_IF(isDebug(), "%s: Queue right-handle successful: hnd:0x%x "
+ "rdest:%d", __FUNCTION__, (unsigned int) hnd, rdest);
+ }
+ }
+ else {
+ ALOGE("%s: Invalid r-Split Dest", __FUNCTION__);
+ return false;
+ }
+ return true;
+}
+
+bool VPUClient::drawDummyLayers(hwc_context_t* ctx, int dpy,
+ hwc_display_contents_1_t* list)
{
int err = 0;
- if(!mVPU)
- return err;
- // Queue buffers to VPU
- return err;
+ for (unsigned int i=0; i<(list->numHwLayers); ++i) {
+ VpuLayerProp* prop = &mProp[dpy][i];
+
+ if (!prop->vpuLayer)
+ continue;
+
+ // displaying blank screen for the first frame
+ if (prop->firstBuffer) {
+ ALOGD_IF(isDebug(), "%s: Displaying first (blank) frame",
+ __FUNCTION__);
+ prop->firstBuffer = false;
+
+ if (mHnd[dpy][i] != NULL)
+ free_buffer(mHnd[dpy][i]);
+
+ // TO-FIX: out dummy buffer is currently allocated based on
+ // RGB888 format
+ err = alloc_buffer(&mHnd[dpy][i], prop->width, prop->height,
+ HAL_PIXEL_FORMAT_RGB_888, GRALLOC_USAGE_PRIVATE_IOMMU_HEAP);
+ if (err == -1) {
+ ALOGE("%s: Dummy buffer allocation failed!", __FUNCTION__);
+ return false;
+ }
+
+ private_handle_t* hnd = mHnd[dpy][i];
+ if (prop->format == HAL_PIXEL_FORMAT_RGB_888) {
+ ALOGD_IF(isDebug(), "%s: Format: RGB888", __FUNCTION__);
+ memset((void*)hnd->base, 0x0, hnd->size);
+ }
+ else if (prop->format ==
+ HAL_PIXEL_FORMAT_YCbCr_422_I_10BIT_COMPRESSED) {
+ ALOGD_IF(isDebug(), "%s: Format: 10BIT_BWC", __FUNCTION__);
+ memset((void*)hnd->base, 0xaa, hnd->size);
+ }
+ else {
+ ALOGE("%s: Error! Wrong VPU out format - layer:%d",
+ __FUNCTION__, i);
+ return false;
+ }
+
+ bool isSplit = isDisplaySplit(ctx, dpy);
+ if (!isSplit ? !queueHandle(ctx, prop, hnd) :
+ !queueHandleSplit(ctx, prop, hnd)) {
+ ALOGD_IF(isDebug(), "%s: Error in queue handle: layer:%d",
+ __FUNCTION__, i);
+ return false;
+ }
+ else {
+ ALOGD_IF(isDebug(), "%s: queue handle successful: hnd:0x%x "
+ "layer:%d", __FUNCTION__, (unsigned int) hnd, i);
+ }
+ }
+ }
+ return true;
+}
+
+int VPUClient::predraw(hwc_context_t *ctx, int display,
+ hwc_display_contents_1_t* list)
+{
+ if (!mVPU) {
+ return -1;
+ }
+
+ if (!ctx || !list) {
+ ALOGE("%s: invalid contxt or list",__FUNCTION__);
+ return -1;
+ }
+
+ if (ctx->listStats[display].numAppLayers > MAX_NUM_APP_LAYERS) {
+ ALOGE("%s: Exceeding max layer count", __FUNCTION__);
+ return -1;
+ }
+
+ // Although all the video layers are composed through VPU, but still need to
+ // queue the first buffer (blank screen) to mdp in order to initialize the
+ // settings
+ if (!drawDummyLayers(ctx, display, list)) {
+ ALOGE("%s: Failed to draw the first layer through overlay",
+ __FUNCTION__);
+ return -1;
+ }
+ return 0;
+}
+
+int VPUClient::draw(hwc_context_t *ctx, int display,
+ hwc_display_contents_1_t* list)
+{
+ if (!mVPU) {
+ return -1;
+ }
+
+ LayerList *vpuList = vList[display];
+ vpuList->numLayers = list->numHwLayers;
+
+ for (unsigned int i=0; i<(list->numHwLayers); ++i) {
+ hwc_layer_1_t *layer = &list->hwLayers[i];
+ Layer *vLayer = &vpuList->layers[i];
+
+ // setting layer info again for the update content.
+ setLayer(layer, vLayer);
+ }
+
+ // queuing the buffer to VPU
+ if (mVPU->draw((DISPLAY_ID)display, vpuList) != NO_ERROR) {
+ //error in vpu draw
+ ALOGE("%s: ERROR in VPU::draw", __func__);
+ return -1;
+ }
+
+ ALOGD_IF(isDebug2(), "%s: Done VFM draw", __FUNCTION__);
+
+ LayerProp *layerProp = ctx->layerProp[display];
+ // setting releaseFenceFd for the vpu layer
+ for (unsigned int i=0; i<(vpuList->numLayers); ++i) {
+
+ VpuLayerProp* prop = &mProp[display][i];
+ if (!prop->vpuLayer)
+ continue;
+
+ hwc_layer_1_t *layer = &list->hwLayers[i];
+ Layer *vLayer = &vpuList->layers[i];
+
+ // TODO: Fix properly once the releaseFenceFd is implemented
+ layer->releaseFenceFd = vLayer->releaseFenceFd;
+ ALOGD_IF(isDebug(), "%s: releaseFd:%d for layer:%d", __FUNCTION__,
+ layer->releaseFenceFd, i);
+ }
+ return 0;
+}
+
+int VPUClient::getLayerIdx(int dpy, hwc_layer_1_t *layer)
+{
+ for (int i=0; i < MAX_NUM_APP_LAYERS; ++i) {
+ VpuLayerProp* prop = &mProp[dpy][i];
+
+ if (!prop->vpuLayer)
+ continue;
+
+ if (prop->layer == layer) {
+ ALOGD_IF(isDebug2(), "%s: OUT - dpy:%d", __FUNCTION__, dpy);
+ return i;
+ }
+ }
+ return -1;
+}
+
+int VPUClient::getLayerFormat(int dpy, hwc_layer_1_t *layer)
+{
+ if (!mVPU) {
+ return -1;
+ }
+
+ int idx = -1;
+ if ((idx = getLayerIdx(dpy, layer)) == -1) {
+ ALOGE("%s: Layer not found!", __FUNCTION__);
+ return -1;
+ }
+
+ VpuLayerProp* prop = &mProp[dpy][idx];
+ ALOGD_IF(isDebug(), "%s: layer:%d format:0x%x", __FUNCTION__, idx,
+ (unsigned int) prop->format);
+
+ return prop->format;
+}
+
+int VPUClient::getWidth(int dpy, hwc_layer_1_t *layer)
+{
+ if (!mVPU) {
+ return -1;
+ }
+
+ int idx = -1;
+ if ((idx = getLayerIdx(dpy, layer)) == -1) {
+ ALOGE("%s: Layer not found!", __FUNCTION__);
+ return -1;
+ }
+
+ VpuLayerProp* prop = &mProp[dpy][idx];
+ ALOGD_IF(isDebug(), "%s: layer:%d width:%d", __FUNCTION__, idx,
+ prop->width);
+
+ return prop->width;
+}
+
+int VPUClient::getHeight(int dpy, hwc_layer_1_t *layer)
+{
+ if (!mVPU) {
+ return -1;
+ }
+
+ int idx = -1;
+ if ((idx = getLayerIdx(dpy, layer)) == -1) {
+ ALOGE("%s: Layer not found!", __FUNCTION__);
+ return -1;
+ }
+
+ VpuLayerProp* prop = &mProp[dpy][idx];
+ ALOGD_IF(isDebug(), "%s: layer:%d height:%d", __FUNCTION__, idx,
+ prop->height);
+
+ return prop->height;
+}
+
+// TODO: getter function has side-effect. Need to cleanup
+void VPUClient::getPipeId(VpuLayerProp* prop, int &pipe)
+{
+ pipe = (prop->pipeCount == 1) ? (prop->pipeID[0]) : -1;
+}
+
+void VPUClient::getPipeId(VpuLayerProp* prop, int &lPipe, int &rPipe)
+{
+ lPipe = (prop->pipeCount == 2) ? (prop->pipeID[0]) : -1;
+ rPipe = (prop->pipeCount == 2) ? (prop->pipeID[1]) : -1;
+}
+
+int VPUClient::getDest(VpuLayerProp* prop, int pipenum)
+{
+ return (prop->pipeCount > 0) ? (prop->dest[pipenum]) : -1;
+}
+
+void VPUClient::setPipeCount(VpuLayerProp* prop, int count)
+{
+ prop->pipeCount = count;
+}
+
+void VPUClient::setPipeId(VpuLayerProp* prop, int lPipeId, int rPipeId)
+{
+ prop->pipeCount = 2;
+ prop->pipeID[0] = lPipeId;
+ prop->pipeID[1] = rPipeId;
+}
+
+void VPUClient::setPipeId(VpuLayerProp* prop, int pipeId)
+{
+ prop->pipeCount = 1;
+ prop->pipeID[0] = pipeId;
+}
+
+void VPUClient::setDest(VpuLayerProp* prop, int lDest, int rDest)
+{
+ prop->dest[0] = lDest;
+ prop->dest[1] = rDest;
+}
+
+void VPUClient::setDest(VpuLayerProp* prop, int dest)
+{
+ prop->dest[0] = dest;
+}
+
+bool VPUClient::supportedVPULayer(VpuLayerProp* prop)
+{
+ if (!prop->vpuLayer)
+ return false;
+
+ return true;
+}
+
+bool VPUClient::supportedVPULayer(int dpy, hwc_layer_1_t *layer)
+{
+ if (!mVPU) {
+ return false;
+ }
+
+ int idx = -1;
+ if ((idx = getLayerIdx(dpy, layer)) == -1) {
+ ALOGD_IF(isDebug(), "%s: Layer not found!", __FUNCTION__);
+ return false;
+ }
+ return true;
}
int VPUClient::processCommand(uint32_t command,
- const Parcel* inParcel, Parcel* outParcel)
+ const Parcel* inParcel, Parcel* outParcel)
{
- if(!mVPU)
+ if (!mVPU)
return 0;
- //XXX: Enable when VPU enables it
- //return mVPU->processCommand(command, inParcel, outParcel);
- return 0;
+
+ return mVPU->processCommand(command, inParcel, outParcel);
}
}; // namespace qhwc
diff --git a/libhwcomposer/hwc_vpuclient.h b/libhwcomposer/hwc_vpuclient.h
index 9985517..bb2a4b6 100644
--- a/libhwcomposer/hwc_vpuclient.h
+++ b/libhwcomposer/hwc_vpuclient.h
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013 The Linux Foundation. All rights reserved.
+* Copyright (c) 2013-2014 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
@@ -31,13 +31,20 @@
#define HWC_VPU_H
#include <sys/types.h>
+#include "hwc_utils.h"
+
+#define MAX_PIPES_PER_LAYER 2
//Forward declarations
struct hwc_display_contents_1;
typedef struct hwc_display_contents_1 hwc_display_contents_1_t;
+struct hwc_layer_1;
+typedef struct hwc_layer_1 hwc_layer_1_t;
struct hwc_context_t;
+
namespace vpu {
class VPU;
+struct LayerList;
};
namespace android {
class Parcel;
@@ -47,21 +54,91 @@
class VPUClient {
public:
- VPUClient();
+ VPUClient(hwc_context_t *ctx);
~VPUClient();
- int prepare(hwc_context_t *ctx, hwc_display_contents_1_t* list);
-
- int draw(hwc_context_t *ctx, hwc_display_contents_1_t* list);
-
+ int setupVpuSession(hwc_context_t *ctx, int display,
+ hwc_display_contents_1_t* list);
+ int prepare(hwc_context_t *ctx, int display,
+ hwc_display_contents_1_t* list);
+ int predraw(hwc_context_t *ctx, int display,
+ hwc_display_contents_1_t* list);
+ int draw(hwc_context_t *ctx, int display,
+ hwc_display_contents_1_t* list);
int processCommand(uint32_t command,
- const android::Parcel* inParcel, android::Parcel* outParcel);
+ const android::Parcel* inParcel, android::Parcel* outParcel);
+ int getLayerFormat(int dpy, hwc_layer_1_t *layer);
+ int getWidth(int dpy, hwc_layer_1_t *layer);
+ int getHeight(int dpy, hwc_layer_1_t *layer);
+ bool supportedVPULayer(int dpy, hwc_layer_1_t *layer);
private:
vpu::VPU *mVPU;
void* mVPULib;
+ /* VpuLayerProp struct:
+ * This struct corresponds to only one layer
+ * pipeCount: number of pipes required for a layer
+ * pipeID[]: pipe ids corresponding to the layer
+ */
+ struct VpuLayerProp {
+ int format;
+ int width;
+ int height;
+ int pipeCount;
+ bool vpuLayer;
+ bool firstBuffer;
+ hwc_frect_t sourceCropf;
+ hwc_layer_1_t *layer;
+ int pipeID[MAX_PIPES_PER_LAYER];
+ int dest[MAX_PIPES_PER_LAYER];
+ };
+ int mNumVpuLayers; /* total num of vpu supported layers */
+ int mGpuFallback; /* all layers are not supported by vpu */
+
+ VpuLayerProp mProp[HWC_NUM_DISPLAY_TYPES][MAX_NUM_APP_LAYERS];
+ int mDebugLogs;
+ private_handle_t *mHnd[HWC_NUM_DISPLAY_TYPES][MAX_NUM_APP_LAYERS];
+ vpu::LayerList *vList[HWC_NUM_DISPLAY_TYPES];
+
+ /* Private debug functions */
+ int32_t isDebug() { return (mDebugLogs >= 1); }
+ int32_t isDebug2() { return (mDebugLogs >= 2); }
+
+ /* Private Get/Set functions */
+ int getLayerIdx(int dpy, hwc_layer_1_t *layer);
+ void getPipeId(VpuLayerProp* prop, int &pipe);
+ void getPipeId(VpuLayerProp* prop, int &lPipe, int &rPipe);
+ int getDest(VpuLayerProp* prop, int pipenum);
+ void setPipeCount(VpuLayerProp* prop, int count);
+ void setPipeId(VpuLayerProp* prop, int lPipeId, int rPipeId);
+ void setPipeId(VpuLayerProp* prop, int pipeId);
+ void setDest(VpuLayerProp* prop, int lDest, int rDest);
+ void setDest(VpuLayerProp* prop, int dest);
+
+ /* Private implementations */
+ bool supportedVPULayer(VpuLayerProp* prop);
+ bool allocResLayerPipes(hwc_context_t* ctx, int dpy,
+ hwc_display_contents_1_t* list);
+ bool allocLayerPipes(hwc_context_t* ctx, int dpy,
+ hwc_display_contents_1_t* list);
+ bool allocResLayerPipesSplit(hwc_context_t* ctx, int dpy,
+ hwc_display_contents_1_t* list);
+ bool allocLayerPipesSplit(hwc_context_t* ctx, int dpy,
+ hwc_display_contents_1_t* list);
+ bool configureLayers(hwc_context_t* ctx, int dpy,
+ hwc_display_contents_1_t* list);
+ bool configureLayersSplit(hwc_context_t* ctx, int dpy,
+ hwc_display_contents_1_t* list);
+ void setMDPCompLayerFlags(hwc_context_t *ctx, int dpy,
+ hwc_display_contents_1_t* list);
+ bool drawDummyLayers(hwc_context_t* ctx, int dpy,
+ hwc_display_contents_1_t* list);
+ bool queueHandle(hwc_context_t* ctx, VpuLayerProp* prop,
+ private_handle_t* hnd);
+ bool queueHandleSplit(hwc_context_t* ctx, VpuLayerProp* prop,
+ private_handle_t* hnd);
}; // class VPU
}; // namespace qhwc
#endif /* end of include guard: HWC_VPU_H */
diff --git a/liblight/lights.c b/liblight/lights.c
index ccfbe10..229777a 100644
--- a/liblight/lights.c
+++ b/liblight/lights.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2014 The Linux Foundation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -115,6 +116,9 @@
{
int err = 0;
int brightness = rgb_to_brightness(state);
+ if(!dev) {
+ return -1;
+ }
pthread_mutex_lock(&g_lock);
err = write_int(LCD_FILE, brightness);
pthread_mutex_unlock(&g_lock);
@@ -125,12 +129,15 @@
set_speaker_light_locked(struct light_device_t* dev,
struct light_state_t const* state)
{
- int len;
- int alpha, red, green, blue;
+ int red, green, blue;
int blink;
int onMS, offMS;
unsigned int colorRGB;
+ if(!dev) {
+ return -1;
+ }
+
switch (state->flashMode) {
case LIGHT_FLASH_TIMED:
onMS = state->flashOnMS;
@@ -217,6 +224,9 @@
struct light_state_t const* state)
{
int err = 0;
+ if(!dev) {
+ return -1;
+ }
pthread_mutex_lock(&g_lock);
err = write_int(BUTTON_FILE, state->color & 0xFF);
pthread_mutex_unlock(&g_lock);
diff --git a/libmemtrack/memtrack_msm.c b/libmemtrack/memtrack_msm.c
index 6626b89..8adff96 100644
--- a/libmemtrack/memtrack_msm.c
+++ b/libmemtrack/memtrack_msm.c
@@ -22,15 +22,19 @@
int msm_memtrack_init(const struct memtrack_module *module)
{
+ if(!module)
+ return -1;
return 0;
}
int msm_memtrack_get_memory(const struct memtrack_module *module,
pid_t pid,
- enum memtrack_type type,
+ int type,
struct memtrack_record *records,
size_t *num_records)
{
+ if(!module)
+ return -1;
if (type == MEMTRACK_TYPE_GL || type == MEMTRACK_TYPE_GRAPHICS) {
return kgsl_memtrack_get_memory(pid, type, records, num_records);
}
diff --git a/liboverlay/overlayCtrlData.h b/liboverlay/overlayCtrlData.h
index 1b26b66..dbf328a 100644
--- a/liboverlay/overlayCtrlData.h
+++ b/liboverlay/overlayCtrlData.h
@@ -49,13 +49,9 @@
public:
/* ctor */
- explicit Ctrl();
+ explicit Ctrl(const int& dpy);
/* dtor close */
~Ctrl();
- /* init fd etc*/
- bool init(uint32_t dpy);
- /* close underlying mdp */
- bool close();
/* set source using whf, orient and wait flag */
void setSource(const utils::PipeArgs& args);
@@ -90,20 +86,16 @@
private:
// mdp ctrl struct(info e.g.)
- MdpCtrl mMdp;
+ MdpCtrl *mMdp;
};
class Data : utils::NoCopy {
public:
/* init, reset */
- explicit Data();
+ explicit Data(const int& dpy);
/* calls close */
~Data();
- /* init fd etc */
- bool init(uint32_t dpy);
- /* calls underlying mdp close */
- bool close();
/* set overlay pipe id in the mdp struct */
void setPipeId(int id);
/* get overlay id in the mdp struct */
@@ -117,72 +109,46 @@
private:
// mdp data struct
- MdpData mMdp;
-};
-
-/* This class just creates a Ctrl Data pair to be used by a pipe.
- * Although this was legacy design, this separation still makes sense, since we
- * need to use the Ctrl channel in hwc_prepare (i.e config stage) and Data
- * channel in hwc_set (i.e draw stage)
- */
-struct CtrlData {
- Ctrl ctrl;
- Data data;
+ MdpData *mMdp;
};
//-------------Inlines-------------------------------
-inline Ctrl::Ctrl() {
- mMdp.reset();
+inline Ctrl::Ctrl(const int& dpy) : mMdp(new MdpCtrl(dpy)) {
}
inline Ctrl::~Ctrl() {
- close();
-}
-
-inline bool Ctrl::close() {
- if(!mMdp.close())
- return false;
- return true;
-}
-
-inline bool Ctrl::init(uint32_t dpy) {
- // MDP/FD init
- if(!mMdp.init(dpy)) {
- ALOGE("Ctrl failed to init dpy=%d", dpy);
- return false;
- }
- return true;
+ delete mMdp;
}
inline void Ctrl::setSource(const utils::PipeArgs& args)
{
- mMdp.setSource(args);
+ mMdp->setSource(args);
}
inline void Ctrl::setPosition(const utils::Dim& dim)
{
- mMdp.setPosition(dim);
+ mMdp->setPosition(dim);
}
inline void Ctrl::setTransform(const utils::eTransform& orient)
{
- mMdp.setTransform(orient);
+ mMdp->setTransform(orient);
}
inline void Ctrl::setCrop(const utils::Dim& d)
{
- mMdp.setCrop(d);
+ mMdp->setCrop(d);
}
inline void Ctrl::setColor(const uint32_t color)
{
- mMdp.setColor(color);
+ mMdp->setColor(color);
}
inline bool Ctrl::setVisualParams(const MetaData_t &metadata)
{
- if (!mMdp.setVisualParams(metadata)) {
+ if (!mMdp->setVisualParams(metadata)) {
ALOGE("Ctrl setVisualParams failed in MDP setVisualParams");
return false;
}
@@ -191,12 +157,12 @@
inline void Ctrl::dump() const {
ALOGE("== Dump Ctrl start ==");
- mMdp.dump();
+ mMdp->dump();
ALOGE("== Dump Ctrl end ==");
}
inline bool Ctrl::commit() {
- if(!mMdp.set()) {
+ if(!mMdp->set()) {
ALOGE("Ctrl commit failed set overlay");
return false;
}
@@ -204,71 +170,56 @@
}
inline int Ctrl::getPipeId() const {
- return mMdp.getPipeId();
+ return mMdp->getPipeId();
}
inline int Ctrl::getFd() const {
- return mMdp.getFd();
+ return mMdp->getFd();
}
inline void Ctrl::updateSrcFormat(const uint32_t& rotDstFmt) {
- mMdp.updateSrcFormat(rotDstFmt);
+ mMdp->updateSrcFormat(rotDstFmt);
}
inline utils::Dim Ctrl::getCrop() const {
- return mMdp.getSrcRectDim();
+ return mMdp->getSrcRectDim();
}
inline utils::Dim Ctrl::getPosition() const {
- return mMdp.getDstRectDim();
+ return mMdp->getDstRectDim();
}
inline void Ctrl::setDownscale(int dscale_factor) {
- mMdp.setDownscale(dscale_factor);
+ mMdp->setDownscale(dscale_factor);
}
inline void Ctrl::getDump(char *buf, size_t len) {
- mMdp.getDump(buf, len);
+ mMdp->getDump(buf, len);
}
-inline Data::Data() {
- mMdp.reset();
+inline Data::Data(const int& dpy) : mMdp(new MdpData(dpy)) {
}
-inline Data::~Data() { close(); }
-
-inline void Data::setPipeId(int id) { mMdp.setPipeId(id); }
-
-inline int Data::getPipeId() const { return mMdp.getPipeId(); }
-
-inline bool Data::init(uint32_t dpy) {
- if(!mMdp.init(dpy)) {
- ALOGE("Data cannot init mdp");
- return false;
- }
- return true;
+inline Data::~Data() {
+ delete mMdp;
}
-inline bool Data::close() {
- if(!mMdp.close()) {
- ALOGE("Data close failed");
- return false;
- }
- return true;
-}
+inline void Data::setPipeId(int id) { mMdp->setPipeId(id); }
+
+inline int Data::getPipeId() const { return mMdp->getPipeId(); }
inline bool Data::queueBuffer(int fd, uint32_t offset) {
- return mMdp.play(fd, offset);
+ return mMdp->play(fd, offset);
}
inline void Data::dump() const {
ALOGE("== Dump Data MDP start ==");
- mMdp.dump();
+ mMdp->dump();
ALOGE("== Dump Data MDP end ==");
}
inline void Data::getDump(char *buf, size_t len) {
- mMdp.getDump(buf, len);
+ mMdp->getDump(buf, len);
}
} // overlay
diff --git a/liboverlay/overlayMdp.cpp b/liboverlay/overlayMdp.cpp
index 006e05d..3ec0405 100644
--- a/liboverlay/overlayMdp.cpp
+++ b/liboverlay/overlayMdp.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2008 The Android Open Source Project
-* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+* Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -45,7 +45,7 @@
namespace ovutils = overlay::utils;
namespace overlay {
-bool MdpCtrl::init(uint32_t dpy) {
+bool MdpCtrl::init(const int& dpy) {
int fbnum = Overlay::getFbForDpy(dpy);
if( fbnum < 0 ) {
ALOGE("%s: Invalid FB for the display: %d",__FUNCTION__, dpy);
@@ -64,14 +64,11 @@
void MdpCtrl::reset() {
utils::memset0(mOVInfo);
- utils::memset0(mLkgo);
mOVInfo.id = MSMFB_NEW_REQUEST;
- mLkgo.id = MSMFB_NEW_REQUEST;
mOrientation = utils::OVERLAY_TRANSFORM_0;
mDownscale = 0;
mDpy = 0;
#ifdef USES_POST_PROCESSING
- mPPChanged = false;
memset(&mParams, 0, sizeof(struct compute_params));
mParams.params.conv_params.order = hsic_order_hsc_i;
mParams.params.conv_params.interface = interface_rec601;
@@ -210,21 +207,15 @@
doDownscale();
- if(this->ovChanged()) {
- if(!mdp_wrapper::setOverlay(mFd.getFD(), mOVInfo)) {
- ALOGE("MdpCtrl failed to setOverlay, restoring last known "
- "good ov info");
- mdp_wrapper::dump("== Bad OVInfo is: ", mOVInfo);
- mdp_wrapper::dump("== Last good known OVInfo is: ", mLkgo);
- this->restore();
+ if(!mdp_wrapper::setOverlay(mFd.getFD(), mOVInfo)) {
+ ALOGE("MdpCtrl failed to setOverlay");
+ mdp_wrapper::dump("== Bad OVInfo is: ", mOVInfo);
#ifdef USES_QSEED_SCALAR
- if(Overlay::getScalar()) {
- Overlay::getScalar()->configAbort(mDpy);
- }
-#endif
- return false;
+ if(Overlay::getScalar()) {
+ Overlay::getScalar()->configAbort(mDpy);
}
- this->save();
+#endif
+ return false;
}
#ifdef USES_QSEED_SCALAR
@@ -283,8 +274,9 @@
}
bool MdpCtrl::setVisualParams(const MetaData_t& data) {
- bool needUpdate = false;
+ ALOGD_IF(0, "In %s: data.operation = %d", __FUNCTION__, data.operation);
#ifdef USES_POST_PROCESSING
+ bool needUpdate = false;
/* calculate the data */
if (data.operation & PP_PARAM_HSIC) {
if (mParams.params.pa_params.hue != data.hsicData.hue) {
@@ -392,7 +384,6 @@
if (needUpdate) {
display_pp_compute_params(&mParams, &mOVInfo.overlay_pp_cfg);
- mPPChanged = true;
}
#endif
return true;
@@ -400,7 +391,7 @@
//// MdpData ////////////
-bool MdpData::init(uint32_t dpy) {
+bool MdpData::init(const int& dpy) {
int fbnum = Overlay::getFbForDpy(dpy);
if( fbnum < 0 ) {
ALOGE("%s: Invalid FB for the display: %d",__FUNCTION__, dpy);
diff --git a/liboverlay/overlayMdp.h b/liboverlay/overlayMdp.h
index 3cb6a41..daaeaf2 100644
--- a/liboverlay/overlayMdp.h
+++ b/liboverlay/overlayMdp.h
@@ -36,11 +36,11 @@
class MdpCtrl {
public:
/* ctor reset */
- explicit MdpCtrl();
+ explicit MdpCtrl(const int& dpy);
/* dtor close */
~MdpCtrl();
/* init underlying device using fbnum for dpy */
- bool init(uint32_t dpy);
+ bool init(const int& dpy);
/* unset overlay, reset and close fd */
bool close();
/* reset and set ov id to -1 / MSMFB_NEW_REQUEST */
@@ -116,17 +116,8 @@
int getUserData() const;
/* sets user_data[0] */
void setUserData(int v);
- /* return true if current overlay is different
- * than last known good overlay */
- bool ovChanged() const;
- /* save mOVInfo to be last known good ov*/
- void save();
- /* restore last known good ov to be the current */
- void restore();
utils::eTransform mOrientation; //Holds requested orientation
- /* last good known ov info */
- mdp_overlay mLkgo;
/* Actual overlay mdp structure */
mdp_overlay mOVInfo;
/* FD for the mdp fbnum */
@@ -137,8 +128,6 @@
#ifdef USES_POST_PROCESSING
/* PP Compute Params */
struct compute_params mParams;
- /* indicate if PP params have been changed */
- bool mPPChanged;
#endif
};
@@ -171,11 +160,11 @@
class MdpData {
public:
/* ctor reset data */
- explicit MdpData();
+ explicit MdpData(const int& dpy);
/* dtor close*/
~MdpData();
/* init FD */
- bool init(uint32_t dpy);
+ bool init(const int& dpy);
/* memset0 the underlying mdp object */
void reset();
/* close fd, and reset */
@@ -207,8 +196,9 @@
///// MdpCtrl //////
-inline MdpCtrl::MdpCtrl() {
+inline MdpCtrl::MdpCtrl(const int& dpy) {
reset();
+ init(dpy);
}
inline MdpCtrl::~MdpCtrl() {
@@ -265,37 +255,6 @@
}
}
-inline bool MdpCtrl::ovChanged() const {
-#ifdef USES_POST_PROCESSING
- // Some pp params are stored as pointer address,
- // so can't compare their content directly.
- if (mPPChanged) {
- return true;
- }
-#endif
- // 0 means same
- if(0 == ::memcmp(&mOVInfo, &mLkgo, sizeof (mdp_overlay))) {
- return false;
- }
- return true;
-}
-
-inline void MdpCtrl::save() {
- if(static_cast<ssize_t>(mOVInfo.id) == MSMFB_NEW_REQUEST) {
- ALOGE("MdpCtrl current ov has id -1, will not save");
- return;
- }
- mLkgo = mOVInfo;
-}
-
-inline void MdpCtrl::restore() {
- if(static_cast<ssize_t>(mLkgo.id) == MSMFB_NEW_REQUEST) {
- ALOGE("MdpCtrl Lkgo ov has id -1, will not restore");
- return;
- }
- mOVInfo = mLkgo;
-}
-
inline overlay::utils::Whf MdpCtrl::getSrcWhf() const {
return utils::Whf( mOVInfo.src.width,
mOVInfo.src.height,
@@ -388,7 +347,10 @@
/////// MdpData //////
-inline MdpData::MdpData() { reset(); }
+inline MdpData::MdpData(const int& dpy) {
+ reset();
+ init(dpy);
+}
inline MdpData::~MdpData() { close(); }
diff --git a/liboverlay/overlayMdpRot.cpp b/liboverlay/overlayMdpRot.cpp
index ce2ef5b..3e549b1 100755
--- a/liboverlay/overlayMdpRot.cpp
+++ b/liboverlay/overlayMdpRot.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2008 The Android Open Source Project
- * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
* Not a Contribution, Apache license notifications and license are retained
* for attribution purposes only.
*
@@ -94,7 +94,7 @@
mRotImgInfo.dst.height = whf.h;
}
-void MdpRot::setCrop(const utils::Dim& crop) {
+void MdpRot::setCrop(const utils::Dim& /*crop*/) {
// NO-OP for non-mdss rotator due to possible h/w limitations
}
diff --git a/liboverlay/overlayMdssRot.cpp b/liboverlay/overlayMdssRot.cpp
index c6d5332..083e507 100644
--- a/liboverlay/overlayMdssRot.cpp
+++ b/liboverlay/overlayMdssRot.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2008 The Android Open Source Project
- * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
* Not a Contribution, Apache license notifications and license are retained
* for attribution purposes only.
*
@@ -92,7 +92,8 @@
mRotInfo.dst_rect.h = crop.h;
}
-void MdssRot::setDownscale(int ds) {}
+void MdssRot::setDownscale(int /*ds*/) {
+}
void MdssRot::setFlags(const utils::eMdpFlags& flags) {
mRotInfo.flags = flags;
diff --git a/liboverlay/overlayUtils.cpp b/liboverlay/overlayUtils.cpp
index 1377182..5cc4c03 100644
--- a/liboverlay/overlayUtils.cpp
+++ b/liboverlay/overlayUtils.cpp
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+* Copyright (c) 2011-2014, 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
@@ -36,6 +36,7 @@
#include "overlayUtils.h"
#include "mdpWrapper.h"
#include "mdp_version.h"
+#include <hardware/hwcomposer_defs.h>
// just a helper static thingy
namespace {
@@ -145,6 +146,34 @@
return -1;
}
+// This function returns corresponding tile format
+// MDSS support following RGB tile formats
+// 32 bit formats
+// 16 bit formats
+int getMdpFormat(int format, bool tileEnabled)
+{
+ if(!tileEnabled) {
+ return getMdpFormat(format);
+ }
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RGBA_8888 :
+ return MDP_RGBA_8888_TILE;
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ return MDP_RGBX_8888_TILE;
+ case HAL_PIXEL_FORMAT_RGB_565:
+ // Currenty Driver doesnt support 565 tile format
+ return MDP_RGB_565;
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ return MDP_BGRA_8888_TILE;
+ case HAL_PIXEL_FORMAT_BGRX_8888:
+ return MDP_BGRX_8888_TILE;
+ default:
+ return getMdpFormat(format);
+ }
+}
+
+
+
//Takes mdp format as input and translates to equivalent HAL format
//Refer to graphics.h, gralloc_priv.h, msm_mdp.h for formats.
int getHALFormat(int mdpFormat) {
@@ -394,7 +423,7 @@
getDump(buf, len, "\tdst_rect", ov.dst_rect);
}
-void getDump(char *buf, size_t len, const char *prefix,
+void getDump(char *buf, size_t /*len*/, const char *prefix,
const msmfb_img& ov) {
char str_src[256] = {'\0'};
snprintf(str_src, 256,
@@ -404,7 +433,7 @@
strncat(buf, str_src, strlen(str_src));
}
-void getDump(char *buf, size_t len, const char *prefix,
+void getDump(char *buf, size_t /*len*/, const char *prefix,
const mdp_rect& ov) {
char str_rect[256] = {'\0'};
snprintf(str_rect, 256,
@@ -423,7 +452,7 @@
getDump(buf, len, "\tdata", ov.data);
}
-void getDump(char *buf, size_t len, const char *prefix,
+void getDump(char *buf, size_t /*len*/, const char *prefix,
const msmfb_data& ov) {
char str_data[256] = {'\0'};
snprintf(str_data, 256,
diff --git a/liboverlay/overlayUtils.h b/liboverlay/overlayUtils.h
index 904d607..24fba33 100644
--- a/liboverlay/overlayUtils.h
+++ b/liboverlay/overlayUtils.h
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+* Copyright (c) 2011-2014, 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
@@ -272,6 +272,7 @@
OV_MDSS_MDP_BWC_EN = MDP_BWC_EN,
OV_MDSS_MDP_DUAL_PIPE = MDSS_MDP_DUAL_PIPE,
OV_MDP_SOLID_FILL = MDP_SOLID_FILL,
+ OV_MDP_VPU_PIPE = MDP_VPU_PIPE,
};
enum eZorder {
@@ -408,6 +409,7 @@
};
int getMdpFormat(int format);
+int getMdpFormat(int format, bool tileEnabled);
int getHALFormat(int mdpFormat);
int getDownscaleFactor(const int& src_w, const int& src_h,
const int& dst_w, const int& dst_h);
@@ -545,6 +547,14 @@
formats[MDP_BGR_888] = STR(MDP_BGR_888);
formats[MDP_Y_CBCR_H2V2_VENUS] = STR(MDP_Y_CBCR_H2V2_VENUS);
formats[MDP_BGRX_8888] = STR(MDP_BGRX_8888);
+ formats[MDP_RGBA_8888_TILE] = STR(MDP_RGBA_8888_TILE);
+ formats[MDP_ARGB_8888_TILE] = STR(MDP_ARGB_8888_TILE);
+ formats[MDP_ABGR_8888_TILE] = STR(MDP_ABGR_8888_TILE);
+ formats[MDP_BGRA_8888_TILE] = STR(MDP_BGRA_8888_TILE);
+ formats[MDP_RGBX_8888_TILE] = STR(MDP_RGBX_8888_TILE);
+ formats[MDP_XRGB_8888_TILE] = STR(MDP_XRGB_8888_TILE);
+ formats[MDP_XBGR_8888_TILE] = STR(MDP_XBGR_8888_TILE);
+ formats[MDP_BGRX_8888_TILE] = STR(MDP_BGRX_8888_TILE);
formats[MDP_IMGTYPE_LIMIT] = STR(MDP_IMGTYPE_LIMIT);
if(format < 0 || format >= MDP_IMGTYPE_LIMIT) {
diff --git a/liboverlay/pipes/overlayGenPipe.cpp b/liboverlay/pipes/overlayGenPipe.cpp
index e0b580b..394a56e 100644
--- a/liboverlay/pipes/overlayGenPipe.cpp
+++ b/liboverlay/pipes/overlayGenPipe.cpp
@@ -32,73 +32,40 @@
namespace overlay {
-GenericPipe::GenericPipe(int dpy) : mDpy(dpy), mRotDownscaleOpt(false),
- pipeState(CLOSED) {
- init();
+GenericPipe::GenericPipe(const int& dpy) : mDpy(dpy), mRotDownscaleOpt(false),
+ pipeState(CLOSED), mCtrl(new Ctrl(dpy)), mData(new Data(dpy)) {
}
GenericPipe::~GenericPipe() {
- close();
-}
-
-bool GenericPipe::init()
-{
- ALOGE_IF(DEBUG_OVERLAY, "GenericPipe init");
- mRotDownscaleOpt = false;
-
- if(!mCtrlData.ctrl.init(mDpy)) {
- ALOGE("GenericPipe failed to init ctrl");
- return false;
- }
-
- if(!mCtrlData.data.init(mDpy)) {
- ALOGE("GenericPipe failed to init data");
- return false;
- }
-
- return true;
-}
-
-bool GenericPipe::close() {
- bool ret = true;
-
- if(!mCtrlData.ctrl.close()) {
- ALOGE("GenericPipe failed to close ctrl");
- ret = false;
- }
- if (!mCtrlData.data.close()) {
- ALOGE("GenericPipe failed to close data");
- ret = false;
- }
-
+ delete mCtrl;
+ delete mData;
setClosed();
- return ret;
}
void GenericPipe::setSource(const utils::PipeArgs& args) {
mRotDownscaleOpt = args.rotFlags & utils::ROT_DOWNSCALE_ENABLED;
- mCtrlData.ctrl.setSource(args);
+ mCtrl->setSource(args);
}
void GenericPipe::setCrop(const overlay::utils::Dim& d) {
- mCtrlData.ctrl.setCrop(d);
+ mCtrl->setCrop(d);
}
void GenericPipe::setColor(const uint32_t color) {
- mCtrlData.ctrl.setColor(color);
+ mCtrl->setColor(color);
}
void GenericPipe::setTransform(const utils::eTransform& orient) {
- mCtrlData.ctrl.setTransform(orient);
+ mCtrl->setTransform(orient);
}
void GenericPipe::setPosition(const utils::Dim& d) {
- mCtrlData.ctrl.setPosition(d);
+ mCtrl->setPosition(d);
}
bool GenericPipe::setVisualParams(const MetaData_t &metadata)
{
- return mCtrlData.ctrl.setVisualParams(metadata);
+ return mCtrl->setVisualParams(metadata);
}
bool GenericPipe::commit() {
@@ -106,14 +73,14 @@
int downscale_factor = utils::ROT_DS_NONE;
if(mRotDownscaleOpt) {
- ovutils::Dim src(mCtrlData.ctrl.getCrop());
- ovutils::Dim dst(mCtrlData.ctrl.getPosition());
+ ovutils::Dim src(mCtrl->getCrop());
+ ovutils::Dim dst(mCtrl->getPosition());
downscale_factor = ovutils::getDownscaleFactor(
src.w, src.h, dst.w, dst.h);
}
- mCtrlData.ctrl.setDownscale(downscale_factor);
- ret = mCtrlData.ctrl.commit();
+ mCtrl->setDownscale(downscale_factor);
+ ret = mCtrl->commit();
pipeState = ret ? OPEN : CLOSED;
return ret;
@@ -122,36 +89,35 @@
bool GenericPipe::queueBuffer(int fd, uint32_t offset) {
//TODO Move pipe-id transfer to CtrlData class. Make ctrl and data private.
OVASSERT(isOpen(), "State is closed, cannot queueBuffer");
- int pipeId = mCtrlData.ctrl.getPipeId();
+ int pipeId = mCtrl->getPipeId();
OVASSERT(-1 != pipeId, "Ctrl ID should not be -1");
// set pipe id from ctrl to data
- mCtrlData.data.setPipeId(pipeId);
+ mData->setPipeId(pipeId);
- return mCtrlData.data.queueBuffer(fd, offset);
+ return mData->queueBuffer(fd, offset);
}
int GenericPipe::getCtrlFd() const {
- return mCtrlData.ctrl.getFd();
+ return mCtrl->getFd();
}
utils::Dim GenericPipe::getCrop() const
{
- return mCtrlData.ctrl.getCrop();
+ return mCtrl->getCrop();
}
void GenericPipe::dump() const
{
ALOGE("== Dump Generic pipe start ==");
ALOGE("pipe state = %d", (int)pipeState);
- mCtrlData.ctrl.dump();
- mCtrlData.data.dump();
-
+ mCtrl->dump();
+ mData->dump();
ALOGE("== Dump Generic pipe end ==");
}
void GenericPipe::getDump(char *buf, size_t len) {
- mCtrlData.ctrl.getDump(buf, len);
- mCtrlData.data.getDump(buf, len);
+ mCtrl->getDump(buf, len);
+ mData->getDump(buf, len);
}
bool GenericPipe::isClosed() const {
@@ -168,7 +134,7 @@
}
int GenericPipe::getPipeId() {
- return mCtrlData.ctrl.getPipeId();
+ return mCtrl->getPipeId();
}
} //namespace overlay
diff --git a/liboverlay/pipes/overlayGenPipe.h b/liboverlay/pipes/overlayGenPipe.h
index ecdd001..57e1758 100644
--- a/liboverlay/pipes/overlayGenPipe.h
+++ b/liboverlay/pipes/overlayGenPipe.h
@@ -38,11 +38,9 @@
class GenericPipe : utils::NoCopy {
public:
/* ctor */
- explicit GenericPipe(int dpy);
+ explicit GenericPipe(const int& dpy);
/* dtor */
~GenericPipe();
- bool init();
- bool close();
/* Control APIs */
/* set source using whf, orient and wait flag */
void setSource(const utils::PipeArgs& args);
@@ -82,8 +80,6 @@
bool setClosed();
int mDpy;
- /* Ctrl/Data aggregator */
- CtrlData mCtrlData;
//Whether we will do downscale opt. This is just a request. If the frame is
//not a candidate, we might not do it.
bool mRotDownscaleOpt;
@@ -93,6 +89,8 @@
OPEN
};
ePipeState pipeState;
+ Ctrl *mCtrl;
+ Data *mData;
};
} //namespace overlay
diff --git a/libqdutils/Android.mk b/libqdutils/Android.mk
index 06f4f00..2907ccf 100644
--- a/libqdutils/Android.mk
+++ b/libqdutils/Android.mk
@@ -13,7 +13,8 @@
LOCAL_SRC_FILES := profiler.cpp mdp_version.cpp \
idle_invalidator.cpp \
comptype.cpp qd_utils.cpp \
- cb_utils.cpp display_config.cpp
+ cb_utils.cpp display_config.cpp \
+ cb_swap_rect.cpp
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
diff --git a/libqdutils/cb_swap_rect.cpp b/libqdutils/cb_swap_rect.cpp
new file mode 100644
index 0000000..8c8efec
--- /dev/null
+++ b/libqdutils/cb_swap_rect.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2014, 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:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation or the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cb_swap_rect.h"
+
+ANDROID_SINGLETON_STATIC_INSTANCE(qdutils::cb_swap_rect);
+
+namespace qdutils {
+
+cb_swap_rect:: cb_swap_rect(){
+ swap_rect_feature_on = false ;
+}
+void cb_swap_rect::setSwapRectFeature_on( bool value){
+ swap_rect_feature_on = value ;
+}
+bool cb_swap_rect::checkSwapRectFeature_on(){
+ return swap_rect_feature_on;
+}
+
+};
diff --git a/libqdutils/cb_swap_rect.h b/libqdutils/cb_swap_rect.h
new file mode 100644
index 0000000..daaeb37
--- /dev/null
+++ b/libqdutils/cb_swap_rect.h
@@ -0,0 +1,51 @@
+/* Copyright (c) 2014, 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:
+* * Redistributions of source code must retain the above copyrigh
+* notice, this list of conditions and the following disclaimer
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef CB_SWAP_RECT
+#define CB_SWAP_RECT
+
+#include <stdint.h>
+#include <utils/Singleton.h>
+#include <cutils/log.h>
+
+using namespace android;
+namespace qdutils {
+enum {
+HWC_SKIP_HWC_COMPOSITION = 0x00040000,
+};
+
+class cb_swap_rect : public Singleton <cb_swap_rect>
+{
+ bool swap_rect_feature_on;
+ public :
+ cb_swap_rect();
+ void setSwapRectFeature_on( bool value);
+ bool checkSwapRectFeature_on();
+};
+} // namespace qdutils
+#endif
diff --git a/libqdutils/cb_utils.cpp b/libqdutils/cb_utils.cpp
index d8eec2a..3d07c4f 100644
--- a/libqdutils/cb_utils.cpp
+++ b/libqdutils/cb_utils.cpp
@@ -26,9 +26,10 @@
*/
#include "cb_utils.h"
-
+#include "cb_swap_rect.h"
/* get union of two rects into 3rd rect */
void getUnion(hwc_rect_t& rect1,hwc_rect_t& rect2, hwc_rect_t& irect) {
+
irect.left = min(rect1.left, rect2.left);
irect.top = min(rect1.top, rect2.top);
irect.right = max(rect1.right, rect2.right);
@@ -44,15 +45,23 @@
uint32_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);
- for (uint32_t i = 0 ; i < last; i++) {
- //TODO Work on using hwc clear instead of gpu for HWC_BLIT
- //If layer is marked for HWC_BLIT clear is done by GPU
- if(list->hwLayers[i].compositionType == HWC_BLIT)
- return 0;
+ if(cb_swap_rect::getInstance().checkSwapRectFeature_on() == true){
+ wormholeRegion.set(0,0);
+ for(uint32_t i = 0 ; i < last; i++) {
+ if((list->hwLayers[i].blending == HWC_BLENDING_NONE) ||
+ !(layerProp[i].mFlags & HWC_COPYBIT) ||
+ (list->hwLayers[i].flags & HWC_SKIP_HWC_COMPOSITION))
+ continue ;
+ hwc_rect_t displayFrame = list->hwLayers[i].displayFrame;
+ Rect tmpRect(displayFrame.left,displayFrame.top,
+ displayFrame.right,displayFrame.bottom);
+ wormholeRegion.set(tmpRect);
+ }
+ }else{
+ for (uint32_t i = 0 ; i < last; i++) {
// need to take care only in per pixel blending.
// Restrict calculation only for copybit layers.
if((list->hwLayers[i].blending != HWC_BLENDING_NONE) ||
@@ -63,21 +72,27 @@
displayFrame.bottom);
Region tmpRegion(tmpRect);
wormholeRegion.subtractSelf(wormholeRegion.intersect(tmpRegion));
- }
- if (wormholeRegion.isEmpty()) {
+ }
+ }
+ if(wormholeRegion.isEmpty()){
return 0;
- }
- //TO DO :- 1. remove union and call clear for each rect.
- // :- 2. support swap ract feature.
- Region::const_iterator it = wormholeRegion.begin();
- Region::const_iterator const end = wormholeRegion.end();
- while (it != end) {
- const Rect& r = *it++;
- hwc_rect_t tmpWormRect = {r.left,r.top,r.right,r.bottom};
- getUnion(clearWormholeRect, tmpWormRect, clearWormholeRect);
+ }
+ //TO DO :- 1. remove union and call clear for each rect.
+ Region::const_iterator it = wormholeRegion.begin();
+ Region::const_iterator const end = wormholeRegion.end();
+ while (it != end) {
+ const Rect& r = *it++;
+ hwc_rect_t tmpWormRect = {r.left,r.top,r.right,r.bottom};
+ int dst_w = clearWormholeRect.right - clearWormholeRect.left;
+ int dst_h = clearWormholeRect.bottom - clearWormholeRect.top;
- }
- return 1;
+ if (!(dst_w || dst_h))
+ clearWormholeRect = tmpWormRect;
+ else
+ getUnion(clearWormholeRect, tmpWormRect, clearWormholeRect);
+
+ }
+ return 1;
}
}//namespace qdutils
diff --git a/libqdutils/display_config.cpp b/libqdutils/display_config.cpp
index 45b0211..60f1f68 100644
--- a/libqdutils/display_config.cpp
+++ b/libqdutils/display_config.cpp
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013 The Linux Foundation. All rights reserved.
+* Copyright (c) 2013-2014 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
@@ -37,7 +37,7 @@
int isExternalConnected(void) {
int ret;
- status_t err = FAILED_TRANSACTION;
+ status_t err = (status_t) FAILED_TRANSACTION;
sp<IQService> binder = getBinder();
Parcel inParcel, outParcel;
if(binder != NULL) {
@@ -54,7 +54,7 @@
}
int getDisplayAttributes(int dpy, DisplayAttributes_t& dpyattr) {
- status_t err = FAILED_TRANSACTION;
+ status_t err = (status_t) FAILED_TRANSACTION;
sp<IQService> binder = getBinder();
Parcel inParcel, outParcel;
inParcel.writeInt32(dpy);
@@ -76,7 +76,7 @@
}
int setHSIC(int dpy, const HSICData_t& hsic_data) {
- status_t err = FAILED_TRANSACTION;
+ status_t err = (status_t) FAILED_TRANSACTION;
sp<IQService> binder = getBinder();
Parcel inParcel, outParcel;
inParcel.writeInt32(dpy);
@@ -93,7 +93,7 @@
}
int getDisplayVisibleRegion(int dpy, hwc_rect_t &rect) {
- status_t err = FAILED_TRANSACTION;
+ status_t err = (status_t) FAILED_TRANSACTION;
sp<IQService> binder = getBinder();
Parcel inParcel, outParcel;
inParcel.writeInt32(dpy);
diff --git a/libqdutils/idle_invalidator.cpp b/libqdutils/idle_invalidator.cpp
index 97176a4..b53f1a3 100644
--- a/libqdutils/idle_invalidator.cpp
+++ b/libqdutils/idle_invalidator.cpp
@@ -54,16 +54,43 @@
}
bool IdleInvalidator::threadLoop() {
+ struct timeval lastUpdateTime;
ALOGD_IF(II_DEBUG, "%s", __func__);
- usleep(mSleepTime * 500);
+
+ {
+ //If we are here, update(s) happened, i.e mSleepAgain is set
+ Locker::Autolock _l(mLock);
+ mSleepAgain = false;
+ lastUpdateTime = mLastUpdateTime;
+ }
+
+ struct timeval currentTime;
+ gettimeofday(¤tTime, NULL);
+ int timeSinceUpdateUs = (currentTime.tv_sec - lastUpdateTime.tv_sec) *
+ 1000000 + (currentTime.tv_usec - lastUpdateTime.tv_usec);
+ int sleepDurationUs = mSleepTime * 1000 - timeSinceUpdateUs;
+
+ //Sleep only if the duration required is > 1ms, otherwise its not worth it.
+ if(sleepDurationUs > 1000) {
+ usleep(sleepDurationUs);
+ ALOGD_IF(II_DEBUG, "Slept for %d ms", sleepDurationUs / 1000);
+ }
Locker::Autolock _l(mLock);
+ //If an update happened while we were asleep, sleep again
if(mSleepAgain) {
//We need to sleep again!
mSleepAgain = false;
return true;
}
+#if II_DEBUG
+ gettimeofday(¤tTime, NULL);
+ timeSinceUpdateUs = (currentTime.tv_sec - lastUpdateTime.tv_sec) *
+ 1000000 + (currentTime.tv_usec - lastUpdateTime.tv_usec);
+ ALOGD("Idle refresh after %dms", timeSinceUpdateUs / 1000);
+#endif
+
mHandler((void*)mHwcContext);
return false;
}
@@ -77,8 +104,9 @@
ALOGD_IF(II_DEBUG, "%s", __func__);
}
-void IdleInvalidator::markForSleep() {
+void IdleInvalidator::handleUpdateEvent() {
Locker::Autolock _l(mLock);
+ gettimeofday(&mLastUpdateTime, NULL);
mSleepAgain = true;
//Triggers the threadLoop to run, if not already running.
run(threadName, android::PRIORITY_AUDIO);
diff --git a/libqdutils/idle_invalidator.h b/libqdutils/idle_invalidator.h
index abd9b29..f41c15e 100644
--- a/libqdutils/idle_invalidator.h
+++ b/libqdutils/idle_invalidator.h
@@ -38,6 +38,7 @@
class IdleInvalidator : public android::Thread {
void *mHwcContext;
+ struct timeval mLastUpdateTime;
bool mSleepAgain;
unsigned int mSleepTime;
static InvalidatorHandler mHandler;
@@ -49,7 +50,7 @@
/* init timer obj */
int init(InvalidatorHandler reg_handler, void* user_data, unsigned int
idleSleepTime);
- void markForSleep();
+ void handleUpdateEvent();
/*Overrides*/
virtual bool threadLoop();
virtual int readyToRun();
diff --git a/libqdutils/mdp_version.cpp b/libqdutils/mdp_version.cpp
index b219cd5..9e36980 100644
--- a/libqdutils/mdp_version.cpp
+++ b/libqdutils/mdp_version.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2014, 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
@@ -37,6 +37,25 @@
#define TOKEN_PARAMS_DELIM "="
+#ifndef MDSS_MDP_REV
+enum mdp_rev {
+ MDSS_MDP_HW_REV_100 = 0x10000000, //8974 v1
+ MDSS_MDP_HW_REV_101 = 0x10010000, //8x26
+ MDSS_MDP_HW_REV_102 = 0x10020000, //8974 v2
+ MDSS_MDP_HW_REV_103 = 0x10030000, //8084
+ MDSS_MDP_HW_REV_104 = 0x10040000, //Next version
+ MDSS_MDP_HW_REV_105 = 0x10050000, //Next version
+ MDSS_MDP_HW_REV_107 = 0x10070000, //Next version
+ MDSS_MDP_HW_REV_200 = 0x20000000, //8092
+ MDSS_MDP_HW_REV_206 = 0x20060000, //Future
+};
+#else
+enum mdp_rev {
+ MDSS_MDP_HW_REV_104 = 0x10040000, //Next version
+ MDSS_MDP_HW_REV_206 = 0x20060000, //Future
+};
+#endif
+
MDPVersion::MDPVersion()
{
mMDPVersion = MDSS_V5;
@@ -47,6 +66,7 @@
mFeatures = 0;
mMDPUpscale = 0;
mMDPDownscale = 0;
+ mMacroTileEnabled = false;
mPanelType = NO_PANEL;
mLowBw = 0;
mHighBw = 0;
@@ -79,7 +99,7 @@
char* tokenStr[], int *idx) {
char *tmp_token = NULL;
char *temp_ptr;
- int ret = 0, index = 0;
+ int index = 0;
if (!inputParams) {
return -1;
}
@@ -136,6 +156,14 @@
memset(sysfsPath, 0, sizeof(sysfsPath));
snprintf(sysfsPath , sizeof(sysfsPath),
"/sys/class/graphics/fb0/mdp/caps");
+ char property[PROPERTY_VALUE_MAX];
+ bool enableMacroTile = false;
+
+ if((property_get("persist.hwc.macro_tile_enable", property, NULL) > 0) &&
+ (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
+ (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
+ enableMacroTile = true;
+ }
sysfsFd = fopen(sysfsPath, "rb");
@@ -185,6 +213,11 @@
strlen("decimation"))) {
mFeatures |= MDP_DECIMATION_EN;
}
+ else if(!strncmp(tokens[i], "tile_format",
+ strlen("tile_format"))) {
+ if(enableMacroTile)
+ mMacroTileEnabled = true;
+ }
}
}
}
@@ -239,10 +272,39 @@
return mMDPDownscale;
}
+uint32_t MDPVersion::getMaxMDPUpscale() {
+ return mMDPUpscale;
+}
+
bool MDPVersion::supportsBWC() {
// BWC - Bandwidth Compression
return (mFeatures & MDP_BWC_EN);
}
+bool MDPVersion::supportsMacroTile() {
+ // MACRO TILE support
+ return mMacroTileEnabled;
+}
+
+bool MDPVersion::is8x26() {
+ return (mMdpRev >= MDSS_MDP_HW_REV_101 and
+ mMdpRev < MDSS_MDP_HW_REV_102);
+}
+
+bool MDPVersion::is8x74v2() {
+ return (mMdpRev >= MDSS_MDP_HW_REV_102 and
+ mMdpRev < MDSS_MDP_HW_REV_103);
+}
+
+bool MDPVersion::is8084() {
+ return (mMdpRev >= MDSS_MDP_HW_REV_103 and
+ mMdpRev < MDSS_MDP_HW_REV_104);
+}
+
+bool MDPVersion::is8092() {
+ return (mMdpRev >= MDSS_MDP_HW_REV_200 and
+ mMdpRev < MDSS_MDP_HW_REV_206);
+}
+
}; //namespace qdutils
diff --git a/libqdutils/mdp_version.h b/libqdutils/mdp_version.h
index 60a2985..853b9f5 100644
--- a/libqdutils/mdp_version.h
+++ b/libqdutils/mdp_version.h
@@ -63,17 +63,6 @@
// 0000 - minor number
// 8x26 v1 minor number is 0000
// v2 minor number is 0001 etc..
-enum mdp_rev {
- MDSS_MDP_HW_REV_100 = 0x10000000, //8974 v1
- MDSS_MDP_HW_REV_101 = 0x10010000, //8x26
- MDSS_MDP_HW_REV_102 = 0x10020000, //8974 v2
- MDSS_MDP_HW_REV_103 = 0x10030000, //8084
- MDSS_MDP_HW_REV_104 = 0x10040000, //Next version
- MDSS_MDP_HW_REV_105 = 0x10050000, //Next version
- MDSS_MDP_HW_REV_107 = 0x10070000, //Next version
- MDSS_MDP_HW_REV_200 = 0x20000000, //8092
- MDSS_MDP_HW_REV_206 = 0x20060000, //Future
-};
enum {
MAX_DISPLAY_DIM = 2048,
@@ -117,28 +106,17 @@
uint8_t getDMAPipes() { return mDMAPipes; }
bool supportsDecimation();
uint32_t getMaxMDPDownscale();
+ uint32_t getMaxMDPUpscale();
bool supportsBWC();
+ bool supportsMacroTile();
int getLeftSplit() { return mSplit.left(); }
int getRightSplit() { return mSplit.right(); }
unsigned long getLowBw() { return mLowBw; }
unsigned long getHighBw() { return mHighBw; }
-
- bool is8x26() {
- return (mMdpRev >= MDSS_MDP_HW_REV_101 and
- mMdpRev < MDSS_MDP_HW_REV_102);
- }
- bool is8x74v2() {
- return (mMdpRev >= MDSS_MDP_HW_REV_102 and
- mMdpRev < MDSS_MDP_HW_REV_103);
- }
- bool is8084() {
- return (mMdpRev >= MDSS_MDP_HW_REV_103 and
- mMdpRev < MDSS_MDP_HW_REV_104);
- }
- bool is8092() {
- return (mMdpRev >= MDSS_MDP_HW_REV_200 and
- mMdpRev < MDSS_MDP_HW_REV_206);
- }
+ bool is8x26();
+ bool is8x74v2();
+ bool is8084();
+ bool is8092();
private:
bool updateSysFsInfo();
@@ -157,6 +135,7 @@
uint32_t mFeatures;
uint32_t mMDPDownscale;
uint32_t mMDPUpscale;
+ bool mMacroTileEnabled;
Split mSplit;
unsigned long mLowBw; //kbps
unsigned long mHighBw; //kbps
diff --git a/libqdutils/profiler.cpp b/libqdutils/profiler.cpp
index 031fdc3..997c839 100644
--- a/libqdutils/profiler.cpp
+++ b/libqdutils/profiler.cpp
@@ -28,6 +28,9 @@
*/
#define LOG_NDDEBUG 0
+#define __STDC_FORMAT_MACROS 1
+#include <inttypes.h>
+
#include "profiler.h"
#ifdef DEBUG_CALC_FPS
@@ -104,7 +107,7 @@
debug_fps_metadata.curr_frame = 0;
ALOGD("period: %d", debug_fps_metadata.period);
- ALOGD("ignorethresh_us: %lld", debug_fps_metadata.ignorethresh_us);
+ ALOGD("ignorethresh_us: %"PRId64, debug_fps_metadata.ignorethresh_us);
}
void CalcFps::print_fps(float fps)
@@ -124,7 +127,7 @@
for (unsigned int i = 0;
i < ((debug_fps_metadata.framearrival_steps / 6) + 1);
i++) {
- ALOGD("%lld %lld %lld %lld %lld %lld",
+ ALOGD("%"PRId64" %"PRId64" %"PRId64" %"PRId64" %"PRId64" %"PRId64,
debug_fps_metadata.accum_framearrivals[i*6],
debug_fps_metadata.accum_framearrivals[i*6+1],
debug_fps_metadata.accum_framearrivals[i*6+2],
diff --git a/libqdutils/qdMetaData.cpp b/libqdutils/qdMetaData.cpp
index f39eef9..ecbf873 100644
--- a/libqdutils/qdMetaData.cpp
+++ b/libqdutils/qdMetaData.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2014, 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
@@ -31,6 +31,8 @@
#include <sys/mman.h>
#include <cutils/log.h>
#include <gralloc_priv.h>
+#define __STDC_FORMAT_MACROS 1
+#include <inttypes.h>
#include "qdMetaData.h"
int setMetaData(private_handle_t *handle, DispParamType paramType,
@@ -106,7 +108,7 @@
break;
}
if(munmap(base, size))
- ALOGE("%s: failed to unmap ptr 0x%x, err %d", __func__, (int)base,
+ ALOGE("%s: failed to unmap ptr 0x%"PRIdPTR", err %d", __func__, (intptr_t)base,
errno);
return 0;
}
diff --git a/libqdutils/qd_utils.cpp b/libqdutils/qd_utils.cpp
index 5a457d0..0698b33 100644
--- a/libqdutils/qd_utils.cpp
+++ b/libqdutils/qd_utils.cpp
@@ -31,7 +31,6 @@
#define MAX_FRAME_BUFFER_NAME_SIZE (80)
-#define MAX_DISPLAY_DEVICES (3)
int getHDMINode(void)
{
@@ -40,7 +39,7 @@
char msmFbTypePath[MAX_FRAME_BUFFER_NAME_SIZE];
int j = 0;
- for(j = 0; j < MAX_DISPLAY_DEVICES; j++) {
+ for(j = 0; j < HWC_NUM_DISPLAY_TYPES; j++) {
snprintf (msmFbTypePath, sizeof(msmFbTypePath),
"/sys/class/graphics/fb%d/msm_fb_type", j);
displayDeviceFP = fopen(msmFbTypePath, "r");
@@ -58,7 +57,7 @@
}
}
- if (j < MAX_DISPLAY_DEVICES)
+ if (j < HWC_NUM_DISPLAY_TYPES)
return j;
else
ALOGE("%s: Failed to find HDMI node", __func__);
diff --git a/libqdutils/qd_utils.h b/libqdutils/qd_utils.h
index cca55d5..db6d367 100644
--- a/libqdutils/qd_utils.h
+++ b/libqdutils/qd_utils.h
@@ -42,6 +42,7 @@
#include <sys/poll.h>
#include <sys/resource.h>
#include <cutils/properties.h>
+#include <hardware/hwcomposer.h>
#define EDID_RAW_DATA_SIZE 640
diff --git a/libqservice/IQService.cpp b/libqservice/IQService.cpp
index d2180bb..096444f 100644
--- a/libqservice/IQService.cpp
+++ b/libqservice/IQService.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2010 The Android Open Source Project
- * Copyright (C) 2012-2013, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2012-2014, The Linux Foundation. All rights reserved.
*
* Not a Contribution, Apache license notifications and license are
* retained for attribution purposes only.
@@ -55,7 +55,7 @@
virtual android::status_t dispatch(uint32_t command, const Parcel* inParcel,
Parcel* outParcel) {
ALOGD_IF(QSERVICE_DEBUG, "%s: dispatch in:%p", __FUNCTION__, inParcel);
- status_t err = android::FAILED_TRANSACTION;
+ status_t err = (status_t) android::FAILED_TRANSACTION;
Parcel data;
Parcel *reply = outParcel;
data.writeInterfaceToken(IQService::getInterfaceDescriptor());
@@ -80,7 +80,7 @@
IPCThreadState* ipc = IPCThreadState::self();
const int callerPid = ipc->getCallingPid();
const int callerUid = ipc->getCallingUid();
- const size_t MAX_BUF_SIZE = 1024;
+ const int MAX_BUF_SIZE = 1024;
char callingProcName[MAX_BUF_SIZE] = {0};
getProcName(callerPid, callingProcName, MAX_BUF_SIZE);
diff --git a/libqservice/IQService.h b/libqservice/IQService.h
index f8e58ab..33c3ca0 100644
--- a/libqservice/IQService.h
+++ b/libqservice/IQService.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2010 The Android Open Source Project
- * Copyright (C) 2012-2013, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2012-2014, The Linux Foundation. All rights reserved.
*
* Not a Contribution, Apache license notifications and license are
* retained for attribution purposes only.
@@ -49,6 +49,7 @@
GET_DISPLAY_ATTRIBUTES, // Get display attributes
SET_HSIC_DATA, // Set HSIC on dspp
GET_DISPLAY_VISIBLE_REGION, // Get the visibleRegion for dpy
+ PAUSE_WFD, // Pause/Resume WFD
VPU_COMMAND_LIST_START = 100, //Reserved block for VPU commands
VPU_COMMAND_LIST_END = 200,
COMMAND_LIST_END = 400,
diff --git a/libqservice/QService.cpp b/libqservice/QService.cpp
index aac5788..e4af422 100644
--- a/libqservice/QService.cpp
+++ b/libqservice/QService.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2014, 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
@@ -54,7 +54,7 @@
status_t QService::dispatch(uint32_t command, const Parcel* inParcel,
Parcel* outParcel) {
- status_t err = FAILED_TRANSACTION;
+ status_t err = (status_t) FAILED_TRANSACTION;
if (mClient.get()) {
ALOGD_IF(QSERVICE_DEBUG, "Dispatching command: %d", command);
err = mClient->notifyCallback(command, inParcel, outParcel);
diff --git a/libqservice/QServiceUtils.h b/libqservice/QServiceUtils.h
index 3d1adc0..a5f4f7f 100644
--- a/libqservice/QServiceUtils.h
+++ b/libqservice/QServiceUtils.h
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013 The Linux Foundation. All rights reserved.
+* Copyright (c) 2013-14 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
@@ -49,7 +49,7 @@
}
inline android::status_t sendSingleParam(uint32_t command, uint32_t value) {
- android::status_t err = android::FAILED_TRANSACTION;
+ android::status_t err = (status_t) android::FAILED_TRANSACTION;
android::sp<qService::IQService> binder = getBinder();
android::Parcel inParcel, outParcel;
inParcel.writeInt32(value);
@@ -83,4 +83,8 @@
return sendSingleParam(qService::IQService::BUFFER_MIRRORMODE, enable);
}
+inline android::status_t pauseWFD(uint32_t pause) {
+ return sendSingleParam(qService::IQService::PAUSE_WFD, pause);
+}
+
#endif /* end of include guard: QSERVICEUTILS_H */