drm_hwcomposer: Allow for multiple transforms at once

Because sometimes one just ain't enough, allow more than
one transform at a time.

Bug: chrome-os-partner:46710
Test: Tested with the CTS Verifier "Camera Orientation" test

Change-Id: Ie5f9bbbc7c89964feafc78150e18512861c85b69
Signed-off-by: Sean Paul <seanpaul@chromium.org>
diff --git a/drmdisplaycomposition.cpp b/drmdisplaycomposition.cpp
index b266bd7..300414d 100644
--- a/drmdisplaycomposition.cpp
+++ b/drmdisplaycomposition.cpp
@@ -443,23 +443,52 @@
   *out << buffer->width << "/" << buffer->height << "/" << buffer->format;
 }
 
-static const char *TransformToString(DrmHwcTransform transform) {
-  switch (transform) {
-    case DrmHwcTransform::kIdentity:
-      return "IDENTITY";
-    case DrmHwcTransform::kFlipH:
-      return "FLIPH";
-    case DrmHwcTransform::kFlipV:
-      return "FLIPV";
-    case DrmHwcTransform::kRotate90:
-      return "ROTATE90";
-    case DrmHwcTransform::kRotate180:
-      return "ROTATE180";
-    case DrmHwcTransform::kRotate270:
-      return "ROTATE270";
-    default:
-      return "<invalid>";
+static void DumpTransform(uint32_t transform, std::ostringstream *out) {
+  *out << "[";
+
+  if (transform == 0)
+    *out << "IDENTITY";
+
+  bool separator = false;
+  if (transform & DrmHwcTransform::kFlipH) {
+    *out << "FLIPH";
+    separator = true;
   }
+  if (transform & DrmHwcTransform::kFlipV) {
+    if (separator)
+      *out << "|";
+    *out << "FLIPV";
+    separator = true;
+  }
+  if (transform & DrmHwcTransform::kRotate90) {
+    if (separator)
+      *out << "|";
+    *out << "ROTATE90";
+    separator = true;
+  }
+  if (transform & DrmHwcTransform::kRotate180) {
+    if (separator)
+      *out << "|";
+    *out << "ROTATE180";
+    separator = true;
+  }
+  if (transform & DrmHwcTransform::kRotate270) {
+    if (separator)
+      *out << "|";
+    *out << "ROTATE270";
+    separator = true;
+  }
+
+  uint32_t valid_bits = DrmHwcTransform::kFlipH | DrmHwcTransform::kFlipH |
+                        DrmHwcTransform::kRotate90 |
+                        DrmHwcTransform::kRotate180 |
+                        DrmHwcTransform::kRotate270;
+  if (transform & ~valid_bits) {
+    if (separator)
+      *out << "|";
+    *out << "INVALID";
+  }
+  *out << "]";
 }
 
 static const char *BlendingToString(DrmHwcBlending blending) {
@@ -523,8 +552,9 @@
     if (layer.protected_usage())
       *out << " protected";
 
-    *out << " transform=" << TransformToString(layer.transform)
-         << " blending[a=" << (int)layer.alpha
+    *out << " transform=";
+    DumpTransform(layer.transform, out);
+    *out << " blending[a=" << (int)layer.alpha
          << "]=" << BlendingToString(layer.blending) << " source_crop";
     layer.source_crop.Dump(out);
     *out << " display_frame";
diff --git a/drmdisplaycompositor.cpp b/drmdisplaycompositor.cpp
index d18c71b..4a904b2 100644
--- a/drmdisplaycompositor.cpp
+++ b/drmdisplaycompositor.cpp
@@ -684,30 +684,18 @@
         source_crop = layer.source_crop;
         if (layer.blending == DrmHwcBlending::kPreMult)
           alpha = layer.alpha;
-        switch (layer.transform) {
-          case DrmHwcTransform::kFlipH:
-            rotation = 1 << DRM_REFLECT_X;
-            break;
-          case DrmHwcTransform::kFlipV:
-            rotation = 1 << DRM_REFLECT_Y;
-            break;
-          case DrmHwcTransform::kRotate90:
-            rotation = 1 << DRM_ROTATE_90;
-            break;
-          case DrmHwcTransform::kRotate180:
-            rotation = 1 << DRM_ROTATE_180;
-            break;
-          case DrmHwcTransform::kRotate270:
-            rotation = 1 << DRM_ROTATE_270;
-            break;
-          case DrmHwcTransform::kIdentity:
-            rotation = 0;
-            break;
-          default:
-            ALOGE("Invalid transform value 0x%x given", layer.transform);
-            break;
-        }
-        break;
+
+        rotation = 0;
+        if (layer.transform & DrmHwcTransform::kFlipH)
+          rotation |= 1 << DRM_REFLECT_X;
+        if (layer.transform & DrmHwcTransform::kFlipV)
+          rotation |= 1 << DRM_REFLECT_Y;
+        if (layer.transform & DrmHwcTransform::kRotate90)
+          rotation |= 1 << DRM_ROTATE_90;
+        else if (layer.transform & DrmHwcTransform::kRotate180)
+          rotation |= 1 << DRM_ROTATE_180;
+        else if (layer.transform & DrmHwcTransform::kRotate270)
+          rotation |= 1 << DRM_ROTATE_270;
       }
     }
 
diff --git a/drmhwcomposer.h b/drmhwcomposer.h
index e0f8d2b..d087873 100644
--- a/drmhwcomposer.h
+++ b/drmhwcomposer.h
@@ -119,13 +119,13 @@
 template <typename T>
 using DrmHwcRect = separate_rects::Rect<T>;
 
-enum class DrmHwcTransform : uint32_t {
+enum DrmHwcTransform {
   kIdentity = 0,
-  kFlipH = HWC_TRANSFORM_FLIP_H,
-  kFlipV = HWC_TRANSFORM_FLIP_V,
-  kRotate90 = HWC_TRANSFORM_ROT_90,
-  kRotate180 = HWC_TRANSFORM_ROT_180,
-  kRotate270 = HWC_TRANSFORM_ROT_270,
+  kFlipH = 1 << 0,
+  kFlipV = 1 << 1,
+  kRotate90 = 1 << 2,
+  kRotate180 = 1 << 3,
+  kRotate270 = 1 << 4,
 };
 
 enum class DrmHwcBlending : int32_t {
@@ -139,7 +139,7 @@
   int gralloc_buffer_usage = 0;
   DrmHwcBuffer buffer;
   DrmHwcNativeHandle handle;
-  DrmHwcTransform transform = DrmHwcTransform::kIdentity;
+  uint32_t transform;
   DrmHwcBlending blending = DrmHwcBlending::kNone;
   uint8_t alpha = 0xff;
   DrmHwcRect<float> source_crop;
diff --git a/glworker.cpp b/glworker.cpp
index 0b98a51..7f154aa 100644
--- a/glworker.cpp
+++ b/glworker.cpp
@@ -332,40 +332,34 @@
     cmd.texture_count++;
     src.texture_index = texture_index;
 
-    bool swap_xy, flip_xy[2];
-    switch (layer.transform) {
-      case DrmHwcTransform::kFlipH:
-        swap_xy = false;
-        flip_xy[0] = true;
-        flip_xy[1] = false;
-        break;
-      case DrmHwcTransform::kFlipV:
-        swap_xy = false;
-        flip_xy[0] = false;
-        flip_xy[1] = true;
-        break;
-      case DrmHwcTransform::kRotate90:
-        swap_xy = true;
-        flip_xy[0] = false;
-        flip_xy[1] = true;
-        break;
-      case DrmHwcTransform::kRotate180:
-        swap_xy = false;
+    bool swap_xy = false;
+    bool flip_xy[2] = { false, false };
+
+    if (layer.transform == DrmHwcTransform::kRotate180) {
+      swap_xy = false;
+      flip_xy[0] = true;
+      flip_xy[1] = true;
+    } else if (layer.transform == DrmHwcTransform::kRotate270) {
+      swap_xy = true;
+      flip_xy[0] = true;
+      flip_xy[1] = false;
+    } else if (layer.transform & DrmHwcTransform::kRotate90) {
+      swap_xy = true;
+      if (layer.transform & DrmHwcTransform::kFlipH) {
         flip_xy[0] = true;
         flip_xy[1] = true;
-        break;
-      case DrmHwcTransform::kRotate270:
-        swap_xy = true;
-        flip_xy[0] = true;
-        flip_xy[1] = false;
-        break;
-      default:
-        ALOGE("Unknown transform for layer: defaulting to identity transform");
-      case DrmHwcTransform::kIdentity:
-        swap_xy = false;
+      } else if (layer.transform & DrmHwcTransform::kFlipV) {
         flip_xy[0] = false;
         flip_xy[1] = false;
-        break;
+      } else {
+        flip_xy[0] = false;
+        flip_xy[1] = true;
+      }
+    } else {
+      if (layer.transform & DrmHwcTransform::kFlipH)
+        flip_xy[0] = true;
+      if (layer.transform & DrmHwcTransform::kFlipV)
+        flip_xy[1] = true;
     }
 
     if (swap_xy)
diff --git a/hwcomposer.cpp b/hwcomposer.cpp
index e755273..c6f636b 100644
--- a/hwcomposer.cpp
+++ b/hwcomposer.cpp
@@ -252,28 +252,22 @@
       sf_layer->displayFrame.left, sf_layer->displayFrame.top,
       sf_layer->displayFrame.right, sf_layer->displayFrame.bottom);
 
-  switch (sf_layer->transform) {
-    case 0:
-      transform = DrmHwcTransform::kIdentity;
-      break;
-    case HWC_TRANSFORM_FLIP_H:
-      transform = DrmHwcTransform::kFlipH;
-      break;
-    case HWC_TRANSFORM_FLIP_V:
-      transform = DrmHwcTransform::kFlipV;
-      break;
-    case HWC_TRANSFORM_ROT_90:
-      transform = DrmHwcTransform::kRotate90;
-      break;
-    case HWC_TRANSFORM_ROT_180:
-      transform = DrmHwcTransform::kRotate180;
-      break;
-    case HWC_TRANSFORM_ROT_270:
-      transform = DrmHwcTransform::kRotate270;
-      break;
-    default:
-      ALOGE("Invalid transform in hwc_layer_1_t %d", sf_layer->transform);
-      return -EINVAL;
+  transform = 0;
+  // 270* and 180* cannot be combined with flips. More specifically, they
+  // already contain both horizontal and vertical flips, so those fields are
+  // redundant in this case. 90* rotation can be combined with either horizontal
+  // flip or vertical flip, so treat it differently
+  if (sf_layer->transform == HWC_TRANSFORM_ROT_270) {
+    transform = DrmHwcTransform::kRotate270;
+  } else if (sf_layer->transform == HWC_TRANSFORM_ROT_180) {
+    transform = DrmHwcTransform::kRotate180;
+  } else {
+    if (sf_layer->transform & HWC_TRANSFORM_FLIP_H)
+      transform |= DrmHwcTransform::kFlipH;
+    if (sf_layer->transform & HWC_TRANSFORM_FLIP_V)
+      transform |= DrmHwcTransform::kFlipV;
+    if (sf_layer->transform & HWC_TRANSFORM_ROT_90)
+      transform |= DrmHwcTransform::kRotate90;
   }
 
   switch (sf_layer->blending) {