Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android shader compilation failure [Android 8, Android 9] #275

Closed
Shamash2014 opened this issue Sep 19, 2020 · 7 comments
Closed

Android shader compilation failure [Android 8, Android 9] #275

Shamash2014 opened this issue Sep 19, 2020 · 7 comments
Labels

Comments

@Shamash2014
Copy link

Bug reports

[Sat Sep 19 2020 08:41:43.614]  ERROR    [GLError: gl-shader: Error compiling shader:
Compile failed.
ERROR: 0:1: '' :   Invalid directive 14
ERROR: 1 compilation errors. No code generated.

] 

Also Invalid directive changes from 10 to 14
Example code:

//@flow
import React, { PureComponent, Component } from "react";
import { Shaders, Node, GLSL, Bus } from "gl-react";
import { Surface } from "../../gl-react-implementation";
import marioPNG from "../../images/pixeleditor-mario.png";
import respondToTouchPosition from "../../HOC/respondToTouchPosition";

type Vec2 = [number, number];

const shaders = Shaders.create({
  paint: {
    frag: GLSL`
precision highp float;
varying vec2 uv;
uniform vec4 color;
uniform vec2 size, mouse;
uniform float brushRadius;
uniform bool drawing;
void main() {
  vec2 p = floor(uv * size) / size;
  if (drawing) {
    vec2 d = uv - mouse;
    if (length(d) < brushRadius) {
      gl_FragColor = color;
    }
    else {
      discard;
    }
  }
  else {
    discard;
  }
}`
  },
  initTexture: {
    frag: GLSL`
precision highp float;
varying vec2 uv;
uniform sampler2D t;
void main(){
  gl_FragColor=texture2D(t,uv);
}`
  },
  pixelEditor: {
    frag: GLSL`
precision highp float;
varying vec2 uv;
uniform vec4 color;
uniform vec2 size, mouse, gridBorder;
uniform float brushRadius;
uniform sampler2D t;
void main() {
  vec2 p = floor(uv * size) / size;
  vec2 remain = mod(uv * size, vec2(1.0));
  float m =
    step(remain.x, 1.0 - gridBorder.x) *
    step(remain.y, 1.0 - gridBorder.y);
  float inBrushSize =
    step(length(p + (0.5 / size) - mouse), brushRadius);
  vec4 c = mix(texture2D(t, uv), color, 0.6 * inBrushSize);
  gl_FragColor = vec4(
    m * c.rgb,
    mix(1.0, c.a, m));
}`
  }
});

class Paint extends PureComponent {
  state = {
    initialized: false
  };
  onDraw = () => {
    if (!this.state.initialized) {
      this.setState({ initialized: true });
    }
  };
  render() {
    const { initialTexture, onPaintNodeRef, ...rest } = this.props;
    const { initialized } = this.state;
    return (
      <Node
        ref={onPaintNodeRef}
        sync={!initialized}
        shader={!initialized ? shaders.initTexture : shaders.paint}
        width={rest.size[0]}
        height={rest.size[1]}
        uniforms={!initialized ? { t: initialTexture } : rest}
        clear={null}
        onDraw={this.onDraw}
      />
    );
  }
}

class PixelEditor extends PureComponent {
  render() {
    const { gridBorder, ...rest } = this.props;
    const { size, brushRadius, mouse, color } = rest;
    return (
      <Node
        shader={shaders.pixelEditor}
        uniformsOptions={{
          t: { interpolation: "nearest" }
        }}
        uniforms={{
          size,
          gridBorder,
          brushRadius,
          mouse,
          color
        }}
      >
        <Bus uniform="t">
          <Paint {...rest} />
        </Bus>
      </Node>
    );
  }
}

const size = [16, 16];
const gridBorder = [1 / 8, 1 / 8];
const tools = {
  "brush-1": { brushRadius: 0.55 / 16 },
  "brush-2": { brushRadius: 1.1 / 16 },
  "brush-4": { brushRadius: 2.2 / 16 },
  rubber: { brushRadius: 4 / 16, forceColor: [0, 0, 0, 0] },
  "color-picker": { colorPick: true }
};

const Example = respondToTouchPosition(
  class extends Component {
    render() {
      const { color, toolKey, touching, touchPosition, width } = this.props;
      const tool = tools[toolKey];
      return (
        <Surface
          style={{ width, height: width }}
          preload={[marioPNG]}
          webglContextAttributes={{ preserveDrawingBuffer: true }}
        >
          <PixelEditor
            gridBorder={gridBorder}
            initialTexture={marioPNG}
            drawing={touching}
            color={tool.forceColor || color}
            mouse={[touchPosition.x, touchPosition.y]}
            brushRadius={tool.brushRadius || 0}
            size={size}
            onPaintNodeRef={this.onPaintNodeRef}
          />
        </Surface>
      );
    }

    onColorChange = rgb => {
      this.props.setToolState({ color: rgb.concat([1]) });
    };

    paintNode: Node;
    onPaintNodeRef = (ref: Node) => {
      this.paintNode = ref;
    };

    colorPick = ([x, y]: Vec2) => {
      x = Math.floor(x * size[0]);
      y = Math.floor(y * size[1]);
      const ndarray = this.paintNode.capture(x, y, 1, 1);
      this.props.setToolState({
        color: Array.from(ndarray.data).map(n => n / 255)
      });
    };
  }
);

Example.defaultProps = {
  color: [1, 1, 1, 1],
  toolKey: "brush-4"
};

export default Example;

export { tools };

(Example is pixel editor from cookbook)

library version

Unimodules with expo is used on top of bare React Native

Expected behavior

  1. Shaders successfully compiled

Actual behavior

  1. On certain mobile phones shaders are not compiled and causing a crash

NB!: Seems like GLImage from gl-react-image actually works correctly

Steps to reproduce the behavior

  1. Open the screen with Pixel Editor
@Shamash2014
Copy link
Author

In this repo watched?

@gre
Copy link
Owner

gre commented Dec 23, 2020

Sorry for the late response. I was a bit busy this year (and not a lot of contributions on gl-react yet 🙏 )
I will do a big pass on all github issues. Is this still happening to you? I fail to see where the error is in your GLSL code.
I plan to upgrade to GLSL ES 3.0 too which maybe will help resolving this.

@gre gre added the question label Dec 23, 2020
@gre
Copy link
Owner

gre commented Dec 23, 2020

BTW this is dup with #248 , keeping the older issue opened.

@gre gre closed this as completed Dec 23, 2020
@Shamash2014
Copy link
Author

Hi yes it still reproducible, but I found a workaround by not using a Shaders.create for creating a shader. With this call it may fail on android 8 or 9. but once this shader caching is removed - it actually works

@gre
Copy link
Owner

gre commented Dec 24, 2020

interesting. so you mean by creating the shader in the <Node> directly?

@Shamash2014
Copy link
Author

@gre Let me give you an example of the code which worked for me.

This one won`t work on certain phones.

const shaders = Shaders.create({
  paint: {
    frag: GLSL`
precision highp float;
varying vec2 uv;
uniform vec4 color;
uniform vec2 size, mouse;
uniform float brushRadius;
uniform bool drawing;
void main() {
  vec2 p = floor(uv * size) / size;
  if (drawing) {
    vec2 d = uv - mouse;
    if (length(d) < brushRadius) {
      gl_FragColor = color;
    }
    else {
      discard;
    }
  }
  else {
    discard;
  }
}`
  },
  initTexture: {
    frag: GLSL`
precision highp float;
varying vec2 uv;
uniform sampler2D t;
void main(){
  gl_FragColor=texture2D(t,uv);
}`
  },
  pixelEditor: {
    frag: GLSL`
precision highp float;
varying vec2 uv;
uniform vec4 color;
uniform vec2 size, mouse, gridBorder;
uniform float brushRadius;
uniform sampler2D t;
void main() {
  vec2 p = floor(uv * size) / size;
  vec2 remain = mod(uv * size, vec2(1.0));
  float m =
    step(remain.x, 1.0 - gridBorder.x) *
    step(remain.y, 1.0 - gridBorder.y);
  float inBrushSize =
    step(length(p + (0.5 / size) - mouse), brushRadius);
  vec4 c = mix(texture2D(t, uv), color, 0.6 * inBrushSize);
  gl_FragColor = vec4(
    m * c.rgb,
    mix(1.0, c.a, m));
}`
  }
});

This one is actually working fine, even on android 7 or some low tier tablets

const shaders = {
  paint: {
    frag: GLSL`
precision highp float;
varying vec2 uv;
uniform vec4 color;
uniform vec2 size, mouse;
uniform float brushRadius;
uniform bool drawing;
void main() {
  vec2 p = floor(uv * size) / size;
  if (drawing) {
    vec2 d = uv - mouse;
    if (length(d) < brushRadius) {
      gl_FragColor = color;
    }
    else {
      discard;
    }
  }
  else {
    discard;
  }
}`
  },
  initTexture: {
    frag: GLSL`
precision highp float;
varying vec2 uv;
uniform sampler2D t;
void main(){
  gl_FragColor=texture2D(t,uv);
}`
  },
  pixelEditor: {
    frag: GLSL`
precision highp float;
varying vec2 uv;
uniform vec4 color;
uniform vec2 size, mouse, gridBorder;
uniform float brushRadius;
uniform sampler2D t;
void main() {
  vec2 p = floor(uv * size) / size;
  vec2 remain = mod(uv * size, vec2(1.0));
  float m =
    step(remain.x, 1.0 - gridBorder.x) *
    step(remain.y, 1.0 - gridBorder.y);
  float inBrushSize =
    step(length(p + (0.5 / size) - mouse), brushRadius);
  vec4 c = mix(texture2D(t, uv), color, 0.6 * inBrushSize);
  gl_FragColor = vec4(
    m * c.rgb,
    mix(1.0, c.a, m));
}`
  }
};

@Shamash2014
Copy link
Author

And than basically shader is executed on the Node. I haven't found any significant performance problem with this approach as well :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants