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