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