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