Home | History | Annotate | Download | only in service
      1 // Copyright (c) 2012 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/command_buffer/service/gles2_cmd_copy_texture_chromium.h"
      6 
      7 #include <string.h>
      8 #include "base/basictypes.h"
      9 #include "gpu/command_buffer/common/types.h"
     10 #include "gpu/command_buffer/service/gl_utils.h"
     11 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
     12 
     13 #define SHADER0(src) \
     14     "#ifdef GL_ES\n"\
     15     "precision mediump float;\n"\
     16     "#endif\n"\
     17     #src
     18 #define SHADER(src) { false, SHADER0(src), }
     19 #define SHADER_EXTERNAL_OES0(src) \
     20     "#extension GL_OES_EGL_image_external : require\n"\
     21     "#ifdef GL_ES\n"\
     22     "precision mediump float;\n"\
     23     "#endif\n"\
     24     #src
     25 #define SHADER_EXTERNAL_OES(src) { true, SHADER_EXTERNAL_OES0(src), }
     26 
     27 namespace {
     28 
     29 const GLfloat kQuadVertices[] = { -1.0f, -1.0f, 0.0f, 1.0f,
     30                                    1.0f, -1.0f, 0.0f, 1.0f,
     31                                    1.0f,  1.0f, 0.0f, 1.0f,
     32                                   -1.0f,  1.0f, 0.0f, 1.0f };
     33 
     34 enum ProgramId {
     35   PROGRAM_COPY_TEXTURE,
     36   PROGRAM_COPY_TEXTURE_FLIP_Y,
     37   PROGRAM_COPY_TEXTURE_PREMULTIPLY_ALPHA,
     38   PROGRAM_COPY_TEXTURE_UNPREMULTIPLY_ALPHA,
     39   PROGRAM_COPY_TEXTURE_PREMULTIPLY_ALPHA_FLIPY,
     40   PROGRAM_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_FLIPY,
     41   PROGRAM_COPY_TEXTURE_OES,
     42   PROGRAM_COPY_TEXTURE_OES_FLIP_Y,
     43   PROGRAM_COPY_TEXTURE_OES_PREMULTIPLY_ALPHA,
     44   PROGRAM_COPY_TEXTURE_OES_UNPREMULTIPLY_ALPHA,
     45   PROGRAM_COPY_TEXTURE_OES_PREMULTIPLY_ALPHA_FLIPY,
     46   PROGRAM_COPY_TEXTURE_OES_UNPREMULTIPLY_ALPHA_FLIPY,
     47 };
     48 
     49 struct ShaderInfo {
     50   bool needs_egl_image_external;
     51   const char* source;
     52 };
     53 
     54 const ShaderInfo shader_infos[] = {
     55   // VERTEX_SHADER_POS_TEX
     56   SHADER(
     57     uniform mat4 u_matrix;
     58     attribute vec4 a_position;
     59     varying vec2 v_uv;
     60     void main(void) {
     61       gl_Position = u_matrix * a_position;
     62       v_uv = a_position.xy * 0.5 + vec2(0.5, 0.5);
     63     }),
     64   // FRAGMENT_SHADER_TEX
     65   SHADER(
     66     uniform sampler2D u_texSampler;
     67     varying vec2 v_uv;
     68     void main(void) {
     69       gl_FragColor = texture2D(u_texSampler, v_uv.st);
     70     }),
     71   // FRAGMENT_SHADER_TEX_FLIP_Y
     72   SHADER(
     73     uniform sampler2D u_texSampler;
     74     varying vec2 v_uv;
     75     void main(void) {
     76       gl_FragColor = texture2D(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
     77     }),
     78   // FRAGMENT_SHADER_TEX_PREMULTIPLY_ALPHA
     79   SHADER(
     80     uniform sampler2D u_texSampler;
     81     varying vec2 v_uv;
     82     void main(void) {
     83       gl_FragColor = texture2D(u_texSampler, v_uv.st);
     84       gl_FragColor.rgb *= gl_FragColor.a;
     85     }),
     86   // FRAGMENT_SHADER_TEX_UNPREMULTIPLY_ALPHA
     87   SHADER(
     88     uniform sampler2D u_texSampler;
     89     varying vec2 v_uv;
     90     void main(void) {
     91       gl_FragColor = texture2D(u_texSampler, v_uv.st);
     92       if (gl_FragColor.a > 0.0)
     93         gl_FragColor.rgb /= gl_FragColor.a;
     94     }),
     95   // FRAGMENT_SHADER_TEX_PREMULTIPLY_ALPHA_FLIP_Y
     96   SHADER(
     97     uniform sampler2D u_texSampler;
     98     varying vec2 v_uv;
     99     void main(void) {
    100       gl_FragColor = texture2D(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
    101       gl_FragColor.rgb *= gl_FragColor.a;
    102     }),
    103   // FRAGMENT_SHADER_TEX_UNPREMULTIPLY_ALPHA_FLIP_Y
    104   SHADER(
    105     uniform sampler2D u_texSampler;
    106     varying vec2 v_uv;
    107     void main(void) {
    108       gl_FragColor = texture2D(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
    109       if (gl_FragColor.a > 0.0)
    110         gl_FragColor.rgb /= gl_FragColor.a;
    111     }),
    112   // FRAGMENT_SHADER_TEX_OES
    113   SHADER_EXTERNAL_OES(
    114     precision mediump float;
    115     uniform samplerExternalOES u_texSampler;
    116     varying vec2 v_uv;
    117     void main(void) {
    118       gl_FragColor = texture2D(u_texSampler, v_uv.st);
    119     }),
    120   // FRAGMENT_SHADER_TEX_OES_FLIP_Y
    121   SHADER_EXTERNAL_OES(
    122      precision mediump float;
    123      uniform samplerExternalOES u_texSampler;
    124      varying vec2 v_uv;
    125      void main(void) {
    126        gl_FragColor =
    127            texture2D(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
    128      }),
    129   // FRAGMENT_SHADER_TEX_OES_PREMULTIPLY_ALPHA
    130   SHADER_EXTERNAL_OES(
    131      precision mediump float;
    132      uniform samplerExternalOES u_texSampler;
    133      varying vec2 v_uv;
    134      void main(void) {
    135        gl_FragColor = texture2D(u_texSampler, v_uv.st);
    136        gl_FragColor.rgb *= gl_FragColor.a;
    137      }),
    138   // FRAGMENT_SHADER_TEX_OES_UNPREMULTIPLY_ALPHA
    139   SHADER_EXTERNAL_OES(
    140     precision mediump float;
    141     uniform samplerExternalOES u_texSampler;
    142     varying vec2 v_uv;
    143     void main(void) {
    144       gl_FragColor = texture2D(u_texSampler, v_uv.st);
    145       if (gl_FragColor.a > 0.0)
    146         gl_FragColor.rgb /= gl_FragColor.a;
    147     }),
    148   // FRAGMENT_SHADER_TEX_OES_PREMULTIPLY_ALPHA_FLIP_Y
    149   SHADER_EXTERNAL_OES(
    150       precision mediump float;
    151       uniform samplerExternalOES u_texSampler;
    152       varying vec2 v_uv;
    153       void main(void) {
    154         gl_FragColor =
    155             texture2D(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
    156         gl_FragColor.rgb *= gl_FragColor.a;
    157       }),
    158   // FRAGMENT_SHADER_TEX_OES_UNPREMULTIPLY_ALPHA_FLIP_Y
    159   SHADER_EXTERNAL_OES(
    160       precision mediump float;
    161       uniform samplerExternalOES u_texSampler;
    162       varying vec2 v_uv;
    163       void main(void) {
    164         gl_FragColor =
    165             texture2D(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
    166         if (gl_FragColor.a > 0.0)
    167           gl_FragColor.rgb /= gl_FragColor.a;
    168       }),
    169 };
    170 
    171 const int kNumShaders = arraysize(shader_infos);
    172 
    173 // Returns the correct program to evaluate the copy operation for
    174 // the CHROMIUM_flipy and premultiply alpha pixel store settings.
    175 ProgramId GetProgram(
    176     bool flip_y,
    177     bool premultiply_alpha,
    178     bool unpremultiply_alpha,
    179     bool is_source_external_oes) {
    180   // If both pre-multiply and unpremultiply are requested, then perform no
    181   // alpha manipulation.
    182   if (premultiply_alpha && unpremultiply_alpha) {
    183     premultiply_alpha = false;
    184     unpremultiply_alpha = false;
    185   }
    186 
    187   // bit 0: Flip_y
    188   // bit 1: Premult
    189   // bit 2: Unpremult
    190   // bit 3: External_oes
    191   static ProgramId program_ids[] = {
    192     PROGRAM_COPY_TEXTURE,
    193     PROGRAM_COPY_TEXTURE_FLIP_Y,                         // F
    194     PROGRAM_COPY_TEXTURE_PREMULTIPLY_ALPHA,              //   P
    195     PROGRAM_COPY_TEXTURE_PREMULTIPLY_ALPHA_FLIPY,        // F P
    196     PROGRAM_COPY_TEXTURE_UNPREMULTIPLY_ALPHA,            //     U
    197     PROGRAM_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_FLIPY,      // F   U
    198     PROGRAM_COPY_TEXTURE,                                //   P U
    199     PROGRAM_COPY_TEXTURE,                                // F P U
    200     PROGRAM_COPY_TEXTURE_OES,                            //       E
    201     PROGRAM_COPY_TEXTURE_OES_FLIP_Y,                     // F     E
    202     PROGRAM_COPY_TEXTURE_OES_PREMULTIPLY_ALPHA,          //   P   E
    203     PROGRAM_COPY_TEXTURE_OES_PREMULTIPLY_ALPHA_FLIPY,    // F P   E
    204     PROGRAM_COPY_TEXTURE_OES_UNPREMULTIPLY_ALPHA,        //     U E
    205     PROGRAM_COPY_TEXTURE_OES_UNPREMULTIPLY_ALPHA_FLIPY,  // F   U E
    206     PROGRAM_COPY_TEXTURE_OES,                            //   P U E
    207     PROGRAM_COPY_TEXTURE_OES,                            // F P U E
    208   };
    209 
    210   unsigned index = (flip_y                 ? (1 << 0) : 0) |
    211                    (premultiply_alpha      ? (1 << 1) : 0) |
    212                    (unpremultiply_alpha    ? (1 << 2) : 0) |
    213                    (is_source_external_oes ? (1 << 3) : 0);
    214   return program_ids[index];
    215 }
    216 
    217 }  // namespace
    218 
    219 namespace gpu {
    220 
    221 CopyTextureCHROMIUMResourceManager::CopyTextureCHROMIUMResourceManager()
    222   : initialized_(false),
    223     buffer_id_(0),
    224     framebuffer_(0) {
    225   for (int i = 0; i < kNumPrograms; ++i) {
    226     programs_[i] = 0;
    227     matrix_handle_[i] = 0;
    228     sampler_locations_[i] = 0;
    229   }
    230 }
    231 
    232 void CopyTextureCHROMIUMResourceManager::Initialize(
    233     const gles2::GLES2Decoder* decoder) {
    234   COMPILE_ASSERT(
    235       kVertexPositionAttrib == 0u,
    236       Position_attribs_must_be_0);
    237 
    238   const char* extensions =
    239       reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
    240   bool have_egl_image_external = extensions &&
    241       strstr(extensions, "GL_OES_EGL_image_external");
    242 
    243   // Initialize all of the GPU resources required to perform the copy.
    244   glGenBuffersARB(1, &buffer_id_);
    245   glBindBuffer(GL_ARRAY_BUFFER, buffer_id_);
    246   glBufferData(GL_ARRAY_BUFFER, sizeof(kQuadVertices), kQuadVertices,
    247                GL_STATIC_DRAW);
    248 
    249   glGenFramebuffersEXT(1, &framebuffer_);
    250 
    251   // TODO(gman): Init these on demand.
    252   GLuint shaders[kNumShaders];
    253   for (int shader = 0; shader < kNumShaders; ++shader) {
    254     shaders[shader] = glCreateShader(
    255         shader == 0 ? GL_VERTEX_SHADER : GL_FRAGMENT_SHADER);
    256     const ShaderInfo& info = shader_infos[shader];
    257     if (info.needs_egl_image_external && !have_egl_image_external) {
    258       continue;
    259     }
    260     const char* shader_source = shader_infos[shader].source;
    261     glShaderSource(shaders[shader], 1, &shader_source, 0);
    262     glCompileShader(shaders[shader]);
    263 #ifndef NDEBUG
    264     GLint compile_status;
    265     glGetShaderiv(shaders[shader], GL_COMPILE_STATUS, &compile_status);
    266     if (GL_TRUE != compile_status)
    267       DLOG(ERROR) << "CopyTextureCHROMIUM: shader compilation failure.";
    268 #endif
    269   }
    270 
    271   // TODO(gman): Init these on demand.
    272   for (int program = 0; program < kNumPrograms; ++program) {
    273     const ShaderInfo& info = shader_infos[program + 1];
    274     if (info.needs_egl_image_external && !have_egl_image_external) {
    275       continue;
    276     }
    277     programs_[program] = glCreateProgram();
    278     glAttachShader(programs_[program], shaders[0]);
    279     glAttachShader(programs_[program], shaders[program + 1]);
    280 
    281     glBindAttribLocation(programs_[program], kVertexPositionAttrib,
    282                          "a_position");
    283 
    284     glLinkProgram(programs_[program]);
    285 #ifndef NDEBUG
    286     GLint linked;
    287     glGetProgramiv(programs_[program], GL_LINK_STATUS, &linked);
    288     if (!linked)
    289       DLOG(ERROR) << "CopyTextureCHROMIUM: program link failure.";
    290 #endif
    291 
    292     sampler_locations_[program] = glGetUniformLocation(programs_[program],
    293                                                       "u_texSampler");
    294 
    295     matrix_handle_[program] = glGetUniformLocation(programs_[program],
    296                                                    "u_matrix");
    297   }
    298 
    299   for (int shader = 0; shader < kNumShaders; ++shader)
    300     glDeleteShader(shaders[shader]);
    301 
    302   decoder->RestoreBufferBindings();
    303 
    304   initialized_ = true;
    305 }
    306 
    307 void CopyTextureCHROMIUMResourceManager::Destroy() {
    308   if (!initialized_)
    309     return;
    310 
    311   glDeleteFramebuffersEXT(1, &framebuffer_);
    312 
    313   for (int program = 0; program < kNumPrograms; ++program) {
    314     if (programs_[program])
    315       glDeleteProgram(programs_[program]);
    316   }
    317 
    318   glDeleteBuffersARB(1, &buffer_id_);
    319 }
    320 
    321 void CopyTextureCHROMIUMResourceManager::DoCopyTexture(
    322     const gles2::GLES2Decoder* decoder,
    323     GLenum source_target,
    324     GLenum dest_target,
    325     GLuint source_id,
    326     GLuint dest_id,
    327     GLint level,
    328     GLsizei width,
    329     GLsizei height,
    330     bool flip_y,
    331     bool premultiply_alpha,
    332     bool unpremultiply_alpha) {
    333   // Use default transform matrix if no transform passed in.
    334   const static GLfloat default_matrix[16] = {1.0f, 0.0f, 0.0f, 0.0f,
    335                                              0.0f, 1.0f, 0.0f, 0.0f,
    336                                              0.0f, 0.0f, 1.0f, 0.0f,
    337                                              0.0f, 0.0f, 0.0f, 1.0f};
    338   DoCopyTextureWithTransform(decoder, source_target, dest_target, source_id,
    339       dest_id, level, width, height, flip_y, premultiply_alpha,
    340       unpremultiply_alpha, default_matrix);
    341 }
    342 
    343 void CopyTextureCHROMIUMResourceManager::DoCopyTextureWithTransform(
    344     const gles2::GLES2Decoder* decoder,
    345     GLenum source_target,
    346     GLenum dest_target,
    347     GLuint source_id,
    348     GLuint dest_id,
    349     GLint level,
    350     GLsizei width,
    351     GLsizei height,
    352     bool flip_y,
    353     bool premultiply_alpha,
    354     bool unpremultiply_alpha,
    355     const GLfloat transform_matrix[16]) {
    356   DCHECK(source_target == GL_TEXTURE_2D ||
    357          source_target == GL_TEXTURE_EXTERNAL_OES);
    358   if (!initialized_) {
    359     DLOG(ERROR) << "CopyTextureCHROMIUM: Uninitialized manager.";
    360     return;
    361   }
    362 
    363   GLuint program = GetProgram(
    364       flip_y, premultiply_alpha, unpremultiply_alpha,
    365       source_target == GL_TEXTURE_EXTERNAL_OES);
    366   glUseProgram(programs_[program]);
    367 
    368 #ifndef NDEBUG
    369   glValidateProgram(programs_[program]);
    370   GLint validation_status;
    371   glGetProgramiv(programs_[program], GL_VALIDATE_STATUS, &validation_status);
    372   if (GL_TRUE != validation_status) {
    373     DLOG(ERROR) << "CopyTextureCHROMIUM: Invalid shader.";
    374     return;
    375   }
    376 #endif
    377 
    378   glUniformMatrix4fv(matrix_handle_[program], 1, GL_FALSE, transform_matrix);
    379   glActiveTexture(GL_TEXTURE0);
    380   glBindTexture(GL_TEXTURE_2D, dest_id);
    381   // NVidia drivers require texture settings to be a certain way
    382   // or they won't report FRAMEBUFFER_COMPLETE.
    383   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    384   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    385   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    386   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    387   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer_);
    388   glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dest_target,
    389                             dest_id, level);
    390 
    391 #ifndef NDEBUG
    392   GLenum fb_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER);
    393   if (GL_FRAMEBUFFER_COMPLETE != fb_status) {
    394     DLOG(ERROR) << "CopyTextureCHROMIUM: Incomplete framebuffer.";
    395   } else
    396 #endif
    397   {
    398     glEnableVertexAttribArray(kVertexPositionAttrib);
    399 
    400     glBindBuffer(GL_ARRAY_BUFFER, buffer_id_);
    401     glVertexAttribPointer(kVertexPositionAttrib, 4, GL_FLOAT, GL_FALSE,
    402                           4 * sizeof(GLfloat), 0);
    403 
    404     glUniform1i(sampler_locations_[program], 0);
    405 
    406     glBindTexture(source_target, source_id);
    407     glTexParameterf(source_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    408     glTexParameterf(source_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    409     glTexParameteri(source_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    410     glTexParameteri(source_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    411 
    412     glDisable(GL_DEPTH_TEST);
    413     glDisable(GL_SCISSOR_TEST);
    414     glDisable(GL_STENCIL_TEST);
    415     glDisable(GL_CULL_FACE);
    416     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
    417     glDepthMask(GL_FALSE);
    418     glDisable(GL_BLEND);
    419 
    420     glViewport(0, 0, width, height);
    421     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
    422   }
    423 
    424   decoder->RestoreAttribute(kVertexPositionAttrib);
    425   decoder->RestoreTextureState(source_id);
    426   decoder->RestoreTextureState(dest_id);
    427   decoder->RestoreTextureUnitBindings(0);
    428   decoder->RestoreActiveTexture();
    429   decoder->RestoreProgramBindings();
    430   decoder->RestoreBufferBindings();
    431   decoder->RestoreFramebufferBindings();
    432   decoder->RestoreGlobalState();
    433 }
    434 
    435 }  // namespace
    436 
    437