OSDN Git Service

drm_hwcomposer: Do not close duplicate gem handles in nvimporter
[android-x86/external-drm_hwcomposer.git] / glworker.cpp
index 0cb2bf7..162005c 100644 (file)
  */
 
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#define LOG_TAG "GLWorker"
+#define LOG_TAG "hwc-gl-worker"
 
+#include <algorithm>
 #include <string>
 #include <sstream>
 
 #include <sys/resource.h>
 
-#include <sync/sync.h>
-#include <sw_sync.h>
+#include <cutils/properties.h>
 
 #include <hardware/hardware.h>
 #include <hardware/hwcomposer.h>
@@ -33,6 +33,8 @@
 
 #include <utils/Trace.h>
 
+#include "drmdisplaycomposition.h"
+
 #include "glworker.h"
 
 #include "seperate_rects.h"
@@ -49,6 +51,17 @@ namespace android {
 typedef seperate_rects::Rect<float> FRect;
 typedef seperate_rects::RectSet<uint64_t, float> FRectSet;
 
+// clang-format off
+// Column-major order:
+// float mat[4] = { 1, 2, 3, 4 } ===
+// [ 1 3 ]
+// [ 2 4 ]
+float kTextureTransformMatrices[] = {
+   1.0f,  0.0f,  0.0f,  1.0f, // identity matrix
+   0.0f,  1.0f,  1.0f,  0.0f, // swap x and y
+};
+// clang-format on
+
 static const char *GetGLError(void) {
   switch (glGetError()) {
     case GL_NO_ERROR:
@@ -163,52 +176,73 @@ static AutoGLShader CompileAndCheckShader(GLenum type, unsigned source_count,
   return shader;
 }
 
+static std::string GenerateVertexShader(int layer_count) {
+  std::ostringstream vertex_shader_stream;
+  vertex_shader_stream
+      << "#version 300 es\n"
+      << "#define LAYER_COUNT " << layer_count << "\n"
+      << "precision mediump int;\n"
+      << "uniform vec4 uViewport;\n"
+      << "uniform vec4 uLayerCrop[LAYER_COUNT];\n"
+      << "uniform mat2 uTexMatrix[LAYER_COUNT];\n"
+      << "in vec2 vPosition;\n"
+      << "in vec2 vTexCoords;\n"
+      << "out vec2 fTexCoords[LAYER_COUNT];\n"
+      << "void main() {\n"
+      << "  for (int i = 0; i < LAYER_COUNT; i++) {\n"
+      << "    vec2 tempCoords = vTexCoords * uTexMatrix[i];\n"
+      << "    fTexCoords[i] =\n"
+      << "        uLayerCrop[i].xy + tempCoords * uLayerCrop[i].zw;\n"
+      << "  }\n"
+      << "  vec2 scaledPosition = uViewport.xy + vPosition * uViewport.zw;\n"
+      << "  gl_Position =\n"
+      << "      vec4(scaledPosition * vec2(2.0) - vec2(1.0), 0.0, 1.0);\n"
+      << "}\n";
+  return vertex_shader_stream.str();
+}
+
+static std::string GenerateFragmentShader(int layer_count) {
+  std::ostringstream fragment_shader_stream;
+  fragment_shader_stream << "#version 300 es\n"
+                         << "#define LAYER_COUNT " << layer_count << "\n"
+                         << "#extension GL_OES_EGL_image_external : require\n"
+                         << "precision mediump float;\n";
+  for (int i = 0; i < layer_count; ++i) {
+    fragment_shader_stream << "uniform samplerExternalOES uLayerTexture" << i
+                           << ";\n";
+  }
+  fragment_shader_stream << "uniform float uLayerAlpha[LAYER_COUNT];\n"
+                         << "uniform float uLayerPremult[LAYER_COUNT];\n"
+                         << "in vec2 fTexCoords[LAYER_COUNT];\n"
+                         << "out vec4 oFragColor;\n"
+                         << "void main() {\n"
+                         << "  vec3 color = vec3(0.0, 0.0, 0.0);\n"
+                         << "  float alphaCover = 1.0;\n"
+                         << "  vec4 texSample;\n"
+                         << "  vec3 multRgb;\n";
+  for (int i = 0; i < layer_count; ++i) {
+    if (i > 0)
+      fragment_shader_stream << "  if (alphaCover > 0.5/255.0) {\n";
+    // clang-format off
+    fragment_shader_stream
+        << "  texSample = texture2D(uLayerTexture" << i << ",\n"
+        << "                        fTexCoords[" << i << "]);\n"
+        << "  multRgb = texSample.rgb *\n"
+        << "            max(texSample.a, uLayerPremult[" << i << "]);\n"
+        << "  color += multRgb * uLayerAlpha[" << i << "] * alphaCover;\n"
+        << "  alphaCover *= 1.0 - texSample.a * uLayerAlpha[" << i << "];\n";
+    // clang-format on
+  }
+  for (int i = 0; i < layer_count - 1; ++i)
+    fragment_shader_stream << "  }\n";
+  fragment_shader_stream << "  oFragColor = vec4(color, 1.0 - alphaCover);\n"
+                         << "}\n";
+  return fragment_shader_stream.str();
+}
+
 static int GenerateShaders(std::vector<AutoGLProgram> *blend_programs) {
   // Limits: GL_MAX_VARYING_COMPONENTS, GL_MAX_TEXTURE_IMAGE_UNITS,
   // GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
-  // clang-format off
-  const GLchar *shader_preamble = "#version 300 es\n#define LAYER_COUNT ";
-
-  const GLchar *vertex_shader_source =
-"\n"
-"precision mediump int;                                                     \n"
-"uniform vec4 uViewport;                                                    \n"
-"uniform sampler2D uLayerTextures[LAYER_COUNT];                             \n"
-"uniform vec4 uLayerCrop[LAYER_COUNT];                                      \n"
-"in vec2 vPosition;                                                         \n"
-"in vec2 vTexCoords;                                                        \n"
-"out vec2 fTexCoords[LAYER_COUNT];                                          \n"
-"void main() {                                                              \n"
-"  for (int i = 0; i < LAYER_COUNT; i++) {                                  \n"
-"    fTexCoords[i] = (uLayerCrop[i].xy + vTexCoords * uLayerCrop[i].zw) /   \n"
-"                     vec2(textureSize(uLayerTextures[i], 0));              \n"
-"  }                                                                        \n"
-"  vec2 scaledPosition = uViewport.xy + vPosition * uViewport.zw;           \n"
-"  gl_Position = vec4(scaledPosition * vec2(2.0) - vec2(1.0), 0.0, 1.0);    \n"
-"}                                                                          \n";
-
-  const GLchar *fragment_shader_source =
-"\n"
-"precision mediump float;                                                   \n"
-"uniform sampler2D uLayerTextures[LAYER_COUNT];                             \n"
-"uniform float uLayerAlpha[LAYER_COUNT];                                    \n"
-"in vec2 fTexCoords[LAYER_COUNT];                                           \n"
-"out vec4 oFragColor;                                                       \n"
-"void main() {                                                              \n"
-"  vec3 color = vec3(0.0, 0.0, 0.0);                                        \n"
-"  float alphaCover = 1.0;                                                  \n"
-"  for (int i = 0; i < LAYER_COUNT; i++) {                                  \n"
-"    vec4 texSample = texture(uLayerTextures[i], fTexCoords[i]);            \n"
-"    float a = texSample.a * uLayerAlpha[i];                                \n"
-"    color += a * alphaCover * texSample.rgb;                               \n"
-"    alphaCover *= 1.0 - a;                                                 \n"
-"    if (alphaCover <= 0.5/255.0)                                           \n"
-"      break;                                                               \n"
-"  }                                                                        \n"
-"  oFragColor = vec4(color, 1.0 - alphaCover);                              \n"
-"}                                                                          \n";
-  // clang-format on
-
   int i, ret = 1;
   GLint max_texture_images, status;
   AutoGLShader vertex_shader, fragment_shader;
@@ -218,27 +252,26 @@ static int GenerateShaders(std::vector<AutoGLProgram> *blend_programs) {
   glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_texture_images);
 
   for (i = 1; i <= max_texture_images; i++) {
-    std::ostringstream layer_count_formatter;
-    layer_count_formatter << i;
-    std::string layer_count(layer_count_formatter.str());
-    const GLchar *shader_sources[3] = {shader_preamble, layer_count.c_str(),
-                                       NULL};
-
-    shader_sources[2] = vertex_shader_source;
-    vertex_shader = CompileAndCheckShader(GL_VERTEX_SHADER, 3, shader_sources,
-                                          ret ? &shader_log : NULL);
+    std::string vertex_shader_string = GenerateVertexShader(i);
+    const GLchar *vertex_shader_source = vertex_shader_string.c_str();
+    vertex_shader = CompileAndCheckShader(
+        GL_VERTEX_SHADER, 1, &vertex_shader_source, ret ? &shader_log : NULL);
     if (!vertex_shader.get()) {
       if (ret)
-        ALOGE("Failed to make vertex shader:\n%s", shader_log.c_str());
+        ALOGE("Failed to make vertex shader:\n%sshader source:\n%s",
+              shader_log.c_str(), vertex_shader_source);
       break;
     }
 
-    shader_sources[2] = fragment_shader_source;
-    fragment_shader = CompileAndCheckShader(
-        GL_FRAGMENT_SHADER, 3, shader_sources, ret ? &shader_log : NULL);
+    std::string fragment_shader_string = GenerateFragmentShader(i);
+    const GLchar *fragment_shader_source = fragment_shader_string.c_str();
+    fragment_shader =
+        CompileAndCheckShader(GL_FRAGMENT_SHADER, 1, &fragment_shader_source,
+                              ret ? &shader_log : NULL);
     if (!fragment_shader.get()) {
       if (ret)
-        ALOGE("Failed to make fragment shader:\n%s", shader_log.c_str());
+        ALOGE("Failed to make fragment shader:\n%sshader source:\n%s",
+              shader_log.c_str(), fragment_shader_source);
       break;
     }
 
@@ -281,6 +314,8 @@ struct RenderingCommand {
     unsigned texture_index;
     float crop_bounds[4];
     float alpha;
+    float premult;
+    float texture_matrix[4];
   };
 
   float bounds[4];
@@ -291,18 +326,15 @@ struct RenderingCommand {
   }
 };
 
-static void ConstructCommands(const hwc_layer_1 *layers, size_t num_layers,
+static void ConstructCommands(DrmCompositionLayer *layers, size_t num_layers,
                               std::vector<RenderingCommand> *commands) {
   std::vector<FRect> in_rects;
   std::vector<FRectSet> out_rects;
   int i;
 
   for (unsigned rect_index = 0; rect_index < num_layers; rect_index++) {
-    const hwc_layer_1 &layer = layers[rect_index];
-    FRect rect;
-    in_rects.push_back(FRect(layer.displayFrame.left, layer.displayFrame.top,
-                             layer.displayFrame.right,
-                             layer.displayFrame.bottom));
+    DrmCompositionLayer &layer = layers[rect_index];
+    in_rects.emplace_back(layer.display_frame);
   }
 
   seperate_frects_64(in_rects, &out_rects);
@@ -312,23 +344,28 @@ static void ConstructCommands(const hwc_layer_1 *layers, size_t num_layers,
     commands->push_back(RenderingCommand());
     RenderingCommand &cmd = commands->back();
 
-    memcpy(cmd.bounds, out_rect.rect.bounds, sizeof(cmd.bounds));
+    for (int i = 0; i < 4; i++)
+      cmd.bounds[i] = out_rect.rect.bounds[i];
 
     uint64_t tex_set = out_rect.id_set.getBits();
     for (unsigned i = num_layers - 1; tex_set != 0x0; i--) {
       if (tex_set & (0x1 << i)) {
         tex_set &= ~(0x1 << i);
 
-        const hwc_layer_1 &layer = layers[i];
+        DrmCompositionLayer &layer = layers[i];
 
-        FRect display_rect(layer.displayFrame.left, layer.displayFrame.top,
-                           layer.displayFrame.right, layer.displayFrame.bottom);
+        FRect display_rect(layer.display_frame);
         float display_size[2] = {
             display_rect.bounds[2] - display_rect.bounds[0],
             display_rect.bounds[3] - display_rect.bounds[1]};
 
-        FRect crop_rect(layer.sourceCropf.left, layer.sourceCropf.top,
-                        layer.sourceCropf.right, layer.sourceCropf.bottom);
+        float tex_width = layer.buffer->width;
+        float tex_height = layer.buffer->height;
+        FRect crop_rect(layer.source_crop.left / tex_width,
+                        layer.source_crop.top / tex_height,
+                        layer.source_crop.right / tex_width,
+                        layer.source_crop.bottom / tex_height);
+
         float crop_size[2] = {crop_rect.bounds[2] - crop_rect.bounds[0],
                               crop_rect.bounds[3] - crop_rect.bounds[1]};
 
@@ -336,21 +373,72 @@ static void ConstructCommands(const hwc_layer_1 *layers, size_t num_layers,
         cmd.texture_count++;
         src.texture_index = i;
 
-        for (int b = 0; b < 4; b++) {
+        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;
+            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;
+            flip_xy[0] = false;
+            flip_xy[1] = false;
+            break;
+        }
+
+        if (swap_xy)
+          std::copy_n(&kTextureTransformMatrices[4], 4, src.texture_matrix);
+        else
+          std::copy_n(&kTextureTransformMatrices[0], 4, src.texture_matrix);
+
+        for (int j = 0; j < 4; j++) {
+          int b = j ^ (swap_xy ? 1 : 0);
           float bound_percent = (cmd.bounds[b] - display_rect.bounds[b % 2]) /
                                 display_size[b % 2];
-          src.crop_bounds[b] =
-              crop_rect.bounds[b % 2] + bound_percent * crop_size[b % 2];
+          if (flip_xy[j % 2]) {
+            src.crop_bounds[j] =
+                crop_rect.bounds[j % 2 + 2] - bound_percent * crop_size[j % 2];
+          } else {
+            src.crop_bounds[j] =
+                crop_rect.bounds[j % 2] + bound_percent * crop_size[j % 2];
+          }
         }
 
-        if (layer.blending == HWC_BLENDING_NONE) {
-          src.alpha = 1.0f;
+        if (layer.blending == DrmHwcBlending::kNone) {
+          src.alpha = src.premult = 1.0f;
           // This layer is opaque. There is no point in using layers below this
           // one.
           break;
         }
 
-        src.alpha = layer.planeAlpha / 255.0f;
+        src.alpha = layer.alpha / 255.0f;
+        src.premult =
+            (layer.blending == DrmHwcBlending::kPreMult) ? 1.0f : 0.0f;
       }
     }
   }
@@ -393,15 +481,15 @@ static int CreateTextureFromHandle(EGLDisplay egl_display,
 
   GLuint texture;
   glGenTextures(1, &texture);
-  glBindTexture(GL_TEXTURE_2D, texture);
-  glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image);
-  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-  glBindTexture(GL_TEXTURE_2D, 0);
-
-  out->image.reset(image);
+  glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture);
+  glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)image);
+  glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+  glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+  glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_REPEAT);
+  glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_REPEAT);
+  glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
+
+  out->image.reset(egl_display, image);
   out->texture.reset(texture);
 
   return 0;
@@ -488,6 +576,9 @@ int GLWorkerCompositor::Init() {
   if (!HasExtension("GL_OES_EGL_image", gl_extensions))
     ALOGW("GL_OES_EGL_image extension not supported");
 
+  if (!HasExtension("GL_OES_EGL_image_external", gl_extensions))
+    ALOGW("GL_OES_EGL_image_external extension not supported");
+
   GLuint vertex_buffer;
   glGenBuffers(1, &vertex_buffer);
   glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
@@ -508,8 +599,9 @@ GLWorkerCompositor::~GLWorkerCompositor() {
       ALOGE("Failed to destroy OpenGL ES Context: %s", GetEGLError());
 }
 
-int GLWorkerCompositor::Composite(hwc_layer_1 *layers, size_t num_layers,
-                                  sp<GraphicBuffer> framebuffer) {
+int GLWorkerCompositor::Composite(DrmCompositionLayer *layers,
+                                  size_t num_layers,
+                                  const sp<GraphicBuffer> &framebuffer) {
   ATRACE_CALL();
   int ret = 0;
   size_t i;
@@ -522,54 +614,22 @@ int GLWorkerCompositor::Composite(hwc_layer_1 *layers, size_t num_layers,
 
   GLint frame_width = framebuffer->getWidth();
   GLint frame_height = framebuffer->getHeight();
-  EGLSyncKHR finished_sync;
-
-  AutoEGLImageKHR egl_fb_image(
-      eglCreateImageKHR(egl_display_, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
-                        (EGLClientBuffer)framebuffer->getNativeBuffer(),
-                        NULL /* no attribs */),
-      EGLImageDeleter(egl_display_));
-
-  if (egl_fb_image.get() == EGL_NO_IMAGE_KHR) {
-    ALOGE("Failed to make image from target buffer: %s", GetEGLError());
-    return -EINVAL;
-  }
-
-  GLuint gl_fb_tex;
-  glGenTextures(1, &gl_fb_tex);
-  AutoGLTexture gl_fb_tex_auto(gl_fb_tex);
-  glBindTexture(GL_TEXTURE_2D, gl_fb_tex);
-  glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
-                               (GLeglImageOES)egl_fb_image.get());
-  glBindTexture(GL_TEXTURE_2D, 0);
-
-  GLuint gl_fb;
-  glGenFramebuffers(1, &gl_fb);
-  AutoGLFramebuffer gl_fb_auto(gl_fb);
-  glBindFramebuffer(GL_FRAMEBUFFER, gl_fb);
-  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
-                         gl_fb_tex, 0);
-
-  if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
-    ALOGE("Failed framebuffer check for created target buffer: %s",
-          GetGLFramebufferError());
+  CachedFramebuffer *cached_framebuffer =
+      PrepareAndCacheFramebuffer(framebuffer);
+  if (cached_framebuffer == NULL) {
+    ALOGE("Composite failed because of failed framebuffer");
     return -EINVAL;
   }
 
   for (i = 0; i < num_layers; i++) {
-    const struct hwc_layer_1 *layer = &layers[i];
-
-    if (ret) {
-      if (layer->acquireFenceFd >= 0)
-        close(layer->acquireFenceFd);
-      continue;
-    }
+    DrmCompositionLayer *layer = &layers[i];
 
-    layer_textures.emplace_back(egl_display_);
-    ret = CreateTextureFromHandle(egl_display_, layer->handle,
+    layer_textures.emplace_back();
+    ret = CreateTextureFromHandle(egl_display_, layer->get_usable_handle(),
                                   &layer_textures.back());
+
     if (!ret) {
-      ret = EGLFenceWait(egl_display_, layer->acquireFenceFd);
+      ret = EGLFenceWait(egl_display_, layer->acquire_fence.Release());
     }
     if (ret) {
       layer_textures.pop_back();
@@ -611,24 +671,32 @@ int GLWorkerCompositor::Composite(hwc_layer_1 *layers, size_t num_layers,
     GLint program = blend_programs_[cmd.texture_count - 1].get();
     glUseProgram(program);
     GLint gl_viewport_loc = glGetUniformLocation(program, "uViewport");
-    GLint gl_tex_loc = glGetUniformLocation(program, "uLayerTextures");
     GLint gl_crop_loc = glGetUniformLocation(program, "uLayerCrop");
     GLint gl_alpha_loc = glGetUniformLocation(program, "uLayerAlpha");
+    GLint gl_premult_loc = glGetUniformLocation(program, "uLayerPremult");
+    GLint gl_tex_matrix_loc = glGetUniformLocation(program, "uTexMatrix");
     glUniform4f(gl_viewport_loc, cmd.bounds[0] / (float)frame_width,
                 cmd.bounds[1] / (float)frame_height,
                 (cmd.bounds[2] - cmd.bounds[0]) / (float)frame_width,
                 (cmd.bounds[3] - cmd.bounds[1]) / (float)frame_height);
 
     for (unsigned src_index = 0; src_index < cmd.texture_count; src_index++) {
+      std::ostringstream texture_name_formatter;
+      texture_name_formatter << "uLayerTexture" << src_index;
+      GLint gl_tex_loc =
+          glGetUniformLocation(program, texture_name_formatter.str().c_str());
+
       const RenderingCommand::TextureSource &src = cmd.textures[src_index];
       glUniform1f(gl_alpha_loc + src_index, src.alpha);
+      glUniform1f(gl_premult_loc + src_index, src.premult);
       glUniform4f(gl_crop_loc + src_index, src.crop_bounds[0],
                   src.crop_bounds[1], src.crop_bounds[2] - src.crop_bounds[0],
                   src.crop_bounds[3] - src.crop_bounds[1]);
-
-      glUniform1i(gl_tex_loc + src_index, src_index);
+      glUniform1i(gl_tex_loc, src_index);
+      glUniformMatrix2fv(gl_tex_matrix_loc + src_index, 1, GL_FALSE,
+                         src.texture_matrix);
       glActiveTexture(GL_TEXTURE0 + src_index);
-      glBindTexture(GL_TEXTURE_2D,
+      glBindTexture(GL_TEXTURE_EXTERNAL_OES,
                     layer_textures[src.texture_index].texture.get());
     }
 
@@ -638,7 +706,7 @@ int GLWorkerCompositor::Composite(hwc_layer_1 *layers, size_t num_layers,
 
     for (unsigned src_index = 0; src_index < cmd.texture_count; src_index++) {
       glActiveTexture(GL_TEXTURE0 + src_index);
-      glBindTexture(GL_TEXTURE_2D, 0);
+      glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
     }
   }
 
@@ -654,193 +722,103 @@ int GLWorkerCompositor::Composite(hwc_layer_1 *layers, size_t num_layers,
   return ret;
 }
 
-int GLWorker::DoComposition(GLWorkerCompositor &compositor, Work *work) {
-  int ret =
-      compositor.Composite(work->layers, work->num_layers, work->framebuffer);
-
-  int timeline_fd = work->timeline_fd;
-  work->timeline_fd = -1;
-
-  if (ret) {
-    worker_ret_ = ret;
-    glFinish();
-    sw_sync_timeline_inc(timeline_fd, work->num_layers);
-    close(timeline_fd);
-    return pthread_cond_signal(&work_done_cond_);
-  }
-
-  unsigned timeline_count = work->num_layers + 1;
-  worker_ret_ = sw_sync_fence_create(timeline_fd, "GLComposition done fence",
-                                     timeline_count);
-  ret = pthread_cond_signal(&work_done_cond_);
-
+void GLWorkerCompositor::Finish() {
+  ATRACE_CALL();
   glFinish();
 
-  sw_sync_timeline_inc(timeline_fd, timeline_count);
-  close(timeline_fd);
+  char use_framebuffer_cache_opt[PROPERTY_VALUE_MAX];
+  property_get("hwc.drm.use_framebuffer_cache", use_framebuffer_cache_opt, "1");
+  bool use_framebuffer_cache = atoi(use_framebuffer_cache_opt);
 
-  return ret;
+  if (use_framebuffer_cache) {
+    for (auto &fb : cached_framebuffers_)
+      fb.strong_framebuffer.clear();
+  } else {
+    cached_framebuffers_.clear();
+  }
 }
 
-GLWorker::GLWorker() : initialized_(false) {
+GLWorkerCompositor::CachedFramebuffer::CachedFramebuffer(
+    const sp<GraphicBuffer> &gb, AutoEGLDisplayImage &&image,
+    AutoGLTexture &&tex, AutoGLFramebuffer &&fb)
+    : strong_framebuffer(gb),
+      weak_framebuffer(gb),
+      egl_fb_image(std::move(image)),
+      gl_fb_tex(std::move(tex)),
+      gl_fb(std::move(fb)) {
 }
 
-GLWorker::~GLWorker() {
-  if (!initialized_)
-    return;
-
-  if (SignalWorker(NULL, true) != 0 || pthread_join(thread_, NULL) != 0)
-    pthread_kill(thread_, SIGTERM);
-
-  pthread_cond_destroy(&work_ready_cond_);
-  pthread_cond_destroy(&work_done_cond_);
-  pthread_mutex_destroy(&lock_);
+bool GLWorkerCompositor::CachedFramebuffer::Promote() {
+  if (strong_framebuffer.get() != NULL)
+    return true;
+  strong_framebuffer = weak_framebuffer.promote();
+  return strong_framebuffer.get() != NULL;
 }
 
-#define TRY(x, n, g)                  \
-  ret = x;                            \
-  if (ret) {                          \
-    ALOGE("Failed to " n " %d", ret); \
-    g;                                \
-  }
-
-#define TRY_RETURN(x, n) TRY(x, n, return ret)
-
-int GLWorker::Init() {
-  int ret = 0;
-
-  worker_work_ = NULL;
-  worker_exit_ = false;
-  worker_ret_ = -1;
-
-  ret = pthread_cond_init(&work_ready_cond_, NULL);
-  if (ret) {
-    ALOGE("Failed to int GLThread condition %d", ret);
-    return ret;
-  }
-
-  ret = pthread_cond_init(&work_done_cond_, NULL);
-  if (ret) {
-    ALOGE("Failed to int GLThread condition %d", ret);
-    pthread_cond_destroy(&work_ready_cond_);
-    return ret;
-  }
-
-  ret = pthread_mutex_init(&lock_, NULL);
-  if (ret) {
-    ALOGE("Failed to init GLThread lock %d", ret);
-    pthread_cond_destroy(&work_ready_cond_);
-    pthread_cond_destroy(&work_done_cond_);
-    return ret;
-  }
-
-  ret = pthread_create(&thread_, NULL, StartRoutine, this);
-  if (ret) {
-    ALOGE("Failed to create GLThread %d", ret);
-    pthread_cond_destroy(&work_ready_cond_);
-    pthread_cond_destroy(&work_done_cond_);
-    pthread_mutex_destroy(&lock_);
-    return ret;
-  }
-
-  initialized_ = true;
-
-  TRY_RETURN(pthread_mutex_lock(&lock_), "lock GLThread");
-
-  while (!worker_exit_ && worker_ret_ != 0)
-    TRY(pthread_cond_wait(&work_done_cond_, &lock_), "wait on condition",
-        goto out_unlock);
-
-  ret = worker_ret_;
-
-out_unlock:
-  int unlock_ret = pthread_mutex_unlock(&lock_);
-  if (unlock_ret) {
-    ret = unlock_ret;
-    ALOGE("Failed to unlock GLThread %d", unlock_ret);
-  }
-  return ret;
+GLWorkerCompositor::CachedFramebuffer *
+GLWorkerCompositor::FindCachedFramebuffer(
+    const sp<GraphicBuffer> &framebuffer) {
+  for (auto &fb : cached_framebuffers_)
+    if (fb.weak_framebuffer == framebuffer)
+      return &fb;
+  return NULL;
 }
 
-int GLWorker::SignalWorker(Work *work, bool worker_exit) {
-  int ret = 0;
-  if (worker_exit_)
-    return -EINVAL;
-  TRY_RETURN(pthread_mutex_lock(&lock_), "lock GLThread");
-  worker_work_ = work;
-  worker_exit_ = worker_exit;
-  ret = pthread_cond_signal(&work_ready_cond_);
-  if (ret) {
-    ALOGE("Failed to signal GLThread caller %d", ret);
-    pthread_mutex_unlock(&lock_);
-    return ret;
-  }
-  ret = pthread_cond_wait(&work_done_cond_, &lock_);
-  if (ret) {
-    ALOGE("Failed to wait on GLThread %d", ret);
-    pthread_mutex_unlock(&lock_);
-    return ret;
-  }
+GLWorkerCompositor::CachedFramebuffer *
+GLWorkerCompositor::PrepareAndCacheFramebuffer(
+    const sp<GraphicBuffer> &framebuffer) {
+  CachedFramebuffer *cached_framebuffer = FindCachedFramebuffer(framebuffer);
+  if (cached_framebuffer != NULL) {
+    if (cached_framebuffer->Promote()) {
+      glBindFramebuffer(GL_FRAMEBUFFER, cached_framebuffer->gl_fb.get());
+      return cached_framebuffer;
+    }
 
-  ret = worker_ret_;
-  if (ret) {
-    pthread_mutex_unlock(&lock_);
-    return ret;
+    for (auto it = cached_framebuffers_.begin();
+         it != cached_framebuffers_.end(); ++it) {
+      if (it->weak_framebuffer == framebuffer) {
+        cached_framebuffers_.erase(it);
+        break;
+      }
+    }
   }
-  TRY_RETURN(pthread_mutex_unlock(&lock_), "unlock GLThread");
-  return ret;
-}
-
-int GLWorker::DoWork(Work *work) {
-  return SignalWorker(work, false);
-}
 
-void GLWorker::WorkerRoutine() {
-  int ret = 0;
-
-  TRY(pthread_mutex_lock(&lock_), "lock GLThread", return );
-
-  GLWorkerCompositor compositor;
-
-  TRY(compositor.Init(), "initialize GL", goto out_signal_done);
-
-  worker_ret_ = 0;
-  TRY(pthread_cond_signal(&work_done_cond_), "signal GLThread caller",
-      goto out_signal_done);
+  AutoEGLDisplayImage egl_fb_image(
+      egl_display_,
+      eglCreateImageKHR(egl_display_, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+                        (EGLClientBuffer)framebuffer->getNativeBuffer(),
+                        NULL /* no attribs */));
 
-  while (true) {
-    while (worker_work_ == NULL && !worker_exit_)
-      TRY(pthread_cond_wait(&work_ready_cond_, &lock_), "wait on condition",
-          goto out_signal_done);
+  if (egl_fb_image.image() == EGL_NO_IMAGE_KHR) {
+    ALOGE("Failed to make image from target buffer: %s", GetEGLError());
+    return NULL;
+  }
 
-    if (worker_exit_) {
-      ret = 0;
-      break;
-    }
+  GLuint gl_fb_tex;
+  glGenTextures(1, &gl_fb_tex);
+  AutoGLTexture gl_fb_tex_auto(gl_fb_tex);
+  glBindTexture(GL_TEXTURE_2D, gl_fb_tex);
+  glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
+                               (GLeglImageOES)egl_fb_image.image());
+  glBindTexture(GL_TEXTURE_2D, 0);
 
-    ret = DoComposition(compositor, worker_work_);
+  GLuint gl_fb;
+  glGenFramebuffers(1, &gl_fb);
+  AutoGLFramebuffer gl_fb_auto(gl_fb);
+  glBindFramebuffer(GL_FRAMEBUFFER, gl_fb);
+  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+                         gl_fb_tex, 0);
 
-    worker_work_ = NULL;
-    if (ret) {
-      break;
-    }
+  if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
+    ALOGE("Failed framebuffer check for created target buffer: %s",
+          GetGLFramebufferError());
+    return NULL;
   }
 
-out_signal_done:
-  worker_exit_ = true;
-  worker_ret_ = ret;
-  TRY(pthread_cond_signal(&work_done_cond_), "signal GLThread caller",
-      goto out_unlock);
-out_unlock:
-  TRY(pthread_mutex_unlock(&lock_), "unlock GLThread", return );
-}
-
-/* static */
-void *GLWorker::StartRoutine(void *arg) {
-  setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
-  GLWorker *worker = (GLWorker *)arg;
-  worker->WorkerRoutine();
-  return NULL;
+  cached_framebuffers_.emplace_back(framebuffer, std::move(egl_fb_image),
+                                    std::move(gl_fb_tex_auto),
+                                    std::move(gl_fb_auto));
+  return &cached_framebuffers_.back();
 }
 
 }  // namespace android