blob: ed09a3cfcae09421cea9b52eeea5f8a81dd664c4 [file] [log] [blame] [edit]
// Copyright 2021 The Emscripten Authors. All rights reserved.
// Emscripten is available under two separate licenses, the MIT license and the
// University of Illinois/NCSA Open Source License. Both these licenses can be
// found in the LICENSE file.
#include <stdlib.h>
#include <cassert>
#include <cstdio>
#include <emscripten.h>
#include <emscripten/html5.h>
#define GL_GLEXT_PROTOTYPES
#include <GLES3/gl3.h>
int result = 0;
GLuint sampleQuery = 0;
#define GL_CALL( x ) \
{ \
x; \
GLenum error = glGetError(); \
if( error != GL_NO_ERROR ) { \
printf( "GL ERROR: %d, %s\n", (int)error, #x ); \
result = 1; \
} \
} \
void getQueryResult()
{
/* Get the result. It should be nonzero. */
GLuint any;
GL_CALL(glGetQueryObjectuiv(sampleQuery, GL_QUERY_RESULT, &any));
if (!any) return;
printf("queried any samples passed: %u\n", any);
emscripten_cancel_main_loop();
GL_CALL(glDeleteQueries(1, &sampleQuery));
// result == 0 signals success
exit(result);
}
GLuint compile_shader(GLenum shaderType, const char *src)
{
GLuint shader = glCreateShader(shaderType);
GL_CALL(glShaderSource(shader, 1, &src, NULL));
GL_CALL(glCompileShader(shader));
GLint isCompiled = 0;
GL_CALL(glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled));
assert(isCompiled);
return shader;
}
GLuint create_program(GLuint vert, GLuint frag)
{
GLuint program = glCreateProgram();
GL_CALL(glAttachShader(program, vert));
GL_CALL(glAttachShader(program, frag));
GL_CALL(glBindAttribLocation(program, 0, "position"));
GL_CALL(glLinkProgram(program));
return program;
}
int main() {
EmscriptenWebGLContextAttributes attrs;
emscripten_webgl_init_context_attributes(&attrs);
attrs.enableExtensionsByDefault = 1;
attrs.majorVersion = 2;
attrs.minorVersion = 0;
/* Skip WebGL 2 tests if not supported */
EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context = emscripten_webgl_create_context("#canvas", &attrs);
if (!context) {
printf("Skipped: WebGL 2 is not supported.\n");
return 0;
}
emscripten_webgl_make_context_current(context);
/* Generate a query */
GL_CALL(glGenQueries(2, &sampleQuery));
assert(sampleQuery);
/* Begin it */
GL_CALL(glBeginQuery(GL_ANY_SAMPLES_PASSED, sampleQuery));
/* Now, `sampleQuery` should be a query */
bool isQuery = false;
GL_CALL(isQuery = glIsQuery(sampleQuery));
assert(isQuery);
/* Do a draw to actually have something in the queue */
GLuint vert = compile_shader(GL_VERTEX_SHADER,
"#version 300 es\n"
"in vec4 position;\n"
"void main() {\n"
" gl_Position = position;\n"
"}\n");
GLuint frag = compile_shader(GL_FRAGMENT_SHADER,
"#version 300 es\n"
"precision lowp float;\n"
"out vec4 color;\n"
"void main() {\n"
" color = vec4(1.0, 0.3, 0.1, 1.0);\n"
"}\n");
GLuint program = create_program(vert, frag);
GL_CALL(glUseProgram(program));
const float positions[]{
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
GLuint vertices;
GL_CALL(glGenBuffers(1, &vertices));
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, vertices));
GL_CALL(glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW));
GL_CALL(glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 12, 0));
GL_CALL(glEnableVertexAttribArray(0));
GL_CALL(glClearColor(0.5f, 0.7f, 0.9f, 1.0f));
GL_CALL(glClear(GL_COLOR_BUFFER_BIT));
GL_CALL(glDrawArrays(GL_TRIANGLES, 0, 3));
/* End the query after the draw */
GL_CALL(glEndQuery(GL_ANY_SAMPLES_PASSED));
/* In WebGL, query results are available only in the next event loop
iteration, so this should return false */
GLuint isAvailable;
GL_CALL(glGetQueryObjectuiv(sampleQuery, GL_QUERY_RESULT_AVAILABLE, &isAvailable));
assert(!isAvailable);
/* Run the main loop to get the result */
emscripten_set_main_loop(getQueryResult, 0, 0);
return 99;
}