06-22-2018, 07:05 PM
(This post was last modified: 06-22-2018, 08:19 PM by Brian Beuken.)
Ok this is of course the beast in the Odroid Range, well loved for its emulation ability and octocore performance.
And of course as a target machine it is an utter beast to use, hardware acceleration on the OpenGLES, and able to handle OpenGLES3.1
It has an Mali T628 MP6 on board which is really a major boost, and if you want to get very fancy with it it can do OpenCL for some very intense muli system coding, not that its very practical on a games target.
I love this machine though it does have one niggle, the noisy fan, which does come on and off a lot when you are running it hard and can be an irritant. They do have a silent version basically a big lump of metal heat sink. Not sure of it suffers from overheating with it or not. I can't bring myself to buy 2 of them, as they are a bit pricey. Close to my limit when you factor in the shipping.
So far I've only used mine in anger as an OpenGLES2.0 system for my test code, though I have run a few ES3.0 demos to see it working in its glory :
If you plan to do any OpenGLES3.0 this is the one. I am not 100% sure though that the OpenGLES3.1 claim is true as I was unable to get anything to work on 3.1 demos, however I didn't spend a lot of time so maybe I was just not setting it up right
Set up of the XU4 for ES2.0 really isn't too hard. I use their supplied Ubuntu MATE OS which I think came ready to go with no need to install anything else, but its over a year since I got mine and memory might have failed me. If you can't find the OpenGLES2.0 folders then simple apt-get the mesa libs.
Set up in Visual GDB is typical for most non Raspberry systems you need these include libs, assuming you have glm and bullet installed
/usr/include /usr/include/bullet /usr/include/bullet/BulletCollision/CollisionShapes . glm Headers /usr/include/GLES2 /usr/include/arm-linux-gnueabihf /usr/include/arm-linux-gnueabihf/c++/5
and then just this Binary Lib Dir
/usr/lib/arm-linux-gnueabihf
Library names are...
GLESv2 EGL pthread BulletCollision BulletSoftBody BulletDynamics LinearMath X11
Finally you will need to include some flags for g++
-ggdb -ffunction-sections -std=c++11 -O0 -DGL_GLEXT_PROTOTYPES
the 1st set are normal but the Odroids UbuntuMate version of gcc needs that -DGL_GLEXT_PROTOTYPES or it won't compile
Make sure you don't include BCMHost.h in any non Raspberry Build
There after there are only 2 issues.. How to get the screen size to set up full screen, and how to set up an EGL window, this time displayed by X11
So make sure you don't define a preprocessor define for RASPBERRY
and you can use this code for both systems.
This is pretty much the same for every basic SBC system with an X11 display (in other words not Raspberry), as long as the graphics systems are on the target.
The XU4 needs you to use the root though so when you create the ssh connection use root, or it won't let you send files to the target,
And of course as a target machine it is an utter beast to use, hardware acceleration on the OpenGLES, and able to handle OpenGLES3.1
It has an Mali T628 MP6 on board which is really a major boost, and if you want to get very fancy with it it can do OpenCL for some very intense muli system coding, not that its very practical on a games target.
I love this machine though it does have one niggle, the noisy fan, which does come on and off a lot when you are running it hard and can be an irritant. They do have a silent version basically a big lump of metal heat sink. Not sure of it suffers from overheating with it or not. I can't bring myself to buy 2 of them, as they are a bit pricey. Close to my limit when you factor in the shipping.
So far I've only used mine in anger as an OpenGLES2.0 system for my test code, though I have run a few ES3.0 demos to see it working in its glory :
If you plan to do any OpenGLES3.0 this is the one. I am not 100% sure though that the OpenGLES3.1 claim is true as I was unable to get anything to work on 3.1 demos, however I didn't spend a lot of time so maybe I was just not setting it up right
Set up of the XU4 for ES2.0 really isn't too hard. I use their supplied Ubuntu MATE OS which I think came ready to go with no need to install anything else, but its over a year since I got mine and memory might have failed me. If you can't find the OpenGLES2.0 folders then simple apt-get the mesa libs.
Set up in Visual GDB is typical for most non Raspberry systems you need these include libs, assuming you have glm and bullet installed
/usr/include /usr/include/bullet /usr/include/bullet/BulletCollision/CollisionShapes . glm Headers /usr/include/GLES2 /usr/include/arm-linux-gnueabihf /usr/include/arm-linux-gnueabihf/c++/5
and then just this Binary Lib Dir
/usr/lib/arm-linux-gnueabihf
Library names are...
GLESv2 EGL pthread BulletCollision BulletSoftBody BulletDynamics LinearMath X11
Finally you will need to include some flags for g++
-ggdb -ffunction-sections -std=c++11 -O0 -DGL_GLEXT_PROTOTYPES
the 1st set are normal but the Odroids UbuntuMate version of gcc needs that -DGL_GLEXT_PROTOTYPES or it won't compile
Make sure you don't include BCMHost.h in any non Raspberry Build
There after there are only 2 issues.. How to get the screen size to set up full screen, and how to set up an EGL window, this time displayed by X11
So make sure you don't define a preprocessor define for RASPBERRY
and you can use this code for both systems.
Code:
/*
Set up the EGL and in the case of Raspberry DispamX
Set up OpenGL states needed
*/
#ifdef RASPBERRY
void Graphics::init_ogl(Target_State *state, int width, int height, int FBResX, int FBResY)
{
int32_t success = 0;
EGLBoolean result;
EGLint num_config;
//RPI setup is a little different to normal EGL
DISPMANX_ELEMENT_HANDLE_T DispmanElementH;
DISPMANX_DISPLAY_HANDLE_T DispmanDisplayH;
DISPMANX_UPDATE_HANDLE_T DispmanUpdateH;
VC_RECT_T dest_rect;
VC_RECT_T src_rect;
EGLConfig config;
// get an EGL display connection
state->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
// initialize the EGL display connection
result = eglInitialize(state->display, NULL, NULL);
// get an appropriate EGL frame buffer configuration
result = eglChooseConfig(state->display, attribute_list, &config, 1, &num_config);
assert(EGL_FALSE != result);
// get an appropriate EGL frame buffer configuration
result = eglBindAPI(EGL_OPENGL_ES_API);
assert(EGL_FALSE != result);
// create an EGL rendering context
state->context = eglCreateContext(state->display, config, EGL_NO_CONTEXT, context_attributes);
assert(state->context != EGL_NO_CONTEXT);
// create an EGL window surface
state->width = FBResX;
state->height = FBResY;
dest_rect.x = 0; // (1920/2)-FBResX/2; // if using a non display size you can center it here
dest_rect.y = 0; // (1080/2)+(FBResY/2);
dest_rect.width = width; // it needs to know our window size
dest_rect.height = height; //state->height;
src_rect.x = 0;
src_rect.y = 0;
src_rect.width = (FBResX) << 16;
src_rect.height = (FBResY) << 16;
DispmanDisplayH = vc_dispmanx_display_open(0);
DispmanUpdateH = vc_dispmanx_update_start(0);
DispmanElementH = vc_dispmanx_element_add(
DispmanUpdateH,
DispmanDisplayH,
1/*layer*/,
&dest_rect,
0/*source*/,
&src_rect,
DISPMANX_PROTECTION_NONE,
0 /*alpha value*/,
0/*clamp*/,
(DISPMANX_TRANSFORM_T) 0/*transform*/);
state->nativewindow.element = DispmanElementH;
state->nativewindow.width = FBResX; //state->width;
state->nativewindow.height = FBResY; //state->height;
vc_dispmanx_update_submit_sync(DispmanUpdateH);
// normal EGL updates are different
state->surface = eglCreateWindowSurface(state->display, config, &(state->nativewindow), NULL);
assert(state->surface != EGL_NO_SURFACE);
// connect the context to the surface
result = eglMakeCurrent(state->display, state->surface, state->surface, state->context);
assert(EGL_FALSE != result);
// Some OpenGLES2.0 states that we might need
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glViewport(0, 0, state->width, state->height);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glCullFace(GL_BACK);
// stops the targets desktop showing through if we have alpha (but at a frame cost, you can remove if you are sure there are no transparencies)
// glEnable(GL_BLEND);
// glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
eglSwapInterval(state->display,1); // 1 to lock speed to 60fps (assuming we are able to maintain it), 0 for immediate swap (may cause tearing) which will indicate actual frame rate
printf("This GPU supplied by :%s\n", glGetString(GL_VENDOR));
printf("This GPU supports :%s\n", glGetString(GL_VERSION));
printf("This GPU Renders with :%s\n", glGetString(GL_RENDERER));
printf("This GPU supports :%s\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
printf("This GPU supports these extensions :%s\n", glGetString(GL_EXTENSIONS));
}
#else
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#define EGL_FALSE 0
#define EGL_TRUE 1
///
// CreateEGLContext()
//
// Creates an EGL rendering context and all associated elements
static Display* x_display = NULL;
void Graphics::init_ogl(Target_State *state, int width, int height, int FBResX, int FBResY)
{
#define ES_WINDOW_RGB 0
state->width = width;
state->height = height;
EGLint numConfigs;
EGLint majorVersion;
EGLint minorVersion;
EGLDisplay display;
EGLContext context;
EGLSurface surface;
EGLConfig config;
EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE, EGL_NONE };
// EGLint result = eglChooseConfig(state->display, attribute_list, &config, 1, &numConfigs);
/* create a native window */
Window root;
XSetWindowAttributes swa;
XSetWindowAttributes xattr;
Atom wm_state;
XWMHints hints;
XEvent xev;
EGLConfig ecfg;
EGLint num_config;
Window win;
Screen *screen;
eglBindAPI(EGL_OPENGL_ES_API);
/*
* X11 native display initialization
*/
x_display = XOpenDisplay(NULL);
if (x_display == NULL)
{
return ; // we need to trap this;
}
root = DefaultRootWindow(x_display);
screen = ScreenOfDisplay(x_display, 0);
width = screen->width;
height = screen->height; // resplution of screen
state->width = width;
state->height = height;
swa.event_mask = ExposureMask | PointerMotionMask | KeyPressMask | KeyReleaseMask;
swa.background_pixmap = None;
swa.background_pixel = 0;
swa.border_pixel = 0;
swa.override_redirect = true;
win = XCreateWindow(
x_display,
root,
0,
0,
width,
height,
0,
CopyFromParent,
InputOutput,
CopyFromParent,
CWEventMask,
&swa);
XSelectInput(x_display, win, KeyPressMask | KeyReleaseMask);
xattr.override_redirect = TRUE;
XChangeWindowAttributes(x_display, win, CWOverrideRedirect, &xattr);
hints.input = TRUE;
hints.flags = InputHint;
XSetWMHints(x_display, win, &hints);
char* title = (char*)"x11 window Maze3dHunt";
// make the window visible on the screen
XMapWindow(x_display, win);
XStoreName(x_display, win, title);
// get identifiers for the provided atom name strings
wm_state = XInternAtom(x_display, "_NET_WM_STATE", FALSE);
memset(&xev, 0, sizeof(xev));
xev.type = ClientMessage;
xev.xclient.window = win;
xev.xclient.message_type = wm_state;
xev.xclient.format = 32;
xev.xclient.data.l[0] = 1;
xev.xclient.data.l[1] = FALSE;
XSendEvent(
x_display,
DefaultRootWindow(x_display),
FALSE,
SubstructureNotifyMask,
&xev);
state->nativewindow = (EGLNativeWindowType) win;
// Get Display
display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (display == EGL_NO_DISPLAY)
{
return; // EGL_FALSE;
}
// Initialize EGL
if (!eglInitialize(display, &minorVersion,&majorVersion))
{
EGLint err = eglGetError();
return;// EGL_FALSE;
}
// Get configs
if (!eglGetConfigs(display, NULL, 0, &numConfigs))
{
return;// EGL_FALSE;
}
// Choose config
if (!eglChooseConfig(display, attribute_list, &config, 1, &numConfigs))
{
return;// EGL_FALSE;
}
// Create a surface
surface = eglCreateWindowSurface(display, config, state->nativewindow, NULL);
if (surface == EGL_NO_SURFACE)
{
return;// EGL_FALSE;
}
// Create a GL context
context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
if (context == EGL_NO_CONTEXT)
{
return;// EGL_FALSE;
}
// Make the context current
if (!eglMakeCurrent(display, surface, surface, context))
{
return;// EGL_FALSE;
}
state->display = display;
state->surface = surface;
state->context = context;
//return;// EGL_TRUE;
printf("This GPU supplied by :%s\n", glGetString(GL_VENDOR));
printf("This GPU supports :%s\n", glGetString(GL_VERSION));
printf("This GPU Renders with :%s\n", glGetString(GL_RENDERER));
printf("This GPU supports :%s\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
printf("This GPU supports these extensions :%s\n", glGetString(GL_EXTENSIONS));
}
#endif // RASPBERRY
This is pretty much the same for every basic SBC system with an X11 display (in other words not Raspberry), as long as the graphics systems are on the target.
The XU4 needs you to use the root though so when you create the ssh connection use root, or it won't let you send files to the target,
Brian Beuken
Lecturer in Game Programming at Breda University of Applied Sciences.
Author of The Fundamentals of C/C++ Game Programming: Using Target-based Development on SBC's
Lecturer in Game Programming at Breda University of Applied Sciences.
Author of The Fundamentals of C/C++ Game Programming: Using Target-based Development on SBC's