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