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 <algorithm> 8 9 #include "base/basictypes.h" 10 #include "gpu/command_buffer/service/gl_utils.h" 11 #include "gpu/command_buffer/service/gles2_cmd_decoder.h" 12 13 #define SHADER(src) \ 14 "#ifdef GL_ES\n" \ 15 "precision mediump float;\n" \ 16 "#define TexCoordPrecision mediump\n" \ 17 "#else\n" \ 18 "#define TexCoordPrecision\n" \ 19 "#endif\n" #src 20 #define SHADER_2D(src) \ 21 "#define SamplerType sampler2D\n" \ 22 "#define TextureLookup texture2D\n" SHADER(src) 23 #define SHADER_RECTANGLE_ARB(src) \ 24 "#define SamplerType samplerRect\n" \ 25 "#define TextureLookup textureRect\n" SHADER(src) 26 #define SHADER_EXTERNAL_OES(src) \ 27 "#extension GL_OES_EGL_image_external : require\n" \ 28 "#define SamplerType samplerExternalOES\n" \ 29 "#define TextureLookup texture2D\n" SHADER(src) 30 #define FRAGMENT_SHADERS(src) \ 31 SHADER_2D(src), SHADER_RECTANGLE_ARB(src), SHADER_EXTERNAL_OES(src) 32 33 namespace { 34 35 enum VertexShaderId { 36 VERTEX_SHADER_COPY_TEXTURE, 37 VERTEX_SHADER_COPY_TEXTURE_FLIP_Y, 38 NUM_VERTEX_SHADERS, 39 }; 40 41 enum FragmentShaderId { 42 FRAGMENT_SHADER_COPY_TEXTURE_2D, 43 FRAGMENT_SHADER_COPY_TEXTURE_RECTANGLE_ARB, 44 FRAGMENT_SHADER_COPY_TEXTURE_EXTERNAL_OES, 45 FRAGMENT_SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_2D, 46 FRAGMENT_SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_RECTANGLE_ARB, 47 FRAGMENT_SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_EXTERNAL_OES, 48 FRAGMENT_SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_2D, 49 FRAGMENT_SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_RECTANGLE_ARB, 50 FRAGMENT_SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_EXTERNAL_OES, 51 NUM_FRAGMENT_SHADERS, 52 }; 53 54 const char* vertex_shader_source[NUM_VERTEX_SHADERS] = { 55 // VERTEX_SHADER_COPY_TEXTURE 56 SHADER( 57 uniform mat4 u_matrix; 58 uniform vec2 u_half_size; 59 attribute vec4 a_position; 60 varying TexCoordPrecision vec2 v_uv; 61 void main(void) { 62 gl_Position = u_matrix * a_position; 63 v_uv = a_position.xy * vec2(u_half_size.s, u_half_size.t) + 64 vec2(u_half_size.s, u_half_size.t); 65 }), 66 // VERTEX_SHADER_COPY_TEXTURE_FLIP_Y 67 SHADER( 68 uniform mat4 u_matrix; 69 uniform vec2 u_half_size; 70 attribute vec4 a_position; 71 varying TexCoordPrecision vec2 v_uv; 72 void main(void) { 73 gl_Position = u_matrix * a_position; 74 v_uv = a_position.xy * vec2(u_half_size.s, -u_half_size.t) + 75 vec2(u_half_size.s, u_half_size.t); 76 }), 77 }; 78 79 const char* fragment_shader_source[NUM_FRAGMENT_SHADERS] = { 80 // FRAGMENT_SHADER_COPY_TEXTURE_* 81 FRAGMENT_SHADERS( 82 uniform SamplerType u_sampler; 83 varying TexCoordPrecision vec2 v_uv; 84 void main(void) { 85 gl_FragColor = TextureLookup(u_sampler, v_uv.st); 86 }), 87 // FRAGMENT_SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_* 88 FRAGMENT_SHADERS( 89 uniform SamplerType u_sampler; 90 varying TexCoordPrecision vec2 v_uv; 91 void main(void) { 92 gl_FragColor = TextureLookup(u_sampler, v_uv.st); 93 gl_FragColor.rgb *= gl_FragColor.a; 94 }), 95 // FRAGMENT_SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_* 96 FRAGMENT_SHADERS( 97 uniform SamplerType u_sampler; 98 varying TexCoordPrecision vec2 v_uv; 99 void main(void) { 100 gl_FragColor = TextureLookup(u_sampler, v_uv.st); 101 if (gl_FragColor.a > 0.0) 102 gl_FragColor.rgb /= gl_FragColor.a; 103 }), 104 }; 105 106 // Returns the correct vertex shader id to evaluate the copy operation for 107 // the CHROMIUM_flipy setting. 108 VertexShaderId GetVertexShaderId(bool flip_y) { 109 // bit 0: flip y 110 static VertexShaderId shader_ids[] = { 111 VERTEX_SHADER_COPY_TEXTURE, 112 VERTEX_SHADER_COPY_TEXTURE_FLIP_Y, 113 }; 114 115 unsigned index = flip_y ? 1 : 0; 116 return shader_ids[index]; 117 } 118 119 // Returns the correct fragment shader id to evaluate the copy operation for 120 // the premultiply alpha pixel store settings and target. 121 FragmentShaderId GetFragmentShaderId(bool premultiply_alpha, 122 bool unpremultiply_alpha, 123 GLenum target) { 124 enum { 125 SAMPLER_2D, 126 SAMPLER_RECTANGLE_ARB, 127 SAMPLER_EXTERNAL_OES, 128 NUM_SAMPLERS 129 }; 130 131 // bit 0: premultiply alpha 132 // bit 1: unpremultiply alpha 133 static FragmentShaderId shader_ids[][NUM_SAMPLERS] = { 134 { 135 FRAGMENT_SHADER_COPY_TEXTURE_2D, 136 FRAGMENT_SHADER_COPY_TEXTURE_RECTANGLE_ARB, 137 FRAGMENT_SHADER_COPY_TEXTURE_EXTERNAL_OES, 138 }, 139 { 140 FRAGMENT_SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_2D, 141 FRAGMENT_SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_RECTANGLE_ARB, 142 FRAGMENT_SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_EXTERNAL_OES, 143 }, 144 { 145 FRAGMENT_SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_2D, 146 FRAGMENT_SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_RECTANGLE_ARB, 147 FRAGMENT_SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_EXTERNAL_OES, 148 }, 149 { 150 FRAGMENT_SHADER_COPY_TEXTURE_2D, 151 FRAGMENT_SHADER_COPY_TEXTURE_RECTANGLE_ARB, 152 FRAGMENT_SHADER_COPY_TEXTURE_EXTERNAL_OES, 153 }}; 154 155 unsigned index = (premultiply_alpha ? (1 << 0) : 0) | 156 (unpremultiply_alpha ? (1 << 1) : 0); 157 158 switch (target) { 159 case GL_TEXTURE_2D: 160 return shader_ids[index][SAMPLER_2D]; 161 case GL_TEXTURE_RECTANGLE_ARB: 162 return shader_ids[index][SAMPLER_RECTANGLE_ARB]; 163 case GL_TEXTURE_EXTERNAL_OES: 164 return shader_ids[index][SAMPLER_EXTERNAL_OES]; 165 default: 166 break; 167 } 168 169 NOTREACHED(); 170 return shader_ids[index][SAMPLER_2D]; 171 } 172 173 void CompileShader(GLuint shader, const char* shader_source) { 174 glShaderSource(shader, 1, &shader_source, 0); 175 glCompileShader(shader); 176 #ifndef NDEBUG 177 GLint compile_status; 178 glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status); 179 if (GL_TRUE != compile_status) 180 DLOG(ERROR) << "CopyTextureCHROMIUM: shader compilation failure."; 181 #endif 182 } 183 184 void DeleteShader(GLuint shader) { 185 if (shader) 186 glDeleteShader(shader); 187 } 188 189 } // namespace 190 191 namespace gpu { 192 193 CopyTextureCHROMIUMResourceManager::CopyTextureCHROMIUMResourceManager() 194 : initialized_(false), 195 vertex_shaders_(NUM_VERTEX_SHADERS, 0u), 196 fragment_shaders_(NUM_FRAGMENT_SHADERS, 0u), 197 buffer_id_(0u), 198 framebuffer_(0u) {} 199 200 CopyTextureCHROMIUMResourceManager::~CopyTextureCHROMIUMResourceManager() {} 201 202 void CopyTextureCHROMIUMResourceManager::Initialize( 203 const gles2::GLES2Decoder* decoder) { 204 COMPILE_ASSERT( 205 kVertexPositionAttrib == 0u, 206 Position_attribs_must_be_0); 207 208 // Initialize all of the GPU resources required to perform the copy. 209 glGenBuffersARB(1, &buffer_id_); 210 glBindBuffer(GL_ARRAY_BUFFER, buffer_id_); 211 const GLfloat kQuadVertices[] = {-1.0f, -1.0f, 212 1.0f, -1.0f, 213 1.0f, 1.0f, 214 -1.0f, 1.0f}; 215 glBufferData( 216 GL_ARRAY_BUFFER, sizeof(kQuadVertices), kQuadVertices, GL_STATIC_DRAW); 217 218 glGenFramebuffersEXT(1, &framebuffer_); 219 220 decoder->RestoreBufferBindings(); 221 222 initialized_ = true; 223 } 224 225 void CopyTextureCHROMIUMResourceManager::Destroy() { 226 if (!initialized_) 227 return; 228 229 glDeleteFramebuffersEXT(1, &framebuffer_); 230 231 std::for_each(vertex_shaders_.begin(), vertex_shaders_.end(), DeleteShader); 232 std::for_each( 233 fragment_shaders_.begin(), fragment_shaders_.end(), DeleteShader); 234 235 for (ProgramMap::const_iterator it = programs_.begin(); it != programs_.end(); 236 ++it) { 237 const ProgramInfo& info = it->second; 238 glDeleteProgram(info.program); 239 } 240 241 glDeleteBuffersARB(1, &buffer_id_); 242 } 243 244 void CopyTextureCHROMIUMResourceManager::DoCopyTexture( 245 const gles2::GLES2Decoder* decoder, 246 GLenum source_target, 247 GLenum dest_target, 248 GLuint source_id, 249 GLuint dest_id, 250 GLint level, 251 GLsizei width, 252 GLsizei height, 253 bool flip_y, 254 bool premultiply_alpha, 255 bool unpremultiply_alpha) { 256 // Use default transform matrix if no transform passed in. 257 const static GLfloat default_matrix[16] = {1.0f, 0.0f, 0.0f, 0.0f, 258 0.0f, 1.0f, 0.0f, 0.0f, 259 0.0f, 0.0f, 1.0f, 0.0f, 260 0.0f, 0.0f, 0.0f, 1.0f}; 261 DoCopyTextureWithTransform(decoder, source_target, dest_target, source_id, 262 dest_id, level, width, height, flip_y, premultiply_alpha, 263 unpremultiply_alpha, default_matrix); 264 } 265 266 void CopyTextureCHROMIUMResourceManager::DoCopyTextureWithTransform( 267 const gles2::GLES2Decoder* decoder, 268 GLenum source_target, 269 GLenum dest_target, 270 GLuint source_id, 271 GLuint dest_id, 272 GLint level, 273 GLsizei width, 274 GLsizei height, 275 bool flip_y, 276 bool premultiply_alpha, 277 bool unpremultiply_alpha, 278 const GLfloat transform_matrix[16]) { 279 DCHECK(source_target == GL_TEXTURE_2D || 280 source_target == GL_TEXTURE_RECTANGLE_ARB || 281 source_target == GL_TEXTURE_EXTERNAL_OES); 282 if (!initialized_) { 283 DLOG(ERROR) << "CopyTextureCHROMIUM: Uninitialized manager."; 284 return; 285 } 286 287 VertexShaderId vertex_shader_id = GetVertexShaderId(flip_y); 288 DCHECK_LT(static_cast<size_t>(vertex_shader_id), vertex_shaders_.size()); 289 GLuint* vertex_shader = &vertex_shaders_[vertex_shader_id]; 290 if (!*vertex_shader) { 291 *vertex_shader = glCreateShader(GL_VERTEX_SHADER); 292 CompileShader(*vertex_shader, vertex_shader_source[vertex_shader_id]); 293 } 294 295 FragmentShaderId fragment_shader_id = GetFragmentShaderId( 296 premultiply_alpha, unpremultiply_alpha, source_target); 297 DCHECK_LT(static_cast<size_t>(fragment_shader_id), fragment_shaders_.size()); 298 GLuint* fragment_shader = &fragment_shaders_[fragment_shader_id]; 299 if (!*fragment_shader) { 300 *fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); 301 CompileShader(*fragment_shader, fragment_shader_source[fragment_shader_id]); 302 } 303 304 ProgramMapKey key(vertex_shader_id, fragment_shader_id); 305 ProgramInfo* info = &programs_[key]; 306 // Create program if necessary. 307 if (!info->program) { 308 info->program = glCreateProgram(); 309 glAttachShader(info->program, *vertex_shader); 310 glAttachShader(info->program, *fragment_shader); 311 glBindAttribLocation(info->program, kVertexPositionAttrib, "a_position"); 312 glLinkProgram(info->program); 313 #ifndef NDEBUG 314 GLint linked; 315 glGetProgramiv(info->program, GL_LINK_STATUS, &linked); 316 if (!linked) 317 DLOG(ERROR) << "CopyTextureCHROMIUM: program link failure."; 318 #endif 319 info->matrix_handle = glGetUniformLocation(info->program, "u_matrix"); 320 info->half_size_handle = glGetUniformLocation(info->program, "u_half_size"); 321 info->sampler_handle = glGetUniformLocation(info->program, "u_sampler"); 322 } 323 glUseProgram(info->program); 324 325 #ifndef NDEBUG 326 glValidateProgram(info->program); 327 GLint validation_status; 328 glGetProgramiv(info->program, GL_VALIDATE_STATUS, &validation_status); 329 if (GL_TRUE != validation_status) { 330 DLOG(ERROR) << "CopyTextureCHROMIUM: Invalid shader."; 331 return; 332 } 333 #endif 334 335 glUniformMatrix4fv(info->matrix_handle, 1, GL_FALSE, transform_matrix); 336 if (source_target == GL_TEXTURE_RECTANGLE_ARB) 337 glUniform2f(info->half_size_handle, width / 2.0f, height / 2.0f); 338 else 339 glUniform2f(info->half_size_handle, 0.5f, 0.5f); 340 glActiveTexture(GL_TEXTURE0); 341 glBindTexture(GL_TEXTURE_2D, dest_id); 342 // NVidia drivers require texture settings to be a certain way 343 // or they won't report FRAMEBUFFER_COMPLETE. 344 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 345 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 346 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 347 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 348 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer_); 349 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dest_target, 350 dest_id, level); 351 352 #ifndef NDEBUG 353 GLenum fb_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER); 354 if (GL_FRAMEBUFFER_COMPLETE != fb_status) { 355 DLOG(ERROR) << "CopyTextureCHROMIUM: Incomplete framebuffer."; 356 } else 357 #endif 358 { 359 decoder->ClearAllAttributes(); 360 glEnableVertexAttribArray(kVertexPositionAttrib); 361 362 glBindBuffer(GL_ARRAY_BUFFER, buffer_id_); 363 glVertexAttribPointer(kVertexPositionAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0); 364 365 glUniform1i(info->sampler_handle, 0); 366 367 glBindTexture(source_target, source_id); 368 glTexParameterf(source_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 369 glTexParameterf(source_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 370 glTexParameteri(source_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 371 glTexParameteri(source_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 372 373 glDisable(GL_DEPTH_TEST); 374 glDisable(GL_SCISSOR_TEST); 375 glDisable(GL_STENCIL_TEST); 376 glDisable(GL_CULL_FACE); 377 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 378 glDepthMask(GL_FALSE); 379 glDisable(GL_BLEND); 380 381 glViewport(0, 0, width, height); 382 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 383 } 384 385 decoder->RestoreAllAttributes(); 386 decoder->RestoreTextureState(source_id); 387 decoder->RestoreTextureState(dest_id); 388 decoder->RestoreTextureUnitBindings(0); 389 decoder->RestoreActiveTexture(); 390 decoder->RestoreProgramBindings(); 391 decoder->RestoreBufferBindings(); 392 decoder->RestoreFramebufferBindings(); 393 decoder->RestoreGlobalState(); 394 } 395 396 } // namespace gpu 397