shader buffers

hey, i’m still trying out different things with mesh and performance testing

basically trying to test the performance difference between setting shader uniform values directly and using custom buffer attributes instead, if anyone knows of using buffers is faster or not that would save some time :slight_smile:

i ran into a problem when trying to use buffers, and i’m surprised it’s even working because i’m not sure this of the intent of buffers to be used this way

but as you can see in the screen shots the full effect is the normal Ripple shader and the broken half image is my attributes ripple shader


function setup()
  m = mesh()
  m:addRect(WIDTH/2,HEIGHT/2,600,600)
  m.texture = asset.documents.Assets.Demo.Frames.maxSize — your image here
  m.shader = shader(asset.documents.ripple) --shader (vert, frag)
end

function draw()
  background(40, 40, 50)
  
  a = m:buffer("time")
  b = m:buffer("freq")
  a:resize(1)
  b:resize(1)
  a[1] = ElapsedTime
  b[1] = 1

  m:draw()
end


//
// Ripple vertex shader
//

//This is the current model * view * projection matrix
// Codea sets it automatically
uniform mat4 modelViewProjection;

//This is the current mesh vertex position, color and tex coord
// Set automatically
attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;

attribute float time;
attribute float freq;
//This is an output variable that will be passed to the fragment shader
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
varying lowp float vTime;
varying lowp float vFreq;

void main()
{
    gl_Position = modelViewProjection * position;
    
    //Pass values to our fragment shader
    vColor.rgb = color.rgb * color.a;
    vColor.a = color.a;
    vTexCoord = texCoord;
    vTime = time;
    vFreq = freq;
}



//
// Ripple fragment shader
//

//This represents the current texture on the mesh
uniform lowp sampler2D texture;

//The interpolated vertex color for this fragment
varying lowp vec4 vColor;

//The interpolated texture coordinate for this fragment
varying highp vec2 vTexCoord;

varying lowp float vTime;
varying lowp float vFreq;

void main()
{
    highp vec2 tc = vTexCoord.xy;
    highp vec2 p = -1.0 + 2.0 * tc;
    highp float len = length(p);
    highp vec2 uv = tc + (p/len)*vFreq*cos(len*24.0-vTime*4.0)*0.03;
    highp vec4 col = texture2D(texture,uv);
    
    gl_FragColor = vec4(col.rgb * vColor.rgb, col.a);
}


also, when i coded this in the Shader Lab, it shows as a Red Error for the Frag tab but there is no highlight error in the tab itself.

the bindings are empty which I think is expected, BUT, IF this is a bug and I’m using buffers correctly AND buffers are faster than setting shader.uniform directly, then it would be great to have custom attributes appear in bindings

i figured it out lol

the problem is there has to be 6 items in the buffers to account for the corners of both triangles in the texture, so


  a = m:buffer("time")
  b = m:buffer("freq")
  —a:resize(1)
 — b:resize(1)
for i = 1, 6 do
  a[i] = ElapsedTime
  b[i] = 1
end

and that works! but still get the red error in shader lab like it’s expecting something

as for performance goes it have to test it out still

looks like the performance is better to set uniforms directly

i wrote a small performance test that can be used to compare the relative speed of two pieces of code, please feel free to use it and let me know if it is buggy for you , it will also be available on the web repo

@skar it doesn’t run for me because it can’t find a shader.

One of the shaders is in asset.documents, it looks like, and it won’t be bundled with the project unless it’s in the project’s own assets.

@skar After adding the ripple shader, it looks like only testA runs. Couldn’t see why testB wouldn’t.

@skar When I ran testA on my iPad Air 3, I got an averageA of 3.1993. On my iPad Air 4, I got 1.1045 . Still don’t know why B doesn’t start.

sorry guys, that zip didn’t include the reworked shader using attributes, this one will have it, but the core of the project can be used without it, it’s just what i included because of this thread, you can use the project to compare any pieces of code

edit the internal code yourself, it’s pretty straight forward, drop your two different pieces of code into the functions testA and testB defined at the top of the file, put any code you might need as setup code for the tests into testSetup function

been messing more with buffers and instances

strange behaviors from instances can be observed here, notice how every time you run the project the number of instances you can set is different, sometimes after 500 the instancing breaks, sometimes it never breaks, sometimes at 1000 instances the fps is less than 5, sometimes there can be 3000 instances and the fps is 15+


--[[ ********
* buffer Test - 
******** ]]
function test()  
  local xxvv = d:buffer("xXVal") 
  xxvv:resize(instances)    
  for i = 1, instances do
    xxvv[i]=xVal*i
  end
  d.shader.vTime = ElapsedTime
  d.shader.vFreq = 1
  d:draw(instances)
end

--[[ ****************
*********************
********************* ]]
function setup()
  parameter.number("xVal", 0, 100, 0.17)
  parameter.integer("instances", 0, 3000, 100)
  d = mesh ()
  d.texture = asset.builtin.Basic.Icon
  d:addRect(WIDTH/2-400, HEIGHT/2, 400, 400)  
  d.shader = shader(vert, frag)
  local xxvv = d:buffer("xXVal") 
  xxvv.instanced = true
  xxvv:resize(instances) 
end

function draw()
  background(33, 25, 42)
  test()
end

vert = [[
#extension GL_EXT_draw_instanced: enable     
uniform mat4 modelViewProjection;
attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;
attribute float xXVal;
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
varying highp float vXVal;

void main() {
  //[gl_InstanceIDEXT]
  float xOffset = xXVal;
  float yOffset = 0.;
  vec4 offset = vec4(xOffset, yOffset, 0, 0);
  gl_Position = modelViewProjection * (position+offset);
  
  vColor.rgb = color.rgb * color.a;
  vColor.a = color.a;
  vTexCoord = texCoord;
  vXVal = xXVal;
}
]]


frag = [[
uniform lowp sampler2D texture;
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
uniform highp float vTime;
uniform highp float vFreq;
varying highp float vXVal;

void main() {
  highp vec2 tc = vTexCoord.xy;
  highp vec2 p = -1.0 + 2.0 * tc;
  highp float len = length(p);
  highp vec2 uv = tc + (p/len)*vFreq*cos(len*24.0-vTime*4.0)*0.03;
  highp vec4 col = texture2D(texture,uv-vec2(.0, 0.001* vXVal));
  
  gl_FragColor = vec4(col.rgb * vColor.rgb, col.a);
}

]]