diff --git a/Robust.Client/Graphics/Clyde/Clyde.RenderHandle.cs b/Robust.Client/Graphics/Clyde/Clyde.RenderHandle.cs new file mode 100644 index 000000000..ffab78ce6 --- /dev/null +++ b/Robust.Client/Graphics/Clyde/Clyde.RenderHandle.cs @@ -0,0 +1,275 @@ +using System; +using Robust.Client.GameObjects; +using Robust.Client.Graphics.ClientEye; +using Robust.Client.Graphics.Drawing; +using Robust.Client.Graphics.Shaders; +using Robust.Client.Interfaces.Graphics; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Maths; + +namespace Robust.Client.Graphics.Clyde +{ + internal partial class Clyde + { + private sealed class RenderHandle : IRenderHandle + { + private readonly Clyde _clyde; + + public DrawingHandleScreen DrawingHandleScreen { get; } + public DrawingHandleWorld DrawingHandleWorld { get; } + + public RenderHandle(Clyde clyde) + { + _clyde = clyde; + + DrawingHandleScreen = new DrawingHandleScreenImpl(this); + DrawingHandleWorld = new DrawingHandleWorldImpl(this); + } + + public void SetModelTransform(in Matrix3 matrix) + { + _clyde.DrawSetModelTransform(matrix); + } + + public void SetViewTransform(in Matrix3 matrix) + { + _clyde.DrawSetViewTransform(matrix); + } + + public void ResetViewTransform() + { + _clyde.DrawResetViewTransform(); + } + + public void DrawTexture(Texture texture, Vector2 a, Vector2 b, Color modulate, UIBox2? subRegion, + Angle angle) + { + if (texture is AtlasTexture atlas) + { + texture = atlas.SourceTexture; + if (subRegion.HasValue) + { + var offset = atlas.SubRegion.TopLeft; + subRegion = new UIBox2( + subRegion.Value.TopLeft + offset, + subRegion.Value.BottomRight + offset); + } + else + { + subRegion = atlas.SubRegion; + } + } + + var clydeTexture = (ClydeTexture) texture; + + _clyde.DrawTexture(clydeTexture.TextureId, a, b, modulate, subRegion, angle); + } + + public void SetScissor(UIBox2i? scissorBox) + { + _clyde.DrawSetScissor(scissorBox); + } + + public void SetSpace(CurrentSpace space) + { + _clyde.DrawSwitchSpace(space); + } + + public void DrawEntity(IEntity entity, Vector2 position, Vector2 scale) + { + if (entity.Deleted) + { + throw new ArgumentException("Tried to draw an entity has been deleted.", nameof(entity)); + } + + var sprite = entity.GetComponent(); + + // Switch rendering to world space. + SetSpace(CurrentSpace.WorldSpace); + + { + var ofsX = position.X - _clyde.ScreenSize.X / 2f; + var ofsY = position.Y - _clyde.ScreenSize.Y / 2f; + + var viewMatrix = Matrix3.Identity; + viewMatrix.R0C0 = scale.X; + viewMatrix.R1C1 = scale.Y; + viewMatrix.R0C2 = ofsX / EyeManager.PIXELSPERMETER; + viewMatrix.R1C2 = -ofsY / EyeManager.PIXELSPERMETER; + + SetViewTransform(viewMatrix); + } + + // Draw the entity. + sprite.OpenGLRender(DrawingHandleWorld, false); + + // Reset to screen space + SetSpace(CurrentSpace.ScreenSpace); + } + + public void DrawLine(Vector2 a, Vector2 b, Color color) + { + _clyde.DrawLine(a, b, color); + } + + public void UseShader(ShaderInstance shader) + { + if (shader != null && shader.Disposed) + { + throw new ArgumentException("Unable to use disposed shader instance.", nameof(shader)); + } + + var clydeShader = (ClydeShaderInstance) shader; + + _clyde.DrawUseShader(clydeShader?.Handle ?? _clyde._defaultShader.Handle); + } + + public void Viewport(Box2i viewport) + { + _clyde.DrawViewport(viewport); + } + + public void UseRenderTarget(IRenderTarget renderTarget) + { + var target = (RenderTarget) renderTarget; + + _clyde.DrawRenderTarget(target?.Handle ?? default); + } + + public void Clear(Color color) + { + _clyde.DrawClear(color); + } + + private sealed class DrawingHandleScreenImpl : DrawingHandleScreen + { + private readonly RenderHandle _renderHandle; + + public DrawingHandleScreenImpl(RenderHandle renderHandle) + { + _renderHandle = renderHandle; + } + + public override void SetTransform(in Matrix3 matrix) + { + _renderHandle.SetModelTransform(matrix); + } + + public override void UseShader(ShaderInstance shader) + { + _renderHandle.UseShader(shader); + } + + public override void DrawCircle(Vector2 position, float radius, Color color) + { + // TODO: Implement this. + } + + public override void DrawLine(Vector2 from, Vector2 to, Color color) + { + _renderHandle.DrawLine(@from, to, color * Modulate); + } + + public override void DrawRect(UIBox2 rect, Color color, bool filled = true) + { + if (filled) + { + DrawTextureRect(Texture.White, rect, color); + } + else + { + DrawLine(rect.TopLeft, rect.TopRight, color); + DrawLine(rect.TopRight, rect.BottomRight, color); + DrawLine(rect.BottomRight, rect.BottomLeft, color); + DrawLine(rect.BottomLeft, rect.TopLeft, color); + } + } + + public override void DrawTextureRectRegion(Texture texture, UIBox2 rect, UIBox2? subRegion = null, + Color? modulate = null) + { + var color = (modulate ?? Color.White) * Modulate; + _renderHandle.DrawTexture(texture, rect.TopLeft, rect.BottomRight, color, + subRegion, 0); + } + } + + private sealed class DrawingHandleWorldImpl : DrawingHandleWorld + { + private readonly RenderHandle _renderHandle; + + public DrawingHandleWorldImpl(RenderHandle renderHandle) + { + _renderHandle = renderHandle; + } + + public override void SetTransform(in Matrix3 matrix) + { + _renderHandle.SetModelTransform(matrix); + } + + public override void UseShader(ShaderInstance shader) + { + _renderHandle.UseShader(shader); + } + + public override void DrawCircle(Vector2 position, float radius, Color color) + { + // TODO: Implement this. + } + + public override void DrawLine(Vector2 from, Vector2 to, Color color) + { + _renderHandle.DrawLine(@from, to, color * Modulate); + } + + public override void DrawRect(Box2 rect, Color color, bool filled = true) + { + if (filled) + { + DrawTextureRect(Texture.White, rect, color); + } + else + { + DrawLine(rect.TopLeft, rect.TopRight, color); + DrawLine(rect.TopRight, rect.BottomRight, color); + DrawLine(rect.BottomRight, rect.BottomLeft, color); + DrawLine(rect.BottomLeft, rect.TopLeft, color); + } + } + + public override void DrawRect(in Box2Rotated rect, Color color, bool filled = true) + { + if (filled) + { + DrawTextureRect(Texture.White, rect, color); + } + else + { + DrawLine(rect.TopLeft, rect.TopRight, color); + DrawLine(rect.TopRight, rect.BottomRight, color); + DrawLine(rect.BottomRight, rect.BottomLeft, color); + DrawLine(rect.BottomLeft, rect.TopLeft, color); + } + } + + public override void DrawTextureRectRegion(Texture texture, Box2 rect, UIBox2? subRegion = null, + Color? modulate = null) + { + var color = (modulate ?? Color.White) * Modulate; + + _renderHandle.DrawTexture(texture, rect.BottomLeft, rect.TopRight, color, subRegion, 0); + } + + public override void DrawTextureRectRegion(Texture texture, in Box2Rotated rect, + UIBox2? subRegion = null, Color? modulate = null) + { + var color = (modulate ?? Color.White) * Modulate; + + _renderHandle.DrawTexture(texture, rect.Box.BottomLeft, rect.Box.TopRight, color, subRegion, + (float) rect.Rotation); + } + } + } + } +} diff --git a/Robust.Client/Graphics/Clyde/Clyde.Rendering.cs b/Robust.Client/Graphics/Clyde/Clyde.Rendering.cs index 060b46623..8b9e34df6 100644 --- a/Robust.Client/Graphics/Clyde/Clyde.Rendering.cs +++ b/Robust.Client/Graphics/Clyde/Clyde.Rendering.cs @@ -7,13 +7,10 @@ using System.Runtime.InteropServices; using OpenTK.Graphics.OpenGL; using Robust.Client.GameObjects; using Robust.Client.Graphics.ClientEye; -using Robust.Client.Graphics.Drawing; using Robust.Client.Graphics.Overlays; -using Robust.Client.Graphics.Shaders; using Robust.Client.Interfaces.Graphics; using Robust.Client.ResourceManagement; using Robust.Client.Utility; -using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Maths; using Robust.Shared.Utility; @@ -27,6 +24,7 @@ namespace Robust.Client.Graphics.Clyde /// Are we current rendering screen space or world space? Some code works differently between the two. /// private CurrentSpace _currentSpace; + private CurrentSpace _queuedSpace; private bool _lightingReady; @@ -44,20 +42,12 @@ namespace Robust.Client.Graphics.Clyde // Need 5 indices per quad: 4 to draw the quad with triangle strips and another one as primitive restart. private readonly ushort[] BatchIndexData = new ushort[MaxBatchQuads * 5]; - private int BatchIndex; + private int BatchVertexIndex; + private int BatchIndexIndex; - private ClydeHandle? BatchingTexture; - - // We break batching when modulate changes too. - // This simplifies the rendering and catches most cases for now. - // For example all the walls have a single color. - // Yes this can be optimized later. - private Color? BatchingModulate; - - /// - /// If true, re-allocate buffer objects with BufferData instead of using BufferSubData. - /// - private bool _reallocateBuffers; + // Contains information about the currently running batch. + // So we can flush it if the next draw call is incompatible. + private BatchMetaData? _batchMetaData; private ProjViewMatrices _currentMatrices; @@ -69,6 +59,9 @@ namespace Robust.Client.Graphics.Clyde private readonly List _sortingSpritesList = new List(); + private readonly RefList _queuedRenderCommands = new RefList(); + + public void Render() { var size = ScreenSize; @@ -84,13 +77,13 @@ namespace Robust.Client.Graphics.Clyde // Update shared UBOs. _updateUniformConstants(); - _setSpace(CurrentSpace.ScreenSpace); + SetSpaceFull(CurrentSpace.ScreenSpace); // Short path to render only the splash. if (_drawingSplash) { _drawSplash(_renderHandle); - _flushRenderHandle(_renderHandle); + FlushRenderQueue(); SwapBuffers(); return; } @@ -106,13 +99,13 @@ namespace Robust.Client.Graphics.Clyde overlay.ClydeRender(_renderHandle); } - _flushRenderHandle(_renderHandle); + FlushRenderQueue(); } } RenderOverlays(OverlaySpace.ScreenSpaceBelowWorld); - _setSpace(CurrentSpace.WorldSpace); + SetSpaceFull(CurrentSpace.WorldSpace); // Calculate world-space AABB for camera, to cull off-screen things. var eye = _eyeManager.CurrentEye; @@ -210,21 +203,21 @@ namespace Robust.Client.Graphics.Clyde } } - _flushRenderHandle(_renderHandle); + FlushRenderQueue(); } RenderOverlays(OverlaySpace.WorldSpace); _lightingReady = false; - _setSpace(CurrentSpace.ScreenSpace); + SetSpaceFull(CurrentSpace.ScreenSpace); RenderOverlays(OverlaySpace.ScreenSpace); using (DebugGroup("UI")) { _userInterfaceManager.Render(_renderHandle); - _flushRenderHandle(_renderHandle); + FlushRenderQueue(); } // And finally, swap those buffers! @@ -244,7 +237,7 @@ namespace Robust.Client.Graphics.Clyde private void _updateUniformConstants() { var constants = new UniformConstants(Vector2.One / ScreenSize, _renderTime); - _writeBuffer(UniformConstantsUBO, constants); + UniformConstantsUBO.Reallocate(constants); } private ProjViewMatrices _screenMatrices() @@ -398,32 +391,20 @@ namespace Robust.Client.Graphics.Clyde private void _setProjViewMatrices(in ProjViewMatrices matrices) { _currentMatrices = matrices; - _writeBuffer(ProjViewUBO, matrices); + ProjViewUBO.Reallocate(matrices); } - private void _processCommandList(RenderCommandList list) + private void ProcessRenderCommands() { - foreach (ref var command in list.RenderCommands) + foreach (ref var command in _queuedRenderCommands) { switch (command.Type) { - case RenderCommandType.Texture: - _drawCommandTexture(ref command.Texture); - _debugStats.LastClydeDrawCalls += 1; - break; - - case RenderCommandType.Line: - _flushBatchBuffer(); - _drawCommandLine(ref command.Line); - _debugStats.LastClydeDrawCalls += 1; - break; - - case RenderCommandType.ModelMatrix: - _currentModelMatrix = command.ModelMatrix.Matrix; + case RenderCommandType.DrawBatch: + DrawCommandBatch(ref command.DrawBatch); break; case RenderCommandType.Scissor: - _flushBatchBuffer(); var oldIsScissoring = _isScissoring; _isScissoring = command.Scissor.EnableScissor; if (_isScissoring) @@ -445,33 +426,28 @@ namespace Robust.Client.Graphics.Clyde break; case RenderCommandType.ViewMatrix: - _flushBatchBuffer(); var matrices = new ProjViewMatrices(_currentMatrices, command.ViewMatrix.Matrix); _setProjViewMatrices(matrices); break; case RenderCommandType.UseShader: - _flushBatchBuffer(); if (command.UseShader.Handle.Value == _currentShader.Value) { break; } - _currentShader = (ClydeHandle) command.UseShader.Handle; + _currentShader = command.UseShader.Handle; break; case RenderCommandType.ResetViewMatrix: - _flushBatchBuffer(); _setSpace(_currentSpace); break; case RenderCommandType.SwitchSpace: - _flushBatchBuffer(); _setSpace(command.SwitchSpace.NewSpace); break; case RenderCommandType.RenderTarget: - _flushBatchBuffer(); if (command.RenderTarget.RenderTarget.Value == 0) { _popDebugGroupMaybe(); @@ -493,13 +469,11 @@ namespace Robust.Client.Graphics.Clyde break; case RenderCommandType.Viewport: - _flushBatchBuffer(); ref var vp = ref command.Viewport.Viewport; GL.Viewport(vp.Left, vp.Bottom, vp.Width, vp.Height); break; case RenderCommandType.Clear: - _flushBatchBuffer(); ref var color = ref command.Clear.Color; GL.ClearColor(color.R, color.G, color.B, color.A); GL.Clear(ClearBufferMask.ColorBufferBit); @@ -511,178 +485,12 @@ namespace Robust.Client.Graphics.Clyde } } - private void _drawCommandTexture(ref RenderCommandTexture command) + private void DrawCommandBatch(ref RenderCommandDrawBatch command) { - if (BatchingTexture.HasValue) - { - DebugTools.Assert(BatchingModulate.HasValue); - if (BatchingTexture.Value != command.TextureId || - !StrictColorEquality(BatchingModulate.Value, command.Modulate)) - { - _flushBatchBuffer(); - BatchingTexture = command.TextureId; - BatchingModulate = command.Modulate; - } - } - else - { - BatchingTexture = command.TextureId; - BatchingModulate = command.Modulate; - } - - var loadedTexture = _loadedTextures[BatchingTexture.Value]; - UIBox2 sr; - if (command.HasSubRegion) - { - var (w, h) = loadedTexture.Size; - var csr = command.SubRegion; - if (_currentSpace == CurrentSpace.WorldSpace) - { - sr = new UIBox2(csr.Left / w, csr.Top / h, csr.Right / w, csr.Bottom / h); - } - else - { - sr = new UIBox2(csr.Left / w, csr.Bottom / h, csr.Right / w, csr.Top / h); - } - } - else - { - if (_currentSpace == CurrentSpace.WorldSpace) - { - sr = new UIBox2(0, 0, 1, 1); - } - else - { - sr = new UIBox2(0, 1, 1, 0); - } - } - - Vector2 bl; - Vector2 br; - Vector2 tr; - Vector2 tl; - // ReSharper disable once CompareOfFloatsByEqualityOperator - if (command.Angle == Angle.Zero) - { - bl = _currentModelMatrix.Transform(command.PositionA); - br = _currentModelMatrix.Transform(new Vector2(command.PositionB.X, command.PositionA.Y)); - tr = _currentModelMatrix.Transform(command.PositionB); - tl = _currentModelMatrix.Transform(new Vector2(command.PositionA.X, command.PositionB.Y)); - } - else - { - bl = _currentModelMatrix.Transform(command.Angle.RotateVec(command.PositionA)); - br = _currentModelMatrix.Transform( - command.Angle.RotateVec(new Vector2(command.PositionB.X, command.PositionA.Y))); - tr = _currentModelMatrix.Transform(command.Angle.RotateVec(command.PositionB)); - tl = _currentModelMatrix.Transform( - command.Angle.RotateVec(new Vector2(command.PositionA.X, command.PositionB.Y))); - } - - var vIdx = BatchIndex * 4; - BatchVertexData[vIdx + 0] = new Vertex2D(bl, sr.BottomLeft); - BatchVertexData[vIdx + 1] = new Vertex2D(br, sr.BottomRight); - BatchVertexData[vIdx + 2] = new Vertex2D(tl, sr.TopLeft); - BatchVertexData[vIdx + 3] = new Vertex2D(tr, sr.TopRight); - var nIdx = BatchIndex * 5; - var tIdx = (ushort) (BatchIndex * 4); - BatchIndexData[nIdx + 0] = tIdx; - BatchIndexData[nIdx + 1] = (ushort) (tIdx + 1); - BatchIndexData[nIdx + 2] = (ushort) (tIdx + 2); - BatchIndexData[nIdx + 3] = (ushort) (tIdx + 3); - BatchIndexData[nIdx + 4] = ushort.MaxValue; - BatchIndex += 1; - if (BatchIndex >= MaxBatchQuads) - { - throw new NotImplementedException("Can't batch things this big yet sorry."); - } - } - - private void _drawCommandLine(ref RenderCommandLine renderCommandLine) - { - var (program, loaded) = ActivateShaderInstance(_currentShader); - - program.Use(); - program.SetUniformMaybe(UniIModUV, new Vector4(0, 0, 1, 1)); - program.SetUniformMaybe(UniIModulate, renderCommandLine.Color); - - var white = _loadedTextures[((ClydeTexture) Texture.White).TextureId].OpenGLObject; - GL.ActiveTexture(TextureUnit.Texture0); - GL.BindTexture(TextureTarget.Texture2D, white.Handle); - - GL.ActiveTexture(TextureUnit.Texture1); - if (_lightingReady && loaded.HasLighting) - { - var lightTexture = _loadedTextures[LightRenderTarget.Texture.TextureId].OpenGLObject; - GL.BindTexture(TextureTarget.Texture2D, lightTexture.Handle); - } - else - { - GL.BindTexture(TextureTarget.Texture2D, white.Handle); - } - - program.SetUniformTextureMaybe(UniIMainTexture, TextureUnit.Texture0); - program.SetUniformTextureMaybe(UniILightTexture, TextureUnit.Texture1); - - var a = renderCommandLine.PositionA; - var b = renderCommandLine.PositionB; - - GL.BindVertexArray(LineVAO.Handle); - var rectTransform = Matrix3.Identity; - (rectTransform.R0C0, rectTransform.R1C1) = b - a; - (rectTransform.R0C2, rectTransform.R1C2) = a; - rectTransform.Multiply(ref _currentModelMatrix); - program.SetUniformMaybe(UniIModelMatrix, rectTransform); - _debugStats.LastGLDrawCalls += 1; - GL.DrawArrays(PrimitiveType.Lines, 0, 2); - } - - private void _drawQuad(Vector2 a, Vector2 b, ref Matrix3 modelMatrix, ShaderProgram program) - { - GL.BindVertexArray(QuadVAO.Handle); - var rectTransform = Matrix3.Identity; - (rectTransform.R0C0, rectTransform.R1C1) = b - a; - (rectTransform.R0C2, rectTransform.R1C2) = a; - rectTransform.Multiply(ref modelMatrix); - program.SetUniformMaybe(UniIModelMatrix, rectTransform); - - _debugStats.LastGLDrawCalls += 1; - GL.DrawArrays(PrimitiveType.TriangleStrip, 0, 4); - } - - /// - /// Flush the render handle, processing and re-pooling all the command lists. - /// - private void _flushRenderHandle(RenderHandle handle) - { - _processCommandList(handle.CommandList); - handle.CommandList.RenderCommands.Clear(); - - _flushBatchBuffer(); - - // Reset renderer state. - _currentShader = _defaultShader.Handle; - _currentModelMatrix = Matrix3.Identity; - _disableScissor(); - } - - private void _flushBatchBuffer() - { - if (!BatchingTexture.HasValue) - { - return; - } - - _debugStats.LastBatches += 1; - - DebugTools.Assert(BatchingTexture.HasValue); - var loadedTexture = _loadedTextures[BatchingTexture.Value]; + var loadedTexture = _loadedTextures[command.TextureId]; GL.BindVertexArray(BatchVAO.Handle); - _writeBuffer(BatchVBO, new Span(BatchVertexData, 0, BatchIndex * 4)); - _writeBuffer(BatchEBO, new Span(BatchIndexData, 0, BatchIndex * 5)); - var (program, loaded) = ActivateShaderInstance(_currentShader); GL.ActiveTexture(TextureUnit.Texture0); @@ -707,20 +515,78 @@ namespace Robust.Client.Graphics.Clyde program.SetUniformMaybe(UniIModelMatrix, Matrix3.Identity); // Reset ModUV to ensure it's identity and doesn't touch anything. program.SetUniformMaybe(UniIModUV, new Vector4(0, 0, 1, 1)); - // Set modulate. - DebugTools.Assert(BatchingModulate.HasValue); - program.SetUniformMaybe(UniIModulate, BatchingModulate.Value); + + program.SetUniformMaybe(UniIModulate, command.Modulate); program.SetUniformMaybe(UniITexturePixelSize, Vector2.One / loadedTexture.Size); - _debugStats.LastGLDrawCalls += 1; - GL.DrawElements(PrimitiveType.TriangleStrip, BatchIndex * 5, DrawElementsType.UnsignedShort, 0); - // Reset batch state. - BatchIndex = 0; - BatchingTexture = null; - BatchingModulate = null; + var primitiveType = MapPrimitiveType(command.PrimitiveType); + if (command.Indexed) + { + GL.DrawElements(primitiveType, command.Count, DrawElementsType.UnsignedShort, command.StartIndex * sizeof(ushort)); + } + else + { + GL.DrawArrays(primitiveType, command.StartIndex, command.Count); + } + + _debugStats.LastGLDrawCalls += 1; } + private PrimitiveType MapPrimitiveType(BatchPrimitiveType type) + { + return type switch + { + BatchPrimitiveType.Triangles => PrimitiveType.Triangles, + BatchPrimitiveType.TrianglesFan => PrimitiveType.TriangleFan, + BatchPrimitiveType.Line => PrimitiveType.Lines, + _ => PrimitiveType.Triangles + }; + } + + private void _drawQuad(Vector2 a, Vector2 b, ref Matrix3 modelMatrix, ShaderProgram program) + { + GL.BindVertexArray(QuadVAO.Handle); + var rectTransform = Matrix3.Identity; + (rectTransform.R0C0, rectTransform.R1C1) = b - a; + (rectTransform.R0C2, rectTransform.R1C2) = a; + rectTransform.Multiply(ref modelMatrix); + program.SetUniformMaybe(UniIModelMatrix, rectTransform); + + _debugStats.LastGLDrawCalls += 1; + GL.DrawArrays(PrimitiveType.TriangleStrip, 0, 4); + } + + /// + /// Flush the render handle, processing and re-pooling all the command lists. + /// + private void FlushRenderQueue() + { + // Finish any batches that may have been WiP. + BreakBatch(); + + if (BatchVertexIndex != 0) + { + BatchVBO.Reallocate(new Span(BatchVertexData, 0, BatchVertexIndex)); + BatchVertexIndex = 0; + + if (BatchIndexIndex != 0) + { + BatchEBO.Reallocate(new Span(BatchIndexData, 0, BatchIndexIndex)); + } + BatchIndexIndex = 0; + } + + ProcessRenderCommands(); + _queuedRenderCommands.Clear(); + + // Reset renderer state. + _currentShader = _defaultShader.Handle; + _currentModelMatrix = Matrix3.Identity; + _disableScissor(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] private void _disableScissor() { @@ -749,37 +615,24 @@ namespace Robust.Client.Graphics.Clyde } } + private void SetSpaceFull(CurrentSpace newSpace) + { + _setSpace(newSpace); + + SetQueuedSpace(newSpace); + } + + private void SetQueuedSpace(CurrentSpace newSpace) + { + _queuedSpace = newSpace; + } + private void ClearFramebuffer(Color color) { GL.ClearColor(color.ConvertOpenTK()); GL.Clear(ClearBufferMask.ColorBufferBit); } - // Uses either glBufferData or glBufferSubData depending on _reallocateBuffers. - private void _writeBuffer(Buffer buffer, Span data) where T : unmanaged - { - if (_reallocateBuffers) - { - buffer.Reallocate(data); - } - else - { - buffer.WriteSubData(data); - } - } - - private void _writeBuffer(Buffer buffer, in T data) where T : unmanaged - { - if (_reallocateBuffers) - { - buffer.Reallocate(data); - } - else - { - buffer.WriteSubData(data); - } - } - private (ShaderProgram, LoadedShader) ActivateShaderInstance(ClydeHandle handle) { var instance = _shaderInstances[handle]; @@ -849,320 +702,237 @@ namespace Robust.Client.Graphics.Clyde return a.R == b.R && a.G == b.G && a.B == b.B && a.A == b.A; } - private sealed class RenderHandle : IRenderHandle + private ref RenderCommand AllocRenderCommand(RenderCommandType type) { - private readonly Clyde _clyde; - public readonly RenderCommandList CommandList = new RenderCommandList(); + ref var command = ref _queuedRenderCommands.AllocAdd(); + command.Type = type; + return ref command; + } - public DrawingHandleScreen DrawingHandleScreen { get; } - public DrawingHandleWorld DrawingHandleWorld { get; } + private void DrawSetModelTransform(in Matrix3 matrix) + { + _currentModelMatrix = matrix; + } - public RenderHandle(Clyde clyde) + private void DrawSetViewTransform(in Matrix3 matrix) + { + ref var command = ref AllocRenderCommand(RenderCommandType.ViewMatrix); + + command.ViewMatrix.Matrix = matrix; + } + + private void DrawResetViewTransform() + { + AllocRenderCommand(RenderCommandType.ResetViewMatrix); + } + + private void DrawTexture(ClydeHandle texture, Vector2 a, Vector2 b, Color modulate, UIBox2? subRegion, + Angle angle) + { + EnsureBatchState(texture, modulate, true, BatchPrimitiveType.TrianglesFan); + + var loadedTexture = _loadedTextures[texture]; + + UIBox2 sr; + if (subRegion.HasValue) { - _clyde = clyde; - DrawingHandleScreen = new DrawingHandleScreenImpl(this); - DrawingHandleWorld = new DrawingHandleWorldImpl(this); - } - - public void SetModelTransform(in Matrix3 matrix) - { - ref var command = ref CommandList.RenderCommands.AllocAdd(); - command.Type = RenderCommandType.ModelMatrix; - - command.ModelMatrix.Matrix = matrix; - } - - public void SetViewTransform(in Matrix3 matrix) - { - ref var command = ref CommandList.RenderCommands.AllocAdd(); - command.Type = RenderCommandType.ViewMatrix; - - command.ViewMatrix.Matrix = matrix; - } - - public void ResetViewTransform() - { - ref var command = ref CommandList.RenderCommands.AllocAdd(); - command.Type = RenderCommandType.ResetViewMatrix; - } - - public void DrawTexture(Texture texture, Vector2 a, Vector2 b, Color modulate, UIBox2? subRegion, - Angle angle) - { - switch (texture) + var (w, h) = loadedTexture.Size; + var csr = subRegion.Value; + if (_queuedSpace == CurrentSpace.WorldSpace) { - case AtlasTexture atlas: - { - texture = atlas.SourceTexture; - if (subRegion.HasValue) - { - var offset = atlas.SubRegion.TopLeft; - subRegion = new UIBox2( - subRegion.Value.TopLeft + offset, - subRegion.Value.BottomRight + offset); - } - else - { - subRegion = atlas.SubRegion; - } - - break; - } - } - - ref var command = ref CommandList.RenderCommands.AllocAdd(); - command.Type = RenderCommandType.Texture; - - var clydeTexture = (ClydeTexture) texture; - command.Texture.TextureId = clydeTexture.TextureId; - command.Texture.PositionA = a; - command.Texture.PositionB = b; - command.Texture.Angle = angle; - command.Texture.Modulate = modulate; - if (subRegion.HasValue) - { - command.Texture.SubRegion = subRegion.Value; - command.Texture.HasSubRegion = true; + sr = new UIBox2(csr.Left / w, csr.Top / h, csr.Right / w, csr.Bottom / h); } else { - command.Texture.HasSubRegion = false; + sr = new UIBox2(csr.Left / w, csr.Bottom / h, csr.Right / w, csr.Top / h); } } - - public void SetScissor(UIBox2i? scissorBox) + else { - ref var command = ref CommandList.RenderCommands.AllocAdd(); - command.Type = RenderCommandType.Scissor; - - command.Scissor.EnableScissor = scissorBox.HasValue; - if (scissorBox.HasValue) + if (_queuedSpace == CurrentSpace.WorldSpace) { - command.Scissor.Scissor = scissorBox.Value; + sr = new UIBox2(0, 0, 1, 1); + } + else + { + sr = new UIBox2(0, 1, 1, 0); } } - public void SetSpace(CurrentSpace space) + Vector2 bl; + Vector2 br; + Vector2 tr; + Vector2 tl; + if (angle == Angle.Zero) { - ref var commandWorldSpace = ref CommandList.RenderCommands.AllocAdd(); - commandWorldSpace.Type = RenderCommandType.SwitchSpace; - commandWorldSpace.SwitchSpace.NewSpace = space; + bl = _currentModelMatrix.Transform(a); + br = _currentModelMatrix.Transform(new Vector2(b.X, a.Y)); + tr = _currentModelMatrix.Transform(b); + tl = _currentModelMatrix.Transform(new Vector2(a.X, b.Y)); } - - public void DrawEntity(IEntity entity, Vector2 position, Vector2 scale) + else { - if (entity.Deleted) - { - throw new ArgumentException("Tried to draw an entity has been deleted.", nameof(entity)); - } - - var sprite = entity.GetComponent(); - - // Switch rendering to world space. - SetSpace(CurrentSpace.WorldSpace); - - { - // Change view matrix to put entity where we need. - ref var commandViewMatrix = ref CommandList.RenderCommands.AllocAdd(); - commandViewMatrix.Type = RenderCommandType.ViewMatrix; - - var ofsX = position.X - _clyde.ScreenSize.X / 2f; - var ofsY = position.Y - _clyde.ScreenSize.Y / 2f; - ref var viewMatrix = ref commandViewMatrix.ViewMatrix.Matrix; - viewMatrix = Matrix3.Identity; - viewMatrix.R0C0 = scale.X; - viewMatrix.R1C1 = scale.Y; - viewMatrix.R0C2 = ofsX / EyeManager.PIXELSPERMETER; - viewMatrix.R1C2 = -ofsY / EyeManager.PIXELSPERMETER; - } - - // Draw the entity. - sprite.OpenGLRender(DrawingHandleWorld, false); - - // Reset to screen space - SetSpace(CurrentSpace.ScreenSpace); + bl = _currentModelMatrix.Transform(angle.RotateVec(a)); + br = _currentModelMatrix.Transform(angle.RotateVec(new Vector2(b.X, a.Y))); + tr = _currentModelMatrix.Transform(angle.RotateVec(b)); + tl = _currentModelMatrix.Transform(angle.RotateVec(new Vector2(a.X, b.Y))); } - public void DrawLine(Vector2 a, Vector2 b, Color color) + // TODO: split batch if necessary. + var vIdx = BatchVertexIndex; + BatchVertexData[vIdx + 0] = new Vertex2D(bl, sr.BottomLeft); + BatchVertexData[vIdx + 1] = new Vertex2D(br, sr.BottomRight); + BatchVertexData[vIdx + 2] = new Vertex2D(tr, sr.TopRight); + BatchVertexData[vIdx + 3] = new Vertex2D(tl, sr.TopLeft); + BatchVertexIndex += 4; + var nIdx = BatchIndexIndex; + var tIdx = (ushort) vIdx; + BatchIndexData[nIdx + 0] = tIdx; + BatchIndexData[nIdx + 1] = (ushort) (tIdx + 1); + BatchIndexData[nIdx + 2] = (ushort) (tIdx + 2); + BatchIndexData[nIdx + 3] = (ushort) (tIdx + 3); + BatchIndexData[nIdx + 4] = ushort.MaxValue; + BatchIndexIndex += 5; + + _debugStats.LastClydeDrawCalls += 1; + } + + private void DrawLine(Vector2 a, Vector2 b, Color color) + { + EnsureBatchState(((ClydeTexture) Texture.White).TextureId, color, false, BatchPrimitiveType.Line); + + a = _currentModelMatrix.Transform(a); + b = _currentModelMatrix.Transform(b); + + // TODO: split batch if necessary. + var vIdx = BatchVertexIndex; + BatchVertexData[vIdx + 0] = new Vertex2D(a, Vector2.Zero); + BatchVertexData[vIdx + 1] = new Vertex2D(b, Vector2.Zero); + BatchVertexIndex += 2; + + _debugStats.LastClydeDrawCalls += 1; + } + + private void DrawSetScissor(UIBox2i? scissorBox) + { + BreakBatch(); + + ref var command = ref AllocRenderCommand(RenderCommandType.Scissor); + + command.Scissor.EnableScissor = scissorBox.HasValue; + if (scissorBox.HasValue) { - ref var command = ref CommandList.RenderCommands.AllocAdd(); - command.Type = RenderCommandType.Line; - - command.Line.PositionA = a; - command.Line.PositionB = b; - command.Line.Color = color; + command.Scissor.Scissor = scissorBox.Value; } + } - public void UseShader(ShaderInstance shader) + private void DrawSwitchSpace(CurrentSpace space) + { + BreakBatch(); + + ref var command = ref AllocRenderCommand(RenderCommandType.SwitchSpace); + + command.SwitchSpace.NewSpace = space; + + SetQueuedSpace(space); + } + + private void DrawUseShader(ClydeHandle handle) + { + BreakBatch(); + + ref var command = ref AllocRenderCommand(RenderCommandType.UseShader); + + command.UseShader.Handle = handle; + } + + private void DrawClear(Color color) + { + BreakBatch(); + + ref var command = ref AllocRenderCommand(RenderCommandType.Clear); + + command.Clear.Color = color; + } + + private void DrawViewport(Box2i viewport) + { + BreakBatch(); + + ref var command = ref AllocRenderCommand(RenderCommandType.Viewport); + + command.Viewport.Viewport = viewport; + } + + private void DrawRenderTarget(ClydeHandle handle) + { + BreakBatch(); + + ref var command = ref AllocRenderCommand(RenderCommandType.RenderTarget); + + command.RenderTarget.RenderTarget = handle; + } + + /// + /// Ensures that batching metadata matches the current batch. + /// If not, the current batch is finished and a new one is started. + /// + private void EnsureBatchState(ClydeHandle textureId, Color color, bool indexed, BatchPrimitiveType primitiveType) + { + if (_batchMetaData.HasValue) { - if (shader != null && shader.Disposed) + var metaData = _batchMetaData.Value; + if (metaData.TextureId == textureId && + StrictColorEquality(metaData.Color, color) && + indexed == metaData.Indexed && + metaData.PrimitiveType == primitiveType) { - throw new ArgumentException("Unable to use disposed shader instance.", nameof(shader)); + // Data matches, don't have to do anything. + return; } - var clydeShader = (ClydeShaderInstance) shader; - - ref var command = ref CommandList.RenderCommands.AllocAdd(); - command.Type = RenderCommandType.UseShader; - - command.UseShader.Handle = clydeShader?.Handle ?? _clyde._defaultShader.Handle; + // Data does not match. Finish batch... + FinishBatch(); } - public void Viewport(Box2i viewport) + // ... and start another. + _batchMetaData = new BatchMetaData(textureId, color, indexed, primitiveType, + indexed ? BatchIndexIndex : BatchVertexIndex); + } + + private void FinishBatch() + { + if (!_batchMetaData.HasValue) { - ref var command = ref CommandList.RenderCommands.AllocAdd(); - command.Type = RenderCommandType.Viewport; - - command.Viewport.Viewport = viewport; + return; } - public void UseRenderTarget(IRenderTarget renderTarget) - { - var target = (RenderTarget) renderTarget; + var metaData = _batchMetaData.Value; - ref var command = ref CommandList.RenderCommands.AllocAdd(); - command.Type = RenderCommandType.RenderTarget; + var indexed = metaData.Indexed; + var currentIndex = indexed ? BatchIndexIndex : BatchVertexIndex; - command.RenderTarget.RenderTarget = target?.Handle ?? new ClydeHandle(0); - } + ref var command = ref AllocRenderCommand(RenderCommandType.DrawBatch); - public void Clear(Color color) - { - ref var command = ref CommandList.RenderCommands.AllocAdd(); - command.Type = RenderCommandType.Clear; + command.DrawBatch.Indexed = indexed; + command.DrawBatch.StartIndex = metaData.StartIndex; + command.DrawBatch.PrimitiveType = metaData.PrimitiveType; + command.DrawBatch.Modulate = metaData.Color; + command.DrawBatch.TextureId = metaData.TextureId; - command.Clear.Color = color; - } + command.DrawBatch.Count = currentIndex - metaData.StartIndex; - private sealed class DrawingHandleScreenImpl : DrawingHandleScreen - { - private readonly RenderHandle _renderHandle; + _debugStats.LastBatches += 1; + } - public DrawingHandleScreenImpl(RenderHandle renderHandle) - { - _renderHandle = renderHandle; - } + /// + /// Renderer state that cannot be changed mid-batch has been modified and a new batch will have to be started. + /// + private void BreakBatch() + { + FinishBatch(); - public override void SetTransform(in Matrix3 matrix) - { - _renderHandle.SetModelTransform(matrix); - } - - public override void UseShader(ShaderInstance shader) - { - _renderHandle.UseShader(shader); - } - - public override void DrawCircle(Vector2 position, float radius, Color color) - { - // TODO: Implement this. - } - - public override void DrawLine(Vector2 from, Vector2 to, Color color) - { - _renderHandle.DrawLine(from, to, color * Modulate); - } - - public override void DrawRect(UIBox2 rect, Color color, bool filled = true) - { - if (filled) - { - DrawTextureRect(Texture.White, rect, color); - } - else - { - DrawLine(rect.TopLeft, rect.TopRight, color); - DrawLine(rect.TopRight, rect.BottomRight, color); - DrawLine(rect.BottomRight, rect.BottomLeft, color); - DrawLine(rect.BottomLeft, rect.TopLeft, color); - } - } - - public override void DrawTextureRectRegion(Texture texture, UIBox2 rect, UIBox2? subRegion = null, - Color? modulate = null) - { - var color = (modulate ?? Color.White) * Modulate; - _renderHandle.DrawTexture(texture, rect.TopLeft, rect.BottomRight, color, - subRegion, 0); - } - } - - private sealed class DrawingHandleWorldImpl : DrawingHandleWorld - { - private readonly RenderHandle _renderHandle; - - public DrawingHandleWorldImpl(RenderHandle renderHandle) - { - _renderHandle = renderHandle; - } - - public override void SetTransform(in Matrix3 matrix) - { - _renderHandle.SetModelTransform(matrix); - } - - public override void UseShader(ShaderInstance shader) - { - _renderHandle.UseShader(shader); - } - - public override void DrawCircle(Vector2 position, float radius, Color color) - { - // TODO: Implement this. - } - - public override void DrawLine(Vector2 from, Vector2 to, Color color) - { - _renderHandle.DrawLine(from, to, color * Modulate); - } - - public override void DrawRect(Box2 rect, Color color, bool filled = true) - { - if (filled) - { - DrawTextureRect(Texture.White, rect, color); - } - else - { - DrawLine(rect.TopLeft, rect.TopRight, color); - DrawLine(rect.TopRight, rect.BottomRight, color); - DrawLine(rect.BottomRight, rect.BottomLeft, color); - DrawLine(rect.BottomLeft, rect.TopLeft, color); - } - } - - public override void DrawRect(in Box2Rotated rect, Color color, bool filled = true) - { - if (filled) - { - DrawTextureRect(Texture.White, rect, color); - } - else - { - DrawLine(rect.TopLeft, rect.TopRight, color); - DrawLine(rect.TopRight, rect.BottomRight, color); - DrawLine(rect.BottomRight, rect.BottomLeft, color); - DrawLine(rect.BottomLeft, rect.TopLeft, color); - } - } - - public override void DrawTextureRectRegion(Texture texture, Box2 rect, UIBox2? subRegion = null, - Color? modulate = null) - { - var color = (modulate ?? Color.White) * Modulate; - - _renderHandle.DrawTexture(texture, rect.BottomLeft, rect.TopRight, color, subRegion, 0); - } - - public override void DrawTextureRectRegion(Texture texture, in Box2Rotated rect, - UIBox2? subRegion = null, Color? modulate = null) - { - var color = (modulate ?? Color.White) * Modulate; - - _renderHandle.DrawTexture(texture, rect.Box.BottomLeft, rect.Box.TopRight, color, subRegion, - (float) rect.Rotation); - } - } + _batchMetaData = null; } // Use a tagged union to store all render commands. @@ -1173,34 +943,25 @@ namespace Robust.Client.Graphics.Clyde { [FieldOffset(0)] public RenderCommandType Type; - [FieldOffset(4)] public RenderCommandTexture Texture; - [FieldOffset(4)] public RenderCommandModelMatrix ModelMatrix; + [FieldOffset(4)] public RenderCommandDrawBatch DrawBatch; [FieldOffset(4)] public RenderCommandViewMatrix ViewMatrix; [FieldOffset(4)] public RenderCommandScissor Scissor; [FieldOffset(4)] public RenderCommandUseShader UseShader; - [FieldOffset(4)] public RenderCommandLine Line; [FieldOffset(4)] public RenderCommandSwitchSpace SwitchSpace; [FieldOffset(4)] public RenderCommandRenderTarget RenderTarget; [FieldOffset(4)] public RenderCommandViewport Viewport; [FieldOffset(4)] public RenderCommandClear Clear; } - private struct RenderCommandTexture + private struct RenderCommandDrawBatch { public ClydeHandle TextureId; - public bool HasSubRegion; - public UIBox2 SubRegion; - - public Vector2 PositionA; - public Vector2 PositionB; - public Color Modulate; - public Angle Angle; - } - private struct RenderCommandModelMatrix - { - public Matrix3 Matrix; + public int StartIndex; + public int Count; + public bool Indexed; + public BatchPrimitiveType PrimitiveType; } private struct RenderCommandViewMatrix @@ -1219,14 +980,6 @@ namespace Robust.Client.Graphics.Clyde public ClydeHandle Handle; } - private struct RenderCommandLine - { - public Vector2 PositionA; - public Vector2 PositionB; - - public Color Color; - } - private struct RenderCommandSwitchSpace { public CurrentSpace NewSpace; @@ -1249,10 +1002,8 @@ namespace Robust.Client.Graphics.Clyde private enum RenderCommandType { - Texture, - Line, + DrawBatch, - ModelMatrix, ViewMatrix, ResetViewMatrix, SwitchSpace, @@ -1261,6 +1012,7 @@ namespace Robust.Client.Graphics.Clyde UseShader, Scissor, RenderTarget, + Clear } @@ -1285,13 +1037,30 @@ namespace Robust.Client.Graphics.Clyde } } - /// - /// A list of rendering commands to execute in order. Pooled. - /// - // ReSharper disable once ClassNeverInstantiated.Local - private class RenderCommandList + private readonly struct BatchMetaData { - public readonly RefList RenderCommands = new RefList(); + public readonly ClydeHandle TextureId; + public readonly Color Color; + public readonly bool Indexed; + public readonly BatchPrimitiveType PrimitiveType; + public readonly int StartIndex; + + public BatchMetaData(ClydeHandle textureId, Color color, bool indexed, BatchPrimitiveType primitiveType, + int startIndex) + { + TextureId = textureId; + Color = color; + Indexed = indexed; + PrimitiveType = primitiveType; + StartIndex = startIndex; + } + } + + private enum BatchPrimitiveType + { + Triangles, + TrianglesFan, + Line } } } diff --git a/Robust.Client/Graphics/Clyde/Clyde.cs b/Robust.Client/Graphics/Clyde/Clyde.cs index a68cf7be4..bd85a5bc2 100644 --- a/Robust.Client/Graphics/Clyde/Clyde.cs +++ b/Robust.Client/Graphics/Clyde/Clyde.cs @@ -1,18 +1,13 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.Drawing; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; -using System.Threading; using JetBrains.Annotations; -using OpenTK; -using OpenTK.Graphics; using OpenTK.Graphics.OpenGL; using Robust.Client.Graphics.ClientEye; -using Robust.Client.Input; using Robust.Client.Interfaces.Graphics; using Robust.Client.Interfaces.Graphics.ClientEye; using Robust.Client.Interfaces.Graphics.Lighting; @@ -67,13 +62,8 @@ namespace Robust.Client.Graphics.Clyde // VBO to draw a single quad. private Buffer QuadVBO; - private OGLHandle QuadVAO; - // VBO to draw a single line. - private Buffer LineVBO; - private OGLHandle LineVAO; - private const int UniIModUV = 0; private const int UniIModelMatrix = 1; private const int UniIModulate = 2; @@ -210,44 +200,25 @@ namespace Robust.Client.Graphics.Clyde GL.EnableVertexAttribArray(1); } - // Line drawing. + // Batch rendering { - var lineVertices = new[] - { - new Vertex2D(0, 0, 0, 0), - new Vertex2D(1, 1, 1, 1), - }; + BatchVBO = new Buffer(this, BufferTarget.ArrayBuffer, BufferUsageHint.DynamicDraw, + Vertex2D.SizeOf * BatchVertexData.Length, "BatchVBO"); - LineVBO = new Buffer(this, BufferTarget.ArrayBuffer, BufferUsageHint.StaticDraw, lineVertices, - nameof(LineVBO)); - - LineVAO = new OGLHandle((uint) GL.GenVertexArray()); - GL.BindVertexArray(LineVAO.Handle); - _objectLabelMaybe(ObjectLabelIdentifier.VertexArray, LineVAO, nameof(LineVAO)); + BatchVAO = new OGLHandle(GL.GenVertexArray()); + GL.BindVertexArray(BatchVAO.Handle); + _objectLabelMaybe(ObjectLabelIdentifier.VertexArray, BatchVAO, "BatchVAO"); // Vertex Coords GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, Vertex2D.SizeOf, 0); GL.EnableVertexAttribArray(0); // Texture Coords. GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, Vertex2D.SizeOf, 2 * sizeof(float)); GL.EnableVertexAttribArray(1); + + BatchEBO = new Buffer(this, BufferTarget.ElementArrayBuffer, BufferUsageHint.DynamicDraw, + sizeof(ushort) * BatchIndexData.Length, "BatchEBO"); } - BatchVBO = new Buffer(this, BufferTarget.ArrayBuffer, BufferUsageHint.DynamicDraw, - Vertex2D.SizeOf * BatchVertexData.Length, "BatchVBO"); - - BatchVAO = new OGLHandle(GL.GenVertexArray()); - GL.BindVertexArray(BatchVAO.Handle); - _objectLabelMaybe(ObjectLabelIdentifier.VertexArray, BatchVAO, "BatchVAO"); - // Vertex Coords - GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, Vertex2D.SizeOf, 0); - GL.EnableVertexAttribArray(0); - // Texture Coords. - GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, Vertex2D.SizeOf, 2 * sizeof(float)); - GL.EnableVertexAttribArray(1); - - BatchEBO = new Buffer(this, BufferTarget.ElementArrayBuffer, BufferUsageHint.DynamicDraw, - sizeof(ushort) * BatchIndexData.Length, "BatchEBO"); - ProjViewUBO = new Buffer(this, BufferTarget.UniformBuffer, BufferUsageHint.StreamDraw, "ProjViewUBO"); unsafe { @@ -284,11 +255,7 @@ namespace Robust.Client.Graphics.Clyde // ReSharper disable once UnusedParameter.Local private void _loadVendorSettings(string vendor, string renderer, string version) { - if (vendor.IndexOf("intel", StringComparison.InvariantCultureIgnoreCase) != -1) - { - // Intel specific settings. - _reallocateBuffers = true; - } + // Nothing yet. } private Vector2i _lightMapSize()