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"
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"
13 #define SHADER0(src) \
15 "precision mediump float;\n"\
18 #define SHADER(src) { false, SHADER0(src), }
19 #define SHADER_EXTERNAL_OES0(src) \
20 "#extension GL_OES_EGL_image_external : require\n"\
22 "precision mediump float;\n"\
25 #define SHADER_EXTERNAL_OES(src) { true, SHADER_EXTERNAL_OES0(src), }
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 };
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,
50 bool needs_egl_image_external;
54 const ShaderInfo shader_infos[] = {
55 // VERTEX_SHADER_POS_TEX
57 uniform mat4 u_matrix;
58 attribute vec4 a_position;
61 gl_Position = u_matrix * a_position;
62 v_uv = a_position.xy * 0.5 + vec2(0.5, 0.5);
64 // FRAGMENT_SHADER_TEX
66 uniform sampler2D u_texSampler;
69 gl_FragColor = texture2D(u_texSampler, v_uv.st);
71 // FRAGMENT_SHADER_TEX_FLIP_Y
73 uniform sampler2D u_texSampler;
76 gl_FragColor = texture2D(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
78 // FRAGMENT_SHADER_TEX_PREMULTIPLY_ALPHA
80 uniform sampler2D u_texSampler;
83 gl_FragColor = texture2D(u_texSampler, v_uv.st);
84 gl_FragColor.rgb *= gl_FragColor.a;
86 // FRAGMENT_SHADER_TEX_UNPREMULTIPLY_ALPHA
88 uniform sampler2D u_texSampler;
91 gl_FragColor = texture2D(u_texSampler, v_uv.st);
92 if (gl_FragColor.a > 0.0)
93 gl_FragColor.rgb /= gl_FragColor.a;
95 // FRAGMENT_SHADER_TEX_PREMULTIPLY_ALPHA_FLIP_Y
97 uniform sampler2D u_texSampler;
100 gl_FragColor = texture2D(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
101 gl_FragColor.rgb *= gl_FragColor.a;
103 // FRAGMENT_SHADER_TEX_UNPREMULTIPLY_ALPHA_FLIP_Y
105 uniform sampler2D u_texSampler;
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;
112 // FRAGMENT_SHADER_TEX_OES
114 precision mediump float;
115 uniform samplerExternalOES u_texSampler;
118 gl_FragColor = texture2D(u_texSampler, v_uv.st);
120 // FRAGMENT_SHADER_TEX_OES_FLIP_Y
122 precision mediump float;
123 uniform samplerExternalOES u_texSampler;
127 texture2D(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
129 // FRAGMENT_SHADER_TEX_OES_PREMULTIPLY_ALPHA
131 precision mediump float;
132 uniform samplerExternalOES u_texSampler;
135 gl_FragColor = texture2D(u_texSampler, v_uv.st);
136 gl_FragColor.rgb *= gl_FragColor.a;
138 // FRAGMENT_SHADER_TEX_OES_UNPREMULTIPLY_ALPHA
140 precision mediump float;
141 uniform samplerExternalOES u_texSampler;
144 gl_FragColor = texture2D(u_texSampler, v_uv.st);
145 if (gl_FragColor.a > 0.0)
146 gl_FragColor.rgb /= gl_FragColor.a;
148 // FRAGMENT_SHADER_TEX_OES_PREMULTIPLY_ALPHA_FLIP_Y
150 precision mediump float;
151 uniform samplerExternalOES u_texSampler;
155 texture2D(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
156 gl_FragColor.rgb *= gl_FragColor.a;
158 // FRAGMENT_SHADER_TEX_OES_UNPREMULTIPLY_ALPHA_FLIP_Y
160 precision mediump float;
161 uniform samplerExternalOES u_texSampler;
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;
171 const int kNumShaders = arraysize(shader_infos);
173 // Returns the correct program to evaluate the copy operation for
174 // the CHROMIUM_flipy and premultiply alpha pixel store settings.
175 ProgramId GetProgram(
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;
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
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];
221 CopyTextureCHROMIUMResourceManager::CopyTextureCHROMIUMResourceManager()
222 : initialized_(false),
225 for (int i = 0; i < kNumPrograms; ++i) {
227 matrix_handle_[i] = 0;
228 sampler_locations_[i] = 0;
232 void CopyTextureCHROMIUMResourceManager::Initialize(
233 const gles2::GLES2Decoder* decoder) {
235 kVertexPositionAttrib == 0u,
236 Position_attribs_must_be_0);
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");
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,
249 glGenFramebuffersEXT(1, &framebuffer_);
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) {
260 const char* shader_source = shader_infos[shader].source;
261 glShaderSource(shaders[shader], 1, &shader_source, 0);
262 glCompileShader(shaders[shader]);
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.";
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) {
277 programs_[program] = glCreateProgram();
278 glAttachShader(programs_[program], shaders[0]);
279 glAttachShader(programs_[program], shaders[program + 1]);
281 glBindAttribLocation(programs_[program], kVertexPositionAttrib,
284 glLinkProgram(programs_[program]);
287 glGetProgramiv(programs_[program], GL_LINK_STATUS, &linked);
289 DLOG(ERROR) << "CopyTextureCHROMIUM: program link failure.";
292 sampler_locations_[program] = glGetUniformLocation(programs_[program],
295 matrix_handle_[program] = glGetUniformLocation(programs_[program],
299 for (int shader = 0; shader < kNumShaders; ++shader)
300 glDeleteShader(shaders[shader]);
302 decoder->RestoreBufferBindings();
307 void CopyTextureCHROMIUMResourceManager::Destroy() {
311 glDeleteFramebuffersEXT(1, &framebuffer_);
313 for (int program = 0; program < kNumPrograms; ++program) {
314 if (programs_[program])
315 glDeleteProgram(programs_[program]);
318 glDeleteBuffersARB(1, &buffer_id_);
321 void CopyTextureCHROMIUMResourceManager::DoCopyTexture(
322 const gles2::GLES2Decoder* decoder,
323 GLenum source_target,
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);
343 void CopyTextureCHROMIUMResourceManager::DoCopyTextureWithTransform(
344 const gles2::GLES2Decoder* decoder,
345 GLenum source_target,
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);
359 DLOG(ERROR) << "CopyTextureCHROMIUM: Uninitialized manager.";
363 GLuint program = GetProgram(
364 flip_y, premultiply_alpha, unpremultiply_alpha,
365 source_target == GL_TEXTURE_EXTERNAL_OES);
366 glUseProgram(programs_[program]);
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.";
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,
392 GLenum fb_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER);
393 if (GL_FRAMEBUFFER_COMPLETE != fb_status) {
394 DLOG(ERROR) << "CopyTextureCHROMIUM: Incomplete framebuffer.";
398 glEnableVertexAttribArray(kVertexPositionAttrib);
400 glBindBuffer(GL_ARRAY_BUFFER, buffer_id_);
401 glVertexAttribPointer(kVertexPositionAttrib, 4, GL_FLOAT, GL_FALSE,
402 4 * sizeof(GLfloat), 0);
404 glUniform1i(sampler_locations_[program], 0);
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);
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);
420 glViewport(0, 0, width, height);
421 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
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();