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(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 |