summaryrefslogtreecommitdiff
path: root/chromium/ui/ozone/platform/cast/gl_ozone_egl_cast.cc
blob: 93ed64dafb0dbee393ae7cd57170c31de84d7118 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// Copyright 2017 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/cast/gl_ozone_egl_cast.h"

#include <EGL/egl.h>
#include <dlfcn.h>
#include <memory>
#include <utility>

#include "base/command_line.h"
#include "base/macros.h"
#include "base/strings/string_number_conversions.h"
#include "chromecast/base/chromecast_switches.h"
#include "chromecast/public/cast_egl_platform.h"
#include "chromecast/public/graphics_types.h"
#include "ui/gfx/vsync_provider.h"
#include "ui/ozone/platform/cast/gl_surface_cast.h"

using chromecast::CastEglPlatform;

namespace ui {

namespace {

typedef EGLDisplay (*EGLGetDisplayFn)(NativeDisplayType);
typedef EGLBoolean (*EGLTerminateFn)(EGLDisplay);

chromecast::Size FromGfxSize(const gfx::Size& size) {
  return chromecast::Size(size.width(), size.height());
}

// Display resolution, set in browser process and passed by switches.
gfx::Size GetDisplaySize() {
  base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
  int width, height;
  if (base::StringToInt(
          cmd_line->GetSwitchValueASCII(switches::kCastInitialScreenWidth),
          &width) &&
      base::StringToInt(
          cmd_line->GetSwitchValueASCII(switches::kCastInitialScreenHeight),
          &height)) {
    return gfx::Size(width, height);
  }
  LOG(WARNING) << "Unable to get initial screen resolution from command line,"
               << "using default 720p";
  return gfx::Size(1280, 720);
}

}  // namespace

GLOzoneEglCast::GLOzoneEglCast(std::unique_ptr<CastEglPlatform> egl_platform)
    : display_size_(GetDisplaySize()), egl_platform_(std::move(egl_platform)) {}

GLOzoneEglCast::~GLOzoneEglCast() {
  // eglTerminate must be called first on display before releasing resources
  // and shutting down hardware
  TerminateDisplay();
}

void GLOzoneEglCast::InitializeHardwareIfNeeded() {
  if (hardware_initialized_)
    return;

  CHECK(egl_platform_->InitializeHardware());
  hardware_initialized_ = true;
}

void GLOzoneEglCast::TerminateDisplay() {
  void* egl_lib_handle = egl_platform_->GetEglLibrary();
  if (!egl_lib_handle)
    return;

  EGLGetDisplayFn get_display =
      reinterpret_cast<EGLGetDisplayFn>(dlsym(egl_lib_handle, "eglGetDisplay"));
  EGLTerminateFn terminate =
      reinterpret_cast<EGLTerminateFn>(dlsym(egl_lib_handle, "eglTerminate"));
  DCHECK(get_display);
  DCHECK(terminate);

  EGLDisplay display = get_display(GetNativeDisplay().GetDisplay());
  DCHECK_NE(display, EGL_NO_DISPLAY);

  EGLBoolean terminate_result = terminate(display);
  DCHECK_EQ(terminate_result, static_cast<EGLBoolean>(EGL_TRUE));
}

scoped_refptr<gl::GLSurface> GLOzoneEglCast::CreateViewGLSurface(
    gfx::AcceleratedWidget widget) {
  // Verify requested widget dimensions match our current display size.
  DCHECK_EQ(static_cast<int>(widget >> 16), display_size_.width());
  DCHECK_EQ(static_cast<int>(widget & 0xffff), display_size_.height());

  return gl::InitializeGLSurface(new GLSurfaceCast(widget, this));
}

scoped_refptr<gl::GLSurface> GLOzoneEglCast::CreateOffscreenGLSurface(
    const gfx::Size& size) {
  return gl::InitializeGLSurface(new gl::PbufferGLSurfaceEGL(size));
}

gl::EGLDisplayPlatform GLOzoneEglCast::GetNativeDisplay() {
  CreateDisplayTypeAndWindowIfNeeded();
  return gl::EGLDisplayPlatform(
      reinterpret_cast<EGLNativeDisplayType>(display_type_));
}

void GLOzoneEglCast::CreateDisplayTypeAndWindowIfNeeded() {
  InitializeHardwareIfNeeded();

  if (!have_display_type_) {
    chromecast::Size create_size = FromGfxSize(display_size_);
    display_type_ = egl_platform_->CreateDisplayType(create_size);
    have_display_type_ = true;
  }
  if (!window_) {
    chromecast::Size create_size = FromGfxSize(display_size_);
    window_ = egl_platform_->CreateWindow(display_type_, create_size);
    CHECK(window_);
  }
}

intptr_t GLOzoneEglCast::GetNativeWindow() {
  CreateDisplayTypeAndWindowIfNeeded();
  return reinterpret_cast<intptr_t>(window_);
}

bool GLOzoneEglCast::ResizeDisplay(gfx::Size size) {
  DCHECK_EQ(size.width(), display_size_.width());
  DCHECK_EQ(size.height(), display_size_.height());
  return true;
}

bool GLOzoneEglCast::LoadGLES2Bindings(gl::GLImplementation implementation) {
  InitializeHardwareIfNeeded();

  void* lib_egl = egl_platform_->GetEglLibrary();
  void* lib_gles2 = egl_platform_->GetGles2Library();
  gl::GLGetProcAddressProc gl_proc = reinterpret_cast<gl::GLGetProcAddressProc>(
      egl_platform_->GetGLProcAddressProc());
  if (!lib_egl || !lib_gles2 || !gl_proc) {
    return false;
  }

  gl::SetGLGetProcAddressProc(gl_proc);
  gl::AddGLNativeLibrary(lib_egl);
  gl::AddGLNativeLibrary(lib_gles2);
  return true;
}

}  // namespace ui