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 s_gles2.glEnable(GL_BLEND);
284 s_gles2.glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
285 #ifndef NDEBUG
286 GLenum err = s_gles2.glGetError();
287 if (err != GL_NO_ERROR) {
288 ERR("%s: Could not use program error=0x%x\n",
289 __FUNCTION__, err);
290 }
291 #endif
292
293 // Setup the |position| attribute values.
294 s_gles2.glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
295
296 #ifndef NDEBUG
297 err = s_gles2.glGetError();
298 if (err != GL_NO_ERROR) {
299 ERR("%s: Could not bind GL_ARRAY_BUFFER error=0x%x\n",
300 __FUNCTION__, err);
301 }
302 #endif
303
304 s_gles2.glEnableVertexAttribArray(mPositionSlot);
305 s_gles2.glVertexAttribPointer(mPositionSlot,
306 3,
307 GL_FLOAT,
308 GL_FALSE,
309 sizeof(Vertex),
310 0);
311
312 #ifndef NDEBUG
313 err = s_gles2.glGetError();
314 if (err != GL_NO_ERROR) {
315 ERR("%s: Could glVertexAttribPointer with mPositionSlot error=0x%x\n",
316 __FUNCTION__, err);
317 }
318 #endif
319
320 // Setup the |inCoord| attribute values.
321 s_gles2.glEnableVertexAttribArray(mInCoordSlot);
322 s_gles2.glVertexAttribPointer(mInCoordSlot,
323 2,
324 GL_FLOAT,
325 GL_FALSE,
326 sizeof(Vertex),
327 reinterpret_cast<GLvoid*>(
328 static_cast<uintptr_t>(
329 sizeof(float) * 3)));
330
331 // setup the |texture| uniform value.
332 s_gles2.glActiveTexture(GL_TEXTURE0);
333 s_gles2.glBindTexture(GL_TEXTURE_2D, texture);
334 s_gles2.glUniform1i(mTextureSlot, 0);
335
336 // setup the |translation| uniform value.
337 s_gles2.glUniform2f(mTranslationSlot, dx, dy);
338
339 #ifndef NDEBUG
340 // Validate program, just to be sure.
341 s_gles2.glValidateProgram(mProgram);
342 GLint validState = 0;
343 s_gles2.glGetProgramiv(mProgram, GL_VALIDATE_STATUS, &validState);
344 if (validState == GL_FALSE) {
345 GLchar messages[256] = {};
346 s_gles2.glGetProgramInfoLog(
347 mProgram, sizeof(messages), 0, &messages[0]);
348 ERR("%s: Could not run program: '%s'\n", __FUNCTION__, messages);
349 return false;
350 }
351 #endif
352
353 // Do the rendering.
354 s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
355 #ifndef NDEBUG
356 err = s_gles2.glGetError();
357 if (err != GL_NO_ERROR) {
358 ERR("%s: Could not glBindBuffer(GL_ELEMENT_ARRAY_BUFFER) error=0x%x\n",
359 __FUNCTION__, err);
360 }
361 #endif
362
363 // We may only get 0, 90, 180, 270 in |rotation| so far.
364 const int intRotation = ((int)rotation)/90;
365 assert(intRotation >= 0 && intRotation <= 3);
366 intptr_t indexShift = 0;
367 switch (intRotation) {
368 case 0:
369 indexShift = 5 * kIndicesPerDraw;
370 break;
371 case 1:
372 indexShift = 7 * kIndicesPerDraw;
373 break;
374 case 2:
375 indexShift = 4 * kIndicesPerDraw;
376 break;
377 case 3:
378 indexShift = 6 * kIndicesPerDraw;
379 break;
380 }
381 s_gles2.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
382 s_gles2.glClear(GL_COLOR_BUFFER_BIT);
383 s_gles2.glDrawElements(GL_TRIANGLES, kIndicesPerDraw, GL_UNSIGNED_BYTE,
384 (const GLvoid*)indexShift);
385
386 bool shouldDrawMask = false;
387 GLfloat scale[2];
388 s_gles2.glGetUniformfv(mProgram, mScaleSlot, scale);
389 GLfloat overlayScale[2];
390 {
391 android::base::AutoLock lock(mMaskLock);
392 if (wantOverlay && mHaveNewMask) {
393 // Create a texture from the mask image and make it
394 // available to be blended
395 GLint prevUnpackAlignment;
396 s_gles2.glGetIntegerv(GL_UNPACK_ALIGNMENT, &prevUnpackAlignment);
397 s_gles2.glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
398
399 s_gles2.glBindTexture(GL_TEXTURE_2D, mMaskTexture);
400
401 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
402 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
403
404 if (mShouldReallocateTexture) {
405 mMaskTextureWidth = mMaskWidth;
406 mMaskTextureHeight = mMaskHeight;
407 // mMaskPixels is actually not used here, we only use
408 // glTexImage2D here to resize the texture
409 s_gles2.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,
410 mMaskTextureWidth, mMaskTextureHeight, 0,
411 GL_RGBA, GL_UNSIGNED_BYTE,
412 mMaskPixels.data());
413 mShouldReallocateTexture = false;
414 }
415
416 // Put the new texture in the center.
417 s_gles2.glTexSubImage2D(
418 GL_TEXTURE_2D, 0, (mMaskTextureWidth - mMaskWidth) / 2,
419 (mMaskTextureHeight - mMaskHeight) / 2, mMaskWidth,
420 mMaskHeight, GL_RGBA, GL_UNSIGNED_BYTE, mMaskPixels.data());
421
422 s_gles2.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
423 s_gles2.glEnable(GL_BLEND);
424
425 s_gles2.glPixelStorei(GL_UNPACK_ALIGNMENT, prevUnpackAlignment);
426
427 mHaveNewMask = false;
428 mMaskIsValid = true;
429 }
430 shouldDrawMask = mMaskIsValid && wantOverlay;
431 // Scale the texture to only show that actual mask.
432 overlayScale[0] = static_cast<float>(mMaskTextureWidth) /
433 static_cast<float>(mMaskWidth) * scale[0];
434 overlayScale[1] = static_cast<float>(mMaskTextureHeight) /
435 static_cast<float>(mMaskHeight) * scale[1];
436 }
437
438 if (shouldDrawMask) {
439 if (mBlendResetNeeded) {
440 s_gles2.glEnable(GL_BLEND);
441 mBlendResetNeeded = false;
442 }
443 s_gles2.glUniform2f(mScaleSlot, overlayScale[0], overlayScale[1]);
444 // mMaskTexture should only be accessed on the thread where drawImpl is
445 // called, hence no need for lock.
446 s_gles2.glBindTexture(GL_TEXTURE_2D, mMaskTexture);
447 s_gles2.glDrawElements(GL_TRIANGLES, kIndicesPerDraw, GL_UNSIGNED_BYTE,
448 (const GLvoid*)indexShift);
449 // Reset to the "normal" texture
450 s_gles2.glBindTexture(GL_TEXTURE_2D, texture);
451 s_gles2.glUniform2f(mScaleSlot, scale[0], scale[1]);
452 }
453
454 #ifndef NDEBUG
455 err = s_gles2.glGetError();
456 if (err != GL_NO_ERROR) {
457 ERR("%s: Could not glDrawElements() error=0x%x\n",
458 __FUNCTION__, err);
459 }
460 #endif
461
462 // TODO(digit): Restore previous program state.
463 // For now, reset back to zero and assume other users will
464 // follow the same protocol.
465 s_gles2.glUseProgram(0);
466 s_gles2.glDisableVertexAttribArray(mPositionSlot);
467 s_gles2.glDisableVertexAttribArray(mInCoordSlot);
468 s_gles2.glBindBuffer(GL_ARRAY_BUFFER, 0);
469 s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
470
471 return true;
472 }
473
~TextureDraw()474 TextureDraw::~TextureDraw() {
475 s_gles2.glDeleteBuffers(1, &mIndexBuffer);
476 s_gles2.glDeleteBuffers(1, &mVertexBuffer);
477
478 if (mFragmentShader) {
479 s_gles2.glDeleteShader(mFragmentShader);
480 }
481 if (mVertexShader) {
482 s_gles2.glDeleteShader(mVertexShader);
483 }
484 if (mMaskTexture) {
485 s_gles2.glDeleteTextures(1, &mMaskTexture);
486 }
487 }
488
setScreenMask(int width,int height,const unsigned char * rgbaData)489 void TextureDraw::setScreenMask(int width, int height, const unsigned char* rgbaData) {
490 android::base::AutoLock lock(mMaskLock);
491 if (width <= 0 || height <= 0 || rgbaData == nullptr) {
492 mMaskIsValid = false;
493 return;
494 }
495
496 mShouldReallocateTexture =
497 (width > mMaskTextureWidth) || (height > mMaskTextureHeight);
498 auto nextMaskTextureWidth = std::max(width, mMaskTextureWidth);
499 auto nextMaskTextureHeight = std::max(height, mMaskTextureHeight);
500 mMaskPixels.resize(nextMaskTextureWidth * nextMaskTextureHeight * 4);
501 // Save the data for use in the right context
502 std::copy(rgbaData, rgbaData + width * height * 4, mMaskPixels.begin());
503
504 mHaveNewMask = true;
505 mMaskWidth = width;
506 mMaskHeight = height;
507 }
508
preDrawLayer()509 void TextureDraw::preDrawLayer() {
510 if (!mProgram) {
511 ERR("%s: no program\n", __FUNCTION__);
512 return;
513 }
514 s_gles2.glUseProgram(mProgram);
515 #ifndef NDEBUG
516 GLenum err = s_gles2.glGetError();
517 if (err != GL_NO_ERROR) {
518 ERR("%s: Could not use program error=0x%x\n",
519 __FUNCTION__, err);
520 }
521 #endif
522
523 s_gles2.glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
524 #ifndef NDEBUG
525 err = s_gles2.glGetError();
526 if (err != GL_NO_ERROR) {
527 ERR("%s: Could not bind GL_ARRAY_BUFFER error=0x%x\n",
528 __FUNCTION__, err);
529 }
530 #endif
531 s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
532 #ifndef NDEBUG
533 err = s_gles2.glGetError();
534 if (err != GL_NO_ERROR) {
535 ERR("%s: Could not glBindBuffer(GL_ELEMENT_ARRAY_BUFFER) error=0x%x\n",
536 __FUNCTION__, err);
537 }
538 #endif
539
540 s_gles2.glEnableVertexAttribArray(mPositionSlot);
541 s_gles2.glVertexAttribPointer(mPositionSlot,
542 3,
543 GL_FLOAT,
544 GL_FALSE,
545 sizeof(Vertex),
546 0);
547
548 s_gles2.glEnableVertexAttribArray(mInCoordSlot);
549 s_gles2.glVertexAttribPointer(mInCoordSlot,
550 2,
551 GL_FLOAT,
552 GL_FALSE,
553 sizeof(Vertex),
554 reinterpret_cast<GLvoid*>(
555 static_cast<uintptr_t>(
556 sizeof(float) * 3)));
557 #ifndef NDEBUG
558 err = s_gles2.glGetError();
559 if (err != GL_NO_ERROR) {
560 ERR("%s: Could glVertexAttribPointer with mPositionSlot error=0x%x\n",
561 __FUNCTION__, err);
562 }
563 #endif
564
565 // set composition default
566 s_gles2.glUniform1i(mComposeMode, 2);
567 s_gles2.glActiveTexture(GL_TEXTURE0);
568 s_gles2.glUniform1i(mTextureSlot, 0);
569 s_gles2.glEnable(GL_BLEND);
570 s_gles2.glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
571 }
572
prepareForDrawLayer()573 void TextureDraw::prepareForDrawLayer() {
574 // clear color
575 s_gles2.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
576 }
577
drawLayer(const ComposeLayer & layer,int frameWidth,int frameHeight,int cbWidth,int cbHeight,GLuint texture)578 void TextureDraw::drawLayer(const ComposeLayer& layer, int frameWidth, int frameHeight,
579 int cbWidth, int cbHeight, GLuint texture) {
580 preDrawLayer();
581 switch(layer.composeMode) {
582 case HWC2_COMPOSITION_DEVICE:
583 s_gles2.glBindTexture(GL_TEXTURE_2D, texture);
584 break;
585 case HWC2_COMPOSITION_SOLID_COLOR: {
586 s_gles2.glUniform1i(mComposeMode, layer.composeMode);
587 s_gles2.glUniform4f(mColor,
588 layer.color.r/255.0, layer.color.g/255.0,
589 layer.color.b/255.0, layer.color.a/255.0);
590 break;
591 }
592 case HWC2_COMPOSITION_CLIENT:
593 case HWC2_COMPOSITION_CURSOR:
594 case HWC2_COMPOSITION_SIDEBAND:
595 case HWC2_COMPOSITION_INVALID:
596 default:
597 ERR("%s: invalid composition mode %d", __FUNCTION__, layer.composeMode);
598 return;
599 }
600
601 switch(layer.blendMode) {
602 case HWC2_BLEND_MODE_NONE:
603 s_gles2.glDisable(GL_BLEND);
604 mBlendResetNeeded = true;
605 break;
606 case HWC2_BLEND_MODE_PREMULTIPLIED:
607 break;
608 case HWC2_BLEND_MODE_INVALID:
609 case HWC2_BLEND_MODE_COVERAGE:
610 default:
611 ERR("%s: invalid blendMode %d", __FUNCTION__, layer.blendMode);
612 return;
613 }
614
615 s_gles2.glUniform1f(mAlpha, layer.alpha);
616
617 float edges[4];
618 edges[0] = 1 - 2.0 * (frameWidth - layer.displayFrame.left)/frameWidth;
619 edges[1] = 1 - 2.0 * (frameHeight - layer.displayFrame.top)/frameHeight;
620 edges[2] = 1 - 2.0 * (frameWidth - layer.displayFrame.right)/frameWidth;
621 edges[3] = 1- 2.0 * (frameHeight - layer.displayFrame.bottom)/frameHeight;
622
623 float crop[4];
624 crop[0] = layer.crop.left/cbWidth;
625 crop[1] = layer.crop.top/cbHeight;
626 crop[2] = layer.crop.right/cbWidth;
627 crop[3] = layer.crop.bottom/cbHeight;
628
629 // setup the |translation| uniform value.
630 s_gles2.glUniform2f(mTranslationSlot, (-edges[2] - edges[0])/2,
631 (-edges[3] - edges[1])/2);
632 s_gles2.glUniform2f(mScaleSlot, (edges[2] - edges[0])/2,
633 (edges[1] - edges[3])/2);
634 s_gles2.glUniform2f(mCoordTranslation, crop[0], crop[3]);
635 s_gles2.glUniform2f(mCoordScale, crop[2] - crop[0], crop[1] - crop[3]);
636
637 intptr_t indexShift;
638 switch(layer.transform) {
639 case HWC_TRANSFORM_ROT_90:
640 indexShift = 1 * kIndicesPerDraw;
641 break;
642 case HWC_TRANSFORM_ROT_180:
643 indexShift = 2 * kIndicesPerDraw;
644 break;
645 case HWC_TRANSFORM_ROT_270:
646 indexShift = 3 * kIndicesPerDraw;
647 break;
648 case HWC_TRANSFORM_FLIP_H:
649 indexShift = 4 * kIndicesPerDraw;
650 break;
651 case HWC_TRANSFORM_FLIP_V:
652 indexShift = 5 * kIndicesPerDraw;
653 break;
654 case HWC_TRANSFORM_FLIP_H_ROT_90:
655 indexShift = 6 * kIndicesPerDraw;
656 break;
657 case HWC_TRANSFORM_FLIP_V_ROT_90:
658 indexShift = 7 * kIndicesPerDraw;
659 break;
660 default:
661 indexShift = 0;
662 }
663 s_gles2.glDrawElements(GL_TRIANGLES, kIndicesPerDraw, GL_UNSIGNED_BYTE,
664 (const GLvoid*)indexShift);
665 #ifndef NDEBUG
666 GLenum err = s_gles2.glGetError();
667 if (err != GL_NO_ERROR) {
668 ERR("%s: Could not glDrawElements() error=0x%x\n",
669 __FUNCTION__, err);
670 }
671 #endif
672
673 // restore the default value for the next draw layer
674 if (layer.composeMode != HWC2_COMPOSITION_DEVICE) {
675 s_gles2.glUniform1i(mComposeMode, HWC2_COMPOSITION_DEVICE);
676 }
677 if (layer.blendMode != HWC2_BLEND_MODE_PREMULTIPLIED) {
678 s_gles2.glEnable(GL_BLEND);
679 mBlendResetNeeded = false;
680 s_gles2.glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
681 }
682 }
683
684 // Do Post right after drawing each layer, so keep using this program
cleanupForDrawLayer()685 void TextureDraw::cleanupForDrawLayer() {
686 s_gles2.glUniform1f(mAlpha, 1.0);
687 s_gles2.glUniform1i(mComposeMode, HWC2_COMPOSITION_DEVICE);
688 s_gles2.glUniform2f(mTranslationSlot, 0.0, 0.0);
689 s_gles2.glUniform2f(mScaleSlot, 1.0, 1.0);
690 s_gles2.glUniform2f(mCoordTranslation, 0.0, 0.0);
691 s_gles2.glUniform2f(mCoordScale, 1.0, 1.0);
692 }
693
694 } // namespace gl
695 } // namespace gfxstream
696