| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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 "content/common/gpu/client/gl_helper.h" | |
| 6 | |
| 7 #include <stddef.h> | |
| 8 #include <stdint.h> | |
| 9 | |
| 10 #include <queue> | |
| 11 #include <string> | |
| 12 | |
| 13 #include "base/bind.h" | |
| 14 #include "base/lazy_instance.h" | |
| 15 #include "base/logging.h" | |
| 16 #include "base/macros.h" | |
| 17 #include "base/memory/ref_counted.h" | |
| 18 #include "base/message_loop/message_loop.h" | |
| 19 #include "base/strings/string_util.h" | |
| 20 #include "base/time/time.h" | |
| 21 #include "base/trace_event/trace_event.h" | |
| 22 #include "content/common/gpu/client/gl_helper_readback_support.h" | |
| 23 #include "content/common/gpu/client/gl_helper_scaling.h" | |
| 24 #include "gpu/GLES2/gl2extchromium.h" | |
| 25 #include "gpu/command_buffer/client/context_support.h" | |
| 26 #include "gpu/command_buffer/common/mailbox.h" | |
| 27 #include "gpu/command_buffer/common/mailbox_holder.h" | |
| 28 #include "media/base/video_frame.h" | |
| 29 #include "media/base/video_util.h" | |
| 30 #include "third_party/skia/include/core/SkRegion.h" | |
| 31 #include "ui/gfx/geometry/point.h" | |
| 32 #include "ui/gfx/geometry/rect.h" | |
| 33 #include "ui/gfx/geometry/size.h" | |
| 34 | |
| 35 using gpu::gles2::GLES2Interface; | |
| 36 | |
| 37 namespace { | |
| 38 | |
| 39 class ScopedFlush { | |
| 40 public: | |
| 41 explicit ScopedFlush(gpu::gles2::GLES2Interface* gl) : gl_(gl) {} | |
| 42 | |
| 43 ~ScopedFlush() { gl_->Flush(); } | |
| 44 | |
| 45 private: | |
| 46 gpu::gles2::GLES2Interface* gl_; | |
| 47 | |
| 48 DISALLOW_COPY_AND_ASSIGN(ScopedFlush); | |
| 49 }; | |
| 50 | |
| 51 // Helper class for allocating and holding an RGBA texture of a given | |
| 52 // size and an associated framebuffer. | |
| 53 class TextureFrameBufferPair { | |
| 54 public: | |
| 55 TextureFrameBufferPair(GLES2Interface* gl, gfx::Size size) | |
| 56 : texture_(gl), framebuffer_(gl), size_(size) { | |
| 57 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl, texture_); | |
| 58 gl->TexImage2D(GL_TEXTURE_2D, | |
| 59 0, | |
| 60 GL_RGBA, | |
| 61 size.width(), | |
| 62 size.height(), | |
| 63 0, | |
| 64 GL_RGBA, | |
| 65 GL_UNSIGNED_BYTE, | |
| 66 NULL); | |
| 67 content::ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder( | |
| 68 gl, framebuffer_); | |
| 69 gl->FramebufferTexture2D( | |
| 70 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_, 0); | |
| 71 } | |
| 72 | |
| 73 GLuint texture() const { return texture_.id(); } | |
| 74 GLuint framebuffer() const { return framebuffer_.id(); } | |
| 75 gfx::Size size() const { return size_; } | |
| 76 | |
| 77 private: | |
| 78 content::ScopedTexture texture_; | |
| 79 content::ScopedFramebuffer framebuffer_; | |
| 80 gfx::Size size_; | |
| 81 | |
| 82 DISALLOW_COPY_AND_ASSIGN(TextureFrameBufferPair); | |
| 83 }; | |
| 84 | |
| 85 // Helper class for holding a scaler, a texture for the output of that | |
| 86 // scaler and an associated frame buffer. This is inteded to be used | |
| 87 // when the output of a scaler is to be sent to a readback. | |
| 88 class ScalerHolder { | |
| 89 public: | |
| 90 ScalerHolder(GLES2Interface* gl, content::GLHelper::ScalerInterface* scaler) | |
| 91 : texture_and_framebuffer_(gl, scaler->DstSize()), scaler_(scaler) {} | |
| 92 | |
| 93 void Scale(GLuint src_texture) { | |
| 94 scaler_->Scale(src_texture, texture_and_framebuffer_.texture()); | |
| 95 } | |
| 96 | |
| 97 content::GLHelper::ScalerInterface* scaler() const { return scaler_.get(); } | |
| 98 TextureFrameBufferPair* texture_and_framebuffer() { | |
| 99 return &texture_and_framebuffer_; | |
| 100 } | |
| 101 GLuint texture() const { return texture_and_framebuffer_.texture(); } | |
| 102 | |
| 103 private: | |
| 104 TextureFrameBufferPair texture_and_framebuffer_; | |
| 105 scoped_ptr<content::GLHelper::ScalerInterface> scaler_; | |
| 106 | |
| 107 DISALLOW_COPY_AND_ASSIGN(ScalerHolder); | |
| 108 }; | |
| 109 | |
| 110 } // namespace | |
| 111 | |
| 112 namespace content { | |
| 113 typedef GLHelperReadbackSupport::FormatSupport FormatSupport; | |
| 114 | |
| 115 // Implements GLHelper::CropScaleReadbackAndCleanTexture and encapsulates | |
| 116 // the data needed for it. | |
| 117 class GLHelper::CopyTextureToImpl | |
| 118 : public base::SupportsWeakPtr<GLHelper::CopyTextureToImpl> { | |
| 119 public: | |
| 120 CopyTextureToImpl(GLES2Interface* gl, | |
| 121 gpu::ContextSupport* context_support, | |
| 122 GLHelper* helper) | |
| 123 : gl_(gl), | |
| 124 context_support_(context_support), | |
| 125 helper_(helper), | |
| 126 flush_(gl), | |
| 127 max_draw_buffers_(0) { | |
| 128 const GLubyte* extensions = gl_->GetString(GL_EXTENSIONS); | |
| 129 if (!extensions) | |
| 130 return; | |
| 131 std::string extensions_string = | |
| 132 " " + std::string(reinterpret_cast<const char*>(extensions)) + " "; | |
| 133 if (extensions_string.find(" GL_EXT_draw_buffers ") != std::string::npos) { | |
| 134 gl_->GetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &max_draw_buffers_); | |
| 135 } | |
| 136 } | |
| 137 ~CopyTextureToImpl() { CancelRequests(); } | |
| 138 | |
| 139 GLuint ConsumeMailboxToTexture(const gpu::Mailbox& mailbox, | |
| 140 const gpu::SyncToken& sync_token) { | |
| 141 return helper_->ConsumeMailboxToTexture(mailbox, sync_token); | |
| 142 } | |
| 143 | |
| 144 void CropScaleReadbackAndCleanTexture( | |
| 145 GLuint src_texture, | |
| 146 const gfx::Size& src_size, | |
| 147 const gfx::Rect& src_subrect, | |
| 148 const gfx::Size& dst_size, | |
| 149 unsigned char* out, | |
| 150 const SkColorType out_color_type, | |
| 151 const base::Callback<void(bool)>& callback, | |
| 152 GLHelper::ScalerQuality quality); | |
| 153 | |
| 154 void ReadbackTextureSync(GLuint texture, | |
| 155 const gfx::Rect& src_rect, | |
| 156 unsigned char* out, | |
| 157 SkColorType format); | |
| 158 | |
| 159 void ReadbackTextureAsync(GLuint texture, | |
| 160 const gfx::Size& dst_size, | |
| 161 unsigned char* out, | |
| 162 SkColorType color_type, | |
| 163 const base::Callback<void(bool)>& callback); | |
| 164 | |
| 165 // Reads back bytes from the currently bound frame buffer. | |
| 166 // Note that dst_size is specified in bytes, not pixels. | |
| 167 void ReadbackAsync( | |
| 168 const gfx::Size& dst_size, | |
| 169 int32_t bytes_per_row, // generally dst_size.width() * 4 | |
| 170 int32_t row_stride_bytes, // generally dst_size.width() * 4 | |
| 171 unsigned char* out, | |
| 172 GLenum format, | |
| 173 GLenum type, | |
| 174 size_t bytes_per_pixel, | |
| 175 const base::Callback<void(bool)>& callback); | |
| 176 | |
| 177 void ReadbackPlane(TextureFrameBufferPair* source, | |
| 178 const scoped_refptr<media::VideoFrame>& target, | |
| 179 int plane, | |
| 180 int size_shift, | |
| 181 const gfx::Rect& paste_rect, | |
| 182 ReadbackSwizzle swizzle, | |
| 183 const base::Callback<void(bool)>& callback); | |
| 184 | |
| 185 GLuint CopyAndScaleTexture(GLuint texture, | |
| 186 const gfx::Size& src_size, | |
| 187 const gfx::Size& dst_size, | |
| 188 bool vertically_flip_texture, | |
| 189 GLHelper::ScalerQuality quality); | |
| 190 | |
| 191 ReadbackYUVInterface* CreateReadbackPipelineYUV( | |
| 192 GLHelper::ScalerQuality quality, | |
| 193 const gfx::Size& src_size, | |
| 194 const gfx::Rect& src_subrect, | |
| 195 const gfx::Size& dst_size, | |
| 196 bool flip_vertically, | |
| 197 bool use_mrt); | |
| 198 | |
| 199 // Returns the maximum number of draw buffers available, | |
| 200 // 0 if GL_EXT_draw_buffers is not available. | |
| 201 GLint MaxDrawBuffers() const { return max_draw_buffers_; } | |
| 202 | |
| 203 FormatSupport GetReadbackConfig(SkColorType color_type, | |
| 204 bool can_swizzle, | |
| 205 GLenum* format, | |
| 206 GLenum* type, | |
| 207 size_t* bytes_per_pixel); | |
| 208 | |
| 209 private: | |
| 210 // A single request to CropScaleReadbackAndCleanTexture. | |
| 211 // The main thread can cancel the request, before it's handled by the helper | |
| 212 // thread, by resetting the texture and pixels fields. Alternatively, the | |
| 213 // thread marks that it handles the request by resetting the pixels field | |
| 214 // (meaning it guarantees that the callback with be called). | |
| 215 // In either case, the callback must be called exactly once, and the texture | |
| 216 // must be deleted by the main thread gl. | |
| 217 struct Request { | |
| 218 Request(const gfx::Size& size_, | |
| 219 int32_t bytes_per_row_, | |
| 220 int32_t row_stride_bytes_, | |
| 221 unsigned char* pixels_, | |
| 222 const base::Callback<void(bool)>& callback_) | |
| 223 : done(false), | |
| 224 size(size_), | |
| 225 bytes_per_row(bytes_per_row_), | |
| 226 row_stride_bytes(row_stride_bytes_), | |
| 227 pixels(pixels_), | |
| 228 callback(callback_), | |
| 229 buffer(0), | |
| 230 query(0) {} | |
| 231 | |
| 232 bool done; | |
| 233 bool result; | |
| 234 gfx::Size size; | |
| 235 int bytes_per_row; | |
| 236 int row_stride_bytes; | |
| 237 unsigned char* pixels; | |
| 238 base::Callback<void(bool)> callback; | |
| 239 GLuint buffer; | |
| 240 GLuint query; | |
| 241 }; | |
| 242 | |
| 243 // We must take care to call the callbacks last, as they may | |
| 244 // end up destroying the gl_helper and make *this invalid. | |
| 245 // We stick the finished requests in a stack object that calls | |
| 246 // the callbacks when it goes out of scope. | |
| 247 class FinishRequestHelper { | |
| 248 public: | |
| 249 FinishRequestHelper() {} | |
| 250 ~FinishRequestHelper() { | |
| 251 while (!requests_.empty()) { | |
| 252 Request* request = requests_.front(); | |
| 253 requests_.pop(); | |
| 254 request->callback.Run(request->result); | |
| 255 delete request; | |
| 256 } | |
| 257 } | |
| 258 void Add(Request* r) { | |
| 259 requests_.push(r); | |
| 260 } | |
| 261 private: | |
| 262 std::queue<Request*> requests_; | |
| 263 DISALLOW_COPY_AND_ASSIGN(FinishRequestHelper); | |
| 264 }; | |
| 265 | |
| 266 // A readback pipeline that also converts the data to YUV before | |
| 267 // reading it back. | |
| 268 class ReadbackYUVImpl : public ReadbackYUVInterface { | |
| 269 public: | |
| 270 ReadbackYUVImpl(GLES2Interface* gl, | |
| 271 CopyTextureToImpl* copy_impl, | |
| 272 GLHelperScaling* scaler_impl, | |
| 273 GLHelper::ScalerQuality quality, | |
| 274 const gfx::Size& src_size, | |
| 275 const gfx::Rect& src_subrect, | |
| 276 const gfx::Size& dst_size, | |
| 277 bool flip_vertically, | |
| 278 ReadbackSwizzle swizzle); | |
| 279 | |
| 280 void ReadbackYUV(const gpu::Mailbox& mailbox, | |
| 281 const gpu::SyncToken& sync_token, | |
| 282 const scoped_refptr<media::VideoFrame>& target, | |
| 283 const gfx::Point& paste_location, | |
| 284 const base::Callback<void(bool)>& callback) override; | |
| 285 | |
| 286 ScalerInterface* scaler() override { return scaler_.scaler(); } | |
| 287 | |
| 288 private: | |
| 289 GLES2Interface* gl_; | |
| 290 CopyTextureToImpl* copy_impl_; | |
| 291 gfx::Size dst_size_; | |
| 292 ReadbackSwizzle swizzle_; | |
| 293 ScalerHolder scaler_; | |
| 294 ScalerHolder y_; | |
| 295 ScalerHolder u_; | |
| 296 ScalerHolder v_; | |
| 297 | |
| 298 DISALLOW_COPY_AND_ASSIGN(ReadbackYUVImpl); | |
| 299 }; | |
| 300 | |
| 301 // A readback pipeline that also converts the data to YUV before | |
| 302 // reading it back. This one uses Multiple Render Targets, which | |
| 303 // may not be supported on all platforms. | |
| 304 class ReadbackYUV_MRT : public ReadbackYUVInterface { | |
| 305 public: | |
| 306 ReadbackYUV_MRT(GLES2Interface* gl, | |
| 307 CopyTextureToImpl* copy_impl, | |
| 308 GLHelperScaling* scaler_impl, | |
| 309 GLHelper::ScalerQuality quality, | |
| 310 const gfx::Size& src_size, | |
| 311 const gfx::Rect& src_subrect, | |
| 312 const gfx::Size& dst_size, | |
| 313 bool flip_vertically, | |
| 314 ReadbackSwizzle swizzle); | |
| 315 | |
| 316 void ReadbackYUV(const gpu::Mailbox& mailbox, | |
| 317 const gpu::SyncToken& sync_token, | |
| 318 const scoped_refptr<media::VideoFrame>& target, | |
| 319 const gfx::Point& paste_location, | |
| 320 const base::Callback<void(bool)>& callback) override; | |
| 321 | |
| 322 ScalerInterface* scaler() override { return scaler_.scaler(); } | |
| 323 | |
| 324 private: | |
| 325 GLES2Interface* gl_; | |
| 326 CopyTextureToImpl* copy_impl_; | |
| 327 gfx::Size dst_size_; | |
| 328 GLHelper::ScalerQuality quality_; | |
| 329 ReadbackSwizzle swizzle_; | |
| 330 ScalerHolder scaler_; | |
| 331 scoped_ptr<content::GLHelperScaling::ShaderInterface> pass1_shader_; | |
| 332 scoped_ptr<content::GLHelperScaling::ShaderInterface> pass2_shader_; | |
| 333 TextureFrameBufferPair y_; | |
| 334 ScopedTexture uv_; | |
| 335 TextureFrameBufferPair u_; | |
| 336 TextureFrameBufferPair v_; | |
| 337 | |
| 338 DISALLOW_COPY_AND_ASSIGN(ReadbackYUV_MRT); | |
| 339 }; | |
| 340 | |
| 341 // Copies the block of pixels specified with |src_subrect| from |src_texture|, | |
| 342 // scales it to |dst_size|, writes it into a texture, and returns its ID. | |
| 343 // |src_size| is the size of |src_texture|. | |
| 344 GLuint ScaleTexture(GLuint src_texture, | |
| 345 const gfx::Size& src_size, | |
| 346 const gfx::Rect& src_subrect, | |
| 347 const gfx::Size& dst_size, | |
| 348 bool vertically_flip_texture, | |
| 349 bool swizzle, | |
| 350 SkColorType color_type, | |
| 351 GLHelper::ScalerQuality quality); | |
| 352 | |
| 353 // Converts each four consecutive pixels of the source texture into one pixel | |
| 354 // in the result texture with each pixel channel representing the grayscale | |
| 355 // color of one of the four original pixels: | |
| 356 // R1G1B1A1 R2G2B2A2 R3G3B3A3 R4G4B4A4 -> X1X2X3X4 | |
| 357 // The resulting texture is still an RGBA texture (which is ~4 times narrower | |
| 358 // than the original). If rendered directly, it wouldn't show anything useful, | |
| 359 // but the data in it can be used to construct a grayscale image. | |
| 360 // |encoded_texture_size| is the exact size of the resulting RGBA texture. It | |
| 361 // is equal to src_size.width()/4 rounded upwards. Some channels in the last | |
| 362 // pixel ((-src_size.width()) % 4) to be exact) are padding and don't contain | |
| 363 // useful data. | |
| 364 // If swizzle is set to true, the transformed pixels are reordered: | |
| 365 // R1G1B1A1 R2G2B2A2 R3G3B3A3 R4G4B4A4 -> X3X2X1X4. | |
| 366 GLuint EncodeTextureAsGrayscale(GLuint src_texture, | |
| 367 const gfx::Size& src_size, | |
| 368 gfx::Size* const encoded_texture_size, | |
| 369 bool vertically_flip_texture, | |
| 370 bool swizzle); | |
| 371 | |
| 372 static void nullcallback(bool success) {} | |
| 373 void ReadbackDone(Request *request, int bytes_per_pixel); | |
| 374 void FinishRequest(Request* request, | |
| 375 bool result, | |
| 376 FinishRequestHelper* helper); | |
| 377 void CancelRequests(); | |
| 378 | |
| 379 static const float kRGBtoYColorWeights[]; | |
| 380 static const float kRGBtoUColorWeights[]; | |
| 381 static const float kRGBtoVColorWeights[]; | |
| 382 static const float kRGBtoGrayscaleColorWeights[]; | |
| 383 | |
| 384 GLES2Interface* gl_; | |
| 385 gpu::ContextSupport* context_support_; | |
| 386 GLHelper* helper_; | |
| 387 | |
| 388 // A scoped flush that will ensure all resource deletions are flushed when | |
| 389 // this object is destroyed. Must be declared before other Scoped* fields. | |
| 390 ScopedFlush flush_; | |
| 391 | |
| 392 std::queue<Request*> request_queue_; | |
| 393 GLint max_draw_buffers_; | |
| 394 }; | |
| 395 | |
| 396 GLHelper::ScalerInterface* GLHelper::CreateScaler(ScalerQuality quality, | |
| 397 const gfx::Size& src_size, | |
| 398 const gfx::Rect& src_subrect, | |
| 399 const gfx::Size& dst_size, | |
| 400 bool vertically_flip_texture, | |
| 401 bool swizzle) { | |
| 402 InitScalerImpl(); | |
| 403 return scaler_impl_->CreateScaler(quality, | |
| 404 src_size, | |
| 405 src_subrect, | |
| 406 dst_size, | |
| 407 vertically_flip_texture, | |
| 408 swizzle); | |
| 409 } | |
| 410 | |
| 411 GLuint GLHelper::CopyTextureToImpl::ScaleTexture( | |
| 412 GLuint src_texture, | |
| 413 const gfx::Size& src_size, | |
| 414 const gfx::Rect& src_subrect, | |
| 415 const gfx::Size& dst_size, | |
| 416 bool vertically_flip_texture, | |
| 417 bool swizzle, | |
| 418 SkColorType color_type, | |
| 419 GLHelper::ScalerQuality quality) { | |
| 420 GLuint dst_texture = 0u; | |
| 421 gl_->GenTextures(1, &dst_texture); | |
| 422 { | |
| 423 GLenum format = GL_RGBA, type = GL_UNSIGNED_BYTE; | |
| 424 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, dst_texture); | |
| 425 | |
| 426 // Use GL_RGBA for destination/temporary texture unless we're working with | |
| 427 // 16-bit data | |
| 428 if (color_type == kRGB_565_SkColorType) { | |
| 429 format = GL_RGB; | |
| 430 type = GL_UNSIGNED_SHORT_5_6_5; | |
| 431 } | |
| 432 | |
| 433 gl_->TexImage2D(GL_TEXTURE_2D, | |
| 434 0, | |
| 435 format, | |
| 436 dst_size.width(), | |
| 437 dst_size.height(), | |
| 438 0, | |
| 439 format, | |
| 440 type, | |
| 441 NULL); | |
| 442 } | |
| 443 scoped_ptr<ScalerInterface> scaler( | |
| 444 helper_->CreateScaler(quality, | |
| 445 src_size, | |
| 446 src_subrect, | |
| 447 dst_size, | |
| 448 vertically_flip_texture, | |
| 449 swizzle)); | |
| 450 scaler->Scale(src_texture, dst_texture); | |
| 451 return dst_texture; | |
| 452 } | |
| 453 | |
| 454 GLuint GLHelper::CopyTextureToImpl::EncodeTextureAsGrayscale( | |
| 455 GLuint src_texture, | |
| 456 const gfx::Size& src_size, | |
| 457 gfx::Size* const encoded_texture_size, | |
| 458 bool vertically_flip_texture, | |
| 459 bool swizzle) { | |
| 460 GLuint dst_texture = 0u; | |
| 461 gl_->GenTextures(1, &dst_texture); | |
| 462 // The size of the encoded texture. | |
| 463 *encoded_texture_size = | |
| 464 gfx::Size((src_size.width() + 3) / 4, src_size.height()); | |
| 465 { | |
| 466 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, dst_texture); | |
| 467 gl_->TexImage2D(GL_TEXTURE_2D, | |
| 468 0, | |
| 469 GL_RGBA, | |
| 470 encoded_texture_size->width(), | |
| 471 encoded_texture_size->height(), | |
| 472 0, | |
| 473 GL_RGBA, | |
| 474 GL_UNSIGNED_BYTE, | |
| 475 NULL); | |
| 476 } | |
| 477 | |
| 478 helper_->InitScalerImpl(); | |
| 479 scoped_ptr<ScalerInterface> grayscale_scaler( | |
| 480 helper_->scaler_impl_.get()->CreatePlanarScaler( | |
| 481 src_size, | |
| 482 gfx::Rect(0, 0, (src_size.width() + 3) & ~3, src_size.height()), | |
| 483 *encoded_texture_size, | |
| 484 vertically_flip_texture, | |
| 485 swizzle, | |
| 486 kRGBtoGrayscaleColorWeights)); | |
| 487 grayscale_scaler->Scale(src_texture, dst_texture); | |
| 488 return dst_texture; | |
| 489 } | |
| 490 | |
| 491 void GLHelper::CopyTextureToImpl::ReadbackAsync( | |
| 492 const gfx::Size& dst_size, | |
| 493 int32_t bytes_per_row, | |
| 494 int32_t row_stride_bytes, | |
| 495 unsigned char* out, | |
| 496 GLenum format, | |
| 497 GLenum type, | |
| 498 size_t bytes_per_pixel, | |
| 499 const base::Callback<void(bool)>& callback) { | |
| 500 TRACE_EVENT0("gpu.capture", "GLHelper::CopyTextureToImpl::ReadbackAsync"); | |
| 501 Request* request = | |
| 502 new Request(dst_size, bytes_per_row, row_stride_bytes, out, callback); | |
| 503 request_queue_.push(request); | |
| 504 request->buffer = 0u; | |
| 505 | |
| 506 gl_->GenBuffers(1, &request->buffer); | |
| 507 gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, request->buffer); | |
| 508 gl_->BufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, | |
| 509 bytes_per_pixel * dst_size.GetArea(), | |
| 510 NULL, | |
| 511 GL_STREAM_READ); | |
| 512 | |
| 513 request->query = 0u; | |
| 514 gl_->GenQueriesEXT(1, &request->query); | |
| 515 gl_->BeginQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM, request->query); | |
| 516 gl_->ReadPixels(0, | |
| 517 0, | |
| 518 dst_size.width(), | |
| 519 dst_size.height(), | |
| 520 format, | |
| 521 type, | |
| 522 NULL); | |
| 523 gl_->EndQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM); | |
| 524 gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0); | |
| 525 context_support_->SignalQuery( | |
| 526 request->query, | |
| 527 base::Bind(&CopyTextureToImpl::ReadbackDone, AsWeakPtr(), | |
| 528 request, bytes_per_pixel)); | |
| 529 } | |
| 530 | |
| 531 void GLHelper::CopyTextureToImpl::CropScaleReadbackAndCleanTexture( | |
| 532 GLuint src_texture, | |
| 533 const gfx::Size& src_size, | |
| 534 const gfx::Rect& src_subrect, | |
| 535 const gfx::Size& dst_size, | |
| 536 unsigned char* out, | |
| 537 const SkColorType out_color_type, | |
| 538 const base::Callback<void(bool)>& callback, | |
| 539 GLHelper::ScalerQuality quality) { | |
| 540 GLenum format, type; | |
| 541 size_t bytes_per_pixel; | |
| 542 SkColorType readback_color_type = out_color_type; | |
| 543 // Single-component textures are not supported by all GPUs, so we implement | |
| 544 // kAlpha_8_SkColorType support here via a special encoding (see below) using | |
| 545 // a 32-bit texture to represent an 8-bit image. | |
| 546 // Thus we use generic 32-bit readback in this case. | |
| 547 if (out_color_type == kAlpha_8_SkColorType) { | |
| 548 readback_color_type = kRGBA_8888_SkColorType; | |
| 549 } | |
| 550 | |
| 551 FormatSupport supported = GetReadbackConfig( | |
| 552 readback_color_type, true, &format, &type, &bytes_per_pixel); | |
| 553 | |
| 554 if (supported == GLHelperReadbackSupport::NOT_SUPPORTED) { | |
| 555 callback.Run(false); | |
| 556 return; | |
| 557 } | |
| 558 | |
| 559 GLuint texture = src_texture; | |
| 560 | |
| 561 // Scale texture if needed | |
| 562 // Optimization: SCALER_QUALITY_FAST is just a single bilinear pass, which we | |
| 563 // can do just as well in EncodeTextureAsGrayscale, which we will do if | |
| 564 // out_color_type is kAlpha_8_SkColorType, so let's skip the scaling step | |
| 565 // in that case. | |
| 566 bool scale_texture = out_color_type != kAlpha_8_SkColorType || | |
| 567 quality != GLHelper::SCALER_QUALITY_FAST; | |
| 568 if (scale_texture) { | |
| 569 // Don't swizzle during the scale step for kAlpha_8_SkColorType. | |
| 570 // We will swizzle in the encode step below if needed. | |
| 571 bool scale_swizzle = out_color_type == kAlpha_8_SkColorType | |
| 572 ? false | |
| 573 : supported == GLHelperReadbackSupport::SWIZZLE; | |
| 574 texture = | |
| 575 ScaleTexture(src_texture, | |
| 576 src_size, | |
| 577 src_subrect, | |
| 578 dst_size, | |
| 579 true, | |
| 580 scale_swizzle, | |
| 581 out_color_type == kAlpha_8_SkColorType ? kN32_SkColorType | |
| 582 : out_color_type, | |
| 583 quality); | |
| 584 DCHECK(texture); | |
| 585 } | |
| 586 | |
| 587 gfx::Size readback_texture_size = dst_size; | |
| 588 // Encode texture to grayscale if needed. | |
| 589 if (out_color_type == kAlpha_8_SkColorType) { | |
| 590 // Do the vertical flip here if we haven't already done it when we scaled | |
| 591 // the texture. | |
| 592 bool encode_as_grayscale_vertical_flip = !scale_texture; | |
| 593 // EncodeTextureAsGrayscale by default creates a texture which should be | |
| 594 // read back as RGBA, so need to swizzle if the readback format is BGRA. | |
| 595 bool encode_as_grayscale_swizzle = format == GL_BGRA_EXT; | |
| 596 GLuint tmp_texture = | |
| 597 EncodeTextureAsGrayscale(texture, | |
| 598 dst_size, | |
| 599 &readback_texture_size, | |
| 600 encode_as_grayscale_vertical_flip, | |
| 601 encode_as_grayscale_swizzle); | |
| 602 // If the scaled texture was created - delete it | |
| 603 if (scale_texture) | |
| 604 gl_->DeleteTextures(1, &texture); | |
| 605 texture = tmp_texture; | |
| 606 DCHECK(texture); | |
| 607 } | |
| 608 | |
| 609 // Readback the pixels of the resulting texture | |
| 610 ScopedFramebuffer dst_framebuffer(gl_); | |
| 611 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_, | |
| 612 dst_framebuffer); | |
| 613 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture); | |
| 614 gl_->FramebufferTexture2D(GL_FRAMEBUFFER, | |
| 615 GL_COLOR_ATTACHMENT0, | |
| 616 GL_TEXTURE_2D, | |
| 617 texture, | |
| 618 0); | |
| 619 | |
| 620 int32_t bytes_per_row = out_color_type == kAlpha_8_SkColorType | |
| 621 ? dst_size.width() | |
| 622 : dst_size.width() * bytes_per_pixel; | |
| 623 | |
| 624 ReadbackAsync(readback_texture_size, | |
| 625 bytes_per_row, | |
| 626 bytes_per_row, | |
| 627 out, | |
| 628 format, | |
| 629 type, | |
| 630 bytes_per_pixel, | |
| 631 callback); | |
| 632 gl_->DeleteTextures(1, &texture); | |
| 633 } | |
| 634 | |
| 635 void GLHelper::CopyTextureToImpl::ReadbackTextureSync( | |
| 636 GLuint texture, | |
| 637 const gfx::Rect& src_rect, | |
| 638 unsigned char* out, | |
| 639 SkColorType color_type) { | |
| 640 GLenum format, type; | |
| 641 size_t bytes_per_pixel; | |
| 642 FormatSupport supported = | |
| 643 GetReadbackConfig(color_type, false, &format, &type, &bytes_per_pixel); | |
| 644 if (supported == GLHelperReadbackSupport::NOT_SUPPORTED) { | |
| 645 return; | |
| 646 } | |
| 647 | |
| 648 ScopedFramebuffer dst_framebuffer(gl_); | |
| 649 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_, | |
| 650 dst_framebuffer); | |
| 651 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture); | |
| 652 gl_->FramebufferTexture2D( | |
| 653 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); | |
| 654 gl_->ReadPixels(src_rect.x(), | |
| 655 src_rect.y(), | |
| 656 src_rect.width(), | |
| 657 src_rect.height(), | |
| 658 format, | |
| 659 type, | |
| 660 out); | |
| 661 } | |
| 662 | |
| 663 void GLHelper::CopyTextureToImpl::ReadbackTextureAsync( | |
| 664 GLuint texture, | |
| 665 const gfx::Size& dst_size, | |
| 666 unsigned char* out, | |
| 667 SkColorType color_type, | |
| 668 const base::Callback<void(bool)>& callback) { | |
| 669 GLenum format, type; | |
| 670 size_t bytes_per_pixel; | |
| 671 FormatSupport supported = | |
| 672 GetReadbackConfig(color_type, false, &format, &type, &bytes_per_pixel); | |
| 673 if (supported == GLHelperReadbackSupport::NOT_SUPPORTED) { | |
| 674 callback.Run(false); | |
| 675 return; | |
| 676 } | |
| 677 | |
| 678 ScopedFramebuffer dst_framebuffer(gl_); | |
| 679 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_, | |
| 680 dst_framebuffer); | |
| 681 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture); | |
| 682 gl_->FramebufferTexture2D(GL_FRAMEBUFFER, | |
| 683 GL_COLOR_ATTACHMENT0, | |
| 684 GL_TEXTURE_2D, | |
| 685 texture, | |
| 686 0); | |
| 687 ReadbackAsync(dst_size, | |
| 688 dst_size.width() * bytes_per_pixel, | |
| 689 dst_size.width() * bytes_per_pixel, | |
| 690 out, | |
| 691 format, | |
| 692 type, | |
| 693 bytes_per_pixel, | |
| 694 callback); | |
| 695 } | |
| 696 | |
| 697 GLuint GLHelper::CopyTextureToImpl::CopyAndScaleTexture( | |
| 698 GLuint src_texture, | |
| 699 const gfx::Size& src_size, | |
| 700 const gfx::Size& dst_size, | |
| 701 bool vertically_flip_texture, | |
| 702 GLHelper::ScalerQuality quality) { | |
| 703 return ScaleTexture(src_texture, | |
| 704 src_size, | |
| 705 gfx::Rect(src_size), | |
| 706 dst_size, | |
| 707 vertically_flip_texture, | |
| 708 false, | |
| 709 kRGBA_8888_SkColorType, // GL_RGBA | |
| 710 quality); | |
| 711 } | |
| 712 | |
| 713 void GLHelper::CopyTextureToImpl::ReadbackDone(Request* finished_request, | |
| 714 int bytes_per_pixel) { | |
| 715 TRACE_EVENT0("gpu.capture", | |
| 716 "GLHelper::CopyTextureToImpl::CheckReadbackFramebufferComplete"); | |
| 717 finished_request->done = true; | |
| 718 | |
| 719 FinishRequestHelper finish_request_helper; | |
| 720 | |
| 721 // We process transfer requests in the order they were received, regardless | |
| 722 // of the order we get the callbacks in. | |
| 723 while (!request_queue_.empty()) { | |
| 724 Request* request = request_queue_.front(); | |
| 725 if (!request->done) { | |
| 726 break; | |
| 727 } | |
| 728 | |
| 729 bool result = false; | |
| 730 if (request->buffer != 0) { | |
| 731 gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, request->buffer); | |
| 732 unsigned char* data = static_cast<unsigned char*>(gl_->MapBufferCHROMIUM( | |
| 733 GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY)); | |
| 734 if (data) { | |
| 735 result = true; | |
| 736 if (request->bytes_per_row == request->size.width() * bytes_per_pixel && | |
| 737 request->bytes_per_row == request->row_stride_bytes) { | |
| 738 memcpy(request->pixels, data, | |
| 739 request->size.GetArea() * bytes_per_pixel); | |
| 740 } else { | |
| 741 unsigned char* out = request->pixels; | |
| 742 for (int y = 0; y < request->size.height(); y++) { | |
| 743 memcpy(out, data, request->bytes_per_row); | |
| 744 out += request->row_stride_bytes; | |
| 745 data += request->size.width() * bytes_per_pixel; | |
| 746 } | |
| 747 } | |
| 748 gl_->UnmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM); | |
| 749 } | |
| 750 gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0); | |
| 751 } | |
| 752 FinishRequest(request, result, &finish_request_helper); | |
| 753 } | |
| 754 } | |
| 755 | |
| 756 void GLHelper::CopyTextureToImpl::FinishRequest( | |
| 757 Request* request, | |
| 758 bool result, | |
| 759 FinishRequestHelper* finish_request_helper) { | |
| 760 TRACE_EVENT0("gpu.capture", "GLHelper::CopyTextureToImpl::FinishRequest"); | |
| 761 DCHECK(request_queue_.front() == request); | |
| 762 request_queue_.pop(); | |
| 763 request->result = result; | |
| 764 ScopedFlush flush(gl_); | |
| 765 if (request->query != 0) { | |
| 766 gl_->DeleteQueriesEXT(1, &request->query); | |
| 767 request->query = 0; | |
| 768 } | |
| 769 if (request->buffer != 0) { | |
| 770 gl_->DeleteBuffers(1, &request->buffer); | |
| 771 request->buffer = 0; | |
| 772 } | |
| 773 finish_request_helper->Add(request); | |
| 774 } | |
| 775 | |
| 776 void GLHelper::CopyTextureToImpl::CancelRequests() { | |
| 777 FinishRequestHelper finish_request_helper; | |
| 778 while (!request_queue_.empty()) { | |
| 779 Request* request = request_queue_.front(); | |
| 780 FinishRequest(request, false, &finish_request_helper); | |
| 781 } | |
| 782 } | |
| 783 | |
| 784 FormatSupport GLHelper::CopyTextureToImpl::GetReadbackConfig( | |
| 785 SkColorType color_type, | |
| 786 bool can_swizzle, | |
| 787 GLenum* format, | |
| 788 GLenum* type, | |
| 789 size_t* bytes_per_pixel) { | |
| 790 return helper_->readback_support_->GetReadbackConfig( | |
| 791 color_type, can_swizzle, format, type, bytes_per_pixel); | |
| 792 } | |
| 793 | |
| 794 GLHelper::GLHelper(GLES2Interface* gl, gpu::ContextSupport* context_support) | |
| 795 : gl_(gl), | |
| 796 context_support_(context_support), | |
| 797 readback_support_(new GLHelperReadbackSupport(gl)) {} | |
| 798 | |
| 799 GLHelper::~GLHelper() {} | |
| 800 | |
| 801 void GLHelper::CropScaleReadbackAndCleanTexture( | |
| 802 GLuint src_texture, | |
| 803 const gfx::Size& src_size, | |
| 804 const gfx::Rect& src_subrect, | |
| 805 const gfx::Size& dst_size, | |
| 806 unsigned char* out, | |
| 807 const SkColorType out_color_type, | |
| 808 const base::Callback<void(bool)>& callback, | |
| 809 GLHelper::ScalerQuality quality) { | |
| 810 InitCopyTextToImpl(); | |
| 811 copy_texture_to_impl_->CropScaleReadbackAndCleanTexture(src_texture, | |
| 812 src_size, | |
| 813 src_subrect, | |
| 814 dst_size, | |
| 815 out, | |
| 816 out_color_type, | |
| 817 callback, | |
| 818 quality); | |
| 819 } | |
| 820 | |
| 821 void GLHelper::CropScaleReadbackAndCleanMailbox( | |
| 822 const gpu::Mailbox& src_mailbox, | |
| 823 const gpu::SyncToken& sync_token, | |
| 824 const gfx::Size& src_size, | |
| 825 const gfx::Rect& src_subrect, | |
| 826 const gfx::Size& dst_size, | |
| 827 unsigned char* out, | |
| 828 const SkColorType out_color_type, | |
| 829 const base::Callback<void(bool)>& callback, | |
| 830 GLHelper::ScalerQuality quality) { | |
| 831 GLuint mailbox_texture = ConsumeMailboxToTexture(src_mailbox, sync_token); | |
| 832 CropScaleReadbackAndCleanTexture(mailbox_texture, | |
| 833 src_size, | |
| 834 src_subrect, | |
| 835 dst_size, | |
| 836 out, | |
| 837 out_color_type, | |
| 838 callback, | |
| 839 quality); | |
| 840 gl_->DeleteTextures(1, &mailbox_texture); | |
| 841 } | |
| 842 | |
| 843 void GLHelper::ReadbackTextureSync(GLuint texture, | |
| 844 const gfx::Rect& src_rect, | |
| 845 unsigned char* out, | |
| 846 SkColorType format) { | |
| 847 InitCopyTextToImpl(); | |
| 848 copy_texture_to_impl_->ReadbackTextureSync(texture, src_rect, out, format); | |
| 849 } | |
| 850 | |
| 851 void GLHelper::ReadbackTextureAsync( | |
| 852 GLuint texture, | |
| 853 const gfx::Size& dst_size, | |
| 854 unsigned char* out, | |
| 855 SkColorType color_type, | |
| 856 const base::Callback<void(bool)>& callback) { | |
| 857 InitCopyTextToImpl(); | |
| 858 copy_texture_to_impl_->ReadbackTextureAsync(texture, | |
| 859 dst_size, | |
| 860 out, | |
| 861 color_type, | |
| 862 callback); | |
| 863 } | |
| 864 | |
| 865 GLuint GLHelper::CopyTexture(GLuint texture, const gfx::Size& size) { | |
| 866 InitCopyTextToImpl(); | |
| 867 return copy_texture_to_impl_->CopyAndScaleTexture( | |
| 868 texture, size, size, false, GLHelper::SCALER_QUALITY_FAST); | |
| 869 } | |
| 870 | |
| 871 GLuint GLHelper::CopyAndScaleTexture(GLuint texture, | |
| 872 const gfx::Size& src_size, | |
| 873 const gfx::Size& dst_size, | |
| 874 bool vertically_flip_texture, | |
| 875 ScalerQuality quality) { | |
| 876 InitCopyTextToImpl(); | |
| 877 return copy_texture_to_impl_->CopyAndScaleTexture( | |
| 878 texture, src_size, dst_size, vertically_flip_texture, quality); | |
| 879 } | |
| 880 | |
| 881 GLuint GLHelper::CompileShaderFromSource(const GLchar* source, GLenum type) { | |
| 882 GLuint shader = gl_->CreateShader(type); | |
| 883 GLint length = strlen(source); | |
| 884 gl_->ShaderSource(shader, 1, &source, &length); | |
| 885 gl_->CompileShader(shader); | |
| 886 GLint compile_status = 0; | |
| 887 gl_->GetShaderiv(shader, GL_COMPILE_STATUS, &compile_status); | |
| 888 if (!compile_status) { | |
| 889 GLint log_length = 0; | |
| 890 gl_->GetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length); | |
| 891 if (log_length) { | |
| 892 scoped_ptr<GLchar[]> log(new GLchar[log_length]); | |
| 893 GLsizei returned_log_length = 0; | |
| 894 gl_->GetShaderInfoLog( | |
| 895 shader, log_length, &returned_log_length, log.get()); | |
| 896 LOG(ERROR) << std::string(log.get(), returned_log_length); | |
| 897 } | |
| 898 gl_->DeleteShader(shader); | |
| 899 return 0; | |
| 900 } | |
| 901 return shader; | |
| 902 } | |
| 903 | |
| 904 void GLHelper::InitCopyTextToImpl() { | |
| 905 // Lazily initialize |copy_texture_to_impl_| | |
| 906 if (!copy_texture_to_impl_) | |
| 907 copy_texture_to_impl_.reset( | |
| 908 new CopyTextureToImpl(gl_, context_support_, this)); | |
| 909 } | |
| 910 | |
| 911 void GLHelper::InitScalerImpl() { | |
| 912 // Lazily initialize |scaler_impl_| | |
| 913 if (!scaler_impl_) | |
| 914 scaler_impl_.reset(new GLHelperScaling(gl_, this)); | |
| 915 } | |
| 916 | |
| 917 GLint GLHelper::MaxDrawBuffers() { | |
| 918 InitCopyTextToImpl(); | |
| 919 return copy_texture_to_impl_->MaxDrawBuffers(); | |
| 920 } | |
| 921 | |
| 922 void GLHelper::CopySubBufferDamage(GLenum target, | |
| 923 GLuint texture, | |
| 924 GLuint previous_texture, | |
| 925 const SkRegion& new_damage, | |
| 926 const SkRegion& old_damage) { | |
| 927 SkRegion region(old_damage); | |
| 928 if (region.op(new_damage, SkRegion::kDifference_Op)) { | |
| 929 ScopedFramebuffer dst_framebuffer(gl_); | |
| 930 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_, | |
| 931 dst_framebuffer); | |
| 932 gl_->BindTexture(target, texture); | |
| 933 gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, | |
| 934 previous_texture, 0); | |
| 935 for (SkRegion::Iterator it(region); !it.done(); it.next()) { | |
| 936 const SkIRect& rect = it.rect(); | |
| 937 gl_->CopyTexSubImage2D(target, 0, rect.x(), rect.y(), rect.x(), rect.y(), | |
| 938 rect.width(), rect.height()); | |
| 939 } | |
| 940 gl_->BindTexture(target, 0); | |
| 941 gl_->Flush(); | |
| 942 } | |
| 943 } | |
| 944 | |
| 945 GLuint GLHelper::CreateTexture() { | |
| 946 GLuint texture = 0u; | |
| 947 gl_->GenTextures(1, &texture); | |
| 948 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture); | |
| 949 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
| 950 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
| 951 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
| 952 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
| 953 return texture; | |
| 954 } | |
| 955 | |
| 956 void GLHelper::DeleteTexture(GLuint texture_id) { | |
| 957 gl_->DeleteTextures(1, &texture_id); | |
| 958 } | |
| 959 | |
| 960 void GLHelper::GenerateSyncToken(gpu::SyncToken* sync_token) { | |
| 961 const uint64_t fence_sync = gl_->InsertFenceSyncCHROMIUM(); | |
| 962 gl_->ShallowFlushCHROMIUM(); | |
| 963 gl_->GenSyncTokenCHROMIUM(fence_sync, sync_token->GetData()); | |
| 964 } | |
| 965 | |
| 966 void GLHelper::WaitSyncToken(const gpu::SyncToken& sync_token) { | |
| 967 gl_->WaitSyncTokenCHROMIUM(sync_token.GetConstData()); | |
| 968 } | |
| 969 | |
| 970 gpu::MailboxHolder GLHelper::ProduceMailboxHolderFromTexture( | |
| 971 GLuint texture_id) { | |
| 972 gpu::Mailbox mailbox; | |
| 973 gl_->GenMailboxCHROMIUM(mailbox.name); | |
| 974 gl_->ProduceTextureDirectCHROMIUM(texture_id, GL_TEXTURE_2D, mailbox.name); | |
| 975 | |
| 976 gpu::SyncToken sync_token; | |
| 977 GenerateSyncToken(&sync_token); | |
| 978 | |
| 979 return gpu::MailboxHolder(mailbox, sync_token, GL_TEXTURE_2D); | |
| 980 } | |
| 981 | |
| 982 GLuint GLHelper::ConsumeMailboxToTexture(const gpu::Mailbox& mailbox, | |
| 983 const gpu::SyncToken& sync_token) { | |
| 984 if (mailbox.IsZero()) | |
| 985 return 0; | |
| 986 if (sync_token.HasData()) | |
| 987 WaitSyncToken(sync_token); | |
| 988 GLuint texture = | |
| 989 gl_->CreateAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name); | |
| 990 return texture; | |
| 991 } | |
| 992 | |
| 993 void GLHelper::ResizeTexture(GLuint texture, const gfx::Size& size) { | |
| 994 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture); | |
| 995 gl_->TexImage2D(GL_TEXTURE_2D, | |
| 996 0, | |
| 997 GL_RGB, | |
| 998 size.width(), | |
| 999 size.height(), | |
| 1000 0, | |
| 1001 GL_RGB, | |
| 1002 GL_UNSIGNED_BYTE, | |
| 1003 NULL); | |
| 1004 } | |
| 1005 | |
| 1006 void GLHelper::CopyTextureSubImage(GLuint texture, const gfx::Rect& rect) { | |
| 1007 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture); | |
| 1008 gl_->CopyTexSubImage2D(GL_TEXTURE_2D, | |
| 1009 0, | |
| 1010 rect.x(), | |
| 1011 rect.y(), | |
| 1012 rect.x(), | |
| 1013 rect.y(), | |
| 1014 rect.width(), | |
| 1015 rect.height()); | |
| 1016 } | |
| 1017 | |
| 1018 void GLHelper::CopyTextureFullImage(GLuint texture, const gfx::Size& size) { | |
| 1019 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture); | |
| 1020 gl_->CopyTexImage2D( | |
| 1021 GL_TEXTURE_2D, 0, GL_RGB, 0, 0, size.width(), size.height(), 0); | |
| 1022 } | |
| 1023 | |
| 1024 void GLHelper::Flush() { | |
| 1025 gl_->Flush(); | |
| 1026 } | |
| 1027 | |
| 1028 void GLHelper::InsertOrderingBarrier() { | |
| 1029 gl_->OrderingBarrierCHROMIUM(); | |
| 1030 } | |
| 1031 | |
| 1032 void GLHelper::CopyTextureToImpl::ReadbackPlane( | |
| 1033 TextureFrameBufferPair* source, | |
| 1034 const scoped_refptr<media::VideoFrame>& target, | |
| 1035 int plane, | |
| 1036 int size_shift, | |
| 1037 const gfx::Rect& paste_rect, | |
| 1038 ReadbackSwizzle swizzle, | |
| 1039 const base::Callback<void(bool)>& callback) { | |
| 1040 gl_->BindFramebuffer(GL_FRAMEBUFFER, source->framebuffer()); | |
| 1041 const size_t offset = target->stride(plane) * (paste_rect.y() >> size_shift) + | |
| 1042 (paste_rect.x() >> size_shift); | |
| 1043 ReadbackAsync(source->size(), | |
| 1044 paste_rect.width() >> size_shift, | |
| 1045 target->stride(plane), | |
| 1046 target->data(plane) + offset, | |
| 1047 (swizzle == kSwizzleBGRA) ? GL_BGRA_EXT : GL_RGBA, | |
| 1048 GL_UNSIGNED_BYTE, | |
| 1049 4, | |
| 1050 callback); | |
| 1051 } | |
| 1052 | |
| 1053 const float GLHelper::CopyTextureToImpl::kRGBtoYColorWeights[] = { | |
| 1054 0.257f, 0.504f, 0.098f, 0.0625f}; | |
| 1055 const float GLHelper::CopyTextureToImpl::kRGBtoUColorWeights[] = { | |
| 1056 -0.148f, -0.291f, 0.439f, 0.5f}; | |
| 1057 const float GLHelper::CopyTextureToImpl::kRGBtoVColorWeights[] = { | |
| 1058 0.439f, -0.368f, -0.071f, 0.5f}; | |
| 1059 const float GLHelper::CopyTextureToImpl::kRGBtoGrayscaleColorWeights[] = { | |
| 1060 0.213f, 0.715f, 0.072f, 0.0f}; | |
| 1061 | |
| 1062 // YUV readback constructors. Initiates the main scaler pipeline and | |
| 1063 // one planar scaler for each of the Y, U and V planes. | |
| 1064 GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUVImpl( | |
| 1065 GLES2Interface* gl, | |
| 1066 CopyTextureToImpl* copy_impl, | |
| 1067 GLHelperScaling* scaler_impl, | |
| 1068 GLHelper::ScalerQuality quality, | |
| 1069 const gfx::Size& src_size, | |
| 1070 const gfx::Rect& src_subrect, | |
| 1071 const gfx::Size& dst_size, | |
| 1072 bool flip_vertically, | |
| 1073 ReadbackSwizzle swizzle) | |
| 1074 : gl_(gl), | |
| 1075 copy_impl_(copy_impl), | |
| 1076 dst_size_(dst_size), | |
| 1077 swizzle_(swizzle), | |
| 1078 scaler_(gl, | |
| 1079 scaler_impl->CreateScaler(quality, | |
| 1080 src_size, | |
| 1081 src_subrect, | |
| 1082 dst_size, | |
| 1083 flip_vertically, | |
| 1084 false)), | |
| 1085 y_(gl, | |
| 1086 scaler_impl->CreatePlanarScaler( | |
| 1087 dst_size, | |
| 1088 gfx::Rect(0, | |
| 1089 0, | |
| 1090 (dst_size.width() + 3) & ~3, | |
| 1091 dst_size.height()), | |
| 1092 gfx::Size((dst_size.width() + 3) / 4, dst_size.height()), | |
| 1093 false, | |
| 1094 (swizzle == kSwizzleBGRA), | |
| 1095 kRGBtoYColorWeights)), | |
| 1096 u_(gl, | |
| 1097 scaler_impl->CreatePlanarScaler( | |
| 1098 dst_size, | |
| 1099 gfx::Rect(0, | |
| 1100 0, | |
| 1101 (dst_size.width() + 7) & ~7, | |
| 1102 (dst_size.height() + 1) & ~1), | |
| 1103 gfx::Size((dst_size.width() + 7) / 8, | |
| 1104 (dst_size.height() + 1) / 2), | |
| 1105 false, | |
| 1106 (swizzle == kSwizzleBGRA), | |
| 1107 kRGBtoUColorWeights)), | |
| 1108 v_(gl, | |
| 1109 scaler_impl->CreatePlanarScaler( | |
| 1110 dst_size, | |
| 1111 gfx::Rect(0, | |
| 1112 0, | |
| 1113 (dst_size.width() + 7) & ~7, | |
| 1114 (dst_size.height() + 1) & ~1), | |
| 1115 gfx::Size((dst_size.width() + 7) / 8, | |
| 1116 (dst_size.height() + 1) / 2), | |
| 1117 false, | |
| 1118 (swizzle == kSwizzleBGRA), | |
| 1119 kRGBtoVColorWeights)) { | |
| 1120 DCHECK(!(dst_size.width() & 1)); | |
| 1121 DCHECK(!(dst_size.height() & 1)); | |
| 1122 } | |
| 1123 | |
| 1124 static void CallbackKeepingVideoFrameAlive( | |
| 1125 scoped_refptr<media::VideoFrame> video_frame, | |
| 1126 const base::Callback<void(bool)>& callback, | |
| 1127 bool success) { | |
| 1128 callback.Run(success); | |
| 1129 } | |
| 1130 | |
| 1131 void GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUV( | |
| 1132 const gpu::Mailbox& mailbox, | |
| 1133 const gpu::SyncToken& sync_token, | |
| 1134 const scoped_refptr<media::VideoFrame>& target, | |
| 1135 const gfx::Point& paste_location, | |
| 1136 const base::Callback<void(bool)>& callback) { | |
| 1137 DCHECK(!(paste_location.x() & 1)); | |
| 1138 DCHECK(!(paste_location.y() & 1)); | |
| 1139 | |
| 1140 GLuint mailbox_texture = | |
| 1141 copy_impl_->ConsumeMailboxToTexture(mailbox, sync_token); | |
| 1142 | |
| 1143 // Scale texture to right size. | |
| 1144 scaler_.Scale(mailbox_texture); | |
| 1145 gl_->DeleteTextures(1, &mailbox_texture); | |
| 1146 | |
| 1147 // Convert the scaled texture in to Y, U and V planes. | |
| 1148 y_.Scale(scaler_.texture()); | |
| 1149 u_.Scale(scaler_.texture()); | |
| 1150 v_.Scale(scaler_.texture()); | |
| 1151 | |
| 1152 const gfx::Rect paste_rect(paste_location, dst_size_); | |
| 1153 if (!target->visible_rect().Contains(paste_rect)) { | |
| 1154 LOG(DFATAL) << "Paste rect not inside VideoFrame's visible rect!"; | |
| 1155 callback.Run(false); | |
| 1156 return; | |
| 1157 } | |
| 1158 | |
| 1159 // Read back planes, one at a time. Keep the video frame alive while doing the | |
| 1160 // readback. | |
| 1161 copy_impl_->ReadbackPlane(y_.texture_and_framebuffer(), | |
| 1162 target, | |
| 1163 media::VideoFrame::kYPlane, | |
| 1164 0, | |
| 1165 paste_rect, | |
| 1166 swizzle_, | |
| 1167 base::Bind(&nullcallback)); | |
| 1168 copy_impl_->ReadbackPlane(u_.texture_and_framebuffer(), | |
| 1169 target, | |
| 1170 media::VideoFrame::kUPlane, | |
| 1171 1, | |
| 1172 paste_rect, | |
| 1173 swizzle_, | |
| 1174 base::Bind(&nullcallback)); | |
| 1175 copy_impl_->ReadbackPlane( | |
| 1176 v_.texture_and_framebuffer(), | |
| 1177 target, | |
| 1178 media::VideoFrame::kVPlane, | |
| 1179 1, | |
| 1180 paste_rect, | |
| 1181 swizzle_, | |
| 1182 base::Bind(&CallbackKeepingVideoFrameAlive, target, callback)); | |
| 1183 gl_->BindFramebuffer(GL_FRAMEBUFFER, 0); | |
| 1184 media::LetterboxYUV(target.get(), paste_rect); | |
| 1185 } | |
| 1186 | |
| 1187 // YUV readback constructors. Initiates the main scaler pipeline and | |
| 1188 // one planar scaler for each of the Y, U and V planes. | |
| 1189 GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV_MRT( | |
| 1190 GLES2Interface* gl, | |
| 1191 CopyTextureToImpl* copy_impl, | |
| 1192 GLHelperScaling* scaler_impl, | |
| 1193 GLHelper::ScalerQuality quality, | |
| 1194 const gfx::Size& src_size, | |
| 1195 const gfx::Rect& src_subrect, | |
| 1196 const gfx::Size& dst_size, | |
| 1197 bool flip_vertically, | |
| 1198 ReadbackSwizzle swizzle) | |
| 1199 : gl_(gl), | |
| 1200 copy_impl_(copy_impl), | |
| 1201 dst_size_(dst_size), | |
| 1202 quality_(quality), | |
| 1203 swizzle_(swizzle), | |
| 1204 scaler_(gl, | |
| 1205 scaler_impl->CreateScaler(quality, | |
| 1206 src_size, | |
| 1207 src_subrect, | |
| 1208 dst_size, | |
| 1209 false, | |
| 1210 false)), | |
| 1211 pass1_shader_(scaler_impl->CreateYuvMrtShader( | |
| 1212 dst_size, | |
| 1213 gfx::Rect(0, 0, (dst_size.width() + 3) & ~3, dst_size.height()), | |
| 1214 gfx::Size((dst_size.width() + 3) / 4, dst_size.height()), | |
| 1215 flip_vertically, | |
| 1216 (swizzle == kSwizzleBGRA), | |
| 1217 GLHelperScaling::SHADER_YUV_MRT_PASS1)), | |
| 1218 pass2_shader_(scaler_impl->CreateYuvMrtShader( | |
| 1219 gfx::Size((dst_size.width() + 3) / 4, dst_size.height()), | |
| 1220 gfx::Rect(0, | |
| 1221 0, | |
| 1222 (dst_size.width() + 7) / 8 * 2, | |
| 1223 dst_size.height()), | |
| 1224 gfx::Size((dst_size.width() + 7) / 8, | |
| 1225 (dst_size.height() + 1) / 2), | |
| 1226 false, | |
| 1227 (swizzle == kSwizzleBGRA), | |
| 1228 GLHelperScaling::SHADER_YUV_MRT_PASS2)), | |
| 1229 y_(gl, gfx::Size((dst_size.width() + 3) / 4, dst_size.height())), | |
| 1230 uv_(gl), | |
| 1231 u_(gl, | |
| 1232 gfx::Size((dst_size.width() + 7) / 8, | |
| 1233 (dst_size.height() + 1) / 2)), | |
| 1234 v_(gl, | |
| 1235 gfx::Size((dst_size.width() + 7) / 8, | |
| 1236 (dst_size.height() + 1) / 2)) { | |
| 1237 DCHECK(!(dst_size.width() & 1)); | |
| 1238 DCHECK(!(dst_size.height() & 1)); | |
| 1239 | |
| 1240 content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl, uv_); | |
| 1241 gl->TexImage2D(GL_TEXTURE_2D, | |
| 1242 0, | |
| 1243 GL_RGBA, | |
| 1244 (dst_size.width() + 3) / 4, | |
| 1245 dst_size.height(), | |
| 1246 0, | |
| 1247 GL_RGBA, | |
| 1248 GL_UNSIGNED_BYTE, | |
| 1249 NULL); | |
| 1250 } | |
| 1251 | |
| 1252 void GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV( | |
| 1253 const gpu::Mailbox& mailbox, | |
| 1254 const gpu::SyncToken& sync_token, | |
| 1255 const scoped_refptr<media::VideoFrame>& target, | |
| 1256 const gfx::Point& paste_location, | |
| 1257 const base::Callback<void(bool)>& callback) { | |
| 1258 DCHECK(!(paste_location.x() & 1)); | |
| 1259 DCHECK(!(paste_location.y() & 1)); | |
| 1260 | |
| 1261 GLuint mailbox_texture = | |
| 1262 copy_impl_->ConsumeMailboxToTexture(mailbox, sync_token); | |
| 1263 | |
| 1264 GLuint texture; | |
| 1265 if (quality_ == GLHelper::SCALER_QUALITY_FAST) { | |
| 1266 // Optimization: SCALER_QUALITY_FAST is just a single bilinear | |
| 1267 // pass, which pass1_shader_ can do just as well, so let's skip | |
| 1268 // the actual scaling in that case. | |
| 1269 texture = mailbox_texture; | |
| 1270 } else { | |
| 1271 // Scale texture to right size. | |
| 1272 scaler_.Scale(mailbox_texture); | |
| 1273 texture = scaler_.texture(); | |
| 1274 } | |
| 1275 | |
| 1276 std::vector<GLuint> outputs(2); | |
| 1277 // Convert the scaled texture in to Y, U and V planes. | |
| 1278 outputs[0] = y_.texture(); | |
| 1279 outputs[1] = uv_; | |
| 1280 pass1_shader_->Execute(texture, outputs); | |
| 1281 | |
| 1282 gl_->DeleteTextures(1, &mailbox_texture); | |
| 1283 | |
| 1284 outputs[0] = u_.texture(); | |
| 1285 outputs[1] = v_.texture(); | |
| 1286 pass2_shader_->Execute(uv_, outputs); | |
| 1287 | |
| 1288 const gfx::Rect paste_rect(paste_location, dst_size_); | |
| 1289 if (!target->visible_rect().Contains(paste_rect)) { | |
| 1290 LOG(DFATAL) << "Paste rect not inside VideoFrame's visible rect!"; | |
| 1291 callback.Run(false); | |
| 1292 return; | |
| 1293 } | |
| 1294 | |
| 1295 // Read back planes, one at a time. | |
| 1296 copy_impl_->ReadbackPlane(&y_, | |
| 1297 target, | |
| 1298 media::VideoFrame::kYPlane, | |
| 1299 0, | |
| 1300 paste_rect, | |
| 1301 swizzle_, | |
| 1302 base::Bind(&nullcallback)); | |
| 1303 copy_impl_->ReadbackPlane(&u_, | |
| 1304 target, | |
| 1305 media::VideoFrame::kUPlane, | |
| 1306 1, | |
| 1307 paste_rect, | |
| 1308 swizzle_, | |
| 1309 base::Bind(&nullcallback)); | |
| 1310 copy_impl_->ReadbackPlane( | |
| 1311 &v_, | |
| 1312 target, | |
| 1313 media::VideoFrame::kVPlane, | |
| 1314 1, | |
| 1315 paste_rect, | |
| 1316 swizzle_, | |
| 1317 base::Bind(&CallbackKeepingVideoFrameAlive, target, callback)); | |
| 1318 gl_->BindFramebuffer(GL_FRAMEBUFFER, 0); | |
| 1319 media::LetterboxYUV(target.get(), paste_rect); | |
| 1320 } | |
| 1321 | |
| 1322 bool GLHelper::IsReadbackConfigSupported(SkColorType color_type) { | |
| 1323 DCHECK(readback_support_.get()); | |
| 1324 GLenum format, type; | |
| 1325 size_t bytes_per_pixel; | |
| 1326 FormatSupport support = readback_support_->GetReadbackConfig( | |
| 1327 color_type, false, &format, &type, &bytes_per_pixel); | |
| 1328 | |
| 1329 return (support == GLHelperReadbackSupport::SUPPORTED); | |
| 1330 } | |
| 1331 | |
| 1332 ReadbackYUVInterface* GLHelper::CopyTextureToImpl::CreateReadbackPipelineYUV( | |
| 1333 GLHelper::ScalerQuality quality, | |
| 1334 const gfx::Size& src_size, | |
| 1335 const gfx::Rect& src_subrect, | |
| 1336 const gfx::Size& dst_size, | |
| 1337 bool flip_vertically, | |
| 1338 bool use_mrt) { | |
| 1339 helper_->InitScalerImpl(); | |
| 1340 // Just query if the best readback configuration needs a swizzle In | |
| 1341 // ReadbackPlane() we will choose GL_RGBA/GL_BGRA_EXT based on swizzle | |
| 1342 GLenum format, type; | |
| 1343 size_t bytes_per_pixel; | |
| 1344 FormatSupport supported = GetReadbackConfig( | |
| 1345 kRGBA_8888_SkColorType, true, &format, &type, &bytes_per_pixel); | |
| 1346 DCHECK((format == GL_RGBA || format == GL_BGRA_EXT) && | |
| 1347 type == GL_UNSIGNED_BYTE); | |
| 1348 | |
| 1349 ReadbackSwizzle swizzle = kSwizzleNone; | |
| 1350 if (supported == GLHelperReadbackSupport::SWIZZLE) | |
| 1351 swizzle = kSwizzleBGRA; | |
| 1352 | |
| 1353 if (max_draw_buffers_ >= 2 && use_mrt) { | |
| 1354 return new ReadbackYUV_MRT(gl_, | |
| 1355 this, | |
| 1356 helper_->scaler_impl_.get(), | |
| 1357 quality, | |
| 1358 src_size, | |
| 1359 src_subrect, | |
| 1360 dst_size, | |
| 1361 flip_vertically, | |
| 1362 swizzle); | |
| 1363 } | |
| 1364 return new ReadbackYUVImpl(gl_, | |
| 1365 this, | |
| 1366 helper_->scaler_impl_.get(), | |
| 1367 quality, | |
| 1368 src_size, | |
| 1369 src_subrect, | |
| 1370 dst_size, | |
| 1371 flip_vertically, | |
| 1372 swizzle); | |
| 1373 } | |
| 1374 | |
| 1375 ReadbackYUVInterface* GLHelper::CreateReadbackPipelineYUV( | |
| 1376 ScalerQuality quality, | |
| 1377 const gfx::Size& src_size, | |
| 1378 const gfx::Rect& src_subrect, | |
| 1379 const gfx::Size& dst_size, | |
| 1380 bool flip_vertically, | |
| 1381 bool use_mrt) { | |
| 1382 InitCopyTextToImpl(); | |
| 1383 return copy_texture_to_impl_->CreateReadbackPipelineYUV(quality, | |
| 1384 src_size, | |
| 1385 src_subrect, | |
| 1386 dst_size, | |
| 1387 flip_vertically, | |
| 1388 use_mrt); | |
| 1389 } | |
| 1390 | |
| 1391 } // namespace content | |
| OLD | NEW |