diff options
Diffstat (limited to 'demos/compute')
| -rw-r--r-- | demos/compute/rend_compute.c | 226 | ||||
| -rw-r--r-- | demos/compute/rend_compute.slang | 146 | ||||
| -rwxr-xr-x | demos/compute/rend_compute_demo | bin | 446416 -> 434248 bytes | |||
| -rwxr-xr-x | demos/compute/rend_compute_fast | bin | 474256 -> 0 bytes |
4 files changed, 372 insertions, 0 deletions
diff --git a/demos/compute/rend_compute.c b/demos/compute/rend_compute.c new file mode 100644 index 0000000..37ee207 --- /dev/null +++ b/demos/compute/rend_compute.c @@ -0,0 +1,226 @@ +#define PEAK_IMPLEMENTATION +#include "../Rend/rend.h" +#include "../Rend/rend.c" +#include <stddef.h> +#include <string.h> + +#define malloc(size) peak_debug_malloc_impl((size), __FILE__, __LINE__, __func__) +#define realloc(ptr, size) peak_debug_realloc_impl((ptr), (size), __FILE__, __LINE__, __func__) +#define free(ptr) peak_debug_free_impl((ptr), __FILE__, __LINE__, __func__) + +float delta = 0; +PeakWindow win; +PeakEvent ev; + +bool vsync = true; + +#define PARTICLE_COUNT 1024 * 10 +#define GRID_WIDTH 512 +#define GRID_HEIGHT 512 + +typedef struct { + uint64_t particles; + uint64_t src_grid; + uint64_t dst_grid; + uint32_t particle_count; + uint32_t width; + uint32_t height; + float delta_time; + uint32_t render_mode; +} PushConstants; + +typedef struct Particle { + float pos[2]; + float vel[2]; +} Particle; + +uint32_t pcg_hash(uint32_t seed) { + uint32_t state = seed * 747796405u + 2891336453u; + uint32_t word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; + return (word >> 22u) ^ word; +} + +float cool_beans(uint32_t *seed) { + *seed = pcg_hash(*seed); + return (float) *seed / 4294967295.0; +} + +static uint8_t * +load_spv(const char *a, const char *b, unsigned long *size) +{ + uint8_t *p = peak_file_alloc(a, size); + if (p) return p; + return peak_file_alloc(b, size); +} + +int main() { + + if (!peak_init()) { + PFATAL("Failed to init Peak!"); + return 1; + } + + win = peak_window_open("demo", 800, 600, 0); + if (!win.running) { + PFATAL("Failed to open a window!"); + return 1; + } + + // bindless setup + RendBindingInfo bind_info = {0}; + RendRenderer renderer = rend_renderer_create(&win, REND_BACKEND_AUTO, NULL, vsync, &bind_info); + if (!renderer) { + PFATAL("Failed to create renderer!"); + peak_window_close(&win); + peak_quit(); + return 1; + } + + unsigned long particles_bytes = 0; + uint8_t *particles_shader = load_spv("particle.spv", "demos/compute/particle.spv", &particles_bytes); + + unsigned long sand_bytes = 0; + uint8_t *sand_shader = load_spv("sand.spv", "demos/compute/sand.spv", &sand_bytes); + + unsigned long vert_size = 0; + uint8_t *vert = load_spv("vert.spv", "demos/compute/vert.spv", &vert_size); + + unsigned long frag_size = 0; + uint8_t *frag = load_spv("frag.spv", "demos/compute/frag.spv", &frag_size); + + uint32_t seed = 0xC0FFEE; + + Particle *initial_particles = malloc(PARTICLE_COUNT * sizeof *initial_particles); + for (int i = 0; i < PARTICLE_COUNT; i++) { + initial_particles[i].pos[0] = cool_beans(&seed) * 2.0f - 1.0f; + initial_particles[i].pos[1] = cool_beans(&seed) * 2.0f - 1.0f; + initial_particles[i].vel[0] = cool_beans(&seed) * 0.4f - 0.2f; + initial_particles[i].vel[1] = cool_beans(&seed) * 0.4f - 0.2f; + } + + size_t buffer_size = PARTICLE_COUNT * sizeof(Particle); + RendBuffer particle_buf = rend_buffer_create(renderer, buffer_size, REND_BUFFER_STORAGE, true); + rend_buffer_write(renderer, &particle_buf, initial_particles, buffer_size, 0); + + size_t grid_buffer_size = GRID_WIDTH * GRID_HEIGHT * sizeof(uint32_t); + uint32_t *initial_grid = calloc(GRID_WIDTH * GRID_HEIGHT, sizeof(uint32_t)); + + for (int y = 0; y < 100; y++) { + for (int x = 150; x < 362; x++) { + initial_grid[y * GRID_WIDTH + x] = 1; // 1 = sand + } + } + + RendBuffer src_buf = rend_buffer_create(renderer, GRID_WIDTH * GRID_HEIGHT * sizeof(uint32_t), REND_BUFFER_STORAGE, false); + RendBuffer dst_buf = rend_buffer_create(renderer, GRID_WIDTH * GRID_HEIGHT * sizeof(uint32_t), REND_BUFFER_STORAGE, false); + rend_buffer_write(renderer, &src_buf, initial_grid, grid_buffer_size, 0); + rend_buffer_write(renderer, &dst_buf, initial_grid, grid_buffer_size, 0); + + uint64_t particles_address = rend_buffer_address(&particle_buf); + + RendBuffer *src_grid = &src_buf; + RendBuffer *dst_grid = &dst_buf; + + RendPushConstantInfo pc = { .offset = 0, .size = sizeof(PushConstants) }; + RendPipeline particle_compute = rend_pipeline_create_compute_spirv(renderer, particles_shader, particles_bytes, &pc, 1); + RendPipeline sand_compute = rend_pipeline_create_compute_spirv(renderer, sand_shader, sand_bytes, &pc, 1); + free(particles_shader); + free(sand_shader); + + RendPipeline graphics_pipeline = rend_pipeline_create_graphics_bindless_spirv(renderer, vert, vert_size, frag, frag_size, &pc, 1, REND_POLYGON_MODE_FILL, REND_CULL_MODE_NONE, REND_TOPOLOGY_TRIANGLE_LIST, 0, true); + + free(vert); + free(frag); + + float dt = 1.0f / 60.0f; + uint64_t dt_ns = (uint64_t) (dt * NANOS_PER_SEC); + + uint32_t mode = 2; + while (mode > 0) { + + uint64_t start = peak_get_time(); + + PeakEvent ev; + while (peak_window_epoll(&win, &ev)) { + if (ev.type == PEAK_EVENT_WINDOW_CLOSE) { + mode -= 1; + break; + } + } + + if (rend_renderer_frame_begin(renderer)) { + + PushConstants pc = {0}; + + if (mode == 2) { + /* + * Sand Simulation + */ + pc.delta_time = dt; + pc.width = GRID_WIDTH; + pc.height = GRID_HEIGHT; + pc.render_mode = 1; + pc.src_grid = src_grid->gpu_address; + pc.dst_grid = dst_grid->gpu_address; + + rend_pipeline_bind(sand_compute); + rend_pipeline_push_constants(sand_compute, &pc, sizeof(pc)); + + uint32_t x = (GRID_WIDTH + 15) / 16; + uint32_t y = (GRID_HEIGHT + 15) / 16; + rend_pipeline_dispatch(sand_compute, x, y, 1); + + RendBuffer *temp = src_grid; + src_grid = dst_grid; + dst_grid = temp; + + memset(src_grid->mapped_memory, 0, grid_buffer_size); + + } else { + /* + * Particles Simulation + */ + pc.particles = particles_address; + pc.delta_time = dt; + pc.particle_count = PARTICLE_COUNT; + pc.render_mode = 0; + + rend_pipeline_bind(particle_compute); + rend_pipeline_push_constants(particle_compute, &pc, sizeof(pc)); + rend_pipeline_dispatch(particle_compute, (PARTICLE_COUNT + 255) / 256, 1, 1); + } + + rend_renderer_render_pass_begin(renderer, 0.5f, 0.5f, 0.5f, 0.0f); { + rend_pipeline_bind(graphics_pipeline); + rend_pipeline_push_constants(graphics_pipeline, &pc, sizeof(pc)); + + uint32_t vertex_count = (mode == 2) ? (6 * GRID_WIDTH * GRID_HEIGHT) : (6 * PARTICLE_COUNT); + rend_pipeline_draw(graphics_pipeline, vertex_count, 1); + + } rend_renderer_render_pass_end(renderer); + + rend_renderer_frame_end(renderer, NULL); + } + + uint64_t delta_ns = peak_get_time() - start; + if (delta_ns < dt_ns) { + peak_sleep_ns(dt_ns - delta_ns); + } + } + + free(initial_particles); + free(initial_grid); + + rend_buffer_destroy(&particle_buf); + rend_buffer_destroy(&src_buf); + rend_buffer_destroy(&dst_buf); + + rend_renderer_destroy(renderer); + // rend_quit(); + + peak_window_close(&win); + peak_quit(); + + peak_debug_memory_report(); + return 0; +} diff --git a/demos/compute/rend_compute.slang b/demos/compute/rend_compute.slang new file mode 100644 index 0000000..5fb124b --- /dev/null +++ b/demos/compute/rend_compute.slang @@ -0,0 +1,146 @@ +struct Particle { + float2 position; + float2 velocity; +}; + +struct PushConstants { + Particle* particles; + uint* srcGrid; + uint* dstGrid; + uint particleCount; + uint width; + uint height; + float deltaTime; + uint renderMode; // 0 = particles, 1 = sand +}; + +struct VSOutput { + float4 position : SV_Position; + float4 color : COLOR0; +}; + +[[vk::push_constant]] +PushConstants pc; + +uint getIndex(uint x, uint y) { + return y * pc.width + x; +} + +bool isEmpty(uint x, uint y) { + if (x >= pc.width || y >= pc.height) return false; + return pc.srcGrid[getIndex(x, y)] == 0; +} + +[shader("compute")] +[numthreads(256, 1, 1)] +void particleMain(uint3 threadId : SV_DispatchThreadID) { + uint index = threadId.x; + if (index >= pc.particleCount) return; + + Particle p = pc.particles[index]; + + p.position += p.velocity * pc.deltaTime; + p.velocity *= exp(-0.005 * pc.deltaTime); + + pc.particles[index] = p; +} + +[shader("compute")] +[numthreads(16, 16, 1)] +void sandMain(uint3 threadId : SV_DispatchThreadID) { + uint x = threadId.x; + uint y = threadId.y; + + if (x >= pc.width || y >= pc.height) return; + + uint currentIdx = getIndex(x, y); + uint cellState = pc.srcGrid[currentIdx]; + + if (cellState == 1) { // Sand + if (y + 1 < pc.height && isEmpty(x, y + 1)) { + pc.dstGrid[getIndex(x, y + 1)] = 1; + pc.dstGrid[currentIdx] = 0; + return; + } + + bool fallLeftFirst = ((x + y) % 2) == 0; + int dir1 = fallLeftFirst ? -1 : 1; + int dir2 = fallLeftFirst ? 1 : -1; + + if (y + 1 < pc.height && isEmpty(x + dir1, y + 1)) { + pc.dstGrid[getIndex(x + dir1, y + 1)] = 1; + pc.dstGrid[currentIdx] = 0; + return; + } + else if (y + 1 < pc.height && isEmpty(x + dir2, y + 1)) { + pc.dstGrid[getIndex(x + dir2, y + 1)] = 1; + pc.dstGrid[currentIdx] = 0; + return; + } + + pc.dstGrid[currentIdx] = 1; + } +} + +static const float2 QUAD_OFFSETS[6] = { + float2(-0.5, -0.5), float2( 0.5, -0.5), float2(-0.5, 0.5), + float2(-0.5, 0.5), float2( 0.5, -0.5), float2( 0.5, 0.5) +}; + +float3 cosinePalette(float t, float3 a, float3 b, float3 c, float3 d) { + return a + b * cos(6.28318 * (c * t + d)); +} + +[shader("vertex")] +VSOutput vertMain(uint vertexID : SV_VertexID) { + VSOutput output; + + uint elementIdx = vertexID / 6; + uint cornerIdx = vertexID % 6; + + float2 worldPos = float2(0.0, 0.0); + float3 color = float3(0.0, 0.0, 0.0); + + if (pc.renderMode == 0) { + Particle p = pc.particles[elementIdx]; + worldPos = p.position; + + float speed = length(p.velocity); + color = cosinePalette( + speed * 0.8, + float3(0.5, 0.5, 0.5), + float3(0.5, 0.5, 0.5), + float3(1.0, 1.0, 1.0), + float3(0.0, 0.33, 0.67) + ); + } + + else { + uint x = elementIdx % pc.width; + uint y = elementIdx / pc.width; + + uint cellState = pc.srcGrid[elementIdx]; + + if (cellState == 0) { + output.position = float4(0, 0, 0, 0); + output.color = float4(0, 0, 0, 0); + return output; + } + + worldPos.x = ((float)x / (float)pc.width) * 2.0 - 1.0; + worldPos.y = ((float)y / (float)pc.height) * 2.0 - 1.0; + + color = float3(0.94, 0.82, 0.53); + } + + float2 quadOffset = QUAD_OFFSETS[cornerIdx] * 0.01; + output.position = float4(worldPos + quadOffset, 0.0, 1.0); + output.color = float4(color, 1.0); + + return output; +} + +[shader("fragment")] +float4 fragMain(VSOutput input) : SV_Target { + return input.color; +} diff --git a/demos/compute/rend_compute_demo b/demos/compute/rend_compute_demo Binary files differindex 1aecc00..46734c6 100755 --- a/demos/compute/rend_compute_demo +++ b/demos/compute/rend_compute_demo diff --git a/demos/compute/rend_compute_fast b/demos/compute/rend_compute_fast Binary files differdeleted file mode 100755 index d9583f6..0000000 --- a/demos/compute/rend_compute_fast +++ /dev/null |
