diff --git a/Assets/Scripts/Game/GameAssets.cs b/Assets/Scripts/Game/GameAssets.cs index b0db6dc..ae0063c 100644 --- a/Assets/Scripts/Game/GameAssets.cs +++ b/Assets/Scripts/Game/GameAssets.cs @@ -1,5 +1,6 @@ using System.Collections; using System.Collections.Generic; +using Unity.Collections; using UnityEngine; public class GameAssets @@ -63,15 +64,33 @@ public class GameAssets } public void UploadLightmap(int lightmapNum, int width, int height, byte[] data) + { + var lightmap = GetOrCreateLightmap(lightmapNum, width, height); + lightmap.SetPixelData(data, 0); + lightmap.Apply(); + } + + public void UploadLightmap(int lightmapNum, int width, int height, NativeArray data) + { + var lightmap = GetOrCreateLightmap(lightmapNum, width, height); + lightmap.SetPixelData(data, 0); + lightmap.Apply(); + } + + private Texture2D GetOrCreateLightmap(int lightmapNum, int width, int height) { if (!lightmaps.TryGetValue(lightmapNum, out var lightmap)) { - lightmap = new Texture2D(width, height, TextureFormat.RGBA32, false) { name = $"Lightmap_{lightmapNum}", wrapMode = TextureWrapMode.Clamp }; + lightmap = new Texture2D(width, height, TextureFormat.RGBA32, false) + { + name = $"Lightmap_{lightmapNum}", + wrapMode = TextureWrapMode.Clamp, + }; + lightmaps.Add(lightmapNum, lightmap); } - lightmap.SetPixelData(data, 0); - lightmap.Apply(); + return lightmap; } public bool TryGetLightmap(int lightmapNum, out Texture2D lightmap) diff --git a/Assets/Scripts/Modules/RenderModule.Interop.cs b/Assets/Scripts/Modules/RenderModule.Interop.cs index ac39906..d9c7e33 100644 --- a/Assets/Scripts/Modules/RenderModule.Interop.cs +++ b/Assets/Scripts/Modules/RenderModule.Interop.cs @@ -1,6 +1,8 @@ using System; using System.Runtime.InteropServices; using AOT; +using Unity.Collections; +using Unity.Collections.LowLevel.Unsafe; using UnityEngine; using UnityEngine.Profiling; @@ -138,7 +140,9 @@ public partial class RenderModule: CallbackHandler return result; } +#if UNITY_EDITOR private readonly byte[] lightmapBytes = new byte[QConstants.LightmapBlockWidth * QConstants.LightmapBlockHeight * 4]; // 32 bits per pixel +#endif [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate bool UploadLightmapCallback(IntPtr context, int lmap, IntPtr data); @@ -146,13 +150,26 @@ public partial class RenderModule: CallbackHandler [MonoPInvokeCallback(typeof(UploadLightmapCallback))] private static bool Callback_UploadLightmap(IntPtr context, int lmap, IntPtr data) { + bool result; Profiler.BeginSample("UploadLightmap"); - // TODO: this is a fairly pointless additional data copy step; we could probably make this faster by wrapping the IntPtr directly into a NativeArray +#if UNITY_EDITOR + // This is fairly pointless additional data copy step; the below NativeArray approach is faster and doesn't + // produce any garbage, but it doesn't work inside the Unity Editor for some reason. var self = GetSelf(context); Marshal.Copy(data, self.lightmapBytes, 0, self.lightmapBytes.Length); - bool result = self.UploadLightmap(lmap, QConstants.LightmapBlockWidth, QConstants.LightmapBlockHeight, self.lightmapBytes); - + result = self.UploadLightmap(lmap, QConstants.LightmapBlockWidth, QConstants.LightmapBlockHeight, self.lightmapBytes); +#else + unsafe + { + // More efficient code path that passes the native byte buffer directly to the Texture2D's pixel data + var dataArray = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray(data.ToPointer(), + QConstants.LightmapBlockWidth * QConstants.LightmapBlockHeight * 4, Allocator.None); + + result = GetSelf(context).UploadLightmap(lmap, QConstants.LightmapBlockWidth, QConstants.LightmapBlockHeight, dataArray); + } +#endif + Profiler.EndSample(); return result; } diff --git a/Assets/Scripts/Modules/RenderModule.cs b/Assets/Scripts/Modules/RenderModule.cs index bf75e35..3cd480b 100644 --- a/Assets/Scripts/Modules/RenderModule.cs +++ b/Assets/Scripts/Modules/RenderModule.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Unity.Collections; using UnityEngine; using UnityEngine.Rendering; @@ -77,6 +78,15 @@ public partial class RenderModule return true; } + private bool UploadLightmap(int lightmapNum, int width, int height, NativeArray data) + { + if (width == 0 || height == 0) + return false; + + uq.GameAssets.UploadLightmap(lightmapNum, width, height, data); + return true; + } + private void SetupView(QVec3 origin, QVec3 angles, QLeaf viewLeaf) { var cam = uq.Camera; diff --git a/Assets/Scripts/UniQuake.cs b/Assets/Scripts/UniQuake.cs index 7c513ec..a537829 100644 --- a/Assets/Scripts/UniQuake.cs +++ b/Assets/Scripts/UniQuake.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Text; using UnityEngine; +using UnityEngine.Profiling; public partial class UniQuake: MonoBehaviour { @@ -133,6 +134,8 @@ public partial class UniQuake: MonoBehaviour logHandler = CollectLog; // Collect and dump logs to Unity once per frame + Profiler.BeginSample("QuakeEngineUpdate"); + try { UniQuake_Update(Time.deltaTime); @@ -152,6 +155,8 @@ public partial class UniQuake: MonoBehaviour Shutdown(); } + Profiler.EndSample(); + FlushLog(); } diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset index 9bdbf4c..ebbe776 100644 --- a/ProjectSettings/ProjectSettings.asset +++ b/ProjectSettings/ProjectSettings.asset @@ -609,7 +609,7 @@ PlayerSettings: managedStrippingLevel: {} incrementalIl2cppBuild: {} suppressCommonWarnings: 1 - allowUnsafeCode: 0 + allowUnsafeCode: 1 useDeterministicCompilation: 1 useReferenceAssemblies: 1 enableRoslynAnalyzers: 1