Deduplicate multiple mesh instances
This commit is contained in:
+8
-10
@@ -100,20 +100,18 @@ load_test_model :: proc() {
|
|||||||
"assets/cube.obj",
|
"assets/cube.obj",
|
||||||
cube.vertices,
|
cube.vertices,
|
||||||
cube.indices,
|
cube.indices,
|
||||||
true,
|
0,
|
||||||
)
|
)
|
||||||
platform.create_renderable(
|
platform.create_renderable(
|
||||||
"assets/suzanne.obj",
|
"assets/suzanne.obj",
|
||||||
suzanne.vertices,
|
suzanne.vertices,
|
||||||
suzanne.indices,
|
suzanne.indices,
|
||||||
false,
|
3,
|
||||||
|
)
|
||||||
|
platform.create_renderable(
|
||||||
|
"assets/suzanne.obj",
|
||||||
|
suzanne.vertices,
|
||||||
|
suzanne.indices,
|
||||||
|
-3,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// per-object:
|
|
||||||
// - vertex buffer
|
|
||||||
// - index buffer
|
|
||||||
// - uniform buffer (model matrix)
|
|
||||||
// - texture
|
|
||||||
// - material
|
|
||||||
// - 1 drawcall
|
|
||||||
|
|||||||
+87
-73
@@ -25,7 +25,7 @@ Material_Uniform :: struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Updated once per mesh
|
// Updated once per mesh
|
||||||
Renderable_Uniform :: struct {
|
Object_Uniform :: struct {
|
||||||
transform: base.Mat4,
|
transform: base.Mat4,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,13 +34,16 @@ Material :: struct {
|
|||||||
uniform_buffer: wgpu.Buffer,
|
uniform_buffer: wgpu.Buffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Split Renderable into mesh (vert, idx, #idx) and object (bg, ub)
|
Object :: struct {
|
||||||
Renderable :: struct {
|
name: string,
|
||||||
bind_group: wgpu.BindGroup,
|
bind_group: wgpu.BindGroup,
|
||||||
uniform_buffer: wgpu.Buffer,
|
uniform_buffer: wgpu.Buffer,
|
||||||
vertex_buffer: wgpu.Buffer,
|
}
|
||||||
index_buffer: wgpu.Buffer,
|
|
||||||
index_count: u32,
|
Mesh :: struct {
|
||||||
|
vertex_buffer: wgpu.Buffer,
|
||||||
|
index_buffer: wgpu.Buffer,
|
||||||
|
index_count: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
@@ -48,38 +51,39 @@ Renderable :: struct {
|
|||||||
|
|
||||||
// Instance -> Surface -> Adapter -> Device -> Queue
|
// Instance -> Surface -> Adapter -> Device -> Queue
|
||||||
state: struct {
|
state: struct {
|
||||||
ctx: runtime.Context,
|
ctx: runtime.Context,
|
||||||
os: OS,
|
os: OS,
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
instance: wgpu.Instance, // entry point: creates Adapter, Device and Surface
|
instance: wgpu.Instance, // entry point: creates Adapter, Device and Surface
|
||||||
surface: wgpu.Surface, // handle to a presentable surface (e.g. a window)
|
surface: wgpu.Surface, // handle to a presentable surface (e.g. a window)
|
||||||
adapter: wgpu.Adapter, // handle to physical GPU
|
adapter: wgpu.Adapter, // handle to physical GPU
|
||||||
device: wgpu.Device, // open connection to a GPU
|
device: wgpu.Device, // open connection to a GPU
|
||||||
queue: wgpu.Queue, // handle to command queue on a Device
|
queue: wgpu.Queue, // handle to command queue on a Device
|
||||||
config: wgpu.SurfaceConfiguration,
|
config: wgpu.SurfaceConfiguration,
|
||||||
module: wgpu.ShaderModule,
|
module: wgpu.ShaderModule,
|
||||||
pipeline_layout: wgpu.PipelineLayout,
|
pipeline_layout: wgpu.PipelineLayout,
|
||||||
pipeline: wgpu.RenderPipeline,
|
pipeline: wgpu.RenderPipeline,
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
capabilities: wgpu.SurfaceCapabilities,
|
capabilities: wgpu.SurfaceCapabilities,
|
||||||
vsync: bool,
|
vsync: bool,
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
depth_texture: wgpu.Texture,
|
depth_texture: wgpu.Texture,
|
||||||
depth_texture_view: wgpu.TextureView,
|
depth_texture_view: wgpu.TextureView,
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
camera_uniform_buffer: wgpu.Buffer,
|
camera_uniform_buffer: wgpu.Buffer,
|
||||||
camera_bind_group_layout: wgpu.BindGroupLayout,
|
camera_bind_group_layout: wgpu.BindGroupLayout,
|
||||||
camera_bind_group: wgpu.BindGroup,
|
camera_bind_group: wgpu.BindGroup,
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
material_bind_group_layout: wgpu.BindGroupLayout,
|
material_bind_group_layout: wgpu.BindGroupLayout,
|
||||||
materials: map[string]Material,
|
materials: map[string]Material,
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
renderable_bind_group_layout: wgpu.BindGroupLayout,
|
objects_bind_group_layout: wgpu.BindGroupLayout,
|
||||||
renderables: map[string]Renderable,
|
objects: [dynamic]Object,
|
||||||
|
meshes: map[string]Mesh,
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
diffuse_texture: wgpu.Texture,
|
diffuse_texture: wgpu.Texture,
|
||||||
diffuse_texture_view: wgpu.TextureView,
|
diffuse_texture_view: wgpu.TextureView,
|
||||||
diffuse_sampler: wgpu.Sampler,
|
diffuse_sampler: wgpu.Sampler,
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
@@ -92,7 +96,8 @@ instance_init :: proc(
|
|||||||
state.ctx = context
|
state.ctx = context
|
||||||
|
|
||||||
state.materials = make(map[string]Material, allocator)
|
state.materials = make(map[string]Material, allocator)
|
||||||
state.renderables = make(map[string]Renderable, allocator)
|
state.objects = make([dynamic]Object, allocator)
|
||||||
|
state.meshes = make(map[string]Mesh, allocator)
|
||||||
|
|
||||||
wgpu.SetLogCallback(log_callback, nil)
|
wgpu.SetLogCallback(log_callback, nil)
|
||||||
wgpu.SetLogLevel(.Warn)
|
wgpu.SetLogLevel(.Warn)
|
||||||
@@ -142,16 +147,21 @@ instance_destroy :: proc() {
|
|||||||
}
|
}
|
||||||
wgpu.BindGroupLayoutRelease(state.material_bind_group_layout)
|
wgpu.BindGroupLayoutRelease(state.material_bind_group_layout)
|
||||||
|
|
||||||
if state.renderables != nil {
|
if state.meshes != nil {
|
||||||
for _, r in state.renderables {
|
for _, m in state.meshes {
|
||||||
|
wgpu.BufferRelease(m.vertex_buffer)
|
||||||
|
wgpu.BufferRelease(m.index_buffer)
|
||||||
|
}
|
||||||
|
delete(state.meshes)
|
||||||
|
}
|
||||||
|
if state.objects != nil {
|
||||||
|
for r in state.objects {
|
||||||
wgpu.BufferRelease(r.uniform_buffer)
|
wgpu.BufferRelease(r.uniform_buffer)
|
||||||
wgpu.BindGroupRelease(r.bind_group)
|
wgpu.BindGroupRelease(r.bind_group)
|
||||||
wgpu.BufferRelease(r.vertex_buffer)
|
|
||||||
wgpu.BufferRelease(r.index_buffer)
|
|
||||||
}
|
}
|
||||||
delete(state.renderables)
|
delete(state.objects)
|
||||||
}
|
}
|
||||||
wgpu.BindGroupLayoutRelease(state.renderable_bind_group_layout)
|
wgpu.BindGroupLayoutRelease(state.objects_bind_group_layout)
|
||||||
|
|
||||||
wgpu.RenderPipelineRelease(state.pipeline)
|
wgpu.RenderPipelineRelease(state.pipeline)
|
||||||
wgpu.PipelineLayoutRelease(state.pipeline_layout)
|
wgpu.PipelineLayoutRelease(state.pipeline_layout)
|
||||||
@@ -256,6 +266,7 @@ frame :: proc "c" () {
|
|||||||
dynamicOffsets = nil, // reuse bind group af different byte offsets, per binding
|
dynamicOffsets = nil, // reuse bind group af different byte offsets, per binding
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Uniform group 1, materials
|
||||||
m := state.materials["dummy"]
|
m := state.materials["dummy"]
|
||||||
wgpu.RenderPassEncoderSetBindGroup(
|
wgpu.RenderPassEncoderSetBindGroup(
|
||||||
render_pass_encoder,
|
render_pass_encoder,
|
||||||
@@ -264,27 +275,29 @@ frame :: proc "c" () {
|
|||||||
dynamicOffsets = nil, // reuse bind group af different byte offsets, per binding
|
dynamicOffsets = nil, // reuse bind group af different byte offsets, per binding
|
||||||
)
|
)
|
||||||
|
|
||||||
// Render all renderables
|
// Render all objects
|
||||||
for _, r in state.renderables {
|
for o in state.objects {
|
||||||
// Uniform group 2
|
m := state.meshes[o.name]
|
||||||
|
|
||||||
|
// Uniform group 2, object
|
||||||
wgpu.RenderPassEncoderSetBindGroup(
|
wgpu.RenderPassEncoderSetBindGroup(
|
||||||
render_pass_encoder,
|
render_pass_encoder,
|
||||||
2,
|
2,
|
||||||
r.bind_group,
|
o.bind_group,
|
||||||
dynamicOffsets = nil, // reuse bind group af different byte offsets, per binding
|
dynamicOffsets = nil, // reuse bind group af different byte offsets, per binding
|
||||||
)
|
)
|
||||||
|
|
||||||
wgpu.RenderPassEncoderSetVertexBuffer(
|
wgpu.RenderPassEncoderSetVertexBuffer(
|
||||||
render_pass_encoder,
|
render_pass_encoder,
|
||||||
slot = 0,
|
slot = 0,
|
||||||
buffer = r.vertex_buffer,
|
buffer = m.vertex_buffer,
|
||||||
offset = 0, // offset into buffer to start from
|
offset = 0, // offset into buffer to start from
|
||||||
size = wgpu.WHOLE_SIZE, // x bytes of the buffer to use
|
size = wgpu.WHOLE_SIZE, // x bytes of the buffer to use
|
||||||
)
|
)
|
||||||
|
|
||||||
wgpu.RenderPassEncoderSetIndexBuffer(
|
wgpu.RenderPassEncoderSetIndexBuffer(
|
||||||
render_pass_encoder,
|
render_pass_encoder,
|
||||||
buffer = r.index_buffer,
|
buffer = m.index_buffer,
|
||||||
format = .Uint16, // type of each element in the buffer
|
format = .Uint16, // type of each element in the buffer
|
||||||
offset = 0, // offset into buffer to start from
|
offset = 0, // offset into buffer to start from
|
||||||
size = wgpu.WHOLE_SIZE, // x bytes of the buffer to use
|
size = wgpu.WHOLE_SIZE, // x bytes of the buffer to use
|
||||||
@@ -292,13 +305,12 @@ frame :: proc "c" () {
|
|||||||
|
|
||||||
wgpu.RenderPassEncoderDrawIndexed(
|
wgpu.RenderPassEncoderDrawIndexed(
|
||||||
render_pass_encoder,
|
render_pass_encoder,
|
||||||
r.index_count,
|
m.index_count,
|
||||||
instanceCount = 1, // draw x instance(s) of the mesh
|
instanceCount = 1, // draw x instance(s) of the mesh
|
||||||
firstIndex = 0, // offset into buffer to start from, useful for drawing sub-mesh
|
firstIndex = 0, // offset into buffer to start from, useful for drawing sub-mesh
|
||||||
baseVertex = 0, // value added to index before vertex fetch, useful for multi-mesh vertex buffers
|
baseVertex = 0, // value added to index before vertex fetch, useful for multi-mesh vertex buffers
|
||||||
firstInstance = 0, // number to start instance index from
|
firstInstance = 0, // number to start instance index from
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wgpu.RenderPassEncoderEnd(render_pass_encoder)
|
wgpu.RenderPassEncoderEnd(render_pass_encoder)
|
||||||
@@ -362,27 +374,20 @@ create_renderable :: proc(
|
|||||||
name: string,
|
name: string,
|
||||||
vertices: []base.Vertex,
|
vertices: []base.Vertex,
|
||||||
indices: []u16,
|
indices: []u16,
|
||||||
first: bool,
|
x_offset: f32,
|
||||||
) {
|
) {
|
||||||
if name in state.renderables do return
|
|
||||||
|
|
||||||
uniform_buffer := wgpu.DeviceCreateBuffer(
|
uniform_buffer := wgpu.DeviceCreateBuffer(
|
||||||
state.device,
|
state.device,
|
||||||
&{
|
&{
|
||||||
label = "renderable uniform",
|
label = "object uniform",
|
||||||
usage = {.Uniform, .CopyDst}, // shader reads, queue writes
|
usage = {.Uniform, .CopyDst}, // shader reads, queue writes
|
||||||
size = cast(u64)size_of(Renderable_Uniform),
|
size = cast(u64)size_of(Object_Uniform),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
transform: base.Mat4
|
uniform := Object_Uniform {
|
||||||
if first {
|
// transform = linalg.identity(base.Mat4)
|
||||||
transform = linalg.identity(base.Mat4)
|
transform = linalg.matrix4_translate(base.Vec3{x_offset, 0, 0}),
|
||||||
} else {
|
|
||||||
transform = linalg.matrix4_translate(base.Vec3{3, 0, 0})
|
|
||||||
}
|
|
||||||
uniform := Renderable_Uniform {
|
|
||||||
transform = transform,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// bufferOffset = offset into buffer to start from
|
// bufferOffset = offset into buffer to start from
|
||||||
@@ -391,7 +396,7 @@ create_renderable :: proc(
|
|||||||
uniform_buffer,
|
uniform_buffer,
|
||||||
0,
|
0,
|
||||||
&uniform,
|
&uniform,
|
||||||
size_of(Renderable_Uniform),
|
size_of(Object_Uniform),
|
||||||
)
|
)
|
||||||
|
|
||||||
entries := [?]wgpu.BindGroupEntry {
|
entries := [?]wgpu.BindGroupEntry {
|
||||||
@@ -399,19 +404,30 @@ create_renderable :: proc(
|
|||||||
binding = 0, // slot 0
|
binding = 0, // slot 0
|
||||||
buffer = uniform_buffer,
|
buffer = uniform_buffer,
|
||||||
offset = 0, // offset into buffer to start from
|
offset = 0, // offset into buffer to start from
|
||||||
size = cast(u64)size_of(Renderable_Uniform),
|
size = cast(u64)size_of(Object_Uniform),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
bind_group := wgpu.DeviceCreateBindGroup(
|
bind_group := wgpu.DeviceCreateBindGroup(
|
||||||
state.device,
|
state.device,
|
||||||
&{
|
&{
|
||||||
label = "renderable bind group",
|
label = "object bind group",
|
||||||
layout = state.renderable_bind_group_layout,
|
layout = state.objects_bind_group_layout,
|
||||||
entryCount = len(entries),
|
entryCount = len(entries),
|
||||||
entries = raw_data(entries[:]),
|
entries = raw_data(entries[:]),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
append(
|
||||||
|
&state.objects,
|
||||||
|
Object {
|
||||||
|
name = name,
|
||||||
|
bind_group = bind_group,
|
||||||
|
uniform_buffer = uniform_buffer,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if name in state.meshes do return
|
||||||
|
|
||||||
vertex_buffer := wgpu.DeviceCreateBuffer(
|
vertex_buffer := wgpu.DeviceCreateBuffer(
|
||||||
state.device,
|
state.device,
|
||||||
&{
|
&{
|
||||||
@@ -446,12 +462,10 @@ create_renderable :: proc(
|
|||||||
cast(uint)(len(indices) * size_of(u16)),
|
cast(uint)(len(indices) * size_of(u16)),
|
||||||
)
|
)
|
||||||
|
|
||||||
state.renderables[name] = {
|
state.meshes[name] = {
|
||||||
bind_group = bind_group,
|
vertex_buffer = vertex_buffer,
|
||||||
uniform_buffer = uniform_buffer,
|
index_buffer = index_buffer,
|
||||||
vertex_buffer = vertex_buffer,
|
index_count = cast(u32)len(indices),
|
||||||
index_buffer = index_buffer,
|
|
||||||
index_count = cast(u32)len(indices),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -522,7 +536,7 @@ on_device :: proc "c" (
|
|||||||
material_struct := to_wgsl_struct(Material_Uniform, "Material")
|
material_struct := to_wgsl_struct(Material_Uniform, "Material")
|
||||||
defer delete(material_struct)
|
defer delete(material_struct)
|
||||||
|
|
||||||
renderable_struct := to_wgsl_struct(Renderable_Uniform, "Renderable")
|
renderable_struct := to_wgsl_struct(Object_Uniform, "Renderable")
|
||||||
defer delete(renderable_struct)
|
defer delete(renderable_struct)
|
||||||
|
|
||||||
shader := fmt.tprintf(
|
shader := fmt.tprintf(
|
||||||
@@ -653,11 +667,11 @@ on_device :: proc "c" (
|
|||||||
visibility = {.Vertex},
|
visibility = {.Vertex},
|
||||||
buffer = {
|
buffer = {
|
||||||
type = .Uniform,
|
type = .Uniform,
|
||||||
minBindingSize = cast(u64)size_of(Renderable_Uniform),
|
minBindingSize = cast(u64)size_of(Object_Uniform),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
state.renderable_bind_group_layout = wgpu.DeviceCreateBindGroupLayout(
|
state.objects_bind_group_layout = wgpu.DeviceCreateBindGroupLayout(
|
||||||
state.device,
|
state.device,
|
||||||
&{
|
&{
|
||||||
label = "renderable layout",
|
label = "renderable layout",
|
||||||
@@ -690,7 +704,7 @@ on_device :: proc "c" (
|
|||||||
group_layouts := [?]wgpu.BindGroupLayout {
|
group_layouts := [?]wgpu.BindGroupLayout {
|
||||||
state.camera_bind_group_layout,
|
state.camera_bind_group_layout,
|
||||||
state.material_bind_group_layout,
|
state.material_bind_group_layout,
|
||||||
state.renderable_bind_group_layout,
|
state.objects_bind_group_layout,
|
||||||
}
|
}
|
||||||
state.pipeline_layout = wgpu.DeviceCreatePipelineLayout(
|
state.pipeline_layout = wgpu.DeviceCreatePipelineLayout(
|
||||||
state.device,
|
state.device,
|
||||||
|
|||||||
Reference in New Issue
Block a user