1 // Copyright (C) 2015 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "TextureDraw.h"
16 
17 #include <assert.h>
18 #include <stdio.h>
19 #include <string.h>
20 
21 #include <algorithm>
22 #include <string>
23 
24 #include "OpenGLESDispatch/DispatchTables.h"
25 #include "host-common/crash_reporter.h"
26 #include "host-common/logging.h"
27 
28 #ifndef NDEBUG
29 #define DEBUG_TEXTURE_DRAW
30 #endif
31 
32 namespace gfxstream {
33 namespace gl {
34 namespace {
35 
36 // Helper function to create a new shader.
37 // |shaderType| is the shader type (e.g. GL_VERTEX_SHADER).
38 // |shaderText| is a 0-terminated C string for the shader source to use.
39 // On success, return the handle of the new compiled shader, or 0 on failure.
createShader(GLint shaderType,const char * shaderText)40 GLuint createShader(GLint shaderType, const char* shaderText) {
41     // Create new shader handle and attach source.
42     GLuint shader = s_gles2.glCreateShader(shaderType);
43     if (!shader) {
44         return 0;
45     }
46     const GLchar* text = static_cast<const GLchar*>(shaderText);
47     const GLint textLen = ::strlen(shaderText);
48     s_gles2.glShaderSource(shader, 1, &text, &textLen);
49 
50     // Compiler the shader.
51     GLint success;
52     s_gles2.glCompileShader(shader);
53     s_gles2.glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
54     if (success == GL_FALSE) {
55         GLint infoLogLength;
56         s_gles2.glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
57         std::string infoLog(infoLogLength + 1, '\0');
58         fprintf(stderr, "%s: TextureDraw shader compile failed.\n", __func__);
59         s_gles2.glGetShaderInfoLog(shader, infoLogLength, 0, &infoLog[0]);
60         fprintf(stderr, "%s: Info log:\n%s\n", __func__,
61                 infoLog.c_str());
62         fprintf(stderr, "%s: Source:\n%s\n", __func__,
63                 shaderText);
64         s_gles2.glDeleteShader(shader);
65 
66         // No point in continuing as it's going to be a black screen.
67         // Send a crash report.
68         // emugl::emugl_crash_reporter(
69         //     "FATAL: Could not compile shader for guest framebuffer blit. "
70         //     "There may be an issue with the GPU drivers on your machine. "
71         //     "Try using software rendering; launch the emulator "
72         //     "from the command line with -gpu swiftshader_indirect. ");
73     }
74 
75     return shader;
76 }
77 
78 // No scaling / projection since we want to fill the whole viewport with
79 // the texture, hence a trivial vertex shader that only supports translation.
80 // Note: we used to have a proper free-angle rotation support in this shader,
81 //  but looks like SwiftShader doesn't support either complicated calculations
82 //  for gl_Position/varyings or just doesn't like trigonometric functions in
83 //  shader; anyway the new code has hardcoded texture coordinate mapping for
84 //  different rotation angles and works in both native OpenGL and SwiftShader.
85 const char kVertexShaderSource[] =
86     "attribute vec4 position;\n"
87     "attribute vec2 inCoord;\n"
88     "varying vec2 outCoord;\n"
89     "uniform vec2 translation;\n"
90     "uniform vec2 scale;\n"
91     "uniform vec2 coordTranslation;\n"
92     "uniform vec2 coordScale;\n"
93 
94     "void main(void) {\n"
95     "  gl_Position.xy = position.xy * scale.xy - translation.xy;\n"
96     "  gl_Position.zw = position.zw;\n"
97     "  outCoord = inCoord * coordScale + coordTranslation;\n"
98     "}\n";
99 
100 // Similarly, just interpolate texture coordinates.
101 const char kFragmentShaderSource[] =
102     "#define kComposeModeDevice 2\n"
103     "precision mediump float;\n"
104     "varying lowp vec2 outCoord;\n"
105     "uniform sampler2D tex;\n"
106     "uniform float alpha;\n"
107     "uniform int composeMode;\n"
108     "uniform vec4 color ;\n"
109 
110     "void main(void) {\n"
111     "  if (composeMode == kComposeModeDevice) {\n"
112     "    gl_FragColor = alpha * texture2D(tex, outCoord);\n"
113     "  } else {\n"
114     "    gl_FragColor = alpha * color;\n"
115     "  }\n"
116     "}\n";
117 
118 // Hard-coded arrays of vertex information.
119 struct Vertex {
120     float pos[3];
121     float coord[2];
122 };
123 
124 const Vertex kVertices[] = {
125     // 0 degree
126     {{ +1, -1, +0 }, { +1, +0 }},
127     {{ +1, +1, +0 }, { +1, +1 }},
128     {{ -1, +1, +0 }, { +0, +1 }},
129     {{ -1, -1, +0 }, { +0, +0 }},
130     // 90 degree clock-wise
131     {{ +1, -1, +0 }, { +1, +1 }},
132     {{ +1, +1, +0 }, { +0, +1 }},
133     {{ -1, +1, +0 }, { +0, +0 }},
134     {{ -1, -1, +0 }, { +1, +0 }},
135     // 180 degree clock-wise
136     {{ +1, -1, +0 }, { +0, +1 }},
137     {{ +1, +1, +0 }, { +0, +0 }},
138     {{ -1, +1, +0 }, { +1, +0 }},
139     {{ -1, -1, +0 }, { +1, +1 }},
140     // 270 degree clock-wise
141     {{ +1, -1, +0 }, { +0, +0 }},
142     {{ +1, +1, +0 }, { +1, +0 }},
143     {{ -1, +1, +0 }, { +1, +1 }},
144     {{ -1, -1, +0 }, { +0, +1 }},
145     // flip horizontally
146     {{ +1, -1, +0 }, { +0, +0 }},
147     {{ +1, +1, +0 }, { +0, +1 }},
148     {{ -1, +1, +0 }, { +1, +1 }},
149     {{ -1, -1, +0 }, { +1, +0 }},
150     // flip vertically
151     {{ +1, -1, +0 }, { +1, +1 }},
152     {{ +1, +1, +0 }, { +1, +0 }},
153     {{ -1, +1, +0 }, { +0, +0 }},
154     {{ -1, -1, +0 }, { +0, +1 }},
155     // flip source image horizontally, the rotate 90 degrees clock-wise
156     {{ +1, -1, +0 }, { +0, +1 }},
157     {{ +1, +1, +0 }, { +1, +1 }},
158     {{ -1, +1, +0 }, { +1, +0 }},
159     {{ -1, -1, +0 }, { +0, +0 }},
160     // flip source image vertically, the rotate 90 degrees clock-wise
161     {{ +1, -1, +0 }, { +1, +0 }},
162     {{ +1, +1, +0 }, { +0, +0 }},
163     {{ -1, +1, +0 }, { +0, +1 }},
164     {{ -1, -1, +0 }, { +1, +1 }},
165 };
166 
167 // Vertex indices for predefined rotation angles.
168 const GLubyte kIndices[] = {
169     0, 1, 2, 2, 3, 0,      // 0
170     4, 5, 6, 6, 7, 4,      // 90
171     8, 9, 10, 10, 11, 8,   // 180
172     12, 13, 14, 14, 15, 12, // 270
173     16, 17, 18 ,18, 19, 16, // flip h
174     20, 21, 22, 22, 23, 20, // flip v
175     24, 25, 26, 26, 27, 24, // flip h, 90
176     28, 29, 30, 30, 31, 28  // flip v, 90
177 };
178 
179 const GLint kIndicesPerDraw = 6;
180 
181 }  // namespace
182 
TextureDraw()183 TextureDraw::TextureDraw()
184     : mVertexShader(0),
185       mFragmentShader(0),
186       mProgram(0),
187       mCoordTranslation(-1),
188       mCoordScale(-1),
189       mPositionSlot(-1),
190       mInCoordSlot(-1),
191       mScaleSlot(-1),
192       mTextureSlot(-1),
193       mTranslationSlot(-1),
194       mMaskTexture(0),
195       mMaskTextureWidth(0),
196       mMaskTextureHeight(0),
197       mHaveNewMask(false),
198       mMaskIsValid(false),
199       mShouldReallocateTexture(true) {
200     // Create shaders and program.
201     mVertexShader = createShader(GL_VERTEX_SHADER, kVertexShaderSource);
202     mFragmentShader = createShader(GL_FRAGMENT_SHADER, kFragmentShaderSource);
203 
204     mProgram = s_gles2.glCreateProgram();
205     s_gles2.glAttachShader(mProgram, mVertexShader);
206     s_gles2.glAttachShader(mProgram, mFragmentShader);
207 
208     GLint success;
209     s_gles2.glLinkProgram(mProgram);
210     s_gles2.glGetProgramiv(mProgram, GL_LINK_STATUS, &success);
211     if (success == GL_FALSE) {
212         GLchar messages[256];
213         s_gles2.glGetProgramInfoLog(
214                 mProgram, sizeof(messages), 0, &messages[0]);
215         ERR("%s: Could not create/link program: %s\n", __FUNCTION__, messages);
216         s_gles2.glDeleteProgram(mProgram);
217         mProgram = 0;
218         return;
219     }
220 
221     s_gles2.glUseProgram(mProgram);
222 
223     // Retrieve attribute/uniform locations.
224     mPositionSlot = s_gles2.glGetAttribLocation(mProgram, "position");
225     s_gles2.glEnableVertexAttribArray(mPositionSlot);
226 
227     mInCoordSlot = s_gles2.glGetAttribLocation(mProgram, "inCoord");
228     s_gles2.glEnableVertexAttribArray(mInCoordSlot);
229 
230     mAlpha = s_gles2.glGetUniformLocation(mProgram, "alpha");
231     mComposeMode = s_gles2.glGetUniformLocation(mProgram, "composeMode");
232     mColor = s_gles2.glGetUniformLocation(mProgram, "color");
233     mCoordTranslation = s_gles2.glGetUniformLocation(mProgram, "coordTranslation");
234     mCoordScale = s_gles2.glGetUniformLocation(mProgram, "coordScale");
235     mScaleSlot = s_gles2.glGetUniformLocation(mProgram, "scale");
236     mTranslationSlot = s_gles2.glGetUniformLocation(mProgram, "translation");
237     mTextureSlot = s_gles2.glGetUniformLocation(mProgram, "tex");
238 
239     // set default uniform values
240     s_gles2.glUniform1f(mAlpha, 1.0);
241     s_gles2.glUniform1i(mComposeMode, 2);
242     s_gles2.glUniform2f(mTranslationSlot, 0.0, 0.0);
243     s_gles2.glUniform2f(mScaleSlot, 1.0, 1.0);
244     s_gles2.glUniform2f(mCoordTranslation, 0.0, 0.0);
245     s_gles2.glUniform2f(mCoordScale, 1.0, 1.0);
246 
247 #if 0
248     printf("SLOTS position=%d inCoord=%d texture=%d translation=%d\n",
249           mPositionSlot, mInCoordSlot, mTextureSlot, mTranslationSlot);
250 #endif
251 
252     // Create vertex and index buffers.
253     s_gles2.glGenBuffers(1, &mVertexBuffer);
254     s_gles2.glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
255     s_gles2.glBufferData(
256             GL_ARRAY_BUFFER, sizeof(kVertices), kVertices, GL_STATIC_DRAW);
257 
258     s_gles2.glGenBuffers(1, &mIndexBuffer);
259     s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
260     s_gles2.glBufferData(GL_ELEMENT_ARRAY_BUFFER,
261                          sizeof(kIndices),
262                          kIndices,
263                          GL_STATIC_DRAW);
264 
265     // Reset state.
266     s_gles2.glUseProgram(0);
267     s_gles2.glDisableVertexAttribArray(mPositionSlot);
268     s_gles2.glDisableVertexAttribArray(mInCoordSlot);
269     s_gles2.glBindBuffer(GL_ARRAY_BUFFER, 0);
270     s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
271 
272     // Create a texture handle for use with an overlay mask
273     s_gles2.glGenTextures(1, &mMaskTexture);
274 }
275 
drawImpl(GLuint texture,float rotation,float dx,float dy,bool wantOverlay)276 bool TextureDraw::drawImpl(GLuint texture, float rotation,
277                            float dx, float dy, bool wantOverlay) {
278     if (!mProgram) {
279         ERR("%s: no program\n", __FUNCTION__);
280         return false;
281     }
282 
283     // TODO(digit): Save previous program state.
284 
285     s_gles2.glUseProgram(mProgram);
286 
287     s_gles2.glEnable(GL_BLEND);
288     s_gles2.glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
289 #ifdef DEBUG_TEXTURE_DRAW
290     GLenum err = s_gles2.glGetError();
291     if (err != GL_NO_ERROR) {
292         ERR("%s: Could not use program error=0x%x\n",
293             __FUNCTION__, err);
294     }
295 #endif
296 
297     // Setup the |position| attribute values.
298     s_gles2.glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
299 
300 #ifdef DEBUG_TEXTURE_DRAW
301     err = s_gles2.glGetError();
302     if (err != GL_NO_ERROR) {
303         ERR("%s: Could not bind GL_ARRAY_BUFFER error=0x%x\n",
304             __FUNCTION__, err);
305     }
306 #endif
307 
308     s_gles2.glEnableVertexAttribArray(mPositionSlot);
309     s_gles2.glVertexAttribPointer(mPositionSlot,
310                                   3,
311                                   GL_FLOAT,
312                                   GL_FALSE,
313                                   sizeof(Vertex),
314                                   0);
315 
316 #ifdef DEBUG_TEXTURE_DRAW
317     err = s_gles2.glGetError();
318     if (err != GL_NO_ERROR) {
319         ERR("%s: Could glVertexAttribPointer with mPositionSlot error=0x%x\n",
320             __FUNCTION__, err);
321     }
322 #endif
323 
324     // Setup the |inCoord| attribute values.
325     s_gles2.glEnableVertexAttribArray(mInCoordSlot);
326     s_gles2.glVertexAttribPointer(mInCoordSlot,
327                                   2,
328                                   GL_FLOAT,
329                                   GL_FALSE,
330                                   sizeof(Vertex),
331                                   reinterpret_cast<GLvoid*>(
332                                         static_cast<uintptr_t>(
333                                                 sizeof(float) * 3)));
334 
335     // setup the |texture| uniform value.
336     s_gles2.glActiveTexture(GL_TEXTURE0);
337     s_gles2.glBindTexture(GL_TEXTURE_2D, texture);
338     s_gles2.glUniform1i(mTextureSlot, 0);
339 
340     // setup the |translation| uniform value.
341     s_gles2.glUniform2f(mTranslationSlot, dx, dy);
342 
343 #ifdef DEBUG_TEXTURE_DRAW
344     // Validate program, just to be sure.
345     s_gles2.glValidateProgram(mProgram);
346     GLint validState = 0;
347     s_gles2.glGetProgramiv(mProgram, GL_VALIDATE_STATUS, &validState);
348     if (validState == GL_FALSE) {
349         GLchar messages[256] = {};
350         s_gles2.glGetProgramInfoLog(
351                 mProgram, sizeof(messages), 0, &messages[0]);
352         ERR("%s: Could not run program: '%s'\n", __FUNCTION__, messages);
353         return false;
354     }
355 #endif
356 
357     // Do the rendering.
358     s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
359 #ifdef DEBUG_TEXTURE_DRAW
360     err = s_gles2.glGetError();
361     if (err != GL_NO_ERROR) {
362         ERR("%s: Could not glBindBuffer(GL_ELEMENT_ARRAY_BUFFER) error=0x%x\n",
363             __FUNCTION__, err);
364     }
365 #endif
366 
367     // We may only get 0, 90, 180, 270 in |rotation| so far.
368     const int intRotation = ((int)rotation)/90;
369     assert(intRotation >= 0 && intRotation <= 3);
370     intptr_t indexShift = 0;
371     switch (intRotation) {
372     case 0:
373         indexShift = 5 * kIndicesPerDraw;
374         break;
375     case 1:
376         indexShift = 7 * kIndicesPerDraw;
377         break;
378     case 2:
379         indexShift = 4 * kIndicesPerDraw;
380         break;
381     case 3:
382         indexShift = 6 * kIndicesPerDraw;
383         break;
384     }
385     s_gles2.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
386     s_gles2.glClear(GL_COLOR_BUFFER_BIT);
387     s_gles2.glDrawElements(GL_TRIANGLES, kIndicesPerDraw, GL_UNSIGNED_BYTE,
388                            (const GLvoid*)indexShift);
389 
390     bool shouldDrawMask = false;
391     GLfloat scale[2];
392     s_gles2.glGetUniformfv(mProgram, mScaleSlot, scale);
393     GLfloat overlayScale[2];
394     {
395         android::base::AutoLock lock(mMaskLock);
396         if (wantOverlay && mHaveNewMask) {
397             // Create a texture from the mask image and make it
398             // available to be blended
399             GLint prevUnpackAlignment;
400             s_gles2.glGetIntegerv(GL_UNPACK_ALIGNMENT, &prevUnpackAlignment);
401             s_gles2.glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
402 
403             s_gles2.glBindTexture(GL_TEXTURE_2D, mMaskTexture);
404 
405             s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
406             s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
407 
408             if (mShouldReallocateTexture) {
409                 mMaskTextureWidth = mMaskWidth;
410                 mMaskTextureHeight = mMaskHeight;
411                 // mMaskPixels is actually not used here, we only use
412                 // glTexImage2D here to resize the texture
413                 s_gles2.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,
414                                      mMaskTextureWidth, mMaskTextureHeight, 0,
415                                      GL_RGBA, GL_UNSIGNED_BYTE,
416                                      mMaskPixels.data());
417                 mShouldReallocateTexture = false;
418             }
419 
420             // Put the new texture in the center.
421             s_gles2.glTexSubImage2D(
422                     GL_TEXTURE_2D, 0, (mMaskTextureWidth - mMaskWidth) / 2,
423                     (mMaskTextureHeight - mMaskHeight) / 2, mMaskWidth,
424                     mMaskHeight, GL_RGBA, GL_UNSIGNED_BYTE, mMaskPixels.data());
425 
426             s_gles2.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
427             s_gles2.glEnable(GL_BLEND);
428 
429             s_gles2.glPixelStorei(GL_UNPACK_ALIGNMENT, prevUnpackAlignment);
430 
431             mHaveNewMask = false;
432             mMaskIsValid = true;
433         }
434         shouldDrawMask = mMaskIsValid && wantOverlay;
435         // Scale the texture to only show that actual mask.
436         overlayScale[0] = static_cast<float>(mMaskTextureWidth) /
437                           static_cast<float>(mMaskWidth) * scale[0];
438         overlayScale[1] = static_cast<float>(mMaskTextureHeight) /
439                           static_cast<float>(mMaskHeight) * scale[1];
440     }
441 
442     if (shouldDrawMask) {
443         if (mBlendResetNeeded) {
444             s_gles2.glEnable(GL_BLEND);
445             mBlendResetNeeded = false;
446         }
447         s_gles2.glUniform2f(mScaleSlot, overlayScale[0], overlayScale[1]);
448         // mMaskTexture should only be accessed on the thread where drawImpl is
449         // called, hence no need for lock.
450         s_gles2.glBindTexture(GL_TEXTURE_2D, mMaskTexture);
451         s_gles2.glDrawElements(GL_TRIANGLES, kIndicesPerDraw, GL_UNSIGNED_BYTE,
452                                (const GLvoid*)indexShift);
453         // Reset to the "normal" texture
454         s_gles2.glBindTexture(GL_TEXTURE_2D, texture);
455         s_gles2.glUniform2f(mScaleSlot, scale[0], scale[1]);
456     }
457 
458 #ifdef DEBUG_TEXTURE_DRAW
459     err = s_gles2.glGetError();
460     if (err != GL_NO_ERROR) {
461         ERR("%s: Could not glDrawElements() error=0x%x\n",
462             __FUNCTION__, err);
463     }
464 #endif
465 
466     // TODO(digit): Restore previous program state.
467     // For now, reset back to zero and assume other users will
468     // follow the same protocol.
469     s_gles2.glUseProgram(0);
470     s_gles2.glDisableVertexAttribArray(mPositionSlot);
471     s_gles2.glDisableVertexAttribArray(mInCoordSlot);
472     s_gles2.glBindBuffer(GL_ARRAY_BUFFER, 0);
473     s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
474 
475     return true;
476 }
477 
~TextureDraw()478 TextureDraw::~TextureDraw() {
479     s_gles2.glDeleteBuffers(1, &mIndexBuffer);
480     s_gles2.glDeleteBuffers(1, &mVertexBuffer);
481 
482     if (mFragmentShader) {
483         s_gles2.glDeleteShader(mFragmentShader);
484     }
485     if (mVertexShader) {
486         s_gles2.glDeleteShader(mVertexShader);
487     }
488     if (mMaskTexture) {
489         s_gles2.glDeleteTextures(1, &mMaskTexture);
490     }
491 }
492 
setScreenMask(int width,int height,const unsigned char * rgbaData)493 void TextureDraw::setScreenMask(int width, int height, const unsigned char* rgbaData) {
494     android::base::AutoLock lock(mMaskLock);
495     if (width <= 0 || height <= 0 || rgbaData == nullptr) {
496         mMaskIsValid = false;
497         return;
498     }
499 
500     mShouldReallocateTexture =
501             (width > mMaskTextureWidth) || (height > mMaskTextureHeight);
502     auto nextMaskTextureWidth = std::max(width, mMaskTextureWidth);
503     auto nextMaskTextureHeight = std::max(height, mMaskTextureHeight);
504     mMaskPixels.resize(nextMaskTextureWidth * nextMaskTextureHeight * 4);
505     // Save the data for use in the right context
506     std::copy(rgbaData, rgbaData + width * height * 4, mMaskPixels.begin());
507 
508     mHaveNewMask = true;
509     mMaskWidth = width;
510     mMaskHeight = height;
511 }
512 
preDrawLayer()513 void TextureDraw::preDrawLayer() {
514     if (!mProgram) {
515         ERR("%s: no program\n", __FUNCTION__);
516         return;
517     }
518     s_gles2.glUseProgram(mProgram);
519 #ifdef DEBUG_TEXTURE_DRAW
520     GLenum err = s_gles2.glGetError();
521     if (err != GL_NO_ERROR) {
522         ERR("%s: Could not use program error=0x%x\n",
523             __FUNCTION__, err);
524     }
525 #endif
526 
527     s_gles2.glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
528 #ifdef DEBUG_TEXTURE_DRAW
529     err = s_gles2.glGetError();
530     if (err != GL_NO_ERROR) {
531         ERR("%s: Could not bind GL_ARRAY_BUFFER error=0x%x\n",
532             __FUNCTION__, err);
533     }
534 #endif
535     s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
536 #ifdef DEBUG_TEXTURE_DRAW
537     err = s_gles2.glGetError();
538     if (err != GL_NO_ERROR) {
539         ERR("%s: Could not glBindBuffer(GL_ELEMENT_ARRAY_BUFFER) error=0x%x\n",
540             __FUNCTION__, err);
541     }
542 #endif
543 
544     s_gles2.glEnableVertexAttribArray(mPositionSlot);
545     s_gles2.glVertexAttribPointer(mPositionSlot,
546                                   3,
547                                   GL_FLOAT,
548                                   GL_FALSE,
549                                   sizeof(Vertex),
550                                   0);
551 
552     s_gles2.glEnableVertexAttribArray(mInCoordSlot);
553     s_gles2.glVertexAttribPointer(mInCoordSlot,
554                                   2,
555                                   GL_FLOAT,
556                                   GL_FALSE,
557                                   sizeof(Vertex),
558                                   reinterpret_cast<GLvoid*>(
559                                         static_cast<uintptr_t>(
560                                                 sizeof(float) * 3)));
561 #ifdef DEBUG_TEXTURE_DRAW
562     err = s_gles2.glGetError();
563     if (err != GL_NO_ERROR) {
564         ERR("%s: Could glVertexAttribPointer with mPositionSlot error=0x%x\n",
565             __FUNCTION__, err);
566     }
567 #endif
568 
569    // set composition default
570     s_gles2.glUniform1i(mComposeMode, 2);
571     s_gles2.glActiveTexture(GL_TEXTURE0);
572     s_gles2.glUniform1i(mTextureSlot, 0);
573     s_gles2.glEnable(GL_BLEND);
574     s_gles2.glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
575 }
576 
prepareForDrawLayer()577 void TextureDraw::prepareForDrawLayer() {
578     // clear color
579     s_gles2.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
580 }
581 
drawLayer(const ComposeLayer & layer,int frameWidth,int frameHeight,int cbWidth,int cbHeight,GLuint texture)582 void TextureDraw::drawLayer(const ComposeLayer& layer, int frameWidth, int frameHeight,
583                             int cbWidth, int cbHeight, GLuint texture) {
584     preDrawLayer();
585     switch(layer.composeMode) {
586         case HWC2_COMPOSITION_DEVICE:
587             s_gles2.glBindTexture(GL_TEXTURE_2D, texture);
588             break;
589         case HWC2_COMPOSITION_SOLID_COLOR: {
590             s_gles2.glUniform1i(mComposeMode, layer.composeMode);
591             s_gles2.glUniform4f(mColor,
592                                 layer.color.r/255.0, layer.color.g/255.0,
593                                 layer.color.b/255.0, layer.color.a/255.0);
594             break;
595         }
596         case HWC2_COMPOSITION_CLIENT:
597         case HWC2_COMPOSITION_CURSOR:
598         case HWC2_COMPOSITION_SIDEBAND:
599         case HWC2_COMPOSITION_INVALID:
600         default:
601             ERR("%s: invalid composition mode %d", __FUNCTION__, layer.composeMode);
602             return;
603     }
604 
605     switch(layer.blendMode) {
606         case HWC2_BLEND_MODE_NONE:
607             s_gles2.glDisable(GL_BLEND);
608             mBlendResetNeeded = true;
609             break;
610         case HWC2_BLEND_MODE_PREMULTIPLIED:
611             break;
612         case HWC2_BLEND_MODE_INVALID:
613         case HWC2_BLEND_MODE_COVERAGE:
614         default:
615             ERR("%s: invalid blendMode %d", __FUNCTION__, layer.blendMode);
616             return;
617     }
618 
619     s_gles2.glUniform1f(mAlpha, layer.alpha);
620 
621     float edges[4];
622     edges[0] = 1 - 2.0 * (frameWidth - layer.displayFrame.left)/frameWidth;
623     edges[1] = 1 - 2.0 * (frameHeight - layer.displayFrame.top)/frameHeight;
624     edges[2] = 1 - 2.0 * (frameWidth - layer.displayFrame.right)/frameWidth;
625     edges[3] = 1- 2.0 * (frameHeight - layer.displayFrame.bottom)/frameHeight;
626 
627     float crop[4];
628     crop[0] = layer.crop.left/cbWidth;
629     crop[1] = layer.crop.top/cbHeight;
630     crop[2] = layer.crop.right/cbWidth;
631     crop[3] = layer.crop.bottom/cbHeight;
632 
633     // setup the |translation| uniform value.
634     s_gles2.glUniform2f(mTranslationSlot, (-edges[2] - edges[0])/2,
635                         (-edges[3] - edges[1])/2);
636     s_gles2.glUniform2f(mScaleSlot, (edges[2] - edges[0])/2,
637                         (edges[1] - edges[3])/2);
638     s_gles2.glUniform2f(mCoordTranslation, crop[0], crop[3]);
639     s_gles2.glUniform2f(mCoordScale, crop[2] - crop[0], crop[1] - crop[3]);
640 
641     intptr_t indexShift;
642     switch(layer.transform) {
643     case HWC_TRANSFORM_ROT_90:
644         indexShift = 1 * kIndicesPerDraw;
645         break;
646     case HWC_TRANSFORM_ROT_180:
647         indexShift = 2 * kIndicesPerDraw;
648         break;
649     case HWC_TRANSFORM_ROT_270:
650         indexShift = 3 * kIndicesPerDraw;
651         break;
652     case HWC_TRANSFORM_FLIP_H:
653         indexShift = 4 * kIndicesPerDraw;
654         break;
655     case HWC_TRANSFORM_FLIP_V:
656         indexShift = 5 * kIndicesPerDraw;
657         break;
658     case HWC_TRANSFORM_FLIP_H_ROT_90:
659         indexShift = 6 * kIndicesPerDraw;
660         break;
661     case HWC_TRANSFORM_FLIP_V_ROT_90:
662         indexShift = 7 * kIndicesPerDraw;
663         break;
664     default:
665         indexShift = 0;
666     }
667     s_gles2.glDrawElements(GL_TRIANGLES, kIndicesPerDraw, GL_UNSIGNED_BYTE,
668                            (const GLvoid*)indexShift);
669 #ifdef DEBUG_TEXTURE_DRAW
670     GLenum err = s_gles2.glGetError();
671     if (err != GL_NO_ERROR) {
672         ERR("%s: Could not glDrawElements() error=0x%x\n",
673             __FUNCTION__, err);
674     }
675 #endif
676 
677     // restore the default value for the next draw layer
678     if (layer.composeMode != HWC2_COMPOSITION_DEVICE) {
679         s_gles2.glUniform1i(mComposeMode, HWC2_COMPOSITION_DEVICE);
680     }
681     if (layer.blendMode != HWC2_BLEND_MODE_PREMULTIPLIED) {
682         s_gles2.glEnable(GL_BLEND);
683         mBlendResetNeeded = false;
684         s_gles2.glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
685     }
686 }
687 
688 // Do Post right after drawing each layer, so keep using this program
cleanupForDrawLayer()689 void TextureDraw::cleanupForDrawLayer() {
690     s_gles2.glUniform1f(mAlpha, 1.0);
691     s_gles2.glUniform1i(mComposeMode, HWC2_COMPOSITION_DEVICE);
692     s_gles2.glUniform2f(mTranslationSlot, 0.0, 0.0);
693     s_gles2.glUniform2f(mScaleSlot, 1.0, 1.0);
694     s_gles2.glUniform2f(mCoordTranslation, 0.0, 0.0);
695     s_gles2.glUniform2f(mCoordScale, 1.0, 1.0);
696 }
697 
698 }  // namespace gl
699 }  // namespace gfxstream
700