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

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 piman and kbr 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
« no previous file with comments | « gpu/command_buffer/service/gles2_cmd_srgb_converter.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
36
37 void SRGBConverter::InitializeSRGBConverterProgram() {
38 if (srgb_converter_program_) {
39 return;
40 }
41
42 srgb_converter_program_ = glCreateProgram();
43
44 // Compile the vertex shader
45 const char* vs_source =
46 "#version 150\n"
47 "out vec2 v_texcoord;\n"
48 "\n"
49 "void main()\n"
50 "{\n"
51 " const vec2 quad_positions[6] = vec2[6]\n"
52 " (\n"
53 " vec2(0.0f, 0.0f),\n"
54 " vec2(0.0f, 1.0f),\n"
55 " vec2(1.0f, 0.0f),\n"
56 "\n"
57 " vec2(0.0f, 1.0f),\n"
58 " vec2(1.0f, 0.0f),\n"
59 " vec2(1.0f, 1.0f)\n"
60 " );\n"
61 "\n"
62 " vec2 xy = vec2((quad_positions[gl_VertexID] * 2.0) - 1.0);\n"
63 " gl_Position = vec4(xy, 0.0, 1.0);\n"
64 " v_texcoord = quad_positions[gl_VertexID];\n"
65 "}\n";
66 GLuint vs = glCreateShader(GL_VERTEX_SHADER);
67 CompileShader(vs, vs_source);
68 glAttachShader(srgb_converter_program_, vs);
69 glDeleteShader(vs);
70
71 // Compile the fragment shader
72
73 // Sampling texels from a srgb texture to a linear image, it will convert
74 // the srgb color space to linear color space automatically as a part of
75 // filtering. See the section <sRGB Texture Color Conversion> in GLES and
76 // OpenGL spec. So during decoding, we don't need to use the equation to
77 // explicitly decode srgb to linear in fragment shader.
78 // Drawing to a srgb image, it will convert linear to srgb automatically.
79 // See the section <sRGB Conversion> in GLES and OpenGL spec. So during
80 // encoding, we don't need to use the equation to explicitly encode linear
81 // to srgb in fragment shader.
82 // As a result, we just use a simple fragment shader to do srgb conversion.
83 const char* fs_source =
84 "#version 150\n"
85 "uniform sampler2D u_source_texture;\n"
86 "in vec2 v_texcoord;\n"
87 "out vec4 output_color;\n"
88 "\n"
89 "void main()\n"
90 "{\n"
91 " vec4 c = texture(u_source_texture, v_texcoord);\n"
92 " output_color = c;\n"
93 "}\n";
94
95 GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
96 CompileShader(fs, fs_source);
97 glAttachShader(srgb_converter_program_, fs);
98 glDeleteShader(fs);
99
100 glLinkProgram(srgb_converter_program_);
101 #ifndef NDEBUG
102 GLint linked = 0;
103 glGetProgramiv(srgb_converter_program_, GL_LINK_STATUS, &linked);
104 if (!linked) {
105 DLOG(ERROR) << "BlitFramebuffer: program link failure.";
106 }
107 #endif
108
109 GLuint texture_uniform =
110 glGetUniformLocation(srgb_converter_program_, "u_source_texture");
111 glUseProgram(srgb_converter_program_);
112 glUniform1i(texture_uniform, 0);
113 }
114
115 void SRGBConverter::InitializeSRGBConverter(
116 const gles2::GLES2Decoder* decoder) {
117 if (srgb_converter_initialized_) {
118 return;
119 }
120
121 InitializeSRGBConverterProgram();
122
123 glGenTextures(
124 srgb_converter_textures_.size(), srgb_converter_textures_.data());
125 glActiveTexture(GL_TEXTURE0);
126 for (auto srgb_converter_texture : srgb_converter_textures_) {
127 glBindTexture(GL_TEXTURE_2D, srgb_converter_texture);
128
129 // Use linear, non-mipmapped sampling with the srgb converter texture
130 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
131 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
132 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
133 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
134 }
135
136 glGenFramebuffersEXT(1, &srgb_decoder_fbo_);
137 glGenFramebuffersEXT(1, &srgb_encoder_fbo_);
138
139 glGenVertexArraysOES(1, &srgb_converter_vao_);
140
141 decoder->RestoreTextureUnitBindings(0);
142 decoder->RestoreActiveTexture();
143 decoder->RestoreProgramBindings();
144
145 srgb_converter_initialized_ = true;
146 }
147
148 void SRGBConverter::Destroy() {
149 if (srgb_converter_initialized_) {
150 glDeleteTextures(srgb_converter_textures_.size(),
151 srgb_converter_textures_.data());
152 srgb_converter_textures_.fill(0);
153
154 glDeleteFramebuffersEXT(1, &srgb_decoder_fbo_);
155 srgb_decoder_fbo_ = 0;
156 glDeleteFramebuffersEXT(1, &srgb_encoder_fbo_);
157 srgb_encoder_fbo_ = 0;
158
159 glDeleteVertexArraysOES(1, &srgb_converter_vao_);
160 srgb_converter_vao_ = 0;
161
162 glDeleteProgram(srgb_converter_program_);
163 srgb_converter_program_ = 0;
164
165 srgb_converter_initialized_ = false;
166 }
167 }
168
169 void SRGBConverter::Blit(
170 const gles2::GLES2Decoder* decoder,
171 GLint srcX0,
172 GLint srcY0,
173 GLint srcX1,
174 GLint srcY1,
175 GLint dstX0,
176 GLint dstY0,
177 GLint dstX1,
178 GLint dstY1,
179 GLbitfield mask,
180 GLenum filter,
181 const gfx::Size& framebuffer_size,
182 GLuint src_framebuffer,
183 GLenum src_framebuffer_internal_format,
184 GLenum src_framebuffer_format,
185 GLenum src_framebuffer_type,
186 GLuint dst_framebuffer,
187 bool decode,
188 bool encode) {
189 // This function blits srgb image in src fb to srgb image in dst fb.
190 // The steps are:
191 // 1) Copy and crop pixels from source srgb image to the 1st texture(srgb).
192 // 2) Sampling from the 1st texture and drawing to the 2nd texture(linear).
193 // During this step, color space is converted from srgb to linear.
194 // 3) Blit pixels from the 2nd texture to the 3rd texture(linear).
195 // 4) Sampling from the 3rd texture and drawing to the dst image(srgb).
196 // During this step, color space is converted from linear to srgb.
197 // If we need to blit from linear to srgb or vice versa, some steps will be
198 // skipped.
199 DCHECK(srgb_converter_initialized_);
200
201 // Set the states
202 glActiveTexture(GL_TEXTURE0);
203 glDisable(GL_SCISSOR_TEST);
204 glDisable(GL_DEPTH_TEST);
205 glDisable(GL_STENCIL_TEST);
206 glDisable(GL_CULL_FACE);
207 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
208 glDepthMask(GL_FALSE);
209 glDisable(GL_BLEND);
210 glDisable(GL_DITHER);
211
212 // Copy the image from read buffer to the 1st texture(srgb).
213 // TODO(yunchao) If the read buffer is a fbo texture, we can sample
214 // directly from that texture. In this way, we can save gpu memory.
215 GLuint width_read = 0, height_read = 0, xoffset = 0, yoffset = 0;
216 if (decode) {
217 glBindFramebufferEXT(GL_FRAMEBUFFER, src_framebuffer);
218 glBindTexture(GL_TEXTURE_2D, srgb_converter_textures_[0]);
219
220 // We should not copy pixels outside of the read framebuffer. If we read
221 // these pixels, they would become in-bound during BlitFramebuffer. However,
222 // Out-of-bounds pixels will be initialized to 0 in CopyTexSubImage.
223 // But they should read as if the GL_CLAMP_TO_EDGE texture mapping mode
224 // were applied during BlitFramebuffer when the filter is GL_LINEAR.
225 GLuint x = srcX1 > srcX0 ? srcX0 : srcX1;
226 GLuint y = srcY1 > srcY0 ? srcY0 : srcY1;
227 width_read = srcX1 > srcX0 ? srcX1 - srcX0 : srcX0 - srcX1;
228 height_read = srcY1 > srcY0 ? srcY1 - srcY0 : srcY0 - srcY1;
229 gfx::Rect c(0, 0, framebuffer_size.width(), framebuffer_size.height());
230 c.Intersect(gfx::Rect(x, y, width_read, height_read));
231 xoffset = c.x() - x;
232 yoffset = c.y() - y;
233 glCopyTexImage2D(GL_TEXTURE_2D, 0, src_framebuffer_internal_format,
234 c.x(), c.y(), c.width(), c.height(), 0);
235
236 // Make a temporary linear texture as the 2nd texture, where we
237 // render the converted (srgb to linear) result to.
238 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
239
240 glBindTexture(GL_TEXTURE_2D, srgb_converter_textures_[1]);
241 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
242 c.width(), c.height(),
243 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
244 glBindFramebufferEXT(GL_FRAMEBUFFER, srgb_decoder_fbo_);
245 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
246 GL_TEXTURE_2D, srgb_converter_textures_[1], 0);
247
248 // Sampling from the 1st texture(srgb) and drawing to the
249 // 2nd texture(linear),
250 glUseProgram(srgb_converter_program_);
251 glViewport(0, 0, width_read, height_read);
252
253 glBindTexture(GL_TEXTURE_2D, srgb_converter_textures_[0]);
254 glBindVertexArrayOES(srgb_converter_vao_);
255
256 glDrawArrays(GL_TRIANGLES, 0, 6);
257 } else {
258 // Set approriate read framebuffer if decoding is skipped.
259 glBindFramebufferEXT(GL_READ_FRAMEBUFFER, src_framebuffer);
260 }
261
262 // Create the 3rd texture(linear) as encoder_fbo's draw buffer. But we can
263 // reuse the 1st texture and re-allocate the image. Then Blit framebuffer
264 // from the 2nd texture(linear) to the 3rd texture. Filtering is done
265 // during bliting. Note that the src and dst coordinates may be reversed.
266 GLuint width_draw = 0, height_draw = 0;
267 if (encode) {
268 glBindTexture(GL_TEXTURE_2D, srgb_converter_textures_[0]);
269
270 width_draw = dstX1 > dstX0 ? dstX1 - dstX0 : dstX0 - dstX1;
271 height_draw = dstY1 > dstY0 ? dstY1 - dstY0 : dstY0 - dstY1;
272 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
273 glTexImage2D(
274 GL_TEXTURE_2D, 0, decode ? GL_RGBA : src_framebuffer_internal_format,
275 width_draw, height_draw, 0,
276 decode ? GL_RGBA : src_framebuffer_format,
277 decode ? GL_UNSIGNED_BYTE : src_framebuffer_type,
278 nullptr);
279
280 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, srgb_encoder_fbo_);
281 glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
282 GL_TEXTURE_2D, srgb_converter_textures_[0], 0);
283 } else {
284 // Set approriate draw framebuffer if encoding is skipped.
285 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, dst_framebuffer);
286 }
287
288 glBlitFramebuffer(
289 decode ? (srcX0 < srcX1 ? 0 - xoffset : width_read - xoffset) : srcX0,
290 decode ? (srcY0 < srcY1 ? 0 - yoffset : height_read - yoffset) : srcY0,
291 decode ? (srcX0 < srcX1 ? width_read - xoffset : 0 - xoffset) : srcX1,
292 decode ? (srcY0 < srcY1 ? height_read - yoffset : 0 - yoffset) : srcY1,
293 encode ? (dstX0 < dstX1 ? 0 : width_draw) : dstX0,
294 encode ? (dstY0 < dstY1 ? 0 : height_draw) : dstY0,
295 encode ? (dstX0 < dstX1 ? width_draw : 0) : dstX1,
296 encode ? (dstY0 < dstY1 ? height_draw : 0) : dstY1,
297 mask, filter);
298
299 // Sampling from the 3rd texture(linear) and drawing to the target srgb image.
300 // During this step, color space is converted from linear to srgb. We should
301 // set appropriate viewport to draw to the correct location in target FB.
302 if (encode) {
303 GLuint xstart = dstX0 < dstX1 ? dstX0 : dstX1;
304 GLuint ystart = dstY0 < dstY1 ? dstY0 : dstY1;
305 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, dst_framebuffer);
306 glUseProgram(srgb_converter_program_);
307 glViewport(xstart, ystart, width_draw, height_draw);
308
309 glBindTexture(GL_TEXTURE_2D, srgb_converter_textures_[0]);
310 glBindVertexArrayOES(srgb_converter_vao_);
311
312 glDrawArrays(GL_TRIANGLES, 0, 6);
313 }
314
315 // Restore state
316 decoder->RestoreAllAttributes();
317 decoder->RestoreTextureUnitBindings(0);
318 decoder->RestoreActiveTexture();
319 decoder->RestoreProgramBindings();
320 decoder->RestoreBufferBindings();
321 decoder->RestoreFramebufferBindings();
322 decoder->RestoreGlobalState();
323 }
324
325 } // namespace gles2.
326 } // namespace gpu
OLDNEW
« no previous file with comments | « gpu/command_buffer/service/gles2_cmd_srgb_converter.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698