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