#include "base/debug/trace_event.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread_restrictions.h"
+#include "base/tracked_objects.h"
#include "content/browser/gpu/gpu_data_manager_impl.h"
+#include "content/browser/gpu/gpu_memory_buffer_factory_host_impl.h"
#include "content/browser/gpu/gpu_process_host.h"
#include "content/browser/gpu/gpu_surface_tracker.h"
#include "content/common/child_process_host_impl.h"
BrowserGpuChannelHostFactory* BrowserGpuChannelHostFactory::instance_ = NULL;
struct BrowserGpuChannelHostFactory::CreateRequest {
- CreateRequest()
- : event(true, false), gpu_host_id(0), route_id(MSG_ROUTING_NONE),
+ CreateRequest(int32 route_id)
+ : event(true, false),
+ gpu_host_id(0),
+ route_id(route_id),
result(CREATE_COMMAND_BUFFER_FAILED) {}
~CreateRequest() {}
base::WaitableEvent event;
CreateCommandBufferResult result;
};
+struct BrowserGpuChannelHostFactory::AllocateGpuMemoryBufferRequest {
+ AllocateGpuMemoryBufferRequest(size_t width,
+ size_t height,
+ unsigned internalformat,
+ unsigned usage,
+ int client_id)
+ : event(true, false),
+ width(width),
+ height(height),
+ internalformat(internalformat),
+ usage(usage),
+ client_id(client_id) {}
+ ~AllocateGpuMemoryBufferRequest() {}
+ base::WaitableEvent event;
+ size_t width;
+ size_t height;
+ unsigned internalformat;
+ unsigned usage;
+ int client_id;
+ scoped_ptr<gfx::GpuMemoryBuffer> result;
+};
+
class BrowserGpuChannelHostFactory::EstablishRequest
: public base::RefCountedThreadSafe<EstablishRequest> {
public:
void BrowserGpuChannelHostFactory::EstablishRequest::Wait() {
DCHECK(main_loop_->BelongsToCurrentThread());
{
+ // Since the current task synchronously waits for establishing a GPU
+ // channel, it shouldn't be tallied because its execution time has nothing
+ // to do with its efficiency. Using task stopwatch to exclude the waiting
+ // time from the current task run time.
+ tracked_objects::TaskStopwatch stopwatch;
// We're blocking the UI thread, which is generally undesirable.
// In this case we need to wait for this before we can show any UI
// /anyway/, so it won't cause additional jank.
"BrowserGpuChannelHostFactory::EstablishGpuChannelSync");
base::ThreadRestrictions::ScopedAllowWait allow_wait;
event_.Wait();
+
+ stopwatch.Stop();
}
FinishOnMain();
}
BrowserGpuChannelHostFactory::BrowserGpuChannelHostFactory()
: gpu_client_id_(ChildProcessHostImpl::GenerateChildProcessUniqueId()),
shutdown_event_(new base::WaitableEvent(true, false)),
- gpu_host_id_(0),
- next_create_gpu_memory_buffer_request_id_(0) {
+ gpu_memory_buffer_factory_host_(new GpuMemoryBufferFactoryHostImpl),
+ gpu_host_id_(0) {
}
BrowserGpuChannelHostFactory::~BrowserGpuChannelHostFactory() {
DCHECK(IsMainThread());
- if (pending_request_)
+ if (pending_request_.get())
pending_request_->Cancel();
for (size_t n = 0; n < established_callbacks_.size(); n++)
established_callbacks_[n].Run();
int32 surface_id,
const GPUCreateCommandBufferConfig& init_params,
int32 route_id) {
- CreateRequest request;
- request.route_id = route_id;
+ CreateRequest request(route_id);
GetIOLoopProxy()->PostTask(FROM_HERE, base::Bind(
&BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO,
base::Unretained(this),
CauseForGpuLaunch cause_for_gpu_launch) {
EstablishGpuChannel(cause_for_gpu_launch, base::Closure());
- if (pending_request_)
+ if (pending_request_.get())
pending_request_->Wait();
return gpu_channel_.get();
CauseForGpuLaunch cause_for_gpu_launch,
const base::Closure& callback) {
if (gpu_channel_.get() && gpu_channel_->IsLost()) {
- DCHECK(!pending_request_);
+ DCHECK(!pending_request_.get());
// Recreate the channel if it has been lost.
gpu_channel_ = NULL;
}
- if (!gpu_channel_ && !pending_request_) {
+ if (!gpu_channel_.get() && !pending_request_.get()) {
// We should only get here if the context was lost.
pending_request_ = EstablishRequest::Create(
cause_for_gpu_launch, gpu_client_id_, gpu_host_id_);
}
if (!callback.is_null()) {
- if (gpu_channel_)
+ if (gpu_channel_.get())
callback.Run();
else
established_callbacks_.push_back(callback);
}
GpuChannelHost* BrowserGpuChannelHostFactory::GetGpuChannel() {
- if (gpu_channel_ && !gpu_channel_->IsLost())
- return gpu_channel_;
+ if (gpu_channel_.get() && !gpu_channel_->IsLost())
+ return gpu_channel_.get();
return NULL;
}
void BrowserGpuChannelHostFactory::GpuChannelEstablished() {
DCHECK(IsMainThread());
- DCHECK(pending_request_);
+ DCHECK(pending_request_.get());
if (pending_request_->channel_handle().name.empty()) {
- DCHECK(!gpu_channel_);
+ DCHECK(!gpu_channel_.get());
} else {
GetContentClient()->SetGpuInfo(pending_request_->gpu_info());
gpu_channel_ = GpuChannelHost::Create(this,
shutdown_event_.get());
}
gpu_host_id_ = pending_request_->gpu_host_id();
+ gpu_memory_buffer_factory_host_->set_gpu_host_id(gpu_host_id_);
pending_request_ = NULL;
for (size_t n = 0; n < established_callbacks_.size(); n++)
size_t height,
unsigned internalformat,
unsigned usage) {
- if (!GpuMemoryBufferImpl::IsFormatValid(internalformat) ||
- !GpuMemoryBufferImpl::IsUsageValid(usage))
- return scoped_ptr<gfx::GpuMemoryBuffer>();
+ DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
- return GpuMemoryBufferImpl::Create(gfx::Size(width, height),
- internalformat,
- usage).PassAs<gfx::GpuMemoryBuffer>();
+ AllocateGpuMemoryBufferRequest request(
+ width, height, internalformat, usage, gpu_client_id_);
+ GetIOLoopProxy()->PostTask(
+ FROM_HERE,
+ base::Bind(&BrowserGpuChannelHostFactory::AllocateGpuMemoryBufferOnIO,
+ base::Unretained(&request)));
+
+ // We're blocking the UI thread, which is generally undesirable.
+ TRACE_EVENT0("browser",
+ "BrowserGpuChannelHostFactory::AllocateGpuMemoryBuffer");
+ base::ThreadRestrictions::ScopedAllowWait allow_wait;
+ request.event.Wait();
+ return request.result.Pass();
}
// static
filter));
}
-void BrowserGpuChannelHostFactory::CreateGpuMemoryBuffer(
- const gfx::GpuMemoryBufferHandle& handle,
- const gfx::Size& size,
- unsigned internalformat,
- unsigned usage,
- const CreateGpuMemoryBufferCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- uint32 request_id = next_create_gpu_memory_buffer_request_id_++;
- create_gpu_memory_buffer_requests_[request_id] = callback;
- GetIOLoopProxy()->PostTask(
- FROM_HERE,
- base::Bind(&BrowserGpuChannelHostFactory::CreateGpuMemoryBufferOnIO,
- base::Unretained(this),
- handle,
- size,
- internalformat,
- usage,
- request_id));
-}
-
-void BrowserGpuChannelHostFactory::DestroyGpuMemoryBuffer(
- const gfx::GpuMemoryBufferHandle& handle,
- int32 sync_point) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- GetIOLoopProxy()->PostTask(
- FROM_HERE,
- base::Bind(&BrowserGpuChannelHostFactory::DestroyGpuMemoryBufferOnIO,
- base::Unretained(this),
- handle,
- sync_point));
-}
-
-void BrowserGpuChannelHostFactory::CreateGpuMemoryBufferOnIO(
- const gfx::GpuMemoryBufferHandle& handle,
- const gfx::Size& size,
- unsigned internalformat,
- unsigned usage,
- uint32 request_id) {
- GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
- if (!host) {
- GpuMemoryBufferCreatedOnIO(request_id, gfx::GpuMemoryBufferHandle());
+// static
+void BrowserGpuChannelHostFactory::AllocateGpuMemoryBufferOnIO(
+ AllocateGpuMemoryBufferRequest* request) {
+ if (!GpuMemoryBufferImpl::IsFormatValid(request->internalformat) ||
+ !GpuMemoryBufferImpl::IsUsageValid(request->usage)) {
+ request->result = scoped_ptr<gfx::GpuMemoryBuffer>();
+ request->event.Signal();
return;
}
- host->CreateGpuMemoryBuffer(
- handle,
- size,
- internalformat,
- usage,
- base::Bind(&BrowserGpuChannelHostFactory::GpuMemoryBufferCreatedOnIO,
- base::Unretained(this),
- request_id));
-}
-
-void BrowserGpuChannelHostFactory::GpuMemoryBufferCreatedOnIO(
- uint32 request_id,
- const gfx::GpuMemoryBufferHandle& handle) {
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
+ GpuMemoryBufferImpl::Create(
+ gfx::Size(request->width, request->height),
+ request->internalformat,
+ request->usage,
+ request->client_id,
base::Bind(&BrowserGpuChannelHostFactory::OnGpuMemoryBufferCreated,
- base::Unretained(this),
- request_id,
- handle));
+ base::Unretained(request)));
}
+// static
void BrowserGpuChannelHostFactory::OnGpuMemoryBufferCreated(
- uint32 request_id,
- const gfx::GpuMemoryBufferHandle& handle) {
- CreateGpuMemoryBufferCallbackMap::iterator iter =
- create_gpu_memory_buffer_requests_.find(request_id);
- DCHECK(iter != create_gpu_memory_buffer_requests_.end());
- iter->second.Run(handle);
- create_gpu_memory_buffer_requests_.erase(iter);
-}
-
-void BrowserGpuChannelHostFactory::DestroyGpuMemoryBufferOnIO(
- const gfx::GpuMemoryBufferHandle& handle,
- int32 sync_point) {
- GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
- if (!host)
- return;
+ AllocateGpuMemoryBufferRequest* request,
+ scoped_ptr<GpuMemoryBufferImpl> buffer) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- host->DestroyGpuMemoryBuffer(handle, sync_point);
+ request->result = buffer.PassAs<gfx::GpuMemoryBuffer>();
+ request->event.Signal();
}
} // namespace content