Skip to content

Instantly share code, notes, and snippets.

@chaosddp
Created May 4, 2023 08:23
Show Gist options
  • Save chaosddp/df22276dbe12ddc6ab0120994355db0a to your computer and use it in GitHub Desktop.
Save chaosddp/df22276dbe12ddc6ab0120994355db0a to your computer and use it in GitHub Desktop.
use ffi and love.data.newByteData to speedup compute shader initialization
#include <stdlib.h>
#include <stdio.h>
const int FLOAT_PER_PARTICLE = 8;
float randff(float max)
{
return rand() * (max / RAND_MAX);
}
void GenerateParticles(float* particles, int particle_count, int width, int height)
{
for(int i=0;i<particle_count * FLOAT_PER_PARTICLE;i+=8)
{
particles[i] = randff(width);
particles[i + 1] = randff(height);
particles[i + 2] = randff(100);
particles[i + 3] = randff(100);
particles[i + 4] = randff(1.0);
particles[i + 5] = randff(1.0);
particles[i + 6] = randff(1.0);
particles[i + 7] = randff(1.0);
}
}
-- need love2d 12+ to run this script
local ffi = require "ffi"
-- only tested on windows, but should work on other platform
local particles_lib = ffi.load("gen_particles.dll")
ffi.cdef[[
void GenerateParticles(float* particles, int particle_count, int width, int height);
]]
function love.load()
computer = love.graphics.newComputeShader([[
layout(std430) buffer;
struct Particle {
vec2 position;
vec2 velocity;
vec4 color;
};
buffer Particles {
Particle particles[];
};
uniform float dt;
uniform uint count;
layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
void computemain() {
uint index = love_GlobalThreadID.x;
// Since the total count isn't evenly divisible by local_size (threadgroup size),
// the last group launched will have more threads than we want.
if (index >= count)
return;
// Move
particles[index].position += particles[index].velocity * dt;
// Bounce
vec2 position = particles[index].position;
if (position.x < 0. || position.x > 800.) particles[index].velocity.x = -particles[index].velocity.x;
if (position.y < 0. || position.y > 600.) particles[index].velocity.y = -particles[index].velocity.y;
}
]])
renderer = love.graphics.newShader([[
#pragma language glsl4
layout(std430) buffer;
struct Particle {
vec2 position;
vec2 velocity;
vec4 color;
};
readonly buffer Particles {
Particle particles[];
};
#ifdef VERTEX
out vec4 vColor;
vec4 position(mat4 transform_projection, vec4 vertex_position) {
gl_PointSize = 2.;
uint index = love_VertexID;
vColor = particles[index].color;
return transform_projection * vec4(particles[index].position, 0., 1.);
}
#endif
#ifdef PIXEL
in vec4 vColor;
vec4 effect(vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords) {
return vColor;
}
#endif
]])
format = {
{ name = 'position', format = 'floatvec2' },
{ name = 'velocity', format = 'floatvec2' },
{ name = 'color', format = 'floatvec4' }
}
count = 10000000
particles = love.graphics.newBuffer(format, count, { shaderstorage = true })
computer:send('Particles', particles)
computer:send("count", count)
renderer:send('Particles', particles)
local width, height = love.graphics.getDimensions()
local data2 = love.data.newByteData(ffi.sizeof("float") * 8 * count)
local data_float_ptr = ffi.cast("float *", data2:getFFIPointer())
particles_lib.GenerateParticles(data_float_ptr, count, width, height)
particles:setArrayData(data2)
mesh = love.graphics.newMesh({{ name = 'VertexPosition', format = 'float' }}, count, 'points')
end
function love.update(dt)
computer:send('dt', dt)
local groupCount = math.ceil(count / computer:getLocalThreadgroupSize())
love.graphics.dispatchThreadgroups(computer, groupCount)
end
function love.draw()
love.graphics.setShader(renderer)
love.graphics.draw(mesh)
love.graphics.setShader()
love.graphics.print(count .. ' compute particles @' .. love.timer.getFPS() .. ' FPS')
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment