| // Copyright 2016 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. |
| |
| #define GL_GLEXT_PROTOTYPES |
| #include <GLES/gl.h> |
| #include <GLES/glext.h> |
| #include <GLES3/gl3.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <emscripten.h> |
| #include <emscripten/html5.h> |
| #include <assert.h> |
| |
| int result = 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; \ |
| } \ |
| } \ |
| |
| |
| int main() |
| { |
| EmscriptenWebGLContextAttributes attrs; |
| emscripten_webgl_init_context_attributes(&attrs); |
| |
| attrs.enableExtensionsByDefault = 1; |
| attrs.majorVersion = 2; |
| attrs.minorVersion = 0; |
| |
| EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context = emscripten_webgl_create_context( "#canvas", &attrs ); |
| if (!context) |
| { |
| printf("Skipped: WebGL 2 is not supported.\n"); |
| #ifdef REPORT_RESULT |
| REPORT_RESULT(result); |
| #endif |
| return 0; |
| } |
| emscripten_webgl_make_context_current(context); |
| |
| const char *vertexShader = |
| "#version 300 es\n" |
| "uniform mat4 a;\n" |
| "uniform Block1a {\n" |
| " uniform mat4 var1;\n" |
| " uniform vec4 variable2;\n" |
| "} block1bb;\n" |
| "uniform Block2ccc {\n" |
| " uniform mat4 var1;\n" |
| " uniform vec4 variable2;\n" |
| "} block2dddd;\n" |
| "void main() {\n" |
| " gl_Position = a * block1bb.var1*block1bb.variable2 + block2dddd.var1*block2dddd.variable2;\n" |
| "}\n"; |
| |
| const char *fragmentShader = |
| "#version 300 es\n" |
| "precision lowp float;\n" |
| " uniform Block3eeeee {\n" |
| " uniform vec4 var1;\n" |
| " uniform vec4 variable2;\n" |
| "} block3ffffff;\n" // Append characters of different lengths to test name string lengths. |
| "out vec4 outColor;\n" |
| "void main() {\n" |
| " outColor = block3ffffff.var1 + block3ffffff.variable2;\n" |
| "}\n"; |
| |
| GLuint vs = glCreateShader(GL_VERTEX_SHADER); |
| glShaderSource(vs, 1, &vertexShader, NULL); |
| glCompileShader(vs); |
| int ok = 0; |
| glGetShaderiv(vs, GL_COMPILE_STATUS, &ok); |
| if (!ok) { |
| printf("Shader compilation error with vertex\n"); |
| GLint infoLen = 0; |
| glGetShaderiv (vs, GL_INFO_LOG_LENGTH, &infoLen); |
| if (infoLen > 1) |
| { |
| char* infoLog = (char *)malloc(sizeof(char) * infoLen+1); |
| glGetShaderInfoLog(vs, infoLen, NULL, infoLog); |
| printf("Error compiling shader:\n%s\n", infoLog); |
| } |
| } |
| |
| GLuint fs = glCreateShader(GL_FRAGMENT_SHADER); |
| glShaderSource(fs, 1, &fragmentShader, NULL); |
| glCompileShader(fs); |
| glGetShaderiv(fs, GL_COMPILE_STATUS, &ok); |
| if (!ok) { |
| printf("Shader compilation error with fragment\n"); |
| GLint infoLen = 0; |
| glGetShaderiv (fs, GL_INFO_LOG_LENGTH, &infoLen); |
| if (infoLen > 1) |
| { |
| char* infoLog = (char *)malloc(sizeof(char) * infoLen+1); |
| glGetShaderInfoLog(fs, infoLen, NULL, infoLog); |
| printf("Error compiling shader:\n%s\n", infoLog); |
| } |
| } |
| |
| GLuint program = glCreateProgram(); |
| |
| glAttachShader(program, vs); |
| glAttachShader(program, fs); |
| glLinkProgram(program); |
| glGetProgramiv(program, GL_LINK_STATUS, &ok); |
| assert(ok); |
| |
| int maxLength = 0; |
| glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &maxLength); |
| printf("GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH: %d\n", maxLength); |
| assert(maxLength == 12); |
| |
| GLint numActiveUniforms = -1; |
| glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &numActiveUniforms); |
| printf("GL_ACTIVE_UNIFORMS: %d\n", numActiveUniforms); |
| assert(numActiveUniforms == 7); |
| |
| for(int i = 0; i < numActiveUniforms; ++i) |
| { |
| char str[256] = {}; |
| GLsizei length = -1; |
| GLint size = -1; |
| GLenum type = -1; |
| glGetActiveUniform(program, i, 255, &length, &size, &type, str); |
| |
| GLint loc = glGetUniformLocation(program, str); |
| |
| GLint indx = -1; |
| glGetActiveUniformsiv(program, 1, (GLuint*)&i, GL_UNIFORM_BLOCK_INDEX, &indx); |
| |
| printf("Active uniform at index %d: %s\n", i, str); |
| printf("glGetUniformLocation = %d \t GL_UNIFORM_BLOCK_INDEX = %d \t size = %d \t type = %d\n", loc, indx, size, type); |
| |
| assert((loc == -1) != (indx == -1)); // one of them must be true |
| } |
| |
| GLint numActiveUniformBlocks = -1; |
| glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &numActiveUniformBlocks); |
| assert(numActiveUniformBlocks == 3); |
| |
| // Dump all active uniform buffer blocks of the current program. |
| for(int i = 0; i < numActiveUniformBlocks; ++i) |
| { |
| char str[256] = {}; |
| GLsizei length = -1; |
| glGetActiveUniformBlockName(program, i, 255, &length, str); |
| assert(length > 0); |
| printf("Active uniform block at index %d: %s\n", i, str); |
| |
| GLint param = -1; |
| #define DUMPUNIFORMBLOCKSTATUS(stat) glGetActiveUniformBlockiv(program, i, stat, ¶m); printf("%s: %d\n", #stat, param); |
| DUMPUNIFORMBLOCKSTATUS(GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER); |
| DUMPUNIFORMBLOCKSTATUS(GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER); |
| DUMPUNIFORMBLOCKSTATUS(GL_UNIFORM_BLOCK_BINDING); |
| DUMPUNIFORMBLOCKSTATUS(GL_UNIFORM_BLOCK_DATA_SIZE); |
| DUMPUNIFORMBLOCKSTATUS(GL_UNIFORM_BLOCK_NAME_LENGTH); |
| DUMPUNIFORMBLOCKSTATUS(GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS); |
| GLint indices[16] = {}; |
| glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, indices); |
| for(size_t i = 0; i < param; ++i) |
| printf("offset for index %d: %d\n", i, indices[i]); |
| } |
| |
| #ifdef REPORT_RESULT |
| REPORT_RESULT(result); |
| #endif |
| return 0; |
| } |