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 |