private WorldData AllocateWorldData(MgStorageBlockAllocationRequest dynamiceRequest, uint maxUniformBufferRange) { const uint LOW_RES = 16384; const uint HIGH_RES = 65536; if (maxUniformBufferRange < LOW_RES) { throw new InvalidOperationException("not enough space"); } var noOfCameras = 32U; var noOfLights = 256U; if (maxUniformBufferRange >= HIGH_RES) { noOfCameras = 128U; noOfLights = 1024U; } var upperLimit = (maxUniformBufferRange >= HIGH_RES) ? HIGH_RES : LOW_RES; var cameraStride = Marshal.SizeOf(typeof(CameraUBO)); var lightStride = Marshal.SizeOf(typeof(LightUBO)); var cameraLength = cameraStride * noOfCameras; var lightLength = lightStride * noOfLights; var totalSize = (ulong)(cameraLength + lightLength); if (totalSize > upperLimit) { throw new InvalidOperationException("not enough space for uniform block"); } var location = dynamiceRequest.Insert( new MgStorageBlockAllocationInfo { Usage = MgBufferUsageFlagBits.UNIFORM_BUFFER_BIT, MemoryPropertyFlags = MgMemoryPropertyFlagBits.HOST_VISIBLE_BIT, Size = totalSize, } ); return(new WorldData { StorageIndex = location, MaxNoOfCameras = noOfCameras, MaxNoOfLights = noOfLights, }); }
public void TwoBuckets_0() { var request = new MgStorageBlockAllocationRequest(); var cameras = new GltfBucketAllocationInfo <CameraUnit> { BucketSize = 3, Usage = Magnesium.MgBufferUsageFlagBits.UNIFORM_BUFFER_BIT, MemoryPropertyFlags = Magnesium.MgMemoryPropertyFlagBits.HOST_COHERENT_BIT, ElementByteSize = 0, }; var result = cameras.Prepare(4, request); Assert.AreEqual(4, result.Count); Assert.IsNotNull(result.Slots); Assert.AreEqual(2, result.Slots.Length); var actual = request.ToArray(); Assert.AreEqual(2, actual.Length); }
private static int ExtractVertices(uint vertexCount, MgStorageBlockAllocationRequest request, MgtfAccessor[] accessors, MgtfBufferView[] bufferViews, IMgtfPerVertexDataLocator locator, out GltfInterleavedOperation[] vertexCopies) { var totalSize = 0UL; var vertexFields = new int?[] { locator.Position, locator.Normal, locator.Tangent, locator.TexCoords0, locator.TexCoords1, locator.Color0, locator.Color1, locator.Joints0, locator.Joints1, locator.Weights0, locator.Weights1, }; var DEFAULT_PADDING_BYTE_STRIDE = new uint[] { 12U, 12U, 16U, 8U, 8U, 16U, 16U, 4U, 4U, 16U, 16U, }; var copyOps = new List <GltfInterleavedOperation>(); var vertexBufferStride = 0U; for (var i = 0; i < vertexFields.Length; i += 1) { var field = vertexFields[i]; if (field.HasValue) { var selected = accessors[field.Value]; var op = GenerateCopyOperation(selected, bufferViews); copyOps.Add(op); vertexBufferStride += op.ByteStride; totalSize += selected.TotalByteSize; } else { vertexBufferStride += DEFAULT_PADDING_BYTE_STRIDE[i]; totalSize += vertexCount * DEFAULT_PADDING_BYTE_STRIDE[i]; } } foreach (var op in copyOps) { op.DstStride = vertexBufferStride; } var vertexInfo = new MgStorageBlockAllocationInfo { MemoryPropertyFlags = MgMemoryPropertyFlagBits.HOST_COHERENT_BIT, Usage = MgBufferUsageFlagBits.VERTEX_BUFFER_BIT, ElementByteSize = vertexBufferStride, Size = totalSize, }; vertexCopies = copyOps.ToArray(); return(request.Insert(vertexInfo)); }
private GltfPrimitiveStorageLocation[] AllocateMeshes( MgStorageBlockAllocationRequest request, MgtfMesh[] meshes, MgtfAccessor[] accessors, MgtfBufferView[] bufferViews) { var noOfMeshes = meshes != null ? meshes.Length : 0; var locations = new List <GltfPrimitiveStorageLocation>(); for (var i = 0; i < noOfMeshes; i += 1) { var mesh = meshes[i]; var noOfPrimitives = mesh.Primitives != null ? mesh.Primitives.Length : 0; for (var j = 0; j < noOfPrimitives; j += 1) { var primitive = mesh.Primitives[j]; var locator = primitive.VertexLocations; int?indexLocation = null; GltfInterleavedOperation indexCopy = null; if (locator.Indices.HasValue) { var accessor = accessors[locator.Indices.Value]; indexCopy = GenerateCopyOperation(accessor, bufferViews); indexCopy.DstStride = accessor.ElementByteSize; indexLocation = request.Insert(GetIndexAllocation(accessor)); } var vertexLocation = ExtractVertices( primitive.VertexCount, request, accessors, bufferViews, locator, out GltfInterleavedOperation[] vertexCopies); var copyOperations = new List <GltfInterleavedOperation>(); if (indexCopy != null) { copyOperations.Add(indexCopy); } copyOperations.AddRange(vertexCopies); var location = new GltfPrimitiveStorageLocation { Mesh = i, MeshPrimitive = j, FinalDefinition = PadVertexDefinition(primitive.InitialDefinition), Index = indexLocation, Vertex = vertexLocation, CopyOperations = copyOperations.ToArray(), }; locations.Add(location); } } return(locations.ToArray()); }
private static int[] AllocateMaterials(MgtfMaterial[] materials, MgStorageBlockAllocationRequest dynamicRequest, MgPhysicalDeviceLimits limits) { // materials var query = new PerMaterialTextureStorageQuery(limits); var noOfSamplers = query.GetMaxNoOfCombinedImageSamplers(); const uint PBR_TEXTURES_PER_MATERIALS = 5U; var blockSize = (uint)Marshal.SizeOf(typeof(MaterialUBO)); const uint HI_RES = 32U; const uint LOW_RES = 16U; // GONNA RESERVE 5 BINDINGS SLOTS // IN VK, a global binding range is used by all descriptors // IN OPENGL/WEBGL, buffer and textures have the own binding range // THEREFORE, Mg standard is not to overlap binding values between descriptors // OTHERWISE, separate sets implementation (TODO) could be used to handle separate ranges const uint NO_OF_RESERVED_BINDINGS = 5U; var range = noOfSamplers - NO_OF_RESERVED_BINDINGS; if (noOfSamplers < LOW_RES) { throw new InvalidOperationException("not enough combined samplers for pbr"); } // pick between hi res and low res bool isHighRes = (noOfSamplers >= HI_RES); uint bindableImages = isHighRes ? 32U : 16U; var elementRange = query.GetElementRange( MgBufferUsageFlagBits.UNIFORM_BUFFER_BIT, PBR_TEXTURES_PER_MATERIALS, blockSize); if (isHighRes) { // floor(no_of_samplers - reserved_slots / textures_per_mat) = floor((32 - 5)/5) = 5 if (elementRange < 5U) { throw new InvalidOperationException("hi res not applicable"); } elementRange = 5U; } else { // floor(no_of_samplers - reserved_slots / textures_per_mat) = floor((16 - 5)/5) = 2 if (elementRange < 2U) { throw new InvalidOperationException("low res not applicable"); } elementRange = 2U; } var noOfAllocations = (materials.Length / elementRange); noOfAllocations += (materials.Length % elementRange == 0) ? 0 : 1; var info = new MgStorageBlockAllocationInfo { Usage = MgBufferUsageFlagBits.UNIFORM_BUFFER_BIT, MemoryPropertyFlags = MgMemoryPropertyFlagBits.HOST_VISIBLE_BIT, Size = elementRange * blockSize, }; var materialIndices = new int[noOfAllocations]; for (var i = 0; i < noOfAllocations; i += 1) { materialIndices[i] = dynamicRequest.Insert(info); } return(materialIndices); }
public void Prepare(IMgGraphicsConfiguration configuration, IMgGraphicsDevice screen) { var loader = new Loader(); var dataLoader = new DataLoader(); var device = configuration.Device; using (var fs = File.Open("Data/Triangle.gltf", FileMode.Open)) { // load model file var model = glTFLoader.Interface.LoadModel(fs); // load meta data var metaData = loader.LoadMetaData(model); // load data var data = dataLoader.LoadData(".", model); var staticRequest = new MgStorageBlockAllocationRequest(); // allocate partitions for static data // mesh var meshLocations = AllocateMeshes(staticRequest, metaData.Meshes, metaData.Accessors, metaData.BufferViews); var meshPrimitives = ExtractMeshPrimitives(metaData.Materials, out MgtfMaterial[] sceneMaterials, metaData.Meshes, meshLocations); // images var images = ExamineImages(data.Images, data.Buffers); // initialize static data storage var staticCreateInfo = new MgOptimizedStorageCreateInfo { Allocations = staticRequest.ToArray(), }; mStaticStorage = mBuilder.Build(staticCreateInfo); // build static artifacts // render target // descriptor set layout + pipeline layout var pass = new ScenePass { RenderTarget = screen, Effects = new[] { new ScenePassEffect { Factory = mPbrFactory, EffectLayout = mPbrFactory.CreateEffectLayout(configuration.Device), } } }; pass.Initialize( configuration.Device, meshPrimitives, sceneMaterials); // allocate dynamic data var dynamicRequest = new MgStorageBlockAllocationRequest(); var limits = new MgPhysicalDeviceLimits(); var worldData = AllocateWorldData(dynamicRequest, limits.MaxUniformBufferRange); var storageIndices = AllocateMaterials(sceneMaterials, dynamicRequest, limits); // per instance data // build dynamic artifacts // semaphores // fences // descriptor sets // initialize dynamic data storage // copy data across // buffers // images // map dynamic data // build command buffers } }