|
0 |
const std = @import("std");
|
0 | 1 |
const dg = @import("diligent");
|
1 | 2 |
const graphics = @import("graphics.zig");
|
|
3 |
usingnamespace @import("xrvk.zig");
|
2 | 4 |
|
3 | 5 |
const vertex_source =
|
4 | 6 |
\\layout(location = 0) out vec3 out_Color;
|
|
21 | 23 |
;
|
22 | 24 |
|
23 | 25 |
const geometry_source =
|
24 | |
\\layout(triangles, invocations=2) in;
|
|
26 |
\\layout(triangles, invocations = 2) in;
|
25 | 27 |
\\layout(max_vertices = 3, triangle_strip) out;
|
26 | 28 |
\\
|
27 | 29 |
\\struct VSOutput {
|
|
29 | 31 |
\\ vec3 color;
|
30 | 32 |
\\};
|
31 | 33 |
\\
|
|
34 |
\\struct ViewUBO {
|
|
35 |
\\ mat4 projection;
|
|
36 |
\\ mat4 modelview;
|
|
37 |
\\};
|
|
38 |
\\
|
|
39 |
\\layout(binding = 0) uniform Views {
|
|
40 |
\\ ViewUBO views[2];
|
|
41 |
\\};
|
|
42 |
\\
|
32 | 43 |
\\layout(location = 0) out vec3 out_Color;
|
33 | 44 |
\\layout(location = 0) in vec3 in_Color[3];
|
34 | 45 |
\\
|
35 | 46 |
\\void main() {
|
36 | |
\\ VSOutput triangle[3] = VSOutput[](
|
37 | |
\\ VSOutput(gl_in[0].gl_Position, in_Color[0]),
|
38 | |
\\ VSOutput(gl_in[1].gl_Position, in_Color[1]),
|
39 | |
\\ VSOutput(gl_in[2].gl_Position, in_Color[2])
|
40 | |
\\ );
|
41 | |
\\ for (int i = 0; i < 3; i++)
|
42 | |
\\ {
|
43 | |
\\ gl_Position = triangle[i].position;
|
44 | |
\\ out_Color = triangle[i].color;
|
|
47 |
\\ for (int i = 0; i < 3; i++) {
|
|
48 |
\\ vec4 worldPos = views[gl_InvocationID].modelview * gl_in[i].gl_Position;
|
|
49 |
\\ gl_Position = views[gl_InvocationID].projection * worldPos;
|
45 | 50 |
\\ gl_ViewportIndex = int(gl_InvocationID);
|
|
51 |
\\ out_Color = in_Color[i];
|
46 | 52 |
\\ EmitVertex();
|
47 | 53 |
\\ }
|
48 | 54 |
\\ EndPrimitive();
|
|
59 | 65 |
;
|
60 | 66 |
|
61 | 67 |
pub const Scene = struct {
|
62 | |
pipeline_state: *dg.IPipelineState,
|
63 | 68 |
viewports: []dg.Viewport,
|
64 | 69 |
scissors: []dg.Rect,
|
|
70 |
|
|
71 |
pipeline_state: dg.IPipelineState_Wrapper,
|
|
72 |
resource_binding: dg.IShaderResourceBinding_Wrapper,
|
|
73 |
views_ubo: dg.IBuffer_Wrapper,
|
|
74 |
views: []ViewUBO,
|
65 | 75 |
|
66 | 76 |
ctx: dg.IDeviceContext_Wrapper,
|
67 | 77 |
dev: dg.IRenderDeviceVk_Wrapper,
|
68 | 78 |
swc: dg.ISwapChainVk_Wrapper,
|
69 | 79 |
|
70 | |
fn createShader(
|
71 | |
self: *const Scene,
|
72 | |
name: [:0]const u8,
|
73 | |
shader_type: dg.SHADER_TYPE,
|
74 | |
language: dg.SHADER_SOURCE_LANGUAGE,
|
75 | |
source: [:0]const u8,
|
76 | |
) !*dg.IShader {
|
77 | |
var shader: ?*dg.IShader = null;
|
78 | |
self.dev.CreateShader(&dg.ShaderCreateInfo{
|
79 | |
.Desc = .{
|
80 | |
._DeviceObjectAttribs = .{ .Name = name },
|
81 | |
.ShaderType = shader_type,
|
82 | |
},
|
83 | |
|
84 | |
.Source = source,
|
85 | |
.SourceLanguage = language,
|
86 | |
|
87 | |
// default
|
88 | |
.FilePath = null,
|
89 | |
.pShaderSourceStreamFactory = null,
|
90 | |
.ppConversionStream = null,
|
91 | |
.ByteCode = null,
|
92 | |
.ByteCodeSize = 0,
|
93 | |
.EntryPoint = "main",
|
94 | |
.Macros = null,
|
95 | |
.UseCombinedTextureSamplers = false,
|
96 | |
.CombinedSamplerSuffix = "_sampler",
|
97 | |
.ShaderCompiler = dg.SHADER_COMPILER_DEFAULT,
|
98 | |
.HLSLVersion = .{ .Major = 0, .Minor = 0 },
|
99 | |
.GLSLVersion = .{ .Major = 0, .Minor = 0 },
|
100 | |
.GLESSLVersion = .{ .Major = 0, .Minor = 0 },
|
101 | |
.ppCompilerOutput = null,
|
102 | |
}, &shader);
|
103 | |
|
104 | |
return shader orelse error.ShaderCreationError;
|
105 | |
}
|
|
80 |
const ViewUBO = packed struct {
|
|
81 |
projection: [16]f32,
|
|
82 |
modelview: [16]f32,
|
|
83 |
};
|
106 | 84 |
|
107 | 85 |
pub fn init(gfx: *const graphics.Graphics) !Scene {
|
108 | 86 |
const dev = gfx.dg_device;
|
|
117 | 95 |
errdefer gfx.allocator.free(self.viewports);
|
118 | 96 |
self.scissors = try gfx.allocator.alloc(dg.Rect, gfx.swapchain.image_rects.len);
|
119 | 97 |
errdefer gfx.allocator.free(self.scissors);
|
|
98 |
self.views = try gfx.allocator.alloc(ViewUBO, gfx.swapchain.image_rects.len);
|
|
99 |
errdefer gfx.allocator.free(self.views);
|
120 | 100 |
|
121 | 101 |
for (gfx.swapchain.image_rects) |rect, i| {
|
122 | 102 |
self.viewports[i] = .{
|
|
134 | 114 |
.top = rect.offset.y,
|
135 | 115 |
.bottom = rect.offset.y + rect.extent.height,
|
136 | 116 |
};
|
|
117 |
|
|
118 |
self.views[i] = .{
|
|
119 |
.projection = [_]f32{
|
|
120 |
1, 0, 0, 0,
|
|
121 |
0, 1, 0, 0,
|
|
122 |
0, 0, 1, 0,
|
|
123 |
0, 0, 0, 1,
|
|
124 |
},
|
|
125 |
.modelview = [_]f32{
|
|
126 |
1, 0, 0, 0,
|
|
127 |
0, 1, 0, 0,
|
|
128 |
0, 0, 1, 0,
|
|
129 |
0, 0, 0, 1,
|
|
130 |
},
|
|
131 |
};
|
137 | 132 |
}
|
138 | 133 |
|
139 | |
const vertex_shader = try self.createShader("Vertex Shader", dg.SHADER_TYPE_VERTEX, dg.SHADER_SOURCE_LANGUAGE_GLSL, vertex_source);
|
140 | |
const geometry_shader = try self.createShader("Geometry Shader", dg.SHADER_TYPE_GEOMETRY, dg.SHADER_SOURCE_LANGUAGE_GLSL, geometry_source);
|
141 | |
const fragment_shader = try self.createShader("Fragment Shader", dg.SHADER_TYPE_PIXEL, dg.SHADER_SOURCE_LANGUAGE_GLSL, fragment_source);
|
|
134 |
const vertex_shader = try self.createShader(
|
|
135 |
"Vertex Shader",
|
|
136 |
dg.SHADER_TYPE_VERTEX,
|
|
137 |
dg.SHADER_SOURCE_LANGUAGE_GLSL,
|
|
138 |
vertex_source,
|
|
139 |
);
|
|
140 |
const geometry_shader = try self.createShader(
|
|
141 |
"Geometry Shader",
|
|
142 |
dg.SHADER_TYPE_GEOMETRY,
|
|
143 |
dg.SHADER_SOURCE_LANGUAGE_GLSL,
|
|
144 |
geometry_source,
|
|
145 |
);
|
|
146 |
const fragment_shader = try self.createShader(
|
|
147 |
"Fragment Shader",
|
|
148 |
dg.SHADER_TYPE_PIXEL,
|
|
149 |
dg.SHADER_SOURCE_LANGUAGE_GLSL,
|
|
150 |
fragment_source,
|
|
151 |
);
|
142 | 152 |
|
143 | 153 |
var pipeline_state: ?*dg.IPipelineState = null;
|
144 | 154 |
dev.CreateGraphicsPipelineState(&dg.GraphicsPipelineStateCreateInfo{
|
|
235 | 245 |
.pAS = null,
|
236 | 246 |
.pMS = null,
|
237 | 247 |
}, &pipeline_state);
|
238 | |
self.pipeline_state = pipeline_state orelse return error.PipelineCreateError;
|
|
248 |
self.pipeline_state = dg.IPipelineState_Wrapper.wrap(pipeline_state);
|
|
249 |
errdefer self.pipeline_state.Release();
|
|
250 |
|
|
251 |
self.views_ubo = try self.createBuffer(
|
|
252 |
[2]ViewUBO,
|
|
253 |
"View Uniform Buffer",
|
|
254 |
null,
|
|
255 |
dg.BIND_UNIFORM_BUFFER,
|
|
256 |
dg.USAGE_DYNAMIC,
|
|
257 |
dg.CPU_ACCESS_WRITE,
|
|
258 |
);
|
|
259 |
errdefer self.views_ubo.Release();
|
|
260 |
|
|
261 |
const shader_variable = self.pipeline_state.GetStaticVariableByIndex(dg.SHADER_TYPE_GEOMETRY, 0);
|
|
262 |
dg.IShaderResourceVariable_Wrapper.wrap(shader_variable).Set(@ptrCast(*dg.IDeviceObject, self.views_ubo.ptr));
|
|
263 |
|
|
264 |
var resource_binding: ?*dg.IShaderResourceBinding = null;
|
|
265 |
self.pipeline_state.CreateShaderResourceBinding(&resource_binding, true);
|
|
266 |
self.resource_binding = dg.IShaderResourceBinding_Wrapper.wrap(resource_binding);
|
|
267 |
errdefer self.resource_binding.Release();
|
239 | 268 |
|
240 | 269 |
return self;
|
241 | 270 |
}
|
242 | 271 |
|
243 | 272 |
pub fn deinit(self: *const Scene) void {
|
|
273 |
self.resource_binding.Release();
|
|
274 |
self.views_ubo.Release();
|
|
275 |
self.pipeline_state.Release();
|
|
276 |
|
244 | 277 |
gfx.allocator.free(self.viewports);
|
245 | |
}
|
246 | |
|
247 | |
pub fn render(self: *const Scene) !void {
|
|
278 |
gfx.allocator.free(self.scissors);
|
|
279 |
gfx.allocator.free(self.views);
|
|
280 |
}
|
|
281 |
|
|
282 |
pub fn render(self: *const Scene, views: []const xr.View) !void {
|
|
283 |
// update uniform buffer
|
|
284 |
for (views) |view, i| {
|
|
285 |
self.views[i].modelview[3] = view.pose.position.x / 3.0;
|
|
286 |
}
|
|
287 |
try self.updateBufferSlice(ViewUBO, self.views_ubo, self.views);
|
|
288 |
|
|
289 |
// setup and clear render targets
|
248 | 290 |
var rtv = self.swc.GetCurrentBackBufferRTV();
|
249 | 291 |
const dsv = self.swc.GetDepthBufferDSV();
|
250 | 292 |
|
|
264 | 306 |
|
265 | 307 |
const clear_color = [_]f32{ 0.35, 0.35, 0.35, 1 };
|
266 | 308 |
self.ctx.ClearRenderTarget(rtv, clear_color[0..], dg.RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
|
267 | |
self.ctx.ClearDepthStencil(dsv, dg.CLEAR_DEPTH_FLAG, 1, 0, dg.RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
|
268 | |
|
269 | |
self.ctx.SetPipelineState(self.pipeline_state);
|
|
309 |
self.ctx.ClearDepthStencil(
|
|
310 |
dsv,
|
|
311 |
dg.CLEAR_DEPTH_FLAG,
|
|
312 |
1,
|
|
313 |
0,
|
|
314 |
dg.RESOURCE_STATE_TRANSITION_MODE_TRANSITION,
|
|
315 |
);
|
|
316 |
|
|
317 |
// record drenderpass
|
|
318 |
self.ctx.SetPipelineState(self.pipeline_state.ptr);
|
|
319 |
self.ctx.CommitShaderResources(self.resource_binding.ptr, dg.RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
|
270 | 320 |
|
271 | 321 |
self.ctx.Draw(&dg.DrawAttribs{
|
272 | 322 |
.NumVertices = 3,
|
|
277 | 327 |
.FirstInstanceLocation = 0,
|
278 | 328 |
});
|
279 | 329 |
}
|
|
330 |
|
|
331 |
fn createShader(
|
|
332 |
self: *const Scene,
|
|
333 |
name: [:0]const u8,
|
|
334 |
shader_type: dg.SHADER_TYPE,
|
|
335 |
language: dg.SHADER_SOURCE_LANGUAGE,
|
|
336 |
source: [:0]const u8,
|
|
337 |
) !*dg.IShader {
|
|
338 |
var shader: ?*dg.IShader = null;
|
|
339 |
self.dev.CreateShader(&dg.ShaderCreateInfo{
|
|
340 |
.Desc = .{
|
|
341 |
._DeviceObjectAttribs = .{ .Name = name },
|
|
342 |
.ShaderType = shader_type,
|
|
343 |
},
|
|
344 |
|
|
345 |
.Source = source,
|
|
346 |
.SourceLanguage = language,
|
|
347 |
|
|
348 |
// default
|
|
349 |
.FilePath = null,
|
|
350 |
.pShaderSourceStreamFactory = null,
|
|
351 |
.ppConversionStream = null,
|
|
352 |
.ByteCode = null,
|
|
353 |
.ByteCodeSize = 0,
|
|
354 |
.EntryPoint = "main",
|
|
355 |
.Macros = null,
|
|
356 |
.UseCombinedTextureSamplers = false,
|
|
357 |
.CombinedSamplerSuffix = "_sampler",
|
|
358 |
.ShaderCompiler = dg.SHADER_COMPILER_DEFAULT,
|
|
359 |
.HLSLVersion = .{ .Major = 0, .Minor = 0 },
|
|
360 |
.GLSLVersion = .{ .Major = 0, .Minor = 0 },
|
|
361 |
.GLESSLVersion = .{ .Major = 0, .Minor = 0 },
|
|
362 |
.ppCompilerOutput = null,
|
|
363 |
}, &shader);
|
|
364 |
|
|
365 |
return shader orelse error.ShaderCreationError;
|
|
366 |
}
|
|
367 |
|
|
368 |
fn createBuffer(
|
|
369 |
self: *const Scene,
|
|
370 |
comptime T: type,
|
|
371 |
name: [:0]const u8,
|
|
372 |
initial: ?*T,
|
|
373 |
bind: dg.BIND_FLAGS,
|
|
374 |
usage: dg.USAGE,
|
|
375 |
cpu_access: dg.CPU_ACCESS_FLAGS,
|
|
376 |
) !dg.IBuffer_Wrapper {
|
|
377 |
var buffer: ?*dg.IBuffer = null;
|
|
378 |
var data_ptr: ?*const dg.BufferData = null;
|
|
379 |
|
|
380 |
if (initial) |ptr| {
|
|
381 |
const data = dg.BufferData{
|
|
382 |
.pData = ptr,
|
|
383 |
.DataSize = @sizeOf(T),
|
|
384 |
};
|
|
385 |
data_ptr = &data;
|
|
386 |
}
|
|
387 |
|
|
388 |
self.dev.CreateBuffer(&dg.BufferDesc{
|
|
389 |
._DeviceObjectAttribs = .{ .Name = name },
|
|
390 |
.uiSizeInBytes = @sizeOf(T),
|
|
391 |
.BindFlags = bind, // default: dg.BIND_NONE
|
|
392 |
.Usage = usage, // default: dg.USAGE_DEFAULT
|
|
393 |
.CPUAccessFlags = cpu_access, // default: dg.CPU_ACCESS_NONE
|
|
394 |
.Mode = dg.BUFFER_MODE_UNDEFINED,
|
|
395 |
.ElementByteStride = 0,
|
|
396 |
.CommandQueueMask = 1,
|
|
397 |
}, data_ptr, &buffer);
|
|
398 |
|
|
399 |
return dg.IBuffer_Wrapper.wrap(buffer);
|
|
400 |
}
|
|
401 |
|
|
402 |
fn updateBuffer(
|
|
403 |
self: *const Scene,
|
|
404 |
comptime T: type,
|
|
405 |
buffer: dg.IBuffer_Wrapper,
|
|
406 |
value: *T,
|
|
407 |
) !void {
|
|
408 |
var data: ?*T = null;
|
|
409 |
self.ctx.MapBuffer(buffer.ptr, dg.MAP_WRITE, dg.MAP_FLAG_DISCARD, @ptrCast(?*c_void, &data));
|
|
410 |
if (data) |ptr| {
|
|
411 |
ptr.* = value;
|
|
412 |
self.ctx.UnmapBuffer(buffer.ptr, dg.MAP_WRITE);
|
|
413 |
} else {
|
|
414 |
return error.MapFailed;
|
|
415 |
}
|
|
416 |
}
|
|
417 |
|
|
418 |
fn updateBufferSlice(
|
|
419 |
self: *const Scene,
|
|
420 |
comptime T: type,
|
|
421 |
buffer: dg.IBuffer_Wrapper,
|
|
422 |
values: []const T,
|
|
423 |
) !void {
|
|
424 |
var data: [*c]T = null;
|
|
425 |
self.ctx.MapBuffer(buffer.ptr, dg.MAP_WRITE, dg.MAP_FLAG_DISCARD, @ptrCast([*c]?*c_void, &data));
|
|
426 |
if (data) |ptr| {
|
|
427 |
std.mem.copy(T, data[0..values.len], values);
|
|
428 |
self.ctx.UnmapBuffer(buffer.ptr, dg.MAP_WRITE);
|
|
429 |
} else {
|
|
430 |
return error.MapFailed;
|
|
431 |
}
|
|
432 |
}
|
280 | 433 |
};
|