diff options
20 files changed, 253 insertions, 124 deletions
diff --git a/content/common/gpu/gpu_channel.cc b/content/common/gpu/gpu_channel.cc index 17de5c4..459c5ec 100644 --- a/content/common/gpu/gpu_channel.cc +++ b/content/common/gpu/gpu_channel.cc @@ -189,12 +189,22 @@ void GpuChannel::CreateViewCommandBuffer( content::GetContentClient()->SetActiveURL(init_params.active_url); #if defined(ENABLE_GPU) + GpuCommandBufferStub* share_group = stubs_.Lookup(init_params.share_group_id); + *route_id = GenerateRouteID(); scoped_ptr<GpuCommandBufferStub> stub(new GpuCommandBufferStub( - this, window, gfx::Size(), disallowed_extensions_, + this, + share_group, + window, + gfx::Size(), + disallowed_extensions_, init_params.allowed_extensions, - init_params.attribs, *route_id, renderer_id_, render_view_id, - watchdog_, software_)); + init_params.attribs, + *route_id, + renderer_id_, + render_view_id, + watchdog_, + software_)); router_.AddRoute(*route_id, stub.get()); stubs_.AddWithID(stub.release(), *route_id); #endif // ENABLE_GPU @@ -293,10 +303,13 @@ void GpuChannel::OnCreateOffscreenCommandBuffer( content::GetContentClient()->SetActiveURL(init_params.active_url); #if defined(ENABLE_GPU) + GpuCommandBufferStub* share_group = stubs_.Lookup(init_params.share_group_id); + route_id = GenerateRouteID(); scoped_ptr<GpuCommandBufferStub> stub(new GpuCommandBufferStub( this, + share_group, gfx::kNullPluginWindow, size, disallowed_extensions_, diff --git a/content/common/gpu/gpu_command_buffer_stub.cc b/content/common/gpu/gpu_command_buffer_stub.cc index e1e95bb..8291648 100644 --- a/content/common/gpu/gpu_command_buffer_stub.cc +++ b/content/common/gpu/gpu_command_buffer_stub.cc @@ -29,6 +29,7 @@ using gpu::Buffer; GpuCommandBufferStub::GpuCommandBufferStub( GpuChannel* channel, + GpuCommandBufferStub* share_group, gfx::PluginWindowHandle handle, const gfx::Size& size, const gpu::gles2::DisallowedExtensions& disallowed_extensions, @@ -54,6 +55,10 @@ GpuCommandBufferStub::GpuCommandBufferStub( parent_texture_for_initialization_(0), watchdog_(watchdog), task_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { + if (share_group) + context_group_ = share_group->context_group_; + else + context_group_ = new gpu::gles2::ContextGroup; } GpuCommandBufferStub::~GpuCommandBufferStub() { @@ -147,7 +152,7 @@ void GpuCommandBufferStub::OnInitialize( if (command_buffer_->Initialize(&shared_memory, size)) { scheduler_.reset(gpu::GpuScheduler::Create(command_buffer_.get(), channel_, - NULL)); + context_group_.get())); #if defined(TOUCH_UI) if (software_) { OnInitializeFailed(reply_message); diff --git a/content/common/gpu/gpu_command_buffer_stub.h b/content/common/gpu/gpu_command_buffer_stub.h index a6e91fb..f6e31f8 100644 --- a/content/common/gpu/gpu_command_buffer_stub.h +++ b/content/common/gpu/gpu_command_buffer_stub.h @@ -17,6 +17,7 @@ #include "base/task.h" #include "content/common/gpu/media/gpu_video_decode_accelerator.h" #include "gpu/command_buffer/service/command_buffer_service.h" +#include "gpu/command_buffer/service/context_group.h" #include "gpu/command_buffer/service/gpu_scheduler.h" #include "ipc/ipc_channel.h" #include "ipc/ipc_message.h" @@ -33,6 +34,7 @@ class GpuCommandBufferStub public: GpuCommandBufferStub( GpuChannel* channel, + GpuCommandBufferStub* share_group, gfx::PluginWindowHandle handle, const gfx::Size& size, const gpu::gles2::DisallowedExtensions& disallowed_extensions, @@ -133,6 +135,9 @@ class GpuCommandBufferStub // are destroyed. So a raw pointer is safe. GpuChannel* channel_; + // The group of contexts that share namespaces with this context. + scoped_refptr<gpu::gles2::ContextGroup> context_group_; + gfx::PluginWindowHandle handle_; gfx::Size initial_size_; gpu::gles2::DisallowedExtensions disallowed_extensions_; diff --git a/content/common/gpu/gpu_messages.h b/content/common/gpu/gpu_messages.h index 1b48b53..2861a25 100644 --- a/content/common/gpu/gpu_messages.h +++ b/content/common/gpu/gpu_messages.h @@ -23,6 +23,7 @@ #define IPC_MESSAGE_START GpuMsgStart IPC_STRUCT_BEGIN(GPUCreateCommandBufferConfig) + IPC_STRUCT_MEMBER(int32, share_group_id) IPC_STRUCT_MEMBER(std::string, allowed_extensions) IPC_STRUCT_MEMBER(std::vector<int>, attribs) IPC_STRUCT_MEMBER(GURL, active_url) diff --git a/content/renderer/gpu/gpu_channel_host.cc b/content/renderer/gpu/gpu_channel_host.cc index ee79249..a82ce74 100644 --- a/content/renderer/gpu/gpu_channel_host.cc +++ b/content/renderer/gpu/gpu_channel_host.cc @@ -97,6 +97,7 @@ bool GpuChannelHost::Send(IPC::Message* message) { CommandBufferProxy* GpuChannelHost::CreateViewCommandBuffer( int render_view_id, + CommandBufferProxy* share_group, const std::string& allowed_extensions, const std::vector<int32>& attribs, const GURL& active_url) { @@ -106,13 +107,17 @@ CommandBufferProxy* GpuChannelHost::CreateViewCommandBuffer( return NULL; GPUCreateCommandBufferConfig init_params; + init_params.share_group_id = + share_group ? share_group->route_id() : MSG_ROUTING_NONE; init_params.allowed_extensions = allowed_extensions; init_params.attribs = attribs; init_params.active_url = active_url; int32 route_id; if (!RenderThread::current()->Send( new GpuHostMsg_CreateViewCommandBuffer( - render_view_id, init_params, &route_id))) { + render_view_id, + init_params, + &route_id))) { return NULL; } @@ -140,6 +145,7 @@ GpuVideoDecodeAcceleratorHost* GpuChannelHost::CreateVideoDecoder( CommandBufferProxy* GpuChannelHost::CreateOffscreenCommandBuffer( const gfx::Size& size, + CommandBufferProxy* share_group, const std::string& allowed_extensions, const std::vector<int32>& attribs, const GURL& active_url) { @@ -149,6 +155,8 @@ CommandBufferProxy* GpuChannelHost::CreateOffscreenCommandBuffer( return NULL; GPUCreateCommandBufferConfig init_params; + init_params.share_group_id = + share_group ? share_group->route_id() : MSG_ROUTING_NONE; init_params.allowed_extensions = allowed_extensions; init_params.attribs = attribs; init_params.active_url = active_url; diff --git a/content/renderer/gpu/gpu_channel_host.h b/content/renderer/gpu/gpu_channel_host.h index c2eb9ff..4f77738 100644 --- a/content/renderer/gpu/gpu_channel_host.h +++ b/content/renderer/gpu/gpu_channel_host.h @@ -69,6 +69,7 @@ class GpuChannelHost : public IPC::Channel::Listener, // Create and connect to a command buffer in the GPU process. CommandBufferProxy* CreateViewCommandBuffer( int render_view_id, + CommandBufferProxy* share_group, const std::string& allowed_extensions, const std::vector<int32>& attribs, const GURL& active_url); @@ -76,6 +77,7 @@ class GpuChannelHost : public IPC::Channel::Listener, // Create and connect to a command buffer in the GPU process. CommandBufferProxy* CreateOffscreenCommandBuffer( const gfx::Size& size, + CommandBufferProxy* share_group, const std::string& allowed_extensions, const std::vector<int32>& attribs, const GURL& active_url); diff --git a/content/renderer/gpu/renderer_gl_context.cc b/content/renderer/gpu/renderer_gl_context.cc index 894a950..4a969d3 100644 --- a/content/renderer/gpu/renderer_gl_context.cc +++ b/content/renderer/gpu/renderer_gl_context.cc @@ -83,6 +83,7 @@ RendererGLContext::~RendererGLContext() { RendererGLContext* RendererGLContext::CreateViewContext( GpuChannelHost* channel, int render_view_id, + RendererGLContext* share_group, const char* allowed_extensions, const int32* attrib_list, const GURL& active_url) { @@ -92,6 +93,7 @@ RendererGLContext* RendererGLContext::CreateViewContext( true, render_view_id, gfx::Size(), + share_group, allowed_extensions, attrib_list, active_url)) @@ -114,6 +116,7 @@ void RendererGLContext::ResizeOnscreen(const gfx::Size& size) { RendererGLContext* RendererGLContext::CreateOffscreenContext( GpuChannelHost* channel, const gfx::Size& size, + RendererGLContext* share_group, const char* allowed_extensions, const int32* attrib_list, const GURL& active_url) { @@ -123,6 +126,7 @@ RendererGLContext* RendererGLContext::CreateOffscreenContext( false, 0, size, + share_group, allowed_extensions, attrib_list, active_url)) @@ -195,45 +199,14 @@ uint32 RendererGLContext::GetParentTextureId() { } uint32 RendererGLContext::CreateParentTexture(const gfx::Size& size) { - // Allocate a texture ID with respect to the parent. - if (parent_.get()) { - if (!MakeCurrent(parent_.get())) - return 0; - uint32 texture_id = parent_->gles2_implementation_->MakeTextureId(); - parent_->gles2_implementation_->BindTexture(GL_TEXTURE_2D, texture_id); - parent_->gles2_implementation_->TexParameteri( - GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - parent_->gles2_implementation_->TexParameteri( - GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - parent_->gles2_implementation_->TexParameteri( - GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - parent_->gles2_implementation_->TexParameteri( - GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - parent_->gles2_implementation_->TexImage2D(GL_TEXTURE_2D, - 0, // mip level - GL_RGBA, - size.width(), - size.height(), - 0, // border - GL_RGBA, - GL_UNSIGNED_BYTE, - NULL); - // Make sure that the parent texture's storage is allocated before we let - // the caller attempt to use it. - int32 token = parent_->gles2_helper_->InsertToken(); - parent_->gles2_helper_->WaitForToken(token); - return texture_id; - } - return 0; + uint32 texture_id = 0; + gles2_implementation_->GenTextures(1, &texture_id); + gles2_implementation_->Flush(); + return texture_id; } void RendererGLContext::DeleteParentTexture(uint32 texture) { - if (parent_.get()) { - if (!MakeCurrent(parent_.get())) - return; - parent_->gles2_implementation_->DeleteTextures(1, &texture); - } + gles2_implementation_->DeleteTextures(1, &texture); } void RendererGLContext::SetSwapBuffersCallback(Callback0::Type* callback) { @@ -330,6 +303,7 @@ RendererGLContext::RendererGLContext(GpuChannelHost* channel) bool RendererGLContext::Initialize(bool onscreen, int render_view_id, const gfx::Size& size, + RendererGLContext* share_group, const char* allowed_extensions, const int32* attrib_list, const GURL& active_url) { @@ -377,12 +351,14 @@ bool RendererGLContext::Initialize(bool onscreen, "RendererGLContext::Initialize::CreateViewCommandBuffer"); command_buffer_ = channel_->CreateViewCommandBuffer( render_view_id, + share_group ? share_group->command_buffer_ : NULL, allowed_extensions, attribs, active_url); } else { command_buffer_ = channel_->CreateOffscreenCommandBuffer( size, + share_group ? share_group->command_buffer_ : NULL, allowed_extensions, attribs, active_url); @@ -441,7 +417,7 @@ bool RendererGLContext::Initialize(bool onscreen, transfer_buffer.size, transfer_buffer.ptr, transfer_buffer_id_, - false); + true); size_ = size; @@ -452,8 +428,17 @@ void RendererGLContext::Destroy() { TRACE_EVENT0("gpu", "RendererGLContext::Destroy"); SetParent(NULL); - delete gles2_implementation_; - gles2_implementation_ = NULL; + if (gles2_implementation_) { + // First flush the context to ensure that any pending frees of resources + // are completed. Otherwise, if this context is part of a share group, + // those resources might leak. Also, any remaining side effects of commands + // issued on this context might not be visible to other contexts in the + // share group. + gles2_implementation_->Flush(); + + delete gles2_implementation_; + gles2_implementation_ = NULL; + } // Do not destroy this transfer buffer here, because commands are still // in flight on the GPU process that may access them. When the command buffer diff --git a/content/renderer/gpu/renderer_gl_context.h b/content/renderer/gpu/renderer_gl_context.h index 9fa3315..ad69f4b 100644 --- a/content/renderer/gpu/renderer_gl_context.h +++ b/content/renderer/gpu/renderer_gl_context.h @@ -100,6 +100,7 @@ class RendererGLContext : public base::SupportsWeakPtr<RendererGLContext> { static RendererGLContext* CreateViewContext( GpuChannelHost* channel, int render_view_id, + RendererGLContext* share_group, const char* allowed_extensions, const int32* attrib_list, const GURL& active_arl); @@ -122,6 +123,7 @@ class RendererGLContext : public base::SupportsWeakPtr<RendererGLContext> { static RendererGLContext* CreateOffscreenContext( GpuChannelHost* channel, const gfx::Size& size, + RendererGLContext* share_group, const char* allowed_extensions, const int32* attrib_list, const GURL& active_url); @@ -189,6 +191,7 @@ class RendererGLContext : public base::SupportsWeakPtr<RendererGLContext> { bool Initialize(bool onscreen, int render_view_id, const gfx::Size& size, + RendererGLContext* share_group, const char* allowed_extensions, const int32* attrib_list, const GURL& active_url); diff --git a/content/renderer/gpu/webgraphicscontext3d_command_buffer_impl.cc b/content/renderer/gpu/webgraphicscontext3d_command_buffer_impl.cc index 88f1505..35bf246 100644 --- a/content/renderer/gpu/webgraphicscontext3d_command_buffer_impl.cc +++ b/content/renderer/gpu/webgraphicscontext3d_command_buffer_impl.cc @@ -13,7 +13,9 @@ #include <GLES2/gl2ext.h> #include <algorithm> +#include <set> +#include "base/lazy_instance.h" #include "base/string_tokenizer.h" #include "base/command_line.h" #include "base/debug/trace_event.h" @@ -30,6 +32,9 @@ #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" #include "webkit/glue/gl_bindings_skia_cmd_buffer.h" +static base::LazyInstance<std::set<WebGraphicsContext3DCommandBufferImpl*> > + g_all_contexts(base::LINKER_INITIALIZED); + WebGraphicsContext3DCommandBufferImpl::WebGraphicsContext3DCommandBufferImpl() : context_(NULL), gl_(NULL), @@ -47,6 +52,7 @@ WebGraphicsContext3DCommandBufferImpl::WebGraphicsContext3DCommandBufferImpl() WebGraphicsContext3DCommandBufferImpl:: ~WebGraphicsContext3DCommandBufferImpl() { + g_all_contexts.Pointer()->erase(this); delete context_; } @@ -107,6 +113,16 @@ bool WebGraphicsContext3DCommandBufferImpl::initialize( if (web_view && web_view->mainFrame()) active_url = GURL(web_view->mainFrame()->document().url()); + // HACK: Assume this is a WebGL context by looking for the noExtensions + // attribute. WebGL contexts must not go in the share group because they + // rely on destruction of the context to clean up owned resources. Putting + // them in a share group would prevent this from happening. + RendererGLContext* share_group = NULL; + if (!attributes.noExtensions) { + share_group = g_all_contexts.Pointer()->empty() ? + NULL : (*g_all_contexts.Pointer()->begin())->context_; + } + if (render_directly_to_web_view) { RenderView* renderview = RenderView::FromWebView(web_view); if (!renderview) @@ -116,6 +132,7 @@ bool WebGraphicsContext3DCommandBufferImpl::initialize( context_ = RendererGLContext::CreateViewContext( host, renderview->routing_id(), + share_group, preferred_extensions, attribs, active_url); @@ -128,6 +145,7 @@ bool WebGraphicsContext3DCommandBufferImpl::initialize( context_ = RendererGLContext::CreateOffscreenContext( host, gfx::Size(1, 1), + share_group, preferred_extensions, attribs, active_url); @@ -164,6 +182,9 @@ bool WebGraphicsContext3DCommandBufferImpl::initialize( attributes_.antialias = samples > 0; } + if (!attributes.noExtensions) + g_all_contexts.Pointer()->insert(this); + return true; } diff --git a/content/renderer/pepper_platform_context_3d_impl.cc b/content/renderer/pepper_platform_context_3d_impl.cc index 60c9603..a2a898f 100644 --- a/content/renderer/pepper_platform_context_3d_impl.cc +++ b/content/renderer/pepper_platform_context_3d_impl.cc @@ -95,6 +95,7 @@ bool PlatformContext3DImpl::Init(const int32* attrib_list) { parent_context_->GetCommandBufferProxy(); command_buffer_ = channel_->CreateOffscreenCommandBuffer( surface_size, + NULL, "*", attribs, GURL::EmptyGURL()); diff --git a/content/renderer/render_widget_fullscreen_pepper.cc b/content/renderer/render_widget_fullscreen_pepper.cc index f596d47..78df423 100644 --- a/content/renderer/render_widget_fullscreen_pepper.cc +++ b/content/renderer/render_widget_fullscreen_pepper.cc @@ -346,6 +346,7 @@ void RenderWidgetFullscreenPepper::CreateContext() { context_ = RendererGLContext::CreateViewContext( host, routing_id(), + NULL, "GL_OES_packed_depth_stencil GL_OES_depth24", attribs, active_url_); diff --git a/gpu/command_buffer/common/gles2_cmd_format.h b/gpu/command_buffer/common/gles2_cmd_format.h index ec9ea33..484b266 100644 --- a/gpu/command_buffer/common/gles2_cmd_format.h +++ b/gpu/command_buffer/common/gles2_cmd_format.h @@ -52,7 +52,8 @@ enum IdNamespaces { kFramebuffers, kProgramsAndShaders, kRenderbuffers, - kTextures + kTextures, + kNumIdNamespaces }; // These numbers must not change diff --git a/gpu/command_buffer/common/id_allocator.cc b/gpu/command_buffer/common/id_allocator.cc index eb450f3..e3fbdd5 100644 --- a/gpu/command_buffer/common/id_allocator.cc +++ b/gpu/command_buffer/common/id_allocator.cc @@ -9,6 +9,9 @@ namespace gpu { +IdAllocatorInterface::~IdAllocatorInterface() { +} + IdAllocator::IdAllocator() {} IdAllocator::~IdAllocator() {} @@ -85,4 +88,34 @@ ResourceId IdAllocator::FindFirstUnusedId() const { return id; } +NonReusedIdAllocator::NonReusedIdAllocator() : last_id_(0) { +} + +NonReusedIdAllocator::~NonReusedIdAllocator() { +} + +ResourceId NonReusedIdAllocator::AllocateID() { + return ++last_id_; +} + +ResourceId NonReusedIdAllocator::AllocateIDAtOrAbove(ResourceId desired_id) { + if (desired_id > last_id_) + last_id_ = desired_id; + + return ++last_id_; +} + +bool NonReusedIdAllocator::MarkAsUsed(ResourceId id) { + GPU_NOTREACHED(); + return false; +} + +void NonReusedIdAllocator::FreeID(ResourceId id) { +} + +bool NonReusedIdAllocator::InUse(ResourceId id) const { + GPU_NOTREACHED(); + return false; +} + } // namespace gpu diff --git a/gpu/command_buffer/common/id_allocator.h b/gpu/command_buffer/common/id_allocator.h index 4e80290..23c93d2 100644 --- a/gpu/command_buffer/common/id_allocator.h +++ b/gpu/command_buffer/common/id_allocator.h @@ -11,6 +11,10 @@ #include <utility> #include "../common/types.h" +// TODO(apatrick): Having regular GL flush semantics on the client side, it +// probably isn't necessary to round trip to the service to allocate IDs. +// Retire this code. + namespace gpu { // A resource ID, key to the resource maps. @@ -18,27 +22,39 @@ typedef uint32 ResourceId; // Invalid resource ID. static const ResourceId kInvalidResource = 0u; -// A class to manage the allocation of resource IDs. -class IdAllocator { +class IdAllocatorInterface { public: - IdAllocator(); - ~IdAllocator(); + virtual ~IdAllocatorInterface(); // Allocates a new resource ID. - ResourceId AllocateID(); + virtual ResourceId AllocateID() = 0; // Allocates an Id starting at or above desired_id. // Note: may wrap if it starts near limit. - ResourceId AllocateIDAtOrAbove(ResourceId desired_id); + virtual ResourceId AllocateIDAtOrAbove(ResourceId desired_id) = 0; // Marks an id as used. Returns false if id was already used. - bool MarkAsUsed(ResourceId id); + virtual bool MarkAsUsed(ResourceId id) = 0; // Frees a resource ID. - void FreeID(ResourceId id); + virtual void FreeID(ResourceId id) = 0; // Checks whether or not a resource ID is in use. - bool InUse(ResourceId id) const; + virtual bool InUse(ResourceId id) const = 0; +}; + +// A class to manage the allocation of resource IDs. +class IdAllocator : public IdAllocatorInterface { + public: + IdAllocator(); + virtual ~IdAllocator(); + + // Implement IdAllocatorInterface. + virtual ResourceId AllocateID(); + virtual ResourceId AllocateIDAtOrAbove(ResourceId desired_id); + virtual bool MarkAsUsed(ResourceId id); + virtual void FreeID(ResourceId id); + virtual bool InUse(ResourceId id) const; private: // TODO(gman): This would work much better with ranges or a hash table. @@ -56,6 +72,28 @@ class IdAllocator { DISALLOW_COPY_AND_ASSIGN(IdAllocator); }; +// A class to manage the allocation of resource IDs that are never reused. This +// implementation does not track which IDs are currently used. It is useful for +// shared and programs which cannot be implicitly created by binding a +// previously unused ID. +class NonReusedIdAllocator : public IdAllocatorInterface { + public: + NonReusedIdAllocator(); + virtual ~NonReusedIdAllocator(); + + // Implement IdAllocatorInterface. + virtual ResourceId AllocateID(); + virtual ResourceId AllocateIDAtOrAbove(ResourceId desired_id); + virtual bool MarkAsUsed(ResourceId id); + virtual void FreeID(ResourceId id); + virtual bool InUse(ResourceId id) const; + + private: + ResourceId last_id_; + + DISALLOW_COPY_AND_ASSIGN(NonReusedIdAllocator); +}; + } // namespace gpu #endif // GPU_COMMAND_BUFFER_CLIENT_ID_ALLOCATOR_H_ diff --git a/gpu/command_buffer/service/context_group.cc b/gpu/command_buffer/service/context_group.cc index 7b474d3..f852835 100644 --- a/gpu/command_buffer/service/context_group.cc +++ b/gpu/command_buffer/service/context_group.cc @@ -27,6 +27,12 @@ ContextGroup::ContextGroup() max_fragment_uniform_vectors_(0u), max_varying_vectors_(0u), max_vertex_uniform_vectors_(0u) { + id_namespaces_[id_namespaces::kBuffers].reset(new IdAllocator); + id_namespaces_[id_namespaces::kFramebuffers].reset(new IdAllocator); + id_namespaces_[id_namespaces::kProgramsAndShaders].reset( + new NonReusedIdAllocator); + id_namespaces_[id_namespaces::kRenderbuffers].reset(new IdAllocator); + id_namespaces_[id_namespaces::kTextures].reset(new IdAllocator); } ContextGroup::~ContextGroup() { @@ -145,14 +151,11 @@ void ContextGroup::Destroy() { } } -IdAllocator* ContextGroup::GetIdAllocator(unsigned namespace_id) { - IdAllocatorMap::iterator it = id_namespaces_.find(namespace_id); - if (it != id_namespaces_.end()) { - return it->second.get(); - } - IdAllocator* id_allocator = new IdAllocator(); - id_namespaces_[namespace_id] = linked_ptr<IdAllocator>(id_allocator); - return id_allocator; +IdAllocatorInterface* ContextGroup::GetIdAllocator(unsigned namespace_id) { + if (namespace_id >= arraysize(id_namespaces_)) + return NULL; + + return id_namespaces_[namespace_id].get(); } } // namespace gles2 diff --git a/gpu/command_buffer/service/context_group.h b/gpu/command_buffer/service/context_group.h index 9bd3a58..a2e6382 100644 --- a/gpu/command_buffer/service/context_group.h +++ b/gpu/command_buffer/service/context_group.h @@ -11,12 +11,13 @@ #include "base/memory/linked_ptr.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" +#include "gpu/command_buffer/common/gles2_cmd_format.h" #include "gpu/command_buffer/service/gles2_cmd_validation.h" #include "gpu/command_buffer/service/feature_info.h" namespace gpu { -class IdAllocator; +class IdAllocatorInterface; namespace gles2 { @@ -103,7 +104,7 @@ class ContextGroup : public base::RefCounted<ContextGroup> { return shader_manager_.get(); } - IdAllocator* GetIdAllocator(unsigned namepsace_id); + IdAllocatorInterface* GetIdAllocator(unsigned namespace_id); private: // Destroys all the resources. @@ -133,8 +134,8 @@ class ContextGroup : public base::RefCounted<ContextGroup> { scoped_ptr<ShaderManager> shader_manager_; - typedef base::hash_map<uint32, linked_ptr<IdAllocator> > IdAllocatorMap; - IdAllocatorMap id_namespaces_; + linked_ptr<IdAllocatorInterface> + id_namespaces_[id_namespaces::kNumIdNamespaces]; FeatureInfo feature_info_; diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index c982c9a..1dd1bfd 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -1649,7 +1649,7 @@ GLES2DecoderImpl::GLES2DecoderImpl(SurfaceManager* surface_manager, ContextGroup* group) : GLES2Decoder(), surface_manager_(surface_manager), - group_(ContextGroup::Ref(group ? group : new ContextGroup())), + group_(group), error_bits_(0), pack_alignment_(4), unpack_alignment_(4), @@ -1695,6 +1695,8 @@ GLES2DecoderImpl::GLES2DecoderImpl(SurfaceManager* surface_manager, frame_number_(0), has_arb_robustness_(false), reset_status_(GL_NO_ERROR) { + DCHECK(group); + attrib_0_value_.v[0] = 0.0f; attrib_0_value_.v[1] = 0.0f; attrib_0_value_.v[2] = 0.0f; @@ -2727,7 +2729,7 @@ void GLES2DecoderImpl::DoBindBuffer(GLenum target, GLuint client_id) { glGenBuffersARB(1, &service_id); CreateBufferInfo(client_id, service_id); info = GetBufferInfo(client_id); - IdAllocator* id_allocator = + IdAllocatorInterface* id_allocator = group_->GetIdAllocator(id_namespaces::kBuffers); id_allocator->MarkAsUsed(client_id); } @@ -2806,7 +2808,7 @@ void GLES2DecoderImpl::DoBindFramebuffer(GLenum target, GLuint client_id) { glGenFramebuffersEXT(1, &service_id); CreateFramebufferInfo(client_id, service_id); info = GetFramebufferInfo(client_id); - IdAllocator* id_allocator = + IdAllocatorInterface* id_allocator = group_->GetIdAllocator(id_namespaces::kFramebuffers); id_allocator->MarkAsUsed(client_id); } else { @@ -2845,7 +2847,7 @@ void GLES2DecoderImpl::DoBindRenderbuffer(GLenum target, GLuint client_id) { glGenRenderbuffersEXT(1, &service_id); CreateRenderbufferInfo(client_id, service_id); info = GetRenderbufferInfo(client_id); - IdAllocator* id_allocator = + IdAllocatorInterface* id_allocator = group_->GetIdAllocator(id_namespaces::kRenderbuffers); id_allocator->MarkAsUsed(client_id); } else { @@ -2867,7 +2869,7 @@ void GLES2DecoderImpl::DoBindTexture(GLenum target, GLuint client_id) { glGenTextures(1, &service_id); CreateTextureInfo(client_id, service_id); info = GetTextureInfo(client_id); - IdAllocator* id_allocator = + IdAllocatorInterface* id_allocator = group_->GetIdAllocator(id_namespaces::kTextures); id_allocator->MarkAsUsed(client_id); } @@ -3360,7 +3362,7 @@ error::Error GLES2DecoderImpl::HandleDeleteProgram( void GLES2DecoderImpl::DoDeleteSharedIdsCHROMIUM( GLuint namespace_id, GLsizei n, const GLuint* ids) { - IdAllocator* id_allocator = group_->GetIdAllocator(namespace_id); + IdAllocatorInterface* id_allocator = group_->GetIdAllocator(namespace_id); for (GLsizei ii = 0; ii < n; ++ii) { id_allocator->FreeID(ids[ii]); } @@ -3389,7 +3391,7 @@ error::Error GLES2DecoderImpl::HandleDeleteSharedIdsCHROMIUM( void GLES2DecoderImpl::DoGenSharedIdsCHROMIUM( GLuint namespace_id, GLuint id_offset, GLsizei n, GLuint* ids) { - IdAllocator* id_allocator = group_->GetIdAllocator(namespace_id); + IdAllocatorInterface* id_allocator = group_->GetIdAllocator(namespace_id); if (id_offset == 0) { for (GLsizei ii = 0; ii < n; ++ii) { ids[ii] = id_allocator->AllocateID(); @@ -3426,7 +3428,7 @@ error::Error GLES2DecoderImpl::HandleGenSharedIdsCHROMIUM( void GLES2DecoderImpl::DoRegisterSharedIdsCHROMIUM( GLuint namespace_id, GLsizei n, const GLuint* ids) { - IdAllocator* id_allocator = group_->GetIdAllocator(namespace_id); + IdAllocatorInterface* id_allocator = group_->GetIdAllocator(namespace_id); for (GLsizei ii = 0; ii < n; ++ii) { if (!id_allocator->MarkAsUsed(ids[ii])) { for (GLsizei jj = 0; jj < ii; ++jj) { diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc index 823cc1a..e145a79 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc @@ -2310,7 +2310,7 @@ TEST_F(GLES2DecoderTest, SharedIds) { GLuint* ids = GetSharedMemoryAs<GLuint*>(); gen_cmd.Init(kNamespaceId, 0, 2, kSharedMemoryId, kSharedMemoryOffset); EXPECT_EQ(error::kNoError, ExecuteCmd(gen_cmd)); - IdAllocator* id_allocator = GetIdAllocator(kNamespaceId); + IdAllocatorInterface* id_allocator = GetIdAllocator(kNamespaceId); ASSERT_TRUE(id_allocator != NULL); // This check is implementation dependant but it's kind of hard to check // otherwise. diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h index 3762952..b7379a4 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h @@ -128,7 +128,7 @@ class GLES2DecoderTestBase : public testing::Test { return reinterpret_cast<T>(ptr); } - IdAllocator* GetIdAllocator(GLuint namespace_id) { + IdAllocatorInterface* GetIdAllocator(GLuint namespace_id) { return group_->GetIdAllocator(namespace_id); } diff --git a/webkit/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc b/webkit/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc index c046bc3..0c70da7 100644 --- a/webkit/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc +++ b/webkit/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc @@ -13,6 +13,7 @@ #include <GLES2/gl2ext.h> #include <algorithm> +#include <set> #include "base/string_tokenizer.h" #include "base/command_line.h" @@ -24,6 +25,7 @@ #include "gpu/command_buffer/client/gles2_lib.h" #include "gpu/command_buffer/client/gles2_implementation.h" #include "gpu/command_buffer/common/constants.h" +#include "gpu/command_buffer/service/context_group.h" #include "gpu/command_buffer/service/gpu_scheduler.h" #include "gpu/command_buffer/service/command_buffer_service.h" #include "gpu/GLES2/gles2_command_buffer.h" @@ -96,6 +98,7 @@ class GLInProcessContext : public base::SupportsWeakPtr<GLInProcessContext> { // static GLInProcessContext* CreateViewContext( gfx::PluginWindowHandle render_surface, + GLInProcessContext* context_group, const char* allowed_extensions, const int32* attrib_list, const GURL& active_arl); @@ -118,6 +121,7 @@ class GLInProcessContext : public base::SupportsWeakPtr<GLInProcessContext> { static GLInProcessContext* CreateOffscreenContext( GLInProcessContext* parent, const gfx::Size& size, + GLInProcessContext* context_group, const char* allowed_extensions, const int32* attrib_list, const GURL& active_url); @@ -178,6 +182,7 @@ class GLInProcessContext : public base::SupportsWeakPtr<GLInProcessContext> { bool Initialize(bool onscreen, gfx::PluginWindowHandle render_surface, const gfx::Size& size, + GLInProcessContext* context_group, const char* allowed_extensions, const int32* attrib_list, const GURL& active_url); @@ -208,6 +213,10 @@ const int32 kCommandBufferSize = 1024 * 1024; // creation attributes. const int32 kTransferBufferSize = 1024 * 1024; +static base::LazyInstance< + std::set<WebGraphicsContext3DInProcessCommandBufferImpl*> > g_all_contexts( + base::LINKER_INITIALIZED); + // Singleton used to initialize and terminate the gles2 library. class GLES2Initializer { public: @@ -236,6 +245,7 @@ GLInProcessContext::~GLInProcessContext() { GLInProcessContext* GLInProcessContext::CreateViewContext( gfx::PluginWindowHandle render_surface, + GLInProcessContext* context_group, const char* allowed_extensions, const int32* attrib_list, const GURL& active_url) { @@ -245,6 +255,7 @@ GLInProcessContext* GLInProcessContext::CreateViewContext( true, render_surface, gfx::Size(), + context_group, allowed_extensions, attrib_list, active_url)) @@ -266,6 +277,7 @@ void GLInProcessContext::ResizeOnscreen(const gfx::Size& size) { GLInProcessContext* GLInProcessContext::CreateOffscreenContext( GLInProcessContext* parent, const gfx::Size& size, + GLInProcessContext* context_group, const char* allowed_extensions, const int32* attrib_list, const GURL& active_url) { @@ -275,6 +287,7 @@ GLInProcessContext* GLInProcessContext::CreateOffscreenContext( false, gfx::kNullPluginWindow, size, + context_group, allowed_extensions, attrib_list, active_url)) @@ -297,12 +310,9 @@ void GLInProcessContext::ResizeOffscreen(const gfx::Size& size) { } void GLInProcessContext::PumpCommands() { - ::gpu::CommandBuffer::State state; - do { - gpu_scheduler_->PutChanged(); - MessageLoop::current()->RunAllPending(); - state = command_buffer_->GetState(); - } while (state.get_offset != state.put_offset); + gpu_scheduler_->PutChanged(); + ::gpu::CommandBuffer::State state = command_buffer_->GetState(); + CHECK(state.error == ::gpu::error::kNoError); } uint32 GLInProcessContext::GetParentTextureId() { @@ -310,45 +320,14 @@ uint32 GLInProcessContext::GetParentTextureId() { } uint32 GLInProcessContext::CreateParentTexture(const gfx::Size& size) { - // Allocate a texture ID with respect to the parent. - if (parent_.get()) { - if (!MakeCurrent(parent_.get())) - return 0; - uint32 texture_id = parent_->gles2_implementation_->MakeTextureId(); - parent_->gles2_implementation_->BindTexture(GL_TEXTURE_2D, texture_id); - parent_->gles2_implementation_->TexParameteri( - GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - parent_->gles2_implementation_->TexParameteri( - GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - parent_->gles2_implementation_->TexParameteri( - GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - parent_->gles2_implementation_->TexParameteri( - GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - parent_->gles2_implementation_->TexImage2D(GL_TEXTURE_2D, - 0, // mip level - GL_RGBA, - size.width(), - size.height(), - 0, // border - GL_RGBA, - GL_UNSIGNED_BYTE, - NULL); - // Make sure that the parent texture's storage is allocated before we let - // the caller attempt to use it. - int32 token = parent_->gles2_helper_->InsertToken(); - parent_->gles2_helper_->WaitForToken(token); - return texture_id; - } - return 0; + uint32 texture = 0; + gles2_implementation_->GenTextures(1, &texture); + gles2_implementation_->Flush(); + return texture; } void GLInProcessContext::DeleteParentTexture(uint32 texture) { - if (parent_.get()) { - if (!MakeCurrent(parent_.get())) - return; - parent_->gles2_implementation_->DeleteTextures(1, &texture); - } + gles2_implementation_->DeleteTextures(1, &texture); } void GLInProcessContext::SetSwapBuffersCallback(Callback0::Type* callback) { @@ -434,6 +413,7 @@ GLInProcessContext::GLInProcessContext(GLInProcessContext* parent) bool GLInProcessContext::Initialize(bool onscreen, gfx::PluginWindowHandle render_surface, const gfx::Size& size, + GLInProcessContext* context_group, const char* allowed_extensions, const int32* attrib_list, const GURL& active_url) { @@ -486,9 +466,12 @@ bool GLInProcessContext::Initialize(bool onscreen, if (!command_buffer_->Initialize(kCommandBufferSize)) return false; - gpu_scheduler_ = GpuScheduler::Create(command_buffer_.get(), - NULL, - NULL); + gpu_scheduler_ = GpuScheduler::Create( + command_buffer_.get(), + NULL, + context_group ? + context_group->gpu_scheduler_->decoder()->GetContextGroup() : + new ::gpu::gles2::ContextGroup); if (onscreen) { if (render_surface == gfx::kNullPluginWindow) { @@ -562,7 +545,7 @@ bool GLInProcessContext::Initialize(bool onscreen, transfer_buffer.size, transfer_buffer.ptr, transfer_buffer_id_, - false); + true); size_ = size; @@ -575,8 +558,17 @@ void GLInProcessContext::Destroy() { parent_texture_id_ = 0; } - delete gles2_implementation_; - gles2_implementation_ = NULL; + if (gles2_implementation_) { + // First flush the context to ensure that any pending frees of resources + // are completed. Otherwise, if this context is part of a share group, + // those resources might leak. Also, any remaining side effects of commands + // issued on this context might not be visible to other contexts in the + // share group. + gles2_implementation_->Flush(); + + delete gles2_implementation_; + gles2_implementation_ = NULL; + } if (command_buffer_.get() && transfer_buffer_id_ != -1) { command_buffer_->DestroyTransferBuffer(transfer_buffer_id_); @@ -616,6 +608,7 @@ WebGraphicsContext3DInProcessCommandBufferImpl:: WebGraphicsContext3DInProcessCommandBufferImpl:: ~WebGraphicsContext3DInProcessCommandBufferImpl() { + g_all_contexts.Pointer()->erase(this); } // This string should only be passed for WebGL contexts. Nothing ELSE!!! @@ -667,9 +660,19 @@ bool WebGraphicsContext3DInProcessCommandBufferImpl::initialize( } } + // HACK: Assume this is a WebGL context by looking for the noExtensions + // attribute. WebGL contexts must not go in the share group because they + // rely on destruction of the context to clean up owned resources. Putting + // them in a share group would prevent this from happening. + WebGraphicsContext3DInProcessCommandBufferImpl* context_group = NULL; + if (!attributes.noExtensions) + context_group = g_all_contexts.Pointer()->empty() ? + NULL : *g_all_contexts.Pointer()->begin(); + context_ = GLInProcessContext::CreateOffscreenContext( parent_context, gfx::Size(1, 1), + context_group ? context_group->context_ : NULL, preferred_extensions, attribs, active_url); @@ -702,6 +705,9 @@ bool WebGraphicsContext3DInProcessCommandBufferImpl::initialize( } makeContextCurrent(); + if (!attributes.noExtensions) + g_all_contexts.Pointer()->insert(this); + return true; } |