예제 #1
0
        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,
            });
        }
예제 #2
0
        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);
        }
예제 #3
0
        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));
        }
예제 #4
0
        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());
        }
예제 #5
0
        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);
        }
예제 #6
0
        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
            }
        }