Mercurial > games > semicongine
comparison src/semicongine/renderer.nim @ 326:4ec852355750
fix: many issues, better mesh-handling, still need to cope with different binding numbers when using different pipelines...
author | Sam <sam@basx.dev> |
---|---|
date | Fri, 25 Aug 2023 00:29:51 +0700 |
parents | 9defff46da48 |
children | a63bd8f29252 |
comparison
equal
deleted
inserted
replaced
325:0c3f4f6f1aa2 | 326:4ec852355750 |
---|---|
1 import std/options | 1 import std/options |
2 import std/tables | 2 import std/tables |
3 import std/strformat | 3 import std/strformat |
4 import std/sequtils | |
4 import std/logging | 5 import std/logging |
5 import std/sequtils | 6 import std/enumerate |
6 | 7 |
7 import ./core | 8 import ./core |
8 import ./vulkan/buffer | 9 import ./vulkan/buffer |
9 import ./vulkan/device | 10 import ./vulkan/device |
10 import ./vulkan/drawable | 11 import ./vulkan/drawable |
17 import ./vulkan/image | 18 import ./vulkan/image |
18 | 19 |
19 import ./scene | 20 import ./scene |
20 import ./mesh | 21 import ./mesh |
21 | 22 |
23 const MATERIALINDEXATTRIBUTE = "materialIndex" | |
24 const TRANSFORMATTRIBUTE = "transform" | |
25 | |
22 type | 26 type |
23 SceneData = object | 27 SceneData = object |
24 drawables*: OrderedTable[Mesh, Drawable] | 28 drawables*: seq[tuple[drawable: Drawable, meshIndex: int]] |
25 vertexBuffers*: Table[MemoryPerformanceHint, Buffer] | 29 vertexBuffers*: Table[MemoryPerformanceHint, Buffer] |
26 indexBuffer*: Buffer | 30 indexBuffer*: Buffer |
27 uniformBuffers*: Table[VkPipeline, seq[Buffer]] # one per frame-in-flight | 31 uniformBuffers*: Table[VkPipeline, seq[Buffer]] # one per frame-in-flight |
28 textures*: Table[string, seq[VulkanTexture]] # per frame-in-flight | 32 textures*: Table[string, seq[VulkanTexture]] # per frame-in-flight |
29 attributeLocation*: Table[string, MemoryPerformanceHint] | 33 attributeLocation*: Table[string, MemoryPerformanceHint] |
30 attributeBindingNumber*: Table[string, int] | 34 attributeBindingNumber*: Table[string, int] |
31 transformAttribute: string # name of attribute that is used for per-instance mesh transformation | |
32 materialIndexAttribute: string # name of attribute that is used for material selection | |
33 materials: seq[Material] | |
34 entityTransformationCache: Table[Mesh, Mat4] # remembers last transformation, avoid to send GPU-updates if no changes | |
35 descriptorPools*: Table[VkPipeline, DescriptorPool] | 35 descriptorPools*: Table[VkPipeline, DescriptorPool] |
36 descriptorSets*: Table[VkPipeline, seq[DescriptorSet]] | 36 descriptorSets*: Table[VkPipeline, seq[DescriptorSet]] |
37 materials: seq[Material] | |
37 Renderer* = object | 38 Renderer* = object |
38 device: Device | 39 device: Device |
39 surfaceFormat: VkSurfaceFormatKHR | 40 surfaceFormat: VkSurfaceFormatKHR |
40 renderPass: RenderPass | 41 renderPass: RenderPass |
41 swapchain: Swapchain | 42 swapchain: Swapchain |
42 scenedata: Table[Scene, SceneData] | 43 scenedata: Table[Scene, SceneData] |
43 emptyTexture: VulkanTexture | 44 emptyTexture: VulkanTexture |
44 | 45 |
45 func usesMaterialType(scenedata: SceneData, materialType: string): bool = | 46 func usesMaterialType(scene: Scene, materialType: string): bool = |
46 for drawable in scenedata.drawables.values: | 47 return scene.meshes.anyIt(it.material.materialType == materialType) |
47 if drawable.mesh.material.materialType == materialType: | |
48 return true | |
49 return false | |
50 | 48 |
51 proc initRenderer*(device: Device, shaders: Table[string, ShaderConfiguration], clearColor=Vec4f([0.8'f32, 0.8'f32, 0.8'f32, 1'f32])): Renderer = | 49 proc initRenderer*(device: Device, shaders: Table[string, ShaderConfiguration], clearColor=Vec4f([0.8'f32, 0.8'f32, 0.8'f32, 1'f32])): Renderer = |
52 assert device.vk.valid | 50 assert device.vk.valid |
53 | 51 |
54 result.device = device | 52 result.device = device |
60 raise newException(Exception, "Unable to create swapchain") | 58 raise newException(Exception, "Unable to create swapchain") |
61 | 59 |
62 result.swapchain = swapchain.get() | 60 result.swapchain = swapchain.get() |
63 result.emptyTexture = device.uploadTexture(EMPTYTEXTURE) | 61 result.emptyTexture = device.uploadTexture(EMPTYTEXTURE) |
64 | 62 |
65 func inputs(renderer: Renderer): seq[ShaderAttribute] = | 63 func inputs(renderer: Renderer, scene: Scene): seq[ShaderAttribute] = |
64 var found: Table[string, ShaderAttribute] | |
66 for i in 0 ..< renderer.renderPass.subpasses.len: | 65 for i in 0 ..< renderer.renderPass.subpasses.len: |
67 for pipeline in renderer.renderPass.subpasses[i].pipelines.values: | 66 for materialType, pipeline in renderer.renderPass.subpasses[i].pipelines.pairs: |
68 result.add pipeline.inputs | 67 if scene.usesMaterialType(materialType): |
69 | 68 for input in pipeline.inputs: |
70 func samplers(renderer: Renderer): seq[ShaderAttribute] = | 69 if found.contains(input.name): |
70 assert input == found[input.name] | |
71 else: | |
72 result.add input | |
73 found[input.name] = input | |
74 | |
75 func samplers(renderer: Renderer, scene: Scene): seq[ShaderAttribute] = | |
71 for i in 0 ..< renderer.renderPass.subpasses.len: | 76 for i in 0 ..< renderer.renderPass.subpasses.len: |
72 for pipeline in renderer.renderPass.subpasses[i].pipelines.values: | 77 for materialType, pipeline in renderer.renderPass.subpasses[i].pipelines.pairs: |
73 result.add pipeline.samplers | 78 if scene.usesMaterialType(materialType): |
74 | 79 result.add pipeline.samplers |
75 proc setupDrawableBuffers*(renderer: var Renderer, scene: Scene) = | 80 |
81 proc setupDrawableBuffers*(renderer: var Renderer, scene: var Scene) = | |
76 assert not (scene in renderer.scenedata) | 82 assert not (scene in renderer.scenedata) |
77 const VERTEX_ATTRIB_ALIGNMENT = 4 # used for buffer alignment | 83 const VERTEX_ATTRIB_ALIGNMENT = 4 # used for buffer alignment |
78 | 84 |
79 let | 85 let |
80 inputs = renderer.inputs | 86 inputs = renderer.inputs(scene) |
81 samplers = renderer.samplers | 87 samplers = renderer.samplers(scene) |
82 var scenedata = SceneData() | 88 var scenedata = SceneData() |
83 | 89 |
84 # if mesh transformation are handled through the scenegraph-transformation, set it up here | 90 for mesh in scene.meshes: |
85 if scene.transformAttribute != "": | |
86 var hasTransformAttribute = false | |
87 for input in inputs: | |
88 if input.name == scene.transformAttribute: | |
89 assert input.perInstance == true, $input | |
90 assert getDataType[Mat4]() == input.thetype, $input | |
91 hasTransformAttribute = true | |
92 assert hasTransformAttribute | |
93 scenedata.transformAttribute = scene.transformAttribute | |
94 | |
95 # check if we have support for material indices, if required | |
96 if scene.materialIndexAttribute != "": | |
97 var hasMaterialIndexAttribute = false | |
98 for input in inputs: | |
99 if input.name == scene.materialIndexAttribute: | |
100 assert getDataType[uint16]() == input.thetype | |
101 hasMaterialIndexAttribute = true | |
102 assert hasMaterialIndexAttribute | |
103 scenedata.materialIndexAttribute = scene.materialIndexAttribute | |
104 | |
105 for mesh in allComponentsOfType[Mesh](scene.root): | |
106 if mesh.material != nil and not scenedata.materials.contains(mesh.material): | 91 if mesh.material != nil and not scenedata.materials.contains(mesh.material): |
107 scenedata.materials.add mesh.material | 92 scenedata.materials.add mesh.material |
108 for textureName, texture in mesh.material.textures.pairs: | 93 for textureName, texture in mesh.material.textures.pairs: |
109 if not scenedata.textures.hasKey(textureName): | 94 if not scenedata.textures.hasKey(textureName): |
110 scenedata.textures[textureName] = @[] | 95 scenedata.textures[textureName] = @[] |
111 scenedata.textures[textureName].add renderer.device.uploadTexture(texture) | 96 scenedata.textures[textureName].add renderer.device.uploadTexture(texture) |
112 | 97 |
113 # find all meshes, populate missing attribute values for shader | 98 # find all meshes, populate missing attribute values for shader |
114 var allMeshes: seq[Mesh] | 99 for mesh in scene.meshes.mitems: |
115 for mesh in allComponentsOfType[Mesh](scene.root): | |
116 allMeshes.add mesh | |
117 for inputAttr in inputs: | 100 for inputAttr in inputs: |
118 if scenedata.materialIndexAttribute != "" and inputAttr.name == scenedata.materialIndexAttribute: | 101 if inputAttr.name == TRANSFORMATTRIBUTE: |
119 assert mesh.material != nil, "Missing material specification for mesh. Either set the 'materials' attribute or pass the argument 'materialIndexAttribute=\"\"' when calling 'addScene'" | 102 mesh.initInstanceAttribute(inputAttr.name, inputAttr.thetype) |
103 elif inputAttr.name == MATERIALINDEXATTRIBUTE: | |
104 assert mesh.material != nil, "Missing material specification for mesh. Set material attribute on mesh" | |
120 let matIndex = scenedata.materials.find(mesh.material) | 105 let matIndex = scenedata.materials.find(mesh.material) |
121 if matIndex < 0: | 106 if matIndex < 0: |
122 raise newException(Exception, &"Required material '{mesh.material}' not available in scene (available are: {scenedata.materials})") | 107 raise newException(Exception, &"Required material '{mesh.material}' not available in scene (available are: {scenedata.materials})") |
123 mesh.initAttribute(inputAttr, uint16(matIndex)) | 108 mesh.initInstanceAttribute(inputAttr.name, uint16(matIndex)) |
124 elif not mesh.hasAttribute(inputAttr.name): | 109 elif not mesh.attributes.contains(inputAttr.name): |
125 warn(&"Mesh is missing data for shader attribute {inputAttr.name}, auto-filling with empty values") | 110 warn(&"Mesh is missing data for shader attribute {inputAttr.name}, auto-filling with empty values") |
126 mesh.initAttribute(inputAttr) | 111 if inputAttr.perInstance: |
112 mesh.initInstanceAttribute(inputAttr.name, inputAttr.thetype) | |
113 else: | |
114 mesh.initVertexAttribute(inputAttr.name, inputAttr.thetype) | |
127 assert mesh.attributeType(inputAttr.name) == inputAttr.thetype, &"mesh attribute {inputAttr.name} has type {mesh.attributeType(inputAttr.name)} but shader expects {inputAttr.thetype}" | 115 assert mesh.attributeType(inputAttr.name) == inputAttr.thetype, &"mesh attribute {inputAttr.name} has type {mesh.attributeType(inputAttr.name)} but shader expects {inputAttr.thetype}" |
128 | 116 |
129 # create index buffer if necessary | 117 # create index buffer if necessary |
130 var indicesBufferSize = 0'u64 | 118 var indicesBufferSize = 0 |
131 for mesh in allMeshes: | 119 for mesh in scene.meshes: |
132 if mesh.indexType != MeshIndexType.None: | 120 if mesh.indexType != MeshIndexType.None: |
133 let indexAlignment = case mesh.indexType | 121 let indexAlignment = case mesh.indexType |
134 of MeshIndexType.None: 0'u64 | 122 of MeshIndexType.None: 0 |
135 of Tiny: 1'u64 | 123 of Tiny: 1 |
136 of Small: 2'u64 | 124 of Small: 2 |
137 of Big: 4'u64 | 125 of Big: 4 |
138 # index value alignment required by Vulkan | 126 # index value alignment required by Vulkan |
139 if indicesBufferSize mod indexAlignment != 0: | 127 if indicesBufferSize mod indexAlignment != 0: |
140 indicesBufferSize += indexAlignment - (indicesBufferSize mod indexAlignment) | 128 indicesBufferSize += indexAlignment - (indicesBufferSize mod indexAlignment) |
141 indicesBufferSize += mesh.indexSize | 129 indicesBufferSize += mesh.indexSize |
142 if indicesBufferSize > 0: | 130 if indicesBufferSize > 0: |
148 ) | 136 ) |
149 | 137 |
150 # create vertex buffers and calculcate offsets | 138 # create vertex buffers and calculcate offsets |
151 # trying to use one buffer per memory type | 139 # trying to use one buffer per memory type |
152 var | 140 var |
153 perLocationOffsets: Table[MemoryPerformanceHint, uint64] | 141 perLocationOffsets: Table[MemoryPerformanceHint, int] |
154 perLocationSizes: Table[MemoryPerformanceHint, uint64] | 142 perLocationSizes: Table[MemoryPerformanceHint, int] |
155 bindingNumber = 0 | 143 bindingNumber = 0 |
156 for hint in MemoryPerformanceHint: | 144 for hint in MemoryPerformanceHint: |
157 perLocationOffsets[hint] = 0 | 145 perLocationOffsets[hint] = 0 |
158 perLocationSizes[hint] = 0 | 146 perLocationSizes[hint] = 0 |
159 for attribute in inputs: | 147 for attribute in inputs: |
160 scenedata.attributeLocation[attribute.name] = attribute.memoryPerformanceHint | 148 scenedata.attributeLocation[attribute.name] = attribute.memoryPerformanceHint |
161 scenedata.attributeBindingNumber[attribute.name] = bindingNumber | 149 scenedata.attributeBindingNumber[attribute.name] = bindingNumber |
162 inc bindingNumber | 150 inc bindingNumber |
163 # setup one buffer per attribute-location-type | 151 # setup one buffer per attribute-location-type |
164 for mesh in allMeshes: | 152 for mesh in scene.meshes: |
165 # align size to VERTEX_ATTRIB_ALIGNMENT bytes (the important thing is the correct alignment of the offsets, but | 153 # align size to VERTEX_ATTRIB_ALIGNMENT bytes (the important thing is the correct alignment of the offsets, but |
166 # we need to expand the buffer size as well, therefore considering alignment already here as well | 154 # we need to expand the buffer size as well, therefore considering alignment already here as well |
167 if perLocationSizes[attribute.memoryPerformanceHint] mod VERTEX_ATTRIB_ALIGNMENT != 0: | 155 if perLocationSizes[attribute.memoryPerformanceHint] mod VERTEX_ATTRIB_ALIGNMENT != 0: |
168 perLocationSizes[attribute.memoryPerformanceHint] += VERTEX_ATTRIB_ALIGNMENT - (perLocationSizes[attribute.memoryPerformanceHint] mod VERTEX_ATTRIB_ALIGNMENT) | 156 perLocationSizes[attribute.memoryPerformanceHint] += VERTEX_ATTRIB_ALIGNMENT - (perLocationSizes[attribute.memoryPerformanceHint] mod VERTEX_ATTRIB_ALIGNMENT) |
169 perLocationSizes[attribute.memoryPerformanceHint] += mesh.attributeSize(attribute.name) | 157 perLocationSizes[attribute.memoryPerformanceHint] += mesh.attributeSize(attribute.name) |
175 requireMappable=memoryPerformanceHint==PreferFastWrite, | 163 requireMappable=memoryPerformanceHint==PreferFastWrite, |
176 preferVRAM=true, | 164 preferVRAM=true, |
177 ) | 165 ) |
178 | 166 |
179 # fill vertex buffers | 167 # fill vertex buffers |
180 var indexBufferOffset = 0'u64 | 168 var indexBufferOffset = 0 |
181 for mesh in allMeshes: | 169 for (meshIndex, mesh) in enumerate(scene.meshes): |
182 var offsets: seq[(string, MemoryPerformanceHint, uint64)] | 170 var offsets: seq[(string, MemoryPerformanceHint, int)] |
183 for attribute in inputs: | 171 for attribute in inputs: |
184 offsets.add (attribute.name, attribute.memoryPerformanceHint, perLocationOffsets[attribute.memoryPerformanceHint]) | 172 offsets.add (attribute.name, attribute.memoryPerformanceHint, perLocationOffsets[attribute.memoryPerformanceHint]) |
185 var (pdata, size) = mesh.getRawData(attribute.name) | 173 var (pdata, size) = mesh.getRawData(attribute.name) |
186 if pdata != nil: # no data | 174 if pdata != nil: # no data |
187 scenedata.vertexBuffers[attribute.memoryPerformanceHint].setData(pdata, size, perLocationOffsets[attribute.memoryPerformanceHint]) | 175 scenedata.vertexBuffers[attribute.memoryPerformanceHint].setData(pdata, size, perLocationOffsets[attribute.memoryPerformanceHint]) |
189 if perLocationOffsets[attribute.memoryPerformanceHint] mod VERTEX_ATTRIB_ALIGNMENT != 0: | 177 if perLocationOffsets[attribute.memoryPerformanceHint] mod VERTEX_ATTRIB_ALIGNMENT != 0: |
190 perLocationOffsets[attribute.memoryPerformanceHint] += VERTEX_ATTRIB_ALIGNMENT - (perLocationOffsets[attribute.memoryPerformanceHint] mod VERTEX_ATTRIB_ALIGNMENT) | 178 perLocationOffsets[attribute.memoryPerformanceHint] += VERTEX_ATTRIB_ALIGNMENT - (perLocationOffsets[attribute.memoryPerformanceHint] mod VERTEX_ATTRIB_ALIGNMENT) |
191 | 179 |
192 let indexed = mesh.indexType != MeshIndexType.None | 180 let indexed = mesh.indexType != MeshIndexType.None |
193 var drawable = Drawable( | 181 var drawable = Drawable( |
194 mesh: mesh, | |
195 elementCount: if indexed: mesh.indicesCount else: mesh.vertexCount, | 182 elementCount: if indexed: mesh.indicesCount else: mesh.vertexCount, |
196 bufferOffsets: offsets, | 183 bufferOffsets: offsets, |
197 instanceCount: mesh.instanceCount, | 184 instanceCount: mesh.instanceCount, |
198 indexed: indexed, | 185 indexed: indexed, |
199 ) | 186 ) |
200 if indexed: | 187 if indexed: |
201 let indexAlignment = case mesh.indexType | 188 let indexAlignment = case mesh.indexType |
202 of MeshIndexType.None: 0'u64 | 189 of MeshIndexType.None: 0 |
203 of Tiny: 1'u64 | 190 of Tiny: 1 |
204 of Small: 2'u64 | 191 of Small: 2 |
205 of Big: 4'u64 | 192 of Big: 4 |
206 # index value alignment required by Vulkan | 193 # index value alignment required by Vulkan |
207 if indexBufferOffset mod indexAlignment != 0: | 194 if indexBufferOffset mod indexAlignment != 0: |
208 indexBufferOffset += indexAlignment - (indexBufferOffset mod indexAlignment) | 195 indexBufferOffset += indexAlignment - (indexBufferOffset mod indexAlignment) |
209 drawable.indexBufferOffset = indexBufferOffset | 196 drawable.indexBufferOffset = indexBufferOffset |
210 drawable.indexType = mesh.indexType | 197 drawable.indexType = mesh.indexType |
211 var (pdata, size) = mesh.getRawIndexData() | 198 var (pdata, size) = mesh.getRawIndexData() |
212 scenedata.indexBuffer.setData(pdata, size, indexBufferOffset) | 199 scenedata.indexBuffer.setData(pdata, size, indexBufferOffset) |
213 indexBufferOffset += size | 200 indexBufferOffset += size |
214 scenedata.drawables[mesh] = drawable | 201 scenedata.drawables.add (drawable, meshIndex) |
215 | 202 |
216 # setup uniforms and samplers | 203 # setup uniforms and samplers |
217 for subpass_i in 0 ..< renderer.renderPass.subpasses.len: | 204 for subpass_i in 0 ..< renderer.renderPass.subpasses.len: |
218 for material, pipeline in renderer.renderPass.subpasses[subpass_i].pipelines.pairs: | 205 for materialType, pipeline in renderer.renderPass.subpasses[subpass_i].pipelines.pairs: |
219 var uniformBufferSize = 0'u64 | 206 if scene.usesMaterialType(materialType): |
220 for uniform in pipeline.uniforms: | 207 var uniformBufferSize = 0 |
221 uniformBufferSize += uniform.size | 208 for uniform in pipeline.uniforms: |
222 if uniformBufferSize > 0: | 209 uniformBufferSize += uniform.size |
223 scenedata.uniformBuffers[pipeline.vk] = newSeq[Buffer]() | 210 if uniformBufferSize > 0: |
211 scenedata.uniformBuffers[pipeline.vk] = newSeq[Buffer]() | |
212 for frame_i in 0 ..< renderer.swapchain.inFlightFrames: | |
213 scenedata.uniformBuffers[pipeline.vk].add renderer.device.createBuffer( | |
214 size=uniformBufferSize, | |
215 usage=[VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT], | |
216 requireMappable=true, | |
217 preferVRAM=true, | |
218 ) | |
219 | |
220 var poolsizes = @[(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, renderer.swapchain.inFlightFrames)] | |
221 if samplers.len > 0: | |
222 var samplercount = 0 | |
223 for sampler in samplers: | |
224 samplercount += (if sampler.arrayCount == 0: 1 else: sampler.arrayCount) | |
225 poolsizes.add (VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, renderer.swapchain.inFlightFrames * samplercount * 2) | |
226 | |
227 scenedata.descriptorPools[pipeline.vk] = renderer.device.createDescriptorSetPool(poolsizes) | |
228 | |
229 scenedata.descriptorSets[pipeline.vk] = pipeline.setupDescriptors( | |
230 scenedata.descriptorPools[pipeline.vk], | |
231 scenedata.uniformBuffers.getOrDefault(pipeline.vk, @[]), | |
232 scenedata.textures, | |
233 inFlightFrames=renderer.swapchain.inFlightFrames, | |
234 emptyTexture=renderer.emptyTexture, | |
235 ) | |
224 for frame_i in 0 ..< renderer.swapchain.inFlightFrames: | 236 for frame_i in 0 ..< renderer.swapchain.inFlightFrames: |
225 scenedata.uniformBuffers[pipeline.vk].add renderer.device.createBuffer( | 237 scenedata.descriptorSets[pipeline.vk][frame_i].writeDescriptorSet() |
226 size=uniformBufferSize, | |
227 usage=[VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT], | |
228 requireMappable=true, | |
229 preferVRAM=true, | |
230 ) | |
231 | |
232 var poolsizes = @[(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, uint32(renderer.swapchain.inFlightFrames))] | |
233 if samplers.len > 0: | |
234 var samplercount = 0'u32 | |
235 for sampler in samplers: | |
236 samplercount += (if sampler.arrayCount == 0: 1'u32 else: sampler.arrayCount) | |
237 poolsizes.add (VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, uint32(renderer.swapchain.inFlightFrames) * samplercount * 2) | |
238 | |
239 scenedata.descriptorPools[pipeline.vk] = renderer.device.createDescriptorSetPool(poolsizes) | |
240 | |
241 scenedata.descriptorSets[pipeline.vk] = pipeline.setupDescriptors( | |
242 scenedata.descriptorPools[pipeline.vk], | |
243 scenedata.uniformBuffers.getOrDefault(pipeline.vk, @[]), | |
244 scenedata.textures, | |
245 inFlightFrames=renderer.swapchain.inFlightFrames, | |
246 emptyTexture=renderer.emptyTexture, | |
247 ) | |
248 for frame_i in 0 ..< renderer.swapchain.inFlightFrames: | |
249 scenedata.descriptorSets[pipeline.vk][frame_i].writeDescriptorSet() | |
250 | 238 |
251 renderer.scenedata[scene] = scenedata | 239 renderer.scenedata[scene] = scenedata |
252 | 240 |
253 proc refreshMeshAttributeData(sceneData: var SceneData, mesh: Mesh, attribute: string) = | 241 proc refreshMeshAttributeData(renderer: Renderer, scene: Scene, drawable: Drawable, meshIndex: int, attribute: string) = |
254 debug &"Refreshing data on mesh {mesh} for {attribute}" | 242 debug &"Refreshing data on mesh {scene.meshes[meshIndex]} for {attribute}" |
255 # ignore attributes that are not used in this shader | 243 # ignore attributes that are not used in this shader |
256 if not (attribute in sceneData.attributeLocation): | 244 if not (attribute in renderer.scenedata[scene].attributeLocation): |
257 return | 245 return |
258 var (pdata, size) = mesh.getRawData(attribute) | 246 var (pdata, size) = scene.meshes[meshIndex].getRawData(attribute) |
259 let memoryPerformanceHint = sceneData.attributeLocation[attribute] | 247 let memoryPerformanceHint = renderer.scenedata[scene].attributeLocation[attribute] |
260 let bindingNumber = sceneData.attributeBindingNumber[attribute] | 248 let bindingNumber = renderer.scenedata[scene].attributeBindingNumber[attribute] |
261 sceneData.vertexBuffers[memoryPerformanceHint].setData(pdata, size, sceneData.drawables[mesh].bufferOffsets[bindingNumber][2]) | 249 renderer.scenedata[scene].vertexBuffers[memoryPerformanceHint].setData(pdata, size, drawable.bufferOffsets[bindingNumber][2]) |
262 | 250 |
263 proc updateMeshData*(renderer: var Renderer, scene: Scene) = | 251 proc updateMeshData*(renderer: var Renderer, scene: var Scene) = |
264 assert scene in renderer.scenedata | 252 assert scene in renderer.scenedata |
265 | 253 |
266 for mesh in allComponentsOfType[Mesh](scene.root): | 254 for (drawable, meshIndex) in renderer.scenedata[scene].drawables.mitems: |
267 # if mesh transformation attribute is enabled, update the model matrix | 255 if scene.meshes[meshIndex].attributes.contains(TRANSFORMATTRIBUTE): |
268 if renderer.scenedata[scene].transformAttribute != "": | 256 scene.meshes[meshIndex].updateInstanceTransforms(TRANSFORMATTRIBUTE) |
269 let transform = mesh.entity.getModelTransform() | 257 for attribute in scene.meshes[meshIndex].dirtyAttributes: |
270 if not (mesh in renderer.scenedata[scene].entityTransformationCache) or renderer.scenedata[scene].entityTransformationCache[mesh] != transform or mesh.areInstanceTransformsDirty : | 258 renderer.refreshMeshAttributeData(scene, drawable, meshIndex, attribute) |
271 var updatedTransform = newSeq[Mat4](int(mesh.instanceCount)) | 259 debug &"Update mesh attribute {attribute}" |
272 for i in 0 ..< mesh.instanceCount: | 260 scene.meshes[meshIndex].clearDirtyAttributes() |
273 updatedTransform[i] = transform * mesh.getInstanceTransform(i) | |
274 debug &"Update mesh transformation" | |
275 mesh.updateInstanceData(renderer.scenedata[scene].transformAttribute, updatedTransform) | |
276 renderer.scenedata[scene].entityTransformationCache[mesh] = transform | |
277 | |
278 # update any changed mesh attributes | |
279 for attribute in mesh.vertexAttributes: | |
280 if mesh.hasDataChanged(attribute): | |
281 renderer.scenedata[scene].refreshMeshAttributeData(mesh, attribute) | |
282 debug &"Update mesh vertex attribute {attribute}" | |
283 for attribute in mesh.instanceAttributes: | |
284 if mesh.hasDataChanged(attribute): | |
285 renderer.scenedata[scene].refreshMeshAttributeData(mesh, attribute) | |
286 debug &"Update mesh instance attribute {attribute}" | |
287 var m = mesh | |
288 m.clearDataChanged() | |
289 | |
290 proc updateAnimations*(renderer: var Renderer, scene: var Scene, dt: float32) = | |
291 for animation in allComponentsOfType[EntityAnimation](scene.root): | |
292 debug &"Update animation {animation}" | |
293 animation.update(dt) | |
294 | 261 |
295 proc updateUniformData*(renderer: var Renderer, scene: var Scene) = | 262 proc updateUniformData*(renderer: var Renderer, scene: var Scene) = |
296 assert scene in renderer.scenedata | 263 assert scene in renderer.scenedata |
297 | 264 |
298 for i in 0 ..< renderer.renderPass.subpasses.len: | 265 for i in 0 ..< renderer.renderPass.subpasses.len: |
299 for materialType, pipeline in renderer.renderPass.subpasses[i].pipelines.pairs: | 266 for materialType, pipeline in renderer.renderPass.subpasses[i].pipelines.pairs: |
300 if renderer.scenedata[scene].usesMaterialType(materialType) and renderer.scenedata[scene].uniformBuffers.hasKey(pipeline.vk) and renderer.scenedata[scene].uniformBuffers[pipeline.vk].len != 0: | 267 if scene.usesMaterialType(materialType) and renderer.scenedata[scene].uniformBuffers.hasKey(pipeline.vk) and renderer.scenedata[scene].uniformBuffers[pipeline.vk].len != 0: |
301 assert renderer.scenedata[scene].uniformBuffers[pipeline.vk][renderer.swapchain.currentInFlight].vk.valid | 268 assert renderer.scenedata[scene].uniformBuffers[pipeline.vk][renderer.swapchain.currentInFlight].vk.valid |
302 var offset = 0'u64 | 269 var offset = 0 |
303 for uniform in pipeline.uniforms: | 270 for uniform in pipeline.uniforms: |
304 if not scene.shaderGlobals.hasKey(uniform.name): | 271 if not scene.shaderGlobals.hasKey(uniform.name): |
305 raise newException(Exception, &"Uniform '{uniform.name}' not found in scene shaderGlobals") | 272 raise newException(Exception, &"Uniform '{uniform.name}' not found in scene shaderGlobals") |
306 if uniform.thetype != scene.shaderGlobals[uniform.name].thetype: | 273 if uniform.thetype != scene.shaderGlobals[uniform.name].thetype: |
307 raise newException(Exception, &"Uniform '{uniform.name}' has wrong type {uniform.thetype}, required is {scene.shaderGlobals[uniform.name].thetype}") | 274 raise newException(Exception, &"Uniform '{uniform.name}' has wrong type {uniform.thetype}, required is {scene.shaderGlobals[uniform.name].thetype}") |
308 debug &"Update uniforms {uniform.name}" | 275 debug &"Update uniforms {uniform.name}" |
309 let (pdata, size) = scene.shaderGlobals[uniform.name].getRawData() | 276 let (pdata, size) = scene.shaderGlobals[uniform.name].getRawData() |
310 renderer.scenedata[scene].uniformBuffers[pipeline.vk][renderer.swapchain.currentInFlight].setData(pdata, size, offset) | 277 renderer.scenedata[scene].uniformBuffers[pipeline.vk][renderer.swapchain.currentInFlight].setData(pdata, size, offset) |
311 offset += size | 278 offset += size |
312 | 279 |
313 proc render*(renderer: var Renderer, scene: var Scene) = | 280 proc render*(renderer: var Renderer, scene: Scene) = |
314 assert scene in renderer.scenedata | 281 assert scene in renderer.scenedata |
315 | 282 |
316 var | 283 var |
317 commandBufferResult = renderer.swapchain.nextFrame() | 284 commandBufferResult = renderer.swapchain.nextFrame() |
318 commandBuffer: VkCommandBuffer | 285 commandBuffer: VkCommandBuffer |
334 debug " ", location, ": ", buffer | 301 debug " ", location, ": ", buffer |
335 debug " Index buffer: ", renderer.scenedata[scene].indexBuffer | 302 debug " Index buffer: ", renderer.scenedata[scene].indexBuffer |
336 | 303 |
337 for i in 0 ..< renderer.renderPass.subpasses.len: | 304 for i in 0 ..< renderer.renderPass.subpasses.len: |
338 for materialType, pipeline in renderer.renderPass.subpasses[i].pipelines.pairs: | 305 for materialType, pipeline in renderer.renderPass.subpasses[i].pipelines.pairs: |
339 if renderer.scenedata[scene].usesMaterialType(materialType): | 306 if scene.usesMaterialType(materialType): |
340 debug &"Start pipeline for {materialType}" | 307 debug &"Start pipeline for {materialType}" |
341 commandBuffer.vkCmdBindPipeline(renderer.renderPass.subpasses[i].pipelineBindPoint, pipeline.vk) | 308 commandBuffer.vkCmdBindPipeline(renderer.renderPass.subpasses[i].pipelineBindPoint, pipeline.vk) |
342 commandBuffer.vkCmdBindDescriptorSets(renderer.renderPass.subpasses[i].pipelineBindPoint, pipeline.layout, 0, 1, addr(renderer.scenedata[scene].descriptorSets[pipeline.vk][renderer.swapchain.currentInFlight].vk), 0, nil) | 309 commandBuffer.vkCmdBindDescriptorSets(renderer.renderPass.subpasses[i].pipelineBindPoint, pipeline.layout, 0, 1, addr(renderer.scenedata[scene].descriptorSets[pipeline.vk][renderer.swapchain.currentInFlight].vk), 0, nil) |
343 | 310 |
344 for drawable in renderer.scenedata[scene].drawables.values: | 311 for (drawable, meshIndex) in renderer.scenedata[scene].drawables: |
345 if drawable.mesh.material != nil and drawable.mesh.material.materialType == materialType: | 312 if scene.meshes[meshIndex].material != nil and scene.meshes[meshIndex].material.materialType == materialType: |
346 drawable.draw(commandBuffer, vertexBuffers=renderer.scenedata[scene].vertexBuffers, indexBuffer=renderer.scenedata[scene].indexBuffer) | 313 drawable.draw(commandBuffer, vertexBuffers=renderer.scenedata[scene].vertexBuffers, indexBuffer=renderer.scenedata[scene].indexBuffer) |
347 | 314 |
348 if i < renderer.renderPass.subpasses.len - 1: | 315 if i < renderer.renderPass.subpasses.len - 1: |
349 commandBuffer.vkCmdNextSubpass(VK_SUBPASS_CONTENTS_INLINE) | 316 commandBuffer.vkCmdNextSubpass(VK_SUBPASS_CONTENTS_INLINE) |
350 | 317 |