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( | |
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 in decoder, we don't need to decode again. | |
77 // Drawing to a srgb image, it will convert linear to srgb automatically. | |
78 // See the section <sRGB Conversion> in GLES and OpenGL spec. | |
79 // So we just use a simple fragment shader. We don't need to use an equation | |
80 // in shader to do explicit srgb conversion to/from linear. | |
81 const char* fs_source = | |
82 "#version 150\n" | |
83 "uniform sampler2D u_source_texture;\n" | |
84 "in vec2 v_texcoord;\n" | |
85 "out vec4 output_color;\n" | |
86 "\n" | |
87 "void main()\n" | |
88 "{\n" | |
89 " vec4 c = texture(u_source_texture, v_texcoord);\n" | |
90 " output_color = c;\n" | |
91 "}\n"; | |
92 | |
93 GLuint fs = glCreateShader(GL_FRAGMENT_SHADER); | |
94 CompileShader(fs, fs_source); | |
95 glAttachShader(srgb_converter_program_, fs); | |
96 glDeleteShader(fs); | |
97 | |
98 glLinkProgram(srgb_converter_program_); | |
99 #ifndef NDEBUG | |
100 GLint linked = 0; | |
101 glGetProgramiv(srgb_converter_program_, GL_LINK_STATUS, &linked); | |
102 if (!linked) { | |
103 DLOG(ERROR) << "BlitFramebuffer: program link failure."; | |
104 } | |
105 #endif | |
106 | |
107 GLuint texture_uniform = | |
108 glGetUniformLocation(srgb_converter_program_, "u_source_texture"); | |
109 glUseProgram(srgb_converter_program_); | |
110 glUniform1i(texture_uniform, 0); | |
111 } | |
112 | |
113 void SRGBConverter::InitializeSRGBDecoder( | |
114 const gles2::GLES2Decoder* decoder) { | |
115 if (srgb_decoder_initialized_) { | |
116 return; | |
117 } | |
118 | |
119 InitializeSRGBConverterProgram(); | |
120 | |
121 glGenTextures(srgb_decoder_textures_.size(), srgb_decoder_textures_.data()); | |
122 glActiveTexture(GL_TEXTURE0); | |
123 for (auto srgb_decoder_texture : srgb_decoder_textures_) { | |
124 glBindTexture(GL_TEXTURE_2D, srgb_decoder_texture); | |
125 | |
126 // Use linear, non-mipmapped sampling with the srgb decoder texture | |
127 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
128 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
129 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
130 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
131 } | |
132 | |
133 glGenFramebuffersEXT(1, &srgb_decoder_fbo_); | |
134 glGenVertexArraysOES(1, &srgb_decoder_vao_); | |
135 | |
136 decoder->RestoreTextureUnitBindings(0); | |
137 decoder->RestoreActiveTexture(); | |
138 decoder->RestoreProgramBindings(); | |
139 | |
140 srgb_decoder_initialized_ = true; | |
141 } | |
142 | |
143 void SRGBConverter::InitializeSRGBEncoder( | |
144 const gles2::GLES2Decoder* decoder) { | |
145 if (srgb_encoder_initialized_) { | |
146 return; | |
147 } | |
148 | |
149 InitializeSRGBConverterProgram(); | |
150 | |
151 glGenTextures(srgb_encoder_textures_.size(), srgb_encoder_textures_.data()); | |
152 glActiveTexture(GL_TEXTURE0); | |
153 for (auto srgb_encoder_texture : srgb_encoder_textures_) { | |
154 glBindTexture(GL_TEXTURE_2D, srgb_encoder_texture); | |
155 | |
156 // Use linear, non-mipmapped sampling with the srgb encoder texture | |
157 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
158 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
159 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
160 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
161 } | |
162 | |
163 glGenFramebuffersEXT(1, &srgb_encoder_fbo_); | |
164 glGenVertexArraysOES(1, &srgb_encoder_vao_); | |
165 | |
166 decoder->RestoreTextureUnitBindings(0); | |
167 decoder->RestoreActiveTexture(); | |
168 decoder->RestoreProgramBindings(); | |
169 | |
170 srgb_encoder_initialized_ = true; | |
171 } | |
172 | |
173 void SRGBConverter::Destroy() { | |
174 if (srgb_decoder_initialized_) { | |
175 glDeleteTextures(srgb_decoder_textures_.size(), | |
176 srgb_decoder_textures_.data()); | |
177 srgb_decoder_textures_.fill(0); | |
178 | |
179 glDeleteFramebuffersEXT(1, &srgb_decoder_fbo_); | |
180 srgb_decoder_fbo_ = 0; | |
181 | |
182 glDeleteVertexArraysOES(1, &srgb_decoder_vao_); | |
183 srgb_decoder_vao_ = 0; | |
184 | |
185 srgb_decoder_initialized_ = false; | |
186 } | |
187 | |
188 if (srgb_encoder_initialized_) { | |
189 glDeleteTextures(srgb_encoder_textures_.size(), | |
190 srgb_encoder_textures_.data()); | |
191 srgb_encoder_textures_.fill(0); | |
192 | |
193 glDeleteFramebuffersEXT(1, &srgb_encoder_fbo_); | |
194 srgb_encoder_fbo_ = 0; | |
195 | |
196 glDeleteVertexArraysOES(1, &srgb_encoder_vao_); | |
197 srgb_encoder_vao_ = 0; | |
198 | |
199 srgb_encoder_initialized_ = false; | |
200 } | |
201 | |
202 glDeleteProgram(srgb_converter_program_); | |
203 srgb_converter_program_ = 0; | |
204 } | |
205 | |
206 void SRGBConverter::SRGBToLinear( | |
207 const gles2::GLES2Decoder* decoder, | |
208 GLint srcX0, | |
209 GLint srcY0, | |
210 GLint srcX1, | |
211 GLint srcY1, | |
212 GLint dstX0, | |
213 GLint dstY0, | |
214 GLint dstX1, | |
215 GLint dstY1, | |
216 GLbitfield mask, | |
217 GLenum filter, | |
218 const gfx::Size& framebuffer_size, | |
219 GLuint src_framebuffer, | |
220 GLenum src_framebuffer_internal_format, | |
221 GLuint dst_framebuffer) { | |
222 // This function blits srgb image in src fb to linear image in dst fb. | |
223 // The steps are: | |
224 // 1) Copy and crop pixels from source srgb image to the 1st texture(srgb). | |
225 // 2) Sampling from the 1st texture and drawing to the 2nd texture(linear). | |
226 // During this step, color space is converted from srgb to linear. | |
227 // 3) Finally, blit pixels from the 2nd texture to the target, which is | |
228 // also a linear image. | |
229 DCHECK(srgb_decoder_initialized_); | |
230 | |
231 // Copy the image from read buffer to the decoder's 1st texture(srgb). | |
232 // TODO(yunchao) If the read buffer is a fbo texture, we can sample | |
233 // directly from that texture. In this way, we can save gpu memory. | |
234 glBindFramebufferEXT(GL_FRAMEBUFFER, src_framebuffer); | |
235 glActiveTexture(GL_TEXTURE0); | |
236 glBindTexture(GL_TEXTURE_2D, srgb_decoder_textures_[0]); | |
237 | |
238 // We should not copy pixels outside of the read framebuffer. If we read | |
239 // these pixels, they would become in-bound during BlitFramebuffer. However, | |
240 // Out-of-bounds pixels will be initialized to 0 in CopyTexSubImage. But they | |
241 // should read as if the GL_CLAMP_TO_EDGE texture mapping mode were applied | |
242 // during BlitFramebuffer when the filter is GL_LINEAR. | |
243 GLuint x = srcX1 > srcX0 ? srcX0 : srcX1; | |
244 GLuint y = srcY1 > srcY0 ? srcY0 : srcY1; | |
245 GLuint width = srcX1 > srcX0 ? srcX1 - srcX0 : srcX0 - srcX1; | |
246 GLuint height = srcY1 > srcY0 ? srcY1 - srcY0 : srcY0 - srcY1; | |
247 gfx::Rect c(0, 0, framebuffer_size.width(), framebuffer_size.height()); | |
248 c.Intersect(gfx::Rect(x, y, width, height)); | |
249 GLuint xoffset = c.x() - x; | |
250 GLuint yoffset = c.y() - y; | |
251 glCopyTexImage2D(GL_TEXTURE_2D, 0, src_framebuffer_internal_format, | |
yunchao
2016/09/14 16:11:33
If the read buffer is a multisampled renderbuffer
piman
2016/09/15 03:34:31
I'm pretty sure that's the intended behavior - it
yunchao
2016/09/16 06:20:52
Done.
| |
252 c.x(), c.y(), c.width(), c.height(), 0); | |
253 | |
254 // Make a temporary linear texture as the decoder's 2nd texture, where we | |
255 // render the converted (srgb to linear) result to. | |
256 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); | |
257 | |
258 glBindTexture(GL_TEXTURE_2D, srgb_decoder_textures_[1]); | |
259 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, | |
260 c.width(), c.height(), | |
261 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); | |
262 glBindFramebufferEXT(GL_FRAMEBUFFER, srgb_decoder_fbo_); | |
263 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | |
264 GL_TEXTURE_2D, srgb_decoder_textures_[1], 0); | |
265 | |
266 // Sampling from the decoder's first texture(srgb) and drawing to the | |
267 // decoder's 2nd texture(linear), | |
268 glUseProgram(srgb_converter_program_); | |
269 glViewport(0, 0, width, height); | |
270 glDisable(GL_SCISSOR_TEST); | |
271 glDisable(GL_DEPTH_TEST); | |
272 glDisable(GL_STENCIL_TEST); | |
273 glDisable(GL_CULL_FACE); | |
274 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); | |
275 glDepthMask(GL_FALSE); | |
276 glDisable(GL_BLEND); | |
277 glDisable(GL_DITHER); | |
278 | |
279 glBindTexture(GL_TEXTURE_2D, srgb_decoder_textures_[0]); | |
280 glBindVertexArrayOES(srgb_decoder_vao_); | |
281 | |
282 glDrawArrays(GL_TRIANGLES, 0, 6); | |
283 | |
284 // Finally, bind the decoder framebuffer as read framebuffer, | |
285 // blit the converted texture in decoder fbo to the destination texture | |
286 // in destination framebuffer. | |
287 glBindFramebufferEXT(GL_READ_FRAMEBUFFER, srgb_decoder_fbo_); | |
288 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, dst_framebuffer); | |
289 // Note that the source region has been changed in decoder framebuffer. | |
290 // The xoffset/yoffset can make bliting clamp to the correct edge if | |
291 // CLAMP_TO_EDGE is necessary. | |
292 glBlitFramebuffer(srcX0 < srcX1 ? 0 - xoffset : width - xoffset, | |
293 srcY0 < srcY1 ? 0 - yoffset : height - yoffset, | |
294 srcX0 < srcX1 ? width - xoffset : 0 - xoffset, | |
295 srcY0 < srcY1 ? height - yoffset : 0 - yoffset, | |
296 dstX0, dstY0, dstX1, dstY1, mask, filter); | |
297 | |
298 // Restore state | |
299 decoder->RestoreAllAttributes(); | |
300 decoder->RestoreTextureUnitBindings(0); | |
301 decoder->RestoreActiveTexture(); | |
302 decoder->RestoreProgramBindings(); | |
303 decoder->RestoreBufferBindings(); | |
304 decoder->RestoreFramebufferBindings(); | |
305 decoder->RestoreGlobalState(); | |
306 } | |
307 | |
308 void SRGBConverter::LinearToSRGB( | |
309 const gles2::GLES2Decoder* decoder, | |
310 GLint srcX0, | |
311 GLint srcY0, | |
312 GLint srcX1, | |
313 GLint srcY1, | |
314 GLint dstX0, | |
315 GLint dstY0, | |
316 GLint dstX1, | |
317 GLint dstY1, | |
318 GLbitfield mask, | |
319 GLenum filter, | |
320 GLuint src_framebuffer, | |
321 GLenum src_framebuffer_internal_format, | |
322 GLenum src_framebuffer_format, | |
323 GLenum src_framebuffer_type, | |
324 GLuint dst_framebuffer) { | |
325 // This function blits linear image in src fb to srgb image in dst fb. | |
326 // The steps are: | |
327 // 1) BlitFramebuffer from source linear image to a temp linear texture. | |
328 // 2) Sampling from the temp texture and drawing to the target srgb | |
329 // image. During this step, color space is converted from linear to srgb. | |
330 | |
331 DCHECK(srgb_encoder_initialized_); | |
332 | |
333 // Create a temp linear texture as draw buffer. Blit framebuffer from | |
334 // source linear image to the temp linear texture. Filtering is done | |
335 // during bliting. Note that the src and dst coordinates may be reversed. | |
336 glActiveTexture(GL_TEXTURE0); | |
337 glBindTexture(GL_TEXTURE_2D, srgb_encoder_textures_[0]); | |
338 | |
339 GLuint width = dstX1 > dstX0 ? dstX1 - dstX0 : dstX0 - dstX1; | |
340 GLuint height = dstY1 > dstY0 ? dstY1 - dstY0 : dstY0 - dstY1; | |
341 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); | |
342 glTexImage2D(GL_TEXTURE_2D, 0, src_framebuffer_internal_format, | |
343 width, height, | |
344 0, src_framebuffer_format, src_framebuffer_type, nullptr); | |
345 | |
346 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, srgb_encoder_fbo_); | |
347 glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | |
348 GL_TEXTURE_2D, srgb_encoder_textures_[0], 0); | |
349 glBindFramebufferEXT(GL_READ_FRAMEBUFFER, src_framebuffer); | |
350 glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, | |
351 dstX0 < dstX1 ? 0 : width, | |
352 dstY0 < dstY1 ? 0 : height, | |
353 dstX0 < dstX1 ? width : 0, | |
354 dstY0 < dstY1 ? height : 0, | |
355 mask, filter); | |
356 | |
357 // Sampling from the linear texture and drawing to the target srgb image. | |
358 // During this step, color space is converted from linear to srgb. We should | |
359 // set appropriate viewport to draw to the correct location in target FB. | |
360 GLuint xstart = dstX0 < dstX1 ? dstX0 : dstX1; | |
361 GLuint ystart = dstY0 < dstY1 ? dstY0 : dstY1; | |
362 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, dst_framebuffer); | |
363 glUseProgram(srgb_converter_program_); | |
364 glViewport(xstart, ystart, width, height); | |
365 glDisable(GL_SCISSOR_TEST); | |
366 glDisable(GL_DEPTH_TEST); | |
367 glDisable(GL_STENCIL_TEST); | |
368 glDisable(GL_CULL_FACE); | |
369 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); | |
370 glDepthMask(GL_FALSE); | |
371 glDisable(GL_BLEND); | |
372 glDisable(GL_DITHER); | |
373 | |
374 glBindTexture(GL_TEXTURE_2D, srgb_encoder_textures_[0]); | |
375 glBindVertexArrayOES(srgb_encoder_vao_); | |
376 | |
377 glDrawArrays(GL_TRIANGLES, 0, 6); | |
378 | |
379 // Restore state | |
380 decoder->RestoreAllAttributes(); | |
381 decoder->RestoreTextureUnitBindings(0); | |
382 decoder->RestoreActiveTexture(); | |
383 decoder->RestoreProgramBindings(); | |
384 decoder->RestoreBufferBindings(); | |
385 decoder->RestoreFramebufferBindings(); | |
386 decoder->RestoreGlobalState(); | |
387 } | |
388 | |
389 void SRGBConverter::SRGBToSRGB( | |
390 const gles2::GLES2Decoder* decoder, | |
391 GLint srcX0, | |
392 GLint srcY0, | |
393 GLint srcX1, | |
394 GLint srcY1, | |
395 GLint dstX0, | |
396 GLint dstY0, | |
397 GLint dstX1, | |
398 GLint dstY1, | |
399 GLbitfield mask, | |
400 GLenum filter, | |
401 const gfx::Size& framebuffer_size, | |
402 GLuint src_framebuffer, | |
403 GLenum src_framebuffer_internal_format, | |
404 GLuint dst_framebuffer) { | |
405 // This function blits srgb image in src fb to srgb image in dst fb. | |
406 // It needs to use decoder's resource, as well as encoder's resources, | |
407 // for instance, decoder's and encoder's fbos, programs and textuers. | |
408 // The steps are: | |
409 // 1) Copy and crop pixels from source srgb image to the 1st texture(srgb). | |
410 // 2) Sampling from the 1st texture and drawing to the 2nd texture(linear). | |
411 // During this step, color space is converted from srgb to linear. | |
412 // 3) Blit pixels from the 2nd texture to the 3rd texture(linear). | |
413 // 4) Sampling from the 3rd texture and drawing to the dst image(srgb). | |
414 // During this step, color space is converted from linear to srgb. | |
piman
2016/09/15 03:34:31
The 2 other functions could be considered a simpli
yunchao
2016/09/16 06:20:52
Done. Very good idea to remove the code duplicatio
yunchao
2016/09/16 14:07:56
It is not necessary to associate texture and vao w
| |
415 DCHECK(srgb_decoder_initialized_ && srgb_encoder_initialized_); | |
416 | |
417 // Copy the image from read buffer to the decoder's 1st texture(srgb). | |
418 // TODO(yunchao) If the read buffer is a fbo texture, we can sample | |
419 // directly from that texture. In this way, we can save gpu memory. | |
420 glBindFramebufferEXT(GL_FRAMEBUFFER, src_framebuffer); | |
421 glActiveTexture(GL_TEXTURE0); | |
422 glBindTexture(GL_TEXTURE_2D, srgb_decoder_textures_[0]); | |
423 | |
424 // We should not copy pixels outside of the read framebuffer. If we read | |
425 // these pixels, they would become in-bound during BlitFramebuffer. However, | |
426 // Out-of-bounds pixels will be initialized to 0 in CopyTexSubImage. But they | |
427 // should read as if the GL_CLAMP_TO_EDGE texture mapping mode were applied | |
428 // during BlitFramebuffer when the filter is GL_LINEAR. | |
429 GLuint x = srcX1 > srcX0 ? srcX0 : srcX1; | |
430 GLuint y = srcY1 > srcY0 ? srcY0 : srcY1; | |
431 GLuint width_read = srcX1 > srcX0 ? srcX1 - srcX0 : srcX0 - srcX1; | |
432 GLuint height_read = srcY1 > srcY0 ? srcY1 - srcY0 : srcY0 - srcY1; | |
433 gfx::Rect c(0, 0, framebuffer_size.width(), framebuffer_size.height()); | |
434 c.Intersect(gfx::Rect(x, y, width_read, height_read)); | |
435 GLuint xoffset = c.x() - x; | |
436 GLuint yoffset = c.y() - y; | |
437 glCopyTexImage2D(GL_TEXTURE_2D, 0, src_framebuffer_internal_format, | |
438 c.x(), c.y(), c.width(), c.height(), 0); | |
439 | |
440 // Make a temporary linear texture as the decoder's 2nd texture, where we | |
441 // render the converted (srgb to linear) result to. | |
442 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); | |
443 | |
444 glBindTexture(GL_TEXTURE_2D, srgb_decoder_textures_[1]); | |
445 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, | |
446 c.width(), c.height(), | |
447 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); | |
448 glBindFramebufferEXT(GL_FRAMEBUFFER, srgb_decoder_fbo_); | |
449 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | |
450 GL_TEXTURE_2D, srgb_decoder_textures_[1], 0); | |
451 | |
452 // Sampling from the decoder's first texture(srgb) and drawing to the | |
453 // decoder's 2nd texture(linear), | |
454 glUseProgram(srgb_converter_program_); | |
455 glViewport(0, 0, width_read, height_read); | |
456 glDisable(GL_SCISSOR_TEST); | |
457 glDisable(GL_DEPTH_TEST); | |
458 glDisable(GL_STENCIL_TEST); | |
459 glDisable(GL_CULL_FACE); | |
460 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); | |
461 glDepthMask(GL_FALSE); | |
462 glDisable(GL_BLEND); | |
463 glDisable(GL_DITHER); | |
464 | |
465 glBindTexture(GL_TEXTURE_2D, srgb_decoder_textures_[0]); | |
466 glBindVertexArrayOES(srgb_decoder_vao_); | |
467 | |
468 glDrawArrays(GL_TRIANGLES, 0, 6); | |
469 | |
470 // Create the 3rd texture(linear) as encoder's draw buffer. Blit framebuffer | |
471 // from the 2nd texture(linear) to the 3rd texture. Filtering is done | |
472 // during bliting. Note that the src and dst coordinates may be reversed. | |
473 glBindTexture(GL_TEXTURE_2D, srgb_encoder_textures_[0]); | |
474 | |
475 GLuint width_draw = dstX1 > dstX0 ? dstX1 - dstX0 : dstX0 - dstX1; | |
476 GLuint height_draw = dstY1 > dstY0 ? dstY1 - dstY0 : dstY0 - dstY1; | |
477 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); | |
478 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, | |
479 width_draw, height_draw, | |
480 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); | |
481 | |
482 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, srgb_encoder_fbo_); | |
483 glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | |
484 GL_TEXTURE_2D, srgb_encoder_textures_[0], 0); | |
485 glBindFramebufferEXT(GL_READ_FRAMEBUFFER, srgb_decoder_fbo_); | |
486 glBlitFramebuffer(srcX0 < srcX1 ? 0 - xoffset : width_read - xoffset, | |
487 srcY0 < srcY1 ? 0 - yoffset : height_read - yoffset, | |
488 srcX0 < srcX1 ? width_read - xoffset : 0 - xoffset, | |
489 srcY0 < srcY1 ? height_read - yoffset : 0 - yoffset, | |
490 dstX0 < dstX1 ? 0 : width_draw, | |
491 dstY0 < dstY1 ? 0 : height_draw, | |
492 dstX0 < dstX1 ? width_draw : 0, | |
493 dstY0 < dstY1 ? height_draw : 0, | |
494 mask, filter); | |
495 | |
496 // Sampling from the 3rd texture(linear) and drawing to the target srgb image. | |
497 // During this step, color space is converted from linear to srgb. We should | |
498 // set appropriate viewport to draw to the correct location in target FB. | |
499 GLuint xstart = dstX0 < dstX1 ? dstX0 : dstX1; | |
500 GLuint ystart = dstY0 < dstY1 ? dstY0 : dstY1; | |
501 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, dst_framebuffer); | |
502 glUseProgram(srgb_converter_program_); | |
503 glViewport(xstart, ystart, width_draw, height_draw); | |
504 | |
505 glBindTexture(GL_TEXTURE_2D, srgb_encoder_textures_[0]); | |
506 glBindVertexArrayOES(srgb_encoder_vao_); | |
507 | |
508 glDrawArrays(GL_TRIANGLES, 0, 6); | |
509 | |
510 // Restore state | |
511 decoder->RestoreAllAttributes(); | |
512 decoder->RestoreTextureUnitBindings(0); | |
513 decoder->RestoreActiveTexture(); | |
514 decoder->RestoreProgramBindings(); | |
515 decoder->RestoreBufferBindings(); | |
516 decoder->RestoreFramebufferBindings(); | |
517 decoder->RestoreGlobalState(); | |
518 } | |
519 | |
520 } // namespace gles2. | |
521 } // namespace gpu | |
OLD | NEW |