Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / gpu / command_buffer / service / gles2_cmd_copy_texture_chromium.cc
bloba987a39ce37e1c86113b443cfed9e602d9987557
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"
7 #include <algorithm>
9 #include "base/basictypes.h"
10 #include "gpu/command_buffer/service/gl_utils.h"
11 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
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 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)
33 namespace {
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};
40 enum VertexShaderId {
41 VERTEX_SHADER_COPY_TEXTURE,
42 VERTEX_SHADER_COPY_TEXTURE_FLIP_Y,
43 NUM_VERTEX_SHADERS,
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,
56 NUM_FRAGMENT_SHADERS,
59 const char* vertex_shader_source[NUM_VERTEX_SHADERS] = {
60 // VERTEX_SHADER_COPY_TEXTURE
61 SHADER(
62 uniform vec2 u_vertex_translate;
63 uniform vec2 u_half_size;
64 attribute vec4 a_position;
65 varying TexCoordPrecision vec2 v_uv;
66 void main(void) {
67 gl_Position = a_position + vec4(u_vertex_translate, 0.0, 0.0);
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);
70 }),
71 // VERTEX_SHADER_COPY_TEXTURE_FLIP_Y
72 SHADER(
73 uniform vec2 u_vertex_translate;
74 uniform vec2 u_half_size;
75 attribute vec4 a_position;
76 varying TexCoordPrecision vec2 v_uv;
77 void main(void) {
78 gl_Position = a_position + vec4(u_vertex_translate, 0.0, 0.0);
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);
81 }),
84 const char* fragment_shader_source[NUM_FRAGMENT_SHADERS] = {
85 // FRAGMENT_SHADER_COPY_TEXTURE_*
86 FRAGMENT_SHADERS(
87 uniform SamplerType u_sampler;
88 uniform mat4 u_tex_coord_transform;
89 varying TexCoordPrecision vec2 v_uv;
90 void main(void) {
91 TexCoordPrecision vec4 uv = u_tex_coord_transform * vec4(v_uv, 0, 1);
92 gl_FragColor = TextureLookup(u_sampler, uv.st);
93 }),
94 // FRAGMENT_SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_*
95 FRAGMENT_SHADERS(
96 uniform SamplerType u_sampler;
97 uniform mat4 u_tex_coord_transform;
98 varying TexCoordPrecision vec2 v_uv;
99 void main(void) {
100 TexCoordPrecision vec4 uv = u_tex_coord_transform * vec4(v_uv, 0, 1);
101 gl_FragColor = TextureLookup(u_sampler, uv.st);
102 gl_FragColor.rgb *= gl_FragColor.a;
104 // FRAGMENT_SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_*
105 FRAGMENT_SHADERS(
106 uniform SamplerType u_sampler;
107 uniform mat4 u_tex_coord_transform;
108 varying TexCoordPrecision vec2 v_uv;
109 void main(void) {
110 TexCoordPrecision vec4 uv = u_tex_coord_transform * vec4(v_uv, 0, 1);
111 gl_FragColor = TextureLookup(u_sampler, uv.st);
112 if (gl_FragColor.a > 0.0)
113 gl_FragColor.rgb /= gl_FragColor.a;
117 // Returns the correct vertex shader id to evaluate the copy operation for
118 // the CHROMIUM_flipy setting.
119 VertexShaderId GetVertexShaderId(bool flip_y) {
120 // bit 0: flip y
121 static VertexShaderId shader_ids[] = {
122 VERTEX_SHADER_COPY_TEXTURE,
123 VERTEX_SHADER_COPY_TEXTURE_FLIP_Y,
126 unsigned index = flip_y ? 1 : 0;
127 return shader_ids[index];
130 // Returns the correct fragment shader id to evaluate the copy operation for
131 // the premultiply alpha pixel store settings and target.
132 FragmentShaderId GetFragmentShaderId(bool premultiply_alpha,
133 bool unpremultiply_alpha,
134 GLenum target) {
135 enum {
136 SAMPLER_2D,
137 SAMPLER_RECTANGLE_ARB,
138 SAMPLER_EXTERNAL_OES,
139 NUM_SAMPLERS
142 // bit 0: premultiply alpha
143 // bit 1: unpremultiply alpha
144 static FragmentShaderId shader_ids[][NUM_SAMPLERS] = {
146 FRAGMENT_SHADER_COPY_TEXTURE_2D,
147 FRAGMENT_SHADER_COPY_TEXTURE_RECTANGLE_ARB,
148 FRAGMENT_SHADER_COPY_TEXTURE_EXTERNAL_OES,
151 FRAGMENT_SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_2D,
152 FRAGMENT_SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_RECTANGLE_ARB,
153 FRAGMENT_SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_EXTERNAL_OES,
156 FRAGMENT_SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_2D,
157 FRAGMENT_SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_RECTANGLE_ARB,
158 FRAGMENT_SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_EXTERNAL_OES,
161 FRAGMENT_SHADER_COPY_TEXTURE_2D,
162 FRAGMENT_SHADER_COPY_TEXTURE_RECTANGLE_ARB,
163 FRAGMENT_SHADER_COPY_TEXTURE_EXTERNAL_OES,
166 unsigned index = (premultiply_alpha ? (1 << 0) : 0) |
167 (unpremultiply_alpha ? (1 << 1) : 0);
169 switch (target) {
170 case GL_TEXTURE_2D:
171 return shader_ids[index][SAMPLER_2D];
172 case GL_TEXTURE_RECTANGLE_ARB:
173 return shader_ids[index][SAMPLER_RECTANGLE_ARB];
174 case GL_TEXTURE_EXTERNAL_OES:
175 return shader_ids[index][SAMPLER_EXTERNAL_OES];
176 default:
177 break;
180 NOTREACHED();
181 return shader_ids[0][SAMPLER_2D];
184 void CompileShader(GLuint shader, const char* shader_source) {
185 glShaderSource(shader, 1, &shader_source, 0);
186 glCompileShader(shader);
187 #ifndef NDEBUG
188 GLint compile_status;
189 glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
190 if (GL_TRUE != compile_status)
191 DLOG(ERROR) << "CopyTextureCHROMIUM: shader compilation failure.";
192 #endif
195 void DeleteShader(GLuint shader) {
196 if (shader)
197 glDeleteShader(shader);
200 bool BindFramebufferTexture2D(GLenum target,
201 GLuint texture_id,
202 GLuint framebuffer) {
203 DCHECK(target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE_ARB);
204 glActiveTexture(GL_TEXTURE0);
205 glBindTexture(target, texture_id);
206 // NVidia drivers require texture settings to be a certain way
207 // or they won't report FRAMEBUFFER_COMPLETE.
208 glTexParameterf(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
209 glTexParameterf(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
210 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
211 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
212 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer);
213 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target,
214 texture_id, 0);
216 #ifndef NDEBUG
217 GLenum fb_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER);
218 if (GL_FRAMEBUFFER_COMPLETE != fb_status) {
219 DLOG(ERROR) << "CopyTextureCHROMIUM: Incomplete framebuffer.";
220 return false;
222 #endif
223 return true;
226 void DoCopyTexImage2D(const gpu::gles2::GLES2Decoder* decoder,
227 GLenum source_target,
228 GLuint source_id,
229 GLuint dest_id,
230 GLenum dest_internal_format,
231 GLsizei width,
232 GLsizei height,
233 GLuint framebuffer) {
234 DCHECK(source_target == GL_TEXTURE_2D ||
235 source_target == GL_TEXTURE_RECTANGLE_ARB);
236 if (BindFramebufferTexture2D(source_target, source_id, framebuffer)) {
237 glBindTexture(GL_TEXTURE_2D, dest_id);
238 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
239 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
240 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
241 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
242 glCopyTexImage2D(GL_TEXTURE_2D, 0 /* level */, dest_internal_format,
243 0 /* x */, 0 /* y */, width, height, 0 /* border */);
246 decoder->RestoreTextureState(source_id);
247 decoder->RestoreTextureState(dest_id);
248 decoder->RestoreTextureUnitBindings(0);
249 decoder->RestoreActiveTexture();
250 decoder->RestoreFramebufferBindings();
253 void DoCopyTexSubImage2D(const gpu::gles2::GLES2Decoder* decoder,
254 GLenum source_target,
255 GLuint source_id,
256 GLuint dest_id,
257 GLint xoffset,
258 GLint yoffset,
259 GLint source_x,
260 GLint source_y,
261 GLsizei source_width,
262 GLsizei source_height,
263 GLuint framebuffer) {
264 DCHECK(source_target == GL_TEXTURE_2D ||
265 source_target == GL_TEXTURE_RECTANGLE_ARB);
266 if (BindFramebufferTexture2D(source_target, source_id, framebuffer)) {
267 glBindTexture(GL_TEXTURE_2D, dest_id);
268 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
269 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
270 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
271 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
272 glCopyTexSubImage2D(GL_TEXTURE_2D, 0 /* level */, xoffset, yoffset,
273 source_x, source_y, source_width, source_height);
276 decoder->RestoreTextureState(source_id);
277 decoder->RestoreTextureState(dest_id);
278 decoder->RestoreTextureUnitBindings(0);
279 decoder->RestoreActiveTexture();
280 decoder->RestoreFramebufferBindings();
283 } // namespace
285 namespace gpu {
287 CopyTextureCHROMIUMResourceManager::CopyTextureCHROMIUMResourceManager()
288 : initialized_(false),
289 vertex_shaders_(NUM_VERTEX_SHADERS, 0u),
290 fragment_shaders_(NUM_FRAGMENT_SHADERS, 0u),
291 buffer_id_(0u),
292 framebuffer_(0u) {}
294 CopyTextureCHROMIUMResourceManager::~CopyTextureCHROMIUMResourceManager() {
295 // |buffer_id_| and |framebuffer_| can be not-null because when GPU context is
296 // lost, this class can be deleted without releasing resources like
297 // GLES2DecoderImpl.
300 void CopyTextureCHROMIUMResourceManager::Initialize(
301 const gles2::GLES2Decoder* decoder) {
302 static_assert(
303 kVertexPositionAttrib == 0u,
304 "kVertexPositionAttrib must be 0");
305 DCHECK(!buffer_id_);
306 DCHECK(!framebuffer_);
307 DCHECK(programs_.empty());
309 // Initialize all of the GPU resources required to perform the copy.
310 glGenBuffersARB(1, &buffer_id_);
311 glBindBuffer(GL_ARRAY_BUFFER, buffer_id_);
312 const GLfloat kQuadVertices[] = {-1.0f, -1.0f,
313 1.0f, -1.0f,
314 1.0f, 1.0f,
315 -1.0f, 1.0f};
316 glBufferData(
317 GL_ARRAY_BUFFER, sizeof(kQuadVertices), kQuadVertices, GL_STATIC_DRAW);
319 glGenFramebuffersEXT(1, &framebuffer_);
321 decoder->RestoreBufferBindings();
323 initialized_ = true;
326 void CopyTextureCHROMIUMResourceManager::Destroy() {
327 if (!initialized_)
328 return;
330 glDeleteFramebuffersEXT(1, &framebuffer_);
331 framebuffer_ = 0;
333 std::for_each(vertex_shaders_.begin(), vertex_shaders_.end(), DeleteShader);
334 std::for_each(
335 fragment_shaders_.begin(), fragment_shaders_.end(), DeleteShader);
337 for (ProgramMap::const_iterator it = programs_.begin(); it != programs_.end();
338 ++it) {
339 const ProgramInfo& info = it->second;
340 glDeleteProgram(info.program);
343 glDeleteBuffersARB(1, &buffer_id_);
344 buffer_id_ = 0;
347 void CopyTextureCHROMIUMResourceManager::DoCopyTexture(
348 const gles2::GLES2Decoder* decoder,
349 GLenum source_target,
350 GLuint source_id,
351 GLenum source_internal_format,
352 GLuint dest_id,
353 GLenum dest_internal_format,
354 GLsizei width,
355 GLsizei height,
356 bool flip_y,
357 bool premultiply_alpha,
358 bool unpremultiply_alpha) {
359 bool premultiply_alpha_change = premultiply_alpha ^ unpremultiply_alpha;
360 // GL_INVALID_OPERATION is generated if the currently bound framebuffer's
361 // format does not contain a superset of the components required by the base
362 // format of internalformat.
363 // https://www.khronos.org/opengles/sdk/docs/man/xhtml/glCopyTexImage2D.xml
364 bool source_format_contain_superset_of_dest_format =
365 (source_internal_format == dest_internal_format &&
366 source_internal_format != GL_BGRA_EXT) ||
367 (source_internal_format == GL_RGBA && dest_internal_format == GL_RGB);
368 // GL_TEXTURE_RECTANGLE_ARB on FBO is supported by OpenGL, not GLES2,
369 // so restrict this to GL_TEXTURE_2D.
370 if (source_target == GL_TEXTURE_2D && !flip_y && !premultiply_alpha_change &&
371 source_format_contain_superset_of_dest_format) {
372 DoCopyTexImage2D(decoder,
373 source_target,
374 source_id,
375 dest_id,
376 dest_internal_format,
377 width,
378 height,
379 framebuffer_);
380 return;
383 // Use kIdentityMatrix if no transform passed in.
384 DoCopyTextureWithTransform(decoder, source_target, source_id, dest_id, width,
385 height, flip_y, premultiply_alpha,
386 unpremultiply_alpha, kIdentityMatrix);
389 void CopyTextureCHROMIUMResourceManager::DoCopySubTexture(
390 const gles2::GLES2Decoder* decoder,
391 GLenum source_target,
392 GLuint source_id,
393 GLenum source_internal_format,
394 GLuint dest_id,
395 GLenum dest_internal_format,
396 GLint xoffset,
397 GLint yoffset,
398 GLint x,
399 GLint y,
400 GLsizei width,
401 GLsizei height,
402 GLsizei dest_width,
403 GLsizei dest_height,
404 GLsizei source_width,
405 GLsizei source_height,
406 bool flip_y,
407 bool premultiply_alpha,
408 bool unpremultiply_alpha) {
409 bool premultiply_alpha_change = premultiply_alpha ^ unpremultiply_alpha;
410 // GL_INVALID_OPERATION is generated if the currently bound framebuffer's
411 // format does not contain a superset of the components required by the base
412 // format of internalformat.
413 // https://www.khronos.org/opengles/sdk/docs/man/xhtml/glCopyTexImage2D.xml
414 bool source_format_contain_superset_of_dest_format =
415 (source_internal_format == dest_internal_format &&
416 source_internal_format != GL_BGRA_EXT) ||
417 (source_internal_format == GL_RGBA && dest_internal_format == GL_RGB);
418 // GL_TEXTURE_RECTANGLE_ARB on FBO is supported by OpenGL, not GLES2,
419 // so restrict this to GL_TEXTURE_2D.
420 if (source_target == GL_TEXTURE_2D && !flip_y && !premultiply_alpha_change &&
421 source_format_contain_superset_of_dest_format) {
422 DoCopyTexSubImage2D(decoder, source_target, source_id, dest_id, xoffset,
423 yoffset, x, y, width, height, framebuffer_);
424 return;
427 DoCopyTextureInternal(decoder, source_target, source_id, dest_id, xoffset,
428 yoffset, x, y, width, height, dest_width, dest_height,
429 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,
436 GLuint source_id,
437 GLuint dest_id,
438 GLsizei width,
439 GLsizei height,
440 bool flip_y,
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, 0, 0,
447 width, height, dest_width, dest_height, width, height,
448 flip_y, premultiply_alpha, unpremultiply_alpha,
449 transform_matrix);
452 void CopyTextureCHROMIUMResourceManager::DoCopyTextureInternal(
453 const gles2::GLES2Decoder* decoder,
454 GLenum source_target,
455 GLuint source_id,
456 GLuint dest_id,
457 GLint xoffset,
458 GLint yoffset,
459 GLint x,
460 GLint y,
461 GLsizei width,
462 GLsizei height,
463 GLsizei dest_width,
464 GLsizei dest_height,
465 GLsizei source_width,
466 GLsizei source_height,
467 bool flip_y,
468 bool premultiply_alpha,
469 bool unpremultiply_alpha,
470 const GLfloat transform_matrix[16]) {
471 DCHECK(source_target == GL_TEXTURE_2D ||
472 source_target == GL_TEXTURE_RECTANGLE_ARB ||
473 source_target == GL_TEXTURE_EXTERNAL_OES);
474 DCHECK_GE(xoffset, 0);
475 DCHECK_LE(xoffset + width, dest_width);
476 DCHECK_GE(yoffset, 0);
477 DCHECK_LE(yoffset + height, dest_height);
478 if (!initialized_) {
479 DLOG(ERROR) << "CopyTextureCHROMIUM: Uninitialized manager.";
480 return;
483 VertexShaderId vertex_shader_id = GetVertexShaderId(flip_y);
484 DCHECK_LT(static_cast<size_t>(vertex_shader_id), vertex_shaders_.size());
485 FragmentShaderId fragment_shader_id = GetFragmentShaderId(
486 premultiply_alpha, unpremultiply_alpha, source_target);
487 DCHECK_LT(static_cast<size_t>(fragment_shader_id), fragment_shaders_.size());
489 ProgramMapKey key(vertex_shader_id, fragment_shader_id);
490 ProgramInfo* info = &programs_[key];
491 // Create program if necessary.
492 if (!info->program) {
493 info->program = glCreateProgram();
494 GLuint* vertex_shader = &vertex_shaders_[vertex_shader_id];
495 if (!*vertex_shader) {
496 *vertex_shader = glCreateShader(GL_VERTEX_SHADER);
497 CompileShader(*vertex_shader, vertex_shader_source[vertex_shader_id]);
499 glAttachShader(info->program, *vertex_shader);
500 GLuint* fragment_shader = &fragment_shaders_[fragment_shader_id];
501 if (!*fragment_shader) {
502 *fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
503 CompileShader(*fragment_shader,
504 fragment_shader_source[fragment_shader_id]);
506 glAttachShader(info->program, *fragment_shader);
507 glBindAttribLocation(info->program, kVertexPositionAttrib, "a_position");
508 glLinkProgram(info->program);
509 #ifndef NDEBUG
510 GLint linked;
511 glGetProgramiv(info->program, GL_LINK_STATUS, &linked);
512 if (!linked)
513 DLOG(ERROR) << "CopyTextureCHROMIUM: program link failure.";
514 #endif
515 info->vertex_translate_handle = glGetUniformLocation(info->program,
516 "u_vertex_translate");
517 info->tex_coord_transform_handle =
518 glGetUniformLocation(info->program, "u_tex_coord_transform");
519 info->half_size_handle = glGetUniformLocation(info->program, "u_half_size");
520 info->sampler_handle = glGetUniformLocation(info->program, "u_sampler");
522 glUseProgram(info->program);
524 glUniformMatrix4fv(info->tex_coord_transform_handle, 1, GL_FALSE,
525 transform_matrix);
527 GLint x_translate = xoffset - x;
528 GLint y_translate = yoffset - y;
529 if (!x_translate && !y_translate) {
530 glUniform2f(info->vertex_translate_handle, 0.0f, 0.0f);
531 } else {
532 // transform offsets from ([0, dest_width], [0, dest_height]) coord.
533 // to ([-1, 1], [-1, 1]) coord.
534 GLfloat x_translate_on_vertex = ((2.f * x_translate) / dest_width);
535 GLfloat y_translate_on_vertex = ((2.f * y_translate) / dest_height);
537 // Pass translation to the shader program.
538 glUniform2f(info->vertex_translate_handle, x_translate_on_vertex,
539 y_translate_on_vertex);
541 if (source_target == GL_TEXTURE_RECTANGLE_ARB)
542 glUniform2f(info->half_size_handle, source_width / 2.0f,
543 source_height / 2.0f);
544 else
545 glUniform2f(info->half_size_handle, 0.5f, 0.5f);
547 if (BindFramebufferTexture2D(GL_TEXTURE_2D, dest_id, framebuffer_)) {
548 #ifndef NDEBUG
549 // glValidateProgram of MACOSX validates FBO unlike other platforms, so
550 // glValidateProgram must be called after FBO binding. crbug.com/463439
551 glValidateProgram(info->program);
552 GLint validation_status;
553 glGetProgramiv(info->program, GL_VALIDATE_STATUS, &validation_status);
554 if (GL_TRUE != validation_status) {
555 DLOG(ERROR) << "CopyTextureCHROMIUM: Invalid shader.";
556 return;
558 #endif
559 decoder->ClearAllAttributes();
560 glEnableVertexAttribArray(kVertexPositionAttrib);
562 glBindBuffer(GL_ARRAY_BUFFER, buffer_id_);
563 glVertexAttribPointer(kVertexPositionAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0);
565 glUniform1i(info->sampler_handle, 0);
567 glBindTexture(source_target, source_id);
568 glTexParameterf(source_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
569 glTexParameterf(source_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
570 glTexParameteri(source_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
571 glTexParameteri(source_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
573 glDisable(GL_DEPTH_TEST);
574 glDisable(GL_STENCIL_TEST);
575 glDisable(GL_CULL_FACE);
576 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
577 glDepthMask(GL_FALSE);
578 glDisable(GL_BLEND);
580 bool need_scissor =
581 xoffset || yoffset || width != dest_width || height != dest_height;
582 if (need_scissor) {
583 glEnable(GL_SCISSOR_TEST);
584 glScissor(xoffset, yoffset, width, height);
585 } else {
586 glDisable(GL_SCISSOR_TEST);
588 glViewport(0, 0, dest_width, dest_height);
589 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
592 decoder->RestoreAllAttributes();
593 decoder->RestoreTextureState(source_id);
594 decoder->RestoreTextureState(dest_id);
595 decoder->RestoreTextureUnitBindings(0);
596 decoder->RestoreActiveTexture();
597 decoder->RestoreProgramBindings();
598 decoder->RestoreBufferBindings();
599 decoder->RestoreFramebufferBindings();
600 decoder->RestoreGlobalState();
603 } // namespace gpu