blob: bbb2c407426f4f6f935f1ac6ecd0c3a0967128ba [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 "ui/ozone/platform/dri/gbm_surface_factory.h"
#include <gbm.h>
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "third_party/khronos/EGL/egl.h"
#include "ui/ozone/platform/dri/dri_window_delegate_impl.h"
#include "ui/ozone/platform/dri/dri_window_delegate_manager.h"
#include "ui/ozone/platform/dri/gbm_buffer.h"
#include "ui/ozone/platform/dri/gbm_surface.h"
#include "ui/ozone/platform/dri/gbm_surfaceless.h"
#include "ui/ozone/platform/dri/screen_manager.h"
#include "ui/ozone/public/native_pixmap.h"
#include "ui/ozone/public/overlay_candidates_ozone.h"
#include "ui/ozone/public/ozone_switches.h"
#include "ui/ozone/public/surface_ozone_egl.h"
namespace ui {
namespace {
class SingleOverlay : public OverlayCandidatesOzone {
public:
SingleOverlay() {}
virtual ~SingleOverlay() {}
virtual void CheckOverlaySupport(
OverlaySurfaceCandidateList* candidates) override {
if (candidates->size() == 2) {
OverlayCandidatesOzone::OverlaySurfaceCandidate* first =
&(*candidates)[0];
OverlayCandidatesOzone::OverlaySurfaceCandidate* second =
&(*candidates)[1];
OverlayCandidatesOzone::OverlaySurfaceCandidate* overlay;
if (first->plane_z_order == 0) {
overlay = second;
} else if (second->plane_z_order == 0) {
overlay = first;
} else {
NOTREACHED();
return;
}
if (overlay->plane_z_order > 0 &&
IsTransformSupported(overlay->transform)) {
overlay->overlay_handled = true;
}
}
}
private:
bool IsTransformSupported(gfx::OverlayTransform transform) {
switch (transform) {
case gfx::OVERLAY_TRANSFORM_NONE:
return true;
default:
return false;
}
}
DISALLOW_COPY_AND_ASSIGN(SingleOverlay);
};
} // namespace
GbmSurfaceFactory::GbmSurfaceFactory(bool allow_surfaceless)
: DriSurfaceFactory(NULL, NULL, NULL),
device_(NULL),
allow_surfaceless_(allow_surfaceless) {
}
GbmSurfaceFactory::~GbmSurfaceFactory() {}
void GbmSurfaceFactory::InitializeGpu(
DriWrapper* dri,
gbm_device* device,
ScreenManager* screen_manager,
DriWindowDelegateManager* window_manager) {
drm_ = dri;
device_ = device;
screen_manager_ = screen_manager;
window_manager_ = window_manager;
}
intptr_t GbmSurfaceFactory::GetNativeDisplay() {
DCHECK(state_ == INITIALIZED);
return reinterpret_cast<intptr_t>(device_);
}
const int32* GbmSurfaceFactory::GetEGLSurfaceProperties(
const int32* desired_list) {
static const int32 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;
}
bool GbmSurfaceFactory::LoadEGLGLES2Bindings(
AddGLLibraryCallback add_gl_library,
SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
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;
}
set_gl_get_proc_address.Run(get_proc_address);
add_gl_library.Run(egl_library);
add_gl_library.Run(gles_library);
return true;
}
scoped_ptr<SurfaceOzoneEGL> GbmSurfaceFactory::CreateEGLSurfaceForWidget(
gfx::AcceleratedWidget widget) {
DCHECK(state_ == INITIALIZED);
DriWindowDelegate* delegate = GetOrCreateWindowDelegate(widget);
scoped_ptr<GbmSurface> surface(new GbmSurface(delegate, device_, drm_));
if (!surface->Initialize())
return nullptr;
return surface.Pass();
}
scoped_ptr<SurfaceOzoneEGL>
GbmSurfaceFactory::CreateSurfacelessEGLSurfaceForWidget(
gfx::AcceleratedWidget widget) {
if (!allow_surfaceless_)
return scoped_ptr<SurfaceOzoneEGL>();
DriWindowDelegate* delegate = GetOrCreateWindowDelegate(widget);
return scoped_ptr<SurfaceOzoneEGL>(new GbmSurfaceless(delegate));
}
scoped_refptr<ui::NativePixmap> GbmSurfaceFactory::CreateNativePixmap(
gfx::Size size,
BufferFormat format) {
scoped_refptr<GbmBuffer> buffer = GbmBuffer::CreateBuffer(
drm_, device_, format, size, true);
if (!buffer.get())
return NULL;
scoped_refptr<GbmPixmap> pixmap(new GbmPixmap(buffer));
if (!pixmap->Initialize(drm_))
return NULL;
return pixmap;
}
OverlayCandidatesOzone* GbmSurfaceFactory::GetOverlayCandidates(
gfx::AcceleratedWidget w) {
if (CommandLine::ForCurrentProcess()->HasSwitch(
switches::kOzoneTestSingleOverlaySupport))
return new SingleOverlay();
return NULL;
}
bool GbmSurfaceFactory::ScheduleOverlayPlane(
gfx::AcceleratedWidget widget,
int plane_z_order,
gfx::OverlayTransform plane_transform,
scoped_refptr<NativePixmap> buffer,
const gfx::Rect& display_bounds,
const gfx::RectF& crop_rect) {
scoped_refptr<GbmPixmap> pixmap = static_cast<GbmPixmap*>(buffer.get());
if (!pixmap.get()) {
LOG(ERROR) << "ScheduleOverlayPlane passed NULL buffer.";
return false;
}
HardwareDisplayController* hdc =
window_manager_->GetWindowDelegate(widget)->GetController();
if (!hdc)
return true;
hdc->QueueOverlayPlane(OverlayPlane(pixmap->buffer(),
plane_z_order,
plane_transform,
display_bounds,
crop_rect));
return true;
}
bool GbmSurfaceFactory::CanShowPrimaryPlaneAsOverlay() {
return allow_surfaceless_;
}
DriWindowDelegate* GbmSurfaceFactory::GetOrCreateWindowDelegate(
gfx::AcceleratedWidget widget) {
if (!window_manager_->HasWindowDelegate(widget)) {
scoped_ptr<DriWindowDelegate> delegate(
new DriWindowDelegateImpl(widget, screen_manager_));
delegate->Initialize();
window_manager_->AddWindowDelegate(widget, delegate.Pass());
}
return window_manager_->GetWindowDelegate(widget);
}
} // namespace ui