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.
5 #include "gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h"
9 #include "base/basictypes.h"
10 #include "gpu/command_buffer/service/gl_utils.h"
11 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
15 "precision mediump float;\n" \
16 "#define TexCoordPrecision mediump\n" \
18 "#define TexCoordPrecision\n" \
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 sampler2DRect\n" \
25 "#define TextureLookup texture2DRect\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)
36 VERTEX_SHADER_COPY_TEXTURE
,
37 VERTEX_SHADER_COPY_TEXTURE_FLIP_Y
,
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
,
54 const char* vertex_shader_source
[NUM_VERTEX_SHADERS
] = {
55 // VERTEX_SHADER_COPY_TEXTURE
57 uniform mat4 u_matrix
;
58 uniform vec2 u_half_size
;
59 attribute vec4 a_position
;
60 varying TexCoordPrecision vec2 v_uv
;
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
);
66 // VERTEX_SHADER_COPY_TEXTURE_FLIP_Y
68 uniform mat4 u_matrix
;
69 uniform vec2 u_half_size
;
70 attribute vec4 a_position
;
71 varying TexCoordPrecision vec2 v_uv
;
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
);
79 const char* fragment_shader_source
[NUM_FRAGMENT_SHADERS
] = {
80 // FRAGMENT_SHADER_COPY_TEXTURE_*
82 uniform SamplerType u_sampler
;
83 varying TexCoordPrecision vec2 v_uv
;
85 gl_FragColor
= TextureLookup(u_sampler
, v_uv
.st
);
87 // FRAGMENT_SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_*
89 uniform SamplerType u_sampler
;
90 varying TexCoordPrecision vec2 v_uv
;
92 gl_FragColor
= TextureLookup(u_sampler
, v_uv
.st
);
93 gl_FragColor
.rgb
*= gl_FragColor
.a
;
95 // FRAGMENT_SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_*
97 uniform SamplerType u_sampler
;
98 varying TexCoordPrecision vec2 v_uv
;
100 gl_FragColor
= TextureLookup(u_sampler
, v_uv
.st
);
101 if (gl_FragColor
.a
> 0.0)
102 gl_FragColor
.rgb
/= gl_FragColor
.a
;
106 // Returns the correct vertex shader id to evaluate the copy operation for
107 // the CHROMIUM_flipy setting.
108 VertexShaderId
GetVertexShaderId(bool flip_y
) {
110 static VertexShaderId shader_ids
[] = {
111 VERTEX_SHADER_COPY_TEXTURE
,
112 VERTEX_SHADER_COPY_TEXTURE_FLIP_Y
,
115 unsigned index
= flip_y
? 1 : 0;
116 return shader_ids
[index
];
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
,
126 SAMPLER_RECTANGLE_ARB
,
127 SAMPLER_EXTERNAL_OES
,
131 // bit 0: premultiply alpha
132 // bit 1: unpremultiply alpha
133 static FragmentShaderId shader_ids
[][NUM_SAMPLERS
] = {
135 FRAGMENT_SHADER_COPY_TEXTURE_2D
,
136 FRAGMENT_SHADER_COPY_TEXTURE_RECTANGLE_ARB
,
137 FRAGMENT_SHADER_COPY_TEXTURE_EXTERNAL_OES
,
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
,
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
,
150 FRAGMENT_SHADER_COPY_TEXTURE_2D
,
151 FRAGMENT_SHADER_COPY_TEXTURE_RECTANGLE_ARB
,
152 FRAGMENT_SHADER_COPY_TEXTURE_EXTERNAL_OES
,
155 unsigned index
= (premultiply_alpha
? (1 << 0) : 0) |
156 (unpremultiply_alpha
? (1 << 1) : 0);
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
];
170 return shader_ids
[0][SAMPLER_2D
];
173 void CompileShader(GLuint shader
, const char* shader_source
) {
174 glShaderSource(shader
, 1, &shader_source
, 0);
175 glCompileShader(shader
);
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.";
184 void DeleteShader(GLuint shader
) {
186 glDeleteShader(shader
);
189 bool BindFramebufferTexture2D(GLenum target
,
192 GLuint framebuffer
) {
193 DCHECK(target
== GL_TEXTURE_2D
|| target
== GL_TEXTURE_RECTANGLE_ARB
);
194 glActiveTexture(GL_TEXTURE0
);
195 glBindTexture(target
, texture_id
);
196 // NVidia drivers require texture settings to be a certain way
197 // or they won't report FRAMEBUFFER_COMPLETE.
198 glTexParameterf(target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
199 glTexParameterf(target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
200 glTexParameteri(target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
201 glTexParameteri(target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
202 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, framebuffer
);
203 glFramebufferTexture2DEXT(
204 GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
, target
, texture_id
, level
);
207 GLenum fb_status
= glCheckFramebufferStatusEXT(GL_FRAMEBUFFER
);
208 if (GL_FRAMEBUFFER_COMPLETE
!= fb_status
) {
209 DLOG(ERROR
) << "CopyTextureCHROMIUM: Incomplete framebuffer.";
216 void DoCopyTexImage2D(const gpu::gles2::GLES2Decoder
* decoder
,
217 GLenum source_target
,
221 GLenum dest_internal_format
,
224 GLuint framebuffer
) {
225 DCHECK(source_target
== GL_TEXTURE_2D
||
226 source_target
== GL_TEXTURE_RECTANGLE_ARB
);
227 if (BindFramebufferTexture2D(
228 source_target
, source_id
, 0 /* level */, framebuffer
)) {
229 glBindTexture(GL_TEXTURE_2D
, dest_id
);
230 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
231 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
232 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
233 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
234 glCopyTexImage2D(GL_TEXTURE_2D
,
236 dest_internal_format
,
244 decoder
->RestoreTextureState(source_id
);
245 decoder
->RestoreTextureState(dest_id
);
246 decoder
->RestoreTextureUnitBindings(0);
247 decoder
->RestoreActiveTexture();
248 decoder
->RestoreFramebufferBindings();
255 CopyTextureCHROMIUMResourceManager::CopyTextureCHROMIUMResourceManager()
256 : initialized_(false),
257 vertex_shaders_(NUM_VERTEX_SHADERS
, 0u),
258 fragment_shaders_(NUM_FRAGMENT_SHADERS
, 0u),
262 CopyTextureCHROMIUMResourceManager::~CopyTextureCHROMIUMResourceManager() {
263 // |buffer_id_| and |framebuffer_| can be not-null because when GPU context is
264 // lost, this class can be deleted without releasing resources like
268 void CopyTextureCHROMIUMResourceManager::Initialize(
269 const gles2::GLES2Decoder
* decoder
) {
271 kVertexPositionAttrib
== 0u,
272 "kVertexPositionAttrib must be 0");
274 DCHECK(!framebuffer_
);
275 DCHECK(programs_
.empty());
277 // Initialize all of the GPU resources required to perform the copy.
278 glGenBuffersARB(1, &buffer_id_
);
279 glBindBuffer(GL_ARRAY_BUFFER
, buffer_id_
);
280 const GLfloat kQuadVertices
[] = {-1.0f
, -1.0f
,
285 GL_ARRAY_BUFFER
, sizeof(kQuadVertices
), kQuadVertices
, GL_STATIC_DRAW
);
287 glGenFramebuffersEXT(1, &framebuffer_
);
289 decoder
->RestoreBufferBindings();
294 void CopyTextureCHROMIUMResourceManager::Destroy() {
298 glDeleteFramebuffersEXT(1, &framebuffer_
);
301 std::for_each(vertex_shaders_
.begin(), vertex_shaders_
.end(), DeleteShader
);
303 fragment_shaders_
.begin(), fragment_shaders_
.end(), DeleteShader
);
305 for (ProgramMap::const_iterator it
= programs_
.begin(); it
!= programs_
.end();
307 const ProgramInfo
& info
= it
->second
;
308 glDeleteProgram(info
.program
);
311 glDeleteBuffersARB(1, &buffer_id_
);
315 void CopyTextureCHROMIUMResourceManager::DoCopyTexture(
316 const gles2::GLES2Decoder
* decoder
,
317 GLenum source_target
,
319 GLenum source_internal_format
,
322 GLenum dest_internal_format
,
326 bool premultiply_alpha
,
327 bool unpremultiply_alpha
) {
328 bool premultiply_alpha_change
= premultiply_alpha
^ unpremultiply_alpha
;
329 // GL_INVALID_OPERATION is generated if the currently bound framebuffer's
330 // format does not contain a superset of the components required by the base
331 // format of internalformat.
332 // https://www.khronos.org/opengles/sdk/docs/man/xhtml/glCopyTexImage2D.xml
333 bool source_format_contain_superset_of_dest_format
=
334 (source_internal_format
== dest_internal_format
&&
335 source_internal_format
!= GL_BGRA_EXT
) ||
336 (source_internal_format
== GL_RGBA
&& dest_internal_format
== GL_RGB
);
337 // GL_TEXTURE_RECTANGLE_ARB on FBO is supported by OpenGL, not GLES2,
338 // so restrict this to GL_TEXTURE_2D.
339 if (source_target
== GL_TEXTURE_2D
&& !flip_y
&& !premultiply_alpha_change
&&
340 source_format_contain_superset_of_dest_format
) {
341 DoCopyTexImage2D(decoder
,
346 dest_internal_format
,
353 // Use default transform matrix if no transform passed in.
354 const static GLfloat default_matrix
[16] = {1.0f
, 0.0f
, 0.0f
, 0.0f
,
355 0.0f
, 1.0f
, 0.0f
, 0.0f
,
356 0.0f
, 0.0f
, 1.0f
, 0.0f
,
357 0.0f
, 0.0f
, 0.0f
, 1.0f
};
358 DoCopyTextureWithTransform(decoder
,
371 void CopyTextureCHROMIUMResourceManager::DoCopyTextureWithTransform(
372 const gles2::GLES2Decoder
* decoder
,
373 GLenum source_target
,
380 bool premultiply_alpha
,
381 bool unpremultiply_alpha
,
382 const GLfloat transform_matrix
[16]) {
383 DCHECK(source_target
== GL_TEXTURE_2D
||
384 source_target
== GL_TEXTURE_RECTANGLE_ARB
||
385 source_target
== GL_TEXTURE_EXTERNAL_OES
);
387 DLOG(ERROR
) << "CopyTextureCHROMIUM: Uninitialized manager.";
391 VertexShaderId vertex_shader_id
= GetVertexShaderId(flip_y
);
392 DCHECK_LT(static_cast<size_t>(vertex_shader_id
), vertex_shaders_
.size());
393 FragmentShaderId fragment_shader_id
= GetFragmentShaderId(
394 premultiply_alpha
, unpremultiply_alpha
, source_target
);
395 DCHECK_LT(static_cast<size_t>(fragment_shader_id
), fragment_shaders_
.size());
397 ProgramMapKey
key(vertex_shader_id
, fragment_shader_id
);
398 ProgramInfo
* info
= &programs_
[key
];
399 // Create program if necessary.
400 if (!info
->program
) {
401 info
->program
= glCreateProgram();
402 GLuint
* vertex_shader
= &vertex_shaders_
[vertex_shader_id
];
403 if (!*vertex_shader
) {
404 *vertex_shader
= glCreateShader(GL_VERTEX_SHADER
);
405 CompileShader(*vertex_shader
, vertex_shader_source
[vertex_shader_id
]);
407 glAttachShader(info
->program
, *vertex_shader
);
408 GLuint
* fragment_shader
= &fragment_shaders_
[fragment_shader_id
];
409 if (!*fragment_shader
) {
410 *fragment_shader
= glCreateShader(GL_FRAGMENT_SHADER
);
411 CompileShader(*fragment_shader
,
412 fragment_shader_source
[fragment_shader_id
]);
414 glAttachShader(info
->program
, *fragment_shader
);
415 glBindAttribLocation(info
->program
, kVertexPositionAttrib
, "a_position");
416 glLinkProgram(info
->program
);
419 glGetProgramiv(info
->program
, GL_LINK_STATUS
, &linked
);
421 DLOG(ERROR
) << "CopyTextureCHROMIUM: program link failure.";
423 info
->matrix_handle
= glGetUniformLocation(info
->program
, "u_matrix");
424 info
->half_size_handle
= glGetUniformLocation(info
->program
, "u_half_size");
425 info
->sampler_handle
= glGetUniformLocation(info
->program
, "u_sampler");
427 glUseProgram(info
->program
);
430 glValidateProgram(info
->program
);
431 GLint validation_status
;
432 glGetProgramiv(info
->program
, GL_VALIDATE_STATUS
, &validation_status
);
433 if (GL_TRUE
!= validation_status
) {
434 DLOG(ERROR
) << "CopyTextureCHROMIUM: Invalid shader.";
439 glUniformMatrix4fv(info
->matrix_handle
, 1, GL_FALSE
, transform_matrix
);
440 if (source_target
== GL_TEXTURE_RECTANGLE_ARB
)
441 glUniform2f(info
->half_size_handle
, width
/ 2.0f
, height
/ 2.0f
);
443 glUniform2f(info
->half_size_handle
, 0.5f
, 0.5f
);
445 if (BindFramebufferTexture2D(
446 GL_TEXTURE_2D
, dest_id
, dest_level
, framebuffer_
)) {
447 decoder
->ClearAllAttributes();
448 glEnableVertexAttribArray(kVertexPositionAttrib
);
450 glBindBuffer(GL_ARRAY_BUFFER
, buffer_id_
);
451 glVertexAttribPointer(kVertexPositionAttrib
, 2, GL_FLOAT
, GL_FALSE
, 0, 0);
453 glUniform1i(info
->sampler_handle
, 0);
455 glBindTexture(source_target
, source_id
);
456 glTexParameterf(source_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
457 glTexParameterf(source_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
458 glTexParameteri(source_target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
459 glTexParameteri(source_target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
461 glDisable(GL_DEPTH_TEST
);
462 glDisable(GL_SCISSOR_TEST
);
463 glDisable(GL_STENCIL_TEST
);
464 glDisable(GL_CULL_FACE
);
465 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
466 glDepthMask(GL_FALSE
);
469 glViewport(0, 0, width
, height
);
470 glDrawArrays(GL_TRIANGLE_FAN
, 0, 4);
473 decoder
->RestoreAllAttributes();
474 decoder
->RestoreTextureState(source_id
);
475 decoder
->RestoreTextureState(dest_id
);
476 decoder
->RestoreTextureUnitBindings(0);
477 decoder
->RestoreActiveTexture();
478 decoder
->RestoreProgramBindings();
479 decoder
->RestoreBufferBindings();
480 decoder
->RestoreFramebufferBindings();
481 decoder
->RestoreGlobalState();