void updateDynamicUniformBuffer(bool force = false) { // Update at max. 60 fps animationTimer += (frameTimer * 100.0f); if ((animationTimer <= 1.0f / 60.0f) && (!force)) { return; } // Dynamic ubo with per-object model matrices indexed by offsets in the command buffer uint dim = (uint)(Math.Pow(OBJECT_INSTANCES, (1.0f / 3.0f))); Vector3 offset = new Vector3(5.0f); for (uint x = 0; x < dim; x++) { for (uint y = 0; y < dim; y++) { for (uint z = 0; z < dim; z++) { uint index = x * dim * dim + y * dim + z; // Aligned offset Matrix4x4 *modelMat = (Matrix4x4 *)(((ulong)uboDataDynamic_model + (index * (ulong)dynamicAlignment))); // Update rotations rotations[index] += animationTimer * rotationSpeeds[index]; // Update matrices Vector3 pos = new Vector3(-((dim * offset.X) / 2.0f) + offset.X / 2.0f + x * offset.X, -((dim * offset.Y) / 2.0f) + offset.Y / 2.0f + y * offset.Y, -((dim * offset.Z) / 2.0f) + offset.Z / 2.0f + z * offset.Z); * modelMat = Matrix4x4.CreateTranslation(pos); * modelMat = Matrix4x4.CreateRotationX(Util.DegreesToRadians(rotations[index].X)) * *modelMat; * modelMat = Matrix4x4.CreateRotationY(Util.DegreesToRadians(rotations[index].Y)) * *modelMat; * modelMat = Matrix4x4.CreateRotationZ(Util.DegreesToRadians(rotations[index].Z)) * *modelMat; } } } animationTimer = 0.0f; Unsafe.CopyBlock(uniformBuffers_dynamic.mapped, uboDataDynamic_model, (uint)uniformBuffers_dynamic.size); // Flush to make changes visible to the host VkMappedMemoryRange memoryRange = Initializers.mappedMemoryRange(); memoryRange.memory = uniformBuffers_dynamic.memory; memoryRange.size = uniformBuffers_dynamic.size; vkFlushMappedMemoryRanges(device, 1, &memoryRange); }
/** * Create a buffer on the device * * @param usageFlags Usage flag bitmask for the buffer (i.e. index, vertex, uniform buffer) * @param memoryPropertyFlags Memory properties for this buffer (i.e. device local, host visible, coherent) * @param size Size of the buffer in byes * @param buffer Pointer to the buffer handle acquired by the function * @param memory Pointer to the memory handle acquired by the function * @param data Pointer to the data that should be copied to the buffer after creation (optional, if not set, no data is copied over) * * @return VK_SUCCESS if buffer handle and memory have been created and (optionally passed) data has been copied */ public VkResult createBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, ulong size, VkBuffer *buffer, VkDeviceMemory *memory, void *data = null) { // Create the buffer handle VkBufferCreateInfo bufferCreateInfo = Initializers.bufferCreateInfo(usageFlags, size); bufferCreateInfo.sharingMode = VkSharingMode.Exclusive; Util.CheckResult(vkCreateBuffer(LogicalDevice, &bufferCreateInfo, null, buffer)); // Create the memory backing up the buffer handle VkMemoryRequirements memReqs; VkMemoryAllocateInfo memAlloc = Initializers.memoryAllocateInfo(); vkGetBufferMemoryRequirements(LogicalDevice, *buffer, &memReqs); memAlloc.allocationSize = memReqs.size; // Find a memory type index that fits the properties of the buffer memAlloc.memoryTypeIndex = GetMemoryType(memReqs.memoryTypeBits, memoryPropertyFlags); Util.CheckResult(vkAllocateMemory(LogicalDevice, &memAlloc, null, memory)); // If a pointer to the buffer data has been passed, map the buffer and copy over the data if (data != null) { void *mapped; Util.CheckResult(vkMapMemory(LogicalDevice, *memory, 0, size, 0, &mapped)); Unsafe.CopyBlock(mapped, data, (uint)size); // If host coherency hasn't been requested, do a manual flush to make writes visible if ((memoryPropertyFlags & VkMemoryPropertyFlags.HostCoherent) == 0) { VkMappedMemoryRange mappedRange = Initializers.mappedMemoryRange(); mappedRange.memory = *memory; mappedRange.offset = 0; mappedRange.size = size; vkFlushMappedMemoryRanges(LogicalDevice, 1, &mappedRange); } vkUnmapMemory(LogicalDevice, *memory); } // Attach the memory to the buffer object Util.CheckResult(vkBindBufferMemory(LogicalDevice, *buffer, *memory, 0)); return(VkResult.Success); }