summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorapatrick@chromium.org <apatrick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-25 22:08:35 +0000
committerapatrick@chromium.org <apatrick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-25 22:08:35 +0000
commit6217d397bf501ec1ec5b7270d493006badd4d87a (patch)
treefce6c8e9c15b79bab29a9535ce9929dd9d53735b
parent21dedcc12d21ccb288244249522d77bc074c501e (diff)
downloadchromium_src-6217d397bf501ec1ec5b7270d493006badd4d87a.zip
chromium_src-6217d397bf501ec1ec5b7270d493006badd4d87a.tar.gz
chromium_src-6217d397bf501ec1ec5b7270d493006badd4d87a.tar.bz2
Calling OpenGL from the renderer process
- Added ability for renderer processes to render to a real window (Windows only so far). - Added ability to create offscreen frame buffer objects that can be resized later. - OpenGL context can have a "parent" context that can access its last swapped back buffer through a texture ID. - Moved code to establish GPU channel from RenderWidget to RenderThread. - Changed way service size command buffer object lifetimes are managed. TEST=trybot and visual verification that OpenGL can clear the browser window to magenta. BUG=none Review URL: http://codereview.chromium.org/1136006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@42679 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/gpu_process_host.cc14
-rw-r--r--chrome/browser/gpu_process_host.h12
-rw-r--r--chrome/browser/renderer_host/browser_render_process_host.cc8
-rw-r--r--chrome/browser/renderer_host/browser_render_process_host.h1
-rw-r--r--chrome/browser/renderer_host/render_widget_host.cc8
-rw-r--r--chrome/browser/renderer_host/render_widget_host.h4
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_win.cc9
-rw-r--r--chrome/common/chrome_constants.cc2
-rw-r--r--chrome/common/chrome_constants.h2
-rw-r--r--chrome/common/gpu_messages_internal.h23
-rw-r--r--chrome/common/render_messages_internal.h6
-rw-r--r--chrome/gpu/gpu_channel.cc112
-rw-r--r--chrome/gpu/gpu_channel.h32
-rw-r--r--chrome/gpu/gpu_command_buffer_stub.cc34
-rw-r--r--chrome/gpu/gpu_command_buffer_stub.h16
-rw-r--r--chrome/gpu/gpu_thread.cc24
-rw-r--r--chrome/gpu/gpu_thread.h4
-rw-r--r--chrome/plugin/command_buffer_stub.cc6
-rw-r--r--chrome/plugin/command_buffer_stub.h2
-rw-r--r--chrome/renderer/command_buffer_proxy.cc4
-rw-r--r--chrome/renderer/command_buffer_proxy.h4
-rw-r--r--chrome/renderer/ggl/ggl.cc88
-rw-r--r--chrome/renderer/ggl/ggl.h34
-rw-r--r--chrome/renderer/gpu_channel_host.cc34
-rw-r--r--chrome/renderer/gpu_channel_host.h10
-rw-r--r--chrome/renderer/render_thread.cc50
-rw-r--r--chrome/renderer/render_thread.h16
-rw-r--r--chrome/renderer/render_widget.cc46
-rw-r--r--chrome/renderer/render_widget.h15
-rwxr-xr-xgpu/command_buffer/build_gles2_cmd_buffer.py10
-rw-r--r--gpu/command_buffer/client/cmd_buffer_helper_test.cc7
-rw-r--r--gpu/command_buffer/client/fenced_allocator_test.cc7
-rw-r--r--gpu/command_buffer/client/gles2_demo.cc10
-rw-r--r--gpu/command_buffer/client/gles2_implementation.h2
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.cc727
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.h12
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_autogen.h6
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_mock.h6
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc2
-rw-r--r--gpu/command_buffer/service/gpu_processor.cc15
-rw-r--r--gpu/command_buffer/service/gpu_processor.h39
-rw-r--r--gpu/command_buffer/service/gpu_processor_linux.cc25
-rw-r--r--gpu/command_buffer/service/gpu_processor_mac.cc23
-rw-r--r--gpu/command_buffer/service/gpu_processor_unittest.cc10
-rw-r--r--gpu/command_buffer/service/gpu_processor_win.cc20
-rw-r--r--gpu/command_buffer/service/texture_manager.cc9
-rw-r--r--gpu/command_buffer/service/texture_manager.h2
-rw-r--r--gpu/demos/framework/window.cc9
-rw-r--r--gpu/gpu.gyp1
49 files changed, 1251 insertions, 311 deletions
diff --git a/chrome/browser/gpu_process_host.cc b/chrome/browser/gpu_process_host.cc
index fc10107..9fa0092 100644
--- a/chrome/browser/gpu_process_host.cc
+++ b/chrome/browser/gpu_process_host.cc
@@ -126,13 +126,11 @@ void GpuProcessHost::RemoveRoute(int32 routing_id) {
router_.RemoveRoute(routing_id);
}
-void GpuProcessHost::EstablishGpuChannel(
- int renderer_id,
- int routing_id) {
+void GpuProcessHost::EstablishGpuChannel(int renderer_id) {
if (Send(new GpuMsg_EstablishChannel(renderer_id)))
- sent_requests_.push(ChannelRequest(renderer_id, routing_id));
+ sent_requests_.push(ChannelRequest(renderer_id));
else
- ReplyToRenderer(renderer_id, routing_id, IPC::ChannelHandle());
+ ReplyToRenderer(renderer_id, IPC::ChannelHandle());
}
void GpuProcessHost::OnControlMessageReceived(const IPC::Message& message) {
@@ -146,21 +144,19 @@ void GpuProcessHost::OnChannelEstablished(
const IPC::ChannelHandle& channel_handle) {
const ChannelRequest& request = sent_requests_.front();
- ReplyToRenderer(request.renderer_id, request.routing_id, channel_handle);
+ ReplyToRenderer(request.renderer_id, channel_handle);
sent_requests_.pop();
}
void GpuProcessHost::ReplyToRenderer(
int renderer_id,
- int routing_id,
const IPC::ChannelHandle& channel) {
// Check whether the renderer process is still around.
RenderProcessHost* process_host = RenderProcessHost::FromID(renderer_id);
if (!process_host)
return;
- CHECK(process_host->Send(new ViewMsg_GpuChannelEstablished(routing_id,
- channel)));
+ CHECK(process_host->Send(new ViewMsg_GpuChannelEstablished(channel)));
}
void GpuProcessHost::PropagateBrowserCommandLineToGpu(
diff --git a/chrome/browser/gpu_process_host.h b/chrome/browser/gpu_process_host.h
index 36d068f..4d74e00 100644
--- a/chrome/browser/gpu_process_host.h
+++ b/chrome/browser/gpu_process_host.h
@@ -13,6 +13,7 @@
#include "chrome/browser/child_process_launcher.h"
#include "chrome/common/gpu_native_window_handle.h"
#include "chrome/common/message_router.h"
+#include "gfx/native_widget_types.h"
#include "ipc/ipc_channel_handle.h"
#include "ipc/ipc_channel_proxy.h"
@@ -50,26 +51,20 @@ class GpuProcessHost : public IPC::Channel::Sender,
// Tells the GPU process to create a new channel for communication with a
// renderer. Will asynchronously send message to object with given routing id
// on completion.
- void EstablishGpuChannel(int renderer_id, int routing_id);
+ void EstablishGpuChannel(int renderer_id);
private:
friend struct DefaultSingletonTraits<GpuProcessHost>;
// Used to queue pending channel requests.
struct ChannelRequest {
- ChannelRequest(int renderer_id,
- int routing_id) :
- renderer_id(renderer_id),
- routing_id(routing_id) {}
+ explicit ChannelRequest(int renderer_id) : renderer_id(renderer_id) {}
// Used to identify the renderer. The ID is used instead of a pointer to
// the RenderProcessHost in case it is destroyed while the request is
// pending.
// TODO(apatrick): investigate whether these IDs are used for future
// render processes.
int renderer_id;
-
- // Routing ID of object to receive reply message.
- int routing_id;
};
GpuProcessHost();
@@ -81,7 +76,6 @@ class GpuProcessHost : public IPC::Channel::Sender,
void OnChannelEstablished(const IPC::ChannelHandle& channel_handle);
void ReplyToRenderer(int renderer_id,
- int routing_id,
const IPC::ChannelHandle& channel);
// These are the channel requests that we have already sent to
diff --git a/chrome/browser/renderer_host/browser_render_process_host.cc b/chrome/browser/renderer_host/browser_render_process_host.cc
index 0757d17..dccc34d 100644
--- a/chrome/browser/renderer_host/browser_render_process_host.cc
+++ b/chrome/browser/renderer_host/browser_render_process_host.cc
@@ -29,6 +29,7 @@
#include "chrome/browser/extensions/extension_message_service.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/extensions/user_script_master.h"
+#include "chrome/browser/gpu_process_host.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/io_thread.h"
#include "chrome/browser/net/url_request_context_getter.h"
@@ -45,6 +46,7 @@
#include "chrome/browser/visitedlink_master.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/child_process_info.h"
+#include "chrome/common/gpu_messages.h"
#include "chrome/common/logging_chrome.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
@@ -770,6 +772,8 @@ void BrowserRenderProcessHost::OnMessageReceived(const IPC::Message& msg) {
OnExtensionRemoveListener)
IPC_MESSAGE_HANDLER(ViewHostMsg_ExtensionCloseChannel,
OnExtensionCloseChannel)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_EstablishGpuChannel,
+ OnMsgEstablishGpuChannel)
IPC_MESSAGE_HANDLER(ViewHostMsg_SpellChecker_RequestDictionary,
OnSpellCheckerRequestDictionary)
IPC_MESSAGE_UNHANDLED_ERROR()
@@ -974,6 +978,10 @@ void BrowserRenderProcessHost::OnExtensionCloseChannel(int port_id) {
}
}
+void BrowserRenderProcessHost::OnMsgEstablishGpuChannel() {
+ GpuProcessHost::Get()->EstablishGpuChannel(id());
+}
+
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 277a53e..372045a 100644
--- a/chrome/browser/renderer_host/browser_render_process_host.h
+++ b/chrome/browser/renderer_host/browser_render_process_host.h
@@ -110,6 +110,7 @@ class BrowserRenderProcessHost : public RenderProcessHost,
void OnExtensionAddListener(const std::string& event_name);
void OnExtensionRemoveListener(const std::string& event_name);
void OnExtensionCloseChannel(int port_id);
+ void OnMsgEstablishGpuChannel();
// Initialize support for visited links. Send the renderer process its initial
// set of visited links.
diff --git a/chrome/browser/renderer_host/render_widget_host.cc b/chrome/browser/renderer_host/render_widget_host.cc
index 152aae1..5dc9badc 100644
--- a/chrome/browser/renderer_host/render_widget_host.cc
+++ b/chrome/browser/renderer_host/render_widget_host.cc
@@ -8,7 +8,6 @@
#include "base/histogram.h"
#include "base/keyboard_codes.h"
#include "base/message_loop.h"
-#include "chrome/browser/gpu_process_host.h"
#include "chrome/browser/renderer_host/backing_store.h"
#include "chrome/browser/renderer_host/backing_store_manager.h"
#include "chrome/browser/renderer_host/render_process_host.h"
@@ -16,7 +15,6 @@
#include "chrome/browser/renderer_host/render_widget_host_painting_observer.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/renderer_host/video_layer.h"
-#include "chrome/common/gpu_messages.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/render_messages.h"
#include "webkit/glue/webcursor.h"
@@ -139,8 +137,6 @@ void RenderWidgetHost::OnMessageReceived(const IPC::Message &msg) {
IPC_MESSAGE_HANDLER(ViewHostMsg_FocusedNodeChanged, OnMsgFocusedNodeChanged)
IPC_MESSAGE_HANDLER(ViewHostMsg_SetCursor, OnMsgSetCursor)
IPC_MESSAGE_HANDLER(ViewHostMsg_ImeUpdateStatus, OnMsgImeUpdateStatus)
- IPC_MESSAGE_HANDLER(ViewHostMsg_EstablishGpuChannel,
- OnMsgEstablishGpuChannel)
#if defined(OS_LINUX)
IPC_MESSAGE_HANDLER(ViewHostMsg_CreatePluginContainer,
OnMsgCreatePluginContainer)
@@ -869,10 +865,6 @@ void RenderWidgetHost::OnMsgImeUpdateStatus(int control,
}
}
-void RenderWidgetHost::OnMsgEstablishGpuChannel() {
- GpuProcessHost::Get()->EstablishGpuChannel(process_->id(), routing_id_);
-}
-
#if defined(OS_LINUX)
void RenderWidgetHost::OnMsgCreatePluginContainer(gfx::PluginWindowHandle id) {
diff --git a/chrome/browser/renderer_host/render_widget_host.h b/chrome/browser/renderer_host/render_widget_host.h
index 5c95535..f8b8218 100644
--- a/chrome/browser/renderer_host/render_widget_host.h
+++ b/chrome/browser/renderer_host/render_widget_host.h
@@ -445,10 +445,6 @@ class RenderWidgetHost : public IPC::Channel::Listener,
// having to bring in render_messages.h in a header file.
void OnMsgImeUpdateStatus(int control, const gfx::Rect& caret_rect);
- // Renderer process is requesting that the browser process establish a GPU
- // channel.
- void OnMsgEstablishGpuChannel();
-
#if defined(OS_LINUX)
void OnMsgCreatePluginContainer(gfx::PluginWindowHandle id);
void OnMsgDestroyPluginContainer(gfx::PluginWindowHandle id);
diff --git a/chrome/browser/renderer_host/render_widget_host_view_win.cc b/chrome/browser/renderer_host/render_widget_host_view_win.cc
index 55e2762..2d08f42 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_win.cc
+++ b/chrome/browser/renderer_host/render_widget_host_view_win.cc
@@ -293,6 +293,15 @@ RenderWidgetHostViewWin::~RenderWidgetHostViewWin() {
void RenderWidgetHostViewWin::CreateWnd(HWND parent) {
Create(parent); // ATL function to create the window.
+
+ // Add a property indicating that a particular renderer is associated with
+ // this window. Used by the GPU process to validate window handles it
+ // receives from renderer processes.
+ int renderer_id = render_widget_host_->process()->id();
+ SetProp(m_hWnd,
+ chrome::kChromiumRendererIdProperty,
+ reinterpret_cast<HANDLE>(renderer_id));
+
// Uncommenting this will enable experimental out-of-process painting.
// Contact brettw for more,
// gpu_view_host_.reset(new GpuViewHost(render_widget_host_, m_hWnd));
diff --git a/chrome/common/chrome_constants.cc b/chrome/common/chrome_constants.cc
index 38cf59e..a6ad651 100644
--- a/chrome/common/chrome_constants.cc
+++ b/chrome/common/chrome_constants.cc
@@ -134,6 +134,8 @@ const int kHistogramSynchronizerReservedSequenceNumber = 0;
const int kMaxSessionHistoryEntries = 50;
+const wchar_t kChromiumRendererIdProperty[] = L"ChromiumRendererId";
+
} // namespace chrome
#undef FPL
diff --git a/chrome/common/chrome_constants.h b/chrome/common/chrome_constants.h
index 554a48b..456cea0 100644
--- a/chrome/common/chrome_constants.h
+++ b/chrome/common/chrome_constants.h
@@ -83,6 +83,8 @@ extern const int kHistogramSynchronizerReservedSequenceNumber;
// The maximum number of session history entries per tab.
extern const int kMaxSessionHistoryEntries;
+extern const wchar_t kChromiumRendererIdProperty[];
+
} // namespace chrome
#endif // CHROME_COMMON_CHROME_CONSTANTS_H_
diff --git a/chrome/common/gpu_messages_internal.h b/chrome/common/gpu_messages_internal.h
index 6780a5e..9107aed 100644
--- a/chrome/common/gpu_messages_internal.h
+++ b/chrome/common/gpu_messages_internal.h
@@ -9,6 +9,7 @@
// This file needs to be included again, even though we're actually included
// from it via utility_messages.h.
#include "base/shared_memory.h"
+#include "gfx/size.h"
#include "ipc/ipc_channel_handle.h"
#include "ipc/ipc_message_macros.h"
@@ -96,9 +97,21 @@ IPC_END_MESSAGES(GpuHost)
// These are messages from a renderer process to the GPU process.
IPC_BEGIN_MESSAGES(GpuChannel)
- // Tells the GPU process to create a new command buffer with the given
- // id. A corresponding GpuCommandBufferStub is created.
- IPC_SYNC_MESSAGE_CONTROL0_1(GpuChannelMsg_CreateCommandBuffer,
+ // Tells the GPU process to create a new command buffer that renders directly
+ // to a native view. A corresponding GpuCommandBufferStub is created.
+ IPC_SYNC_MESSAGE_CONTROL1_1(GpuChannelMsg_CreateViewCommandBuffer,
+ gfx::NativeViewId, /* view */
+ int32 /* route_id */)
+
+ // Tells the GPU process to create a new command buffer that renders to an
+ // offscreen frame buffer. If parent_route_id is not zero, the texture backing
+ // the frame buffer is mapped into the corresponding parent command buffer's
+ // namespace, with the name of parent_texture_id. This ID is in the parent's
+ // namespace.
+ IPC_SYNC_MESSAGE_CONTROL3_1(GpuChannelMsg_CreateOffscreenCommandBuffer,
+ int32, /* parent_route_id */
+ gfx::Size, /* size */
+ uint32, /* parent_texture_id */
int32 /* route_id */)
// The CommandBufferProxy sends this to the GpuCommandBufferStub in its
@@ -168,6 +181,10 @@ IPC_BEGIN_MESSAGES(GpuCommandBuffer)
// repainted.
IPC_MESSAGE_ROUTED0(GpuCommandBufferMsg_NotifyRepaint)
+ // Tells the GPU process to resize an offscreen frame buffer.
+ IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_ResizeOffscreenFrameBuffer,
+ gfx::Size /* size */)
+
#if defined(OS_MACOSX)
// On Mac OS X the GPU plugin must be offscreen, because there is no
// true cross-process window hierarchy. For this reason we must send
diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h
index a0f5d14..0372a49 100644
--- a/chrome/common/render_messages_internal.h
+++ b/chrome/common/render_messages_internal.h
@@ -604,8 +604,8 @@ IPC_BEGIN_MESSAGES(View)
// The browser sends this to a renderer process in response to a
// ViewHostMsg_EstablishGpuChannel message.
- IPC_MESSAGE_ROUTED1(ViewMsg_GpuChannelEstablished,
- IPC::ChannelHandle /* handle to channel */)
+ IPC_MESSAGE_CONTROL1(ViewMsg_GpuChannelEstablished,
+ IPC::ChannelHandle /* handle to channel */)
// Notifies the renderer of the appcache that has been selected for a
// a particular host. This is sent in reply to AppCacheMsg_SelectCache.
@@ -1340,7 +1340,7 @@ IPC_BEGIN_MESSAGES(ViewHost)
// create connect to the GPU. The browser will create the GPU process if
// necessary, and will return a handle to the channel via
// a GpuChannelEstablished message.
- IPC_MESSAGE_ROUTED0(ViewHostMsg_EstablishGpuChannel)
+ IPC_MESSAGE_CONTROL0(ViewHostMsg_EstablishGpuChannel)
// 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
diff --git a/chrome/gpu/gpu_channel.cc b/chrome/gpu/gpu_channel.cc
index 4269022..b2b5bf9 100644
--- a/chrome/gpu/gpu_channel.cc
+++ b/chrome/gpu/gpu_channel.cc
@@ -2,6 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
#include "chrome/gpu/gpu_channel.h"
#include "base/command_line.h"
@@ -11,6 +15,7 @@
#include "base/waitable_event.h"
#include "build/build_config.h"
#include "chrome/common/child_process.h"
+#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/gpu_messages.h"
#include "chrome/gpu/gpu_thread.h"
@@ -27,44 +32,12 @@ class GpuReleaseTask : public Task {
}
};
-typedef base::hash_map<std::string, scoped_refptr<GpuChannel> >
- GpuChannelMap;
-
// How long we wait before releasing the GPU process.
const int kGpuReleaseTimeMS = 10000;
-
-GpuChannelMap g_gpu_channels;
} // namespace anonymous
-GpuChannel* GpuChannel::EstablishGpuChannel(int renderer_id) {
- // Map renderer ID to a (single) channel to that process.
- std::string channel_name = StringPrintf(
- "%d.r%d", base::GetCurrentProcId(), renderer_id);
-
- scoped_refptr<GpuChannel> channel;
-
- GpuChannelMap::const_iterator iter = g_gpu_channels.find(channel_name);
- if (iter == g_gpu_channels.end()) {
- channel = new GpuChannel;
- } else {
- channel = iter->second;
- }
-
- DCHECK(channel != NULL);
-
- if (!channel->channel_.get()) {
- if (channel->Init(channel_name)) {
- g_gpu_channels[channel_name] = channel;
- } else {
- channel = NULL;
- }
- }
-
- return channel.get();
-}
-
-GpuChannel::GpuChannel()
- : renderer_id_(-1)
+GpuChannel::GpuChannel(int renderer_id)
+ : renderer_id_(renderer_id)
#if defined(OS_POSIX)
, renderer_fd_(-1)
#endif
@@ -141,8 +114,10 @@ bool GpuChannel::Send(IPC::Message* message) {
void GpuChannel::OnControlMessageReceived(const IPC::Message& msg) {
IPC_BEGIN_MESSAGE_MAP(GpuChannel, msg)
- IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateCommandBuffer,
- OnCreateCommandBuffer)
+ IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateViewCommandBuffer,
+ OnCreateViewCommandBuffer)
+ IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateOffscreenCommandBuffer,
+ OnCreateOffscreenCommandBuffer)
IPC_MESSAGE_HANDLER(GpuChannelMsg_DestroyCommandBuffer,
OnDestroyCommandBuffer)
IPC_MESSAGE_UNHANDLED_ERROR()
@@ -154,11 +129,57 @@ int GpuChannel::GenerateRouteID() {
return ++last_id;
}
-void GpuChannel::OnCreateCommandBuffer(int* route_id) {
+void GpuChannel::OnCreateViewCommandBuffer(gfx::NativeViewId view_id,
+ int32* route_id) {
+ *route_id = 0;
+
#if defined(ENABLE_GPU)
+
+#if defined(OS_WIN)
+ gfx::NativeView view = gfx::NativeViewFromId(view_id);
+
+ // Check that the calling renderer is allowed to render to this window.
+ // TODO(apatrick): consider killing the renderer process rather than failing.
+ int view_renderer_id = reinterpret_cast<int>(
+ GetProp(view, chrome::kChromiumRendererIdProperty));
+ if (view_renderer_id != renderer_id_)
+ return;
+#else
+ // TODO(apatrick): This needs to be something valid for mac and linux.
+ // Offscreen rendering will work on these platforms but not rendering to the
+ // window.
+ DCHECK_EQ(view_id, 0);
+ gfx::NativeView view = 0;
+#endif
+
*route_id = GenerateRouteID();
scoped_refptr<GpuCommandBufferStub> stub = new GpuCommandBufferStub(
- this, *route_id);
+ this, view, NULL, gfx::Size(), 0, *route_id);
+ router_.AddRoute(*route_id, stub);
+ stubs_[*route_id] = stub;
+#endif // ENABLE_GPU
+}
+
+void GpuChannel::OnCreateOffscreenCommandBuffer(int32 parent_route_id,
+ const gfx::Size& size,
+ uint32 parent_texture_id,
+ int32* route_id) {
+#if defined(ENABLE_GPU)
+ *route_id = GenerateRouteID();
+ scoped_refptr<GpuCommandBufferStub> parent_stub;
+ if (parent_route_id != 0) {
+ StubMap::iterator it = stubs_.find(parent_route_id);
+ DCHECK(it != stubs_.end());
+ parent_stub = it->second;
+ }
+
+ scoped_refptr<GpuCommandBufferStub> stub = new GpuCommandBufferStub(
+ this,
+ NULL,
+ parent_stub.get(),
+ size,
+ parent_texture_id,
+ *route_id);
router_.AddRoute(*route_id, stub);
stubs_[*route_id] = stub;
#else
@@ -166,7 +187,7 @@ void GpuChannel::OnCreateCommandBuffer(int* route_id) {
#endif
}
-void GpuChannel::OnDestroyCommandBuffer(int route_id) {
+void GpuChannel::OnDestroyCommandBuffer(int32 route_id) {
#if defined(ENABLE_GPU)
StubMap::iterator it = stubs_.find(route_id);
DCHECK(it != stubs_.end());
@@ -175,8 +196,13 @@ void GpuChannel::OnDestroyCommandBuffer(int route_id) {
#endif
}
-bool GpuChannel::Init(const std::string& channel_name) {
- channel_name_ = channel_name;
+bool GpuChannel::Init() {
+ // Check whether we're already initialized.
+ if (channel_.get())
+ return true;
+
+ // Map renderer ID to a (single) channel to that process.
+ std::string channel_name = GetChannelName();
#if defined(OS_POSIX)
// This gets called when the GpuChannel is initially created. At this
// point, create the socketpair and assign the GPU side FD to the channel
@@ -192,3 +218,7 @@ bool GpuChannel::Init(const std::string& channel_name) {
ChildProcess::current()->GetShutDownEvent()));
return true;
}
+
+std::string GpuChannel::GetChannelName() {
+ return StringPrintf("%d.r%d", base::GetCurrentProcId(), renderer_id_);
+}
diff --git a/chrome/gpu/gpu_channel.h b/chrome/gpu/gpu_channel.h
index 17ea363..60dc906 100644
--- a/chrome/gpu/gpu_channel.h
+++ b/chrome/gpu/gpu_channel.h
@@ -13,6 +13,8 @@
#include "build/build_config.h"
#include "chrome/common/message_router.h"
#include "chrome/gpu/gpu_command_buffer_stub.h"
+#include "gfx/native_widget_types.h"
+#include "gfx/size.h"
#include "ipc/ipc_channel.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_sync_channel.h"
@@ -23,17 +25,12 @@ class GpuChannel : public IPC::Channel::Listener,
public IPC::Message::Sender,
public base::RefCountedThreadSafe<GpuChannel> {
public:
- // Get a new GpuChannel object for the current process to talk to the
- // given renderer process. The renderer ID is an opaque unique ID generated
- // by the browser.
- //
- // POSIX only: If |channel_fd| > 0, use that file descriptor for the
- // channel socket.
- static GpuChannel* EstablishGpuChannel(int renderer_id);
-
+ explicit GpuChannel(int renderer_id);
virtual ~GpuChannel();
- std::string channel_name() const { return channel_name_; }
+ bool Init();
+
+ std::string GetChannelName();
base::ProcessHandle renderer_handle() const {
return renderer_process_.handle();
@@ -60,21 +57,20 @@ class GpuChannel : public IPC::Channel::Listener,
virtual bool Send(IPC::Message* msg);
private:
- // Called on the plugin thread
- GpuChannel();
-
- bool Init(const std::string& channel_name);
-
void OnControlMessageReceived(const IPC::Message& msg);
int GenerateRouteID();
// Message handlers.
- void OnCreateCommandBuffer(int* instance_id);
- void OnDestroyCommandBuffer(int instance_id);
+ void OnCreateViewCommandBuffer(gfx::NativeViewId view,
+ int32* route_id);
+ void OnCreateOffscreenCommandBuffer(int32 parent_route_id,
+ const gfx::Size& size,
+ uint32 parent_texture_id,
+ int32* route_id);
+ void OnDestroyCommandBuffer(int32 route_id);
scoped_ptr<IPC::SyncChannel> channel_;
- std::string channel_name_;
// Handle to the renderer process who is on the other side of the channel.
base::ScopedOpenProcess renderer_process_;
@@ -92,7 +88,7 @@ class GpuChannel : public IPC::Channel::Listener,
MessageRouter router_;
#if defined(ENABLE_GPU)
- typedef base::hash_map<int, scoped_refptr<GpuCommandBufferStub> > StubMap;
+ typedef base::hash_map<int32, scoped_refptr<GpuCommandBufferStub> > StubMap;
StubMap stubs_;
#endif
diff --git a/chrome/gpu/gpu_command_buffer_stub.cc b/chrome/gpu/gpu_command_buffer_stub.cc
index 6c3f5cc..5d6842d 100644
--- a/chrome/gpu/gpu_command_buffer_stub.cc
+++ b/chrome/gpu/gpu_command_buffer_stub.cc
@@ -6,6 +6,7 @@
#include "base/process_util.h"
#include "base/shared_memory.h"
+#include "build/build_config.h"
#include "chrome/common/gpu_messages.h"
#include "chrome/gpu/gpu_channel.h"
#include "chrome/gpu/gpu_command_buffer_stub.h"
@@ -13,12 +14,23 @@
using gpu::Buffer;
GpuCommandBufferStub::GpuCommandBufferStub(GpuChannel* channel,
+ gfx::NativeView view,
+ GpuCommandBufferStub* parent,
+ const gfx::Size& size,
+ uint32 parent_texture_id,
int32 route_id)
: channel_(channel),
+ view_(view),
+ parent_(parent),
+ initial_size_(size),
+ parent_texture_id_(parent_texture_id),
route_id_(route_id) {
}
GpuCommandBufferStub::~GpuCommandBufferStub() {
+ if (processor_.get()) {
+ processor_->Destroy();
+ }
}
void GpuCommandBufferStub::OnMessageReceived(const IPC::Message& message) {
@@ -34,6 +46,8 @@ void GpuCommandBufferStub::OnMessageReceived(const IPC::Message& message) {
OnDestroyTransferBuffer);
IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_GetTransferBuffer,
OnGetTransferBuffer);
+ IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_ResizeOffscreenFrameBuffer,
+ OnResizeOffscreenFrameBuffer);
IPC_MESSAGE_UNHANDLED_ERROR()
IPC_END_MESSAGE_MAP()
}
@@ -55,8 +69,18 @@ void GpuCommandBufferStub::OnInitialize(
if (command_buffer_->Initialize(size)) {
Buffer buffer = command_buffer_->GetRingBuffer();
if (buffer.shared_memory) {
- processor_ = new gpu::GPUProcessor(command_buffer_.get());
- if (processor_->Initialize(gfx::kNullPluginWindow)) {
+ gpu::GPUProcessor* parent_processor =
+ parent_ ? parent_->processor_.get() : NULL;
+ processor_.reset(new gpu::GPUProcessor(command_buffer_.get()));
+ // TODO(apatrick): The reinterpret_cast below is only valid on windows.
+#if !defined(OS_WIN)
+ DCHECK_EQ(view_, static_cast<gfx::NativeView>(0));
+#endif
+ if (processor_->Initialize(
+ reinterpret_cast<gfx::PluginWindowHandle>(view_),
+ parent_processor,
+ initial_size_,
+ parent_texture_id_)) {
command_buffer_->SetPutOffsetChangeCallback(
NewCallback(processor_.get(),
&gpu::GPUProcessor::ProcessCommands));
@@ -66,7 +90,7 @@ void GpuCommandBufferStub::OnInitialize(
buffer.shared_memory->ShareToProcess(channel_->renderer_handle(),
ring_buffer);
} else {
- processor_ = NULL;
+ processor_.reset();
command_buffer_.reset();
}
}
@@ -117,4 +141,8 @@ void GpuCommandBufferStub::OnGetTransferBuffer(
}
}
+void GpuCommandBufferStub::OnResizeOffscreenFrameBuffer(const gfx::Size& size) {
+ processor_->ResizeOffscreenFrameBuffer(size);
+}
+
#endif // ENABLE_GPU
diff --git a/chrome/gpu/gpu_command_buffer_stub.h b/chrome/gpu/gpu_command_buffer_stub.h
index eb927a3..7aaf68a 100644
--- a/chrome/gpu/gpu_command_buffer_stub.h
+++ b/chrome/gpu/gpu_command_buffer_stub.h
@@ -10,6 +10,7 @@
#include "base/process.h"
#include "base/ref_counted.h"
#include "gfx/native_widget_types.h"
+#include "gfx/size.h"
#include "gpu/command_buffer/service/command_buffer_service.h"
#include "gpu/command_buffer/service/gpu_processor.h"
#include "ipc/ipc_channel.h"
@@ -23,6 +24,10 @@ class GpuCommandBufferStub
public base::RefCountedThreadSafe<GpuCommandBufferStub> {
public:
GpuCommandBufferStub(GpuChannel* channel,
+ gfx::NativeView view,
+ GpuCommandBufferStub* parent,
+ const gfx::Size& size,
+ uint32 parent_texture_id,
int32 route_id);
virtual ~GpuCommandBufferStub();
@@ -33,7 +38,7 @@ class GpuCommandBufferStub
// IPC::Message::Sender implementation:
virtual bool Send(IPC::Message* msg);
- int route_id() const { return route_id_; }
+ int32 route_id() const { return route_id_; }
private:
// Message handlers:
@@ -47,12 +52,17 @@ class GpuCommandBufferStub
void OnGetTransferBuffer(int32 id,
base::SharedMemoryHandle* transfer_buffer,
uint32* size);
+ void OnResizeOffscreenFrameBuffer(const gfx::Size& size);
scoped_refptr<GpuChannel> channel_;
- int route_id_;
+ gfx::NativeView view_;
+ scoped_refptr<GpuCommandBufferStub> parent_;
+ gfx::Size initial_size_;
+ uint32 parent_texture_id_;
+ int32 route_id_;
scoped_ptr<gpu::CommandBufferService> command_buffer_;
- scoped_refptr<gpu::GPUProcessor> processor_;
+ scoped_ptr<gpu::GPUProcessor> processor_;
DISALLOW_COPY_AND_ASSIGN(GpuCommandBufferStub);
};
diff --git a/chrome/gpu/gpu_thread.cc b/chrome/gpu/gpu_thread.cc
index 1839412..9de441c 100644
--- a/chrome/gpu/gpu_thread.cc
+++ b/chrome/gpu/gpu_thread.cc
@@ -7,7 +7,6 @@
#include "build/build_config.h"
#include "chrome/common/child_process.h"
#include "chrome/common/gpu_messages.h"
-#include "chrome/gpu/gpu_channel.h"
#include "chrome/gpu/gpu_config.h"
#if defined(OS_WIN)
@@ -47,11 +46,28 @@ void GpuThread::OnControlMessageReceived(const IPC::Message& msg) {
}
void GpuThread::OnEstablishChannel(int renderer_id) {
- scoped_refptr<GpuChannel> channel =
- GpuChannel::EstablishGpuChannel(renderer_id);
+ scoped_refptr<GpuChannel> channel;
+
+ GpuChannelMap::const_iterator iter = gpu_channels_.find(renderer_id);
+ if (iter == gpu_channels_.end()) {
+ channel = new GpuChannel(renderer_id);
+ } else {
+ channel = iter->second;
+ }
+
+ DCHECK(channel != NULL);
+
+ if (channel->Init()) {
+ // TODO(apatrick): figure out when to remove channels from the map. They
+ // will never be destroyed otherwise.
+ gpu_channels_[renderer_id] = channel;
+ } else {
+ channel = NULL;
+ }
+
IPC::ChannelHandle channel_handle;
if (channel.get()) {
- channel_handle.name = channel->channel_name();
+ channel_handle.name = channel->GetChannelName();
#if defined(OS_POSIX)
// On POSIX, pass the renderer-side FD. Also mark it as auto-close so that
// it gets closed after it has been sent.
diff --git a/chrome/gpu/gpu_thread.h b/chrome/gpu/gpu_thread.h
index c32b513..23b8ba1 100644
--- a/chrome/gpu/gpu_thread.h
+++ b/chrome/gpu/gpu_thread.h
@@ -10,6 +10,7 @@
#include "build/build_config.h"
#include "chrome/common/child_thread.h"
#include "chrome/common/gpu_native_window_handle.h"
+#include "chrome/gpu/gpu_channel.h"
#include "chrome/gpu/gpu_config.h"
#include "chrome/gpu/x_util.h"
#include "gfx/native_widget_types.h"
@@ -38,6 +39,9 @@ class GpuThread : public ChildThread {
void OnNewRenderWidgetHostView(GpuNativeWindowHandle parent_window,
int32 routing_id);
+ typedef base::hash_map<int, scoped_refptr<GpuChannel> > GpuChannelMap;
+ GpuChannelMap gpu_channels_;
+
#if defined(GPU_USE_GLX)
Display* display_;
scoped_ptr<GpuBackingStoreGLXContext> glx_context_;
diff --git a/chrome/plugin/command_buffer_stub.cc b/chrome/plugin/command_buffer_stub.cc
index 7dc049c..de18db6 100644
--- a/chrome/plugin/command_buffer_stub.cc
+++ b/chrome/plugin/command_buffer_stub.cc
@@ -92,8 +92,8 @@ void CommandBufferStub::OnInitialize(int32 size,
}
// Initialize the GPUProcessor.
- processor_ = new gpu::GPUProcessor(command_buffer_.get());
- if (!processor_->Initialize(window_)) {
+ processor_.reset(new gpu::GPUProcessor(command_buffer_.get()));
+ if (!processor_->Initialize(window_, NULL, gfx::Size(), 0)) {
Destroy();
return;
}
@@ -175,7 +175,7 @@ void CommandBufferStub::OnGetTransferBuffer(
}
void CommandBufferStub::Destroy() {
- processor_ = NULL;
+ processor_.reset();
command_buffer_.reset();
DestroyPlatformSpecific();
diff --git a/chrome/plugin/command_buffer_stub.h b/chrome/plugin/command_buffer_stub.h
index 026110f..83564ca 100644
--- a/chrome/plugin/command_buffer_stub.h
+++ b/chrome/plugin/command_buffer_stub.h
@@ -73,7 +73,7 @@ class CommandBufferStub : public IPC::Channel::Listener,
gfx::PluginWindowHandle window_;
int route_id_;
scoped_ptr<gpu::CommandBufferService> command_buffer_;
- scoped_refptr<gpu::GPUProcessor> processor_;
+ scoped_ptr<gpu::GPUProcessor> processor_;
};
#endif // ENABLE_GPU
diff --git a/chrome/renderer/command_buffer_proxy.cc b/chrome/renderer/command_buffer_proxy.cc
index bd0f3a0..4a624a3 100644
--- a/chrome/renderer/command_buffer_proxy.cc
+++ b/chrome/renderer/command_buffer_proxy.cc
@@ -183,6 +183,10 @@ void CommandBufferProxy::SetParseError(
NOTREACHED();
}
+void CommandBufferProxy::ResizeOffscreenFrameBuffer(const gfx::Size& size) {
+ Send(new GpuCommandBufferMsg_ResizeOffscreenFrameBuffer(route_id_, size));
+}
+
#if defined(OS_MACOSX)
void CommandBufferProxy::SetWindowSize(int32 width, int32 height) {
Send(new GpuCommandBufferMsg_SetWindowSize(route_id_, width, height));
diff --git a/chrome/renderer/command_buffer_proxy.h b/chrome/renderer/command_buffer_proxy.h
index 5d72f2c..e6fce0a 100644
--- a/chrome/renderer/command_buffer_proxy.h
+++ b/chrome/renderer/command_buffer_proxy.h
@@ -15,6 +15,7 @@
#include "base/scoped_ptr.h"
#include "base/shared_memory.h"
#include "base/task.h"
+#include "gfx/size.h"
#include "gpu/command_buffer/common/command_buffer.h"
#include "ipc/ipc_channel.h"
#include "ipc/ipc_message.h"
@@ -51,6 +52,9 @@ class CommandBufferProxy : public gpu::CommandBuffer,
virtual void SetToken(int32 token);
virtual void SetParseError(gpu::error::Error error);
+ // Asynchronously resizes an offscreen frame buffer.
+ void ResizeOffscreenFrameBuffer(const gfx::Size& size);
+
// Set a task that will be invoked the next time the window becomes invalid
// and needs to be repainted. Takes ownership of task.
void SetNotifyRepaintTask(Task* task) {
diff --git a/chrome/renderer/ggl/ggl.cc b/chrome/renderer/ggl/ggl.cc
index b5c1d9d..2c41126 100644
--- a/chrome/renderer/ggl/ggl.cc
+++ b/chrome/renderer/ggl/ggl.cc
@@ -50,12 +50,21 @@ class GLES2Initializer {
// Manages a GL context.
class Context {
public:
- Context();
+ Context(GpuChannelHost* channel, Context* parent);
~Context();
// Initialize a GGL context that can be used in association with a a GPU
// channel acquired from a RenderWidget or RenderView.
- bool Initialize(GpuChannelHost* channel);
+ bool Initialize(gfx::NativeViewId view, const gfx::Size& size);
+
+ // Asynchronously resizes an offscreen frame buffer.
+ void ResizeOffscreen(const gfx::Size& size);
+
+ // For an offscreen frame buffer context, return the frame buffer ID with
+ // respect to the parent.
+ uint32 parent_texture_id() const {
+ return parent_texture_id_;
+ }
// Destroy all resources associated with the GGL context.
void Destroy();
@@ -73,6 +82,8 @@ class Context {
private:
scoped_refptr<GpuChannelHost> channel_;
+ Context* parent_;
+ uint32 parent_texture_id_;
CommandBufferProxy* command_buffer_;
gpu::gles2::GLES2CmdHelper* gles2_helper_;
int32 transfer_buffer_id_;
@@ -81,31 +92,46 @@ class Context {
DISALLOW_COPY_AND_ASSIGN(Context);
};
-Context::Context()
- : channel_(NULL),
+Context::Context(GpuChannelHost* channel, Context* parent)
+ : channel_(channel),
+ parent_(parent),
+ parent_texture_id_(0),
command_buffer_(NULL),
gles2_helper_(NULL),
transfer_buffer_id_(0),
gles2_implementation_(NULL) {
+ DCHECK(channel);
}
Context::~Context() {
Destroy();
}
-bool Context::Initialize(GpuChannelHost* channel) {
- DCHECK(channel);
+bool Context::Initialize(gfx::NativeViewId view, const gfx::Size& size) {
+ DCHECK(size.width() >= 0 && size.height() >= 0);
- if (!channel->ready())
+ if (!channel_->ready())
return false;
- channel_ = channel;
-
// Ensure the gles2 library is initialized first in a thread safe way.
Singleton<GLES2Initializer>::get();
+ // Allocate a frame buffer ID with respect to the parent.
+ if (parent_) {
+ parent_->gles2_implementation_->MakeIds(1, &parent_texture_id_);
+ }
+
// Create a proxy to a command buffer in the GPU process.
- command_buffer_ = channel_->CreateCommandBuffer();
+ if (view) {
+ command_buffer_ = channel_->CreateViewCommandBuffer(view);
+ } else {
+ CommandBufferProxy* parent_command_buffer =
+ parent_ ? parent_->command_buffer_ : NULL;
+ command_buffer_ = channel_->CreateOffscreenCommandBuffer(
+ parent_command_buffer,
+ size,
+ parent_texture_id_);
+ }
if (!command_buffer_) {
Destroy();
return false;
@@ -151,7 +177,15 @@ bool Context::Initialize(GpuChannelHost* channel) {
return true;
}
+void Context::ResizeOffscreen(const gfx::Size& size) {
+ DCHECK(size.width() > 0 && size.height() > 0);
+ command_buffer_->ResizeOffscreenFrameBuffer(size);
+}
+
void Context::Destroy() {
+ if (parent_ && parent_texture_id_ != 0)
+ parent_->gles2_implementation_->FreeIds(1, &parent_texture_id_);
+
delete gles2_implementation_;
gles2_implementation_ = NULL;
@@ -213,10 +247,10 @@ Error Context::GetError() {
#endif // ENABLE_GPU
-Context* CreateContext(GpuChannelHost* channel) {
+Context* CreateViewContext(GpuChannelHost* channel, gfx::NativeViewId view) {
#if defined(ENABLE_GPU)
- scoped_ptr<Context> context(new Context);
- if (!context->Initialize(channel))
+ scoped_ptr<Context> context(new Context(channel, NULL));
+ if (!context->Initialize(view, gfx::Size()))
return NULL;
return context.release();
@@ -225,6 +259,34 @@ Context* CreateContext(GpuChannelHost* channel) {
#endif
}
+Context* CreateOffscreenContext(GpuChannelHost* channel,
+ Context* parent,
+ const gfx::Size& size) {
+#if defined(ENABLE_GPU)
+ scoped_ptr<Context> context(new Context(channel, parent));
+ if (!context->Initialize(NULL, size))
+ return NULL;
+
+ return context.release();
+#else
+ return NULL;
+#endif
+}
+
+void ResizeOffscreenContext(Context* context, const gfx::Size& size) {
+#if defined(ENABLE_GPU)
+ context->ResizeOffscreen(size);
+#endif
+}
+
+uint32 GetParentTextureId(Context* context) {
+#if defined(ENABLE_GPU)
+ return context->parent_texture_id();
+#else
+ return 0;
+#endif
+}
+
bool MakeCurrent(Context* context) {
#if defined(ENABLE_GPU)
return Context::MakeCurrent(context);
diff --git a/chrome/renderer/ggl/ggl.h b/chrome/renderer/ggl/ggl.h
index 26607ec..e5c661f 100644
--- a/chrome/renderer/ggl/ggl.h
+++ b/chrome/renderer/ggl/ggl.h
@@ -10,6 +10,9 @@
#ifndef CHROME_RENDERER_GGL_GGL_H_
#define CHROME_RENDERER_GGL_GGL_H_
+#include "gfx/native_widget_types.h"
+#include "gfx/size.h"
+
class GpuChannelHost;
namespace ggl {
@@ -32,8 +35,30 @@ bool Initialize();
// have completed.
bool Terminate();
-// Create A GGL context for an offscreen 1 x 1 pbuffer.
-Context* CreateContext(GpuChannelHost* channel);
+// Create a GGL context that renders directly to a view.
+Context* CreateViewContext(GpuChannelHost* channel, gfx::NativeViewId view);
+
+// Create a GGL context that renders to an offscreen frame buffer. If parent is
+// not NULL, that context can access a copy of the created
+// context's frame buffer that is updated every time SwapBuffers is called. It
+// is not as general as shared contexts in other implementations of OpenGL. If
+// parent is not NULL, it must be used on the same thread as the parent. A child
+// context may not outlive its parent.
+Context* CreateOffscreenContext(GpuChannelHost* channel,
+ Context* parent,
+ const gfx::Size& size);
+
+// Resize an offscreen frame buffer. The resize occurs on the next call to
+// SwapBuffers. This is to avoid waiting until all pending GL calls have been
+// executed by the GPU process. Everything rendered up to the call to
+// SwapBuffers will be lost. A lost context will be reported if the resize
+// fails.
+void ResizeOffscreenContext(Context* context, const gfx::Size& size);
+
+// For an offscreen frame buffer context, return the texture ID with
+// respect to the parent context. Returns zero if context does not have a
+// parent.
+uint32 GetParentTextureId(Context* context);
// Set the current GGL context for the calling thread.
bool MakeCurrent(Context* context);
@@ -41,7 +66,10 @@ bool MakeCurrent(Context* context);
// Get the calling thread's current GGL context.
Context* GetCurrentContext();
-// Display everything that has been rendered since the last call.
+// For a view context, display everything that has been rendered since the
+// last call. For an offscreen context, resolve everything that has been
+// rendered since the last call to a copy that can be accessed by the parent
+// context.
bool SwapBuffers();
// Destroy the given GGL context.
diff --git a/chrome/renderer/gpu_channel_host.cc b/chrome/renderer/gpu_channel_host.cc
index 8e48b85..8d2cdd9 100644
--- a/chrome/renderer/gpu_channel_host.cc
+++ b/chrome/renderer/gpu_channel_host.cc
@@ -64,14 +64,43 @@ bool GpuChannelHost::Send(IPC::Message* message) {
return channel_->Send(message);
}
-CommandBufferProxy* GpuChannelHost::CreateCommandBuffer() {
+CommandBufferProxy* GpuChannelHost::CreateViewCommandBuffer(
+ gfx::NativeViewId view) {
#if defined(ENABLE_GPU)
// An error occurred. Need to get the host again to reinitialize it.
if (!channel_.get())
return NULL;
int32 route_id;
- if (!Send(new GpuChannelMsg_CreateCommandBuffer(&route_id)) &&
+ if (!Send(new GpuChannelMsg_CreateViewCommandBuffer(view, &route_id)) &&
+ route_id != MSG_ROUTING_NONE) {
+ return NULL;
+ }
+
+ CommandBufferProxy* command_buffer = new CommandBufferProxy(this, route_id);
+ router_.AddRoute(route_id, command_buffer);
+ proxies_[route_id] = command_buffer;
+ return command_buffer;
+#else
+ return NULL;
+#endif
+}
+
+CommandBufferProxy* GpuChannelHost::CreateOffscreenCommandBuffer(
+ CommandBufferProxy* parent,
+ const gfx::Size& size,
+ uint32 parent_texture_id) {
+#if defined(ENABLE_GPU)
+ // An error occurred. Need to get the host again to reinitialize it.
+ if (!channel_.get())
+ return NULL;
+
+ int32 parent_route_id = parent ? parent->route_id() : 0;
+ int32 route_id;
+ if (!Send(new GpuChannelMsg_CreateOffscreenCommandBuffer(parent_route_id,
+ size,
+ parent_texture_id,
+ &route_id)) &&
route_id != MSG_ROUTING_NONE) {
return NULL;
}
@@ -99,3 +128,4 @@ void GpuChannelHost::DestroyCommandBuffer(CommandBufferProxy* command_buffer) {
delete command_buffer;
#endif
}
+
diff --git a/chrome/renderer/gpu_channel_host.h b/chrome/renderer/gpu_channel_host.h
index 00a6129..4b982bf 100644
--- a/chrome/renderer/gpu_channel_host.h
+++ b/chrome/renderer/gpu_channel_host.h
@@ -9,6 +9,8 @@
#include "base/hash_tables.h"
#include "chrome/common/message_router.h"
+#include "gfx/native_widget_types.h"
+#include "gfx/size.h"
#include "ipc/ipc_channel.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_sync_channel.h"
@@ -52,7 +54,13 @@ class GpuChannelHost : public IPC::Channel::Listener,
virtual bool Send(IPC::Message* msg);
// Create and connect to a command buffer in the GPU process.
- CommandBufferProxy* CreateCommandBuffer();
+ CommandBufferProxy* CreateViewCommandBuffer(gfx::NativeViewId view);
+
+ // Create and connect to a command buffer in the GPU process.
+ CommandBufferProxy* CreateOffscreenCommandBuffer(CommandBufferProxy* parent,
+ const gfx::Size& size,
+ uint32 parent_texture_id);
+
// Destroy a command buffer created by this channel.
void DestroyCommandBuffer(CommandBufferProxy* command_buffer);
diff --git a/chrome/renderer/render_thread.cc b/chrome/renderer/render_thread.cc
index ab97f2a..4fb0971 100644
--- a/chrome/renderer/render_thread.cc
+++ b/chrome/renderer/render_thread.cc
@@ -90,6 +90,10 @@
#include "chrome/app/breakpad_mac.h"
#endif
+#if defined(OS_POSIX)
+#include "ipc/ipc_channel_posix.h"
+#endif
+
using WebKit::WebCache;
using WebKit::WebCrossOriginPreflightResultCache;
using WebKit::WebFontCache;
@@ -565,6 +569,7 @@ void RenderThread::OnControlMessageReceived(const IPC::Message& msg) {
OnSpellCheckWordAdded)
IPC_MESSAGE_HANDLER(ViewMsg_SpellChecker_EnableAutoSpellCorrect,
OnSpellCheckEnableAutoSpellCorrect)
+ IPC_MESSAGE_HANDLER(ViewMsg_GpuChannelEstablished, OnGpuChannelEstablished)
IPC_END_MESSAGE_MAP()
}
@@ -680,6 +685,34 @@ void RenderThread::UpdateActiveExtensions() {
child_process_logging::SetActiveExtensions(active_extensions);
}
+void RenderThread::EstablishGpuChannel() {
+ if (gpu_channel_.get()) {
+ // Do nothing if we are already establishing GPU channel.
+ if (gpu_channel_->state() == GpuChannelHost::UNCONNECTED)
+ return;
+
+ // Recreate the channel if it has been lost.
+ if (gpu_channel_->state() == GpuChannelHost::LOST)
+ gpu_channel_ = NULL;
+ }
+
+ if (!gpu_channel_.get())
+ gpu_channel_ = new GpuChannelHost;
+
+ // Ask the browser for the channel name.
+ Send(new ViewHostMsg_EstablishGpuChannel());
+}
+
+GpuChannelHost* RenderThread::GetGpuChannel() {
+ if (!gpu_channel_.get())
+ return NULL;
+
+ if (gpu_channel_->state() != GpuChannelHost::CONNECTED)
+ return NULL;
+
+ return gpu_channel_.get();
+}
+
static void* CreateHistogram(
const char *name, int min, int max, size_t buckets) {
if (min <= 0)
@@ -940,3 +973,20 @@ void RenderThread::OnSpellCheckEnableAutoSpellCorrect(bool enable) {
void RenderThread::OnSetIsIncognitoProcess(bool is_incognito_process) {
is_incognito_process_ = is_incognito_process;
}
+
+void RenderThread::OnGpuChannelEstablished(
+ const IPC::ChannelHandle& channel_handle) {
+#if defined(OS_POSIX)
+ // If we received a ChannelHandle, register it now.
+ if (channel_handle.socket.fd >= 0)
+ IPC::AddChannelSocket(channel_handle.name, channel_handle.socket.fd);
+#endif
+
+ if (channel_handle.name.size() != 0) {
+ // Connect to the GPU process if a channel name was received.
+ gpu_channel_->Connect(channel_handle.name);
+ } else {
+ // Otherwise cancel the connection.
+ gpu_channel_ = NULL;
+ }
+}
diff --git a/chrome/renderer/render_thread.h b/chrome/renderer/render_thread.h
index fea7e41..3caed00 100644
--- a/chrome/renderer/render_thread.h
+++ b/chrome/renderer/render_thread.h
@@ -18,9 +18,11 @@
#include "chrome/common/child_thread.h"
#include "chrome/common/css_colors.h"
#include "chrome/common/dom_storage_common.h"
+#include "chrome/renderer/gpu_channel_host.h"
#include "chrome/renderer/renderer_histogram_snapshots.h"
#include "chrome/renderer/visitedlink_slave.h"
#include "gfx/native_widget_types.h"
+#include "ipc/ipc_channel_handle.h"
#include "ipc/ipc_platform_file.h"
class AppCacheDispatcher;
@@ -165,6 +167,15 @@ class RenderThread : public RenderThreadBase,
// Update the list of active extensions that will be reported when we crash.
void UpdateActiveExtensions();
+ // Asynchronously establish a channel to the GPU plugin if not previously
+ // established or if it has been lost (for example if the GPU plugin crashed).
+ // Use GetGpuChannel() to determine when the channel is ready for use.
+ void EstablishGpuChannel();
+
+ // Get the GPU channel. Returns NULL if the channel is not established or
+ // has been lost.
+ GpuChannelHost* GetGpuChannel();
+
private:
virtual void OnControlMessageReceived(const IPC::Message& msg);
@@ -220,6 +231,8 @@ class RenderThread : public RenderThreadBase,
void OnSpellCheckWordAdded(const std::string& word);
void OnSpellCheckEnableAutoSpellCorrect(bool enable);
+ void OnGpuChannelEstablished(const IPC::ChannelHandle& channel_handle);
+
// Gather usage statistics from the in-memory cache and inform our host.
// These functions should be call periodically so that the host can make
// decisions about how to allocation resources using current information.
@@ -288,6 +301,9 @@ class RenderThread : public RenderThreadBase,
// not idle, to ensure that IdleHandle gets called eventually.
base::RepeatingTimer<RenderThread> forced_idle_timer_;
+ // The channel from the renderer process to the GPU process.
+ scoped_refptr<GpuChannelHost> gpu_channel_;
+
DISALLOW_COPY_AND_ASSIGN(RenderThread);
};
diff --git a/chrome/renderer/render_widget.cc b/chrome/renderer/render_widget.cc
index def6e47..50af08f 100644
--- a/chrome/renderer/render_widget.cc
+++ b/chrome/renderer/render_widget.cc
@@ -150,7 +150,6 @@ IPC_DEFINE_MESSAGE_MAP(RenderWidget)
IPC_MESSAGE_HANDLER(ViewMsg_ImeSetComposition, OnImeSetComposition)
IPC_MESSAGE_HANDLER(ViewMsg_Repaint, OnMsgRepaint)
IPC_MESSAGE_HANDLER(ViewMsg_SetTextDirection, OnSetTextDirection)
- IPC_MESSAGE_HANDLER(ViewMsg_GpuChannelEstablished, OnGpuChannelEstablished)
IPC_MESSAGE_HANDLER(ViewMsg_Move_ACK, OnRequestMoveAck)
IPC_MESSAGE_UNHANDLED_ERROR()
IPC_END_MESSAGE_MAP()
@@ -732,23 +731,6 @@ void RenderWidget::OnSetTextDirection(WebTextDirection direction) {
webwidget_->setTextDirection(direction);
}
-void RenderWidget::OnGpuChannelEstablished(
- const IPC::ChannelHandle& channel_handle) {
-#if defined(OS_POSIX)
- // If we received a ChannelHandle, register it now.
- if (channel_handle.socket.fd >= 0)
- IPC::AddChannelSocket(channel_handle.name, channel_handle.socket.fd);
-#endif
-
- if (channel_handle.name.size() != 0) {
- // Connect to the GPU process if a channel name was received.
- gpu_channel_->Connect(channel_handle.name);
- } else {
- // Otherwise cancel the connection.
- gpu_channel_ = NULL;
- }
-}
-
void RenderWidget::SetHidden(bool hidden) {
if (is_hidden_ == hidden)
return;
@@ -892,31 +874,3 @@ void RenderWidget::CleanupWindowInPluginMoves(gfx::PluginWindowHandle window) {
}
}
-void RenderWidget::EstablishGpuChannel() {
- if (gpu_channel_.get()) {
- // Do nothing if we are already establishing GPU channel.
- if (gpu_channel_->state() == GpuChannelHost::UNCONNECTED)
- return;
-
- // Recreate the channel if it has been lost.
- if (gpu_channel_->state() == GpuChannelHost::LOST)
- gpu_channel_ = NULL;
- }
-
- if (!gpu_channel_.get())
- gpu_channel_ = new GpuChannelHost;
-
- // Ask the browser for the channel name.
- CHECK(Send(new ViewHostMsg_EstablishGpuChannel(routing_id_)));
-}
-
-GpuChannelHost* RenderWidget::GetGpuChannel() {
- if (!gpu_channel_.get())
- return NULL;
-
- if (gpu_channel_->state() != GpuChannelHost::CONNECTED)
- return NULL;
-
- return gpu_channel_.get();
-}
-
diff --git a/chrome/renderer/render_widget.h b/chrome/renderer/render_widget.h
index 4759e30..4781790 100644
--- a/chrome/renderer/render_widget.h
+++ b/chrome/renderer/render_widget.h
@@ -10,7 +10,6 @@
#include "base/basictypes.h"
#include "base/ref_counted.h"
#include "base/shared_memory.h"
-#include "chrome/renderer/gpu_channel_host.h"
#include "chrome/renderer/paint_aggregator.h"
#include "chrome/renderer/render_process.h"
#include "gfx/native_widget_types.h"
@@ -18,7 +17,6 @@
#include "gfx/rect.h"
#include "gfx/size.h"
#include "ipc/ipc_channel.h"
-#include "ipc/ipc_channel_handle.h"
#include "skia/ext/platform_canvas.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/WebKit/WebKit/chromium/public/WebCompositionCommand.h"
@@ -107,15 +105,6 @@ class RenderWidget : public IPC::Channel::Listener,
// Close the underlying WebWidget.
virtual void Close();
- // Asynchronously establish a channel to the GPU plugin if not previously
- // established or if it has been lost (for example if the GPU plugin crashed).
- // Use GetGpuChannel() to determine when the channel is ready for use.
- void EstablishGpuChannel();
-
- // Get the GPU channel. Returns NULL if the channel is not established or
- // has been lost.
- GpuChannelHost* GetGpuChannel();
-
protected:
// Friend RefCounted so that the dtor can be non-public. Using this class
// without ref-counting is an error.
@@ -171,7 +160,6 @@ class RenderWidget : public IPC::Channel::Listener,
const string16& ime_string);
void OnMsgRepaint(const gfx::Size& size_to_paint);
void OnSetTextDirection(WebKit::WebTextDirection direction);
- void OnGpuChannelEstablished(const IPC::ChannelHandle& channel_handle);
// Override point to notify derived classes that a paint has happened.
// DidInitiatePaint happens when we've generated a new bitmap and sent it to
@@ -332,9 +320,6 @@ class RenderWidget : public IPC::Channel::Listener,
// Indicates if the next sequence of Char events should be suppressed or not.
bool suppress_next_char_events_;
- // The channel from the renderer process to the GPU process.
- scoped_refptr<GpuChannelHost> gpu_channel_;
-
DISALLOW_COPY_AND_ASSIGN(RenderWidget);
};
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index 16f084b..6d11c08 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -1178,6 +1178,11 @@ _FUNCTION_INFO = {
'cmd_args':
'GLuint shader, const char* data',
},
+ 'SwapBuffers': {
+ 'type': 'Custom',
+ 'impl_func': False,
+ 'unit_test': False,
+ },
'TexImage2D': {'type': 'Manual', 'immediate': True},
'TexParameterf': {'decoder_func': 'DoTexParameterf'},
'TexParameteri': {'decoder_func': 'DoTexParameteri'},
@@ -1222,11 +1227,6 @@ _FUNCTION_INFO = {
'cmd_args': 'GLuint indx, GLint size, GLenum type, GLboolean normalized, '
'GLsizei stride, GLuint offset',
},
- 'SwapBuffers': {
- 'impl_func': False,
- 'decoder_func': 'DoSwapBuffers',
- 'unit_test': False,
- },
}
diff --git a/gpu/command_buffer/client/cmd_buffer_helper_test.cc b/gpu/command_buffer/client/cmd_buffer_helper_test.cc
index ffb8137..d754f5b 100644
--- a/gpu/command_buffer/client/cmd_buffer_helper_test.cc
+++ b/gpu/command_buffer/client/cmd_buffer_helper_test.cc
@@ -51,12 +51,12 @@ class CommandBufferHelperTest : public testing::Test {
0,
api_mock_.get());
- scoped_refptr<GPUProcessor> gpu_processor(new GPUProcessor(
+ gpu_processor_.reset(new GPUProcessor(
command_buffer_.get(), NULL, parser_, 1));
command_buffer_->SetPutOffsetChangeCallback(NewCallback(
- gpu_processor.get(), &GPUProcessor::ProcessCommands));
+ gpu_processor_.get(), &GPUProcessor::ProcessCommands));
- api_mock_->set_engine(gpu_processor.get());
+ api_mock_->set_engine(gpu_processor_.get());
helper_.reset(new CommandBufferHelper(command_buffer_.get()));
helper_->Initialize();
@@ -132,6 +132,7 @@ class CommandBufferHelperTest : public testing::Test {
MessageLoop message_loop_;
scoped_ptr<AsyncAPIMock> api_mock_;
scoped_ptr<CommandBufferService> command_buffer_;
+ scoped_ptr<GPUProcessor> gpu_processor_;
CommandParser* parser_;
scoped_ptr<CommandBufferHelper> helper_;
Sequence sequence_;
diff --git a/gpu/command_buffer/client/fenced_allocator_test.cc b/gpu/command_buffer/client/fenced_allocator_test.cc
index c47f355..8dc1b780 100644
--- a/gpu/command_buffer/client/fenced_allocator_test.cc
+++ b/gpu/command_buffer/client/fenced_allocator_test.cc
@@ -52,12 +52,12 @@ class BaseFencedAllocatorTest : public testing::Test {
0,
api_mock_.get());
- scoped_refptr<GPUProcessor> gpu_processor(new GPUProcessor(
+ gpu_processor_.reset(new GPUProcessor(
command_buffer_.get(), NULL, parser_, INT_MAX));
command_buffer_->SetPutOffsetChangeCallback(NewCallback(
- gpu_processor.get(), &GPUProcessor::ProcessCommands));
+ gpu_processor_.get(), &GPUProcessor::ProcessCommands));
- api_mock_->set_engine(gpu_processor.get());
+ api_mock_->set_engine(gpu_processor_.get());
helper_.reset(new CommandBufferHelper(command_buffer_.get()));
helper_->Initialize();
@@ -76,6 +76,7 @@ class BaseFencedAllocatorTest : public testing::Test {
MessageLoop message_loop_;
scoped_ptr<AsyncAPIMock> api_mock_;
scoped_ptr<CommandBufferService> command_buffer_;
+ scoped_ptr<GPUProcessor> gpu_processor_;
CommandParser* parser_;
scoped_ptr<CommandBufferHelper> helper_;
};
diff --git a/gpu/command_buffer/client/gles2_demo.cc b/gpu/command_buffer/client/gles2_demo.cc
index 41c42b1..6035042 100644
--- a/gpu/command_buffer/client/gles2_demo.cc
+++ b/gpu/command_buffer/client/gles2_demo.cc
@@ -54,14 +54,16 @@ bool GLES2Demo::Setup(void* hwnd, int32 size) {
if (!command_buffer->Initialize(size))
return NULL;
- scoped_refptr<GPUProcessor> gpu_processor(
- new GPUProcessor(command_buffer.get()));
- if (!gpu_processor->Initialize(reinterpret_cast<HWND>(hwnd))) {
+ GPUProcessor* gpu_processor = new GPUProcessor(command_buffer.get());
+ if (!gpu_processor->Initialize(reinterpret_cast<HWND>(hwnd),
+ NULL,
+ gfx::Size(),
+ 0)) {
return NULL;
}
command_buffer->SetPutOffsetChangeCallback(
- NewCallback(gpu_processor.get(), &GPUProcessor::ProcessCommands));
+ NewCallback(gpu_processor, &GPUProcessor::ProcessCommands));
GLES2CmdHelper* helper = new GLES2CmdHelper(command_buffer.get());
if (!helper->Initialize()) {
diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h
index c1ee9c6..fd98686 100644
--- a/gpu/command_buffer/client/gles2_implementation.h
+++ b/gpu/command_buffer/client/gles2_implementation.h
@@ -43,13 +43,13 @@ class GLES2Implementation {
// this file instead of having to edit some template or the code generator.
#include "../client/gles2_implementation_autogen.h"
- private:
// Makes a set of Ids for glGen___ functions.
void MakeIds(GLsizei n, GLuint* ids);
// Frees a set of Ids for glDelete___ functions.
void FreeIds(GLsizei n, const GLuint* ids);
+ private:
// Gets the shared memory id for the result buffer.
uint32 result_shm_id() const {
return transfer_buffer_id_;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 512a819..23c3423 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -14,6 +14,7 @@
#include "base/callback.h"
#include "base/linked_ptr.h"
#include "base/scoped_ptr.h"
+#include "base/weak_ptr.h"
#define GLES2_GPU_SERVICE 1
#include "gpu/command_buffer/common/gles2_cmd_format.h"
#include "gpu/command_buffer/common/gles2_cmd_utils.h"
@@ -36,9 +37,15 @@
#include "app/surface/accelerated_surface_mac.h"
#endif
+#if !defined(GL_DEPTH24_STENCIL8)
+#define GL_DEPTH24_STENCIL8 0x88F0
+#endif
+
namespace gpu {
namespace gles2 {
+class GLES2DecoderImpl;
+
// Check that certain assumptions the code makes are true. There are places in
// the code where shared memory is passed direclty to GL. Example, glUniformiv,
// glShaderSource. The command buffer code assumes GLint and GLsizei (and maybe
@@ -107,6 +114,144 @@ const CommandInfo g_command_info[] = {
#undef GLES2_CMD_OP
};
+// This class prevents any GL errors that occur when it is in scope from
+// being reported to the client.
+class ScopedGLErrorSuppressor {
+ public:
+ explicit ScopedGLErrorSuppressor(GLES2DecoderImpl* decoder);
+ ~ScopedGLErrorSuppressor();
+ private:
+ GLES2DecoderImpl* decoder_;
+ DISALLOW_COPY_AND_ASSIGN(ScopedGLErrorSuppressor);
+};
+
+// Temporarily changes a decoder's bound 2D texture and restore it when this
+// object goes out of scope. Also temporarily switches to using active texture
+// unit zero in case the client has changed that to something invalid.
+class ScopedTexture2DBinder {
+ public:
+ ScopedTexture2DBinder(GLES2DecoderImpl* decoder, GLuint id);
+ ~ScopedTexture2DBinder();
+
+ private:
+ GLES2DecoderImpl* decoder_;
+ DISALLOW_COPY_AND_ASSIGN(ScopedTexture2DBinder);
+};
+
+// Temporarily changes a decoder's bound render buffer and restore it when this
+// object goes out of scope.
+class ScopedRenderBufferBinder {
+ public:
+ ScopedRenderBufferBinder(GLES2DecoderImpl* decoder, GLuint id);
+ ~ScopedRenderBufferBinder();
+
+ private:
+ GLES2DecoderImpl* decoder_;
+ DISALLOW_COPY_AND_ASSIGN(ScopedRenderBufferBinder);
+};
+
+// Temporarily changes a decoder's bound frame buffer and restore it when this
+// object goes out of scope.
+class ScopedFrameBufferBinder {
+ public:
+ ScopedFrameBufferBinder(GLES2DecoderImpl* decoder, GLuint id);
+ ~ScopedFrameBufferBinder();
+
+ private:
+ GLES2DecoderImpl* decoder_;
+ DISALLOW_COPY_AND_ASSIGN(ScopedFrameBufferBinder);
+};
+
+// Encapsulates an OpenGL texture.
+class Texture {
+ public:
+ explicit Texture(GLES2DecoderImpl* decoder);
+ ~Texture();
+
+ // Create a new render texture.
+ void Create();
+
+ // Set the initial size and format of a render texture or resize it.
+ bool AllocateStorage(const gfx::Size& size);
+
+ // Copy the contents of the currently bound frame buffer.
+ void Copy(const gfx::Size& size);
+
+ // Destroy the render texture. This must be explicitly called before
+ // destroying this object.
+ void Destroy();
+
+ GLuint id() const {
+ return id_;
+ }
+
+ private:
+ GLES2DecoderImpl* decoder_;
+ GLuint id_;
+ DISALLOW_COPY_AND_ASSIGN(Texture);
+};
+
+// Encapsulates an OpenGL render buffer of any format.
+class RenderBuffer {
+ public:
+ explicit RenderBuffer(GLES2DecoderImpl* decoder);
+ ~RenderBuffer();
+
+ // Create a new render buffer.
+ void Create();
+
+ // Set the initial size and format of a render buffer or resize it.
+ bool AllocateStorage(const gfx::Size& size, GLenum format);
+
+ // Destroy the render buffer. This must be explicitly called before destroying
+ // this object.
+ void Destroy();
+
+ GLuint id() const {
+ return id_;
+ }
+
+ private:
+ GLES2DecoderImpl* decoder_;
+ GLuint id_;
+ DISALLOW_COPY_AND_ASSIGN(RenderBuffer);
+};
+
+// Encapsulates an OpenGL frame buffer.
+class FrameBuffer {
+ public:
+ explicit FrameBuffer(GLES2DecoderImpl* decoder);
+ ~FrameBuffer();
+
+ // Create a new frame buffer.
+ void Create();
+
+ // Attach a color render buffer to a frame buffer.
+ void AttachRenderTexture(Texture* texture);
+
+ // Attach a depth stencil render buffer to a frame buffer. Note that
+ // this unbinds any currently bound frame buffer.
+ void AttachDepthStencilRenderBuffer(RenderBuffer* render_buffer);
+
+ // Clear the given attached buffers.
+ void Clear(GLbitfield buffers);
+
+ // Destroy the frame buffer. This must be explicitly called before destroying
+ // this object.
+ void Destroy();
+
+ // See glCheckFramebufferStatusEXT.
+ GLenum CheckStatus();
+
+ GLuint id() const {
+ return id_;
+ }
+
+ private:
+ GLES2DecoderImpl* decoder_;
+ GLuint id_;
+ DISALLOW_COPY_AND_ASSIGN(FrameBuffer);
+};
// } // anonymous namespace.
GLES2Decoder::GLES2Decoder(ContextGroup* group)
@@ -129,7 +274,8 @@ GLES2Decoder::~GLES2Decoder() {
// This class implements GLES2Decoder so we don't have to expose all the GLES2
// cmd stuff to outside this class.
-class GLES2DecoderImpl : public GLES2Decoder {
+class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>,
+ public GLES2Decoder {
public:
explicit GLES2DecoderImpl(ContextGroup* group);
@@ -210,8 +356,11 @@ class GLES2DecoderImpl : public GLES2Decoder {
virtual const char* GetCommandName(unsigned int command_id) const;
// Overridden from GLES2Decoder.
- virtual bool Initialize();
+ virtual bool Initialize(GLES2Decoder* parent,
+ const gfx::Size& size,
+ uint32 parent_client_texture_id);
virtual void Destroy();
+ virtual void ResizeOffscreenFrameBuffer(const gfx::Size& size);
virtual bool MakeCurrent();
virtual uint32 GetServiceIdForTesting(uint32 client_id);
virtual GLES2Util* GetGLES2Util() { return &util_; }
@@ -239,6 +388,13 @@ class GLES2DecoderImpl : public GLES2Decoder {
virtual void SetSwapBuffersCallback(Callback0::Type* callback);
private:
+ friend class ScopedGLErrorSuppressor;
+ friend class ScopedTexture2DBinder;
+ friend class ScopedFrameBufferBinder;
+ friend class ScopedRenderBufferBinder;
+ friend class RenderBuffer;
+ friend class FrameBuffer;
+
// State associated with each texture unit.
struct TextureUnit {
TextureUnit() : bind_target(GL_TEXTURE_2D) { }
@@ -309,6 +465,8 @@ class GLES2DecoderImpl : public GLES2Decoder {
static bool InitGlew();
void DestroyPlatformSpecific();
+ bool UpdateOffscreenFrameBufferSize();
+
// Template to help call glGenXXX functions.
template <void gl_gen_function(GLES2DecoderImpl*, GLsizei, GLuint*)>
bool GenGLObjects(GLsizei n, const GLuint* client_ids) {
@@ -343,8 +501,8 @@ class GLES2DecoderImpl : public GLES2Decoder {
GLsizei n, const GLuint* client_ids, GLuint* service_ids);
// Creates a TextureInfo for the given texture.
- void CreateTextureInfo(GLuint texture) {
- texture_manager()->CreateTextureInfo(texture);
+ TextureManager::TextureInfo* CreateTextureInfo(GLuint texture) {
+ return texture_manager()->CreateTextureInfo(texture);
}
// Gets the texture info for the given texture. Returns NULL if none exists.
@@ -561,9 +719,6 @@ class GLES2DecoderImpl : public GLES2Decoder {
void DoRenderbufferStorage(
GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
- // Swaps the buffers (copies/renders to the current window).
- void DoSwapBuffers();
-
// Wrappers for glTexParameter functions.
void DoTexParameterf(GLenum target, GLenum pname, GLfloat param);
void DoTexParameteri(GLenum target, GLenum pname, GLint param);
@@ -590,6 +745,10 @@ class GLES2DecoderImpl : public GLES2Decoder {
// command.
void CopyRealGLErrorsToWrapper();
+ // Clear all real GL errors. This is to prevent the client from seeing any
+ // errors caused by GL calls that it was not responsible for issuing.
+ void ClearRealGLErrors();
+
// Checks if the current program and vertex attributes are valid for drawing.
bool IsDrawValid(GLuint max_vertex_accessed);
@@ -654,6 +813,17 @@ class GLES2DecoderImpl : public GLES2Decoder {
#undef GLES2_CMD_OP
+ // A parent decoder can access this decoders saved offscreen frame buffer.
+ // The parent pointer is reset if the parent is destroyed.
+ base::WeakPtr<GLES2DecoderImpl> parent_;
+
+ // Width and height to which an offscreen frame buffer should be resized on
+ // the next call to SwapBuffers.
+ gfx::Size pending_size_;
+
+ // Width and height of a decoder that renders to an offscreen frame buffer.
+ gfx::Size current_size_;
+
// Current GL error bits.
uint32 error_bits_;
@@ -714,11 +884,252 @@ class GLES2DecoderImpl : public GLES2Decoder {
bool anti_aliased_;
+ // The offscreen frame buffer that the client renders to.
+ scoped_ptr<FrameBuffer> offscreen_target_frame_buffer_;
+ scoped_ptr<Texture> offscreen_target_color_texture_;
+ scoped_ptr<RenderBuffer> offscreen_target_depth_stencil_render_buffer_;
+
+ // The copy that is saved when SwapBuffers is called.
+ scoped_ptr<Texture> offscreen_saved_color_texture_;
+
+ // A frame buffer used for rendering to render textures and render buffers
+ // without concern about any state the client might have changed on the frame
+ // buffers it has access to.
+ scoped_ptr<FrameBuffer> temporary_frame_buffer_;
+
scoped_ptr<Callback0::Type> swap_buffers_callback_;
DISALLOW_COPY_AND_ASSIGN(GLES2DecoderImpl);
};
+ScopedGLErrorSuppressor::ScopedGLErrorSuppressor(GLES2DecoderImpl* decoder)
+ : decoder_(decoder) {
+ decoder_->CopyRealGLErrorsToWrapper();
+}
+
+ScopedGLErrorSuppressor::~ScopedGLErrorSuppressor() {
+ decoder_->ClearRealGLErrors();
+}
+
+ScopedTexture2DBinder::ScopedTexture2DBinder(GLES2DecoderImpl* decoder,
+ GLuint id)
+ : decoder_(decoder) {
+ ScopedGLErrorSuppressor suppressor(decoder_);
+
+ // TODO(apatrick): Check if there are any other states that need to be reset
+ // before binding a new texture.
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, id);
+}
+
+ScopedTexture2DBinder::~ScopedTexture2DBinder() {
+ ScopedGLErrorSuppressor suppressor(decoder_);
+ GLES2DecoderImpl::TextureUnit& info = decoder_->texture_units_[0];
+ GLuint last_id;
+ if (info.bound_texture_2d)
+ last_id = info.bound_texture_2d->texture_id();
+ else
+ last_id = 0;
+
+ glBindTexture(GL_TEXTURE_2D, last_id);
+ glActiveTexture(GL_TEXTURE0 + decoder_->active_texture_unit_);
+}
+
+ScopedRenderBufferBinder::ScopedRenderBufferBinder(GLES2DecoderImpl* decoder,
+ GLuint id)
+ : decoder_(decoder) {
+ ScopedGLErrorSuppressor suppressor(decoder_);
+ glBindRenderbufferEXT(GL_RENDERBUFFER, id);
+}
+
+ScopedRenderBufferBinder::~ScopedRenderBufferBinder() {
+ ScopedGLErrorSuppressor suppressor(decoder_);
+ glBindRenderbufferEXT(GL_RENDERBUFFER, decoder_->bound_renderbuffer_);
+}
+
+ScopedFrameBufferBinder::ScopedFrameBufferBinder(GLES2DecoderImpl* decoder,
+ GLuint id)
+ : decoder_(decoder) {
+ ScopedGLErrorSuppressor suppressor(decoder_);
+ glBindFramebufferEXT(GL_FRAMEBUFFER, id);
+}
+
+ScopedFrameBufferBinder::~ScopedFrameBufferBinder() {
+ ScopedGLErrorSuppressor suppressor(decoder_);
+ if (decoder_->bound_framebuffer_ == 0 &&
+ decoder_->offscreen_target_frame_buffer_.get()) {
+ glBindFramebufferEXT(GL_FRAMEBUFFER,
+ decoder_->offscreen_target_frame_buffer_->id());
+ } else {
+ glBindFramebufferEXT(GL_FRAMEBUFFER, decoder_->bound_framebuffer_);
+ }
+}
+
+Texture::Texture(GLES2DecoderImpl* decoder)
+ : decoder_(decoder),
+ id_(0) {
+}
+
+Texture::~Texture() {
+ // This does not destroy the render texture because that would require that
+ // the associated GL context was current. Just check that it was explicitly
+ // destroyed.
+ DCHECK_EQ(id_, 0u);
+}
+
+void Texture::Create() {
+ ScopedGLErrorSuppressor suppressor(decoder_);
+ Destroy();
+ glGenTextures(1, &id_);
+}
+
+bool Texture::AllocateStorage(const gfx::Size& size) {
+ DCHECK_NE(id_, 0u);
+ ScopedGLErrorSuppressor suppressor(decoder_);
+ ScopedTexture2DBinder binder(decoder_, id_);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(
+ GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
+
+ glTexImage2D(GL_TEXTURE_2D,
+ 0, // mip level
+ GL_RGBA,
+ size.width(),
+ size.height(),
+ 0, // border
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ NULL);
+
+ return glGetError() == GL_NO_ERROR;
+}
+
+void Texture::Copy(const gfx::Size& size) {
+ DCHECK_NE(id_, 0u);
+ ScopedGLErrorSuppressor suppressor(decoder_);
+ ScopedTexture2DBinder binder(decoder_, id_);
+ glCopyTexImage2D(GL_TEXTURE_2D,
+ 0, // level
+ GL_RGBA,
+ 0, 0,
+ size.width(),
+ size.height(),
+ 0); // border
+}
+
+void Texture::Destroy() {
+ if (id_ != 0) {
+ ScopedGLErrorSuppressor suppressor(decoder_);
+ glDeleteTextures(1, &id_);
+ id_ = 0;
+ }
+}
+
+RenderBuffer::RenderBuffer(GLES2DecoderImpl* decoder)
+ : decoder_(decoder),
+ id_(0) {
+}
+
+RenderBuffer::~RenderBuffer() {
+ // This does not destroy the render buffer because that would require that
+ // the associated GL context was current. Just check that it was explicitly
+ // destroyed.
+ DCHECK_EQ(id_, 0u);
+}
+
+void RenderBuffer::Create() {
+ ScopedGLErrorSuppressor suppressor(decoder_);
+ Destroy();
+ glGenRenderbuffersEXT(1, &id_);
+}
+
+bool RenderBuffer::AllocateStorage(const gfx::Size& size, GLenum format) {
+ ScopedGLErrorSuppressor suppressor(decoder_);
+ ScopedRenderBufferBinder binder(decoder_, id_);
+ glRenderbufferStorageEXT(GL_RENDERBUFFER,
+ format,
+ size.width(),
+ size.height());
+ return glGetError() == GL_NO_ERROR;
+}
+
+void RenderBuffer::Destroy() {
+ if (id_ != 0) {
+ ScopedGLErrorSuppressor suppressor(decoder_);
+ glDeleteRenderbuffersEXT(1, &id_);
+ id_ = 0;
+ }
+}
+
+FrameBuffer::FrameBuffer(GLES2DecoderImpl* decoder)
+ : decoder_(decoder),
+ id_(0) {
+}
+
+FrameBuffer::~FrameBuffer() {
+ // This does not destroy the frame buffer because that would require that
+ // the associated GL context was current. Just check that it was explicitly
+ // destroyed.
+ DCHECK_EQ(id_, 0u);
+}
+
+void FrameBuffer::Create() {
+ ScopedGLErrorSuppressor suppressor(decoder_);
+ Destroy();
+ glGenFramebuffersEXT(1, &id_);
+}
+
+void FrameBuffer::AttachRenderTexture(Texture* texture) {
+ DCHECK_NE(id_, 0u);
+ ScopedGLErrorSuppressor suppressor(decoder_);
+ ScopedFrameBufferBinder binder(decoder_, id_);
+ GLuint attach_id = texture ? texture->id() : 0;
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D,
+ attach_id,
+ 0);
+}
+
+void FrameBuffer::AttachDepthStencilRenderBuffer(RenderBuffer* render_buffer) {
+ DCHECK_NE(id_, 0u);
+ ScopedGLErrorSuppressor suppressor(decoder_);
+ ScopedFrameBufferBinder binder(decoder_, id_);
+ GLuint attach_id = render_buffer ? render_buffer->id() : 0;
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER,
+ GL_DEPTH_ATTACHMENT,
+ GL_RENDERBUFFER,
+ attach_id);
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER,
+ GL_STENCIL_ATTACHMENT,
+ GL_RENDERBUFFER,
+ attach_id);
+}
+
+void FrameBuffer::Clear(GLbitfield buffers) {
+ ScopedGLErrorSuppressor suppressor(decoder_);
+ ScopedFrameBufferBinder binder(decoder_, id_);
+ glClear(buffers);
+}
+
+void FrameBuffer::Destroy() {
+ if (id_ != 0) {
+ ScopedGLErrorSuppressor suppressor(decoder_);
+ glDeleteFramebuffersEXT(1, &id_);
+ id_ = 0;
+ }
+}
+
+GLenum FrameBuffer::CheckStatus() {
+ DCHECK_NE(id_, 0u);
+ ScopedGLErrorSuppressor suppressor(decoder_);
+ ScopedFrameBufferBinder binder(decoder_, id_);
+ return glCheckFramebufferStatusEXT(GL_FRAMEBUFFER);
+}
+
GLES2Decoder* GLES2Decoder::Create(ContextGroup* group) {
return new GLES2DecoderImpl(group);
}
@@ -750,11 +1161,21 @@ GLES2DecoderImpl::GLES2DecoderImpl(ContextGroup* group)
anti_aliased_(false) {
}
-bool GLES2DecoderImpl::Initialize() {
+bool GLES2DecoderImpl::Initialize(GLES2Decoder* parent,
+ const gfx::Size& size,
+ uint32 parent_client_texture_id) {
+ // Keep only a weak pointer to the parent so we don't unmap its client
+ // frame buffer is after it has been destroyed.
+ if (parent)
+ parent_ = static_cast<GLES2DecoderImpl*>(parent)->AsWeakPtr();
+
+ pending_size_ = size;
+
if (!InitPlatformSpecific()) {
Destroy();
return false;
}
+
if (!MakeCurrent()) {
Destroy();
return false;
@@ -806,6 +1227,52 @@ bool GLES2DecoderImpl::Initialize() {
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
CHECK_GL_ERROR();
+ if (size.width() > 0 && size.height() > 0) {
+ // Create the target frame buffer. This is the one that the client renders
+ // directly to.
+ offscreen_target_frame_buffer_.reset(new FrameBuffer(this));
+ offscreen_target_frame_buffer_->Create();
+ offscreen_target_color_texture_.reset(new Texture(this));
+ offscreen_target_color_texture_->Create();
+ offscreen_target_depth_stencil_render_buffer_.reset(
+ new RenderBuffer(this));
+ offscreen_target_depth_stencil_render_buffer_->Create();
+
+ // Create the saved offscreen texture. The target frame buffer is copied
+ // here when SwapBuffers is called.
+ offscreen_saved_color_texture_.reset(new Texture(this));
+ offscreen_saved_color_texture_->Create();
+
+ // Create the temporary frame buffer, used to operate on render textures
+ // without concern for state the client might have changed on the frame
+ // buffers it has access to, like the clear color and the color mask.
+ temporary_frame_buffer_.reset(new FrameBuffer(this));
+ temporary_frame_buffer_->Create();
+
+ // Map the ID of the saved offscreen texture into the parent so that
+ // it can reference it.
+ if (parent_) {
+ GLuint service_id = offscreen_saved_color_texture_->id();
+ parent_->id_manager()->AddMapping(parent_client_texture_id,
+ service_id);
+ TextureManager::TextureInfo* info =
+ parent_->CreateTextureInfo(service_id);
+ parent_->texture_manager()->SetInfoTarget(info, GL_TEXTURE_2D);
+ }
+
+ // Allocate the render buffers at their initial size and check the status
+ // of the frame buffers is okay.
+ if (!UpdateOffscreenFrameBufferSize()) {
+ DLOG(ERROR) << "Could not allocate offscreen buffer storage.";
+ Destroy();
+ return false;
+ }
+
+ // Bind to the new default frame buffer (the offscreen target frame buffer).
+ // This should now be associated with ID zero.
+ DoBindFramebuffer(GL_FRAMEBUFFER, 0);
+ }
+
return true;
}
@@ -919,7 +1386,7 @@ bool GLES2DecoderImpl::InitializeOneOff(bool anti_aliased) {
// GL context was successfully created and applied to the window's DC.
// Startup GLEW, the GL extensions wrangler.
if (InitGlew()) {
- DLOG(INFO) << "Initialized GLEW " << ::glewGetString(GLEW_VERSION);
+ DLOG(INFO) << "Initialized GLEW " << glewGetString(GLEW_VERSION);
} else {
::wglMakeCurrent(intermediate_dc, NULL);
::wglDeleteContext(gl_context);
@@ -1124,6 +1591,7 @@ void GLES2DecoderImpl::UnregisterObjects(
}
bool GLES2DecoderImpl::InitPlatformSpecific() {
+ bool offscreen = pending_size_.width() > 0 && pending_size_.height() > 0;
#if defined(UNIT_TEST)
#elif defined(GLES2_GPU_SERVICE_BACKEND_NATIVE_GLES2)
#elif defined(OS_WIN)
@@ -1132,22 +1600,13 @@ bool GLES2DecoderImpl::InitPlatformSpecific() {
if (!success)
return false;
- if (hwnd()) {
- // The GL context will render to this window.
- gl_device_context_ = ::GetDC(hwnd());
-
- if (!::SetPixelFormat(gl_device_context_,
- pixel_format_,
- &kPixelFormatDescriptor)) {
- DLOG(ERROR) << "Unable to set the pixel format for GL context.";
- DestroyPlatformSpecific();
- return false;
- }
- } else {
+ if (offscreen) {
// Create a device context compatible with the primary display.
HDC display_device_context = ::CreateDC(L"DISPLAY", NULL, NULL, NULL);
- // Create a 1 x 1 pbuffer suitable for use with the device.
+ // Create a 1 x 1 pbuffer suitable for use with the device. This is just
+ // a stepping stone towards creating a frame buffer object. It doesn't
+ // matter what size it is.
const int kNoAttributes[] = { 0 };
pbuffer_ = ::wglCreatePbufferARB(display_device_context,
pixel_format_,
@@ -1166,6 +1625,17 @@ bool GLES2DecoderImpl::InitPlatformSpecific() {
DestroyPlatformSpecific();
return false;
}
+ } else {
+ // The GL context will render to this window.
+ gl_device_context_ = ::GetDC(hwnd());
+
+ if (!::SetPixelFormat(gl_device_context_,
+ pixel_format_,
+ &kPixelFormatDescriptor)) {
+ DLOG(ERROR) << "Unable to set the pixel format for GL context.";
+ DestroyPlatformSpecific();
+ return false;
+ }
}
gl_context_ = ::wglCreateContext(gl_device_context_);
@@ -1174,11 +1644,32 @@ bool GLES2DecoderImpl::InitPlatformSpecific() {
DestroyPlatformSpecific();
return false;
}
+
+ if (parent_) {
+ if (!wglShareLists(parent_->gl_context_, gl_context_)) {
+ DLOG(ERROR) << "Could not share GL contexts.";
+ DestroyPlatformSpecific();
+ return false;
+ }
+ }
+
#elif defined(OS_LINUX)
+ // TODO(apatrick): offscreen rendering not yet supported on this platform.
+ DCHECK(!offscreen);
+
+ // TODO(apatrick): parent contexts not yet supported on this platform.
+ DCHECK(!parent_);
+
DCHECK(window());
if (!window()->Initialize())
return false;
#elif defined(OS_MACOSX)
+ // TODO(apatrick): offscreen rendering not yet supported on this platform.
+ DCHECK(!offscreen);
+
+ // TODO(apatrick): parent contexts not yet supported on this platform.
+ DCHECK(!parent_);
+
return surface_.Initialize();
#endif
@@ -1192,7 +1683,7 @@ bool GLES2DecoderImpl::InitGlew() {
GLenum glew_error = glewInit();
if (glew_error != GLEW_OK) {
DLOG(ERROR) << "Unable to initialise GLEW : "
- << ::glewGetErrorString(glew_error);
+ << glewGetErrorString(glew_error);
return false;
}
@@ -1265,6 +1756,85 @@ void GLES2DecoderImpl::DestroyPlatformSpecific() {
#endif
}
+bool GLES2DecoderImpl::UpdateOffscreenFrameBufferSize() {
+ if (current_size_ != pending_size_)
+ return true;
+
+ // Reallocate the offscreen target buffers.
+ if (!offscreen_target_color_texture_->AllocateStorage(pending_size_)) {
+ return false;
+ }
+
+ if (!offscreen_target_depth_stencil_render_buffer_->AllocateStorage(
+ pending_size_, GL_DEPTH24_STENCIL8)) {
+ return false;
+ }
+
+ // Attach the offscreen target buffers to the temporary frame buffer
+ // so they can be cleared using that frame buffer's clear parameters (all
+ // zero, no color mask, etc).
+ temporary_frame_buffer_->AttachRenderTexture(
+ offscreen_target_color_texture_.get());
+ temporary_frame_buffer_->AttachDepthStencilRenderBuffer(
+ offscreen_target_depth_stencil_render_buffer_.get());
+ if (temporary_frame_buffer_->CheckStatus() !=
+ GL_FRAMEBUFFER_COMPLETE) {
+ return false;
+ }
+
+ // Clear the offscreen target buffers to all zero (using the saved frame
+ // buffer they are temporarily attached to).
+ temporary_frame_buffer_->Clear(
+ GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+
+ // Detach the offscreen target buffer.
+ temporary_frame_buffer_->AttachRenderTexture(NULL);
+ temporary_frame_buffer_->AttachDepthStencilRenderBuffer(NULL);
+
+ // Attach the offscreen target buffers to the proper frame buffer.
+ offscreen_target_frame_buffer_->AttachRenderTexture(
+ offscreen_target_color_texture_.get());
+ offscreen_target_frame_buffer_->AttachDepthStencilRenderBuffer(
+ offscreen_target_depth_stencil_render_buffer_.get());
+ if (offscreen_target_frame_buffer_->CheckStatus() !=
+ GL_FRAMEBUFFER_COMPLETE) {
+ return false;
+ }
+
+ // Create the saved offscreen color texture.
+ offscreen_saved_color_texture_->AllocateStorage(pending_size_);
+
+ // Clear the offscreen saved color texture by copying the cleared target
+ // frame buffer into it.
+ {
+ ScopedFrameBufferBinder binder(this, offscreen_target_frame_buffer_->id());
+ offscreen_saved_color_texture_->Copy(pending_size_);
+ }
+
+ // Update the info about the offscreen saved color texture in the parent.
+ // The reference to the parent is a weak pointer and will become null if the
+ // parent is later destroyed.
+ if (parent_) {
+ GLuint service_id = offscreen_saved_color_texture_->id();
+
+ TextureManager::TextureInfo* info =
+ parent_->texture_manager()->GetTextureInfo(service_id);
+ DCHECK(info);
+
+ info->SetLevelInfo(GL_TEXTURE_2D,
+ 0, // level
+ GL_RGBA,
+ pending_size_.width(), pending_size_.height(),
+ 1, // depth
+ 0, // border
+ GL_RGBA,
+ GL_UNSIGNED_BYTE);
+ }
+
+ current_size_ = pending_size_;
+ return true;
+}
+
#if defined(OS_MACOSX)
uint64 GLES2DecoderImpl::SetWindowSizeForIOSurface(int32 width, int32 height) {
@@ -1300,6 +1870,37 @@ void GLES2DecoderImpl::SetSwapBuffersCallback(Callback0::Type* callback) {
}
void GLES2DecoderImpl::Destroy() {
+ MakeCurrent();
+
+ // Remove the saved frame buffer mapping from the parent decoder. The
+ // parent pointer is a weak pointer so it will be null if the parent has
+ // already been destroyed.
+ if (parent_) {
+ // First check the texture has been mapped into the parent. This might not
+ // be the case if initialization failed midway through.
+ GLuint service_id = offscreen_saved_color_texture_->id();
+ GLuint client_id;
+ if (parent_->id_manager()->GetClientId(service_id, &client_id)) {
+ parent_->texture_manager()->RemoveTextureInfo(service_id);
+ parent_->id_manager()->RemoveMapping(client_id, service_id);
+ }
+ }
+
+ if (offscreen_target_frame_buffer_.get())
+ offscreen_target_frame_buffer_->Destroy();
+
+ if (offscreen_target_color_texture_.get())
+ offscreen_target_color_texture_->Destroy();
+
+ if (offscreen_target_depth_stencil_render_buffer_.get())
+ offscreen_target_depth_stencil_render_buffer_->Destroy();
+
+ if (temporary_frame_buffer_.get())
+ temporary_frame_buffer_->Destroy();
+
+ if (offscreen_saved_color_texture_.get())
+ offscreen_saved_color_texture_->Destroy();
+
#if defined(UNIT_TEST)
#elif defined(GLES2_GPU_SERVICE_BACKEND_NATIVE_GLES2)
#elif defined(OS_LINUX)
@@ -1312,6 +1913,13 @@ void GLES2DecoderImpl::Destroy() {
DestroyPlatformSpecific();
}
+void GLES2DecoderImpl::ResizeOffscreenFrameBuffer(const gfx::Size& size) {
+ // We can't resize the render buffers immediately because there might be a
+ // partial frame rendered into them and we don't want the tail end of that
+ // rendered into the reallocated storage. Defer until the next SwapBuffers.
+ pending_size_ = size;
+}
+
const char* GLES2DecoderImpl::GetCommandName(unsigned int command_id) const {
if (command_id > kStartPoint && command_id < kNumCommands) {
return gles2::GetCommandName(static_cast<CommandId>(command_id));
@@ -1452,6 +2060,12 @@ void GLES2DecoderImpl::DoBindBuffer(GLenum target, GLuint buffer) {
void GLES2DecoderImpl::DoBindFramebuffer(GLenum target, GLuint framebuffer) {
bound_framebuffer_ = framebuffer;
+
+ // When rendering to an offscreen frame buffer, instead of unbinding from
+ // the current frame buffer, bind to the offscreen target frame buffer.
+ if (framebuffer == 0 && offscreen_target_frame_buffer_.get())
+ framebuffer = offscreen_target_frame_buffer_->id();
+
glBindFramebufferEXT(target, framebuffer);
}
@@ -1685,24 +2299,6 @@ void GLES2DecoderImpl::DoLinkProgram(GLuint program) {
}
};
-void GLES2DecoderImpl::DoSwapBuffers() {
-#if defined(UNIT_TEST)
-#elif defined(GLES2_GPU_SERVICE_BACKEND_NATIVE_GLES2)
-#elif defined(OS_WIN)
- ::SwapBuffers(gl_device_context_);
-#elif defined(OS_LINUX)
- DCHECK(window());
- window()->SwapBuffers();
-#elif defined(OS_MACOSX)
- // TODO(kbr): Need to property hook up and track the OpenGL state and hook
- // up the notion of the currently bound FBO.
- surface_.SwapBuffers();
-#endif
- if (swap_buffers_callback_.get()) {
- swap_buffers_callback_->Run();
- }
-}
-
void GLES2DecoderImpl::DoTexParameterf(
GLenum target, GLenum pname, GLfloat param) {
TextureManager::TextureInfo* info = GetTextureInfoForTarget(target);
@@ -1812,6 +2408,13 @@ void GLES2DecoderImpl::CopyRealGLErrorsToWrapper() {
}
}
+void GLES2DecoderImpl::ClearRealGLErrors() {
+ GLenum error;
+ while ((error = glGetError()) != GL_NO_ERROR) {
+ NOTREACHED() << "GL error " << error << " was unhandled.";
+ }
+}
+
bool GLES2DecoderImpl::VertexAttribInfo::CanAccess(GLuint index) {
if (!enabled_) {
return true;
@@ -2981,6 +3584,48 @@ error::Error GLES2DecoderImpl::HandleGetActiveAttrib(
return error::kNoError;
}
+error::Error GLES2DecoderImpl::HandleSwapBuffers(
+ uint32 immediate_data_size, const gles2::SwapBuffers& c) {
+ // Check a client created frame buffer is not bound. TODO(apatrick):
+ // this error is overkill. It will require that the client recreate the
+ // context to continue.
+ if (bound_framebuffer_ != 0)
+ return error::kLostContext;
+
+ // If offscreen then don't actually SwapBuffers to the display. Just copy
+ // the rendered frame to another frame buffer.
+ if (offscreen_target_frame_buffer_.get()) {
+ ScopedGLErrorSuppressor suppressor(this);
+
+ // First check to see if a deferred offscreen render buffer resize is
+ // pending.
+ if (!UpdateOffscreenFrameBufferSize())
+ return error::kLostContext;
+
+ ScopedFrameBufferBinder binder(this, offscreen_target_frame_buffer_->id());
+ offscreen_saved_color_texture_->Copy(current_size_);
+ } else {
+#if defined(UNIT_TEST)
+#elif defined(GLES2_GPU_SERVICE_BACKEND_NATIVE_GLES2)
+#elif defined(OS_WIN)
+ ::SwapBuffers(gl_device_context_);
+#elif defined(OS_LINUX)
+ DCHECK(window());
+ window()->SwapBuffers();
+#elif defined(OS_MACOSX)
+ // TODO(kbr): Need to property hook up and track the OpenGL state and hook
+ // up the notion of the currently bound FBO.
+ surface_.SwapBuffers();
+#endif
+ }
+
+ if (swap_buffers_callback_.get()) {
+ swap_buffers_callback_->Run();
+ }
+
+ return error::kNoError;
+}
+
// Include the auto-generated part of this file. We split this because it means
// we can easily edit the non-auto generated parts right here in this file
// instead of having to edit some template or the code generator.
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.h b/gpu/command_buffer/service/gles2_cmd_decoder.h
index 26c6239..58e1193 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.h
@@ -15,6 +15,8 @@
#if defined(OS_MACOSX)
#include "app/surface/transport_dib.h"
#endif
+
+#include "gfx/size.h"
#include "gpu/command_buffer/service/common_decoder.h"
@@ -71,14 +73,20 @@ class GLES2Decoder : public CommonDecoder {
Callback1<TransportDIB::Id>::Type* deallocator) = 0;
#endif
- // Initializes the graphics context.
+ // Initializes the graphics context. Can create an offscreen
+ // decoder with a frame buffer that can be referenced from the parent.
// Returns:
// true if successful.
- virtual bool Initialize() = 0;
+ virtual bool Initialize(GLES2Decoder* parent,
+ const gfx::Size& size,
+ uint32 parent_texture_id) = 0;
// Destroys the graphics context.
virtual void Destroy() = 0;
+ // Resize an offscreen frame buffer.
+ virtual void ResizeOffscreenFrameBuffer(const gfx::Size& size) = 0;
+
// Make this decoder's GL context current.
virtual bool MakeCurrent() = 0;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
index cb534a4..7507d95 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
@@ -2842,11 +2842,5 @@ error::Error GLES2DecoderImpl::HandleViewport(
return error::kNoError;
}
-error::Error GLES2DecoderImpl::HandleSwapBuffers(
- uint32 immediate_data_size, const gles2::SwapBuffers& c) {
- DoSwapBuffers();
- return error::kNoError;
-}
-
#endif // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_AUTOGEN_H_
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
index 2ef2d2d..f94eb7d 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
@@ -7,6 +7,7 @@
#ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_MOCK_H_
#define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_MOCK_H_
+#include "gfx/size.h"
#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
#include "base/callback.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -28,8 +29,11 @@ class MockGLES2Decoder : public GLES2Decoder {
#if defined(OS_MACOSX)
MOCK_METHOD2(SetWindowSize, uint64(int32 width, int32 height));
#endif
- MOCK_METHOD0(Initialize, bool());
+ MOCK_METHOD3(Initialize, bool(GLES2Decoder* parent,
+ const gfx::Size& size,
+ uint32 parent_texture_id));
MOCK_METHOD0(Destroy, void());
+ MOCK_METHOD1(ResizeOffscreenFrameBuffer, void(const gfx::Size& size));
MOCK_METHOD0(MakeCurrent, bool());
MOCK_METHOD1(GetServiceIdForTesting, uint32(uint32 client_id));
MOCK_METHOD0(GetGLES2Util, GLES2Util*());
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
index 0bb32c6..10acd1b 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -92,7 +92,7 @@ void GLES2DecoderTestBase::SetUp() {
shared_memory_id_ = kSharedMemoryId;
decoder_.reset(GLES2Decoder::Create(&group_));
- decoder_->Initialize();
+ decoder_->Initialize(NULL, gfx::Size(), 0);
decoder_->set_engine(engine_.get());
EXPECT_CALL(*gl_, GenBuffersARB(_, _))
diff --git a/gpu/command_buffer/service/gpu_processor.cc b/gpu/command_buffer/service/gpu_processor.cc
index 7a748e7..d08069c 100644
--- a/gpu/command_buffer/service/gpu_processor.cc
+++ b/gpu/command_buffer/service/gpu_processor.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/callback.h"
+#include "base/compiler_specific.h"
#include "base/message_loop.h"
#include "gpu/command_buffer/service/gpu_processor.h"
@@ -12,7 +13,8 @@ namespace gpu {
GPUProcessor::GPUProcessor(CommandBuffer* command_buffer)
: command_buffer_(command_buffer),
- commands_per_update_(100) {
+ commands_per_update_(100),
+ method_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
DCHECK(command_buffer);
decoder_.reset(gles2::GLES2Decoder::Create(&group_));
decoder_->set_engine(this);
@@ -23,13 +25,15 @@ GPUProcessor::GPUProcessor(CommandBuffer* command_buffer,
CommandParser* parser,
int commands_per_update)
: command_buffer_(command_buffer),
- commands_per_update_(commands_per_update) {
+ commands_per_update_(commands_per_update),
+ method_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
DCHECK(command_buffer);
decoder_.reset(decoder);
parser_.reset(parser);
}
GPUProcessor::~GPUProcessor() {
+ Destroy();
}
void GPUProcessor::ProcessCommands() {
@@ -59,7 +63,8 @@ void GPUProcessor::ProcessCommands() {
if (!parser_->IsEmpty()) {
MessageLoop::current()->PostTask(
- FROM_HERE, NewRunnableMethod(this, &GPUProcessor::ProcessCommands));
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(&GPUProcessor::ProcessCommands));
}
}
@@ -83,6 +88,10 @@ int32 GPUProcessor::GetGetOffset() {
return parser_->get();
}
+void GPUProcessor::ResizeOffscreenFrameBuffer(const gfx::Size& size) {
+ decoder_->ResizeOffscreenFrameBuffer(size);
+}
+
#if defined(OS_MACOSX)
uint64 GPUProcessor::SetWindowSizeForIOSurface(int32 width, int32 height) {
return decoder_->SetWindowSizeForIOSurface(width, height);
diff --git a/gpu/command_buffer/service/gpu_processor.h b/gpu/command_buffer/service/gpu_processor.h
index d34e35d..d61bd60 100644
--- a/gpu/command_buffer/service/gpu_processor.h
+++ b/gpu/command_buffer/service/gpu_processor.h
@@ -9,7 +9,9 @@
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "base/shared_memory.h"
+#include "base/task.h"
#include "gfx/native_widget_types.h"
+#include "gfx/size.h"
#include "gpu/command_buffer/common/command_buffer.h"
#include "gpu/command_buffer/service/cmd_buffer_engine.h"
#include "gpu/command_buffer/service/cmd_parser.h"
@@ -20,8 +22,7 @@ namespace gpu {
// This class processes commands in a command buffer. It is event driven and
// posts tasks to the current message loop to do additional work.
-class GPUProcessor : public base::RefCounted<GPUProcessor>,
- public CommandBufferEngine {
+class GPUProcessor : public CommandBufferEngine {
public:
explicit GPUProcessor(CommandBuffer* command_buffer);
@@ -31,7 +32,10 @@ class GPUProcessor : public base::RefCounted<GPUProcessor>,
CommandParser* parser,
int commands_per_update);
- virtual bool Initialize(gfx::PluginWindowHandle hwnd);
+ virtual bool Initialize(gfx::PluginWindowHandle hwnd,
+ GPUProcessor* parent,
+ const gfx::Size& size,
+ uint32 parent_texture_id);
virtual ~GPUProcessor();
@@ -45,6 +49,9 @@ class GPUProcessor : public base::RefCounted<GPUProcessor>,
virtual bool SetGetOffset(int32 offset);
virtual int32 GetGetOffset();
+ // Asynchronously resizes an offscreen frame buffer.
+ void ResizeOffscreenFrameBuffer(const gfx::Size& size);
+
#if defined(OS_MACOSX)
// Needed only on Mac OS X, which does not render into an on-screen
// window and therefore requires the backing store to be resized
@@ -71,37 +78,15 @@ class GPUProcessor : public base::RefCounted<GPUProcessor>,
// through the ProcessCommands callback.
CommandBuffer* command_buffer_;
- scoped_ptr< ::base::SharedMemory> mapped_ring_buffer_;
int commands_per_update_;
gles2::ContextGroup group_;
scoped_ptr<gles2::GLES2Decoder> decoder_;
scoped_ptr<CommandParser> parser_;
+
+ ScopedRunnableMethodFactory<GPUProcessor> method_factory_;
};
} // namespace gpu
-// Callbacks to the GPUProcessor hold a reference count.
-template <typename Method>
-class CallbackStorage<gpu::GPUProcessor, Method> {
- public:
- CallbackStorage(gpu::GPUProcessor* obj, Method method)
- : obj_(obj),
- meth_(method) {
- DCHECK(obj_);
- obj_->AddRef();
- }
-
- ~CallbackStorage() {
- obj_->Release();
- }
-
- protected:
- gpu::GPUProcessor* obj_;
- Method meth_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(CallbackStorage);
-};
-
#endif // GPU_COMMAND_BUFFER_SERVICE_GPU_PROCESSOR_H_
diff --git a/gpu/command_buffer/service/gpu_processor_linux.cc b/gpu/command_buffer/service/gpu_processor_linux.cc
index 205cceb..d430933 100644
--- a/gpu/command_buffer/service/gpu_processor_linux.cc
+++ b/gpu/command_buffer/service/gpu_processor_linux.cc
@@ -10,7 +10,10 @@ using ::base::SharedMemory;
namespace gpu {
-bool GPUProcessor::Initialize(gfx::PluginWindowHandle handle) {
+bool GPUProcessor::Initialize(gfx::PluginWindowHandle handle,
+ GPUProcessor* parent,
+ const gfx::Size& size,
+ uint32 parent_texture_id) {
DCHECK(handle);
// Cannot reinitialize.
@@ -34,17 +37,27 @@ bool GPUProcessor::Initialize(gfx::PluginWindowHandle handle) {
// Initialize GAPI immediately if the window handle is valid.
XWindowWrapper *window = new XWindowWrapper(GDK_DISPLAY(), handle);
decoder_->set_window_wrapper(window);
- return decoder_->Initialize();
-}
+ gles2::GLES2Decoder* parent_decoder = parent ? parent->decoder_.get() : NULL;
+ if (!decoder_->Initialize(parent_decoder,
+ size,
+ parent_texture_id)) {
+ Destroy();
+ return false;
+ }
+
+ return true;}
void GPUProcessor::Destroy() {
- // Destroy GAPI if window handle has not already become invalid.
- XWindowWrapper *window = decoder_->window();
- if (window) {
+ // Destroy decoder if initialized.
+ if (decoder_.get()) {
+ XWindowWrapper *window = decoder_->window();
decoder_->Destroy();
decoder_->set_window_wrapper(NULL);
delete window;
+ decoder_.reset();
}
+
+ parser_.reset();
}
} // namespace gpu
diff --git a/gpu/command_buffer/service/gpu_processor_mac.cc b/gpu/command_buffer/service/gpu_processor_mac.cc
index a36560c..ef13fc6 100644
--- a/gpu/command_buffer/service/gpu_processor_mac.cc
+++ b/gpu/command_buffer/service/gpu_processor_mac.cc
@@ -8,7 +8,10 @@ using ::base::SharedMemory;
namespace gpu {
-bool GPUProcessor::Initialize(gfx::PluginWindowHandle handle) {
+bool GPUProcessor::Initialize(gfx::PluginWindowHandle handle,
+ GPUProcessor* parent,
+ const gfx::Size& size,
+ uint32 parent_texture_id) {
// At this level we do not need the PluginWindowHandle. It is only
// needed at the CommandBufferStub level to identify which GPU
// plugin instance is creating a new backing store in response to a
@@ -29,11 +32,25 @@ bool GPUProcessor::Initialize(gfx::PluginWindowHandle handle) {
}
// Initialize GAPI.
- return decoder_->Initialize();
+ gles2::GLES2Decoder* parent_decoder = parent ? parent->decoder_.get() : NULL;
+ if (!decoder_->Initialize(parent_decoder,
+ size,
+ parent_texture_id)) {
+ Destroy();
+ return false;
+ }
+
+ return true;
}
void GPUProcessor::Destroy() {
- decoder_->Destroy();
+ // Destroy decoder if initialized.
+ if (decoder_.get()) {
+ decoder_->Destroy();
+ decoder_.reset();
+ }
+
+ parser_.reset();
}
} // namespace gpu
diff --git a/gpu/command_buffer/service/gpu_processor_unittest.cc b/gpu/command_buffer/service/gpu_processor_unittest.cc
index 51cfe01..95be087 100644
--- a/gpu/command_buffer/service/gpu_processor_unittest.cc
+++ b/gpu/command_buffer/service/gpu_processor_unittest.cc
@@ -58,10 +58,10 @@ class GPUProcessorTest : public testing::Test {
0,
async_api_.get());
- processor_ = new GPUProcessor(command_buffer_.get(),
- decoder_,
- parser_,
- 2);
+ processor_.reset(new GPUProcessor(command_buffer_.get(),
+ decoder_,
+ parser_,
+ 2));
}
virtual void TearDown() {
@@ -85,7 +85,7 @@ class GPUProcessorTest : public testing::Test {
gles2::MockGLES2Decoder* decoder_;
CommandParser* parser_;
scoped_ptr<AsyncAPIMock> async_api_;
- scoped_refptr<GPUProcessor> processor_;
+ scoped_ptr<GPUProcessor> processor_;
};
TEST_F(GPUProcessorTest, ProcessorDoesNothingIfRingBufferIsEmpty) {
diff --git a/gpu/command_buffer/service/gpu_processor_win.cc b/gpu/command_buffer/service/gpu_processor_win.cc
index bce783b..537872c 100644
--- a/gpu/command_buffer/service/gpu_processor_win.cc
+++ b/gpu/command_buffer/service/gpu_processor_win.cc
@@ -10,7 +10,10 @@ using ::base::SharedMemory;
namespace gpu {
-bool GPUProcessor::Initialize(gfx::PluginWindowHandle handle) {
+bool GPUProcessor::Initialize(gfx::PluginWindowHandle handle,
+ GPUProcessor* parent,
+ const gfx::Size& size,
+ uint32 parent_texture_id) {
// Cannot reinitialize.
if (parser_.get())
return false;
@@ -31,14 +34,25 @@ bool GPUProcessor::Initialize(gfx::PluginWindowHandle handle) {
// Initialize GAPI immediately if the window handle is valid.
decoder_->set_hwnd(handle);
- return decoder_->Initialize();
+ gles2::GLES2Decoder* parent_decoder = parent ? parent->decoder_.get() : NULL;
+ if (!decoder_->Initialize(parent_decoder,
+ size,
+ parent_texture_id)) {
+ Destroy();
+ return false;
+ }
+
+ return true;
}
void GPUProcessor::Destroy() {
// Destroy decoder if initialized.
- if (parser_.get()) {
+ if (decoder_.get()) {
decoder_->Destroy();
decoder_->set_hwnd(NULL);
+ decoder_.reset();
}
+
+ parser_.reset();
}
} // namespace gpu
diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc
index d6a1dce..4369199 100644
--- a/gpu/command_buffer/service/texture_manager.cc
+++ b/gpu/command_buffer/service/texture_manager.cc
@@ -265,12 +265,13 @@ TextureManager::TextureManager(
max_cube_map_texture_size)) {
}
-void TextureManager::CreateTextureInfo(GLuint texture_id) {
+TextureManager::TextureInfo* TextureManager::CreateTextureInfo(
+ GLuint texture_id) {
+ TextureInfo::Ref info(new TextureInfo(texture_id));
std::pair<TextureInfoMap::iterator, bool> result =
- texture_infos_.insert(
- std::make_pair(texture_id,
- TextureInfo::Ref(new TextureInfo(texture_id))));
+ texture_infos_.insert(std::make_pair(texture_id, info));
DCHECK(result.second);
+ return info.get();
}
TextureManager::TextureInfo* TextureManager::GetTextureInfo(
diff --git a/gpu/command_buffer/service/texture_manager.h b/gpu/command_buffer/service/texture_manager.h
index 358cbbc..2dba85d 100644
--- a/gpu/command_buffer/service/texture_manager.h
+++ b/gpu/command_buffer/service/texture_manager.h
@@ -229,7 +229,7 @@ class TextureManager {
}
// Creates a new texture info.
- void CreateTextureInfo(GLuint texture_id);
+ TextureInfo* CreateTextureInfo(GLuint texture_id);
// Gets the texture info for the given texture.
TextureInfo* GetTextureInfo(GLuint texture_id);
diff --git a/gpu/demos/framework/window.cc b/gpu/demos/framework/window.cc
index 600514f..0a9db79 100644
--- a/gpu/demos/framework/window.cc
+++ b/gpu/demos/framework/window.cc
@@ -50,20 +50,23 @@ void Window::OnPaint() {
::gles2::GetGLContext()->SwapBuffers();
}
+// TODO(apatrick): It looks like all the resources allocated here leak. We
+// should fix that if we want to use this Window class for anything beyond this
+// simple use case.
bool Window::CreateRenderContext(gfx::PluginWindowHandle hwnd) {
scoped_ptr<CommandBufferService> command_buffer(new CommandBufferService);
if (!command_buffer->Initialize(kCommandBufferSize)) {
return false;
}
- scoped_refptr<GPUProcessor> gpu_processor(
+ GPUProcessor* gpu_processor(
new GPUProcessor(command_buffer.get()));
- if (!gpu_processor->Initialize(hwnd)) {
+ if (!gpu_processor->Initialize(hwnd, NULL, gfx::Size(), 0)) {
return false;
}
command_buffer->SetPutOffsetChangeCallback(
- NewCallback(gpu_processor.get(), &GPUProcessor::ProcessCommands));
+ NewCallback(gpu_processor, &GPUProcessor::ProcessCommands));
GLES2CmdHelper* helper = new GLES2CmdHelper(command_buffer.get());
if (!helper->Initialize()) {
diff --git a/gpu/gpu.gyp b/gpu/gpu.gyp
index 4e3106f..06818fc 100644
--- a/gpu/gpu.gyp
+++ b/gpu/gpu.gyp
@@ -247,6 +247,7 @@
'dependencies': [
'command_buffer_common',
'gl_libs',
+ '../gfx/gfx.gyp:gfx',
],
'sources': [
'command_buffer/service/common_decoder.cc',