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