Merge "sdm: Use safe mode on External display on low end device"
diff --git a/libmemtrack/kgsl.c b/libmemtrack/kgsl.c
index 11c7e8a..9ec69f0 100644
--- a/libmemtrack/kgsl.c
+++ b/libmemtrack/kgsl.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2013, 2016 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -48,7 +48,6 @@
     FILE *fp;
     char line[1024];
     char tmp[128];
-    bool is_surfaceflinger = false;
     size_t accounted_size = 0;
     size_t unaccounted_size = 0;
 
@@ -59,16 +58,6 @@
         return 0;
     }
 
-    snprintf(tmp, sizeof(tmp), "/proc/%d/cmdline", pid);
-    fp = fopen(tmp, "r");
-    if (fp != NULL) {
-        if (fgets(line, sizeof(line), fp)) {
-            if (strcmp(line, "/system/bin/surfaceflinger") == 0)
-                is_surfaceflinger = true;
-        }
-        fclose(fp);
-    }
-
     memcpy(records, record_templates,
            sizeof(struct memtrack_record) * allocated_records);
 
@@ -87,19 +76,20 @@
         char line_type[7];
         char flags[9];
         char line_usage[19];
-        int ret;
+        int ret, egl_surface_count = 0, egl_image_count = 0;
 
         if (fgets(line, sizeof(line), fp) == NULL) {
             break;
         }
 
         /* Format:
-         *  gpuaddr useraddr     size    id flags       type            usage sglen mapsize
-         * 545ba000 545ba000     4096     1 -----pY     gpumem      arraybuffer     1  4096
+         *  gpuaddr useraddr     size    id flags       type            usage sglen mapsize eglsrf eglimg
+         * 545ba000 545ba000     4096     1 -----pY     gpumem      arraybuffer     1  4096      0      0
          */
-        ret = sscanf(line, "%*x %*x %lu %*d %8s %6s %18s %*d %lu\n",
-                     &size, flags, line_type, line_usage, &mapsize);
-        if (ret != 5) {
+        ret = sscanf(line, "%*x %*x %lu %*d %8s %6s %18s %*d %lu %6d %6d\n",
+			&size, flags, line_type, line_usage, &mapsize,
+			&egl_surface_count, &egl_image_count);
+        if (ret != 7) {
             continue;
         }
 
@@ -112,9 +102,10 @@
                 unaccounted_size += size;
 
         } else if (type == MEMTRACK_TYPE_GRAPHICS && strcmp(line_type, "ion") == 0) {
-            if ( !(is_surfaceflinger == false && strcmp(line_usage, "egl_surface") == 0)) {
+            if (strcmp(line_usage, "egl_surface") == 0)
                 unaccounted_size += size;
-            }
+            else if (egl_surface_count == 0)
+		unaccounted_size += size / (egl_image_count ? egl_image_count : 1);
         }
     }
 
diff --git a/sdm/include/core/layer_buffer.h b/sdm/include/core/layer_buffer.h
index 4f80f86..a98bf44 100644
--- a/sdm/include/core/layer_buffer.h
+++ b/sdm/include/core/layer_buffer.h
@@ -273,6 +273,13 @@
                                 //!< Specifies the buffer id.
 };
 
+// This enum represents buffer layout types.
+enum BufferLayout {
+  kLinear,    //!< Linear data
+  kUBWC,      //!< UBWC aligned data
+  kTPTiled    //!< Tightly Packed data
+};
+
 }  // namespace sdm
 
 #endif  // __LAYER_BUFFER_H__
diff --git a/sdm/include/private/hw_info_types.h b/sdm/include/private/hw_info_types.h
index b960955..e6e8b6c 100644
--- a/sdm/include/private/hw_info_types.h
+++ b/sdm/include/private/hw_info_types.h
@@ -128,6 +128,7 @@
   uint32_t num_rotator = 0;
   bool has_downscale = false;
   std::string device_path = "";
+  float min_downscale = 2.0f;
 
   void Reset() { *this = HWRotatorInfo(); }
 };
diff --git a/sdm/include/private/resource_interface.h b/sdm/include/private/resource_interface.h
index 3f34e91..48b7a02 100644
--- a/sdm/include/private/resource_interface.h
+++ b/sdm/include/private/resource_interface.h
@@ -51,7 +51,7 @@
   virtual void Purge(Handle display_ctx) = 0;
   virtual DisplayError SetMaxMixerStages(Handle display_ctx, uint32_t max_mixer_stages) = 0;
   virtual DisplayError ValidateScaling(const LayerRect &crop, const LayerRect &dst,
-                                       bool rotate90, bool ubwc_tiled,
+                                       bool rotate90, BufferLayout layout,
                                        bool use_rotator_downscale) = 0;
   virtual DisplayError ValidateCursorConfig(Handle display_ctx, const Layer *layer,
                                             bool is_top) = 0;
diff --git a/sdm/include/utils/formats.h b/sdm/include/utils/formats.h
index 67548f3..dd819dc 100644
--- a/sdm/include/utils/formats.h
+++ b/sdm/include/utils/formats.h
@@ -37,6 +37,7 @@
 bool IsUBWCFormat(LayerBufferFormat format);
 bool Is10BitFormat(LayerBufferFormat format);
 const char *GetFormatString(const LayerBufferFormat &format);
+BufferLayout GetBufferLayout(LayerBufferFormat format);
 
 }  // namespace sdm
 
diff --git a/sdm/libs/core/comp_manager.cpp b/sdm/libs/core/comp_manager.cpp
index a00e8dd..9fc44e0 100644
--- a/sdm/libs/core/comp_manager.cpp
+++ b/sdm/libs/core/comp_manager.cpp
@@ -33,6 +33,12 @@
 
 namespace sdm {
 
+static bool NeedsScaledComposition(const DisplayConfigVariableInfo &fb_config,
+                                   const HWMixerAttributes &mixer_attributes) {
+  return ((fb_config.x_pixels != mixer_attributes.width) ||
+          (fb_config.y_pixels != mixer_attributes.height));
+}
+
 DisplayError CompManager::Init(const HWResourceInfo &hw_res_info,
                                ExtensionInterface *extension_intf,
                                BufferAllocator *buffer_allocator,
@@ -122,6 +128,7 @@
     max_sde_ext_layers_ = UINT32(Debug::GetExtMaxlayers());
   }
 
+  display_comp_ctx->scaled_composition = NeedsScaledComposition(fb_config, mixer_attributes);
   DLOGV_IF(kTagCompManager, "registered display bit mask 0x%x, configured display bit mask 0x%x, " \
            "display type %d", registered_displays_.to_ulong(), configured_displays_.to_ulong(),
            display_comp_ctx->display_type);
@@ -200,6 +207,8 @@
     }
   }
 
+  display_comp_ctx->scaled_composition = NeedsScaledComposition(fb_config, mixer_attributes);
+
   return error;
 }
 
@@ -430,8 +439,8 @@
 
 DisplayError CompManager::ValidateScaling(const LayerRect &crop, const LayerRect &dst,
                                           bool rotate90) {
-  return resource_intf_->ValidateScaling(crop, dst, rotate90, Debug::IsUbwcTiledFrameBuffer(),
-                                         true /* use_rotator_downscale */);
+  BufferLayout layout = Debug::IsUbwcTiledFrameBuffer() ? kUBWC : kLinear;
+  return resource_intf_->ValidateScaling(crop, dst, rotate90, layout, true);
 }
 
 DisplayError CompManager::ValidateCursorPosition(Handle display_ctx, HWLayers *hw_layers,
@@ -451,7 +460,8 @@
   bool supported = false;
   int32_t gpu_index = -1;
 
-  if (!layer_stack->flags.cursor_present) {
+  // HW Cursor cannot be used, if Display configuration needs scaled composition.
+  if (display_comp_ctx->scaled_composition || !layer_stack->flags.cursor_present) {
     return supported;
   }
 
diff --git a/sdm/libs/core/comp_manager.h b/sdm/libs/core/comp_manager.h
index 39a3bf3..49a7ce0 100644
--- a/sdm/libs/core/comp_manager.h
+++ b/sdm/libs/core/comp_manager.h
@@ -95,6 +95,7 @@
     bool is_primary_panel = false;
     bool valid_cursor = false;
     PUConstraints pu_constraints = {};
+    bool scaled_composition = false;
   };
 
   Locker locker_;
diff --git a/sdm/libs/core/fb/hw_info.cpp b/sdm/libs/core/fb/hw_info.cpp
index ef450c0..9f9cae4 100644
--- a/sdm/libs/core/fb/hw_info.cpp
+++ b/sdm/libs/core/fb/hw_info.cpp
@@ -386,18 +386,20 @@
     }
   }
 
-  DLOGI("MDSS Rotator: Count = %d, Downscale = %d", hw_resource->hw_rot_info.num_rotator,
-        hw_resource->hw_rot_info.has_downscale);
+  DLOGI("MDSS Rotator: Count = %d, Downscale = %d, Min_downscale = %f",
+        hw_resource->hw_rot_info.num_rotator, hw_resource->hw_rot_info.has_downscale,
+        hw_resource->hw_rot_info.min_downscale);
 
   return kErrorNone;
 }
 
 DisplayError HWInfo::GetV4L2RotatorInfo(HWResourceInfo *hw_resource) {
+  string v4l2_path = "/sys/class/video4linux/video";
   const uint32_t kMaxV4L2Nodes = 64;
   bool found = false;
 
   for (uint32_t i = 0; (i < kMaxV4L2Nodes) && (false == found); i++) {
-    string path = "/sys/class/video4linux/video" + to_string(i) + "/name";
+    string path = v4l2_path + to_string(i) + "/name";
     Sys::fstream fs(path, fstream::in);
     if (!fs.is_open()) {
       continue;
@@ -410,13 +412,32 @@
        hw_resource->hw_rot_info.num_rotator++;
        hw_resource->hw_rot_info.type = HWRotatorInfo::ROT_TYPE_V4L2;
        hw_resource->hw_rot_info.has_downscale = true;
+
+       string caps_path = v4l2_path + to_string(i) + "/device/caps";
+       Sys::fstream caps_fs(caps_path, fstream::in);
+
+       if (caps_fs.is_open()) {
+         uint32_t token_count = 0;
+         const uint32_t max_count = 10;
+         char *tokens[max_count] = { NULL };
+         string caps;
+         while (Sys::getline_(caps_fs, caps)) {
+           if (!ParseString(caps.c_str(), tokens, max_count, ":, =\n", &token_count)) {
+             if (!strncmp(tokens[0], "min_downscale", strlen("min_downscale"))) {
+               hw_resource->hw_rot_info.min_downscale = FLOAT(atof(tokens[1]));
+             }
+           }
+         }
+       }
+
        // We support only 1 rotator
        found = true;
     }
   }
 
-  DLOGI("V4L2 Rotator: Count = %d, Downscale = %d", hw_resource->hw_rot_info.num_rotator,
-        hw_resource->hw_rot_info.has_downscale);
+  DLOGI("V4L2 Rotator: Count = %d, Downscale = %d, Min_downscale = %f",
+        hw_resource->hw_rot_info.num_rotator, hw_resource->hw_rot_info.has_downscale,
+        hw_resource->hw_rot_info.min_downscale);
 
   return kErrorNone;
 }
diff --git a/sdm/libs/core/fb/hw_primary.cpp b/sdm/libs/core/fb/hw_primary.cpp
index 6f62143..e4a055e 100644
--- a/sdm/libs/core/fb/hw_primary.cpp
+++ b/sdm/libs/core/fb/hw_primary.cpp
@@ -223,10 +223,11 @@
     return kErrorHardware;
   }
 
-  // If driver doesn't return width/height information, default to 160 dpi
+  // If driver doesn't return width/height information, default to 320 dpi
   if (INT(var_screeninfo.width) <= 0 || INT(var_screeninfo.height) <= 0) {
-    var_screeninfo.width  = UINT32(((FLOAT(var_screeninfo.xres) * 25.4f)/160.0f) + 0.5f);
-    var_screeninfo.height = UINT32(((FLOAT(var_screeninfo.yres) * 25.4f)/160.0f) + 0.5f);
+    var_screeninfo.width  = UINT32(((FLOAT(var_screeninfo.xres) * 25.4f)/320.0f) + 0.5f);
+    var_screeninfo.height = UINT32(((FLOAT(var_screeninfo.yres) * 25.4f)/320.0f) + 0.5f);
+    DLOGW("Driver doesn't report panel physical width and height - defaulting to 320dpi");
   }
 
   display_attributes_.x_pixels = var_screeninfo.xres;
diff --git a/sdm/libs/core/resource_default.cpp b/sdm/libs/core/resource_default.cpp
index 54a6658..39b792e 100644
--- a/sdm/libs/core/resource_default.cpp
+++ b/sdm/libs/core/resource_default.cpp
@@ -558,8 +558,8 @@
     return error;
   }
 
-  bool ubwc_tiled = IsUBWCFormat(layer->input_buffer->format);
-  error = ValidateScaling(src_rect, dst_rect, false /*rotated90 */, ubwc_tiled,
+  BufferLayout layout = GetBufferLayout(layer->input_buffer->format);
+  error = ValidateScaling(src_rect, dst_rect, false /*rotated90 */, layout,
                           false /* use_rotator_downscale */);
   if (error != kErrorNone) {
     return error;
@@ -716,7 +716,7 @@
   return kErrorNone;
 }
 
-DisplayError ResourceDefault::ValidatePipeParams(HWPipeInfo *pipe_info, bool ubwc_tiled) {
+DisplayError ResourceDefault::ValidatePipeParams(HWPipeInfo *pipe_info, LayerBufferFormat format) {
   DisplayError error = kErrorNone;
 
   const LayerRect &src_rect = pipe_info->src_roi;
@@ -727,7 +727,8 @@
     return error;
   }
 
-  error = ValidateScaling(src_rect, dst_rect, false /* rotated90 */, ubwc_tiled,
+  BufferLayout layout = GetBufferLayout(format);
+  error = ValidateScaling(src_rect, dst_rect, false /* rotated90 */, layout,
                           false /* use_rotator_downscale */);
   if (error != kErrorNone) {
     return error;
@@ -737,7 +738,7 @@
 }
 
 DisplayError ResourceDefault::ValidateScaling(const LayerRect &crop, const LayerRect &dst,
-                                              bool rotate90, bool ubwc_tiled,
+                                              bool rotate90, BufferLayout layout,
                                               bool use_rotator_downscale) {
   DisplayError error = kErrorNone;
 
@@ -749,7 +750,7 @@
     return error;
   }
 
-  error = ValidateDownScaling(scale_x, scale_y, ubwc_tiled);
+  error = ValidateDownScaling(scale_x, scale_y, (layout != kLinear));
   if (error != kErrorNone) {
     return error;
   }
@@ -884,8 +885,7 @@
     return kErrorNotSupported;
   }
 
-  bool ubwc_tiled = IsUBWCFormat(layer->input_buffer->format);
-  error = ValidatePipeParams(left_pipe, ubwc_tiled);
+  error = ValidatePipeParams(left_pipe, layer->input_buffer->format);
   if (error != kErrorNone) {
     goto PipeConfigExit;
   }
@@ -894,7 +894,7 @@
     // Make sure the  left and right ROI are conjunct
     right_pipe->src_roi.left = left_pipe->src_roi.right;
     right_pipe->dst_roi.left = left_pipe->dst_roi.right;
-    error = ValidatePipeParams(right_pipe, ubwc_tiled);
+    error = ValidatePipeParams(right_pipe, layer->input_buffer->format);
   }
 
 PipeConfigExit:
diff --git a/sdm/libs/core/resource_default.h b/sdm/libs/core/resource_default.h
index 9f08155..9fab0d0 100644
--- a/sdm/libs/core/resource_default.h
+++ b/sdm/libs/core/resource_default.h
@@ -57,8 +57,8 @@
   virtual DisplayError PostCommit(Handle display_ctx, HWLayers *hw_layers);
   virtual void Purge(Handle display_ctx);
   virtual DisplayError SetMaxMixerStages(Handle display_ctx, uint32_t max_mixer_stages);
-  virtual DisplayError ValidateScaling(const LayerRect &crop, const LayerRect &dst,
-                                       bool rotate90, bool ubwc_tiled, bool use_rotator_downscale);
+  virtual DisplayError ValidateScaling(const LayerRect &crop, const LayerRect &dst, bool rotate90,
+                                       BufferLayout layout, bool use_rotator_downscale);
   DisplayError ValidateCursorConfig(Handle display_ctx, const Layer *layer, bool is_top);
   DisplayError ValidateCursorPosition(Handle display_ctx, HWLayers *hw_layers, int x, int y);
   DisplayError SetMaxBandwidthMode(HWBwModes mode);
@@ -121,7 +121,7 @@
   bool CalculateCropRects(const LayerRect &scissor, LayerRect *crop, LayerRect *dst);
   DisplayError ValidateLayerParams(const Layer *layer);
   DisplayError ValidateDimensions(const LayerRect &crop, const LayerRect &dst);
-  DisplayError ValidatePipeParams(HWPipeInfo *pipe_info, bool ubwc_tiled);
+  DisplayError ValidatePipeParams(HWPipeInfo *pipe_info, LayerBufferFormat format);
   DisplayError ValidateDownScaling(float scale_x, float scale_y, bool ubwc_tiled);
   DisplayError ValidateUpScaling(float scale_x, float scale_y);
   DisplayError GetScaleFactor(const LayerRect &crop, const LayerRect &dst, float *scale_x,
diff --git a/sdm/libs/hwc/hwc_session.cpp b/sdm/libs/hwc/hwc_session.cpp
index 6aab6d6..a7f4d67 100644
--- a/sdm/libs/hwc/hwc_session.cpp
+++ b/sdm/libs/hwc/hwc_session.cpp
@@ -275,6 +275,7 @@
 
     if (hwc_session->need_invalidate_) {
       hwc_procs->invalidate(hwc_procs);
+      hwc_session->need_invalidate_ = false;
     }
 
     hwc_session->HandleSecureDisplaySession(displays);
diff --git a/sdm/libs/utils/formats.cpp b/sdm/libs/utils/formats.cpp
index 546c0c7..8e9d0b8 100644
--- a/sdm/libs/utils/formats.cpp
+++ b/sdm/libs/utils/formats.cpp
@@ -114,5 +114,14 @@
   }
 }
 
+BufferLayout GetBufferLayout(LayerBufferFormat format) {
+  switch (format) {
+  case kFormatYCbCr420TP10Ubwc:
+    return kTPTiled;
+  default:
+    return (IsUBWCFormat(format) ? kUBWC : kLinear);
+  }
+}
+
 }  // namespace sdm