Issue
I have been struggling to correctly render any geometry using OpenGLES 1.0, 2.0, or 3.0 techniques. My testing device is a Samsung Galaxy S7 Edge (running Android 7.0). I have implemented numerous guides for both OpenGLES and EGL such as:
https://www.khronos.org/registry/EGL/sdk/docs/man/html/
https://www.khronos.org/assets/uploads/books/openglr_es_20_programming_guide_sample.pdf
http://www.ikerhurtado.com/egl-use-android-native-opengles-applications
The code was initially adapted from the "native-activity" example:
https://github.com/googlesamples/android-ndk/tree/master/native-activity
Android Manifest: (mostly from native-activity example)
...
<!-- Tell the system this app requires OpenGL ES 3.0. -->
<uses-feature android:glEsVersion="0x00030000" android:required="true" />
...
CMAKE: (mostly from native-activity example)
...
add_library(
native-activity
SHARED
main.cpp)
target_include_directories(
native-activity
PRIVATE
${ANDROID_NDK}/sources/android/native_app_glue)
# add lib dependencies
target_link_libraries(
native-activity
android
native_app_glue
EGL
GLESv3
log)
...
main.cpp: (mostly from native-activity example, cropped for relevance)
...
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES3/gl3.h>
#include <GLES3/gl3ext.h>
#include <android_native_app_glue.h>
...
/*
*Test GLES 1.0, should draw a white triangle on red background
*/
class TestGLES10 {
public:
GLuint program;
void create() {
char vssource[] =
"attribute vec4 vertexPosition; \n"
"void main(){ \n"
" gl_Position = vertexPosition; \n"
"} \n";
char fssource[] =
"precision mediump float; \n"
"void main(){ \n"
" gl_FragColor = vec4(1.0); "
"} \n";
auto compile = [](const char *source, GLenum type){
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &source, nullptr);
glCompileShader(shader);
return shader;
};
GLuint vs = compile(string(vssource).c_str(), GL_VERTEX_SHADER);
GLuint fs = compile(string(fssource).c_str(), GL_FRAGMENT_SHADER);
program = glCreateProgram();
glAttachShader(program, vs);
glAttachShader(program, fs);
glBindAttribLocation(program, 0, "vertexPosition");
glLinkProgram(program);
glDisable(GL_DEPTH_TEST);
}
void update() {
glClearColor(1,0,0,1);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program);
float positions[]{
0.0f, 0.1f,
-0.1f, -0.1f,
0.1f, -0.1f
};
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, positions);
glEnableVertexAttribArray(0);
glDrawArrays(GL_TRIANGLES, 0, 3);
}
};
/*
*Test GLES 3.0, should draw a white triangle on blue background
*/
class TestGLES30 {
public:
GLuint vbo, vao, program;
void create() {
char vssource[] =
"#version 300 es\n"
"layout(location=0) in vec4 vertexPosition; \n"
"void main(){ \n"
" gl_Position = vertexPosition; \n"
"} \n";
char fssource[] =
"#version 300 es\n"
"precision mediump float; \n"
"out vec4 fragment; \n"
"void main(){ \n"
" fragment = vec4(1.0); "
"} \n";
auto compile = [](const char *source, GLenum type){
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &source, nullptr);
glCompileShader(shader);
return shader;
};
GLuint vs = compile(string(vssource).c_str(), GL_VERTEX_SHADER);
GLuint fs = compile(string(fssource).c_str(), GL_FRAGMENT_SHADER);
program = glCreateProgram();
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
float positions[]{
0.0f, 0.5f,
-0.5f, -0.5f,
0.5f, -0.5f
};
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, 2*4, positions, GL_STATIC_DRAW);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2*4, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
void update() {
glClearColor(0,0,1,1);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program);
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
}
};
...
void android_main(android_app* appInterface) {
appInterface->onAppCmd = commandRelay;
appInterface->onInputEvent = inputRelay;
while(appInterface->window == nullptr){
pollEvents(appInterface);
}
EGLDisplay display;
EGLSurface surface;
EGLContext context;
EGLint majorVersion, minorVersion;
EGLConfig config;
EGLint width, height;
EGLint nativeVisualID;
EGLint configCount;
display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
assert(display != EGL_NO_DISPLAY);
eglInitialize(display, &majorVersion, &minorVersion);
//https://www.khronos.org/registry/EGL/sdk/docs/man/html/eglChooseConfig.xhtml
const EGLint displayAttrib[] = {
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,//egl 1.3 req
EGL_NATIVE_RENDERABLE, EGL_TRUE,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_BLUE_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_RED_SIZE, 8,
EGL_NONE
};
//retreive configs
eglChooseConfig(display, displayAttrib, 0, 0, &configCount);
std::unique_ptr<EGLConfig[]> supported(new EGLConfig[configCount]);
eglChooseConfig(display, displayAttrib, supported.get(), configCount, &configCount);
EGLint i = 0, v;
for (; i < configCount; i++) {
auto get = [&](EGLint attrib){
eglGetConfigAttrib(display, supported[i], attrib, &v);
return v;
};
if (Math2::equal(8,
get(EGL_RED_SIZE),
get(EGL_GREEN_SIZE),
get(EGL_BLUE_SIZE),
get(EGL_DEPTH_SIZE))) {//expands to 8 == get(EGL_RED_SIZE) == ...
config = supported[i];
break;
}
}
if (i == configCount) {//default to first
config = supported[0];
}
const EGLint surfaceAttrib[] = {
EGL_RENDER_BUFFER, EGL_BACK_BUFFER,// render to the back buffer, egl 1.2 req
EGL_NONE
};
eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &nativeVisualID);
surface = eglCreateWindowSurface(display, config, appInterface->window, surfaceAttrib);
const EGLint contextAttrib[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,// request a context using Open GL ES 2.0
EGL_NONE
};
context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttrib);
assert(context != EGL_NO_CONTEXT);
//sets initial viewport and scissor dimensions to draw surface size
eglMakeCurrent(display, surface, surface, context);
eglQuerySurface(display, surface, EGL_WIDTH, &width);
eglQuerySurface(display, surface, EGL_HEIGHT, &height);
//this call was mentioned, but missing from the example (removing has same effect)
ANativeWindow_setBuffersGeometry(appInterface->window, width, height, nativeVisualID);
TestGLES10 test;
test.create();
while (true){
test.update();
eglSwapBuffers(display, surface);
}
}
Results:
Logged Info:
Vendor : Qualcomm
Renderer : Adreno (TM) 530
Version : OpenGL ES 3.2 [email protected] (GIT@I86b60582e4)
EGL version : 1.4
Window dimensions : 1080, 1920
Additionally, the device has resolution scaling set to 1080x1920.
Test 1.0: https://i.imgur.com/dmofGYw.png Test 3.0: https://i.imgur.com/uoghOZc.png
According to: https://www.khronos.org/registry/EGL/sdk/docs/man/html/eglMakeCurrent.xhtml the glViewPort should have been initialized to the surface size (1080x1920), so I am at a loss for how the white rectangle could occur.
The shader code for both tests compile without errors from Adreno.
Why wont it render geometry correctly?
According to : https://www.khronos.org/registry/EGL/sdk/docs/man/html/eglCreateContext.xhtml there is no way to specifically request a 3.0 or higher context, why does the created context have version 3.2 when I can only request 2.0?
Solution
Why wont it render geometry correctly?
Your position arrays are three vertices of two compoenents each (x, y), but you're telling GL they have three components each:
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, positions);
why does the created context have version 3.2 when I can only request 2.0?
Versions 3.x are entirely forward compatible with code written for version 2.0, so it's legal for the drivers just to up-convert a context to the newest version they support.
Answered By - solidpixel
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.