Skip to content

Commit

Permalink
Update to newest bindings
Browse files Browse the repository at this point in the history
  • Loading branch information
SogoCZE committed Aug 12, 2024
0 parents commit b906e79
Show file tree
Hide file tree
Showing 17 changed files with 2,835 additions and 0 deletions.
Binary file added .DS_Store
Binary file not shown.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "wgpu/wgpu-native"]
path = wgpu/wgpu-native
url = https://github.com/gfx-rs/wgpu-native
Binary file added examples/.DS_Store
Binary file not shown.
Binary file added examples/hello_triangle/.DS_Store
Binary file not shown.
2 changes: 2 additions & 0 deletions examples/hello_triangle/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.build
bin
232 changes: 232 additions & 0 deletions examples/hello_triangle/helpers.jai
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
print_c :: (format: string, args: ..Any, to_standard_error := false) #expand {
new_context: Context;
push_context new_context {
print(format, ..args, to_standard_error);
}
} @PrintLike

request_adapter :: (instance: wgpu.Instance, surface: wgpu.Surface, powerPreference: wgpu.PowerPreference, forceFallbackAdapter := false) -> wgpu.Adapter {
adapter: wgpu.Adapter;

request_adapter_options := wgpu.RequestAdapterOptions.{
compatibleSurface = surface,
powerPreference = powerPreference,
forceFallbackAdapter = forceFallbackAdapter,
};

wgpu.InstanceRequestAdapter(instance, *request_adapter_options, (status: wgpu.RequestAdapterStatus, adapter: wgpu.Adapter, message: *u8, user_data: *void) #c_call {
if status != .Success {
print_c("%\n", message);
return;
};

<< cast(*wgpu.Adapter) user_data = adapter;
}, *adapter);

return adapter;
}

create_surface :: (instance: wgpu.Instance, window: *SDL_Window, label := "Main Surface") -> wgpu.Surface {
surface_desc: wgpu.SurfaceDescriptor;
surface_desc.label = to_c_string(label);

#if OS == .WINDOWS {
sdl_info: SDL_SysWMinfo;
assert(xx SDL_GetWindowWMInfo(window, *sdl_info), "Cannot get SDL info!\n");

surface_desc_from_windows_hwnd: wgpu.SurfaceDescriptorFromWindowsHWND;
surface_desc_from_windows_hwnd.chain.sType = .SurfaceDescriptorFromWindowsHWND;
surface_desc_from_windows_hwnd.hwnd = sdl_info.info.win.window;

surface_desc.nextInChain = xx *surface_desc_from_windows_hwnd;
}

#if OS == .MACOS {
metal_view := SDL_Metal_CreateView(window);
metal_layer := SDL_Metal_GetLayer(metal_view);

surface_desc_from_metal_layer: wgpu.SurfaceDescriptorFromMetalLayer;
surface_desc_from_metal_layer.layer = metal_layer;
surface_desc_from_metal_layer.chain.sType = .SurfaceDescriptorFromMetalLayer;

surface_desc.nextInChain = xx *surface_desc_from_metal_layer;
}

#if OS == .LINUX #assert false "LINUX IS NOT SUPPORTED RIGHT NOW.";

surface := wgpu.InstanceCreateSurface(instance, *surface_desc);

return surface;
}

request_device :: (adapter: wgpu.Adapter) -> wgpu.Device {
device_descriptor: wgpu.DeviceDescriptor;
device: wgpu.Device;

wgpu.AdapterRequestDevice(adapter, *device_descriptor, (status: wgpu.RequestDeviceStatus, device: wgpu.Device, message: *u8, user_data: *void) #c_call {
if status != .Success {
print_c("Status: %, Device: %, Message: %", status, device, to_string(message));
return;
}

(cast(*wgpu.Device) user_data).* = device;
}, *device);
assert(device != null, "GPU Device is not created correctly");

return device;
}

create_shader :: (device: wgpu.Device, source: string, label := "Main shader") -> wgpu.ShaderModule {
wgslDescriptor: wgpu.ShaderModuleWGSLDescriptor;
wgslDescriptor.chain.next = null;
wgslDescriptor.chain.sType=.ShaderModuleWGSLDescriptor;
wgslDescriptor.code = to_c_string(source);

shaderModuleDescriptor: wgpu.ShaderModuleDescriptor;
shaderModuleDescriptor.label = to_c_string(label);
shaderModuleDescriptor.nextInChain = xx *wgslDescriptor;

return wgpu.DeviceCreateShaderModule(device, *shaderModuleDescriptor);
}

make_vertex_layout :: ($type: Type) -> wgpu.VertexBufferLayout {
info := type_info(type);

vertex_buffer_layout := wgpu.VertexBufferLayout.{
arrayStride=size_of(type),
stepMode=.Vertex,
};

vertex_attributes := NewArray(info.members.count, wgpu.VertexAttribute);

for info.members {
vertex_attribute: wgpu.VertexAttribute;

if it.type.type == {
case .BOOL;
vertex_attribute.format = .Sint32;

case .INTEGER;
int_type_info := cast(*Type_Info_Integer) it.type;

if int_type_info.signed {
vertex_attribute.format = .Sint32;
} else {
vertex_attribute.format = .Uint32;
}

case .FLOAT;
assert(it.type.runtime_size <= 4, "Only float32 is supported in Vertex Attribute Data.");
vertex_attribute.format = .Float32;

case .STRUCT;
struct_type_info := cast(*Type_Info_Struct) it.type;

if struct_type_info.name == {
case "Vector4";
vertex_attribute.format = .Float32x4;
case "Vector3";
vertex_attribute.format = .Float32x3;
case "Vector2";
vertex_attribute.format = .Float32x2;
case;
assert(false, "Unsupported struct type. Only Vector2, Vector3, Vector4 are supported");
}

}

vertex_attribute.offset= xx it.offset_in_bytes;
vertex_attribute.shaderLocation= xx it_index;

vertex_attributes[it_index] = vertex_attribute;
}

vertex_buffer_layout.attributeCount = xx vertex_attributes.count;
vertex_buffer_layout.attributes = vertex_attributes.data;

return vertex_buffer_layout;
}

create_pipeline :: (surface: wgpu.Surface, adapter: wgpu.Adapter, device: wgpu.Device, shader: wgpu.ShaderModule, $vertex_buffer_layout_type: Type) -> wgpu.RenderPipeline {
surface_capabilities: wgpu.SurfaceCapabilities;
wgpu.SurfaceGetCapabilities(surface, adapter, *surface_capabilities);

preferred_texture_format := surface_capabilities.formats[0];

pipeline_descriptor: wgpu.RenderPipelineDescriptor;
pipeline_descriptor.label = "Render Pipeline";

pipeline_layout_descriptor: wgpu.PipelineLayoutDescriptor;

pipeline_descriptor.layout = wgpu.DeviceCreatePipelineLayout(device, *pipeline_layout_descriptor);

vertex_state: wgpu.VertexState;
vertex_state.module = shader;
vertex_state.entryPoint = "vertex";
vertex_state.bufferCount = 1;
vertex_state.buffers = *make_vertex_layout(vertex_buffer_layout_type);

pipeline_descriptor.vertex = vertex_state;

pipeline_descriptor.primitive = .{
topology=.TriangleList,
stripIndexFormat=.Undefined,
frontFace=.CCW,
cullMode=.None,
};

pipeline_descriptor.multisample = .{
count = 1,
mask = 1,
alphaToCoverageEnabled = false,
};

color_target_state: wgpu.ColorTargetState;
color_target_state.format = preferred_texture_format;
color_target_state.blend = *(wgpu.BlendState.{
color = .{ srcFactor = .One, dstFactor = .Zero, operation = .Add },
alpha = .{ srcFactor = .One, dstFactor = .Zero, operation = .Add },
});
color_target_state.writeMask = xx wgpu.ColorWriteMask.All;

fragment_state: wgpu.FragmentState;
fragment_state.module = shader;
fragment_state.entryPoint = "fragment";
fragment_state.targetCount = 1;
fragment_state.targets = *color_target_state;

pipeline_descriptor.fragment = *fragment_state;

pipeline_descriptor.depthStencil = null;

return wgpu.DeviceCreateRenderPipeline(device, *pipeline_descriptor);
}

configure_surface :: (surface: wgpu.Surface, adapter: wgpu.Adapter, device: wgpu.Device, width: int, height: int) {
surface_capabilities: wgpu.SurfaceCapabilities;
wgpu.SurfaceGetCapabilities(surface, adapter, *surface_capabilities);

surface_config := wgpu.SurfaceConfiguration.{
device=device,
usage=xx wgpu.TextureUsage.RenderAttachment,
format=surface_capabilities.formats[0],
width=xx width,
height=xx height,
presentMode=.Fifo
};
wgpu.SurfaceConfigure(surface, *surface_config);
}

vertex_array_to_buffer :: (device: wgpu.Device, queue: wgpu.Queue, vertices: []Vertex) -> wgpu.Buffer, u64 {
size := cast(u64) vertices.count * size_of(Vertex);

buffer := wgpu.DeviceCreateBuffer(device, *(wgpu.BufferDescriptor.{
usage = xx (wgpu.BufferUsage.Vertex | wgpu.BufferUsage.CopyDst),
size=size
}));
assert(buffer != null, "Buffer is not created correctly");

wgpu.QueueWriteBuffer(queue, buffer, 0, vertices.data, size);

return buffer, size;
}
152 changes: 152 additions & 0 deletions examples/hello_triangle/main.jai
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
#import "Basic";
#import "SDL";
#import "Math";
wgpu :: #import,file "../../wgpu/module.jai"; // in normal project with modules folder you would just use `#import "wgpu"`

#load "helpers.jai";

WINDOW_WIDTH :: 1280;
WINDOW_HEIGHT :: 720;

wgpu_log_callback :: (level: wgpu.LogLevel, msg: *u8, userdata: *void) #c_call {
print_c("[WGPU :: %]: %\n", level, to_string(msg));
}

Vertex :: struct {
position: Vector3;
color: Vector3;
}

SHADER :: #string WGSL
struct VertexInput {
@location(0) position: vec3<f32>,
@location(1) color: vec3<f32>,
};

struct VertexOutput {
@builtin(position) clip_position: vec4<f32>,
@location(0) color: vec3<f32>,
};

@vertex
fn vertex(model: VertexInput) -> VertexOutput {
var out: VertexOutput;
out.clip_position = vec4<f32>(model.position, 1.0);
out.color = model.color;
return out;
}

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
return vec4<f32>(in.color, 1.0);
}
WGSL;

VERTICES :: Vertex.[
.{ position=.{0.0, 0.5, 0.0}, color=.{1.0, 0.0, 0.0} },
.{ position=.{-0.5, -0.5, 0.0}, color=.{0.0, 1.0, 0.0} },
.{ position=.{0.5, -0.5, 0.0}, color=.{0.0, 0.0, 1.0} },
];

main :: () {
SDL_Init(SDL_INIT_VIDEO);

window := SDL_CreateWindow("Jai WebGPU Hello Triangle", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_ALLOW_HIGHDPI);
assert(window != null, "Could not create window: %\n", to_string(SDL_GetError()));

wgpu.SetLogCallback(wgpu_log_callback, null);
wgpu.SetLogLevel(.Error);

instance_desc: wgpu.InstanceDescriptor;
instance := wgpu.CreateInstance(*instance_desc);
assert(instance != null, "Instance is not created correctly");

surface := create_surface(instance, window);
assert(surface != null, "Surface is not created correctly");

adapter := request_adapter(instance, surface, powerPreference = .HighPerformance);
assert(adapter != null, "Adapter is not created correctly");

device := request_device(adapter);
assert(device != null, "Device is not created correctly");

queue := wgpu.DeviceGetQueue(device);
assert(queue != null, "Queue is not created correctly");

shader := create_shader(device, SHADER);
assert(shader != null, "Shader is not created correctly");

vertex_buffer, vertex_buffer_size := vertex_array_to_buffer(device, queue, VERTICES);

pipeline := create_pipeline(surface, adapter, device, shader, Vertex);
assert(pipeline != null, "Pipeline is not created correctly");

configure_surface(surface, adapter, device, WINDOW_WIDTH, WINDOW_HEIGHT);

wgpu.QueueSubmit(queue, 0, null);

exit := false;
while !exit {
event: SDL_Event;
while SDL_PollEvent(*event) {
if event.type == SDL_QUIT {
exit = true;
}
}

surface_texture: wgpu.SurfaceTexture;
wgpu.SurfaceGetCurrentTexture(surface, *surface_texture);
display_view := wgpu.TextureCreateView(surface_texture.texture, null);

cmd_encoder := wgpu.DeviceCreateCommandEncoder(
device,
*(wgpu.CommandEncoderDescriptor.{label = "Main Command Encoder"}),
);

colorAttachment := wgpu.RenderPassColorAttachment.{
loadOp = wgpu.LoadOp.Clear,
storeOp = wgpu.StoreOp.Store,
clearValue = wgpu.Color.{0.0, 0.0, 0.0, 1.0},
};

colorAttachment.view = display_view;

render_pass_descriptor := wgpu.RenderPassDescriptor.{ label = "Main Render Pass" };
render_pass_descriptor.colorAttachmentCount = 1;
render_pass_descriptor.colorAttachments = *colorAttachment;

render_pass := wgpu.CommandEncoderBeginRenderPass(cmd_encoder, *render_pass_descriptor);

wgpu.RenderPassEncoderSetPipeline(render_pass, pipeline);
wgpu.RenderPassEncoderSetVertexBuffer(render_pass, 0, vertex_buffer, 0, vertex_buffer_size);

wgpu.RenderPassEncoderDraw(render_pass, VERTICES.count, 1, 0, 0);
wgpu.RenderPassEncoderEnd(render_pass);
wgpu.TextureViewRelease(display_view);

cmd_buffer := wgpu.CommandEncoderFinish(cmd_encoder, *(wgpu.CommandBufferDescriptor.{label = "Main Command Buffer"}));

wgpu.QueueSubmit(queue, 1, *cmd_buffer);

wgpu.SurfacePresent(surface);
}

// Close and destroy the window
SDL_DestroyWindow(window);

// Clean up
SDL_Quit();
}

// Build
#run {
#import "Compiler";
#import "File";

make_directory_if_it_does_not_exist("./bin/");

set_build_options_dc(.{
output_executable_name = "hello_triangle",
output_path = "./bin/"
});
}
Loading

0 comments on commit b906e79

Please sign in to comment.