TYPE3
[iec.git] / src / type3_AndroidCloud / anbox-master / src / anbox / graphics / emugl / TextureResize.cpp
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 "anbox/graphics/emugl/TextureResize.h"
18 #include "anbox/graphics/emugl/DispatchTables.h"
19 #include "anbox/logger.h"
20
21 #include <stdio.h>
22 #include <sstream>
23 #include <string>
24 #include <utility>
25
26 #define MAX_FACTOR_POWER 4
27
28 static const char kCommonShaderSource[] =
29     "precision mediump float;\n"
30     "varying vec2 vUV00, vUV01;\n"
31     "#if FACTOR > 2\n"
32     "varying vec2 vUV02, vUV03;\n"
33     "#if FACTOR > 4\n"
34     "varying vec2 vUV04, vUV05, vUV06, vUV07;\n"
35     "#if FACTOR > 8\n"
36     "varying vec2 vUV08, vUV09, vUV10, vUV11, vUV12, vUV13, vUV14, vUV15;\n"
37     "#endif\n"
38     "#endif\n"
39     "#endif\n";
40
41 static const char kVertexShaderSource[] =
42     "attribute vec2 aPosition;\n"
43
44     "void main() {\n"
45     "  gl_Position = vec4(aPosition, 0, 1);\n"
46     "  vec2 uv = ((aPosition + 1.0) / 2.0) + 0.5 / kDimension;\n"
47     "  vUV00 = uv;\n"
48     "  #ifdef HORIZONTAL\n"
49     "  vUV01 = uv + vec2( 1.0 / kDimension.x, 0);\n"
50     "  #if FACTOR > 2\n"
51     "  vUV02 = uv + vec2( 2.0 / kDimension.x, 0);\n"
52     "  vUV03 = uv + vec2( 3.0 / kDimension.x, 0);\n"
53     "  #if FACTOR > 4\n"
54     "  vUV04 = uv + vec2( 4.0 / kDimension.x, 0);\n"
55     "  vUV05 = uv + vec2( 5.0 / kDimension.x, 0);\n"
56     "  vUV06 = uv + vec2( 6.0 / kDimension.x, 0);\n"
57     "  vUV07 = uv + vec2( 7.0 / kDimension.x, 0);\n"
58     "  #if FACTOR > 8\n"
59     "  vUV08 = uv + vec2( 8.0 / kDimension.x, 0);\n"
60     "  vUV09 = uv + vec2( 9.0 / kDimension.x, 0);\n"
61     "  vUV10 = uv + vec2(10.0 / kDimension.x, 0);\n"
62     "  vUV11 = uv + vec2(11.0 / kDimension.x, 0);\n"
63     "  vUV12 = uv + vec2(12.0 / kDimension.x, 0);\n"
64     "  vUV13 = uv + vec2(13.0 / kDimension.x, 0);\n"
65     "  vUV14 = uv + vec2(14.0 / kDimension.x, 0);\n"
66     "  vUV15 = uv + vec2(15.0 / kDimension.x, 0);\n"
67     "  #endif\n"  // FACTOR > 8
68     "  #endif\n"  // FACTOR > 4
69     "  #endif\n"  // FACTOR > 2
70
71     "  #else\n"
72     "  vUV01 = uv + vec2(0,  1.0 / kDimension.y);\n"
73     "  #if FACTOR > 2\n"
74     "  vUV02 = uv + vec2(0,  2.0 / kDimension.y);\n"
75     "  vUV03 = uv + vec2(0,  3.0 / kDimension.y);\n"
76     "  #if FACTOR > 4\n"
77     "  vUV04 = uv + vec2(0,  4.0 / kDimension.y);\n"
78     "  vUV05 = uv + vec2(0,  5.0 / kDimension.y);\n"
79     "  vUV06 = uv + vec2(0,  6.0 / kDimension.y);\n"
80     "  vUV07 = uv + vec2(0,  7.0 / kDimension.y);\n"
81     "  #if FACTOR > 8\n"
82     "  vUV08 = uv + vec2(0,  8.0 / kDimension.y);\n"
83     "  vUV09 = uv + vec2(0,  9.0 / kDimension.y);\n"
84     "  vUV10 = uv + vec2(0, 10.0 / kDimension.y);\n"
85     "  vUV11 = uv + vec2(0, 11.0 / kDimension.y);\n"
86     "  vUV12 = uv + vec2(0, 12.0 / kDimension.y);\n"
87     "  vUV13 = uv + vec2(0, 13.0 / kDimension.y);\n"
88     "  vUV14 = uv + vec2(0, 14.0 / kDimension.y);\n"
89     "  vUV15 = uv + vec2(0, 15.0 / kDimension.y);\n"
90     "  #endif\n"  // FACTOR > 8
91     "  #endif\n"  // FACTOR > 4
92     "  #endif\n"  // FACTOR > 2
93     "  #endif\n"  // HORIZONTAL/VERTICAL
94     "}\n";
95
96 const char kFragmentShaderSource[] =
97     "uniform sampler2D uTexture;\n"
98
99     "vec4 read(vec2 uv) {\n"
100     "  vec4 r = texture2D(uTexture, uv);\n"
101     "  #ifdef HORIZONTAL\n"
102     "  r.rgb = pow(r.rgb, vec3(2.2));\n"
103     "  #endif\n"
104     "  return r;\n"
105     "}\n"
106
107     "void main() {\n"
108     "  vec4 sum = read(vUV00) + read(vUV01);\n"
109     "  #if FACTOR > 2\n"
110     "  sum += read(vUV02) + read(vUV03);\n"
111     "  #if FACTOR > 4\n"
112     "  sum += read(vUV04) + read(vUV05) + read(vUV06) + read(vUV07);\n"
113     "  #if FACTOR > 8\n"
114     "  sum += read(vUV08) + read(vUV09) + read(vUV10) + read(vUV11) +"
115     "      read(vUV12) + read(vUV13) + read(vUV14) + read(vUV15);\n"
116     "  #endif\n"
117     "  #endif\n"
118     "  #endif\n"
119     "  sum /= float(FACTOR);\n"
120     "  #ifdef VERTICAL\n"
121     "  sum.rgb = pow(sum.rgb, vec3(1.0 / 2.2));\n"
122     "  #endif\n"
123     "  gl_FragColor = sum;\n"
124     "}\n";
125
126 static const float kVertexData[] = {-1, -1, 3, -1, -1, 3};
127
128 static void detachShaders(GLuint program) {
129   GLuint shaders[2] = {};
130   GLsizei count = 0;
131   s_gles2.glGetAttachedShaders(program, 2, &count, shaders);
132   if (s_gles2.glGetError() == GL_NO_ERROR) {
133     for (GLsizei i = 0; i < count; i++) {
134       s_gles2.glDetachShader(program, shaders[i]);
135       s_gles2.glDeleteShader(shaders[i]);
136     }
137   }
138 }
139
140 static GLuint createShader(GLenum type,
141                            const std::initializer_list<const char*>& source) {
142   GLint success, infoLength;
143
144   GLuint shader = s_gles2.glCreateShader(type);
145   if (shader) {
146     s_gles2.glShaderSource(shader, source.size(), source.begin(), nullptr);
147     s_gles2.glCompileShader(shader);
148     s_gles2.glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
149     if (success == GL_FALSE) {
150       s_gles2.glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLength);
151       std::string infoLog(infoLength + 1, '\0');
152       s_gles2.glGetShaderInfoLog(shader, infoLength, nullptr, &infoLog[0]);
153       ERROR("%s shader compile failed: %s", (type == GL_VERTEX_SHADER) ? "Vertex" : "Fragment", infoLog.c_str());
154       s_gles2.glDeleteShader(shader);
155       shader = 0;
156     }
157   }
158   return shader;
159 }
160
161 static void attachShaders(TextureResize::Framebuffer* fb,
162                           const char* factorDefine, const char* dimensionDefine,
163                           GLuint width, GLuint height) {
164   std::ostringstream dimensionConst;
165   dimensionConst << "const vec2 kDimension = vec2(" << width << ", " << height
166                  << ");\n";
167
168   GLuint vShader = createShader(
169       GL_VERTEX_SHADER, {factorDefine, dimensionDefine, kCommonShaderSource,
170                          dimensionConst.str().c_str(), kVertexShaderSource});
171   GLuint fShader = createShader(
172       GL_FRAGMENT_SHADER, {factorDefine, dimensionDefine, kCommonShaderSource,
173                            kFragmentShaderSource});
174
175   if (!vShader || !fShader) {
176     return;
177   }
178
179   s_gles2.glAttachShader(fb->program, vShader);
180   s_gles2.glAttachShader(fb->program, fShader);
181   s_gles2.glLinkProgram(fb->program);
182
183   s_gles2.glUseProgram(fb->program);
184   fb->aPosition = s_gles2.glGetAttribLocation(fb->program, "aPosition");
185   fb->uTexture = s_gles2.glGetUniformLocation(fb->program, "uTexture");
186 }
187
188 TextureResize::TextureResize(GLuint width, GLuint height)
189     : mWidth(width),
190       mHeight(height),
191       mFactor(1) {
192   s_gles2.glGenTextures(1, &mFBWidth.texture);
193   s_gles2.glBindTexture(GL_TEXTURE_2D, mFBWidth.texture);
194   s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
195   s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
196   s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
197   s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
198
199   s_gles2.glGenTextures(1, &mFBHeight.texture);
200   s_gles2.glBindTexture(GL_TEXTURE_2D, mFBHeight.texture);
201   s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
202   s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
203   s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
204   s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
205
206   s_gles2.glGenFramebuffers(1, &mFBWidth.framebuffer);
207   s_gles2.glGenFramebuffers(1, &mFBHeight.framebuffer);
208
209   mFBWidth.program = s_gles2.glCreateProgram();
210   mFBHeight.program = s_gles2.glCreateProgram();
211
212   s_gles2.glGenBuffers(1, &mVertexBuffer);
213   s_gles2.glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
214   s_gles2.glBufferData(GL_ARRAY_BUFFER, sizeof(kVertexData), kVertexData,
215                        GL_STATIC_DRAW);
216 }
217
218 TextureResize::~TextureResize() {
219   GLuint fb[2] = {mFBWidth.framebuffer, mFBHeight.framebuffer};
220   s_gles2.glDeleteFramebuffers(2, fb);
221
222   GLuint tex[2] = {mFBWidth.texture, mFBHeight.texture};
223   s_gles2.glDeleteTextures(2, tex);
224
225   s_gles2.glDeleteProgram(mFBWidth.program);
226   s_gles2.glDeleteProgram(mFBHeight.program);
227
228   s_gles2.glDeleteBuffers(1, &mVertexBuffer);
229 }
230
231 GLuint TextureResize::update(GLuint texture) {
232   // Store the viewport. The viewport is clobbered due to the framebuffers.
233   GLint vport[4] = {
234       0,
235   };
236   s_gles2.glGetIntegerv(GL_VIEWPORT, vport);
237
238   // Correctly deal with rotated screens.
239   GLint tWidth = vport[2], tHeight = vport[3];
240   if ((mWidth < mHeight) != (tWidth < tHeight)) {
241     std::swap(tWidth, tHeight);
242   }
243
244   // Compute the scaling factor needed to get an image just larger than the
245   // target viewport.
246   unsigned int factor = 1;
247   for (int i = 0, w = mWidth / 2, h = mHeight / 2;
248        i < MAX_FACTOR_POWER && w >= tWidth && h >= tHeight;
249        i++, w /= 2, h /= 2, factor *= 2) {
250   }
251
252   // No resizing needed.
253   if (factor == 1) {
254     return texture;
255   }
256
257   s_gles2.glGetError();  // Clear any GL errors.
258   setupFramebuffers(factor);
259   resize(texture);
260   s_gles2.glViewport(vport[0], vport[1], vport[2],
261                      vport[3]);  // Restore the viewport.
262
263   // If there was an error while resizing, just use the unscaled texture.
264   GLenum error = s_gles2.glGetError();
265   if (error != GL_NO_ERROR) {
266     ERROR("GL error while resizing: 0x%x (ignored)", error);
267     return texture;
268   }
269
270   return mFBHeight.texture;
271 }
272
273 void TextureResize::setupFramebuffers(unsigned int factor) {
274   if (factor == mFactor) {
275     // The factor hasn't changed, no need to update the framebuffers.
276     return;
277   }
278
279   // Update the framebuffer sizes to match the new factor.
280   s_gles2.glBindTexture(GL_TEXTURE_2D, mFBWidth.texture);
281   s_gles2.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mWidth / factor, mHeight, 0,
282                        GL_RGBA, GL_FLOAT, nullptr);
283   s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, mFBWidth.framebuffer);
284   s_gles2.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
285                                  GL_TEXTURE_2D, mFBWidth.texture, 0);
286
287   s_gles2.glBindTexture(GL_TEXTURE_2D, mFBHeight.texture);
288   s_gles2.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mWidth / factor,
289                        mHeight / factor, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
290   s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, mFBHeight.framebuffer);
291   s_gles2.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
292                                  GL_TEXTURE_2D, mFBHeight.texture, 0);
293
294   // Update the shaders to the new factor. First detach the old shaders...
295   detachShaders(mFBWidth.program);
296   detachShaders(mFBHeight.program);
297
298   // ... then attach the new ones.
299   std::ostringstream factorDefine;
300   factorDefine << "#define FACTOR " << factor << "\n";
301   attachShaders(&mFBWidth, factorDefine.str().c_str(), "#define HORIZONTAL\n",
302                 mWidth, mHeight);
303   attachShaders(&mFBHeight, factorDefine.str().c_str(), "#define VERTICAL\n",
304                 mWidth, mHeight);
305
306   mFactor = factor;
307 }
308
309 void TextureResize::resize(GLuint texture) {
310   s_gles2.glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
311   s_gles2.glActiveTexture(GL_TEXTURE0);
312
313   // First scale the horizontal dimension by rendering the input texture to a
314   // scaled framebuffer.
315   s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, mFBWidth.framebuffer);
316   s_gles2.glViewport(0, 0, mWidth / mFactor, mHeight);
317   s_gles2.glUseProgram(mFBWidth.program);
318   s_gles2.glEnableVertexAttribArray(mFBWidth.aPosition);
319   s_gles2.glVertexAttribPointer(mFBWidth.aPosition, 2, GL_FLOAT, GL_FALSE, 0,
320                                 0);
321   s_gles2.glBindTexture(GL_TEXTURE_2D, texture);
322
323   // Store the current texture filters and set to nearest for scaling.
324   GLint mag_filter, min_filter;
325   s_gles2.glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
326                               &mag_filter);
327   s_gles2.glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
328                               &min_filter);
329   s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
330   s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
331   s_gles2.glUniform1i(mFBWidth.uTexture, 0);
332   s_gles2.glDrawArrays(GL_TRIANGLES, 0,
333                        sizeof(kVertexData) / (2 * sizeof(float)));
334
335   // Restore the previous texture filters.
336   s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
337   s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
338
339   // Secondly, scale the vertical dimension using the second framebuffer.
340   s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, mFBHeight.framebuffer);
341   s_gles2.glViewport(0, 0, mWidth / mFactor, mHeight / mFactor);
342   s_gles2.glUseProgram(mFBHeight.program);
343   s_gles2.glEnableVertexAttribArray(mFBHeight.aPosition);
344   s_gles2.glVertexAttribPointer(mFBHeight.aPosition, 2, GL_FLOAT, GL_FALSE, 0,
345                                 0);
346   s_gles2.glBindTexture(GL_TEXTURE_2D, mFBWidth.texture);
347   s_gles2.glUniform1i(mFBHeight.uTexture, 0);
348   s_gles2.glDrawArrays(GL_TRIANGLES, 0,
349                        sizeof(kVertexData) / (2 * sizeof(float)));
350
351   // Clear the bindings.
352   s_gles2.glBindBuffer(GL_ARRAY_BUFFER, 0);
353   s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, 0);
354   s_gles2.glBindTexture(GL_TEXTURE_2D, 0);
355 }