diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc index 1e758c35a0ddc..f3d7fdde1b3e1 100644 --- a/content/browser/renderer_host/compositor_impl_android.cc +++ b/content/browser/renderer_host/compositor_impl_android.cc @@ -27,11 +27,13 @@ #include "cc/trees/layer_tree_host.h" #include "content/browser/gpu/browser_gpu_channel_host_factory.h" #include "content/browser/gpu/gpu_surface_tracker.h" +#include "content/browser/renderer_host/image_transport_factory_android.h" #include "content/common/gpu/client/command_buffer_proxy_impl.h" #include "content/common/gpu/client/context_provider_command_buffer.h" #include "content/common/gpu/client/gl_helper.h" +#include "content/common/gpu/client/gl_helper_browser.h" #include "content/common/gpu/client/gpu_channel_host.h" -#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h" +#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_browser_impl.h" #include "content/common/gpu/gpu_process_launch_causes.h" #include "content/public/browser/android/compositor_client.h" #include "content/public/common/content_switches.h" @@ -380,7 +382,8 @@ bool CompositorImpl::CopyTextureToBitmap(WebKit::WebGLId texture_id, DCHECK(bitmap.size() == sub_rect.size()); if (bitmap.size() != sub_rect.size() || texture_id == 0) return false; - GLHelper* helper = ImageTransportFactoryAndroid::GetInstance()->GetGLHelper(); + GLHelperBrowser* helper = + ImageTransportFactoryAndroid::GetInstance()->GetGLHelperBrowser(); helper->ReadbackTextureSync(texture_id, sub_rect, static_cast (bitmap.pixels())); @@ -454,6 +457,38 @@ scoped_ptr CompositorImpl::CreateOutputSurface( if (!context_provider.get()) { LOG(ERROR) << "Failed to create 3D context for compositor."; return scoped_ptr(); + } else { + DCHECK(window_ && surface_id_); + GpuChannelHostFactory* factory = BrowserGpuChannelHostFactory::instance(); + GURL url("chrome://gpu/Compositor::createContext3D"); + scoped_ptr context( + new WebGraphicsContext3DCommandBufferBrowserImpl( + surface_id_, + url, + factory, + weak_factory_.GetWeakPtr())); + static const size_t kBytesPerPixel = 4; + gfx::DeviceDisplayInfo display_info; + size_t full_screen_texture_size_in_bytes = + display_info.GetDisplayHeight() * + display_info.GetDisplayWidth() * + kBytesPerPixel; + if (!context->Initialize( + attrs, + false, + CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE, + 64 * 1024, // command buffer size + std::min(full_screen_texture_size_in_bytes, + kDefaultStartTransferBufferSize), + kDefaultMinTransferBufferSize, + std::min(3 * full_screen_texture_size_in_bytes, + kDefaultMaxTransferBufferSize))) { + LOG(ERROR) << "Failed to create 3D context for compositor."; + return scoped_ptr(); + } + return scoped_ptr( + new OutputSurfaceWithoutParent( + context.PassAs())); } return scoped_ptr( diff --git a/content/browser/renderer_host/image_transport_factory_android.cc b/content/browser/renderer_host/image_transport_factory_android.cc index bc0d365d2491a..b5bb4107b6862 100644 --- a/content/browser/renderer_host/image_transport_factory_android.cc +++ b/content/browser/renderer_host/image_transport_factory_android.cc @@ -9,8 +9,8 @@ #include "base/strings/stringprintf.h" #include "content/browser/gpu/browser_gpu_channel_host_factory.h" #include "content/browser/renderer_host/compositor_impl_android.h" -#include "content/common/gpu/client/gl_helper.h" -#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h" +#include "content/common/gpu/client/gl_helper_browser.h" +#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_browser_impl.h" #include "content/common/gpu/gpu_process_launch_causes.h" #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" #include "third_party/khronos/GLES2/gl2.h" @@ -55,7 +55,7 @@ class DirectGLImageTransportFactory : public ImageTransportFactoryAndroid { virtual WebKit::WebGraphicsContext3D* GetContext3D() OVERRIDE { return context_.get(); } - virtual GLHelper* GetGLHelper() OVERRIDE { return NULL; } + virtual GLHelperBrowser* GetGLHelperBrowser() OVERRIDE { return NULL; } private: scoped_ptr context_; @@ -94,11 +94,11 @@ class CmdBufferImageTransportFactory : public ImageTransportFactoryAndroid { virtual WebKit::WebGraphicsContext3D* GetContext3D() OVERRIDE { return context_.get(); } - virtual GLHelper* GetGLHelper() OVERRIDE; + virtual GLHelperBrowser* GetGLHelperBrowser() OVERRIDE; private: - scoped_ptr context_; - scoped_ptr gl_helper_; + scoped_ptr context_; + scoped_ptr gl_helper_; DISALLOW_COPY_AND_ASSIGN(CmdBufferImageTransportFactory); }; @@ -109,10 +109,11 @@ CmdBufferImageTransportFactory::CmdBufferImageTransportFactory() { GpuChannelHostFactory* factory = BrowserGpuChannelHostFactory::instance(); GURL url("chrome://gpu/ImageTransportFactoryAndroid"); base::WeakPtr swap_client; - context_.reset(new WebGraphicsContext3DCommandBufferImpl(0, // offscreen - url, - factory, - swap_client)); + context_.reset( + new WebGraphicsContext3DCommandBufferBrowserImpl(0, // offscreen + url, + factory, + swap_client)); static const size_t kBytesPerPixel = 4; gfx::DeviceDisplayInfo display_info; size_t full_screen_texture_size_in_bytes = @@ -185,9 +186,9 @@ void CmdBufferImageTransportFactory::AcquireTexture( context_->flush(); } -GLHelper* CmdBufferImageTransportFactory::GetGLHelper() { +GLHelperBrowser* CmdBufferImageTransportFactory::GetGLHelperBrowser() { if (!gl_helper_) - gl_helper_.reset(new GLHelper(context_.get())); + gl_helper_.reset(new GLHelperBrowser(context_.get())); return gl_helper_.get(); } diff --git a/content/browser/renderer_host/image_transport_factory_android.h b/content/browser/renderer_host/image_transport_factory_android.h index 22dc09ef4359b..336df13f6fea2 100644 --- a/content/browser/renderer_host/image_transport_factory_android.h +++ b/content/browser/renderer_host/image_transport_factory_android.h @@ -18,6 +18,7 @@ class WebGraphicsContext3D; namespace content { class GLHelper; +class GLHelperBrowser; class GLContextLostListener; class ImageTransportFactoryAndroidObserver { @@ -40,7 +41,7 @@ class ImageTransportFactoryAndroid { uint32 texture_id, const signed char* mailbox_name) = 0; virtual WebKit::WebGraphicsContext3D* GetContext3D() = 0; - virtual GLHelper* GetGLHelper() = 0; + virtual GLHelperBrowser* GetGLHelperBrowser() = 0; static void AddObserver(ImageTransportFactoryAndroidObserver* observer); static void RemoveObserver(ImageTransportFactoryAndroidObserver* observer); diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc index 3b94566748f4d..cd61e3cf84b3d 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.cc +++ b/content/browser/renderer_host/render_widget_host_view_android.cc @@ -34,7 +34,9 @@ #include "content/browser/renderer_host/image_transport_factory_android.h" #include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/browser/renderer_host/surface_texture_transport_client_android.h" +#include "content/browser/renderer_host/touch_smooth_scroll_gesture_android.h" #include "content/common/gpu/client/gl_helper.h" +#include "content/common/gpu/client/gl_helper_browser.h" #include "content/common/gpu/gpu_messages.h" #include "content/common/input_messages.h" #include "content/common/view_messages.h" @@ -253,12 +255,13 @@ WebKit::WebGLId RenderWidgetHostViewAndroid::GetScaledContentTexture( if (out_size) *out_size = size; - GLHelper* helper = ImageTransportFactoryAndroid::GetInstance()->GetGLHelper(); + GLHelperBrowser* helper = + ImageTransportFactoryAndroid::GetInstance()->GetGLHelperBrowser(); return helper->CopyAndScaleTexture(texture_id_in_layer_, texture_size_in_layer_, size, true, - GLHelper::SCALER_QUALITY_FAST); + GLHelperBrowser::SCALER_QUALITY_FAST); } bool RenderWidgetHostViewAndroid::PopulateBitmapWithContents(jobject jbitmap) { @@ -272,14 +275,15 @@ bool RenderWidgetHostViewAndroid::PopulateBitmapWithContents(jobject jbitmap) { // TODO(dtrainor): Eventually add support for multiple formats here. DCHECK(bitmap.format() == ANDROID_BITMAP_FORMAT_RGBA_8888); - GLHelper* helper = ImageTransportFactoryAndroid::GetInstance()->GetGLHelper(); + GLHelperBrowser* helper = + ImageTransportFactoryAndroid::GetInstance()->GetGLHelperBrowser(); WebKit::WebGLId texture = helper->CopyAndScaleTexture( texture_id_in_layer_, texture_size_in_layer_, bitmap.size(), true, - GLHelper::SCALER_QUALITY_FAST); + GLHelperBrowser::SCALER_QUALITY_FAST); if (texture == 0) return false; diff --git a/content/common/gpu/client/gl_helper_browser.cc b/content/common/gpu/client/gl_helper_browser.cc new file mode 100644 index 0000000000000..9959988ce8d99 --- /dev/null +++ b/content/common/gpu/client/gl_helper_browser.cc @@ -0,0 +1,971 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/common/gpu/client/gl_helper_browser.h" + +#include +#include + +#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" +#include "base/message_loop/message_loop.h" +#include "base/time/time.h" +#include "cc/resources/sync_point_helper.h" +#include "content/common/gpu/client/gl_helper.h" +#include "content/common/gpu/client/gl_helper_scaling_browser.h" +#include "media/base/video_frame.h" +#include "media/base/video_util.h" +#include "third_party/WebKit/public/platform/WebCString.h" +#include "third_party/skia/include/core/SkRegion.h" +#include "ui/gfx/rect.h" +#include "ui/gfx/size.h" +#include "ui/gl/gl_bindings.h" + +using WebKit::WebGLId; +using WebKit::WebGraphicsContext3D; + +namespace { + +// Helper class for allocating and holding an RGBA texture of a given +// size and an associated framebuffer. +class TextureFrameBufferPair { + public: + TextureFrameBufferPair(WebGraphicsContext3D* context, + gfx::Size size) + : texture_(context, context->createTexture()), + framebuffer_(context, context->createFramebuffer()), + size_(size) { + content::ScopedTextureBinder texture_binder(context, + texture_); + context->texImage2D(GL_TEXTURE_2D, + 0, + GL_RGBA, + size.width(), + size.height(), + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + NULL); + content::ScopedFramebufferBinder framebuffer_binder( + context, + framebuffer_); + context->framebufferTexture2D(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + texture_, + 0); + } + + WebGLId texture() const { return texture_.id(); } + WebGLId framebuffer() const { return framebuffer_.id(); } + gfx::Size size() const { return size_; } + + private: + content::ScopedTexture texture_; + content::ScopedFramebuffer framebuffer_; + gfx::Size size_; + + DISALLOW_COPY_AND_ASSIGN(TextureFrameBufferPair); +}; + +// Helper class for holding a scaler, a texture for the output of that +// scaler and an associated frame buffer. This is inteded to be used +// when the output of a scaler is to be sent to a readback. +class ScalerHolder { + public: + ScalerHolder(WebGraphicsContext3D* context, + content::GLHelperBrowser::ScalerInterface *scaler) + : texture_and_framebuffer_(context, scaler->DstSize()), + scaler_(scaler) { + } + + void Scale(WebKit::WebGLId src_texture) { + scaler_->Scale(src_texture, texture_and_framebuffer_.texture()); + } + + content::GLHelperBrowser::ScalerInterface* scaler() const { return scaler_.get(); } + TextureFrameBufferPair *texture_and_framebuffer() { + return &texture_and_framebuffer_; + } + WebGLId texture() const { return texture_and_framebuffer_.texture(); } + + private: + TextureFrameBufferPair texture_and_framebuffer_; + scoped_ptr scaler_; + + DISALLOW_COPY_AND_ASSIGN(ScalerHolder); +}; + +} // namespace + +namespace content { + +// Implements GLHelperBrowser::CropScaleReadbackAndCleanTexture and encapsulates +// the data needed for it. +class GLHelperBrowser::CopyTextureToImpl : + public base::SupportsWeakPtr { + public: + CopyTextureToImpl(WebGraphicsContext3D* context, + GLHelperBrowser* helper) + : context_(context), + helper_(helper), + flush_(context), + max_draw_buffers_(0) { + std::string extensions_string = " " + + UTF16ToASCII(context_->getString(GL_EXTENSIONS)) + " "; + if (extensions_string.find(" GL_EXT_draw_buffers ") != std::string::npos) { + context_->getIntegerv(GL_MAX_DRAW_BUFFERS, &max_draw_buffers_); + } + } + ~CopyTextureToImpl() { + CancelRequests(); + } + + void CropScaleReadbackAndCleanTexture( + WebGLId src_texture, + const gfx::Size& src_size, + const gfx::Rect& src_subrect, + const gfx::Size& dst_size, + unsigned char* out, + const base::Callback& callback, + GLHelperBrowser::ScalerQuality quality); + + void ReadbackTextureSync(WebGLId texture, + const gfx::Rect& src_rect, + unsigned char* out); + + // Reads back bytes from the currently bound frame buffer. + // Note that dst_size is specified in bytes, not pixels. + void ReadbackAsync( + const gfx::Size& dst_size, + int32 bytes_per_row, // generally dst_size.width() * 4 + int32 row_stride_bytes, // generally dst_size.width() * 4 + unsigned char* out, + const base::Callback& callback); + + void ReadbackPlane(TextureFrameBufferPair* source, + media::VideoFrame* target, + int plane, + int size_shift, + const gfx::Rect& dst_subrect, + const base::Callback& callback); + + WebKit::WebGLId CopyAndScaleTexture(WebGLId texture, + const gfx::Size& src_size, + const gfx::Size& dst_size, + bool vertically_flip_texture, + GLHelperBrowser::ScalerQuality quality); + + ReadbackYUVInterfaceBrowser* CreateReadbackPipelineYUV( + GLHelperBrowser::ScalerQuality quality, + const gfx::Size& src_size, + const gfx::Rect& src_subrect, + const gfx::Size& dst_size, + const gfx::Rect& dst_subrect, + bool flip_vertically, + bool use_mrt); + + // Returns the maximum number of draw buffers available, + // 0 if GL_EXT_draw_buffers is not available. + WebKit::WGC3Dint MaxDrawBuffers() const { + return max_draw_buffers_; + } + + private: + // A single request to CropScaleReadbackAndCleanTexture. + // 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 { + Request(const gfx::Size& size_, + int32 bytes_per_row_, + int32 row_stride_bytes_, + unsigned char* pixels_, + const base::Callback& callback_) + : size(size_), + bytes_per_row(bytes_per_row_), + row_stride_bytes(row_stride_bytes_), + pixels(pixels_), + callback(callback_), + buffer(0) { + } + + gfx::Size size; + int bytes_per_row; + int row_stride_bytes; + unsigned char* pixels; + base::Callback callback; + GLuint buffer; + }; + + // A readback pipeline that also converts the data to YUV before + // reading it back. + class ReadbackYUVImpl : public ReadbackYUVInterfaceBrowser { + public: + ReadbackYUVImpl(WebGraphicsContext3D* context, + CopyTextureToImpl* copy_impl, + GLHelperScalingBrowser* scaler_impl, + GLHelperBrowser::ScalerQuality quality, + const gfx::Size& src_size, + const gfx::Rect& src_subrect, + const gfx::Size& dst_size, + const gfx::Rect& dst_subrect, + bool flip_vertically); + + virtual void ReadbackYUV( + WebKit::WebGLId src_texture, + media::VideoFrame* target, + const base::Callback& callback) OVERRIDE; + + virtual ScalerInterface* scaler() OVERRIDE { + return scaler_.scaler(); + } + + private: + WebGraphicsContext3D* context_; + CopyTextureToImpl* copy_impl_; + gfx::Size dst_size_; + gfx::Rect dst_subrect_; + ScalerHolder scaler_; + ScalerHolder y_; + ScalerHolder u_; + ScalerHolder v_; + + DISALLOW_COPY_AND_ASSIGN(ReadbackYUVImpl); + }; + + // A readback pipeline that also converts the data to YUV before + // reading it back. This one uses Multiple Render Targets, which + // may not be supported on all platforms. + class ReadbackYUV_MRT : public ReadbackYUVInterfaceBrowser { + public: + ReadbackYUV_MRT(WebGraphicsContext3D* context, + CopyTextureToImpl* copy_impl, + GLHelperScalingBrowser* scaler_impl, + GLHelperBrowser::ScalerQuality quality, + const gfx::Size& src_size, + const gfx::Rect& src_subrect, + const gfx::Size& dst_size, + const gfx::Rect& dst_subrect, + bool flip_vertically); + + virtual void ReadbackYUV( + WebKit::WebGLId src_texture, + media::VideoFrame* target, + const base::Callback& callback) OVERRIDE; + + virtual ScalerInterface* scaler() OVERRIDE { + return scaler_.scaler(); + } + + private: + WebGraphicsContext3D* context_; + CopyTextureToImpl* copy_impl_; + gfx::Size dst_size_; + gfx::Rect dst_subrect_; + ScalerHolder scaler_; + scoped_ptr pass1_shader_; + scoped_ptr pass2_shader_; + TextureFrameBufferPair y_; + ScopedTexture uv_; + TextureFrameBufferPair u_; + TextureFrameBufferPair v_; + + DISALLOW_COPY_AND_ASSIGN(ReadbackYUV_MRT); + }; + + // Copies the block of pixels specified with |src_subrect| from |src_texture|, + // scales it to |dst_size|, writes it into a texture, and returns its ID. + // |src_size| is the size of |src_texture|. + WebGLId ScaleTexture(WebGLId src_texture, + const gfx::Size& src_size, + const gfx::Rect& src_subrect, + const gfx::Size& dst_size, + bool vertically_flip_texture, + bool swizzle, + GLHelperBrowser::ScalerQuality quality); + + static void nullcallback(bool success) {} + void ReadbackDone(Request* request); + void FinishRequest(Request* request, bool result); + void CancelRequests(); + + static const float kRGBtoYColorWeights[]; + static const float kRGBtoUColorWeights[]; + static const float kRGBtoVColorWeights[]; + + WebGraphicsContext3D* context_; + GLHelperBrowser* helper_; + + // A scoped flush that will ensure all resource deletions are flushed when + // this object is destroyed. Must be declared before other Scoped* fields. + ScopedFlush flush_; + + std::queue request_queue_; + WebKit::WGC3Dint max_draw_buffers_; +}; + +GLHelperBrowser::ScalerInterface* GLHelperBrowser::CreateScaler( + ScalerQuality quality, + const gfx::Size& src_size, + const gfx::Rect& src_subrect, + const gfx::Size& dst_size, + bool vertically_flip_texture, + bool swizzle) { + InitScalerImpl(); + return scaler_impl_->CreateScaler(quality, + src_size, + src_subrect, + dst_size, + vertically_flip_texture, + swizzle); +} + +WebGLId GLHelperBrowser::CopyTextureToImpl::ScaleTexture( + WebGLId src_texture, + const gfx::Size& src_size, + const gfx::Rect& src_subrect, + const gfx::Size& dst_size, + bool vertically_flip_texture, + bool swizzle, + GLHelperBrowser::ScalerQuality quality) { + scoped_ptr scaler( + helper_->CreateScaler(quality, + src_size, + src_subrect, + dst_size, + vertically_flip_texture, + swizzle)); + + WebGLId dst_texture = context_->createTexture(); + { + ScopedTextureBinder texture_binder(context_, dst_texture); + context_->texImage2D(GL_TEXTURE_2D, + 0, + GL_RGBA, + dst_size.width(), + dst_size.height(), + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + NULL); + } + scaler->Scale(src_texture, dst_texture); + return dst_texture; +} + +void GLHelperBrowser::CopyTextureToImpl::ReadbackAsync( + const gfx::Size& dst_size, + int32 bytes_per_row, + int32 row_stride_bytes, + unsigned char* out, + const base::Callback& callback) { + Request* request = new Request(dst_size, + bytes_per_row, + row_stride_bytes, + out, + callback); + request_queue_.push(request); + request->buffer = context_->createBuffer(); + context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, + request->buffer); + context_->bufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, + 4 * dst_size.GetArea(), + NULL, + GL_STREAM_READ); + + context_->readPixels(0, 0, dst_size.width(), dst_size.height(), + GL_RGBA, GL_UNSIGNED_BYTE, NULL); + context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0); + cc::SyncPointHelper::SignalSyncPoint( + context_, + context_->insertSyncPoint(), + base::Bind(&CopyTextureToImpl::ReadbackDone, AsWeakPtr(), request)); +} + + +void GLHelperBrowser::CopyTextureToImpl::CropScaleReadbackAndCleanTexture( + WebGLId src_texture, + const gfx::Size& src_size, + const gfx::Rect& src_subrect, + const gfx::Size& dst_size, + unsigned char* out, + const base::Callback& callback, + GLHelperBrowser::ScalerQuality quality) { + WebGLId texture = ScaleTexture(src_texture, + src_size, + src_subrect, + dst_size, + true, +#if (SK_R32_SHIFT == 16) && !SK_B32_SHIFT + true, +#else + false, +#endif + quality); + ScopedFramebuffer dst_framebuffer(context_, context_->createFramebuffer()); + ScopedFramebufferBinder framebuffer_binder(context_, + dst_framebuffer); + ScopedTextureBinder texture_binder(context_, texture); + context_->framebufferTexture2D(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + texture, + 0); + ReadbackAsync(dst_size, + dst_size.width() * 4, + dst_size.width() * 4, + out, + callback); + context_->deleteTexture(texture); +} + +void GLHelperBrowser::CopyTextureToImpl::ReadbackTextureSync( + WebGLId texture, + const gfx::Rect& src_rect, + unsigned char* out) { + ScopedFramebuffer dst_framebuffer(context_, context_->createFramebuffer()); + ScopedFramebufferBinder framebuffer_binder(context_, + dst_framebuffer); + ScopedTextureBinder texture_binder(context_, texture); + context_->framebufferTexture2D(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + texture, + 0); + context_->readPixels(src_rect.x(), + src_rect.y(), + src_rect.width(), + src_rect.height(), + GL_RGBA, + GL_UNSIGNED_BYTE, + out); +} + +WebKit::WebGLId GLHelperBrowser::CopyTextureToImpl::CopyAndScaleTexture( + WebGLId src_texture, + const gfx::Size& src_size, + const gfx::Size& dst_size, + bool vertically_flip_texture, + GLHelperBrowser::ScalerQuality quality) { + return ScaleTexture(src_texture, + src_size, + gfx::Rect(src_size), + dst_size, + vertically_flip_texture, + false, + quality); +} + +void GLHelperBrowser::CopyTextureToImpl::ReadbackDone(Request* request) { + TRACE_EVENT0("mirror", + "GLHelperBrowser::CopyTextureToImpl::CheckReadbackFramebufferComplete"); + DCHECK(request == request_queue_.front()); + + bool result = false; + if (request->buffer != 0) { + context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, + request->buffer); + unsigned char* data = static_cast( + context_->mapBufferCHROMIUM( + GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY)); + if (data) { + result = true; + if (request->bytes_per_row == request->size.width() * 4 && + request->bytes_per_row == request->row_stride_bytes) { + memcpy(request->pixels, data, request->size.GetArea() * 4); + } else { + unsigned char* out = request->pixels; + for (int y = 0; y < request->size.height(); y++) { + memcpy(out, data, request->bytes_per_row); + out += request->row_stride_bytes; + data += request->size.width() * 4; + } + } + context_->unmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM); + } + context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0); + } + + FinishRequest(request, result); +} + +void GLHelperBrowser::CopyTextureToImpl::FinishRequest(Request* request, + bool result) { + DCHECK(request_queue_.front() == request); + request_queue_.pop(); + request->callback.Run(result); + ScopedFlush flush(context_); + if (request->buffer != 0) { + context_->deleteBuffer(request->buffer); + request->buffer = 0; + } + delete request; +} + +void GLHelperBrowser::CopyTextureToImpl::CancelRequests() { + while (!request_queue_.empty()) { + Request* request = request_queue_.front(); + FinishRequest(request, false); + } +} + +GLHelperBrowser::GLHelperBrowser(WebKit::WebGraphicsContext3D* context) + : context_(context) { +} + +GLHelperBrowser::~GLHelperBrowser() { +} + +void GLHelperBrowser::CropScaleReadbackAndCleanTexture( + WebGLId src_texture, + const gfx::Size& src_size, + const gfx::Rect& src_subrect, + const gfx::Size& dst_size, + unsigned char* out, + const base::Callback& callback) { + InitCopyTextToImpl(); + copy_texture_to_impl_->CropScaleReadbackAndCleanTexture( + src_texture, + src_size, + src_subrect, + dst_size, + out, + callback, + GLHelperBrowser::SCALER_QUALITY_FAST); +} + +void GLHelperBrowser::ReadbackTextureSync(WebKit::WebGLId texture, + const gfx::Rect& src_rect, + unsigned char* out) { + InitCopyTextToImpl(); + copy_texture_to_impl_->ReadbackTextureSync(texture, + src_rect, + out); +} + +WebKit::WebGLId GLHelperBrowser::CopyTexture(WebKit::WebGLId texture, + const gfx::Size& size) { + InitCopyTextToImpl(); + return copy_texture_to_impl_->CopyAndScaleTexture( + texture, + size, + size, + false, + GLHelperBrowser::SCALER_QUALITY_FAST); +} + +WebKit::WebGLId GLHelperBrowser::CopyAndScaleTexture( + WebKit::WebGLId texture, + const gfx::Size& src_size, + const gfx::Size& dst_size, + bool vertically_flip_texture, + ScalerQuality quality) { + InitCopyTextToImpl(); + return copy_texture_to_impl_->CopyAndScaleTexture(texture, + src_size, + dst_size, + vertically_flip_texture, + quality); +} + +WebGLId GLHelperBrowser::CompileShaderFromSource( + const WebKit::WGC3Dchar* source, + WebKit::WGC3Denum type) { + ScopedShader shader(context_, context_->createShader(type)); + context_->shaderSource(shader, source); + context_->compileShader(shader); + WebKit::WGC3Dint compile_status = 0; + context_->getShaderiv(shader, GL_COMPILE_STATUS, &compile_status); + if (!compile_status) { + LOG(ERROR) << std::string(context_->getShaderInfoLog(shader).utf8()); + return 0; + } + return shader.Detach(); +} + +void GLHelperBrowser::InitCopyTextToImpl() { + // Lazily initialize |copy_texture_to_impl_| + if (!copy_texture_to_impl_) + copy_texture_to_impl_.reset(new CopyTextureToImpl(context_, this)); +} + +void GLHelperBrowser::InitScalerImpl() { + // Lazily initialize |scaler_impl_| + if (!scaler_impl_) + scaler_impl_.reset(new GLHelperScalingBrowser(context_, this)); +} + +WebKit::WGC3Dint GLHelperBrowser::MaxDrawBuffers() { + InitCopyTextToImpl(); + return copy_texture_to_impl_->MaxDrawBuffers(); +} + +void GLHelperBrowser::CopySubBufferDamage(WebKit::WebGLId texture, + WebKit::WebGLId previous_texture, + const SkRegion& new_damage, + const SkRegion& old_damage) { + SkRegion region(old_damage); + if (region.op(new_damage, SkRegion::kDifference_Op)) { + ScopedFramebuffer dst_framebuffer(context_, + context_->createFramebuffer()); + ScopedFramebufferBinder framebuffer_binder(context_, + dst_framebuffer); + ScopedTextureBinder texture_binder(context_, texture); + context_->framebufferTexture2D(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + previous_texture, + 0); + for (SkRegion::Iterator it(region); !it.done(); it.next()) { + const SkIRect& rect = it.rect(); + context_->copyTexSubImage2D(GL_TEXTURE_2D, 0, + rect.x(), rect.y(), + rect.x(), rect.y(), + rect.width(), rect.height()); + } + context_->flush(); + } +} + +WebKit::WebGLId GLHelperBrowser::CreateTexture() { + WebKit::WebGLId texture = context_->createTexture(); + content::ScopedTextureBinder texture_binder(context_, + texture); + context_->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + context_->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + context_->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + context_->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + return texture; +} + +void GLHelperBrowser::ResizeTexture( + WebKit::WebGLId texture, const gfx::Size& size) { + content::ScopedTextureBinder texture_binder(context_, texture); + context_->texImage2D(GL_TEXTURE_2D, 0, GL_RGB, + size.width(), size.height(), 0, + GL_RGB, GL_UNSIGNED_BYTE, NULL); +} + +void GLHelperBrowser::CopyTextureSubImage(WebKit::WebGLId texture, + const gfx::Rect& rect) { + content::ScopedTextureBinder texture_binder(context_, texture); + context_->copyTexSubImage2D(GL_TEXTURE_2D, 0, + rect.x(), rect.y(), + rect.x(), rect.y(), rect.width(), rect.height()); +} + +void GLHelperBrowser::CopyTextureFullImage(WebKit::WebGLId texture, + const gfx::Size& size) { + content::ScopedTextureBinder texture_binder(context_, texture); + context_->copyTexImage2D(GL_TEXTURE_2D, 0, + GL_RGB, + 0, 0, + size.width(), size.height(), 0); +} + +void GLHelperBrowser::CopyTextureToImpl::ReadbackPlane( + TextureFrameBufferPair* source, + media::VideoFrame* target, + int plane, + int size_shift, + const gfx::Rect& dst_subrect, + const base::Callback& callback) { + context_->bindFramebuffer(GL_FRAMEBUFFER, source->framebuffer()); + size_t offset = target->stride(plane) * (dst_subrect.y() >> size_shift) + + (dst_subrect.x() >> size_shift); + ReadbackAsync( + source->size(), + dst_subrect.width() >> size_shift, + target->stride(plane), + target->data(plane) + offset, + callback); +} + +const float GLHelperBrowser::CopyTextureToImpl::kRGBtoYColorWeights[] = { + 0.257f, 0.504f, 0.098f, 0.0625f +}; +const float GLHelperBrowser::CopyTextureToImpl::kRGBtoUColorWeights[] = { + -0.148f, -0.291f, 0.439f, 0.5f +}; +const float GLHelperBrowser::CopyTextureToImpl::kRGBtoVColorWeights[] = { + 0.439f, -0.368f, -0.071f, 0.5f +}; + +// YUV readback constructors. Initiates the main scaler pipeline and +// one planar scaler for each of the Y, U and V planes. +GLHelperBrowser::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUVImpl( + WebGraphicsContext3D* context, + CopyTextureToImpl* copy_impl, + GLHelperScalingBrowser* scaler_impl, + GLHelperBrowser::ScalerQuality quality, + const gfx::Size& src_size, + const gfx::Rect& src_subrect, + const gfx::Size& dst_size, + const gfx::Rect& dst_subrect, + bool flip_vertically) + : context_(context), + copy_impl_(copy_impl), + dst_size_(dst_size), + dst_subrect_(dst_subrect), + scaler_(context, scaler_impl->CreateScaler( + quality, + src_size, + src_subrect, + dst_subrect.size(), + flip_vertically, + false)), + y_(context, scaler_impl->CreatePlanarScaler( + dst_subrect.size(), + gfx::Rect(0, 0, + (dst_subrect.width() + 3) & ~3, + dst_subrect.height()), + gfx::Size((dst_subrect.width() + 3) / 4, + dst_subrect.height()), + false, + kRGBtoYColorWeights)), + u_(context, scaler_impl->CreatePlanarScaler( + dst_subrect.size(), + gfx::Rect(0, 0, + (dst_subrect.width() + 7) & ~7, + (dst_subrect.height() + 1) & ~1), + gfx::Size((dst_subrect.width() + 7) / 8, + (dst_subrect.height() + 1) / 2), + false, + kRGBtoUColorWeights)), + v_(context, scaler_impl->CreatePlanarScaler( + dst_subrect.size(), + gfx::Rect(0, 0, + (dst_subrect.width() + 7) & ~7, + (dst_subrect.height() + 1) & ~1), + gfx::Size((dst_subrect.width() + 7) / 8, + (dst_subrect.height() + 1) / 2), + false, + kRGBtoVColorWeights)) { + DCHECK(!(dst_size.width() & 1)); + DCHECK(!(dst_size.height() & 1)); + DCHECK(!(dst_subrect.width() & 1)); + DCHECK(!(dst_subrect.height() & 1)); + DCHECK(!(dst_subrect.x() & 1)); + DCHECK(!(dst_subrect.y() & 1)); +} + + +void GLHelperBrowser::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUV( + WebKit::WebGLId src_texture, + media::VideoFrame *target, + const base::Callback& callback) { + // Scale texture to right size. + scaler_.Scale(src_texture); + + // Convert the scaled texture in to Y, U and V planes. + y_.Scale(scaler_.texture()); + u_.Scale(scaler_.texture()); + v_.Scale(scaler_.texture()); + + if (target->coded_size() != dst_size_) { + DCHECK(target->coded_size() == dst_size_); + LOG(ERROR) << "ReadbackYUV size error!"; + callback.Run(false); + return; + } + + // Read back planes, one at a time. + copy_impl_->ReadbackPlane(y_.texture_and_framebuffer(), + target, + media::VideoFrame::kYPlane, + 0, + dst_subrect_, + base::Bind(&nullcallback)); + copy_impl_->ReadbackPlane(u_.texture_and_framebuffer(), + target, + media::VideoFrame::kUPlane, + 1, + dst_subrect_, + base::Bind(&nullcallback)); + copy_impl_->ReadbackPlane(v_.texture_and_framebuffer(), + target, + media::VideoFrame::kVPlane, + 1, + dst_subrect_, + callback); + context_->bindFramebuffer(GL_FRAMEBUFFER, 0); + media::LetterboxYUV(target, dst_subrect_); +} + +// YUV readback constructors. Initiates the main scaler pipeline and +// one planar scaler for each of the Y, U and V planes. +GLHelperBrowser::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV_MRT( + WebGraphicsContext3D* context, + CopyTextureToImpl* copy_impl, + GLHelperScalingBrowser* scaler_impl, + GLHelperBrowser::ScalerQuality quality, + const gfx::Size& src_size, + const gfx::Rect& src_subrect, + const gfx::Size& dst_size, + const gfx::Rect& dst_subrect, + bool flip_vertically) + : context_(context), + copy_impl_(copy_impl), + dst_size_(dst_size), + dst_subrect_(dst_subrect), + scaler_(context, scaler_impl->CreateScaler( + quality, + src_size, + src_subrect, + dst_subrect.size(), + flip_vertically, + false)), + pass1_shader_(scaler_impl->CreateYuvMrtShader( + dst_subrect.size(), + gfx::Rect(0, 0, + (dst_subrect.width() + 3) & ~3, + dst_subrect.height()), + gfx::Size((dst_subrect.width() + 3) / 4, + dst_subrect.height()), + false, + GLHelperScalingBrowser::SHADER_YUV_MRT_PASS1)), + pass2_shader_(scaler_impl->CreateYuvMrtShader( + gfx::Size((dst_subrect.width() + 3) / 4, + dst_subrect.height()), + gfx::Rect(0, 0, + (dst_subrect.width() + 7) / 8 * 2, + dst_subrect.height()), + gfx::Size((dst_subrect.width() + 7) / 8, + (dst_subrect.height() + 1) / 2), + false, + GLHelperScalingBrowser::SHADER_YUV_MRT_PASS2)), + y_(context, gfx::Size((dst_subrect.width() + 3) / 4, + dst_subrect.height())), + uv_(context, context->createTexture()), + u_(context, gfx::Size((dst_subrect.width() + 7) / 8, + (dst_subrect.height() + 1) / 2)), + v_(context, gfx::Size((dst_subrect.width() + 7) / 8, + (dst_subrect.height() + 1) / 2)) { + + content::ScopedTextureBinder texture_binder(context, uv_); + context->texImage2D(GL_TEXTURE_2D, + 0, + GL_RGBA, + (dst_subrect.width() + 3) / 4, + dst_subrect.height(), + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + NULL); + + DCHECK(!(dst_size.width() & 1)); + DCHECK(!(dst_size.height() & 1)); + DCHECK(!(dst_subrect.width() & 1)); + DCHECK(!(dst_subrect.height() & 1)); + DCHECK(!(dst_subrect.x() & 1)); + DCHECK(!(dst_subrect.y() & 1)); +} + +void GLHelperBrowser::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV( + WebKit::WebGLId src_texture, + media::VideoFrame *target, + const base::Callback& callback) { + // Scale texture to right size. + scaler_.Scale(src_texture); + std::vector outputs(2); + // Convert the scaled texture in to Y, U and V planes. + outputs[0] = y_.texture(); + outputs[1] = uv_; + pass1_shader_->Execute(scaler_.texture(), outputs); + outputs[0] = u_.texture(); + outputs[1] = v_.texture(); + pass2_shader_->Execute(uv_, outputs); + + if (target->coded_size() != dst_size_) { + DCHECK(target->coded_size() == dst_size_); + LOG(ERROR) << "ReadbackYUV size error!"; + callback.Run(false); + return; + } + + // Read back planes, one at a time. + copy_impl_->ReadbackPlane(&y_, + target, + media::VideoFrame::kYPlane, + 0, + dst_subrect_, + base::Bind(&nullcallback)); + copy_impl_->ReadbackPlane(&u_, + target, + media::VideoFrame::kUPlane, + 1, + dst_subrect_, + base::Bind(&nullcallback)); + copy_impl_->ReadbackPlane(&v_, + target, + media::VideoFrame::kVPlane, + 1, + dst_subrect_, + callback); + context_->bindFramebuffer(GL_FRAMEBUFFER, 0); + media::LetterboxYUV(target, dst_subrect_); +} + +ReadbackYUVInterfaceBrowser* +GLHelperBrowser::CopyTextureToImpl::CreateReadbackPipelineYUV( + GLHelperBrowser::ScalerQuality quality, + const gfx::Size& src_size, + const gfx::Rect& src_subrect, + const gfx::Size& dst_size, + const gfx::Rect& dst_subrect, + bool flip_vertically, + bool use_mrt) { + helper_->InitScalerImpl(); + if (max_draw_buffers_ >= 2 && use_mrt) { + return new ReadbackYUV_MRT( + context_, + this, + helper_->scaler_impl_.get(), + quality, + src_size, + src_subrect, + dst_size, + dst_subrect, + flip_vertically); + } + return new ReadbackYUVImpl( + context_, + this, + helper_->scaler_impl_.get(), + quality, + src_size, + src_subrect, + dst_size, + dst_subrect, + flip_vertically); +} + +ReadbackYUVInterfaceBrowser* +GLHelperBrowser::CreateReadbackPipelineYUV( + ScalerQuality quality, + const gfx::Size& src_size, + const gfx::Rect& src_subrect, + const gfx::Size& dst_size, + const gfx::Rect& dst_subrect, + bool flip_vertically, + bool use_mrt) { + InitCopyTextToImpl(); + return copy_texture_to_impl_->CreateReadbackPipelineYUV( + quality, + src_size, + src_subrect, + dst_size, + dst_subrect, + flip_vertically, + use_mrt); +} + +} // namespace content diff --git a/content/common/gpu/client/gl_helper_browser.h b/content/common/gpu/client/gl_helper_browser.h new file mode 100644 index 0000000000000..b417d821f473d --- /dev/null +++ b/content/common/gpu/client/gl_helper_browser.h @@ -0,0 +1,208 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_COMMON_GPU_CLIENT_GL_HELPER_BROWSER_H_ +#define CONTENT_COMMON_GPU_CLIENT_GL_HELPER_BROWSER_H_ + +#include "base/atomicops.h" +#include "base/basictypes.h" +#include "base/callback.h" +#include "base/memory/scoped_ptr.h" +#include "content/common/content_export.h" +#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_browser_impl.h" + +namespace gfx { +class Rect; +class Size; +} + +namespace media { +class VideoFrame; +}; + +class SkRegion; + +namespace content { + +class GLHelperScalingBrowser; +class ReadbackYUVInterfaceBrowser; + +// Provides higher level operations on top of the WebKit::WebGraphicsContext3D +// interfaces. +class CONTENT_EXPORT GLHelperBrowser { + public: + explicit GLHelperBrowser(WebKit::WebGraphicsContext3D* context); + ~GLHelperBrowser(); + + enum ScalerQuality { + // Bilinear single pass, fastest possible. + SCALER_QUALITY_FAST = 1, + + // Bilinear upscale + N * 50% bilinear downscales. + // This is still fast enough for most purposes and + // Image quality is nearly as good as the BEST option. + SCALER_QUALITY_GOOD = 2, + + // Bicubic upscale + N * 50% bicubic downscales. + // Produces very good quality scaled images, but it's + // 2-8x slower than the "GOOD" quality, so it's not always + // worth it. + SCALER_QUALITY_BEST = 3, + }; + + + // Copies the block of pixels specified with |src_subrect| from |src_texture|, + // scales it to |dst_size|, and writes it into |out|. + // |src_size| is the size of |src_texture|. The result is of format GL_BGRA + // and is potentially flipped vertically to make it a correct image + // representation. |callback| is invoked with the copy result when the copy + // operation has completed. + // Note that the src_texture will have the min/mag filter set to GL_LINEAR + // and wrap_s/t set to CLAMP_TO_EDGE in this call. + void CropScaleReadbackAndCleanTexture( + WebKit::WebGLId src_texture, + const gfx::Size& src_size, + const gfx::Rect& src_subrect, + const gfx::Size& dst_size, + unsigned char* out, + const base::Callback& callback); + + // Copies the texture data out of |texture| into |out|. |size| is the + // size of the texture. No post processing is applied to the pixels. The + // texture is assumed to have a format of GL_RGBA with a pixel type of + // GL_UNSIGNED_BYTE. This is a blocking call that calls glReadPixels on this + // current context. + void ReadbackTextureSync(WebKit::WebGLId texture, + const gfx::Rect& src_rect, + unsigned char* out); + + // Creates a copy of the specified texture. |size| is the size of the texture. + // Note that the src_texture will have the min/mag filter set to GL_LINEAR + // and wrap_s/t set to CLAMP_TO_EDGE in this call. + WebKit::WebGLId CopyTexture(WebKit::WebGLId texture, + const gfx::Size& size); + + // Creates a scaled copy of the specified texture. |src_size| is the size of + // the texture and |dst_size| is the size of the resulting copy. + // Note that the src_texture will have the min/mag filter set to GL_LINEAR + // and wrap_s/t set to CLAMP_TO_EDGE in this call. + WebKit::WebGLId CopyAndScaleTexture( + WebKit::WebGLId texture, + const gfx::Size& src_size, + const gfx::Size& dst_size, + bool vertically_flip_texture, + ScalerQuality quality); + + // Returns the shader compiled from the source. + WebKit::WebGLId CompileShaderFromSource(const WebKit::WGC3Dchar* source, + WebKit::WGC3Denum type); + + // Copies all pixels from |previous_texture| into |texture| that are + // inside the region covered by |old_damage| but not part of |new_damage|. + void CopySubBufferDamage(WebKit::WebGLId texture, + WebKit::WebGLId previous_texture, + const SkRegion& new_damage, + const SkRegion& old_damage); + + // Simply creates a texture. + WebKit::WebGLId CreateTexture(); + + // Resizes the texture's size to |size|. + void ResizeTexture(WebKit::WebGLId texture, const gfx::Size& size); + + // Copies the framebuffer data given in |rect| to |texture|. + void CopyTextureSubImage(WebKit::WebGLId texture, const gfx::Rect& rect); + + // Copies the all framebuffer data to |texture|. |size| specifies the + // size of the framebuffer. + void CopyTextureFullImage(WebKit::WebGLId texture, const gfx::Size& size); + + // A scaler will cache all intermediate textures and programs + // needed to scale from a specified size to a destination size. + // If the source or destination sizes changes, you must create + // a new scaler. + class CONTENT_EXPORT ScalerInterface { + public: + ScalerInterface() {} + virtual ~ScalerInterface() {} + + // Note that the src_texture will have the min/mag filter set to GL_LINEAR + // and wrap_s/t set to CLAMP_TO_EDGE in this call. + virtual void Scale(WebKit::WebGLId source_texture, + WebKit::WebGLId dest_texture) = 0; + virtual const gfx::Size& SrcSize() = 0; + virtual const gfx::Rect& SrcSubrect() = 0; + virtual const gfx::Size& DstSize() = 0; + }; + + // Note that the quality may be adjusted down if texture + // allocations fail or hardware doesn't support the requtested + // quality. Note that ScalerQuality enum is arranged in + // numerical order for simplicity. + ScalerInterface* CreateScaler(ScalerQuality quality, + const gfx::Size& src_size, + const gfx::Rect& src_subrect, + const gfx::Size& dst_size, + bool vertically_flip_texture, + bool swizzle); + + // Create a readback pipeline that will scale a subsection of the source + // texture, then convert it to YUV422 planar form and then read back that. + // This reduces the amount of memory read from GPU to CPU memory by a factor + // 2.6, which can be quite handy since readbacks have very limited speed + // on some platforms. All values in |dst_size| and |dst_subrect| must be + // a multiple of two. If |use_mrt| is true, the pipeline will try to optimize + // the YUV conversion using the multi-render-target extension. |use_mrt| + // should only be set to false for testing. + ReadbackYUVInterfaceBrowser* CreateReadbackPipelineYUV( + ScalerQuality quality, + const gfx::Size& src_size, + const gfx::Rect& src_subrect, + const gfx::Size& dst_size, + const gfx::Rect& dst_subrect, + bool flip_vertically, + bool use_mrt); + + // Returns the maximum number of draw buffers available, + // 0 if GL_EXT_draw_buffers is not available. + WebKit::WGC3Dint MaxDrawBuffers(); + + protected: + class CopyTextureToImpl; + + // Creates |copy_texture_to_impl_| if NULL. + void InitCopyTextToImpl(); + // Creates |scaler_impl_| if NULL. + void InitScalerImpl(); + + WebKit::WebGraphicsContext3D* context_; + scoped_ptr copy_texture_to_impl_; + scoped_ptr scaler_impl_; + + DISALLOW_COPY_AND_ASSIGN(GLHelperBrowser); +}; + +// Similar to a ScalerInterface, a yuv readback pipeline will +// cache a scaler and all intermediate textures and frame buffers +// needed to scale, crop, letterbox and read back a texture from +// the GPU into CPU-accessible RAM. A single readback pipeline +// can handle multiple outstanding readbacks at the same time, but +// if the source or destination sizes change, you'll need to create +// a new readback pipeline. +class CONTENT_EXPORT ReadbackYUVInterfaceBrowser { +public: + ReadbackYUVInterfaceBrowser() {} + virtual ~ReadbackYUVInterfaceBrowser() {} + + // Note that |target| must use YV12 format. + virtual void ReadbackYUV( + WebKit::WebGLId texture, + media::VideoFrame* target, + const base::Callback& callback) = 0; + virtual GLHelperBrowser::ScalerInterface* scaler() = 0; +}; + +} // namespace content + +#endif // CONTENT_COMMON_GPU_CLIENT_GL_HELPER_BROWSER_H_ diff --git a/content/common/gpu/client/gl_helper_scaling.h b/content/common/gpu/client/gl_helper_scaling.h index eba283cabeab7..d5164c445d616 100644 --- a/content/common/gpu/client/gl_helper_scaling.h +++ b/content/common/gpu/client/gl_helper_scaling.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_COMMON_GPU_CLIENT_GL_HELPER_SCALING_H_ -#define CONTENT_COMMON_GPU_CLIENT_GL_HELPER_SCALING_H_ +#ifndef CONTENT_COMMON_GPU_CLIENT_GL_HELPER_SCALING_BROWSER_H_ +#define CONTENT_COMMON_GPU_CLIENT_GL_HELPER_SCALING_BROWSER_H_ #include @@ -203,4 +203,4 @@ class CONTENT_EXPORT GLHelperScaling { } // namespace content -#endif // CONTENT_COMMON_GPU_CLIENT_GL_HELPER_SCALING_H_ +#endif // CONTENT_COMMON_GPU_CLIENT_GL_HELPER_SCALING_BROWSER_H_ diff --git a/content/common/gpu/client/gl_helper_scaling_browser.cc b/content/common/gpu/client/gl_helper_scaling_browser.cc new file mode 100644 index 0000000000000..222fa2154a7aa --- /dev/null +++ b/content/common/gpu/client/gl_helper_scaling_browser.cc @@ -0,0 +1,950 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/common/gpu/client/gl_helper_scaling_browser.h" + +#include +#include +#include + +#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" +#include "base/message_loop/message_loop.h" +#include "base/time/time.h" +#include "third_party/WebKit/public/platform/WebCString.h" +#include "third_party/skia/include/core/SkRegion.h" +#include "ui/gfx/rect.h" +#include "ui/gfx/size.h" +#include "ui/gl/gl_bindings.h" + +using WebKit::WebGLId; +using WebKit::WebGraphicsContext3D; + +namespace content { + +GLHelperScalingBrowser::GLHelperScalingBrowser( + WebKit::WebGraphicsContext3D* context, + GLHelperBrowser* helper) + : context_(context), + helper_(helper), + vertex_attributes_buffer_(context_, context_->createBuffer()) { + InitBuffer(); +} + +GLHelperScalingBrowser::~GLHelperScalingBrowser() { +} + +// Used to keep track of a generated shader program. The program +// is passed in as text through Setup and is used by calling +// UseProgram() with the right parameters. Note that |context_| +// and |helper_| are assumed to live longer than this program. +class ShaderProgramBrowser : public base::RefCounted { + public: + ShaderProgramBrowser(WebGraphicsContext3D* context, + GLHelperBrowser* helper) + : context_(context), + helper_(helper), + program_(context, context->createProgram()) { + } + + // Compile shader program, return true if successful. + bool Setup(const WebKit::WGC3Dchar* vertex_shader_text, + const WebKit::WGC3Dchar* fragment_shader_text); + + // UseProgram must be called with GL_TEXTURE_2D bound to the + // source texture and GL_ARRAY_BUFFER bound to a vertex + // attribute buffer. + void UseProgram(const gfx::Size& src_size, + const gfx::Rect& src_subrect, + const gfx::Size& dst_size, + bool scale_x, + bool flip_y, + GLfloat color_weights[4]); + + private: + friend class base::RefCounted; + ~ShaderProgramBrowser() {} + + WebGraphicsContext3D* context_; + GLHelperBrowser* helper_; + + // A program for copying a source texture into a destination texture. + ScopedProgram program_; + + // The location of the position in the program. + WebKit::WGC3Dint position_location_; + // The location of the texture coordinate in the program. + WebKit::WGC3Dint texcoord_location_; + // The location of the source texture in the program. + WebKit::WGC3Dint texture_location_; + // The location of the texture coordinate of + // the sub-rectangle in the program. + WebKit::WGC3Dint src_subrect_location_; + // Location of size of source image in pixels. + WebKit::WGC3Dint src_pixelsize_location_; + // Location of size of destination image in pixels. + WebKit::WGC3Dint dst_pixelsize_location_; + // Location of vector for scaling direction. + WebKit::WGC3Dint scaling_vector_location_; + // Location of color weights. + WebKit::WGC3Dint color_weights_location_; + + DISALLOW_COPY_AND_ASSIGN(ShaderProgramBrowser); +}; + + +// Implementation of a single stage in a scaler pipeline. If the pipeline has +// multiple stages, it calls Scale() on the subscaler, then further scales the +// output. Caches textures and framebuffers to avoid allocating/deleting +// them once per frame, which can be expensive on some drivers. +class ScalerImpl : + public GLHelperBrowser::ScalerInterface, + public GLHelperScalingBrowser::ShaderInterface { + public: + // |context| and |copy_impl| are expected to live longer than this object. + // |src_size| is the size of the input texture in pixels. + // |dst_size| is the size of the output texutre in pixels. + // |src_subrect| is the portion of the src to copy to the output texture. + // If |scale_x| is true, we are scaling along the X axis, otherwise Y. + // If we are scaling in both X and Y, |scale_x| is ignored. + // If |vertically_flip_texture| is true, output will be upside-down. + // If |swizzle| is true, RGBA will be transformed into BGRA. + // |color_weights| are only used together with SHADER_PLANAR to specify + // how to convert RGB colors into a single value. + ScalerImpl(WebGraphicsContext3D* context, + GLHelperScalingBrowser* scaler_helper, + const GLHelperScalingBrowser::ScalerStage &scaler_stage, + ScalerImpl* subscaler, + const float* color_weights) : + context_(context), + scaler_helper_(scaler_helper), + spec_(scaler_stage), + intermediate_texture_(0), + dst_framebuffer_(context, context_->createFramebuffer()), + subscaler_(subscaler) { + if (color_weights) { + color_weights_[0] = color_weights[0]; + color_weights_[1] = color_weights[1]; + color_weights_[2] = color_weights[2]; + color_weights_[3] = color_weights[3]; + } else { + color_weights_[0] = 0.0; + color_weights_[1] = 0.0; + color_weights_[2] = 0.0; + color_weights_[3] = 0.0; + } + shader_program_ = scaler_helper_->GetShaderProgramBrowser( + spec_.shader, spec_.swizzle); + + if (subscaler_) { + intermediate_texture_ = context_->createTexture(); + ScopedTextureBinder texture_binder( + context_, + intermediate_texture_); + context_->texImage2D(GL_TEXTURE_2D, + 0, + GL_RGBA, + spec_.src_size.width(), + spec_.src_size.height(), + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + NULL); + } + } + + virtual ~ScalerImpl() { + if (intermediate_texture_) { + context_->deleteTexture(intermediate_texture_); + } + } + + // GLHelperBrowserShader::ShaderInterface implementation. + virtual void Execute( + WebKit::WebGLId source_texture, + const std::vector& dest_textures) OVERRIDE { + if (subscaler_) { + subscaler_->Scale(source_texture, intermediate_texture_); + source_texture = intermediate_texture_; + } + + ScopedFramebufferBinder framebuffer_binder( + context_, + dst_framebuffer_); + DCHECK_GT(dest_textures.size(), 0U); + scoped_ptr buffers( + new WebKit::WGC3Denum[dest_textures.size()]); + for (size_t t = 0; t < dest_textures.size(); t++) { + ScopedTextureBinder texture_binder(context_, + dest_textures[t]); + context_->framebufferTexture2D(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0 + t, + GL_TEXTURE_2D, + dest_textures[t], + 0); + buffers[t] = GL_COLOR_ATTACHMENT0 + t; + } + ScopedTextureBinder texture_binder(context_, + source_texture); + + context_->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, + GL_LINEAR); + context_->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + GL_LINEAR); + context_->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_EDGE); + context_->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_EDGE); + + ScopedBufferBinder buffer_binder( + context_, + scaler_helper_->vertex_attributes_buffer_); + shader_program_->UseProgram(spec_.src_size, + spec_.src_subrect, + spec_.dst_size, + spec_.scale_x, + spec_.vertically_flip_texture, + color_weights_); + context_->viewport(0, 0, spec_.dst_size.width(), spec_.dst_size.height()); + + if (dest_textures.size() > 1) { + DCHECK_LE(static_cast(dest_textures.size()), + scaler_helper_->helper_->MaxDrawBuffers()); + context_->drawBuffersEXT(dest_textures.size(), buffers.get()); + } + // Conduct texture mapping by drawing a quad composed of two triangles. + context_->drawArrays(GL_TRIANGLE_STRIP, 0, 4); + if (dest_textures.size() > 1) { + // Set the draw buffers back to not confuse others. + context_->drawBuffersEXT(1, &buffers[0]); + } + } + + // GLHelperBrowser::ScalerInterface implementation. + virtual void Scale(WebKit::WebGLId source_texture, + WebKit::WebGLId dest_texture) OVERRIDE { + std::vector tmp(1); + tmp[0] = dest_texture; + Execute(source_texture, tmp); + } + + virtual const gfx::Size& SrcSize() OVERRIDE { + if (subscaler_) { + return subscaler_->SrcSize(); + } + return spec_.src_size; + } + virtual const gfx::Rect& SrcSubrect() OVERRIDE { + if (subscaler_) { + return subscaler_->SrcSubrect(); + } + return spec_.src_subrect; + } + virtual const gfx::Size& DstSize() OVERRIDE { + return spec_.dst_size; + } + + private: + WebGraphicsContext3D* context_; + GLHelperScalingBrowser* scaler_helper_; + GLHelperScalingBrowser::ScalerStage spec_; + GLfloat color_weights_[4]; + WebKit::WebGLId intermediate_texture_; + scoped_refptr shader_program_; + ScopedFramebuffer dst_framebuffer_; + scoped_ptr subscaler_; +}; + +GLHelperScalingBrowser::ScalerStage::ScalerStage( + ShaderType shader_, + gfx::Size src_size_, + gfx::Rect src_subrect_, + gfx::Size dst_size_, + bool scale_x_, + bool vertically_flip_texture_, + bool swizzle_) + : shader(shader_), + src_size(src_size_), + src_subrect(src_subrect_), + dst_size(dst_size_), + scale_x(scale_x_), + vertically_flip_texture(vertically_flip_texture_), + swizzle(swizzle_) { +} + +// The important inputs for this function is |x_ops| and +// |y_ops|. They represent scaling operations to be done +// on an imag of size |src_size|. If |quality| is SCALER_QUALITY_BEST, +// then we will interpret these scale operations literally and we'll +// create one scaler stage for each ScaleOp. However, if |quality| +// is SCALER_QUALITY_GOOD, then we can do a whole bunch of optimizations +// by combining two or more ScaleOps in to a single scaler stage. +// Normally we process ScaleOps from |y_ops| first and |x_ops| after +// all |y_ops| are processed, but sometimes we can combine one or more +// operation from both queues essentially for free. This is the reason +// why |x_ops| and |y_ops| aren't just one single queue. +void GLHelperScalingBrowser::ConvertScalerOpsToScalerStages( + GLHelperBrowser::ScalerQuality quality, + gfx::Size src_size, + gfx::Rect src_subrect, + const gfx::Size& dst_size, + bool vertically_flip_texture, + bool swizzle, + std::deque* x_ops, + std::deque* y_ops, + std::vector *scaler_stages) { + while (!x_ops->empty() || !y_ops->empty()) { + gfx::Size intermediate_size = src_subrect.size(); + std::deque* current_queue = NULL; + + if (!y_ops->empty()) { + current_queue = y_ops; + } else { + current_queue = x_ops; + } + + ShaderType current_shader = SHADER_BILINEAR; + switch (current_queue->front().scale_factor) { + case 0: + if (quality == GLHelperBrowser::SCALER_QUALITY_BEST) { + current_shader = SHADER_BICUBIC_UPSCALE; + } + break; + case 2: + if (quality == GLHelperBrowser::SCALER_QUALITY_BEST) { + current_shader = SHADER_BICUBIC_HALF_1D; + } + break; + case 3: + DCHECK(quality != GLHelperBrowser::SCALER_QUALITY_BEST); + current_shader = SHADER_BILINEAR3; + break; + default: + NOTREACHED(); + } + bool scale_x = current_queue->front().scale_x; + current_queue->front().UpdateSize(&intermediate_size); + current_queue->pop_front(); + + // Optimization: Sometimes we can combine 2-4 scaling operations into + // one operation. + if (quality == GLHelperBrowser::SCALER_QUALITY_GOOD) { + if (!current_queue->empty() && current_shader == SHADER_BILINEAR) { + // Combine two steps in the same dimension. + current_queue->front().UpdateSize(&intermediate_size); + current_queue->pop_front(); + current_shader = SHADER_BILINEAR2; + if (!current_queue->empty()) { + // Combine three steps in the same dimension. + current_queue->front().UpdateSize(&intermediate_size); + current_queue->pop_front(); + current_shader = SHADER_BILINEAR4; + } + } + // Check if we can combine some steps in the other dimension as well. + // Since all shaders currently use GL_LINEAR, we can easily scale up + // or scale down by exactly 2x at the same time as we do another + // operation. Currently, the following mergers are supported: + // * 1 bilinear Y-pass with 1 bilinear X-pass (up or down) + // * 2 bilinear Y-passes with 2 bilinear X-passes + // * 1 bilinear Y-pass with N bilinear X-pass + // * N bilinear Y-passes with 1 bilinear X-pass (down only) + // Measurements indicate that generalizing this for 3x3 and 4x4 + // makes it slower on some platforms, such as the Pixel. + if (!scale_x && x_ops->size() > 0 && + x_ops->front().scale_factor <= 2) { + int x_passes = 0; + if (current_shader == SHADER_BILINEAR2 && x_ops->size() >= 2) { + // 2y + 2x passes + x_passes = 2; + current_shader = SHADER_BILINEAR2X2; + } else if (current_shader == SHADER_BILINEAR) { + // 1y + Nx passes + scale_x = true; + switch (x_ops->size()) { + case 0: + NOTREACHED(); + case 1: + if (x_ops->front().scale_factor == 3) { + current_shader = SHADER_BILINEAR3; + } + x_passes = 1; + break; + case 2: + x_passes = 2; + current_shader = SHADER_BILINEAR2; + break; + default: + x_passes = 3; + current_shader = SHADER_BILINEAR4; + break; + } + } else if (x_ops->front().scale_factor == 2) { + // Ny + 1x-downscale + x_passes = 1; + } + + for (int i = 0; i < x_passes; i++) { + x_ops->front().UpdateSize(&intermediate_size); + x_ops->pop_front(); + } + } + } + + scaler_stages->push_back(ScalerStage(current_shader, + src_size, + src_subrect, + intermediate_size, + scale_x, + vertically_flip_texture, + swizzle)); + src_size = intermediate_size; + src_subrect = gfx::Rect(intermediate_size); + vertically_flip_texture = false; + swizzle = false; + } +} + +void GLHelperScalingBrowser::ComputeScalerStages( + GLHelperBrowser::ScalerQuality quality, + const gfx::Size& src_size, + const gfx::Rect& src_subrect, + const gfx::Size& dst_size, + bool vertically_flip_texture, + bool swizzle, + std::vector *scaler_stages) { + if (quality == GLHelperBrowser::SCALER_QUALITY_FAST || + src_subrect.size() == dst_size) { + scaler_stages->push_back(ScalerStage(SHADER_BILINEAR, + src_size, + src_subrect, + dst_size, + false, + vertically_flip_texture, + swizzle)); + return; + } + + std::deque x_ops, y_ops; + GLHelperScalingBrowser::ScaleOp::AddOps( + src_subrect.width(), + dst_size.width(), + true, + quality == GLHelperBrowser::SCALER_QUALITY_GOOD, + &x_ops); + GLHelperScalingBrowser::ScaleOp::AddOps( + src_subrect.height(), + dst_size.height(), + false, + quality == GLHelperBrowser::SCALER_QUALITY_GOOD, + &y_ops); + + ConvertScalerOpsToScalerStages( + quality, + src_size, + src_subrect, + dst_size, + vertically_flip_texture, + swizzle, + &x_ops, + &y_ops, + scaler_stages); +} + +GLHelperBrowser::ScalerInterface* +GLHelperScalingBrowser::CreateScaler(GLHelperBrowser::ScalerQuality quality, + gfx::Size src_size, + gfx::Rect src_subrect, + const gfx::Size& dst_size, + bool vertically_flip_texture, + bool swizzle) { + std::vector scaler_stages; + ComputeScalerStages(quality, + src_size, + src_subrect, + dst_size, + vertically_flip_texture, + swizzle, + &scaler_stages); + + ScalerImpl* ret = NULL; + for (unsigned int i = 0; i < scaler_stages.size(); i++) { + ret = new ScalerImpl(context_, this, scaler_stages[i], ret, NULL); + } + return ret; +} + +GLHelperBrowser::ScalerInterface* +GLHelperScalingBrowser::CreatePlanarScaler( + const gfx::Size& src_size, + const gfx::Rect& src_subrect, + const gfx::Size& dst_size, + bool vertically_flip_texture, + const float color_weights[4]) { + ScalerStage stage(SHADER_PLANAR, + src_size, + src_subrect, + dst_size, + true, + vertically_flip_texture, + false); + return new ScalerImpl(context_, this, stage, NULL, color_weights); +} + +GLHelperScalingBrowser::ShaderInterface* +GLHelperScalingBrowser::CreateYuvMrtShader( + const gfx::Size& src_size, + const gfx::Rect& src_subrect, + const gfx::Size& dst_size, + bool vertically_flip_texture, + ShaderType shader) { + DCHECK(shader == SHADER_YUV_MRT_PASS1 || shader == SHADER_YUV_MRT_PASS2); + ScalerStage stage(shader, + src_size, + src_subrect, + dst_size, + true, + vertically_flip_texture, + false); + return new ScalerImpl(context_, this, stage, NULL, NULL); +} + +const WebKit::WGC3Dfloat GLHelperScalingBrowser::kVertexAttributes[] = { + -1.0f, -1.0f, 0.0f, 0.0f, + 1.0f, -1.0f, 1.0f, 0.0f, + -1.0f, 1.0f, 0.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, +}; + +void GLHelperScalingBrowser::InitBuffer() { + ScopedBufferBinder buffer_binder( + context_, vertex_attributes_buffer_); + context_->bufferData(GL_ARRAY_BUFFER, + sizeof(kVertexAttributes), + kVertexAttributes, + GL_STATIC_DRAW); +} + +scoped_refptr +GLHelperScalingBrowser::GetShaderProgramBrowser(ShaderType type, + bool swizzle) { + ShaderProgramBrowserKeyType key(type, swizzle); + scoped_refptr& cache_entry(shader_programs_[key]); + if (!cache_entry.get()) { + cache_entry = new ShaderProgramBrowser(context_, helper_); + std::basic_string vertex_program; + std::basic_string fragment_program; + std::basic_string vertex_header; + std::basic_string fragment_directives; + std::basic_string fragment_header; + std::basic_string shared_variables; + + vertex_header.append( + "precision highp float;\n" + "attribute vec2 a_position;\n" + "attribute vec2 a_texcoord;\n"); + + fragment_header.append( + "precision mediump float;\n" + "uniform sampler2D s_texture;\n"); + + shared_variables.append( + "uniform vec4 src_subrect;\n" + "uniform vec2 src_pixelsize;\n" + "uniform vec2 dst_pixelsize;\n" + "uniform vec2 scaling_vector;\n"); + + vertex_program.append( + " gl_Position = vec4(a_position, 0.0, 1.0);\n" + " vec2 texcoord = src_subrect.xy + a_texcoord * src_subrect.zw;\n"); + + switch (type) { + case SHADER_BILINEAR: + shared_variables.append("varying vec2 v_texcoord;\n"); + vertex_program.append(" v_texcoord = texcoord;\n"); + fragment_program.append( + " gl_FragColor = texture2D(s_texture, v_texcoord);\n"); + break; + + case SHADER_BILINEAR2: + // This is equivialent to two passes of the BILINEAR shader above. + // It can be used to scale an image down 1.0x-2.0x in either dimension, + // or exactly 4x. + shared_variables.append( + "varying vec4 v_texcoords;\n"); // 2 texcoords packed in one quad + vertex_program.append( + " vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n" + " step /= 4.0;\n" + " v_texcoords.xy = texcoord + step;\n" + " v_texcoords.zw = texcoord - step;\n"); + + fragment_program.append( + " gl_FragColor = (texture2D(s_texture, v_texcoords.xy) +\n" + " texture2D(s_texture, v_texcoords.zw)) / 2.0;\n"); + break; + + case SHADER_BILINEAR3: + // This is kind of like doing 1.5 passes of the BILINEAR shader. + // It can be used to scale an image down 1.5x-3.0x, or exactly 6x. + shared_variables.append( + "varying vec4 v_texcoords1;\n" // 2 texcoords packed in one quad + "varying vec2 v_texcoords2;\n"); + vertex_program.append( + " vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n" + " step /= 3.0;\n" + " v_texcoords1.xy = texcoord + step;\n" + " v_texcoords1.zw = texcoord;\n" + " v_texcoords2 = texcoord - step;\n"); + fragment_program.append( + " gl_FragColor = (texture2D(s_texture, v_texcoords1.xy) +\n" + " texture2D(s_texture, v_texcoords1.zw) +\n" + " texture2D(s_texture, v_texcoords2)) / 3.0;\n"); + break; + + case SHADER_BILINEAR4: + // This is equivialent to three passes of the BILINEAR shader above, + // It can be used to scale an image down 2.0x-4.0x or exactly 8x. + shared_variables.append( + "varying vec4 v_texcoords[2];\n"); + vertex_program.append( + " vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n" + " step /= 8.0;\n" + " v_texcoords[0].xy = texcoord - step * 3.0;\n" + " v_texcoords[0].zw = texcoord - step;\n" + " v_texcoords[1].xy = texcoord + step;\n" + " v_texcoords[1].zw = texcoord + step * 3.0;\n"); + fragment_program.append( + " gl_FragColor = (\n" + " texture2D(s_texture, v_texcoords[0].xy) +\n" + " texture2D(s_texture, v_texcoords[0].zw) +\n" + " texture2D(s_texture, v_texcoords[1].xy) +\n" + " texture2D(s_texture, v_texcoords[1].zw)) / 4.0;\n"); + break; + + case SHADER_BILINEAR2X2: + // This is equivialent to four passes of the BILINEAR shader above. + // Two in each dimension. It can be used to scale an image down + // 1.0x-2.0x in both X and Y directions. Or, it could be used to + // scale an image down by exactly 4x in both dimensions. + shared_variables.append( + "varying vec4 v_texcoords[2];\n"); + vertex_program.append( + " vec2 step = src_subrect.zw / 4.0 / dst_pixelsize;\n" + " v_texcoords[0].xy = texcoord + vec2(step.x, step.y);\n" + " v_texcoords[0].zw = texcoord + vec2(step.x, -step.y);\n" + " v_texcoords[1].xy = texcoord + vec2(-step.x, step.y);\n" + " v_texcoords[1].zw = texcoord + vec2(-step.x, -step.y);\n"); + fragment_program.append( + " gl_FragColor = (\n" + " texture2D(s_texture, v_texcoords[0].xy) +\n" + " texture2D(s_texture, v_texcoords[0].zw) +\n" + " texture2D(s_texture, v_texcoords[1].xy) +\n" + " texture2D(s_texture, v_texcoords[1].zw)) / 4.0;\n"); + break; + + case SHADER_BICUBIC_HALF_1D: + // This scales down texture by exactly half in one dimension. + // directions in one pass. We use bilinear lookup to reduce + // the number of texture reads from 8 to 4 + shared_variables.append( + "const float CenterDist = 99.0 / 140.0;\n" + "const float LobeDist = 11.0 / 4.0;\n" + "const float CenterWeight = 35.0 / 64.0;\n" + "const float LobeWeight = -3.0 / 64.0;\n" + "varying vec4 v_texcoords[2];\n"); + vertex_program.append( + " vec2 step = src_subrect.zw * scaling_vector / src_pixelsize;\n" + " v_texcoords[0].xy = texcoord - LobeDist * step;\n" + " v_texcoords[0].zw = texcoord - CenterDist * step;\n" + " v_texcoords[1].xy = texcoord + CenterDist * step;\n" + " v_texcoords[1].zw = texcoord + LobeDist * step;\n"); + fragment_program.append( + " gl_FragColor = \n" + // Lobe pixels + " (texture2D(s_texture, v_texcoords[0].xy) +\n" + " texture2D(s_texture, v_texcoords[1].zw)) *\n" + " LobeWeight +\n" + // Center pixels + " (texture2D(s_texture, v_texcoords[0].zw) +\n" + " texture2D(s_texture, v_texcoords[1].xy)) *\n" + " CenterWeight;\n"); + break; + + case SHADER_BICUBIC_UPSCALE: + // When scaling up, we need 4 texture reads, but we can + // save some instructions because will know in which range of + // the bicubic function each call call to the bicubic function + // will be in. + // Also, when sampling the bicubic function like this, the sum + // is always exactly one, so we can skip normalization as well. + shared_variables.append( + "varying vec2 v_texcoord;\n"); + vertex_program.append( + " v_texcoord = texcoord;\n"); + fragment_header.append( + "const float a = -0.5;\n" + // This function is equivialent to calling the bicubic + // function with x-1, x, 1-x and 2-x + // (assuming 0 <= x < 1) + "vec4 filt4(float x) {\n" + " return vec4(x * x * x, x * x, x, 1) *\n" + " mat4( a, -2.0 * a, a, 0.0,\n" + " a + 2.0, -a - 3.0, 0.0, 1.0,\n" + " -a - 2.0, 3.0 + 2.0 * a, -a, 0.0,\n" + " -a, a, 0.0, 0.0);\n" + "}\n" + "mat4 pixels_x(vec2 pos, vec2 step) {\n" + " return mat4(\n" + " texture2D(s_texture, pos - step),\n" + " texture2D(s_texture, pos),\n" + " texture2D(s_texture, pos + step),\n" + " texture2D(s_texture, pos + step * 2.0));\n" + "}\n"); + fragment_program.append( + " vec2 pixel_pos = v_texcoord * src_pixelsize - \n" + " scaling_vector / 2.0;\n" + " float frac = fract(dot(pixel_pos, scaling_vector));\n" + " vec2 base = (floor(pixel_pos) + vec2(0.5)) / src_pixelsize;\n" + " vec2 step = scaling_vector / src_pixelsize;\n" + " gl_FragColor = pixels_x(base, step) * filt4(frac);\n"); + break; + + case SHADER_PLANAR: + // Converts four RGBA pixels into one pixel. Each RGBA + // pixel will be dot-multiplied with the color weights and + // then placed into a component of the output. This is used to + // convert RGBA textures into Y, U and V textures. We do this + // because single-component textures are not renderable on all + // architectures. + shared_variables.append( + "varying vec4 v_texcoords[2];\n" + "uniform vec4 color_weights;\n"); + vertex_program.append( + " vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n" + " step /= 4.0;\n" + " v_texcoords[0].xy = texcoord - step * 1.5;\n" + " v_texcoords[0].zw = texcoord - step * 0.5;\n" + " v_texcoords[1].xy = texcoord + step * 0.5;\n" + " v_texcoords[1].zw = texcoord + step * 1.5;\n"); + fragment_program.append( + " gl_FragColor = color_weights * mat4(\n" + " vec4(texture2D(s_texture, v_texcoords[0].xy).rgb, 1.0),\n" + " vec4(texture2D(s_texture, v_texcoords[0].zw).rgb, 1.0),\n" + " vec4(texture2D(s_texture, v_texcoords[1].xy).rgb, 1.0),\n" + " vec4(texture2D(s_texture, v_texcoords[1].zw).rgb, 1.0));\n"); + // Swizzle makes no sense for this shader. + DCHECK(!swizzle); + break; + + case SHADER_YUV_MRT_PASS1: + // RGB24 to YV12 in two passes; writing two 8888 targets each pass. + // + // YV12 is full-resolution luma and half-resolution blue/red chroma. + // + // (original) + // RGBX RGBX RGBX RGBX RGBX RGBX RGBX RGBX + // RGBX RGBX RGBX RGBX RGBX RGBX RGBX RGBX + // RGBX RGBX RGBX RGBX RGBX RGBX RGBX RGBX + // RGBX RGBX RGBX RGBX RGBX RGBX RGBX RGBX + // RGBX RGBX RGBX RGBX RGBX RGBX RGBX RGBX + // RGBX RGBX RGBX RGBX RGBX RGBX RGBX RGBX + // | + // | (y plane) (temporary) + // | YYYY YYYY UUVV UUVV + // +--> { YYYY YYYY + UUVV UUVV } + // YYYY YYYY UUVV UUVV + // First YYYY YYYY UUVV UUVV + // pass YYYY YYYY UUVV UUVV + // YYYY YYYY UUVV UUVV + // | + // | (u plane) (v plane) + // Second | UUUU VVVV + // pass +--> { UUUU + VVVV } + // UUUU VVVV + // + shared_variables.append( + "varying vec4 v_texcoords[2];\n"); + vertex_program.append( + " vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n" + " step /= 4.0;\n" + " v_texcoords[0].xy = texcoord - step * 1.5;\n" + " v_texcoords[0].zw = texcoord - step * 0.5;\n" + " v_texcoords[1].xy = texcoord + step * 0.5;\n" + " v_texcoords[1].zw = texcoord + step * 1.5;\n"); + fragment_directives.append( + "#extension GL_EXT_draw_buffers : enable\n"); + fragment_header.append( + "const vec3 kRGBtoY = vec3(0.257, 0.504, 0.098);\n" + "const float kYBias = 0.0625;\n" + // Divide U and V by two to compensate for averaging below. + "const vec3 kRGBtoU = vec3(-0.148, -0.291, 0.439) / 2.0;\n" + "const vec3 kRGBtoV = vec3(0.439, -0.368, -0.071) / 2.0;\n" + "const float kUVBias = 0.5;\n"); + fragment_program.append( + " vec3 pixel1 = texture2D(s_texture, v_texcoords[0].xy).rgb;\n" + " vec3 pixel2 = texture2D(s_texture, v_texcoords[0].zw).rgb;\n" + " vec3 pixel3 = texture2D(s_texture, v_texcoords[1].xy).rgb;\n" + " vec3 pixel4 = texture2D(s_texture, v_texcoords[1].zw).rgb;\n" + " vec3 pixel12 = pixel1 + pixel2;\n" + " vec3 pixel34 = pixel3 + pixel4;\n" + " gl_FragData[0] = vec4(dot(pixel1, kRGBtoY),\n" + " dot(pixel2, kRGBtoY),\n" + " dot(pixel3, kRGBtoY),\n" + " dot(pixel4, kRGBtoY)) + kYBias;\n" + " gl_FragData[1] = vec4(dot(pixel12, kRGBtoU),\n" + " dot(pixel34, kRGBtoU),\n" + " dot(pixel12, kRGBtoV),\n" + " dot(pixel34, kRGBtoV)) + kUVBias;\n"); + // Swizzle makes no sense for this shader. + DCHECK(!swizzle); + break; + + case SHADER_YUV_MRT_PASS2: + // We're just sampling two pixels and unswizzling them. There's + // no need to do vertical scaling with math, since bilinear + // interpolation in the sampler takes care of that. + shared_variables.append( + "varying vec4 v_texcoords;\n"); + vertex_program.append( + " vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n" + " step /= 2.0;\n" + " v_texcoords.xy = texcoord - step * 0.5;\n" + " v_texcoords.zw = texcoord + step * 0.5;\n"); + fragment_directives.append( + "#extension GL_EXT_draw_buffers : enable\n"); + fragment_program.append( + " vec4 lo_uuvv = texture2D(s_texture, v_texcoords.xy);\n" + " vec4 hi_uuvv = texture2D(s_texture, v_texcoords.zw);\n" + " gl_FragData[0] = vec4(lo_uuvv.rg, hi_uuvv.rg);\n" + " gl_FragData[1] = vec4(lo_uuvv.ba, hi_uuvv.ba);\n"); + // Swizzle makes no sense for this shader. + DCHECK(!swizzle); + break; + } + if (swizzle) { + fragment_program.append(" gl_FragColor = gl_FragColor.bgra;\n"); + } + + vertex_program = + vertex_header + + shared_variables + + "void main() {\n" + + vertex_program + + "}\n"; + + fragment_program = + fragment_directives + + fragment_header + + shared_variables + + "void main() {\n" + + fragment_program + + "}\n"; + + bool result = cache_entry->Setup(vertex_program.c_str(), + fragment_program.c_str()); + DCHECK(result) + << "vertex_program =\n" << vertex_program + << "fragment_program =\n" << fragment_program; + } + return cache_entry; +} + +bool ShaderProgramBrowser::Setup( + const WebKit::WGC3Dchar* vertex_shader_text, + const WebKit::WGC3Dchar* fragment_shader_text) { + // Shaders to map the source texture to |dst_texture_|. + ScopedShader vertex_shader(context_, helper_->CompileShaderFromSource( + vertex_shader_text, GL_VERTEX_SHADER)); + if (vertex_shader.id() == 0) { + return false; + } + context_->attachShader(program_, vertex_shader); + ScopedShader fragment_shader(context_, helper_->CompileShaderFromSource( + fragment_shader_text, GL_FRAGMENT_SHADER)); + if (fragment_shader.id() == 0) { + return false; + } + context_->attachShader(program_, fragment_shader); + context_->linkProgram(program_); + + WebKit::WGC3Dint link_status = 0; + context_->getProgramiv(program_, GL_LINK_STATUS, &link_status); + if (!link_status) { + LOG(ERROR) << std::string(context_->getProgramInfoLog(program_).utf8()); + return false; + } + position_location_ = context_->getAttribLocation(program_, "a_position"); + texcoord_location_ = context_->getAttribLocation(program_, "a_texcoord"); + texture_location_ = context_->getUniformLocation(program_, "s_texture"); + src_subrect_location_ = context_->getUniformLocation(program_, "src_subrect"); + src_pixelsize_location_ = context_->getUniformLocation(program_, + "src_pixelsize"); + dst_pixelsize_location_ = context_->getUniformLocation(program_, + "dst_pixelsize"); + scaling_vector_location_ = context_->getUniformLocation(program_, + "scaling_vector"); + color_weights_location_ = context_->getUniformLocation(program_, + "color_weights"); + return true; +} + +void ShaderProgramBrowser::UseProgram( + const gfx::Size& src_size, + const gfx::Rect& src_subrect, + const gfx::Size& dst_size, + bool scale_x, + bool flip_y, + GLfloat color_weights[4]) { + context_->useProgram(program_); + + WebKit::WGC3Dintptr offset = 0; + context_->vertexAttribPointer(position_location_, + 2, + GL_FLOAT, + GL_FALSE, + 4 * sizeof(WebKit::WGC3Dfloat), + offset); + context_->enableVertexAttribArray(position_location_); + + offset += 2 * sizeof(WebKit::WGC3Dfloat); + context_->vertexAttribPointer(texcoord_location_, + 2, + GL_FLOAT, + GL_FALSE, + 4 * sizeof(WebKit::WGC3Dfloat), + offset); + context_->enableVertexAttribArray(texcoord_location_); + + context_->uniform1i(texture_location_, 0); + + // Convert |src_subrect| to texture coordinates. + GLfloat src_subrect_texcoord[] = { + static_cast(src_subrect.x()) / src_size.width(), + static_cast(src_subrect.y()) / src_size.height(), + static_cast(src_subrect.width()) / src_size.width(), + static_cast(src_subrect.height()) / src_size.height(), + }; + if (flip_y) { + src_subrect_texcoord[1] += src_subrect_texcoord[3]; + src_subrect_texcoord[3] *= -1.0; + } + context_->uniform4fv(src_subrect_location_, 1, src_subrect_texcoord); + + context_->uniform2f(src_pixelsize_location_, + src_size.width(), + src_size.height()); + context_->uniform2f(dst_pixelsize_location_, + static_cast(dst_size.width()), + static_cast(dst_size.height())); + + context_->uniform2f(scaling_vector_location_, + scale_x ? 1.0 : 0.0, + scale_x ? 0.0 : 1.0); + context_->uniform4fv(color_weights_location_, 1, color_weights); +} + +} // namespace content diff --git a/content/common/gpu/client/gl_helper_scaling_browser.h b/content/common/gpu/client/gl_helper_scaling_browser.h new file mode 100644 index 0000000000000..e79368f180bd2 --- /dev/null +++ b/content/common/gpu/client/gl_helper_scaling_browser.h @@ -0,0 +1,206 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_COMMON_GPU_CLIENT_GL_HELPER_SCALING_BROWSER_H_ +#define CONTENT_COMMON_GPU_CLIENT_GL_HELPER_SCALING_BROWSER_H_ + +#include + +#include "content/common/gpu/client/gl_helper.h" +#include "content/common/gpu/client/gl_helper_browser.h" + +namespace content { + +class ShaderProgramBrowser; +class ScalerImpl; + +// Implements GPU texture scaling methods. +// Note that you should probably not use this class directly. +// See gl_helper.cc::CreateScaler instead. +class CONTENT_EXPORT GLHelperScalingBrowser { + public: + enum ShaderType { + SHADER_BILINEAR, + SHADER_BILINEAR2, + SHADER_BILINEAR3, + SHADER_BILINEAR4, + SHADER_BILINEAR2X2, + SHADER_BICUBIC_UPSCALE, + SHADER_BICUBIC_HALF_1D, + SHADER_PLANAR, + SHADER_YUV_MRT_PASS1, + SHADER_YUV_MRT_PASS2, + }; + + // Similar to ScalerInterface, but can generate multiple outputs. + // Used for YUV conversion in gl_helper.c + class CONTENT_EXPORT ShaderInterface { + public: + ShaderInterface() {} + virtual ~ShaderInterface() {} + // Note that the src_texture will have the min/mag filter set to GL_LINEAR + // and wrap_s/t set to CLAMP_TO_EDGE in this call. + virtual void Execute(WebKit::WebGLId source_texture, + const std::vector& dest_textures) = 0; + }; + + typedef std::pair ShaderProgramBrowserKeyType; + + GLHelperScalingBrowser(WebKit::WebGraphicsContext3D* context, + GLHelperBrowser* helper); + ~GLHelperScalingBrowser(); + void InitBuffer(); + + GLHelperBrowser::ScalerInterface* CreateScaler( + GLHelperBrowser::ScalerQuality quality, + gfx::Size src_size, + gfx::Rect src_subrect, + const gfx::Size& dst_size, + bool vertically_flip_texture, + bool swizzle); + + GLHelperBrowser::ScalerInterface* CreatePlanarScaler( + const gfx::Size& src_size, + const gfx::Rect& src_subrect, + const gfx::Size& dst_size, + bool vertically_flip_texture, + const float color_weights[4]); + + ShaderInterface* CreateYuvMrtShader( + const gfx::Size& src_size, + const gfx::Rect& src_subrect, + const gfx::Size& dst_size, + bool vertically_flip_texture, + ShaderType shader); + + private: + // A ScaleOp represents a pass in a scaler pipeline, in one dimension. + // Note that when quality is GOOD, multiple scaler passes will be + // combined into one operation for increased performance. + // Exposed in the header file for testing purposes. + struct ScaleOp { + ScaleOp(int factor, bool x, int size) + : scale_factor(factor), scale_x(x), scale_size(size) { + } + + // Calculate a set of ScaleOp needed to convert an image of size + // |src| into an image of size |dst|. If |scale_x| is true, then + // the calculations are for the X axis of the image, otherwise Y. + // If |allow3| is true, we can use a SHADER_BILINEAR3 to replace + // a scale up and scale down with a 3-tap bilinear scale. + // The calculated ScaleOps are added to |ops|. + static void AddOps(int src, + int dst, + bool scale_x, + bool allow3, + std::deque* ops) { + int num_downscales = 0; + if (allow3 && dst * 3 >= src && dst * 2 < src) { + // Technically, this should be a scale up and then a + // scale down, but it makes the optimization code more + // complicated. + ops->push_back(ScaleOp(3, scale_x, dst)); + return; + } + while ((dst << num_downscales) < src) { + num_downscales++; + } + if ((dst << num_downscales) != src) { + ops->push_back(ScaleOp(0, scale_x, dst << num_downscales)); + } + while (num_downscales) { + num_downscales--; + ops->push_back(ScaleOp(2, scale_x, dst << num_downscales)); + } + } + + // Update |size| to its new size. Before calling this function + // |size| should be the size of the input image. After calling it, + // |size| will be the size of the image after this particular + // scaling operation. + void UpdateSize(gfx::Size* subrect) { + if (scale_x) { + subrect->set_width(scale_size); + } else { + subrect->set_height(scale_size); + } + } + + // A scale factor of 0 means upscale + // 2 means 50% scale + // 3 means 33% scale, etc. + int scale_factor; + bool scale_x; // Otherwise y + int scale_size; // Size to scale to. + }; + + // Full specification for a single scaling stage. + struct ScalerStage { + ScalerStage(ShaderType shader_, + gfx::Size src_size_, + gfx::Rect src_subrect_, + gfx::Size dst_size_, + bool scale_x_, + bool vertically_flip_texture_, + bool swizzle_); + ShaderType shader; + gfx::Size src_size; + gfx::Rect src_subrect; + gfx::Size dst_size; + bool scale_x; + bool vertically_flip_texture; + bool swizzle; + }; + + // Compute a vector of scaler stages for a particular + // set of input/output parameters. + void ComputeScalerStages(GLHelperBrowser::ScalerQuality quality, + const gfx::Size& src_size, + const gfx::Rect& src_subrect, + const gfx::Size& dst_size, + bool vertically_flip_texture, + bool swizzle, + std::vector *scaler_stages); + + // Take two queues of ScaleOp structs and generate a + // vector of scaler stages. This is the second half of + // ComputeScalerStages. + void ConvertScalerOpsToScalerStages( + GLHelperBrowser::ScalerQuality quality, + gfx::Size src_size, + gfx::Rect src_subrect, + const gfx::Size& dst_size, + bool vertically_flip_texture, + bool swizzle, + std::deque* x_ops, + std::deque* y_ops, + std::vector *scaler_stages); + + + scoped_refptr GetShaderProgramBrowser( + ShaderType type, bool swizzle); + + // Interleaved array of 2-dimentional vertex positions (x, y) and + // 2-dimentional texture coordinates (s, t). + static const WebKit::WGC3Dfloat kVertexAttributes[]; + + WebKit::WebGraphicsContext3D* context_; + GLHelperBrowser* helper_; + + // The buffer that holds the vertices and the texture coordinates data for + // drawing a quad. + ScopedBuffer vertex_attributes_buffer_; + + std::map > shader_programs_; + + friend class ShaderProgramBrowser; + friend class ScalerImpl; + DISALLOW_COPY_AND_ASSIGN(GLHelperScalingBrowser); +}; + + +} // namespace content + +#endif // CONTENT_COMMON_GPU_CLIENT_GL_HELPER_SCALING_H_ diff --git a/content/common/gpu/client/webgraphicscontext3d_command_buffer_browser_impl.cc b/content/common/gpu/client/webgraphicscontext3d_command_buffer_browser_impl.cc new file mode 100644 index 0000000000000..056f9010978f6 --- /dev/null +++ b/content/common/gpu/client/webgraphicscontext3d_command_buffer_browser_impl.cc @@ -0,0 +1,1677 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_browser_impl.h" + +#include "third_party/khronos/GLES2/gl2.h" +#ifndef GL_GLEXT_PROTOTYPES +#define GL_GLEXT_PROTOTYPES 1 +#endif +#include "third_party/khronos/GLES2/gl2ext.h" + +#include +#include + +#include "base/bind.h" +#include "base/command_line.h" +#include "base/debug/trace_event.h" +#include "base/lazy_instance.h" +#include "base/logging.h" +#include "base/message_loop/message_loop.h" +#include "base/metrics/field_trial.h" +#include "base/metrics/histogram.h" +#include "base/synchronization/lock.h" +#include "content/common/gpu/client/gpu_channel_host.h" +#include "content/common/gpu/gpu_memory_allocation.h" +#include "content/common/gpu/gpu_process_launch_causes.h" +#include "content/public/common/content_constants.h" +#include "content/public/common/content_switches.h" +#include "gpu/GLES2/gl2extchromium.h" +#include "gpu/command_buffer/client/gles2_cmd_helper.h" +#include "gpu/command_buffer/client/gles2_implementation.h" +#include "gpu/command_buffer/client/gles2_lib.h" +#include "gpu/command_buffer/client/gles2_trace_implementation.h" +#include "gpu/command_buffer/client/transfer_buffer.h" +#include "gpu/command_buffer/common/constants.h" +#include "gpu/command_buffer/common/mailbox.h" +#include "gpu/ipc/command_buffer_proxy.h" +#include "third_party/skia/include/core/SkTypes.h" +#include "webkit/common/gpu/gl_bindings_skia_cmd_buffer.h" + +namespace content { +static base::LazyInstance::Leaky + g_all_shared_contexts_lock = LAZY_INSTANCE_INITIALIZER; +static base::LazyInstance< + std::set > + g_all_shared_contexts = LAZY_INSTANCE_INITIALIZER; + +namespace { + +void ClearSharedContextsIfInShareSet( + WebGraphicsContext3DCommandBufferBrowserImpl* context) { + // If the given context isn't in the share set, that means that it + // or another context it was previously sharing with already + // provoked a lost context. Other contexts might have since been + // successfully created and added to the share set, so do not clear + // out the share set unless we know that all the contexts in there + // are supposed to be lost simultaneously. + base::AutoLock lock(g_all_shared_contexts_lock.Get()); + std::set* share_set = + g_all_shared_contexts.Pointer(); + for (std::set::iterator iter = + share_set->begin(); iter != share_set->end(); ++iter) { + if (context == *iter) { + share_set->clear(); + return; + } + } +} + +size_t ClampUint64ToSizeT(uint64 value) { + value = std::min(value, + static_cast(std::numeric_limits::max())); + return static_cast(value); +} + +// Singleton used to initialize and terminate the gles2 library. +class GLES2Initializer { + public: + GLES2Initializer() { + gles2::Initialize(); + } + + ~GLES2Initializer() { + gles2::Terminate(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(GLES2Initializer); +}; + +//////////////////////////////////////////////////////////////////////////////// + +base::LazyInstance g_gles2_initializer = + LAZY_INSTANCE_INITIALIZER; + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace anonymous + +// Helper macros to reduce the amount of code. + +#define DELEGATE_TO_GL(name, glname) \ +void WebGraphicsContext3DCommandBufferBrowserImpl::name() { \ + gl_->glname(); \ +} + +#define DELEGATE_TO_GL_R(name, glname, rt) \ +rt WebGraphicsContext3DCommandBufferBrowserImpl::name() { \ + return gl_->glname(); \ +} + +#define DELEGATE_TO_GL_1(name, glname, t1) \ +void WebGraphicsContext3DCommandBufferBrowserImpl::name(t1 a1) { \ + gl_->glname(a1); \ +} + +#define DELEGATE_TO_GL_1R(name, glname, t1, rt) \ +rt WebGraphicsContext3DCommandBufferBrowserImpl::name(t1 a1) { \ + return gl_->glname(a1); \ +} + +#define DELEGATE_TO_GL_1RB(name, glname, t1, rt) \ +rt WebGraphicsContext3DCommandBufferBrowserImpl::name(t1 a1) { \ + return gl_->glname(a1) ? true : false; \ +} + +#define DELEGATE_TO_GL_2(name, glname, t1, t2) \ +void WebGraphicsContext3DCommandBufferBrowserImpl::name(t1 a1, t2 a2) { \ + gl_->glname(a1, a2); \ +} + +#define DELEGATE_TO_GL_2R(name, glname, t1, t2, rt) \ +rt WebGraphicsContext3DCommandBufferBrowserImpl::name(t1 a1, t2 a2) { \ + return gl_->glname(a1, a2); \ +} + +#define DELEGATE_TO_GL_3(name, glname, t1, t2, t3) \ +void WebGraphicsContext3DCommandBufferBrowserImpl::name(t1 a1, t2 a2, t3 a3) { \ + gl_->glname(a1, a2, a3); \ +} + +#define DELEGATE_TO_GL_4(name, glname, t1, t2, t3, t4) \ +void WebGraphicsContext3DCommandBufferBrowserImpl::name(t1 a1, t2 a2, t3 a3, \ + t4 a4) { \ + gl_->glname(a1, a2, a3, a4); \ +} + +#define DELEGATE_TO_GL_4R(name, glname, t1, t2, t3, t4, rt) \ +rt WebGraphicsContext3DCommandBufferBrowserImpl::name(t1 a1, t2 a2, t3 a3, \ + t4 a4) { \ + return gl_->glname(a1, a2, a3, a4); \ +} + +#define DELEGATE_TO_GL_5(name, glname, t1, t2, t3, t4, t5) \ +void WebGraphicsContext3DCommandBufferBrowserImpl::name(t1 a1, t2 a2, t3 a3, \ + t4 a4, t5 a5) { \ + gl_->glname(a1, a2, a3, a4, a5); \ +} + +#define DELEGATE_TO_GL_6(name, glname, t1, t2, t3, t4, t5, t6) \ +void WebGraphicsContext3DCommandBufferBrowserImpl::name(t1 a1, t2 a2, t3 a3, \ + t4 a4, t5 a5, t6 a6) { \ + gl_->glname(a1, a2, a3, a4, a5, a6); \ +} + +#define DELEGATE_TO_GL_7(name, glname, t1, t2, t3, t4, t5, t6, t7) \ +void WebGraphicsContext3DCommandBufferBrowserImpl::name(t1 a1, t2 a2, t3 a3, \ + t4 a4, t5 a5, t6 a6, \ + t7 a7) { \ + gl_->glname(a1, a2, a3, a4, a5, a6, a7); \ +} + +#define DELEGATE_TO_GL_8(name, glname, t1, t2, t3, t4, t5, t6, t7, t8) \ +void WebGraphicsContext3DCommandBufferBrowserImpl::name(t1 a1, t2 a2, t3 a3, \ + t4 a4, t5 a5, t6 a6, \ + t7 a7, t8 a8) { \ + gl_->glname(a1, a2, a3, a4, a5, a6, a7, a8); \ +} + +#define DELEGATE_TO_GL_9(name, glname, t1, t2, t3, t4, t5, t6, t7, t8, t9) \ +void WebGraphicsContext3DCommandBufferBrowserImpl::name(t1 a1, t2 a2, t3 a3, \ + t4 a4, t5 a5, t6 a6, \ + t7 a7, t8 a8, t9 a9) { \ + gl_->glname(a1, a2, a3, a4, a5, a6, a7, a8, a9); \ +} + +class WebGraphicsContext3DBrowserErrorMessageCallback + : public gpu::gles2::GLES2Implementation::ErrorMessageCallback { + public: + WebGraphicsContext3DBrowserErrorMessageCallback( + WebGraphicsContext3DCommandBufferBrowserImpl* context) + : graphics_context_(context) { + } + + virtual void OnErrorMessage(const char* msg, int id) OVERRIDE; + + private: + WebGraphicsContext3DCommandBufferBrowserImpl* graphics_context_; + + DISALLOW_COPY_AND_ASSIGN(WebGraphicsContext3DBrowserErrorMessageCallback); +}; + +void WebGraphicsContext3DBrowserErrorMessageCallback::OnErrorMessage( + const char* msg, int id) { + graphics_context_->OnErrorMessage(msg, id); +} + +WebGraphicsContext3DCommandBufferBrowserImpl:: + WebGraphicsContext3DCommandBufferBrowserImpl( + int surface_id, + const GURL& active_url, + GpuChannelHostFactory* factory, + const base::WeakPtr& swap_client) + : initialize_failed_(false), + factory_(factory), + visible_(false), + free_command_buffer_when_invisible_(false), + host_(NULL), + surface_id_(surface_id), + active_url_(active_url), + swap_client_(swap_client), + context_lost_callback_(0), + context_lost_reason_(GL_NO_ERROR), + error_message_callback_(0), + swapbuffers_complete_callback_(0), + gpu_preference_(gfx::PreferIntegratedGpu), + cached_width_(0), + cached_height_(0), + bound_fbo_(0), + weak_ptr_factory_(this), + initialized_(false), + command_buffer_(NULL), + gles2_helper_(NULL), + transfer_buffer_(NULL), + gl_(NULL), + real_gl_(NULL), + trace_gl_(NULL), + frame_number_(0), + bind_generates_resources_(false), + use_echo_for_swap_ack_(true), + command_buffer_size_(0), + start_transfer_buffer_size_(0), + min_transfer_buffer_size_(0), + max_transfer_buffer_size_(0), + mapped_memory_limit_(gpu::gles2::GLES2Implementation::kNoLimit) { +#if (defined(OS_MACOSX) || defined(OS_WIN)) && !defined(USE_AURA) + // Get ViewMsg_SwapBuffers_ACK from browser for single-threaded path. + const CommandLine& command_line = *CommandLine::ForCurrentProcess(); + use_echo_for_swap_ack_ = + command_line.HasSwitch(switches::kEnableThreadedCompositing); +#endif +} + +WebGraphicsContext3DCommandBufferBrowserImpl:: + ~WebGraphicsContext3DCommandBufferBrowserImpl() { + if (real_gl_) { + real_gl_->SetErrorMessageCallback(NULL); + } + + { + base::AutoLock lock(g_all_shared_contexts_lock.Get()); + g_all_shared_contexts.Pointer()->erase(this); + } + Destroy(); +} + +bool WebGraphicsContext3DCommandBufferBrowserImpl:: + InitializeWithDefaultBufferSizes( + const WebGraphicsContext3D::Attributes& attributes, + bool bind_generates_resources, + CauseForGpuLaunch cause) { + return Initialize(attributes, + bind_generates_resources, + cause, + kDefaultCommandBufferSize, + kDefaultStartTransferBufferSize, + kDefaultMinTransferBufferSize, + kDefaultMaxTransferBufferSize, + gpu::gles2::GLES2Implementation::kNoLimit); +} + +bool WebGraphicsContext3DCommandBufferBrowserImpl::Initialize( + const WebGraphicsContext3D::Attributes& attributes, + bool bind_generates_resources, + CauseForGpuLaunch cause, + size_t command_buffer_size, + size_t start_transfer_buffer_size, + size_t min_transfer_buffer_size, + size_t max_transfer_buffer_size, + size_t mapped_memory_limit) { + TRACE_EVENT0("gpu", "WebGfxCtx3DCmdBfrImpl::initialize"); + + attributes_ = attributes; + bind_generates_resources_ = bind_generates_resources; + DCHECK(!command_buffer_); + + if (!factory_) + return false; + + if (attributes.preferDiscreteGPU) + gpu_preference_ = gfx::PreferDiscreteGpu; + + host_ = factory_->EstablishGpuChannelSync(cause); + if (!host_.get()) + return false; + + command_buffer_size_ = command_buffer_size; + start_transfer_buffer_size_ = start_transfer_buffer_size; + min_transfer_buffer_size_ = min_transfer_buffer_size; + max_transfer_buffer_size_ = max_transfer_buffer_size; + mapped_memory_limit_ = mapped_memory_limit; + return true; +} + +bool WebGraphicsContext3DCommandBufferBrowserImpl::MaybeInitializeGL( + const char* allowed_extensions) { + if (initialized_) + return true; + + if (initialize_failed_) + return false; + + TRACE_EVENT0("gpu", "WebGfxCtx3DCmdBfrImpl::MaybeInitializeGL"); + + const char* preferred_extensions = "*"; + + if (!CreateContext(surface_id_ != 0, + allowed_extensions ? + allowed_extensions : preferred_extensions)) { + Destroy(); + initialize_failed_ = true; + return false; + } + + // TODO(twiz): This code is too fragile in that it assumes that only WebGL + // contexts will request noExtensions. + if (gl_ && attributes_.noExtensions) + gl_->EnableFeatureCHROMIUM("webgl_enable_glsl_webgl_validation"); + + command_buffer_->SetChannelErrorCallback( + base::Bind(&WebGraphicsContext3DCommandBufferBrowserImpl::OnContextLost, + weak_ptr_factory_.GetWeakPtr())); + + command_buffer_->SetOnConsoleMessageCallback( + base::Bind(&WebGraphicsContext3DCommandBufferBrowserImpl::OnErrorMessage, + weak_ptr_factory_.GetWeakPtr())); + + client_error_message_callback_.reset( + new WebGraphicsContext3DBrowserErrorMessageCallback(this)); + real_gl_->SetErrorMessageCallback(client_error_message_callback_.get()); + + const CommandLine& command_line = *CommandLine::ForCurrentProcess(); + free_command_buffer_when_invisible_ = + command_line.HasSwitch(switches::kEnablePruneGpuCommandBuffers); + + // Set attributes_ from created offscreen context. + { + static const int pcount = 4; + static const GLenum pnames[pcount] = { + GL_ALPHA_BITS, + GL_DEPTH_BITS, + GL_STENCIL_BITS, + GL_SAMPLE_BUFFERS, + }; + GLint pvalues[pcount] = { 0, 0, 0, 0 }; + + gl_->GetMultipleIntegervCHROMIUM(pnames, pcount, + pvalues, sizeof(pvalues)); + + attributes_.alpha = pvalues[0] > 0; + attributes_.depth = pvalues[1] > 0; + attributes_.stencil = pvalues[2] > 0; + attributes_.antialias = pvalues[3] > 0; + } + + if (attributes_.shareResources) { + base::AutoLock lock(g_all_shared_contexts_lock.Get()); + g_all_shared_contexts.Pointer()->insert(this); + } + + visible_ = true; + initialized_ = true; + return true; +} + +bool WebGraphicsContext3DCommandBufferBrowserImpl::InitializeCommandBuffer( + bool onscreen, + const char* allowed_extensions) { + if (!host_.get()) + return false; + // We need to lock g_all_shared_contexts to ensure that the context we picked + // for our share group isn't deleted. + // (There's also a lock in our destructor.) + base::AutoLock lock(g_all_shared_contexts_lock.Get()); + CommandBufferProxyImpl* share_group = NULL; + if (attributes_.shareResources) { + WebGraphicsContext3DCommandBufferBrowserImpl* share_group_context = + g_all_shared_contexts.Pointer()->empty() ? + NULL : *g_all_shared_contexts.Pointer()->begin(); + share_group = share_group_context ? + share_group_context->command_buffer_ : NULL; + } + + std::vector attribs; + attribs.push_back(ALPHA_SIZE); + attribs.push_back(attributes_.alpha ? 8 : 0); + attribs.push_back(DEPTH_SIZE); + attribs.push_back(attributes_.depth ? 24 : 0); + attribs.push_back(STENCIL_SIZE); + attribs.push_back(attributes_.stencil ? 8 : 0); + attribs.push_back(SAMPLES); + attribs.push_back(attributes_.antialias ? 4 : 0); + attribs.push_back(SAMPLE_BUFFERS); + attribs.push_back(attributes_.antialias ? 1 : 0); + attribs.push_back(NONE); + + // Create a proxy to a command buffer in the GPU process. + if (onscreen) { + command_buffer_ = host_->CreateViewCommandBuffer( + surface_id_, + share_group, + attribs, + active_url_, + gpu_preference_); + } else { + command_buffer_ = host_->CreateOffscreenCommandBuffer( + gfx::Size(1, 1), + share_group, + attribs, + active_url_, + gpu_preference_); + } + + if (!command_buffer_) + return false; + + // Initialize the command buffer. + return command_buffer_->Initialize(); +} + +bool WebGraphicsContext3DCommandBufferBrowserImpl::CreateContext( + bool onscreen, + const char* allowed_extensions) { + + // Ensure the gles2 library is initialized first in a thread safe way. + g_gles2_initializer.Get(); + + if (!command_buffer_ && + !InitializeCommandBuffer(onscreen, + allowed_extensions)) { + return false; + } + + // Create the GLES2 helper, which writes the command buffer protocol. + gles2_helper_ = new gpu::gles2::GLES2CmdHelper(command_buffer_); + if (!gles2_helper_->Initialize(command_buffer_size_)) + return false; + + if (attributes_.noAutomaticFlushes) + gles2_helper_->SetAutomaticFlushes(false); + + // Create a transfer buffer used to copy resources between the renderer + // process and the GPU process. + transfer_buffer_ = new gpu::TransferBuffer(gles2_helper_); + + WebGraphicsContext3DCommandBufferBrowserImpl* share_group_context = + g_all_shared_contexts.Pointer()->empty() ? + NULL : *g_all_shared_contexts.Pointer()->begin(); + + // Create the object exposing the OpenGL API. + real_gl_ = new gpu::gles2::GLES2Implementation( + gles2_helper_, + share_group_context ? + share_group_context->GetImplementation()->share_group() : NULL, + transfer_buffer_, + bind_generates_resources_, + NULL); + gl_ = real_gl_; + + if (!real_gl_->Initialize( + start_transfer_buffer_size_, + min_transfer_buffer_size_, + max_transfer_buffer_size_, + mapped_memory_limit_)) { + return false; + } + + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableGpuClientTracing)) { + trace_gl_ = new gpu::gles2::GLES2TraceImplementation(gl_); + gl_ = trace_gl_; + } + + return true; +} + +bool WebGraphicsContext3DCommandBufferBrowserImpl::makeContextCurrent() { + if (!MaybeInitializeGL(NULL)) + return false; + gles2::SetGLContext(gl_); + if (command_buffer_->GetLastError() != gpu::error::kNoError) + return false; + + return true; +} + +int WebGraphicsContext3DCommandBufferBrowserImpl::width() { + return cached_width_; +} + +int WebGraphicsContext3DCommandBufferBrowserImpl::height() { + return cached_height_; +} + +DELEGATE_TO_GL_R(insertSyncPoint, InsertSyncPointCHROMIUM, unsigned int) + +void WebGraphicsContext3DCommandBufferBrowserImpl::Destroy() { + if (gl_) { + // First flush the context to ensure that any pending frees of resources + // are completed. Otherwise, if this context is part of a share group, + // those resources might leak. Also, any remaining side effects of commands + // issued on this context might not be visible to other contexts in the + // share group. + gl_->Flush(); + gl_ = NULL; + } + + if (trace_gl_) { + delete trace_gl_; + trace_gl_ = NULL; + } + + if (real_gl_) { + delete real_gl_; + real_gl_ = NULL; + } + + if (transfer_buffer_) { + delete transfer_buffer_; + transfer_buffer_ = NULL; + } + + delete gles2_helper_; + gles2_helper_ = NULL; + + if (command_buffer_) { + if (host_.get()) + host_->DestroyCommandBuffer(command_buffer_); + else + delete command_buffer_; + command_buffer_ = NULL; + } + + host_ = NULL; +} + +// TODO(apatrick,piman): This should be renamed to something clearer. +int WebGraphicsContext3DCommandBufferBrowserImpl::GetGPUProcessID() { + return host_.get() ? host_->gpu_host_id() : 0; +} + +int WebGraphicsContext3DCommandBufferBrowserImpl::GetChannelID() { + return host_.get() ? host_->client_id() : 0; +} + +int WebGraphicsContext3DCommandBufferBrowserImpl::GetContextID() { + return command_buffer_->GetRouteID(); +} + +void WebGraphicsContext3DCommandBufferBrowserImpl::prepareTexture() { + TRACE_EVENT1("gpu", + "WebGraphicsContext3DCommandBufferBrowserImpl::SwapBuffers", + "frame", frame_number_); + frame_number_++; + // Copies the contents of the off-screen render target into the texture + // used by the compositor. + if (ShouldUseSwapClient()) + swap_client_->OnViewContextSwapBuffersPosted(); + + if (command_buffer_->GetLastState().error == gpu::error::kNoError) + gl_->SwapBuffers(); + + if (use_echo_for_swap_ack_) { + command_buffer_->Echo(base::Bind( + &WebGraphicsContext3DCommandBufferBrowserImpl::OnSwapBuffersComplete, + weak_ptr_factory_.GetWeakPtr())); + } +#if defined(OS_MACOSX) + // It appears that making the compositor's on-screen context current on + // other platforms implies this flush. TODO(kbr): this means that the + // TOUCH build and, in the future, other platforms might need this. + gl_->Flush(); +#endif +} + +void WebGraphicsContext3DCommandBufferBrowserImpl::postSubBufferCHROMIUM( + int x, int y, int width, int height) { + // Same flow control as + // WebGraphicsContext3DCommandBufferBrowserImpl::prepareTexture + // (see above). + if (ShouldUseSwapClient()) + swap_client_->OnViewContextSwapBuffersPosted(); + gl_->PostSubBufferCHROMIUM(x, y, width, height); + command_buffer_->Echo(base::Bind( + &WebGraphicsContext3DCommandBufferBrowserImpl::OnSwapBuffersComplete, + weak_ptr_factory_.GetWeakPtr())); +} + +void WebGraphicsContext3DCommandBufferBrowserImpl::reshape( + int width, int height) { + reshapeWithScaleFactor(width, height, 1.f); +} + +void WebGraphicsContext3DCommandBufferBrowserImpl::reshapeWithScaleFactor( + int width, int height, float scale_factor) { + cached_width_ = width; + cached_height_ = height; + + gl_->ResizeCHROMIUM(width, height, scale_factor); +} + +void WebGraphicsContext3DCommandBufferBrowserImpl::FlipVertically( + uint8* framebuffer, + unsigned int width, + unsigned int height) { + if (width == 0) + return; + scanline_.resize(width * 4); + uint8* scanline = &scanline_[0]; + unsigned int row_bytes = width * 4; + unsigned int count = height / 2; + for (unsigned int i = 0; i < count; i++) { + uint8* row_a = framebuffer + i * row_bytes; + uint8* row_b = framebuffer + (height - i - 1) * row_bytes; + // TODO(kbr): this is where the multiplication of the alpha + // channel into the color buffer will need to occur if the + // user specifies the "premultiplyAlpha" flag in the context + // creation attributes. + memcpy(scanline, row_b, row_bytes); + memcpy(row_b, row_a, row_bytes); + memcpy(row_a, scanline, row_bytes); + } +} + +bool WebGraphicsContext3DCommandBufferBrowserImpl::readBackFramebuffer( + unsigned char* pixels, + size_t buffer_size, + WebGLId buffer, + int width, + int height) { + if (buffer_size != static_cast(4 * width * height)) { + return false; + } + + // Earlier versions of this code used the GPU to flip the + // framebuffer vertically before reading it back for compositing + // via software. This code was quite complicated, used a lot of + // GPU memory, and didn't provide an obvious speedup. Since this + // vertical flip is only a temporary solution anyway until Chrome + // is fully GPU composited, it wasn't worth the complexity. + + bool mustRestoreFBO = (bound_fbo_ != buffer); + if (mustRestoreFBO) { + gl_->BindFramebuffer(GL_FRAMEBUFFER, buffer); + } + gl_->ReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + +#if (SK_R32_SHIFT == 16) && !SK_B32_SHIFT + // Swizzle red and blue channels to match SkBitmap's byte ordering. + // TODO(kbr): expose GL_BGRA as extension. + for (size_t i = 0; i < buffer_size; i += 4) { + std::swap(pixels[i], pixels[i + 2]); + } +#endif + + if (mustRestoreFBO) { + gl_->BindFramebuffer(GL_FRAMEBUFFER, bound_fbo_); + } + + if (pixels) { + FlipVertically(pixels, width, height); + } + + return true; +} + +bool WebGraphicsContext3DCommandBufferBrowserImpl::readBackFramebuffer( + unsigned char* pixels, + size_t buffer_size) { + return readBackFramebuffer(pixels, buffer_size, 0, width(), height()); +} + +void WebGraphicsContext3DCommandBufferBrowserImpl::synthesizeGLError( + WGC3Denum error) { + if (std::find(synthetic_errors_.begin(), synthetic_errors_.end(), error) == + synthetic_errors_.end()) { + synthetic_errors_.push_back(error); + } +} + +DELEGATE_TO_GL_4R(mapBufferSubDataCHROMIUM, MapBufferSubDataCHROMIUM, WGC3Denum, + WGC3Dintptr, WGC3Dsizeiptr, WGC3Denum, void*) + +DELEGATE_TO_GL_1(unmapBufferSubDataCHROMIUM, UnmapBufferSubDataCHROMIUM, + const void*) + +void* WebGraphicsContext3DCommandBufferBrowserImpl::mapTexSubImage2DCHROMIUM( + WGC3Denum target, + WGC3Dint level, + WGC3Dint xoffset, + WGC3Dint yoffset, + WGC3Dsizei width, + WGC3Dsizei height, + WGC3Denum format, + WGC3Denum type, + WGC3Denum access) { + return gl_->MapTexSubImage2DCHROMIUM( + target, level, xoffset, yoffset, width, height, format, type, access); +} + +DELEGATE_TO_GL_1(unmapTexSubImage2DCHROMIUM, UnmapTexSubImage2DCHROMIUM, + const void*) + +void WebGraphicsContext3DCommandBufferBrowserImpl::setVisibilityCHROMIUM( + bool visible) { + gl_->Flush(); + visible_ = visible; + command_buffer_->SetSurfaceVisible(visible); + if (!visible) + real_gl_->FreeEverything(); +} + +DELEGATE_TO_GL_3(discardFramebufferEXT, DiscardFramebufferEXT, WGC3Denum, + WGC3Dsizei, const WGC3Denum*) + +void WebGraphicsContext3DCommandBufferBrowserImpl::discardBackbufferCHROMIUM() { + gl_->Flush(); + command_buffer_->DiscardBackbuffer(); +} + +void WebGraphicsContext3DCommandBufferBrowserImpl::ensureBackbufferCHROMIUM() { + gl_->Flush(); + command_buffer_->EnsureBackbuffer(); +} + +void WebGraphicsContext3DCommandBufferBrowserImpl:: + sendManagedMemoryStatsCHROMIUM( + const WebGraphicsManagedMemoryStats* stats) +{ + CHECK(command_buffer_); + command_buffer_->SendManagedMemoryStats(GpuManagedMemoryStats( + stats->bytesVisible, + stats->bytesVisibleAndNearby, + stats->bytesAllocated, + stats->backbufferRequested)); +} + +void WebGraphicsContext3DCommandBufferBrowserImpl:: + setMemoryAllocationChangedCallbackCHROMIUM( + WebGraphicsMemoryAllocationChangedCallbackCHROMIUM* callback) { + if (!command_buffer_) + return; + + if (callback) + command_buffer_->SetMemoryAllocationChangedCallback(base::Bind( + &WebGraphicsContext3DCommandBufferBrowserImpl::OnMemoryAllocationChanged, + weak_ptr_factory_.GetWeakPtr(), + callback)); + else + command_buffer_->SetMemoryAllocationChangedCallback( + base::Callback()); +} + + +void WebGraphicsContext3DCommandBufferBrowserImpl:: + copyTextureToParentTextureCHROMIUM( + WebGLId texture, WebGLId parentTexture) { + NOTIMPLEMENTED(); +} + +DELEGATE_TO_GL(rateLimitOffscreenContextCHROMIUM, + RateLimitOffscreenContextCHROMIUM) + +WebKit::WebString WebGraphicsContext3DCommandBufferBrowserImpl:: + getRequestableExtensionsCHROMIUM() { + return WebKit::WebString::fromUTF8( + gl_->GetRequestableExtensionsCHROMIUM()); +} + +DELEGATE_TO_GL_1(requestExtensionCHROMIUM, RequestExtensionCHROMIUM, + const char*) + +void WebGraphicsContext3DCommandBufferBrowserImpl::blitFramebufferCHROMIUM( + WGC3Dint srcX0, WGC3Dint srcY0, WGC3Dint srcX1, WGC3Dint srcY1, + WGC3Dint dstX0, WGC3Dint dstY0, WGC3Dint dstX1, WGC3Dint dstY1, + WGC3Dbitfield mask, WGC3Denum filter) { + gl_->BlitFramebufferEXT( + srcX0, srcY0, srcX1, srcY1, + dstX0, dstY0, dstX1, dstY1, + mask, filter); +} + +DELEGATE_TO_GL_5(renderbufferStorageMultisampleCHROMIUM, + RenderbufferStorageMultisampleEXT, WGC3Denum, WGC3Dsizei, + WGC3Denum, WGC3Dsizei, WGC3Dsizei) + +DELEGATE_TO_GL_1R(createStreamTextureCHROMIUM, CreateStreamTextureCHROMIUM, + WebGLId, WebGLId) + +DELEGATE_TO_GL_1(destroyStreamTextureCHROMIUM, DestroyStreamTextureCHROMIUM, + WebGLId) + +DELEGATE_TO_GL_1(activeTexture, ActiveTexture, WGC3Denum) + +DELEGATE_TO_GL_2(attachShader, AttachShader, WebGLId, WebGLId) + +DELEGATE_TO_GL_3(bindAttribLocation, BindAttribLocation, WebGLId, + WGC3Duint, const WGC3Dchar*) + +DELEGATE_TO_GL_2(bindBuffer, BindBuffer, WGC3Denum, WebGLId) + +void WebGraphicsContext3DCommandBufferBrowserImpl::bindFramebuffer( + WGC3Denum target, + WebGLId framebuffer) { + gl_->BindFramebuffer(target, framebuffer); + bound_fbo_ = framebuffer; +} + +DELEGATE_TO_GL_2(bindRenderbuffer, BindRenderbuffer, WGC3Denum, WebGLId) + +DELEGATE_TO_GL_2(bindTexture, BindTexture, WGC3Denum, WebGLId) + +DELEGATE_TO_GL_4(blendColor, BlendColor, + WGC3Dclampf, WGC3Dclampf, WGC3Dclampf, WGC3Dclampf) + +DELEGATE_TO_GL_1(blendEquation, BlendEquation, WGC3Denum) + +DELEGATE_TO_GL_2(blendEquationSeparate, BlendEquationSeparate, + WGC3Denum, WGC3Denum) + +DELEGATE_TO_GL_2(blendFunc, BlendFunc, WGC3Denum, WGC3Denum) + +DELEGATE_TO_GL_4(blendFuncSeparate, BlendFuncSeparate, + WGC3Denum, WGC3Denum, WGC3Denum, WGC3Denum) + +DELEGATE_TO_GL_4(bufferData, BufferData, + WGC3Denum, WGC3Dsizeiptr, const void*, WGC3Denum) + +DELEGATE_TO_GL_4(bufferSubData, BufferSubData, + WGC3Denum, WGC3Dintptr, WGC3Dsizeiptr, const void*) + +DELEGATE_TO_GL_1R(checkFramebufferStatus, CheckFramebufferStatus, + WGC3Denum, WGC3Denum) + +DELEGATE_TO_GL_1(clear, Clear, WGC3Dbitfield) + +DELEGATE_TO_GL_4(clearColor, ClearColor, + WGC3Dclampf, WGC3Dclampf, WGC3Dclampf, WGC3Dclampf) + +DELEGATE_TO_GL_1(clearDepth, ClearDepthf, WGC3Dclampf) + +DELEGATE_TO_GL_1(clearStencil, ClearStencil, WGC3Dint) + +DELEGATE_TO_GL_4(colorMask, ColorMask, + WGC3Dboolean, WGC3Dboolean, WGC3Dboolean, WGC3Dboolean) + +DELEGATE_TO_GL_1(compileShader, CompileShader, WebGLId) + +DELEGATE_TO_GL_8(compressedTexImage2D, CompressedTexImage2D, + WGC3Denum, WGC3Dint, WGC3Denum, WGC3Dint, WGC3Dint, + WGC3Dsizei, WGC3Dsizei, const void*) + +DELEGATE_TO_GL_9(compressedTexSubImage2D, CompressedTexSubImage2D, + WGC3Denum, WGC3Dint, WGC3Dint, WGC3Dint, WGC3Dint, WGC3Dint, + WGC3Denum, WGC3Dsizei, const void*) + +DELEGATE_TO_GL_8(copyTexImage2D, CopyTexImage2D, + WGC3Denum, WGC3Dint, WGC3Denum, WGC3Dint, WGC3Dint, + WGC3Dsizei, WGC3Dsizei, WGC3Dint) + +DELEGATE_TO_GL_8(copyTexSubImage2D, CopyTexSubImage2D, + WGC3Denum, WGC3Dint, WGC3Dint, WGC3Dint, WGC3Dint, WGC3Dint, + WGC3Dsizei, WGC3Dsizei) + +DELEGATE_TO_GL_1(cullFace, CullFace, WGC3Denum) + +DELEGATE_TO_GL_1(depthFunc, DepthFunc, WGC3Denum) + +DELEGATE_TO_GL_1(depthMask, DepthMask, WGC3Dboolean) + +DELEGATE_TO_GL_2(depthRange, DepthRangef, WGC3Dclampf, WGC3Dclampf) + +DELEGATE_TO_GL_2(detachShader, DetachShader, WebGLId, WebGLId) + +DELEGATE_TO_GL_1(disable, Disable, WGC3Denum) + +DELEGATE_TO_GL_1(disableVertexAttribArray, DisableVertexAttribArray, + WGC3Duint) + +DELEGATE_TO_GL_3(drawArrays, DrawArrays, WGC3Denum, WGC3Dint, WGC3Dsizei) + +void WebGraphicsContext3DCommandBufferBrowserImpl::drawElements( + WGC3Denum mode, + WGC3Dsizei count, + WGC3Denum type, + WGC3Dintptr offset) { + gl_->DrawElements( + mode, count, type, + reinterpret_cast(static_cast(offset))); +} + +DELEGATE_TO_GL_1(enable, Enable, WGC3Denum) + +DELEGATE_TO_GL_1(enableVertexAttribArray, EnableVertexAttribArray, + WGC3Duint) + +void WebGraphicsContext3DCommandBufferBrowserImpl::finish() { + gl_->Finish(); + if (!visible_ && free_command_buffer_when_invisible_) + real_gl_->FreeEverything(); +} + +void WebGraphicsContext3DCommandBufferBrowserImpl::flush() { + gl_->Flush(); + if (!visible_ && free_command_buffer_when_invisible_) + real_gl_->FreeEverything(); +} + +DELEGATE_TO_GL_4(framebufferRenderbuffer, FramebufferRenderbuffer, + WGC3Denum, WGC3Denum, WGC3Denum, WebGLId) + +DELEGATE_TO_GL_5(framebufferTexture2D, FramebufferTexture2D, + WGC3Denum, WGC3Denum, WGC3Denum, WebGLId, WGC3Dint) + +DELEGATE_TO_GL_1(frontFace, FrontFace, WGC3Denum) + +DELEGATE_TO_GL_1(generateMipmap, GenerateMipmap, WGC3Denum) + +bool WebGraphicsContext3DCommandBufferBrowserImpl::getActiveAttrib( + WebGLId program, WGC3Duint index, ActiveInfo& info) { + if (!program) { + synthesizeGLError(GL_INVALID_VALUE); + return false; + } + GLint max_name_length = -1; + gl_->GetProgramiv( + program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_name_length); + if (max_name_length < 0) + return false; + scoped_ptr name(new GLchar[max_name_length]); + if (!name) { + synthesizeGLError(GL_OUT_OF_MEMORY); + return false; + } + GLsizei length = 0; + GLint size = -1; + GLenum type = 0; + gl_->GetActiveAttrib( + program, index, max_name_length, &length, &size, &type, name.get()); + if (size < 0) { + return false; + } + info.name = WebKit::WebString::fromUTF8(name.get(), length); + info.type = type; + info.size = size; + return true; +} + +bool WebGraphicsContext3DCommandBufferBrowserImpl::getActiveUniform( + WebGLId program, WGC3Duint index, ActiveInfo& info) { + GLint max_name_length = -1; + gl_->GetProgramiv( + program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_name_length); + if (max_name_length < 0) + return false; + scoped_ptr name(new GLchar[max_name_length]); + if (!name) { + synthesizeGLError(GL_OUT_OF_MEMORY); + return false; + } + GLsizei length = 0; + GLint size = -1; + GLenum type = 0; + gl_->GetActiveUniform( + program, index, max_name_length, &length, &size, &type, name.get()); + if (size < 0) { + return false; + } + info.name = WebKit::WebString::fromUTF8(name.get(), length); + info.type = type; + info.size = size; + return true; +} + +DELEGATE_TO_GL_4(getAttachedShaders, GetAttachedShaders, + WebGLId, WGC3Dsizei, WGC3Dsizei*, WebGLId*) + +DELEGATE_TO_GL_2R(getAttribLocation, GetAttribLocation, + WebGLId, const WGC3Dchar*, WGC3Dint) + +DELEGATE_TO_GL_2(getBooleanv, GetBooleanv, WGC3Denum, WGC3Dboolean*) + +DELEGATE_TO_GL_3(getBufferParameteriv, GetBufferParameteriv, + WGC3Denum, WGC3Denum, WGC3Dint*) + +WebKit::WebGraphicsContext3D::Attributes +WebGraphicsContext3DCommandBufferBrowserImpl::getContextAttributes() { + return attributes_; +} + +WGC3Denum WebGraphicsContext3DCommandBufferBrowserImpl::getError() { + if (!synthetic_errors_.empty()) { + std::vector::iterator iter = synthetic_errors_.begin(); + WGC3Denum err = *iter; + synthetic_errors_.erase(iter); + return err; + } + + return gl_->GetError(); +} + +bool WebGraphicsContext3DCommandBufferBrowserImpl::isContextLost() { + return initialize_failed_ || + (command_buffer_ && IsCommandBufferContextLost()) || + context_lost_reason_ != GL_NO_ERROR; +} + +DELEGATE_TO_GL_2(getFloatv, GetFloatv, WGC3Denum, WGC3Dfloat*) + +DELEGATE_TO_GL_4(getFramebufferAttachmentParameteriv, + GetFramebufferAttachmentParameteriv, + WGC3Denum, WGC3Denum, WGC3Denum, WGC3Dint*) + +DELEGATE_TO_GL_2(getIntegerv, GetIntegerv, WGC3Denum, WGC3Dint*) + +DELEGATE_TO_GL_3(getProgramiv, GetProgramiv, WebGLId, WGC3Denum, WGC3Dint*) + +WebKit::WebString WebGraphicsContext3DCommandBufferBrowserImpl:: + getProgramInfoLog(WebGLId program) { + GLint logLength = 0; + gl_->GetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength); + if (!logLength) + return WebKit::WebString(); + scoped_ptr log(new GLchar[logLength]); + if (!log) + return WebKit::WebString(); + GLsizei returnedLogLength = 0; + gl_->GetProgramInfoLog( + program, logLength, &returnedLogLength, log.get()); + DCHECK_EQ(logLength, returnedLogLength + 1); + WebKit::WebString res = + WebKit::WebString::fromUTF8(log.get(), returnedLogLength); + return res; +} + +DELEGATE_TO_GL_3(getRenderbufferParameteriv, GetRenderbufferParameteriv, + WGC3Denum, WGC3Denum, WGC3Dint*) + +DELEGATE_TO_GL_3(getShaderiv, GetShaderiv, WebGLId, WGC3Denum, WGC3Dint*) + +WebKit::WebString WebGraphicsContext3DCommandBufferBrowserImpl:: + getShaderInfoLog(WebGLId shader) { + GLint logLength = 0; + gl_->GetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength); + if (!logLength) + return WebKit::WebString(); + scoped_ptr log(new GLchar[logLength]); + if (!log) + return WebKit::WebString(); + GLsizei returnedLogLength = 0; + gl_->GetShaderInfoLog( + shader, logLength, &returnedLogLength, log.get()); + DCHECK_EQ(logLength, returnedLogLength + 1); + WebKit::WebString res = + WebKit::WebString::fromUTF8(log.get(), returnedLogLength); + return res; +} + +DELEGATE_TO_GL_4(getShaderPrecisionFormat, GetShaderPrecisionFormat, + WGC3Denum, WGC3Denum, WGC3Dint*, WGC3Dint*) + +WebKit::WebString WebGraphicsContext3DCommandBufferBrowserImpl::getShaderSource( + WebGLId shader) { + GLint logLength = 0; + gl_->GetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &logLength); + if (!logLength) + return WebKit::WebString(); + scoped_ptr log(new GLchar[logLength]); + if (!log) + return WebKit::WebString(); + GLsizei returnedLogLength = 0; + gl_->GetShaderSource( + shader, logLength, &returnedLogLength, log.get()); + if (!returnedLogLength) + return WebKit::WebString(); + DCHECK_EQ(logLength, returnedLogLength + 1); + WebKit::WebString res = + WebKit::WebString::fromUTF8(log.get(), returnedLogLength); + return res; +} + +WebKit::WebString WebGraphicsContext3DCommandBufferBrowserImpl:: + getTranslatedShaderSourceANGLE(WebGLId shader) { + GLint logLength = 0; + gl_->GetShaderiv( + shader, GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE, &logLength); + if (!logLength) + return WebKit::WebString(); + scoped_ptr log(new GLchar[logLength]); + if (!log) + return WebKit::WebString(); + GLsizei returnedLogLength = 0; + gl_->GetTranslatedShaderSourceANGLE( + shader, logLength, &returnedLogLength, log.get()); + if (!returnedLogLength) + return WebKit::WebString(); + DCHECK_EQ(logLength, returnedLogLength + 1); + WebKit::WebString res = + WebKit::WebString::fromUTF8(log.get(), returnedLogLength); + return res; +} + +WebKit::WebString WebGraphicsContext3DCommandBufferBrowserImpl::getString( + WGC3Denum name) { + return WebKit::WebString::fromUTF8( + reinterpret_cast(gl_->GetString(name))); +} + +DELEGATE_TO_GL_3(getTexParameterfv, GetTexParameterfv, + WGC3Denum, WGC3Denum, WGC3Dfloat*) + +DELEGATE_TO_GL_3(getTexParameteriv, GetTexParameteriv, + WGC3Denum, WGC3Denum, WGC3Dint*) + +DELEGATE_TO_GL_3(getUniformfv, GetUniformfv, WebGLId, WGC3Dint, WGC3Dfloat*) + +DELEGATE_TO_GL_3(getUniformiv, GetUniformiv, WebGLId, WGC3Dint, WGC3Dint*) + +DELEGATE_TO_GL_2R(getUniformLocation, GetUniformLocation, + WebGLId, const WGC3Dchar*, WGC3Dint) + +DELEGATE_TO_GL_3(getVertexAttribfv, GetVertexAttribfv, + WGC3Duint, WGC3Denum, WGC3Dfloat*) + +DELEGATE_TO_GL_3(getVertexAttribiv, GetVertexAttribiv, + WGC3Duint, WGC3Denum, WGC3Dint*) + +WGC3Dsizeiptr WebGraphicsContext3DCommandBufferBrowserImpl:: + getVertexAttribOffset(WGC3Duint index, WGC3Denum pname) { + GLvoid* value = NULL; + // NOTE: If pname is ever a value that returns more then 1 element + // this will corrupt memory. + gl_->GetVertexAttribPointerv(index, pname, &value); + return static_cast(reinterpret_cast(value)); +} + +DELEGATE_TO_GL_2(hint, Hint, WGC3Denum, WGC3Denum) + +DELEGATE_TO_GL_1RB(isBuffer, IsBuffer, WebGLId, WGC3Dboolean) + +DELEGATE_TO_GL_1RB(isEnabled, IsEnabled, WGC3Denum, WGC3Dboolean) + +DELEGATE_TO_GL_1RB(isFramebuffer, IsFramebuffer, WebGLId, WGC3Dboolean) + +DELEGATE_TO_GL_1RB(isProgram, IsProgram, WebGLId, WGC3Dboolean) + +DELEGATE_TO_GL_1RB(isRenderbuffer, IsRenderbuffer, WebGLId, WGC3Dboolean) + +DELEGATE_TO_GL_1RB(isShader, IsShader, WebGLId, WGC3Dboolean) + +DELEGATE_TO_GL_1RB(isTexture, IsTexture, WebGLId, WGC3Dboolean) + +DELEGATE_TO_GL_1(lineWidth, LineWidth, WGC3Dfloat) + +DELEGATE_TO_GL_1(linkProgram, LinkProgram, WebGLId) + +DELEGATE_TO_GL_2(pixelStorei, PixelStorei, WGC3Denum, WGC3Dint) + +DELEGATE_TO_GL_2(polygonOffset, PolygonOffset, WGC3Dfloat, WGC3Dfloat) + +DELEGATE_TO_GL_7(readPixels, ReadPixels, + WGC3Dint, WGC3Dint, WGC3Dsizei, WGC3Dsizei, WGC3Denum, + WGC3Denum, void*) + +void WebGraphicsContext3DCommandBufferBrowserImpl::releaseShaderCompiler() { +} + +DELEGATE_TO_GL_4(renderbufferStorage, RenderbufferStorage, + WGC3Denum, WGC3Denum, WGC3Dsizei, WGC3Dsizei) + +DELEGATE_TO_GL_2(sampleCoverage, SampleCoverage, WGC3Dfloat, WGC3Dboolean) + +DELEGATE_TO_GL_4(scissor, Scissor, WGC3Dint, WGC3Dint, WGC3Dsizei, WGC3Dsizei) + +void WebGraphicsContext3DCommandBufferBrowserImpl::shaderSource( + WebGLId shader, const WGC3Dchar* string) { + GLint length = strlen(string); + gl_->ShaderSource(shader, 1, &string, &length); +} + +DELEGATE_TO_GL_3(stencilFunc, StencilFunc, WGC3Denum, WGC3Dint, WGC3Duint) + +DELEGATE_TO_GL_4(stencilFuncSeparate, StencilFuncSeparate, + WGC3Denum, WGC3Denum, WGC3Dint, WGC3Duint) + +DELEGATE_TO_GL_1(stencilMask, StencilMask, WGC3Duint) + +DELEGATE_TO_GL_2(stencilMaskSeparate, StencilMaskSeparate, + WGC3Denum, WGC3Duint) + +DELEGATE_TO_GL_3(stencilOp, StencilOp, + WGC3Denum, WGC3Denum, WGC3Denum) + +DELEGATE_TO_GL_4(stencilOpSeparate, StencilOpSeparate, + WGC3Denum, WGC3Denum, WGC3Denum, WGC3Denum) + +DELEGATE_TO_GL_9(texImage2D, TexImage2D, + WGC3Denum, WGC3Dint, WGC3Denum, WGC3Dsizei, WGC3Dsizei, + WGC3Dint, WGC3Denum, WGC3Denum, const void*) + +DELEGATE_TO_GL_3(texParameterf, TexParameterf, + WGC3Denum, WGC3Denum, WGC3Dfloat); + +static const unsigned int kTextureWrapR = 0x8072; + +void WebGraphicsContext3DCommandBufferBrowserImpl::texParameteri( + WGC3Denum target, WGC3Denum pname, WGC3Dint param) { + // TODO(kbr): figure out whether the setting of TEXTURE_WRAP_R in + // GraphicsContext3D.cpp is strictly necessary to avoid seams at the + // edge of cube maps, and, if it is, push it into the GLES2 service + // side code. + if (pname == kTextureWrapR) { + return; + } + gl_->TexParameteri(target, pname, param); +} + +DELEGATE_TO_GL_9(texSubImage2D, TexSubImage2D, + WGC3Denum, WGC3Dint, WGC3Dint, WGC3Dint, WGC3Dsizei, + WGC3Dsizei, WGC3Denum, WGC3Denum, const void*) + +DELEGATE_TO_GL_2(uniform1f, Uniform1f, WGC3Dint, WGC3Dfloat) + +DELEGATE_TO_GL_3(uniform1fv, Uniform1fv, WGC3Dint, WGC3Dsizei, + const WGC3Dfloat*) + +DELEGATE_TO_GL_2(uniform1i, Uniform1i, WGC3Dint, WGC3Dint) + +DELEGATE_TO_GL_3(uniform1iv, Uniform1iv, WGC3Dint, WGC3Dsizei, const WGC3Dint*) + +DELEGATE_TO_GL_3(uniform2f, Uniform2f, WGC3Dint, WGC3Dfloat, WGC3Dfloat) + +DELEGATE_TO_GL_3(uniform2fv, Uniform2fv, WGC3Dint, WGC3Dsizei, + const WGC3Dfloat*) + +DELEGATE_TO_GL_3(uniform2i, Uniform2i, WGC3Dint, WGC3Dint, WGC3Dint) + +DELEGATE_TO_GL_3(uniform2iv, Uniform2iv, WGC3Dint, WGC3Dsizei, const WGC3Dint*) + +DELEGATE_TO_GL_4(uniform3f, Uniform3f, WGC3Dint, + WGC3Dfloat, WGC3Dfloat, WGC3Dfloat) + +DELEGATE_TO_GL_3(uniform3fv, Uniform3fv, WGC3Dint, WGC3Dsizei, + const WGC3Dfloat*) + +DELEGATE_TO_GL_4(uniform3i, Uniform3i, WGC3Dint, WGC3Dint, WGC3Dint, WGC3Dint) + +DELEGATE_TO_GL_3(uniform3iv, Uniform3iv, WGC3Dint, WGC3Dsizei, const WGC3Dint*) + +DELEGATE_TO_GL_5(uniform4f, Uniform4f, WGC3Dint, + WGC3Dfloat, WGC3Dfloat, WGC3Dfloat, WGC3Dfloat) + +DELEGATE_TO_GL_3(uniform4fv, Uniform4fv, WGC3Dint, WGC3Dsizei, + const WGC3Dfloat*) + +DELEGATE_TO_GL_5(uniform4i, Uniform4i, WGC3Dint, + WGC3Dint, WGC3Dint, WGC3Dint, WGC3Dint) + +DELEGATE_TO_GL_3(uniform4iv, Uniform4iv, WGC3Dint, WGC3Dsizei, const WGC3Dint*) + +DELEGATE_TO_GL_4(uniformMatrix2fv, UniformMatrix2fv, + WGC3Dint, WGC3Dsizei, WGC3Dboolean, const WGC3Dfloat*) + +DELEGATE_TO_GL_4(uniformMatrix3fv, UniformMatrix3fv, + WGC3Dint, WGC3Dsizei, WGC3Dboolean, const WGC3Dfloat*) + +DELEGATE_TO_GL_4(uniformMatrix4fv, UniformMatrix4fv, + WGC3Dint, WGC3Dsizei, WGC3Dboolean, const WGC3Dfloat*) + +DELEGATE_TO_GL_1(useProgram, UseProgram, WebGLId) + +DELEGATE_TO_GL_1(validateProgram, ValidateProgram, WebGLId) + +DELEGATE_TO_GL_2(vertexAttrib1f, VertexAttrib1f, WGC3Duint, WGC3Dfloat) + +DELEGATE_TO_GL_2(vertexAttrib1fv, VertexAttrib1fv, WGC3Duint, + const WGC3Dfloat*) + +DELEGATE_TO_GL_3(vertexAttrib2f, VertexAttrib2f, WGC3Duint, + WGC3Dfloat, WGC3Dfloat) + +DELEGATE_TO_GL_2(vertexAttrib2fv, VertexAttrib2fv, WGC3Duint, + const WGC3Dfloat*) + +DELEGATE_TO_GL_4(vertexAttrib3f, VertexAttrib3f, WGC3Duint, + WGC3Dfloat, WGC3Dfloat, WGC3Dfloat) + +DELEGATE_TO_GL_2(vertexAttrib3fv, VertexAttrib3fv, WGC3Duint, + const WGC3Dfloat*) + +DELEGATE_TO_GL_5(vertexAttrib4f, VertexAttrib4f, WGC3Duint, + WGC3Dfloat, WGC3Dfloat, WGC3Dfloat, WGC3Dfloat) + +DELEGATE_TO_GL_2(vertexAttrib4fv, VertexAttrib4fv, WGC3Duint, + const WGC3Dfloat*) + +void WebGraphicsContext3DCommandBufferBrowserImpl::vertexAttribPointer( + WGC3Duint index, WGC3Dint size, WGC3Denum type, WGC3Dboolean normalized, + WGC3Dsizei stride, WGC3Dintptr offset) { + gl_->VertexAttribPointer( + index, size, type, normalized, stride, + reinterpret_cast(static_cast(offset))); +} + +DELEGATE_TO_GL_4(viewport, Viewport, + WGC3Dint, WGC3Dint, WGC3Dsizei, WGC3Dsizei) + +WebGLId WebGraphicsContext3DCommandBufferBrowserImpl::createBuffer() { + GLuint o; + gl_->GenBuffers(1, &o); + return o; +} + +WebGLId WebGraphicsContext3DCommandBufferBrowserImpl::createFramebuffer() { + GLuint o = 0; + gl_->GenFramebuffers(1, &o); + return o; +} + +DELEGATE_TO_GL_R(createProgram, CreateProgram, WebGLId) + +WebGLId WebGraphicsContext3DCommandBufferBrowserImpl::createRenderbuffer() { + GLuint o; + gl_->GenRenderbuffers(1, &o); + return o; +} + +DELEGATE_TO_GL_1R(createShader, CreateShader, WGC3Denum, WebGLId) + +WebGLId WebGraphicsContext3DCommandBufferBrowserImpl::createTexture() { + GLuint o; + gl_->GenTextures(1, &o); + return o; +} + +void WebGraphicsContext3DCommandBufferBrowserImpl:: + deleteBuffer(WebGLId buffer) { + gl_->DeleteBuffers(1, &buffer); +} + +void WebGraphicsContext3DCommandBufferBrowserImpl::deleteFramebuffer( + WebGLId framebuffer) { + gl_->DeleteFramebuffers(1, &framebuffer); +} + +DELEGATE_TO_GL_1(deleteProgram, DeleteProgram, WebGLId) + +void WebGraphicsContext3DCommandBufferBrowserImpl::deleteRenderbuffer( + WebGLId renderbuffer) { + gl_->DeleteRenderbuffers(1, &renderbuffer); +} + +DELEGATE_TO_GL_1(deleteShader, DeleteShader, WebGLId) + +void WebGraphicsContext3DCommandBufferBrowserImpl:: + deleteTexture(WebGLId texture) { + gl_->DeleteTextures(1, &texture); +} + +bool WebGraphicsContext3DCommandBufferBrowserImpl::ShouldUseSwapClient() { + return factory_ && factory_->IsMainThread() && swap_client_.get(); +} + +void WebGraphicsContext3DCommandBufferBrowserImpl::OnSwapBuffersComplete() { + typedef WebGraphicsContext3DSwapBuffersClient WGC3DSwapClient; + // This may be called after tear-down of the RenderView. + if (ShouldUseSwapClient()) { + base::MessageLoop::current()->PostTask( + FROM_HERE, + base::Bind(&WGC3DSwapClient::OnViewContextSwapBuffersComplete, + swap_client_)); + } + + if (swapbuffers_complete_callback_) + swapbuffers_complete_callback_->onSwapBuffersComplete(); +} + +WebGraphicsMemoryAllocation::PriorityCutoff + WebGraphicsContext3DCommandBufferBrowserImpl::WebkitPriorityCutoff( + GpuMemoryAllocationForRenderer::PriorityCutoff priorityCutoff) { + switch (priorityCutoff) { + case GpuMemoryAllocationForRenderer::kPriorityCutoffAllowNothing: + return WebGraphicsMemoryAllocation::PriorityCutoffAllowNothing; + case GpuMemoryAllocationForRenderer::kPriorityCutoffAllowOnlyRequired: + return WebGraphicsMemoryAllocation::PriorityCutoffAllowVisibleOnly; + case GpuMemoryAllocationForRenderer::kPriorityCutoffAllowNiceToHave: + return WebGraphicsMemoryAllocation::PriorityCutoffAllowVisibleAndNearby; + case GpuMemoryAllocationForRenderer::kPriorityCutoffAllowEverything: + return WebGraphicsMemoryAllocation::PriorityCutoffAllowEverything; + } + NOTREACHED(); + return WebGraphicsMemoryAllocation::PriorityCutoffAllowEverything; +} + +void WebGraphicsContext3DCommandBufferBrowserImpl::OnMemoryAllocationChanged( + WebGraphicsMemoryAllocationChangedCallbackCHROMIUM* callback, + const GpuMemoryAllocationForRenderer& allocation) { + + // Convert the gpu structure to the WebKit structure. + WebGraphicsMemoryAllocation web_allocation; + web_allocation.bytesLimitWhenVisible = + ClampUint64ToSizeT(allocation.bytes_limit_when_visible); + web_allocation.priorityCutoffWhenVisible = + WebkitPriorityCutoff(allocation.priority_cutoff_when_visible); + web_allocation.bytesLimitWhenNotVisible = + ClampUint64ToSizeT(allocation.bytes_limit_when_not_visible); + web_allocation.priorityCutoffWhenNotVisible = + WebkitPriorityCutoff(allocation.priority_cutoff_when_not_visible); + web_allocation.haveBackbufferWhenNotVisible = + allocation.have_backbuffer_when_not_visible; + + // Populate deprecated WebKit fields. These may be removed when references to + // them in WebKit are removed. + web_allocation.gpuResourceSizeInBytes = + ClampUint64ToSizeT(allocation.bytes_limit_when_visible); + web_allocation.suggestHaveBackbuffer = + allocation.have_backbuffer_when_not_visible; + + if (callback) + callback->onMemoryAllocationChanged(web_allocation); + + // We may have allocated transfer buffers in order to free GL resources in a + // backgrounded tab. Re-free the transfer buffers. + if (!visible_) + real_gl_->FreeEverything(); +} + +void WebGraphicsContext3DCommandBufferBrowserImpl::setErrorMessageCallback( + WebGraphicsContext3D::WebGraphicsErrorMessageCallback* cb) { + error_message_callback_ = cb; +} + +void WebGraphicsContext3DCommandBufferBrowserImpl::setContextLostCallback( + WebGraphicsContext3D::WebGraphicsContextLostCallback* cb) { + context_lost_callback_ = cb; +} + +WGC3Denum WebGraphicsContext3DCommandBufferBrowserImpl:: + getGraphicsResetStatusARB() { + if (IsCommandBufferContextLost() && + context_lost_reason_ == GL_NO_ERROR) { + return GL_UNKNOWN_CONTEXT_RESET_ARB; + } + + return context_lost_reason_; +} + +bool WebGraphicsContext3DCommandBufferBrowserImpl:: + IsCommandBufferContextLost() { + // If the channel shut down unexpectedly, let that supersede the + // command buffer's state. + if (host_.get() && host_->IsLost()) + return true; + gpu::CommandBuffer::State state = command_buffer_->GetLastState(); + return state.error == gpu::error::kLostContext; +} + +// static +WebGraphicsContext3DCommandBufferBrowserImpl* +WebGraphicsContext3DCommandBufferBrowserImpl::CreateOffscreenContext( + GpuChannelHostFactory* factory, + const WebGraphicsContext3D::Attributes& attributes, + const GURL& active_url) { + if (!factory) + return NULL; + base::WeakPtr null_client; + scoped_ptr context( + new WebGraphicsContext3DCommandBufferBrowserImpl( + 0, active_url, factory, null_client)); + CauseForGpuLaunch cause = + CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE; + if (context->InitializeWithDefaultBufferSizes(attributes, false, cause)) + return context.release(); + return NULL; +} + +void WebGraphicsContext3DCommandBufferBrowserImpl:: + setSwapBuffersCompleteCallbackCHROMIUM( + WebGraphicsContext3D::WebGraphicsSwapBuffersCompleteCallbackCHROMIUM* cb) { + swapbuffers_complete_callback_ = cb; +} + +DELEGATE_TO_GL_5(texImageIOSurface2DCHROMIUM, TexImageIOSurface2DCHROMIUM, + WGC3Denum, WGC3Dint, WGC3Dint, WGC3Duint, WGC3Duint) + +DELEGATE_TO_GL_5(texStorage2DEXT, TexStorage2DEXT, + WGC3Denum, WGC3Dint, WGC3Duint, WGC3Dint, WGC3Dint) + +WebGLId WebGraphicsContext3DCommandBufferBrowserImpl::createQueryEXT() { + GLuint o; + gl_->GenQueriesEXT(1, &o); + return o; +} + +void WebGraphicsContext3DCommandBufferBrowserImpl::deleteQueryEXT( + WebGLId query) { + gl_->DeleteQueriesEXT(1, &query); +} + +DELEGATE_TO_GL_1R(isQueryEXT, IsQueryEXT, WebGLId, WGC3Dboolean) +DELEGATE_TO_GL_2(beginQueryEXT, BeginQueryEXT, WGC3Denum, WebGLId) +DELEGATE_TO_GL_1(endQueryEXT, EndQueryEXT, WGC3Denum) +DELEGATE_TO_GL_3(getQueryivEXT, GetQueryivEXT, WGC3Denum, WGC3Denum, WGC3Dint*) +DELEGATE_TO_GL_3(getQueryObjectuivEXT, GetQueryObjectuivEXT, + WebGLId, WGC3Denum, WGC3Duint*) + +DELEGATE_TO_GL_6(copyTextureCHROMIUM, CopyTextureCHROMIUM, WGC3Denum, + WebGLId, WebGLId, WGC3Dint, WGC3Denum, WGC3Denum); + +DELEGATE_TO_GL_3(bindUniformLocationCHROMIUM, BindUniformLocationCHROMIUM, + WebGLId, WGC3Dint, const WGC3Dchar*) + +DELEGATE_TO_GL(shallowFlushCHROMIUM, ShallowFlushCHROMIUM); +DELEGATE_TO_GL(shallowFinishCHROMIUM, ShallowFinishCHROMIUM); + +DELEGATE_TO_GL_1(waitSyncPoint, WaitSyncPointCHROMIUM, GLuint) + +static void SignalSyncPointCallback( + scoped_ptr< + WebKit::WebGraphicsContext3D::WebGraphicsSyncPointCallback> callback) { + callback->onSyncPointReached(); +} + +void WebGraphicsContext3DCommandBufferBrowserImpl::signalSyncPoint( + unsigned sync_point, + WebGraphicsSyncPointCallback* callback) { + // Take ownership of the callback. + scoped_ptr own_callback(callback); + command_buffer_->SignalSyncPoint( + sync_point, + base::Bind(&SignalSyncPointCallback, base::Passed(&own_callback))); +} + +void WebGraphicsContext3DCommandBufferBrowserImpl::genMailboxCHROMIUM( + WGC3Dbyte* name) { + std::vector names; + if (command_buffer_->GenerateMailboxNames(1, &names)) + memcpy(name, names[0].name, GL_MAILBOX_SIZE_CHROMIUM); + else + synthesizeGLError(GL_OUT_OF_MEMORY); +} + +DELEGATE_TO_GL_2(produceTextureCHROMIUM, ProduceTextureCHROMIUM, + WGC3Denum, const WGC3Dbyte*) +DELEGATE_TO_GL_2(consumeTextureCHROMIUM, ConsumeTextureCHROMIUM, + WGC3Denum, const WGC3Dbyte*) + +void WebGraphicsContext3DCommandBufferBrowserImpl::insertEventMarkerEXT( + const WGC3Dchar* marker) { + gl_->InsertEventMarkerEXT(0, marker); +} + +void WebGraphicsContext3DCommandBufferBrowserImpl::pushGroupMarkerEXT( + const WGC3Dchar* marker) { + gl_->PushGroupMarkerEXT(0, marker); +} + +DELEGATE_TO_GL(popGroupMarkerEXT, PopGroupMarkerEXT); + +WebGLId WebGraphicsContext3DCommandBufferBrowserImpl::createVertexArrayOES() { + GLuint array; + gl_->GenVertexArraysOES(1, &array); + return array; +} + +void WebGraphicsContext3DCommandBufferBrowserImpl::deleteVertexArrayOES( + WebGLId array) { + gl_->DeleteVertexArraysOES(1, &array); +} + +DELEGATE_TO_GL_1R(isVertexArrayOES, IsVertexArrayOES, WebGLId, WGC3Dboolean) +DELEGATE_TO_GL_1(bindVertexArrayOES, BindVertexArrayOES, WebGLId) + +DELEGATE_TO_GL_2(bindTexImage2DCHROMIUM, BindTexImage2DCHROMIUM, + WGC3Denum, WGC3Dint) +DELEGATE_TO_GL_2(releaseTexImage2DCHROMIUM, ReleaseTexImage2DCHROMIUM, + WGC3Denum, WGC3Dint) + +DELEGATE_TO_GL_2R(mapBufferCHROMIUM, MapBufferCHROMIUM, WGC3Denum, WGC3Denum, + void*) +DELEGATE_TO_GL_1R(unmapBufferCHROMIUM, UnmapBufferCHROMIUM, WGC3Denum, + WGC3Dboolean) + +DELEGATE_TO_GL_9(asyncTexImage2DCHROMIUM, AsyncTexImage2DCHROMIUM, WGC3Denum, + WGC3Dint, WGC3Denum, WGC3Dsizei, WGC3Dsizei, WGC3Dint, + WGC3Denum, WGC3Denum, const void*) +DELEGATE_TO_GL_9(asyncTexSubImage2DCHROMIUM, AsyncTexSubImage2DCHROMIUM, + WGC3Denum, WGC3Dint, WGC3Dint, WGC3Dint, WGC3Dsizei, + WGC3Dsizei, WGC3Denum, WGC3Denum, const void*) + +DELEGATE_TO_GL_1(waitAsyncTexImage2DCHROMIUM, WaitAsyncTexImage2DCHROMIUM, + WGC3Denum) + +DELEGATE_TO_GL_2(drawBuffersEXT, DrawBuffersEXT, WGC3Dsizei, const WGC3Denum*) + +DELEGATE_TO_GL_4(drawArraysInstancedANGLE, DrawArraysInstancedANGLE, WGC3Denum, + WGC3Dint, WGC3Dsizei, WGC3Dsizei) + +void WebGraphicsContext3DCommandBufferBrowserImpl::drawElementsInstancedANGLE( + WGC3Denum mode, + WGC3Dsizei count, + WGC3Denum type, + WGC3Dintptr offset, + WGC3Dsizei primcount) { + gl_->DrawElementsInstancedANGLE( + mode, count, type, + reinterpret_cast(static_cast(offset)), primcount); +} + +DELEGATE_TO_GL_2(vertexAttribDivisorANGLE, VertexAttribDivisorANGLE, WGC3Duint, + WGC3Duint) + +GrGLInterface* WebGraphicsContext3DCommandBufferBrowserImpl:: + onCreateGrGLInterface() { + return webkit::gpu::CreateCommandBufferSkiaGLBinding(); +} + +namespace { + +WGC3Denum convertReason(gpu::error::ContextLostReason reason) { + switch (reason) { + case gpu::error::kGuilty: + return GL_GUILTY_CONTEXT_RESET_ARB; + case gpu::error::kInnocent: + return GL_INNOCENT_CONTEXT_RESET_ARB; + case gpu::error::kUnknown: + return GL_UNKNOWN_CONTEXT_RESET_ARB; + } + + NOTREACHED(); + return GL_UNKNOWN_CONTEXT_RESET_ARB; +} + +} // anonymous namespace + +void WebGraphicsContext3DCommandBufferBrowserImpl::OnContextLost() { + context_lost_reason_ = convertReason( + command_buffer_->GetLastState().context_lost_reason); + if (context_lost_callback_) { + context_lost_callback_->onContextLost(); + } + if (attributes_.shareResources) + ClearSharedContextsIfInShareSet(this); + if (ShouldUseSwapClient()) + swap_client_->OnViewContextSwapBuffersAborted(); +} + +void WebGraphicsContext3DCommandBufferBrowserImpl::OnErrorMessage( + const std::string& message, int id) { + if (error_message_callback_) { + WebKit::WebString str = WebKit::WebString::fromUTF8(message.c_str()); + error_message_callback_->onErrorMessage(str, id); + } +} + +} // namespace content diff --git a/content/common/gpu/client/webgraphicscontext3d_command_buffer_browser_impl.h b/content/common/gpu/client/webgraphicscontext3d_command_buffer_browser_impl.h new file mode 100644 index 0000000000000..7ebdf35b6da6a --- /dev/null +++ b/content/common/gpu/client/webgraphicscontext3d_command_buffer_browser_impl.h @@ -0,0 +1,759 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_COMMON_GPU_CLIENT_WEBGRAPHICSCONTEXT3D_COMMAND_BUFFER_BROWSER_IMPL_H_ +#define CONTENT_COMMON_GPU_CLIENT_WEBGRAPHICSCONTEXT3D_COMMAND_BUFFER_BROWSER_IMPL_H_ + +#include +#include + +#include "base/callback.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "content/common/gpu/client/command_buffer_proxy_impl.h" +#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h" +#include "content/common/gpu/gpu_process_launch_causes.h" +#include "url/gurl.h" +#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" +#include "third_party/WebKit/public/platform/WebString.h" +#include "ui/gl/gpu_preference.h" +#include "ui/gfx/native_widget_types.h" + +namespace gpu { + +class TransferBuffer; + +namespace gles2 { +class GLES2CmdHelper; +class GLES2Implementation; +class GLES2Interface; +} +} + +using WebKit::WebGLId; + +using WebKit::WGC3Dbyte; +using WebKit::WGC3Dchar; +using WebKit::WGC3Denum; +using WebKit::WGC3Dboolean; +using WebKit::WGC3Dbitfield; +using WebKit::WGC3Dint; +using WebKit::WGC3Dsizei; +using WebKit::WGC3Duint; +using WebKit::WGC3Dfloat; +using WebKit::WGC3Dclampf; +using WebKit::WGC3Dintptr; +using WebKit::WGC3Dsizeiptr; +using WebKit::WebGraphicsManagedMemoryStats; +using WebKit::WebGraphicsMemoryAllocation; + +namespace content { +class GpuChannelHost; +class GpuChannelHostFactory; +struct GpuMemoryAllocationForRenderer; + +extern const size_t kDefaultCommandBufferSize; +extern const size_t kDefaultStartTransferBufferSize; +extern const size_t kDefaultMinTransferBufferSize; +extern const size_t kDefaultMaxTransferBufferSize; + +class WebGraphicsContext3DBrowserErrorMessageCallback; + +class WebGraphicsContext3DCommandBufferBrowserImpl + : public WebKit::WebGraphicsContext3D, + public base::SupportsWeakPtr< + WebGraphicsContext3DCommandBufferBrowserImpl> { + public: + WebGraphicsContext3DCommandBufferBrowserImpl( + int surface_id, + const GURL& active_url, + GpuChannelHostFactory* factory, + const base::WeakPtr& swap_client); + + virtual ~WebGraphicsContext3DCommandBufferBrowserImpl(); + + bool Initialize(const Attributes& attributes, + bool bind_generates_resources, + CauseForGpuLaunch cause, + size_t command_buffer_size, + size_t start_transfer_buffer_size, + size_t min_transfer_buffer_size, + size_t max_transfer_buffer_size, + size_t mapped_memory_limit); + + bool InitializeWithDefaultBufferSizes(const Attributes& attributes, + bool bind_generates_resources, + CauseForGpuLaunch cause); + + // The following 3 IDs let one uniquely identify this context. + // Gets the GPU process ID for this context. + int GetGPUProcessID(); + + // Gets the channel ID for this context. + int GetChannelID(); + + // Gets the context ID (relative to the channel). + int GetContextID(); + + CommandBufferProxyImpl* GetCommandBufferProxy() { return command_buffer_; } + + gpu::gles2::GLES2Implementation* GetImplementation() { return real_gl_; } + + // Return true if GPU process reported context lost or there was a + // problem communicating with the GPU process. + bool IsCommandBufferContextLost(); + + // Create & initialize a WebGraphicsContext3DCommandBufferBrowserImpl. + // Return NULL on any failure. + static WebGraphicsContext3DCommandBufferBrowserImpl* CreateOffscreenContext( + GpuChannelHostFactory* factory, + const WebGraphicsContext3D::Attributes& attributes, + const GURL& active_url); + + //---------------------------------------------------------------------- + // WebGraphicsContext3D methods + + // Must be called after initialize() and before any of the following methods. + // Permanently binds to the first calling thread. Returns false if the + // graphics context fails to create. Do not call from more than one thread. + virtual bool makeContextCurrent(); + + virtual int width(); + virtual int height(); + + virtual unsigned int insertSyncPoint(); + virtual void waitSyncPoint(unsigned int sync_point); + virtual void signalSyncPoint(unsigned sync_point, + WebGraphicsSyncPointCallback* callback); + + virtual void reshape(int width, int height); + virtual void reshapeWithScaleFactor( + int width, int height, float scale_factor); + + virtual bool readBackFramebuffer(unsigned char* pixels, size_t buffer_size); + virtual bool readBackFramebuffer(unsigned char* pixels, size_t buffer_size, + WebGLId framebuffer, int width, int height); + + virtual void prepareTexture(); + virtual void postSubBufferCHROMIUM(int x, int y, int width, int height); + + virtual void activeTexture(WGC3Denum texture); + virtual void attachShader(WebGLId program, WebGLId shader); + virtual void bindAttribLocation(WebGLId program, WGC3Duint index, + const WGC3Dchar* name); + virtual void bindBuffer(WGC3Denum target, WebGLId buffer); + virtual void bindFramebuffer(WGC3Denum target, WebGLId framebuffer); + virtual void bindRenderbuffer(WGC3Denum target, WebGLId renderbuffer); + virtual void bindTexture(WGC3Denum target, WebGLId texture); + virtual void blendColor(WGC3Dclampf red, WGC3Dclampf green, + WGC3Dclampf blue, WGC3Dclampf alpha); + virtual void blendEquation(WGC3Denum mode); + virtual void blendEquationSeparate(WGC3Denum modeRGB, + WGC3Denum modeAlpha); + virtual void blendFunc(WGC3Denum sfactor, WGC3Denum dfactor); + virtual void blendFuncSeparate(WGC3Denum srcRGB, + WGC3Denum dstRGB, + WGC3Denum srcAlpha, + WGC3Denum dstAlpha); + + virtual void bufferData(WGC3Denum target, WGC3Dsizeiptr size, + const void* data, WGC3Denum usage); + virtual void bufferSubData(WGC3Denum target, WGC3Dintptr offset, + WGC3Dsizeiptr size, const void* data); + + virtual WGC3Denum checkFramebufferStatus(WGC3Denum target); + virtual void clear(WGC3Dbitfield mask); + virtual void clearColor(WGC3Dclampf red, WGC3Dclampf green, + WGC3Dclampf blue, WGC3Dclampf alpha); + virtual void clearDepth(WGC3Dclampf depth); + virtual void clearStencil(WGC3Dint s); + virtual void colorMask(WGC3Dboolean red, WGC3Dboolean green, + WGC3Dboolean blue, WGC3Dboolean alpha); + virtual void compileShader(WebGLId shader); + + virtual void compressedTexImage2D(WGC3Denum target, + WGC3Dint level, + WGC3Denum internalformat, + WGC3Dsizei width, + WGC3Dsizei height, + WGC3Dint border, + WGC3Dsizei imageSize, + const void* data); + virtual void compressedTexSubImage2D(WGC3Denum target, + WGC3Dint level, + WGC3Dint xoffset, + WGC3Dint yoffset, + WGC3Dsizei width, + WGC3Dsizei height, + WGC3Denum format, + WGC3Dsizei imageSize, + const void* data); + virtual void copyTexImage2D(WGC3Denum target, + WGC3Dint level, + WGC3Denum internalformat, + WGC3Dint x, + WGC3Dint y, + WGC3Dsizei width, + WGC3Dsizei height, + WGC3Dint border); + virtual void copyTexSubImage2D(WGC3Denum target, + WGC3Dint level, + WGC3Dint xoffset, + WGC3Dint yoffset, + WGC3Dint x, + WGC3Dint y, + WGC3Dsizei width, + WGC3Dsizei height); + virtual void cullFace(WGC3Denum mode); + virtual void depthFunc(WGC3Denum func); + virtual void depthMask(WGC3Dboolean flag); + virtual void depthRange(WGC3Dclampf zNear, WGC3Dclampf zFar); + virtual void detachShader(WebGLId program, WebGLId shader); + virtual void disable(WGC3Denum cap); + virtual void disableVertexAttribArray(WGC3Duint index); + virtual void drawArrays(WGC3Denum mode, WGC3Dint first, WGC3Dsizei count); + virtual void drawElements(WGC3Denum mode, + WGC3Dsizei count, + WGC3Denum type, + WGC3Dintptr offset); + + virtual void enable(WGC3Denum cap); + virtual void enableVertexAttribArray(WGC3Duint index); + virtual void finish(); + virtual void flush(); + virtual void framebufferRenderbuffer(WGC3Denum target, + WGC3Denum attachment, + WGC3Denum renderbuffertarget, + WebGLId renderbuffer); + virtual void framebufferTexture2D(WGC3Denum target, + WGC3Denum attachment, + WGC3Denum textarget, + WebGLId texture, + WGC3Dint level); + virtual void frontFace(WGC3Denum mode); + virtual void generateMipmap(WGC3Denum target); + + virtual bool getActiveAttrib(WebGLId program, + WGC3Duint index, + ActiveInfo&); + virtual bool getActiveUniform(WebGLId program, + WGC3Duint index, + ActiveInfo&); + + virtual void getAttachedShaders(WebGLId program, + WGC3Dsizei maxCount, + WGC3Dsizei* count, + WebGLId* shaders); + + virtual WGC3Dint getAttribLocation(WebGLId program, const WGC3Dchar* name); + + virtual void getBooleanv(WGC3Denum pname, WGC3Dboolean* value); + + virtual void getBufferParameteriv(WGC3Denum target, + WGC3Denum pname, + WGC3Dint* value); + + virtual Attributes getContextAttributes(); + + virtual WGC3Denum getError(); + + virtual bool isContextLost(); + + virtual void getFloatv(WGC3Denum pname, WGC3Dfloat* value); + + virtual void getFramebufferAttachmentParameteriv(WGC3Denum target, + WGC3Denum attachment, + WGC3Denum pname, + WGC3Dint* value); + + virtual void getIntegerv(WGC3Denum pname, WGC3Dint* value); + + virtual void getProgramiv(WebGLId program, WGC3Denum pname, WGC3Dint* value); + + virtual WebKit::WebString getProgramInfoLog(WebGLId program); + + virtual void getRenderbufferParameteriv(WGC3Denum target, + WGC3Denum pname, + WGC3Dint* value); + + virtual void getShaderiv(WebGLId shader, WGC3Denum pname, WGC3Dint* value); + + virtual WebKit::WebString getShaderInfoLog(WebGLId shader); + + virtual void getShaderPrecisionFormat(WGC3Denum shadertype, + WGC3Denum precisiontype, + WGC3Dint* range, + WGC3Dint* precision); + + virtual WebKit::WebString getShaderSource(WebGLId shader); + virtual WebKit::WebString getString(WGC3Denum name); + + virtual void getTexParameterfv(WGC3Denum target, + WGC3Denum pname, + WGC3Dfloat* value); + virtual void getTexParameteriv(WGC3Denum target, + WGC3Denum pname, + WGC3Dint* value); + + virtual void getUniformfv(WebGLId program, + WGC3Dint location, + WGC3Dfloat* value); + virtual void getUniformiv(WebGLId program, + WGC3Dint location, + WGC3Dint* value); + + virtual WGC3Dint getUniformLocation(WebGLId program, const WGC3Dchar* name); + + virtual void getVertexAttribfv(WGC3Duint index, WGC3Denum pname, + WGC3Dfloat* value); + virtual void getVertexAttribiv(WGC3Duint index, WGC3Denum pname, + WGC3Dint* value); + + virtual WGC3Dsizeiptr getVertexAttribOffset(WGC3Duint index, WGC3Denum pname); + + virtual void hint(WGC3Denum target, WGC3Denum mode); + virtual WGC3Dboolean isBuffer(WebGLId buffer); + virtual WGC3Dboolean isEnabled(WGC3Denum cap); + virtual WGC3Dboolean isFramebuffer(WebGLId framebuffer); + virtual WGC3Dboolean isProgram(WebGLId program); + virtual WGC3Dboolean isRenderbuffer(WebGLId renderbuffer); + virtual WGC3Dboolean isShader(WebGLId shader); + virtual WGC3Dboolean isTexture(WebGLId texture); + virtual void lineWidth(WGC3Dfloat); + virtual void linkProgram(WebGLId program); + virtual void pixelStorei(WGC3Denum pname, WGC3Dint param); + virtual void polygonOffset(WGC3Dfloat factor, WGC3Dfloat units); + + virtual void readPixels(WGC3Dint x, + WGC3Dint y, + WGC3Dsizei width, + WGC3Dsizei height, + WGC3Denum format, + WGC3Denum type, + void* pixels); + + virtual void releaseShaderCompiler(); + virtual void renderbufferStorage(WGC3Denum target, + WGC3Denum internalformat, + WGC3Dsizei width, + WGC3Dsizei height); + virtual void sampleCoverage(WGC3Dfloat value, WGC3Dboolean invert); + virtual void scissor(WGC3Dint x, WGC3Dint y, + WGC3Dsizei width, WGC3Dsizei height); + virtual void shaderSource(WebGLId shader, const WGC3Dchar* string); + virtual void stencilFunc(WGC3Denum func, WGC3Dint ref, WGC3Duint mask); + virtual void stencilFuncSeparate(WGC3Denum face, + WGC3Denum func, + WGC3Dint ref, + WGC3Duint mask); + virtual void stencilMask(WGC3Duint mask); + virtual void stencilMaskSeparate(WGC3Denum face, WGC3Duint mask); + virtual void stencilOp(WGC3Denum fail, + WGC3Denum zfail, + WGC3Denum zpass); + virtual void stencilOpSeparate(WGC3Denum face, + WGC3Denum fail, + WGC3Denum zfail, + WGC3Denum zpass); + + virtual void texImage2D(WGC3Denum target, + WGC3Dint level, + WGC3Denum internalformat, + WGC3Dsizei width, + WGC3Dsizei height, + WGC3Dint border, + WGC3Denum format, + WGC3Denum type, + const void* pixels); + + virtual void texParameterf(WGC3Denum target, + WGC3Denum pname, + WGC3Dfloat param); + virtual void texParameteri(WGC3Denum target, + WGC3Denum pname, + WGC3Dint param); + + virtual void texSubImage2D(WGC3Denum target, + WGC3Dint level, + WGC3Dint xoffset, + WGC3Dint yoffset, + WGC3Dsizei width, + WGC3Dsizei height, + WGC3Denum format, + WGC3Denum type, + const void* pixels); + + virtual void uniform1f(WGC3Dint location, WGC3Dfloat x); + virtual void uniform1fv(WGC3Dint location, + WGC3Dsizei count, const WGC3Dfloat* v); + virtual void uniform1i(WGC3Dint location, WGC3Dint x); + virtual void uniform1iv(WGC3Dint location, + WGC3Dsizei count, const WGC3Dint* v); + virtual void uniform2f(WGC3Dint location, WGC3Dfloat x, WGC3Dfloat y); + virtual void uniform2fv(WGC3Dint location, + WGC3Dsizei count, const WGC3Dfloat* v); + virtual void uniform2i(WGC3Dint location, WGC3Dint x, WGC3Dint y); + virtual void uniform2iv(WGC3Dint location, + WGC3Dsizei count, const WGC3Dint* v); + virtual void uniform3f(WGC3Dint location, + WGC3Dfloat x, WGC3Dfloat y, WGC3Dfloat z); + virtual void uniform3fv(WGC3Dint location, + WGC3Dsizei count, const WGC3Dfloat* v); + virtual void uniform3i(WGC3Dint location, + WGC3Dint x, WGC3Dint y, WGC3Dint z); + virtual void uniform3iv(WGC3Dint location, + WGC3Dsizei count, const WGC3Dint* v); + virtual void uniform4f(WGC3Dint location, + WGC3Dfloat x, WGC3Dfloat y, + WGC3Dfloat z, WGC3Dfloat w); + virtual void uniform4fv(WGC3Dint location, + WGC3Dsizei count, const WGC3Dfloat* v); + virtual void uniform4i(WGC3Dint location, + WGC3Dint x, WGC3Dint y, WGC3Dint z, WGC3Dint w); + virtual void uniform4iv(WGC3Dint location, + WGC3Dsizei count, const WGC3Dint* v); + virtual void uniformMatrix2fv(WGC3Dint location, + WGC3Dsizei count, + WGC3Dboolean transpose, + const WGC3Dfloat* value); + virtual void uniformMatrix3fv(WGC3Dint location, + WGC3Dsizei count, + WGC3Dboolean transpose, + const WGC3Dfloat* value); + virtual void uniformMatrix4fv(WGC3Dint location, + WGC3Dsizei count, + WGC3Dboolean transpose, + const WGC3Dfloat* value); + + virtual void useProgram(WebGLId program); + virtual void validateProgram(WebGLId program); + + virtual void vertexAttrib1f(WGC3Duint index, WGC3Dfloat x); + virtual void vertexAttrib1fv(WGC3Duint index, const WGC3Dfloat* values); + virtual void vertexAttrib2f(WGC3Duint index, WGC3Dfloat x, WGC3Dfloat y); + virtual void vertexAttrib2fv(WGC3Duint index, const WGC3Dfloat* values); + virtual void vertexAttrib3f(WGC3Duint index, + WGC3Dfloat x, WGC3Dfloat y, WGC3Dfloat z); + virtual void vertexAttrib3fv(WGC3Duint index, const WGC3Dfloat* values); + virtual void vertexAttrib4f(WGC3Duint index, + WGC3Dfloat x, WGC3Dfloat y, + WGC3Dfloat z, WGC3Dfloat w); + virtual void vertexAttrib4fv(WGC3Duint index, const WGC3Dfloat* values); + virtual void vertexAttribPointer(WGC3Duint index, + WGC3Dint size, + WGC3Denum type, + WGC3Dboolean normalized, + WGC3Dsizei stride, + WGC3Dintptr offset); + + virtual void viewport(WGC3Dint x, WGC3Dint y, + WGC3Dsizei width, WGC3Dsizei height); + + // Support for buffer creation and deletion + virtual WebGLId createBuffer(); + virtual WebGLId createFramebuffer(); + virtual WebGLId createProgram(); + virtual WebGLId createRenderbuffer(); + virtual WebGLId createShader(WGC3Denum); + virtual WebGLId createTexture(); + + virtual void deleteBuffer(WebGLId); + virtual void deleteFramebuffer(WebGLId); + virtual void deleteProgram(WebGLId); + virtual void deleteRenderbuffer(WebGLId); + virtual void deleteShader(WebGLId); + virtual void deleteTexture(WebGLId); + + virtual void synthesizeGLError(WGC3Denum); + + virtual void* mapBufferSubDataCHROMIUM( + WGC3Denum target, WGC3Dintptr offset, + WGC3Dsizeiptr size, WGC3Denum access); + virtual void unmapBufferSubDataCHROMIUM(const void*); + virtual void* mapTexSubImage2DCHROMIUM( + WGC3Denum target, + WGC3Dint level, + WGC3Dint xoffset, + WGC3Dint yoffset, + WGC3Dsizei width, + WGC3Dsizei height, + WGC3Denum format, + WGC3Denum type, + WGC3Denum access); + virtual void unmapTexSubImage2DCHROMIUM(const void*); + + virtual void setVisibilityCHROMIUM(bool visible); + + virtual void discardFramebufferEXT(WGC3Denum target, + WGC3Dsizei numAttachments, + const WGC3Denum* attachments); + virtual void discardBackbufferCHROMIUM(); + virtual void ensureBackbufferCHROMIUM(); + + virtual void setMemoryAllocationChangedCallbackCHROMIUM( + WebGraphicsMemoryAllocationChangedCallbackCHROMIUM* callback); + + virtual void sendManagedMemoryStatsCHROMIUM( + const WebGraphicsManagedMemoryStats* stats); + + virtual void copyTextureToParentTextureCHROMIUM( + WebGLId texture, WebGLId parentTexture); + + virtual void rateLimitOffscreenContextCHROMIUM(); + + virtual WebKit::WebString getRequestableExtensionsCHROMIUM(); + virtual void requestExtensionCHROMIUM(const char*); + + virtual void blitFramebufferCHROMIUM( + WGC3Dint srcX0, WGC3Dint srcY0, WGC3Dint srcX1, WGC3Dint srcY1, + WGC3Dint dstX0, WGC3Dint dstY0, WGC3Dint dstX1, WGC3Dint dstY1, + WGC3Dbitfield mask, WGC3Denum filter); + virtual void renderbufferStorageMultisampleCHROMIUM( + WGC3Denum target, WGC3Dsizei samples, WGC3Denum internalformat, + WGC3Dsizei width, WGC3Dsizei height); + + virtual WebKit::WebString getTranslatedShaderSourceANGLE(WebGLId shader); + + virtual void setContextLostCallback( + WebGraphicsContext3D::WebGraphicsContextLostCallback* callback); + + virtual WGC3Denum getGraphicsResetStatusARB(); + + virtual void setErrorMessageCallback( + WebGraphicsContext3D::WebGraphicsErrorMessageCallback* callback); + + virtual void setSwapBuffersCompleteCallbackCHROMIUM( + WebGraphicsContext3D:: + WebGraphicsSwapBuffersCompleteCallbackCHROMIUM* callback); + + virtual void texImageIOSurface2DCHROMIUM( + WGC3Denum target, WGC3Dint width, WGC3Dint height, + WGC3Duint ioSurfaceId, WGC3Duint plane); + + virtual void texStorage2DEXT( + WGC3Denum target, WGC3Dint levels, WGC3Duint internalformat, + WGC3Dint width, WGC3Dint height); + + virtual WebGLId createQueryEXT(); + virtual void deleteQueryEXT(WebGLId query); + virtual WGC3Dboolean isQueryEXT(WGC3Duint query); + virtual void beginQueryEXT(WGC3Denum target, WebGLId query); + virtual void endQueryEXT(WGC3Denum target); + virtual void getQueryivEXT( + WGC3Denum target, WGC3Denum pname, WGC3Dint* params); + virtual void getQueryObjectuivEXT( + WebGLId query, WGC3Denum pname, WGC3Duint* params); + + virtual void copyTextureCHROMIUM(WGC3Denum target, WebGLId source_id, + WebGLId dest_id, WGC3Dint level, + WGC3Denum internal_format, + WGC3Denum dest_type); + + virtual void bindUniformLocationCHROMIUM(WebGLId program, WGC3Dint location, + const WGC3Dchar* uniform); + + virtual void shallowFlushCHROMIUM(); + virtual void shallowFinishCHROMIUM(); + + virtual void genMailboxCHROMIUM(WGC3Dbyte* mailbox); + virtual void produceTextureCHROMIUM(WGC3Denum target, + const WGC3Dbyte* mailbox); + virtual void consumeTextureCHROMIUM(WGC3Denum target, + const WGC3Dbyte* mailbox); + + virtual void insertEventMarkerEXT(const WGC3Dchar* marker); + virtual void pushGroupMarkerEXT(const WGC3Dchar* marker); + virtual void popGroupMarkerEXT(); + + // GL_OES_vertex_array_object + virtual WebGLId createVertexArrayOES(); + virtual void deleteVertexArrayOES(WebGLId array); + virtual WGC3Dboolean isVertexArrayOES(WebGLId array); + virtual void bindVertexArrayOES(WebGLId array); + + virtual void bindTexImage2DCHROMIUM(WGC3Denum target, WGC3Dint image_id); + virtual void releaseTexImage2DCHROMIUM(WGC3Denum target, WGC3Dint image_id); + + virtual WebGLId createStreamTextureCHROMIUM(WebGLId texture); + virtual void destroyStreamTextureCHROMIUM(WebGLId texture); + + virtual void* mapBufferCHROMIUM(WGC3Denum target, WGC3Denum access); + virtual WGC3Dboolean unmapBufferCHROMIUM(WGC3Denum target); + + // Async pixel transfer functions. + virtual void asyncTexImage2DCHROMIUM( + WGC3Denum target, + WGC3Dint level, + WGC3Denum internalformat, + WGC3Dsizei width, + WGC3Dsizei height, + WGC3Dint border, + WGC3Denum format, + WGC3Denum type, + const void* pixels); + virtual void asyncTexSubImage2DCHROMIUM( + WGC3Denum target, + WGC3Dint level, + WGC3Dint xoffset, + WGC3Dint yoffset, + WGC3Dsizei width, + WGC3Dsizei height, + WGC3Denum format, + WGC3Denum type, + const void* pixels); + virtual void waitAsyncTexImage2DCHROMIUM(WGC3Denum target); + + // GL_EXT_draw_buffers + virtual void drawBuffersEXT( + WGC3Dsizei n, + const WGC3Denum* bufs); + + // GL_ANGLE_instanced_arrays + virtual void drawArraysInstancedANGLE(WGC3Denum mode, WGC3Dint first, + WGC3Dsizei count, WGC3Dsizei primcount); + virtual void drawElementsInstancedANGLE(WGC3Denum mode, WGC3Dsizei count, + WGC3Denum type, WGC3Dintptr offset, WGC3Dsizei primcount); + virtual void vertexAttribDivisorANGLE(WGC3Duint index, WGC3Duint divisor); + + protected: + virtual GrGLInterface* onCreateGrGLInterface(); + + private: + // These are the same error codes as used by EGL. + enum Error { + SUCCESS = 0x3000, + BAD_ATTRIBUTE = 0x3004, + CONTEXT_LOST = 0x300E + }; + // WebGraphicsContext3DCommandBufferBrowserImpl configuration attributes. + // Those in the 16-bit range are the same as used by EGL. Those outside the + // 16-bit range are unique to Chromium. Attributes are matched using a closest + // fit algorithm. + enum Attribute { + ALPHA_SIZE = 0x3021, + BLUE_SIZE = 0x3022, + GREEN_SIZE = 0x3023, + RED_SIZE = 0x3024, + DEPTH_SIZE = 0x3025, + STENCIL_SIZE = 0x3026, + SAMPLES = 0x3031, + SAMPLE_BUFFERS = 0x3032, + HEIGHT = 0x3056, + WIDTH = 0x3057, + NONE = 0x3038, // Attrib list = terminator + SHARE_RESOURCES = 0x10000, + BIND_GENERATES_RESOURCES = 0x10001 + }; + friend class WebGraphicsContext3DBrowserErrorMessageCallback; + + // Initialize the underlying GL context. May be called multiple times; second + // and subsequent calls are ignored. Must be called from the thread that is + // going to use this object to issue GL commands (which might not be the main + // thread). + bool MaybeInitializeGL(const char* allowed_extensions); + + bool InitializeCommandBuffer( + bool onscreen, + const char* allowed_extensions); + + void Destroy(); + + // Create a CommandBufferProxy that renders directly to a view. The view and + // the associated window must not be destroyed until the returned + // CommandBufferProxy has been destroyed, otherwise the GPU process might + // attempt to render to an invalid window handle. + // + // NOTE: on Mac OS X, this entry point is only used to set up the + // accelerated compositor's output. On this platform, we actually pass + // a gfx::PluginWindowHandle in place of the gfx::NativeViewId, + // because the facility to allocate a fake PluginWindowHandle is + // already in place. We could add more entry points and messages to + // allocate both fake PluginWindowHandles and NativeViewIds and map + // from fake NativeViewIds to PluginWindowHandles, but this seems like + // unnecessary complexity at the moment. + bool CreateContext(bool onscreen, + const char* allowed_extensions); + + // SwapBuffers callback. + void OnSwapBuffersComplete(); + virtual void OnContextLost(); + virtual void OnErrorMessage(const std::string& message, int id); + + // Check if we should call into the swap client. We can only do that on the + // main thread. + bool ShouldUseSwapClient(); + + // MemoryAllocationChanged callback. + void OnMemoryAllocationChanged( + WebGraphicsMemoryAllocationChangedCallbackCHROMIUM* callback, + const GpuMemoryAllocationForRenderer& allocation); + + // Convert the gpu cutoff enum to the WebKit enum. + static WebGraphicsMemoryAllocation::PriorityCutoff WebkitPriorityCutoff( + GpuMemoryAllocationForRenderer::PriorityCutoff priorityCutoff); + + bool initialize_failed_; + + // The channel factory to talk to the GPU process + GpuChannelHostFactory* factory_; + + bool visible_; + bool free_command_buffer_when_invisible_; + + // State needed by MaybeInitializeGL. + scoped_refptr host_; + int32 surface_id_; + GURL active_url_; + base::WeakPtr swap_client_; + + WebGraphicsContext3D::WebGraphicsContextLostCallback* context_lost_callback_; + WGC3Denum context_lost_reason_; + + WebGraphicsContext3D::WebGraphicsErrorMessageCallback* + error_message_callback_; + scoped_ptr + client_error_message_callback_; + + WebGraphicsContext3D::WebGraphicsSwapBuffersCompleteCallbackCHROMIUM* + swapbuffers_complete_callback_; + + WebKit::WebGraphicsContext3D::Attributes attributes_; + gfx::GpuPreference gpu_preference_; + int cached_width_, cached_height_; + + // For tracking which FBO is bound. + WebGLId bound_fbo_; + + // Errors raised by synthesizeGLError(). + std::vector synthetic_errors_; + + base::WeakPtrFactory + weak_ptr_factory_; + + std::vector scanline_; + void FlipVertically(uint8* framebuffer, + unsigned int width, + unsigned int height); + + bool initialized_; + CommandBufferProxyImpl* command_buffer_; + gpu::gles2::GLES2CmdHelper* gles2_helper_; + gpu::TransferBuffer* transfer_buffer_; + gpu::gles2::GLES2Interface* gl_; + gpu::gles2::GLES2Implementation* real_gl_; + gpu::gles2::GLES2Interface* trace_gl_; + Error last_error_; + int frame_number_; + bool bind_generates_resources_; + bool use_echo_for_swap_ack_; + size_t command_buffer_size_; + size_t start_transfer_buffer_size_; + size_t min_transfer_buffer_size_; + size_t max_transfer_buffer_size_; + size_t mapped_memory_limit_; +}; + +} // namespace content + +#endif // CONTENT_COMMON_GPU_CLIENT_WEBGRAPHICSCONTEXT3D_COMMAND_BUFFER_BROWSER_IMPL_H_ diff --git a/content/content_common.gypi b/content/content_common.gypi index 8c455744e2676..bc232fc8e14d6 100644 --- a/content/content_common.gypi +++ b/content/content_common.gypi @@ -185,16 +185,22 @@ 'common/gpu/client/context_provider_command_buffer.h', 'common/gpu/client/gl_helper.cc', 'common/gpu/client/gl_helper.h', + 'common/gpu/client/gl_helper_browser.cc', + 'common/gpu/client/gl_helper_browser.h', 'common/gpu/client/gl_helper_scaling.cc', 'common/gpu/client/gl_helper_scaling.h', 'common/gpu/client/gl_surface_capturer_host.cc', 'common/gpu/client/gl_surface_capturer_host.h', + 'common/gpu/client/gl_helper_scaling_browser.cc', + 'common/gpu/client/gl_helper_scaling_browser.h', 'common/gpu/client/gpu_channel_host.cc', 'common/gpu/client/gpu_channel_host.h', 'common/gpu/client/gpu_video_decode_accelerator_host.cc', 'common/gpu/client/gpu_video_decode_accelerator_host.h', 'common/gpu/client/gpu_video_encode_accelerator_host.cc', 'common/gpu/client/gpu_video_encode_accelerator_host.h', + 'common/gpu/client/webgraphicscontext3d_command_buffer_browser_impl.cc', + 'common/gpu/client/webgraphicscontext3d_command_buffer_browser_impl.h', 'common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc', 'common/gpu/client/webgraphicscontext3d_command_buffer_impl.h', 'common/gpu/gpu_channel.cc',