Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(16)

Side by Side Diff: content/common/gpu/client/gl_helper.cc

Issue 1802383002: Move gl_helper to content/browser/compositor (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebased Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « content/common/gpu/client/gl_helper.h ('k') | content/common/gpu/client/gl_helper_benchmark.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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
OLDNEW
« no previous file with comments | « content/common/gpu/client/gl_helper.h ('k') | content/common/gpu/client/gl_helper_benchmark.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698