Chromium Code Reviews| 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 |