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