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