Skip to content

Commit 8104c04

Browse files
arttu-peltonenEvergreen
authored andcommitted
Final polish pass to RenderGraph Viewer UX
This PR implements polish based on designer & user feedback listed here: https://jira.unity3d.com/browse/XPIPELINE-863 List of changes made: - Smaller default width of the side panel - Cap maximum width of the camera dropdown element - Add "Graph" and "Camera" labels to header dropdowns - Improve # icon - Bold Pass names in side panel - Fix "compatible pass" blinking animation getting out of sync with each other as you hover the blinking elements - Change active camera selection to automatically trigger a view refresh - Make resource/pass list panels resizeable vertically (see gif) ![rg-viewer-splitpane-resize2](https://media.github.cds.internal.unity3d.com/user/3380/files/b4ac0467-72f0-44e7-9dcf-be2133e6e21d)
1 parent 97ecbb1 commit 8104c04

File tree

8 files changed

+165
-89
lines changed

8 files changed

+165
-89
lines changed
5.87 KB
Loading
5.98 KB
Loading

Packages/com.unity.render-pipelines.core/Editor/RenderGraph/RenderGraphViewer.SidePanel.cs

Lines changed: 105 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public partial class RenderGraphViewer
1919

2020
static partial class Names
2121
{
22+
public const string kPanelContainer = "panel-container";
2223
public const string kResourceListFoldout = "panel-resource-list";
2324
public const string kPassListFoldout = "panel-pass-list";
2425
public const string kResourceSearchField = "resource-search-field";
@@ -40,18 +41,31 @@ static partial class Classes
4041
const string k_SelectionColorBeginTag = "<mark=#3169ACAB>";
4142
const string k_SelectionColorEndTag = "</mark>";
4243

44+
TwoPaneSplitView m_SidePanelSplitView;
4345
bool m_ResourceListExpanded = true;
4446
bool m_PassListExpanded = true;
47+
float m_SidePanelVerticalAspectRatio = 0.5f;
48+
float m_SidePanelFixedPaneHeight = 0;
4549

4650
Dictionary<VisualElement, List<TextElement>> m_ResourceDescendantCache = new ();
4751
Dictionary<VisualElement, List<TextElement>> m_PassDescendantCache = new ();
4852

4953
void InitializeSidePanel()
5054
{
55+
m_SidePanelSplitView = rootVisualElement.Q<TwoPaneSplitView>(Names.kPanelContainer);
56+
rootVisualElement.RegisterCallback<GeometryChangedEvent>(_ =>
57+
{
58+
SaveSplitViewFixedPaneHeight(); // Window resized - save the current pane height
59+
UpdatePanelHeights();
60+
});
61+
5162
// Callbacks for dynamic height allocation between resource & pass lists
5263
HeaderFoldout resourceListFoldout = rootVisualElement.Q<HeaderFoldout>(Names.kResourceListFoldout);
5364
resourceListFoldout.RegisterValueChangedCallback(evt =>
5465
{
66+
if (m_ResourceListExpanded)
67+
SaveSplitViewFixedPaneHeight(); // Closing the foldout - save the current pane height
68+
5569
m_ResourceListExpanded = resourceListFoldout.value;
5670
UpdatePanelHeights();
5771
});
@@ -61,6 +75,9 @@ void InitializeSidePanel()
6175
HeaderFoldout passListFoldout = rootVisualElement.Q<HeaderFoldout>(Names.kPassListFoldout);
6276
passListFoldout.RegisterValueChangedCallback(evt =>
6377
{
78+
if (m_PassListExpanded)
79+
SaveSplitViewFixedPaneHeight(); // Closing the foldout - save the current pane height
80+
6481
m_PassListExpanded = passListFoldout.value;
6582
UpdatePanelHeights();
6683
});
@@ -247,8 +264,9 @@ void CreateTextElement(VisualElement parent, string text, string className = nul
247264
}
248265

249266
var passItem = new Foldout();
250-
passItem.text = string.Join(", ", passNames);
251-
passItem.Q<Toggle>().tooltip = passItem.text;
267+
var passesText = string.Join(", ", passNames);
268+
passItem.text = $"<b>{passesText}</b>";
269+
passItem.Q<Toggle>().tooltip = passesText;
252270
passItem.value = false;
253271
passItem.userData = m_PassIdToVisiblePassIndex[visiblePassElement.passId];
254272
passItem.AddToClassList(Classes.kPanelListItem);
@@ -270,71 +288,75 @@ void CreateTextElement(VisualElement parent, string text, string className = nul
270288
}
271289
else
272290
{
291+
CreateTextElement(passItem, "Pass break reasoning", Classes.kSubHeaderText);
273292
var msg = $"This is a {k_PassTypeNames[(int) firstPassData.type]}. Only Raster Render Passes can be merged.";
274293
msg = msg.Replace("a Unsafe", "an Unsafe");
275294
CreateTextElement(passItem, msg);
276295
}
277296

278-
CreateTextElement(passItem, "Render Graph Pass Info", Classes.kSubHeaderText);
279-
foreach (int passId in groupedPassIds)
280-
{
281-
var pass = m_CurrentDebugData.passList[passId];
282-
Debug.Assert(pass.nrpInfo != null); // This overlay currently assumes NRP compiler
283-
var passFoldout = new Foldout();
284-
passFoldout.text = $"{pass.name} ({k_PassTypeNames[(int) pass.type]})";
285-
passFoldout.AddToClassList(Classes.kAttachmentInfoItem);
286-
passFoldout.AddToClassList(Classes.kCustomFoldoutArrow);
287-
passFoldout.Q<Toggle>().tooltip = passFoldout.text;
288-
289-
var foldoutCheckmark = passFoldout.Q("unity-checkmark");
290-
foldoutCheckmark.BringToFront(); // Move foldout checkmark to the right
291-
292-
var lineBreak = new VisualElement();
293-
lineBreak.AddToClassList(Classes.kPanelListLineBreak);
294-
passFoldout.Add(lineBreak);
295-
296-
CreateTextElement(passFoldout,
297-
$"Attachment dimensions: {pass.nrpInfo.width}x{pass.nrpInfo.height}x{pass.nrpInfo.volumeDepth}");
298-
CreateTextElement(passFoldout, $"Has depth attachment: {pass.nrpInfo.hasDepth}");
299-
CreateTextElement(passFoldout, $"MSAA samples: {pass.nrpInfo.samples}");
300-
CreateTextElement(passFoldout, $"Async compute: {pass.async}");
301-
302-
passItem.Add(passFoldout);
303-
}
304-
305-
CreateTextElement(passItem, "Attachment Load/Store Actions", Classes.kSubHeaderText);
306-
if (nativePassInfo != null && nativePassInfo.attachmentInfos.Count > 0)
297+
if (nativePassInfo != null)
307298
{
308-
foreach (var attachmentInfo in nativePassInfo.attachmentInfos)
299+
CreateTextElement(passItem, "Render Graph Pass Info", Classes.kSubHeaderText);
300+
foreach (int passId in groupedPassIds)
309301
{
310-
var attachmentFoldout = new Foldout();
311-
attachmentFoldout.text = attachmentInfo.resourceName;
312-
attachmentFoldout.AddToClassList(Classes.kAttachmentInfoItem);
313-
attachmentFoldout.AddToClassList(Classes.kCustomFoldoutArrow);
314-
attachmentFoldout.Q<Toggle>().tooltip = attachmentFoldout.text;
315-
316-
var foldoutCheckmark = attachmentFoldout.Q("unity-checkmark");
302+
var pass = m_CurrentDebugData.passList[passId];
303+
Debug.Assert(pass.nrpInfo != null); // This overlay currently assumes NRP compiler
304+
var passFoldout = new Foldout();
305+
passFoldout.text = $"{pass.name} ({k_PassTypeNames[(int) pass.type]})";
306+
passFoldout.AddToClassList(Classes.kAttachmentInfoItem);
307+
passFoldout.AddToClassList(Classes.kCustomFoldoutArrow);
308+
passFoldout.Q<Toggle>().tooltip = passFoldout.text;
309+
310+
var foldoutCheckmark = passFoldout.Q("unity-checkmark");
317311
foldoutCheckmark.BringToFront(); // Move foldout checkmark to the right
318312

319313
var lineBreak = new VisualElement();
320314
lineBreak.AddToClassList(Classes.kPanelListLineBreak);
321-
attachmentFoldout.Add(lineBreak);
315+
passFoldout.Add(lineBreak);
322316

323-
attachmentFoldout.Add(new TextElement
324-
{
325-
text = $"<b>Load action:</b> {attachmentInfo.loadAction} ({attachmentInfo.loadReason})"
326-
});
327-
attachmentFoldout.Add(new TextElement
328-
{
329-
text = $"<b>Store action:</b> {attachmentInfo.storeAction} ({attachmentInfo.storeReason})"
330-
});
317+
CreateTextElement(passFoldout,
318+
$"Attachment dimensions: {pass.nrpInfo.width}x{pass.nrpInfo.height}x{pass.nrpInfo.volumeDepth}");
319+
CreateTextElement(passFoldout, $"Has depth attachment: {pass.nrpInfo.hasDepth}");
320+
CreateTextElement(passFoldout, $"MSAA samples: {pass.nrpInfo.samples}");
321+
CreateTextElement(passFoldout, $"Async compute: {pass.async}");
331322

332-
passItem.Add(attachmentFoldout);
323+
passItem.Add(passFoldout);
324+
}
325+
326+
CreateTextElement(passItem, "Attachment Load/Store Actions", Classes.kSubHeaderText);
327+
if (nativePassInfo != null && nativePassInfo.attachmentInfos.Count > 0)
328+
{
329+
foreach (var attachmentInfo in nativePassInfo.attachmentInfos)
330+
{
331+
var attachmentFoldout = new Foldout();
332+
attachmentFoldout.text = attachmentInfo.resourceName;
333+
attachmentFoldout.AddToClassList(Classes.kAttachmentInfoItem);
334+
attachmentFoldout.AddToClassList(Classes.kCustomFoldoutArrow);
335+
attachmentFoldout.Q<Toggle>().tooltip = attachmentFoldout.text;
336+
337+
var foldoutCheckmark = attachmentFoldout.Q("unity-checkmark");
338+
foldoutCheckmark.BringToFront(); // Move foldout checkmark to the right
339+
340+
var lineBreak = new VisualElement();
341+
lineBreak.AddToClassList(Classes.kPanelListLineBreak);
342+
attachmentFoldout.Add(lineBreak);
343+
344+
attachmentFoldout.Add(new TextElement
345+
{
346+
text = $"<b>Load action:</b> {attachmentInfo.loadAction} ({attachmentInfo.loadReason})"
347+
});
348+
attachmentFoldout.Add(new TextElement
349+
{
350+
text = $"<b>Store action:</b> {attachmentInfo.storeAction} ({attachmentInfo.storeReason})"
351+
});
352+
353+
passItem.Add(attachmentFoldout);
354+
}
355+
}
356+
else
357+
{
358+
CreateTextElement(passItem, "No attachments.");
333359
}
334-
}
335-
else
336-
{
337-
CreateTextElement(passItem, "No attachments.");
338360
}
339361

340362
content.Add(passItem);
@@ -343,32 +365,48 @@ void CreateTextElement(VisualElement parent, string text, string className = nul
343365
}
344366
}
345367

346-
void UpdatePanelHeights()
368+
void SaveSplitViewFixedPaneHeight()
347369
{
348-
HeaderFoldout resourceListFoldout = rootVisualElement.Q<HeaderFoldout>(Names.kResourceListFoldout);
349-
HeaderFoldout passListFoldout = rootVisualElement.Q<HeaderFoldout>(Names.kPassListFoldout);
370+
m_SidePanelFixedPaneHeight = m_SidePanelSplitView.fixedPane?.resolvedStyle?.height ?? 0;
371+
}
350372

373+
void UpdatePanelHeights()
374+
{
351375
bool passListExpanded = m_PassListExpanded && (m_CurrentDebugData != null && m_CurrentDebugData.isNRPCompiler);
352376
const int kFoldoutHeaderHeightPx = 18;
353-
if (m_ResourceListExpanded && !passListExpanded)
377+
const int kWindowExtraMarginPx = 6;
378+
379+
float panelHeightPx = focusedWindow.position.height - kHeaderContainerHeightPx - kWindowExtraMarginPx;
380+
if (!m_ResourceListExpanded)
381+
{
382+
m_SidePanelSplitView.fixedPaneInitialDimension = kFoldoutHeaderHeightPx;
383+
}
384+
else if (!passListExpanded)
354385
{
355-
resourceListFoldout.style.maxHeight = Length.Percent(100);
356-
passListFoldout.style.maxHeight = kFoldoutHeaderHeightPx;
386+
m_SidePanelSplitView.fixedPaneInitialDimension = panelHeightPx - kFoldoutHeaderHeightPx;
357387
}
358-
else if (!m_ResourceListExpanded && passListExpanded)
388+
else
359389
{
360-
resourceListFoldout.style.maxHeight = kFoldoutHeaderHeightPx;
361-
passListFoldout.style.maxHeight = Length.Percent(100);
390+
// Update aspect ratio in case user has dragged the split view
391+
if (m_SidePanelFixedPaneHeight > kFoldoutHeaderHeightPx && m_SidePanelFixedPaneHeight < panelHeightPx - kFoldoutHeaderHeightPx)
392+
{
393+
m_SidePanelVerticalAspectRatio = m_SidePanelFixedPaneHeight / panelHeightPx;
394+
}
395+
m_SidePanelSplitView.fixedPaneInitialDimension = panelHeightPx * m_SidePanelVerticalAspectRatio;
362396
}
363-
else if (m_ResourceListExpanded && passListExpanded)
397+
398+
// Disable drag line when one of the foldouts is collapsed
399+
var dragLine = m_SidePanelSplitView.Q("unity-dragline");
400+
var dragLineAnchor = m_SidePanelSplitView.Q("unity-dragline-anchor");
401+
if (!m_ResourceListExpanded || !passListExpanded)
364402
{
365-
resourceListFoldout.style.maxHeight = Length.Percent(50);
366-
passListFoldout.style.maxHeight = Length.Percent(50);
403+
dragLine.pickingMode = PickingMode.Ignore;
404+
dragLineAnchor.pickingMode = PickingMode.Ignore;
367405
}
368406
else
369407
{
370-
resourceListFoldout.style.maxHeight = kFoldoutHeaderHeightPx;
371-
passListFoldout.style.maxHeight = kFoldoutHeaderHeightPx;
408+
dragLine.pickingMode = PickingMode.Position;
409+
dragLineAnchor.pickingMode = PickingMode.Position;
372410
}
373411
}
374412

Packages/com.unity.render-pipelines.core/Editor/RenderGraph/RenderGraphViewer.cs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ static partial class Classes
9090
const int kDependencyBlockHeightPx = 26;
9191
const int kDependencyBlockWidthPx = kPassWidthPx;
9292
const int kPassTitleAllowanceMargin = 120;
93+
const int kHeaderContainerHeightPx = 24;
9394

9495
static readonly Color kReadWriteBlockFillColorDark = new Color32(0xA9, 0xD1, 0x36, 255);
9596
static readonly Color kReadWriteBlockFillColorLight = new Color32(0x67, 0x9C, 0x33, 255);
@@ -136,7 +137,7 @@ enum EmptyStateReason
136137
static readonly string[] kEmptyStateMessages =
137138
{
138139
"",
139-
L10n.Tr("No Render Graph execution has been registered. Activate a viewport to trigger camera rendering."),
140+
L10n.Tr("The selected camera is not active. Activate the selected camera to display data in the Render Graph viewer."),
140141
L10n.Tr("No data to display. Click refresh to capture data."),
141142
L10n.Tr("Waiting for the selected camera to render. Depending on the camera, you may need to trigger rendering by selecting the Scene or Game view."),
142143
L10n.Tr("No passes to display. Select a different Pass Filter to display contents."),
@@ -799,11 +800,17 @@ void SelectedRenderGraphChanged(string newRenderGraphName)
799800
}
800801
}
801802
selectedRenderGraph = null;
803+
804+
if (m_CurrentDebugData != null)
805+
RequestCaptureSelectedExecution();
802806
}
803807

804808
void SelectedExecutionChanged(string newExecutionName)
805809
{
806810
selectedExecutionName = newExecutionName;
811+
812+
if (m_CurrentDebugData != null)
813+
RequestCaptureSelectedExecution();
807814
}
808815

809816
void ClearEmptyStateMessage()
@@ -1122,12 +1129,22 @@ VisualElement CreatePassListItem(int passId, RenderGraph.DebugData.PassData pass
11221129

11231130
var passBlock = new VisualElement();
11241131
passBlock.AddToClassList(Classes.kPassBlock);
1125-
passBlock.RegisterCallback<MouseOverEvent>(_ => passBlock.AddToClassList(Classes.kPassBlockScriptLink));
1126-
passBlock.RegisterCallback<MouseOutEvent>(_ => passBlock.RemoveFromClassList(Classes.kPassBlockScriptLink));
1132+
passBlock.RegisterCallback<MouseEnterEvent>(_ =>
1133+
{
1134+
var scriptLinkBlock = new VisualElement();
1135+
scriptLinkBlock.pickingMode = PickingMode.Ignore;
1136+
scriptLinkBlock.AddToClassList(Classes.kPassBlock);
1137+
scriptLinkBlock.AddToClassList(Classes.kPassBlockScriptLink);
1138+
passBlock.Add(scriptLinkBlock);
1139+
});
1140+
passBlock.RegisterCallback<MouseLeaveEvent>(_ => passBlock.Clear());
11271141
passBlock.RegisterCallback<MouseUpEvent>(evt =>
11281142
{
1129-
var scriptAsset = FindScriptAssetByAbsolutePath(pass.scriptInfo.filePath);
1130-
AssetDatabase.OpenAsset(scriptAsset, pass.scriptInfo.line);
1143+
if (evt.button == 0)
1144+
{
1145+
var scriptAsset = FindScriptAssetByAbsolutePath(pass.scriptInfo.filePath);
1146+
AssetDatabase.OpenAsset(scriptAsset, pass.scriptInfo.line);
1147+
}
11311148
evt.StopImmediatePropagation();
11321149
});
11331150

Packages/com.unity.render-pipelines.core/Editor/StyleSheets/RenderGraphViewer.uss

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,19 @@
7272
background-color: var(--main-background-color);
7373
}
7474

75+
#current-graph-dropdown {
76+
max-width: 200px;
77+
}
78+
79+
#current-execution-dropdown {
80+
max-width: 300px;
81+
}
82+
83+
#header-container DropdownField .unity-base-popup-field__text {
84+
overflow: hidden;
85+
text-overflow: ellipsis;
86+
}
87+
7588
/* Passes */
7689

7790
#pass-list-scroll-view {
@@ -168,14 +181,6 @@
168181
transition-timing-function: ease-in-out;
169182
}
170183

171-
/* this needs to be declared after other pass block USS classes because they have equal selector precedence and
172-
we want this to have the highest priority */
173-
.pass-block.pass-block-script-link {
174-
-unity-background-scale-mode:scale-to-fit;
175-
border-width: 0;
176-
transition-duration: 0s; /* block the compatibility highlight animation */
177-
}
178-
179184
.pass-block.pass-compatibility-message-indicator--compatible {
180185
background-color: var(--native-pass-accent-compatible-color);
181186
}
@@ -184,6 +189,13 @@
184189
background-color: var(--pass-block-color--async);
185190
}
186191

192+
.pass-block.pass-block-script-link {
193+
/*-unity-background-scale-mode:scale-to-fit;*/
194+
border-width: 2px;
195+
margin: -1px;
196+
padding: 0;
197+
}
198+
187199
#pass-list-corner-occluder {
188200
position: absolute;
189201
min-width: var(--resource-column-width);
@@ -384,20 +396,27 @@
384396
flex-grow: 1;
385397
flex-shrink: 1;
386398
min-height: 18px;
399+
background-color: var(--side-panel-background-color);
400+
}
401+
402+
#panel-resource-list-scroll-view {
403+
min-height: 30px;
387404
}
388405

389406
#panel-pass-list {
390407
flex-grow: 0;
391408
flex-shrink: 1;
392409
min-height: 18px;
410+
border-bottom-width: 0;
411+
background-color: var(--side-panel-background-color);
393412
}
394413

395-
#panel-container .header-foldout {
396-
margin: 0; /* Counteract built-in margins inside HeaderFoldout */
414+
#panel-pass-list-scroll-view {
415+
min-height: 30px;
397416
}
398417

399-
#panel-pass-list {
400-
border-bottom-width: 0;
418+
#panel-container .header-foldout {
419+
margin: 0; /* Counteract built-in margins inside HeaderFoldout */
401420
}
402421

403422
#panel-container .header-foldout > Toggle {

0 commit comments

Comments
 (0)