- add sources.
[platform/framework/web/crosswalk.git] / src / gpu / command_buffer / service / gles2_cmd_copy_texture_chromium.cc
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 <string.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"
12
13 #define SHADER0(src) \
14     "#ifdef GL_ES\n"\
15     "precision mediump float;\n"\
16     "#endif\n"\
17     #src
18 #define SHADER(src) { false, SHADER0(src), }
19 #define SHADER_EXTERNAL_OES0(src) \
20     "#extension GL_OES_EGL_image_external : require\n"\
21     "#ifdef GL_ES\n"\
22     "precision mediump float;\n"\
23     "#endif\n"\
24     #src
25 #define SHADER_EXTERNAL_OES(src) { true, SHADER_EXTERNAL_OES0(src), }
26
27 namespace {
28
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 };
33
34 enum ProgramId {
35   PROGRAM_COPY_TEXTURE,
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,
47 };
48
49 struct ShaderInfo {
50   bool needs_egl_image_external;
51   const char* source;
52 };
53
54 const ShaderInfo shader_infos[] = {
55   // VERTEX_SHADER_POS_TEX
56   SHADER(
57     uniform mat4 u_matrix;
58     attribute vec4 a_position;
59     varying vec2 v_uv;
60     void main(void) {
61       gl_Position = u_matrix * a_position;
62       v_uv = a_position.xy * 0.5 + vec2(0.5, 0.5);
63     }),
64   // FRAGMENT_SHADER_TEX
65   SHADER(
66     uniform sampler2D u_texSampler;
67     varying vec2 v_uv;
68     void main(void) {
69       gl_FragColor = texture2D(u_texSampler, v_uv.st);
70     }),
71   // FRAGMENT_SHADER_TEX_FLIP_Y
72   SHADER(
73     uniform sampler2D u_texSampler;
74     varying vec2 v_uv;
75     void main(void) {
76       gl_FragColor = texture2D(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
77     }),
78   // FRAGMENT_SHADER_TEX_PREMULTIPLY_ALPHA
79   SHADER(
80     uniform sampler2D u_texSampler;
81     varying vec2 v_uv;
82     void main(void) {
83       gl_FragColor = texture2D(u_texSampler, v_uv.st);
84       gl_FragColor.rgb *= gl_FragColor.a;
85     }),
86   // FRAGMENT_SHADER_TEX_UNPREMULTIPLY_ALPHA
87   SHADER(
88     uniform sampler2D u_texSampler;
89     varying vec2 v_uv;
90     void main(void) {
91       gl_FragColor = texture2D(u_texSampler, v_uv.st);
92       if (gl_FragColor.a > 0.0)
93         gl_FragColor.rgb /= gl_FragColor.a;
94     }),
95   // FRAGMENT_SHADER_TEX_PREMULTIPLY_ALPHA_FLIP_Y
96   SHADER(
97     uniform sampler2D u_texSampler;
98     varying vec2 v_uv;
99     void main(void) {
100       gl_FragColor = texture2D(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
101       gl_FragColor.rgb *= gl_FragColor.a;
102     }),
103   // FRAGMENT_SHADER_TEX_UNPREMULTIPLY_ALPHA_FLIP_Y
104   SHADER(
105     uniform sampler2D u_texSampler;
106     varying vec2 v_uv;
107     void main(void) {
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;
111     }),
112   // FRAGMENT_SHADER_TEX_OES
113   SHADER_EXTERNAL_OES(
114     precision mediump float;
115     uniform samplerExternalOES u_texSampler;
116     varying vec2 v_uv;
117     void main(void) {
118       gl_FragColor = texture2D(u_texSampler, v_uv.st);
119     }),
120   // FRAGMENT_SHADER_TEX_OES_FLIP_Y
121   SHADER_EXTERNAL_OES(
122      precision mediump float;
123      uniform samplerExternalOES u_texSampler;
124      varying vec2 v_uv;
125      void main(void) {
126        gl_FragColor =
127            texture2D(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
128      }),
129   // FRAGMENT_SHADER_TEX_OES_PREMULTIPLY_ALPHA
130   SHADER_EXTERNAL_OES(
131      precision mediump float;
132      uniform samplerExternalOES u_texSampler;
133      varying vec2 v_uv;
134      void main(void) {
135        gl_FragColor = texture2D(u_texSampler, v_uv.st);
136        gl_FragColor.rgb *= gl_FragColor.a;
137      }),
138   // FRAGMENT_SHADER_TEX_OES_UNPREMULTIPLY_ALPHA
139   SHADER_EXTERNAL_OES(
140     precision mediump float;
141     uniform samplerExternalOES u_texSampler;
142     varying vec2 v_uv;
143     void main(void) {
144       gl_FragColor = texture2D(u_texSampler, v_uv.st);
145       if (gl_FragColor.a > 0.0)
146         gl_FragColor.rgb /= gl_FragColor.a;
147     }),
148   // FRAGMENT_SHADER_TEX_OES_PREMULTIPLY_ALPHA_FLIP_Y
149   SHADER_EXTERNAL_OES(
150       precision mediump float;
151       uniform samplerExternalOES u_texSampler;
152       varying vec2 v_uv;
153       void main(void) {
154         gl_FragColor =
155             texture2D(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
156         gl_FragColor.rgb *= gl_FragColor.a;
157       }),
158   // FRAGMENT_SHADER_TEX_OES_UNPREMULTIPLY_ALPHA_FLIP_Y
159   SHADER_EXTERNAL_OES(
160       precision mediump float;
161       uniform samplerExternalOES u_texSampler;
162       varying vec2 v_uv;
163       void main(void) {
164         gl_FragColor =
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;
168       }),
169 };
170
171 const int kNumShaders = arraysize(shader_infos);
172
173 // Returns the correct program to evaluate the copy operation for
174 // the CHROMIUM_flipy and premultiply alpha pixel store settings.
175 ProgramId GetProgram(
176     bool flip_y,
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;
185   }
186
187   // bit 0: Flip_y
188   // bit 1: Premult
189   // bit 2: Unpremult
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
208   };
209
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];
215 }
216
217 }  // namespace
218
219 namespace gpu {
220
221 CopyTextureCHROMIUMResourceManager::CopyTextureCHROMIUMResourceManager()
222   : initialized_(false),
223     buffer_id_(0),
224     framebuffer_(0) {
225   for (int i = 0; i < kNumPrograms; ++i) {
226     programs_[i] = 0;
227     matrix_handle_[i] = 0;
228     sampler_locations_[i] = 0;
229   }
230 }
231
232 void CopyTextureCHROMIUMResourceManager::Initialize(
233     const gles2::GLES2Decoder* decoder) {
234   COMPILE_ASSERT(
235       kVertexPositionAttrib == 0u,
236       Position_attribs_must_be_0);
237
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");
242
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,
247                GL_STATIC_DRAW);
248
249   glGenFramebuffersEXT(1, &framebuffer_);
250
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) {
258       continue;
259     }
260     const char* shader_source = shader_infos[shader].source;
261     glShaderSource(shaders[shader], 1, &shader_source, 0);
262     glCompileShader(shaders[shader]);
263 #ifndef NDEBUG
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.";
268 #endif
269   }
270
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) {
275       continue;
276     }
277     programs_[program] = glCreateProgram();
278     glAttachShader(programs_[program], shaders[0]);
279     glAttachShader(programs_[program], shaders[program + 1]);
280
281     glBindAttribLocation(programs_[program], kVertexPositionAttrib,
282                          "a_position");
283
284     glLinkProgram(programs_[program]);
285 #ifndef NDEBUG
286     GLint linked;
287     glGetProgramiv(programs_[program], GL_LINK_STATUS, &linked);
288     if (!linked)
289       DLOG(ERROR) << "CopyTextureCHROMIUM: program link failure.";
290 #endif
291
292     sampler_locations_[program] = glGetUniformLocation(programs_[program],
293                                                       "u_texSampler");
294
295     matrix_handle_[program] = glGetUniformLocation(programs_[program],
296                                                    "u_matrix");
297   }
298
299   for (int shader = 0; shader < kNumShaders; ++shader)
300     glDeleteShader(shaders[shader]);
301
302   decoder->RestoreBufferBindings();
303
304   initialized_ = true;
305 }
306
307 void CopyTextureCHROMIUMResourceManager::Destroy() {
308   if (!initialized_)
309     return;
310
311   glDeleteFramebuffersEXT(1, &framebuffer_);
312
313   for (int program = 0; program < kNumPrograms; ++program) {
314     if (programs_[program])
315       glDeleteProgram(programs_[program]);
316   }
317
318   glDeleteBuffersARB(1, &buffer_id_);
319 }
320
321 void CopyTextureCHROMIUMResourceManager::DoCopyTexture(
322     const gles2::GLES2Decoder* decoder,
323     GLenum source_target,
324     GLenum dest_target,
325     GLuint source_id,
326     GLuint dest_id,
327     GLint level,
328     GLsizei width,
329     GLsizei height,
330     bool flip_y,
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);
341 }
342
343 void CopyTextureCHROMIUMResourceManager::DoCopyTextureWithTransform(
344     const gles2::GLES2Decoder* decoder,
345     GLenum source_target,
346     GLenum dest_target,
347     GLuint source_id,
348     GLuint dest_id,
349     GLint level,
350     GLsizei width,
351     GLsizei height,
352     bool flip_y,
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);
358   if (!initialized_) {
359     DLOG(ERROR) << "CopyTextureCHROMIUM: Uninitialized manager.";
360     return;
361   }
362
363   GLuint program = GetProgram(
364       flip_y, premultiply_alpha, unpremultiply_alpha,
365       source_target == GL_TEXTURE_EXTERNAL_OES);
366   glUseProgram(programs_[program]);
367
368 #ifndef NDEBUG
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.";
374     return;
375   }
376 #endif
377
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,
389                             dest_id, level);
390
391 #ifndef NDEBUG
392   GLenum fb_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER);
393   if (GL_FRAMEBUFFER_COMPLETE != fb_status) {
394     DLOG(ERROR) << "CopyTextureCHROMIUM: Incomplete framebuffer.";
395   } else
396 #endif
397   {
398     glEnableVertexAttribArray(kVertexPositionAttrib);
399
400     glBindBuffer(GL_ARRAY_BUFFER, buffer_id_);
401     glVertexAttribPointer(kVertexPositionAttrib, 4, GL_FLOAT, GL_FALSE,
402                           4 * sizeof(GLfloat), 0);
403
404     glUniform1i(sampler_locations_[program], 0);
405
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);
411
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);
418     glDisable(GL_BLEND);
419
420     glViewport(0, 0, width, height);
421     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
422   }
423
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();
433 }
434
435 }  // namespace
436