OpenGL ES 3.0 in Android NDK r9 - opengl-es

The recent Android NDK r9 unveils support of OpenGL ES 3.0. There is an example samples/gles3jni which demonstrates how to use OpenGL ES 3.0 from JNI/native code. The sample can be built two different ways:
Compatible with API level 11 and later
Require API level 18 or later.
Both versions include an OpenGL ES 2.0 fallback path for devices that don't support OpenGL ES 3.0. However, the in the first case example is statically linked against OpenGL ES 2 using LOCAL_LDLIBS option -lGLESv2. In the second case it is statically linked with GLES 3 the same way.
The initialization goes like this:
const char* versionStr = (const char*)glGetString(GL_VERSION);
if (strstr(versionStr, "OpenGL ES 3.") && gl3stubInit()) {
g_renderer = createES3Renderer();
} else if (strstr(versionStr, "OpenGL ES 2.")) {
g_renderer = createES2Renderer();
}
How can I omit the static linking at all and load GLES 2 or 3 dynamically from .so?

On API 18 and later, you can use eglGetProcAddress to dynamically query ES 2.0 functions, just like gl3stub.c in the sample does for ES 3.0 functions. Before API 18, you need to do something like this:
// global scope, probably a header file
extern GL_APICALL const GLubyte* (* GL_APIENTRY glGetString) (GLenum name);
extern GL_APICALL GLenum (* GL_APIENTRY glGetError) (void);
...
// initialization code
void* libGLESv2 = dlopen("libGLESv2.so", RTLD_GLOBAL | RTLD_NOW);
glGetString = dlsym(libGLESv2, "glGetString");
glGetError = dlsym(libGLESv2, "glGetError");
...
Add error-checking on the dlopen and dlsym calls, of course.
I'm not sure why you'd do this, though. libGLESv2.so is present on any version of Android you're likely to want to target, there shouldn't be any downside to linking against it.

I didn't have a 4.3 device to test it, but my understanding is that the 1st method actually uses GLES 3 if available, so it is equivalent to dynamically linking libGLESv3.
Dynamic linking with libglesxx.so is also possible, but then you don't have shortcuts, and have to dlsym all functions that you use. It's not worth it, IMHO.

Related

Is there any GLES #define in C?

I'm working with a codebase that supports OpenGL and OpenGL ES.
Is there any GLES define I can use to write conditional code in C? Something like:
#include <GLES/gl.h>
#ifdef __GLES
//
#else
//
#endif
In GLSL shaders
For conditional compilation of GLSL shaders, there is GL_ES. The GLSL ES 1.00 specification defines under section 3.4 "Preprocessor":
The following predefined macros are available
__LINE__
__FILE__
__VERSION__
GL_ES
GL_ES will be defined and set to 1. This is not true for the non-ES OpenGL Shading Language, so it can
be used to do a compile time test to see whether a shader is running on ES.
So you can check for GL_ES in shaders.
In host/C code
If you want to know whether any particular C file is being compiled in a project for a particular version of OpenGL ES, then you can use the defines from GLES/gl.h, GLES2/gl2.h, GLES3/gl3.h, GLES3/gl31.h or GLES3/gl32.h, which are: GL_VERSION_ES_CM_1_0, GL_ES_VERSION_2_0, GL_ES_VERSION_3_0, GL_ES_VERSION_3_1 and GL_ES_VERSION_3_2, respectively. Starting with GLES2/gl2.h and anything above, you will always have the defines of the previous versions (up to GLES 2.0) also defined. So when you include GLES3/gl31.h then you will find GL_ES_VERSION_2_0, GL_ES_VERSION_3_0 and GL_ES_VERSION_3_1 to be defined.
However, you make the decision in your application whether to include the OpenGL Desktop header files or the OpenGL ES header files and you could use that same condition for conditionally compiling code that relies on you compiling for either OpenGL Desktop or OpenGL ES. So, you really don't need any pre-defined defines because you make the decision yourself earlier in the program about which header you include.

Exploring c++ forward declarations of nested types and a standards compliance teaser?

I recently, thanks to awesome Jan 9th 2018 planet clang team work and others great articles, figured out how to configure my dev-setup to integrate llvm 7.0, visual studio 2017 15.5.6 for 32-bit and 64-bit Intel architecture.
My motivation for this was forced by Microsoft's 15.4.X breaking std lib framework changes that rendered the Microsoft experimental clang c2 front end (somewhat buggy anyway) to break.
In the Intel setup I use LLVM tools to both compile and link PDB debuggable Windows code.
See other posts I made on that topic for instructions on how to integrate everything so you can use latest updates to Visual Studio 2017 tools and debugging with latest 7.X builds of LLVM/clang. For those interested in full Windows 10 on ARM development (not UWP sillyness), I am separately still working the same setup for arm-32, arm-64 to all work together using LLVM tools as well as use Wine-ARM for Linux.
Once done with that integration, I was looking to see what LLVM 7.0 clang allowed to be done without needing P0289R0 Forward declarations of nested classes.
struct ds1; struct ds1::ds2;
I started fiddling around and wrote the sample below. It compiles and runs correctly with clang-llvm 7.0. It will not compile (without errors) when using Microsoft's latest c++ front-ends.
So, I scratched my head wondering if it is actually legal c++ code. I often do that, as I use c++ in non-standard style with templates and forward references. For example, I only use one cpp file per module and use includes within templates to minimize any forward declarations. That pattern avoids the need for makefiles and dramatically improves portability, compilation time, and often code generation quality. In effect, I use the .cpp file as a makefile with minimal to no macros and pure clang/gcc and c++ features.
In asking myself if the code was actually legit c++ according to the standard, I re-read through standard. I concluded that yes it was standard compliant to template rules, but that would make Microsoft's compiler be non-compliant. So I wondered if others more knowledgeable might chime in and clarify the question.
Here is the code sample:
(note it happens to also be intentionally infinitely recursive in a number of ways to test compiler detection)
// P0289R0 clang Forward declarations of nested classes
//- http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0289r0.pdf
// struct ds1; struct ds1::ds2;
struct nested1;
struct nested2;
// Code that references "nested1" here (could be pointer, but in template model this is more interesting case)
template <bool f_ta = true>
void foo(nested1& n1) {
n1.run();
}
template <bool f_ta = true>
struct outer {
struct inner {
void run() {
nested1 n1; nested2 n2;
n2.test();
foo(n1);
}
};
void test() {
nested1 n1;
foo(n1);
}
};
//using nested = outer::inner; // Must be defined at module-scope
//typedef outer::inner nested; // Must be defined at module-scope
struct nested1 : outer<>::inner { using super_t = outer<>::inner; using super_t::super_t; };
struct nested2 : outer<> { using super_t = outer<>; using super_t::super_t; };
bool fAutoRunIt = []() {
nested2 a;
a.test();
return true;
}();
You can easily modify the example to not be recursive and still test out the other forward reference behavior.
Cheers, David

gcc vector extensions don't work as stated in docs

As per Using vector instructions through built-in functions, this program should compile:
int main(){
double v_sse __attribute__ ((vector_size (16)));
/*
* Should work: "For the convenience in C it is allowed to use a binary vector operation where one operand is a scalar."
*/
v_sse=v_sse+3.4;
/*
* Should work: "Vectors can be subscripted as if the vector were an array with the same number of elements and base type."
*/
double result=v_sse[0];
}
Instead I get errors at both operations, complaining about invalid operand/types.
I compile on a x86-64 system, so -msse2 is implicit, and my compiler is 4.6.3 (tested also with 4.7.0, it doesn't work). Where's the catch?
The documentation at http://gcc.gnu.org/onlinedocs/gcc/ refers to current development.
Look at http://gcc.gnu.org/onlinedocs/gcc-X.Y.Z/ to find the documentation for the version you're using (see the index at http://gcc.gnu.org/onlinedocs/ for links to the docs for the most recent point release of each series).
In this case:
the binary operator functionality is not documented for 4.6.3 - because it was introduced as a new feature in 4.7: see the 4.7 release notes;
the subscript feature is present in 4.6.3; and
both features are specifically documented as working "in C"
...which explains what you're seeing.
Both of these do work with 4.7.0 when compiling as C -- but not when compiling as C++.

OpenGL Extensions: How to use them under OS X -- OpenGL newbie

Can anybody point me in a direction to a great tutorial or how-to for using OpenGL Extensions using OS X. I'm learning OpenGL and somewhat of a newbie. I'm using a textbook to learn graphics but it doesn't give platform specific instructions on how to get the code to work.
I'm running OS X(10.6.7) on a MacBookPro with a NVidia GeForce 9400M. I have XCode installed, so I have the necessary headers and libraries to compile and run graphics code. I'm attempting to use the OpenGL extensions and now I'm stuck. Here's my problem:
An example in my textbook utilizes a function called glGenVertexArrays. I see in glext.h that there is a function called glGenVertexArrays, a APIENTRYP next to it, and a typedef slightly below it:
wdyn-n233-240-235:GL marklagatuz$ cat glext.h | grep glGenVertexArrays
GLAPI void APIENTRY glGenVertexArrays (GLsizei, GLuint *);
GLAPI void APIENTRY glGenVertexArraysAPPLE (GLsizei, GLuint *);
typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays);
My question is how to utilize this function in my .cpp source code? I've perused the net, and haven't found great documentation. Maybe cause I'm new to this. Could somebody point me into some great help and tutorials?
If you want to make your life simple, don't bother with glext.h but use a extension wrapper instead. I recommend GLEW, http://glew.sourceforge.net

Difference between API and ABI

I am new to Linux system programming and I came across API and ABI while reading
Linux System Programming.
Definition of API:
An API defines the interfaces by which
one piece of software communicates
with another at the source level.
Definition of ABI:
Whereas an API defines a source
interface, an ABI defines the
low-level binary interface between two
or more pieces of software on a
particular architecture. It defines
how an application interacts with
itself, how an application interacts
with the kernel, and how an
application interacts with libraries.
How can a program communicate at a source level? What is a source level? Is it related to source code in any way? Or the source of the library gets included in the main program?
The only difference I know is API is mostly used by programmers and ABI is mostly used by a compiler.
API: Application Program Interface
This is the set of public types/variables/functions that you expose from your application/library.
In C/C++ this is what you expose in the header files that you ship with the application.
ABI: Application Binary Interface
This is how the compiler builds an application.
It defines things (but is not limited to):
How parameters are passed to functions (registers/stack).
Who cleans parameters from the stack (caller/callee).
Where the return value is placed for return.
How exceptions propagate.
The API is what humans use. We write source code. When we write a program and want to use some library function we write code like:
long howManyDecibels = 123L;
int ok = livenMyHills(howManyDecibels);
and we needed to know that there is a method livenMyHills(), which takes a long integer parameter. So as a Programming Interface it's all expressed in source code. The compiler turns this into executable instructions which conform to the implementation of this language on this particular operating system. And in this case result in some low level operations on an Audio unit. So particular bits and bytes are squirted at some hardware. So at runtime there's lots of Binary level action going on which we don't usually see.
At the binary level there must be a precise definition of what bytes are passed at the Binary level, for example the order of bytes in a 4 byte integer, or the layout of a complex data structure - are there padding bytes to align some values. This definition is the ABI.
I mostly come across these terms in the sense of an API-incompatible change, or an ABI-incompatible change.
An API change is essentially where code that would have compiled with the previous version won't work anymore. This can happen because you added an argument to a function, or changed the name of something accessible outside of your local code. Any time you change a header, and it forces you to change something in a .c/.cpp file, you've made an API-change.
An ABI change is where code that has already been compiled against version 1 will no longer work with version 2 of a codebase (usually a library). This is generally trickier to keep track of than API-incompatible change since something as simple as adding a virtual method to a class can be ABI incompatible.
I've found two extremely useful resources for figuring out what ABI compatibility is and how to preserve it:
The list of Do's and Dont's with C++ for the KDE project
Ulrich Drepper's How to Write Shared Libraries.pdf (primary author of glibc)
Linux shared library minimal runnable API vs ABI example
This answer has been extracted from my other answer: What is an application binary interface (ABI)? but I felt that it directly answers this one as well, and that the questions are not duplicates.
In the context of shared libraries, the most important implication of "having a stable ABI" is that you don't need to recompile your programs after the library changes.
As we will see in the example below, it is possible to modify the ABI, breaking programs, even though the API is unchanged.
main.c
#include <assert.h>
#include <stdlib.h>
#include "mylib.h"
int main(void) {
mylib_mystruct *myobject = mylib_init(1);
assert(myobject->old_field == 1);
free(myobject);
return EXIT_SUCCESS;
}
mylib.c
#include <stdlib.h>
#include "mylib.h"
mylib_mystruct* mylib_init(int old_field) {
mylib_mystruct *myobject;
myobject = malloc(sizeof(mylib_mystruct));
myobject->old_field = old_field;
return myobject;
}
mylib.h
#ifndef MYLIB_H
#define MYLIB_H
typedef struct {
int old_field;
} mylib_mystruct;
mylib_mystruct* mylib_init(int old_field);
#endif
Compiles and runs fine with:
cc='gcc -pedantic-errors -std=c89 -Wall -Wextra'
$cc -fPIC -c -o mylib.o mylib.c
$cc -L . -shared -o libmylib.so mylib.o
$cc -L . -o main.out main.c -lmylib
LD_LIBRARY_PATH=. ./main.out
Now, suppose that for v2 of the library, we want to add a new field to mylib_mystruct called new_field.
If we added the field before old_field as in:
typedef struct {
int new_field;
int old_field;
} mylib_mystruct;
and rebuilt the library but not main.out, then the assert fails!
This is because the line:
myobject->old_field == 1
had generated assembly that is trying to access the very first int of the struct, which is now new_field instead of the expected old_field.
Therefore this change broke the ABI.
If, however, we add new_field after old_field:
typedef struct {
int old_field;
int new_field;
} mylib_mystruct;
then the old generated assembly still accesses the first int of the struct, and the program still works, because we kept the ABI stable.
Here is a fully automated version of this example on GitHub.
Another way to keep this ABI stable would have been to treat mylib_mystruct as an opaque struct, and only access its fields through method helpers. This makes it easier to keep the ABI stable, but would incur a performance overhead as we'd do more function calls.
API vs ABI
In the previous example, it is interesting to note that adding the new_field before old_field, only broke the ABI, but not the API.
What this means, is that if we had recompiled our main.c program against the library, it would have worked regardless.
We would also have broken the API however if we had changed for example the function signature:
mylib_mystruct* mylib_init(int old_field, int new_field);
since in that case, main.c would stop compiling altogether.
Semantic API vs Programming API
We can also classify API changes in a third type: semantic changes.
The semantic API, is usually a natural language description of what the API is supposed to do, usually included in the API documentation.
It is therefore possible to break the semantic API without breaking the program build itself.
For example, if we had modified
myobject->old_field = old_field;
to:
myobject->old_field = old_field + 1;
then this would have broken neither programming API, nor ABI, but main.c the semantic API would break.
There are two ways to programmatically check the contract API:
test a bunch of corner cases. Easy to do, but you might always miss one.
formal verification. Harder to do, but produces mathematical proof of correctness, essentially unifying documentation and tests into a "human" / machine verifiable manner! As long as there isn't a bug in your formal description of course ;-)
Tested in Ubuntu 18.10, GCC 8.2.0.
This is my layman explanations:
API - think of include files. They provide programming interfaces.
ABI - think of kernel module. When you run it on some kernel, it has to agree on how to communicate without include files, i.e. as low-level binary interface.
(Application Binary Interface) A specification for a specific hardware platform combined with the operating system. It is one step beyond the API (Application Program Interface), which defines the calls from the application to the operating system. The ABI defines the API plus the machine language for a particular CPU family. An API does not ensure runtime compatibility, but an ABI does, because it defines the machine language, or runtime, format.
Courtesy
Let me give a specific example how ABI and API differ in Java.
An ABI incompatible change is if I change a method A#m() from taking a String as an argument to String... argument. This is not ABI compatible because you have to recompile code that is calling that, but it is API compatible as you can resolve it by recompiling without any code changes in the caller.
Here is the example spelled out. I have my Java library with class A
// Version 1.0.0
public class A {
public void m(String string) {
System.out.println(string);
}
}
And I have a class that uses this library
public class Main {
public static void main(String[] args) {
(new A()).m("string");
}
}
Now, the library author compiled their class A, I compiled my class Main and it is all working nicely. Imagine a new version of A comes
// Version 2.0.0
public class A {
public void m(String... string) {
System.out.println(string[0]);
}
}
If I just take the new compiled class A and drop it together with the previously compiled class Main, I get an exception on attempt to invoke the method
Exception in thread "main" java.lang.NoSuchMethodError: A.m(Ljava/lang/String;)V
at Main.main(Main.java:5)
If I recompile Main, this is fixed and all is working again.
Your program (source code) can be compiled with modules who provide proper API.
Your program (binary) can run on platforms who provide proper ABI.
API restricts type definitions, function definitions, macros, sometimes global variables a library should expose.
ABI restricts what a "platform" should provide for you program to run on. I like to consider it in 3 levels:
processor level - the instruction set, the calling convention
kernel level - the system call convention, the special file path convention (e.g. the /proc and /sys files in Linux), etc.
OS level - the object format, the runtime libraries, etc.
Consider a cross-compiler named arm-linux-gnueabi-gcc. "arm" indicates the processor architecture, "linux" indicates the kernel, "gnu" indicates its target programs use GNU's libc as runtime library, different from arm-linux-androideabi-gcc which use Android's libc implementation.
API - Application Programming Interface is a compile time interface which can is used by developer to use non-project functionality like library, OS, core calls in source code
ABI[About] - Application Binary Interface is a runtime interface which is used by a program during executing for communication between components in machine code
The ABI refers to the layout of an object file / library and final binary from the perspective of successfully linking, loading and executing certain binaries without link errors or logic errors occuring due to binary incompatibility.
The binary format specification (PE, COFF, ELF, .obj, .o, .a, .lib (import library, static library), .NET assembly, .pyc, COM .dll): the headers, the header format, defining where the sections are and where the import / export / exception tables are and the format of those
The instruction set used to encode the bytes in the code section, as well as the specific machine instructions
The actual signature of the functions and data as defined in the API (as well as how they are represented in the binary (the next 2 points))
The calling convention of the functions in the code section, which may be called by other binaries (particularly relevant to ABI compatibility being the functions that are actually exported)
The way data is represented and aligned in the data section with respect to its type (particularly relevant to ABI compatibility being the data that is actually exported)
The system call numbers or interrupt vectors hooked in the code
The name decoration of exported functions and data
Linker directives in object files
Preprocessor / compiler / assembler / linker flags and directives used by the API programmer and how they are interpreted to omit, optimise, inline or change the linkage of certain symbols or code in the library or final binary (be that binary a .dll or the executable in the event of static linking)
The bytecode format of .NET C# is an ABI (general), which includes the .NET assembly .dll format. The virtual machine that interprets the bytecode has a specific ABI that is C++ based, where types need to be marshalled between native C++ types that the native code's specific ABI uses and the boxed types of the virtual machine's ABI when calling bytecode from native code and native code from bytecode. Here I am calling an ABI of a specific program a specific ABI, whereas an ABI in general, such as 'MS ABI' or 'C ABI' simply refers to the calling convention and the way structures are organised, but not a specific embodiment of the ABI by a specific binary that introduces a new level of ABI compatibility concerns.
An API refers to the set of type definitions exported by a particular library imported and used in a particular translation unit, from the perspective of the compiler of a translation unit, to successfully resolve and check type references to be able to compile a binary, and that binary will adhere to the standard of the target ABI, such that if the library that actually implements the API is also compiled to a compatible ABI, it will link and work as intended. If the API is updated the application may still compile, but there will now be a binary incompatibility and therefore a new binary needs to be used.
An API involves:
Functions, variables, classes, objects, constants, their names, types and definitions presented in the language in which they are coded in a syntactically and semantically correct manner
What those functions actually do and how to use them in the source language
The source code files that need to be included / binaries that need to be linked to in order to make use of them, and the ABI compatibility thereof
I'll begin by answering your specific questions.
1.What is a source level? Is it related to source code in any way?
Yes, the term source level refers to the level of source code. The term level refers to the semantic level of the computation requirements as they get translated from the application domain level to the source code level and from the source code level to the machine code level (binary codes). The application domain level refers what end-users of the software want and specify as their computation requirements. The source code level refers to what programmers make of the application level requirements and then specify as a program in a certain language.
How can a program communicate at a source level? Or the source of the library gets included in the main program?
Language API refers specifically to all that a language requires(specifies) (hence interfaces) to write reusable modules in that language. A reusable program conforms to these interface (API) requirements to be reused in other programs in the same language. Every reuse needs to conform to the same API requirements as well. So, the word "communicate" refers to reuse.
Yes, source code (of a reusable module; in the case of C/C++, .h files ) getting included (copied at pre-processing stage) is the common way of reusing in C/C++ and is thus part of C++ API. Even when you just write a simple function foo() in the global space of a C++ program and then call the function as foo(); any number of times is reuse as per the C++language API. Java classes in Java packages are reusable modules in Java. The Java beans specification is also a Java API enabling reusable programs (beans) to be reused by other modules ( could be another bean) with the help of runtimes/containers (conforming to that specification).
Coming to your overall question of the difference between language API and ABI, and how service-oriented APIs compare with language APIs, my answer here on SO should be helpful.

Resources