JeVois  1.20
JeVois Smart Embedded Machine Vision Toolkit
Share this page:
VideoDisplayBackend.C
Go to the documentation of this file.
1 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2 //
3 // JeVois Smart Embedded Machine Vision Toolkit - Copyright (C) 2020 by Laurent Itti, the University of Southern
4 // California (USC), and iLab at USC. See http://iLab.usc.edu and http://jevois.org for information about this project.
5 //
6 // This file is part of the JeVois Smart Embedded Machine Vision Toolkit. This program is free software; you can
7 // redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software
8 // Foundation, version 2. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
10 // License for more details. You should have received a copy of the GNU General Public License along with this program;
11 // if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
12 //
13 // Contact information: Laurent Itti - 3641 Watt Way, HNB-07A - Los Angeles, CA 90089-2520 - USA.
14 // Tel: +1 213 740 3527 - itti@pollux.usc.edu - http://iLab.usc.edu - http://jevois.org
15 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
16 
17 // Some of this code inspired by:
18 // https://github.com/D3Engineering/410c_camera_support
19 
20 /* Copyright (c) 2017 D3 Engineering
21  * MIT License
22  *
23  * Permission is hereby granted, free of charge, to any person obtaining a copy
24  * of this software and associated documentation files (the "Software"), to deal
25  * in the Software without restriction, including without limitation the rights
26  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
27  * copies of the Software, and to permit persons to whom the Software is
28  * furnished to do so, subject to the following conditions:
29  *
30  * The above copyright notice and this permission notice shall be included in all
31  * copies or substantial portions of the Software.
32  *
33  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39  * SOFTWARE. */
40 
41 #ifdef JEVOIS_PRO
42 
44 
45 // ##############################################################################################################
47 { }
48 
49 // ##############################################################################################################
51 {
52  // It is better to call uninit() explicitly from the same thread that called init() and others, but just in case:
53  uninit();
54 }
55 
56 // ##############################################################################################################
57 void jevois::VideoDisplayBackend::init(unsigned short JEVOIS_UNUSED_PARAM(w), unsigned short JEVOIS_UNUSED_PARAM(h),
58  EGLNativeWindowType win)
59 {
60  if (itsDisplay) { LERROR("Display already initialized -- IGNORED"); return; }
61 
62  // Get an EGL display connection:
63  itsDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
64  if (itsDisplay == EGL_NO_DISPLAY) LFATAL("Could not get an OpenGL display");
65 
66  // Initialize the EGL display connection:
67  EGLint major, minor;
68  GL_CHECK_BOOL(eglInitialize(itsDisplay, &major, &minor););
69  LINFO("Initialized EGL v" << major << '.' << minor);
70 
71  // Query the EGL API. We need OpenGL-ES:
72  EGLenum const api = eglQueryAPI();
73  switch(api)
74  {
75  case EGL_OPENGL_API: LFATAL("EGL API is unsupported EGL_OPENGL_API"); break;
76  case EGL_OPENGL_ES_API: LINFO("EGL API is EGL_OPENGL_ES_API"); break;
77  case EGL_OPENVG_API: LFATAL("EGL API is unsupported EGL_OPENVG_API"); break;
78  case EGL_NONE: LFATAL("EGL API is unsupported EGL_NONE"); break;
79  default: LFATAL("EGL API is unknown");
80  }
81 
82  // Get an appropriate EGL configuration:
83  static EGLint const cfg_attr[] =
84  {
85  EGL_SAMPLES, EGL_DONT_CARE, // 4
86  EGL_ALPHA_SIZE, 8,
87  EGL_RED_SIZE, 8,
88  EGL_GREEN_SIZE, 8,
89  EGL_BLUE_SIZE, 8,
90  EGL_BUFFER_SIZE, 32,
91  EGL_STENCIL_SIZE, 0,
92  EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR,
93  EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
94  EGL_DEPTH_SIZE, 16,
95  EGL_CONFORMANT, EGL_OPENGL_ES2_BIT,
96  EGL_NONE
97  };
98 
99  EGLint num_config;
100  GL_CHECK_BOOL(eglChooseConfig(itsDisplay, cfg_attr, nullptr, 0, &num_config));
101  LINFO("OpenGL configs available: " << num_config);
102  if (num_config < 1) LFATAL("Could not find a suitable OpenGL config");
103 
104  EGLConfig * configs = new EGLConfig[num_config];
105  GL_CHECK_BOOL(eglChooseConfig(itsDisplay, cfg_attr, configs, num_config, &num_config));
106  bool gotit = false;
107  for (int i = 0; i < num_config; ++i)
108  {
109  EGLint val = 0;
110  std::string info;
111 
112 #define JEVOIS_EGL_INFO(x) GL_CHECK(eglGetConfigAttrib(itsDisplay, configs[i], x, &val)); \
113  info += std::string(#x) + '=' + std::to_string(val) + ", ";
114 
115  JEVOIS_EGL_INFO(EGL_CONFIG_ID);
116  JEVOIS_EGL_INFO(EGL_RED_SIZE);
117  JEVOIS_EGL_INFO(EGL_GREEN_SIZE);
118  JEVOIS_EGL_INFO(EGL_BLUE_SIZE);
119  JEVOIS_EGL_INFO(EGL_ALPHA_SIZE);
120  JEVOIS_EGL_INFO(EGL_ALPHA_MASK_SIZE);
121  JEVOIS_EGL_INFO(EGL_DEPTH_SIZE);
122  JEVOIS_EGL_INFO(EGL_STENCIL_SIZE);
123  JEVOIS_EGL_INFO(EGL_SAMPLE_BUFFERS);
124  JEVOIS_EGL_INFO(EGL_SAMPLES);
125  JEVOIS_EGL_INFO(EGL_CONFIG_CAVEAT);
126 
127  JEVOIS_EGL_INFO(EGL_MAX_PBUFFER_WIDTH);
128  JEVOIS_EGL_INFO(EGL_MAX_PBUFFER_HEIGHT);
129  JEVOIS_EGL_INFO(EGL_MAX_PBUFFER_PIXELS);
130  JEVOIS_EGL_INFO(EGL_NATIVE_RENDERABLE);
131  JEVOIS_EGL_INFO(EGL_NATIVE_VISUAL_ID);
132  JEVOIS_EGL_INFO(EGL_NATIVE_VISUAL_TYPE);
133  JEVOIS_EGL_INFO(EGL_SURFACE_TYPE);
134  JEVOIS_EGL_INFO(EGL_TRANSPARENT_TYPE);
135  JEVOIS_EGL_INFO(EGL_BIND_TO_TEXTURE_RGB);
136  JEVOIS_EGL_INFO(EGL_BIND_TO_TEXTURE_RGBA);
137  JEVOIS_EGL_INFO(EGL_MAX_SWAP_INTERVAL);
138  JEVOIS_EGL_INFO(EGL_MIN_SWAP_INTERVAL);
139  JEVOIS_EGL_INFO(EGL_CONFORMANT);
140 
141  LINFO("EGL config " << i << ": " << info);
142 
143 #undef JEVOIS_EGL_INFO
144 
145  GL_CHECK(eglGetConfigAttrib(itsDisplay, configs[i], EGL_RED_SIZE, &val));
146  if (val != 8) continue;
147  GL_CHECK(eglGetConfigAttrib(itsDisplay, configs[i], EGL_GREEN_SIZE, &val));
148  if (val != 8) continue;
149  GL_CHECK(eglGetConfigAttrib(itsDisplay, configs[i], EGL_BLUE_SIZE, &val));
150  if (val != 8) continue;
151  if (gotit == false)
152  {
153  LINFO("Using config " << i << " with 8-bit R,G,B.");
154  itsConfig = configs[i];
155  gotit = true;
156  //break;
157  }
158  }
159  delete [] configs;
160 
161  if (gotit == false) LFATAL("Could not find a suitable OpenGL config");
162 
163  // Create a native surface:
164  static EGLint const win_attr[] =
165  {
166  //EGL_RENDER_BUFFER, EGL_BACK_BUFFER,
167  EGL_NONE
168  };
169  GL_CHECK(itsSurface = eglCreateWindowSurface(itsDisplay, itsConfig, win, win_attr));
170  LINFO("OpenGL surface created ok.");
171 
172  // Bind to OpenGL-ES API:
173  GL_CHECK_BOOL(eglBindAPI(EGL_OPENGL_ES_API));
174 
175  LINFO("OpenGL-ES API bound ok.");
176 
177  // Create an EGL rendering context:
178  static EGLint const ctx_attr[] =
179  {
180  EGL_CONTEXT_CLIENT_VERSION, 3,
181  EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
182  EGL_CONTEXT_MINOR_VERSION_KHR, 2,
183  EGL_NONE
184  };
185 
186  GL_CHECK(itsContext = eglCreateContext(itsDisplay, itsConfig, EGL_NO_CONTEXT, ctx_attr));
187  if (itsContext == EGL_NO_CONTEXT) LFATAL("Failed to create OpenGL context");
188  LINFO("OpenGL context ok");
189 
190  // Bind the context to the surface:
191  GL_CHECK(eglMakeCurrent(itsDisplay, itsSurface, itsSurface, itsContext));
192 
193  // Show OpenGL-ES version:
194  glGetIntegerv(GL_MAJOR_VERSION, &major);
195  glGetIntegerv(GL_MINOR_VERSION, &minor);
196  LINFO(glGetString(GL_VERSION) <<' '<< glGetString(GL_VENDOR) << " (" << glGetString(GL_RENDERER) <<
197  ") GL_VER=" << major << '.' << minor);
198  LINFO("OpenGL extensions: " << glGetString(GL_EXTENSIONS));
199 
200  // Synchronize buffer swapping to vsync for tear-free display:
201  GL_CHECK_BOOL(eglSwapInterval(itsDisplay, 0));
202 
203  // Enable blending, used for RGBA textures that have transparency:
204  glEnable(GL_BLEND);
205  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
206 }
207 
208 // ##############################################################################################################
210 {
211  if (itsDisplay != EGL_NO_DISPLAY)
212  {
213  eglBindAPI(EGL_OPENGL_ES_API);
214  eglMakeCurrent(itsDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, itsContext);
215  eglMakeCurrent(itsDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
216  if (itsSurface) { eglDestroySurface(itsDisplay, itsSurface); itsSurface = 0; }
217  eglDestroyContext(itsDisplay, itsContext); itsContext = EGL_NO_CONTEXT;
218  eglTerminate(itsDisplay); itsDisplay = EGL_NO_DISPLAY;
219  itsConfig = 0;
220  }
221 }
222 
223 // ##############################################################################################################
225 {
226  // Check if display window has been resized by user:
227  unsigned short w, h; getWindowSize(w, h);
228 
229  if (w == 0) LFATAL("Need to call init() first");
230 
231  // Set the viewport and clear the display:
232  glViewport(0, 0, w, h);
233  glClear(GL_COLOR_BUFFER_BIT);
234 }
235 
236 // ##############################################################################################################
238 {
239  // Display the frame after render is complete at the next vertical sync. This is drawn on our EGL surface:
240  GL_CHECK_BOOL(eglSwapBuffers(itsDisplay, itsSurface));
241 }
242 
243 // ##############################################################################################################
244 void jevois::VideoDisplayBackend::getWindowSize(unsigned short & w, unsigned short & h) const
245 {
246  if (itsSurface)
247  {
248  EGLint ww, hh;
249  GL_CHECK(eglQuerySurface(itsDisplay, itsSurface, EGL_WIDTH, &ww));
250  GL_CHECK(eglQuerySurface(itsDisplay, itsSurface, EGL_HEIGHT, &hh));
251  w = ww; h = hh;
252  }
253  else
254  {
255  w = 0; h = 0;
256  }
257 }
258 
259 // ##############################################################################################################
261 { return itsDisplay; }
262 
263 #endif // JEVOIS_PRO
VideoDisplayBackend.H
jevois::VideoDisplayBackend::newFrame
virtual void newFrame()
Start a new frame and clear the window/framebuffer.
Definition: VideoDisplayBackend.C:224
jevois::VideoDisplayBackend::render
virtual void render()
Render the VideoDisplay graphics.
Definition: VideoDisplayBackend.C:237
jevois::VideoDisplayBackend::VideoDisplayBackend
VideoDisplayBackend()
Constructor.
Definition: VideoDisplayBackend.C:46
GL_CHECK
#define GL_CHECK(stmt)
Simple macro to check for OpenGL errors.
Definition: OpenGL.H:77
LERROR
#define LERROR(msg)
Convenience macro for users to print out console or syslog messages, ERROR level.
Definition: Log.H:211
jevois::VideoDisplayBackend::~VideoDisplayBackend
virtual ~VideoDisplayBackend()
Virtual destructor for safe inheritance, free resources.
Definition: VideoDisplayBackend.C:50
GL_CHECK_BOOL
#define GL_CHECK_BOOL(stmt)
Simple macro to check for OpenGL errors when a boolean result is expected.
Definition: OpenGL.H:81
jevois::VideoDisplayBackend::getWindowSize
virtual void getWindowSize(unsigned short &w, unsigned short &h) const
Definition: VideoDisplayBackend.C:244
jevois::VideoDisplayBackend::uninit
virtual void uninit()
Un-initialize the underlying engine, close windows, etc.
Definition: VideoDisplayBackend.C:209
jevois::VideoDisplayBackend::init
virtual void init(unsigned short w, unsigned short h, bool fullscreen=false)=0
Initialize the underlying engine that will process events, create windows, etc.
jevois::VideoDisplayBackend::getDisplay
EGLDisplay getDisplay() const
Access our display.
Definition: VideoDisplayBackend.C:260
LFATAL
#define LFATAL(msg)
Convenience macro for users to print out console or syslog messages, FATAL level.
JEVOIS_EGL_INFO
#define JEVOIS_EGL_INFO(x)
h
int h
Definition: GUIhelper.C:2373
LINFO
#define LINFO(msg)
Convenience macro for users to print out console or syslog messages, INFO level.
Definition: Log.H:194