| Index: content/common/gpu/client/gl_helper.cc
|
| diff --git a/content/common/gpu/client/gl_helper.cc b/content/common/gpu/client/gl_helper.cc
|
| index 0d295f03643b12961487d78454d2fbca199874fb..d39c8a1b64c4516d1e4eff797e99e63fbc84a7b7 100644
|
| --- a/content/common/gpu/client/gl_helper.cc
|
| +++ b/content/common/gpu/client/gl_helper.cc
|
| @@ -7,6 +7,7 @@
|
| #include <queue>
|
|
|
| #include "base/bind.h"
|
| +#include "base/debug/trace_event.h"
|
| #include "base/lazy_instance.h"
|
| #include "base/logging.h"
|
| #include "base/memory/ref_counted.h"
|
| @@ -15,6 +16,7 @@
|
| #include "base/synchronization/waitable_event.h"
|
| #include "base/threading/thread.h"
|
| #include "base/threading/thread_restrictions.h"
|
| +#include "base/time.h"
|
| #include "third_party/WebKit/Source/Platform/chromium/public/WebCString.h"
|
| #include "third_party/WebKit/Source/Platform/chromium/public/WebString.h"
|
| #include "third_party/skia/include/core/SkRegion.h"
|
| @@ -27,24 +29,6 @@ using WebKit::WebGraphicsContext3D;
|
|
|
| namespace {
|
|
|
| -const char kGLHelperThreadName[] = "GLHelperThread";
|
| -
|
| -class GLHelperThread : public base::Thread {
|
| - public:
|
| - GLHelperThread() : base::Thread(kGLHelperThreadName) {
|
| - Start();
|
| - }
|
| - virtual ~GLHelperThread() {
|
| - Stop();
|
| - }
|
| -
|
| - private:
|
| - DISALLOW_COPY_AND_ASSIGN(GLHelperThread);
|
| -};
|
| -
|
| -base::LazyInstance<GLHelperThread> g_gl_helper_thread =
|
| - LAZY_INSTANCE_INITIALIZER;
|
| -
|
| class ScopedWebGLId {
|
| public:
|
| typedef void (WebGraphicsContext3D::*DeleteFunc)(WebGLId);
|
| @@ -236,13 +220,12 @@ namespace content {
|
|
|
| // Implements GLHelper::CropScaleReadbackAndCleanTexture and encapsulates the
|
| // data needed for it.
|
| -class GLHelper::CopyTextureToImpl {
|
| +class GLHelper::CopyTextureToImpl :
|
| + public base::SupportsWeakPtr<GLHelper::CopyTextureToImpl> {
|
| public:
|
| CopyTextureToImpl(WebGraphicsContext3D* context,
|
| - WebGraphicsContext3D* context_for_thread,
|
| GLHelper* helper)
|
| : context_(context),
|
| - context_for_thread_(context_for_thread),
|
| helper_(helper),
|
| flush_(context),
|
| program_(context, context->createProgram()),
|
| @@ -253,7 +236,6 @@ class GLHelper::CopyTextureToImpl {
|
| }
|
| ~CopyTextureToImpl() {
|
| CancelRequests();
|
| - DeleteContextForThread();
|
| }
|
|
|
| void InitBuffer();
|
| @@ -278,40 +260,32 @@ class GLHelper::CopyTextureToImpl {
|
|
|
| private:
|
| // A single request to CropScaleReadbackAndCleanTexture.
|
| - // Thread-safety notes: the main thread creates instances of this class. The
|
| - // main thread can cancel the request, before it's handled by the helper
|
| + // The main thread can cancel the request, before it's handled by the helper
|
| // thread, by resetting the texture and pixels fields. Alternatively, the
|
| // thread marks that it handles the request by resetting the pixels field
|
| // (meaning it guarantees that the callback with be called).
|
| // In either case, the callback must be called exactly once, and the texture
|
| // must be deleted by the main thread context.
|
| - struct Request : public base::RefCountedThreadSafe<Request> {
|
| - Request(CopyTextureToImpl* impl,
|
| - WebGLId texture_,
|
| + struct Request {
|
| + Request(WebGLId texture_,
|
| const gfx::Size& size_,
|
| unsigned char* pixels_,
|
| const base::Callback<void(bool)>& callback_)
|
| - : copy_texture_impl(impl),
|
| - size(size_),
|
| - callback(callback_),
|
| - lock(),
|
| - texture(texture_),
|
| - pixels(pixels_) {
|
| + : size(size_),
|
| + callback(callback_),
|
| + texture(texture_),
|
| + pixels(pixels_),
|
| + buffer(0),
|
| + query(0) {
|
| }
|
|
|
| - // These members are only accessed on the main thread.
|
| - GLHelper::CopyTextureToImpl* copy_texture_impl;
|
| gfx::Size size;
|
| base::Callback<void(bool)> callback;
|
|
|
| - // Locks access to below members, which can be accessed on any thread.
|
| - base::Lock lock;
|
| WebGLId texture;
|
| unsigned char* pixels;
|
| -
|
| - private:
|
| - friend class base::RefCountedThreadSafe<Request>;
|
| - ~Request() {}
|
| + GLuint buffer;
|
| + GLuint query;
|
| };
|
|
|
| // Copies the block of pixels specified with |src_subrect| from |src_texture|,
|
| @@ -323,14 +297,9 @@ class GLHelper::CopyTextureToImpl {
|
| const gfx::Size& dst_size,
|
| bool vertically_flip_texture);
|
|
|
| - // Deletes the context for GLHelperThread.
|
| - void DeleteContextForThread();
|
| - static void ReadBackFramebuffer(scoped_refptr<Request> request,
|
| - WebGraphicsContext3D* context,
|
| - scoped_refptr<base::TaskRunner> reply_loop);
|
| - static void ReadBackFramebufferComplete(scoped_refptr<Request> request,
|
| - bool result);
|
| - void FinishRequest(scoped_refptr<Request> request);
|
| + void ScheduleCheckReadbackDone();
|
| + void CheckReadbackDone();
|
| + void FinishRequest(Request* request, bool result);
|
| void CancelRequests();
|
|
|
| // Interleaved array of 2-dimentional vertex positions (x, y) and
|
| @@ -345,7 +314,6 @@ class GLHelper::CopyTextureToImpl {
|
| static const WebKit::WGC3Dchar kCopyFragmentShader[];
|
|
|
| WebGraphicsContext3D* context_;
|
| - WebGraphicsContext3D* context_for_thread_;
|
| GLHelper* helper_;
|
|
|
| // A scoped flush that will ensure all resource deletions are flushed when
|
| @@ -366,7 +334,7 @@ class GLHelper::CopyTextureToImpl {
|
| WebKit::WGC3Dint texture_location_;
|
| // The location of the texture coordinate of the sub-rectangle in the program.
|
| WebKit::WGC3Dint src_subrect_location_;
|
| - std::queue<scoped_refptr<Request> > request_queue_;
|
| + std::queue<Request*> request_queue_;
|
| };
|
|
|
| const WebKit::WGC3Dfloat GLHelper::CopyTextureToImpl::kVertexAttributes[] = {
|
| @@ -394,6 +362,16 @@ const WebKit::WGC3Dchar GLHelper::CopyTextureToImpl::kCopyVertexShader[] =
|
| " v_texcoord = src_subrect.xy + a_texcoord * src_subrect.zw;"
|
| "}";
|
|
|
| +
|
| +#if (SK_R32_SHIFT == 16) && !SK_B32_SHIFT
|
| +const WebKit::WGC3Dchar GLHelper::CopyTextureToImpl::kCopyFragmentShader[] =
|
| + "precision mediump float;"
|
| + "varying vec2 v_texcoord;"
|
| + "uniform sampler2D s_texture;"
|
| + "void main() {"
|
| + " gl_FragColor = texture2D(s_texture, v_texcoord).bgra;"
|
| + "}";
|
| +#else
|
| const WebKit::WGC3Dchar GLHelper::CopyTextureToImpl::kCopyFragmentShader[] =
|
| "precision mediump float;"
|
| "varying vec2 v_texcoord;"
|
| @@ -401,6 +379,8 @@ const WebKit::WGC3Dchar GLHelper::CopyTextureToImpl::kCopyFragmentShader[] =
|
| "void main() {"
|
| " gl_FragColor = texture2D(s_texture, v_texcoord);"
|
| "}";
|
| +#endif
|
| +
|
|
|
| void GLHelper::CopyTextureToImpl::InitBuffer() {
|
| ScopedBufferBinder<GL_ARRAY_BUFFER> buffer_binder(
|
| @@ -517,17 +497,6 @@ WebGLId GLHelper::CopyTextureToImpl::ScaleTexture(
|
| return dst_texture;
|
| }
|
|
|
| -void GLHelper::CopyTextureToImpl::DeleteContextForThread() {
|
| - if (!context_for_thread_)
|
| - return;
|
| -
|
| - g_gl_helper_thread.Pointer()->message_loop_proxy()->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&DeleteContext,
|
| - context_for_thread_));
|
| - context_for_thread_ = NULL;
|
| -}
|
| -
|
| void GLHelper::CopyTextureToImpl::CropScaleReadbackAndCleanTexture(
|
| WebGLId src_texture,
|
| const gfx::Size& src_size,
|
| @@ -535,26 +504,52 @@ void GLHelper::CopyTextureToImpl::CropScaleReadbackAndCleanTexture(
|
| const gfx::Size& dst_size,
|
| unsigned char* out,
|
| const base::Callback<void(bool)>& callback) {
|
| - if (!context_for_thread_) {
|
| - callback.Run(false);
|
| - return;
|
| - }
|
| -
|
| WebGLId texture = ScaleTexture(src_texture,
|
| src_size,
|
| src_subrect,
|
| dst_size,
|
| - false);
|
| +#ifdef USE_SKIA
|
| + true
|
| +#else
|
| + false
|
| +#endif
|
| + );
|
| context_->flush();
|
| - scoped_refptr<Request> request =
|
| - new Request(this, texture, dst_size, out, callback);
|
| + Request *request = new Request(texture, dst_size, out, callback);
|
| request_queue_.push(request);
|
| + if (request_queue_.size() == 1) {
|
| + ScheduleCheckReadbackDone();
|
| + }
|
| +
|
| + ScopedFlush flush(context_);
|
| + ScopedFramebuffer dst_framebuffer(context_, context_->createFramebuffer());
|
| + gfx::Size size;
|
| + size = request->size;
|
| +
|
| + ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(
|
| + context_, dst_framebuffer);
|
| + ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(
|
| + context_, request->texture);
|
| + context_->framebufferTexture2D(GL_FRAMEBUFFER,
|
| + GL_COLOR_ATTACHMENT0,
|
| + GL_TEXTURE_2D,
|
| + request->texture,
|
| + 0);
|
| + request->buffer = context_->createBuffer();
|
| + context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
|
| + request->buffer);
|
| + context_->bufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
|
| + 4 * size.GetArea(),
|
| + NULL,
|
| + GL_STREAM_READ);
|
| +
|
| + request->query = context_->createQueryEXT();
|
| + context_->beginQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM, request->query);
|
| + context_->readPixels(0, 0, size.width(), size.height(),
|
| + GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
| + context_->endQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM);
|
| + context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
|
|
|
| - g_gl_helper_thread.Pointer()->message_loop_proxy()->PostTask(FROM_HERE,
|
| - base::Bind(&ReadBackFramebuffer,
|
| - request,
|
| - context_for_thread_,
|
| - base::MessageLoopProxy::current()));
|
| }
|
|
|
| void GLHelper::CopyTextureToImpl::ReadbackTextureSync(WebGLId texture,
|
| @@ -590,133 +585,81 @@ WebKit::WebGLId GLHelper::CopyTextureToImpl::CopyAndScaleTexture(
|
| vertically_flip_texture);
|
| }
|
|
|
| -void GLHelper::CopyTextureToImpl::ReadBackFramebuffer(
|
| - scoped_refptr<Request> request,
|
| - WebGraphicsContext3D* context,
|
| - scoped_refptr<base::TaskRunner> reply_loop) {
|
| - DCHECK(context);
|
| - if (!context->makeContextCurrent() || context->isContextLost()) {
|
| - base::AutoLock auto_lock(request->lock);
|
| - if (request->pixels) {
|
| - // Only report failure if the request wasn't canceled (otherwise the
|
| - // failure has already been reported).
|
| - request->pixels = NULL;
|
| - reply_loop->PostTask(
|
| - FROM_HERE, base::Bind(ReadBackFramebufferComplete, request, false));
|
| - }
|
| - return;
|
| - }
|
| - ScopedFlush flush(context);
|
| - ScopedFramebuffer dst_framebuffer(context, context->createFramebuffer());
|
| - unsigned char* pixels = NULL;
|
| - gfx::Size size;
|
| - {
|
| - // Note: We don't want to keep the lock while doing the readBack (since we
|
| - // don't want to block the UI thread). We rely on the fact that once the
|
| - // texture is bound to a FBO (that isn't current), deleting the texture is
|
| - // delayed until the FBO is deleted. We ensure ordering by flushing while
|
| - // the lock is held. Either the main thread cancelled before we get the
|
| - // lock, and we'll exit early, or we ensure that the texture is bound to the
|
| - // framebuffer before the main thread has a chance to delete it.
|
| - base::AutoLock auto_lock(request->lock);
|
| - if (!request->texture || !request->pixels)
|
| - return;
|
| - pixels = request->pixels;
|
| - request->pixels = NULL;
|
| - size = request->size;
|
| - {
|
| - ScopedFlush flush(context);
|
| - ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(
|
| - context, dst_framebuffer);
|
| - ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(
|
| - context, request->texture);
|
| - context->framebufferTexture2D(GL_FRAMEBUFFER,
|
| - GL_COLOR_ATTACHMENT0,
|
| - GL_TEXTURE_2D,
|
| - request->texture,
|
| - 0);
|
| - }
|
| - }
|
| - bool result = context->readBackFramebuffer(
|
| - pixels,
|
| - 4 * size.GetArea(),
|
| - dst_framebuffer.id(),
|
| - size.width(),
|
| - size.height());
|
| - reply_loop->PostTask(
|
| - FROM_HERE, base::Bind(ReadBackFramebufferComplete, request, result));
|
| +
|
| +void GLHelper::CopyTextureToImpl::ScheduleCheckReadbackDone() {
|
| + DCHECK(!request_queue_.empty());
|
| + base::MessageLoopProxy::current()->PostDelayedTask(
|
| + FROM_HERE,
|
| + base::Bind(&CopyTextureToImpl::CheckReadbackDone, AsWeakPtr()),
|
| + base::TimeDelta::FromMilliseconds(2));
|
| }
|
|
|
| -void GLHelper::CopyTextureToImpl::ReadBackFramebufferComplete(
|
| - scoped_refptr<Request> request,
|
| - bool result) {
|
| - request->callback.Run(result);
|
| - if (request->copy_texture_impl)
|
| - request->copy_texture_impl->FinishRequest(request);
|
| +void GLHelper::CopyTextureToImpl::CheckReadbackDone() {
|
| + TRACE_EVENT0("mirror",
|
| + "GLHelper::CopyTextureToImpl::CheckReadBackFramebufferComplete");
|
| + while (!request_queue_.empty()) {
|
| + Request* request = request_queue_.front();
|
| +
|
| + bool result = false;
|
| + if (request->buffer != 0) {
|
| + unsigned int done = 1;
|
| + context_->getQueryObjectuivEXT(request->query,
|
| + GL_QUERY_RESULT_AVAILABLE_EXT, &done);
|
| + if (!done) {
|
| + ScheduleCheckReadbackDone();
|
| + return;
|
| + }
|
| + context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
|
| + request->buffer);
|
| + void* data = context_->mapBufferCHROMIUM(
|
| + GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY);
|
| +
|
| + if (data) {
|
| + result = true;
|
| + memcpy(request->pixels, data, request->size.GetArea() * 4);
|
| + context_->unmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM);
|
| + }
|
| + context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
|
| + }
|
| +
|
| + FinishRequest(request, result);
|
| + }
|
| }
|
|
|
| -void GLHelper::CopyTextureToImpl::FinishRequest(
|
| - scoped_refptr<Request> request) {
|
| - CHECK(request_queue_.front() == request);
|
| +void GLHelper::CopyTextureToImpl::FinishRequest(Request* request, bool result) {
|
| + DCHECK(request_queue_.front() == request);
|
| request_queue_.pop();
|
| - base::AutoLock auto_lock(request->lock);
|
| + request->callback.Run(result);
|
| if (request->texture != 0) {
|
| context_->deleteTexture(request->texture);
|
| request->texture = 0;
|
| context_->flush();
|
| }
|
| + if (request->buffer != 0) {
|
| + context_->deleteBuffer(request->buffer);
|
| + request->buffer = 0;
|
| + context_->flush();
|
| + }
|
| + if (request->query != 0) {
|
| + context_->deleteQueryEXT(request->query);
|
| + request->query = 0;
|
| + context_->flush();
|
| + }
|
| + delete request;
|
| }
|
|
|
| void GLHelper::CopyTextureToImpl::CancelRequests() {
|
| while (!request_queue_.empty()) {
|
| - scoped_refptr<Request> request = request_queue_.front();
|
| - request_queue_.pop();
|
| - request->copy_texture_impl = NULL;
|
| - bool cancelled = false;
|
| - {
|
| - base::AutoLock auto_lock(request->lock);
|
| - if (request->texture != 0) {
|
| - context_->deleteTexture(request->texture);
|
| - request->texture = 0;
|
| - }
|
| - if (request->pixels != NULL) {
|
| - request->pixels = NULL;
|
| - cancelled = true;
|
| - }
|
| - }
|
| - if (cancelled)
|
| - request->callback.Run(false);
|
| + Request* request = request_queue_.front();
|
| + FinishRequest(request, false);
|
| }
|
| }
|
|
|
| -base::subtle::Atomic32 GLHelper::count_ = 0;
|
| -
|
| -GLHelper::GLHelper(WebGraphicsContext3D* context,
|
| - WebGraphicsContext3D* context_for_thread)
|
| - : context_(context),
|
| - context_for_thread_(context_for_thread) {
|
| - base::subtle::NoBarrier_AtomicIncrement(&count_, 1);
|
| +GLHelper::GLHelper(WebGraphicsContext3D* context)
|
| + : context_(context) {
|
| }
|
|
|
| GLHelper::~GLHelper() {
|
| - DCHECK_NE(MessageLoop::current(),
|
| - g_gl_helper_thread.Pointer()->message_loop());
|
| - base::subtle::Atomic32 decremented_count =
|
| - base::subtle::NoBarrier_AtomicIncrement(&count_, -1);
|
| - if (decremented_count == 0) {
|
| - // When this is the last instance, we synchronize with the pending
|
| - // operations on GLHelperThread. Otherwise on shutdown we may kill the GPU
|
| - // process infrastructure (BrowserGpuChannelHostFactory) before they have
|
| - // a chance to complete, likely leading to a crash.
|
| - base::WaitableEvent event(false, false);
|
| - g_gl_helper_thread.Pointer()->message_loop_proxy()->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&SignalWaitableEvent,
|
| - &event));
|
| - // http://crbug.com/125415
|
| - base::ThreadRestrictions::ScopedAllowWait allow_wait;
|
| - event.Wait();
|
| - }
|
| }
|
|
|
| WebGraphicsContext3D* GLHelper::context() const {
|
| @@ -786,9 +729,7 @@ WebGLId GLHelper::CompileShaderFromSource(
|
| void GLHelper::InitCopyTextToImpl() {
|
| // Lazily initialize |copy_texture_to_impl_|
|
| if (!copy_texture_to_impl_.get())
|
| - copy_texture_to_impl_.reset(new CopyTextureToImpl(context_,
|
| - context_for_thread_,
|
| - this));
|
| + copy_texture_to_impl_.reset(new CopyTextureToImpl(context_, this));
|
| }
|
|
|
| void GLHelper::CopySubBufferDamage(WebKit::WebGLId texture,
|
|
|