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
22 #include <sstream>
23 #include <string>
24 #include <utility>
25
26 #include "DispatchTables.h"
27 #include "FrameBuffer.h"
28 #include "GLES2/gl2ext.h"
29 #include "host-common/logging.h"
30 #include "host-common/misc.h"
31
32 // #define V(...) VERBOSE_PRINT(gles,__VA_ARGS__)
33 #define V(...)
34 #define MAX_FACTOR_POWER 4
35
36 static const char kCommonShaderSource[] =
37 "precision mediump float;\n"
38 "varying vec2 vUV00, vUV01;\n"
39 "#if FACTOR > 2\n"
40 "varying vec2 vUV02, vUV03;\n"
41 "#if FACTOR > 4\n"
42 "varying vec2 vUV04, vUV05, vUV06, vUV07;\n"
43 "#if FACTOR > 8\n"
44 "varying vec2 vUV08, vUV09, vUV10, vUV11, vUV12, vUV13, vUV14, vUV15;\n"
45 "#endif\n"
46 "#endif\n"
47 "#endif\n";
48
49 static const char kVertexShaderSource[] =
50 "attribute vec2 aPosition;\n"
51
52 "void main() {\n"
53 " gl_Position = vec4(aPosition, 0, 1);\n"
54 " vec2 uv = ((aPosition + 1.0) / 2.0) + 0.5 / kDimension;\n"
55 " vUV00 = uv;\n"
56 " #ifdef HORIZONTAL\n"
57 " vUV01 = uv + vec2( 1.0 / kDimension.x, 0);\n"
58 " #if FACTOR > 2\n"
59 " vUV02 = uv + vec2( 2.0 / kDimension.x, 0);\n"
60 " vUV03 = uv + vec2( 3.0 / kDimension.x, 0);\n"
61 " #if FACTOR > 4\n"
62 " vUV04 = uv + vec2( 4.0 / kDimension.x, 0);\n"
63 " vUV05 = uv + vec2( 5.0 / kDimension.x, 0);\n"
64 " vUV06 = uv + vec2( 6.0 / kDimension.x, 0);\n"
65 " vUV07 = uv + vec2( 7.0 / kDimension.x, 0);\n"
66 " #if FACTOR > 8\n"
67 " vUV08 = uv + vec2( 8.0 / kDimension.x, 0);\n"
68 " vUV09 = uv + vec2( 9.0 / kDimension.x, 0);\n"
69 " vUV10 = uv + vec2(10.0 / kDimension.x, 0);\n"
70 " vUV11 = uv + vec2(11.0 / kDimension.x, 0);\n"
71 " vUV12 = uv + vec2(12.0 / kDimension.x, 0);\n"
72 " vUV13 = uv + vec2(13.0 / kDimension.x, 0);\n"
73 " vUV14 = uv + vec2(14.0 / kDimension.x, 0);\n"
74 " vUV15 = uv + vec2(15.0 / kDimension.x, 0);\n"
75 " #endif\n" // FACTOR > 8
76 " #endif\n" // FACTOR > 4
77 " #endif\n" // FACTOR > 2
78
79 " #else\n"
80 " vUV01 = uv + vec2(0, 1.0 / kDimension.y);\n"
81 " #if FACTOR > 2\n"
82 " vUV02 = uv + vec2(0, 2.0 / kDimension.y);\n"
83 " vUV03 = uv + vec2(0, 3.0 / kDimension.y);\n"
84 " #if FACTOR > 4\n"
85 " vUV04 = uv + vec2(0, 4.0 / kDimension.y);\n"
86 " vUV05 = uv + vec2(0, 5.0 / kDimension.y);\n"
87 " vUV06 = uv + vec2(0, 6.0 / kDimension.y);\n"
88 " vUV07 = uv + vec2(0, 7.0 / kDimension.y);\n"
89 " #if FACTOR > 8\n"
90 " vUV08 = uv + vec2(0, 8.0 / kDimension.y);\n"
91 " vUV09 = uv + vec2(0, 9.0 / kDimension.y);\n"
92 " vUV10 = uv + vec2(0, 10.0 / kDimension.y);\n"
93 " vUV11 = uv + vec2(0, 11.0 / kDimension.y);\n"
94 " vUV12 = uv + vec2(0, 12.0 / kDimension.y);\n"
95 " vUV13 = uv + vec2(0, 13.0 / kDimension.y);\n"
96 " vUV14 = uv + vec2(0, 14.0 / kDimension.y);\n"
97 " vUV15 = uv + vec2(0, 15.0 / kDimension.y);\n"
98 " #endif\n" // FACTOR > 8
99 " #endif\n" // FACTOR > 4
100 " #endif\n" // FACTOR > 2
101 " #endif\n" // HORIZONTAL/VERTICAL
102 "}\n";
103
104 const char kFragmentShaderSource[] =
105 "uniform sampler2D uTexture;\n"
106
107 "vec3 read(vec2 uv) {\n"
108 " vec3 r = texture2D(uTexture, uv).rgb;\n"
109 " #ifdef HORIZONTAL\n"
110 " r.rgb = pow(r.rgb, vec3(2.2));\n"
111 " #endif\n"
112 " return r;\n"
113 "}\n"
114
115 "void main() {\n"
116 " vec3 sum = read(vUV00) + read(vUV01);\n"
117 " #if FACTOR > 2\n"
118 " sum += read(vUV02) + read(vUV03);\n"
119 " #if FACTOR > 4\n"
120 " sum += read(vUV04) + read(vUV05) + read(vUV06) + read(vUV07);\n"
121 " #if FACTOR > 8\n"
122 " sum += read(vUV08) + read(vUV09) + read(vUV10) + read(vUV11) +"
123 " read(vUV12) + read(vUV13) + read(vUV14) + read(vUV15);\n"
124 " #endif\n"
125 " #endif\n"
126 " #endif\n"
127 " sum /= float(FACTOR);\n"
128 " #ifdef VERTICAL\n"
129 " sum.rgb = pow(sum.rgb, vec3(1.0 / 2.2));\n"
130 " #endif\n"
131 " gl_FragColor = vec4(sum.rgb, 1.0);\n"
132 "}\n";
133
134 // Vertex shader for anti-aliasing - doesn't do anything special.
135 const char kGenericVertexShaderSource[] = R"(
136 attribute vec2 position;
137 attribute vec2 inCoord;
138 varying vec2 outCoord;
139 void main(void) {
140 gl_Position = vec4(position.x, position.y, 0.0, 1.0);
141 outCoord = inCoord;
142 })";
143
144 // Fragment shader
145 const char kGenericFragmentShaderSource[] = R"(
146 precision mediump float;
147 uniform sampler2D texSampler;
148 varying vec2 outCoord;
149 void main(void) {
150 gl_FragColor = texture2D(texSampler, outCoord);
151 }
152 )";
153
154 static const float kVertexData[] = {-1, -1, 3, -1, -1, 3};
155
detachShaders(GLuint program)156 static void detachShaders(GLuint program) {
157 GLuint shaders[2] = {};
158 GLsizei count = 0;
159 s_gles2.glGetAttachedShaders(program, 2, &count, shaders);
160 if (s_gles2.glGetError() == GL_NO_ERROR) {
161 for (GLsizei i = 0; i < count; i++) {
162 s_gles2.glDetachShader(program, shaders[i]);
163 s_gles2.glDeleteShader(shaders[i]);
164 }
165 }
166 }
167
createShader(GLenum type,std::initializer_list<const char * > source)168 static GLuint createShader(GLenum type, std::initializer_list<const char*> source) {
169 GLint success, infoLength;
170
171 GLuint shader = s_gles2.glCreateShader(type);
172 if (shader) {
173 s_gles2.glShaderSource(shader, source.size(), source.begin(), nullptr);
174 s_gles2.glCompileShader(shader);
175 s_gles2.glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
176 if (success == GL_FALSE) {
177 s_gles2.glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLength);
178 std::string infoLog(infoLength + 1, '\0');
179 s_gles2.glGetShaderInfoLog(shader, infoLength, nullptr, &infoLog[0]);
180 ERR("%s shader compile failed:\n%s\n",
181 (type == GL_VERTEX_SHADER) ? "Vertex" : "Fragment",
182 infoLog.c_str());
183 s_gles2.glDeleteShader(shader);
184 shader = 0;
185 }
186 }
187 return shader;
188 }
189
attachShaders(TextureResize::Framebuffer * fb,const char * factorDefine,const char * dimensionDefine,GLuint width,GLuint height)190 static void attachShaders(TextureResize::Framebuffer* fb, const char* factorDefine,
191 const char* dimensionDefine, GLuint width, GLuint height) {
192
193 std::ostringstream dimensionConst;
194 dimensionConst << "const vec2 kDimension = vec2(" << width << ", " << height << ");\n";
195
196 GLuint vShader = createShader(GL_VERTEX_SHADER, {
197 factorDefine, dimensionDefine,
198 kCommonShaderSource, dimensionConst.str().c_str(), kVertexShaderSource
199 });
200 GLuint fShader = createShader(GL_FRAGMENT_SHADER, {
201 factorDefine, dimensionDefine, kCommonShaderSource, kFragmentShaderSource
202 });
203
204 if (!vShader || !fShader) {
205 return;
206 }
207
208 s_gles2.glAttachShader(fb->program, vShader);
209 s_gles2.glAttachShader(fb->program, fShader);
210 s_gles2.glLinkProgram(fb->program);
211
212 s_gles2.glUseProgram(fb->program);
213 fb->aPosition = s_gles2.glGetAttribLocation(fb->program, "aPosition");
214 fb->uTexture = s_gles2.glGetUniformLocation(fb->program, "uTexture");
215 }
216
TextureResize(GLuint width,GLuint height)217 TextureResize::TextureResize(GLuint width, GLuint height) :
218 mWidth(width),
219 mHeight(height),
220 mFactor(1),
221 mFBWidth({0,}),
222 mFBHeight({0,}),
223 // Use unsigned byte as the default since it has the most support
224 // and is the input/output format in the end
225 // (TODO) until HDR is common on both guest and host, and we'll
226 // cross that bridge when we get there.
227 mTextureDataType(GL_UNSIGNED_BYTE) {
228
229 // Fix color banding by trying to use a texture type with a high precision.
230 const char* exts = (const char*)s_gles2.glGetString(GL_EXTENSIONS);
231
232 bool hasColorBufferFloat =
233 emugl::getRenderer() == SELECTED_RENDERER_HOST ||
234 emugl::hasExtension(exts, "GL_EXT_color_buffer_float");
235 bool hasColorBufferHalfFloat =
236 emugl::hasExtension(exts, "GL_EXT_color_buffer_half_float");
237 bool hasTextureFloat =
238 emugl::hasExtension(exts, "GL_OES_texture_float");
239 bool hasTextureHalfFloat =
240 emugl::hasExtension(exts, "GL_OES_texture_half_float");
241 bool hasTextureFloatLinear =
242 emugl::hasExtension(exts, "GL_OES_texture_float_linear");
243
244 if (hasColorBufferFloat && hasTextureFloat) {
245 mTextureDataType = GL_FLOAT;
246 } else if (hasColorBufferHalfFloat && hasTextureHalfFloat) {
247 mTextureDataType = GL_HALF_FLOAT_OES;
248 }
249
250 if (hasTextureFloat || hasTextureHalfFloat) {
251 mTextureFilteringMode =
252 hasTextureFloatLinear ? GL_LINEAR : GL_NEAREST;
253 }
254
255 s_gles2.glGenTextures(1, &mFBWidth.texture);
256 s_gles2.glBindTexture(GL_TEXTURE_2D, mFBWidth.texture);
257 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
258 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
259 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
260 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
261
262 s_gles2.glGenTextures(1, &mFBHeight.texture);
263 s_gles2.glBindTexture(GL_TEXTURE_2D, mFBHeight.texture);
264 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mTextureFilteringMode);
265 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mTextureFilteringMode);
266 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
267 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
268
269 s_gles2.glGenFramebuffers(1, &mFBWidth.framebuffer);
270 s_gles2.glGenFramebuffers(1, &mFBHeight.framebuffer);
271
272 mFBWidth.program = s_gles2.glCreateProgram();
273 mFBHeight.program = s_gles2.glCreateProgram();
274
275 s_gles2.glGenBuffers(1, &mVertexBuffer);
276 s_gles2.glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
277 s_gles2.glBufferData(GL_ARRAY_BUFFER, sizeof(kVertexData), kVertexData, GL_STATIC_DRAW);
278
279 // Clear bindings.
280 s_gles2.glBindTexture(GL_TEXTURE_2D, 0);
281 s_gles2.glBindBuffer(GL_ARRAY_BUFFER, 0);
282 }
283
~TextureResize()284 TextureResize::~TextureResize() {
285 GLuint fb[2] = {mFBWidth.framebuffer, mFBHeight.framebuffer};
286 s_gles2.glDeleteFramebuffers(2, fb);
287
288 GLuint tex[2] = {mFBWidth.texture, mFBHeight.texture};
289 s_gles2.glDeleteTextures(2, tex);
290
291 detachShaders(mFBWidth.program);
292 detachShaders(mFBHeight.program);
293
294 s_gles2.glDeleteProgram(mFBWidth.program);
295 s_gles2.glDeleteProgram(mFBHeight.program);
296
297 s_gles2.glDeleteBuffers(1, &mVertexBuffer);
298 }
299
update(GLuint texture)300 GLuint TextureResize::update(GLuint texture) {
301 // Store the viewport. The viewport is clobbered due to the framebuffers.
302 GLint vport[4] = { 0, };
303 s_gles2.glGetIntegerv(GL_VIEWPORT, vport);
304
305 // Correctly deal with rotated screens.
306 GLint tWidth = vport[2], tHeight = vport[3];
307 if ((mWidth < mHeight) != (tWidth < tHeight)) {
308 std::swap(tWidth, tHeight);
309 }
310
311 // Compute the scaling factor needed to get an image just larger than the target viewport.
312 unsigned int factor = 1;
313 for (int i = 0, w = mWidth / 2, h = mHeight / 2;
314 i < MAX_FACTOR_POWER && w >= tWidth && h >= tHeight;
315 i++, w /= 2, h /= 2, factor *= 2) {
316 }
317
318 // No resizing needed if factor == 1
319 if (factor == 1) {
320 return texture;
321 }
322
323 s_gles2.glGetError(); // Clear any GL errors.
324 setupFramebuffers(factor);
325 resize(texture);
326 s_gles2.glViewport(vport[0], vport[1], vport[2], vport[3]); // Restore the viewport.
327
328 // If there was an error while resizing, just use the unscaled texture.
329 GLenum error = s_gles2.glGetError();
330 if (error != GL_NO_ERROR) {
331 V("GL error while resizing: 0x%x (ignored)\n", error);
332 return texture;
333 }
334
335 return mFBHeight.texture;
336 }
337
update(GLuint texture,int width,int height,int rotation)338 GLuint TextureResize::update(GLuint texture, int width, int height, int rotation) {
339 if (mGenericResizer.get() == nullptr) {
340 mGenericResizer.reset(new TextureResize::GenericResizer());
341 }
342 return mGenericResizer->draw(texture, width, height, rotation);
343 }
344
setupFramebuffers(unsigned int factor)345 void TextureResize::setupFramebuffers(unsigned int factor) {
346 if (factor == mFactor) {
347 // The factor hasn't changed, no need to update the framebuffers.
348 return;
349 }
350
351 // Update the framebuffer sizes to match the new factor.
352 s_gles2.glBindTexture(GL_TEXTURE_2D, mFBWidth.texture);
353 s_gles2.glTexImage2D(
354 GL_TEXTURE_2D, 0, GL_RGB, mWidth / factor, mHeight, 0, GL_RGB,
355 mTextureDataType, nullptr);
356 s_gles2.glBindTexture(GL_TEXTURE_2D, 0);
357
358 s_gles2.glBindTexture(GL_TEXTURE_2D, mFBHeight.texture);
359 s_gles2.glTexImage2D(
360 GL_TEXTURE_2D, 0, GL_RGB, mWidth / factor, mHeight / factor, 0, GL_RGB,
361 mTextureDataType, nullptr);
362 s_gles2.glBindTexture(GL_TEXTURE_2D, 0);
363
364 // Update the shaders to the new factor. First detach the old shaders...
365 detachShaders(mFBWidth.program);
366 detachShaders(mFBHeight.program);
367
368 // ... then attach the new ones.
369 std::ostringstream factorDefine;
370 factorDefine << "#define FACTOR " << factor << '\n';
371 const std::string factorDefineStr = factorDefine.str();
372 attachShaders(&mFBWidth, factorDefineStr.c_str(), "#define HORIZONTAL\n", mWidth, mHeight);
373 attachShaders(&mFBHeight, factorDefineStr.c_str(), "#define VERTICAL\n", mWidth, mHeight);
374
375 mFactor = factor;
376
377 s_gles2.glBindTexture(GL_TEXTURE_2D, 0);
378 }
379
resize(GLuint texture)380 void TextureResize::resize(GLuint texture) {
381 s_gles2.glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
382 s_gles2.glActiveTexture(GL_TEXTURE0);
383
384 // First scale the horizontal dimension by rendering the input texture to a scaled framebuffer.
385 s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, mFBWidth.framebuffer);
386 s_gles2.glFramebufferTexture2D(
387 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mFBWidth.texture, 0);
388 s_gles2.glClear(GL_COLOR_BUFFER_BIT);
389 s_gles2.glViewport(0, 0, mWidth / mFactor, mHeight);
390 s_gles2.glUseProgram(mFBWidth.program);
391 s_gles2.glEnableVertexAttribArray(mFBWidth.aPosition);
392 s_gles2.glVertexAttribPointer(mFBWidth.aPosition, 2, GL_FLOAT, GL_FALSE, 0, 0);
393 s_gles2.glBindTexture(GL_TEXTURE_2D, texture);
394
395 // Store the current texture filters and set to nearest for scaling.
396 GLint mag_filter, min_filter;
397 s_gles2.glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, &mag_filter);
398 s_gles2.glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, &min_filter);
399 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
400 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
401 s_gles2.glUniform1i(mFBWidth.uTexture, 0);
402 s_gles2.glDrawArrays(GL_TRIANGLES, 0, sizeof(kVertexData) / (2 * sizeof(float)));
403
404 // Restore the previous texture filters.
405 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
406 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
407 s_gles2.glFramebufferTexture2D(
408 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
409 // Secondly, scale the vertical dimension using the second framebuffer.
410 s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, mFBHeight.framebuffer);
411 s_gles2.glFramebufferTexture2D(
412 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mFBHeight.texture, 0);
413 s_gles2.glClear(GL_COLOR_BUFFER_BIT);
414 s_gles2.glViewport(0, 0, mWidth / mFactor, mHeight / mFactor);
415 s_gles2.glUseProgram(mFBHeight.program);
416 s_gles2.glEnableVertexAttribArray(mFBHeight.aPosition);
417 s_gles2.glVertexAttribPointer(mFBHeight.aPosition, 2, GL_FLOAT, GL_FALSE, 0, 0);
418 s_gles2.glBindTexture(GL_TEXTURE_2D, mFBWidth.texture);
419 s_gles2.glUniform1i(mFBHeight.uTexture, 0);
420 s_gles2.glDrawArrays(GL_TRIANGLES, 0, sizeof(kVertexData) / (2 * sizeof(float)));
421 s_gles2.glFramebufferTexture2D(
422 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
423 // Clear the bindings. (Viewport restored outside)
424 s_gles2.glBindBuffer(GL_ARRAY_BUFFER, 0);
425 s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, 0);
426 s_gles2.glBindTexture(GL_TEXTURE_2D, 0);
427 s_gles2.glDisableVertexAttribArray(mFBWidth.aPosition);
428 s_gles2.glDisableVertexAttribArray(mFBHeight.aPosition);
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 }
591 s_gles2.glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, (const GLvoid*)indexShift);
592
593 // Clear the bindings.
594 s_gles2.glBindBuffer(GL_ARRAY_BUFFER, 0);
595 s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
596 s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, 0);
597 s_gles2.glBindTexture(GL_TEXTURE_2D, 0);
598 s_gles2.glDisableVertexAttribArray(mPositionAttribLocation);
599 s_gles2.glDisableVertexAttribArray(mInCoordAttribLocation);
600
601 // Restore the viewport.
602 s_gles2.glViewport(vport[0], vport[1], vport[2], vport[3]);
603
604 return mFrameBuffer.texture;
605 }
606
~GenericResizer()607 TextureResize::GenericResizer::~GenericResizer() {
608 s_gles2.glDeleteFramebuffers(1, &mFrameBuffer.framebuffer);
609 s_gles2.glDeleteTextures(1, &mFrameBuffer.texture);
610 detachShaders(mProgram);
611 s_gles2.glUseProgram(0);
612 s_gles2.glDeleteProgram(mProgram);
613 s_gles2.glBindBuffer(GL_ARRAY_BUFFER, 0);
614 s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
615 s_gles2.glDeleteBuffers(1, &mVertexBuffer);
616 s_gles2.glDeleteBuffers(1, &mIndexBuffer);
617 }
618
619
620