aboutsummaryrefslogtreecommitdiffstats
path: root/src/output.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/output.zig')
-rw-r--r--src/output.zig203
1 files changed, 189 insertions, 14 deletions
diff --git a/src/output.zig b/src/output.zig
index 459bedb..960c8ae 100644
--- a/src/output.zig
+++ b/src/output.zig
@@ -1,31 +1,202 @@
-const c = @import("c.zig");
const std = @import("std");
+const c = @import("c.zig");
+const build_config = @import("build_config");
const cfg = @import("config.zig");
const gl = @import("gl.zig");
+const yaml = @import("yaml.zig");
pub const Output = struct {
- update: *const fn (*Output, c.GLuint) bool,
- destroy: *const fn (*Output) void,
+ update_fn: *const fn (output: *Output, texture_id: c.GLuint) bool,
+ destroy_fn: *const fn (output: *Output, allocator: std.mem.Allocator) void,
- fn init(update: *const fn (*Output, c.GLuint) bool, destroy: *const fn (*Output) void) Output {
- return Output{
- .update = update,
- .destroy = destroy,
+ pub fn create(
+ allocator: std.mem.Allocator,
+ config: *const cfg.OutputConfig,
+ constants: *gl.Constants,
+ ) *Output {
+ return switch (config.*) {
+ .window => |*con| WindowOutput.create(allocator, con, constants),
+ .texture_share_vk => |*con| if (build_config.have_tsv) TSVOutput.create(allocator, con, constants) else unreachable,
};
}
+ pub fn update(self: *Output, texture_id: c.GLuint) bool {
+ return self.update_fn(self, texture_id);
+ }
+
+ pub fn destroy(self: *Output, allocator: std.mem.Allocator) void {
+ return self.destroy_fn(self, allocator);
+ }
+};
+
+pub const TSVOutput = struct {
+ pub const Config = struct {
+ name: [:0]const u8,
+
+ pub const default: Config = .{
+ .name = "glsl-view",
+ };
+
+ pub fn parse(parser: *c.yaml_parser_t, allocator: std.mem.Allocator) !Config {
+ var self: Config = .default;
+
+ while (true) {
+ var event: c.yaml_event_t = undefined;
+ if (c.yaml_parser_parse(parser, &event) != 1)
+ return error.YAMLParserError;
+ defer c.yaml_event_delete(&event);
+
+ switch (event.type) {
+ c.YAML_MAPPING_END_EVENT => break,
+ c.YAML_SCALAR_EVENT => {
+ const data = event.data.scalar;
+ const key: []const u8 = data.value[0..data.length];
+
+ if (std.mem.eql(u8, key, "name")) {
+ self.name = try yaml.parseStringZ(parser, allocator);
+ } else {
+ std.debug.print("unknown key: '{s}'\n", .{key});
+ try yaml.skipAny(parser);
+ }
+ },
+ else => {
+ std.debug.print("unexpected event: {}\n", .{event.type});
+ return error.InvalidConfiguration;
+ },
+ }
+ }
+
+ return self;
+ }
+ };
+
+ output: Output,
+ config: *const Config,
+ client: *c.GlClient,
+ image_size: c.GlImageExtent,
+
pub fn create(
allocator: std.mem.Allocator,
- config: cfg.OutputConfig,
+ config: *const Config,
constants: *gl.Constants,
) *Output {
- return switch (config.type) {
- .window => WindowOutput.create(allocator, config, constants),
+ const self = allocator.create(TSVOutput) catch unreachable;
+
+ _ = c.gl_client_initialize_external_gl() or unreachable;
+
+ self.* = .{
+ .output = .{
+ .update_fn = update,
+ .destroy_fn = destroy,
+ },
+ .config = config,
+ .client = c.gl_client_new(c.VK_SERVER_DEFAULT_SOCKET_PATH, 1000) orelse unreachable,
+ .image_size = .{
+ .top_left = .{ 0, 0 },
+ .bottom_right = .{ constants.config.width, constants.config.height },
+ },
};
+
+ _ = c.gl_client_init_image(
+ self.client,
+ config.name,
+ @intCast(constants.config.width),
+ @intCast(constants.config.height),
+ c.R8G8B8A8,
+ true,
+ );
+
+ return &self.output;
+ }
+
+ fn update(output: *Output, texture_id: c.GLuint) bool {
+ const self: *TSVOutput = @fieldParentPtr("output", output);
+
+ var fbo: c.GLint = undefined;
+ c.glGetIntegerv(c.GL_DRAW_FRAMEBUFFER_BINDING, &fbo);
+
+ _ = c.gl_client_send_image(
+ self.client,
+ self.config.name,
+ texture_id,
+ c.GL_TEXTURE_2D,
+ false,
+ @intCast(fbo),
+ &self.image_size,
+ );
+ return false;
+ }
+
+ fn destroy(output: *Output, allocator: std.mem.Allocator) void {
+ const self: *TSVOutput = @fieldParentPtr("output", output);
+
+ allocator.destroy(self);
}
};
pub const WindowOutput = struct {
+ pub const Config = struct {
+ const FilterMode = enum(c.GLuint) {
+ nearest = c.GL_NEAREST,
+ linear = c.GL_LINEAR,
+ };
+
+ width: i32,
+ height: i32,
+ filter: FilterMode,
+
+ monitor: []const u8,
+ fullscreen: bool,
+
+ pub const default: Config = .{
+ .width = 800,
+ .height = 600,
+ .filter = .linear,
+ .monitor = "",
+ .fullscreen = false,
+ };
+
+ pub fn parse(parser: *c.yaml_parser_t, allocator: std.mem.Allocator) !Config {
+ var self: Config = .default;
+
+ while (true) {
+ var event: c.yaml_event_t = undefined;
+ if (c.yaml_parser_parse(parser, &event) != 1)
+ return error.YAMLParserError;
+ defer c.yaml_event_delete(&event);
+
+ switch (event.type) {
+ c.YAML_MAPPING_END_EVENT => break,
+ c.YAML_SCALAR_EVENT => {
+ const data = event.data.scalar;
+ const key: []const u8 = data.value[0..data.length];
+
+ if (std.mem.eql(u8, key, "width")) {
+ self.width = try yaml.parseInt(parser, i32);
+ } else if (std.mem.eql(u8, key, "height")) {
+ self.height = try yaml.parseInt(parser, i32);
+ } else if (std.mem.eql(u8, key, "filter")) {
+ self.filter = try yaml.parseEnum(parser, FilterMode);
+ } else if (std.mem.eql(u8, key, "monitor")) {
+ self.monitor = try yaml.parseString(parser, allocator);
+ } else if (std.mem.eql(u8, key, "fullscreen")) {
+ self.fullscreen = try yaml.parseBool(parser);
+ } else {
+ std.debug.print("unknown key: '{s}'\n", .{key});
+ try yaml.skipAny(parser);
+ }
+ },
+ else => {
+ std.debug.print("unexpected event: {}\n", .{event.type});
+ return error.InvalidConfiguration;
+ },
+ }
+ }
+
+ return self;
+ }
+ };
+
output: Output,
window: *c.GLFWwindow,
constants: *gl.Constants,
@@ -34,16 +205,19 @@ pub const WindowOutput = struct {
pub fn create(
allocator: std.mem.Allocator,
- config: cfg.OutputConfig,
+ config: *const Config,
constants: *gl.Constants,
) *Output {
const self = allocator.create(WindowOutput) catch unreachable;
c.glfwDefaultWindowHints();
- self.* = WindowOutput{
+ self.* = .{
.constants = constants,
- .output = Output.init(update, destroy),
+ .output = .{
+ .update_fn = update,
+ .destroy_fn = destroy,
+ },
.window = c.glfwCreateWindow(
config.width,
config.height,
@@ -108,10 +282,11 @@ pub const WindowOutput = struct {
return false;
}
- fn destroy(output: *Output) void {
+ fn destroy(output: *Output, allocator: std.mem.Allocator) void {
const self: *WindowOutput = @fieldParentPtr("output", output);
c.glfwDestroyWindow(self.window);
+ allocator.destroy(self);
}
fn keyCallback(