OLD | NEW |
---|---|
(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(const gles2::FeatureInfo* feature_info) | |
29 : feature_info_(feature_info) {} | |
30 | |
31 SRGBConverter::~SRGBConverter() {} | |
32 | |
33 // Vertex shader, shared by both decoder program and encoder program | |
34 static const char* vs_source = | |
35 "#version 150\n" | |
36 "out vec2 v_texcoord;\n" | |
37 "\n" | |
38 "void main()\n" | |
39 "{\n" | |
40 " const vec2 quad_positions[6] = vec2[6]\n" | |
41 " (\n" | |
42 " vec2(0.0f, 0.0f),\n" | |
43 " vec2(0.0f, 1.0f),\n" | |
44 " vec2(1.0f, 0.0f),\n" | |
45 "\n" | |
46 " vec2(0.0f, 1.0f),\n" | |
47 " vec2(1.0f, 0.0f),\n" | |
48 " vec2(1.0f, 1.0f)\n" | |
49 " );\n" | |
50 "\n" | |
51 " vec2 xy = vec2((quad_positions[gl_VertexID] * 2.0) - 1.0);\n" | |
52 " gl_Position = vec4(xy, 0.0, 1.0);\n" | |
53 " v_texcoord = quad_positions[gl_VertexID];\n" | |
54 "}\n"; | |
55 | |
56 void SRGBConverter::InitializeSRGBDecoder(const gles2::GLES2Decoder* decoder) { | |
57 if (srgb_decoder_initialized_) { | |
58 return; | |
59 } | |
60 | |
61 srgb_decoder_program_ = glCreateProgram(); | |
62 | |
63 // Compile the vertex shader | |
64 GLuint vs = glCreateShader(GL_VERTEX_SHADER); | |
65 CompileShader(vs, vs_source); | |
66 glAttachShader(srgb_decoder_program_, vs); | |
67 glDeleteShader(vs); | |
68 | |
69 // Compile the fragment shader | |
70 | |
71 // Sampling texels from a srgb texture to a linear image, it will convert | |
72 // the srgb color space to linear color space automatically as a part of | |
73 // filtering. See the section <sRGB Texture Color Conversion> in GLES and | |
74 // OpenGL spec. So in decoder, we don't need to decode again. | |
75 // However, sampling texels from a linear texture to a srgb image, it will | |
76 // not convert linear to srgb automatically. Shader should always operates | |
77 // in linear space. So in encoder, we need to encode explicitly in shader. | |
78 const char* fs_source = | |
79 "#version 150\n" | |
80 "uniform sampler2D u_source_texture;\n" | |
81 "in vec2 v_texcoord;\n" | |
82 "out vec4 output_color;\n" | |
83 "\n" | |
84 "void main()\n" | |
85 "{\n" | |
86 " vec4 c = texture(u_source_texture, v_texcoord);\n" | |
87 " output_color = c;\n" | |
88 "}\n"; | |
89 | |
90 GLuint fs = glCreateShader(GL_FRAGMENT_SHADER); | |
91 CompileShader(fs, fs_source); | |
92 glAttachShader(srgb_decoder_program_, fs); | |
93 glDeleteShader(fs); | |
94 | |
95 glLinkProgram(srgb_decoder_program_); | |
96 #ifndef NDEBUG | |
97 GLint linked = 0; | |
98 glGetProgramiv(srgb_decoder_program_, GL_LINK_STATUS, &linked); | |
99 if (!linked) { | |
100 DLOG(ERROR) << "BlitFramebuffer: program link failure."; | |
101 } | |
102 #endif | |
103 | |
104 GLuint texture_uniform = | |
105 glGetUniformLocation(srgb_decoder_program_, "u_source_texture"); | |
106 glUseProgram(srgb_decoder_program_); | |
107 glUniform1i(texture_uniform, 0); | |
108 | |
109 glGenTextures(srgb_decoder_textures_.size(), srgb_decoder_textures_.data()); | |
110 glActiveTexture(GL_TEXTURE0); | |
111 for (auto srgb_decoder_texture : srgb_decoder_textures_) { | |
112 glBindTexture(GL_TEXTURE_2D, srgb_decoder_texture); | |
113 | |
114 // Use linear, non-mipmapped sampling with the srgb decoder texture | |
115 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
116 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
117 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
118 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
119 } | |
120 | |
121 glGenFramebuffersEXT(1, &srgb_decoder_fbo_); | |
122 glGenVertexArraysOES(1, &srgb_decoder_vao_); | |
123 | |
124 decoder->RestoreTextureUnitBindings(0); | |
125 decoder->RestoreActiveTexture(); | |
126 decoder->RestoreProgramBindings(); | |
127 | |
128 srgb_decoder_initialized_ = true; | |
129 } | |
130 | |
131 void SRGBConverter::InitializeSRGBEncoder(const gles2::GLES2Decoder* decoder) { | |
132 if (srgb_encoder_initialized_) { | |
133 return; | |
134 } | |
135 | |
136 srgb_encoder_program_ = glCreateProgram(); | |
137 | |
138 // Compile the vertex shader | |
139 GLuint vs = glCreateShader(GL_VERTEX_SHADER); | |
140 CompileShader(vs, vs_source); | |
141 glAttachShader(srgb_encoder_program_, vs); | |
142 glDeleteShader(vs); | |
143 | |
144 // Compile the fragment shader | |
145 | |
146 // Sampling texels from a srgb texture to a linear image, it will convert | |
147 // the srgb color space to linear color space automatically as a part of | |
148 // filtering. See the section <sRGB Texture Color Conversion> in GLES and | |
149 // OpenGL spec. So in decoder, we don't need to decode again. | |
150 // However, sampling texels from a linear texture to a srgb image, it will | |
151 // not convert linear to srgb automatically. Shader should always operates | |
152 // in linear space. So in encoder, we need to encode explicitly in shader. | |
153 const char* fs_source = | |
154 "#version 150\n" | |
155 "uniform sampler2D u_source_texture;\n" | |
156 "in vec2 v_texcoord;\n" | |
157 "out vec4 output_color;\n" | |
158 "\n" | |
159 "float encode(float color)\n" | |
160 "{\n" | |
161 " float encoded_color;\n" | |
162 " if (color <= 0.0) {\n" | |
163 " return 0.0;\n" | |
164 " } else if (color < 0.0031308) {\n" | |
165 " return color * 12.92;\n" | |
166 " } else if (color < 1) {\n" | |
167 " return pow(color, 0.41666) * 1.055 - 0.055;\n" | |
168 " } else {\n" | |
169 " return 1.0;\n" | |
170 " }\n" | |
171 "}\n" | |
172 "\n" | |
173 "void main()\n" | |
174 "{\n" | |
175 " vec4 c = texture(u_source_texture, v_texcoord);\n" | |
176 " output_color = vec4(encode(c.r), encode(c.g), encode(c.b), c.a);\n" | |
177 "}\n"; | |
178 | |
179 GLuint fs = glCreateShader(GL_FRAGMENT_SHADER); | |
180 CompileShader(fs, fs_source); | |
181 glAttachShader(srgb_encoder_program_, fs); | |
182 glDeleteShader(fs); | |
183 | |
184 glLinkProgram(srgb_encoder_program_); | |
185 #ifndef NDEBUG | |
186 GLint linked = 0; | |
187 glGetProgramiv(srgb_encoder_program_, GL_LINK_STATUS, &linked); | |
188 if (!linked) { | |
189 DLOG(ERROR) << "SRGB Encoder for BlitFramebuffer: program link failure."; | |
190 } | |
191 #endif | |
192 | |
193 GLuint texture_uniform = | |
194 glGetUniformLocation(srgb_encoder_program_, "u_source_texture"); | |
195 glUseProgram(srgb_encoder_program_); | |
196 glUniform1i(texture_uniform, 0); | |
197 | |
198 glGenTextures(srgb_encoder_textures_.size(), srgb_encoder_textures_.data()); | |
199 glActiveTexture(GL_TEXTURE0); | |
200 for (auto srgb_encoder_texture : srgb_encoder_textures_) { | |
201 glBindTexture(GL_TEXTURE_2D, srgb_encoder_texture); | |
202 | |
203 // Use linear, non-mipmapped sampling with the srgb encoder texture | |
204 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
205 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
206 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
207 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
208 } | |
209 | |
210 glGenFramebuffersEXT(1, &srgb_encoder_fbo_); | |
211 glGenVertexArraysOES(1, &srgb_encoder_vao_); | |
212 | |
213 decoder->RestoreTextureUnitBindings(0); | |
214 decoder->RestoreActiveTexture(); | |
215 decoder->RestoreProgramBindings(); | |
216 | |
217 srgb_encoder_initialized_ = true; | |
218 } | |
219 | |
220 void SRGBConverter::Destroy() { | |
221 if (srgb_decoder_initialized_) { | |
222 glDeleteProgram(srgb_decoder_program_); | |
223 srgb_decoder_program_ = 0; | |
224 | |
225 glDeleteTextures(srgb_decoder_textures_.size(), | |
226 srgb_decoder_textures_.data()); | |
227 srgb_decoder_textures_.fill(0); | |
228 | |
229 glDeleteFramebuffersEXT(1, &srgb_decoder_fbo_); | |
230 srgb_decoder_fbo_ = 0; | |
231 | |
232 glDeleteVertexArraysOES(1, &srgb_decoder_vao_); | |
233 srgb_decoder_vao_ = 0; | |
234 | |
235 srgb_decoder_initialized_ = false; | |
236 } | |
237 | |
238 if (srgb_encoder_initialized_) { | |
239 glDeleteProgram(srgb_encoder_program_); | |
240 srgb_encoder_program_ = 0; | |
241 | |
242 glDeleteTextures(srgb_encoder_textures_.size(), | |
243 srgb_encoder_textures_.data()); | |
244 srgb_encoder_textures_.fill(0); | |
245 | |
246 glDeleteFramebuffersEXT(1, &srgb_encoder_fbo_); | |
247 srgb_encoder_fbo_ = 0; | |
248 | |
249 glDeleteVertexArraysOES(1, &srgb_encoder_vao_); | |
250 srgb_encoder_vao_ = 0; | |
251 | |
252 srgb_encoder_initialized_ = false; | |
253 } | |
254 } | |
255 | |
256 void SRGBConverter::SRGBToLinear(const gles2::GLES2Decoder* decoder, | |
257 GLint srcX0, | |
258 GLint srcY0, | |
259 GLint srcX1, | |
260 GLint srcY1, | |
261 GLint dstX0, | |
262 GLint dstY0, | |
263 GLint dstX1, | |
264 GLint dstY1, | |
265 GLbitfield mask, | |
266 GLenum filter, | |
267 const gfx::Size& framebuffer_size, | |
268 GLuint src_framebuffer, | |
269 GLenum src_framebuffer_internal_format, | |
270 GLuint dst_framebuffer) { | |
271 // This function blits srgb image in src fb to linear image in dst fb. | |
272 // The steps are: | |
273 // 1) Copy and crop pixels from source srgb image to the 1st texture(srgb). | |
274 // 2) Sampling from the 1st texture and drawing to the 2nd texture(linear). | |
275 // During this step, color space is converted from srgb to linear. | |
276 // 3) Finally, blit pixels from the 2nd texture to the target, which is | |
277 // also a linear image. | |
278 DCHECK(srgb_decoder_initialized_); | |
279 | |
280 // Copy the image from read buffer to the decoder's 1st texture(srgb). | |
281 // TODO(yunchao) If the read buffer is a fbo texture, we can sample | |
282 // directly from that texture. In this way, we can save gpu memory. | |
283 glBindFramebufferEXT(GL_FRAMEBUFFER, src_framebuffer); | |
284 glActiveTexture(GL_TEXTURE0); | |
285 glBindTexture(GL_TEXTURE_2D, srgb_decoder_textures_[0]); | |
286 | |
287 // We should not copy pixels outside of the read framebuffer. If we read | |
288 // these pixels, they would become in-bound during BlitFramebuffer. However, | |
289 // Out-of-bounds pixels will be initialized to 0 in CopyTexSubImage. But they | |
290 // should read as if the GL_CLAMP_TO_EDGE texture mapping mode were applied | |
291 // during BlitFramebuffer when the filter is GL_LINEAR. | |
292 GLuint x = srcX1 > srcX0 ? srcX0 : srcX1; | |
293 GLuint y = srcY1 > srcY0 ? srcY0 : srcY1; | |
294 GLuint width = srcX1 > srcX0 ? srcX1 - srcX0 : srcX0 - srcX1; | |
295 GLuint height = srcY1 > srcY0 ? srcY1 - srcY0 : srcY0 - srcY1; | |
296 gfx::Rect c(0, 0, framebuffer_size.width(), framebuffer_size.height()); | |
297 c.Intersect(gfx::Rect(x, y, width, height)); | |
298 GLuint xoffset = c.x() - x; | |
299 GLuint yoffset = c.y() - y; | |
300 glCopyTexImage2D(GL_TEXTURE_2D, 0, src_framebuffer_internal_format, c.x(), | |
301 c.y(), c.width(), c.height(), 0); | |
302 | |
303 // Make a temporary linear texture as the decoder's 2nd texture, where we | |
304 // render the converted (srgb to linear) result to. | |
305 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); | |
306 | |
307 glBindTexture(GL_TEXTURE_2D, srgb_decoder_textures_[1]); | |
308 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, c.width(), c.height(), 0, GL_RGBA, | |
309 GL_UNSIGNED_BYTE, nullptr); | |
310 glBindFramebufferEXT(GL_FRAMEBUFFER, srgb_decoder_fbo_); | |
311 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, | |
312 srgb_decoder_textures_[1], 0); | |
313 | |
314 // Sampling from the decoder's first texture(srgb) and drawing to the | |
315 // decoder's 2nd texture(linear), | |
316 glUseProgram(srgb_decoder_program_); | |
317 glViewport(0, 0, width, height); | |
318 glDisable(GL_SCISSOR_TEST); | |
319 glDisable(GL_DEPTH_TEST); | |
320 glDisable(GL_STENCIL_TEST); | |
321 glDisable(GL_CULL_FACE); | |
322 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); | |
323 glDepthMask(GL_FALSE); | |
324 glDisable(GL_BLEND); | |
325 glDisable(GL_DITHER); | |
326 | |
327 glBindTexture(GL_TEXTURE_2D, srgb_decoder_textures_[0]); | |
328 glBindVertexArrayOES(srgb_decoder_vao_); | |
329 | |
330 glDrawArrays(GL_TRIANGLES, 0, 6); | |
331 | |
332 // Finally, bind the decoder framebuffer as read framebuffer, | |
333 // blit the converted texture in decoder fbo to the destination texture | |
334 // in destination framebuffer. | |
335 glBindFramebufferEXT(GL_READ_FRAMEBUFFER, srgb_decoder_fbo_); | |
336 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, dst_framebuffer); | |
337 // Note that the source region has been changed in decoder framebuffer. | |
338 // The xoffset/yoffset can make bliting clamp to the correct edge if | |
339 // CLAMP_TO_EDGE is necessary. | |
340 glBlitFramebuffer(srcX0 < srcX1 ? 0 - xoffset : width - xoffset, | |
341 srcY0 < srcY1 ? 0 - yoffset : height - yoffset, | |
342 srcX0 < srcX1 ? width - xoffset : 0 - xoffset, | |
343 srcY0 < srcY1 ? height - yoffset : 0 - yoffset, dstX0, | |
344 dstY0, dstX1, dstY1, mask, filter); | |
345 | |
346 // Restore state | |
347 decoder->RestoreAllAttributes(); | |
348 decoder->RestoreTextureUnitBindings(0); | |
349 decoder->RestoreActiveTexture(); | |
350 decoder->RestoreProgramBindings(); | |
351 decoder->RestoreBufferBindings(); | |
352 decoder->RestoreFramebufferBindings(); | |
353 decoder->RestoreGlobalState(); | |
354 } | |
355 | |
356 void SRGBConverter::LinearToSRGB(const gles2::GLES2Decoder* decoder, | |
357 GLint srcX0, | |
358 GLint srcY0, | |
359 GLint srcX1, | |
360 GLint srcY1, | |
361 GLint dstX0, | |
362 GLint dstY0, | |
363 GLint dstX1, | |
364 GLint dstY1, | |
365 GLbitfield mask, | |
366 GLenum filter, | |
367 GLuint src_framebuffer, | |
368 GLenum src_framebuffer_internal_format, | |
369 GLenum src_framebuffer_format, | |
370 GLenum src_framebuffer_type, | |
371 GLuint dst_framebuffer) { | |
372 // This function blits linear image in src fb to srgb image in dst fb. | |
373 // The steps are: | |
374 // 1) BlitFramebuffer from source linear image to a temp linear texture. | |
375 // 2) Sampling from the temp texture and drawing to the target srgb | |
376 // image. During this step, color space is converted from linear to srgb. | |
377 | |
378 DCHECK(srgb_encoder_initialized_); | |
379 | |
380 // Create a temp linear texture as draw buffer. Blit framebuffer from | |
381 // source linear image to the temp linear texture. Filtering is done | |
382 // during bliting. Note that the src and dst coordinates may be reversed. | |
383 glActiveTexture(GL_TEXTURE0); | |
384 glBindTexture(GL_TEXTURE_2D, srgb_encoder_textures_[0]); | |
385 | |
386 GLuint width = dstX1 > dstX0 ? dstX1 - dstX0 : dstX0 - dstX1; | |
387 GLuint height = dstY1 > dstY0 ? dstY1 - dstY0 : dstY0 - dstY1; | |
388 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); | |
389 glTexImage2D(GL_TEXTURE_2D, 0, src_framebuffer_internal_format, width, height, | |
390 0, src_framebuffer_format, src_framebuffer_type, nullptr); | |
391 | |
392 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, srgb_encoder_fbo_); | |
393 glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | |
394 GL_TEXTURE_2D, srgb_encoder_textures_[0], 0); | |
395 glBindFramebufferEXT(GL_READ_FRAMEBUFFER, src_framebuffer); | |
396 glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0 < dstX1 ? 0 : width, | |
397 dstY0 < dstY1 ? 0 : height, dstX0 < dstX1 ? width : 0, | |
398 dstY0 < dstY1 ? height : 0, mask, filter); | |
399 | |
400 // Sampling from the linear texture and drawing to the target srgb image. | |
401 // During this step, color space is converted from linear to srgb. We should | |
402 // set appropriate viewport to draw to the correct location in target FB. | |
403 GLuint xstart = dstX0 < dstX1 ? dstX0 : dstX1; | |
404 GLuint ystart = dstY0 < dstY1 ? dstY0 : dstY1; | |
405 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, dst_framebuffer); | |
406 glUseProgram(srgb_encoder_program_); | |
407 glViewport(xstart, ystart, width, height); | |
408 glDisable(GL_SCISSOR_TEST); | |
409 glDisable(GL_DEPTH_TEST); | |
410 glDisable(GL_STENCIL_TEST); | |
411 glDisable(GL_CULL_FACE); | |
412 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); | |
413 glDepthMask(GL_FALSE); | |
414 glDisable(GL_BLEND); | |
415 glDisable(GL_DITHER); | |
416 | |
417 glBindTexture(GL_TEXTURE_2D, srgb_encoder_textures_[0]); | |
418 glBindVertexArrayOES(srgb_encoder_vao_); | |
419 | |
420 glDrawArrays(GL_TRIANGLES, 0, 6); | |
421 | |
422 // Restore state | |
423 decoder->RestoreAllAttributes(); | |
424 decoder->RestoreTextureUnitBindings(0); | |
425 decoder->RestoreActiveTexture(); | |
426 decoder->RestoreProgramBindings(); | |
427 decoder->RestoreBufferBindings(); | |
428 decoder->RestoreFramebufferBindings(); | |
429 decoder->RestoreGlobalState(); | |
430 } | |
431 | |
432 void SRGBConverter::SRGBToSRGB(const gles2::GLES2Decoder* decoder, | |
433 GLint srcX0, | |
434 GLint srcY0, | |
435 GLint srcX1, | |
436 GLint srcY1, | |
437 GLint dstX0, | |
438 GLint dstY0, | |
439 GLint dstX1, | |
440 GLint dstY1, | |
441 GLbitfield mask, | |
442 GLenum filter, | |
443 const gfx::Size& framebuffer_size, | |
444 GLuint src_framebuffer, | |
445 GLenum src_framebuffer_internal_format, | |
446 GLuint dst_framebuffer) { | |
447 // This function blits srgb image in src fb to srgb image in dst fb. | |
448 // It needs to use decoder's resource, as well as encoder's resources, | |
449 // for instance, decoder's and encoder's fbos, programs and textuers. | |
450 // The steps are: | |
451 // 1) Copy and crop pixels from source srgb image to the 1st texture(srgb). | |
452 // 2) Sampling from the 1st texture and drawing to the 2nd texture(linear). | |
453 // During this step, color space is converted from srgb to linear. | |
454 // 3) Blit pixels from the 2nd texture to the 3rd texture(linear). | |
455 // 4) Sampling from the 3rd texture and drawing to the dst image(srgb). | |
456 // During this step, color space is converted from linear to srgb. | |
457 DCHECK(srgb_decoder_initialized_ && srgb_encoder_initialized_); | |
458 | |
459 // Copy the image from read buffer to the decoder's 1st texture(srgb). | |
460 // TODO(yunchao) If the read buffer is a fbo texture, we can sample | |
461 // directly from that texture. In this way, we can save gpu memory. | |
462 glBindFramebufferEXT(GL_FRAMEBUFFER, src_framebuffer); | |
463 glActiveTexture(GL_TEXTURE0); | |
464 glBindTexture(GL_TEXTURE_2D, srgb_decoder_textures_[0]); | |
465 | |
466 // We should not copy pixels outside of the read framebuffer. If we read | |
467 // these pixels, they would become in-bound during BlitFramebuffer. However, | |
468 // Out-of-bounds pixels will be initialized to 0 in CopyTexSubImage. But they | |
469 // should read as if the GL_CLAMP_TO_EDGE texture mapping mode were applied | |
470 // during BlitFramebuffer when the filter is GL_LINEAR. | |
471 GLuint x = srcX1 > srcX0 ? srcX0 : srcX1; | |
472 GLuint y = srcY1 > srcY0 ? srcY0 : srcY1; | |
473 GLuint width_read = srcX1 > srcX0 ? srcX1 - srcX0 : srcX0 - srcX1; | |
474 GLuint height_read = srcY1 > srcY0 ? srcY1 - srcY0 : srcY0 - srcY1; | |
475 gfx::Rect c(0, 0, framebuffer_size.width(), framebuffer_size.height()); | |
476 c.Intersect(gfx::Rect(x, y, width_read, height_read)); | |
477 GLuint xoffset = c.x() - x; | |
478 GLuint yoffset = c.y() - y; | |
479 glCopyTexImage2D(GL_TEXTURE_2D, 0, src_framebuffer_internal_format, c.x(), | |
480 c.y(), c.width(), c.height(), 0); | |
481 | |
482 // Make a temporary linear texture as the decoder's 2nd texture, where we | |
483 // render the converted (srgb to linear) result to. | |
484 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); | |
485 | |
486 glBindTexture(GL_TEXTURE_2D, srgb_decoder_textures_[1]); | |
487 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, c.width(), c.height(), 0, GL_RGBA, | |
488 GL_UNSIGNED_BYTE, nullptr); | |
489 glBindFramebufferEXT(GL_FRAMEBUFFER, srgb_decoder_fbo_); | |
490 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, | |
491 srgb_decoder_textures_[1], 0); | |
492 | |
493 // Sampling from the decoder's first texture(srgb) and drawing to the | |
494 // decoder's 2nd texture(linear), | |
495 glUseProgram(srgb_decoder_program_); | |
496 glViewport(0, 0, width_read, height_read); | |
497 glDisable(GL_SCISSOR_TEST); | |
498 glDisable(GL_DEPTH_TEST); | |
499 glDisable(GL_STENCIL_TEST); | |
500 glDisable(GL_CULL_FACE); | |
501 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); | |
502 glDepthMask(GL_FALSE); | |
503 glDisable(GL_BLEND); | |
504 glDisable(GL_DITHER); | |
505 | |
506 glBindTexture(GL_TEXTURE_2D, srgb_decoder_textures_[0]); | |
507 glBindVertexArrayOES(srgb_decoder_vao_); | |
508 | |
509 glDrawArrays(GL_TRIANGLES, 0, 6); | |
510 | |
511 // Create the 3rd texture(linear) as decoder's draw buffer. Blit framebuffer | |
512 // from the 2nd texture(linear) to the 3rd texture. Filtering is done | |
513 // during bliting. Note that the src and dst coordinates may be reversed. | |
514 glBindTexture(GL_TEXTURE_2D, srgb_encoder_textures_[0]); | |
515 | |
516 GLuint width_draw = dstX1 > dstX0 ? dstX1 - dstX0 : dstX0 - dstX1; | |
517 GLuint height_draw = dstY1 > dstY0 ? dstY1 - dstY0 : dstY0 - dstY1; | |
518 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); | |
519 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_draw, height_draw, 0, GL_RGBA, | |
520 GL_UNSIGNED_BYTE, nullptr); | |
521 | |
522 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, srgb_encoder_fbo_); | |
523 glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | |
524 GL_TEXTURE_2D, srgb_encoder_textures_[0], 0); | |
525 glBindFramebufferEXT(GL_READ_FRAMEBUFFER, srgb_decoder_fbo_); | |
526 glBlitFramebuffer(srcX0 < srcX1 ? 0 - xoffset : width_read - xoffset, | |
527 srcY0 < srcY1 ? 0 - yoffset : height_read - yoffset, | |
528 srcX0 < srcX1 ? width_read - xoffset : 0 - xoffset, | |
529 srcY0 < srcY1 ? height_read - yoffset : 0 - yoffset, | |
530 dstX0 < dstX1 ? 0 : width_draw, | |
531 dstY0 < dstY1 ? 0 : height_draw, | |
532 dstX0 < dstX1 ? width_draw : 0, | |
533 dstY0 < dstY1 ? height_draw : 0, mask, filter); | |
534 | |
535 // Sampling from the 3rd texture(linear) and drawing to the target srgb image. | |
536 // During this step, color space is converted from linear to srgb. We should | |
537 // set appropriate viewport to draw to the correct location in target FB. | |
538 GLuint xstart = dstX0 < dstX1 ? dstX0 : dstX1; | |
539 GLuint ystart = dstY0 < dstY1 ? dstY0 : dstY1; | |
540 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, dst_framebuffer); | |
541 glUseProgram(srgb_encoder_program_); | |
542 glViewport(xstart, ystart, width_draw, height_draw); | |
543 | |
544 glBindTexture(GL_TEXTURE_2D, srgb_encoder_textures_[0]); | |
545 glBindVertexArrayOES(srgb_encoder_vao_); | |
546 | |
547 glDrawArrays(GL_TRIANGLES, 0, 6); | |
548 | |
549 // Restore state | |
550 decoder->RestoreAllAttributes(); | |
551 decoder->RestoreTextureUnitBindings(0); | |
552 decoder->RestoreActiveTexture(); | |
553 decoder->RestoreProgramBindings(); | |
554 decoder->RestoreBufferBindings(); | |
555 decoder->RestoreFramebufferBindings(); | |
556 decoder->RestoreGlobalState(); | |
557 } | |
558 | |
559 void SRGBConverter::SRGBGenerateMipmap(const gles2::GLES2Decoder* decoder, | |
560 Texture* tex, | |
561 GLenum target) { | |
562 DCHECK(srgb_decoder_initialized_); | |
563 | |
564 GLsizei width; | |
565 GLsizei height; | |
566 GLsizei depth; | |
567 GLenum type = 0; | |
568 GLenum internal_format = 0; | |
569 GLsizei base_level = tex->base_level(); | |
570 tex->GetLevelSize(target, base_level, &width, &height, &depth); | |
571 tex->GetLevelType(target, 0, &type, &internal_format); | |
572 const GLint mipmap_level = | |
573 TextureManager::ComputeMipMapCount(target, width, height, depth); | |
574 | |
575 // copy tex to srgb_decoder_textures_[0] with srgb format | |
576 glBindTexture(target, tex->service_id()); | |
577 glBindFramebufferEXT(GL_READ_FRAMEBUFFER, srgb_encoder_fbo_); | |
yunchao
2016/09/13 08:55:40
decoder_fbo_
| |
578 glFramebufferTexture2DEXT(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | |
579 GL_TEXTURE_2D, tex->service_id(), 0); | |
580 glBindTexture(GL_TEXTURE_2D, srgb_decoder_textures_[0]); | |
581 glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, GL_SRGB, | |
582 GL_UNSIGNED_BYTE, nullptr); | |
583 glCopyTexImage2D(GL_TEXTURE_2D, 0, internal_format, 0, 0, width, height, 0); | |
584 | |
585 // bind srgb_decoder_textures_[1] to draw framebuffer | |
586 glBindTexture(GL_TEXTURE_2D, srgb_decoder_textures_[1]); | |
587 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, | |
588 GL_UNSIGNED_BYTE, nullptr); | |
589 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, srgb_decoder_fbo_); | |
590 glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | |
591 GL_TEXTURE_2D, srgb_decoder_textures_[1], 0); | |
592 // bind tex with srgb format and render with srgb_decoder_program_ | |
593 glUseProgram(srgb_decoder_program_); | |
594 glViewport(0, 0, width, height); | |
595 glDisable(GL_SCISSOR_TEST); | |
596 glDisable(GL_DEPTH_TEST); | |
597 glDisable(GL_STENCIL_TEST); | |
598 glDisable(GL_CULL_FACE); | |
599 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); | |
600 glDepthMask(GL_FALSE); | |
601 glDisable(GL_BLEND); | |
602 glDisable(GL_DITHER); | |
603 | |
604 glBindTexture(GL_TEXTURE_2D, srgb_decoder_textures_[0]); | |
yunchao
2016/09/13 08:55:40
bind VAO
| |
605 glDrawArrays(GL_TRIANGLES, 0, 6); | |
606 | |
607 // tex and srgb_decoder_textures_[1] generateMipmap | |
608 glBindTexture(GL_TEXTURE_2D, tex->service_id()); | |
609 glGenerateMipmapEXT(GL_TEXTURE_2D); | |
610 glBindTexture(GL_TEXTURE_2D, srgb_decoder_textures_[1]); | |
611 glGenerateMipmapEXT(GL_TEXTURE_2D); | |
612 | |
613 // bind tex with rgba format and render with srgb_encoder_program_ | |
614 InitializeSRGBEncoder(decoder); | |
yunchao
2016/09/13 08:55:40
remove this line
| |
615 glUseProgram(srgb_encoder_program_); | |
616 glViewport(0, 0, width, height); | |
617 glDisable(GL_SCISSOR_TEST); | |
618 glDisable(GL_DEPTH_TEST); | |
619 glDisable(GL_STENCIL_TEST); | |
620 glDisable(GL_CULL_FACE); | |
621 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); | |
622 glDepthMask(GL_FALSE); | |
623 glDisable(GL_BLEND); | |
624 glDisable(GL_DITHER); | |
yunchao
2016/09/13 08:55:40
remove these code
| |
625 | |
626 glBindVertexArrayOES(srgb_encoder_vao_); | |
627 | |
628 for (GLint level = base_level; level < mipmap_level; level++) { | |
629 glBindTexture(GL_TEXTURE_2D, tex->service_id()); | |
630 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, srgb_encoder_fbo_); | |
631 glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | |
632 GL_TEXTURE_2D, tex->service_id(), level); | |
633 | |
634 glActiveTexture(GL_TEXTURE0); | |
635 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, | |
636 GL_NEAREST_MIPMAP_NEAREST); | |
637 glBindTexture(GL_TEXTURE_2D, srgb_decoder_textures_[1]); | |
638 | |
639 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, level); | |
yunchao
2016/09/13 08:55:40
This line can get the similar effect with the line
| |
640 glViewport(0, 0, width, height); | |
641 glDrawArrays(GL_TRIANGLES, 0, 6); | |
642 width /= 2; | |
643 height /= 2; | |
644 } | |
645 | |
646 // Restore state | |
647 decoder->RestoreAllAttributes(); | |
648 decoder->RestoreTextureUnitBindings(0); | |
649 decoder->RestoreActiveTexture(); | |
650 decoder->RestoreProgramBindings(); | |
651 decoder->RestoreBufferBindings(); | |
652 decoder->RestoreFramebufferBindings(); | |
653 decoder->RestoreGlobalState(); | |
654 } | |
655 | |
656 } // namespace gles2. | |
657 } // namespace gpu | |
OLD | NEW |