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..4ddc549b0895c5c44fbf5109719b8094ba49410b 100644 |
--- a/content/common/gpu/client/gl_helper.cc |
+++ b/content/common/gpu/client/gl_helper.cc |
@@ -4,9 +4,10 @@ |
#include "content/common/gpu/client/gl_helper.h" |
-#include <queue> |
+#include <set> |
#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); |
@@ -239,10 +223,8 @@ namespace content { |
class 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 +235,6 @@ class GLHelper::CopyTextureToImpl { |
} |
~CopyTextureToImpl() { |
CancelRequests(); |
- DeleteContextForThread(); |
} |
void InitBuffer(); |
@@ -323,13 +304,8 @@ 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); |
+ GLuint buffer, GLuint query); |
void FinishRequest(scoped_refptr<Request> request); |
void CancelRequests(); |
@@ -345,7 +321,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 +341,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::set<scoped_refptr<Request> > request_set_; |
}; |
const WebKit::WGC3Dfloat GLHelper::CopyTextureToImpl::kVertexAttributes[] = { |
@@ -394,6 +369,20 @@ 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;" |
+ "const mediump mat4 swizzle = mat4( 0.0, 0.0, 1.0, 0.0, " |
+ " 0.0, 1.0, 0.0, 0.0, " |
+ " 1.0, 0.0, 0.0, 0.0, " |
+ " 0.0, 0.0, 0.0, 1.0 );" |
+ "void main() {" |
+ " 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.
|
+ "}"; |
+#else |
const WebKit::WGC3Dchar GLHelper::CopyTextureToImpl::kCopyFragmentShader[] = |
"precision mediump float;" |
"varying vec2 v_texcoord;" |
@@ -401,6 +390,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 +508,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 +515,54 @@ 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_queue_.push(request); |
+ request_set_.insert(request); |
- g_gl_helper_thread.Pointer()->message_loop_proxy()->PostTask(FROM_HERE, |
- base::Bind(&ReadBackFramebuffer, |
- request, |
- context_for_thread_, |
- base::MessageLoopProxy::current())); |
+ ScopedFlush flush(context_); |
+ ScopedFramebuffer dst_framebuffer(context_, context_->createFramebuffer()); |
+ gfx::Size size; |
+ base::AutoLock auto_lock(request->lock); |
+ 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); |
+ GLuint buffer = context_->createBuffer(); |
+ context_->bindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, |
+ buffer); |
+ context_->bufferData(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, |
+ 4 * size.GetArea(), |
+ NULL, |
+ GL_STREAM_READ); |
+ |
+ GLuint query = context_->createQueryEXT(); |
+ context_->beginQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM, query); |
+ context_->readPixels(0, 0, size.width(), size.height(), |
+ GL_RGBA, GL_UNSIGNED_BYTE, 0); |
+ 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.
|
+ 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
|
+ base::MessageLoopProxy::current()->PostDelayedTask( |
+ FROM_HERE, |
+ base::Bind(&ReadBackFramebufferComplete, request, buffer, query), |
+ base::TimeDelta::FromMilliseconds(2)); |
} |
void GLHelper::CopyTextureToImpl::ReadbackTextureSync(WebGLId texture, |
@@ -590,75 +598,60 @@ WebKit::WebGLId GLHelper::CopyTextureToImpl::CopyAndScaleTexture( |
vertically_flip_texture); |
} |
-void GLHelper::CopyTextureToImpl::ReadBackFramebuffer( |
+void GLHelper::CopyTextureToImpl::ReadBackFramebufferComplete( |
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)); |
- } |
+ GLuint buffer, GLuint query) { |
+ |
+ TRACE_EVENT0("mirror", |
+ "GLHelper::CopyTextureToImpl::ReadBackFramebufferComplete"); |
+ |
+ if (!request->copy_texture_impl) { |
+ request->callback.Run(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) |
+ |
+ WebKit::WebGraphicsContext3D* context = request->copy_texture_impl->context_; |
+ bool result = false; |
+ |
+ if (buffer != 0) { |
+ unsigned int done = 1; |
+ context->getQueryObjectuivEXT(query, GL_QUERY_RESULT_AVAILABLE_EXT, &done); |
+ if (!done) { |
+ TRACE_EVENT0("mirror", |
+ "GLHelper::CopyTextureToImpl::Reschedule"); |
+ base::MessageLoopProxy::current()->PostDelayedTask( |
+ FROM_HERE, |
+ base::Bind(&ReadBackFramebufferComplete, request, buffer, query), |
+ base::TimeDelta::FromMilliseconds(2)); |
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); |
} |
+ context->deleteQueryEXT(query); |
+ context->bindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, |
+ buffer); |
+ void* data = context->mapBufferCHROMIUM( |
+ GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY); |
+ |
+ if (data) { |
+ result = true; |
+ memcpy(request->pixels, data, request->size.GetArea() * 4); |
+ context->unmapBufferCHROMIUM(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM); |
+ } else { |
+ 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.
|
+ } |
+ 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
|
+ context->deleteBuffer(buffer); |
+ } else { |
+ 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.
|
} |
- 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::ReadBackFramebufferComplete( |
- scoped_refptr<Request> request, |
- bool result) { |
request->callback.Run(result); |
- if (request->copy_texture_impl) |
- request->copy_texture_impl->FinishRequest(request); |
+ request->copy_texture_impl->FinishRequest(request); |
} |
void GLHelper::CopyTextureToImpl::FinishRequest( |
scoped_refptr<Request> request) { |
- CHECK(request_queue_.front() == request); |
- request_queue_.pop(); |
+ CHECK(request_set_.find(request) != request_set_.end()); |
+ request_set_.erase(request); |
base::AutoLock auto_lock(request->lock); |
if (request->texture != 0) { |
context_->deleteTexture(request->texture); |
@@ -668,9 +661,9 @@ void GLHelper::CopyTextureToImpl::FinishRequest( |
} |
void GLHelper::CopyTextureToImpl::CancelRequests() { |
- while (!request_queue_.empty()) { |
- scoped_refptr<Request> request = request_queue_.front(); |
- request_queue_.pop(); |
+ while (!request_set_.empty()) { |
+ scoped_refptr<Request> request = *request_set_.begin(); |
+ request_set_.erase(request); |
request->copy_texture_impl = NULL; |
bool cancelled = false; |
{ |
@@ -689,34 +682,11 @@ void GLHelper::CopyTextureToImpl::CancelRequests() { |
} |
} |
-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 +756,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, |