Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ jobs:
odin check directx/d3d11_minimal_sdl2 -target:windows_amd64 $FLAGS
odin check directx/d3d11_minimal_sdl3 -target:windows_amd64 $FLAGS
odin check opengl/compute_shader_glfw $FLAGS
odin check opengl/minimal_sdl2 $FLAGS
odin check vulkan/triangle_glfw $FLAGS
Expand Down
13 changes: 13 additions & 0 deletions opengl/compute_shader_glfw/glsl/compute.comp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#version 430 core

layout (local_size_x = 10, local_size_y = 10, local_size_z = 1) in;
layout(rgba32f, binding = 0) uniform image2D out_colorbuffer;

void main() {
vec4 color = vec4(0.0, 0.0, 0.0, 1.0);
ivec2 texel_coord = ivec2(gl_GlobalInvocationID.xy);
vec2 pos = vec2(float(texel_coord.x) / (gl_NumWorkGroups.x * gl_WorkGroupSize.x), float(texel_coord.y) / (gl_NumWorkGroups.y * gl_WorkGroupSize.y));
// NOTE: Do stuff here and then store the color in the colorbuffer
color.xy = pos; // <-- Replace this
imageStore(out_colorbuffer, texel_coord, color);
}
9 changes: 9 additions & 0 deletions opengl/compute_shader_glfw/glsl/screen.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#version 330 core

in vec2 vs_tex_coords;
out vec4 fs_color;
uniform sampler2D colorbuf_tex;

void main() {
fs_color = vec4(texture(colorbuf_tex, vs_tex_coords).rgb, 1.0);
}
9 changes: 9 additions & 0 deletions opengl/compute_shader_glfw/glsl/screen.vert
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#version 330 core

const vec4 coords[4] = vec4[4]( vec4(-1.0, -1.0, 0.0, 1.0), vec4( 1.0, -1.0, 1.0, 1.0), vec4( 1.0, 1.0, 1.0, 0.0), vec4(-1.0, 1.0, 0.0, 0.0) );
out vec2 vs_tex_coords;

void main() {
gl_Position = vec4(coords[gl_VertexID].xy, 0.0, 1.0);
vs_tex_coords = coords[gl_VertexID].zw;
}
178 changes: 178 additions & 0 deletions opengl/compute_shader_glfw/main.odin
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package main
import "core:log"
import "core:mem"
import "core:os"
import gl "vendor:OpenGL"
import "vendor:glfw"

WINDOW_TITLE :: "compute_shader_example"
GL_VERSION_MAJOR :: 4
GL_VERSION_MINOR :: 3
OPTION_VSYNC :: false
OPTION_ANTI_ALIAS :: false
OPTION_GAMMA_CORRECTION :: false
SHADER_SCREEN_VERT :: "./glsl/screen.vert"
SHADER_SCREEN_FRAG :: "./glsl/screen.frag"
SHADER_COMPUTE :: "./glsl/compute.comp"
WINDOW_WIDTH :: 1280
WINDOW_HEIGHT :: 720
COMPUTE_RENDER_WIDTH :: 1280
COMPUTE_RENDER_HEIGHT :: 720
BACKGROUND_COLOR :[3]f32: {0, 0, 0}

App :: struct {
window: glfw.WindowHandle,
colorbuf_tex: u32,
vao: u32,
vbo: u32,
sp_compute: u32,
sp_screen: u32,
}

main :: proc() {
// Tracking allocator and logger set up
context.logger = log.create_console_logger()
tracking_allocator: mem.Tracking_Allocator
mem.tracking_allocator_init(&tracking_allocator, context.allocator)
context.allocator = mem.tracking_allocator(&tracking_allocator)
defer {
for _, entry in tracking_allocator.allocation_map {
log.errorf("%v: Leaked %v bytes", entry.location, entry.size)
}
mem.tracking_allocator_destroy(&tracking_allocator)
}

// Program initialization
app := App{}
init(&app)

// Main Loop
for !glfw.WindowShouldClose(app.window) {
input(&app)
render(&app)
glfw.PollEvents()
free_all(context.temp_allocator)
}

// Exit the program
exit(&app)
}

gl_check_error :: proc(location := #caller_location) {
if err := gl.GetError(); err != gl.NO_ERROR {
log.errorf("OpenGL error! %s", gl.GL_Enum(err), location = location)
}
}

gl_shader_load_vs_fs :: proc(vs, fs: string) -> u32 {
sp, ok := gl.load_shaders_file(vs, fs)
if !ok {
log.errorf("Shader loading failed. (%s %s)", vs, fs)
os.exit(1)
}
return sp
}

gl_shader_load_cs :: proc(cs: string) -> u32 {
sp, ok := gl.load_compute_file(cs)
if !ok {
log.errorf("Shader loading failed (%s).", cs)
os.exit(1)
}
return sp
}

init :: proc(app: ^App) {
// GLFW and OpenGL initialization
glfw.Init()
glfw.WindowHint(glfw.CONTEXT_VERSION_MAJOR, GL_VERSION_MAJOR)
glfw.WindowHint(glfw.CONTEXT_VERSION_MINOR, GL_VERSION_MINOR)
glfw.WindowHint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)
glfw.WindowHint(glfw.RESIZABLE, glfw.FALSE)
glfw.WindowHint(glfw.DECORATED, glfw.TRUE)
if OPTION_ANTI_ALIAS {
glfw.WindowHint(glfw.SAMPLES, 4)
}
app.window = glfw.CreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE, nil, nil)
if app.window == nil {
log.errorf("GLFW window creation failed.")
glfw.Terminate()
os.exit(1)
}
glfw.MakeContextCurrent(app.window)
if !OPTION_VSYNC {
glfw.SwapInterval(0)
}
gl.load_up_to(GL_VERSION_MAJOR, GL_VERSION_MINOR, glfw.gl_set_proc_address)
gl.Viewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT)

// OpenGL settings
gl.Enable(gl.CULL_FACE)
gl.Enable(gl.LINE_SMOOTH)
gl.LineWidth(2)
gl.Enable(gl.BLEND)
gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
if OPTION_GAMMA_CORRECTION {
gl.Enable(gl.FRAMEBUFFER_SRGB)
}
if OPTION_ANTI_ALIAS {
gl.Enable(gl.MULTISAMPLE)
}

// Vertex array object & vertex buffer object setup
gl.GenVertexArrays(1, &app.vao)
gl.BindVertexArray(app.vao)
gl.GenBuffers(1, &app.vbo)
gl.BindBuffer(gl.ARRAY_BUFFER, app.vbo)

// Load shaders
app.sp_screen = gl_shader_load_vs_fs(SHADER_SCREEN_VERT, SHADER_SCREEN_FRAG)
app.sp_compute = gl_shader_load_cs(SHADER_COMPUTE)

// Colorbuffer texture setup
gl.GenTextures(1, &app.colorbuf_tex)
gl.ActiveTexture(gl.TEXTURE1)
gl.BindTexture(gl.TEXTURE_2D, app.colorbuf_tex)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA32F, COMPUTE_RENDER_WIDTH, COMPUTE_RENDER_HEIGHT, 0, gl.RGBA, gl.UNSIGNED_BYTE, nil)
gl.BindImageTexture(0, app.colorbuf_tex, 0, gl.FALSE, 0, gl.READ_ONLY, gl.RGBA32F)
gl.UseProgram(app.sp_screen)
gl.Uniform1i(gl.GetUniformLocation(app.sp_screen, "colorbuf_tex"), 1)
}

input :: proc(app: ^App) {
if glfw.GetKey(app.window, glfw.KEY_ESCAPE) == glfw.PRESS { glfw.SetWindowShouldClose(app.window, true) }
}

render :: proc(app: ^App) {
// Clear screen
gl.ClearColor(BACKGROUND_COLOR.r, BACKGROUND_COLOR.g, BACKGROUND_COLOR.b, 1.0)
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
gl.BindVertexArray(app.vao)

// Run compute shader to generate colorbuffer and depthbuffer
gl.UseProgram(app.sp_compute)
gl.DispatchCompute(COMPUTE_RENDER_WIDTH/10, COMPUTE_RENDER_WIDTH/10, 1)
gl.MemoryBarrier(gl.SHADER_IMAGE_ACCESS_BARRIER_BIT)

// Run screen shader to draw the colorbuffer to the framebuffer
gl.Enable(gl.DEPTH_TEST)
gl.UseProgram(app.sp_screen)
gl.DrawArrays(gl.TRIANGLE_FAN, 0, 4)

// Swap buffers (present the framebuffer)
glfw.SwapBuffers(app.window)
gl_check_error()
}

exit :: proc(app: ^App) {
gl.DeleteProgram(app.sp_screen)
gl.DeleteProgram(app.sp_compute)
gl.DeleteVertexArrays(1, &app.vao)
gl.DeleteBuffers(1, &app.vbo)
gl.DeleteTextures(1, &app.colorbuf_tex)
glfw.Terminate()
}