Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(560)

Side by Side Diff: gpu/command_buffer/service/gles2_cmd_srgb_converter.cc

Issue 2286593002: [Command Buffer] emulate SRGB color format for BlitFramebuffer in OpenGL (Closed)
Patch Set: addressed feedbacks from zhenyao and qiankun Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2016 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_srgb_converter.h"
6
7 #include "gpu/command_buffer/service/texture_manager.h"
8 #include "ui/gl/gl_version_info.h"
9
10 namespace {
11
12 void CompileShader(GLuint shader, const char* shader_source) {
13 glShaderSource(shader, 1, &shader_source, 0);
14 glCompileShader(shader);
15 #ifndef NDEBUG
16 GLint compile_status;
17 glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
18 if (GL_TRUE != compile_status)
19 DLOG(ERROR) << "CopyTexImage: shader compilation failure.";
20 #endif
21 }
22
23 } // anonymous namespace
24
25 namespace gpu {
26 namespace gles2 {
27
28 SRGBConverter::SRGBConverter(
29 const gles2::FeatureInfo* feature_info)
30 : feature_info_(feature_info) {
31 }
32
33 SRGBConverter::~SRGBConverter() {}
34
35 void SRGBConverter::InitializeSRGBDecoder(
36 const gles2::GLES2Decoder* decoder) {
37 if (srgb_decoder_initialized_) {
38 return;
39 }
40
41 srgb_decoder_program_ = glCreateProgram();
42
43 // Compile the vertex shader
44 const char* vs_source =
45 "#version 150\n"
46 "out vec2 v_texcoord;\n"
47 "\n"
48 "void main()\n"
49 "{\n"
50 " const vec2 quad_positions[6] = vec2[6]\n"
51 " (\n"
52 " vec2(0.0f, 0.0f),\n"
53 " vec2(0.0f, 1.0f),\n"
54 " vec2(1.0f, 0.0f),\n"
55 "\n"
56 " vec2(0.0f, 1.0f),\n"
57 " vec2(1.0f, 0.0f),\n"
58 " vec2(1.0f, 1.0f)\n"
59 " );\n"
60 "\n"
61 " vec2 xy = vec2((quad_positions[gl_VertexID] * 2.0) - 1.0);\n"
62 " gl_Position = vec4(xy, 0.0, 1.0);\n"
63 " v_texcoord = quad_positions[gl_VertexID];\n"
64 "}\n";
65
66 GLuint vs = glCreateShader(GL_VERTEX_SHADER);
67 CompileShader(vs, vs_source);
68 glAttachShader(srgb_decoder_program_, vs);
69 glDeleteShader(vs);
70
71 // Compile the fragment shader
72 // Sampling from a srgb texture and drawing to a linear color buffer, it will
73 // convert the srgb color space to linear color space automatically.
74 // However, sampling from a linear texture and drawing to a srgb color buffer,
75 // it will not convert linear to srgb automatically.
76 const char* fs_source =
77 "#version 150\n"
78 "uniform sampler2D u_source_texture;\n"
79 "in vec2 v_texcoord;\n"
80 "out vec4 output_color;\n"
81 "\n"
82 /* "float decode(float color)\n"
83 "{\n"
84 " float decoded_color;\n"
85 " if (color <= 0.04045) {\n"
86 " decoded_color = color / 12.92;\n"
87 " } else {\n"
88 " decoded_color = (color + 0.055) / 1.055;\n"
89 " decoded_color = pow(decoded_color, 2.4);\n"
90 " }\n"
91 " return decoded_color;\n"
92 "}\n"
93 "\n" */
94 "void main()\n"
95 "{\n"
96 " vec4 c = texture(u_source_texture, v_texcoord);\n"
97 //" output_color = vec4(decode(c.r), decode(c.g), decode(c.b), c.a);\n"
98 " output_color = c;\n"
99 "}\n";
100
101 GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
102 CompileShader(fs, fs_source);
103 glAttachShader(srgb_decoder_program_, fs);
104 glDeleteShader(fs);
105
106 glLinkProgram(srgb_decoder_program_);
107 #ifndef NDEBUG
108 GLint linked = 0;
109 glGetProgramiv(srgb_decoder_program_, GL_LINK_STATUS, &linked);
110 if (!linked) {
111 DLOG(ERROR) << "BlitFramebuffer: program link failure.";
112 }
113 #endif
114
115 GLuint texture_uniform =
116 glGetUniformLocation(srgb_decoder_program_, "u_source_texture");
117 glUseProgram(srgb_decoder_program_);
118 glUniform1i(texture_uniform, 0);
119
120 glGenTextures(srgb_decoder_textures_.size(), srgb_decoder_textures_.data());
121 glActiveTexture(GL_TEXTURE0);
122 for (auto srgb_decoder_texture : srgb_decoder_textures_) {
123 glBindTexture(GL_TEXTURE_2D, srgb_decoder_texture);
124
125 // Use nearest, non-mipmapped sampling with the srgb decoder texture
126 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
127 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
128 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
129 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
130 }
131
132 glGenFramebuffersEXT(1, &srgb_decoder_fbo_);
133 glGenVertexArraysOES(1, &srgb_decoder_vao_);
134
135 decoder->RestoreTextureUnitBindings(0);
136 decoder->RestoreActiveTexture();
137 decoder->RestoreProgramBindings();
138
139 srgb_decoder_initialized_ = true;
140 }
141
142 void SRGBConverter::InitializeSRGBEncoder(
143 const gles2::GLES2Decoder* decoder) {
144 if (srgb_encoder_initialized_) {
145 return;
146 }
147
148 srgb_encoder_program_ = glCreateProgram();
149
150 // Compile the vertex shader
151 const char* vs_source =
152 "#version 150\n"
153 "out vec2 v_texcoord;\n"
154 "\n"
155 "void main()\n"
156 "{\n"
157 " const vec2 quad_positions[6] = vec2[6]\n"
158 " (\n"
159 " vec2(0.0f, 0.0f),\n"
160 " vec2(0.0f, 1.0f),\n"
161 " vec2(1.0f, 0.0f),\n"
162 "\n"
163 " vec2(0.0f, 1.0f),\n"
164 " vec2(1.0f, 0.0f),\n"
165 " vec2(1.0f, 1.0f)\n"
166 " );\n"
167 "\n"
168 " vec2 xy = vec2((quad_positions[gl_VertexID] * 2.0) - 1.0);\n"
169 " gl_Position = vec4(xy, 0.0, 1.0);\n"
170 " v_texcoord = quad_positions[gl_VertexID];\n"
171 "}\n";
172
173 GLuint vs = glCreateShader(GL_VERTEX_SHADER);
174 CompileShader(vs, vs_source);
175 glAttachShader(srgb_encoder_program_, vs);
176 glDeleteShader(vs);
177
178 // Compile the fragment shader
179 const char* fs_source =
180 "#version 150\n"
181 "uniform sampler2D u_source_texture;\n"
182 "in vec2 v_texcoord;\n"
183 "out vec4 output_color;\n"
184 "\n"
185 "float encode(float color)\n"
186 "{\n"
187 " float encoded_color;\n"
188 " if (color <= 0.0) {\n"
189 " return 0.0;\n"
190 " } else if (color < 0.0031308) {\n"
191 " return color * 12.92;\n"
192 " } else if (color < 1) {\n"
193 " return pow(color, 0.41666) * 1.055 - 0.055;\n"
194 " } else {\n"
195 " return 1.0;\n"
196 " }\n"
197 "}\n"
198 "\n"
199 "void main()\n"
200 "{\n"
201 " vec4 c = texture(u_source_texture, v_texcoord);\n"
202 " output_color = vec4(encode(c.r), encode(c.g), encode(c.b), c.a);\n"
203 "}\n";
204
205 GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
206 CompileShader(fs, fs_source);
207 glAttachShader(srgb_encoder_program_, fs);
208 glDeleteShader(fs);
209
210 glLinkProgram(srgb_encoder_program_);
211 #ifndef NDEBUG
212 GLint linked = 0;
213 glGetProgramiv(srgb_encoder_program_, GL_LINK_STATUS, &linked);
214 if (!linked) {
215 DLOG(ERROR) << "SRGB Encoder for BlitFramebuffer: program link failure.";
216 }
217 #endif
218
219 GLuint texture_uniform =
220 glGetUniformLocation(srgb_encoder_program_, "u_source_texture");
221 glUseProgram(srgb_encoder_program_);
222 glUniform1i(texture_uniform, 0);
223
224 glGenTextures(srgb_encoder_textures_.size(), srgb_encoder_textures_.data());
225 glActiveTexture(GL_TEXTURE0);
226 for (auto srgb_encoder_texture : srgb_encoder_textures_) {
227 glBindTexture(GL_TEXTURE_2D, srgb_encoder_texture);
228
229 // Use nearest, non-mipmapped sampling with the srgb encoder texture
230 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
231 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
232 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
233 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
234 }
235
236 glGenFramebuffersEXT(1, &srgb_encoder_fbo_);
237 glGenVertexArraysOES(1, &srgb_encoder_vao_);
238
239 decoder->RestoreTextureUnitBindings(0);
240 decoder->RestoreActiveTexture();
241 decoder->RestoreProgramBindings();
242
243 srgb_encoder_initialized_ = true;
244 }
245
246 void SRGBConverter::Destroy() {
247 if (srgb_decoder_initialized_) {
248 glDeleteProgram(srgb_decoder_program_);
249 srgb_decoder_program_ = 0;
250
251 glDeleteTextures(srgb_decoder_textures_.size(),
252 srgb_decoder_textures_.data());
253 srgb_decoder_textures_.fill(0);
254
255 glDeleteFramebuffersEXT(1, &srgb_decoder_fbo_);
256 srgb_decoder_fbo_ = 0;
257
258 glDeleteVertexArraysOES(1, &srgb_decoder_vao_);
259 srgb_decoder_vao_ = 0;
260
261 srgb_decoder_initialized_ = false;
262 }
263
264 if (srgb_encoder_initialized_) {
265 glDeleteProgram(srgb_encoder_program_);
266 srgb_encoder_program_ = 0;
267
268 glDeleteTextures(srgb_encoder_textures_.size(),
269 srgb_encoder_textures_.data());
270 srgb_encoder_textures_.fill(0);
271
272 glDeleteFramebuffersEXT(1, &srgb_encoder_fbo_);
273 srgb_encoder_fbo_ = 0;
274
275 glDeleteVertexArraysOES(1, &srgb_encoder_vao_);
276 srgb_encoder_vao_ = 0;
277
278 srgb_encoder_initialized_ = false;
279 }
280 }
281
282 void SRGBConverter::SRGBToLinear(
283 const gles2::GLES2Decoder* decoder,
284 GLint srcX0,
285 GLint srcY0,
286 GLint srcX1,
287 GLint srcY1,
288 GLint dstX0,
289 GLint dstY0,
290 GLint dstX1,
291 GLint dstY1,
292 GLbitfield mask,
293 GLenum filter,
294 const gfx::Size& framebuffer_size,
295 GLuint src_framebuffer,
296 GLenum src_framebuffer_internal_format,
297 GLuint dst_framebuffer,
298 GLenum dst_framebuffer_internal_format,
299 GLenum dst_framebuffer_format,
300 GLenum dst_framebuffer_type) {
301
302 DCHECK(srgb_decoder_initialized_);
303
304 // Copy the image from framebuffer to the first srgb decoder texture
305 // TODO(yunchao) If the read buffer is a fbo texture, we can sample
306 // directly from that texture. In this way, we can save gpu memory.
307 glBindFramebufferEXT(GL_FRAMEBUFFER, src_framebuffer);
308 glActiveTexture(GL_TEXTURE0);
309 glBindTexture(GL_TEXTURE_2D, srgb_decoder_textures_[0]);
310
311 // We should not copy pixels outside of the read framebuffer. If we read
312 // these pixels, they would become in-bound during BlitFramebuffer. However,
313 // Out-of-bounds pixels will be initialized to 0 in CopyTexSubImage. But they
314 // should read as if the GL_CLAMP_TO_EDGE texture mapping mode were applied
315 // during BlitFramebuffer when the filter is GL_LINEAR.
316 GLuint x = srcX1 > srcX0 ? srcX0 : srcX1;
317 GLuint width = srcX1 > srcX0 ? srcX1 - srcX0 : srcX0 - srcX1;
318 GLuint y = srcY1 > srcY0 ? srcY0 : srcY1;
319 GLuint height = srcY1 > srcY0 ? srcY1 - srcY0 : srcY0 - srcY1;
320 gfx::Rect c(0, 0, framebuffer_size.width(), framebuffer_size.height());
321 c.Intersect(gfx::Rect(x, y, width, height));
322 glCopyTexImage2D(GL_TEXTURE_2D, 0, src_framebuffer_internal_format,
323 c.x(), c.y(), c.width(), c.height(), 0);
324
325 // Make a temporary framebuffer using the second srgb decoder texture to
326 // render the converted (linear to srgb) result to.
327 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
328
329 glBindTexture(GL_TEXTURE_2D, srgb_decoder_textures_[1]);
330 glTexImage2D(GL_TEXTURE_2D, 0, dst_framebuffer_internal_format,
331 c.width(), c.height(),
332 0, dst_framebuffer_format, dst_framebuffer_type, nullptr);
333 glBindFramebufferEXT(GL_FRAMEBUFFER, srgb_decoder_fbo_);
334 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
335 srgb_decoder_textures_[1], 0);
336
337 // Render to the second srgb decoder texture,
338 // sampling from the first srgb decoder texture.
339 glUseProgram(srgb_decoder_program_);
340 glViewport(0, 0, width, height);
341 glDisable(GL_SCISSOR_TEST);
342 glDisable(GL_DEPTH_TEST);
343 glDisable(GL_STENCIL_TEST);
344 glDisable(GL_CULL_FACE);
345 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
346 glDepthMask(GL_FALSE);
347 glDisable(GL_BLEND);
348 glDisable(GL_DITHER);
349
350 glBindTexture(GL_TEXTURE_2D, srgb_decoder_textures_[0]);
351 glBindVertexArrayOES(srgb_decoder_vao_);
352
353 glDrawArrays(GL_TRIANGLES, 0, 6);
354
355 // Finally, bind the temporary framebuffer as read framebuffer,
356 // blit the converted texture in temp fbo to the destination texture
357 // in destination framebuffer.
358 glBindFramebufferEXT(GL_READ_FRAMEBUFFER, srgb_decoder_fbo_);
359 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, dst_framebuffer);
360 // Note that the source region has been changed in temp framebuffer
361 glBlitFramebuffer(srcX0 < srcX1 ? 0 : width,
362 srcY0 < srcY1 ? 0 : height,
363 srcX0 < srcX1 ? width : 0,
364 srcY0 < srcY1 ? height : 0,
365 dstX0, dstY0, dstX1, dstY1, mask, filter);
Zhenyao Mo 2016/09/01 19:28:33 I still think this is incorrect. At glCopyTexImag
yunchao 2016/09/02 14:11:16 Got it. You are correct. This algorithm would make
366
367 // Restore state
368 decoder->RestoreAllAttributes();
369 decoder->RestoreTextureUnitBindings(0);
370 decoder->RestoreActiveTexture();
371 decoder->RestoreProgramBindings();
372 decoder->RestoreBufferBindings();
373 decoder->RestoreFramebufferBindings();
374 decoder->RestoreGlobalState();
375 }
376
377 void SRGBConverter::LinearToSRGB(
378 const gles2::GLES2Decoder* decoder,
379 GLint srcX0,
380 GLint srcY0,
381 GLint srcX1,
382 GLint srcY1,
383 GLint dstX0,
384 GLint dstY0,
385 GLint dstX1,
386 GLint dstY1,
387 GLbitfield mask,
388 GLenum filter,
389 const gfx::Size& framebuffer_size,
390 GLuint src_framebuffer,
391 GLenum src_framebuffer_internal_format,
392 GLuint dst_framebuffer,
393 GLenum dst_framebuffer_internal_format,
394 GLenum dst_framebuffer_format,
395 GLenum dst_framebuffer_type) {
396
397 DCHECK(srgb_encoder_initialized_);
398
399 // Copy the framebuffer to the first srgb encoder texture
400 glBindFramebufferEXT(GL_FRAMEBUFFER, src_framebuffer);
401 glActiveTexture(GL_TEXTURE0);
402 glBindTexture(GL_TEXTURE_2D, srgb_encoder_textures_[0]);
403
404 // We should not copy pixels outside of the read framebuffer. If we read
405 // these pixels, they would become in-bound during BlitFramebuffer. However,
406 // Out-of-bounds pixels will be initialized to 0 in CopyTexSubImage. But they
407 // should read as if the GL_CLAMP_TO_EDGE texture mapping mode were applied
408 // during BlitFramebuffer when the filter is GL_LINEAR.
409 GLuint x = srcX1 > srcX0 ? srcX0 : srcX1;
410 GLuint width = srcX1 > srcX0 ? srcX1 - srcX0 : srcX0 - srcX1;
411 GLuint y = srcY1 > srcY0 ? srcY0 : srcY1;
412 GLuint height = srcY1 > srcY0 ? srcY1 - srcY0 : srcY0 - srcY1;
413 gfx::Rect c(0, 0, framebuffer_size.width(), framebuffer_size.height());
414 c.Intersect(gfx::Rect(x, y, width, height));
415 glCopyTexImage2D(GL_TEXTURE_2D, 0, src_framebuffer_internal_format,
416 c.x(), c.y(), c.width(), c.height(), 0);
417
418 // Make a temporary framebuffer using the second srgb encoder texture to
419 // render the converted (linear to srgb) result to.
420 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
421
422 glBindTexture(GL_TEXTURE_2D, srgb_encoder_textures_[1]);
423 glTexImage2D(GL_TEXTURE_2D, 0, dst_framebuffer_internal_format,
424 c.width(), c.height(),
425 0, dst_framebuffer_format, dst_framebuffer_type, nullptr);
426 glBindFramebufferEXT(GL_FRAMEBUFFER, srgb_encoder_fbo_);
427 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
428 srgb_encoder_textures_[1], 0);
429
430 // Render to the second srgb encoder texture,
431 // sampling from the first srgb encoder texture.
432 glUseProgram(srgb_encoder_program_);
433 glViewport(0, 0, width, height);
434 glDisable(GL_SCISSOR_TEST);
435 glDisable(GL_DEPTH_TEST);
436 glDisable(GL_STENCIL_TEST);
437 glDisable(GL_CULL_FACE);
438 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
439 glDepthMask(GL_FALSE);
440 glDisable(GL_BLEND);
441 glDisable(GL_DITHER);
442
443 glBindTexture(GL_TEXTURE_2D, srgb_encoder_textures_[0]);
444 glBindVertexArrayOES(srgb_encoder_vao_);
445
446 glDrawArrays(GL_TRIANGLES, 0, 6);
447
448 // Finally, bind the temporary framebuffer as read framebuffer,
449 // blit the converted texture in temp fbo to the destination texture
450 // in destination framebuffer.
451 glBindFramebufferEXT(GL_READ_FRAMEBUFFER, srgb_encoder_fbo_);
452 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, dst_framebuffer);
453 // Note that the source region has been changed in temp framebuffer
454 glBlitFramebuffer(srcX0 < srcX1 ? 0 : width,
455 srcY0 < srcY1 ? 0 : height,
456 srcX0 < srcX1 ? width : 0,
457 srcY0 < srcY1 ? height : 0,
458 dstX0, dstY0, dstX1, dstY1, mask, filter);
Zhenyao Mo 2016/09/01 19:28:33 Same situation here.
yunchao 2016/09/02 14:11:16 Done.
459
460 // Restore state
461 decoder->RestoreAllAttributes();
462 decoder->RestoreTextureUnitBindings(0);
463 decoder->RestoreActiveTexture();
464 decoder->RestoreProgramBindings();
465 decoder->RestoreBufferBindings();
466 decoder->RestoreFramebufferBindings();
467 decoder->RestoreGlobalState();
468 }
469
470 } // namespace gles2.
471 } // namespace gpu
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698