diff --git a/build.zig b/build.zig index f94630f..bb37cd5 100644 --- a/build.zig +++ b/build.zig @@ -15,7 +15,7 @@ pub const ResourceGenStep = struct { const self = builder.allocator.create(ResourceGenStep) catch unreachable; self.* = .{ .step = Step.init(.Custom, "resources", builder.allocator, make), - .shader_step = vkgen.ShaderCompileStep.init(builder, "glslc"), + .shader_step = vkgen.ShaderCompileStep.init(builder, &[_][]const u8{"glslc", "--target-env=vulkan1.2"}), .builder = builder, .full_out_path = path.join(builder.allocator, &[_][]const u8{ self.builder.build_root, @@ -32,7 +32,7 @@ pub const ResourceGenStep = struct { pub fn addShader(self: *ResourceGenStep, name: []const u8, source: []const u8) void { self.resources.writer().print( "pub const {} = @embedFile(\"{}\");\n", - .{name, self.shader_step.add("examples/shaders/test.frag")} + .{name, self.shader_step.add(source)} ) catch unreachable; } @@ -64,7 +64,8 @@ pub fn build(b: *Builder) void { example_exe.addPackagePath("vulkan", gen.full_out_path); const res = ResourceGenStep.init(b, "resources.zig"); - res.addShader("test_frag", "examples/shaders/test.frag"); + res.addShader("triangle_vert", "examples/shaders/triangle.vert"); + res.addShader("triangle_frag", "examples/shaders/triangle.frag"); example_exe.step.dependOn(&res.step); example_exe.addPackagePath("resources", res.full_out_path); diff --git a/examples/graphics_context.zig b/examples/graphics_context.zig index d3953d4..6111f4a 100644 --- a/examples/graphics_context.zig +++ b/examples/graphics_context.zig @@ -55,6 +55,14 @@ const DeviceDispatch = struct { vkEndCommandBuffer: vk.PfnEndCommandBuffer, vkQueueWaitIdle: vk.PfnQueueWaitIdle, vkCmdPipelineBarrier: vk.PfnCmdPipelineBarrier, + vkCreateShaderModule: vk.PfnCreateShaderModule, + vkDestroyShaderModule: vk.PfnDestroyShaderModule, + vkCreatePipelineLayout: vk.PfnCreatePipelineLayout, + vkDestroyPipelineLayout: vk.PfnDestroyPipelineLayout, + vkCreateRenderPass: vk.PfnCreateRenderPass, + vkDestroyRenderPass: vk.PfnDestroyRenderPass, + vkCreateGraphicsPipelines: vk.PfnCreateGraphicsPipelines, + vkDestroyPipeline: vk.PfnDestroyPipeline, usingnamespace vk.DeviceWrapper(@This()); }; diff --git a/examples/main.zig b/examples/main.zig index 729a5dc..811501d 100644 --- a/examples/main.zig +++ b/examples/main.zig @@ -12,12 +12,12 @@ pub fn main() !void { if (c.glfwInit() != c.GLFW_TRUE) return error.GlfwInitFailed; defer c.glfwTerminate(); - const extent = vk.Extent2D{.width = 800, .height = 600}; + var extent = vk.Extent2D{.width = 800, .height = 600}; c.glfwWindowHint(c.GLFW_CLIENT_API, c.GLFW_NO_API); const window = c.glfwCreateWindow( - extent.width, - extent.height, + @intCast(c_int, extent.width), + @intCast(c_int, extent.height), app_name, null, null @@ -34,6 +34,21 @@ pub fn main() !void { var swapchain = try Swapchain.init(&gc, allocator, extent); defer swapchain.deinit(); + const pipeline_layout = try gc.vkd.createPipelineLayout(gc.dev, .{ + .flags = .{}, + .set_layout_count = 0, + .p_set_layouts = undefined, + .push_constant_range_count = 0, + .p_push_constant_ranges = undefined, + }, null); + defer gc.vkd.destroyPipelineLayout(gc.dev, pipeline_layout, null); + + const render_pass = try createRenderPass(&gc, &swapchain); + defer gc.vkd.destroyRenderPass(gc.dev, render_pass, null); + + const pipeline = try createPipeline(&gc, extent, pipeline_layout, render_pass); + defer gc.vkd.destroyPipeline(gc.dev, pipeline, null); + const pool = try gc.vkd.createCommandPool(gc.dev, .{ .flags = .{}, .queue_family_index = gc.graphics_queue.family, @@ -55,8 +70,9 @@ pub fn main() !void { var w: c_int = undefined; var h: c_int = undefined; c.glfwGetWindowSize(window, &w, &h); - - try swapchain.recreate(.{.width = @intCast(u32, w), .height = @intCast(u32, h)}); + extent.width = @intCast(u32, w); + extent.height = @intCast(u32, h); + try swapchain.recreate(extent); destroyCommandBuffers(&gc, pool, allocator, cmdbufs); cmdbufs = try createCommandBuffers(&gc, pool, allocator, swapchain); @@ -141,6 +157,203 @@ fn destroyCommandBuffers(gc: *const GraphicsContext, pool: vk.CommandPool, alloc allocator.free(cmdbufs); } +fn createRenderPass(gc: *const GraphicsContext, swapchain: *const Swapchain) !vk.RenderPass { + const color_attachment = vk.AttachmentDescription{ + .flags = .{}, + .format = swapchain.surface_format.format, + .samples = .{.@"1_bit" = true}, + .load_op = .clear, + .store_op = .store, + .stencil_load_op = .dont_care, + .stencil_store_op = .dont_care, + .initial_layout = .@"undefined", + .final_layout = .present_src_khr, + }; + + const color_attachment_ref = vk.AttachmentReference{ + .attachment = 0, + .layout = .color_attachment_optimal, + }; + + const subpass = vk.SubpassDescription{ + .flags = .{}, + .pipeline_bind_point = .graphics, + .input_attachment_count = 0, + .p_input_attachments = undefined, + .color_attachment_count = 1, + .p_color_attachments = @ptrCast([*]const vk.AttachmentReference, &color_attachment_ref), + .p_resolve_attachments = null, + .p_depth_stencil_attachment = null, + .preserve_attachment_count = 0, + .p_preserve_attachments = undefined, + }; + + return try gc.vkd.createRenderPass(gc.dev, .{ + .flags = .{}, + .attachment_count = 1, + .p_attachments = @ptrCast([*]const vk.AttachmentDescription, &color_attachment), + .subpass_count = 1, + .p_subpasses = @ptrCast([*]const vk.SubpassDescription, &subpass), + .dependency_count = 0, + .p_dependencies = undefined, + }, null); +} + +fn createPipeline( + gc: *const GraphicsContext, + extent: vk.Extent2D, + layout: vk.PipelineLayout, + render_pass: vk.RenderPass, +) !vk.Pipeline { + const vert = try gc.vkd.createShaderModule(gc.dev, .{ + .flags = .{}, + .code_size = resources.triangle_vert.len, + .p_code = @ptrCast([*]const u32, resources.triangle_vert), + }, null); + defer gc.vkd.destroyShaderModule(gc.dev, vert, null); + + const frag = try gc.vkd.createShaderModule(gc.dev, .{ + .flags = .{}, + .code_size = resources.triangle_frag.len, + .p_code = @ptrCast([*]const u32, resources.triangle_frag), + }, null); + defer gc.vkd.destroyShaderModule(gc.dev, frag, null); + + const pssci = [_]vk.PipelineShaderStageCreateInfo{ + .{ + .flags = .{}, + .stage = .{.vertex_bit = true}, + .module = vert, + .p_name = "main", + .p_specialization_info = null, + }, + .{ + .flags = .{}, + .stage = .{.fragment_bit = true}, + .module = frag, + .p_name = "main", + .p_specialization_info = null, + }, + }; + + const pvisci = vk.PipelineVertexInputStateCreateInfo{ + .flags = .{}, + .vertex_binding_description_count = 0, + .p_vertex_binding_descriptions = undefined, + .vertex_attribute_description_count = 0, + .p_vertex_attribute_descriptions = undefined, + }; + + const piasci = vk.PipelineInputAssemblyStateCreateInfo{ + .flags = .{}, + .topology = .triangle_list, + .primitive_restart_enable = vk.FALSE, + }; + + const viewport = vk.Viewport{ + .x = 0, + .y = 0, + .width = @intToFloat(f32, extent.width), + .height = @intToFloat(f32, extent.height), + .min_depth = 0, + .max_depth = 1, + }; + + const scissor = vk.Rect2D{ + .offset = .{.x = 0, .y = 0}, + .extent = extent, + }; + + const pvsci = vk.PipelineViewportStateCreateInfo{ + .flags = .{}, + .viewport_count = 1, + .p_viewports = @ptrCast([*]const vk.Viewport, &viewport), + .scissor_count = 1, + .p_scissors = @ptrCast([*]const vk.Rect2D, &scissor), + }; + + const prsci = vk.PipelineRasterizationStateCreateInfo{ + .flags = .{}, + .depth_clamp_enable = vk.FALSE, + .rasterizer_discard_enable = vk.FALSE, + .polygon_mode = .fill, + .cull_mode = .{.back_bit = true}, + .front_face = .clockwise, + .depth_bias_enable = vk.FALSE, + .depth_bias_constant_factor = 0, + .depth_bias_clamp = 0, + .depth_bias_slope_factor = 0, + .line_width = 1, + }; + + const pmsci = vk.PipelineMultisampleStateCreateInfo{ + .flags = .{}, + .rasterization_samples = .{.@"1_bit" = true}, + .sample_shading_enable = vk.FALSE, + .min_sample_shading = 1, + .p_sample_mask = null, + .alpha_to_coverage_enable = vk.FALSE, + .alpha_to_one_enable = vk.FALSE, + }; + + const pcbas = vk.PipelineColorBlendAttachmentState{ + .blend_enable = vk.FALSE, + .src_color_blend_factor = .one, + .dst_color_blend_factor = .zero, + .color_blend_op = .add, + .src_alpha_blend_factor = .one, + .dst_alpha_blend_factor = .zero, + .alpha_blend_op = .add, + .color_write_mask = .{.r_bit = true, .g_bit = true, .b_bit = true, .a_bit = true}, + }; + + const pcbsci = vk.PipelineColorBlendStateCreateInfo{ + .flags = .{}, + .logic_op_enable = vk.FALSE, + .logic_op = .copy, + .attachment_count = 1, + .p_attachments = @ptrCast([*]const vk.PipelineColorBlendAttachmentState, &pcbas), + .blend_constants = [_]f32{0, 0, 0, 0}, + }; + + const dynstate = vk.DynamicState.viewport; + const pdsci = vk.PipelineDynamicStateCreateInfo{ + .flags = .{}, + .dynamic_state_count = 1, + .p_dynamic_states = @ptrCast([*]const vk.DynamicState, &dynstate), + }; + + const gpci = vk.GraphicsPipelineCreateInfo{ + .flags = .{}, + .stage_count = 2, + .p_stages = &pssci, + .p_vertex_input_state = &pvisci, + .p_input_assembly_state = &piasci, + .p_tessellation_state = null, + .p_viewport_state = &pvsci, + .p_rasterization_state = &prsci, + .p_multisample_state = &pmsci, + .p_depth_stencil_state = null, + .p_color_blend_state = &pcbsci, + .p_dynamic_state = &pdsci, + .layout = layout, + .render_pass = render_pass, + .subpass = 0, + .base_pipeline_handle = .null_handle, + .base_pipeline_index = -1, + }; + + var pipeline: vk.Pipeline = undefined; + _ = try gc.vkd.createGraphicsPipelines( + gc.dev, + .null_handle, + 1, @ptrCast([*]const vk.GraphicsPipelineCreateInfo, &gpci), + null, + @ptrCast([*]vk.Pipeline, &pipeline), + ); + return pipeline; +} + const ImageState = struct { layout: vk.ImageLayout, stage: vk.PipelineStageFlags, diff --git a/examples/shaders/test.frag b/examples/shaders/test.frag deleted file mode 100644 index 40e75e9..0000000 --- a/examples/shaders/test.frag +++ /dev/null @@ -1,7 +0,0 @@ -#version 450 - -layout(location = 0) out vec4 f_color; - -void main() { - f_color = vec4(1.0, 0.0, 0.0, 1.0); -} diff --git a/examples/shaders/triangle.frag b/examples/shaders/triangle.frag new file mode 100644 index 0000000..8c952fe --- /dev/null +++ b/examples/shaders/triangle.frag @@ -0,0 +1,9 @@ +#version 450 + +layout(location = 0) in vec3 v_color; + +layout(location = 0) out vec4 f_color; + +void main() { + f_color = vec4(v_color, 1.0); +} diff --git a/examples/shaders/triangle.vert b/examples/shaders/triangle.vert new file mode 100644 index 0000000..23666c7 --- /dev/null +++ b/examples/shaders/triangle.vert @@ -0,0 +1,20 @@ +#version 450 + +const vec2 positions[3] = vec2[]( + vec2(0.0, -0.5), + vec2(0.5, 0.5), + vec2(-0.5, 0.5) +); + +const vec3 colors[3] = vec3[]( + vec3(1.0, 0.0, 0.0), + vec3(0.0, 1.0, 0.0), + vec3(0.0, 0.0, 1.0) +); + +layout(location = 0) out vec3 v_color; + +void main() { + gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); + v_color = colors[gl_VertexIndex]; +} diff --git a/generator/build-integration.zig b/generator/build-integration.zig index d0c1a55..ced7c82 100644 --- a/generator/build-integration.zig +++ b/generator/build-integration.zig @@ -11,15 +11,15 @@ pub const ShaderCompileStep = struct { step: Step, builder: *Builder, - glslc_path: []const u8, + glslc_cmd: []const []const u8, shaders: std.ArrayList(Shader), - pub fn init(builder: *Builder, glslc_path: []const u8) *ShaderCompileStep { + pub fn init(builder: *Builder, glslc_cmd: []const []const u8) *ShaderCompileStep { const self = builder.allocator.create(ShaderCompileStep) catch unreachable; self.* = .{ .step = Step.init(.Custom, "shader-compile", builder.allocator, make), .builder = builder, - .glslc_path = glslc_path, + .glslc_cmd = glslc_cmd, .shaders = std.ArrayList(Shader).init(builder.allocator), }; return self; @@ -40,15 +40,18 @@ pub const ShaderCompileStep = struct { const self = @fieldParentPtr(ShaderCompileStep, "step", step); const cwd = std.fs.cwd(); + const cmd = try self.builder.allocator.alloc([]const u8, self.glslc_cmd.len + 3); + for (self.glslc_cmd) |part, i| { + cmd[i] = part; + } + cmd[cmd.len - 2] = "-o"; + for (self.shaders.items) |shader| { const dir = path.dirname(shader.full_out_path).?; try cwd.makePath(dir); - try self.builder.spawnChild(&[_][]const u8{ - self.glslc_path, - shader.source_path, - "-o", - shader.full_out_path, - }); + cmd[cmd.len - 3] = shader.source_path; + cmd[cmd.len - 1] = shader.full_out_path; + try self.builder.spawnChild(cmd); } } };