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 |
