1// Copyright 2015 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#define WAFFLE_API_VERSION 0x0106
6
7#include <memory>
8
9#include "base/logging.h"
10#include "main.h"
11#include "waffle_stuff.h"
12#include <stdio.h>
13
14GLint g_width = WINDOW_WIDTH;
15GLint g_height = WINDOW_HEIGHT;
16
17std::unique_ptr<GLInterface> g_main_gl_interface;
18
19#ifdef USE_OPENGL
20namespace gl {
21#define F(fun, type) type fun = NULL;
22LIST_PROC_FUNCTIONS(F)
23#undef F
24};
25#define GL_API WAFFLE_CONTEXT_OPENGL
26#else
27#define GL_API WAFFLE_CONTEXT_OPENGL_ES2
28#endif
29
30#define ID_PLATFORM_GLX     1
31#define ID_PLATFORM_X11_EGL 2
32#define ID_PLATFORM_NULL    3
33
34#define CONCAT(a,b) a ## b
35#define PLATFORM_ID(x) CONCAT(ID_, x)
36#define PLATFORM_ENUM(x) CONCAT(WAFFLE_, x)
37#define THIS_IS(x) PLATFORM_ID(x) == PLATFORM_ID(PLATFORM)
38
39#if THIS_IS(PLATFORM_GLX)
40#include "waffle_glx.h"
41#elif THIS_IS(PLATFORM_X11_EGL)
42#include "waffle_x11_egl.h"
43#elif THIS_IS(PLATFORM_NULL)
44#include "waffle_null.h"
45#else
46#error "Compile with -DPLATFORM=PLATFORM_<x> where <x> is NULL, GLX or X11_EGL."
47#endif
48
49#define WAFFLE_CHECK_ERROR do { CHECK(WaffleOK()); } while (0)
50
51GLInterface* GLInterface::Create() {
52  return new WaffleInterface;
53}
54
55static bool WaffleOK() {
56  const waffle_error_info *info = waffle_error_get_info();
57  if (info->code == WAFFLE_NO_ERROR)
58    return true;
59  printf("# Error: %s: %s\n",
60         waffle_error_to_string(info->code),
61         info->message);
62  return false;
63}
64
65void WaffleInterface::GetSurfaceSize(GLint *width, GLint *height) {
66  union waffle_native_window *nw = waffle_window_get_native(surface_);
67
68#if THIS_IS(PLATFORM_NULL)
69  *width = nw->null->width;
70  *height = nw->null->height;
71#elif THIS_IS(PLATFORM_GLX)
72  unsigned w, h;
73#if 0
74  // doesn't work with mesa - https://bugs.freedesktop.org/show_bug.cgi?id=54080
75  glXQueryDrawable(nw->glx->xlib_display, nw->glx->xlib_window, GLX_WIDTH, &w);
76  glXQueryDrawable(nw->glx->xlib_display, nw->glx->xlib_window, GLX_HEIGHT, &h);
77#else
78   Window root;
79   int x, y;
80   unsigned bd, depth;
81   XGetGeometry(nw->glx->xlib_display, nw->glx->xlib_window,
82                &root, &x, &y, &w, &h, &bd, &depth);
83#endif
84  *width = w;
85  *height = h;
86#elif THIS_IS(PLATFORM_X11_EGL)
87  EGLint w, h;
88  eglQuerySurface(nw->x11_egl->display.egl_display, nw->x11_egl->egl_surface,
89                  EGL_WIDTH, &w);
90  eglQuerySurface(nw->x11_egl->display.egl_display, nw->x11_egl->egl_surface,
91                  EGL_HEIGHT, &h);
92  *width = w;
93  *height = h;
94#else
95#error "Compile with -DPLATFORM=PLATFORM_<x> where <x> is NULL, GLX or X11_EGL."
96#endif
97
98  free(nw);
99}
100
101void WaffleInterface::InitOnce() {
102  // Prevent multiple initializations.
103  if (surface_)
104    return;
105
106  int32_t initAttribs[] = {
107    WAFFLE_PLATFORM, PLATFORM_ENUM(PLATFORM),
108    0
109  };
110
111  waffle_init(initAttribs);
112  WAFFLE_CHECK_ERROR;
113
114  display_ = waffle_display_connect(NULL);
115  WAFFLE_CHECK_ERROR;
116
117  int32_t configAttribs[] = {
118    WAFFLE_CONTEXT_API,     GL_API,
119    WAFFLE_RED_SIZE,        1,
120    WAFFLE_GREEN_SIZE,      1,
121    WAFFLE_BLUE_SIZE,       1,
122    WAFFLE_ALPHA_SIZE,      1,
123    WAFFLE_DEPTH_SIZE,      1,
124    WAFFLE_STENCIL_SIZE,    1,
125    WAFFLE_DOUBLE_BUFFERED, true,
126    0
127  };
128
129  config_ = waffle_config_choose(display_, configAttribs);
130  WAFFLE_CHECK_ERROR;
131
132  if (g_width == -1 && g_height == -1) {
133    const intptr_t attrib[] = {
134      WAFFLE_WINDOW_FULLSCREEN, 1,
135      0
136    };
137    surface_ = waffle_window_create2(config_, attrib);
138    GetSurfaceSize(&g_width, &g_height);
139  } else {
140    surface_ = waffle_window_create(config_, g_width, g_height);
141  }
142  WAFFLE_CHECK_ERROR;
143
144  waffle_window_show(surface_);
145  WAFFLE_CHECK_ERROR;
146}
147
148bool WaffleInterface::Init() {
149  InitOnce();
150
151  context_ = CreateContext();
152  CHECK(context_);
153
154  waffle_make_current(display_, surface_, context_);
155  WAFFLE_CHECK_ERROR;
156
157#if defined(USE_OPENGL)
158#define F(fun, type) fun = reinterpret_cast<type>(waffle_get_proc_address(#fun));
159  LIST_PROC_FUNCTIONS(F)
160#undef F
161#endif
162
163  return true;
164}
165
166void WaffleInterface::Cleanup() {
167  waffle_make_current(display_, NULL, NULL);
168  WAFFLE_CHECK_ERROR;
169
170  waffle_context_destroy(context_);
171  WAFFLE_CHECK_ERROR;
172}
173
174void WaffleInterface::SwapBuffers() {
175  waffle_window_swap_buffers(surface_);
176  WAFFLE_CHECK_ERROR;
177}
178
179bool WaffleInterface::SwapInterval(int interval) {
180  return false;
181}
182
183bool WaffleInterface::MakeCurrent(const GLContext& context) {
184  return waffle_make_current(display_, surface_, context);
185}
186
187const GLContext WaffleInterface::CreateContext() {
188  return waffle_context_create(config_, NULL);
189}
190
191void WaffleInterface::CheckError() {
192}
193
194void WaffleInterface::DeleteContext(const GLContext& context) {
195  waffle_context_destroy(context);
196  WAFFLE_CHECK_ERROR;
197}
198