Esempio n. 1
0
        public ModelInstanceHandle CreateInstance(ModelHandle modelHandle, Material material, Transform initialTransform)
        {
            uint modelIndex = modelHandle.ModelIndex;

            Assure.NotNull(material);
            Assure.False(material.IsDisposed, "Given material was disposed!");
            return(GeometryCache.GetCacheByID(modelHandle.GeoCacheID).AllocInstance(modelIndex, OwningLayer.Index, material.Index, initialTransform));
        }
        public unsafe void TestProperties()
        {
            // Define variables and constants
            const int FAKE_CACHE_ID = 1351617;

            IVertexBuffer[] buffers = new IVertexBuffer[2];
            buffers[0] = BufferFactory.NewVertexBuffer <Vector3>()
                         .WithInitialData(new[] { Vector3.ONE * 0f, Vector3.ONE * 1f, Vector3.ONE * 2f, Vector3.ONE * 3f, Vector3.ONE * 4f, Vector3.ONE * 5f })
                         .WithUsage(ResourceUsage.Immutable)
                         .Create();
            buffers[1] = BufferFactory.NewVertexBuffer <Vector2>()
                         .WithInitialData(new[] { Vector2.ONE * 0f, Vector2.ONE * 1f, Vector2.ONE * 2f, Vector2.ONE * 3f, Vector2.ONE * 4f, Vector2.ONE * 5f })
                         .WithUsage(ResourceUsage.Immutable)
                         .Create();
            string[]         semantics = { "POSITION", "TEXCOORD" };
            ResourceFormat[] formats   = { ResourceFormat.R32G32B32Float, ResourceFormat.R32G32Float };
            IndexBuffer      indices   = BufferFactory.NewIndexBuffer()
                                         .WithInitialData(new uint[] { 0, 1, 2, 1, 2, 0, 2, 1, 0, 3, 4, 5, 4, 5, 3, 5, 3, 4, 5, 3, 4 })
                                         .WithUsage(ResourceUsage.Immutable);
            AlignedAllocation <uint> componentStartPointsAlloc = AlignedAllocation <uint> .AllocArray(7L, 3);

            *(((uint *)componentStartPointsAlloc.AlignedPointer) + 0) = 0U;
            *(((uint *)componentStartPointsAlloc.AlignedPointer) + 1) = 3U;
            *(((uint *)componentStartPointsAlloc.AlignedPointer) + 2) = 6U;
            AlignedAllocation <uint> indexStartPointsAlloc = AlignedAllocation <uint> .AllocArray(7L, 3);

            *(((uint *)indexStartPointsAlloc.AlignedPointer) + 0) = 0U;
            *(((uint *)indexStartPointsAlloc.AlignedPointer) + 1) = 9U;
            *(((uint *)indexStartPointsAlloc.AlignedPointer) + 2) = 21U;
            Dictionary <string, ModelHandle> modelNameMap = new Dictionary <string, ModelHandle>()
            {
                { FAKE_CACHE_ID + "A", new ModelHandle(FAKE_CACHE_ID, 0U) },
                { FAKE_CACHE_ID + "B", new ModelHandle(FAKE_CACHE_ID, 1U) }
            };
            const uint NUM_MODELS = 2;

            // Set up context
            GeometryCache cache = new GeometryCache(
                buffers, semantics, formats,
                indices, componentStartPointsAlloc, indexStartPointsAlloc,
                NUM_MODELS, typeof(FakeVertex), FAKE_CACHE_ID, modelNameMap
                );


            // Execute


            // Assert outcome
            Assert.AreEqual(buffers[0], cache.VertexBuffers[0]);
            Assert.AreEqual(buffers[1], cache.VertexBuffers[1]);
            Assert.AreEqual(semantics[0], cache.VertexSemantics[0]);
            Assert.AreEqual(semantics[1], cache.VertexSemantics[1]);
            Assert.AreEqual(formats[0], cache.VertexFormats[0]);
            Assert.AreEqual(formats[1], cache.VertexFormats[1]);
            Assert.AreEqual(indices, cache.IndexBuffer);

            cache.Dispose();
        }
Esempio n. 3
0
 public void SetVSForCache(GeometryCache cache, VertexShader vs)
 {
     Assure.NotNull(cache);
     using (RenderingModule.RenderStateBarrier.AcquirePermit(withLock: InstanceMutationLock)) {
         if (vs == null)
         {
             deferredGeometryVertexShaders.Remove(cache);
         }
         else
         {
             deferredGeometryVertexShaders[cache] = vs;
         }
     }
 }
Esempio n. 4
0
 private Font(string name, uint lineHeightPixels, int kerningPixels, GeometryCache characterGeometry,
              ITexture2D[] characterPages, ShaderResourceView[] characterPageViews, Dictionary <char, FontCharacter> characters,
              ConstantBufferBinding textFsColorCbb, uint maxCharHeight)
 {
     Name                    = name;
     LineHeightPixels        = lineHeightPixels;
     KerningPixels           = kerningPixels;
     this.characterPages     = characterPages;
     this.characters         = characters;
     TextFSColorCBB          = textFsColorCbb;
     MaxCharHeight           = maxCharHeight;
     CharacterGeometry       = characterGeometry;
     this.characterPageViews = characterPageViews;
 }
        public void ShouldRejectDuplicateModelNames()
        {
            GeometryCacheBuilder <DefaultVertex> gcbA = new GeometryCacheBuilder <DefaultVertex>();

            gcbA.AddModel("SRDMN_A", new[] { new DefaultVertex(Vector3.ONE) }, new[] { 1U });
            gcbA.AddModel("SRDMN_B", new[] { new DefaultVertex(Vector3.ONE) }, new[] { 1U });

            GeometryCache gcA = gcbA.Build();

            GeometryCacheBuilder <DefaultVertex> gcbB = new GeometryCacheBuilder <DefaultVertex>();

            gcbB.AddModel("SRDMN_1", new[] { new DefaultVertex(Vector3.ONE) }, new[] { 1U });
            gcbB.AddModel("SRDMN_2", new[] { new DefaultVertex(Vector3.ONE) }, new[] { 1U });
            gcbB.AddModel("SRDMN_3", new[] { new DefaultVertex(Vector3.ONE) }, new[] { 1U });
            GeometryCache gcB = gcbB.Build();

            GeometryCacheBuilder <DefaultVertex> gcbC = new GeometryCacheBuilder <DefaultVertex>();

            gcbC.AddModel("SRDMN_1", new[] { new DefaultVertex(Vector3.ONE) }, new[] { 1U });
            try {
                gcbC.Build();
                Assert.Fail();
            }
            catch (InvalidOperationException) { }

            gcbC = new GeometryCacheBuilder <DefaultVertex>();
            gcbC.AddModel("SRDMN_A", new[] { new DefaultVertex(Vector3.ONE) }, new[] { 1U });
            try {
                gcbC.Build();
                Assert.Fail();
            }
            catch (InvalidOperationException) { }

            gcbC = new GeometryCacheBuilder <DefaultVertex>();
            gcbC.AddModel("SRDMN_X", new[] { new DefaultVertex(Vector3.ONE) }, new[] { 1U });
            gcbC.AddModel("SRDMN_Y", new[] { new DefaultVertex(Vector3.ONE) }, new[] { 1U });
            gcbC.AddModel("SRDMN_Z", new[] { new DefaultVertex(Vector3.ONE) }, new[] { 1U });
            gcbC.AddModel("SRDMN_Z", new[] { new DefaultVertex(Vector3.ONE) }, new[] { 1U });
            try {
                gcbC.Build();
                Assert.Fail();
            }
            catch (InvalidOperationException) { }

            gcA.Dispose();
            gcB.Dispose();
        }
Esempio n. 6
0
        internal unsafe GeometryInputLayout(
            InputLayoutHandle inputLayoutHandle,
            KeyValuePair <VertexInputBinding, IVertexBuffer>[] boundComponentBuffers,
            VertexShader associatedShader,
            GeometryCache associatedCache
            ) : base(inputLayoutHandle, ResourceUsage.Immutable, APPROX_INPUT_ELEMENT_DESC_SIZE_BYTES * boundComponentBuffers.Length)
        {
            BoundComponentBuffers = boundComponentBuffers;
            AssociatedShader      = associatedShader;
            AssociatedCache       = associatedCache;

            ResourcePackage = new ShaderResourcePackage();
            foreach (KeyValuePair <VertexInputBinding, IVertexBuffer> pair in boundComponentBuffers)
            {
                ResourcePackage.SetValue(pair.Key, pair.Value);
            }
        }
        public void TestSetInputLayout()
        {
            GeometryCacheBuilder <DefaultVertex> gcb = new GeometryCacheBuilder <DefaultVertex>();

            gcb.AddModel("TSIL_a", new DefaultVertex[] { new DefaultVertex(Vector3.ONE) }, new uint[] { 0U });
            GeometryCache           cache  = gcb.Build();
            ConstantBuffer <Matrix> vpMat  = BufferFactory.NewConstantBuffer <Matrix>().WithUsage(ResourceUsage.DiscardWrite);
            VertexShader            shader = new VertexShader(
                @"Tests\SimpleVS.cso",
                new VertexInputBinding(0U, "INSTANCE_TRANSFORM"),
                new ConstantBufferBinding(0U, "CameraTransform", vpMat),
                new VertexInputBinding(1U, "POSITION")
                );

            GeometryInputLayout gil = cache.GetInputLayout(shader);

            RenderCommand testCommand = RenderCommand.SetInputLayout(gil);

            Assert.AreEqual(RenderCommandInstruction.SetInputLayout, testCommand.Instruction);
            Assert.AreEqual((RenderCommandArgument)(IntPtr)gil.ResourceHandle, testCommand.Arg1);

#if !DEVELOPMENT && !RELEASE
            try {
                RenderCommand.SetInputLayout(null);
                Assert.Fail();
            }
            catch (AssuranceFailedException) { }
#endif

            shader.Dispose();
            vpMat.Dispose();
            cache.Dispose();
            gil.Dispose();

#if !DEVELOPMENT && !RELEASE
            try {
                RenderCommand.SetInputLayout(gil);
                Assert.Fail();
            }
            catch (AssuranceFailedException) { }
#endif
        }
        public void TestGettingModelsByName()
        {
            GeometryCacheBuilder <DefaultVertex> gcbA = new GeometryCacheBuilder <DefaultVertex>();
            ModelHandle modelA = gcbA.AddModel("TGMBN_A", new[] { new DefaultVertex(Vector3.ONE) }, new[] { 1U });
            ModelHandle modelB = gcbA.AddModel("TGMBN_B", new[] { new DefaultVertex(Vector3.ONE) }, new[] { 1U });

            GeometryCache gcA = gcbA.Build();

            GeometryCacheBuilder <DefaultVertex> gcbB = new GeometryCacheBuilder <DefaultVertex>();
            ModelHandle   model1 = gcbB.AddModel("TGMBN_1", new[] { new DefaultVertex(Vector3.ONE) }, new[] { 1U });
            ModelHandle   model2 = gcbB.AddModel("TGMBN_2", new[] { new DefaultVertex(Vector3.ONE) }, new[] { 1U });
            ModelHandle   model3 = gcbB.AddModel("TGMBN_3", new[] { new DefaultVertex(Vector3.ONE) }, new[] { 1U });
            GeometryCache gcB    = gcbB.Build();

            Assert.AreEqual(modelA, gcA.GetModelByName("TGMBN_A"));
            Assert.AreEqual(model3, gcB.GetModelByName("TGMBN_3"));

            Assert.AreEqual(model1, GeometryCache.GloballyGetModelByName("TGMBN_1"));
            Assert.AreEqual(model2, GeometryCache.GloballyGetModelByName("TGMBN_2"));
            Assert.AreEqual(modelB, GeometryCache.GloballyGetModelByName("TGMBN_B"));

            try {
                gcA.GetModelByName("TGMBN_1");
                Assert.Fail();
            }
            catch (KeyNotFoundException) { }

            try {
                gcB.GetModelByName("TGMBN_B");
                Assert.Fail();
            }
            catch (KeyNotFoundException) { }

            try {
                GeometryCache.GloballyGetModelByName("TGMBN_C");
                Assert.Fail();
            }
            catch (KeyNotFoundException) { }
        }
Esempio n. 9
0
        protected internal override void Execute(ParallelizationProvider pp)
        {
            DepthStencilViewHandle _;

            if (!output.TargetWindow.GetWindowRTVAndDSV(out windowRTVH, out _))
            {
                return;
            }

            List <GeometryCache> activeCaches = GeometryCache.ActiveCaches;

            foreach (GeometryCache c in activeCaches)
            {
                // Set view/proj matrix
                Matrix vpMat    = (*((Matrix *)Input.GetRecalculatedViewMatrix()) * *((Matrix *)Output.GetRecalculatedProjectionMatrix(Input))).Transpose;
                byte * vpMapPtr = (byte *)&vpMat;
                VertexShader.ViewProjMatBinding.SetValue(vpMapPtr);

                // Set state for current cache
                cpuInstanceBufferCurIndex = 0;
                List <SceneLayer> allEnabledLayers = Scene.EnabledLayers;
                uint maxLayer = 0U;
                for (int i = 0; i < allEnabledLayers.Count; ++i)
                {
                    if (allEnabledLayers[i].Index > maxLayer)
                    {
                        maxLayer = allEnabledLayers[i].Index;
                    }
                }
                if (allEnabledLayers.Count > 0 && currentSceneLayers.Length <= maxLayer)
                {
                    currentSceneLayers = new SceneLayer[maxLayer + 1U];
                }
                Array.Clear(currentSceneLayers, 0, currentSceneLayers.Length);
                foreach (SceneLayer layer in allEnabledLayers)
                {
                    currentSceneLayers[layer.Index] = layer;
                }
                currentCache = c;
                ++frameNum;
                Thread.MemoryBarrier();
                currentInstanceData = currentCache.GetModelInstanceData();

                // Set up each thread
                pp.InvokeOnAll(setUpCacheForLocalThreadAct, true);                 // also emits a membar

                // Iterate all model instances (ordered by material)
                pp.Execute((int)currentInstanceData.Length, (int)(currentInstanceData.Length / (pp.NumThreads << 3)) + 1, renderCacheIterateMatAct);

                // Set instance buffer and write to it
                if (gpuInstanceBuffer == null || gpuInstanceBuffer.Length < cpuInstanceBuffer.Length)
                {
                    if (gpuInstanceBuffer != null)
                    {
                        gpuInstanceBuffer.Dispose();
                    }
                    gpuInstanceBuffer = gpuInstanceBufferBuilder.WithLength((uint)cpuInstanceBuffer.Length).Create();
                }
                gpuInstanceBuffer.DiscardWrite(cpuInstanceBuffer);                 // Happens immediately (required)

                // Set instance buffer and flush all commands, first on immediate context, then on each deferred
                SetInstanceBufferAndFlushCommands();
                pp.InvokeOnAll(setInstanceBufferAndFlushCommandsAct, false);
            }

            // Present
            FlushRenderCommands();
            if (presentAfterPass)
            {
                PresentBackBuffer(Output.TargetWindow);
            }
        }
Esempio n. 10
0
        /// <summary>
        /// Builds the <see cref="GeometryCache"/> with all the models that have previously been added with <see cref="AddModel"/>.
        /// This method may only be called once per GeometryCacheBuilder.
        /// </summary>
        /// <returns>A new <see cref="GeometryCache"/> containing 'baked' resource data for all the loaded models and an
        /// "instance pool", allowing model instances to be created and loaded in to the <see cref="Scene"/>.</returns>
        public unsafe GeometryCache Build()
        {
            lock (instanceMutationLock) {
                if (isBuilt)
                {
                    throw new InvalidOperationException("Cache has already been built!");
                }

                FieldInfo[] vertexComponents = typeof(TVertex).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
                if (vertexComponents.Length > VertexShader.MAX_VS_INPUT_BINDINGS)
                {
                    throw new InvalidOperationException("Vertex type '" + typeof(TVertex).Name + "' has too many components. Maximum " +
                                                        "permissible is " + VertexShader.MAX_VS_INPUT_BINDINGS + ", but the vertex type has " + vertexComponents.Length + " fields.");
                }
                else if (vertexComponents.Length == 0)
                {
                    throw new InvalidOperationException("Vertex type '" + typeof(TVertex).Name + "' has no components. Please choose a type with " +
                                                        "at least one field.");
                }

                if (vertexCounts.Count == 0)
                {
                    throw new InvalidOperationException("Can not build empty geometry cache: Please add at least one model first!");
                }

                if (modelNames.AnyDuplicates())
                {
                    throw new InvalidOperationException("No two models should have the same name.");
                }
                if (GeometryCache.CheckForModelNameClashes(modelNames))
                {
                    throw new InvalidOperationException("One or more model names added to this builder have already been used in other active geometry caches.");
                }



                IVertexBuffer[]  vertexComponentBuffers   = new IVertexBuffer[vertexComponents.Length];
                string[]         vertexComponentSemantics = new string[vertexComponents.Length];
                ResourceFormat[] vertexComponentFormats   = new ResourceFormat[vertexComponents.Length];

                for (int i = 0; i < vertexComponents.Length; ++i)
                {
                    FieldInfo component = vertexComponents[i];
                    if (!component.FieldType.IsBlittable())
                    {
                        throw new InvalidOperationException("Invalid vertex component type: '" + component.FieldType.Name + "'.");
                    }
                    if (!component.HasCustomAttribute <VertexComponentAttribute>())
                    {
                        throw new InvalidOperationException("Every field on given vertex type (" + typeof(TVertex).Name + ") must be annoted with " +
                                                            "a " + typeof(VertexComponentAttribute).Name + "!");
                    }

                    typeof(GeometryCacheBuilder <TVertex>)
                    .GetMethod("FillComponentBuffer", BindingFlags.NonPublic | BindingFlags.Instance)                             // TODO replace with nameof() operator when C#6 is released
                    .MakeGenericMethod(component.FieldType)
                    .Invoke(this, new object[] { component, i, vertexComponentBuffers, vertexComponentSemantics, vertexComponentFormats });
                }

                IndexBuffer indexBuffer = BufferFactory.NewIndexBuffer().WithInitialData(indices.ToArray()).WithUsage(ResourceUsage.Immutable);

                Assure.Equal(vertexCounts.Count, indexCounts.Count);
                AlignedAllocation <uint> componentStartPointsAlloc = AlignedAllocation <uint> .AllocArray(
                    START_POINT_ARRAY_ALIGNMENT,
                    (uint)vertexCounts.Count + 1U                      // Extra one so we can set the last value to one-past-the-end (performance improvement later on)
                    );

                AlignedAllocation <uint> indexStartPointsAlloc = AlignedAllocation <uint> .AllocArray(
                    START_POINT_ARRAY_ALIGNMENT,
                    (uint)vertexCounts.Count + 1U                      // Extra one so we can set the last value to one-past-the-end (performance improvement later on)
                    );

                uint *componentStartPtr = (uint *)componentStartPointsAlloc.AlignedPointer;
                uint *indexStartPtr     = (uint *)indexStartPointsAlloc.AlignedPointer;
                uint  vbCounter         = 0U;
                uint  ibCounter         = 0U;
                for (int i = 0; i < vertexCounts.Count; ++i)
                {
                    componentStartPtr[i] = vbCounter;
                    indexStartPtr[i]     = ibCounter;
                    vbCounter           += vertexCounts[i];
                    ibCounter           += indexCounts[i];
                }

                // Set the last two elements of each start-point array to one-past-the-last, so we don't have to test
                // for being the 'last' count later on
                componentStartPtr[vertexCounts.Count] = (uint)vertices.Count;
                indexStartPtr[vertexCounts.Count]     = (uint)indices.Count;

                Dictionary <string, ModelHandle> modelNameToHandleMap = new Dictionary <string, ModelHandle>();
                for (uint i = 0U; i < modelNames.Count; ++i)
                {
                    modelNameToHandleMap.Add(modelNames[(int)i], new ModelHandle(cacheID, i));
                }

                isBuilt = true;

                return(new GeometryCache(
                           vertexComponentBuffers,
                           vertexComponentSemantics,
                           vertexComponentFormats,
                           indexBuffer,
                           componentStartPointsAlloc,
                           indexStartPointsAlloc,
                           (uint)vertexCounts.Count,
                           typeof(TVertex),
                           cacheID,
                           modelNameToHandleMap,
                           orderFirst
                           ));
            }
        }
        public unsafe void TestGetModelBufferValues()
        {
            // Define variables and constants
            const int FAKE_CACHE_ID = 1351616;

            IVertexBuffer[] buffers = new IVertexBuffer[2];
            buffers[0] = BufferFactory.NewVertexBuffer <Vector3>()
                         .WithInitialData(new[] { Vector3.ONE * 0f, Vector3.ONE * 1f, Vector3.ONE * 2f, Vector3.ONE * 3f, Vector3.ONE * 4f, Vector3.ONE * 5f })
                         .WithUsage(ResourceUsage.Immutable)
                         .Create();
            buffers[1] = BufferFactory.NewVertexBuffer <Vector2>()
                         .WithInitialData(new[] { Vector2.ONE * 0f, Vector2.ONE * 1f, Vector2.ONE * 2f, Vector2.ONE * 3f, Vector2.ONE * 4f, Vector2.ONE * 5f })
                         .WithUsage(ResourceUsage.Immutable)
                         .Create();
            string[]         semantics = { "POSITION", "TEXCOORD" };
            ResourceFormat[] formats   = { ResourceFormat.R32G32B32Float, ResourceFormat.R32G32Float };
            IndexBuffer      indices   = BufferFactory.NewIndexBuffer()
                                         .WithInitialData(new uint[] { 0, 1, 2, 1, 2, 0, 2, 1, 0, 3, 4, 5, 4, 5, 3, 5, 3, 4, 5, 3, 4 })
                                         .WithUsage(ResourceUsage.Immutable);
            AlignedAllocation <uint> componentStartPointsAlloc = AlignedAllocation <uint> .AllocArray(7L, 3);

            *(((uint *)componentStartPointsAlloc.AlignedPointer) + 0) = 0U;
            *(((uint *)componentStartPointsAlloc.AlignedPointer) + 1) = 3U;
            *(((uint *)componentStartPointsAlloc.AlignedPointer) + 2) = 6U;
            AlignedAllocation <uint> indexStartPointsAlloc = AlignedAllocation <uint> .AllocArray(7L, 3);

            *(((uint *)indexStartPointsAlloc.AlignedPointer) + 0) = 0U;
            *(((uint *)indexStartPointsAlloc.AlignedPointer) + 1) = 9U;
            *(((uint *)indexStartPointsAlloc.AlignedPointer) + 2) = 21U;
            Dictionary <string, ModelHandle> modelNameMap = new Dictionary <string, ModelHandle>()
            {
                { FAKE_CACHE_ID + "A", new ModelHandle(FAKE_CACHE_ID, 0U) },
                { FAKE_CACHE_ID + "B", new ModelHandle(FAKE_CACHE_ID, 1U) }
            };
            const uint NUM_MODELS = 2;

            uint outVBStartIndex, outIBStartIndex, outVBCount, outIBCount;

            // Set up context
            GeometryCache cache = new GeometryCache(
                buffers, semantics, formats,
                indices, componentStartPointsAlloc, indexStartPointsAlloc,
                NUM_MODELS, typeof(FakeVertex), FAKE_CACHE_ID, modelNameMap
                );

            // Execute
            cache.GetModelBufferValues(0U, out outVBStartIndex, out outIBStartIndex, out outVBCount, out outIBCount);

            // Assert outcome
            Assert.AreEqual(0U, outVBStartIndex);
            Assert.AreEqual(0U, outIBStartIndex);
            Assert.AreEqual(3U, outVBCount);
            Assert.AreEqual(9U, outIBCount);

            cache.GetModelBufferValues(1U, out outVBStartIndex, out outIBStartIndex, out outVBCount, out outIBCount);

            Assert.AreEqual(3U, outVBStartIndex);
            Assert.AreEqual(9U, outIBStartIndex);
            Assert.AreEqual(3U, outVBCount);
            Assert.AreEqual(12U, outIBCount);

#if !DEVELOPMENT && !RELEASE
            try {
                cache.GetModelBufferValues(2U, out outVBStartIndex, out outIBStartIndex, out outVBCount, out outIBCount);
                Assert.Fail();
            }
            catch (AssuranceFailedException) { }
#endif

            cache.Dispose();
        }
        public unsafe void TestGetInputLayout()
        {
            // Define variables and constants
            const int FAKE_CACHE_ID = 1351618;

            IVertexBuffer[] buffers = new IVertexBuffer[2];
            buffers[0] = BufferFactory.NewVertexBuffer <Vector3>()
                         .WithInitialData(new[] { Vector3.ONE * 0f, Vector3.ONE * 1f, Vector3.ONE * 2f, Vector3.ONE * 3f, Vector3.ONE * 4f, Vector3.ONE * 5f })
                         .WithUsage(ResourceUsage.Immutable)
                         .Create();
            buffers[1] = BufferFactory.NewVertexBuffer <float>()
                         .WithInitialData(new[] { 0f, 1f, 2f, 3f, 4f, 5f })
                         .WithUsage(ResourceUsage.Immutable)
                         .Create();
            string[]         semantics = { "POSITION", "RANDOM_FLOATS" };
            ResourceFormat[] formats   = { ResourceFormat.R32G32B32Float, ResourceFormat.R32G32Float };
            IndexBuffer      indices   = BufferFactory.NewIndexBuffer()
                                         .WithInitialData(new uint[] { 0, 1, 2, 1, 2, 0, 2, 1, 0, 3, 4, 5, 4, 5, 3, 5, 3, 4, 5, 3, 4 })
                                         .WithUsage(ResourceUsage.Immutable);
            AlignedAllocation <uint> componentStartPointsAlloc = AlignedAllocation <uint> .AllocArray(7L, 3);

            *(((uint *)componentStartPointsAlloc.AlignedPointer) + 0) = 0U;
            *(((uint *)componentStartPointsAlloc.AlignedPointer) + 1) = 3U;
            *(((uint *)componentStartPointsAlloc.AlignedPointer) + 2) = 6U;
            AlignedAllocation <uint> indexStartPointsAlloc = AlignedAllocation <uint> .AllocArray(7L, 3);

            *(((uint *)indexStartPointsAlloc.AlignedPointer) + 0) = 0U;
            *(((uint *)indexStartPointsAlloc.AlignedPointer) + 1) = 9U;
            *(((uint *)indexStartPointsAlloc.AlignedPointer) + 2) = 21U;
            Dictionary <string, ModelHandle> modelNameMap = new Dictionary <string, ModelHandle>()
            {
                { FAKE_CACHE_ID + "A", new ModelHandle(FAKE_CACHE_ID, 0U) },
                { FAKE_CACHE_ID + "B", new ModelHandle(FAKE_CACHE_ID, 1U) }
            };
            const uint NUM_MODELS = 2;

            // Set up context
            GeometryCache cache = new GeometryCache(
                buffers, semantics, formats,
                indices, componentStartPointsAlloc, indexStartPointsAlloc,
                NUM_MODELS, typeof(Vector4), FAKE_CACHE_ID, modelNameMap
                );

            ConstantBuffer <Matrix> instanceCBuffer = BufferFactory.NewConstantBuffer <Matrix>().WithUsage(ResourceUsage.DiscardWrite);
            VertexShader            vs1             = new VertexShader(
                @"Tests\SimpleVS.cso",
                new VertexInputBinding(0U, "INSTANCE_TRANSFORM"),
                new ConstantBufferBinding(0U, "CameraTransform", instanceCBuffer),
                new VertexInputBinding(1U, "POSITION")
                );
            VertexShader vs2 = new VertexShader(
                @"Tests\SimpleVS.cso",
                new VertexInputBinding(0U, "INSTANCE_TRANSFORM"),
                new ConstantBufferBinding(0U, "CameraTransform", instanceCBuffer),
                new VertexInputBinding(1U, "RANDOM_FLOATS"),
                new VertexInputBinding(2U, "POSITION")
                );
            VertexShader vs3 = new VertexShader(
                @"Tests\SimpleVS.cso",
                new VertexInputBinding(0U, "INSTANCE"),
                new ConstantBufferBinding(0U, "VPTransform", instanceCBuffer),
                new VertexInputBinding(1U, "TEXCOORD")
                );

            // Execute
            GeometryInputLayout inputLayout1 = cache.GetInputLayout(vs1);
            GeometryInputLayout inputLayout2 = cache.GetInputLayout(vs2);

            try {
                cache.GetInputLayout(vs3);
                Assert.Fail();
            }
            catch (InvalidOperationException) { }

            // Assert outcome
            Assert.AreEqual(cache, inputLayout1.AssociatedCache);
            Assert.AreEqual(cache, inputLayout2.AssociatedCache);

            Assert.AreEqual(vs1, inputLayout1.AssociatedShader);
            Assert.AreEqual(vs2, inputLayout2.AssociatedShader);

            KeyValuePair <VertexInputBinding, IVertexBuffer>[] boundCompBuffers = inputLayout1.BoundComponentBuffers;
            Assert.AreEqual(buffers[0], boundCompBuffers.First(kvp => kvp.Key == vs1.GetBindingByIdentifier("POSITION")).Value);
            Assert.IsFalse(boundCompBuffers.Any(kvp => kvp.Value == buffers[1]));

            boundCompBuffers = inputLayout2.BoundComponentBuffers;
            Assert.AreEqual(buffers[0], boundCompBuffers.First(kvp => kvp.Key == vs2.GetBindingByIdentifier("POSITION")).Value);
            Assert.AreEqual(buffers[1], boundCompBuffers.First(kvp => kvp.Key == vs2.GetBindingByIdentifier("RANDOM_FLOATS")).Value);

            Assert.AreEqual(inputLayout1, cache.GetInputLayout(vs1));
            Assert.AreEqual(inputLayout2, cache.GetInputLayout(vs2));

            cache.Dispose();
            inputLayout2.Dispose();
            inputLayout1.Dispose();
            vs1.Dispose();
            vs2.Dispose();
            vs3.Dispose();
            instanceCBuffer.Dispose();
            indices.Dispose();
            buffers[1].Dispose();
            buffers[0].Dispose();
        }
Esempio n. 13
0
        protected internal unsafe override void Execute(ParallelizationProvider pp)
        {
            // See if we need to resize the depth buffer
            Vector2 viewportDimensions = output.SizePixels;

            if (viewportDimensions.X < 1f || viewportDimensions.Y < 1f)
            {
                return;
            }
            uint viewportX = (uint)viewportDimensions.X;
            uint viewportY = (uint)viewportDimensions.Y;

            if (shadowBuffer == null || shadowBufferDSV == null || shadowBufferDSV.ResourceOrViewDisposed ||
                shadowBufferSRV == null || shadowBufferSRV.ResourceOrViewDisposed ||
                shadowBuffer.Width != viewportX || shadowBuffer.Height != viewportY)
            {
                if (shadowBufferDSV != null && !shadowBufferDSV.IsDisposed)
                {
                    shadowBufferDSV.Dispose();
                }
                if (shadowBuffer != null && !shadowBuffer.IsDisposed)
                {
                    shadowBuffer.Dispose();
                }
                shadowBuffer    = shadowBufferBuilder.WithWidth(viewportX).WithHeight(viewportY);
                shadowBufferDSV = shadowBuffer.CreateDepthStencilView <TexelFormat.DepthStencil>(0U);
                shadowBufferSRV = shadowBuffer.CreateView <TexelFormat.R24UnormX8Typeless>(0U, 1U);
            }

            // Clear the depth buffer
            QueueRenderCommand(RenderCommand.ClearDepthStencil(shadowBufferDSV));

            List <GeometryCache> activeCaches = GeometryCache.ActiveCaches;

            foreach (GeometryCache c in activeCaches)
            {
                // Set view/proj matrix
                Matrix vpMat    = (*((Matrix *)lightCam.GetRecalculatedViewMatrix()) * *((Matrix *)Output.GetRecalculatedProjectionMatrix(lightCam))).Transpose;
                byte * vpMapPtr = (byte *)&vpMat;
                shadowVS.ViewProjMatBinding.SetValue(vpMapPtr);

                // Set state for current cache
                cpuInstanceBufferCurIndex = 0;
                List <SceneLayer> allEnabledLayers = Scene.EnabledLayers;
                uint maxLayer = 0U;
                for (int i = 0; i < allEnabledLayers.Count; ++i)
                {
                    if (allEnabledLayers[i].Index > maxLayer)
                    {
                        maxLayer = allEnabledLayers[i].Index;
                    }
                }
                if (allEnabledLayers.Count > 0 && currentSceneLayers.Length <= maxLayer)
                {
                    currentSceneLayers = new SceneLayer[maxLayer + 1U];
                }
                Array.Clear(currentSceneLayers, 0, currentSceneLayers.Length);
                foreach (SceneLayer layer in allEnabledLayers)
                {
                    currentSceneLayers[layer.Index] = layer;
                }
                currentCache = c;
                ++frameNum;
                Thread.MemoryBarrier();
                currentInstanceData = currentCache.GetModelInstanceData();

                // Set up each thread
                pp.InvokeOnAll(setUpCacheForLocalThreadAct, true);                 // membar here

                // Iterate all model instances (ordered by material)
                pp.Execute((int)currentInstanceData.Length, (int)(currentInstanceData.Length / (pp.NumThreads << 3)) + 1, renderCacheIterateMatAct);

                // Set instance buffer and write to it
                if (gpuInstanceBuffer == null || gpuInstanceBuffer.Length < cpuInstanceBuffer.Length)
                {
                    if (gpuInstanceBuffer != null)
                    {
                        gpuInstanceBuffer.Dispose();
                    }
                    gpuInstanceBuffer = gpuInstanceBufferBuilder.WithLength((uint)cpuInstanceBuffer.Length).Create();
                }
                gpuInstanceBuffer.DiscardWrite(cpuInstanceBuffer);                 // Happens immediately (required)

                // Set instance buffer and flush all commands, first on immediate context, then on each deferred
                SetInstanceBufferAndFlushCommands();
                pp.InvokeOnAll(setInstanceBufferAndFlushCommandsAct, false);
            }
        }
        protected internal override void Execute(ParallelizationProvider pp)
        {
            for (int i = 0; i < NUM_GBUFFER_TEXTURES; ++i)
            {
                if (gBufferViews[i] != null)
                {
                    QueueRenderCommand(RenderCommand.ClearRenderTarget(gBufferViews[i]));
                }
            }
            if (clearOutputBeforePass)
            {
                QueueRenderCommand(RenderCommand.ClearRenderTarget(output.TargetWindow));
                QueueRenderCommand(RenderCommand.ClearDepthStencil(output.TargetWindow));
            }

            Vector2 outputSizePixels = output.SizePixels;

            if (gBuffer[0] == null || gBuffer[0].Width != (uint)outputSizePixels.X || gBuffer[0].Height != (uint)outputSizePixels.Y)
            {
                for (int i = 0; i < NUM_GBUFFER_TEXTURES; ++i)
                {
                    if (gBufferViews[i] != null)
                    {
                        gBufferViews[i].Dispose();
                    }
                    if (gBuffer[i] != null)
                    {
                        gBuffer[i].Dispose();
                    }
                    gBuffer[i]      = gBufferBuilder.WithWidth((uint)outputSizePixels.X).WithHeight((uint)outputSizePixels.Y);
                    gBufferViews[i] = gBuffer[i].CreateRenderTargetView(0U);
                }
            }
            if (primaryDSBuffer == null || primaryDSBuffer.Width != outputSizePixels.X || primaryDSBuffer.Height != outputSizePixels.Y)
            {
                if (primaryDSBuffer != null)
                {
                    primaryDSBuffer.Dispose();
                }
                if (primaryDSBufferDSV != null)
                {
                    primaryDSBufferDSV.Dispose();
                }
                if (primaryDSBufferSRV != null)
                {
                    primaryDSBufferSRV.Dispose();
                }

                primaryDSBuffer    = dsBufferBuilder.WithWidth((uint)outputSizePixels.X).WithHeight((uint)outputSizePixels.Y);
                primaryDSBufferDSV = primaryDSBuffer.CreateDepthStencilView <TexelFormat.DepthStencil>(0U);
                primaryDSBufferSRV = primaryDSBuffer.CreateView <TexelFormat.R24UnormX8Typeless>(0U, 1U);
            }
            previousShadowBufferSRV = shadowPass.ShadowBufferSRV;

            // Clear main DSV
            QueueRenderCommand(RenderCommand.ClearDepthStencil(primaryDSBufferDSV));

            List <GeometryCache> activeCaches = GeometryCache.ActiveCaches;

            foreach (GeometryCache c in activeCaches)
            {
                if (!deferredGeometryVertexShaders.ContainsKey(c))
                {
                    continue;
                }
                currentVS = deferredGeometryVertexShaders[c];

                // Set view/proj matrices
                var vpMatrices = new GeomPassProjViewMatrices {
                    MainCameraVPMat   = (*((Matrix *)Input.GetRecalculatedViewMatrix()) * *((Matrix *)Output.GetRecalculatedProjectionMatrix(Input))).Transpose,
                    ShadowCameraVPMat = (*((Matrix *)shadowPass.LightCam.GetRecalculatedViewMatrix()) * *((Matrix *)Output.GetRecalculatedProjectionMatrix(shadowPass.LightCam))).Transpose
                };
                byte *vpMatPtr = (byte *)&vpMatrices;
                currentVS.ViewProjMatBinding.SetValue(vpMatPtr);

                // Set state for current cache
                cpuInstanceBufferCurIndex = 0;
                List <SceneLayer> allEnabledLayers = Scene.EnabledLayers;
                uint maxLayer = 0U;
                for (int i = 0; i < allEnabledLayers.Count; ++i)
                {
                    if (allEnabledLayers[i].Index > maxLayer)
                    {
                        maxLayer = allEnabledLayers[i].Index;
                    }
                }
                if (allEnabledLayers.Count > 0 && currentSceneLayers.Length <= maxLayer)
                {
                    currentSceneLayers = new SceneLayer[maxLayer + 1U];
                }
                Array.Clear(currentSceneLayers, 0, currentSceneLayers.Length);
                foreach (SceneLayer layer in allEnabledLayers)
                {
                    currentSceneLayers[layer.Index] = layer;
                }
                currentCache = c;
                ++frameNum;
                Thread.MemoryBarrier();
                currentInstanceData = currentCache.GetModelInstanceData();

                // Set up each thread
                pp.InvokeOnAll(setUpCacheForLocalThreadAct, true);                 // membar here

                // Iterate all model instances (ordered by material)
                pp.Execute((int)currentInstanceData.Length, (int)(currentInstanceData.Length / (pp.NumThreads << 3)) + 1, renderCacheIterateMatAct);

                // Set instance buffer and write to it
                if (gpuInstanceBuffer == null || gpuInstanceBuffer.Length < cpuInstanceBuffer.Length)
                {
                    if (gpuInstanceBuffer != null)
                    {
                        gpuInstanceBuffer.Dispose();
                    }
                    gpuInstanceBuffer = gpuInstanceBufferBuilder.WithLength((uint)cpuInstanceBuffer.Length).Create();
                }
                gpuInstanceBuffer.DiscardWrite(cpuInstanceBuffer);                 // Happens immediately (required)

                // Unbind shadow buffer
                QueueShaderSwitch(geomFSWithShadowSupport);
                QueueShaderResourceUpdate(geomFSWithShadowSupport, geomFSShadowUnbindPackage);

                // Set instance buffer and flush all commands, first on immediate context, then on each deferred
                SetInstanceBufferAndFlushCommands();
                pp.InvokeOnAll(setInstanceBufferAndFlushCommandsAct, false);
            }
        }
        public unsafe void TestCreateAndDestroyInstance()
        {
            // Define variables and constants
            const int NUM_INSTANCES = 1000;

            var gcb = new GeometryCacheBuilder <TestVertex>();

            gcb.AddModel("TCADI_a", new[] { new TestVertex(Vector3.ONE), new TestVertex(Vector3.LEFT), }, new[] { 0U, 1U, 1U, 0U, 1U, 0U });
            gcb.AddModel("TCADI_b", new[] { new TestVertex(Vector3.RIGHT), new TestVertex(Vector3.UP), }, new[] { 0U, 1U, 1U, 0U, 1U, 0U });
            gcb.AddModel("TCADI_c", new[] { new TestVertex(Vector3.ZERO), new TestVertex(Vector3.DOWN), }, new[] { 0U, 1U, 1U, 0U, 1U, 0U });
            GeometryCache testCache = gcb.Build();

            SceneLayer testLayerA = Scene.CreateLayer("Test Layer A");
            SceneLayer testLayerB = Scene.CreateLayer("Test Layer B");
            ConstantBuffer <Vector4> fsColorBuffer = BufferFactory.NewConstantBuffer <Vector4>().WithUsage(ResourceUsage.DiscardWrite);
            FragmentShader           fs            = new FragmentShader(@"Tests\SimpleFS.cso", new ConstantBufferBinding(0U, "MaterialProperties", fsColorBuffer));
            Material testMatA = new Material("Brick", fs);
            Material testMatB = new Material("Wood", fs);

            // Set up context


            // Execute
            ModelInstanceHandle[] instanceArr = new ModelInstanceHandle[NUM_INSTANCES];
            for (int i = 0; i < NUM_INSTANCES; ++i)
            {
                Transform transform = new Transform(
                    Vector3.ONE * i,
                    Quaternion.FromAxialRotation(Vector3.UP, i),
                    Vector3.ONE * -i
                    );
                if (i % 5 == 0)
                {
                    instanceArr[i] = testLayerA.CreateModelInstance(new ModelHandle(testCache.ID, (uint)(i % 3)), (i % 2 == 0 ? testMatA : testMatB), transform);
                }
                else
                {
                    instanceArr[i] = testLayerB.CreateModelInstance(new ModelHandle(testCache.ID, (uint)(i % 3)), (i % 2 == 0 ? testMatA : testMatB), transform);
                }
            }

            // Assert outcome
            RenderingModule.RenderStateBarrier.FreezeMutations();             // Cheeky, but we have to on debug mode (and it's re-entrant for now, so no problem)
            var instanceData = testCache.GetModelInstanceData();

            for (int i = 0; i < NUM_INSTANCES; ++i)
            {
                Material instanceMaterial = Material.GetMaterialByIndex(instanceArr[i].MaterialIndex);
                ModelInstanceManager.MIDArray materialDataArray = instanceData.First(kvp => kvp.Key == instanceMaterial).Value;

                Assert.AreEqual((i % 2 == 0 ? testMatA : testMatB), instanceMaterial);
                Assert.AreEqual((i % 5 == 0 ? testLayerA : testLayerB), Scene.GetLayerByIndex(materialDataArray.Data[GetMIHInstanceIndex(instanceArr[i])].SceneLayerIndex));
                Assert.IsTrue(materialDataArray.Data[GetMIHInstanceIndex(instanceArr[i])].InUse);
                Assert.AreEqual((uint)(i % 3), materialDataArray.Data[GetMIHInstanceIndex(instanceArr[i])].ModelIndex);
                Assert.AreEqual(
                    new Transform(
                        Vector3.ONE * i,
                        Quaternion.FromAxialRotation(Vector3.UP, i),
                        Vector3.ONE * -i
                        ),
                    instanceArr[i].Transform
                    );
                Assert.AreEqual(instanceArr[i].Transform, materialDataArray.Data[GetMIHInstanceIndex(instanceArr[i])].Transform);

                instanceArr[i].Dispose();
                Assert.IsFalse(materialDataArray.Data[GetMIHInstanceIndex(instanceArr[i])].InUse);
            }

            RenderingModule.RenderStateBarrier.UnfreezeMutations();

            testCache.Dispose();
            testMatA.Dispose();
            testMatB.Dispose();
            testLayerA.Dispose();
            testLayerB.Dispose();
            fs.Dispose();
            fsColorBuffer.Dispose();
        }
        public void ShouldCookParametersCorrectly()
        {
            // Define variables and constants
            GeometryCacheBuilder <TestVertex> testVertexCacheBuilder = new GeometryCacheBuilder <TestVertex>();
            int cacheID = (int)typeof(GeometryCacheBuilder <TestVertex>).GetField("cacheID", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(testVertexCacheBuilder);

            TestVertex[] model1Verts =
            {
                new TestVertex(Vector3.ONE * 0f, Vector2.ONE * 0f),
                new TestVertex(Vector3.ONE * 1f, Vector2.ONE * 1f),
                new TestVertex(Vector3.ONE * 2f, Vector2.ONE * 2f),
            };
            TestVertex[] model2Verts =
            {
                new TestVertex(Vector3.ONE * 3f, Vector2.ONE * 3f),
                new TestVertex(Vector3.ONE * 4f, Vector2.ONE * 4f),
                new TestVertex(Vector3.ONE * 5f, Vector2.ONE * 5f),
            };

            uint[] model1Indices =
            {
                0U, 1U, 2U,
                1U, 2U, 0U,
                2U, 0U, 1U
            };
            uint[] model2Indices =
            {
                3U, 4U, 5U,
                4U, 5U, 3U,
                5U, 3U, 4U,
                3U, 5U, 4U
            };

            uint outVBStartIndex, outIBStartIndex, outVBCount, outIBCount;

            // Set up context
            Assert.AreEqual(new ModelHandle(cacheID, 0U), testVertexCacheBuilder.AddModel("SCPC_a", model1Verts, model1Indices));
            Assert.AreEqual(new ModelHandle(cacheID, 1U), testVertexCacheBuilder.AddModel("SCPC_b", model2Verts, model2Indices));

            // Execute
            GeometryCache result = testVertexCacheBuilder.Build();

            // Assert outcome
            Assert.AreEqual(cacheID, result.ID);
            Assert.AreEqual(result, GeometryCache.GetCacheByID(cacheID));

            Assert.AreEqual((uint)(model1Indices.Length + model2Indices.Length), result.IndexBuffer.Length);
            Assert.AreEqual((uint)(model1Verts.Length + model2Verts.Length), result.VertexBuffers[0].Length);
            Assert.AreEqual(2, result.VertexBuffers.Count);
            Assert.AreEqual(ResourceFormat.R32G32B32Float, result.VertexFormats[0]);
            Assert.AreEqual(ResourceFormat.R32G32Float, result.VertexFormats[1]);
            Assert.AreEqual(2U, result.NumModels);
            Assert.AreEqual(6U, result.NumVertices);

            Assert.AreEqual(typeof(VertexBuffer <Vector3>), result.VertexBuffers[0].GetType());
            Assert.AreEqual(typeof(VertexBuffer <Vector2>), result.VertexBuffers[1].GetType());

            Assert.AreEqual("POSITION", result.VertexSemantics[0]);
            Assert.AreEqual("TEXCOORD", result.VertexSemantics[1]);

            result.GetModelBufferValues(0U, out outVBStartIndex, out outIBStartIndex, out outVBCount, out outIBCount);

            Assert.AreEqual(0U, outVBStartIndex);
            Assert.AreEqual(0U, outIBStartIndex);
            Assert.AreEqual(3U, outVBCount);
            Assert.AreEqual(9U, outIBCount);

            result.GetModelBufferValues(1U, out outVBStartIndex, out outIBStartIndex, out outVBCount, out outIBCount);

            Assert.AreEqual(3U, outVBStartIndex);
            Assert.AreEqual(9U, outIBStartIndex);
            Assert.AreEqual(3U, outVBCount);
            Assert.AreEqual(12U, outIBCount);

#if !DEVELOPMENT && !RELEASE
            try {
                result.GetModelBufferValues(2U, out outVBStartIndex, out outIBStartIndex, out outVBCount, out outIBCount);
                Assert.Fail();
            }
            catch (AssuranceFailedException) { }
#endif

            result.Dispose();
        }
        protected internal override void Execute(ParallelizationProvider pp)
        {
            // Set up buffers
            if (!output.TargetWindow.GetWindowRTVAndDSV(out windowRTVH, out windowDSVH))
            {
                return;
            }
            Vector2 viewportSizePixels = output.TargetWindow.AddedViewports.First().SizePixels;

            if (viewportSizePixels.X <= 0f || viewportSizePixels.Y <= 0f)
            {
                return;
            }
            SetUpBuffers(viewportSizePixels);

            // Clear pre-glow buffer
            QueueRenderCommand(RenderCommand.ClearRenderTarget(preGlowTargetBufferRTV));
            QueueRenderCommand(RenderCommand.ClearRenderTarget(glowSrcBufferRTV));
            QueueRenderCommand(RenderCommand.ClearRenderTarget(glowDstBufferRTV));

            List <GeometryCache> activeCaches = GeometryCache.ActiveCaches;

            foreach (GeometryCache c in activeCaches)
            {
                // Set view/proj matrix
                Matrix vpMat    = (*((Matrix *)Input.GetRecalculatedViewMatrix()) * *((Matrix *)Output.GetRecalculatedProjectionMatrix(Input))).Transpose;
                byte * vpMapPtr = (byte *)&vpMat;
                VertexShader.ViewProjMatBinding.SetValue(vpMapPtr);

                // Set state for current cache
                cpuInstanceBufferCurIndex = 0;
                List <SceneLayer> allEnabledLayers = Scene.EnabledLayers;
                uint maxLayer = 0U;
                for (int i = 0; i < allEnabledLayers.Count; ++i)
                {
                    if (allEnabledLayers[i].Index > maxLayer)
                    {
                        maxLayer = allEnabledLayers[i].Index;
                    }
                }
                if (allEnabledLayers.Count > 0 && currentSceneLayers.Length <= maxLayer)
                {
                    currentSceneLayers = new SceneLayer[maxLayer + 1U];
                }
                Array.Clear(currentSceneLayers, 0, currentSceneLayers.Length);
                foreach (SceneLayer layer in allEnabledLayers)
                {
                    currentSceneLayers[layer.Index] = layer;
                }
                currentCache = c;
                ++frameNum;
                Thread.MemoryBarrier();
                currentInstanceData = currentCache.GetModelInstanceData();

                // Set up each thread
                SetUpCacheForLocalThread();

                // Iterate all model instances (ordered by material && ZIndex)
                //if (instanceDataSortSpace.Length < currentInstanceData.Length) instanceDataSortSpace = new KeyValuePair<Material, ModelInstanceManager.MIDArray>[currentInstanceData.Length * 2];
                //for (int i = 0; i < currentInstanceData.Length; i += 2) {
                //	var a = currentInstanceData[i];
                //	if (currentInstanceData.Length == i + 1) {
                //		if (currentInstanceData.Length >= 3) {
                //			if (a.Key.ZIndex < instanceDataSortSpace[i - 2].Key.ZIndex) {
                //				instanceDataSortSpace[i] = instanceDataSortSpace[i - 1];
                //				instanceDataSortSpace[i - 1] = instanceDataSortSpace[i - 2];
                //				instanceDataSortSpace[i - 2] = a;
                //			}
                //			else if (a.Key.ZIndex < instanceDataSortSpace[i - 1].Key.ZIndex) {
                //				instanceDataSortSpace[i] = instanceDataSortSpace[i - 1];
                //				instanceDataSortSpace[i - 1] = a;
                //			}
                //			else instanceDataSortSpace[i] = a;
                //		}
                //		else instanceDataSortSpace[i] = a;
                //	}
                //	else {
                //		var b = currentInstanceData[i + 1];
                //		if (a.Key.ZIndex <= b.Key.ZIndex) {
                //			instanceDataSortSpace[i] = a;
                //			instanceDataSortSpace[i + 1] = b;
                //		}
                //		else {
                //			instanceDataSortSpace[i] = b;
                //			instanceDataSortSpace[i + 1] = a;
                //		}
                //	}
                //}
                Array.Sort(currentInstanceData.ContainingArray, 0, (int)currentInstanceData.Length, zIndexComparer);
                foreach (KeyValuePair <Material, ModelInstanceManager.MIDArray> material in currentInstanceData)
                {
                    for (int i = 0; i < currentInstanceData.Length; ++i)
                    {
                        if (currentInstanceData[i].Value == material.Value && currentInstanceData[i].Key == material.Key)
                        {
                            RenderCache_IterateMaterial(i);
                            break;
                        }
                    }
                }

                // Set instance buffer and write to it
                if (gpuInstanceBuffer == null || gpuInstanceBuffer.Length < cpuInstanceBuffer.Length)
                {
                    if (gpuInstanceBuffer != null)
                    {
                        gpuInstanceBuffer.Dispose();
                    }
                    gpuInstanceBuffer = gpuInstanceBufferBuilder.WithLength((uint)cpuInstanceBuffer.Length).Create();
                }
                gpuInstanceBuffer.DiscardWrite(cpuInstanceBuffer);                 // Happens immediately (required)

                // Set instance buffer and flush all commands, first on immediate context, then on each deferred
                SetInstanceBufferAndFlushCommands();
            }

            ///* =============================================
            // * PREPARE FOR GLOW
            // * ============================================= */

            //// Clear glow buffers
            //QueueRenderCommand(RenderCommand.ClearRenderTarget(glowSrcBufferRTV));

            //// Set blend state
            //QueueRenderCommand(RenderCommand.SetBlendState(glowBlendState));

            //// Set topology
            //QueueRenderCommand(RenderCommand.SetPrimitiveTopology(RenderCommand.DEFAULT_PRIMITIVE_TOPOLOGY));

            //// Set input layout
            //QueueRenderCommand(RenderCommand.SetInputLayout(glowPlaneInputLayout));

            //// Enqueue VS commands
            //QueueShaderSwitch(glowVS);
            //QueueShaderResourceUpdate(glowVS);

            ///* =============================================
            // * DOWNSCALE TO GLOW SRC BUFFER
            // * ============================================= */

            //// Set up output merger
            //QueueRenderCommand(RenderCommand.SetRenderTargets(glowDSBufferDSV, glowSrcBufferRTV));

            //// Switch to copy shader
            //QueueShaderSwitch(scaleDownShader);
            //QueueShaderResourceUpdate(scaleDownShader, scaleDownShaderResPkg);

            //// Draw fullscreen triangles
            //QueueRenderCommand(RenderCommand.Draw(0, 3U));
            //QueueRenderCommand(RenderCommand.Draw(3, 3U));

            //// Unbind resources
            //QueueShaderResourceUpdate(scaleDownShader, scaleDownShaderResUnbindPkg);

            ///* =============================================
            // * RENDER GLOW
            // * ============================================= */

            //// Set up output merger
            //QueueRenderCommand(RenderCommand.SetRenderTargets(glowDSBufferDSV, glowDstBufferRTV));

            //// Switch to glow shader
            //QueueShaderSwitch(glowShader);
            //QueueShaderResourceUpdate(glowShader, glowShaderVResPkg);

            //// Set blend state
            //QueueRenderCommand(RenderCommand.SetBlendState(dstMergeBlend));

            //// Draw fullscreen triangles
            //QueueRenderCommand(RenderCommand.Draw(0, 3U));
            //QueueRenderCommand(RenderCommand.Draw(3, 3U));

            //// Unbind resources
            //QueueShaderResourceUpdate(glowShader, glowShaderVResUnbindPkg);

            ///* =============================================
            // * UPSCALE TO BACK BUFFER
            // * ============================================= */

            //// Set up output merger
            //QueueRenderCommand(RenderCommand.SetRenderTargets(output.TargetWindow));

            //// Switch to copy shader
            //QueueShaderSwitch(scaleUpShader);
            //QueueShaderResourceUpdate(scaleUpShader, scaleUpShaderResPkg);

            //// Draw fullscreen triangles
            //QueueRenderCommand(RenderCommand.Draw(0, 3U));
            //QueueRenderCommand(RenderCommand.Draw(3, 3U));

            //// Unbind resources
            //QueueShaderResourceUpdate(scaleUpShader, scaleUpShaderResUnbindPkg);

            // Present
            FlushRenderCommands();
            if (presentAfterPass)
            {
                PresentBackBuffer(Output.TargetWindow);
            }
        }