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_postContextResources;
161 static std::vector<GLuint> s_programsToRelease;
162 static std::vector<GLuint> s_framebuffersToRelease;
163
createShader(GLenum type,std::initializer_list<const char * > source)164 static GLuint createShader(GLenum type, std::initializer_list<const char*> source) {
165 GLint success, infoLength;
166
167 GLuint shader = s_gles2.glCreateShader(type);
168 if (shader) {
169 s_gles2.glShaderSource(shader, source.size(), source.begin(), nullptr);
170 s_gles2.glCompileShader(shader);
171 s_gles2.glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
172 if (success == GL_FALSE) {
173 s_gles2.glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLength);
174 std::string infoLog(infoLength + 1, '\0');
175 s_gles2.glGetShaderInfoLog(shader, infoLength, nullptr, &infoLog[0]);
176 ERR("%s shader compile failed:\n%s\n",
177 (type == GL_VERTEX_SHADER) ? "Vertex" : "Fragment",
178 infoLog.c_str());
179 s_gles2.glDeleteShader(shader);
180 shader = 0;
181 }
182 }
183 return shader;
184 }
185
attachShaders(TextureResize::Framebuffer * fb,const char * factorDefine,const char * dimensionDefine,GLuint width,GLuint height)186 static void attachShaders(TextureResize::Framebuffer* fb, const char* factorDefine,
187 const char* dimensionDefine, GLuint width, GLuint height) {
188
189 std::ostringstream dimensionConst;
190 dimensionConst << "const vec2 kDimension = vec2(" << width << ", " << height << ");\n";
191
192 GLuint vShader = createShader(GL_VERTEX_SHADER, {
193 factorDefine, dimensionDefine,
194 kCommonShaderSource, dimensionConst.str().c_str(), kVertexShaderSource
195 });
196 GLuint fShader = createShader(GL_FRAGMENT_SHADER, {
197 factorDefine, dimensionDefine, kCommonShaderSource, kFragmentShaderSource
198 });
199
200 if (!vShader || !fShader) {
201 return;
202 }
203 if (!fb->program) {
204 fb->program = s_gles2.glCreateProgram();
205 }
206 s_gles2.glAttachShader(fb->program, vShader);
207 s_gles2.glAttachShader(fb->program, fShader);
208 s_gles2.glLinkProgram(fb->program);
209 s_gles2.glDeleteShader(vShader);
210 s_gles2.glDeleteShader(fShader);
211
212 fb->aPosition = s_gles2.glGetAttribLocation(fb->program, "aPosition");
213 fb->uTexture = s_gles2.glGetUniformLocation(fb->program, "uTexture");
214 }
215
TextureResize(GLuint width,GLuint height)216 TextureResize::TextureResize(GLuint width, GLuint height) :
217 mWidth(width),
218 mHeight(height),
219 mFactor(1),
220 mFBWidth({0,}),
221 mFBHeight({0,}),
222 // Use unsigned byte as the default since it has the most support
223 // and is the input/output format in the end
224 // (TODO) until HDR is common on both guest and host, and we'll
225 // cross that bridge when we get there.
226 mTextureDataType(GL_UNSIGNED_BYTE) {
227
228 // Fix color banding by trying to use a texture type with a high precision.
229 const char* exts = (const char*)s_gles2.glGetString(GL_EXTENSIONS);
230
231 bool hasColorBufferFloat =
232 emugl::getRenderer() == SELECTED_RENDERER_HOST ||
233 emugl::hasExtension(exts, "GL_EXT_color_buffer_float");
234 bool hasColorBufferHalfFloat =
235 emugl::hasExtension(exts, "GL_EXT_color_buffer_half_float");
236 bool hasTextureFloat =
237 emugl::hasExtension(exts, "GL_OES_texture_float");
238 bool hasTextureHalfFloat =
239 emugl::hasExtension(exts, "GL_OES_texture_half_float");
240 bool hasTextureFloatLinear =
241 emugl::hasExtension(exts, "GL_OES_texture_float_linear");
242
243 if (hasColorBufferFloat && hasTextureFloat) {
244 mTextureDataType = GL_FLOAT;
245 } else if (hasColorBufferHalfFloat && hasTextureHalfFloat) {
246 mTextureDataType = GL_HALF_FLOAT_OES;
247 }
248
249 if (hasTextureFloat || hasTextureHalfFloat) {
250 mTextureFilteringMode =
251 hasTextureFloatLinear ? GL_LINEAR : GL_NEAREST;
252 }
253
254 s_gles2.glGenTextures(1, &mFBWidth.texture);
255 s_gles2.glBindTexture(GL_TEXTURE_2D, mFBWidth.texture);
256 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
257 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
258 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
259 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
260
261 s_gles2.glGenTextures(1, &mFBHeight.texture);
262 s_gles2.glBindTexture(GL_TEXTURE_2D, mFBHeight.texture);
263 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mTextureFilteringMode);
264 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mTextureFilteringMode);
265 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
266 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
267
268 s_gles2.glGenBuffers(1, &mVertexBuffer);
269 s_gles2.glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
270 s_gles2.glBufferData(GL_ARRAY_BUFFER, sizeof(kVertexData), kVertexData, GL_STATIC_DRAW);
271
272 // Clear bindings.
273 s_gles2.glBindTexture(GL_TEXTURE_2D, 0);
274 s_gles2.glBindBuffer(GL_ARRAY_BUFFER, 0);
275 }
276
~TextureResize()277 TextureResize::~TextureResize() {
278 GLuint tex[2] = {mFBWidth.texture, mFBHeight.texture};
279 s_gles2.glDeleteTextures(2, tex);
280 s_gles2.glDeleteBuffers(1, &mVertexBuffer);
281 // b/242245912
282 // There seems to be a mesa bug that we have to delete the
283 // program in the post thread.
284 android::base::AutoLock lock(s_postContextResources);
285 s_programsToRelease.push_back(mFBWidth.program);
286 s_programsToRelease.push_back(mFBHeight.program);
287 // b/285421327
288 // We should create, use and destroy framebuffers in the same context.
289 // Framebuffer ownership is driver-dependent.
290 s_framebuffersToRelease.push_back(mFBWidth.framebuffer);
291 s_framebuffersToRelease.push_back(mFBHeight.framebuffer);
292 }
293
update(GLuint texture)294 GLuint TextureResize::update(GLuint texture) {
295 // Store the viewport. The viewport is clobbered due to the framebuffers.
296 GLint vport[4] = { 0, };
297 s_gles2.glGetIntegerv(GL_VIEWPORT, vport);
298 GLint prevFbo = 0;
299 s_gles2.glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &prevFbo);
300 // Correctly deal with rotated screens.
301 GLint tWidth = vport[2], tHeight = vport[3];
302 if ((mWidth < mHeight) != (tWidth < tHeight)) {
303 std::swap(tWidth, tHeight);
304 }
305
306 // Compute the scaling factor needed to get an image just larger than the target viewport.
307 unsigned int factor = 1;
308 for (int i = 0, w = mWidth / 2, h = mHeight / 2;
309 i < MAX_FACTOR_POWER && w >= tWidth && h >= tHeight;
310 i++, w /= 2, h /= 2, factor *= 2) {
311 }
312
313 // No resizing needed if factor == 1
314 if (factor == 1) {
315 return texture;
316 }
317
318 s_gles2.glGetError(); // Clear any GL errors.
319 setupFramebuffers(factor);
320 resize(texture);
321 s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, prevFbo);
322 s_gles2.glViewport(vport[0], vport[1], vport[2], vport[3]); // Restore the viewport.
323 // If there was an error while resizing, just use the unscaled texture.
324 GLenum error = s_gles2.glGetError();
325 if (error != GL_NO_ERROR) {
326 V("GL error while resizing: 0x%x (ignored)\n", error);
327 return texture;
328 }
329
330 return mFBHeight.texture;
331 }
332
update(GLuint texture,int width,int height,int rotation)333 GLuint TextureResize::update(GLuint texture, int width, int height, int rotation) {
334 if (mGenericResizer.get() == nullptr) {
335 mGenericResizer.reset(new TextureResize::GenericResizer());
336 }
337 return mGenericResizer->draw(texture, width, height, rotation);
338 }
339
setupFramebuffers(unsigned int factor)340 void TextureResize::setupFramebuffers(unsigned int factor) {
341 if (factor == mFactor) {
342 // The factor hasn't changed, no need to update the framebuffers.
343 return;
344 }
345
346 // Update the framebuffer sizes to match the new factor.
347 s_gles2.glBindTexture(GL_TEXTURE_2D, mFBWidth.texture);
348 s_gles2.glTexImage2D(
349 GL_TEXTURE_2D, 0, GL_RGB, mWidth / factor, mHeight, 0, GL_RGB,
350 mTextureDataType, nullptr);
351 s_gles2.glBindTexture(GL_TEXTURE_2D, 0);
352
353 s_gles2.glBindTexture(GL_TEXTURE_2D, mFBHeight.texture);
354 s_gles2.glTexImage2D(
355 GL_TEXTURE_2D, 0, GL_RGB, mWidth / factor, mHeight / factor, 0, GL_RGB,
356 mTextureDataType, nullptr);
357 s_gles2.glBindTexture(GL_TEXTURE_2D, 0);
358
359 // Update the shaders to the new factor.
360 std::ostringstream factorDefine;
361 factorDefine << "#define FACTOR " << factor << '\n';
362 const std::string factorDefineStr = factorDefine.str();
363 attachShaders(&mFBWidth, factorDefineStr.c_str(), "#define HORIZONTAL\n", mWidth, mHeight);
364 attachShaders(&mFBHeight, factorDefineStr.c_str(), "#define VERTICAL\n", mWidth, mHeight);
365
366 mFactor = factor;
367
368 s_gles2.glBindTexture(GL_TEXTURE_2D, 0);
369 }
370
resize(GLuint texture)371 void TextureResize::resize(GLuint texture) {
372 s_gles2.glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
373 s_gles2.glActiveTexture(GL_TEXTURE0);
374
375 if (!mFBWidth.framebuffer) {
376 s_gles2.glGenFramebuffers(1, &mFBWidth.framebuffer);
377 }
378 if (!mFBHeight.framebuffer) {
379 s_gles2.glGenFramebuffers(1, &mFBHeight.framebuffer);
380 }
381
382 // First scale the horizontal dimension by rendering the input texture to a scaled framebuffer.
383 s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, mFBWidth.framebuffer);
384 s_gles2.glFramebufferTexture2D(
385 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mFBWidth.texture, 0);
386 s_gles2.glClear(GL_COLOR_BUFFER_BIT);
387 s_gles2.glViewport(0, 0, mWidth / mFactor, mHeight);
388 s_gles2.glUseProgram(mFBWidth.program);
389 s_gles2.glEnableVertexAttribArray(mFBWidth.aPosition);
390 s_gles2.glVertexAttribPointer(mFBWidth.aPosition, 2, GL_FLOAT, GL_FALSE, 0, 0);
391 s_gles2.glBindTexture(GL_TEXTURE_2D, texture);
392
393 // Store the current texture filters and set to nearest for scaling.
394 GLint mag_filter, min_filter;
395 s_gles2.glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, &mag_filter);
396 s_gles2.glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, &min_filter);
397 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
398 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
399 s_gles2.glUniform1i(mFBWidth.uTexture, 0);
400 s_gles2.glDrawArrays(GL_TRIANGLES, 0, sizeof(kVertexData) / (2 * sizeof(float)));
401
402 // Restore the previous texture filters.
403 s_gles2.glDisableVertexAttribArray(mFBWidth.aPosition);
404 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
405 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
406 s_gles2.glFramebufferTexture2D(
407 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
408 // Secondly, scale the vertical dimension using the second framebuffer.
409 s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, mFBHeight.framebuffer);
410 s_gles2.glFramebufferTexture2D(
411 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mFBHeight.texture, 0);
412 s_gles2.glClear(GL_COLOR_BUFFER_BIT);
413 s_gles2.glViewport(0, 0, mWidth / mFactor, mHeight / mFactor);
414 s_gles2.glUseProgram(mFBHeight.program);
415 s_gles2.glEnableVertexAttribArray(mFBHeight.aPosition);
416 s_gles2.glVertexAttribPointer(mFBHeight.aPosition, 2, GL_FLOAT, GL_FALSE, 0, 0);
417 s_gles2.glBindTexture(GL_TEXTURE_2D, mFBWidth.texture);
418 s_gles2.glUniform1i(mFBHeight.uTexture, 0);
419 s_gles2.glDrawArrays(GL_TRIANGLES, 0, sizeof(kVertexData) / (2 * sizeof(float)));
420 s_gles2.glFramebufferTexture2D(
421 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
422 // Clear the bindings. (Viewport restored outside)
423 s_gles2.glBindBuffer(GL_ARRAY_BUFFER, 0);
424 s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, 0);
425 s_gles2.glBindTexture(GL_TEXTURE_2D, 0);
426 s_gles2.glDisableVertexAttribArray(mFBHeight.aPosition);
427 s_gles2.glUseProgram(0);
428 android::base::AutoLock lock(s_postContextResources);
429 while (s_programsToRelease.size()) {
430 s_gles2.glDeleteProgram(s_programsToRelease.back());
431 s_programsToRelease.pop_back();
432 }
433 if (s_framebuffersToRelease.size()) {
434 s_gles2.glDeleteFramebuffers(s_framebuffersToRelease.size(),
435 s_framebuffersToRelease.data());
436 s_framebuffersToRelease.clear();
437 }
438 }
439
440 struct Vertex {
441 float pos[2];
442 float coord[2];
443 };
444
GenericResizer()445 TextureResize::GenericResizer::GenericResizer() :
446 mProgram(0),
447 mVertexBuffer(0),
448 mIndexBuffer(0),
449 mWidth(0),
450 mHeight(0) {
451 GLuint vertex_shader =
452 createShader(GL_VERTEX_SHADER, {kGenericVertexShaderSource});
453 GLuint fragment_shader =
454 createShader(GL_FRAGMENT_SHADER, {kGenericFragmentShaderSource});
455
456 mProgram = s_gles2.glCreateProgram();
457 s_gles2.glAttachShader(mProgram, vertex_shader);
458 s_gles2.glAttachShader(mProgram, fragment_shader);
459 s_gles2.glLinkProgram(mProgram);
460
461 // Shader objects no longer needed.
462 s_gles2.glDeleteShader(vertex_shader);
463 s_gles2.glDeleteShader(fragment_shader);
464
465 // Check for errors.
466 GLint success;
467 s_gles2.glGetProgramiv(mProgram, GL_LINK_STATUS, &success);
468 if (success == GL_FALSE) {
469 GLchar infolog[256];
470 s_gles2.glGetProgramInfoLog(mProgram, sizeof(infolog), 0, infolog);
471 fprintf(stderr, "Could not create/link program: %s\n", infolog);
472 return;
473 }
474
475 // Get all the attributes and uniforms.
476 mPositionAttribLocation =
477 s_gles2.glGetAttribLocation(mProgram, "position");
478 mInCoordAttribLocation =
479 s_gles2.glGetAttribLocation(mProgram, "inCoord");
480 mInputUniformLocation =
481 s_gles2.glGetUniformLocation(mProgram, "texSampler");
482
483 // Create vertex buffers.
484 static const Vertex kVertices[] = {
485 // 0 degree
486 {{ +1, -1 }, { +1, +0 }},
487 {{ +1, +1 }, { +1, +1 }},
488 {{ -1, +1 }, { +0, +1 }},
489 {{ -1, -1 }, { +0, +0 }},
490 // 90 degree clock-wise
491 {{ +1, -1 }, { +0, +0 }},
492 {{ +1, +1 }, { +1, +0 }},
493 {{ -1, +1 }, { +1, +1 }},
494 {{ -1, -1 }, { +0, +1 }},
495 // 180 degree clock-wise
496 {{ +1, -1 }, { +0, +1 }},
497 {{ +1, +1 }, { +0, +0 }},
498 {{ -1, +1 }, { +1, +0 }},
499 {{ -1, -1 }, { +1, +1 }},
500 // 270 degree clock-wise
501 {{ +1, -1 }, { +1, +1 }},
502 {{ +1, +1 }, { +0, +1 }},
503 {{ -1, +1 }, { +0, +0 }},
504 {{ -1, -1 }, { +1, +0 }},
505 };
506 s_gles2.glGenBuffers(1, &mVertexBuffer);
507 s_gles2.glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
508 s_gles2.glBufferData(GL_ARRAY_BUFFER,
509 sizeof(kVertices),
510 kVertices,
511 GL_STATIC_DRAW);
512
513 // indices for predefined rotation angles.
514 static const GLubyte kIndices[] = {
515 0, 1, 2, 2, 3, 0, // 0
516 4, 5, 6, 6, 7, 4, // 90
517 8, 9, 10, 10, 11, 8, // 180
518 12, 13, 14, 14, 15, 12, // 270
519 };
520 s_gles2.glGenBuffers(1, &mIndexBuffer);
521 s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
522 s_gles2.glBufferData(GL_ELEMENT_ARRAY_BUFFER,
523 sizeof(kIndices),
524 kIndices,
525 GL_STATIC_DRAW);
526
527 s_gles2.glGenTextures(1, &mFrameBuffer.texture);
528 s_gles2.glBindTexture(GL_TEXTURE_2D, mFrameBuffer.texture);
529 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
530 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
531 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
532 s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
533
534 s_gles2.glGenFramebuffers(1, &mFrameBuffer.framebuffer);
535
536 // Clear bindings.
537 s_gles2.glBindTexture(GL_TEXTURE_2D, 0);
538 s_gles2.glBindBuffer(GL_ARRAY_BUFFER, 0);
539 s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
540 }
541
draw(GLuint texture,int width,int height,int rotation)542 GLuint TextureResize::GenericResizer::draw(GLuint texture, int width, int height,
543 int rotation) {
544 if (mWidth != width || mHeight != height) {
545 // update the framebuffer to match the new resolution
546 mWidth = width;
547 mHeight = height;
548 s_gles2.glBindTexture(GL_TEXTURE_2D, mFrameBuffer.texture);
549 s_gles2.glTexImage2D(
550 GL_TEXTURE_2D, 0, GL_RGB, mWidth, mHeight, 0, GL_RGB,
551 GL_UNSIGNED_BYTE, nullptr);
552 s_gles2.glBindTexture(GL_TEXTURE_2D, 0);
553
554 }
555
556 // Store the viewport.
557 GLint vport[4] = { 0, };
558 s_gles2.glGetIntegerv(GL_VIEWPORT, vport);
559
560 s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, mFrameBuffer.framebuffer);
561 s_gles2.glFramebufferTexture2D(
562 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mFrameBuffer.texture, 0);
563 s_gles2.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
564 s_gles2.glViewport(0, 0, mWidth, mHeight);
565 s_gles2.glUseProgram(mProgram);
566 s_gles2.glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
567 s_gles2.glEnableVertexAttribArray(mPositionAttribLocation);
568 s_gles2.glVertexAttribPointer(mPositionAttribLocation,
569 2, // components per attrib
570 GL_FLOAT,
571 GL_FALSE,
572 sizeof(Vertex), // stride
573 0); // offset
574 s_gles2.glEnableVertexAttribArray(mInCoordAttribLocation);
575 s_gles2.glVertexAttribPointer(mInCoordAttribLocation,
576 2,
577 GL_FLOAT,
578 GL_FALSE,
579 sizeof(Vertex),
580 reinterpret_cast<GLvoid*>(sizeof(float) * 2));
581 s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
582 s_gles2.glActiveTexture(GL_TEXTURE0);
583 s_gles2.glBindTexture(GL_TEXTURE_2D, texture);
584 s_gles2.glUniform1i(mInputUniformLocation, 0);
585 intptr_t indexShift;
586 switch(rotation) {
587 case SKIN_ROTATION_0:
588 indexShift = 0;
589 break;
590 case SKIN_ROTATION_90:
591 indexShift = 6;
592 break;
593 case SKIN_ROTATION_180:
594 indexShift = 12;
595 break;
596 case SKIN_ROTATION_270:
597 indexShift = 18;
598 break;
599 default:
600 indexShift = 0;
601 }
602 s_gles2.glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, (const GLvoid*)indexShift);
603
604 // Clear the bindings.
605 s_gles2.glBindBuffer(GL_ARRAY_BUFFER, 0);
606 s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
607 s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, 0);
608 s_gles2.glBindTexture(GL_TEXTURE_2D, 0);
609 s_gles2.glDisableVertexAttribArray(mPositionAttribLocation);
610 s_gles2.glDisableVertexAttribArray(mInCoordAttribLocation);
611
612 // Restore the viewport.
613 s_gles2.glViewport(vport[0], vport[1], vport[2], vport[3]);
614
615 return mFrameBuffer.texture;
616 }
617
~GenericResizer()618 TextureResize::GenericResizer::~GenericResizer() {
619 s_gles2.glDeleteFramebuffers(1, &mFrameBuffer.framebuffer);
620 s_gles2.glDeleteTextures(1, &mFrameBuffer.texture);
621 s_gles2.glUseProgram(0);
622 s_gles2.glDeleteProgram(mProgram);
623 s_gles2.glBindBuffer(GL_ARRAY_BUFFER, 0);
624 s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
625 s_gles2.glDeleteBuffers(1, &mVertexBuffer);
626 s_gles2.glDeleteBuffers(1, &mIndexBuffer);
627 }
628
629 } // namespace gl
630 } // namespace gfxstream
631