public int Insert(MgStorageBlockAllocationInfo info) { int count = mItems.Count; mItems.Add(info); return(count); }
private MgOptimizedStorageContainer GenerateMesh( glTFLoader.Schema.Gltf model, glTFLoader.Schema.Mesh mesh, IEffect effect, List <byte[]> buffers, BufferViewInfo[] bufferViews ) { var shaderLocations = effect.GetShaderAttributeLocations(); var accessors = new List <GltfMeshAccessor>(); uint primitiveIndex = 0U; foreach (var primitive in mesh.Primitives) { if (primitive.Indices.HasValue) { var accessor = ExtractAccessor(model, primitive.Indices.Value); accessor.PrimitiveIndex = primitiveIndex; accessor.Usage = MgBufferUsageFlagBits.INDEX_BUFFER_BIT; accessors.Add(accessor); } foreach (var attr in primitive.Attributes) { var locationName = attr.Key; var accessorIndex = attr.Value; var accessor = ExtractAccessor(model, accessorIndex); accessor.PrimitiveIndex = primitiveIndex; accessor.Usage = MgBufferUsageFlagBits.VERTEX_BUFFER_BIT; accessor.LocationIndex = shaderLocations[locationName]; accessor.LocationName = locationName; accessors.Add(accessor); } primitiveIndex += 1; } var usedBufferViews = new bool[bufferViews.Length]; var blockAllocations = new List <MgStorageBlockAllocationInfo>(); foreach (var attr in accessors) { var allocation = new MgStorageBlockAllocationInfo { MemoryPropertyFlags = MgMemoryPropertyFlagBits.HOST_COHERENT_BIT, Usage = attr.Usage, ElementByteSize = attr.ElementByteSize, Size = (ulong)(attr.NoOfComponents * attr.ElementCount * attr.ElementByteSize), }; if (attr.BufferViewIndex.HasValue) { usedBufferViews[attr.BufferViewIndex.Value] = true; } blockAllocations.Add(allocation); } var createInfo = new MgOptimizedStorageCreateInfo { Allocations = blockAllocations.ToArray(), }; var meshData = mBuilder.Build(createInfo); var metaData = InitializeMetaData(meshData, usedBufferViews, bufferViews, accessors); // copy buffer data into device memory CopyBuffersInto(meshData, buffers, bufferViews, accessors); return(meshData); }
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 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); }
private static GltfInterleavedOperation[] GenerateCopyOps(uint vertexCount, MgStorageBlockAllocationRequest request, GltfAccessor[] accessors, GltfBufferView[] bufferViews, IPerVertexDataLocator locator, GltfPrimitiveStorageLocation finalLocation) { 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 paddingByteStride = 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 = CreateCopyOp(copyOps, selected, bufferViews); vertexBufferStride += op.ByteStride; totalSize += selected.TotalByteSize; } else { vertexBufferStride += paddingByteStride[i]; totalSize += vertexCount * paddingByteStride[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, }; finalLocation.Vertex = request.Insert(vertexInfo); if (locator.Indices.HasValue) { var selected = accessors[locator.Indices.Value]; var op = CreateCopyOp(copyOps, selected, bufferViews); op.DstStride = selected.ElementByteSize; var indexInfo = new MgStorageBlockAllocationInfo { MemoryPropertyFlags = MgMemoryPropertyFlagBits.HOST_COHERENT_BIT, Usage = MgBufferUsageFlagBits.INDEX_BUFFER_BIT, Size = selected.TotalByteSize, ElementByteSize = selected.ElementByteSize, }; finalLocation.Index = request.Insert(indexInfo); } return(copyOps.ToArray()); }
public GltfScene Load(IMgDevice device, IMgEffectFramework framework, string modelFilePath) { var model = Interface.LoadModel(modelFilePath); var baseDir = Path.GetDirectoryName(modelFilePath); var buffers = ExtractBuffers(model, baseDir); var request = new MgStorageBlockAllocationRequest(); const int MAX_NO_OF_CAMERAS = 1; var cameraAllocationInfo = new GltfBucketAllocationInfo <CameraUBO> { BucketSize = MAX_NO_OF_CAMERAS, Usage = MgBufferUsageFlagBits.UNIFORM_BUFFER_BIT, MemoryPropertyFlags = MgMemoryPropertyFlagBits.HOST_VISIBLE_BIT, }; var cameraSlots = cameraAllocationInfo.Prepare(model.Cameras != null ? model.Cameras.Length : 0, request); var accessors = ExtractAccessors(model); var bufferViews = ExtractBufferViews(model); const int MAX_NO_OF_MATERIALS = 16; var materialAllocationInfo = new GltfBucketAllocationInfo <MaterialUBO> { BucketSize = MAX_NO_OF_MATERIALS, Usage = MgBufferUsageFlagBits.UNIFORM_BUFFER_BIT, MemoryPropertyFlags = MgMemoryPropertyFlagBits.HOST_VISIBLE_BIT, }; var images = ExtractImages(baseDir, model.Images, bufferViews, buffers); var samplers = ExtractSamplers(device, model.Samplers); const int MAX_NO_OF_LIGHTS = 4; const int MAX_NO_OF_TEXTURES = 16; // var textures = AllocateTextures(MAX_NO_OF_TEXTURES, model.Textures, images); var materialSlots = materialAllocationInfo.Prepare(model.Materials != null ? model.Materials.Length : 0, request); var materialChunks = ExtractMaterials(materialSlots.BucketSize, model.Materials); var meshes = ExtractMeshes(model, accessors, materialSlots); PadMeshes(meshes); var meshLocations = AllocateMeshes(request, meshes, accessors, bufferViews); var nodes = ExtractNodes(model, cameraSlots); var pDsCreateInfo = new MgDescriptorSetLayoutCreateInfo { Bindings = new[] { // CAMERA new MgDescriptorSetLayoutBinding { Binding = 0, DescriptorType = MgDescriptorType.UNIFORM_BUFFER, DescriptorCount = MAX_NO_OF_CAMERAS, StageFlags = MgShaderStageFlagBits.VERTEX_BIT, }, // LIGHTS new MgDescriptorSetLayoutBinding { Binding = 1, DescriptorType = MgDescriptorType.UNIFORM_BUFFER, DescriptorCount = MAX_NO_OF_LIGHTS, StageFlags = MgShaderStageFlagBits.VERTEX_BIT, }, // MATERIALS new MgDescriptorSetLayoutBinding { Binding = 2, DescriptorType = MgDescriptorType.UNIFORM_BUFFER, DescriptorCount = MAX_NO_OF_MATERIALS, StageFlags = MgShaderStageFlagBits.FRAGMENT_BIT, }, // TEXTURES new MgDescriptorSetLayoutBinding { Binding = 3, DescriptorType = MgDescriptorType.COMBINED_IMAGE_SAMPLER, DescriptorCount = MAX_NO_OF_TEXTURES, StageFlags = MgShaderStageFlagBits.FRAGMENT_BIT, }, } }; var err = device.CreateDescriptorSetLayout(pDsCreateInfo, null, out IMgDescriptorSetLayout dsLayout); if (err != Result.SUCCESS) { throw new InvalidOperationException("CreatePipelineLayout failed"); } var pCreateInfo = new MgPipelineLayoutCreateInfo { SetLayouts = new[] { dsLayout, } }; err = device.CreatePipelineLayout(pCreateInfo, null, out IMgPipelineLayout layout); if (err != Result.SUCCESS) { throw new InvalidOperationException("CreatePipelineLayout failed"); } var pbrEffect = new EffectPipelineDictionary(); var pbrFactory = new PbrEffectVariantFactory(mPbrEffectPath); var instanceDrawGroups = new Dictionary <GltfInstancedGroupKey, GltfInstanceDrawGroup>(); foreach (var node in nodes) { if (node.Mesh.HasValue) { var options = new EffectVariantOptions { }; var meshIndex = node.Mesh.Value; var mesh = meshes[meshIndex]; options.FrontFace = node.IsMirrored ? MgFrontFace.CLOCKWISE : MgFrontFace.COUNTER_CLOCKWISE; foreach (var primitive in mesh.Primitives) { options.Topology = primitive.Topology; var materialItem = materialChunks[primitive.Material.BucketIndex].Items[primitive.Material.Offset]; options.CullMode = materialItem.DoubleSided ? MgCullModeFlagBits.NONE : MgCullModeFlagBits.BACK_BIT; var key = new EffectVariantKey { Definition = PerVertexDefinitionEncoder.Encode(primitive.FinalDefinition), Options = EffectVariantEncoder.Encode(options), }; if (!pbrEffect.TryGetValue(key, out EffectVariant found)) { var vertexInput = new PerVertexInputPipelineState(primitive.FinalDefinition); found = pbrFactory.Initialize(device, layout, framework.Renderpass, vertexInput, options); pbrEffect.Add(key, found); } AppendToGroup(instanceDrawGroups, node, meshIndex, primitive, key, found); } } } var stride = Marshal.SizeOf(typeof(PerInstance)); var perInstances = new List <GltfInstanceRenderGroup>(); foreach (var group in instanceDrawGroups.Values) { var slotInfo = new MgStorageBlockAllocationInfo { MemoryPropertyFlags = MgMemoryPropertyFlagBits.HOST_VISIBLE_BIT, Usage = MgBufferUsageFlagBits.VERTEX_BUFFER_BIT, ElementByteSize = (uint)stride, Size = (ulong)(group.Members.Count * stride), }; var instanceGroup = new GltfInstanceRenderGroup { Variant = group.Variant, StorageIndex = request.Insert(slotInfo), Members = group.Members.ToArray(), }; perInstances.Add(instanceGroup); } var storage = mBuilder.Build( new MgOptimizedStorageCreateInfo { Allocations = request.ToArray() } ); // MAP DATA var finalMaterials = new List <GltfMaterialInfo>(); for (var i = 0; i < materialChunks.Length; i += 1) { var slot = materialSlots.Slots[i]; var chunk = materialChunks[i]; for (var j = 0; j < chunk.Items.Length; j += 1) { var values = chunk.Items[j]; var mat = new GltfMaterialInfo { StorageIndex = slot, BucketIndex = i, SetOffset = j, Values = values, }; } } return(new GltfScene { //Cameras = new [] //{ //}, DescriptorSets = new IMgDescriptorSet[] { }, Effects = new [] { new Effect { DescriptorSetLayout = dsLayout, Layout = layout, Variants = pbrEffect, } }, //Meshes = new[] //{ //}, Materials = finalMaterials.ToArray(), //Nodes = new [] //{ //}, PerInstances = perInstances.ToArray(), Samplers = samplers, Storage = storage, //Textures = new [] //{ //}, }); }