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