Index: gpu/command_buffer/service/gles2_cmd_srgb_converter.cc |
diff --git a/gpu/command_buffer/service/gles2_cmd_srgb_converter.cc b/gpu/command_buffer/service/gles2_cmd_srgb_converter.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..2deee0d2e594fca34364eecdd4bda1ca3f285470 |
--- /dev/null |
+++ b/gpu/command_buffer/service/gles2_cmd_srgb_converter.cc |
@@ -0,0 +1,521 @@ |
+// Copyright (c) 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "gpu/command_buffer/service/gles2_cmd_srgb_converter.h" |
+ |
+#include "gpu/command_buffer/service/texture_manager.h" |
+#include "ui/gl/gl_version_info.h" |
+ |
+namespace { |
+ |
+void CompileShader(GLuint shader, const char* shader_source) { |
+ glShaderSource(shader, 1, &shader_source, 0); |
+ glCompileShader(shader); |
+#ifndef NDEBUG |
+ GLint compile_status; |
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status); |
+ if (GL_TRUE != compile_status) |
+ DLOG(ERROR) << "CopyTexImage: shader compilation failure."; |
+#endif |
+} |
+ |
+} // anonymous namespace |
+ |
+namespace gpu { |
+namespace gles2 { |
+ |
+SRGBConverter::SRGBConverter( |
+ const gles2::FeatureInfo* feature_info) |
+ : feature_info_(feature_info) { |
+} |
+ |
+SRGBConverter::~SRGBConverter() {} |
+ |
+ |
+ |
+void SRGBConverter::InitializeSRGBConverterProgram() { |
+ if (srgb_converter_program_) { |
+ return; |
+ } |
+ |
+ srgb_converter_program_ = glCreateProgram(); |
+ |
+ // Compile the vertex shader |
+ const char* vs_source = |
+ "#version 150\n" |
+ "out vec2 v_texcoord;\n" |
+ "\n" |
+ "void main()\n" |
+ "{\n" |
+ " const vec2 quad_positions[6] = vec2[6]\n" |
+ " (\n" |
+ " vec2(0.0f, 0.0f),\n" |
+ " vec2(0.0f, 1.0f),\n" |
+ " vec2(1.0f, 0.0f),\n" |
+ "\n" |
+ " vec2(0.0f, 1.0f),\n" |
+ " vec2(1.0f, 0.0f),\n" |
+ " vec2(1.0f, 1.0f)\n" |
+ " );\n" |
+ "\n" |
+ " vec2 xy = vec2((quad_positions[gl_VertexID] * 2.0) - 1.0);\n" |
+ " gl_Position = vec4(xy, 0.0, 1.0);\n" |
+ " v_texcoord = quad_positions[gl_VertexID];\n" |
+ "}\n"; |
+ GLuint vs = glCreateShader(GL_VERTEX_SHADER); |
+ CompileShader(vs, vs_source); |
+ glAttachShader(srgb_converter_program_, vs); |
+ glDeleteShader(vs); |
+ |
+ // Compile the fragment shader |
+ |
+ // Sampling texels from a srgb texture to a linear image, it will convert |
+ // the srgb color space to linear color space automatically as a part of |
+ // filtering. See the section <sRGB Texture Color Conversion> in GLES and |
+ // OpenGL spec. So in decoder, we don't need to decode again. |
+ // Drawing to a srgb image, it will convert linear to srgb automatically. |
+ // See the section <sRGB Conversion> in GLES and OpenGL spec. |
+ // So we just use a simple fragment shader. We don't need to use an equation |
+ // in shader to do explicit srgb conversion to/from linear. |
+ const char* fs_source = |
+ "#version 150\n" |
+ "uniform sampler2D u_source_texture;\n" |
+ "in vec2 v_texcoord;\n" |
+ "out vec4 output_color;\n" |
+ "\n" |
+ "void main()\n" |
+ "{\n" |
+ " vec4 c = texture(u_source_texture, v_texcoord);\n" |
+ " output_color = c;\n" |
+ "}\n"; |
+ |
+ GLuint fs = glCreateShader(GL_FRAGMENT_SHADER); |
+ CompileShader(fs, fs_source); |
+ glAttachShader(srgb_converter_program_, fs); |
+ glDeleteShader(fs); |
+ |
+ glLinkProgram(srgb_converter_program_); |
+#ifndef NDEBUG |
+ GLint linked = 0; |
+ glGetProgramiv(srgb_converter_program_, GL_LINK_STATUS, &linked); |
+ if (!linked) { |
+ DLOG(ERROR) << "BlitFramebuffer: program link failure."; |
+ } |
+#endif |
+ |
+ GLuint texture_uniform = |
+ glGetUniformLocation(srgb_converter_program_, "u_source_texture"); |
+ glUseProgram(srgb_converter_program_); |
+ glUniform1i(texture_uniform, 0); |
+} |
+ |
+void SRGBConverter::InitializeSRGBDecoder( |
+ const gles2::GLES2Decoder* decoder) { |
+ if (srgb_decoder_initialized_) { |
+ return; |
+ } |
+ |
+ InitializeSRGBConverterProgram(); |
+ |
+ glGenTextures(srgb_decoder_textures_.size(), srgb_decoder_textures_.data()); |
+ glActiveTexture(GL_TEXTURE0); |
+ for (auto srgb_decoder_texture : srgb_decoder_textures_) { |
+ glBindTexture(GL_TEXTURE_2D, srgb_decoder_texture); |
+ |
+ // Use linear, non-mipmapped sampling with the srgb decoder texture |
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
+ } |
+ |
+ glGenFramebuffersEXT(1, &srgb_decoder_fbo_); |
+ glGenVertexArraysOES(1, &srgb_decoder_vao_); |
+ |
+ decoder->RestoreTextureUnitBindings(0); |
+ decoder->RestoreActiveTexture(); |
+ decoder->RestoreProgramBindings(); |
+ |
+ srgb_decoder_initialized_ = true; |
+} |
+ |
+void SRGBConverter::InitializeSRGBEncoder( |
+ const gles2::GLES2Decoder* decoder) { |
+ if (srgb_encoder_initialized_) { |
+ return; |
+ } |
+ |
+ InitializeSRGBConverterProgram(); |
+ |
+ glGenTextures(srgb_encoder_textures_.size(), srgb_encoder_textures_.data()); |
+ glActiveTexture(GL_TEXTURE0); |
+ for (auto srgb_encoder_texture : srgb_encoder_textures_) { |
+ glBindTexture(GL_TEXTURE_2D, srgb_encoder_texture); |
+ |
+ // Use linear, non-mipmapped sampling with the srgb encoder texture |
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
+ } |
+ |
+ glGenFramebuffersEXT(1, &srgb_encoder_fbo_); |
+ glGenVertexArraysOES(1, &srgb_encoder_vao_); |
+ |
+ decoder->RestoreTextureUnitBindings(0); |
+ decoder->RestoreActiveTexture(); |
+ decoder->RestoreProgramBindings(); |
+ |
+ srgb_encoder_initialized_ = true; |
+} |
+ |
+void SRGBConverter::Destroy() { |
+ if (srgb_decoder_initialized_) { |
+ glDeleteTextures(srgb_decoder_textures_.size(), |
+ srgb_decoder_textures_.data()); |
+ srgb_decoder_textures_.fill(0); |
+ |
+ glDeleteFramebuffersEXT(1, &srgb_decoder_fbo_); |
+ srgb_decoder_fbo_ = 0; |
+ |
+ glDeleteVertexArraysOES(1, &srgb_decoder_vao_); |
+ srgb_decoder_vao_ = 0; |
+ |
+ srgb_decoder_initialized_ = false; |
+ } |
+ |
+ if (srgb_encoder_initialized_) { |
+ glDeleteTextures(srgb_encoder_textures_.size(), |
+ srgb_encoder_textures_.data()); |
+ srgb_encoder_textures_.fill(0); |
+ |
+ glDeleteFramebuffersEXT(1, &srgb_encoder_fbo_); |
+ srgb_encoder_fbo_ = 0; |
+ |
+ glDeleteVertexArraysOES(1, &srgb_encoder_vao_); |
+ srgb_encoder_vao_ = 0; |
+ |
+ srgb_encoder_initialized_ = false; |
+ } |
+ |
+ glDeleteProgram(srgb_converter_program_); |
+ srgb_converter_program_ = 0; |
+} |
+ |
+void SRGBConverter::SRGBToLinear( |
+ const gles2::GLES2Decoder* decoder, |
+ GLint srcX0, |
+ GLint srcY0, |
+ GLint srcX1, |
+ GLint srcY1, |
+ GLint dstX0, |
+ GLint dstY0, |
+ GLint dstX1, |
+ GLint dstY1, |
+ GLbitfield mask, |
+ GLenum filter, |
+ const gfx::Size& framebuffer_size, |
+ GLuint src_framebuffer, |
+ GLenum src_framebuffer_internal_format, |
+ GLuint dst_framebuffer) { |
+ // This function blits srgb image in src fb to linear image in dst fb. |
+ // The steps are: |
+ // 1) Copy and crop pixels from source srgb image to the 1st texture(srgb). |
+ // 2) Sampling from the 1st texture and drawing to the 2nd texture(linear). |
+ // During this step, color space is converted from srgb to linear. |
+ // 3) Finally, blit pixels from the 2nd texture to the target, which is |
+ // also a linear image. |
+ DCHECK(srgb_decoder_initialized_); |
+ |
+ // Copy the image from read buffer to the decoder's 1st texture(srgb). |
+ // TODO(yunchao) If the read buffer is a fbo texture, we can sample |
+ // directly from that texture. In this way, we can save gpu memory. |
+ glBindFramebufferEXT(GL_FRAMEBUFFER, src_framebuffer); |
+ glActiveTexture(GL_TEXTURE0); |
+ glBindTexture(GL_TEXTURE_2D, srgb_decoder_textures_[0]); |
+ |
+ // We should not copy pixels outside of the read framebuffer. If we read |
+ // these pixels, they would become in-bound during BlitFramebuffer. However, |
+ // Out-of-bounds pixels will be initialized to 0 in CopyTexSubImage. But they |
+ // should read as if the GL_CLAMP_TO_EDGE texture mapping mode were applied |
+ // during BlitFramebuffer when the filter is GL_LINEAR. |
+ GLuint x = srcX1 > srcX0 ? srcX0 : srcX1; |
+ GLuint y = srcY1 > srcY0 ? srcY0 : srcY1; |
+ GLuint width = srcX1 > srcX0 ? srcX1 - srcX0 : srcX0 - srcX1; |
+ GLuint height = srcY1 > srcY0 ? srcY1 - srcY0 : srcY0 - srcY1; |
+ gfx::Rect c(0, 0, framebuffer_size.width(), framebuffer_size.height()); |
+ c.Intersect(gfx::Rect(x, y, width, height)); |
+ GLuint xoffset = c.x() - x; |
+ GLuint yoffset = c.y() - y; |
+ 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.
|
+ c.x(), c.y(), c.width(), c.height(), 0); |
+ |
+ // Make a temporary linear texture as the decoder's 2nd texture, where we |
+ // render the converted (srgb to linear) result to. |
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); |
+ |
+ glBindTexture(GL_TEXTURE_2D, srgb_decoder_textures_[1]); |
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, |
+ c.width(), c.height(), |
+ 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
+ glBindFramebufferEXT(GL_FRAMEBUFFER, srgb_decoder_fbo_); |
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
+ GL_TEXTURE_2D, srgb_decoder_textures_[1], 0); |
+ |
+ // Sampling from the decoder's first texture(srgb) and drawing to the |
+ // decoder's 2nd texture(linear), |
+ glUseProgram(srgb_converter_program_); |
+ glViewport(0, 0, width, height); |
+ glDisable(GL_SCISSOR_TEST); |
+ glDisable(GL_DEPTH_TEST); |
+ glDisable(GL_STENCIL_TEST); |
+ glDisable(GL_CULL_FACE); |
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
+ glDepthMask(GL_FALSE); |
+ glDisable(GL_BLEND); |
+ glDisable(GL_DITHER); |
+ |
+ glBindTexture(GL_TEXTURE_2D, srgb_decoder_textures_[0]); |
+ glBindVertexArrayOES(srgb_decoder_vao_); |
+ |
+ glDrawArrays(GL_TRIANGLES, 0, 6); |
+ |
+ // Finally, bind the decoder framebuffer as read framebuffer, |
+ // blit the converted texture in decoder fbo to the destination texture |
+ // in destination framebuffer. |
+ glBindFramebufferEXT(GL_READ_FRAMEBUFFER, srgb_decoder_fbo_); |
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, dst_framebuffer); |
+ // Note that the source region has been changed in decoder framebuffer. |
+ // The xoffset/yoffset can make bliting clamp to the correct edge if |
+ // CLAMP_TO_EDGE is necessary. |
+ glBlitFramebuffer(srcX0 < srcX1 ? 0 - xoffset : width - xoffset, |
+ srcY0 < srcY1 ? 0 - yoffset : height - yoffset, |
+ srcX0 < srcX1 ? width - xoffset : 0 - xoffset, |
+ srcY0 < srcY1 ? height - yoffset : 0 - yoffset, |
+ dstX0, dstY0, dstX1, dstY1, mask, filter); |
+ |
+ // Restore state |
+ decoder->RestoreAllAttributes(); |
+ decoder->RestoreTextureUnitBindings(0); |
+ decoder->RestoreActiveTexture(); |
+ decoder->RestoreProgramBindings(); |
+ decoder->RestoreBufferBindings(); |
+ decoder->RestoreFramebufferBindings(); |
+ decoder->RestoreGlobalState(); |
+} |
+ |
+void SRGBConverter::LinearToSRGB( |
+ const gles2::GLES2Decoder* decoder, |
+ GLint srcX0, |
+ GLint srcY0, |
+ GLint srcX1, |
+ GLint srcY1, |
+ GLint dstX0, |
+ GLint dstY0, |
+ GLint dstX1, |
+ GLint dstY1, |
+ GLbitfield mask, |
+ GLenum filter, |
+ GLuint src_framebuffer, |
+ GLenum src_framebuffer_internal_format, |
+ GLenum src_framebuffer_format, |
+ GLenum src_framebuffer_type, |
+ GLuint dst_framebuffer) { |
+ // This function blits linear image in src fb to srgb image in dst fb. |
+ // The steps are: |
+ // 1) BlitFramebuffer from source linear image to a temp linear texture. |
+ // 2) Sampling from the temp texture and drawing to the target srgb |
+ // image. During this step, color space is converted from linear to srgb. |
+ |
+ DCHECK(srgb_encoder_initialized_); |
+ |
+ // Create a temp linear texture as draw buffer. Blit framebuffer from |
+ // source linear image to the temp linear texture. Filtering is done |
+ // during bliting. Note that the src and dst coordinates may be reversed. |
+ glActiveTexture(GL_TEXTURE0); |
+ glBindTexture(GL_TEXTURE_2D, srgb_encoder_textures_[0]); |
+ |
+ GLuint width = dstX1 > dstX0 ? dstX1 - dstX0 : dstX0 - dstX1; |
+ GLuint height = dstY1 > dstY0 ? dstY1 - dstY0 : dstY0 - dstY1; |
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); |
+ glTexImage2D(GL_TEXTURE_2D, 0, src_framebuffer_internal_format, |
+ width, height, |
+ 0, src_framebuffer_format, src_framebuffer_type, nullptr); |
+ |
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, srgb_encoder_fbo_); |
+ glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
+ GL_TEXTURE_2D, srgb_encoder_textures_[0], 0); |
+ glBindFramebufferEXT(GL_READ_FRAMEBUFFER, src_framebuffer); |
+ glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, |
+ dstX0 < dstX1 ? 0 : width, |
+ dstY0 < dstY1 ? 0 : height, |
+ dstX0 < dstX1 ? width : 0, |
+ dstY0 < dstY1 ? height : 0, |
+ mask, filter); |
+ |
+ // Sampling from the linear texture and drawing to the target srgb image. |
+ // During this step, color space is converted from linear to srgb. We should |
+ // set appropriate viewport to draw to the correct location in target FB. |
+ GLuint xstart = dstX0 < dstX1 ? dstX0 : dstX1; |
+ GLuint ystart = dstY0 < dstY1 ? dstY0 : dstY1; |
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, dst_framebuffer); |
+ glUseProgram(srgb_converter_program_); |
+ glViewport(xstart, ystart, width, height); |
+ glDisable(GL_SCISSOR_TEST); |
+ glDisable(GL_DEPTH_TEST); |
+ glDisable(GL_STENCIL_TEST); |
+ glDisable(GL_CULL_FACE); |
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
+ glDepthMask(GL_FALSE); |
+ glDisable(GL_BLEND); |
+ glDisable(GL_DITHER); |
+ |
+ glBindTexture(GL_TEXTURE_2D, srgb_encoder_textures_[0]); |
+ glBindVertexArrayOES(srgb_encoder_vao_); |
+ |
+ glDrawArrays(GL_TRIANGLES, 0, 6); |
+ |
+ // Restore state |
+ decoder->RestoreAllAttributes(); |
+ decoder->RestoreTextureUnitBindings(0); |
+ decoder->RestoreActiveTexture(); |
+ decoder->RestoreProgramBindings(); |
+ decoder->RestoreBufferBindings(); |
+ decoder->RestoreFramebufferBindings(); |
+ decoder->RestoreGlobalState(); |
+} |
+ |
+void SRGBConverter::SRGBToSRGB( |
+ const gles2::GLES2Decoder* decoder, |
+ GLint srcX0, |
+ GLint srcY0, |
+ GLint srcX1, |
+ GLint srcY1, |
+ GLint dstX0, |
+ GLint dstY0, |
+ GLint dstX1, |
+ GLint dstY1, |
+ GLbitfield mask, |
+ GLenum filter, |
+ const gfx::Size& framebuffer_size, |
+ GLuint src_framebuffer, |
+ GLenum src_framebuffer_internal_format, |
+ GLuint dst_framebuffer) { |
+ // This function blits srgb image in src fb to srgb image in dst fb. |
+ // It needs to use decoder's resource, as well as encoder's resources, |
+ // for instance, decoder's and encoder's fbos, programs and textuers. |
+ // The steps are: |
+ // 1) Copy and crop pixels from source srgb image to the 1st texture(srgb). |
+ // 2) Sampling from the 1st texture and drawing to the 2nd texture(linear). |
+ // During this step, color space is converted from srgb to linear. |
+ // 3) Blit pixels from the 2nd texture to the 3rd texture(linear). |
+ // 4) Sampling from the 3rd texture and drawing to the dst image(srgb). |
+ // 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
|
+ DCHECK(srgb_decoder_initialized_ && srgb_encoder_initialized_); |
+ |
+ // Copy the image from read buffer to the decoder's 1st texture(srgb). |
+ // TODO(yunchao) If the read buffer is a fbo texture, we can sample |
+ // directly from that texture. In this way, we can save gpu memory. |
+ glBindFramebufferEXT(GL_FRAMEBUFFER, src_framebuffer); |
+ glActiveTexture(GL_TEXTURE0); |
+ glBindTexture(GL_TEXTURE_2D, srgb_decoder_textures_[0]); |
+ |
+ // We should not copy pixels outside of the read framebuffer. If we read |
+ // these pixels, they would become in-bound during BlitFramebuffer. However, |
+ // Out-of-bounds pixels will be initialized to 0 in CopyTexSubImage. But they |
+ // should read as if the GL_CLAMP_TO_EDGE texture mapping mode were applied |
+ // during BlitFramebuffer when the filter is GL_LINEAR. |
+ GLuint x = srcX1 > srcX0 ? srcX0 : srcX1; |
+ GLuint y = srcY1 > srcY0 ? srcY0 : srcY1; |
+ GLuint width_read = srcX1 > srcX0 ? srcX1 - srcX0 : srcX0 - srcX1; |
+ GLuint height_read = srcY1 > srcY0 ? srcY1 - srcY0 : srcY0 - srcY1; |
+ gfx::Rect c(0, 0, framebuffer_size.width(), framebuffer_size.height()); |
+ c.Intersect(gfx::Rect(x, y, width_read, height_read)); |
+ GLuint xoffset = c.x() - x; |
+ GLuint yoffset = c.y() - y; |
+ glCopyTexImage2D(GL_TEXTURE_2D, 0, src_framebuffer_internal_format, |
+ c.x(), c.y(), c.width(), c.height(), 0); |
+ |
+ // Make a temporary linear texture as the decoder's 2nd texture, where we |
+ // render the converted (srgb to linear) result to. |
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); |
+ |
+ glBindTexture(GL_TEXTURE_2D, srgb_decoder_textures_[1]); |
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, |
+ c.width(), c.height(), |
+ 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
+ glBindFramebufferEXT(GL_FRAMEBUFFER, srgb_decoder_fbo_); |
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
+ GL_TEXTURE_2D, srgb_decoder_textures_[1], 0); |
+ |
+ // Sampling from the decoder's first texture(srgb) and drawing to the |
+ // decoder's 2nd texture(linear), |
+ glUseProgram(srgb_converter_program_); |
+ glViewport(0, 0, width_read, height_read); |
+ glDisable(GL_SCISSOR_TEST); |
+ glDisable(GL_DEPTH_TEST); |
+ glDisable(GL_STENCIL_TEST); |
+ glDisable(GL_CULL_FACE); |
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
+ glDepthMask(GL_FALSE); |
+ glDisable(GL_BLEND); |
+ glDisable(GL_DITHER); |
+ |
+ glBindTexture(GL_TEXTURE_2D, srgb_decoder_textures_[0]); |
+ glBindVertexArrayOES(srgb_decoder_vao_); |
+ |
+ glDrawArrays(GL_TRIANGLES, 0, 6); |
+ |
+ // Create the 3rd texture(linear) as encoder's draw buffer. Blit framebuffer |
+ // from the 2nd texture(linear) to the 3rd texture. Filtering is done |
+ // during bliting. Note that the src and dst coordinates may be reversed. |
+ glBindTexture(GL_TEXTURE_2D, srgb_encoder_textures_[0]); |
+ |
+ GLuint width_draw = dstX1 > dstX0 ? dstX1 - dstX0 : dstX0 - dstX1; |
+ GLuint height_draw = dstY1 > dstY0 ? dstY1 - dstY0 : dstY0 - dstY1; |
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); |
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, |
+ width_draw, height_draw, |
+ 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
+ |
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, srgb_encoder_fbo_); |
+ glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
+ GL_TEXTURE_2D, srgb_encoder_textures_[0], 0); |
+ glBindFramebufferEXT(GL_READ_FRAMEBUFFER, srgb_decoder_fbo_); |
+ glBlitFramebuffer(srcX0 < srcX1 ? 0 - xoffset : width_read - xoffset, |
+ srcY0 < srcY1 ? 0 - yoffset : height_read - yoffset, |
+ srcX0 < srcX1 ? width_read - xoffset : 0 - xoffset, |
+ srcY0 < srcY1 ? height_read - yoffset : 0 - yoffset, |
+ dstX0 < dstX1 ? 0 : width_draw, |
+ dstY0 < dstY1 ? 0 : height_draw, |
+ dstX0 < dstX1 ? width_draw : 0, |
+ dstY0 < dstY1 ? height_draw : 0, |
+ mask, filter); |
+ |
+ // Sampling from the 3rd texture(linear) and drawing to the target srgb image. |
+ // During this step, color space is converted from linear to srgb. We should |
+ // set appropriate viewport to draw to the correct location in target FB. |
+ GLuint xstart = dstX0 < dstX1 ? dstX0 : dstX1; |
+ GLuint ystart = dstY0 < dstY1 ? dstY0 : dstY1; |
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, dst_framebuffer); |
+ glUseProgram(srgb_converter_program_); |
+ glViewport(xstart, ystart, width_draw, height_draw); |
+ |
+ glBindTexture(GL_TEXTURE_2D, srgb_encoder_textures_[0]); |
+ glBindVertexArrayOES(srgb_encoder_vao_); |
+ |
+ glDrawArrays(GL_TRIANGLES, 0, 6); |
+ |
+ // Restore state |
+ decoder->RestoreAllAttributes(); |
+ decoder->RestoreTextureUnitBindings(0); |
+ decoder->RestoreActiveTexture(); |
+ decoder->RestoreProgramBindings(); |
+ decoder->RestoreBufferBindings(); |
+ decoder->RestoreFramebufferBindings(); |
+ decoder->RestoreGlobalState(); |
+} |
+ |
+} // namespace gles2. |
+} // namespace gpu |