Moved creation of GPU command buffer shared memory into the browser process.
This is to allow the GPU process to be sandboxed on all platforms. TEST=try, run WebGL app on win and mac. BUG=none Review URL: http://codereview.chromium.org/6588029 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@76307 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
chrome
common
gpu
plugin
renderer
gpu
command_buffer
client
common
service
pgl
ppapi/proxy
@ -225,9 +225,10 @@ IPC_SYNC_MESSAGE_CONTROL1_0(GpuChannelMsg_DestroyVideoDecoder,
|
||||
// Initialize a command buffer with the given number of command entries.
|
||||
// Returns the shared memory handle for the command buffer mapped to the
|
||||
// calling process.
|
||||
IPC_SYNC_MESSAGE_ROUTED1_1(GpuCommandBufferMsg_Initialize,
|
||||
IPC_SYNC_MESSAGE_ROUTED2_1(GpuCommandBufferMsg_Initialize,
|
||||
base::SharedMemoryHandle /* ring_buffer */,
|
||||
int32 /* size */,
|
||||
base::SharedMemoryHandle /* ring_buffer */)
|
||||
bool /* result */)
|
||||
|
||||
// Get the current state of the command buffer.
|
||||
IPC_SYNC_MESSAGE_ROUTED0_1(GpuCommandBufferMsg_GetState,
|
||||
|
@ -192,11 +192,12 @@ bool GpuCommandBufferStub::Send(IPC::Message* message) {
|
||||
}
|
||||
|
||||
void GpuCommandBufferStub::OnInitialize(
|
||||
base::SharedMemoryHandle ring_buffer,
|
||||
int32 size,
|
||||
base::SharedMemoryHandle* ring_buffer) {
|
||||
bool* result) {
|
||||
DCHECK(!command_buffer_.get());
|
||||
|
||||
*ring_buffer = base::SharedMemory::NULLHandle();
|
||||
*result = false;
|
||||
|
||||
command_buffer_.reset(new gpu::CommandBufferService);
|
||||
|
||||
@ -215,50 +216,57 @@ void GpuCommandBufferStub::OnInitialize(
|
||||
gfx::PluginWindowHandle output_window_handle = handle_;
|
||||
#endif // defined(OS_WIN)
|
||||
|
||||
// Initialize the CommandBufferService and GPUProcessor.
|
||||
if (command_buffer_->Initialize(size)) {
|
||||
Buffer buffer = command_buffer_->GetRingBuffer();
|
||||
if (buffer.shared_memory) {
|
||||
gpu::GPUProcessor* parent_processor =
|
||||
parent_ ? parent_->processor_.get() : NULL;
|
||||
processor_.reset(new gpu::GPUProcessor(command_buffer_.get(), NULL));
|
||||
if (processor_->Initialize(
|
||||
output_window_handle,
|
||||
initial_size_,
|
||||
allowed_extensions_.c_str(),
|
||||
requested_attribs_,
|
||||
parent_processor,
|
||||
parent_texture_id_)) {
|
||||
command_buffer_->SetPutOffsetChangeCallback(
|
||||
NewCallback(processor_.get(),
|
||||
&gpu::GPUProcessor::ProcessCommands));
|
||||
processor_->SetSwapBuffersCallback(
|
||||
NewCallback(this, &GpuCommandBufferStub::OnSwapBuffers));
|
||||
#if defined(OS_WIN)
|
||||
// Windows dups the shared memory handle it receives into the current process
|
||||
// and closes it when this variable goes out of scope.
|
||||
base::SharedMemory shared_memory(ring_buffer,
|
||||
false,
|
||||
channel_->renderer_process());
|
||||
#else
|
||||
// POSIX receives a dup of the shared memory handle and closes the dup when
|
||||
// this variable goes out of scope.
|
||||
base::SharedMemory shared_memory(ring_buffer, false);
|
||||
#endif
|
||||
|
||||
// Initialize the CommandBufferService and GPUProcessor.
|
||||
if (command_buffer_->Initialize(&shared_memory, size)) {
|
||||
gpu::GPUProcessor* parent_processor =
|
||||
parent_ ? parent_->processor_.get() : NULL;
|
||||
processor_.reset(new gpu::GPUProcessor(command_buffer_.get(), NULL));
|
||||
if (processor_->Initialize(
|
||||
output_window_handle,
|
||||
initial_size_,
|
||||
allowed_extensions_.c_str(),
|
||||
requested_attribs_,
|
||||
parent_processor,
|
||||
parent_texture_id_)) {
|
||||
command_buffer_->SetPutOffsetChangeCallback(
|
||||
NewCallback(processor_.get(),
|
||||
&gpu::GPUProcessor::ProcessCommands));
|
||||
processor_->SetSwapBuffersCallback(
|
||||
NewCallback(this, &GpuCommandBufferStub::OnSwapBuffers));
|
||||
|
||||
// Assume service is responsible for duplicating the handle from the
|
||||
// calling process.
|
||||
buffer.shared_memory->ShareToProcess(channel_->renderer_process(),
|
||||
ring_buffer);
|
||||
#if defined(OS_MACOSX)
|
||||
if (handle_) {
|
||||
// This context conceptually puts its output directly on the
|
||||
// screen, rendered by the accelerated plugin layer in
|
||||
// RenderWidgetHostViewMac. Set up a pathway to notify the
|
||||
// browser process when its contents change.
|
||||
processor_->SetSwapBuffersCallback(
|
||||
NewCallback(this,
|
||||
&GpuCommandBufferStub::SwapBuffersCallback));
|
||||
}
|
||||
if (handle_) {
|
||||
// This context conceptually puts its output directly on the
|
||||
// screen, rendered by the accelerated plugin layer in
|
||||
// RenderWidgetHostViewMac. Set up a pathway to notify the
|
||||
// browser process when its contents change.
|
||||
processor_->SetSwapBuffersCallback(
|
||||
NewCallback(this,
|
||||
&GpuCommandBufferStub::SwapBuffersCallback));
|
||||
}
|
||||
#endif // defined(OS_MACOSX)
|
||||
|
||||
// Set up a pathway for resizing the output window or framebuffer at the
|
||||
// right time relative to other GL commands.
|
||||
processor_->SetResizeCallback(
|
||||
NewCallback(this, &GpuCommandBufferStub::ResizeCallback));
|
||||
} else {
|
||||
processor_.reset();
|
||||
command_buffer_.reset();
|
||||
}
|
||||
// Set up a pathway for resizing the output window or framebuffer at the
|
||||
// right time relative to other GL commands.
|
||||
processor_->SetResizeCallback(
|
||||
NewCallback(this, &GpuCommandBufferStub::ResizeCallback));
|
||||
|
||||
*result = true;
|
||||
} else {
|
||||
processor_.reset();
|
||||
command_buffer_.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,9 @@ class GpuCommandBufferStub
|
||||
|
||||
private:
|
||||
// Message handlers:
|
||||
void OnInitialize(int32 size, base::SharedMemoryHandle* ring_buffer);
|
||||
void OnInitialize(base::SharedMemoryHandle ring_buffer,
|
||||
int32 size,
|
||||
bool* result);
|
||||
void OnGetState(gpu::CommandBuffer::State* state);
|
||||
void OnAsyncGetState();
|
||||
void OnFlush(int32 put_offset, gpu::CommandBuffer::State* state);
|
||||
|
@ -2,12 +2,13 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/plugin/command_buffer_stub.h"
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/scoped_open_process.h"
|
||||
#include "base/shared_memory.h"
|
||||
#include "chrome/common/gpu_messages.h"
|
||||
#include "chrome/common/plugin_messages.h"
|
||||
#include "chrome/plugin/command_buffer_stub.h"
|
||||
#include "chrome/plugin/plugin_channel.h"
|
||||
|
||||
using gpu::Buffer;
|
||||
@ -67,66 +68,13 @@ void CommandBufferStub::NotifyRepaint() {
|
||||
Send(new GpuCommandBufferMsg_NotifyRepaint(route_id_));
|
||||
}
|
||||
|
||||
void CommandBufferStub::OnInitialize(int32 size,
|
||||
base::SharedMemoryHandle* ring_buffer) {
|
||||
DCHECK(!command_buffer_.get());
|
||||
|
||||
*ring_buffer = base::SharedMemory::NULLHandle();
|
||||
|
||||
// Assume service is responsible for duplicating the handle from the calling
|
||||
// process.
|
||||
base::ScopedOpenProcess peer_process;
|
||||
if (!peer_process.Open(channel_->peer_pid()))
|
||||
return;
|
||||
|
||||
command_buffer_.reset(new gpu::CommandBufferService);
|
||||
|
||||
// Initialize the CommandBufferService.
|
||||
if (!command_buffer_->Initialize(size)) {
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the ring buffer.
|
||||
Buffer buffer = command_buffer_->GetRingBuffer();
|
||||
if (!buffer.shared_memory) {
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize the GPUProcessor.
|
||||
processor_.reset(new gpu::GPUProcessor(command_buffer_.get(), NULL));
|
||||
if (!processor_->Initialize(window_, gfx::Size(), NULL, std::vector<int32>(),
|
||||
NULL, 0)) {
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
// Perform platform specific initialization.
|
||||
if (!InitializePlatformSpecific()) {
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
// Share the ring buffer to the client process.
|
||||
if (!buffer.shared_memory->ShareToProcess(peer_process.handle(),
|
||||
ring_buffer)) {
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
// Setup callbacks for events.
|
||||
command_buffer_->SetPutOffsetChangeCallback(
|
||||
NewCallback(processor_.get(),
|
||||
&gpu::GPUProcessor::ProcessCommands));
|
||||
#if defined(OS_MACOSX)
|
||||
processor_->SetSwapBuffersCallback(
|
||||
NewCallback(this,
|
||||
&CommandBufferStub::SwapBuffersCallback));
|
||||
processor_->SetTransportDIBAllocAndFree(
|
||||
NewCallback(this, &CommandBufferStub::AllocTransportDIB),
|
||||
NewCallback(this, &CommandBufferStub::FreeTransportDIB));
|
||||
#endif
|
||||
void CommandBufferStub::OnInitialize(base::SharedMemoryHandle ring_buffer,
|
||||
int32 size,
|
||||
bool* result) {
|
||||
// TODO(apatrick): Pepper3D v1 is not used anymore. This function is never
|
||||
// called. Delete the GPU plugin.
|
||||
NOTREACHED();
|
||||
*result = false;
|
||||
}
|
||||
|
||||
void CommandBufferStub::OnGetState(gpu::CommandBuffer::State* state) {
|
||||
|
@ -45,7 +45,9 @@ class CommandBufferStub : public IPC::Channel::Listener,
|
||||
|
||||
private:
|
||||
// Message handlers:
|
||||
void OnInitialize(int32 size, base::SharedMemoryHandle* ring_buffer);
|
||||
void OnInitialize(base::SharedMemoryHandle ring_buffer,
|
||||
int32 size,
|
||||
bool* result);
|
||||
void OnGetState(gpu::CommandBuffer::State* state);
|
||||
void OnAsyncGetState();
|
||||
void OnFlush(int32 put_offset, gpu::CommandBuffer::State* state);
|
||||
|
@ -68,22 +68,62 @@ void CommandBufferProxy::SetChannelErrorCallback(Callback0::Type* callback) {
|
||||
bool CommandBufferProxy::Initialize(int32 size) {
|
||||
DCHECK(!ring_buffer_.get());
|
||||
|
||||
// Initialize the service. Assuming we are sandboxed, the GPU
|
||||
// process is responsible for duplicating the handle. This might not be true
|
||||
// for NaCl.
|
||||
base::SharedMemoryHandle handle;
|
||||
if (Send(new GpuCommandBufferMsg_Initialize(route_id_, size, &handle)) &&
|
||||
base::SharedMemory::IsHandleValid(handle)) {
|
||||
ring_buffer_.reset(new base::SharedMemory(handle, false));
|
||||
if (ring_buffer_->Map(size)) {
|
||||
num_entries_ = size / sizeof(gpu::CommandBufferEntry);
|
||||
return true;
|
||||
}
|
||||
RenderThread* render_thread = RenderThread::current();
|
||||
if (!render_thread)
|
||||
return false;
|
||||
|
||||
ring_buffer_.reset();
|
||||
base::SharedMemoryHandle handle;
|
||||
if (!render_thread->Send(new ViewHostMsg_AllocateSharedMemoryBuffer(
|
||||
size,
|
||||
&handle))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
if (!base::SharedMemory::IsHandleValid(handle))
|
||||
return false;
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
handle.auto_close = false;
|
||||
#endif
|
||||
|
||||
// Take ownership of shared memory. This will close the handle if Send below
|
||||
// fails. Otherwise, callee takes ownership before this variable
|
||||
// goes out of scope.
|
||||
base::SharedMemory shared_memory(handle, false);
|
||||
|
||||
return Initialize(&shared_memory, size);
|
||||
}
|
||||
|
||||
bool CommandBufferProxy::Initialize(base::SharedMemory* buffer, int32 size) {
|
||||
bool result;
|
||||
if (!Send(new GpuCommandBufferMsg_Initialize(route_id_,
|
||||
buffer->handle(),
|
||||
size,
|
||||
&result))) {
|
||||
LOG(ERROR) << "Could not send GpuCommandBufferMsg_Initialize.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
LOG(ERROR) << "Failed to initialize command buffer service.";
|
||||
return false;
|
||||
}
|
||||
|
||||
base::SharedMemoryHandle handle;
|
||||
if (!buffer->GiveToProcess(base::GetCurrentProcessHandle(), &handle)) {
|
||||
LOG(ERROR) << "Failed to duplicate command buffer handle.";
|
||||
return false;
|
||||
}
|
||||
|
||||
ring_buffer_.reset(new base::SharedMemory(handle, false));
|
||||
if (!ring_buffer_->Map(size)) {
|
||||
LOG(ERROR) << "Failed to map shared memory for command buffer.";
|
||||
ring_buffer_.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
num_entries_ = size / sizeof(gpu::CommandBufferEntry);
|
||||
return true;
|
||||
}
|
||||
|
||||
Buffer CommandBufferProxy::GetRingBuffer() {
|
||||
|
@ -45,6 +45,7 @@ class CommandBufferProxy : public gpu::CommandBuffer,
|
||||
|
||||
// CommandBuffer implementation:
|
||||
virtual bool Initialize(int32 size);
|
||||
virtual bool Initialize(base::SharedMemory* buffer, int32 size);
|
||||
virtual gpu::Buffer GetRingBuffer();
|
||||
virtual State GetState();
|
||||
virtual void Flush(int32 put_offset);
|
||||
|
@ -33,6 +33,11 @@ class GLES2MockCommandBufferHelper : public CommandBuffer {
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool Initialize(base::SharedMemory* buffer, int32 size) {
|
||||
GPU_NOTREACHED();
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual Buffer GetRingBuffer() {
|
||||
return ring_buffer_buffer_;
|
||||
}
|
||||
|
@ -8,6 +8,10 @@
|
||||
#include "../common/buffer.h"
|
||||
#include "../common/constants.h"
|
||||
|
||||
namespace base {
|
||||
class SharedMemory;
|
||||
}
|
||||
|
||||
namespace gpu {
|
||||
|
||||
// Common interface for CommandBuffer implementations.
|
||||
@ -55,6 +59,9 @@ class CommandBuffer {
|
||||
// Initialize the command buffer with the given size.
|
||||
virtual bool Initialize(int32 size) = 0;
|
||||
|
||||
// Initialize the command buffer using the given preallocated buffer.
|
||||
virtual bool Initialize(base::SharedMemory* buffer, int32 size) = 0;
|
||||
|
||||
// Gets the ring buffer for the command buffer.
|
||||
virtual Buffer GetRingBuffer() = 0;
|
||||
|
||||
|
@ -22,6 +22,7 @@ class MockCommandBuffer : public CommandBuffer {
|
||||
virtual ~MockCommandBuffer();
|
||||
|
||||
MOCK_METHOD1(Initialize, bool(int32 size));
|
||||
MOCK_METHOD2(Initialize, bool(base::SharedMemory* buffer, int32 size));
|
||||
MOCK_METHOD0(GetRingBuffer, Buffer());
|
||||
MOCK_METHOD0(GetState, State());
|
||||
MOCK_METHOD1(Flush, void(int32 put_offset));
|
||||
|
@ -25,6 +25,8 @@ CommandBufferService::CommandBufferService()
|
||||
}
|
||||
|
||||
CommandBufferService::~CommandBufferService() {
|
||||
delete ring_buffer_.shared_memory;
|
||||
|
||||
for (size_t i = 0; i < registered_objects_.size(); ++i) {
|
||||
if (registered_objects_[i].shared_memory)
|
||||
delete registered_objects_[i].shared_memory;
|
||||
@ -33,42 +35,59 @@ CommandBufferService::~CommandBufferService() {
|
||||
|
||||
bool CommandBufferService::Initialize(int32 size) {
|
||||
// Fail if already initialized.
|
||||
if (ring_buffer_.get()) {
|
||||
LOG(ERROR) << "CommandBufferService::Initialize "
|
||||
<< "failed because already initialized.";
|
||||
if (ring_buffer_.shared_memory) {
|
||||
LOG(ERROR) << "Failed because already initialized.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (size <= 0 || size > kMaxCommandBufferSize) {
|
||||
LOG(ERROR) << "CommandBufferService::Initialize "
|
||||
<< "because command buffer size was invalid.";
|
||||
LOG(ERROR) << "Failed because command buffer size was invalid.";
|
||||
return false;
|
||||
}
|
||||
|
||||
num_entries_ = size / sizeof(CommandBufferEntry);
|
||||
|
||||
ring_buffer_.reset(new SharedMemory);
|
||||
if (ring_buffer_->CreateAndMapAnonymous(size)) {
|
||||
SharedMemory shared_memory;
|
||||
if (!shared_memory.CreateAnonymous(size)) {
|
||||
LOG(ERROR) << "Failed to create shared memory for command buffer.";
|
||||
return true;
|
||||
}
|
||||
|
||||
num_entries_ = 0;
|
||||
ring_buffer_.reset();
|
||||
return Initialize(&shared_memory, size);
|
||||
}
|
||||
|
||||
LOG(ERROR) << "CommandBufferService::Initialize failed because ring buffer "
|
||||
<< "could not be created or mapped ";
|
||||
bool CommandBufferService::Initialize(base::SharedMemory* buffer, int32 size) {
|
||||
// Fail if already initialized.
|
||||
if (ring_buffer_.shared_memory) {
|
||||
LOG(ERROR) << "Failed because already initialized.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
base::SharedMemoryHandle shared_memory_handle;
|
||||
if (!buffer->ShareToProcess(base::GetCurrentProcessHandle(),
|
||||
&shared_memory_handle)) {
|
||||
LOG(ERROR) << "Failed to duplicate command buffer shared memory handle.";
|
||||
return false;
|
||||
}
|
||||
|
||||
ring_buffer_.shared_memory = new base::SharedMemory(shared_memory_handle,
|
||||
false);
|
||||
if (!ring_buffer_.shared_memory->Map(size)) {
|
||||
LOG(ERROR) << "Failed because ring buffer could not be created or mapped ";
|
||||
delete ring_buffer_.shared_memory;
|
||||
ring_buffer_.shared_memory = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
ring_buffer_.ptr = ring_buffer_.shared_memory->memory();
|
||||
ring_buffer_.size = size;
|
||||
num_entries_ = size / sizeof(CommandBufferEntry);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Buffer CommandBufferService::GetRingBuffer() {
|
||||
Buffer buffer;
|
||||
if (ring_buffer_.get()) {
|
||||
buffer.ptr = ring_buffer_->memory();
|
||||
buffer.size = ring_buffer_->created_size();
|
||||
buffer.shared_memory = ring_buffer_.get();
|
||||
}
|
||||
return buffer;
|
||||
return ring_buffer_;
|
||||
}
|
||||
|
||||
CommandBufferService::State CommandBufferService::GetState() {
|
||||
|
@ -26,6 +26,7 @@ class CommandBufferService : public CommandBuffer {
|
||||
|
||||
// CommandBuffer implementation:
|
||||
virtual bool Initialize(int32 size);
|
||||
virtual bool Initialize(base::SharedMemory* buffer, int32 size);
|
||||
virtual Buffer GetRingBuffer();
|
||||
virtual State GetState();
|
||||
virtual void Flush(int32 put_offset);
|
||||
@ -52,7 +53,7 @@ class CommandBufferService : public CommandBuffer {
|
||||
virtual void SetPutOffsetChangeCallback(Callback0::Type* callback);
|
||||
|
||||
private:
|
||||
scoped_ptr< base::SharedMemory> ring_buffer_;
|
||||
Buffer ring_buffer_;
|
||||
int32 num_entries_;
|
||||
int32 get_offset_;
|
||||
int32 put_offset_;
|
||||
|
@ -27,6 +27,11 @@ bool CommandBufferPepper::Initialize(int32 size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CommandBufferPepper::Initialize(base::SharedMemory* buffer, int32 size) {
|
||||
GPU_NOTREACHED();
|
||||
return false;
|
||||
}
|
||||
|
||||
Buffer CommandBufferPepper::GetRingBuffer() {
|
||||
Buffer buffer;
|
||||
#if defined(ENABLE_NEW_NPDEVICE_API)
|
||||
|
@ -15,6 +15,10 @@
|
||||
#include "third_party/npapi/bindings/nphostapi.h"
|
||||
#endif // __native_client__
|
||||
|
||||
namespace {
|
||||
class SharedMemory;
|
||||
}
|
||||
|
||||
// A CommandBuffer proxy implementation that uses the Pepper API to access
|
||||
// the command buffer.
|
||||
|
||||
@ -27,6 +31,7 @@ class CommandBufferPepper : public gpu::CommandBuffer {
|
||||
|
||||
// CommandBuffer implementation.
|
||||
virtual bool Initialize(int32 size);
|
||||
virtual bool Initialize(base::SharedMemory* buffer, int32 size);
|
||||
virtual gpu::Buffer GetRingBuffer();
|
||||
virtual State GetState();
|
||||
virtual void Flush(int32 put_offset);
|
||||
|
@ -177,6 +177,7 @@ class PepperCommandBuffer : public gpu::CommandBuffer {
|
||||
|
||||
// CommandBuffer implementation:
|
||||
virtual bool Initialize(int32 size);
|
||||
virtual bool Initialize(base::SharedMemory* buffer, int32 size);
|
||||
virtual gpu::Buffer GetRingBuffer();
|
||||
virtual State GetState();
|
||||
virtual void Flush(int32 put_offset);
|
||||
@ -248,6 +249,12 @@ bool PepperCommandBuffer::Initialize(int32 size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PepperCommandBuffer::Initialize(base::SharedMemory* buffer, int32 size) {
|
||||
// Not implemented in proxy.
|
||||
NOTREACHED();
|
||||
return false;
|
||||
}
|
||||
|
||||
gpu::Buffer PepperCommandBuffer::GetRingBuffer() {
|
||||
// Return locally cached ring buffer.
|
||||
gpu::Buffer buffer;
|
||||
|
Reference in New Issue
Block a user