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)
35 const GLfloat kIdentityMatrix
[16] = {1.0f
, 0.0f
, 0.0f
, 0.0f
,
36 0.0f
, 1.0f
, 0.0f
, 0.0f
,
37 0.0f
, 0.0f
, 1.0f
, 0.0f
,
38 0.0f
, 0.0f
, 0.0f
, 1.0f
};
41 VERTEX_SHADER_COPY_TEXTURE
,
42 VERTEX_SHADER_COPY_TEXTURE_FLIP_Y
,
46 enum FragmentShaderId
{
47 FRAGMENT_SHADER_COPY_TEXTURE_2D
,
48 FRAGMENT_SHADER_COPY_TEXTURE_RECTANGLE_ARB
,
49 FRAGMENT_SHADER_COPY_TEXTURE_EXTERNAL_OES
,
50 FRAGMENT_SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_2D
,
51 FRAGMENT_SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_RECTANGLE_ARB
,
52 FRAGMENT_SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_EXTERNAL_OES
,
53 FRAGMENT_SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_2D
,
54 FRAGMENT_SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_RECTANGLE_ARB
,
55 FRAGMENT_SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_EXTERNAL_OES
,
59 const char* vertex_shader_source
[NUM_VERTEX_SHADERS
] = {
60 // VERTEX_SHADER_COPY_TEXTURE
62 uniform mat4 u_matrix
;
63 uniform vec2 u_half_size
;
64 attribute vec4 a_position
;
65 varying TexCoordPrecision vec2 v_uv
;
67 gl_Position
= u_matrix
* a_position
;
68 v_uv
= a_position
.xy
* vec2(u_half_size
.s
, u_half_size
.t
) +
69 vec2(u_half_size
.s
, u_half_size
.t
);
71 // VERTEX_SHADER_COPY_TEXTURE_FLIP_Y
73 uniform mat4 u_matrix
;
74 uniform vec2 u_half_size
;
75 attribute vec4 a_position
;
76 varying TexCoordPrecision vec2 v_uv
;
78 gl_Position
= u_matrix
* a_position
;
79 v_uv
= a_position
.xy
* vec2(u_half_size
.s
, -u_half_size
.t
) +
80 vec2(u_half_size
.s
, u_half_size
.t
);
84 const char* fragment_shader_source
[NUM_FRAGMENT_SHADERS
] = {
85 // FRAGMENT_SHADER_COPY_TEXTURE_*
87 uniform SamplerType u_sampler
;
88 varying TexCoordPrecision vec2 v_uv
;
90 gl_FragColor
= TextureLookup(u_sampler
, v_uv
.st
);
92 // FRAGMENT_SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_*
94 uniform SamplerType u_sampler
;
95 varying TexCoordPrecision vec2 v_uv
;
97 gl_FragColor
= TextureLookup(u_sampler
, v_uv
.st
);
98 gl_FragColor
.rgb
*= gl_FragColor
.a
;
100 // FRAGMENT_SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_*
102 uniform SamplerType u_sampler
;
103 varying TexCoordPrecision vec2 v_uv
;
105 gl_FragColor
= TextureLookup(u_sampler
, v_uv
.st
);
106 if (gl_FragColor
.a
> 0.0)
107 gl_FragColor
.rgb
/= gl_FragColor
.a
;
111 // Returns the correct vertex shader id to evaluate the copy operation for
112 // the CHROMIUM_flipy setting.
113 VertexShaderId
GetVertexShaderId(bool flip_y
) {
115 static VertexShaderId shader_ids
[] = {
116 VERTEX_SHADER_COPY_TEXTURE
,
117 VERTEX_SHADER_COPY_TEXTURE_FLIP_Y
,
120 unsigned index
= flip_y
? 1 : 0;
121 return shader_ids
[index
];
124 // Returns the correct fragment shader id to evaluate the copy operation for
125 // the premultiply alpha pixel store settings and target.
126 FragmentShaderId
GetFragmentShaderId(bool premultiply_alpha
,
127 bool unpremultiply_alpha
,
131 SAMPLER_RECTANGLE_ARB
,
132 SAMPLER_EXTERNAL_OES
,
136 // bit 0: premultiply alpha
137 // bit 1: unpremultiply alpha
138 static FragmentShaderId shader_ids
[][NUM_SAMPLERS
] = {
140 FRAGMENT_SHADER_COPY_TEXTURE_2D
,
141 FRAGMENT_SHADER_COPY_TEXTURE_RECTANGLE_ARB
,
142 FRAGMENT_SHADER_COPY_TEXTURE_EXTERNAL_OES
,
145 FRAGMENT_SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_2D
,
146 FRAGMENT_SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_RECTANGLE_ARB
,
147 FRAGMENT_SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_EXTERNAL_OES
,
150 FRAGMENT_SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_2D
,
151 FRAGMENT_SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_RECTANGLE_ARB
,
152 FRAGMENT_SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_EXTERNAL_OES
,
155 FRAGMENT_SHADER_COPY_TEXTURE_2D
,
156 FRAGMENT_SHADER_COPY_TEXTURE_RECTANGLE_ARB
,
157 FRAGMENT_SHADER_COPY_TEXTURE_EXTERNAL_OES
,
160 unsigned index
= (premultiply_alpha
? (1 << 0) : 0) |
161 (unpremultiply_alpha
? (1 << 1) : 0);
165 return shader_ids
[index
][SAMPLER_2D
];
166 case GL_TEXTURE_RECTANGLE_ARB
:
167 return shader_ids
[index
][SAMPLER_RECTANGLE_ARB
];
168 case GL_TEXTURE_EXTERNAL_OES
:
169 return shader_ids
[index
][SAMPLER_EXTERNAL_OES
];
175 return shader_ids
[0][SAMPLER_2D
];
178 void CompileShader(GLuint shader
, const char* shader_source
) {
179 glShaderSource(shader
, 1, &shader_source
, 0);
180 glCompileShader(shader
);
182 GLint compile_status
;
183 glGetShaderiv(shader
, GL_COMPILE_STATUS
, &compile_status
);
184 if (GL_TRUE
!= compile_status
)
185 DLOG(ERROR
) << "CopyTextureCHROMIUM: shader compilation failure.";
189 void DeleteShader(GLuint shader
) {
191 glDeleteShader(shader
);
194 bool BindFramebufferTexture2D(GLenum target
,
196 GLuint framebuffer
) {
197 DCHECK(target
== GL_TEXTURE_2D
|| target
== GL_TEXTURE_RECTANGLE_ARB
);
198 glActiveTexture(GL_TEXTURE0
);
199 glBindTexture(target
, texture_id
);
200 // NVidia drivers require texture settings to be a certain way
201 // or they won't report FRAMEBUFFER_COMPLETE.
202 glTexParameterf(target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
203 glTexParameterf(target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
204 glTexParameteri(target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
205 glTexParameteri(target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
206 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, framebuffer
);
207 glFramebufferTexture2DEXT(GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
, target
,
211 GLenum fb_status
= glCheckFramebufferStatusEXT(GL_FRAMEBUFFER
);
212 if (GL_FRAMEBUFFER_COMPLETE
!= fb_status
) {
213 DLOG(ERROR
) << "CopyTextureCHROMIUM: Incomplete framebuffer.";
220 void DoCopyTexImage2D(const gpu::gles2::GLES2Decoder
* decoder
,
221 GLenum source_target
,
224 GLenum dest_internal_format
,
227 GLuint framebuffer
) {
228 DCHECK(source_target
== GL_TEXTURE_2D
||
229 source_target
== GL_TEXTURE_RECTANGLE_ARB
);
230 if (BindFramebufferTexture2D(source_target
, source_id
, framebuffer
)) {
231 glBindTexture(GL_TEXTURE_2D
, dest_id
);
232 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
233 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
234 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
235 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
236 glCopyTexImage2D(GL_TEXTURE_2D
, 0 /* level */, dest_internal_format
,
237 0 /* x */, 0 /* y */, width
, height
, 0 /* border */);
240 decoder
->RestoreTextureState(source_id
);
241 decoder
->RestoreTextureState(dest_id
);
242 decoder
->RestoreTextureUnitBindings(0);
243 decoder
->RestoreActiveTexture();
244 decoder
->RestoreFramebufferBindings();
247 void DoCopyTexSubImage2D(const gpu::gles2::GLES2Decoder
* decoder
,
248 GLenum source_target
,
253 GLsizei source_width
,
254 GLsizei source_height
,
255 GLuint framebuffer
) {
256 DCHECK(source_target
== GL_TEXTURE_2D
||
257 source_target
== GL_TEXTURE_RECTANGLE_ARB
);
258 if (BindFramebufferTexture2D(source_target
, source_id
, framebuffer
)) {
259 glBindTexture(GL_TEXTURE_2D
, dest_id
);
260 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
261 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
262 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
263 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
264 glCopyTexSubImage2D(GL_TEXTURE_2D
, 0 /* level */, xoffset
, yoffset
,
265 0 /* x */, 0 /* y */, source_width
, source_height
);
268 decoder
->RestoreTextureState(source_id
);
269 decoder
->RestoreTextureState(dest_id
);
270 decoder
->RestoreTextureUnitBindings(0);
271 decoder
->RestoreActiveTexture();
272 decoder
->RestoreFramebufferBindings();
275 // Copy from SkMatrix44::preTranslate
276 void PreTranslate(GLfloat
* matrix
, GLfloat dx
, GLfloat dy
, GLfloat dz
) {
277 if (!dx
&& !dy
&& !dz
)
280 for (int i
= 0; i
< 4; ++i
) {
281 matrix
[(3 * 4) + i
] = matrix
[(0 * 4) + i
] * dx
+ matrix
[(1 * 4) + i
] * dy
+
282 matrix
[(2 * 4) + i
] * dz
+ matrix
[(3 * 4) + i
];
290 CopyTextureCHROMIUMResourceManager::CopyTextureCHROMIUMResourceManager()
291 : initialized_(false),
292 vertex_shaders_(NUM_VERTEX_SHADERS
, 0u),
293 fragment_shaders_(NUM_FRAGMENT_SHADERS
, 0u),
297 CopyTextureCHROMIUMResourceManager::~CopyTextureCHROMIUMResourceManager() {
298 // |buffer_id_| and |framebuffer_| can be not-null because when GPU context is
299 // lost, this class can be deleted without releasing resources like
303 void CopyTextureCHROMIUMResourceManager::Initialize(
304 const gles2::GLES2Decoder
* decoder
) {
306 kVertexPositionAttrib
== 0u,
307 "kVertexPositionAttrib must be 0");
309 DCHECK(!framebuffer_
);
310 DCHECK(programs_
.empty());
312 // Initialize all of the GPU resources required to perform the copy.
313 glGenBuffersARB(1, &buffer_id_
);
314 glBindBuffer(GL_ARRAY_BUFFER
, buffer_id_
);
315 const GLfloat kQuadVertices
[] = {-1.0f
, -1.0f
,
320 GL_ARRAY_BUFFER
, sizeof(kQuadVertices
), kQuadVertices
, GL_STATIC_DRAW
);
322 glGenFramebuffersEXT(1, &framebuffer_
);
324 decoder
->RestoreBufferBindings();
329 void CopyTextureCHROMIUMResourceManager::Destroy() {
333 glDeleteFramebuffersEXT(1, &framebuffer_
);
336 std::for_each(vertex_shaders_
.begin(), vertex_shaders_
.end(), DeleteShader
);
338 fragment_shaders_
.begin(), fragment_shaders_
.end(), DeleteShader
);
340 for (ProgramMap::const_iterator it
= programs_
.begin(); it
!= programs_
.end();
342 const ProgramInfo
& info
= it
->second
;
343 glDeleteProgram(info
.program
);
346 glDeleteBuffersARB(1, &buffer_id_
);
350 void CopyTextureCHROMIUMResourceManager::DoCopyTexture(
351 const gles2::GLES2Decoder
* decoder
,
352 GLenum source_target
,
354 GLenum source_internal_format
,
356 GLenum dest_internal_format
,
360 bool premultiply_alpha
,
361 bool unpremultiply_alpha
) {
362 bool premultiply_alpha_change
= premultiply_alpha
^ unpremultiply_alpha
;
363 // GL_INVALID_OPERATION is generated if the currently bound framebuffer's
364 // format does not contain a superset of the components required by the base
365 // format of internalformat.
366 // https://www.khronos.org/opengles/sdk/docs/man/xhtml/glCopyTexImage2D.xml
367 bool source_format_contain_superset_of_dest_format
=
368 (source_internal_format
== dest_internal_format
&&
369 source_internal_format
!= GL_BGRA_EXT
) ||
370 (source_internal_format
== GL_RGBA
&& dest_internal_format
== GL_RGB
);
371 // GL_TEXTURE_RECTANGLE_ARB on FBO is supported by OpenGL, not GLES2,
372 // so restrict this to GL_TEXTURE_2D.
373 if (source_target
== GL_TEXTURE_2D
&& !flip_y
&& !premultiply_alpha_change
&&
374 source_format_contain_superset_of_dest_format
) {
375 DoCopyTexImage2D(decoder
,
379 dest_internal_format
,
386 // Use kIdentityMatrix if no transform passed in.
387 DoCopyTextureWithTransform(decoder
, source_target
, source_id
, dest_id
, width
,
388 height
, flip_y
, premultiply_alpha
,
389 unpremultiply_alpha
, kIdentityMatrix
);
392 void CopyTextureCHROMIUMResourceManager::DoCopySubTexture(
393 const gles2::GLES2Decoder
* decoder
,
394 GLenum source_target
,
396 GLenum source_internal_format
,
398 GLenum dest_internal_format
,
403 GLsizei source_width
,
404 GLsizei source_height
,
406 bool premultiply_alpha
,
407 bool unpremultiply_alpha
) {
408 bool premultiply_alpha_change
= premultiply_alpha
^ unpremultiply_alpha
;
409 // GL_INVALID_OPERATION is generated if the currently bound framebuffer's
410 // format does not contain a superset of the components required by the base
411 // format of internalformat.
412 // https://www.khronos.org/opengles/sdk/docs/man/xhtml/glCopyTexImage2D.xml
413 bool source_format_contain_superset_of_dest_format
=
414 (source_internal_format
== dest_internal_format
&&
415 source_internal_format
!= GL_BGRA_EXT
) ||
416 (source_internal_format
== GL_RGBA
&& dest_internal_format
== GL_RGB
);
417 // GL_TEXTURE_RECTANGLE_ARB on FBO is supported by OpenGL, not GLES2,
418 // so restrict this to GL_TEXTURE_2D.
419 if (source_target
== GL_TEXTURE_2D
&& !flip_y
&& !premultiply_alpha_change
&&
420 source_format_contain_superset_of_dest_format
) {
421 DoCopyTexSubImage2D(decoder
, source_target
, source_id
, dest_id
, xoffset
,
422 yoffset
, source_width
, source_height
, framebuffer_
);
426 // Use kIdentityMatrix if no transform passed in.
427 DoCopySubTextureWithTransform(
428 decoder
, source_target
, source_id
, dest_id
, xoffset
, yoffset
, dest_width
,
429 dest_height
, source_width
, source_height
, flip_y
, premultiply_alpha
,
430 unpremultiply_alpha
, kIdentityMatrix
);
433 void CopyTextureCHROMIUMResourceManager::DoCopyTextureWithTransform(
434 const gles2::GLES2Decoder
* decoder
,
435 GLenum source_target
,
441 bool premultiply_alpha
,
442 bool unpremultiply_alpha
,
443 const GLfloat transform_matrix
[16]) {
444 GLsizei dest_width
= width
;
445 GLsizei dest_height
= height
;
446 DoCopyTextureInternal(decoder
, source_target
, source_id
, dest_id
, 0, 0,
447 dest_width
, dest_height
, width
, height
, flip_y
,
448 premultiply_alpha
, unpremultiply_alpha
,
452 void CopyTextureCHROMIUMResourceManager::DoCopySubTextureWithTransform(
453 const gles2::GLES2Decoder
* decoder
,
454 GLenum source_target
,
461 GLsizei source_width
,
462 GLsizei source_height
,
464 bool premultiply_alpha
,
465 bool unpremultiply_alpha
,
466 const GLfloat transform_matrix
[16]) {
467 DoCopyTextureInternal(decoder
, source_target
, source_id
, dest_id
, xoffset
,
468 yoffset
, dest_width
, dest_height
, source_width
,
469 source_height
, flip_y
, premultiply_alpha
,
470 unpremultiply_alpha
, transform_matrix
);
473 void CopyTextureCHROMIUMResourceManager::DoCopyTextureInternal(
474 const gles2::GLES2Decoder
* decoder
,
475 GLenum source_target
,
482 GLsizei source_width
,
483 GLsizei source_height
,
485 bool premultiply_alpha
,
486 bool unpremultiply_alpha
,
487 const GLfloat transform_matrix
[16]) {
488 DCHECK(source_target
== GL_TEXTURE_2D
||
489 source_target
== GL_TEXTURE_RECTANGLE_ARB
||
490 source_target
== GL_TEXTURE_EXTERNAL_OES
);
491 DCHECK(xoffset
>= 0 && xoffset
+ source_width
<= dest_width
);
492 DCHECK(yoffset
>= 0 && yoffset
+ source_height
<= dest_height
);
494 DLOG(ERROR
) << "CopyTextureCHROMIUM: Uninitialized manager.";
498 VertexShaderId vertex_shader_id
= GetVertexShaderId(flip_y
);
499 DCHECK_LT(static_cast<size_t>(vertex_shader_id
), vertex_shaders_
.size());
500 FragmentShaderId fragment_shader_id
= GetFragmentShaderId(
501 premultiply_alpha
, unpremultiply_alpha
, source_target
);
502 DCHECK_LT(static_cast<size_t>(fragment_shader_id
), fragment_shaders_
.size());
504 ProgramMapKey
key(vertex_shader_id
, fragment_shader_id
);
505 ProgramInfo
* info
= &programs_
[key
];
506 // Create program if necessary.
507 if (!info
->program
) {
508 info
->program
= glCreateProgram();
509 GLuint
* vertex_shader
= &vertex_shaders_
[vertex_shader_id
];
510 if (!*vertex_shader
) {
511 *vertex_shader
= glCreateShader(GL_VERTEX_SHADER
);
512 CompileShader(*vertex_shader
, vertex_shader_source
[vertex_shader_id
]);
514 glAttachShader(info
->program
, *vertex_shader
);
515 GLuint
* fragment_shader
= &fragment_shaders_
[fragment_shader_id
];
516 if (!*fragment_shader
) {
517 *fragment_shader
= glCreateShader(GL_FRAGMENT_SHADER
);
518 CompileShader(*fragment_shader
,
519 fragment_shader_source
[fragment_shader_id
]);
521 glAttachShader(info
->program
, *fragment_shader
);
522 glBindAttribLocation(info
->program
, kVertexPositionAttrib
, "a_position");
523 glLinkProgram(info
->program
);
526 glGetProgramiv(info
->program
, GL_LINK_STATUS
, &linked
);
528 DLOG(ERROR
) << "CopyTextureCHROMIUM: program link failure.";
530 info
->matrix_handle
= glGetUniformLocation(info
->program
, "u_matrix");
531 info
->half_size_handle
= glGetUniformLocation(info
->program
, "u_half_size");
532 info
->sampler_handle
= glGetUniformLocation(info
->program
, "u_sampler");
534 glUseProgram(info
->program
);
536 if (!xoffset
&& !yoffset
) {
537 glUniformMatrix4fv(info
->matrix_handle
, 1, GL_FALSE
, transform_matrix
);
539 // transform offsets from ([0, dest_width], [0, dest_height]) coord.
540 // to ([-1, 1], [-1, 1]) coord.
541 GLfloat xoffset_on_vertex
= ((2.f
* xoffset
) / dest_width
);
542 GLfloat yoffset_on_vertex
= ((2.f
* yoffset
) / dest_height
);
544 // Pass view_matrix * offset_matrix to the program.
545 GLfloat view_transform
[16];
546 memcpy(view_transform
, transform_matrix
, 16 * sizeof(GLfloat
));
547 PreTranslate(view_transform
, xoffset_on_vertex
, yoffset_on_vertex
, 0);
548 glUniformMatrix4fv(info
->matrix_handle
, 1, GL_FALSE
, view_transform
);
550 if (source_target
== GL_TEXTURE_RECTANGLE_ARB
)
551 glUniform2f(info
->half_size_handle
, source_width
/ 2.0f
,
552 source_height
/ 2.0f
);
554 glUniform2f(info
->half_size_handle
, 0.5f
, 0.5f
);
556 if (BindFramebufferTexture2D(GL_TEXTURE_2D
, dest_id
, framebuffer_
)) {
558 // glValidateProgram of MACOSX validates FBO unlike other platforms, so
559 // glValidateProgram must be called after FBO binding. crbug.com/463439
560 glValidateProgram(info
->program
);
561 GLint validation_status
;
562 glGetProgramiv(info
->program
, GL_VALIDATE_STATUS
, &validation_status
);
563 if (GL_TRUE
!= validation_status
) {
564 DLOG(ERROR
) << "CopyTextureCHROMIUM: Invalid shader.";
568 decoder
->ClearAllAttributes();
569 glEnableVertexAttribArray(kVertexPositionAttrib
);
571 glBindBuffer(GL_ARRAY_BUFFER
, buffer_id_
);
572 glVertexAttribPointer(kVertexPositionAttrib
, 2, GL_FLOAT
, GL_FALSE
, 0, 0);
574 glUniform1i(info
->sampler_handle
, 0);
576 glBindTexture(source_target
, source_id
);
577 glTexParameterf(source_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
578 glTexParameterf(source_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
579 glTexParameteri(source_target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
580 glTexParameteri(source_target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
582 glDisable(GL_DEPTH_TEST
);
583 glDisable(GL_SCISSOR_TEST
);
584 glDisable(GL_STENCIL_TEST
);
585 glDisable(GL_CULL_FACE
);
586 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
587 glDepthMask(GL_FALSE
);
590 glViewport(0, 0, dest_width
, dest_height
);
591 glDrawArrays(GL_TRIANGLE_FAN
, 0, 4);
594 decoder
->RestoreAllAttributes();
595 decoder
->RestoreTextureState(source_id
);
596 decoder
->RestoreTextureState(dest_id
);
597 decoder
->RestoreTextureUnitBindings(0);
598 decoder
->RestoreActiveTexture();
599 decoder
->RestoreProgramBindings();
600 decoder
->RestoreBufferBindings();
601 decoder
->RestoreFramebufferBindings();
602 decoder
->RestoreGlobalState();