Chromium Code Reviews| 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..e04b4cdc773fbb3b9c448058020b908140cb2583 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" |
|
apatrick_chromium
2013/03/20 18:39:09
I think some of these includes are not needed now,
hubbe
2013/03/20 22:03:48
Done
(Is there something like iwyu for chrome sour
|
| #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); |
| @@ -99,15 +83,6 @@ class ScopedFramebuffer : public ScopedWebGLId { |
| &WebGraphicsContext3D::deleteFramebuffer) {} |
| }; |
| -class ScopedRenderbuffer : public ScopedWebGLId { |
| - public: |
| - ScopedRenderbuffer(WebGraphicsContext3D* context, |
| - WebGLId id) |
| - : ScopedWebGLId(context, |
| - id, |
| - &WebGraphicsContext3D::deleteRenderbuffer) {} |
| -}; |
| - |
| class ScopedProgram : public ScopedWebGLId { |
| public: |
| ScopedProgram(WebGraphicsContext3D* context, |
| @@ -144,19 +119,16 @@ class ScopedBinder { |
| WebGLId id, |
| BindFunc bind_func) |
| : context_(context), |
| - id_(id), |
| bind_func_(bind_func) { |
| - (context_->*bind_func_)(target, id_); |
| + (context_->*bind_func_)(target, id); |
| } |
| virtual ~ScopedBinder() { |
| - if (id_ != 0) |
| - (context_->*bind_func_)(target, 0); |
| + (context_->*bind_func_)(target, 0); |
| } |
| private: |
| WebGraphicsContext3D* context_; |
| - WebGLId id_; |
| BindFunc bind_func_; |
| DISALLOW_COPY_AND_ASSIGN(ScopedBinder); |
| @@ -185,17 +157,6 @@ class ScopedFramebufferBinder : ScopedBinder<target> { |
| }; |
| template <WebKit::WGC3Denum target> |
| -class ScopedRenderbufferBinder : ScopedBinder<target> { |
| - public: |
| - ScopedRenderbufferBinder(WebGraphicsContext3D* context, |
| - WebGLId id) |
| - : ScopedBinder<target>( |
| - context, |
| - id, |
| - &WebGraphicsContext3D::bindRenderbuffer) {} |
| -}; |
| - |
| -template <WebKit::WGC3Denum target> |
| class ScopedTextureBinder : ScopedBinder<target> { |
| public: |
| ScopedTextureBinder(WebGraphicsContext3D* context, |
| @@ -236,13 +197,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 +213,6 @@ class GLHelper::CopyTextureToImpl { |
| } |
| ~CopyTextureToImpl() { |
| CancelRequests(); |
| - DeleteContextForThread(); |
| } |
| void InitBuffer(); |
| @@ -278,40 +237,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 +274,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 +291,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 +311,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 +339,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 +356,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( |
| @@ -451,11 +408,10 @@ WebGLId GLHelper::CopyTextureToImpl::ScaleTexture( |
| WebGLId dst_texture = context_->createTexture(); |
| { |
| ScopedFramebuffer dst_framebuffer(context_, context_->createFramebuffer()); |
| - ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder( |
| - context_, dst_framebuffer); |
| + ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(context_, |
| + dst_framebuffer); |
| { |
| - ScopedTextureBinder<GL_TEXTURE_2D> texture_binder( |
| - context_, dst_texture); |
| + ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_, dst_texture); |
| context_->texImage2D(GL_TEXTURE_2D, |
| 0, |
| GL_RGBA, |
| @@ -475,8 +431,8 @@ WebGLId GLHelper::CopyTextureToImpl::ScaleTexture( |
| ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_, src_texture); |
| WebKit::WebGLId vertex_attributes_buffer = vertically_flip_texture ? |
| flipped_vertex_attributes_buffer_ : vertex_attributes_buffer_; |
| - ScopedBufferBinder<GL_ARRAY_BUFFER> buffer_binder( |
| - context_, vertex_attributes_buffer); |
| + ScopedBufferBinder<GL_ARRAY_BUFFER> buffer_binder(context_, |
| + vertex_attributes_buffer); |
| context_->viewport(0, 0, dst_size.width(), dst_size.height()); |
| context_->useProgram(program_); |
| @@ -517,17 +473,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,34 +480,59 @@ 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, |
| const gfx::Rect& src_rect, |
| unsigned char* out) { |
| ScopedFramebuffer dst_framebuffer(context_, context_->createFramebuffer()); |
| - ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder( |
| - context_, dst_framebuffer); |
| + ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(context_, |
| + dst_framebuffer); |
| ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_, texture); |
| context_->framebufferTexture2D(GL_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |
| @@ -590,133 +560,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(); |
|
apatrick_chromium
2013/03/20 18:39:09
You could just flush once at the end of this funct
hubbe
2013/03/20 22:03:48
Done.
|
| + } |
| + 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 +704,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, |
| @@ -798,8 +714,8 @@ void GLHelper::CopySubBufferDamage(WebKit::WebGLId texture, |
| SkRegion region(old_damage); |
| if (region.op(new_damage, SkRegion::kDifference_Op)) { |
| ScopedFramebuffer dst_framebuffer(context_, context_->createFramebuffer()); |
| - ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder( |
| - context_, dst_framebuffer); |
| + ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(context_, |
| + dst_framebuffer); |
| ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_, texture); |
| context_->framebufferTexture2D(GL_FRAMEBUFFER, |
| GL_COLOR_ATTACHMENT0, |