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(); }
private unsafe void ResizeList() { uint newListLen = CurListLen + LIST_SIZE_INCREMENT; GC.RemoveMemoryPressure(sizeof(RenderCommand) * CurListLen); AlignedAllocation <RenderCommand> newListSpace = AlignedAllocation <RenderCommand> .AllocArray(LIST_ALIGNMENT, newListLen); GC.AddMemoryPressure(sizeof(RenderCommand) * CurListLen); UnsafeUtils.MemCopy(RenderCommandList.AlignedPointer, newListSpace.AlignedPointer, (uint)sizeof(RenderCommand) * CurListLen); CurListLen = newListLen; RenderCommandList.Dispose(); RenderCommandList = newListSpace; }
public unsafe void TestAllocArray() { // Define variables and constants const int NUM_ALLOCS = 2000; const long ALLOC_ALIGNMENT = 2L; // Set up context AlignedAllocation <Vector4> alignedArray = AlignedAllocation <Vector4> .AllocArray(ALLOC_ALIGNMENT, NUM_ALLOCS); // Execute *((Vector4 *)(alignedArray.AlignedPointer + NUM_ALLOCS - 1)) = new Vector4(1, 2, 3, 4); // Assert outcome Assert.AreEqual(new Vector4(1, 2, 3, 4), *((Vector4 *)(alignedArray.AlignedPointer + NUM_ALLOCS - 1))); Assert.AreEqual(0L, (long)alignedArray.AlignedPointer % ALLOC_ALIGNMENT); alignedArray.Dispose(); }
/// <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(); }