blob: 42c08c36ba9c5d300d482118c1f540192ad18741 [file] [log] [blame]
// Copyright 2014 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 <utility>
#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/task_scheduler/task_scheduler.h"
#include "base/threading/thread_task_runner_handle.h"
#include "ui/display/types/display_snapshot.h"
#include "ui/display/types/native_display_delegate.h"
#include "ui/display/types/native_display_observer.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/events/ozone/layout/keyboard_layout_engine.h"
#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gl/gl_surface.h"
#include "ui/gl/init/gl_factory.h"
#include "ui/ozone/demo/gl_renderer.h"
#include "ui/ozone/demo/software_renderer.h"
#include "ui/ozone/demo/surfaceless_gl_renderer.h"
#include "ui/ozone/public/ozone_gpu_test_helper.h"
#include "ui/ozone/public/ozone_platform.h"
#include "ui/ozone/public/ozone_switches.h"
#include "ui/platform_window/platform_window.h"
#include "ui/platform_window/platform_window_delegate.h"
const int kTestWindowWidth = 800;
const int kTestWindowHeight = 600;
const char kDisableGpu[] = "disable-gpu";
const char kDisableSurfaceless[] = "disable-surfaceless";
const char kWindowSize[] = "window-size";
class DemoWindow;
scoped_refptr<gl::GLSurface> CreateGLSurface(gfx::AcceleratedWidget widget) {
scoped_refptr<gl::GLSurface> surface;
if (!base::CommandLine::ForCurrentProcess()->HasSwitch(kDisableSurfaceless))
surface = gl::init::CreateSurfacelessViewGLSurface(widget);
if (!surface)
surface = gl::init::CreateViewGLSurface(widget);
return surface;
}
class RendererFactory {
public:
enum RendererType {
GL,
SOFTWARE,
};
RendererFactory();
~RendererFactory();
bool Initialize();
std::unique_ptr<ui::Renderer> CreateRenderer(gfx::AcceleratedWidget widget,
const gfx::Size& size);
private:
RendererType type_ = SOFTWARE;
// Helper for applications that do GL on main thread.
ui::OzoneGpuTestHelper gpu_helper_;
DISALLOW_COPY_AND_ASSIGN(RendererFactory);
};
class WindowManager : public display::NativeDisplayObserver {
public:
WindowManager(const base::Closure& quit_closure);
~WindowManager() override;
void Quit();
void AddWindow(DemoWindow* window);
void RemoveWindow(DemoWindow* window);
private:
void OnDisplaysAquired(
const std::vector<display::DisplaySnapshot*>& displays);
void OnDisplayConfigured(const gfx::Rect& bounds, bool success);
// display::NativeDisplayDelegate:
void OnConfigurationChanged() override;
void OnDisplaySnapshotsInvalidated() override;
std::unique_ptr<display::NativeDisplayDelegate> delegate_;
base::Closure quit_closure_;
RendererFactory renderer_factory_;
std::vector<std::unique_ptr<DemoWindow>> windows_;
// Flags used to keep track of the current state of display configuration.
//
// True if configuring the displays. In this case a new display configuration
// isn't started.
bool is_configuring_ = false;
// If |is_configuring_| is true and another display configuration event
// happens, the event is deferred. This is set to true and a display
// configuration will be scheduled after the current one finishes.
bool should_configure_ = false;
DISALLOW_COPY_AND_ASSIGN(WindowManager);
};
class DemoWindow : public ui::PlatformWindowDelegate {
public:
DemoWindow(WindowManager* window_manager,
RendererFactory* renderer_factory,
const gfx::Rect& bounds)
: window_manager_(window_manager),
renderer_factory_(renderer_factory),
weak_ptr_factory_(this) {
platform_window_ =
ui::OzonePlatform::GetInstance()->CreatePlatformWindow(this, bounds);
}
~DemoWindow() override {}
gfx::AcceleratedWidget GetAcceleratedWidget() {
// TODO(spang): We should start rendering asynchronously.
DCHECK_NE(widget_, gfx::kNullAcceleratedWidget)
<< "Widget not available synchronously";
return widget_;
}
gfx::Size GetSize() { return platform_window_->GetBounds().size(); }
void Start() {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(&DemoWindow::StartOnGpu, weak_ptr_factory_.GetWeakPtr()));
}
void Quit() {
window_manager_->Quit();
}
// PlatformWindowDelegate:
void OnBoundsChanged(const gfx::Rect& new_bounds) override {}
void OnDamageRect(const gfx::Rect& damaged_region) override {}
void DispatchEvent(ui::Event* event) override {
if (event->IsKeyEvent() && event->AsKeyEvent()->code() == ui::DomCode::US_Q)
Quit();
}
void OnCloseRequest() override { Quit(); }
void OnClosed() override {}
void OnWindowStateChanged(ui::PlatformWindowState new_state) override {}
void OnLostCapture() override {}
void OnAcceleratedWidgetAvailable(gfx::AcceleratedWidget widget,
float device_pixel_ratio) override {
DCHECK_NE(widget, gfx::kNullAcceleratedWidget);
widget_ = widget;
}
void OnAcceleratedWidgetDestroyed() override {
NOTREACHED();
}
void OnActivationChanged(bool active) override {}
private:
// Since we pretend to have a GPU process, we should also pretend to
// initialize the GPU resources via a posted task.
void StartOnGpu() {
renderer_ =
renderer_factory_->CreateRenderer(GetAcceleratedWidget(), GetSize());
renderer_->Initialize();
}
WindowManager* window_manager_; // Not owned.
RendererFactory* renderer_factory_; // Not owned.
std::unique_ptr<ui::Renderer> renderer_;
// Window-related state.
std::unique_ptr<ui::PlatformWindow> platform_window_;
gfx::AcceleratedWidget widget_ = gfx::kNullAcceleratedWidget;
base::WeakPtrFactory<DemoWindow> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(DemoWindow);
};
///////////////////////////////////////////////////////////////////////////////
// RendererFactory implementation:
RendererFactory::RendererFactory() {
}
RendererFactory::~RendererFactory() {
}
bool RendererFactory::Initialize() {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (!command_line->HasSwitch(kDisableGpu) && gl::init::InitializeGLOneOff() &&
gpu_helper_.Initialize(base::ThreadTaskRunnerHandle::Get(),
base::ThreadTaskRunnerHandle::Get())) {
type_ = GL;
} else {
type_ = SOFTWARE;
}
return true;
}
std::unique_ptr<ui::Renderer> RendererFactory::CreateRenderer(
gfx::AcceleratedWidget widget,
const gfx::Size& size) {
switch (type_) {
case GL: {
scoped_refptr<gl::GLSurface> surface = CreateGLSurface(widget);
if (!surface)
LOG(FATAL) << "Failed to create GL surface";
if (!surface->SupportsAsyncSwap())
LOG(FATAL) << "GL surface must support SwapBuffersAsync";
if (surface->IsSurfaceless())
return base::MakeUnique<ui::SurfacelessGlRenderer>(widget, surface,
size);
else
return base::MakeUnique<ui::GlRenderer>(widget, surface, size);
}
case SOFTWARE:
return base::MakeUnique<ui::SoftwareRenderer>(widget, size);
}
return nullptr;
}
///////////////////////////////////////////////////////////////////////////////
// WindowManager implementation:
WindowManager::WindowManager(const base::Closure& quit_closure)
: delegate_(
ui::OzonePlatform::GetInstance()->CreateNativeDisplayDelegate()),
quit_closure_(quit_closure) {
if (!renderer_factory_.Initialize())
LOG(FATAL) << "Failed to initialize renderer factory";
if (delegate_) {
delegate_->AddObserver(this);
delegate_->Initialize();
OnConfigurationChanged();
} else {
LOG(WARNING) << "No display delegate; falling back to test window";
int width = kTestWindowWidth;
int height = kTestWindowHeight;
sscanf(base::CommandLine::ForCurrentProcess()
->GetSwitchValueASCII(kWindowSize)
.c_str(),
"%dx%d", &width, &height);
DemoWindow* window = new DemoWindow(this, &renderer_factory_,
gfx::Rect(gfx::Size(width, height)));
window->Start();
}
}
WindowManager::~WindowManager() {
if (delegate_)
delegate_->RemoveObserver(this);
}
void WindowManager::Quit() {
quit_closure_.Run();
}
void WindowManager::OnConfigurationChanged() {
if (is_configuring_) {
should_configure_ = true;
return;
}
is_configuring_ = true;
delegate_->GrabServer();
delegate_->GetDisplays(
base::Bind(&WindowManager::OnDisplaysAquired, base::Unretained(this)));
}
void WindowManager::OnDisplaySnapshotsInvalidated() {}
void WindowManager::OnDisplaysAquired(
const std::vector<display::DisplaySnapshot*>& displays) {
windows_.clear();
gfx::Point origin;
for (auto* display : displays) {
if (!display->native_mode()) {
LOG(ERROR) << "Display " << display->display_id()
<< " doesn't have a native mode";
continue;
}
delegate_->Configure(
*display, display->native_mode(), origin,
base::Bind(&WindowManager::OnDisplayConfigured, base::Unretained(this),
gfx::Rect(origin, display->native_mode()->size())));
origin.Offset(display->native_mode()->size().width(), 0);
}
delegate_->UngrabServer();
is_configuring_ = false;
if (should_configure_) {
should_configure_ = false;
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(&WindowManager::OnConfigurationChanged,
base::Unretained(this)));
}
}
void WindowManager::OnDisplayConfigured(const gfx::Rect& bounds, bool success) {
if (success) {
std::unique_ptr<DemoWindow> window(
new DemoWindow(this, &renderer_factory_, bounds));
window->Start();
windows_.push_back(std::move(window));
} else {
LOG(ERROR) << "Failed to configure display at " << bounds.ToString();
}
}
int main(int argc, char** argv) {
base::CommandLine::Init(argc, argv);
base::AtExitManager exit_manager;
// Initialize logging so we can enable VLOG messages.
logging::LoggingSettings settings;
logging::InitLogging(settings);
// Build UI thread message loop. This is used by platform
// implementations for event polling & running background tasks.
base::MessageLoopForUI message_loop;
constexpr int kMaxTaskSchedulerThreads = 3;
base::TaskScheduler::CreateAndSetSimpleTaskScheduler(
kMaxTaskSchedulerThreads);
ui::OzonePlatform::InitializeForUI();
ui::KeyboardLayoutEngineManager::GetKeyboardLayoutEngine()
->SetCurrentLayoutByName("us");
base::RunLoop run_loop;
WindowManager window_manager(run_loop.QuitClosure());
run_loop.Run();
return 0;
}