普通文本  |  210行  |  6.57 KB

// Copyright 2013 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 "base/command_line.h"
#include "base/run_loop.h"
#include "content/browser/gpu/browser_gpu_channel_host_factory.h"
#include "content/browser/gpu/gpu_process_host_ui_shim.h"
#include "content/common/gpu/client/context_provider_command_buffer.h"
#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
#include "content/common/gpu/gpu_process_launch_causes.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/gpu_data_manager.h"
#include "content/public/common/content_switches.h"
#include "content/test/content_browser_test.h"
#include "ui/gl/gl_switches.h"
#include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"

namespace {

using content::WebGraphicsContext3DCommandBufferImpl;

class ContextTestBase : public content::ContentBrowserTest {
 public:
  virtual void SetUpOnMainThread() OVERRIDE {
    if (!content::BrowserGpuChannelHostFactory::CanUseForTesting())
      return;

    if (!content::BrowserGpuChannelHostFactory::instance())
      content::BrowserGpuChannelHostFactory::Initialize(true);

    content::BrowserGpuChannelHostFactory* factory =
        content::BrowserGpuChannelHostFactory::instance();
    CHECK(factory);
    scoped_refptr<content::GpuChannelHost> gpu_channel_host(
        factory->EstablishGpuChannelSync(
            content::
                CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE));
    context_.reset(
        WebGraphicsContext3DCommandBufferImpl::CreateOffscreenContext(
            gpu_channel_host.get(),
            blink::WebGraphicsContext3D::Attributes(),
            GURL(),
            WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits()));
    CHECK(context_.get());
    context_->makeContextCurrent();
    context_support_ = context_->GetContextSupport();
    ContentBrowserTest::SetUpOnMainThread();
  }

  virtual void TearDownOnMainThread() OVERRIDE {
    // Must delete the context first.
    context_.reset(NULL);
    ContentBrowserTest::TearDownOnMainThread();
  }

 protected:
  scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context_;
  gpu::ContextSupport* context_support_;
};

}  // namespace

// Include the shared tests.
#define CONTEXT_TEST_F IN_PROC_BROWSER_TEST_F
#include "content/common/gpu/client/gpu_context_tests.h"

namespace content {

class BrowserGpuChannelHostFactoryTest : public ContextTestBase {
 public:
  virtual void SetUpOnMainThread() OVERRIDE {
    if (!content::BrowserGpuChannelHostFactory::CanUseForTesting())
      return;

    // Start all tests without a gpu channel so that the tests exercise a
    // consistent codepath.
    if (!content::BrowserGpuChannelHostFactory::instance())
      content::BrowserGpuChannelHostFactory::Initialize(false);

    CHECK(GetFactory());

    ContentBrowserTest::SetUpOnMainThread();
  }

  virtual void TearDownOnMainThread() OVERRIDE {
    ContextTestBase::TearDownOnMainThread();
  }

  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    // Start all tests without a gpu channel so that the tests exercise a
    // consistent codepath.
    command_line->AppendSwitch(switches::kDisableGpuProcessPrelaunch);
  }

  void OnContextLost(const base::Closure callback, int* counter) {
    (*counter)++;
    callback.Run();
  }

 protected:
  BrowserGpuChannelHostFactory* GetFactory() {
    return BrowserGpuChannelHostFactory::instance();
  }

  bool IsChannelEstablished() {
    return GetFactory()->GetGpuChannel() != NULL;
  }

  void EstablishAndWait() {
    base::RunLoop run_loop;
    GetFactory()->EstablishGpuChannel(
        CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE,
        run_loop.QuitClosure());
    run_loop.Run();
  }

  GpuChannelHost* GetGpuChannel() {
    return GetFactory()->GetGpuChannel();
  }

  static void Signal(bool *event) {
    CHECK_EQ(*event, false);
    *event = true;
  }

  scoped_ptr<WebGraphicsContext3DCommandBufferImpl> CreateContext() {
    return make_scoped_ptr(
        WebGraphicsContext3DCommandBufferImpl::CreateOffscreenContext(
            GetGpuChannel(),
            blink::WebGraphicsContext3D::Attributes(),
            GURL(),
            WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits()));
  }
};

IN_PROC_BROWSER_TEST_F(BrowserGpuChannelHostFactoryTest, Basic) {
  if (!context_)
    return;

  DCHECK(!IsChannelEstablished());
  EstablishAndWait();
  EXPECT_TRUE(GetGpuChannel() != NULL);
}

IN_PROC_BROWSER_TEST_F(BrowserGpuChannelHostFactoryTest,
                       EstablishAndTerminate) {
  if (!context_)
    return;

  DCHECK(!IsChannelEstablished());
  base::RunLoop run_loop;
  GetFactory()->EstablishGpuChannel(
      CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE,
      run_loop.QuitClosure());
  GetFactory()->Terminate();

  // The callback should still trigger.
  run_loop.Run();
}

IN_PROC_BROWSER_TEST_F(BrowserGpuChannelHostFactoryTest, AlreadyEstablished) {
  if (!context_)
    return;

  DCHECK(!IsChannelEstablished());
  scoped_refptr<GpuChannelHost> gpu_channel =
      GetFactory()->EstablishGpuChannelSync(
          CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE);

  // Expect established callback immediately.
  bool event = false;
  GetFactory()->EstablishGpuChannel(
      CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE,
      base::Bind(&BrowserGpuChannelHostFactoryTest::Signal, &event));
  EXPECT_TRUE(event);
  EXPECT_EQ(gpu_channel, GetGpuChannel());
}

IN_PROC_BROWSER_TEST_F(BrowserGpuChannelHostFactoryTest, CrashAndRecover) {
  if (!context_)
    return;

  DCHECK(!IsChannelEstablished());
  EstablishAndWait();
  scoped_refptr<GpuChannelHost> host = GetGpuChannel();

  scoped_refptr<ContextProviderCommandBuffer> provider =
      ContextProviderCommandBuffer::Create(CreateContext(),
                                           "BrowserGpuChannelHostFactoryTest");
  base::RunLoop run_loop;
  int counter = 0;
  provider->SetLostContextCallback(
      base::Bind(&BrowserGpuChannelHostFactoryTest::OnContextLost,
                 base::Unretained(this), run_loop.QuitClosure(), &counter));
  EXPECT_TRUE(provider->BindToCurrentThread());
  GpuProcessHostUIShim* shim =
      GpuProcessHostUIShim::FromID(GetFactory()->GpuProcessHostId());
  EXPECT_TRUE(shim != NULL);
  shim->SimulateCrash();
  run_loop.Run();

  EXPECT_EQ(1, counter);
  EXPECT_FALSE(IsChannelEstablished());
  EstablishAndWait();
  EXPECT_TRUE(IsChannelEstablished());
}

}  // namespace content