1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define ATRACE_TAG ATRACE_TAG_GRAPHICS
18#define LOG_TAG "hwc-gl-worker"
19
20#include <algorithm>
21#include <string>
22#include <sstream>
23#include <unordered_set>
24
25#include <sys/resource.h>
26
27#include <cutils/properties.h>
28
29#include <hardware/hardware.h>
30#include <hardware/hwcomposer.h>
31
32#include <ui/GraphicBuffer.h>
33#include <ui/PixelFormat.h>
34
35#include <utils/Trace.h>
36
37#include "drmdisplaycomposition.h"
38
39#include "glworker.h"
40
41// TODO(zachr): use hwc_drm_bo to turn buffer handles into textures
42#ifndef EGL_NATIVE_HANDLE_ANDROID_NVX
43#define EGL_NATIVE_HANDLE_ANDROID_NVX 0x322A
44#endif
45
46#define MAX_OVERLAPPING_LAYERS 64
47
48namespace android {
49
50// clang-format off
51// Column-major order:
52// float mat[4] = { 1, 2, 3, 4 } ===
53// [ 1 3 ]
54// [ 2 4 ]
55float kTextureTransformMatrices[] = {
56   1.0f,  0.0f,  0.0f,  1.0f, // identity matrix
57   0.0f,  1.0f,  1.0f,  0.0f, // swap x and y
58};
59// clang-format on
60
61static const char *GetGLError(void) {
62  switch (glGetError()) {
63    case GL_NO_ERROR:
64      return "GL_NO_ERROR";
65    case GL_INVALID_ENUM:
66      return "GL_INVALID_ENUM";
67    case GL_INVALID_VALUE:
68      return "GL_INVALID_VALUE";
69    case GL_INVALID_OPERATION:
70      return "GL_INVALID_OPERATION";
71    case GL_INVALID_FRAMEBUFFER_OPERATION:
72      return "GL_INVALID_FRAMEBUFFER_OPERATION";
73    case GL_OUT_OF_MEMORY:
74      return "GL_OUT_OF_MEMORY";
75    default:
76      return "Unknown error";
77  }
78}
79
80static const char *GetGLFramebufferError(void) {
81  switch (glCheckFramebufferStatus(GL_FRAMEBUFFER)) {
82    case GL_FRAMEBUFFER_COMPLETE:
83      return "GL_FRAMEBUFFER_COMPLETE";
84    case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
85      return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
86    case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
87      return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
88    case GL_FRAMEBUFFER_UNSUPPORTED:
89      return "GL_FRAMEBUFFER_UNSUPPORTED";
90    case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
91      return "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
92    default:
93      return "Unknown error";
94  }
95}
96
97static const char *GetEGLError(void) {
98  switch (eglGetError()) {
99    case EGL_SUCCESS:
100      return "EGL_SUCCESS";
101    case EGL_NOT_INITIALIZED:
102      return "EGL_NOT_INITIALIZED";
103    case EGL_BAD_ACCESS:
104      return "EGL_BAD_ACCESS";
105    case EGL_BAD_ALLOC:
106      return "EGL_BAD_ALLOC";
107    case EGL_BAD_ATTRIBUTE:
108      return "EGL_BAD_ATTRIBUTE";
109    case EGL_BAD_CONTEXT:
110      return "EGL_BAD_CONTEXT";
111    case EGL_BAD_CONFIG:
112      return "EGL_BAD_CONFIG";
113    case EGL_BAD_CURRENT_SURFACE:
114      return "EGL_BAD_CURRENT_SURFACE";
115    case EGL_BAD_DISPLAY:
116      return "EGL_BAD_DISPLAY";
117    case EGL_BAD_SURFACE:
118      return "EGL_BAD_SURFACE";
119    case EGL_BAD_MATCH:
120      return "EGL_BAD_MATCH";
121    case EGL_BAD_PARAMETER:
122      return "EGL_BAD_PARAMETER";
123    case EGL_BAD_NATIVE_PIXMAP:
124      return "EGL_BAD_NATIVE_PIXMAP";
125    case EGL_BAD_NATIVE_WINDOW:
126      return "EGL_BAD_NATIVE_WINDOW";
127    case EGL_CONTEXT_LOST:
128      return "EGL_CONTEXT_LOST";
129    default:
130      return "Unknown error";
131  }
132}
133
134static bool HasExtension(const char *extension, const char *extensions) {
135  const char *start, *where, *terminator;
136  start = extensions;
137  for (;;) {
138    where = (char *)strstr((const char *)start, extension);
139    if (!where)
140      break;
141    terminator = where + strlen(extension);
142    if (where == start || *(where - 1) == ' ')
143      if (*terminator == ' ' || *terminator == '\0')
144        return true;
145    start = terminator;
146  }
147  return false;
148}
149
150static AutoGLShader CompileAndCheckShader(GLenum type, unsigned source_count,
151                                          const GLchar **sources,
152                                          std::ostringstream *shader_log) {
153  GLint status;
154  AutoGLShader shader(glCreateShader(type));
155  if (shader.get() == 0) {
156    if (shader_log)
157      *shader_log << "Failed glCreateShader call";
158    return 0;
159  }
160
161  glShaderSource(shader.get(), source_count, sources, NULL);
162  glCompileShader(shader.get());
163  glGetShaderiv(shader.get(), GL_COMPILE_STATUS, &status);
164  if (!status) {
165    if (shader_log) {
166      GLint log_length;
167      glGetShaderiv(shader.get(), GL_INFO_LOG_LENGTH, &log_length);
168      std::string info_log(log_length, ' ');
169      glGetShaderInfoLog(shader.get(), log_length, NULL, &info_log.front());
170      *shader_log << "Failed to compile shader:\n" << info_log.c_str()
171                  << "\nShader Source:\n";
172      for (unsigned i = 0; i < source_count; i++) {
173        *shader_log << sources[i];
174      }
175      *shader_log << "\n";
176    }
177    return 0;
178  }
179
180  return shader;
181}
182
183static std::string GenerateVertexShader(int layer_count) {
184  std::ostringstream vertex_shader_stream;
185  vertex_shader_stream
186      << "#version 300 es\n"
187      << "#define LAYER_COUNT " << layer_count << "\n"
188      << "precision mediump int;\n"
189      << "uniform vec4 uViewport;\n"
190      << "uniform vec4 uLayerCrop[LAYER_COUNT];\n"
191      << "uniform mat2 uTexMatrix[LAYER_COUNT];\n"
192      << "in vec2 vPosition;\n"
193      << "in vec2 vTexCoords;\n"
194      << "out vec2 fTexCoords[LAYER_COUNT];\n"
195      << "void main() {\n"
196      << "  for (int i = 0; i < LAYER_COUNT; i++) {\n"
197      << "    vec2 tempCoords = vTexCoords * uTexMatrix[i];\n"
198      << "    fTexCoords[i] =\n"
199      << "        uLayerCrop[i].xy + tempCoords * uLayerCrop[i].zw;\n"
200      << "  }\n"
201      << "  vec2 scaledPosition = uViewport.xy + vPosition * uViewport.zw;\n"
202      << "  gl_Position =\n"
203      << "      vec4(scaledPosition * vec2(2.0) - vec2(1.0), 0.0, 1.0);\n"
204      << "}\n";
205  return vertex_shader_stream.str();
206}
207
208static std::string GenerateFragmentShader(int layer_count) {
209  std::ostringstream fragment_shader_stream;
210  fragment_shader_stream << "#version 300 es\n"
211                         << "#define LAYER_COUNT " << layer_count << "\n"
212                         << "#extension GL_OES_EGL_image_external : require\n"
213                         << "precision mediump float;\n";
214  for (int i = 0; i < layer_count; ++i) {
215    fragment_shader_stream << "uniform samplerExternalOES uLayerTexture" << i
216                           << ";\n";
217  }
218  fragment_shader_stream << "uniform float uLayerAlpha[LAYER_COUNT];\n"
219                         << "uniform float uLayerPremult[LAYER_COUNT];\n"
220                         << "in vec2 fTexCoords[LAYER_COUNT];\n"
221                         << "out vec4 oFragColor;\n"
222                         << "void main() {\n"
223                         << "  vec3 color = vec3(0.0, 0.0, 0.0);\n"
224                         << "  float alphaCover = 1.0;\n"
225                         << "  vec4 texSample;\n"
226                         << "  vec3 multRgb;\n";
227  for (int i = 0; i < layer_count; ++i) {
228    if (i > 0)
229      fragment_shader_stream << "  if (alphaCover > 0.5/255.0) {\n";
230    // clang-format off
231    fragment_shader_stream
232        << "  texSample = texture2D(uLayerTexture" << i << ",\n"
233        << "                        fTexCoords[" << i << "]);\n"
234        << "  multRgb = texSample.rgb *\n"
235        << "            max(texSample.a, uLayerPremult[" << i << "]);\n"
236        << "  color += multRgb * uLayerAlpha[" << i << "] * alphaCover;\n"
237        << "  alphaCover *= 1.0 - texSample.a * uLayerAlpha[" << i << "];\n";
238    // clang-format on
239  }
240  for (int i = 0; i < layer_count - 1; ++i)
241    fragment_shader_stream << "  }\n";
242  fragment_shader_stream << "  oFragColor = vec4(color, 1.0 - alphaCover);\n"
243                         << "}\n";
244  return fragment_shader_stream.str();
245}
246
247static AutoGLProgram GenerateProgram(unsigned num_textures,
248                                     std::ostringstream *shader_log) {
249  std::string vertex_shader_string = GenerateVertexShader(num_textures);
250  const GLchar *vertex_shader_source = vertex_shader_string.c_str();
251  AutoGLShader vertex_shader = CompileAndCheckShader(
252      GL_VERTEX_SHADER, 1, &vertex_shader_source, shader_log);
253  if (!vertex_shader.get())
254    return 0;
255
256  std::string fragment_shader_string = GenerateFragmentShader(num_textures);
257  const GLchar *fragment_shader_source = fragment_shader_string.c_str();
258  AutoGLShader fragment_shader = CompileAndCheckShader(
259      GL_FRAGMENT_SHADER, 1, &fragment_shader_source, shader_log);
260  if (!fragment_shader.get())
261    return 0;
262
263  AutoGLProgram program(glCreateProgram());
264  if (!program.get()) {
265    if (shader_log)
266      *shader_log << "Failed to create program: " << GetGLError() << "\n";
267    return 0;
268  }
269
270  glAttachShader(program.get(), vertex_shader.get());
271  glAttachShader(program.get(), fragment_shader.get());
272  glBindAttribLocation(program.get(), 0, "vPosition");
273  glBindAttribLocation(program.get(), 1, "vTexCoords");
274  glLinkProgram(program.get());
275  glDetachShader(program.get(), vertex_shader.get());
276  glDetachShader(program.get(), fragment_shader.get());
277
278  GLint status;
279  glGetProgramiv(program.get(), GL_LINK_STATUS, &status);
280  if (!status) {
281    if (shader_log) {
282      GLint log_length;
283      glGetProgramiv(program.get(), GL_INFO_LOG_LENGTH, &log_length);
284      std::string program_log(log_length, ' ');
285      glGetProgramInfoLog(program.get(), log_length, NULL,
286                          &program_log.front());
287      *shader_log << "Failed to link program:\n" << program_log.c_str() << "\n";
288    }
289    return 0;
290  }
291
292  return program;
293}
294
295struct RenderingCommand {
296  struct TextureSource {
297    unsigned texture_index;
298    float crop_bounds[4];
299    float alpha;
300    float premult;
301    float texture_matrix[4];
302  };
303
304  float bounds[4];
305  unsigned texture_count = 0;
306  TextureSource textures[MAX_OVERLAPPING_LAYERS];
307};
308
309static void ConstructCommand(const DrmHwcLayer *layers,
310                             const DrmCompositionRegion &region,
311                             RenderingCommand &cmd) {
312  std::copy_n(region.frame.bounds, 4, cmd.bounds);
313
314  for (size_t texture_index : region.source_layers) {
315    const DrmHwcLayer &layer = layers[texture_index];
316
317    DrmHwcRect<float> display_rect(layer.display_frame);
318    float display_size[2] = {display_rect.bounds[2] - display_rect.bounds[0],
319                             display_rect.bounds[3] - display_rect.bounds[1]};
320
321    float tex_width = layer.buffer->width;
322    float tex_height = layer.buffer->height;
323    DrmHwcRect<float> crop_rect(layer.source_crop.left / tex_width,
324                                layer.source_crop.top / tex_height,
325                                layer.source_crop.right / tex_width,
326                                layer.source_crop.bottom / tex_height);
327
328    float crop_size[2] = {crop_rect.bounds[2] - crop_rect.bounds[0],
329                          crop_rect.bounds[3] - crop_rect.bounds[1]};
330
331    RenderingCommand::TextureSource &src = cmd.textures[cmd.texture_count];
332    cmd.texture_count++;
333    src.texture_index = texture_index;
334
335    bool swap_xy = false;
336    bool flip_xy[2] = { false, false };
337
338    if (layer.transform == DrmHwcTransform::kRotate180) {
339      swap_xy = false;
340      flip_xy[0] = true;
341      flip_xy[1] = true;
342    } else if (layer.transform == DrmHwcTransform::kRotate270) {
343      swap_xy = true;
344      flip_xy[0] = true;
345      flip_xy[1] = false;
346    } else if (layer.transform & DrmHwcTransform::kRotate90) {
347      swap_xy = true;
348      if (layer.transform & DrmHwcTransform::kFlipH) {
349        flip_xy[0] = true;
350        flip_xy[1] = true;
351      } else if (layer.transform & DrmHwcTransform::kFlipV) {
352        flip_xy[0] = false;
353        flip_xy[1] = false;
354      } else {
355        flip_xy[0] = false;
356        flip_xy[1] = true;
357      }
358    } else {
359      if (layer.transform & DrmHwcTransform::kFlipH)
360        flip_xy[0] = true;
361      if (layer.transform & DrmHwcTransform::kFlipV)
362        flip_xy[1] = true;
363    }
364
365    if (swap_xy)
366      std::copy_n(&kTextureTransformMatrices[4], 4, src.texture_matrix);
367    else
368      std::copy_n(&kTextureTransformMatrices[0], 4, src.texture_matrix);
369
370    for (int j = 0; j < 4; j++) {
371      int b = j ^ (swap_xy ? 1 : 0);
372      float bound_percent =
373          (cmd.bounds[b] - display_rect.bounds[b % 2]) / display_size[b % 2];
374      if (flip_xy[j % 2]) {
375        src.crop_bounds[j] =
376            crop_rect.bounds[j % 2 + 2] - bound_percent * crop_size[j % 2];
377      } else {
378        src.crop_bounds[j] =
379            crop_rect.bounds[j % 2] + bound_percent * crop_size[j % 2];
380      }
381    }
382
383    if (layer.blending == DrmHwcBlending::kNone) {
384      src.alpha = src.premult = 1.0f;
385      // This layer is opaque. There is no point in using layers below this one.
386      break;
387    }
388
389    src.alpha = layer.alpha / 255.0f;
390    src.premult = (layer.blending == DrmHwcBlending::kPreMult) ? 1.0f : 0.0f;
391  }
392}
393
394static int EGLFenceWait(EGLDisplay egl_display, int acquireFenceFd) {
395  int ret = 0;
396
397  EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, acquireFenceFd,
398                      EGL_NONE};
399  EGLSyncKHR egl_sync =
400      eglCreateSyncKHR(egl_display, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
401  if (egl_sync == EGL_NO_SYNC_KHR) {
402    ALOGE("Failed to make EGLSyncKHR from acquireFenceFd: %s", GetEGLError());
403    close(acquireFenceFd);
404    return 1;
405  }
406
407  EGLint success = eglWaitSyncKHR(egl_display, egl_sync, 0);
408  if (success == EGL_FALSE) {
409    ALOGE("Failed to wait for acquire: %s", GetEGLError());
410    ret = 1;
411  }
412  eglDestroySyncKHR(egl_display, egl_sync);
413
414  return ret;
415}
416
417static int CreateTextureFromHandle(EGLDisplay egl_display,
418                                   buffer_handle_t handle,
419                                   AutoEGLImageAndGLTexture *out) {
420  EGLImageKHR image = eglCreateImageKHR(
421      egl_display, EGL_NO_CONTEXT, EGL_NATIVE_HANDLE_ANDROID_NVX,
422      (EGLClientBuffer)handle, NULL /* no attribs */);
423
424  if (image == EGL_NO_IMAGE_KHR) {
425    ALOGE("Failed to make image %s %p", GetEGLError(), handle);
426    return -EINVAL;
427  }
428
429  GLuint texture;
430  glGenTextures(1, &texture);
431  glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture);
432  glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)image);
433  glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
434  glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
435  glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_REPEAT);
436  glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_REPEAT);
437  glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
438
439  out->image.reset(egl_display, image);
440  out->texture.reset(texture);
441
442  return 0;
443}
444
445GLWorkerCompositor::GLWorkerCompositor()
446    : egl_display_(EGL_NO_DISPLAY), egl_ctx_(EGL_NO_CONTEXT) {
447}
448
449int GLWorkerCompositor::Init() {
450  int ret = 0;
451  const char *egl_extensions;
452  const char *gl_extensions;
453  EGLint num_configs;
454  EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE};
455  EGLConfig egl_config;
456
457  // clang-format off
458  const GLfloat verts[] = {
459    0.0f,  0.0f,    0.0f, 0.0f,
460    0.0f,  2.0f,    0.0f, 2.0f,
461    2.0f,  0.0f,    2.0f, 0.0f
462  };
463  // clang-format on
464
465  const EGLint config_attribs[] = {EGL_RENDERABLE_TYPE,
466                                   EGL_OPENGL_ES2_BIT,
467                                   EGL_RED_SIZE,
468                                   8,
469                                   EGL_GREEN_SIZE,
470                                   8,
471                                   EGL_BLUE_SIZE,
472                                   8,
473                                   EGL_NONE};
474
475  const EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
476
477  egl_display_ = eglGetDisplay(EGL_DEFAULT_DISPLAY);
478  if (egl_display_ == EGL_NO_DISPLAY) {
479    ALOGE("Failed to get egl display");
480    return 1;
481  }
482
483  if (!eglInitialize(egl_display_, NULL, NULL)) {
484    ALOGE("Failed to initialize egl: %s", GetEGLError());
485    return 1;
486  }
487
488  egl_extensions = eglQueryString(egl_display_, EGL_EXTENSIONS);
489
490  // These extensions are all technically required but not always reported due
491  // to meta EGL filtering them out.
492  if (!HasExtension("EGL_KHR_image_base", egl_extensions))
493    ALOGW("EGL_KHR_image_base extension not supported");
494
495  if (!HasExtension("EGL_ANDROID_image_native_buffer", egl_extensions))
496    ALOGW("EGL_ANDROID_image_native_buffer extension not supported");
497
498  if (!HasExtension("EGL_ANDROID_native_fence_sync", egl_extensions))
499    ALOGW("EGL_ANDROID_native_fence_sync extension not supported");
500
501  if (!eglChooseConfig(egl_display_, config_attribs, &egl_config, 1,
502                       &num_configs)) {
503    ALOGE("eglChooseConfig() failed with error: %s", GetEGLError());
504    return 1;
505  }
506
507  egl_ctx_ =
508      eglCreateContext(egl_display_, egl_config,
509                       EGL_NO_CONTEXT /* No shared context */, context_attribs);
510
511  if (egl_ctx_ == EGL_NO_CONTEXT) {
512    ALOGE("Failed to create OpenGL ES Context: %s", GetEGLError());
513    return 1;
514  }
515
516  if (!eglMakeCurrent(egl_display_, EGL_NO_SURFACE, EGL_NO_SURFACE, egl_ctx_)) {
517    ALOGE("Failed to make the OpenGL ES Context current: %s", GetEGLError());
518    return 1;
519  }
520
521  gl_extensions = (const char *)glGetString(GL_EXTENSIONS);
522
523  if (!HasExtension("GL_OES_EGL_image", gl_extensions))
524    ALOGW("GL_OES_EGL_image extension not supported");
525
526  if (!HasExtension("GL_OES_EGL_image_external", gl_extensions))
527    ALOGW("GL_OES_EGL_image_external extension not supported");
528
529  GLuint vertex_buffer;
530  glGenBuffers(1, &vertex_buffer);
531  glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
532  glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);
533  glBindBuffer(GL_ARRAY_BUFFER, 0);
534  vertex_buffer_.reset(vertex_buffer);
535
536  std::ostringstream shader_log;
537  blend_programs_.emplace_back(GenerateProgram(1, &shader_log));
538  if (blend_programs_.back().get() == 0) {
539    ALOGE("%s", shader_log.str().c_str());
540    return 1;
541  }
542
543  return 0;
544}
545
546GLWorkerCompositor::~GLWorkerCompositor() {
547  if (egl_display_ != EGL_NO_DISPLAY && egl_ctx_ != EGL_NO_CONTEXT)
548    if (eglDestroyContext(egl_display_, egl_ctx_) == EGL_FALSE)
549      ALOGE("Failed to destroy OpenGL ES Context: %s", GetEGLError());
550}
551
552int GLWorkerCompositor::Composite(DrmHwcLayer *layers,
553                                  DrmCompositionRegion *regions,
554                                  size_t num_regions,
555                                  const sp<GraphicBuffer> &framebuffer) {
556  ATRACE_CALL();
557  int ret = 0;
558  std::vector<AutoEGLImageAndGLTexture> layer_textures;
559  std::vector<RenderingCommand> commands;
560
561  if (num_regions == 0) {
562    return -EALREADY;
563  }
564
565  GLint frame_width = framebuffer->getWidth();
566  GLint frame_height = framebuffer->getHeight();
567  CachedFramebuffer *cached_framebuffer =
568      PrepareAndCacheFramebuffer(framebuffer);
569  if (cached_framebuffer == NULL) {
570    ALOGE("Composite failed because of failed framebuffer");
571    return -EINVAL;
572  }
573
574  std::unordered_set<size_t> layers_used_indices;
575  for (size_t region_index = 0; region_index < num_regions; region_index++) {
576    DrmCompositionRegion &region = regions[region_index];
577    layers_used_indices.insert(region.source_layers.begin(),
578                               region.source_layers.end());
579    commands.emplace_back();
580    ConstructCommand(layers, region, commands.back());
581  }
582
583  for (size_t layer_index = 0; layer_index < MAX_OVERLAPPING_LAYERS;
584       layer_index++) {
585    DrmHwcLayer *layer = &layers[layer_index];
586
587    layer_textures.emplace_back();
588
589    if (layers_used_indices.count(layer_index) == 0)
590      continue;
591
592    ret = CreateTextureFromHandle(egl_display_, layer->get_usable_handle(),
593                                  &layer_textures.back());
594
595    if (!ret) {
596      ret = EGLFenceWait(egl_display_, layer->acquire_fence.Release());
597    }
598    if (ret) {
599      layer_textures.pop_back();
600      ret = -EINVAL;
601    }
602  }
603
604  if (ret)
605    return ret;
606
607  glViewport(0, 0, frame_width, frame_height);
608
609  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
610  glClear(GL_COLOR_BUFFER_BIT);
611
612  glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_.get());
613  glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, NULL);
614  glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4,
615                        (void *)(sizeof(float) * 2));
616  glEnableVertexAttribArray(0);
617  glEnableVertexAttribArray(1);
618  glEnable(GL_SCISSOR_TEST);
619
620  for (const RenderingCommand &cmd : commands) {
621    if (cmd.texture_count == 0)
622      continue;
623
624    // TODO(zachr): handle the case of too many overlapping textures for one
625    // area by falling back to rendering as many layers as possible using
626    // multiple blending passes.
627    GLint program = PrepareAndCacheProgram(cmd.texture_count);
628    if (program == 0) {
629      ALOGE("Too many layers to render in one area");
630      continue;
631    }
632
633    glUseProgram(program);
634    GLint gl_viewport_loc = glGetUniformLocation(program, "uViewport");
635    GLint gl_crop_loc = glGetUniformLocation(program, "uLayerCrop");
636    GLint gl_alpha_loc = glGetUniformLocation(program, "uLayerAlpha");
637    GLint gl_premult_loc = glGetUniformLocation(program, "uLayerPremult");
638    GLint gl_tex_matrix_loc = glGetUniformLocation(program, "uTexMatrix");
639    glUniform4f(gl_viewport_loc, cmd.bounds[0] / (float)frame_width,
640                cmd.bounds[1] / (float)frame_height,
641                (cmd.bounds[2] - cmd.bounds[0]) / (float)frame_width,
642                (cmd.bounds[3] - cmd.bounds[1]) / (float)frame_height);
643
644    for (unsigned src_index = 0; src_index < cmd.texture_count; src_index++) {
645      std::ostringstream texture_name_formatter;
646      texture_name_formatter << "uLayerTexture" << src_index;
647      GLint gl_tex_loc =
648          glGetUniformLocation(program, texture_name_formatter.str().c_str());
649
650      const RenderingCommand::TextureSource &src = cmd.textures[src_index];
651      glUniform1f(gl_alpha_loc + src_index, src.alpha);
652      glUniform1f(gl_premult_loc + src_index, src.premult);
653      glUniform4f(gl_crop_loc + src_index, src.crop_bounds[0],
654                  src.crop_bounds[1], src.crop_bounds[2] - src.crop_bounds[0],
655                  src.crop_bounds[3] - src.crop_bounds[1]);
656      glUniform1i(gl_tex_loc, src_index);
657      glUniformMatrix2fv(gl_tex_matrix_loc + src_index, 1, GL_FALSE,
658                         src.texture_matrix);
659      glActiveTexture(GL_TEXTURE0 + src_index);
660      glBindTexture(GL_TEXTURE_EXTERNAL_OES,
661                    layer_textures[src.texture_index].texture.get());
662    }
663
664    glScissor(cmd.bounds[0], cmd.bounds[1], cmd.bounds[2] - cmd.bounds[0],
665              cmd.bounds[3] - cmd.bounds[1]);
666    glDrawArrays(GL_TRIANGLES, 0, 3);
667
668    for (unsigned src_index = 0; src_index < cmd.texture_count; src_index++) {
669      glActiveTexture(GL_TEXTURE0 + src_index);
670      glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
671    }
672  }
673
674  glDisable(GL_SCISSOR_TEST);
675  glActiveTexture(GL_TEXTURE0);
676  glDisableVertexAttribArray(0);
677  glDisableVertexAttribArray(1);
678  glBindBuffer(GL_ARRAY_BUFFER, 0);
679  glUseProgram(0);
680
681  glBindFramebuffer(GL_FRAMEBUFFER, 0);
682
683  return ret;
684}
685
686void GLWorkerCompositor::Finish() {
687  ATRACE_CALL();
688  glFinish();
689
690  char use_framebuffer_cache_opt[PROPERTY_VALUE_MAX];
691  property_get("hwc.drm.use_framebuffer_cache", use_framebuffer_cache_opt, "1");
692  bool use_framebuffer_cache = atoi(use_framebuffer_cache_opt);
693
694  if (use_framebuffer_cache) {
695    for (auto &fb : cached_framebuffers_)
696      fb.strong_framebuffer.clear();
697  } else {
698    cached_framebuffers_.clear();
699  }
700}
701
702GLWorkerCompositor::CachedFramebuffer::CachedFramebuffer(
703    const sp<GraphicBuffer> &gb, AutoEGLDisplayImage &&image,
704    AutoGLTexture &&tex, AutoGLFramebuffer &&fb)
705    : strong_framebuffer(gb),
706      weak_framebuffer(gb),
707      egl_fb_image(std::move(image)),
708      gl_fb_tex(std::move(tex)),
709      gl_fb(std::move(fb)) {
710}
711
712bool GLWorkerCompositor::CachedFramebuffer::Promote() {
713  if (strong_framebuffer.get() != NULL)
714    return true;
715  strong_framebuffer = weak_framebuffer.promote();
716  return strong_framebuffer.get() != NULL;
717}
718
719GLWorkerCompositor::CachedFramebuffer *
720GLWorkerCompositor::FindCachedFramebuffer(
721    const sp<GraphicBuffer> &framebuffer) {
722  for (auto &fb : cached_framebuffers_)
723    if (fb.weak_framebuffer == framebuffer)
724      return &fb;
725  return NULL;
726}
727
728GLWorkerCompositor::CachedFramebuffer *
729GLWorkerCompositor::PrepareAndCacheFramebuffer(
730    const sp<GraphicBuffer> &framebuffer) {
731  CachedFramebuffer *cached_framebuffer = FindCachedFramebuffer(framebuffer);
732  if (cached_framebuffer != NULL) {
733    if (cached_framebuffer->Promote()) {
734      glBindFramebuffer(GL_FRAMEBUFFER, cached_framebuffer->gl_fb.get());
735      return cached_framebuffer;
736    }
737
738    for (auto it = cached_framebuffers_.begin();
739         it != cached_framebuffers_.end(); ++it) {
740      if (it->weak_framebuffer == framebuffer) {
741        cached_framebuffers_.erase(it);
742        break;
743      }
744    }
745  }
746
747  AutoEGLDisplayImage egl_fb_image(
748      egl_display_,
749      eglCreateImageKHR(egl_display_, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
750                        (EGLClientBuffer)framebuffer->getNativeBuffer(),
751                        NULL /* no attribs */));
752
753  if (egl_fb_image.image() == EGL_NO_IMAGE_KHR) {
754    ALOGE("Failed to make image from target buffer: %s", GetEGLError());
755    return NULL;
756  }
757
758  GLuint gl_fb_tex;
759  glGenTextures(1, &gl_fb_tex);
760  AutoGLTexture gl_fb_tex_auto(gl_fb_tex);
761  glBindTexture(GL_TEXTURE_2D, gl_fb_tex);
762  glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
763                               (GLeglImageOES)egl_fb_image.image());
764  glBindTexture(GL_TEXTURE_2D, 0);
765
766  GLuint gl_fb;
767  glGenFramebuffers(1, &gl_fb);
768  AutoGLFramebuffer gl_fb_auto(gl_fb);
769  glBindFramebuffer(GL_FRAMEBUFFER, gl_fb);
770  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
771                         gl_fb_tex, 0);
772
773  if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
774    ALOGE("Failed framebuffer check for created target buffer: %s",
775          GetGLFramebufferError());
776    return NULL;
777  }
778
779  cached_framebuffers_.emplace_back(framebuffer, std::move(egl_fb_image),
780                                    std::move(gl_fb_tex_auto),
781                                    std::move(gl_fb_auto));
782  return &cached_framebuffers_.back();
783}
784
785GLint GLWorkerCompositor::PrepareAndCacheProgram(unsigned texture_count) {
786  if (blend_programs_.size() >= texture_count) {
787    GLint program = blend_programs_[texture_count - 1].get();
788    if (program != 0)
789      return program;
790  }
791
792  AutoGLProgram program = GenerateProgram(texture_count, NULL);
793  if (program.get() != 0) {
794    if (blend_programs_.size() < texture_count)
795      blend_programs_.resize(texture_count);
796    blend_programs_[texture_count - 1] = std::move(program);
797    return blend_programs_[texture_count - 1].get();
798  }
799
800  return 0;
801}
802
803}  // namespace android
804