Home | History | Annotate | Download | only in compositor_model_bench
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "gpu/tools/compositor_model_bench/shaders.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "gpu/tools/compositor_model_bench/render_model_utils.h"
     10 #include "gpu/tools/compositor_model_bench/render_tree.h"
     11 
     12 using std::min;
     13 
     14 static const int kPositionLocation = 0;
     15 static const int kTexCoordLocation = 1;
     16 
     17 static unsigned g_quad_vertices_vbo;
     18 static unsigned g_quad_elements_vbo;
     19 
     20 // Store a pointer to the transform matrix of the active layer (the complete
     21 // transform isn't build until we draw the quad; then we can apply
     22 // translation/scaling/projection)
     23 static float* g_current_layer_transform;
     24 
     25 // In addition to the transform, store other useful information about tiled
     26 // layers that we'll need to render each tile's quad
     27 static float g_current_tile_layer_width;
     28 static float g_current_tile_layer_height;
     29 static float g_current_tile_width;
     30 static float g_current_tile_height;
     31 
     32 static const float yuv2RGB[9] = {
     33   1.164f, 1.164f, 1.164f,
     34   0.f, -.391f, 2.018f,
     35   1.596f, -.813f, 0.f
     36 };
     37 
     38 // Store shader programs in a sparse array so that they can be addressed easily.
     39 static int g_program_objects[SHADER_ID_MAX*SHADER_ID_MAX];
     40 static int g_active_index = -1;
     41 
     42 ///////////////////////////////////////////////////////////////////////////////
     43 //              L        R           B          T   N  F
     44 //      glOrtho(0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, -1, 1);   // column major
     45 
     46 static float g_projection_matrix[] = {
     47   2.0 / WINDOW_WIDTH, 0.0, 0.0, 0.0,
     48   0.0, 2.0 / -WINDOW_HEIGHT, 0.0, 0.0,
     49   0.0, 0.0, -1.0, 0.0,
     50   -1.0, 1.0, 0.0, 1.0
     51 };
     52 
     53 #define ADDR(i, j) (i*4 + j) /* column major */
     54 static void Project(const float* v, float* p) {
     55   for (int i = 0; i < 4; ++i) {
     56     for (int j = 0; j < 4; ++j) {
     57       p[ADDR(i, j)] = 0;
     58       for (int k = 0; k < 4; ++k) {
     59         p[ADDR(i, j)] += g_projection_matrix[ADDR(k, i)] * v[ADDR(j, k)];
     60       }
     61     }
     62   }
     63 }
     64 
     65 static void Scale(const float* in, float* out, float sx, float sy, float sz) {
     66   for (int i = 0; i < 4; ++i)
     67     out[i] = in[i] * sx;
     68   for (int j = 4; j < 8; ++j)
     69     out[j] = in[j] * sy;
     70   for (int k = 8; k < 12; ++k)
     71     out[k] = in[k] * sz;
     72   for (int l = 12; l < 16; ++l)
     73     out[l] = in[l];
     74 }
     75 
     76 static void TranslateInPlace(float* m, float tx, float ty, float tz) {
     77   m[12] += tx;
     78   m[13] += ty;
     79   m[14] += tz;
     80 }
     81 
     82 ///////////////////////////////////////////////////////////////////////////////
     83 
     84 ShaderID ShaderIDFromString(std::string name) {
     85   if (name == "VertexShaderPosTexYUVStretch")
     86     return VERTEX_SHADER_POS_TEX_YUV_STRETCH;
     87   if (name == "VertexShaderPosTex")
     88     return VERTEX_SHADER_POS_TEX;
     89   if (name == "VertexShaderPosTexTransform")
     90     return VERTEX_SHADER_POS_TEX_TRANSFORM;
     91   if (name == "FragmentShaderYUVVideo")
     92     return FRAGMENT_SHADER_YUV_VIDEO;
     93   if (name == "FragmentShaderRGBATexFlipAlpha")
     94     return FRAGMENT_SHADER_RGBA_TEX_FLIP_ALPHA;
     95   if (name == "FragmentShaderRGBATexAlpha")
     96     return FRAGMENT_SHADER_RGBA_TEX_ALPHA;
     97   return SHADER_UNRECOGNIZED;
     98 }
     99 
    100 std::string ShaderNameFromID(ShaderID id) {
    101   switch (id) {
    102     case VERTEX_SHADER_POS_TEX_YUV_STRETCH:
    103       return "VertexShaderPosTexYUVStretch";
    104     case VERTEX_SHADER_POS_TEX:
    105       return "VertexShaderPosTex";
    106     case VERTEX_SHADER_POS_TEX_TRANSFORM:
    107       return "VertexShaderPosTexTransform";
    108     case FRAGMENT_SHADER_YUV_VIDEO:
    109       return "FragmentShaderYUVVideo";
    110     case FRAGMENT_SHADER_RGBA_TEX_FLIP_ALPHA:
    111       return "FragmentShaderRGBATexFlipAlpha";
    112     case FRAGMENT_SHADER_RGBA_TEX_ALPHA:
    113       return "FragmentShaderRGBATexAlpha";
    114     default:
    115       return "(unknown shader)";
    116   }
    117 }
    118 
    119 #define SHADER0(Src) #Src
    120 #define SHADER(Src) SHADER0(Src)
    121 
    122 const char* GetShaderSource(ShaderID shader) {
    123   switch (shader) {
    124     case VERTEX_SHADER_POS_TEX_YUV_STRETCH:
    125       return SHADER(
    126         #ifdef GL_ES
    127         precision mediump float;
    128         #endif
    129         attribute vec4 a_position;
    130         attribute vec2 a_texCoord;
    131         uniform mat4 matrix;
    132         varying vec2 y_texCoord;
    133         varying vec2 uv_texCoord;
    134         uniform float y_widthScaleFactor;
    135         uniform float uv_widthScaleFactor;
    136         void main() {
    137           gl_Position = matrix * a_position;
    138           y_texCoord = vec2(y_widthScaleFactor * a_texCoord.x,
    139             a_texCoord.y);
    140           uv_texCoord = vec2(uv_widthScaleFactor * a_texCoord.x,
    141             a_texCoord.y);
    142         });
    143       break;
    144     case VERTEX_SHADER_POS_TEX:
    145       return SHADER(
    146         attribute vec4 a_position;
    147         attribute vec2 a_texCoord;
    148         uniform mat4 matrix;
    149         varying vec2 v_texCoord;
    150         void main() {
    151           gl_Position = matrix * a_position;
    152           v_texCoord = a_texCoord;
    153         });
    154       break;
    155     case VERTEX_SHADER_POS_TEX_TRANSFORM:
    156       return SHADER(
    157         attribute vec4 a_position;
    158         attribute vec2 a_texCoord;
    159         uniform mat4 matrix;
    160         uniform vec4 texTransform;
    161         varying vec2 v_texCoord;
    162         void main() {
    163           gl_Position = matrix * a_position;
    164           v_texCoord = a_texCoord*texTransform.zw + texTransform.xy;
    165         });
    166       break;
    167     case FRAGMENT_SHADER_YUV_VIDEO:
    168       return SHADER(
    169         #ifdef GL_ES
    170         precision mediump float;
    171         precision mediump int;
    172         #endif
    173         varying vec2 y_texCoord;
    174         varying vec2 uv_texCoord;
    175         uniform sampler2D y_texture;
    176         uniform sampler2D u_texture;
    177         uniform sampler2D v_texture;
    178         uniform float alpha;
    179         uniform vec3 yuv_adj;
    180         uniform mat3 cc_matrix;
    181         void main() {
    182           float y_raw = texture2D(y_texture, y_texCoord).x;
    183           float u_unsigned = texture2D(u_texture, uv_texCoord).x;
    184           float v_unsigned = texture2D(v_texture, uv_texCoord).x;
    185           vec3 yuv = vec3(y_raw, u_unsigned, v_unsigned) + yuv_adj;
    186           vec3 rgb = cc_matrix * yuv;
    187           gl_FragColor = vec4(rgb, 1.0) * alpha;
    188         });
    189       break;
    190     case FRAGMENT_SHADER_RGBA_TEX_FLIP_ALPHA:
    191       return SHADER(
    192         #ifdef GL_ES
    193         precision mediump float;
    194         #endif
    195         varying vec2 v_texCoord;
    196         uniform sampler2D s_texture;
    197         uniform float alpha;
    198         void main() {
    199           vec4 texColor = texture2D(s_texture,
    200             vec2(v_texCoord.x, 1.0 - v_texCoord.y));
    201           gl_FragColor = vec4(texColor.x,
    202             texColor.y,
    203             texColor.z,
    204             texColor.w) * alpha;
    205         });
    206       break;
    207     case FRAGMENT_SHADER_RGBA_TEX_ALPHA:
    208       return SHADER(
    209         #ifdef GL_ES
    210         precision mediump float;
    211         #endif
    212         varying vec2 v_texCoord;
    213         uniform sampler2D s_texture;
    214         uniform float alpha;
    215         void main() {
    216           vec4 texColor = texture2D(s_texture, v_texCoord);
    217           gl_FragColor = texColor * alpha;
    218         });
    219       break;
    220     default:
    221       printf("Shader source requested for unknown shader\n");
    222       return "";
    223   }
    224 }
    225 
    226 int GetProgramIdx(ShaderID v, ShaderID f) {
    227   return v * SHADER_ID_MAX + f;
    228 }
    229 
    230 static void ReportAnyShaderCompilationErrors(GLuint shader, ShaderID id) {
    231   GLint status;
    232   glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
    233   if (status)
    234     return;
    235   // Get the length of the log string
    236   GLsizei length;
    237   glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
    238   scoped_ptr<GLchar[]> log(new GLchar[length+1]);
    239   glGetShaderInfoLog(shader, length, NULL, log.get());
    240   LOG(ERROR) << log.get() << " in shader " << ShaderNameFromID(id);
    241 }
    242 
    243 static int ActivateShader(ShaderID v, ShaderID f, float* layer_transform) {
    244   int program_index = GetProgramIdx(v, f);
    245   if (!g_program_objects[program_index]) {
    246     g_program_objects[program_index] = glCreateProgramObjectARB();
    247     GLenum vs = glCreateShaderObjectARB(GL_VERTEX_SHADER);
    248     GLenum fs = glCreateShaderObjectARB(GL_FRAGMENT_SHADER);
    249     const char* vs_source = GetShaderSource(v);
    250     const char* fs_source = GetShaderSource(f);
    251     glShaderSourceARB(vs, 1, &vs_source, 0);
    252     glShaderSourceARB(fs, 1, &fs_source, 0);
    253     glCompileShaderARB(vs);
    254     ReportAnyShaderCompilationErrors(vs, v);
    255     glCompileShaderARB(fs);
    256     ReportAnyShaderCompilationErrors(fs, f);
    257     glAttachObjectARB(g_program_objects[program_index], vs);
    258     glAttachObjectARB(g_program_objects[program_index], fs);
    259     glBindAttribLocationARB(g_program_objects[program_index],
    260                             kPositionLocation,
    261                             "a_position");
    262     glBindAttribLocationARB(g_program_objects[program_index],
    263                             kTexCoordLocation,
    264                             "a_texCoord");
    265     glLinkProgramARB(g_program_objects[program_index]);
    266   }
    267   if (g_active_index != program_index)
    268     glUseProgramObjectARB(g_program_objects[program_index]);
    269   g_active_index = program_index;
    270 
    271   g_current_layer_transform = layer_transform;
    272 
    273   return g_program_objects[program_index];
    274 }
    275 
    276 void ConfigAndActivateShaderForNode(CCNode* n) {
    277   ShaderID vs = n->vertex_shader();
    278   ShaderID fs = n->fragment_shader();
    279   float* transform = n->transform();
    280   int program = ActivateShader(vs, fs, transform);
    281   if (vs == VERTEX_SHADER_POS_TEX_YUV_STRETCH) {
    282     GLint y_scale = glGetUniformLocationARB(program, "y_widthScaleFactor");
    283     GLint uv_scale = glGetUniformLocationARB(program, "uv_widthScaleFactor");
    284     glUniform1fARB(y_scale, 1.0);
    285     glUniform1fARB(uv_scale, 1.0);
    286   }
    287   if (vs == VERTEX_SHADER_POS_TEX_TRANSFORM) {
    288     GLint texTrans = glGetUniformLocationARB(program, "texTransform");
    289     glUniform4fARB(texTrans, 0.0, 0.0, 0.0, 0.0);
    290   }
    291   if (fs == FRAGMENT_SHADER_RGBA_TEX_FLIP_ALPHA) {
    292     DCHECK_EQ(n->num_textures(), 1u);
    293     DCHECK_NE(n->texture(0)->texID, -1);
    294     glActiveTexture(GL_TEXTURE0);
    295     glBindTexture(GL_TEXTURE_2D, n->texture(0)->texID);
    296     int sTexLoc = glGetUniformLocationARB(program, "s_texture");
    297     glUniform1iARB(sTexLoc, 0);
    298   }
    299   if (fs == FRAGMENT_SHADER_YUV_VIDEO) {
    300     DCHECK_EQ(n->num_textures(), 3u);
    301     DCHECK_NE(n->texture(0)->texID, -1);
    302     DCHECK_NE(n->texture(1)->texID, -1);
    303     DCHECK_NE(n->texture(2)->texID, -1);
    304     // Bind Y tex.
    305     glActiveTexture(GL_TEXTURE0);
    306     glBindTexture(GL_TEXTURE_2D, n->texture(0)->texID);
    307     int yTexLoc = glGetUniformLocationARB(program, "y_texture");
    308     glUniform1iARB(yTexLoc, 0);
    309     // Bind U tex.
    310     glActiveTexture(GL_TEXTURE0 + 1);
    311     glBindTexture(GL_TEXTURE_2D, n->texture(1)->texID);
    312     int uTexLoc = glGetUniformLocationARB(program, "u_texture");
    313     glUniform1iARB(uTexLoc, 1);
    314     // Bind V tex.
    315     glActiveTexture(GL_TEXTURE0 + 2);
    316     glBindTexture(GL_TEXTURE_2D, n->texture(2)->texID);
    317     int vTexLoc = glGetUniformLocationARB(program, "v_texture");
    318     glUniform1iARB(vTexLoc, 2);
    319     // Set YUV offset.
    320     int yuvAdjLoc = glGetUniformLocationARB(program, "yuv_adj");
    321     glUniform3fARB(yuvAdjLoc, -0.0625f, -0.5f, -0.5f);
    322     // Set YUV matrix.
    323     int ccMatLoc = glGetUniformLocationARB(program, "cc_matrix");
    324     glUniformMatrix3fvARB(ccMatLoc, 1, false, yuv2RGB);
    325   }
    326   GLint alpha = glGetUniformLocationARB(program, "alpha");
    327   glUniform1fARB(alpha, 0.9);
    328 }
    329 
    330 void ConfigAndActivateShaderForTiling(ContentLayerNode* n) {
    331   int program = ActivateShader(VERTEX_SHADER_POS_TEX_TRANSFORM,
    332                                FRAGMENT_SHADER_RGBA_TEX_ALPHA,
    333                                n->transform());
    334   GLint texTrans = glGetUniformLocationARB(program, "texTransform");
    335   glUniform4fARB(texTrans, 0.0, 0.0, 1.0, 1.0);
    336   GLint alpha = glGetUniformLocationARB(program, "alpha");
    337   glUniform1fARB(alpha, 0.9);
    338 
    339   g_current_tile_layer_width = n->width();
    340   g_current_tile_layer_height = n->height();
    341   g_current_tile_width = n->tile_width();
    342   g_current_tile_height = n->tile_height();
    343 }
    344 
    345 void DeleteShaders() {
    346   g_active_index = -1;
    347   glUseProgramObjectARB(0);
    348   for (int i = 0; i < SHADER_ID_MAX*SHADER_ID_MAX; ++i) {
    349     if (g_program_objects[i]) {
    350       glDeleteObjectARB(g_program_objects[i]);
    351     }
    352     g_program_objects[i] = 0;
    353   }
    354 }
    355 
    356 void InitBuffers() {
    357   // Vertex positions and texture coordinates for the 4 corners of a 1x1 quad.
    358   float vertices[] = { -0.5f,  0.5f, 0.0f, 0.0f,  1.0f,
    359                        -0.5f, -0.5f, 0.0f, 0.0f,  0.0f,
    360                        0.5f,  -0.5f, 0.0f, 1.0f,  0.0f,
    361                        0.5f,   0.5f, 0.0f, 1.0f,  1.0f };
    362   uint16_t indices[] = { 0, 1, 2, 0, 2, 3};
    363 
    364   glGenBuffers(1, &g_quad_vertices_vbo);
    365   glGenBuffers(1, &g_quad_elements_vbo);
    366   glBindBuffer(GL_ARRAY_BUFFER, g_quad_vertices_vbo);
    367   glBufferData(GL_ARRAY_BUFFER,
    368                sizeof(vertices),
    369                vertices,
    370                GL_STATIC_DRAW);
    371   glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_quad_elements_vbo);
    372   glBufferData(GL_ELEMENT_ARRAY_BUFFER,
    373                sizeof(indices),
    374                indices,
    375                GL_STATIC_DRAW);
    376 }
    377 
    378 void BeginFrame() {
    379   glBindBuffer(GL_ARRAY_BUFFER, g_quad_vertices_vbo);
    380   glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_quad_elements_vbo);
    381   unsigned offset = 0;
    382   glVertexAttribPointer(kPositionLocation,
    383                         3,
    384                         GL_FLOAT,
    385                         false,
    386                         5 * sizeof(float),
    387                         reinterpret_cast<void*>(offset));
    388   offset += 3 * sizeof(float);
    389   glVertexAttribPointer(kTexCoordLocation,
    390                         2,
    391                         GL_FLOAT,
    392                         false,
    393                         5 * sizeof(float),
    394                         reinterpret_cast<void*>(offset));
    395   glEnableVertexAttribArray(kPositionLocation);
    396   glEnableVertexAttribArray(kTexCoordLocation);
    397 }
    398 
    399 void DrawQuad(float width, float height) {
    400   float mv_transform[16];
    401   float proj_transform[16];
    402   Scale(g_current_layer_transform, mv_transform, width, height, 1.0);
    403   Project(mv_transform, proj_transform);
    404   GLint mat = glGetUniformLocationARB(g_program_objects[g_active_index],
    405                                       "matrix");
    406   glUniformMatrix4fvARB(mat, 1, GL_TRUE, proj_transform);
    407 
    408   glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
    409 }
    410 
    411 void DrawTileQuad(GLuint texID, int x, int y) {
    412   float left = g_current_tile_width*x;
    413   float top = g_current_tile_height*y;
    414   if (left > g_current_tile_layer_width || top > g_current_tile_layer_height)
    415     return;
    416 
    417   float right = min(left+g_current_tile_width, g_current_tile_layer_width);
    418   float bottom = min(top+g_current_tile_height, g_current_tile_layer_height);
    419   float width = right-left;
    420   float height = bottom-top;
    421 
    422   int prog = g_program_objects[g_active_index];
    423 
    424   // Scale the texture if the full tile rectangle doesn't get drawn.
    425   float u_scale = width / g_current_tile_width;
    426   float v_scale = height / g_current_tile_height;
    427   GLint texTrans = glGetUniformLocationARB(prog, "texTransform");
    428   glUniform4fARB(texTrans, 0.0, 0.0, u_scale, v_scale);
    429 
    430   glActiveTexture(GL_TEXTURE0);
    431   glBindTexture(GL_TEXTURE_2D, texID);
    432   int texLoc = glGetUniformLocationARB(prog, "s_texture");
    433   glUniform1iARB(texLoc, 0);
    434 
    435   float mv_transform[16];
    436   float proj_transform[16];
    437   Scale(g_current_layer_transform, mv_transform, width, height, 1.0);
    438 
    439   // We have to position the tile by its center.
    440   float center_x = (left+right)/2 - g_current_tile_layer_width/2;
    441   float center_y = (top+bottom)/2 - g_current_tile_layer_height/2;
    442   TranslateInPlace(mv_transform, center_x, center_y, 0.0);
    443 
    444   Project(mv_transform, proj_transform);
    445   GLint mat = glGetUniformLocationARB(prog, "matrix");
    446   glUniformMatrix4fvARB(mat, 1, GL_TRUE, proj_transform);
    447 
    448   glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
    449 }
    450 
    451