#include "ozone/wayland/display.h"
+#include <EGL/egl.h>
+#include <string>
+
+#include "base/files/file_path.h"
+#include "base/native_library.h"
#include "base/stl_util.h"
#include "ozone/ui/events/event_factory_ozone_wayland.h"
#include "ozone/ui/events/output_change_observer.h"
+#include "ozone/ui/gfx/ozone_display.h"
#include "ozone/wayland/display_poll_thread.h"
#include "ozone/wayland/input/cursor.h"
#include "ozone/wayland/input_device.h"
#include "ozone/wayland/screen.h"
+#include "ozone/wayland/egl/surface_ozone_wayland.h"
#include "ozone/wayland/shell/shell.h"
#include "ozone/wayland/window.h"
+#include "ui/gfx/ozone/surface_ozone_egl.h"
namespace ozonewayland {
WaylandDisplay* WaylandDisplay::instance_ = NULL;
widget_map_(),
serial_(0),
processing_events_(false) {
- display_ = wl_display_connect(NULL);
- if (!display_)
- return;
-
- instance_ = this;
- static const struct wl_registry_listener registry_all = {
- WaylandDisplay::DisplayHandleGlobal
- };
-
- static const struct wl_registry_listener registry_output = {
- WaylandDisplay::DisplayHandleOutputOnly
- };
-
- registry_ = wl_display_get_registry(display_);
- if (type == RegisterAsNeeded) {
- wl_registry_add_listener(registry_, ®istry_all, this);
- shell_ = new WaylandShell();
- } else {
- wl_registry_add_listener(registry_, ®istry_output, this);
- }
-
- if (wl_display_roundtrip(display_) < 0)
- terminate();
- else if (type == RegisterAsNeeded) {
- ui::WindowStateChangeHandler::SetInstance(this);
- display_poll_thread_ = new WaylandDisplayPollThread(display_);
- }
+ if (type == RegisterAsNeeded)
+ gfx::OzoneDisplay::SetInstance(this);
+ else
+ InitializeDisplay(WaylandDisplay::RegisterOutputOnly);
}
WaylandDisplay::~WaylandDisplay() {
- terminate();
+ Terminate();
}
const std::list<WaylandScreen*>& WaylandDisplay::GetScreenList() const {
return text_input_manager_;
}
+void WaylandDisplay::SyncDisplay() {
+ wl_display_roundtrip(display_);
+}
+
void WaylandDisplay::FlushDisplay() {
wl_display_flush(display_);
}
-void WaylandDisplay::SyncDisplay() {
- wl_display_roundtrip(display_);
+void WaylandDisplay::DestroyWindow(unsigned w) {
+ std::map<unsigned, WaylandWindow*>::const_iterator it = widget_map_.find(w);
+ WaylandWindow* widget = it == widget_map_.end() ? NULL : it->second;
+ DCHECK(widget);
+ delete widget;
+ widget_map_.erase(w);
+ if (widget_map_.empty())
+ StopProcessingEvents();
}
-wl_egl_window* WaylandDisplay::RealizeAcceleratedWidget(unsigned w) {
+gfx::AcceleratedWidget WaylandDisplay::GetNativeWindow(unsigned window_handle) {
// Ensure we are processing wayland event requests.
StartProcessingEvents();
- WaylandWindow* widget = GetWidget(w);
+ WaylandWindow* widget = GetWidget(window_handle);
DCHECK(widget);
widget->RealizeAcceleratedWidget();
- return widget->egl_window();
+ return (gfx::AcceleratedWidget)widget->egl_window();
+}
+
+gfx::SurfaceFactoryOzone::HardwareState
+WaylandDisplay::InitializeHardware() {
+ InitializeDisplay(WaylandDisplay::RegisterAsNeeded);
+ if (!display_) {
+ LOG(ERROR) << "WaylandDisplay failed to initialize hardware";
+ return gfx::SurfaceFactoryOzone::FAILED;
+ }
+
+ return gfx::SurfaceFactoryOzone::INITIALIZED;
+}
+
+void WaylandDisplay::ShutdownHardware() {
+ Terminate();
+}
+
+intptr_t WaylandDisplay::GetNativeDisplay() {
+ return (intptr_t)display_;
+}
+
+gfx::AcceleratedWidget WaylandDisplay::GetAcceleratedWidget() {
+ static int opaque_handle = 0;
+ opaque_handle++;
+ ui::WindowStateChangeHandler::GetInstance()->SetWidgetState(opaque_handle,
+ ui::CREATE,
+ 0,
+ 0);
+
+ return (gfx::AcceleratedWidget)opaque_handle;
+}
+
+// TODO(vignatti): GPU process conceptually is the one that deals with hardware
+// details and therefore we assume that the window system connection should
+// happen in there only. There's a glitch with Chrome though, that creates its
+// frame contents requiring access to the window system, before the GPU process
+// even exists. In other words, Chrome runs
+// BrowserMainLoop::PreMainMessageLoopRun before GpuProcessHost::Get. If the
+// assumption of window system connection belongs to the GPU process is valid,
+// then I believe this Chrome behavior needs to be addressed upstream.
+//
+// For now, we create another window system connection to look ahead the needed
+// output properties that Chrome (among others) need and then close right after
+// that. I haven't measured how long it takes to open a Wayland connection,
+// listen all the interface the compositor sends and close it, but _for_ _sure_
+// it slows down the overall initialization time of Chromium targets.
+// Therefore, this is something that has to be solved in the future, moving all
+// Chrome tasks after GPU process is created.
+//
+void WaylandDisplay::LookAheadOutputGeometry() {
+ WaylandDisplay disp_(WaylandDisplay::RegisterOutputOnly);
+ CHECK(disp_.display()) << "Ozone: Wayland server connection not found.";
+
+ while (disp_.PrimaryScreen()->Geometry().IsEmpty())
+ disp_.SyncDisplay();
+
+ ui::EventFactoryOzoneWayland* event_factory =
+ ui::EventFactoryOzoneWayland::GetInstance();
+ DCHECK(event_factory->GetOutputChangeObserver());
+
+ unsigned width = disp_.PrimaryScreen()->Geometry().width();
+ unsigned height = disp_.PrimaryScreen()->Geometry().height();
+ event_factory->GetOutputChangeObserver()->OnOutputSizeChanged(width, height);
+}
+
+scoped_ptr<gfx::SurfaceOzoneEGL> WaylandDisplay::CreateEGLSurfaceForWidget(
+ gfx::AcceleratedWidget w) {
+ return make_scoped_ptr<gfx::SurfaceOzoneEGL>(new SurfaceOzoneWayland(w));
+}
+
+bool WaylandDisplay::LoadEGLGLES2Bindings(
+ gfx::SurfaceFactoryOzone::AddGLLibraryCallback add_gl_library,
+ gfx::SurfaceFactoryOzone::SetGLGetProcAddressProcCallback setprocaddress) {
+ // The variable EGL_PLATFORM specifies native platform to be used by the
+ // drivers (atleast on Mesa). When the variable is not set, Mesa uses the
+ // first platform listed in --with-egl-platforms during compilation. Thus, we
+ // ensure here that wayland is set as the native platform. However, we don't
+ // override the EGL_PLATFORM value in case it has already been set.
+ setenv("EGL_PLATFORM", "wayland", 0);
+ base::NativeLibraryLoadError error;
+ base::NativeLibrary gles_library = base::LoadNativeLibrary(
+ base::FilePath("libGLESv2.so.2"), &error);
+
+ if (!gles_library) {
+ LOG(WARNING) << "Failed to load GLES library: " << error.ToString();
+ return false;
+ }
+
+ base::NativeLibrary egl_library = base::LoadNativeLibrary(
+ base::FilePath("libEGL.so.1"), &error);
+
+ if (!egl_library) {
+ LOG(WARNING) << "Failed to load EGL library: " << error.ToString();
+ base::UnloadNativeLibrary(gles_library);
+ return false;
+ }
+
+ GLGetProcAddressProc get_proc_address =
+ reinterpret_cast<GLGetProcAddressProc>(
+ base::GetFunctionPointerFromNativeLibrary(
+ egl_library, "eglGetProcAddress"));
+
+ if (!get_proc_address) {
+ LOG(ERROR) << "eglGetProcAddress not found.";
+ base::UnloadNativeLibrary(egl_library);
+ base::UnloadNativeLibrary(gles_library);
+ return false;
+ }
+
+ setprocaddress.Run(get_proc_address);
+ add_gl_library.Run(egl_library);
+ add_gl_library.Run(gles_library);
+ return true;
+}
+
+const int32*
+WaylandDisplay::GetEGLSurfaceProperties(const int32* desired_list) {
+ static const EGLint kConfigAttribs[] = {
+ EGL_BUFFER_SIZE, 32,
+ EGL_ALPHA_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_RED_SIZE, 8,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_NONE
+ };
+
+ return kConfigAttribs;
}
void WaylandDisplay::SetWidgetState(unsigned w,
case ui::HIDE:
NOTIMPLEMENTED() << " HIDE " << w;
break;
- case ui::RESIZE:
- {
- WaylandWindow* window = GetWidget(w);
- DCHECK(window);
- window->Resize(width, height);
- break;
- }
- case ui::DESTROYED:
- {
- DestroyWindow(w);
- if (widget_map_.empty())
- StopProcessingEvents();
- break;
- }
default:
break;
}
}
}
+void WaylandDisplay::InitializeDisplay(RegistrationType type) {
+ DCHECK(!display_);
+ display_ = wl_display_connect(NULL);
+ if (!display_)
+ return;
+
+ instance_ = this;
+ static const struct wl_registry_listener registry_all = {
+ WaylandDisplay::DisplayHandleGlobal
+ };
+
+ static const struct wl_registry_listener registry_output = {
+ WaylandDisplay::DisplayHandleOutputOnly
+ };
+
+ registry_ = wl_display_get_registry(display_);
+ if (type == RegisterAsNeeded) {
+ wl_registry_add_listener(registry_, ®istry_all, this);
+ shell_ = new WaylandShell();
+ } else {
+ wl_registry_add_listener(registry_, ®istry_output, this);
+ }
+
+ if (wl_display_roundtrip(display_) < 0)
+ Terminate();
+ else if (type == RegisterAsNeeded) {
+ ui::WindowStateChangeHandler::SetInstance(this);
+ display_poll_thread_ = new WaylandDisplayPollThread(display_);
+ }
+}
+
WaylandWindow* WaylandDisplay::CreateAcceleratedSurface(unsigned w) {
WaylandWindow* window = new WaylandWindow(w);
widget_map_[w] = window;
return window;
}
-void WaylandDisplay::DestroyWindow(unsigned w) {
- std::map<unsigned, WaylandWindow*>::const_iterator it = widget_map_.find(w);
- WaylandWindow* widget = it == widget_map_.end() ? NULL : it->second;
- DCHECK(widget);
- delete widget;
- widget_map_.erase(w);
-}
-
void WaylandDisplay::StartProcessingEvents() {
DCHECK(display_poll_thread_);
// Start polling for wayland events.
}
}
-void WaylandDisplay::terminate() {
+void WaylandDisplay::Terminate() {
if (!widget_map_.empty()) {
STLDeleteValues(&widget_map_);
widget_map_.clear();
}
}
-// static
-// TODO(vignatti): GPU process conceptually is the one that deals with hardware
-// details and therefore we assume that the window system connection should
-// happen in there only. There's a glitch with Chrome though, that creates its
-// frame contents requiring access to the window system, before the GPU process
-// even exists. In other words, Chrome runs
-// BrowserMainLoop::PreMainMessageLoopRun before GpuProcessHost::Get. If the
-// assumption of window system connection belongs to the GPU process is valid,
-// then I believe this Chrome behavior needs to be addressed upstream.
-//
-// For now, we create another window system connection to look ahead the needed
-// output properties that Chrome (among others) need and then close right after
-// that. I haven't measured how long it takes to open a Wayland connection,
-// listen all the interface the compositor sends and close it, but _for_ _sure_
-// it slows down the overall initialization time of Chromium targets.
-// Therefore, this is something that has to be solved in the future, moving all
-// Chrome tasks after GPU process is created.
-//
-void WaylandDisplay::LookAheadOutputGeometry() {
- WaylandDisplay disp_(WaylandDisplay::RegisterOutputOnly);
- CHECK(disp_.display()) << "Ozone: Wayland server connection not found.";
-
- while (disp_.PrimaryScreen()->Geometry().IsEmpty())
- disp_.SyncDisplay();
-
- ui::EventFactoryOzoneWayland* event_factory =
- ui::EventFactoryOzoneWayland::GetInstance();
- DCHECK(event_factory->GetOutputChangeObserver());
-
- unsigned width = disp_.PrimaryScreen()->Geometry().width();
- unsigned height = disp_.PrimaryScreen()->Geometry().height();
- event_factory->GetOutputChangeObserver()->OnOutputSizeChanged(width, height);
-}
-
} // namespace ozonewayland