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

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: fix a small error 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
27 SRGBConverter::SRGBConverter(
28 const gles2::FeatureInfo* feature_info)
29 : feature_info_(feature_info) {
30 DCHECK(feature_info->gl_version_info().is_desktop_core_profile);
Zhenyao Mo 2016/08/29 23:36:50 Again, why desktop core profile only?
yunchao 2016/08/31 09:18:45 I have removed it.
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 " gl_Position = vec4((quad_positions[gl_VertexID] * 2.0) - 1.0, 0.0, "
62 "1.0);\n"
Zhenyao Mo 2016/08/29 23:36:50 nit: ugly formatting
yunchao 2016/08/31 09:18:45 Done.
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 const char* fs_source =
73 "#version 150\n"
74 "uniform sampler2D u_source_texture;\n"
75 "in vec2 v_texcoord;\n"
76 "out vec4 output_color;\n"
77 "\n"
78 "float decode(float color)\n"
79 "{\n"
80 " float decoded_color;\n"
81 " if (color <= 0.04045) {\n"
82 " decoded_color = color / 12.92;\n"
83 " } else {\n"
84 " decoded_color = (color + 0.055) / 1.055;\n"
85 " decoded_color = pow(decoded_color, 4.2);\n"
86 " }\n"
87 " return decoded_color;\n"
88 "}\n"
89 "\n"
90 "void main()\n"
91 "{\n"
92 " vec4 c = texture(u_source_texture, v_texcoord);\n"
93 " output_color = vec4(decode(c.r), decode(c.g), decode(c.b), c.a);\n"
yunchao 2016/08/29 15:16:52 Obviously, the decode function in shader are not n
Zhenyao Mo 2016/08/29 23:36:50 As I pointed in the original bug, 4.2, 4.3, and 4.
yunchao 2016/08/31 09:18:45 My MacOS is OGL 4.1, but it doesn't need to decode
94 " output_color = c;\n"
95 "}\n";
96
97 GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
98 CompileShader(fs, fs_source);
99 glAttachShader(srgb_decoder_program_, fs);
100 glDeleteShader(fs);
101
102 glLinkProgram(srgb_decoder_program_);
103 #ifndef NDEBUG
104 GLint linked = 0;
105 glGetProgramiv(srgb_decoder_program_, GL_LINK_STATUS, &linked);
106 if (!linked) {
107 DLOG(ERROR) << "BlitFramebuffer: program link failure.";
108 }
109 #endif
110
111 GLuint texture_uniform =
112 glGetUniformLocation(srgb_decoder_program_, "u_source_texture");
113 glUseProgram(srgb_decoder_program_);
114 glUniform1i(texture_uniform, 0);
115
116 glGenTextures(srgb_decoder_textures_.size(), srgb_decoder_textures_.data());
117 glActiveTexture(GL_TEXTURE0);
118 for (auto srgb_decoder_texture : srgb_decoder_textures_) {
119 glBindTexture(GL_TEXTURE_2D, srgb_decoder_texture);
120
121 // Use nearest, non-mipmapped sampling with the srgb decoder texture
122 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
123 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
Zhenyao Mo 2016/08/29 23:36:50 I think LINEAR is the correct filter. You should a
yunchao 2016/08/31 09:18:45 Done. Currently there is neither filtering nor rep
124 }
125
126 glGenFramebuffersEXT(1, &srgb_decoder_fbo_);
127 glGenVertexArraysOES(1, &srgb_decoder_vao_);
128
129 decoder->RestoreTextureUnitBindings(0);
130 decoder->RestoreActiveTexture();
131 decoder->RestoreProgramBindings();
132
133 srgb_decoder_initialized_ = true;
134 }
135
136 void SRGBConverter::InitializeSRGBEncoder(
137 const gles2::GLES2Decoder* decoder) {
138 if (srgb_encoder_initialized_) {
139 return;
140 }
141
142 srgb_encoder_program_ = glCreateProgram();
143
144 // Compile the vertex shader
145 const char* vs_source =
146 "#version 150\n"
147 "out vec2 v_texcoord;\n"
148 "\n"
149 "void main()\n"
150 "{\n"
151 " const vec2 quad_positions[6] = vec2[6]\n"
152 " (\n"
153 " vec2(0.0f, 0.0f),\n"
154 " vec2(0.0f, 1.0f),\n"
155 " vec2(1.0f, 0.0f),\n"
156 "\n"
157 " vec2(0.0f, 1.0f),\n"
158 " vec2(1.0f, 0.0f),\n"
159 " vec2(1.0f, 1.0f)\n"
160 " );\n"
161 "\n"
162 " gl_Position = vec4((quad_positions[gl_VertexID] * 2.0) - 1.0, 0.0, "
163 "1.0);\n"
Zhenyao Mo 2016/08/29 23:36:50 nit: ugly formatting
yunchao 2016/08/31 09:18:44 Done.
164 " v_texcoord = quad_positions[gl_VertexID];\n"
165 "}\n";
166
167 GLuint vs = glCreateShader(GL_VERTEX_SHADER);
168 CompileShader(vs, vs_source);
169 glAttachShader(srgb_encoder_program_, vs);
170 glDeleteShader(vs);
171
172 // Compile the fragment shader
173 const char* fs_source =
174 "#version 150\n"
175 "uniform sampler2D u_source_texture;\n"
176 "in vec2 v_texcoord;\n"
177 "out vec4 output_color;\n"
178 "\n"
179 "float encode(float color)\n"
180 "{\n"
181 " float encoded_color;\n"
182 " if (color < 0.0031308) {\n"
183 " encoded_color = color * 12.92;\n"
184 " } else {\n"
185 " encoded_color = pow(color, 0.41666) * 1.055 - 0.055;\n"
186 " }\n"
187 " return encoded_color;\n"
188 "}\n"
189 "\n"
190 "void main()\n"
191 "{\n"
192 " vec4 c = texture(u_source_texture, v_texcoord);\n"
193 " output_color = vec4(encode(c.r), encode(c.g), encode(c.b), c.a);\n"
194 "}\n";
195
196 GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
197 CompileShader(fs, fs_source);
198 glAttachShader(srgb_encoder_program_, fs);
199 glDeleteShader(fs);
200
201 glLinkProgram(srgb_encoder_program_);
202 #ifndef NDEBUG
203 GLint linked = 0;
204 glGetProgramiv(srgb_encoder_program_, GL_LINK_STATUS, &linked);
205 if (!linked) {
206 DLOG(ERROR) << "SRGB Encoder for BlitFramebuffer: program link failure.";
207 }
208 #endif
209
210 GLuint texture_uniform =
211 glGetUniformLocation(srgb_encoder_program_, "u_source_texture");
212 glUseProgram(srgb_encoder_program_);
213 glUniform1i(texture_uniform, 0);
214
215 glGenTextures(srgb_encoder_textures_.size(), srgb_encoder_textures_.data());
216 glActiveTexture(GL_TEXTURE0);
217 for (auto srgb_encoder_texture : srgb_encoder_textures_) {
218 glBindTexture(GL_TEXTURE_2D, srgb_encoder_texture);
219
220 // Use nearest, non-mipmapped sampling with the srgb encoder texture
221 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
222 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
223 }
224
225 glGenFramebuffersEXT(1, &srgb_encoder_fbo_);
226 glGenVertexArraysOES(1, &srgb_encoder_vao_);
227
228 decoder->RestoreTextureUnitBindings(0);
229 decoder->RestoreActiveTexture();
230 decoder->RestoreProgramBindings();
231
232 srgb_encoder_initialized_ = true;
233 }
234
235 void SRGBConverter::Destroy() {
236 if (srgb_decoder_initialized_) {
237 glDeleteProgram(srgb_decoder_program_);
238 srgb_decoder_program_ = 0;
239
240 glDeleteTextures(srgb_decoder_textures_.size(),
241 srgb_decoder_textures_.data());
242 srgb_decoder_textures_.fill(0);
243
244 glDeleteFramebuffersEXT(1, &srgb_decoder_fbo_);
245 srgb_decoder_fbo_ = 0;
246
247 glDeleteVertexArraysOES(1, &srgb_decoder_vao_);
248 srgb_decoder_vao_ = 0;
249
250 srgb_decoder_initialized_ = false;
251 }
252
253 if (srgb_encoder_initialized_) {
254 glDeleteProgram(srgb_encoder_program_);
255 srgb_encoder_program_ = 0;
256
257 glDeleteTextures(srgb_encoder_textures_.size(),
258 srgb_encoder_textures_.data());
259 srgb_encoder_textures_.fill(0);
260
261 glDeleteFramebuffersEXT(1, &srgb_encoder_fbo_);
262 srgb_encoder_fbo_ = 0;
263
264 glDeleteVertexArraysOES(1, &srgb_encoder_vao_);
265 srgb_encoder_vao_ = 0;
266
267 srgb_encoder_initialized_ = false;
268 }
269 }
270
271 void SRGBConverter::SRGBToLinear(
272 const gles2::GLES2Decoder* decoder,
273 GLint srcX0,
274 GLint srcY0,
275 GLint srcX1,
276 GLint srcY1,
277 GLint dstX0,
278 GLint dstY0,
279 GLint dstX1,
280 GLint dstY1,
281 GLbitfield mask,
282 GLenum filter,
283 const gfx::Size& framebuffer_size,
284 GLuint src_framebuffer,
285 GLenum src_framebuffer_internal_format,
286 GLuint dst_framebuffer,
287 GLenum dst_framebuffer_internal_format,
288 GLenum dst_framebuffer_format,
289 GLenum dst_framebuffer_type) {
290
291 DCHECK(srgb_decoder_initialized_);
292
293 // Copy the image from framebuffer to the first srgb decoder texture
294 glBindFramebufferEXT(GL_FRAMEBUFFER, src_framebuffer);
295 glActiveTexture(GL_TEXTURE0);
296 glBindTexture(GL_TEXTURE_2D, srgb_decoder_textures_[0]);
297
298 // We should not copy pixels outside of the read framebuffer. If we read
299 // these pixels, they would become in-bound during BlitFramebuffer. However,
300 // Out-of-bounds pixels will be initialized to 0 in CopyTexSubImage. But they
301 // should read as if the GL_CLAMP_TO_EDGE texture mapping mode were applied
302 // during BlitFramebuffer when the filter is GL_LINEAR.
303 GLuint x = srcX1 > srcX0 ? srcX0 : srcX1;
304 GLuint width = srcX1 > srcX0 ? srcX1 - srcX0 : srcX0 - srcX1;
305 GLuint y = srcY1 > srcY0 ? srcY0 : srcY1;
306 GLuint height = srcY1 > srcY0 ? srcY1 - srcY0 : srcY0 - srcY1;
307 gfx::Rect c(0, 0, framebuffer_size.width(), framebuffer_size.height());
308 c.Intersect(gfx::Rect(x, y, width, height));
309 glCopyTexImage2D(GL_TEXTURE_2D, 0, src_framebuffer_internal_format,
Zhenyao Mo 2016/08/29 23:36:50 If the original fbo read_buffer is a texture, can
yunchao 2016/08/31 09:18:45 Add a TODO first, will revisit this soon.
310 c.x(), c.y(), c.width(), c.height(), 0);
311
312 // Make a temporary framebuffer using the second srgb decoder texture to
313 // render the converted (linear to srgb) result to.
314 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
315
316 glBindTexture(GL_TEXTURE_2D, srgb_decoder_textures_[1]);
317 glTexImage2D(GL_TEXTURE_2D, 0, dst_framebuffer_internal_format,
318 c.width(), c.height(),
Zhenyao Mo 2016/08/30 00:22:05 Thinking more about this, it seems to me that here
yunchao 2016/08/31 09:18:45 As we discussed, the real blitFramebuffer can clam
319 0, dst_framebuffer_format, dst_framebuffer_type, nullptr);
320 glBindFramebufferEXT(GL_FRAMEBUFFER, srgb_decoder_fbo_);
321 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
322 srgb_decoder_textures_[1], 0);
323
324 // Render to the second srgb decoder texture,
325 // sampling from the first srgb decoder texture.
326 glUseProgram(srgb_decoder_program_);
327 glViewport(0, 0, width, height);
328 glDisable(GL_SCISSOR_TEST);
329 glDisable(GL_DEPTH_TEST);
330 glDisable(GL_STENCIL_TEST);
331 glDisable(GL_CULL_FACE);
332 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
333 glDepthMask(GL_FALSE);
334 glDisable(GL_BLEND);
335 glDisable(GL_DITHER);
336
337 glBindTexture(GL_TEXTURE_2D, srgb_decoder_textures_[0]);
338 glBindVertexArrayOES(srgb_decoder_vao_);
339
340 glDrawArrays(GL_TRIANGLES, 0, 6);
341
342 // Finally, bind the temporary framebuffer as read framebuffer,
343 // blit the converted texture in temp fbo to the destination texture
344 // in destination framebuffer.
345 glBindFramebufferEXT(GL_READ_FRAMEBUFFER, srgb_decoder_fbo_);
346 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, dst_framebuffer);
347 // Note that the source region has been changed in temp framebuffer
348 glBlitFramebuffer(srcX0 < srcX1 ? 0 : width,
Zhenyao Mo 2016/08/29 23:36:50 This looks incorrect. src region could be clamped
yunchao 2016/08/31 09:18:44 The same as the issue above. blitFramebuffer will
349 srcY0 < srcY1 ? 0 : height,
350 srcX0 < srcX1 ? width : 0,
351 srcY0 < srcY1 ? height : 0,
352 dstX0, dstY0, dstX1, dstY1, mask, filter);
Zhenyao Mo 2016/08/29 23:36:50 I think you need to enable SCISSOR_TEST before wri
yunchao 2016/08/31 09:18:45 The linear color format has this problem too. I wi
353
354 // Restore state
355 decoder->RestoreAllAttributes();
356 decoder->RestoreTextureUnitBindings(0);
357 decoder->RestoreActiveTexture();
358 decoder->RestoreProgramBindings();
359 decoder->RestoreBufferBindings();
360 decoder->RestoreFramebufferBindings();
361 decoder->RestoreGlobalState();
362 }
363
364 void SRGBConverter::LinearToSRGB(
365 const gles2::GLES2Decoder* decoder,
366 GLint srcX0,
367 GLint srcY0,
368 GLint srcX1,
369 GLint srcY1,
370 GLint dstX0,
371 GLint dstY0,
372 GLint dstX1,
373 GLint dstY1,
374 GLbitfield mask,
375 GLenum filter,
376 const gfx::Size& framebuffer_size,
377 GLuint src_framebuffer,
378 GLenum src_framebuffer_internal_format,
379 GLuint dst_framebuffer,
380 GLenum dst_framebuffer_internal_format,
381 GLenum dst_framebuffer_format,
382 GLenum dst_framebuffer_type) {
383
384 DCHECK(srgb_encoder_initialized_);
385
386 // Copy the framebuffer to the first srgb encoder texture
387 glBindFramebufferEXT(GL_FRAMEBUFFER, src_framebuffer);
388 glActiveTexture(GL_TEXTURE0);
389 glBindTexture(GL_TEXTURE_2D, srgb_encoder_textures_[0]);
390
391 // We should not copy pixels outside of the read framebuffer. If we read
392 // these pixels, they would become in-bound during BlitFramebuffer. However,
393 // Out-of-bounds pixels will be initialized to 0 in CopyTexSubImage. But they
394 // should read as if the GL_CLAMP_TO_EDGE texture mapping mode were applied
395 // during BlitFramebuffer when the filter is GL_LINEAR.
396 GLuint x = srcX1 > srcX0 ? srcX0 : srcX1;
397 GLuint width = srcX1 > srcX0 ? srcX1 - srcX0 : srcX0 - srcX1;
398 GLuint y = srcY1 > srcY0 ? srcY0 : srcY1;
399 GLuint height = srcY1 > srcY0 ? srcY1 - srcY0 : srcY0 - srcY1;
400 gfx::Rect c(0, 0, framebuffer_size.width(), framebuffer_size.height());
401 c.Intersect(gfx::Rect(x, y, width, height));
402 glCopyTexImage2D(GL_TEXTURE_2D, 0, src_framebuffer_internal_format,
403 c.x(), c.y(), c.width(), c.height(), 0);
404
405 // Make a temporary framebuffer using the second srgb encoder texture to
406 // render the converted (linear to srgb) result to.
407 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
408
409 glBindTexture(GL_TEXTURE_2D, srgb_encoder_textures_[1]);
410 glTexImage2D(GL_TEXTURE_2D, 0, dst_framebuffer_internal_format,
411 c.width(), c.height(),
412 0, dst_framebuffer_format, dst_framebuffer_type, nullptr);
413 glBindFramebufferEXT(GL_FRAMEBUFFER, srgb_encoder_fbo_);
414 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
415 srgb_encoder_textures_[1], 0);
416
417 // Render to the second srgb encoder texture,
418 // sampling from the first srgb encoder texture.
419 glUseProgram(srgb_encoder_program_);
420 glViewport(0, 0, width, height);
421 glDisable(GL_SCISSOR_TEST);
422 glDisable(GL_DEPTH_TEST);
423 glDisable(GL_STENCIL_TEST);
424 glDisable(GL_CULL_FACE);
425 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
426 glDepthMask(GL_FALSE);
427 glDisable(GL_BLEND);
428 glDisable(GL_DITHER);
429
430 glBindTexture(GL_TEXTURE_2D, srgb_encoder_textures_[0]);
431 glBindVertexArrayOES(srgb_encoder_vao_);
432
433 glDrawArrays(GL_TRIANGLES, 0, 6);
434
435 // Finally, bind the temporary framebuffer as read framebuffer,
436 // blit the converted texture in temp fbo to the destination texture
437 // in destination framebuffer.
438 glBindFramebufferEXT(GL_READ_FRAMEBUFFER, srgb_encoder_fbo_);
439 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, dst_framebuffer);
440 // Note that the source region has been changed in temp framebuffer
441 glBlitFramebuffer(srcX0 < srcX1 ? 0 : width,
Zhenyao Mo 2016/08/29 23:36:50 I think you need to enable SCISSOR_TEST before wri
yunchao 2016/08/31 09:18:45 Acknowledged.
442 srcY0 < srcY1 ? 0 : height,
443 srcX0 < srcX1 ? width : 0,
444 srcY0 < srcY1 ? height : 0,
445 dstX0, dstY0, dstX1, dstY1, mask, filter);
Zhenyao Mo 2016/08/29 23:36:50 Same here, dst region could be wrong if src region
yunchao 2016/08/31 09:18:45 The same as the issue above. blitFramebuffer will
446
447 // Restore state
448 decoder->RestoreAllAttributes();
449 decoder->RestoreTextureUnitBindings(0);
450 decoder->RestoreActiveTexture();
451 decoder->RestoreProgramBindings();
452 decoder->RestoreBufferBindings();
453 decoder->RestoreFramebufferBindings();
454 decoder->RestoreGlobalState();
455 }
456
457 } // namespace gpu
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698