-
-
Save turbo/4d9cc2ccde7517370f655b698aea22ec to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//\ | |
/* | |
#ifdef NanoCL_WEBGL_EXP_JS /* JavaScript */ | |
(function() { | |
"use strict"; | |
var gl = document.createElement('canvas').getContext( | |
'experimental-webgl', {alpha : false, antialias : false}); | |
if (!gl.getExtension('OES_texture_float')) | |
throw new Error('NanoCL requires OES_texture_float extension.'); | |
function newBuffer(data, f, e) { | |
var buf = gl.createBuffer(); | |
gl.bindBuffer((e || gl.ARRAY_BUFFER), buf); | |
gl.bufferData((e || gl.ARRAY_BUFFER), new (f || Float32Array)(data), | |
gl.STATIC_DRAW); | |
return buf; | |
} | |
var positionBuffer = newBuffer([ -1, -1, 1, -1, 1, 1, -1, 1 ]); | |
var textureBuffer = newBuffer([ 0, 0, 1, 0, 1, 1, 0, 1 ]); | |
var indexBuffer = | |
newBuffer([ 1, 2, 0, 3, 0, 2 ], Uint16Array, gl.ELEMENT_ARRAY_BUFFER); | |
var vertexShaderCode = "attribute vec2 position;\n" + "varying vec2 pos;\n" + | |
"attribute vec2 texture;\n" + "\n" + | |
"void main(void) {\n" + " pos = texture;\n" + | |
" gl_Position = vec4(position.xy, 0.0, 1.0);\n" + "}" | |
var vertexShader = gl.createShader(gl.VERTEX_SHADER); | |
gl.shaderSource(vertexShader, vertexShaderCode); | |
gl.compileShader(vertexShader); | |
if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) | |
throw new Error( | |
"\nERROR: Could not build internal vertex shader (fatal).\n" + "\n" + | |
"INFO: >REPORT< THIS. That's our fault!\n" + "\n" + | |
"--- CODE DUMP ---\n" + vertexShaderCode + "\n\n" + | |
"--- ERROR LOG ---\n" + gl.getShaderInfoLog(vertexShader)); | |
function createTexture(data, size) { | |
var texture = gl.createTexture(); | |
gl.bindTexture(gl.TEXTURE_2D, texture); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); | |
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.FLOAT, | |
data); | |
gl.bindTexture(gl.TEXTURE_2D, null); | |
return texture; | |
} | |
window.NanoCL = {run : function(ipt, code){ | |
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); | |
gl.shaderSource( | |
fragmentShader, | |
"\n" + "precision mediump float;\n" + "uniform sampler2D u_texture;\n" + | |
"varying vec2 pos;\n" + "\n" + "vec4 read(void) {\n" + | |
" return texture2D(u_texture, pos);\n" + "}\n" + "\n" + | |
"void commit(vec4 val) {\n" + " gl_FragColor = val;\n" + "}\n" + | |
"\n" + "// user code begins here\n" + "\n" + code); | |
gl.compileShader(fragmentShader); | |
if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) | |
throw new Error("ERROR: Could not build shader (fatal).\n" + "\n" + | |
"--- CODE DUMP ---\n" + code + "\n" + | |
"--- ERROR LOG ---\n" + | |
gl.getShaderInfoLog(fragmentShader)); | |
var program = gl.createProgram(); | |
gl.attachShader(program, vertexShader); | |
gl.attachShader(program, fragmentShader); | |
gl.linkProgram(program); | |
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) | |
throw new Error('ERROR: Could not initialize shaders (fatal).\n'); | |
var uTexture = gl.getUniformLocation(program, 'u_texture'); | |
var aPosition = gl.getAttribLocation(program, 'position'); | |
var aTexture = gl.getAttribLocation(program, 'texture'); | |
gl.useProgram(program); | |
var size = Math.sqrt(ipt.data.length) / 4; | |
var texture = createTexture(ipt.data, size); | |
gl.viewport(0, 0, size, size); | |
gl.bindFramebuffer(gl.FRAMEBUFFER, gl.createFramebuffer()); | |
var nTexture = createTexture(new Float32Array(ipt.data.length), size); | |
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, | |
nTexture, 0); | |
var frameBufferStatus = | |
(gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE); | |
if (!frameBufferStatus) | |
throw new Error('ERROR: (fatal): ' + frameBufferStatus.message); | |
gl.bindTexture(gl.TEXTURE_2D, texture); | |
gl.activeTexture(gl.TEXTURE0); | |
gl.uniform1i(uTexture, 0); | |
gl.bindBuffer(gl.ARRAY_BUFFER, textureBuffer); | |
gl.enableVertexAttribArray(aTexture); | |
gl.vertexAttribPointer(aTexture, 2, gl.FLOAT, false, 0, 0); | |
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); | |
gl.enableVertexAttribArray(aPosition); | |
gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 0, 0); | |
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer); | |
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); | |
gl.readPixels(0, 0, size, size, gl.RGBA, gl.FLOAT, ipt.data); | |
return ipt.data.subarray(0, ipt.length); | |
}, | |
alloc: function(sz) { | |
if (sz > 16777216) | |
throw new Error("Whoops, the maximum array size is 268435456!"); | |
var ns = Math.pow(Math.pow(2, Math.ceil(Math.log(sz) / 1.386) - 1), 2); | |
return {data : new Float32Array(ns * 16), length : sz}; | |
} | |
} | |
; | |
})(); | |
//\ | |
/* | |
#endif | |
// (c) 2014-2016, git.io/minxomat | |
// MIT licensed | |
#include <windows.h> | |
#include <string> | |
#include <vector> | |
#include <GL/gl.h> | |
#ifndef __MINGW32__ | |
#pragma comment(lib, "opengl32.lib") // MSVC, ICL | |
#pragma comment(lib, "gdi32.lib") // ICL | |
#pragma comment(lib, "user32.lib") // ICL | |
#endif | |
#define NanoCL_MAX_LOG_LENGTH 10000 | |
#define NanoCL_V \ | |
"varying vec2 pos;void " \ | |
"main(void){pos=vec2(gl_MultiTexCoord0);gl_Position=gl_Vertex;}" | |
#define NanoCL_K \ | |
"varying vec2 pos;vec4 read(sampler2D m){return texture2D(m,pos);}" \ | |
"void commit(vec4 d){gl_FragColor=d;}" | |
#define defPROC(a, b, ...) \ | |
typedef a(__stdcall *MCL##b)(__VA_ARGS__); \ | |
MCL##b b = nullptr | |
#define loadPROC(a) \ | |
a = MCL##a((wglGetProcAddress(#a))); \ | |
if (a == nullptr) \ | |
ExitProcess(printf("ERROR: Couldn't load GL(Ext) function %s.\n", #a)); | |
#define kernel(k) #k | |
namespace NanoCL { | |
defPROC(const char *, glGetStringi, int, int); | |
defPROC(void, glActiveTexture, int); | |
defPROC(void, glAttachShader, unsigned, unsigned); | |
defPROC(void, glCompileShader, unsigned); | |
defPROC(void, glDeleteShader, unsigned); | |
defPROC(void, glGetInfoLogARB, unsigned, int, int *, char *); | |
defPROC(void, glGetObjectParameterivARB, unsigned, unsigned, int *); | |
defPROC(void, glLinkProgram, unsigned); | |
defPROC(void, glShaderSource, unsigned, int, const char **, const int *); | |
defPROC(void, glUniform1i, int, int); | |
defPROC(void, glUniform2fv, int, int, const float *); | |
defPROC(void, glUniform4fv, int, int, const float *); | |
defPROC(void, glUseProgram, unsigned); | |
defPROC(void, glBindFramebufferEXT, unsigned, unsigned); | |
defPROC(void, glDeleteFramebuffersEXT, int, const unsigned *); | |
defPROC(void, glFramebufferTexture2DEXT, unsigned, unsigned, unsigned, unsigned, | |
int); | |
defPROC(void, glGenFramebuffersEXT, int, unsigned *); | |
defPROC(void, glGenerateMipmapEXT, unsigned); | |
defPROC(int, glGetUniformLocation, unsigned, const char *); | |
defPROC(int, glCreateProgram, void); | |
defPROC(int, glCreateShader, unsigned); | |
typedef struct NCL_vec4f { float r, g, b, a; } NCL_vec4f; | |
inline void gpgpu_fillscreen(void) { | |
glBegin(6); | |
glTexCoord2f(0.0f, 0.0f); | |
glVertex3f(-1.0f, -1.0f, 0.0f); | |
glTexCoord2f(1.0f, 0.0f); | |
glVertex3f(+1.0f, -1.0f, 0.0f); | |
glTexCoord2f(1.0f, 1.0f); | |
glVertex3f(+1.0f, +1.0f, 0.0f); | |
glTexCoord2f(0.0f, 1.0f); | |
glVertex3f(-1.0f, +1.0f, 0.0f); | |
glEnd(); | |
} | |
class gpgpu_texture2D { | |
public: | |
unsigned handle; | |
int width, height; | |
gpgpu_texture2D(int w, int h) : width(w), height(h) { | |
glGenTextures(1, &handle); | |
update_data(nullptr); | |
bind(); | |
glTexParameteri(0x0DE1, 0x2802, 0x812F); | |
glTexParameteri(0x0DE1, 0x2803, 0x812F); | |
bind(); | |
glTexParameteri(0x0DE1, 0x2801, 0x2600); | |
glTexParameteri(0x0DE1, 0x2800, 0x2600); | |
glGenerateMipmapEXT(0x0DE1); | |
} | |
~gpgpu_texture2D() { | |
glDeleteTextures(1, &handle); | |
handle = 0; | |
} | |
void draw(void) const { | |
bind(); | |
glEnable(0x0DE1); | |
gpgpu_fillscreen(); | |
} | |
void bind(int texture_unit = 0) const { | |
glActiveTexture(0x84C0 + texture_unit); | |
glBindTexture(0x0DE1, handle); | |
} | |
void update_data(const float *dat) { | |
bind(); | |
glTexImage2D(0x0DE1, 0, 0x8814, width, height, 0, 0x1908, 0x1406, dat); | |
} | |
private: | |
gpgpu_texture2D(const gpgpu_texture2D &src); | |
void operator=(const gpgpu_texture2D &src); | |
}; | |
inline void gpgpu_tex_scale(unsigned program, gpgpu_texture2D *tex, | |
const std::string &name) { | |
auto scale = glGetUniformLocation(program, (name + "Scale").c_str()); | |
if (scale <= -1) | |
return; | |
const float argARB[] = {1.0f / tex->width, 1.0f / tex->height, 0.0f, 0.0f}; | |
glUniform2fv(scale, 1, argARB); | |
} | |
inline void gpgpu_add(unsigned program, gpgpu_texture2D *tex, | |
const std::string &name, int texture_unit = 0) { | |
glUseProgram(program); | |
tex->bind(texture_unit); | |
glUniform1i(glGetUniformLocation(program, name.c_str()), texture_unit); | |
gpgpu_tex_scale(program, tex, name); | |
} | |
class gpgpu_framebuffer { | |
public: | |
unsigned handle; | |
gpgpu_texture2D *tex; | |
explicit gpgpu_framebuffer(gpgpu_texture2D *tex_) { | |
glGenFramebuffersEXT(1, &handle); | |
attach(tex_); | |
} | |
~gpgpu_framebuffer() { | |
glDeleteFramebuffersEXT(1, &handle); | |
handle = 0; | |
} | |
void run(unsigned prog) const { | |
bind(); | |
glUseProgram(prog); | |
auto scale_index = glGetUniformLocation(prog, "locationScale"); | |
if (scale_index > -1) { | |
const float argARB[] = {float(tex->width), float(tex->height), 0.0f, | |
0.0f}; | |
glUniform4fv(scale_index, 1, argARB); | |
} | |
gpgpu_fillscreen(); | |
} | |
void read(float *destination, int width, int height) const { | |
bind(); | |
glReadPixels(0, 0, width, height, 0x1908, 0x1406, destination); | |
} | |
void bind(void) const { | |
glBindFramebufferEXT(0x8D40, handle); | |
if (tex) | |
glViewport(0, 0, tex->width, tex->height); | |
} | |
void attach(gpgpu_texture2D *tex_) { | |
tex = tex_; | |
if (!tex) | |
return; | |
glBindFramebufferEXT(0x8D40, handle); | |
glFramebufferTexture2DEXT(0x8D40, 0x8CE0, 0x0DE1, tex->handle, 0); | |
} | |
private: | |
gpgpu_framebuffer(const gpgpu_framebuffer &src); | |
void operator=(const gpgpu_framebuffer &src); | |
}; | |
inline void gpgpu_init() { | |
static auto gpgpu_initted = false; | |
if (gpgpu_initted) | |
return; | |
gpgpu_initted = true; | |
const static PIXELFORMATDESCRIPTOR pfd = { | |
0, 0, PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, | |
0, 0, 0, | |
0, 0, 0, | |
0, 0, 0, | |
0, 0, 0, | |
0, 0, 0, | |
0, 0, 0, | |
0, 0, 0, | |
0, 0}; | |
auto hDC = GetDC(CreateWindow( | |
#if (defined(_MSC_VER) && !defined(__INTEL_COMPILER)) | |
LPCWSTR | |
#else | |
LPCSTR | |
#endif | |
("edit"), | |
nullptr, WS_POPUP | WS_MINIMIZE, 0, 0, 0, 0, nullptr, nullptr, nullptr, | |
nullptr)); | |
SetPixelFormat(hDC, ChoosePixelFormat(hDC, &pfd), &pfd); | |
wglMakeCurrent(hDC, wglCreateContext(hDC)); | |
int extListSize = 0; | |
glGetIntegerv(0x821D, &extListSize); | |
if (extListSize == 0) | |
ExitProcess(printf("ERROR: No GPU extensions detected (OpenGL context init " | |
"might have failed).\n")); | |
#pragma warning(disable : 4312) | |
loadPROC(glActiveTexture); | |
loadPROC(glGetUniformLocation); | |
loadPROC(glAttachShader); | |
loadPROC(glCompileShader); | |
loadPROC(glCreateProgram); | |
loadPROC(glCreateShader); | |
loadPROC(glDeleteShader); | |
loadPROC(glGetInfoLogARB); | |
loadPROC(glGetObjectParameterivARB); | |
loadPROC(glGetUniformLocation); | |
loadPROC(glLinkProgram); | |
loadPROC(glShaderSource); | |
loadPROC(glUniform1i); | |
loadPROC(glUniform2fv); | |
loadPROC(glUniform4fv); | |
loadPROC(glUseProgram); | |
loadPROC(glBindFramebufferEXT); | |
loadPROC(glDeleteFramebuffersEXT); | |
loadPROC(glFramebufferTexture2DEXT); | |
loadPROC(glGenFramebuffersEXT); | |
loadPROC(glGenerateMipmapEXT); | |
loadPROC(glGetStringi); | |
#pragma warning(default : 4312) | |
glDisable(0x0B71); | |
glDisable(0x0BC0); | |
glDisable(0x0BE2); | |
} | |
class gpgpu_array; | |
class context { | |
public: | |
explicit context() { gpgpu_init(); } | |
std::vector<gpgpu_array *> tex; | |
std::string utils; | |
void add_array(gpgpu_array *t) { tex.push_back(t); } | |
}; | |
class gpgpu_array : public gpgpu_texture2D, public gpgpu_framebuffer { | |
public: | |
context &env; | |
std::string name; | |
gpgpu_array(context &env_, std::string name, int w, int h) | |
: gpgpu_texture2D(w, h), gpgpu_framebuffer(this), env(env_), name(name) { | |
env.add_array(this); | |
} | |
std::string get_tex_decls(void) const { | |
std::string s; | |
for (unsigned i = 0; i < env.tex.size(); i++) | |
s += "uniform sampler2D " + env.tex[i]->name + ";uniform vec2 " + | |
env.tex[i]->name + "Scale;"; | |
return s + env.utils; | |
} | |
void swap(gpgpu_array &arr) { | |
std::swap(gpgpu_framebuffer::handle, arr.gpgpu_framebuffer::handle); | |
std::swap(gpgpu_texture2D::handle, arr.gpgpu_texture2D::handle); | |
} | |
}; | |
inline unsigned gpgpu_runprep(gpgpu_array &dest, unsigned code) { | |
auto &env = dest.env; | |
unsigned texunit = 0; | |
for (unsigned i = 0; i < env.tex.size(); i++) { | |
if (env.tex[i] != &dest) | |
gpgpu_add(code, env.tex[i], env.tex[i]->name, texunit++); | |
else | |
gpgpu_tex_scale(code, env.tex[i], env.tex[i]->name); | |
} | |
return code; | |
} | |
// Debug GLSL | |
void checkShaderOp(unsigned obj, unsigned errType, const char *where) { | |
int compiled; | |
glGetObjectParameterivARB(obj, errType, &compiled); | |
if (compiled) | |
return; | |
char errorLog[NanoCL_MAX_LOG_LENGTH]; | |
glGetInfoLogARB(obj, NanoCL_MAX_LOG_LENGTH, nullptr, errorLog); | |
printf("ERROR: Could not build GLSL shader (fatal).\n\n--- CODE DUMP " | |
"---\n%s\n\n--- ERROR LOG ---\n%s\n\n", | |
where, errorLog); | |
} | |
unsigned makeShaderObject(int target, const char *code) { | |
auto h = glCreateShader(target); | |
glShaderSource(h, 1, &code, nullptr); | |
glCompileShader(h); | |
checkShaderOp(h, 0x8B81, code); | |
return h; | |
} | |
unsigned makeProgramObject(const char *vertex, const char *fragment) { | |
if (glUseProgram == nullptr) | |
printf("ERROR: glUseProgram could not be loaded.\n"); | |
auto p = glCreateProgram(); | |
auto vo = makeShaderObject(0x8B31, vertex); | |
auto fo = makeShaderObject(0x8B30, fragment); | |
glAttachShader(p, vo); | |
glAttachShader(p, fo); | |
glLinkProgram(p); | |
checkShaderOp(p, 0x8B82, "link"); | |
glDeleteShader(vo); | |
glDeleteShader(fo); | |
return p; | |
} | |
struct alloc { | |
NCL_vec4f *data; | |
unsigned dataWidth; // (CPU) [internal] texture width | |
unsigned dataHeight; // (CPU) [internal] texture height | |
gpgpu_array *gpuData; // (GPU) float-texture | |
alloc(context &gpuCtx, std::string UID, unsigned length) { | |
dataWidth = length; | |
int x, y; | |
for (x = 0; y = length / ++x | 0, x <= y;) | |
if (!(x * y - length)) | |
dataHeight = y; | |
dataWidth = length / dataHeight; | |
data = new NCL_vec4f[length](); | |
gpuData = new gpgpu_array(gpuCtx, UID, dataWidth, dataHeight); | |
} | |
}; | |
void push(alloc uID) { uID.gpuData->update_data((float *)(uID.data)); } | |
int make(alloc uID, const char *kernel) { | |
return makeProgramObject( | |
NanoCL_V, | |
(NanoCL_K + (*uID.gpuData).get_tex_decls() + std::string(kernel)) | |
.c_str()); | |
} | |
void run(alloc uID, const char *kernel) { | |
(*uID.gpuData).run(gpgpu_runprep(*uID.gpuData, make(uID, kernel))); | |
} | |
void run(alloc uID, int progID) { | |
(*uID.gpuData).run(gpgpu_runprep(*uID.gpuData, progID)); | |
} | |
void pull(alloc uID) { | |
uID.gpuData->read(((float *)(uID.data)), uID.dataWidth, uID.dataHeight); | |
} | |
void swap(alloc A, alloc B) { A.gpuData->swap(*B.gpuData); } | |
} | |
#undef defPROC | |
#undef loadPROC | |
/* EOF */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment