OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/common/gpu/client/gl_helper.h" | 5 #include "content/common/gpu/client/gl_helper.h" |
6 | 6 |
7 #include <queue> | 7 #include <set> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/debug/trace_event.h" | |
10 #include "base/lazy_instance.h" | 11 #include "base/lazy_instance.h" |
11 #include "base/logging.h" | 12 #include "base/logging.h" |
12 #include "base/memory/ref_counted.h" | 13 #include "base/memory/ref_counted.h" |
13 #include "base/message_loop.h" | 14 #include "base/message_loop.h" |
14 #include "base/synchronization/lock.h" | 15 #include "base/synchronization/lock.h" |
15 #include "base/synchronization/waitable_event.h" | 16 #include "base/synchronization/waitable_event.h" |
16 #include "base/threading/thread.h" | 17 #include "base/threading/thread.h" |
17 #include "base/threading/thread_restrictions.h" | 18 #include "base/threading/thread_restrictions.h" |
19 #include "base/time.h" | |
18 #include "third_party/WebKit/Source/Platform/chromium/public/WebCString.h" | 20 #include "third_party/WebKit/Source/Platform/chromium/public/WebCString.h" |
19 #include "third_party/WebKit/Source/Platform/chromium/public/WebString.h" | 21 #include "third_party/WebKit/Source/Platform/chromium/public/WebString.h" |
20 #include "third_party/skia/include/core/SkRegion.h" | 22 #include "third_party/skia/include/core/SkRegion.h" |
21 #include "ui/gfx/rect.h" | 23 #include "ui/gfx/rect.h" |
22 #include "ui/gfx/size.h" | 24 #include "ui/gfx/size.h" |
23 #include "ui/gl/gl_bindings.h" | 25 #include "ui/gl/gl_bindings.h" |
24 | 26 |
25 using WebKit::WebGLId; | 27 using WebKit::WebGLId; |
26 using WebKit::WebGraphicsContext3D; | 28 using WebKit::WebGraphicsContext3D; |
27 | 29 |
28 namespace { | 30 namespace { |
29 | 31 |
30 const char kGLHelperThreadName[] = "GLHelperThread"; | |
31 | |
32 class GLHelperThread : public base::Thread { | |
33 public: | |
34 GLHelperThread() : base::Thread(kGLHelperThreadName) { | |
35 Start(); | |
36 } | |
37 virtual ~GLHelperThread() { | |
38 Stop(); | |
39 } | |
40 | |
41 private: | |
42 DISALLOW_COPY_AND_ASSIGN(GLHelperThread); | |
43 }; | |
44 | |
45 base::LazyInstance<GLHelperThread> g_gl_helper_thread = | |
46 LAZY_INSTANCE_INITIALIZER; | |
47 | |
48 class ScopedWebGLId { | 32 class ScopedWebGLId { |
49 public: | 33 public: |
50 typedef void (WebGraphicsContext3D::*DeleteFunc)(WebGLId); | 34 typedef void (WebGraphicsContext3D::*DeleteFunc)(WebGLId); |
51 ScopedWebGLId(WebGraphicsContext3D* context, | 35 ScopedWebGLId(WebGraphicsContext3D* context, |
52 WebGLId id, | 36 WebGLId id, |
53 DeleteFunc delete_func) | 37 DeleteFunc delete_func) |
54 : context_(context), | 38 : context_(context), |
55 id_(id), | 39 id_(id), |
56 delete_func_(delete_func) { | 40 delete_func_(delete_func) { |
57 } | 41 } |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
232 | 216 |
233 } // namespace | 217 } // namespace |
234 | 218 |
235 namespace content { | 219 namespace content { |
236 | 220 |
237 // Implements GLHelper::CropScaleReadbackAndCleanTexture and encapsulates the | 221 // Implements GLHelper::CropScaleReadbackAndCleanTexture and encapsulates the |
238 // data needed for it. | 222 // data needed for it. |
239 class GLHelper::CopyTextureToImpl { | 223 class GLHelper::CopyTextureToImpl { |
240 public: | 224 public: |
241 CopyTextureToImpl(WebGraphicsContext3D* context, | 225 CopyTextureToImpl(WebGraphicsContext3D* context, |
242 WebGraphicsContext3D* context_for_thread, | |
243 GLHelper* helper) | 226 GLHelper* helper) |
244 : context_(context), | 227 : context_(context), |
245 context_for_thread_(context_for_thread), | |
246 helper_(helper), | 228 helper_(helper), |
247 flush_(context), | 229 flush_(context), |
248 program_(context, context->createProgram()), | 230 program_(context, context->createProgram()), |
249 vertex_attributes_buffer_(context_, context_->createBuffer()), | 231 vertex_attributes_buffer_(context_, context_->createBuffer()), |
250 flipped_vertex_attributes_buffer_(context_, context_->createBuffer()) { | 232 flipped_vertex_attributes_buffer_(context_, context_->createBuffer()) { |
251 InitBuffer(); | 233 InitBuffer(); |
252 InitProgram(); | 234 InitProgram(); |
253 } | 235 } |
254 ~CopyTextureToImpl() { | 236 ~CopyTextureToImpl() { |
255 CancelRequests(); | 237 CancelRequests(); |
256 DeleteContextForThread(); | |
257 } | 238 } |
258 | 239 |
259 void InitBuffer(); | 240 void InitBuffer(); |
260 void InitProgram(); | 241 void InitProgram(); |
261 | 242 |
262 void CropScaleReadbackAndCleanTexture( | 243 void CropScaleReadbackAndCleanTexture( |
263 WebGLId src_texture, | 244 WebGLId src_texture, |
264 const gfx::Size& src_size, | 245 const gfx::Size& src_size, |
265 const gfx::Rect& src_subrect, | 246 const gfx::Rect& src_subrect, |
266 const gfx::Size& dst_size, | 247 const gfx::Size& dst_size, |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
316 | 297 |
317 // Copies the block of pixels specified with |src_subrect| from |src_texture|, | 298 // Copies the block of pixels specified with |src_subrect| from |src_texture|, |
318 // scales it to |dst_size|, writes it into a texture, and returns its ID. | 299 // scales it to |dst_size|, writes it into a texture, and returns its ID. |
319 // |src_size| is the size of |src_texture|. | 300 // |src_size| is the size of |src_texture|. |
320 WebGLId ScaleTexture(WebGLId src_texture, | 301 WebGLId ScaleTexture(WebGLId src_texture, |
321 const gfx::Size& src_size, | 302 const gfx::Size& src_size, |
322 const gfx::Rect& src_subrect, | 303 const gfx::Rect& src_subrect, |
323 const gfx::Size& dst_size, | 304 const gfx::Size& dst_size, |
324 bool vertically_flip_texture); | 305 bool vertically_flip_texture); |
325 | 306 |
326 // Deletes the context for GLHelperThread. | |
327 void DeleteContextForThread(); | |
328 static void ReadBackFramebuffer(scoped_refptr<Request> request, | |
329 WebGraphicsContext3D* context, | |
330 scoped_refptr<base::TaskRunner> reply_loop); | |
331 static void ReadBackFramebufferComplete(scoped_refptr<Request> request, | 307 static void ReadBackFramebufferComplete(scoped_refptr<Request> request, |
332 bool result); | 308 GLuint buffer, GLuint query); |
333 void FinishRequest(scoped_refptr<Request> request); | 309 void FinishRequest(scoped_refptr<Request> request); |
334 void CancelRequests(); | 310 void CancelRequests(); |
335 | 311 |
336 // Interleaved array of 2-dimentional vertex positions (x, y) and | 312 // Interleaved array of 2-dimentional vertex positions (x, y) and |
337 // 2-dimentional texture coordinates (s, t). | 313 // 2-dimentional texture coordinates (s, t). |
338 static const WebKit::WGC3Dfloat kVertexAttributes[]; | 314 static const WebKit::WGC3Dfloat kVertexAttributes[]; |
339 // Interleaved array of 2-dimensional vertex positions (x, y) and | 315 // Interleaved array of 2-dimensional vertex positions (x, y) and |
340 // 2 dimensional texture coordinates (s, t). | 316 // 2 dimensional texture coordinates (s, t). |
341 static const WebKit::WGC3Dfloat kFlippedVertexAttributes[]; | 317 static const WebKit::WGC3Dfloat kFlippedVertexAttributes[]; |
342 // Shader sources used for GLHelper::CropScaleReadbackAndCleanTexture and | 318 // Shader sources used for GLHelper::CropScaleReadbackAndCleanTexture and |
343 // GLHelper::ReadbackTextureSync | 319 // GLHelper::ReadbackTextureSync |
344 static const WebKit::WGC3Dchar kCopyVertexShader[]; | 320 static const WebKit::WGC3Dchar kCopyVertexShader[]; |
345 static const WebKit::WGC3Dchar kCopyFragmentShader[]; | 321 static const WebKit::WGC3Dchar kCopyFragmentShader[]; |
346 | 322 |
347 WebGraphicsContext3D* context_; | 323 WebGraphicsContext3D* context_; |
348 WebGraphicsContext3D* context_for_thread_; | |
349 GLHelper* helper_; | 324 GLHelper* helper_; |
350 | 325 |
351 // A scoped flush that will ensure all resource deletions are flushed when | 326 // A scoped flush that will ensure all resource deletions are flushed when |
352 // this object is destroyed. Must be declared before other Scoped* fields. | 327 // this object is destroyed. Must be declared before other Scoped* fields. |
353 ScopedFlush flush_; | 328 ScopedFlush flush_; |
354 // A program for copying a source texture into a destination texture. | 329 // A program for copying a source texture into a destination texture. |
355 ScopedProgram program_; | 330 ScopedProgram program_; |
356 // The buffer that holds the vertices and the texture coordinates data for | 331 // The buffer that holds the vertices and the texture coordinates data for |
357 // drawing a quad. | 332 // drawing a quad. |
358 ScopedBuffer vertex_attributes_buffer_; | 333 ScopedBuffer vertex_attributes_buffer_; |
359 ScopedBuffer flipped_vertex_attributes_buffer_; | 334 ScopedBuffer flipped_vertex_attributes_buffer_; |
360 | 335 |
361 // The location of the position in the program. | 336 // The location of the position in the program. |
362 WebKit::WGC3Dint position_location_; | 337 WebKit::WGC3Dint position_location_; |
363 // The location of the texture coordinate in the program. | 338 // The location of the texture coordinate in the program. |
364 WebKit::WGC3Dint texcoord_location_; | 339 WebKit::WGC3Dint texcoord_location_; |
365 // The location of the source texture in the program. | 340 // The location of the source texture in the program. |
366 WebKit::WGC3Dint texture_location_; | 341 WebKit::WGC3Dint texture_location_; |
367 // The location of the texture coordinate of the sub-rectangle in the program. | 342 // The location of the texture coordinate of the sub-rectangle in the program. |
368 WebKit::WGC3Dint src_subrect_location_; | 343 WebKit::WGC3Dint src_subrect_location_; |
369 std::queue<scoped_refptr<Request> > request_queue_; | 344 std::set<scoped_refptr<Request> > request_set_; |
370 }; | 345 }; |
371 | 346 |
372 const WebKit::WGC3Dfloat GLHelper::CopyTextureToImpl::kVertexAttributes[] = { | 347 const WebKit::WGC3Dfloat GLHelper::CopyTextureToImpl::kVertexAttributes[] = { |
373 -1.0f, -1.0f, 0.0f, 0.0f, | 348 -1.0f, -1.0f, 0.0f, 0.0f, |
374 1.0f, -1.0f, 1.0f, 0.0f, | 349 1.0f, -1.0f, 1.0f, 0.0f, |
375 -1.0f, 1.0f, 0.0f, 1.0f, | 350 -1.0f, 1.0f, 0.0f, 1.0f, |
376 1.0f, 1.0f, 1.0f, 1.0f, | 351 1.0f, 1.0f, 1.0f, 1.0f, |
377 }; | 352 }; |
378 | 353 |
379 const WebKit::WGC3Dfloat | 354 const WebKit::WGC3Dfloat |
380 GLHelper::CopyTextureToImpl::kFlippedVertexAttributes[] = { | 355 GLHelper::CopyTextureToImpl::kFlippedVertexAttributes[] = { |
381 -1.0f, -1.0f, 0.0f, 1.0f, | 356 -1.0f, -1.0f, 0.0f, 1.0f, |
382 1.0f, -1.0f, 1.0f, 1.0f, | 357 1.0f, -1.0f, 1.0f, 1.0f, |
383 -1.0f, 1.0f, 0.0f, 0.0f, | 358 -1.0f, 1.0f, 0.0f, 0.0f, |
384 1.0f, 1.0f, 1.0f, 0.0f, | 359 1.0f, 1.0f, 1.0f, 0.0f, |
385 }; | 360 }; |
386 | 361 |
387 const WebKit::WGC3Dchar GLHelper::CopyTextureToImpl::kCopyVertexShader[] = | 362 const WebKit::WGC3Dchar GLHelper::CopyTextureToImpl::kCopyVertexShader[] = |
388 "attribute vec2 a_position;" | 363 "attribute vec2 a_position;" |
389 "attribute vec2 a_texcoord;" | 364 "attribute vec2 a_texcoord;" |
390 "varying vec2 v_texcoord;" | 365 "varying vec2 v_texcoord;" |
391 "uniform vec4 src_subrect;" | 366 "uniform vec4 src_subrect;" |
392 "void main() {" | 367 "void main() {" |
393 " gl_Position = vec4(a_position, 0.0, 1.0);" | 368 " gl_Position = vec4(a_position, 0.0, 1.0);" |
394 " v_texcoord = src_subrect.xy + a_texcoord * src_subrect.zw;" | 369 " v_texcoord = src_subrect.xy + a_texcoord * src_subrect.zw;" |
395 "}"; | 370 "}"; |
396 | 371 |
372 | |
373 #if (SK_R32_SHIFT == 16) && !SK_B32_SHIFT | |
397 const WebKit::WGC3Dchar GLHelper::CopyTextureToImpl::kCopyFragmentShader[] = | 374 const WebKit::WGC3Dchar GLHelper::CopyTextureToImpl::kCopyFragmentShader[] = |
398 "precision mediump float;" | 375 "precision mediump float;" |
399 "varying vec2 v_texcoord;" | 376 "varying vec2 v_texcoord;" |
377 "uniform sampler2D s_texture;" | |
378 "const mediump mat4 swizzle = mat4( 0.0, 0.0, 1.0, 0.0, " | |
379 " 0.0, 1.0, 0.0, 0.0, " | |
380 " 1.0, 0.0, 0.0, 0.0, " | |
381 " 0.0, 0.0, 0.0, 1.0 );" | |
382 "void main() {" | |
383 " gl_FragColor = swizzle * texture2D(s_texture, v_texcoord);" | |
apatrick_chromium
2013/03/19 18:34:48
Will this work? Seems a bit simpler.
gl_FragColor
hubbe
2013/03/19 22:42:42
Done.
| |
384 "}"; | |
385 #else | |
386 const WebKit::WGC3Dchar GLHelper::CopyTextureToImpl::kCopyFragmentShader[] = | |
387 "precision mediump float;" | |
388 "varying vec2 v_texcoord;" | |
400 "uniform sampler2D s_texture;" | 389 "uniform sampler2D s_texture;" |
401 "void main() {" | 390 "void main() {" |
402 " gl_FragColor = texture2D(s_texture, v_texcoord);" | 391 " gl_FragColor = texture2D(s_texture, v_texcoord);" |
403 "}"; | 392 "}"; |
393 #endif | |
394 | |
404 | 395 |
405 void GLHelper::CopyTextureToImpl::InitBuffer() { | 396 void GLHelper::CopyTextureToImpl::InitBuffer() { |
406 ScopedBufferBinder<GL_ARRAY_BUFFER> buffer_binder( | 397 ScopedBufferBinder<GL_ARRAY_BUFFER> buffer_binder( |
407 context_, vertex_attributes_buffer_); | 398 context_, vertex_attributes_buffer_); |
408 context_->bufferData(GL_ARRAY_BUFFER, | 399 context_->bufferData(GL_ARRAY_BUFFER, |
409 sizeof(kVertexAttributes), | 400 sizeof(kVertexAttributes), |
410 kVertexAttributes, | 401 kVertexAttributes, |
411 GL_STATIC_DRAW); | 402 GL_STATIC_DRAW); |
412 ScopedBufferBinder<GL_ARRAY_BUFFER> flipped_buffer_binder( | 403 ScopedBufferBinder<GL_ARRAY_BUFFER> flipped_buffer_binder( |
413 context_, flipped_vertex_attributes_buffer_); | 404 context_, flipped_vertex_attributes_buffer_); |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
510 }; | 501 }; |
511 | 502 |
512 context_->uniform4fv(src_subrect_location_, 1, src_subrect_texcoord); | 503 context_->uniform4fv(src_subrect_location_, 1, src_subrect_texcoord); |
513 | 504 |
514 // Conduct texture mapping by drawing a quad composed of two triangles. | 505 // Conduct texture mapping by drawing a quad composed of two triangles. |
515 context_->drawArrays(GL_TRIANGLE_STRIP, 0, 4); | 506 context_->drawArrays(GL_TRIANGLE_STRIP, 0, 4); |
516 } | 507 } |
517 return dst_texture; | 508 return dst_texture; |
518 } | 509 } |
519 | 510 |
520 void GLHelper::CopyTextureToImpl::DeleteContextForThread() { | |
521 if (!context_for_thread_) | |
522 return; | |
523 | |
524 g_gl_helper_thread.Pointer()->message_loop_proxy()->PostTask( | |
525 FROM_HERE, | |
526 base::Bind(&DeleteContext, | |
527 context_for_thread_)); | |
528 context_for_thread_ = NULL; | |
529 } | |
530 | |
531 void GLHelper::CopyTextureToImpl::CropScaleReadbackAndCleanTexture( | 511 void GLHelper::CopyTextureToImpl::CropScaleReadbackAndCleanTexture( |
532 WebGLId src_texture, | 512 WebGLId src_texture, |
533 const gfx::Size& src_size, | 513 const gfx::Size& src_size, |
534 const gfx::Rect& src_subrect, | 514 const gfx::Rect& src_subrect, |
535 const gfx::Size& dst_size, | 515 const gfx::Size& dst_size, |
536 unsigned char* out, | 516 unsigned char* out, |
537 const base::Callback<void(bool)>& callback) { | 517 const base::Callback<void(bool)>& callback) { |
538 if (!context_for_thread_) { | |
539 callback.Run(false); | |
540 return; | |
541 } | |
542 | |
543 WebGLId texture = ScaleTexture(src_texture, | 518 WebGLId texture = ScaleTexture(src_texture, |
544 src_size, | 519 src_size, |
545 src_subrect, | 520 src_subrect, |
546 dst_size, | 521 dst_size, |
547 false); | 522 #ifdef USE_SKIA |
523 true | |
524 #else | |
525 false | |
526 #endif | |
527 ); | |
548 context_->flush(); | 528 context_->flush(); |
549 scoped_refptr<Request> request = | 529 scoped_refptr<Request> request = |
550 new Request(this, texture, dst_size, out, callback); | 530 new Request(this, texture, dst_size, out, callback); |
551 request_queue_.push(request); | 531 request_set_.insert(request); |
552 | 532 |
553 g_gl_helper_thread.Pointer()->message_loop_proxy()->PostTask(FROM_HERE, | 533 ScopedFlush flush(context_); |
554 base::Bind(&ReadBackFramebuffer, | 534 ScopedFramebuffer dst_framebuffer(context_, context_->createFramebuffer()); |
555 request, | 535 gfx::Size size; |
556 context_for_thread_, | 536 base::AutoLock auto_lock(request->lock); |
557 base::MessageLoopProxy::current())); | 537 size = request->size; |
538 | |
539 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder( | |
540 context_, dst_framebuffer); | |
541 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder( | |
542 context_, request->texture); | |
543 context_->framebufferTexture2D(GL_FRAMEBUFFER, | |
544 GL_COLOR_ATTACHMENT0, | |
545 GL_TEXTURE_2D, | |
546 request->texture, | |
547 0); | |
548 GLuint buffer = context_->createBuffer(); | |
549 context_->bindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, | |
550 buffer); | |
551 context_->bufferData(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, | |
552 4 * size.GetArea(), | |
553 NULL, | |
554 GL_STREAM_READ); | |
555 | |
556 GLuint query = context_->createQueryEXT(); | |
557 context_->beginQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM, query); | |
558 context_->readPixels(0, 0, size.width(), size.height(), | |
559 GL_RGBA, GL_UNSIGNED_BYTE, 0); | |
560 context_->endQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM); | |
apatrick_chromium
2013/03/19 18:34:48
You might need to call flush here to guarantee tha
greggman
2013/03/19 20:54:11
yes, you need to call flush. endQueryEXT may or ma
hubbe
2013/03/19 22:42:42
Does the flush need to happen before endQueryExt?
apatrick_chromium
2013/03/19 23:31:20
I missed the ScopedFlush. It will work.
| |
561 context_->bindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); | |
apatrick_chromium
2013/03/19 18:34:48
What if a different buffer was bound to this targe
greggman
2013/03/19 20:54:11
You can't use UNPACK_TRANSFER_BUFFER for READing.
hubbe
2013/03/19 22:42:42
Good question.
Should I document what buffers are
hubbe
2013/03/19 22:42:42
I guess I have to implement that extension then, r
apatrick_chromium
2013/03/19 23:31:20
I think the issue is, before this code was using c
hubbe
2013/03/19 23:39:27
This things are cached in the client side, so rest
apatrick_chromium
2013/03/19 23:53:59
Yes it looks like getInteger(GL_PIXEL_PACK_TRANSFE
| |
562 base::MessageLoopProxy::current()->PostDelayedTask( | |
563 FROM_HERE, | |
564 base::Bind(&ReadBackFramebufferComplete, request, buffer, query), | |
565 base::TimeDelta::FromMilliseconds(2)); | |
558 } | 566 } |
559 | 567 |
560 void GLHelper::CopyTextureToImpl::ReadbackTextureSync(WebGLId texture, | 568 void GLHelper::CopyTextureToImpl::ReadbackTextureSync(WebGLId texture, |
561 const gfx::Rect& src_rect, | 569 const gfx::Rect& src_rect, |
562 unsigned char* out) { | 570 unsigned char* out) { |
563 ScopedFramebuffer dst_framebuffer(context_, context_->createFramebuffer()); | 571 ScopedFramebuffer dst_framebuffer(context_, context_->createFramebuffer()); |
564 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder( | 572 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder( |
565 context_, dst_framebuffer); | 573 context_, dst_framebuffer); |
566 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_, texture); | 574 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_, texture); |
567 context_->framebufferTexture2D(GL_FRAMEBUFFER, | 575 context_->framebufferTexture2D(GL_FRAMEBUFFER, |
(...skipping 15 matching lines...) Expand all Loading... | |
583 const gfx::Size& src_size, | 591 const gfx::Size& src_size, |
584 const gfx::Size& dst_size, | 592 const gfx::Size& dst_size, |
585 bool vertically_flip_texture) { | 593 bool vertically_flip_texture) { |
586 return ScaleTexture(src_texture, | 594 return ScaleTexture(src_texture, |
587 src_size, | 595 src_size, |
588 gfx::Rect(src_size), | 596 gfx::Rect(src_size), |
589 dst_size, | 597 dst_size, |
590 vertically_flip_texture); | 598 vertically_flip_texture); |
591 } | 599 } |
592 | 600 |
593 void GLHelper::CopyTextureToImpl::ReadBackFramebuffer( | |
594 scoped_refptr<Request> request, | |
595 WebGraphicsContext3D* context, | |
596 scoped_refptr<base::TaskRunner> reply_loop) { | |
597 DCHECK(context); | |
598 if (!context->makeContextCurrent() || context->isContextLost()) { | |
599 base::AutoLock auto_lock(request->lock); | |
600 if (request->pixels) { | |
601 // Only report failure if the request wasn't canceled (otherwise the | |
602 // failure has already been reported). | |
603 request->pixels = NULL; | |
604 reply_loop->PostTask( | |
605 FROM_HERE, base::Bind(ReadBackFramebufferComplete, request, false)); | |
606 } | |
607 return; | |
608 } | |
609 ScopedFlush flush(context); | |
610 ScopedFramebuffer dst_framebuffer(context, context->createFramebuffer()); | |
611 unsigned char* pixels = NULL; | |
612 gfx::Size size; | |
613 { | |
614 // Note: We don't want to keep the lock while doing the readBack (since we | |
615 // don't want to block the UI thread). We rely on the fact that once the | |
616 // texture is bound to a FBO (that isn't current), deleting the texture is | |
617 // delayed until the FBO is deleted. We ensure ordering by flushing while | |
618 // the lock is held. Either the main thread cancelled before we get the | |
619 // lock, and we'll exit early, or we ensure that the texture is bound to the | |
620 // framebuffer before the main thread has a chance to delete it. | |
621 base::AutoLock auto_lock(request->lock); | |
622 if (!request->texture || !request->pixels) | |
623 return; | |
624 pixels = request->pixels; | |
625 request->pixels = NULL; | |
626 size = request->size; | |
627 { | |
628 ScopedFlush flush(context); | |
629 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder( | |
630 context, dst_framebuffer); | |
631 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder( | |
632 context, request->texture); | |
633 context->framebufferTexture2D(GL_FRAMEBUFFER, | |
634 GL_COLOR_ATTACHMENT0, | |
635 GL_TEXTURE_2D, | |
636 request->texture, | |
637 0); | |
638 } | |
639 } | |
640 bool result = context->readBackFramebuffer( | |
641 pixels, | |
642 4 * size.GetArea(), | |
643 dst_framebuffer.id(), | |
644 size.width(), | |
645 size.height()); | |
646 reply_loop->PostTask( | |
647 FROM_HERE, base::Bind(ReadBackFramebufferComplete, request, result)); | |
648 } | |
649 | |
650 void GLHelper::CopyTextureToImpl::ReadBackFramebufferComplete( | 601 void GLHelper::CopyTextureToImpl::ReadBackFramebufferComplete( |
651 scoped_refptr<Request> request, | 602 scoped_refptr<Request> request, |
652 bool result) { | 603 GLuint buffer, GLuint query) { |
604 | |
605 TRACE_EVENT0("mirror", | |
606 "GLHelper::CopyTextureToImpl::ReadBackFramebufferComplete"); | |
607 | |
608 if (!request->copy_texture_impl) { | |
609 request->callback.Run(false); | |
610 return; | |
611 } | |
612 | |
613 WebKit::WebGraphicsContext3D* context = request->copy_texture_impl->context_; | |
614 bool result = false; | |
615 | |
616 if (buffer != 0) { | |
617 unsigned int done = 1; | |
618 context->getQueryObjectuivEXT(query, GL_QUERY_RESULT_AVAILABLE_EXT, &done); | |
619 if (!done) { | |
620 TRACE_EVENT0("mirror", | |
621 "GLHelper::CopyTextureToImpl::Reschedule"); | |
622 base::MessageLoopProxy::current()->PostDelayedTask( | |
623 FROM_HERE, | |
624 base::Bind(&ReadBackFramebufferComplete, request, buffer, query), | |
625 base::TimeDelta::FromMilliseconds(2)); | |
626 return; | |
627 } | |
628 context->deleteQueryEXT(query); | |
629 context->bindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, | |
630 buffer); | |
631 void* data = context->mapBufferCHROMIUM( | |
632 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY); | |
633 | |
634 if (data) { | |
635 result = true; | |
636 memcpy(request->pixels, data, request->size.GetArea() * 4); | |
637 context->unmapBufferCHROMIUM(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM); | |
638 } else { | |
639 fprintf(stderr,"mapBuffer Returns NULL\n"); | |
apatrick_chromium
2013/03/19 18:34:48
Use LOG / VLOG instead of fprintf.
hubbe
2013/03/19 22:42:42
Old useless debugging junk. Gone.
| |
640 } | |
641 context->bindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); | |
apatrick_chromium
2013/03/19 18:34:48
Same as above. There might have been a different b
hubbe
2013/03/19 22:42:42
This is in an async callback. Is it really reasona
apatrick_chromium
2013/03/19 23:31:20
The assumption might have been made somewhere. Nee
hubbe
2013/03/19 23:39:27
While it is possible, the browser still works when
apatrick_chromium
2013/03/19 23:53:59
You can do the same thing to get the buffer bindin
| |
642 context->deleteBuffer(buffer); | |
643 } else { | |
644 fprintf(stderr,"Buffer is negative!\n"); | |
apatrick_chromium
2013/03/19 18:34:48
Use LOG / VLOG instead of fprintf.
hubbe
2013/03/19 22:42:42
Gone.
| |
645 } | |
646 | |
653 request->callback.Run(result); | 647 request->callback.Run(result); |
654 if (request->copy_texture_impl) | 648 request->copy_texture_impl->FinishRequest(request); |
655 request->copy_texture_impl->FinishRequest(request); | |
656 } | 649 } |
657 | 650 |
658 void GLHelper::CopyTextureToImpl::FinishRequest( | 651 void GLHelper::CopyTextureToImpl::FinishRequest( |
659 scoped_refptr<Request> request) { | 652 scoped_refptr<Request> request) { |
660 CHECK(request_queue_.front() == request); | 653 CHECK(request_set_.find(request) != request_set_.end()); |
661 request_queue_.pop(); | 654 request_set_.erase(request); |
662 base::AutoLock auto_lock(request->lock); | 655 base::AutoLock auto_lock(request->lock); |
663 if (request->texture != 0) { | 656 if (request->texture != 0) { |
664 context_->deleteTexture(request->texture); | 657 context_->deleteTexture(request->texture); |
665 request->texture = 0; | 658 request->texture = 0; |
666 context_->flush(); | 659 context_->flush(); |
667 } | 660 } |
668 } | 661 } |
669 | 662 |
670 void GLHelper::CopyTextureToImpl::CancelRequests() { | 663 void GLHelper::CopyTextureToImpl::CancelRequests() { |
671 while (!request_queue_.empty()) { | 664 while (!request_set_.empty()) { |
672 scoped_refptr<Request> request = request_queue_.front(); | 665 scoped_refptr<Request> request = *request_set_.begin(); |
673 request_queue_.pop(); | 666 request_set_.erase(request); |
674 request->copy_texture_impl = NULL; | 667 request->copy_texture_impl = NULL; |
675 bool cancelled = false; | 668 bool cancelled = false; |
676 { | 669 { |
677 base::AutoLock auto_lock(request->lock); | 670 base::AutoLock auto_lock(request->lock); |
678 if (request->texture != 0) { | 671 if (request->texture != 0) { |
679 context_->deleteTexture(request->texture); | 672 context_->deleteTexture(request->texture); |
680 request->texture = 0; | 673 request->texture = 0; |
681 } | 674 } |
682 if (request->pixels != NULL) { | 675 if (request->pixels != NULL) { |
683 request->pixels = NULL; | 676 request->pixels = NULL; |
684 cancelled = true; | 677 cancelled = true; |
685 } | 678 } |
686 } | 679 } |
687 if (cancelled) | 680 if (cancelled) |
688 request->callback.Run(false); | 681 request->callback.Run(false); |
689 } | 682 } |
690 } | 683 } |
691 | 684 |
692 base::subtle::Atomic32 GLHelper::count_ = 0; | 685 GLHelper::GLHelper(WebGraphicsContext3D* context) |
693 | 686 : context_(context) { |
694 GLHelper::GLHelper(WebGraphicsContext3D* context, | |
695 WebGraphicsContext3D* context_for_thread) | |
696 : context_(context), | |
697 context_for_thread_(context_for_thread) { | |
698 base::subtle::NoBarrier_AtomicIncrement(&count_, 1); | |
699 } | 687 } |
700 | 688 |
701 GLHelper::~GLHelper() { | 689 GLHelper::~GLHelper() { |
702 DCHECK_NE(MessageLoop::current(), | |
703 g_gl_helper_thread.Pointer()->message_loop()); | |
704 base::subtle::Atomic32 decremented_count = | |
705 base::subtle::NoBarrier_AtomicIncrement(&count_, -1); | |
706 if (decremented_count == 0) { | |
707 // When this is the last instance, we synchronize with the pending | |
708 // operations on GLHelperThread. Otherwise on shutdown we may kill the GPU | |
709 // process infrastructure (BrowserGpuChannelHostFactory) before they have | |
710 // a chance to complete, likely leading to a crash. | |
711 base::WaitableEvent event(false, false); | |
712 g_gl_helper_thread.Pointer()->message_loop_proxy()->PostTask( | |
713 FROM_HERE, | |
714 base::Bind(&SignalWaitableEvent, | |
715 &event)); | |
716 // http://crbug.com/125415 | |
717 base::ThreadRestrictions::ScopedAllowWait allow_wait; | |
718 event.Wait(); | |
719 } | |
720 } | 690 } |
721 | 691 |
722 WebGraphicsContext3D* GLHelper::context() const { | 692 WebGraphicsContext3D* GLHelper::context() const { |
723 return context_; | 693 return context_; |
724 } | 694 } |
725 | 695 |
726 void GLHelper::CropScaleReadbackAndCleanTexture( | 696 void GLHelper::CropScaleReadbackAndCleanTexture( |
727 WebGLId src_texture, | 697 WebGLId src_texture, |
728 const gfx::Size& src_size, | 698 const gfx::Size& src_size, |
729 const gfx::Rect& src_subrect, | 699 const gfx::Rect& src_subrect, |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
779 if (!compile_status) { | 749 if (!compile_status) { |
780 LOG(ERROR) << std::string(context_->getShaderInfoLog(shader).utf8()); | 750 LOG(ERROR) << std::string(context_->getShaderInfoLog(shader).utf8()); |
781 return 0; | 751 return 0; |
782 } | 752 } |
783 return shader.Detach(); | 753 return shader.Detach(); |
784 } | 754 } |
785 | 755 |
786 void GLHelper::InitCopyTextToImpl() { | 756 void GLHelper::InitCopyTextToImpl() { |
787 // Lazily initialize |copy_texture_to_impl_| | 757 // Lazily initialize |copy_texture_to_impl_| |
788 if (!copy_texture_to_impl_.get()) | 758 if (!copy_texture_to_impl_.get()) |
789 copy_texture_to_impl_.reset(new CopyTextureToImpl(context_, | 759 copy_texture_to_impl_.reset(new CopyTextureToImpl(context_, this)); |
790 context_for_thread_, | |
791 this)); | |
792 } | 760 } |
793 | 761 |
794 void GLHelper::CopySubBufferDamage(WebKit::WebGLId texture, | 762 void GLHelper::CopySubBufferDamage(WebKit::WebGLId texture, |
795 WebKit::WebGLId previous_texture, | 763 WebKit::WebGLId previous_texture, |
796 const SkRegion& new_damage, | 764 const SkRegion& new_damage, |
797 const SkRegion& old_damage) { | 765 const SkRegion& old_damage) { |
798 SkRegion region(old_damage); | 766 SkRegion region(old_damage); |
799 if (region.op(new_damage, SkRegion::kDifference_Op)) { | 767 if (region.op(new_damage, SkRegion::kDifference_Op)) { |
800 ScopedFramebuffer dst_framebuffer(context_, context_->createFramebuffer()); | 768 ScopedFramebuffer dst_framebuffer(context_, context_->createFramebuffer()); |
801 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder( | 769 ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder( |
802 context_, dst_framebuffer); | 770 context_, dst_framebuffer); |
803 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_, texture); | 771 ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_, texture); |
804 context_->framebufferTexture2D(GL_FRAMEBUFFER, | 772 context_->framebufferTexture2D(GL_FRAMEBUFFER, |
805 GL_COLOR_ATTACHMENT0, | 773 GL_COLOR_ATTACHMENT0, |
806 GL_TEXTURE_2D, | 774 GL_TEXTURE_2D, |
807 previous_texture, | 775 previous_texture, |
808 0); | 776 0); |
809 for (SkRegion::Iterator it(region); !it.done(); it.next()) { | 777 for (SkRegion::Iterator it(region); !it.done(); it.next()) { |
810 const SkIRect& rect = it.rect(); | 778 const SkIRect& rect = it.rect(); |
811 context_->copyTexSubImage2D(GL_TEXTURE_2D, 0, | 779 context_->copyTexSubImage2D(GL_TEXTURE_2D, 0, |
812 rect.x(), rect.y(), | 780 rect.x(), rect.y(), |
813 rect.x(), rect.y(), | 781 rect.x(), rect.y(), |
814 rect.width(), rect.height()); | 782 rect.width(), rect.height()); |
815 } | 783 } |
816 context_->flush(); | 784 context_->flush(); |
817 } | 785 } |
818 } | 786 } |
819 | 787 |
820 } // namespace content | 788 } // namespace content |
OLD | NEW |