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