1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
/*
* Copyright 2018 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 <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <emscripten/emscripten.h>
#include <emscripten/html5.h>
#include <webgl/webgl1.h>
#include <webgl/webgl1_ext.h>
#include <vector>
#define NUM_SHADERS_TO_LINK 100
GLuint compile_shader(GLenum shaderType, const char *src)
{
GLuint shader = glCreateShader(shaderType);
glShaderSource(shader, 1, &src, NULL);
glCompileShader(shader);
return shader;
}
GLuint create_program(GLuint vertexShader, GLuint fragmentShader)
{
GLuint program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
glBindAttribLocation(program, 0, "apos");
glBindAttribLocation(program, 1, "acolor");
glLinkProgram(program);
return program;
}
bool check_program_link_completed(GLuint program)
{
GLint completed = 0;
glGetProgramiv(program, GL_COMPLETION_STATUS_KHR, &completed);
return completed;
}
double linkStart = 0;
int numRafFramesElapsed = 0;
int numShadersPending = 0;
std::vector<std::pair<GLuint, double> > pendingLinks;
int parallel_shader_compile_is_working = 0;
EM_BOOL tick(double, void*)
{
for(size_t i = 0; i < pendingLinks.size(); ++i)
{
if (pendingLinks[i].first && check_program_link_completed(pendingLinks[i].first))
{
double elapsed = emscripten_get_now() - pendingLinks[i].second;
printf("Shader %d link completed in %d rAF frames/%f msecs.\n", (int)i, numRafFramesElapsed, elapsed);
pendingLinks[i].first = 0;
--numShadersPending;
// This is how we detect that parallel shader compilation must be working: spawning NUM_SHADERS_TO_LINK shader
// compiles cannot all finish within a single rAF() period, so some of them must finish after the first rAF.
// If they all finished within the first rAF(), they must have gotten synchronously linked in main().
if (numRafFramesElapsed > 0)
parallel_shader_compile_is_working = 1;
}
}
if (numShadersPending == 0)
{
printf("All shaders linked in %f msecs. parallel_shader_compile_is_working=%d\n", emscripten_get_now() - linkStart, parallel_shader_compile_is_working);
assert(parallel_shader_compile_is_working);
emscripten_force_exit(0);
}
++numRafFramesElapsed;
return EM_TRUE;
}
int main()
{
EmscriptenWebGLContextAttributes attr;
emscripten_webgl_init_context_attributes(&attr);
EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_create_context("#canvas", &attr);
emscripten_webgl_make_context_current(ctx);
EM_BOOL supported = emscripten_webgl_enable_extension(ctx, "KHR_parallel_shader_compile");
if (!supported)
{
printf("Skipping test, KHR_parallel_shader_compile WebGL extension is not supported.\n");
return 0;
}
linkStart = emscripten_get_now();
for(int i = 0; i < NUM_SHADERS_TO_LINK; ++i)
{
char shader[256];
sprintf(shader,
"attribute vec4 apos;"
"attribute vec4 acolor;"
"varying vec4 color;"
"void main() {"
"color = acolor;"
"gl_Position = apos + vec4(%f,%f,%f,0.0);"
"}", (float)i, (float)i, (float)i);
GLuint vs = compile_shader(GL_VERTEX_SHADER, shader);
sprintf(shader,
"precision lowp float;"
"varying vec4 color;"
"void main() {"
"gl_FragColor = color + vec4(%f,%f,%f,0.0);"
"}", (float)i, (float)i, (float)i);
GLuint fs = compile_shader(GL_FRAGMENT_SHADER, shader);
GLuint program = create_program(vs, fs);
pendingLinks.push_back(std::make_pair(program, emscripten_get_now()));
}
numShadersPending = pendingLinks.size();
printf("Issuing %d shader links took %f msecs.\n", numShadersPending, emscripten_get_now() - linkStart);
emscripten_request_animation_frame_loop(tick, 0);
}
|