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

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 zmo@'s feedback 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.
piman 2016/09/07 23:08:33 I don't think I understand the comment. The shader
yunchao 2016/09/08 18:32:49 I saw the some difference between these 2 situatio
piman 2016/09/08 19:39:18 For the output, the state of texture doesn't matte
yunchao 2016/09/08 23:16:49 (Maybe I am wrong here) I may have different opini
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" */
piman 2016/09/07 23:08:32 nit: remove commented code.
yunchao 2016/09/08 18:32:49 I would like to keep the code here, which indicate
piman 2016/09/08 19:39:17 Please don't. It makes it confusing. The conversio
yunchao 2016/09/08 23:16:49 (Again, maybe I am wrong here) sampling from srgb
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"
piman 2016/09/07 23:08:32 nit: remove commented code.
yunchao 2016/09/08 18:32:49 I'd like to keep the code here.
piman 2016/09/08 19:39:17 Please don't.
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
piman 2016/09/07 23:08:33 nit: you're using linear, not nearest. Fix comment
yunchao 2016/09/08 18:32:49 Done.
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";
piman 2016/09/07 23:08:32 This is the same VS as above for the decoder, can
yunchao 2016/09/08 18:32:49 That's true. Done.
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"
piman 2016/09/07 23:08:33 If we're doing the linear->srgb conversion with a
yunchao 2016/09/08 18:32:49 Prior to OGL 4.4, it can not support FRAMEBUFFER_S
piman 2016/09/08 19:39:18 Why not? FRAMEBUFFER_SRGB is definitely supported
yunchao 2016/09/08 23:16:49 Sorry, I am wrong. FRAMEBUFFER_SRGB exists as long
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
piman 2016/09/07 23:08:32 nit: ditto, nearest->linear
yunchao 2016/09/08 18:32:49 Done.
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) {
piman 2016/09/07 23:08:33 This could use a high-level comment about what we'
yunchao 2016/09/08 18:32:49 Done.
yunchao 2016/09/08 18:32:49 Good suggestions! Done.
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 GLuint xoffset = c.x() - x;
323 GLuint yoffset = c.y() - y;
324 glCopyTexImage2D(GL_TEXTURE_2D, 0, src_framebuffer_internal_format,
325 c.x(), c.y(), c.width(), c.height(), 0);
326
327 // Make a temporary framebuffer using the second srgb decoder texture to
328 // render the converted (linear to srgb) result to.
piman 2016/09/07 23:08:32 nit: you're converting srgb to linear, not linear
yunchao 2016/09/08 18:32:49 Done.
329 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
330
331 glBindTexture(GL_TEXTURE_2D, srgb_decoder_textures_[1]);
332 glTexImage2D(GL_TEXTURE_2D, 0, dst_framebuffer_internal_format,
333 c.width(), c.height(),
334 0, dst_framebuffer_format, dst_framebuffer_type, nullptr);
335 glBindFramebufferEXT(GL_FRAMEBUFFER, srgb_decoder_fbo_);
336 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
337 srgb_decoder_textures_[1], 0);
338
339 // Render to the second srgb decoder texture,
340 // sampling from the first srgb decoder texture.
341 glUseProgram(srgb_decoder_program_);
342 glViewport(0, 0, width, height);
343 glDisable(GL_SCISSOR_TEST);
344 glDisable(GL_DEPTH_TEST);
345 glDisable(GL_STENCIL_TEST);
346 glDisable(GL_CULL_FACE);
347 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
348 glDepthMask(GL_FALSE);
349 glDisable(GL_BLEND);
350 glDisable(GL_DITHER);
351
352 glBindTexture(GL_TEXTURE_2D, srgb_decoder_textures_[0]);
353 glBindVertexArrayOES(srgb_decoder_vao_);
354
355 glDrawArrays(GL_TRIANGLES, 0, 6);
356
357 // Finally, bind the temporary framebuffer as read framebuffer,
358 // blit the converted texture in temp fbo to the destination texture
359 // in destination framebuffer.
360 glBindFramebufferEXT(GL_READ_FRAMEBUFFER, srgb_decoder_fbo_);
361 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, dst_framebuffer);
362 // Note that the source region has been changed in temp framebuffer.
363 // The xoffset/yoffset can make bliting clamp to the correct edge if
364 // CLAMP_TO_EDGE is necessary.
365 glBlitFramebuffer(srcX0 < srcX1 ? 0 - xoffset : width - xoffset,
366 srcY0 < srcY1 ? 0 - yoffset : height - yoffset,
367 srcX0 < srcX1 ? width - xoffset : 0 - xoffset,
368 srcY0 < srcY1 ? height - yoffset : 0 - yoffset,
Zhenyao Mo 2016/09/06 22:30:11 Can you also expand your new conformance test to c
yunchao 2016/09/07 03:46:26 Sure, see the patch at https://github.com/KhronosG
369 dstX0, dstY0, dstX1, dstY1, mask, filter);
370
371 // Restore state
372 decoder->RestoreAllAttributes();
373 decoder->RestoreTextureUnitBindings(0);
374 decoder->RestoreActiveTexture();
375 decoder->RestoreProgramBindings();
376 decoder->RestoreBufferBindings();
377 decoder->RestoreFramebufferBindings();
378 decoder->RestoreGlobalState();
379 }
380
381 void SRGBConverter::LinearToSRGB(
382 const gles2::GLES2Decoder* decoder,
383 GLint srcX0,
384 GLint srcY0,
385 GLint srcX1,
386 GLint srcY1,
387 GLint dstX0,
388 GLint dstY0,
389 GLint dstX1,
390 GLint dstY1,
391 GLbitfield mask,
392 GLenum filter,
393 const gfx::Size& framebuffer_size,
394 GLuint src_framebuffer,
395 GLenum src_framebuffer_internal_format,
396 GLuint dst_framebuffer,
397 GLenum dst_framebuffer_internal_format,
398 GLenum dst_framebuffer_format,
399 GLenum dst_framebuffer_type) {
piman 2016/09/07 23:08:33 ditto, worth a high-level comment about what we do
yunchao 2016/09/08 18:32:49 Done.
400
401 DCHECK(srgb_encoder_initialized_);
402
403 // Copy the framebuffer to the first srgb encoder texture
404 glBindFramebufferEXT(GL_FRAMEBUFFER, src_framebuffer);
405 glActiveTexture(GL_TEXTURE0);
406 glBindTexture(GL_TEXTURE_2D, srgb_encoder_textures_[0]);
407
408 // We should not copy pixels outside of the read framebuffer. If we read
409 // these pixels, they would become in-bound during BlitFramebuffer. However,
410 // Out-of-bounds pixels will be initialized to 0 in CopyTexSubImage. But they
411 // should read as if the GL_CLAMP_TO_EDGE texture mapping mode were applied
412 // during BlitFramebuffer when the filter is GL_LINEAR.
413 GLuint x = srcX1 > srcX0 ? srcX0 : srcX1;
414 GLuint width = srcX1 > srcX0 ? srcX1 - srcX0 : srcX0 - srcX1;
415 GLuint y = srcY1 > srcY0 ? srcY0 : srcY1;
416 GLuint height = srcY1 > srcY0 ? srcY1 - srcY0 : srcY0 - srcY1;
417 gfx::Rect c(0, 0, framebuffer_size.width(), framebuffer_size.height());
418 c.Intersect(gfx::Rect(x, y, width, height));
419 GLuint xoffset = c.x() - x;
420 GLuint yoffset = c.y() - y;
421 glCopyTexImage2D(GL_TEXTURE_2D, 0, src_framebuffer_internal_format,
422 c.x(), c.y(), c.width(), c.height(), 0);
423
424 // Make a temporary framebuffer using the second srgb encoder texture to
425 // render the converted (linear to srgb) result to.
426 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
427
428 glBindTexture(GL_TEXTURE_2D, srgb_encoder_textures_[1]);
429 glTexImage2D(GL_TEXTURE_2D, 0, dst_framebuffer_internal_format,
430 c.width(), c.height(),
431 0, dst_framebuffer_format, dst_framebuffer_type, nullptr);
432 glBindFramebufferEXT(GL_FRAMEBUFFER, srgb_encoder_fbo_);
433 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
434 srgb_encoder_textures_[1], 0);
435
436 // Render to the second srgb encoder texture,
437 // sampling from the first srgb encoder texture.
438 glUseProgram(srgb_encoder_program_);
439 glViewport(0, 0, width, height);
440 glDisable(GL_SCISSOR_TEST);
441 glDisable(GL_DEPTH_TEST);
442 glDisable(GL_STENCIL_TEST);
443 glDisable(GL_CULL_FACE);
444 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
445 glDepthMask(GL_FALSE);
446 glDisable(GL_BLEND);
447 glDisable(GL_DITHER);
448
449 glBindTexture(GL_TEXTURE_2D, srgb_encoder_textures_[0]);
450 glBindVertexArrayOES(srgb_encoder_vao_);
451
452 glDrawArrays(GL_TRIANGLES, 0, 6);
453
454 // Finally, bind the temporary framebuffer as read framebuffer,
455 // blit the converted texture in temp fbo to the destination texture
456 // in destination framebuffer.
457 glBindFramebufferEXT(GL_READ_FRAMEBUFFER, srgb_encoder_fbo_);
458 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, dst_framebuffer);
459 // Note that the source region has been changed in temp framebuffer.
460 // The xoffset/yoffset can make bliting clamp to the correct edge if
461 // CLAMP_TO_EDGE is necessary.
462 glBlitFramebuffer(srcX0 < srcX1 ? 0 - xoffset : width - xoffset,
piman 2016/09/07 23:08:32 If we don't trust glBlitFramebuffer to correctly h
yunchao 2016/09/08 18:32:49 You are correct. My implementation is wrong for en
463 srcY0 < srcY1 ? 0 - yoffset : height - yoffset,
464 srcX0 < srcX1 ? width - xoffset : 0 - xoffset,
465 srcY0 < srcY1 ? height - yoffset : 0 - yoffset,
466 dstX0, dstY0, dstX1, dstY1, mask, filter);
467
468 // Restore state
469 decoder->RestoreAllAttributes();
470 decoder->RestoreTextureUnitBindings(0);
471 decoder->RestoreActiveTexture();
472 decoder->RestoreProgramBindings();
473 decoder->RestoreBufferBindings();
474 decoder->RestoreFramebufferBindings();
475 decoder->RestoreGlobalState();
476 }
477
478 } // namespace gles2.
479 } // namespace gpu
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698