using System; using Azimuth; using UnitTestSharp; using Blacklight.Core; using Blacklight.Core.Cameras; using Blacklight.Core.Drawables; using Blacklight.GPUBridge; namespace Blacklight.GPUBridge.UnitTests { public class ViewportBatcherTests : TestFixture { private static readonly Viewport BatcherViewport = new Viewport(7, 8); private static BatchPoolTests.BatchSourceMock NewBackend(int batchCapacity = int.MaxValue) { return new BatchPoolTests.BatchSourceMock(batchCapacity); } private static void QueueOneUnder(ViewportBatcher batcher, Camera camera) { batcher.StartCameraBatch(camera); batcher.QueuePrimitive(new Rectangle(), AffineMatrix.Identity); batcher.EndCameraBatch(); } public class ReferencePrimitiveMock : IDrawPrimitive { public Color ShellColor { get; set; } public Color InsideColor { get; set; } public Scalar ShellPixelThickness { get; set; } public Scalar ShellModelSpaceThickness { get; set; } public bool SmoothBorder { get; set; } public Texture ShellFillTexture { get; set; } public Texture InsideFillTexture { get; set; } } public class UnroutableDrawableMock : IDrawable { } public class CtorTests : TestFixture { public void ExposesTheViewport() { CheckEqual(BatcherViewport, new ViewportBatcher(NewBackend(), BatcherViewport).Viewport); } } public class FrameResetTests : TestFixture { public void DoesNothingWhenNoCamerasHaveBeenSeen() { var backend = NewBackend(); new ViewportBatcher(backend, BatcherViewport).FrameReset(); CheckEqual(0, backend.Created.Count); } public void ResetsEveryCameraPoolSoItsBatchesAreReused() { var backend = NewBackend(); var batcher = new ViewportBatcher(backend, BatcherViewport); var firstCamera = new MicroscopeCamera(new Viewport(1, 1)); var secondCamera = new MicroscopeCamera(new Viewport(2, 2)); QueueOneUnder(batcher, firstCamera); QueueOneUnder(batcher, secondCamera); batcher.FrameReset(); QueueOneUnder(batcher, firstCamera); QueueOneUnder(batcher, secondCamera); CheckEqual(2, backend.Created.Count); CheckEqual(1, backend.Created[0].Queued); CheckEqual(1, backend.Created[1].Queued); } public void ThrowsIfACameraBatchIsStillOpen() { var batcher = new ViewportBatcher(NewBackend(), BatcherViewport); batcher.StartCameraBatch(new MicroscopeCamera(new Viewport(1, 1))); CheckThrow(typeof(Exception)); batcher.FrameReset(); } } public class StartCameraBatchTests : TestFixture { public void ThrowsIfCalledAgainWithoutEndingFirst() { var batcher = new ViewportBatcher(NewBackend(), BatcherViewport); batcher.StartCameraBatch(new MicroscopeCamera(new Viewport(1, 1))); CheckThrow(typeof(Exception)); batcher.StartCameraBatch(new MicroscopeCamera(new Viewport(1, 1))); } public void ReusesThePoolForARepeatedCamera() { var backend = NewBackend(); var batcher = new ViewportBatcher(backend, BatcherViewport); var camera = new MicroscopeCamera(new Viewport(1, 1)); QueueOneUnder(batcher, camera); QueueOneUnder(batcher, camera); CheckEqual(1, backend.Created.Count); CheckEqual(2, backend.Created[0].Queued); } public void KeepsASeparatePoolPerCamera() { var backend = NewBackend(); var batcher = new ViewportBatcher(backend, BatcherViewport); var firstCamera = new MicroscopeCamera(new Viewport(1, 1)); var secondCamera = new MicroscopeCamera(new Viewport(2, 2)); QueueOneUnder(batcher, firstCamera); QueueOneUnder(batcher, secondCamera); CheckEqual(2, backend.Created.Count); CheckEqual(1, backend.Created[0].Queued); CheckEqual(1, backend.Created[1].Queued); CheckEqual(firstCamera, backend.Created[0].LastCamera); CheckEqual(secondCamera, backend.Created[1].LastCamera); CheckEqual(BatcherViewport, backend.Created[0].LastViewport); CheckEqual(BatcherViewport, backend.Created[1].LastViewport); } } public class EndCameraBatchTests : TestFixture { public void EndsTheOpenBatchSoAnotherCameraCanStart() { var batcher = new ViewportBatcher(NewBackend(), BatcherViewport); batcher.StartCameraBatch(new MicroscopeCamera(new Viewport(1, 1))); batcher.EndCameraBatch(); batcher.StartCameraBatch(new MicroscopeCamera(new Viewport(2, 2))); CheckTrue(batcher.QueuePrimitive(new Rectangle(), AffineMatrix.Identity)); } public void RepeatedCallsAreAllowed() { var batcher = new ViewportBatcher(NewBackend(), BatcherViewport); batcher.StartCameraBatch(new MicroscopeCamera(new Viewport(1, 1))); batcher.EndCameraBatch(); batcher.EndCameraBatch(); } public void CanCallWithoutStartingFirst() { var batcher = new ViewportBatcher(NewBackend(), BatcherViewport); batcher.EndCameraBatch(); } } public class QueuePrimitiveTests : TestFixture { public void Rectangle_QueuesToTheCurrentPool() { var backend = NewBackend(); var batcher = new ViewportBatcher(backend, BatcherViewport); batcher.StartCameraBatch(new MicroscopeCamera(new Viewport(1, 1))); CheckTrue(batcher.QueuePrimitive(new Rectangle(), AffineMatrix.Identity)); CheckEqual(1, backend.Created[0].Queued); } public void Ellipse_QueuesToTheCurrentPool() { var backend = NewBackend(); var batcher = new ViewportBatcher(backend, BatcherViewport); batcher.StartCameraBatch(new MicroscopeCamera(new Viewport(1, 1))); CheckTrue(batcher.QueuePrimitive(new Ellipse(), AffineMatrix.Identity)); CheckEqual(1, backend.Created[0].Queued); } public void BorderTriangle_QueuesToTheCurrentPool() { var backend = NewBackend(); var batcher = new ViewportBatcher(backend, BatcherViewport); batcher.StartCameraBatch(new MicroscopeCamera(new Viewport(1, 1))); CheckTrue(batcher.QueuePrimitive(new BorderTriangle(), AffineMatrix.Identity)); CheckEqual(1, backend.Created[0].Queued); } public void QuadraticBezierTriangle_QueuesToTheCurrentPool() { var backend = NewBackend(); var batcher = new ViewportBatcher(backend, BatcherViewport); batcher.StartCameraBatch(new MicroscopeCamera(new Viewport(1, 1))); CheckTrue(batcher.QueuePrimitive(new QuadraticBezierTriangle(), AffineMatrix.Identity)); CheckEqual(1, backend.Created[0].Queued); } public void Sprite_QueuesToTheCurrentPool() { var backend = NewBackend(); var batcher = new ViewportBatcher(backend, BatcherViewport); batcher.StartCameraBatch(new MicroscopeCamera(new Viewport(1, 1))); CheckTrue(batcher.QueuePrimitive(new Sprite(), AffineMatrix.Identity)); CheckEqual(1, backend.Created[0].Queued); } public void GenericPrimitive_QueuesToTheCurrentPool() { var backend = NewBackend(); var batcher = new ViewportBatcher(backend, BatcherViewport); batcher.StartCameraBatch(new MicroscopeCamera(new Viewport(1, 1))); CheckTrue(batcher.QueuePrimitive(new BatchPoolTests.PrimitiveMock(), AffineMatrix.Identity)); CheckEqual(1, backend.Created[0].Queued); } public void Rectangle_ThrowsWhenNoCameraBatchStarted() { var batcher = new ViewportBatcher(NewBackend(), BatcherViewport); CheckThrow(typeof(Exception)); batcher.QueuePrimitive(new Rectangle(), AffineMatrix.Identity); } public void Ellipse_ThrowsWhenNoCameraBatchStarted() { var batcher = new ViewportBatcher(NewBackend(), BatcherViewport); CheckThrow(typeof(Exception)); batcher.QueuePrimitive(new Ellipse(), AffineMatrix.Identity); } public void BorderTriangle_ThrowsWhenNoCameraBatchStarted() { var batcher = new ViewportBatcher(NewBackend(), BatcherViewport); CheckThrow(typeof(Exception)); batcher.QueuePrimitive(new BorderTriangle(), AffineMatrix.Identity); } public void QuadraticBezierTriangle_ThrowsWhenNoCameraBatchStarted() { var batcher = new ViewportBatcher(NewBackend(), BatcherViewport); CheckThrow(typeof(Exception)); batcher.QueuePrimitive(new QuadraticBezierTriangle(), AffineMatrix.Identity); } public void Sprite_ThrowsWhenNoCameraBatchStarted() { var batcher = new ViewportBatcher(NewBackend(), BatcherViewport); CheckThrow(typeof(Exception)); batcher.QueuePrimitive(new Sprite(), AffineMatrix.Identity); } public void GenericPrimitive_ThrowsWhenNoCameraBatchStarted() { var batcher = new ViewportBatcher(NewBackend(), BatcherViewport); CheckThrow(typeof(Exception)); batcher.QueuePrimitive(new BatchPoolTests.PrimitiveMock(), AffineMatrix.Identity); } } public class QueueEntityTests : TestFixture { public void Collage_Throws() { var batcher = new ViewportBatcher(NewBackend(), BatcherViewport); var entity = new Entity(new Collage(), AffineMatrix.Identity); CheckThrow(typeof(InvalidOperationException)); batcher.QueueEntity(entity); } public void Sprite_RoutesToTheSpriteOverload() { var backend = NewBackend(); var batcher = new ViewportBatcher(backend, BatcherViewport); batcher.StartCameraBatch(new MicroscopeCamera(new Viewport(1, 1))); batcher.QueueEntity(new Entity(new Sprite(), AffineMatrix.Identity)); CheckEqual(1, backend.Created[0].Queued); } public void Rectangle_RoutesToTheRectangleOverload() { var backend = NewBackend(); var batcher = new ViewportBatcher(backend, BatcherViewport); batcher.StartCameraBatch(new MicroscopeCamera(new Viewport(1, 1))); batcher.QueueEntity(new Entity(new Rectangle(), AffineMatrix.Identity)); CheckEqual(1, backend.Created[0].Queued); } public void Ellipse_RoutesToTheEllipseOverload() { var backend = NewBackend(); var batcher = new ViewportBatcher(backend, BatcherViewport); batcher.StartCameraBatch(new MicroscopeCamera(new Viewport(1, 1))); batcher.QueueEntity(new Entity(new Ellipse(), AffineMatrix.Identity)); CheckEqual(1, backend.Created[0].Queued); } public void BorderTriangle_RoutesToTheBorderTriangleOverload() { var backend = NewBackend(); var batcher = new ViewportBatcher(backend, BatcherViewport); batcher.StartCameraBatch(new MicroscopeCamera(new Viewport(1, 1))); batcher.QueueEntity(new Entity(new BorderTriangle(), AffineMatrix.Identity)); CheckEqual(1, backend.Created[0].Queued); } public void QuadraticBezierTriangle_RoutesToTheQuadraticBezierTriangleOverload() { var backend = NewBackend(); var batcher = new ViewportBatcher(backend, BatcherViewport); batcher.StartCameraBatch(new MicroscopeCamera(new Viewport(1, 1))); batcher.QueueEntity( new Entity(new QuadraticBezierTriangle(), AffineMatrix.Identity)); CheckEqual(1, backend.Created[0].Queued); } public void UnrecognizedValueTypePrimitive_ThrowsNotImplemented() { var batcher = new ViewportBatcher(NewBackend(), BatcherViewport); var entity = new Entity( new BatchPoolTests.PrimitiveMock(), AffineMatrix.Identity); CheckThrow(typeof(NotImplementedException)); batcher.QueueEntity(entity); } public void ReferenceTypePrimitive_RoutesThroughTheGenericOverload() { var backend = NewBackend(); var batcher = new ViewportBatcher(backend, BatcherViewport); batcher.StartCameraBatch(new MicroscopeCamera(new Viewport(1, 1))); batcher.QueueEntity(new Entity(new ReferencePrimitiveMock(), AffineMatrix.Identity)); CheckEqual(1, backend.Created[0].Queued); } public void UnroutableDrawable_Throws() { var batcher = new ViewportBatcher(NewBackend(), BatcherViewport); var entity = new Entity(new UnroutableDrawableMock(), AffineMatrix.Identity); CheckThrow(typeof(InvalidOperationException)); batcher.QueueEntity(entity); } } public class SubmitDrawCallsTests : TestFixture { public void BeginsSubmitOnTheBackend() { var backend = NewBackend(); var batcher = new ViewportBatcher(backend, BatcherViewport); batcher.SubmitDrawCalls(); CheckEqual(1, backend.BeginSubmitCount); } public void SubmitsEveryCameraPool() { var backend = NewBackend(); var batcher = new ViewportBatcher(backend, BatcherViewport); QueueOneUnder(batcher, new MicroscopeCamera(new Viewport(1, 1))); QueueOneUnder(batcher, new MicroscopeCamera(new Viewport(2, 2))); batcher.SubmitDrawCalls(); CheckEqual(1, backend.Created[0].SubmitCount); CheckEqual(1, backend.Created[1].SubmitCount); } } public class ReleaseResourcesTests : TestFixture { public void ReleasesEveryCameraPool() { var backend = NewBackend(); var batcher = new ViewportBatcher(backend, BatcherViewport); QueueOneUnder(batcher, new MicroscopeCamera(new Viewport(1, 1))); QueueOneUnder(batcher, new MicroscopeCamera(new Viewport(2, 2))); batcher.ReleaseResources(); CheckEqual(1, backend.Created[0].ReleaseCount); CheckEqual(1, backend.Created[1].ReleaseCount); } public void ReleasesTheBackend() { var backend = NewBackend(); var batcher = new ViewportBatcher(backend, BatcherViewport); batcher.ReleaseResources(); CheckEqual(1, backend.ReleaseResourcesCount); } public void ClearsPoolsSoTheNextStartAllocatesFresh() { var backend = NewBackend(); var batcher = new ViewportBatcher(backend, BatcherViewport); var camera = new MicroscopeCamera(new Viewport(1, 1)); QueueOneUnder(batcher, camera); batcher.ReleaseResources(); QueueOneUnder(batcher, camera); CheckEqual(2, backend.Created.Count); } } public class ResetTests : TestFixture { public void ResetsTheBackend() { var backend = NewBackend(); var batcher = new ViewportBatcher(backend, BatcherViewport); batcher.Reset(); CheckEqual(1, backend.ResetCount); } public void LeavesCameraPoolsIntact() { // Reset forwards only to the backend. Unlike ReleaseResources it must leave the per-camera pools in // place, so a repeated camera reuses its pool instead of allocating a fresh one. var backend = NewBackend(); var batcher = new ViewportBatcher(backend, BatcherViewport); var camera = new MicroscopeCamera(new Viewport(1, 1)); QueueOneUnder(batcher, camera); batcher.Reset(); QueueOneUnder(batcher, camera); CheckEqual(1, backend.Created.Count); } } } }