Commit 8deddda8 authored by Gaëtan Renaudeau's avatar Gaëtan Renaudeau

Forward gl compile status to gl-react for inline shader feature

parent 5dc2413e
...@@ -113,7 +113,7 @@ public class GLCanvas extends GLSurfaceView ...@@ -113,7 +113,7 @@ public class GLCanvas extends GLSurfaceView
if (!shaders.containsKey(id)) { if (!shaders.containsKey(id)) {
GLShaderData shaderData = rnglContext.getShader(id); GLShaderData shaderData = rnglContext.getShader(id);
if (shaderData == null) return null; if (shaderData == null) return null;
shaders.put(id, new GLShader(shaderData)); shaders.put(id, new GLShader(shaderData, id, rnglContext));
} }
return shaders.get(id); return shaders.get(id);
} }
...@@ -315,8 +315,13 @@ public class GLCanvas extends GLSurfaceView ...@@ -315,8 +315,13 @@ public class GLCanvas extends GLSurfaceView
execute(new Runnable() { execute(new Runnable() {
public void run() { public void run() {
// FIXME: maybe should set a flag so we don't do it twice?? // FIXME: maybe should set a flag so we don't do it twice??
if (!syncData()) try {
requestSyncData(); if (!syncData())
requestSyncData();
}
catch (GLShaderCompilationFailed e) {
// This is ignored. It will be handled by RNGLContext.shaderFailedToCompile
}
} }
}); });
} }
......
...@@ -21,29 +21,30 @@ public class GLShader { ...@@ -21,29 +21,30 @@ public class GLShader {
private int pointerLoc; // The "pointer" attribute is used to iterate over vertex private int pointerLoc; // The "pointer" attribute is used to iterate over vertex
private Map<String, Integer> uniformLocations; // The uniform locations cache private Map<String, Integer> uniformLocations; // The uniform locations cache
public GLShader(String name, String vert, String frag) { private Integer id;
this.name = name; private RNGLContext rnglContext;
this.vert = vert; private GLShaderCompilationFailed compilationFailed;
this.frag = frag;
}
public GLShader(GLShaderData data) { public GLShader(GLShaderData data, Integer id, RNGLContext rnglContext) {
this.name = data.name; this.name = data.name;
this.vert = data.vert; this.vert = data.vert;
this.frag = data.frag; this.frag = data.frag;
this.id = id;
this.rnglContext = rnglContext;
} }
@Override @Override
protected void finalize() throws Throwable { protected void finalize() throws Throwable {
super.finalize(); super.finalize();
if (buffer != null) { if (buffer != null) {
// TODO: need to check if this works properly
glDeleteProgram(program); glDeleteProgram(program);
glDeleteBuffers(1, buffer, 0); glDeleteBuffers(1, buffer, 0);
} }
} }
public void runtimeException (String msg) { public void runtimeException (String msg) {
throw new RuntimeException("Shader '"+name+"': "+msg); throw new GLShaderCompilationFailed(name, msg);
} }
public void bind () { public void bind () {
...@@ -64,7 +65,7 @@ public class GLShader { ...@@ -64,7 +65,7 @@ public class GLShader {
glGetProgramiv(program, GL_VALIDATE_STATUS, validSuccess, 0); glGetProgramiv(program, GL_VALIDATE_STATUS, validSuccess, 0);
if (validSuccess[0] == GL_FALSE) { if (validSuccess[0] == GL_FALSE) {
glGetProgramInfoLog(program); glGetProgramInfoLog(program);
runtimeException("Validation failed " + glGetProgramInfoLog(program)); runtimeException(glGetProgramInfoLog(program));
} }
} }
...@@ -133,7 +134,7 @@ public class GLShader { ...@@ -133,7 +134,7 @@ public class GLShader {
int compileSuccess[] = new int[1]; int compileSuccess[] = new int[1];
glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, compileSuccess, 0); glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, compileSuccess, 0);
if (compileSuccess[0] == GL_FALSE) { if (compileSuccess[0] == GL_FALSE) {
runtimeException("failed to compile: " + glGetShaderInfoLog(shaderHandle)); runtimeException(glGetShaderInfoLog(shaderHandle));
return -1; return -1;
} }
return shaderHandle; return shaderHandle;
...@@ -157,7 +158,7 @@ public class GLShader { ...@@ -157,7 +158,7 @@ public class GLShader {
this.uniformLocations = locations; this.uniformLocations = locations;
} }
private void makeProgram () { private void makeProgram () throws GLShaderCompilationFailed {
int vertex = compileShader(vert, GL_VERTEX_SHADER); int vertex = compileShader(vert, GL_VERTEX_SHADER);
if (vertex == -1) return; if (vertex == -1) return;
...@@ -172,7 +173,7 @@ public class GLShader { ...@@ -172,7 +173,7 @@ public class GLShader {
int[] linkSuccess = new int[1]; int[] linkSuccess = new int[1];
glGetProgramiv(program, GL_LINK_STATUS, linkSuccess, 0); glGetProgramiv(program, GL_LINK_STATUS, linkSuccess, 0);
if (linkSuccess[0] == GL_FALSE) { if (linkSuccess[0] == GL_FALSE) {
runtimeException("Linking failed "+glGetProgramInfoLog(program)); runtimeException(glGetProgramInfoLog(program));
} }
glUseProgram(program); glUseProgram(program);
...@@ -208,7 +209,18 @@ public class GLShader { ...@@ -208,7 +209,18 @@ public class GLShader {
} }
public boolean ensureCompile() { public boolean ensureCompile() {
if (!isReady()) makeProgram(); if (!isReady()) {
if (compilationFailed != null) throw compilationFailed;
try {
makeProgram();
rnglContext.shaderSucceedToCompile(id, uniformTypes);
}
catch (GLShaderCompilationFailed e) {
compilationFailed = e;
rnglContext.shaderFailedToCompile(id, e);
throw e;
}
}
return isReady(); return isReady();
} }
} }
package com.projectseptember.RNGL;
public class GLShaderCompilationFailed extends RuntimeException {
public final String shaderName;
public final String compileError;
public GLShaderCompilationFailed(String shaderName, String compileError) {
super("Shader '"+shaderName+"': "+compileError);
this.compileError = compileError;
this.shaderName = shaderName;
}
}
package com.projectseptember.RNGL; package com.projectseptember.RNGL;
import android.util.Log;
import static android.opengl.GLES20.*;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
...@@ -20,6 +26,7 @@ public class RNGLContext extends ReactContextBaseJavaModule { ...@@ -20,6 +26,7 @@ public class RNGLContext extends ReactContextBaseJavaModule {
private Map<Integer, GLShaderData> shaders = new HashMap<>(); private Map<Integer, GLShaderData> shaders = new HashMap<>();
private Map<Integer, GLFBO> fbos = new HashMap<>(); private Map<Integer, GLFBO> fbos = new HashMap<>();
private Map<Integer, Callback> onCompileCallbacks = new HashMap<>();
public RNGLContext (ReactApplicationContext reactContext) { public RNGLContext (ReactApplicationContext reactContext) {
super(reactContext); super(reactContext);
...@@ -35,9 +42,67 @@ public class RNGLContext extends ReactContextBaseJavaModule { ...@@ -35,9 +42,67 @@ public class RNGLContext extends ReactContextBaseJavaModule {
} }
@ReactMethod @ReactMethod
public void addShader (final Integer id, final ReadableMap config) { public void addShader (final Integer id, final ReadableMap config, final Callback onCompile) {
final String frag = config.getString("frag"); final String frag = config.getString("frag");
final String name = config.getString("name"); final String name = config.getString("name");
shaders.put(id, new GLShaderData(name, STATIC_VERT, frag)); shaders.put(id, new GLShaderData(name, STATIC_VERT, frag));
if (onCompile != null) {
onCompileCallbacks.put(id, onCompile);
}
}
@ReactMethod
public void removeShader (final Integer id) {
GLShaderData shader = shaders.remove(id);
if (shader == null) {
throw new Error("removeShader("+id+"): shader does not exist");
}
}
public void shaderFailedToCompile(Integer id, GLShaderCompilationFailed e) {
Callback onCompile = onCompileCallbacks.get(id);
if (onCompile == null) {
Log.e("RNGLContext", e.getMessage());
}
else {
onCompile.invoke(e.compileError);
}
}
public void shaderSucceedToCompile(Integer id, Map<String, Integer> uniformTypes) {
Callback onCompile = onCompileCallbacks.get(id);
onCompileCallbacks.remove(id);
if (onCompile != null) {
WritableMap res = Arguments.createMap();
WritableMap uniforms = Arguments.createMap();
for (String key : uniformTypes.keySet()) {
uniforms.putString(key, glTypeString(uniformTypes.get(key)));
}
res.putMap("uniforms", uniforms);
onCompile.invoke(null, res);
}
}
static String glTypeString (int type) {
switch (type) {
case GL_FLOAT: return "float";
case GL_FLOAT_VEC2: return "vec2";
case GL_FLOAT_VEC3: return "vec3";
case GL_FLOAT_VEC4: return "vec4";
case GL_INT: return "int";
case GL_INT_VEC2: return "ivec2";
case GL_INT_VEC3: return "ivec3";
case GL_INT_VEC4: return "ivec4";
case GL_BOOL: return "bool";
case GL_BOOL_VEC2: return "bvec2";
case GL_BOOL_VEC3: return "bvec3";
case GL_BOOL_VEC4: return "bvec4";
case GL_FLOAT_MAT2: return "mat2";
case GL_FLOAT_MAT3: return "mat3";
case GL_FLOAT_MAT4: return "mat4";
case GL_SAMPLER_2D: return "sampler2D";
case GL_SAMPLER_CUBE: return "samplerCube";
}
return "";
} }
} }
...@@ -173,7 +173,7 @@ RCT_NOT_IMPLEMENTED(-init) ...@@ -173,7 +173,7 @@ RCT_NOT_IMPLEMENTED(-init)
[self setNeedsDisplay]; [self setNeedsDisplay];
} }
- (void)syncData - (bool)syncData:(NSError **)error
{ {
@autoreleasepool { @autoreleasepool {
...@@ -204,6 +204,7 @@ RCT_NOT_IMPLEMENTED(-init) ...@@ -204,6 +204,7 @@ RCT_NOT_IMPLEMENTED(-init)
GLShader *shader = [_bridge.rnglContext getShader:data.shader]; GLShader *shader = [_bridge.rnglContext getShader:data.shader];
if (shader == nil) return nil; if (shader == nil) return nil;
if (![shader ensureCompiles:error]) return nil;
NSDictionary *uniformTypes = [shader uniformTypes]; NSDictionary *uniformTypes = [shader uniformTypes];
NSMutableDictionary *uniforms = [[NSMutableDictionary alloc] init]; NSMutableDictionary *uniforms = [[NSMutableDictionary alloc] init];
...@@ -292,16 +293,15 @@ RCT_NOT_IMPLEMENTED(-init) ...@@ -292,16 +293,15 @@ RCT_NOT_IMPLEMENTED(-init)
GLRenderData *res = traverseTree(_data); GLRenderData *res = traverseTree(_data);
if (res != nil) { if (res != nil) {
_needSync = false;
_renderData = traverseTree(_data); _renderData = traverseTree(_data);
_images = images; _images = images;
for (NSString *src in diff([prevImages allKeys], [images allKeys])) { for (NSString *src in diff([prevImages allKeys], [images allKeys])) {
[_preloaded removeObject:src]; [_preloaded removeObject:src];
} }
return true;
} }
else { else {
// the data is not ready, retry in one tick return false;
[self setNeedsDisplay];
} }
} }
} }
...@@ -374,7 +374,14 @@ RCT_NOT_IMPLEMENTED(-init) ...@@ -374,7 +374,14 @@ RCT_NOT_IMPLEMENTED(-init)
} }
if (_needSync) { if (_needSync) {
[self syncData]; NSError *error;
if(![self syncData:&error] && error==nil) {
// the data is not ready, retry in one tick
[self setNeedsDisplay];
}
else {
_needSync = false;
}
} }
if ([self haveRemainingToPreload]) { if ([self haveRemainingToPreload]) {
......
#import <GLKit/GLKit.h> #import <GLKit/GLKit.h>
#import "RCTBridgeModule.h" #import "RCTBridgeModule.h"
NS_ENUM(NSInteger) {
GLContextFailure = 87001,
GLLinkingFailure = 87002,
GLCompileFailure = 87003
};
@interface GLShader: NSObject @interface GLShader: NSObject
@property EAGLContext *context; @property EAGLContext *context;
...@@ -18,10 +24,7 @@ ...@@ -18,10 +24,7 @@
*/ */
- (void) bind; - (void) bind;
/** - (bool) ensureCompiles: (NSError**)error;
* Check the shader validity
*/
- (void) validate;
/** /**
* Set the value of an uniform * Set the value of an uniform
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
#import "RCTConvert.h" #import "RCTConvert.h"
#import "GLShader.h" #import "GLShader.h"
GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shaderType) { GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shaderType, NSError **error) {
GLuint shaderHandle = glCreateShader(shaderType); GLuint shaderHandle = glCreateShader(shaderType);
...@@ -20,8 +20,10 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade ...@@ -20,8 +20,10 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade
if (compileSuccess == GL_FALSE) { if (compileSuccess == GL_FALSE) {
GLchar messages[256]; GLchar messages[256];
glGetShaderInfoLog(shaderHandle, sizeof(messages), 0, &messages[0]); glGetShaderInfoLog(shaderHandle, sizeof(messages), 0, &messages[0]);
NSString *messageString = [NSString stringWithUTF8String:messages]; *error = [[NSError alloc]
RCTLogError(@"Shader '%@' failed to compile: %@", shaderName, messageString); initWithDomain:[NSString stringWithUTF8String:messages]
code:GLCompileFailure
userInfo:nil];
return -1; return -1;
} }
...@@ -41,6 +43,7 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade ...@@ -41,6 +43,7 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade
GLint pointerLoc; // The "pointer" attribute is used to iterate over vertex GLint pointerLoc; // The "pointer" attribute is used to iterate over vertex
NSDictionary *_uniformTypes; // The types of the GLSL uniforms (N.B: array are not supported) NSDictionary *_uniformTypes; // The types of the GLSL uniforms (N.B: array are not supported)
NSDictionary *_uniformLocations; // The uniform locations cache NSDictionary *_uniformLocations; // The uniform locations cache
NSError *_error;
} }
- (instancetype)initWithContext: (EAGLContext*)context withName:(NSString *)name withVert:(NSString *)vert withFrag:(NSString *)frag - (instancetype)initWithContext: (EAGLContext*)context withName:(NSString *)name withVert:(NSString *)vert withFrag:(NSString *)frag
...@@ -51,7 +54,10 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade ...@@ -51,7 +54,10 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade
_context = context; _context = context;
_vert = vert; _vert = vert;
_frag = frag; _frag = frag;
[self makeProgram]; NSError *error;
if (![self makeProgram:&error]) {
_error = error;
}
} }
return self; return self;
} }
...@@ -62,10 +68,10 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade ...@@ -62,10 +68,10 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade
glDeleteBuffers(1, &buffer); glDeleteBuffers(1, &buffer);
} }
- (bool) ensureContext - (bool) ensureContext: (NSError **)error
{ {
if (![EAGLContext setCurrentContext:_context]) { if (![EAGLContext setCurrentContext:_context]) {
RCTLogError(@"Shader '%@': Failed to set current OpenGL context", _name); *error = [[NSError alloc] initWithDomain:@"Failed to set current OpenGL context" code:GLContextFailure userInfo:nil];
return false; return false;
} }
return true; return true;
...@@ -73,7 +79,11 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade ...@@ -73,7 +79,11 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade
- (void) bind - (void) bind
{ {
if (![self ensureContext]) return; NSError *error;
if (![self ensureContext:&error]) {
RCTLogError(@"%@", error.domain);
return;
}
if ( glIsProgram(program) != GL_TRUE ){ if ( glIsProgram(program) != GL_TRUE ){
RCTLogError(@"Shader '%@': not a program!", _name); RCTLogError(@"Shader '%@': not a program!", _name);
return; return;
...@@ -307,19 +317,6 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade ...@@ -307,19 +317,6 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade
} }
} }
- (void) validate
{
glValidateProgram(program);
GLint validSuccess;
glGetProgramiv(program, GL_VALIDATE_STATUS, &validSuccess);
if (validSuccess == GL_FALSE) {
GLchar messages[256];
glGetProgramInfoLog(program, sizeof(messages), 0, &messages[0]);
NSString *messageString = [NSString stringWithUTF8String:messages];
RCTLogError(@"Shader '%@': Validation failed %@", _name, messageString);
}
}
- (void) computeMeta - (void) computeMeta
{ {
NSMutableDictionary *uniforms = @{}.mutableCopy; NSMutableDictionary *uniforms = @{}.mutableCopy;
...@@ -342,15 +339,22 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade ...@@ -342,15 +339,22 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade
_uniformLocations = locations; _uniformLocations = locations;
} }
- (void) makeProgram - (bool) ensureCompiles: (NSError **)error
{
if (_error == nil) return true;
*error = _error;
return false;
}
- (bool) makeProgram: (NSError **)error
{ {
if (![self ensureContext]) return; if (![self ensureContext:error]) return false;
GLuint vertex = compileShader(_name, _vert, GL_VERTEX_SHADER); GLuint vertex = compileShader(_name, _vert, GL_VERTEX_SHADER, error);
if (vertex == -1) return; if (vertex == -1) return false;
GLuint fragment = compileShader(_name, _frag, GL_FRAGMENT_SHADER); GLuint fragment = compileShader(_name, _frag, GL_FRAGMENT_SHADER, error);
if (fragment == -1) return; if (fragment == -1) return false;
program = glCreateProgram(); program = glCreateProgram();
glAttachShader(program, vertex); glAttachShader(program, vertex);
...@@ -362,9 +366,11 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade ...@@ -362,9 +366,11 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade
if (linkSuccess == GL_FALSE) { if (linkSuccess == GL_FALSE) {
GLchar messages[256]; GLchar messages[256];
glGetProgramInfoLog(program, sizeof(messages), 0, &messages[0]); glGetProgramInfoLog(program, sizeof(messages), 0, &messages[0]);
NSString *messageString = [NSString stringWithUTF8String:messages]; *error = [[NSError alloc]
RCTLogError(@"Shader '%@': Linking failed %@", _name, messageString); initWithDomain:[NSString stringWithUTF8String:messages]
return; code:GLLinkingFailure
userInfo:nil];
return false;
} }
glUseProgram(program); glUseProgram(program);
...@@ -384,6 +390,8 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade ...@@ -384,6 +390,8 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade
1.0, 1.0 1.0, 1.0
}; };
glBufferData(GL_ARRAY_BUFFER, sizeof(buf), buf, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof(buf), buf, GL_STATIC_DRAW);
return true;
} }
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
346089C61BEFD0A500C90DB5 /* GLRenderData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLRenderData.h; sourceTree = "<group>"; }; 346089C61BEFD0A500C90DB5 /* GLRenderData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLRenderData.h; sourceTree = "<group>"; };
346089C71BEFD0A500C90DB5 /* GLRenderData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GLRenderData.m; sourceTree = "<group>"; }; 346089C71BEFD0A500C90DB5 /* GLRenderData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GLRenderData.m; sourceTree = "<group>"; };
346089C81BEFD0A500C90DB5 /* GLShader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLShader.h; sourceTree = "<group>"; }; 346089C81BEFD0A500C90DB5 /* GLShader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLShader.h; sourceTree = "<group>"; };
346089C91BEFD0A500C90DB5 /* GLShader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GLShader.m; sourceTree = "<group>"; }; 346089C91BEFD0A500C90DB5 /* GLShader.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = GLShader.m; sourceTree = "<group>"; tabWidth = 2; };
346089CA1BEFD0A500C90DB5 /* GLTexture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLTexture.h; sourceTree = "<group>"; }; 346089CA1BEFD0A500C90DB5 /* GLTexture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLTexture.h; sourceTree = "<group>"; };
346089CB1BEFD0A500C90DB5 /* GLTexture.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = GLTexture.m; sourceTree = "<group>"; tabWidth = 2; }; 346089CB1BEFD0A500C90DB5 /* GLTexture.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = GLTexture.m; sourceTree = "<group>"; tabWidth = 2; };
346089CC1BEFD0A500C90DB5 /* RCTConvert+GLData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RCTConvert+GLData.h"; sourceTree = "<group>"; }; 346089CC1BEFD0A500C90DB5 /* RCTConvert+GLData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RCTConvert+GLData.h"; sourceTree = "<group>"; };
......
...@@ -45,9 +45,73 @@ RCT_EXPORT_MODULE() ...@@ -45,9 +45,73 @@ RCT_EXPORT_MODULE()
return _context; return _context;
} }
- (void)_addShader:(nonnull NSNumber *)id
withConfig:(NSDictionary *)config
withOnCompile:(RCTResponseSenderBlock)onCompile
{
NSString *frag = [RCTConvert NSString:config[@"frag"]];
NSString *name = [RCTConvert NSString:config[@"name"]];
if (!frag) {
RCTLogError(@"Shader '%@': missing frag field", name);
return;
}
GLShader *shader = [[GLShader alloc] initWithContext:_context withName:name withVert:fullViewportVert withFrag:frag];
NSError *error;
bool success = [shader ensureCompiles:&error];
if (onCompile) {
if (!success) {
onCompile(@[error.domain]);
}
else {
onCompile(@[[NSNull null],
@{
@"uniforms": shader.uniformTypes
}]);
}
}
else {
if (!success) {
RCTLogError(@"Shader '%@': %@", name, error.domain);
}
}
_shaders[id] = shader;
}
static NSString* fullViewportVert = @"attribute vec2 position;varying vec2 uv;void main() {gl_Position = vec4(position,0.0,1.0);uv = vec2(0.5, 0.5) * (position+vec2(1.0, 1.0));}"; static NSString* fullViewportVert = @"attribute vec2 position;varying vec2 uv;void main() {gl_Position = vec4(position,0.0,1.0);uv = vec2(0.5, 0.5) * (position+vec2(1.0, 1.0));}";
RCT_EXPORT_METHOD(addShader:(nonnull NSNumber *)id withConfig:(NSDictionary *)config) { NSString* glTypeString (int type) {
switch (type) {
case GL_FLOAT: return @"float";
case GL_FLOAT_VEC2: return @"vec2";
case GL_FLOAT_VEC3: return @"vec3";
case GL_FLOAT_VEC4: return @"vec4";
case GL_INT: return @"int";
case GL_INT_VEC2: return @"ivec2";
case GL_INT_VEC3: return @"ivec3";
case GL_INT_VEC4: return @"ivec4";
case GL_BOOL: return @"bool";
case GL_BOOL_VEC2: return @"bvec2";
case GL_BOOL_VEC3: return @"bvec3";
case GL_BOOL_VEC4: return @"bvec4";
case GL_FLOAT_MAT2: return @"mat2";
case GL_FLOAT_MAT3: return @"mat3";
case GL_FLOAT_MAT4: return @"mat4";
case GL_SAMPLER_2D: return @"sampler2D";
case GL_SAMPLER_CUBE: return @"samplerCube";
}
return @"";
}
NSDictionary* glTypesString (NSDictionary *types) {
NSMutableDictionary *dict = types.mutableCopy;
for (NSString *key in [dict allKeys]) {
dict[key] = glTypeString([dict[key] intValue]);
}
return dict;
}
RCT_EXPORT_METHOD(addShader:(nonnull NSNumber *)id
withConfig:(NSDictionary *)config
withOnCompile:(RCTResponseSenderBlock)onCompile) {
NSString *frag = [RCTConvert NSString:config[@"frag"]]; NSString *frag = [RCTConvert NSString:config[@"frag"]];
NSString *name = [RCTConvert NSString:config[@"name"]]; NSString *name = [RCTConvert NSString:config[@"name"]];
if (!frag) { if (!frag) {
...@@ -55,9 +119,36 @@ RCT_EXPORT_METHOD(addShader:(nonnull NSNumber *)id withConfig:(NSDictionary *)co ...@@ -55,9 +119,36 @@ RCT_EXPORT_METHOD(addShader:(nonnull NSNumber *)id withConfig:(NSDictionary *)co
return; return;
} }
GLShader *shader = [[GLShader alloc] initWithContext:_context withName:name withVert:fullViewportVert withFrag:frag]; GLShader *shader = [[GLShader alloc] initWithContext:_context withName:name withVert:fullViewportVert withFrag:frag];
NSError *error;
bool success = [shader ensureCompiles:&error];
if (onCompile) {
if (!success) {
onCompile(@[error.domain]);
}
else {
onCompile(@[[NSNull null],
@{
@"uniforms": glTypesString(shader.uniformTypes)
}]);
}
}
else {
if (!success) {
RCTLogError(@"Shader '%@': %@", name, error.domain);
}
}
_shaders[id] = shader; _shaders[id] = shader;
} }
RCT_EXPORT_METHOD(removeShader:(nonnull NSNumber *)id) {
GLShader *shader = [_shaders objectForKey:id];
if (!shader) {
RCTLogError(@"removeShader(%@): shader does not exist", id);
return;
}
[_shaders removeObjectForKey:id];
}
@end @end
@implementation RCTBridge (RNGLContext) @implementation RCTBridge (RNGLContext)
......
...@@ -10,8 +10,8 @@ See README install instructions. ...@@ -10,8 +10,8 @@ See README install instructions.
React.NativeModules.RNGLContext is %s`, RNGLContext); React.NativeModules.RNGLContext is %s`, RNGLContext);
// Hook Shaders to RNGLContext // Hook Shaders to RNGLContext
Shaders.list().map(id => RNGLContext.addShader(id, Shaders.get(id))); Shaders.on("add", (id, shader, onCompile) => RNGLContext.addShader(id, shader, onCompile));
Shaders.on("add", (id, shader) => RNGLContext.addShader(id, shader)); Shaders.on("remove", id => RNGLContext.removeShader(id));
module.exports = { module.exports = {
Surface Surface
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment