Index: content/renderer/renderer_gl_context.cc |
=================================================================== |
--- content/renderer/renderer_gl_context.cc (revision 86484) |
+++ content/renderer/renderer_gl_context.cc (working copy) |
@@ -1,597 +0,0 @@ |
-// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "content/renderer/renderer_gl_context.h" |
- |
-#include "base/debug/trace_event.h" |
-#include "base/lazy_instance.h" |
-#include "base/memory/ref_counted.h" |
-#include "base/memory/scoped_ptr.h" |
-#include "base/memory/singleton.h" |
-#include "base/memory/weak_ptr.h" |
-#include "base/shared_memory.h" |
-#include "content/common/view_messages.h" |
-#include "content/renderer/command_buffer_proxy.h" |
-#include "content/renderer/gpu_channel_host.h" |
-#include "content/renderer/gpu_video_service_host.h" |
-#include "content/renderer/media/gles2_video_decode_context.h" |
-#include "content/renderer/render_thread.h" |
-#include "content/renderer/render_widget.h" |
-#include "content/renderer/transport_texture_host.h" |
-#include "content/renderer/transport_texture_service.h" |
-#include "googleurl/src/gurl.h" |
-#include "ipc/ipc_channel_handle.h" |
- |
-#if defined(ENABLE_GPU) |
-#include "gpu/command_buffer/client/gles2_cmd_helper.h" |
-#include "gpu/command_buffer/client/gles2_implementation.h" |
-#include "gpu/command_buffer/client/gles2_lib.h" |
-#include "gpu/command_buffer/common/constants.h" |
-#include "gpu/GLES2/gles2_command_buffer.h" |
-#endif // ENABLE_GPU |
- |
-namespace { |
- |
-const int32 kCommandBufferSize = 1024 * 1024; |
-// TODO(kbr): make the transfer buffer size configurable via context |
-// creation attributes. |
-const int32 kTransferBufferSize = 1024 * 1024; |
- |
-const uint32 kMaxLatchesPerRenderer = 2048; |
-const uint32 kInvalidLatchId = 0xffffffffu; |
- |
-// Singleton used to initialize and terminate the gles2 library. |
-class GLES2Initializer { |
- public: |
- GLES2Initializer() { |
- gles2::Initialize(); |
- } |
- |
- ~GLES2Initializer() { |
- gles2::Terminate(); |
- } |
- |
- private: |
- DISALLOW_COPY_AND_ASSIGN(GLES2Initializer); |
-}; |
- |
-// Shared memory allocator for latches. Creates a block of shared memory for |
-// each renderer process. |
-class LatchAllocator { |
- public: |
- static LatchAllocator* GetInstance(); |
- static uint32 size() { return kMaxLatchesPerRenderer*sizeof(uint32); } |
- static const uint32_t kFreeLatch = 0xffffffffu; |
- |
- LatchAllocator(); |
- ~LatchAllocator(); |
- |
- base::SharedMemoryHandle handle() const { return shm_->handle(); } |
- base::SharedMemory* shared_memory() { return shm_.get(); } |
- |
- bool AllocateLatch(uint32* latch_id); |
- bool FreeLatch(uint32 latch_id); |
- |
- private: |
- friend struct DefaultSingletonTraits<LatchAllocator>; |
- |
- scoped_ptr<base::SharedMemory> shm_; |
- // Pointer to mapped shared memory. |
- volatile uint32* latches_; |
- |
- DISALLOW_COPY_AND_ASSIGN(LatchAllocator); |
-}; |
- |
-//////////////////////////////////////////////////////////////////////////////// |
-/// LatchAllocator implementation |
- |
-LatchAllocator* LatchAllocator::GetInstance() { |
- return Singleton<LatchAllocator>::get(); |
-} |
- |
-LatchAllocator::LatchAllocator() { |
- base::SharedMemoryHandle handle; |
- RenderThread* render_thread = RenderThread::current(); |
- if (!render_thread->Send( |
- new ViewHostMsg_AllocateSharedMemoryBuffer(size(), &handle))) { |
- NOTREACHED() << "failed to send sync IPC"; |
- } |
- |
- if (!base::SharedMemory::IsHandleValid(handle)) { |
- NOTREACHED() << "failed to create shared memory"; |
- } |
- |
- // Handle is closed by the SharedMemory object below. This stops |
- // base::FileDescriptor from closing it as well. |
-#if defined(OS_POSIX) |
- handle.auto_close = false; |
-#endif |
- |
- shm_.reset(new base::SharedMemory(handle, false)); |
- if (!shm_->Map(size())) { |
- NOTREACHED() << "failed to map shared memory"; |
- } |
- |
- latches_ = static_cast<uint32*>(shm_->memory()); |
- // Mark all latches as unallocated. |
- for (uint32 i = 0; i < kMaxLatchesPerRenderer; ++i) |
- latches_[i] = kFreeLatch; |
-} |
- |
-LatchAllocator::~LatchAllocator() { |
-} |
- |
-bool LatchAllocator::AllocateLatch(uint32* latch_id) { |
- for (uint32 i = 0; i < kMaxLatchesPerRenderer; ++i) { |
- if (latches_[i] == kFreeLatch) { |
- // mark latch as taken and blocked. |
- // 0 means waiter will block, 1 means waiter will pass. |
- latches_[i] = 0; |
- *latch_id = i; |
- return true; |
- } |
- } |
- return false; |
-} |
- |
-bool LatchAllocator::FreeLatch(uint32 latch_id) { |
- if (latch_id < kMaxLatchesPerRenderer && latches_[latch_id] != kFreeLatch) { |
- latches_[latch_id] = kFreeLatch; |
- return true; |
- } |
- return false; |
-} |
- |
-//////////////////////////////////////////////////////////////////////////////// |
- |
-static base::LazyInstance<GLES2Initializer> g_gles2_initializer( |
- base::LINKER_INITIALIZED); |
- |
-} // namespace anonymous |
- |
-RendererGLContext::~RendererGLContext() { |
- Destroy(); |
-} |
- |
-RendererGLContext* RendererGLContext::CreateViewContext( |
- GpuChannelHost* channel, |
- gfx::PluginWindowHandle render_surface, |
- int render_view_id, |
- const char* allowed_extensions, |
- const int32* attrib_list, |
- const GURL& active_url) { |
-#if defined(ENABLE_GPU) |
- scoped_ptr<RendererGLContext> context(new RendererGLContext(channel, NULL)); |
- if (!context->Initialize( |
- true, |
- render_surface, |
- render_view_id, |
- gfx::Size(), |
- allowed_extensions, |
- attrib_list, |
- active_url)) |
- return NULL; |
- |
- return context.release(); |
-#else |
- return NULL; |
-#endif |
-} |
- |
-#if defined(OS_MACOSX) |
-void RendererGLContext::ResizeOnscreen(const gfx::Size& size) { |
- DCHECK(size.width() > 0 && size.height() > 0); |
- size_ = size; |
- command_buffer_->SetWindowSize(size); |
-} |
-#endif |
- |
-RendererGLContext* RendererGLContext::CreateOffscreenContext( |
- GpuChannelHost* channel, |
- RendererGLContext* parent, |
- const gfx::Size& size, |
- const char* allowed_extensions, |
- const int32* attrib_list, |
- const GURL& active_url) { |
-#if defined(ENABLE_GPU) |
- scoped_ptr<RendererGLContext> context(new RendererGLContext(channel, parent)); |
- if (!context->Initialize( |
- false, |
- gfx::kNullPluginWindow, |
- 0, |
- size, |
- allowed_extensions, |
- attrib_list, |
- active_url)) |
- return NULL; |
- |
- return context.release(); |
-#else |
- return NULL; |
-#endif |
-} |
- |
-void RendererGLContext::ResizeOffscreen(const gfx::Size& size) { |
- DCHECK(size.width() > 0 && size.height() > 0); |
- if (size_ != size) { |
- command_buffer_->ResizeOffscreenFrameBuffer(size); |
- size_ = size; |
- } |
-} |
- |
-uint32 RendererGLContext::GetParentTextureId() { |
- return parent_texture_id_; |
-} |
- |
-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; |
-} |
- |
-void RendererGLContext::DeleteParentTexture(uint32 texture) { |
- if (parent_.get()) { |
- if (!MakeCurrent(parent_.get())) |
- return; |
- parent_->gles2_implementation_->DeleteTextures(1, &texture); |
- } |
-} |
- |
-void RendererGLContext::SetSwapBuffersCallback(Callback0::Type* callback) { |
- swap_buffers_callback_.reset(callback); |
-} |
- |
-void RendererGLContext::SetContextLostCallback(Callback0::Type* callback) { |
- context_lost_callback_.reset(callback); |
-} |
- |
-bool RendererGLContext::MakeCurrent(RendererGLContext* context) { |
- if (context) { |
- gles2::SetGLContext(context->gles2_implementation_); |
- |
- // Don't request latest error status from service. Just use the locally |
- // cached information from the last flush. |
- // TODO(apatrick): I'm not sure if this should actually change the |
- // current context if it fails. For now it gets changed even if it fails |
- // because making GL calls with a NULL context crashes. |
- if (context->command_buffer_->GetLastState().error != gpu::error::kNoError) |
- return false; |
- } else { |
- gles2::SetGLContext(NULL); |
- } |
- |
- return true; |
-} |
- |
-bool RendererGLContext::SwapBuffers() { |
- TRACE_EVENT1("gpu", "RendererGLContext::SwapBuffers", "frame", frame_number_); |
- frame_number_++; |
- |
- // Don't request latest error status from service. Just use the locally cached |
- // information from the last flush. |
- if (command_buffer_->GetLastState().error != gpu::error::kNoError) |
- return false; |
- |
- gles2_implementation_->SwapBuffers(); |
- return true; |
-} |
- |
-media::VideoDecodeEngine* RendererGLContext::CreateVideoDecodeEngine() { |
- return channel_->gpu_video_service_host()->CreateVideoDecoder( |
- command_buffer_->route_id()); |
-} |
- |
-media::VideoDecodeContext* RendererGLContext::CreateVideoDecodeContext( |
- MessageLoop* message_loop, bool hardware_decoder) { |
- return new Gles2VideoDecodeContext(message_loop, hardware_decoder, this); |
-} |
- |
-scoped_refptr<TransportTextureHost> |
-RendererGLContext::CreateTransportTextureHost() { |
- return channel_->transport_texture_service()->CreateTransportTextureHost( |
- this, command_buffer_->route_id()); |
-} |
- |
-RendererGLContext::Error RendererGLContext::GetError() { |
- gpu::CommandBuffer::State state = command_buffer_->GetState(); |
- if (state.error == gpu::error::kNoError) { |
- Error old_error = last_error_; |
- last_error_ = SUCCESS; |
- return old_error; |
- } else { |
- // All command buffer errors are unrecoverable. The error is treated as a |
- // lost context: destroy the context and create another one. |
- return CONTEXT_LOST; |
- } |
-} |
- |
-bool RendererGLContext::IsCommandBufferContextLost() { |
- gpu::CommandBuffer::State state = command_buffer_->GetLastState(); |
- return state.error == gpu::error::kLostContext; |
-} |
- |
-CommandBufferProxy* RendererGLContext::GetCommandBufferProxy() { |
- return command_buffer_; |
-} |
- |
-// TODO(gman): Remove This |
-void RendererGLContext::DisableShaderTranslation() { |
- gles2_implementation_->CommandBufferEnableCHROMIUM( |
- PEPPER3D_SKIP_GLSL_TRANSLATION); |
-} |
- |
-gpu::gles2::GLES2Implementation* RendererGLContext::GetImplementation() { |
- return gles2_implementation_; |
-} |
- |
-RendererGLContext::RendererGLContext(GpuChannelHost* channel, |
- RendererGLContext* parent) |
- : channel_(channel), |
- parent_(parent ? |
- parent->AsWeakPtr() : base::WeakPtr<RendererGLContext>()), |
- parent_texture_id_(0), |
- child_to_parent_latch_(kInvalidLatchId), |
- parent_to_child_latch_(kInvalidLatchId), |
- latch_transfer_buffer_id_(-1), |
- command_buffer_(NULL), |
- gles2_helper_(NULL), |
- transfer_buffer_id_(-1), |
- gles2_implementation_(NULL), |
- last_error_(SUCCESS), |
- frame_number_(0) { |
- DCHECK(channel); |
-} |
- |
-bool RendererGLContext::Initialize(bool onscreen, |
- gfx::PluginWindowHandle render_surface, |
- int render_view_id, |
- const gfx::Size& size, |
- const char* allowed_extensions, |
- const int32* attrib_list, |
- const GURL& active_url) { |
- DCHECK(size.width() >= 0 && size.height() >= 0); |
- TRACE_EVENT2("gpu", "RendererGLContext::Initialize", |
- "on_screen", onscreen, "num_pixels", size.GetArea()); |
- |
- if (channel_->state() != GpuChannelHost::kConnected) |
- return false; |
- |
- // Ensure the gles2 library is initialized first in a thread safe way. |
- g_gles2_initializer.Get(); |
- |
- // Allocate a frame buffer ID with respect to the parent. |
- if (parent_.get()) { |
- // Flush any remaining commands in the parent context to make sure the |
- // texture id accounting stays consistent. |
- int32 token = parent_->gles2_helper_->InsertToken(); |
- parent_->gles2_helper_->WaitForToken(token); |
- parent_texture_id_ = parent_->gles2_implementation_->MakeTextureId(); |
- } |
- |
- std::vector<int32> attribs; |
- while (attrib_list) { |
- int32 attrib = *attrib_list++; |
- switch (attrib) { |
- // Known attributes |
- case ALPHA_SIZE: |
- case BLUE_SIZE: |
- case GREEN_SIZE: |
- case RED_SIZE: |
- case DEPTH_SIZE: |
- case STENCIL_SIZE: |
- case SAMPLES: |
- case SAMPLE_BUFFERS: |
- attribs.push_back(attrib); |
- attribs.push_back(*attrib_list++); |
- break; |
- case NONE: |
- attribs.push_back(attrib); |
- attrib_list = NULL; |
- break; |
- default: |
- last_error_ = BAD_ATTRIBUTE; |
- attribs.push_back(NONE); |
- attrib_list = NULL; |
- break; |
- } |
- } |
- |
- // Create a proxy to a command buffer in the GPU process. |
- if (onscreen) { |
- if (render_surface == gfx::kNullPluginWindow) { |
- LOG(ERROR) << "Invalid surface handle for onscreen context."; |
- command_buffer_ = NULL; |
- } else { |
- command_buffer_ = channel_->CreateViewCommandBuffer( |
- render_surface, |
- render_view_id, |
- allowed_extensions, |
- attribs, |
- active_url); |
- } |
- } else { |
- CommandBufferProxy* parent_command_buffer = |
- parent_.get() ? parent_->command_buffer_ : NULL; |
- command_buffer_ = channel_->CreateOffscreenCommandBuffer( |
- parent_command_buffer, |
- size, |
- allowed_extensions, |
- attribs, |
- parent_texture_id_, |
- active_url); |
- } |
- if (!command_buffer_) { |
- Destroy(); |
- return false; |
- } |
- |
- // Initiaize the command buffer. |
- if (!command_buffer_->Initialize(kCommandBufferSize)) { |
- Destroy(); |
- return false; |
- } |
- |
- command_buffer_->SetSwapBuffersCallback( |
- NewCallback(this, &RendererGLContext::OnSwapBuffers)); |
- |
- command_buffer_->SetChannelErrorCallback( |
- NewCallback(this, &RendererGLContext::OnContextLost)); |
- |
- // Create the GLES2 helper, which writes the command buffer protocol. |
- gles2_helper_ = new gpu::gles2::GLES2CmdHelper(command_buffer_); |
- if (!gles2_helper_->Initialize(kCommandBufferSize)) { |
- Destroy(); |
- return false; |
- } |
- |
- // Create a transfer buffer used to copy resources between the renderer |
- // process and the GPU process. |
- transfer_buffer_id_ = |
- command_buffer_->CreateTransferBuffer(kTransferBufferSize, |
- gpu::kCommandBufferSharedMemoryId); |
- if (transfer_buffer_id_ < 0) { |
- Destroy(); |
- return false; |
- } |
- |
- // Map the buffer into the renderer process's address space. |
- gpu::Buffer transfer_buffer = |
- command_buffer_->GetTransferBuffer(transfer_buffer_id_); |
- if (!transfer_buffer.ptr) { |
- Destroy(); |
- return false; |
- } |
- |
- // Register transfer buffer so that the context can access latches. |
- LatchAllocator* latch_shm = LatchAllocator::GetInstance(); |
- latch_transfer_buffer_id_ = command_buffer_->RegisterTransferBuffer( |
- latch_shm->shared_memory(), LatchAllocator::size(), |
- gpu::kLatchSharedMemoryId); |
- if (latch_transfer_buffer_id_ != gpu::kLatchSharedMemoryId) { |
- Destroy(); |
- return false; |
- } |
- |
- // If this is a child context, setup latches for synchronization between child |
- // and parent. |
- if (parent_.get()) { |
- if (!CreateLatch(&child_to_parent_latch_) || |
- !CreateLatch(&parent_to_child_latch_)) { |
- Destroy(); |
- return false; |
- } |
- } |
- |
- // Create the object exposing the OpenGL API. |
- gles2_implementation_ = new gpu::gles2::GLES2Implementation( |
- gles2_helper_, |
- transfer_buffer.size, |
- transfer_buffer.ptr, |
- transfer_buffer_id_, |
- false); |
- |
- size_ = size; |
- |
- return true; |
-} |
- |
-void RendererGLContext::Destroy() { |
- if (parent_.get() && parent_texture_id_ != 0) { |
- parent_->gles2_implementation_->FreeTextureId(parent_texture_id_); |
- parent_texture_id_ = 0; |
- } |
- |
- delete gles2_implementation_; |
- gles2_implementation_ = NULL; |
- |
- if (child_to_parent_latch_ != kInvalidLatchId) { |
- DestroyLatch(child_to_parent_latch_); |
- child_to_parent_latch_ = kInvalidLatchId; |
- } |
- if (parent_to_child_latch_ != kInvalidLatchId) { |
- DestroyLatch(parent_to_child_latch_); |
- parent_to_child_latch_ = kInvalidLatchId; |
- } |
- if (command_buffer_ && latch_transfer_buffer_id_ != -1) { |
- command_buffer_->DestroyTransferBuffer(latch_transfer_buffer_id_); |
- latch_transfer_buffer_id_ = -1; |
- } |
- |
- if (command_buffer_ && transfer_buffer_id_ != -1) { |
- command_buffer_->DestroyTransferBuffer(transfer_buffer_id_); |
- transfer_buffer_id_ = -1; |
- } |
- |
- delete gles2_helper_; |
- gles2_helper_ = NULL; |
- |
- if (channel_ && command_buffer_) { |
- channel_->DestroyCommandBuffer(command_buffer_); |
- command_buffer_ = NULL; |
- } |
- |
- channel_ = NULL; |
-} |
- |
-void RendererGLContext::OnSwapBuffers() { |
- if (swap_buffers_callback_.get()) |
- swap_buffers_callback_->Run(); |
-} |
- |
-void RendererGLContext::OnContextLost() { |
- if (context_lost_callback_.get()) |
- context_lost_callback_->Run(); |
-} |
- |
-bool RendererGLContext::CreateLatch(uint32* ret_latch) { |
- return LatchAllocator::GetInstance()->AllocateLatch(ret_latch); |
-} |
- |
-bool RendererGLContext::DestroyLatch(uint32 latch) { |
- return LatchAllocator::GetInstance()->FreeLatch(latch); |
-} |
- |
-bool RendererGLContext::GetParentToChildLatch(uint32* parent_to_child_latch) { |
- if (parent_.get()) { |
- *parent_to_child_latch = parent_to_child_latch_; |
- return true; |
- } |
- return false; |
-} |
- |
-bool RendererGLContext::GetChildToParentLatch(uint32* child_to_parent_latch) { |
- if (parent_.get()) { |
- *child_to_parent_latch = child_to_parent_latch_; |
- return true; |
- } |
- return false; |
-} |