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

Unified Diff: content/common/gpu/client/gl_helper.cc

Issue 12892005: Implement client side PBOs for glReadPixel (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: pbo unit test added Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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,

Powered by Google App Engine
This is Rietveld 408576698