Implement color layers in RenderEngine::drawLayers

Next cl will be using buffer sources. Afterwards with proper test
coverage we can try baking into the composition loop to verify that
there's no regressions.

Bug: 118461793
Change-Id: I897f6f6dfadcc05d6fa09a11ffad240f67996ad6
Test: librenderengine_test
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 53b0e4c..51cf188 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -648,27 +648,89 @@
     return success;
 }
 
-status_t GLESRenderEngine::drawLayers(const DisplaySettings& /*settings*/,
-                                      const std::vector<LayerSettings>& /*layers*/,
-                                      ANativeWindowBuffer* const /*buffer*/,
-                                      base::unique_fd* /*displayFence*/) const {
+status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
+                                      const std::vector<LayerSettings>& layers,
+                                      ANativeWindowBuffer* const buffer,
+                                      base::unique_fd* drawFence) {
+    if (layers.empty()) {
+        ALOGV("Drawing empty layer stack");
+        return NO_ERROR;
+    }
+
+    BindNativeBufferAsFramebuffer fbo(*this, buffer);
+
+    if (fbo.getStatus() != NO_ERROR) {
+        ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).",
+              buffer->handle);
+        checkErrors();
+        return fbo.getStatus();
+    }
+
+    setViewportAndProjection(display.physicalDisplay, display.clip);
+
+    setOutputDataSpace(display.outputDataspace);
+    setDisplayMaxLuminance(display.maxLuminance);
+
+    mat4 projectionMatrix = mState.projectionMatrix * display.globalTransform;
+
+    Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2);
+    for (auto layer : layers) {
+        // for now, assume that all pixel sources are solid colors.
+        // TODO(alecmouri): support buffer sources
+        if (layer.source.buffer.buffer != nullptr) {
+            continue;
+        }
+
+        setColorTransform(display.colorTransform * layer.colorTransform);
+
+        mState.projectionMatrix = projectionMatrix * layer.geometry.positionTransform;
+
+        FloatRect bounds = layer.geometry.boundaries;
+        Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
+        position[0] = vec2(bounds.left, bounds.top);
+        position[1] = vec2(bounds.left, bounds.bottom);
+        position[2] = vec2(bounds.right, bounds.bottom);
+        position[3] = vec2(bounds.right, bounds.top);
+
+        half3 solidColor = layer.source.solidColor;
+        half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer.alpha);
+        setupLayerBlending(/*premultipliedAlpha=*/true, /*opaque=*/false, /*disableTexture=*/true,
+                           color, /*cornerRadius=*/0.0);
+        setSourceDataSpace(layer.sourceDataspace);
+
+        drawMesh(mesh);
+    }
+
+    *drawFence = flush();
+    // If flush failed or we don't support native fences, we need to force the
+    // gl command stream to be executed.
+    if (drawFence->get() < 0) {
+        bool success = finish();
+        if (!success) {
+            ALOGE("Failed to flush RenderEngine commands");
+            checkErrors();
+            // Chances are, something illegal happened (either the caller passed
+            // us bad parameters, or we messed up our shader generation).
+            return INVALID_OPERATION;
+        }
+    }
+
+    checkErrors();
     return NO_ERROR;
 }
 
 void GLESRenderEngine::setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
                                                 ui::Transform::orientation_flags rotation) {
-    int32_t l = sourceCrop.left;
-    int32_t r = sourceCrop.right;
-    int32_t b = sourceCrop.bottom;
-    int32_t t = sourceCrop.top;
-    std::swap(t, b);
-    mat4 m = mat4::ortho(l, r, b, t, 0, 1);
+    setViewportAndProjection(Rect(vpw, vph), sourceCrop);
+
+    if (rotation == ui::Transform::ROT_0) {
+        return;
+    }
 
     // Apply custom rotation to the projection.
     float rot90InRadians = 2.0f * static_cast<float>(M_PI) / 4.0f;
+    mat4 m = mState.projectionMatrix;
     switch (rotation) {
-        case ui::Transform::ROT_0:
-            break;
         case ui::Transform::ROT_90:
             m = mat4::rotate(rot90InRadians, vec3(0, 0, 1)) * m;
             break;
@@ -681,11 +743,18 @@
         default:
             break;
     }
-
-    glViewport(0, 0, vpw, vph);
     mState.projectionMatrix = m;
-    mVpWidth = vpw;
-    mVpHeight = vph;
+}
+
+void GLESRenderEngine::setViewportAndProjection(Rect viewport, Rect clip) {
+    mVpWidth = viewport.getWidth();
+    mVpHeight = viewport.getHeight();
+
+    // We pass the the top left corner instead of the bottom left corner,
+    // because since we're rendering off-screen first.
+    glViewport(viewport.left, viewport.top, mVpWidth, mVpHeight);
+
+    mState.projectionMatrix = mat4::ortho(clip.left, clip.right, clip.top, clip.bottom, 0, 1);
 }
 
 void GLESRenderEngine::setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,