Skip to content

Usability improvements #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 32 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Refactor
  • Loading branch information
 Kirill Belonogov committed Sep 11, 2019
commit e29c28175cadaa95497e525f925da82414202ca9
Binary file removed OverdrawMonitor/.vs/OverdrawMonitor/v15/.suo
Binary file not shown.
85 changes: 18 additions & 67 deletions OverdrawMonitor/Assets/OverdrawMonitor/CameraOverdrawMonitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,11 @@ public class CameraOverdrawMonitor : MonoBehaviour
const int GroupDimension = 32;
const int DataDimension = 128;
const int DataSize = DataDimension * DataDimension;
const float SampleTime = 1f;

public Camera targetCamera => _targetCamera;

// The number of shaded fragments in the last frame
public long totalShadedFragments { get; private set; }

// The overdraw ratio in the last frame
public float overdrawRatio { get; private set; }

// Number of shaded fragments in the measured time span
public long intervalShadedFragments { get; private set; }

// The average number of shaded fragments in the measured time span
public float intervalAverageShadedFragments { get; private set; }

// The average overdraw in the measured time span
public float intervalAverageOverdraw { get; private set; }
public float accumulatedAverageOverdraw => _accumulatedIntervalOverdraw / _intervalFrames;

// The maximum overdraw measured
public float maxOverdraw { get; private set; }
public long fragmentsCount => isActiveAndEnabled ? _fragmentsCount : 0L;
public float fillRate => isActiveAndEnabled ? _fillRate : 0f;

Camera _targetCamera;
RenderTexture _overdrawTexture;
Expand All @@ -48,10 +31,8 @@ public class CameraOverdrawMonitor : MonoBehaviour
Shader _replacementShader;
int[] _inputData;
int[] _resultData;
long _accumulatedIntervalFragments;
float _accumulatedIntervalOverdraw;
float _intervalTime;
long _intervalFrames;
long _fragmentsCount;
float _fillRate;

void Awake()
{
Expand Down Expand Up @@ -81,15 +62,6 @@ public void SetTargetCamera(Camera targetCamera)
_targetCamera = targetCamera;
}

public void ResetStats()
{
_accumulatedIntervalOverdraw = 0;
_accumulatedIntervalFragments = 0;
_intervalTime = 0;
_intervalFrames = 0;
maxOverdraw = 0;
}

void ReleaseTexture()
{
if (_overdrawTexture != null)
Expand All @@ -104,69 +76,48 @@ void LateUpdate()
if (_targetCamera == null)
return;

// Save original params
CameraClearFlags originalClearFlags = _targetCamera.clearFlags;
Color originalClearColor = _targetCamera.backgroundColor;
RenderTexture originalTargetTexture = _targetCamera.targetTexture;
bool originalIsCameraEnabled = _targetCamera.enabled;

_targetCamera.clearFlags = CameraClearFlags.SolidColor;
_targetCamera.backgroundColor = Color.clear;

// Recreate texture if needed
if (_overdrawTexture == null || _targetCamera.pixelWidth != _overdrawTexture.width || _targetCamera.pixelHeight != _overdrawTexture.height)
{
ReleaseTexture();
_overdrawTexture = new RenderTexture(_targetCamera.pixelWidth, _targetCamera.pixelHeight, 24, RenderTextureFormat.RFloat);
}
_targetCamera.targetTexture = _overdrawTexture;

_intervalTime += Time.deltaTime;
if (_intervalTime > SampleTime)
{
intervalShadedFragments = _accumulatedIntervalFragments;
intervalAverageShadedFragments = (float)_accumulatedIntervalFragments / _intervalFrames;
intervalAverageOverdraw = _accumulatedIntervalOverdraw / _intervalFrames;

_intervalTime -= SampleTime;

_accumulatedIntervalFragments = 0;
_accumulatedIntervalOverdraw = 0;
_intervalFrames = 0;
}

// Set replacement params
_targetCamera.clearFlags = CameraClearFlags.SolidColor;
_targetCamera.backgroundColor = Color.clear;
_targetCamera.targetTexture = _overdrawTexture;
_targetCamera.enabled = false;

// Render
_targetCamera.RenderWithShader(_replacementShader, null);

int kernel = _computeShader.FindKernel("CSMain");

// Setting up the data
// Compute
_resultBuffer.SetData(_inputData);
int kernel = _computeShader.FindKernel("CSMain");
_computeShader.SetInt("BufferSizeX", DataDimension);
_computeShader.SetTexture(kernel, "Overdraw", _overdrawTexture);
_computeShader.SetBuffer(kernel, "Output", _resultBuffer);

// Summing up the fragments
int xGroups = _overdrawTexture.width / GroupDimension;
int yGroups = _overdrawTexture.height / GroupDimension;

// Summing up the fragments
_computeShader.Dispatch(kernel, xGroups, yGroups, 1);
_resultBuffer.GetData(_resultData);

// Getting the results
totalShadedFragments = 0;
// Results
_fragmentsCount = 0;
foreach (int res in _resultData)
totalShadedFragments += res;

overdrawRatio = (float)totalShadedFragments / (Screen.width * Screen.height);

_accumulatedIntervalFragments += totalShadedFragments;
_accumulatedIntervalOverdraw += overdrawRatio;
_intervalFrames++;

if (overdrawRatio > maxOverdraw)
maxOverdraw = overdrawRatio;
_fragmentsCount += res;
_fillRate = fragmentsCount / ((float)_overdrawTexture.width * _overdrawTexture.height);

// Restore original params
_targetCamera.targetTexture = originalTargetTexture;
_targetCamera.clearFlags = originalClearFlags;
_targetCamera.backgroundColor = originalClearColor;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;

public class OverdrawMonitorWindow : EditorWindow
{
bool isEnabled => _monitorsGo != null && Application.isPlaying;
GameObject _monitorsGo;
Dictionary<CameraOverdrawMonitor, CameraOverdrawStats> _globalMaxInfos;

[MenuItem("Tools/Overdraw Monitor")]
static void ShowWindow()
Expand All @@ -20,12 +23,16 @@ void Init()

_monitorsGo = new GameObject("OverdrawMonitor");
_monitorsGo.hideFlags = HideFlags.HideAndDontSave;
_globalMaxInfos = new Dictionary<CameraOverdrawMonitor, CameraOverdrawStats>();
}

void TryShutdown()
{
if (_monitorsGo != null)
DestroyImmediate(_monitorsGo);
if (_monitorsGo == null)
return;

DestroyImmediate(_monitorsGo);
_globalMaxInfos = null;
}

void Update()
Expand Down Expand Up @@ -85,39 +92,59 @@ void OnGUI()
{
GUILayout.FlexibleSpace();

if (GUILayout.Button("Reset Max", GUILayout.Width(100), GUILayout.Height(20)))
{
foreach (CameraOverdrawMonitor monitor in monitors)
monitor.ResetStats();
}
if (GUILayout.Button("Reset Stats", GUILayout.Width(100), GUILayout.Height(20)))
ResetStats();
}

GUILayout.Space(5);

float totalAverage = 0f;
float totalMax = 0f;
Vector2Int gameViewResolution = GetGameViewResolution();
GUILayout.Label($"Screen {gameViewResolution.x}x{gameViewResolution.y}");

GUILayout.Space(5);

foreach (CameraOverdrawMonitor monitor in _globalMaxInfos.Keys.ToArray())
if (!Array.Exists(monitors, m => monitor))
_globalMaxInfos.Remove(monitor);

long gameViewArea = gameViewResolution.x * gameViewResolution.y;
float totalGlobalFillRate = 0f;
foreach (CameraOverdrawMonitor monitor in monitors)
{
using (new GUILayout.HorizontalScope())
{
GUILayout.Label(monitor.targetCamera.name);
Camera cam = monitor.targetCamera;
GUILayout.Label($"{cam.name} {cam.pixelWidth}x{cam.pixelHeight}");

GUILayout.FlexibleSpace();

float accumulatedAverageOverdraw = monitor.isActiveAndEnabled ? monitor.accumulatedAverageOverdraw : 0f;
GUILayout.Label(FormatResult(accumulatedAverageOverdraw, monitor.maxOverdraw));
float localFillRate = monitor.fillRate;
float globalFillRate = monitor.fragmentsCount / (float)gameViewArea;
totalGlobalFillRate += globalFillRate;

totalMax += monitor.maxOverdraw;
totalAverage += accumulatedAverageOverdraw;
if (!_globalMaxInfos.TryGetValue(monitor, out CameraOverdrawStats globalMaxInfo))
{
globalMaxInfo = new CameraOverdrawStats();
_globalMaxInfos.Add(monitor, globalMaxInfo);
}
globalMaxInfo.maxLocalFillRate = Math.Max(localFillRate, globalMaxInfo.maxLocalFillRate);
globalMaxInfo.maxGlobalFillRate = Math.Max(globalFillRate, globalMaxInfo.maxGlobalFillRate);

GUILayout.Label(FormatResult("Local: {0} / {1} \t Global: {2} / {3}",
localFillRate, globalMaxInfo.maxLocalFillRate, globalFillRate, globalMaxInfo.maxGlobalFillRate));
}
}

GUILayout.Space(5);

float maxTotalGlobalFillRate = 0f;
foreach (CameraOverdrawStats stat in _globalMaxInfos.Values)
maxTotalGlobalFillRate += stat.maxGlobalFillRate;
using (new GUILayout.HorizontalScope())
{
GUILayout.Label("TOTAL");
GUILayout.FlexibleSpace();
GUILayout.Label(FormatResult(totalAverage, totalMax));
GUILayout.Label(FormatResult("Global: {0} / {1}", totalGlobalFillRate, maxTotalGlobalFillRate));
}
}
else
Expand All @@ -128,8 +155,28 @@ void OnGUI()
Repaint();
}

string FormatResult(float average, float max)
void ResetStats()
{
_globalMaxInfos.Clear();
}

string FormatResult(string format, params float[] args)
{
var stringArgs = new List<string>();
foreach (float arg in args)
stringArgs.Add($"{arg:N3}");
return string.Format(format, stringArgs.ToArray());
}

static Vector2Int GetGameViewResolution()
{
return $"{average:N3}\tMax: {max:N3}";
var resString = UnityStats.screenRes.Split('x');
return new Vector2Int(int.Parse(resString[0]), int.Parse(resString[1]));
}
}

class CameraOverdrawStats
{
public float maxLocalFillRate;
public float maxGlobalFillRate;
}