1 /*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "TextureResize.h"
18
19 #include <stdio.h>
20 #include <string.h>
21 #include <sstream>
22 #include <string>
23 #include <utility>
24 #include <vector>
25
26 #include <GLES2/gl2ext.h>
27
28 #include "OpenGLESDispatch/DispatchTables.h"
29 #include "aemu/base/synchronization/Lock.h"
30 #include "host-common/logging.h"
31 #include "host-common/misc.h"
32 #include "host-common/opengl/misc.h"
33
34 namespace gfxstream {
35 namespace gl {
36
37 // #define V(...) VERBOSE_PRINT(gles,__VA_ARGS__)
38 #define V(...)
39 #define MAX_FACTOR_POWER 4
40
41 static const char kCommonShaderSource[] =
42 "precision mediump float;\n"
43 "varying vec2 vUV00, vUV01;\n"
44 "#if FACTOR > 2\n"
45 "varying vec2 vUV02, vUV03;\n"
46 "#if FACTOR > 4\n"
47 "varying vec2 vUV04, vUV05, vUV06, vUV07;\n"
48 "#if FACTOR > 8\n"
49 "varying vec2 vUV08, vUV09, vUV10, vUV11, vUV12, vUV13, vUV14, vUV15;\n"
50 "#endif\n"
51 "#endif\n"
52 "#endif\n";
53
54 static const char kVertexShaderSource[] =
55 "attribute vec2 aPosition;\n"
56
57 "void main() {\n"
58 " gl_Position = vec4(aPosition, 0, 1);\n"
59 " vec2 uv = ((aPosition + 1.0) / 2.0) + 0.5 / kDimension;\n"
60 " vUV00 = uv;\n"
61 " #ifdef HORIZONTAL\n"
62 " vUV01 = uv + vec2( 1.0 / kDimension.x, 0);\n"
63 " #if FACTOR > 2\n"
64 " vUV02 = uv + vec2( 2.0 / kDimension.x, 0);\n"
65 " vUV03 = uv + vec2( 3.0 / kDimension.x, 0);\n"
66 " #if FACTOR > 4\n"
67 " vUV04 = uv + vec2( 4.0 / kDimension.x, 0);\n"
68 " vUV05 = uv + vec2( 5.0 / kDimension.x, 0);\n"
69 " vUV06 = uv + vec2( 6.0 / kDimension.x, 0);\n"
70 " vUV07 = uv + vec2( 7.0 / kDimension.x, 0);\n"
71 " #if FACTOR > 8\n"
72 " vUV08 = uv + vec2( 8.0 / kDimension.x, 0);\n"
73 " vUV09 = uv + vec2( 9.0 / kDimension.x, 0);\n"
74 " vUV10 = uv + vec2(10.0 / kDimension.x, 0);\n"
75 " vUV11 = uv + vec2(11.0 / kDimension.x, 0);\n"
76 " vUV12 = uv + vec2(12.0 / kDimension.x, 0);\n"
77 " vUV13 = uv + vec2(13.0 / kDimension.x, 0);\n"
78 " vUV14 = uv + vec2(14.0 / kDimension.x, 0);\n"
79 " vUV15 = uv + vec2(15.0 / kDimension.x, 0);\n"
80 " #endif\n" // FACTOR > 8
81 " #endif\n" // FACTOR > 4
82 " #endif\n" // FACTOR > 2
83
84 " #else\n"
85 " vUV01 = uv + vec2(0, 1.0 / kDimension.y);\n"
86 " #if FACTOR > 2\n"
87 " vUV02 = uv + vec2(0, 2.0 / kDimension.y);\n"
88 " vUV03 = uv + vec2(0, 3.0 / kDimension.y);\n"
89 " #if FACTOR > 4\n"
90 " vUV04 = uv + vec2(0, 4.0 / kDimension.y);\n"
91 " vUV05 = uv + vec2(0, 5.0 / kDimension.y);\n"
92 " vUV06 = uv + vec2(0, 6.0 / kDimension.y);\n"
93 " vUV07 = uv + vec2(0, 7.0 / kDimension.y);\n"
94 " #if FACTOR > 8\n"
95 " vUV08 = uv + vec2(0, 8.0 / kDimension.y);\n"
96 " vUV09 = uv + vec2(0, 9.0 / kDimension.y);\n"
97 " vUV10 = uv + vec2(0, 10.0 / kDimension.y);\n"
98 " vUV11 = uv + vec2(0, 11.0 / kDimension.y);\n"
99 " vUV12 = uv + vec2(0, 12.0 / kDimension.y);\n"
100 " vUV13 = uv + vec2(0, 13.0 / kDimension.y);\n"
101 " vUV14 = uv + vec2(0, 14.0 / kDimension.y);\n"
102 " vUV15 = uv + vec2(0, 15.0 / kDimension.y);\n"
103 " #endif\n" // FACTOR > 8
104 " #endif\n" // FACTOR > 4
105 " #endif\n" // FACTOR > 2
106 " #endif\n" // HORIZONTAL/VERTICAL
107 "}\n";
108
109 const char kFragmentShaderSource[] =
110 "uniform sampler2D uTexture;\n"
111
112 "vec3 read(vec2 uv) {\n"
113 " vec3 r = texture2D(uTexture, uv).rgb;\n"
114 " #ifdef HORIZONTAL\n"
115 " r.rgb = pow(r.rgb, vec3(2.2));\n"
116 " #endif\n"
117 " return r;\n"
118 "}\n"
119
120 "void main() {\n"
121 " vec3 sum = read(vUV00) + read(vUV01);\n"
122 " #if FACTOR > 2\n"
123 " sum += read(vUV02) + read(vUV03);\n"
124 " #if FACTOR > 4\n"
125 " sum += read(vUV04) + read(vUV05) + read(vUV06) + read(vUV07);\n"
126 " #if FACTOR > 8\n"
127 " sum += read(vUV08) + read(vUV09) + read(vUV10) + read(vUV11) +"
128 " read(vUV12) + read(vUV13) + read(vUV14) + read(vUV15);\n"
129 " #endif\n"
130 " #endif\n"
131 " #endif\n"
132 " sum /= float(FACTOR);\n"
133 " #ifdef VERTICAL\n"
134 " sum.rgb = pow(sum.rgb, vec3(1.0 / 2.2));\n"
135 " #endif\n"
136 " gl_FragColor = vec4(sum.rgb, 1.0);\n"
137 "}\n";
138
139 // Vertex shader for anti-aliasing - doesn't do anything special.
140 const char kGenericVertexShaderSource[] = R"(
141 attribute vec2 position;
142 attribute vec2 inCoord;
143 varying vec2 outCoord;
144 void main(void) {
145 gl_Position = vec4(position.x, position.y, 0.0, 1.0);
146 outCoord = inCoord;
147 })";
148
149 // Fragment shader
150 const char kGenericFragmentShaderSource[] = R"(
151 precision mediump float;
152 uniform sampler2D texSampler;
153 varying vec2 outCoord;
154 void main(void) {
155 gl_FragColor = texture2D(texSampler, outCoord);
156 }
157 )";
158
159 static const float kVertexData[] = {-1, -1, 3, -1, -1, 3};
160 static android::base::Lock s_programLock;
161 static std::vector<GLuint> s_programsToRelease;
162
createShader(GLenum type,std::initializer_list<const char * > source)163 static GLuint createShader(GLenum type, std::initializer_list<const char*> source) {
164 GLint success, infoLength;
165
166 GLuint shader = s_gles2.glCreateShader(type);
167 if (shader) {
168 s_gles2.glShaderSource(shader, source.size(), source.begin(), nullptr);
169 s_gles2.glCompileShader(shader);
170 s_gles2.glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
171 if (success == GL_FALSE) {
172 s_gles2.glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLength);
173 std::string infoLog(infoLength + 1, '\0');
174 s_gles2.glGetShaderInfoLog(shader, infoLength, nullptr, &infoLog[0]);
175 ERR("%s shader compile failed:\n%s\n",
176 (type == GL_VERTEX_SHADER) ? "Vertex" : "Fragment",
177 infoLog.c_str());
178 s_gles2.glDeleteShader(shader);
179 shader = 0;
180 }
181 }
182 return shader;
183 }
184
attachShaders(TextureResize::Framebuffer * fb,const char * factorDefine,const char * dimensionDefine,GLuint width,GLuint height)185 static void attachShaders(TextureResize::Framebuffer* fb, const char* factorDefine,
186 const char* dimensionDefine, GLuint width, GLuint height) {
187
188 std::ostringstream dimensionConst;
189 dimensionConst << "const vec2 kDimension = vec2(" << width << ", " << height << ");\n";
190
191 GLuint vShader = createShader(GL_VERTEX_SHADER, {
192 factorDefine, dimensionDefine,
193 kCommonShaderSource, dimensionConst.str().c_str(), kVertexShaderSource
194 });
195 GLuint fShader = createShader(GL_FRAGMENT_SHADER, {
196 factorDefine, dimensionDefine, kCommonShaderSource, kFragmentShaderSource
197 });
198
199 if (!vShader || !fShader) {
200 return;
201 }
202 if (!fb->program) {
203 fb->program = s_gles2.glCreateProgram();
204 }
205 s_gles2.glAttachShader(fb->program, vShader);
206 s_gles2.glAttachShader(fb->program, fShader);
207 s_gles2.glLinkProgram(fb->program);
208 s_gles2.glDeleteShader(vShader);
209 s_gles2.glDeleteShader(fShader);
210
211 fb->aPosition = s_gles2.glGetAttribLocation(fb->program, "aPosition");
212 fb->uTexture = s_gles2.glGetUniformLocation(fb->program, "uTexture");
213 }
214
TextureResize(GLuint width,GLuint height)215 TextureResize::TextureResize(GLuint width, GLuint height) :
216 mWidth(width),
217 mHeight(height),
218 mFactor(1),
219 mFBWidth({0,}),
220 mFBHeight({0,}),
221 // Use unsigned byte as the default since it has the most support
222 // and is the input/output format in the end
223 // (TODO) until HDR is common on both guest and host, and we'll
224 // cross that bridge when we get there.
225 mTextureDataType(GL_UNSIGNED_BYTE) {
226
227 // Fix color banding by trying to use a texture type with a high precision.
228 const char* exts = (const char*)s_gles2.glGetString(GL_EXTENSIONS);
229
230 bool hasColorBufferFloat =
231 emugl::getRenderer() == SELECTED_RENDERER_HOST ||
232 emugl::hasExtension(exts, "GL_EXT_color_buffer_float");
233 bool hasColorBufferHalfFloat =
234 emugl::hasExtension(exts, "GL_EXT_color_buffer_half_float");
235 bool hasTextureFloat =
236 emugl::hasExtension(exts, "GL_OES_texture_float");
237 bool hasTextureHalfFloat =
238 emugl::hasExtension(exts, "GL_OES_texture_half_float");
239 bool hasTextureFloatLinear =
240 emugl::hasExtension(exts, "GL_OES_texture_float_linear");
241
242 if (hasColorBufferFloat && hasTextureFloat) {
243 mTextureDataType = GL_FLOAT;
244 } else if (hasColorBufferHalfFloat && hasTextureHalfFloat) {
245 mTextureDataType = GL_HALF_FLOAT_OES;
246 }
247
248 if (hasTextureFloat || hasTextureHalfFloat) {
249 mTextureFilteringMode =
250 hasTextureFloatLinear ? GL_LINEAR : GL_NEAREST;
251 }
252
253 s_gles2.glGenTextures(1, &mFBWidth.texture);
254 s_gles2.glBindTexture(GL_TEXTURE_2D, mFBWidth.texture);
255 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
256 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
257 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
258 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
259
260 s_gles2.glGenTextures(1, &mFBHeight.texture);
261 s_gles2.glBindTexture(GL_TEXTURE_2D, mFBHeight.texture);
262 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mTextureFilteringMode);
263 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mTextureFilteringMode);
264 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
265 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
266
267 s_gles2.glGenFramebuffers(1, &mFBWidth.framebuffer);
268 s_gles2.glGenFramebuffers(1, &mFBHeight.framebuffer);
269
270 s_gles2.glGenBuffers(1, &mVertexBuffer);
271 s_gles2.glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
272 s_gles2.glBufferData(GL_ARRAY_BUFFER, sizeof(kVertexData), kVertexData, GL_STATIC_DRAW);
273
274 // Clear bindings.
275 s_gles2.glBindTexture(GL_TEXTURE_2D, 0);
276 s_gles2.glBindBuffer(GL_ARRAY_BUFFER, 0);
277 }
278
279
280
~TextureResize()281 TextureResize::~TextureResize() {
282 GLuint fb[2] = {mFBWidth.framebuffer, mFBHeight.framebuffer};
283 s_gles2.glDeleteFramebuffers(2, fb);
284
285 GLuint tex[2] = {mFBWidth.texture, mFBHeight.texture};
286 s_gles2.glDeleteTextures(2, tex);
287
288 s_gles2.glDeleteBuffers(1, &mVertexBuffer);
289 // b/242245912
290 // There seems to be a mesa bug that we have to delete the
291 // program in the post thread.
292 android::base::AutoLock lock(s_programLock);
293 s_programsToRelease.push_back(mFBWidth.program);
294 s_programsToRelease.push_back(mFBHeight.program);
295 }
296
update(GLuint texture)297 GLuint TextureResize::update(GLuint texture) {
298 // Store the viewport. The viewport is clobbered due to the framebuffers.
299 GLint vport[4] = { 0, };
300 s_gles2.glGetIntegerv(GL_VIEWPORT, vport);
301 GLint prevFbo = 0;
302 s_gles2.glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &prevFbo);
303 // Correctly deal with rotated screens.
304 GLint tWidth = vport[2], tHeight = vport[3];
305 if ((mWidth < mHeight) != (tWidth < tHeight)) {
306 std::swap(tWidth, tHeight);
307 }
308
309 // Compute the scaling factor needed to get an image just larger than the target viewport.
310 unsigned int factor = 1;
311 for (int i = 0, w = mWidth / 2, h = mHeight / 2;
312 i < MAX_FACTOR_POWER && w >= tWidth && h >= tHeight;
313 i++, w /= 2, h /= 2, factor *= 2) {
314 }
315
316 // No resizing needed if factor == 1
317 if (factor == 1) {
318 return texture;
319 }
320
321 s_gles2.glGetError(); // Clear any GL errors.
322 setupFramebuffers(factor);
323 resize(texture);
324 s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, prevFbo);
325 s_gles2.glViewport(vport[0], vport[1], vport[2], vport[3]); // Restore the viewport.
326 // If there was an error while resizing, just use the unscaled texture.
327 GLenum error = s_gles2.glGetError();
328 if (error != GL_NO_ERROR) {
329 V("GL error while resizing: 0x%x (ignored)\n", error);
330 return texture;
331 }
332
333 return mFBHeight.texture;
334 }
335
update(GLuint texture,int width,int height,int rotation)336 GLuint TextureResize::update(GLuint texture, int width, int height, int rotation) {
337 if (mGenericResizer.get() == nullptr) {
338 mGenericResizer.reset(new TextureResize::GenericResizer());
339 }
340 return mGenericResizer->draw(texture, width, height, rotation);
341 }
342
setupFramebuffers(unsigned int factor)343 void TextureResize::setupFramebuffers(unsigned int factor) {
344 if (factor == mFactor) {
345 // The factor hasn't changed, no need to update the framebuffers.
346 return;
347 }
348
349 // Update the framebuffer sizes to match the new factor.
350 s_gles2.glBindTexture(GL_TEXTURE_2D, mFBWidth.texture);
351 s_gles2.glTexImage2D(
352 GL_TEXTURE_2D, 0, GL_RGB, mWidth / factor, mHeight, 0, GL_RGB,
353 mTextureDataType, nullptr);
354 s_gles2.glBindTexture(GL_TEXTURE_2D, 0);
355
356 s_gles2.glBindTexture(GL_TEXTURE_2D, mFBHeight.texture);
357 s_gles2.glTexImage2D(
358 GL_TEXTURE_2D, 0, GL_RGB, mWidth / factor, mHeight / factor, 0, GL_RGB,
359 mTextureDataType, nullptr);
360 s_gles2.glBindTexture(GL_TEXTURE_2D, 0);
361
362 // Update the shaders to the new factor.
363 std::ostringstream factorDefine;
364 factorDefine << "#define FACTOR " << factor << '\n';
365 const std::string factorDefineStr = factorDefine.str();
366 attachShaders(&mFBWidth, factorDefineStr.c_str(), "#define HORIZONTAL\n", mWidth, mHeight);
367 attachShaders(&mFBHeight, factorDefineStr.c_str(), "#define VERTICAL\n", mWidth, mHeight);
368
369 mFactor = factor;
370
371 s_gles2.glBindTexture(GL_TEXTURE_2D, 0);
372 }
373
resize(GLuint texture)374 void TextureResize::resize(GLuint texture) {
375 s_gles2.glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
376 s_gles2.glActiveTexture(GL_TEXTURE0);
377
378 // First scale the horizontal dimension by rendering the input texture to a scaled framebuffer.
379 s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, mFBWidth.framebuffer);
380 s_gles2.glFramebufferTexture2D(
381 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mFBWidth.texture, 0);
382 s_gles2.glClear(GL_COLOR_BUFFER_BIT);
383 s_gles2.glViewport(0, 0, mWidth / mFactor, mHeight);
384 s_gles2.glUseProgram(mFBWidth.program);
385 s_gles2.glEnableVertexAttribArray(mFBWidth.aPosition);
386 s_gles2.glVertexAttribPointer(mFBWidth.aPosition, 2, GL_FLOAT, GL_FALSE, 0, 0);
387 s_gles2.glBindTexture(GL_TEXTURE_2D, texture);
388
389 // Store the current texture filters and set to nearest for scaling.
390 GLint mag_filter, min_filter;
391 s_gles2.glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, &mag_filter);
392 s_gles2.glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, &min_filter);
393 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
394 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
395 s_gles2.glUniform1i(mFBWidth.uTexture, 0);
396 s_gles2.glDrawArrays(GL_TRIANGLES, 0, sizeof(kVertexData) / (2 * sizeof(float)));
397
398 // Restore the previous texture filters.
399 s_gles2.glDisableVertexAttribArray(mFBWidth.aPosition);
400 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
401 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
402 s_gles2.glFramebufferTexture2D(
403 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
404 // Secondly, scale the vertical dimension using the second framebuffer.
405 s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, mFBHeight.framebuffer);
406 s_gles2.glFramebufferTexture2D(
407 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mFBHeight.texture, 0);
408 s_gles2.glClear(GL_COLOR_BUFFER_BIT);
409 s_gles2.glViewport(0, 0, mWidth / mFactor, mHeight / mFactor);
410 s_gles2.glUseProgram(mFBHeight.program);
411 s_gles2.glEnableVertexAttribArray(mFBHeight.aPosition);
412 s_gles2.glVertexAttribPointer(mFBHeight.aPosition, 2, GL_FLOAT, GL_FALSE, 0, 0);
413 s_gles2.glBindTexture(GL_TEXTURE_2D, mFBWidth.texture);
414 s_gles2.glUniform1i(mFBHeight.uTexture, 0);
415 s_gles2.glDrawArrays(GL_TRIANGLES, 0, sizeof(kVertexData) / (2 * sizeof(float)));
416 s_gles2.glFramebufferTexture2D(
417 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
418 // Clear the bindings. (Viewport restored outside)
419 s_gles2.glBindBuffer(GL_ARRAY_BUFFER, 0);
420 s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, 0);
421 s_gles2.glBindTexture(GL_TEXTURE_2D, 0);
422 s_gles2.glDisableVertexAttribArray(mFBHeight.aPosition);
423 s_gles2.glUseProgram(0);
424 android::base::AutoLock lock(s_programLock);
425 while (s_programsToRelease.size()) {
426 s_gles2.glDeleteProgram(s_programsToRelease.back());
427 s_programsToRelease.pop_back();
428 }
429 }
430
431 struct Vertex {
432 float pos[2];
433 float coord[2];
434 };
435
GenericResizer()436 TextureResize::GenericResizer::GenericResizer() :
437 mProgram(0),
438 mVertexBuffer(0),
439 mIndexBuffer(0),
440 mWidth(0),
441 mHeight(0) {
442 GLuint vertex_shader =
443 createShader(GL_VERTEX_SHADER, {kGenericVertexShaderSource});
444 GLuint fragment_shader =
445 createShader(GL_FRAGMENT_SHADER, {kGenericFragmentShaderSource});
446
447 mProgram = s_gles2.glCreateProgram();
448 s_gles2.glAttachShader(mProgram, vertex_shader);
449 s_gles2.glAttachShader(mProgram, fragment_shader);
450 s_gles2.glLinkProgram(mProgram);
451
452 // Shader objects no longer needed.
453 s_gles2.glDeleteShader(vertex_shader);
454 s_gles2.glDeleteShader(fragment_shader);
455
456 // Check for errors.
457 GLint success;
458 s_gles2.glGetProgramiv(mProgram, GL_LINK_STATUS, &success);
459 if (success == GL_FALSE) {
460 GLchar infolog[256];
461 s_gles2.glGetProgramInfoLog(mProgram, sizeof(infolog), 0, infolog);
462 fprintf(stderr, "Could not create/link program: %s\n", infolog);
463 return;
464 }
465
466 // Get all the attributes and uniforms.
467 mPositionAttribLocation =
468 s_gles2.glGetAttribLocation(mProgram, "position");
469 mInCoordAttribLocation =
470 s_gles2.glGetAttribLocation(mProgram, "inCoord");
471 mInputUniformLocation =
472 s_gles2.glGetUniformLocation(mProgram, "texSampler");
473
474 // Create vertex buffers.
475 static const Vertex kVertices[] = {
476 // 0 degree
477 {{ +1, -1 }, { +1, +0 }},
478 {{ +1, +1 }, { +1, +1 }},
479 {{ -1, +1 }, { +0, +1 }},
480 {{ -1, -1 }, { +0, +0 }},
481 // 90 degree clock-wise
482 {{ +1, -1 }, { +0, +0 }},
483 {{ +1, +1 }, { +1, +0 }},
484 {{ -1, +1 }, { +1, +1 }},
485 {{ -1, -1 }, { +0, +1 }},
486 // 180 degree clock-wise
487 {{ +1, -1 }, { +0, +1 }},
488 {{ +1, +1 }, { +0, +0 }},
489 {{ -1, +1 }, { +1, +0 }},
490 {{ -1, -1 }, { +1, +1 }},
491 // 270 degree clock-wise
492 {{ +1, -1 }, { +1, +1 }},
493 {{ +1, +1 }, { +0, +1 }},
494 {{ -1, +1 }, { +0, +0 }},
495 {{ -1, -1 }, { +1, +0 }},
496 };
497 s_gles2.glGenBuffers(1, &mVertexBuffer);
498 s_gles2.glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
499 s_gles2.glBufferData(GL_ARRAY_BUFFER,
500 sizeof(kVertices),
501 kVertices,
502 GL_STATIC_DRAW);
503
504 // indices for predefined rotation angles.
505 static const GLubyte kIndices[] = {
506 0, 1, 2, 2, 3, 0, // 0
507 4, 5, 6, 6, 7, 4, // 90
508 8, 9, 10, 10, 11, 8, // 180
509 12, 13, 14, 14, 15, 12, // 270
510 };
511 s_gles2.glGenBuffers(1, &mIndexBuffer);
512 s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
513 s_gles2.glBufferData(GL_ELEMENT_ARRAY_BUFFER,
514 sizeof(kIndices),
515 kIndices,
516 GL_STATIC_DRAW);
517
518 s_gles2.glGenTextures(1, &mFrameBuffer.texture);
519 s_gles2.glBindTexture(GL_TEXTURE_2D, mFrameBuffer.texture);
520 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
521 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
522 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
523 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
524
525 s_gles2.glGenFramebuffers(1, &mFrameBuffer.framebuffer);
526
527 // Clear bindings.
528 s_gles2.glBindTexture(GL_TEXTURE_2D, 0);
529 s_gles2.glBindBuffer(GL_ARRAY_BUFFER, 0);
530 s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
531 }
532
draw(GLuint texture,int width,int height,int rotation)533 GLuint TextureResize::GenericResizer::draw(GLuint texture, int width, int height,
534 int rotation) {
535 if (mWidth != width || mHeight != height) {
536 // update the framebuffer to match the new resolution
537 mWidth = width;
538 mHeight = height;
539 s_gles2.glBindTexture(GL_TEXTURE_2D, mFrameBuffer.texture);
540 s_gles2.glTexImage2D(
541 GL_TEXTURE_2D, 0, GL_RGB, mWidth, mHeight, 0, GL_RGB,
542 GL_UNSIGNED_BYTE, nullptr);
543 s_gles2.glBindTexture(GL_TEXTURE_2D, 0);
544
545 }
546
547 // Store the viewport.
548 GLint vport[4] = { 0, };
549 s_gles2.glGetIntegerv(GL_VIEWPORT, vport);
550
551 s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, mFrameBuffer.framebuffer);
552 s_gles2.glFramebufferTexture2D(
553 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mFrameBuffer.texture, 0);
554 s_gles2.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
555 s_gles2.glViewport(0, 0, mWidth, mHeight);
556 s_gles2.glUseProgram(mProgram);
557 s_gles2.glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
558 s_gles2.glEnableVertexAttribArray(mPositionAttribLocation);
559 s_gles2.glVertexAttribPointer(mPositionAttribLocation,
560 2, // components per attrib
561 GL_FLOAT,
562 GL_FALSE,
563 sizeof(Vertex), // stride
564 0); // offset
565 s_gles2.glEnableVertexAttribArray(mInCoordAttribLocation);
566 s_gles2.glVertexAttribPointer(mInCoordAttribLocation,
567 2,
568 GL_FLOAT,
569 GL_FALSE,
570 sizeof(Vertex),
571 reinterpret_cast<GLvoid*>(sizeof(float) * 2));
572 s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
573 s_gles2.glActiveTexture(GL_TEXTURE0);
574 s_gles2.glBindTexture(GL_TEXTURE_2D, texture);
575 s_gles2.glUniform1i(mInputUniformLocation, 0);
576 intptr_t indexShift;
577 switch(rotation) {
578 case SKIN_ROTATION_0:
579 indexShift = 0;
580 break;
581 case SKIN_ROTATION_90:
582 indexShift = 6;
583 break;
584 case SKIN_ROTATION_180:
585 indexShift = 12;
586 break;
587 case SKIN_ROTATION_270:
588 indexShift = 18;
589 break;
590 default:
591 indexShift = 0;
592 }
593 s_gles2.glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, (const GLvoid*)indexShift);
594
595 // Clear the bindings.
596 s_gles2.glBindBuffer(GL_ARRAY_BUFFER, 0);
597 s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
598 s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, 0);
599 s_gles2.glBindTexture(GL_TEXTURE_2D, 0);
600 s_gles2.glDisableVertexAttribArray(mPositionAttribLocation);
601 s_gles2.glDisableVertexAttribArray(mInCoordAttribLocation);
602
603 // Restore the viewport.
604 s_gles2.glViewport(vport[0], vport[1], vport[2], vport[3]);
605
606 return mFrameBuffer.texture;
607 }
608
~GenericResizer()609 TextureResize::GenericResizer::~GenericResizer() {
610 s_gles2.glDeleteFramebuffers(1, &mFrameBuffer.framebuffer);
611 s_gles2.glDeleteTextures(1, &mFrameBuffer.texture);
612 s_gles2.glUseProgram(0);
613 s_gles2.glDeleteProgram(mProgram);
614 s_gles2.glBindBuffer(GL_ARRAY_BUFFER, 0);
615 s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
616 s_gles2.glDeleteBuffers(1, &mVertexBuffer);
617 s_gles2.glDeleteBuffers(1, &mIndexBuffer);
618 }
619
620 } // namespace gl
621 } // namespace gfxstream
622