diff options
author | kbr@google.com <kbr@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-27 00:23:34 +0000 |
---|---|---|
committer | kbr@google.com <kbr@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-27 00:23:34 +0000 |
commit | 3bf4d53ecb0a07e8639b4403997cddb6869ebc61 (patch) | |
tree | 5283f1b9733ecab92f0b2875110a4194c1ee41e0 /chrome | |
parent | 6f4926b7834dfaf506957b02dd80e6004489824e (diff) | |
download | chromium_src-3bf4d53ecb0a07e8639b4403997cddb6869ebc61.zip chromium_src-3bf4d53ecb0a07e8639b4403997cddb6869ebc61.tar.gz chromium_src-3bf4d53ecb0a07e8639b4403997cddb6869ebc61.tar.bz2 |
Added command buffer implementation of WebGL which runs in the sandbox.
Added synchronous initialization of the channel to the GPU process, needed
to obey WebGL startup semantics. There are problems with this on the
Windows platform which will be addressed via refactoring in the
GpuProcessHost in a subsequent CL. Implemented offscreen rendering code
path in GGL / GLES2CmdDecoder for Mac OS X.
This new code path is not yet complete for all platforms and is still being
stress tested. The previous in-process WebGL implementation is currently
used when the sandbox is disabled; it will be removed in a subsequent CL.
A one-line code change in WebKit is needed after this CL lands to enable
the new code path.
BUG=29120
TEST=ran WebGL demos on command buffer implementation on Mac
Review URL: http://codereview.chromium.org/1328001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@42879 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/gpu_process_host.cc | 39 | ||||
-rw-r--r-- | chrome/browser/gpu_process_host.h | 8 | ||||
-rw-r--r-- | chrome/browser/renderer_host/browser_render_process_host.cc | 8 | ||||
-rw-r--r-- | chrome/browser/renderer_host/browser_render_process_host.h | 5 | ||||
-rwxr-xr-x | chrome/chrome_renderer.gypi | 2 | ||||
-rw-r--r-- | chrome/common/gpu_messages_internal.h | 13 | ||||
-rw-r--r-- | chrome/common/render_messages_internal.h | 5 | ||||
-rw-r--r-- | chrome/common/sandbox_init_wrapper_mac.cc | 3 | ||||
-rw-r--r-- | chrome/gpu/gpu_thread.cc | 6 | ||||
-rw-r--r-- | chrome/gpu/gpu_thread.h | 1 | ||||
-rw-r--r-- | chrome/renderer/ggl/ggl.cc | 2 | ||||
-rw-r--r-- | chrome/renderer/render_thread.cc | 8 | ||||
-rw-r--r-- | chrome/renderer/render_thread.h | 6 | ||||
-rw-r--r-- | chrome/renderer/renderer_webkitclient_impl.cc | 19 | ||||
-rw-r--r-- | chrome/renderer/renderer_webkitclient_impl.h | 2 | ||||
-rw-r--r-- | chrome/renderer/webgraphicscontext3d_command_buffer_impl.cc | 878 | ||||
-rw-r--r-- | chrome/renderer/webgraphicscontext3d_command_buffer_impl.h | 352 |
17 files changed, 1353 insertions, 4 deletions
diff --git a/chrome/browser/gpu_process_host.cc b/chrome/browser/gpu_process_host.cc index 9fa0092..9981133 100644 --- a/chrome/browser/gpu_process_host.cc +++ b/chrome/browser/gpu_process_host.cc @@ -62,6 +62,10 @@ GpuProcessHost::GpuProcessHost() : last_routing_id_(1) { } GpuProcessHost::~GpuProcessHost() { + while (!queued_synchronization_replies_.empty()) { + delete queued_synchronization_replies_.front(); + queued_synchronization_replies_.pop(); + } } // static @@ -133,9 +137,25 @@ void GpuProcessHost::EstablishGpuChannel(int renderer_id) { ReplyToRenderer(renderer_id, IPC::ChannelHandle()); } +void GpuProcessHost::Synchronize(int renderer_id, IPC::Message* reply) { + // ************ + // TODO(kbr): the handling of this synchronous message (which is + // needed for proper initialization semantics of APIs like WebGL) is + // currently broken on Windows because the renderer is sending a + // synchronous message to the browser's UI thread. To fix this, the + // GpuProcessHost needs to move to the IO thread, and any backing + // store handling needs to remain on the UI thread in a new + // GpuProcessHostProxy, where work is sent from the IO thread to the + // UI thread via PostTask. + // ************ + queued_synchronization_replies_.push(reply); + CHECK(Send(new GpuMsg_Synchronize(renderer_id))); +} + void GpuProcessHost::OnControlMessageReceived(const IPC::Message& message) { IPC_BEGIN_MESSAGE_MAP(GpuProcessHost, message) IPC_MESSAGE_HANDLER(GpuHostMsg_ChannelEstablished, OnChannelEstablished) + IPC_MESSAGE_HANDLER(GpuHostMsg_SynchronizeReply, OnSynchronizeReply) IPC_MESSAGE_UNHANDLED_ERROR() IPC_END_MESSAGE_MAP() } @@ -148,6 +168,17 @@ void GpuProcessHost::OnChannelEstablished( sent_requests_.pop(); } +void GpuProcessHost::OnSynchronizeReply(int renderer_id) { + IPC::Message* reply = queued_synchronization_replies_.front(); + queued_synchronization_replies_.pop(); + RenderProcessHost* process_host = RenderProcessHost::FromID(renderer_id); + if (!process_host) { + delete reply; + return; + } + CHECK(process_host->Send(reply)); +} + void GpuProcessHost::ReplyToRenderer( int renderer_id, const IPC::ChannelHandle& channel) { @@ -156,7 +187,13 @@ void GpuProcessHost::ReplyToRenderer( if (!process_host) return; - CHECK(process_host->Send(new ViewMsg_GpuChannelEstablished(channel))); + ViewMsg_GpuChannelEstablished* msg = + new ViewMsg_GpuChannelEstablished(channel); + // If the renderer process is performing synchronous initialization, + // it needs to handle this message before receiving the reply for + // the synchronous ViewHostMsg_SynchronizeGpu message. + msg->set_unblock(true); + CHECK(process_host->Send(msg)); } void GpuProcessHost::PropagateBrowserCommandLineToGpu( diff --git a/chrome/browser/gpu_process_host.h b/chrome/browser/gpu_process_host.h index 4d74e00..27d3fe3 100644 --- a/chrome/browser/gpu_process_host.h +++ b/chrome/browser/gpu_process_host.h @@ -53,6 +53,10 @@ class GpuProcessHost : public IPC::Channel::Sender, // on completion. void EstablishGpuChannel(int renderer_id); + // Sends a reply message later when the next GpuHostMsg_SynchronizeReply comes + // in. + void Synchronize(int renderer_id, IPC::Message* reply); + private: friend struct DefaultSingletonTraits<GpuProcessHost>; @@ -74,6 +78,7 @@ class GpuProcessHost : public IPC::Channel::Sender, // Message handlers. void OnChannelEstablished(const IPC::ChannelHandle& channel_handle); + void OnSynchronizeReply(int renderer_id); void ReplyToRenderer(int renderer_id, const IPC::ChannelHandle& channel); @@ -104,6 +109,9 @@ class GpuProcessHost : public IPC::Channel::Sender, // because the queued messages may have dependencies on the init messages. std::queue<IPC::Message*> queued_messages_; + // The pending synchronization requests we need to reply to. + std::queue<IPC::Message*> queued_synchronization_replies_; + DISALLOW_COPY_AND_ASSIGN(GpuProcessHost); }; diff --git a/chrome/browser/renderer_host/browser_render_process_host.cc b/chrome/browser/renderer_host/browser_render_process_host.cc index dccc34d..1fc8ffa 100644 --- a/chrome/browser/renderer_host/browser_render_process_host.cc +++ b/chrome/browser/renderer_host/browser_render_process_host.cc @@ -773,7 +773,9 @@ void BrowserRenderProcessHost::OnMessageReceived(const IPC::Message& msg) { IPC_MESSAGE_HANDLER(ViewHostMsg_ExtensionCloseChannel, OnExtensionCloseChannel) IPC_MESSAGE_HANDLER(ViewHostMsg_EstablishGpuChannel, - OnMsgEstablishGpuChannel) + OnMsgEstablishGpuChannel) + IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_SynchronizeGpu, + OnMsgSynchronizeGpu) IPC_MESSAGE_HANDLER(ViewHostMsg_SpellChecker_RequestDictionary, OnSpellCheckerRequestDictionary) IPC_MESSAGE_UNHANDLED_ERROR() @@ -982,6 +984,10 @@ void BrowserRenderProcessHost::OnMsgEstablishGpuChannel() { GpuProcessHost::Get()->EstablishGpuChannel(id()); } +void BrowserRenderProcessHost::OnMsgSynchronizeGpu(IPC::Message* reply) { + GpuProcessHost::Get()->Synchronize(id(), reply); +} + void BrowserRenderProcessHost::OnSpellCheckerRequestDictionary() { if (profile()->GetSpellCheckHost()) { // The spellchecker initialization already started and finished; just send diff --git a/chrome/browser/renderer_host/browser_render_process_host.h b/chrome/browser/renderer_host/browser_render_process_host.h index 372045a..9a9c833 100644 --- a/chrome/browser/renderer_host/browser_render_process_host.h +++ b/chrome/browser/renderer_host/browser_render_process_host.h @@ -110,7 +110,12 @@ class BrowserRenderProcessHost : public RenderProcessHost, void OnExtensionAddListener(const std::string& event_name); void OnExtensionRemoveListener(const std::string& event_name); void OnExtensionCloseChannel(int port_id); + // Renderer process is requesting that the browser process establish a GPU + // channel. void OnMsgEstablishGpuChannel(); + // Renderer process is requesting that outstanding asynchronous GPU-related + // messages are processed. + void OnMsgSynchronizeGpu(IPC::Message* reply); // Initialize support for visited links. Send the renderer process its initial // set of visited links. diff --git a/chrome/chrome_renderer.gypi b/chrome/chrome_renderer.gypi index 67df617..abf5eb7 100755 --- a/chrome/chrome_renderer.gypi +++ b/chrome/chrome_renderer.gypi @@ -161,6 +161,8 @@ 'renderer/user_script_slave.h', 'renderer/visitedlink_slave.cc', 'renderer/visitedlink_slave.h', + 'renderer/webgraphicscontext3d_command_buffer_impl.cc', + 'renderer/webgraphicscontext3d_command_buffer_impl.h', 'renderer/webplugin_delegate_proxy.cc', 'renderer/webplugin_delegate_proxy.h', 'renderer/webplugin_delegate_pepper.cc', diff --git a/chrome/common/gpu_messages_internal.h b/chrome/common/gpu_messages_internal.h index 9107aed..628671d 100644 --- a/chrome/common/gpu_messages_internal.h +++ b/chrome/common/gpu_messages_internal.h @@ -26,6 +26,14 @@ IPC_BEGIN_MESSAGES(Gpu) IPC_MESSAGE_CONTROL1(GpuMsg_EstablishChannel, int /* renderer_id */) + // Provides a synchronization point to guarantee that the processing of + // previous asynchronous messages (i.e., GpuMsg_EstablishChannel) has + // completed. (This message can't be synchronous because the + // GpuProcessHost uses an IPC::ChannelProxy, which sends all messages + // asynchronously.) Results in a GpuHostMsg_SynchronizeReply. + IPC_MESSAGE_CONTROL1(GpuMsg_Synchronize, + int /* renderer_id */) + IPC_MESSAGE_CONTROL2(GpuMsg_NewRenderWidgetHostView, GpuNativeWindowHandle, /* parent window */ int32 /* view_id */) @@ -90,6 +98,11 @@ IPC_BEGIN_MESSAGES(GpuHost) // Response to a GpuHostMsg_EstablishChannel message. IPC_MESSAGE_CONTROL1(GpuHostMsg_ChannelEstablished, IPC::ChannelHandle /* channel_handle */) + + // Response to a GpuMsg_Synchronize message. + IPC_MESSAGE_CONTROL1(GpuHostMsg_SynchronizeReply, + int /* renderer_id */) + IPC_END_MESSAGES(GpuHost) //------------------------------------------------------------------------------ diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index 0372a49..c06da08 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -1342,6 +1342,11 @@ IPC_BEGIN_MESSAGES(ViewHost) // a GpuChannelEstablished message. IPC_MESSAGE_CONTROL0(ViewHostMsg_EstablishGpuChannel) + // A renderer sends this to the browser process to provide a synchronization + // point for GPU operations, in particular to make sure the GPU channel has + // been established. + IPC_SYNC_MESSAGE_CONTROL0_0(ViewHostMsg_SynchronizeGpu) + // A renderer sends this to the browser process when it wants to start // a new instance of the Native Client process. The browser will launch // the process and return a handle to an IMC channel. diff --git a/chrome/common/sandbox_init_wrapper_mac.cc b/chrome/common/sandbox_init_wrapper_mac.cc index a47240d..898faed 100644 --- a/chrome/common/sandbox_init_wrapper_mac.cc +++ b/chrome/common/sandbox_init_wrapper_mac.cc @@ -41,7 +41,8 @@ bool SandboxInitWrapper::InitializeSandbox(const CommandLine& command_line, sandbox_process_type = sandbox::SANDBOX_TYPE_WORKER; } else if ((process_type == switches::kNaClLoaderProcess) || (process_type == switches::kPluginProcess) || - (process_type == switches::kProfileImportProcess)) { + (process_type == switches::kProfileImportProcess) || + (process_type == switches::kGpuProcess)) { return true; } else { // Failsafe: If you hit an unreached here, is your new process type in need diff --git a/chrome/gpu/gpu_thread.cc b/chrome/gpu/gpu_thread.cc index 9de441c..5e096a5 100644 --- a/chrome/gpu/gpu_thread.cc +++ b/chrome/gpu/gpu_thread.cc @@ -40,6 +40,8 @@ void GpuThread::OnControlMessageReceived(const IPC::Message& msg) { IPC_BEGIN_MESSAGE_MAP_EX(GpuThread, msg, msg_is_ok) IPC_MESSAGE_HANDLER(GpuMsg_EstablishChannel, OnEstablishChannel) + IPC_MESSAGE_HANDLER(GpuMsg_Synchronize, + OnSynchronize) IPC_MESSAGE_HANDLER(GpuMsg_NewRenderWidgetHostView, OnNewRenderWidgetHostView) IPC_END_MESSAGE_MAP_EX() @@ -79,6 +81,10 @@ void GpuThread::OnEstablishChannel(int renderer_id) { Send(new GpuHostMsg_ChannelEstablished(channel_handle)); } +void GpuThread::OnSynchronize(int renderer_id) { + Send(new GpuHostMsg_SynchronizeReply(renderer_id)); +} + void GpuThread::OnNewRenderWidgetHostView(GpuNativeWindowHandle parent_window, int32 routing_id) { // The GPUView class' lifetime is controlled by the host, which will send a diff --git a/chrome/gpu/gpu_thread.h b/chrome/gpu/gpu_thread.h index 23b8ba1..bc06051 100644 --- a/chrome/gpu/gpu_thread.h +++ b/chrome/gpu/gpu_thread.h @@ -36,6 +36,7 @@ class GpuThread : public ChildThread { // Message handlers. void OnEstablishChannel(int renderer_id); + void OnSynchronize(int renderer_id); void OnNewRenderWidgetHostView(GpuNativeWindowHandle parent_window, int32 routing_id); diff --git a/chrome/renderer/ggl/ggl.cc b/chrome/renderer/ggl/ggl.cc index 2c41126..8973dda 100644 --- a/chrome/renderer/ggl/ggl.cc +++ b/chrome/renderer/ggl/ggl.cc @@ -27,6 +27,8 @@ namespace ggl { namespace { const int32 kCommandBufferSize = 1024 * 1024; +// TODO(kbr): make the transfer buffer size configurable via context +// creation attributes. const int32 kTransferBufferSize = 1024 * 1024; base::ThreadLocalPointer<Context> g_current_context; diff --git a/chrome/renderer/render_thread.cc b/chrome/renderer/render_thread.cc index 4fb0971..aff8fa6 100644 --- a/chrome/renderer/render_thread.cc +++ b/chrome/renderer/render_thread.cc @@ -703,6 +703,14 @@ void RenderThread::EstablishGpuChannel() { Send(new ViewHostMsg_EstablishGpuChannel()); } +GpuChannelHost* RenderThread::EstablishGpuChannelSync() { + EstablishGpuChannel(); + Send(new ViewHostMsg_SynchronizeGpu()); + // TODO(kbr): the GPU channel is still in the unconnected state at this point. + // Need to figure out whether it is really safe to return it. + return gpu_channel_.get(); +} + GpuChannelHost* RenderThread::GetGpuChannel() { if (!gpu_channel_.get()) return NULL; diff --git a/chrome/renderer/render_thread.h b/chrome/renderer/render_thread.h index 3caed00..b774672 100644 --- a/chrome/renderer/render_thread.h +++ b/chrome/renderer/render_thread.h @@ -172,6 +172,12 @@ class RenderThread : public RenderThreadBase, // Use GetGpuChannel() to determine when the channel is ready for use. void EstablishGpuChannel(); + // Synchronously establish a channel to the GPU plugin if not previously + // established or if it has been lost (for example if the GPU plugin crashed). + // If there is a pending asynchronous request, it will be completed by the + // time this routine returns. + GpuChannelHost* EstablishGpuChannelSync(); + // Get the GPU channel. Returns NULL if the channel is not established or // has been lost. GpuChannelHost* GetGpuChannel(); diff --git a/chrome/renderer/renderer_webkitclient_impl.cc b/chrome/renderer/renderer_webkitclient_impl.cc index 1f6736f..33698c5 100644 --- a/chrome/renderer/renderer_webkitclient_impl.cc +++ b/chrome/renderer/renderer_webkitclient_impl.cc @@ -24,8 +24,10 @@ #include "chrome/renderer/render_view.h" #include "chrome/renderer/renderer_webstoragenamespace_impl.h" #include "chrome/renderer/visitedlink_slave.h" +#include "chrome/renderer/webgraphicscontext3d_command_buffer_impl.h" #include "googleurl/src/gurl.h" #include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" +#include "third_party/WebKit/WebKit/chromium/public/WebGraphicsContext3D.h" #include "third_party/WebKit/WebKit/chromium/public/WebStorageEventDispatcher.h" #include "third_party/WebKit/WebKit/chromium/public/WebString.h" #include "third_party/WebKit/WebKit/chromium/public/WebURL.h" @@ -339,6 +341,23 @@ RendererWebKitClientImpl::sharedWorkerRepository() { } } +WebKit::WebGraphicsContext3D* +RendererWebKitClientImpl::createGraphicsContext3D() { + // TODO(kbr): remove the WebGraphicsContext3D::createDefault code path + // completely, and at least for a period of time, either pop up a warning + // dialog, or don't even start the browser, if WebGL is enabled and the + // sandbox isn't. + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoSandbox)) { + return WebKit::WebGraphicsContext3D::createDefault(); + } else { +#if defined(ENABLE_GPU) + return new WebGraphicsContext3DCommandBufferImpl(); +#else + return NULL; +#endif + } +} + //------------------------------------------------------------------------------ WebKit::WebString RendererWebKitClientImpl::signedPublicKeyAndChallengeString( diff --git a/chrome/renderer/renderer_webkitclient_impl.h b/chrome/renderer/renderer_webkitclient_impl.h index f041851..b9232d2 100644 --- a/chrome/renderer/renderer_webkitclient_impl.h +++ b/chrome/renderer/renderer_webkitclient_impl.h @@ -66,8 +66,8 @@ class RendererWebKitClientImpl : public webkit_glue::WebKitClientImpl { const WebKit::WebURL& url); virtual WebKit::WebApplicationCacheHost* createApplicationCacheHost( WebKit::WebApplicationCacheHostClient*); - virtual WebKit::WebSharedWorkerRepository* sharedWorkerRepository(); + virtual WebKit::WebGraphicsContext3D* createGraphicsContext3D(); private: class MimeRegistry : public webkit_glue::SimpleWebMimeRegistryImpl { diff --git a/chrome/renderer/webgraphicscontext3d_command_buffer_impl.cc b/chrome/renderer/webgraphicscontext3d_command_buffer_impl.cc new file mode 100644 index 0000000..af76cb0 --- /dev/null +++ b/chrome/renderer/webgraphicscontext3d_command_buffer_impl.cc @@ -0,0 +1,878 @@ +// Copyright (c) 2010 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. + +#if defined(ENABLE_GPU) + +#include "chrome/renderer/webgraphicscontext3d_command_buffer_impl.h" + +#include <GLES2/gl2.h> + +#include <algorithm> + +#include "base/logging.h" +#include "chrome/renderer/gpu_channel_host.h" +#include "chrome/renderer/render_thread.h" + +// TODO(kbr): OpenGL may return multiple errors from sequential calls +// to glGetError. +static void checkGLError() { + GLenum error = glGetError(); + if (error) { + DLOG(ERROR) << "GL Error " << error; + } +} + +WebGraphicsContext3DCommandBufferImpl::WebGraphicsContext3DCommandBufferImpl() + : context_(NULL), + texture_(0), + fbo_(0), + depth_buffer_(0), + cached_width_(0), + cached_height_(0), + bound_fbo_(0) { +} + +WebGraphicsContext3DCommandBufferImpl:: + ~WebGraphicsContext3DCommandBufferImpl() { + if (context_) { + ggl::DestroyContext(context_); + } +} + +bool WebGraphicsContext3DCommandBufferImpl::initialize( + WebGraphicsContext3D::Attributes attributes) { + RenderThread* render_thread = RenderThread::current(); + if (!render_thread) + return false; + GpuChannelHost* host = render_thread->EstablishGpuChannelSync(); + if (!host) + return false; + DCHECK(host->ready()); + context_ = ggl::CreateOffscreenContext(host, NULL, gfx::Size(1, 1)); + if (!context_) + return false; + return true; +} + +bool WebGraphicsContext3DCommandBufferImpl::makeContextCurrent() { + return ggl::MakeCurrent(context_); +} + +int WebGraphicsContext3DCommandBufferImpl::width() { + return cached_width_; +} + +int WebGraphicsContext3DCommandBufferImpl::height() { + return cached_height_; +} + +int WebGraphicsContext3DCommandBufferImpl::sizeInBytes(int type) { + switch (type) { + case GL_BYTE: + return sizeof(GLbyte); + case GL_UNSIGNED_BYTE: + return sizeof(GLubyte); + case GL_SHORT: + return sizeof(GLshort); + case GL_UNSIGNED_SHORT: + return sizeof(GLushort); + case GL_INT: + return sizeof(GLint); + case GL_UNSIGNED_INT: + return sizeof(GLuint); + case GL_FLOAT: + return sizeof(GLfloat); + } + return 0; +} + +static int createTextureObject(GLenum target) { + GLuint texture = 0; + glGenTextures(1, &texture); + checkGLError(); + glBindTexture(target, texture); + checkGLError(); + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + checkGLError(); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + checkGLError(); + return texture; +} + +void WebGraphicsContext3DCommandBufferImpl::reshape(int width, int height) { + cached_width_ = width; + cached_height_ = height; + makeContextCurrent(); + + checkGLError(); + + GLenum target = GL_TEXTURE_2D; + + // TODO(kbr): switch this code to use the default back buffer of + // GGL / the GLES2 command buffer code. + + // TODO(kbr): determine whether we need to hack in + // GL_TEXTURE_RECTANGLE_ARB support for Mac OS X -- or resize the + // framebuffer objects to the next largest power of two. + + if (!texture_) { + // Generate the texture object + texture_ = createTextureObject(target); + // Generate the framebuffer object + glGenFramebuffers(1, &fbo_); + checkGLError(); + // Generate the depth buffer + glGenRenderbuffers(1, &depth_buffer_); + checkGLError(); + } + + // Reallocate the color and depth buffers + glBindTexture(target, texture_); + checkGLError(); + glTexImage2D(target, 0, GL_RGBA, width, height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, 0); + checkGLError(); + glBindTexture(target, 0); + checkGLError(); + + glBindFramebuffer(GL_FRAMEBUFFER, fbo_); + checkGLError(); + bound_fbo_ = fbo_; + glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer_); + checkGLError(); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, + width, height); + checkGLError(); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + checkGLError(); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + target, texture_, 0); + checkGLError(); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, depth_buffer_); + checkGLError(); + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + checkGLError(); + if (status != GL_FRAMEBUFFER_COMPLETE) { + DLOG(ERROR) << "WebGraphicsContext3DCommandBufferImpl: " + << "framebuffer was incomplete"; + + // TODO(kbr): cleanup. + NOTIMPLEMENTED(); + } + +#ifdef FLIP_FRAMEBUFFER_VERTICALLY + scanline_.reset(new uint8[width * 4]); +#endif // FLIP_FRAMEBUFFER_VERTICALLY + + glClear(GL_COLOR_BUFFER_BIT); + checkGLError(); +} + +#ifdef FLIP_FRAMEBUFFER_VERTICALLY +void WebGraphicsContext3DCommandBufferImpl::FlipVertically( + uint8* framebuffer, + unsigned int width, + unsigned int height) { + uint8* scanline = scanline_.get(); + if (!scanline) + return; + 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); + } +} +#endif + +bool WebGraphicsContext3DCommandBufferImpl::readBackFramebuffer( + unsigned char* pixels, + size_t buffer_size) { + if (buffer_size != static_cast<size_t>(4 * width() * height())) { + return false; + } + + makeContextCurrent(); + + // 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_ != fbo_); + if (mustRestoreFBO) + glBindFramebuffer(GL_FRAMEBUFFER, fbo_); + glReadPixels(0, 0, cached_width_, cached_height_, + GL_RGBA, GL_UNSIGNED_BYTE, pixels); + + // Swizzle red and blue channels + // TODO(kbr): expose GL_BGRA as extension + for (size_t i = 0; i < buffer_size; i += 4) { + std::swap(pixels[i], pixels[i + 2]); + } + + if (mustRestoreFBO) { + glBindFramebuffer(GL_FRAMEBUFFER, bound_fbo_); + } + +#ifdef FLIP_FRAMEBUFFER_VERTICALLY + if (pixels) { + FlipVertically(pixels, cached_width_, cached_height_); + } +#endif + + return true; +} + +void WebGraphicsContext3DCommandBufferImpl::synthesizeGLError( + unsigned long error) { + if (find(synthetic_errors_.begin(), synthetic_errors_.end(), error) == + synthetic_errors_.end()) { + synthetic_errors_.push_back(error); + } +} + +// Helper macros to reduce the amount of code. + +#define DELEGATE_TO_GL(name, glname) \ +void WebGraphicsContext3DCommandBufferImpl::name() { \ + makeContextCurrent(); \ + gl##glname(); \ +} + +#define DELEGATE_TO_GL_1(name, glname, t1) \ +void WebGraphicsContext3DCommandBufferImpl::name(t1 a1) { \ + makeContextCurrent(); \ + gl##glname(a1); \ +} + +#define DELEGATE_TO_GL_1_C(name, glname, t1) \ +void WebGraphicsContext3DCommandBufferImpl::name(t1 a1) { \ + makeContextCurrent(); \ + gl##glname(static_cast<GLclampf>(a1)); \ +} + +#define DELEGATE_TO_GL_1R(name, glname, t1, rt) \ +rt WebGraphicsContext3DCommandBufferImpl::name(t1 a1) { \ + makeContextCurrent(); \ + return gl##glname(a1); \ +} + +#define DELEGATE_TO_GL_1RB(name, glname, t1, rt) \ +rt WebGraphicsContext3DCommandBufferImpl::name(t1 a1) { \ + makeContextCurrent(); \ + return gl##glname(a1) ? true : false; \ +} + +#define DELEGATE_TO_GL_2(name, glname, t1, t2) \ +void WebGraphicsContext3DCommandBufferImpl::name(t1 a1, t2 a2) { \ + makeContextCurrent(); \ + gl##glname(a1, a2); \ +} + +#define DELEGATE_TO_GL_2_C1(name, glname, t1, t2) \ +void WebGraphicsContext3DCommandBufferImpl::name(t1 a1, t2 a2) { \ + makeContextCurrent(); \ + gl##glname(static_cast<GLclampf>(a1), a2); \ +} + +#define DELEGATE_TO_GL_2_C12(name, glname, t1, t2) \ +void WebGraphicsContext3DCommandBufferImpl::name(t1 a1, t2 a2) { \ + makeContextCurrent(); \ + gl##glname(static_cast<GLclampf>(a1), static_cast<GLclampf>(a2)); \ +} + +#define DELEGATE_TO_GL_2R(name, glname, t1, t2, rt) \ +rt WebGraphicsContext3DCommandBufferImpl::name(t1 a1, t2 a2) { \ + makeContextCurrent(); \ + return gl##glname(a1, a2); \ +} + +#define DELEGATE_TO_GL_3(name, glname, t1, t2, t3) \ +void WebGraphicsContext3DCommandBufferImpl::name(t1 a1, t2 a2, t3 a3) { \ + makeContextCurrent(); \ + gl##glname(a1, a2, a3); \ +} + +#define DELEGATE_TO_GL_4(name, glname, t1, t2, t3, t4) \ +void WebGraphicsContext3DCommandBufferImpl::name(t1 a1, t2 a2, t3 a3, t4 a4) { \ + makeContextCurrent(); \ + gl##glname(a1, a2, a3, a4); \ +} + +#define DELEGATE_TO_GL_4_C1234(name, glname, t1, t2, t3, t4) \ +void WebGraphicsContext3DCommandBufferImpl::name(t1 a1, t2 a2, t3 a3, t4 a4) { \ + makeContextCurrent(); \ + gl##glname(static_cast<GLclampf>(a1), static_cast<GLclampf>(a2), \ + static_cast<GLclampf>(a3), static_cast<GLclampf>(a4)); \ +} + +#define DELEGATE_TO_GL_5(name, glname, t1, t2, t3, t4, t5) \ +void WebGraphicsContext3DCommandBufferImpl::name(t1 a1, t2 a2, t3 a3, \ + t4 a4, t5 a5) { \ + makeContextCurrent(); \ + gl##glname(a1, a2, a3, a4, a5); \ +} + +#define DELEGATE_TO_GL_6(name, glname, t1, t2, t3, t4, t5, t6) \ +void WebGraphicsContext3DCommandBufferImpl::name(t1 a1, t2 a2, t3 a3, \ + t4 a4, t5 a5, t6 a6) { \ + makeContextCurrent(); \ + gl##glname(a1, a2, a3, a4, a5, a6); \ +} + +#define DELEGATE_TO_GL_7(name, glname, t1, t2, t3, t4, t5, t6, t7) \ +void WebGraphicsContext3DCommandBufferImpl::name(t1 a1, t2 a2, t3 a3, \ + t4 a4, t5 a5, t6 a6, t7 a7) { \ + makeContextCurrent(); \ + 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 WebGraphicsContext3DCommandBufferImpl::name(t1 a1, t2 a2, t3 a3, \ + t4 a4, t5 a5, t6 a6, \ + t7 a7, t8 a8) { \ + makeContextCurrent(); \ + 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 WebGraphicsContext3DCommandBufferImpl::name(t1 a1, t2 a2, t3 a3, \ + t4 a4, t5 a5, t6 a6, \ + t7 a7, t8 a8, t9 a9) { \ + makeContextCurrent(); \ + gl##glname(a1, a2, a3, a4, a5, a6, a7, a8, a9); \ +} + +DELEGATE_TO_GL_1(activeTexture, ActiveTexture, unsigned long) + +DELEGATE_TO_GL_2(attachShader, AttachShader, WebGLId, WebGLId) + +DELEGATE_TO_GL_3(bindAttribLocation, BindAttribLocation, WebGLId, + unsigned long, const char*) + +DELEGATE_TO_GL_2(bindBuffer, BindBuffer, unsigned long, WebGLId) + +void WebGraphicsContext3DCommandBufferImpl::bindFramebuffer( + unsigned long target, + WebGLId framebuffer) { + makeContextCurrent(); + if (!framebuffer) + framebuffer = fbo_; + glBindFramebuffer(target, framebuffer); + bound_fbo_ = framebuffer; +} + +DELEGATE_TO_GL_2(bindRenderbuffer, BindRenderbuffer, unsigned long, WebGLId) + +DELEGATE_TO_GL_2(bindTexture, BindTexture, unsigned long, WebGLId) + +DELEGATE_TO_GL_4_C1234(blendColor, BlendColor, double, double, double, double) + +DELEGATE_TO_GL_1(blendEquation, BlendEquation, unsigned long) + +DELEGATE_TO_GL_2(blendEquationSeparate, BlendEquationSeparate, + unsigned long, unsigned long) + +DELEGATE_TO_GL_2(blendFunc, BlendFunc, unsigned long, unsigned long) + +DELEGATE_TO_GL_4(blendFuncSeparate, BlendFuncSeparate, + unsigned long, unsigned long, unsigned long, unsigned long) + +DELEGATE_TO_GL_4(bufferData, BufferData, + unsigned long, int, const void*, unsigned long) + +DELEGATE_TO_GL_4(bufferSubData, BufferSubData, + unsigned long, long, int, const void*) + +DELEGATE_TO_GL_1R(checkFramebufferStatus, CheckFramebufferStatus, + unsigned long, unsigned long) + +DELEGATE_TO_GL_1(clear, Clear, unsigned long) + +DELEGATE_TO_GL_4_C1234(clearColor, ClearColor, double, double, double, double) + +DELEGATE_TO_GL_1_C(clearDepth, ClearDepthf, double) + +DELEGATE_TO_GL_1(clearStencil, ClearStencil, long) + +DELEGATE_TO_GL_4(colorMask, ColorMask, bool, bool, bool, bool) + +DELEGATE_TO_GL_1(compileShader, CompileShader, WebGLId) + +DELEGATE_TO_GL_8(copyTexImage2D, CopyTexImage2D, + unsigned long, long, unsigned long, long, long, + unsigned long, unsigned long, long) + +DELEGATE_TO_GL_8(copyTexSubImage2D, CopyTexSubImage2D, + unsigned long, long, long, long, long, long, + unsigned long, unsigned long) + +DELEGATE_TO_GL_1(cullFace, CullFace, unsigned long) + +DELEGATE_TO_GL_1(depthFunc, DepthFunc, unsigned long) + +DELEGATE_TO_GL_1(depthMask, DepthMask, bool) + +DELEGATE_TO_GL_2_C12(depthRange, DepthRangef, double, double) + +DELEGATE_TO_GL_2(detachShader, DetachShader, WebGLId, WebGLId) + +DELEGATE_TO_GL_1(disable, Disable, unsigned long) + +DELEGATE_TO_GL_1(disableVertexAttribArray, DisableVertexAttribArray, + unsigned long) + +DELEGATE_TO_GL_3(drawArrays, DrawArrays, unsigned long, long, long) + +void WebGraphicsContext3DCommandBufferImpl::drawElements(unsigned long mode, + unsigned long count, + unsigned long type, + long offset) { + makeContextCurrent(); + glDrawElements(mode, count, type, + reinterpret_cast<void*>(static_cast<intptr_t>(offset))); +} + +DELEGATE_TO_GL_1(enable, Enable, unsigned long) + +DELEGATE_TO_GL_1(enableVertexAttribArray, EnableVertexAttribArray, + unsigned long) + +DELEGATE_TO_GL(finish, Finish) + +DELEGATE_TO_GL(flush, Flush) + +DELEGATE_TO_GL_4(framebufferRenderbuffer, FramebufferRenderbuffer, + unsigned long, unsigned long, unsigned long, WebGLId) + +DELEGATE_TO_GL_5(framebufferTexture2D, FramebufferTexture2D, + unsigned long, unsigned long, unsigned long, WebGLId, long) + +DELEGATE_TO_GL_1(frontFace, FrontFace, unsigned long) + +DELEGATE_TO_GL_1(generateMipmap, GenerateMipmap, unsigned long) + +bool WebGraphicsContext3DCommandBufferImpl::getActiveAttrib( + WebGLId program, unsigned long index, ActiveInfo& info) { + if (!program) { + synthesizeGLError(GL_INVALID_VALUE); + return false; + } + GLint max_name_length = -1; + glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_name_length); + if (max_name_length < 0) + return false; + scoped_array<GLchar> name(new GLchar[max_name_length]); + if (!name.get()) { + synthesizeGLError(GL_OUT_OF_MEMORY); + return false; + } + GLsizei length = 0; + GLint size = -1; + GLenum type = 0; + glGetActiveAttrib(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 WebGraphicsContext3DCommandBufferImpl::getActiveUniform( + WebGLId program, unsigned long index, ActiveInfo& info) { + GLint max_name_length = -1; + glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_name_length); + if (max_name_length < 0) + return false; + scoped_array<GLchar> name(new GLchar[max_name_length]); + if (!name.get()) { + synthesizeGLError(GL_OUT_OF_MEMORY); + return false; + } + GLsizei length = 0; + GLint size = -1; + GLenum type = 0; + glGetActiveUniform(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_2R(getAttribLocation, GetAttribLocation, + WebGLId, const char*, int) + +DELEGATE_TO_GL_2(getBooleanv, GetBooleanv, unsigned long, unsigned char*) + +DELEGATE_TO_GL_3(getBufferParameteriv, GetBufferParameteriv, + unsigned long, unsigned long, int*) + +WebKit::WebGraphicsContext3D::Attributes +WebGraphicsContext3DCommandBufferImpl::getContextAttributes() { + return attributes_; +} + +unsigned long WebGraphicsContext3DCommandBufferImpl::getError() { + if (synthetic_errors_.size() > 0) { + std::vector<unsigned long>::iterator iter = synthetic_errors_.begin(); + unsigned long err = *iter; + synthetic_errors_.erase(iter); + return err; + } + + makeContextCurrent(); + return glGetError(); +} + +DELEGATE_TO_GL_2(getFloatv, GetFloatv, unsigned long, float*) + +DELEGATE_TO_GL_4(getFramebufferAttachmentParameteriv, + GetFramebufferAttachmentParameteriv, + unsigned long, unsigned long, unsigned long, int*) + +DELEGATE_TO_GL_2(getIntegerv, GetIntegerv, unsigned long, int*) + +DELEGATE_TO_GL_3(getProgramiv, GetProgramiv, WebGLId, unsigned long, int*) + +WebKit::WebString WebGraphicsContext3DCommandBufferImpl::getProgramInfoLog( + WebGLId program) { + makeContextCurrent(); + GLint logLength; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength); + if (!logLength) + return WebKit::WebString(); + scoped_array<GLchar> log(new GLchar[logLength]); + if (!log.get()) + return WebKit::WebString(); + GLsizei returnedLogLength; + glGetProgramInfoLog(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, + unsigned long, unsigned long, int*) + +DELEGATE_TO_GL_3(getShaderiv, GetShaderiv, WebGLId, unsigned long, int*) + +WebKit::WebString WebGraphicsContext3DCommandBufferImpl::getShaderInfoLog( + WebGLId shader) { + makeContextCurrent(); + GLint logLength; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength); + if (!logLength) + return WebKit::WebString(); + scoped_array<GLchar> log(new GLchar[logLength]); + if (!log.get()) + return WebKit::WebString(); + GLsizei returnedLogLength; + glGetShaderInfoLog(shader, logLength, &returnedLogLength, log.get()); + DCHECK_EQ(logLength, returnedLogLength + 1); + WebKit::WebString res = + WebKit::WebString::fromUTF8(log.get(), returnedLogLength); + return res; +} + +WebKit::WebString WebGraphicsContext3DCommandBufferImpl::getShaderSource( + WebGLId shader) { + makeContextCurrent(); + GLint logLength; + glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &logLength); + if (!logLength) + return WebKit::WebString(); + scoped_array<GLchar> log(new GLchar[logLength]); + if (!log.get()) + return WebKit::WebString(); + GLsizei returnedLogLength; + glGetShaderSource(shader, logLength, &returnedLogLength, log.get()); + DCHECK_EQ(logLength, returnedLogLength + 1); + WebKit::WebString res = + WebKit::WebString::fromUTF8(log.get(), returnedLogLength); + return res; +} + +WebKit::WebString WebGraphicsContext3DCommandBufferImpl::getString( + unsigned long name) { + makeContextCurrent(); + return WebKit::WebString::fromUTF8( + reinterpret_cast<const char*>(glGetString(name))); +} + +DELEGATE_TO_GL_3(getTexParameterfv, GetTexParameterfv, + unsigned long, unsigned long, float*) + +DELEGATE_TO_GL_3(getTexParameteriv, GetTexParameteriv, + unsigned long, unsigned long, int*) + +DELEGATE_TO_GL_3(getUniformfv, GetUniformfv, WebGLId, long, float*) + +DELEGATE_TO_GL_3(getUniformiv, GetUniformiv, WebGLId, long, int*) + +DELEGATE_TO_GL_2R(getUniformLocation, GetUniformLocation, + WebGLId, const char*, long) + +DELEGATE_TO_GL_3(getVertexAttribfv, GetVertexAttribfv, + unsigned long, unsigned long, float*) + +DELEGATE_TO_GL_3(getVertexAttribiv, GetVertexAttribiv, + unsigned long, unsigned long, int*) + +long WebGraphicsContext3DCommandBufferImpl::getVertexAttribOffset( + unsigned long index, unsigned long pname) { + // TODO(kbr): implement. + NOTIMPLEMENTED(); + return 0; +} + +DELEGATE_TO_GL_2(hint, Hint, unsigned long, unsigned long) + +DELEGATE_TO_GL_1RB(isBuffer, IsBuffer, WebGLId, bool) + +DELEGATE_TO_GL_1RB(isEnabled, IsEnabled, unsigned long, bool) + +DELEGATE_TO_GL_1RB(isFramebuffer, IsFramebuffer, WebGLId, bool) + +DELEGATE_TO_GL_1RB(isProgram, IsProgram, WebGLId, bool) + +DELEGATE_TO_GL_1RB(isRenderbuffer, IsRenderbuffer, WebGLId, bool) + +DELEGATE_TO_GL_1RB(isShader, IsShader, WebGLId, bool) + +DELEGATE_TO_GL_1RB(isTexture, IsTexture, WebGLId, bool) + +DELEGATE_TO_GL_1_C(lineWidth, LineWidth, double) + +DELEGATE_TO_GL_1(linkProgram, LinkProgram, WebGLId) + +DELEGATE_TO_GL_2(pixelStorei, PixelStorei, unsigned long, long) + +DELEGATE_TO_GL_2_C12(polygonOffset, PolygonOffset, double, double) + +DELEGATE_TO_GL_7(readPixels, ReadPixels, + long, long, unsigned long, unsigned long, unsigned long, + unsigned long, void*) + +void WebGraphicsContext3DCommandBufferImpl::releaseShaderCompiler() { +} + +DELEGATE_TO_GL_4(renderbufferStorage, RenderbufferStorage, + unsigned long, unsigned long, unsigned long, unsigned long) + +DELEGATE_TO_GL_2_C1(sampleCoverage, SampleCoverage, double, bool) + +DELEGATE_TO_GL_4(scissor, Scissor, long, long, unsigned long, unsigned long) + +void WebGraphicsContext3DCommandBufferImpl::shaderSource( + WebGLId shader, const char* string) { + makeContextCurrent(); + GLint length = strlen(string); + glShaderSource(shader, 1, &string, &length); +} + +DELEGATE_TO_GL_3(stencilFunc, StencilFunc, unsigned long, long, unsigned long) + +DELEGATE_TO_GL_4(stencilFuncSeparate, StencilFuncSeparate, + unsigned long, unsigned long, long, unsigned long) + +DELEGATE_TO_GL_1(stencilMask, StencilMask, unsigned long) + +DELEGATE_TO_GL_2(stencilMaskSeparate, StencilMaskSeparate, + unsigned long, unsigned long) + +DELEGATE_TO_GL_3(stencilOp, StencilOp, + unsigned long, unsigned long, unsigned long) + +DELEGATE_TO_GL_4(stencilOpSeparate, StencilOpSeparate, + unsigned long, unsigned long, unsigned long, unsigned long) + +DELEGATE_TO_GL_9(texImage2D, TexImage2D, + unsigned, unsigned, unsigned, unsigned, unsigned, unsigned, + unsigned, unsigned, const void*) + +DELEGATE_TO_GL_3(texParameterf, TexParameterf, unsigned, unsigned, float); + +static const unsigned int kTextureWrapR = 0x8072; + +void WebGraphicsContext3DCommandBufferImpl::texParameteri( + unsigned target, unsigned pname, int 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; + } + makeContextCurrent(); + glTexParameteri(target, pname, param); +} + +DELEGATE_TO_GL_9(texSubImage2D, TexSubImage2D, + unsigned, unsigned, unsigned, unsigned, unsigned, unsigned, + unsigned, unsigned, const void*) + +DELEGATE_TO_GL_2(uniform1f, Uniform1f, long, float) + +DELEGATE_TO_GL_3(uniform1fv, Uniform1fv, long, int, float*) + +DELEGATE_TO_GL_2(uniform1i, Uniform1i, long, int) + +DELEGATE_TO_GL_3(uniform1iv, Uniform1iv, long, int, int*) + +DELEGATE_TO_GL_3(uniform2f, Uniform2f, long, float, float) + +DELEGATE_TO_GL_3(uniform2fv, Uniform2fv, long, int, float*) + +DELEGATE_TO_GL_3(uniform2i, Uniform2i, long, int, int) + +DELEGATE_TO_GL_3(uniform2iv, Uniform2iv, long, int, int*) + +DELEGATE_TO_GL_4(uniform3f, Uniform3f, long, float, float, float) + +DELEGATE_TO_GL_3(uniform3fv, Uniform3fv, long, int, float*) + +DELEGATE_TO_GL_4(uniform3i, Uniform3i, long, int, int, int) + +DELEGATE_TO_GL_3(uniform3iv, Uniform3iv, long, int, int*) + +DELEGATE_TO_GL_5(uniform4f, Uniform4f, long, float, float, float, float) + +DELEGATE_TO_GL_3(uniform4fv, Uniform4fv, long, int, float*) + +DELEGATE_TO_GL_5(uniform4i, Uniform4i, long, int, int, int, int) + +DELEGATE_TO_GL_3(uniform4iv, Uniform4iv, long, int, int*) + +DELEGATE_TO_GL_4(uniformMatrix2fv, UniformMatrix2fv, + long, int, bool, const float*) + +DELEGATE_TO_GL_4(uniformMatrix3fv, UniformMatrix3fv, + long, int, bool, const float*) + +DELEGATE_TO_GL_4(uniformMatrix4fv, UniformMatrix4fv, + long, int, bool, const float*) + +DELEGATE_TO_GL_1(useProgram, UseProgram, WebGLId) + +DELEGATE_TO_GL_1(validateProgram, ValidateProgram, WebGLId) + +DELEGATE_TO_GL_2(vertexAttrib1f, VertexAttrib1f, unsigned long, float) + +DELEGATE_TO_GL_2(vertexAttrib1fv, VertexAttrib1fv, unsigned long, const float*) + +DELEGATE_TO_GL_3(vertexAttrib2f, VertexAttrib2f, unsigned long, float, float) + +DELEGATE_TO_GL_2(vertexAttrib2fv, VertexAttrib2fv, unsigned long, const float*) + +DELEGATE_TO_GL_4(vertexAttrib3f, VertexAttrib3f, + unsigned long, float, float, float) + +DELEGATE_TO_GL_2(vertexAttrib3fv, VertexAttrib3fv, unsigned long, const float*) + +DELEGATE_TO_GL_5(vertexAttrib4f, VertexAttrib4f, + unsigned long, float, float, float, float) + +DELEGATE_TO_GL_2(vertexAttrib4fv, VertexAttrib4fv, unsigned long, const float*) + +void WebGraphicsContext3DCommandBufferImpl::vertexAttribPointer( + unsigned long indx, int size, int type, bool normalized, + unsigned long stride, unsigned long offset) { + makeContextCurrent(); + + glVertexAttribPointer(indx, size, type, normalized, stride, + reinterpret_cast<void*>( + static_cast<intptr_t>(offset))); +} + +DELEGATE_TO_GL_4(viewport, Viewport, long, long, unsigned long, unsigned long) + +unsigned WebGraphicsContext3DCommandBufferImpl::createBuffer() { + makeContextCurrent(); + GLuint o; + glGenBuffers(1, &o); + return o; +} + +unsigned WebGraphicsContext3DCommandBufferImpl::createFramebuffer() { + makeContextCurrent(); + GLuint o = 0; + glGenFramebuffers(1, &o); + return o; +} + +unsigned WebGraphicsContext3DCommandBufferImpl::createProgram() { + makeContextCurrent(); + return glCreateProgram(); +} + +unsigned WebGraphicsContext3DCommandBufferImpl::createRenderbuffer() { + makeContextCurrent(); + GLuint o; + glGenRenderbuffers(1, &o); + return o; +} + +DELEGATE_TO_GL_1R(createShader, CreateShader, unsigned long, unsigned); + +unsigned WebGraphicsContext3DCommandBufferImpl::createTexture() { + makeContextCurrent(); + GLuint o; + glGenTextures(1, &o); + return o; +} + +void WebGraphicsContext3DCommandBufferImpl::deleteBuffer(unsigned buffer) { + makeContextCurrent(); + glDeleteBuffers(1, &buffer); +} + +void WebGraphicsContext3DCommandBufferImpl::deleteFramebuffer( + unsigned framebuffer) { + makeContextCurrent(); + glDeleteFramebuffers(1, &framebuffer); +} + +void WebGraphicsContext3DCommandBufferImpl::deleteProgram(unsigned program) { + makeContextCurrent(); + glDeleteProgram(program); +} + +void WebGraphicsContext3DCommandBufferImpl::deleteRenderbuffer( + unsigned renderbuffer) { + makeContextCurrent(); + glDeleteRenderbuffers(1, &renderbuffer); +} + +void WebGraphicsContext3DCommandBufferImpl::deleteShader(unsigned shader) { + makeContextCurrent(); + glDeleteShader(shader); +} + +void WebGraphicsContext3DCommandBufferImpl::deleteTexture(unsigned texture) { + makeContextCurrent(); + glDeleteTextures(1, &texture); +} + +#endif // defined(ENABLE_GPU) + diff --git a/chrome/renderer/webgraphicscontext3d_command_buffer_impl.h b/chrome/renderer/webgraphicscontext3d_command_buffer_impl.h new file mode 100644 index 0000000..096e465 --- /dev/null +++ b/chrome/renderer/webgraphicscontext3d_command_buffer_impl.h @@ -0,0 +1,352 @@ +// Copyright (c) 2010 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 CHROME_RENDERER_WEBGRAPHICSCONTEXT3D_COMMAND_BUFFER_IMPL_H_ +#define CHROME_RENDERER_WEBGRAPHICSCONTEXT3D_COMMAND_BUFFER_IMPL_H_ + +#if defined(ENABLE_GPU) + +#include <vector> + +#include "base/scoped_ptr.h" +#include "chrome/renderer/ggl/ggl.h" +#include "third_party/WebKit/WebKit/chromium/public/WebGraphicsContext3D.h" +#include "third_party/WebKit/WebKit/chromium/public/WebString.h" + +#if !defined(OS_MACOSX) +#define FLIP_FRAMEBUFFER_VERTICALLY +#endif + +class GpuChannelHost; +class CommandBufferProxy; + +namespace gpu { +namespace gles2 { +class GLES2Implementation; +} +} + +using WebKit::WebGLId; + +class WebGraphicsContext3DCommandBufferImpl + : public WebKit::WebGraphicsContext3D { + public: + + WebGraphicsContext3DCommandBufferImpl(); + virtual ~WebGraphicsContext3DCommandBufferImpl(); + + //---------------------------------------------------------------------- + // WebGraphicsContext3D methods + virtual bool initialize(WebGraphicsContext3D::Attributes attributes); + virtual bool makeContextCurrent(); + + virtual int width(); + virtual int height(); + + virtual int sizeInBytes(int type); + + virtual void reshape(int width, int height); + + virtual bool readBackFramebuffer(unsigned char* pixels, size_t buffer_size); + + virtual void activeTexture(unsigned long texture); + virtual void attachShader(WebGLId program, WebGLId shader); + virtual void bindAttribLocation(WebGLId program, unsigned long index, + const char* name); + virtual void bindBuffer(unsigned long target, WebGLId buffer); + virtual void bindFramebuffer(unsigned long target, WebGLId framebuffer); + virtual void bindRenderbuffer(unsigned long target, WebGLId renderbuffer); + virtual void bindTexture(unsigned long target, WebGLId texture); + virtual void blendColor(double red, double green, + double blue, double alpha); + virtual void blendEquation(unsigned long mode); + virtual void blendEquationSeparate(unsigned long modeRGB, + unsigned long modeAlpha); + virtual void blendFunc(unsigned long sfactor, unsigned long dfactor); + virtual void blendFuncSeparate(unsigned long srcRGB, + unsigned long dstRGB, + unsigned long srcAlpha, + unsigned long dstAlpha); + + virtual void bufferData(unsigned long target, int size, + const void* data, unsigned long usage); + virtual void bufferSubData(unsigned long target, long offset, + int size, const void* data); + + virtual unsigned long checkFramebufferStatus(unsigned long target); + virtual void clear(unsigned long mask); + virtual void clearColor(double red, double green, + double blue, double alpha); + virtual void clearDepth(double depth); + virtual void clearStencil(long s); + virtual void colorMask(bool red, bool green, bool blue, bool alpha); + virtual void compileShader(WebGLId shader); + + virtual void copyTexImage2D(unsigned long target, + long level, + unsigned long internalformat, + long x, + long y, + unsigned long width, + unsigned long height, + long border); + virtual void copyTexSubImage2D(unsigned long target, + long level, + long xoffset, + long yoffset, + long x, + long y, + unsigned long width, + unsigned long height); + virtual void cullFace(unsigned long mode); + virtual void depthFunc(unsigned long func); + virtual void depthMask(bool flag); + virtual void depthRange(double zNear, double zFar); + virtual void detachShader(WebGLId program, WebGLId shader); + virtual void disable(unsigned long cap); + virtual void disableVertexAttribArray(unsigned long index); + virtual void drawArrays(unsigned long mode, long first, long count); + virtual void drawElements(unsigned long mode, + unsigned long count, + unsigned long type, + long offset); + + virtual void enable(unsigned long cap); + virtual void enableVertexAttribArray(unsigned long index); + virtual void finish(); + virtual void flush(); + virtual void framebufferRenderbuffer(unsigned long target, + unsigned long attachment, + unsigned long renderbuffertarget, + WebGLId renderbuffer); + virtual void framebufferTexture2D(unsigned long target, + unsigned long attachment, + unsigned long textarget, + WebGLId texture, + long level); + virtual void frontFace(unsigned long mode); + virtual void generateMipmap(unsigned long target); + + virtual bool getActiveAttrib(WebGLId program, + unsigned long index, + ActiveInfo&); + virtual bool getActiveUniform(WebGLId program, + unsigned long index, + ActiveInfo&); + + virtual int getAttribLocation(WebGLId program, const char* name); + + virtual void getBooleanv(unsigned long pname, unsigned char* value); + + virtual void getBufferParameteriv(unsigned long target, + unsigned long pname, + int* value); + + virtual Attributes getContextAttributes(); + + virtual unsigned long getError(); + + virtual void getFloatv(unsigned long pname, float* value); + + virtual void getFramebufferAttachmentParameteriv(unsigned long target, + unsigned long attachment, + unsigned long pname, + int* value); + + virtual void getIntegerv(unsigned long pname, int* value); + + virtual void getProgramiv(WebGLId program, unsigned long pname, int* value); + + virtual WebKit::WebString getProgramInfoLog(WebGLId program); + + virtual void getRenderbufferParameteriv(unsigned long target, + unsigned long pname, + int* value); + + virtual void getShaderiv(WebGLId shader, unsigned long pname, int* value); + + virtual WebKit::WebString getShaderInfoLog(WebGLId shader); + + // TBD + // void glGetShaderPrecisionFormat (GLenum shadertype, + // GLenum precisiontype, + // GLint* range, + // GLint* precision); + + virtual WebKit::WebString getShaderSource(WebGLId shader); + virtual WebKit::WebString getString(unsigned long name); + + virtual void getTexParameterfv(unsigned long target, + unsigned long pname, + float* value); + virtual void getTexParameteriv(unsigned long target, + unsigned long pname, + int* value); + + virtual void getUniformfv(WebGLId program, long location, float* value); + virtual void getUniformiv(WebGLId program, long location, int* value); + + virtual long getUniformLocation(WebGLId program, const char* name); + + virtual void getVertexAttribfv(unsigned long index, unsigned long pname, + float* value); + virtual void getVertexAttribiv(unsigned long index, unsigned long pname, + int* value); + + virtual long getVertexAttribOffset(unsigned long index, unsigned long pname); + + virtual void hint(unsigned long target, unsigned long mode); + virtual bool isBuffer(WebGLId buffer); + virtual bool isEnabled(unsigned long cap); + virtual bool isFramebuffer(WebGLId framebuffer); + virtual bool isProgram(WebGLId program); + virtual bool isRenderbuffer(WebGLId renderbuffer); + virtual bool isShader(WebGLId shader); + virtual bool isTexture(WebGLId texture); + virtual void lineWidth(double); + virtual void linkProgram(WebGLId program); + virtual void pixelStorei(unsigned long pname, long param); + virtual void polygonOffset(double factor, double units); + + virtual void readPixels(long x, + long y, + unsigned long width, + unsigned long height, + unsigned long format, + unsigned long type, + void* pixels); + + virtual void releaseShaderCompiler(); + virtual void renderbufferStorage(unsigned long target, + unsigned long internalformat, + unsigned long width, + unsigned long height); + virtual void sampleCoverage(double value, bool invert); + virtual void scissor(long x, long y, + unsigned long width, unsigned long height); + virtual void shaderSource(WebGLId shader, const char* string); + virtual void stencilFunc(unsigned long func, long ref, unsigned long mask); + virtual void stencilFuncSeparate(unsigned long face, + unsigned long func, + long ref, + unsigned long mask); + virtual void stencilMask(unsigned long mask); + virtual void stencilMaskSeparate(unsigned long face, unsigned long mask); + virtual void stencilOp(unsigned long fail, + unsigned long zfail, + unsigned long zpass); + virtual void stencilOpSeparate(unsigned long face, + unsigned long fail, + unsigned long zfail, + unsigned long zpass); + + virtual void texImage2D(unsigned target, + unsigned level, + unsigned internalformat, + unsigned width, + unsigned height, + unsigned border, + unsigned format, + unsigned type, + const void* pixels); + + virtual void texParameterf(unsigned target, unsigned pname, float param); + virtual void texParameteri(unsigned target, unsigned pname, int param); + + virtual void texSubImage2D(unsigned target, + unsigned level, + unsigned xoffset, + unsigned yoffset, + unsigned width, + unsigned height, + unsigned format, + unsigned type, + const void* pixels); + + virtual void uniform1f(long location, float x); + virtual void uniform1fv(long location, int count, float* v); + virtual void uniform1i(long location, int x); + virtual void uniform1iv(long location, int count, int* v); + virtual void uniform2f(long location, float x, float y); + virtual void uniform2fv(long location, int count, float* v); + virtual void uniform2i(long location, int x, int y); + virtual void uniform2iv(long location, int count, int* v); + virtual void uniform3f(long location, float x, float y, float z); + virtual void uniform3fv(long location, int count, float* v); + virtual void uniform3i(long location, int x, int y, int z); + virtual void uniform3iv(long location, int count, int* v); + virtual void uniform4f(long location, float x, float y, float z, float w); + virtual void uniform4fv(long location, int count, float* v); + virtual void uniform4i(long location, int x, int y, int z, int w); + virtual void uniform4iv(long location, int count, int* v); + virtual void uniformMatrix2fv(long location, int count, bool transpose, + const float* value); + virtual void uniformMatrix3fv(long location, int count, bool transpose, + const float* value); + virtual void uniformMatrix4fv(long location, int count, bool transpose, + const float* value); + + virtual void useProgram(WebGLId program); + virtual void validateProgram(WebGLId program); + + virtual void vertexAttrib1f(unsigned long indx, float x); + virtual void vertexAttrib1fv(unsigned long indx, const float* values); + virtual void vertexAttrib2f(unsigned long indx, float x, float y); + virtual void vertexAttrib2fv(unsigned long indx, const float* values); + virtual void vertexAttrib3f(unsigned long indx, float x, float y, float z); + virtual void vertexAttrib3fv(unsigned long indx, const float* values); + virtual void vertexAttrib4f(unsigned long indx, + float x, float y, float z, float w); + virtual void vertexAttrib4fv(unsigned long indx, const float* values); + virtual void vertexAttribPointer(unsigned long indx, int size, int type, + bool normalized, unsigned long stride, + unsigned long offset); + + virtual void viewport(long x, long y, + unsigned long width, unsigned long height); + + // Support for buffer creation and deletion + virtual unsigned createBuffer(); + virtual unsigned createFramebuffer(); + virtual unsigned createProgram(); + virtual unsigned createRenderbuffer(); + virtual unsigned createShader(unsigned long); + virtual unsigned createTexture(); + + virtual void deleteBuffer(unsigned); + virtual void deleteFramebuffer(unsigned); + virtual void deleteProgram(unsigned); + virtual void deleteRenderbuffer(unsigned); + virtual void deleteShader(unsigned); + virtual void deleteTexture(unsigned); + + virtual void synthesizeGLError(unsigned long error); + + private: + // The GGL context we use for OpenGL rendering. + ggl::Context* context_; + + WebKit::WebGraphicsContext3D::Attributes attributes_; + unsigned int texture_; + unsigned int fbo_; + unsigned int depth_buffer_; + int cached_width_, cached_height_; + + // For tracking which FBO is bound. + unsigned int bound_fbo_; + + // Errors raised by synthesizeGLError(). + std::vector<unsigned long> synthetic_errors_; + +#ifdef FLIP_FRAMEBUFFER_VERTICALLY + scoped_ptr<uint8> scanline_; + void FlipVertically(uint8* framebuffer, + unsigned int width, + unsigned int height); +#endif +}; + +#endif // defined(ENABLE_GPU) +#endif // CHROME_RENDERER_WEBGRAPHICSCONTEXT3D_COMMAND_BUFFER_IMPL_H_ + |