Skip to content

Commit 0378faf

Browse files
authored
Improved tooltips on Feature Table page (#73)
1 parent fcf7fd0 commit 0378faf

File tree

3 files changed

+61
-62
lines changed

3 files changed

+61
-62
lines changed

source/frontend/assets/css/feature_table.css

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -111,34 +111,7 @@ thead>tr:nth-of-type(2)>th {
111111
z-index: 3;
112112
opacity: 0;
113113
transition: opacity 150ms ease-in, visibility 0ms ease-in 150ms;
114-
}
115-
116-
.tooltiptextbottomright {
117-
top: 110%;
118-
left: 95%;
119-
transform: translateX(-100%);
120-
}
121-
122-
.tooltiptextbottomcenter {
123-
top: 110%;
124-
left: 50%;
125-
transform: translateX(-50%);
126-
}
127-
128-
.tooltiptextbottomleft {
129-
top: 110%;
130-
left: 5%;
131-
}
132-
133-
.tooltiptexttop {
134-
bottom: 110%;
135-
left: 0%;
136-
}
137-
138-
.tooltiptexttopcenter {
139-
bottom: 110%;
140-
left: 50%;
141-
transform: translateX(-50%);
114+
bottom: 100%;
142115
}
143116

144117
.tooltip:hover .tooltiptext {

source/frontend/assets/js/website_feature_table.mjs

Lines changed: 59 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const DefaultTooltipOptions = {
2626
alignOutsideHorizontal: false,
2727
alignOutsideVertical: false,
2828
preferTowardsBottom: false,
29-
tooltipAlignment: "top"
29+
tooltipAlignment: 0.5
3030
};
3131

3232
// Use alignOutside* and preferTowardsBottom to position the tooltip next to the element on the respective side
@@ -42,7 +42,8 @@ function AddTooltipForTable(parent, text, options_param) {
4242
parent.classList.add("tooltip");
4343

4444
const tooltipTextElement = document.createElement("span");
45-
tooltipTextElement.className = "tooltiptext white_space_pre tooltiptext" + options.tooltipAlignment;
45+
tooltipTextElement.className = "tooltiptext white_space_pre tooltiptext";
46+
tooltipTextElement.style = `left: ${options.tooltipAlignment*100}%;transform: translateX(-${options.tooltipAlignment*100}%);`;
4647
tooltipTextElement.textContent = text;
4748
parent.appendChild(tooltipTextElement);
4849

@@ -177,7 +178,7 @@ function UpdateTableFilter() {
177178
AddFilterPanel(headerContainer);
178179
}
179180

180-
function UpdateTableHeader(table) {
181+
function UpdateTableHeader(table, archTooltipAlignments) {
181182
let thead = document.createElement("thead");
182183
let headerRowVendor = document.createElement("tr");
183184
let headerRowArch = document.createElement("tr");
@@ -227,7 +228,7 @@ function UpdateTableHeader(table) {
227228
{
228229
alignOutsideVertical: true,
229230
preferTowardsBottom: true,
230-
tooltipAlignment: "bottomright"
231+
tooltipAlignment: archTooltipAlignments.get(a)
231232
});
232233
}
233234
}
@@ -246,10 +247,10 @@ function AddCellReal(text, featureRow, tooltipText, tooltipAlignment, colspan) {
246247
}
247248
featureRow.appendChild(td);
248249
if (tooltipText)
249-
AddTooltipForTable(td, tooltipText, { alignOutsideVertical: true, tooltipAlignment: tooltipAlignment ?? "bottomcenter" });
250+
AddTooltipForTable(td, tooltipText, { alignOutsideVertical: true, tooltipAlignment: tooltipAlignment});
250251
}
251252

252-
function AddSpecialRowCell(featureRow, archName, featureName) {
253+
function AddSpecialRowCell(featureRow, archName, featureName, tooltipAlignment) {
253254
if (featureName == "TableReleaseDate") {
254255
let releaseDate = Constants.ArchReleaseDates[archName];
255256
if (releaseDate == undefined) {
@@ -262,7 +263,7 @@ function AddSpecialRowCell(featureRow, archName, featureName) {
262263
tooltipText = "WARP is a software rasterizer that continues to receive updates over time.\nComparing its initial release date (2015) to the release dates of hardware GPUs,\nwhich cannot gain new features after release, is not meaningful.";
263264
}
264265

265-
AddCellReal(releaseDate, featureRow, tooltipText);
266+
AddCellReal(releaseDate, featureRow, tooltipText, tooltipAlignment);
266267
return true;
267268
}
268269
else if (featureName == "TableNumReports") {
@@ -284,7 +285,7 @@ function AddSpecialRowCell(featureRow, archName, featureName) {
284285
else {
285286
marketShare = Math.round(marketShare * 10000) / 100 + "%"
286287
}
287-
AddCellReal(marketShare, featureRow, tooltipText);
288+
AddCellReal(marketShare, featureRow, tooltipText, tooltipAlignment);
288289
return true;
289290
}
290291
else if (featureName == "TableReportUsed") {
@@ -341,7 +342,7 @@ function AddSpecialRowCell(featureRow, archName, featureName) {
341342
return false;
342343
}
343344

344-
function OverrideCell(tableRow, archName, featureName, featureValue, newestDriverReport, newestReportContainer) {
345+
function OverrideCell(tableRow, archName, featureName, featureValue, newestDriverReport, newestReportContainer, tooltipAlignment) {
345346
if (featureName == "D3D12_FEATURE_DATA_D3D12_OPTIONS16.GPUUploadHeapSupported") {
346347
if (archName == "WARP")
347348
{
@@ -352,7 +353,7 @@ function OverrideCell(tableRow, archName, featureName, featureValue, newestDrive
352353
for (let r of ArchClassifier.ReportsPerArch.get(archName)) {
353354
// If at least one report has GPUUploadHeapSupported == 1, this means that architecture supports it
354355
if (archName != "WARP" && r.D3D12_FEATURE_DATA_D3D12_OPTIONS16.GPUUploadHeapSupported) {
355-
AddCellReal(Constants.TrueFalseMappingShort["1"] + "*", tableRow, "GPU Upload Heap support depends on BIOS settings and Windows version.\nSame GPU may report different values depending on the system.", "bottomright");
356+
AddCellReal(Constants.TrueFalseMappingShort["1"] + "*", tableRow, "GPU Upload Heap support depends on BIOS settings and Windows version.\nSame GPU may report different values depending on the system.", tooltipAlignment);
356357
return true;
357358
}
358359
}
@@ -361,47 +362,47 @@ function OverrideCell(tableRow, archName, featureName, featureValue, newestDrive
361362
return true;
362363
}
363364
else if ((featureName == "D3D12_FEATURE_DATA_D3D12_OPTIONS6.ShadingRateImageTileSize" || featureName == "D3D12_FEATURE_DATA_D3D12_OPTIONS6.AdditionalShadingRatesSupported" || featureName == "D3D12_FEATURE_DATA_D3D12_OPTIONS6.PerPrimitiveShadingRateSupportedWithViewportIndexing" || featureName == "D3D12_FEATURE_DATA_D3D12_OPTIONS10.VariableRateShadingSumCombinerSupported" || featureName == "D3D12_FEATURE_DATA_D3D12_OPTIONS10.MeshShaderPerPrimitiveShadingRateSupported") && newestDriverReport.D3D12_FEATURE_DATA_D3D12_OPTIONS6.VariableShadingRateTier == 0) {
364-
AddCellReal("N/A", tableRow, "VRS capabilities are only relevant if VRS is supported.");
365+
AddCellReal("N/A", tableRow, "VRS capabilities are only relevant if VRS is supported.", tooltipAlignment);
365366
return true;
366367
}
367368
else if (featureName == "D3D12_FEATURE_DATA_D3D12_OPTIONS6.ShadingRateImageTileSize" && newestDriverReport.D3D12_FEATURE_DATA_D3D12_OPTIONS6.VariableShadingRateTier == 1) {
368-
AddCellReal("N/A", tableRow, "VRS Tier 2 is required for shading rate image support.");
369+
AddCellReal("N/A", tableRow, "VRS Tier 2 is required for shading rate image support.", tooltipAlignment);
369370
return true;
370371
}
371372
else if ((featureName == "D3D12_FEATURE_DATA_D3D12_OPTIONS6.PerPrimitiveShadingRateSupportedWithViewportIndexing" || featureName == "D3D12_FEATURE_DATA_D3D12_OPTIONS10.VariableRateShadingSumCombinerSupported" || featureName == "D3D12_FEATURE_DATA_D3D12_OPTIONS10.MeshShaderPerPrimitiveShadingRateSupported") && newestDriverReport.D3D12_FEATURE_DATA_D3D12_OPTIONS6.VariableShadingRateTier == 1) {
372-
AddCellReal("N/A", tableRow, "VRS Tier 2 is required for this capability.");
373+
AddCellReal("N/A", tableRow, "VRS Tier 2 is required for this capability.", tooltipAlignment);
373374
return true;
374375
}
375376
// If our tiled resource tier is 3, the SRVOnlyTiledResourceTier3 flag does not apply, but is always true, which is misleading
376377
else if (featureName == "D3D12_FEATURE_DATA_D3D12_OPTIONS5.SRVOnlyTiledResourceTier3" && newestDriverReport.D3D12_FEATURE_DATA_D3D12_OPTIONS.TiledResourcesTier >= 3) {
377-
AddCellReal("N/A", tableRow, "SRVOnlyTiledResourceTier3 is always true\nif TiledResourcesTier >= 3.", "bottomright");
378+
AddCellReal("N/A", tableRow, "SRVOnlyTiledResourceTier3 is always true\nif TiledResourcesTier >= 3.", tooltipAlignment);
378379
return true;
379380
}
380381
else if (featureName == "D3D12_FEATURE_DATA_D3D12_OPTIONS5.RaytracingTier" && archName == "Pascal") {
381-
AddCellReal("Tier 1.0 *", tableRow, "Pascal have (software emulated) Tier 1.0 raytracing support, but only if the card has 6GB of VRAM or more");
382+
AddCellReal("Tier 1.0 *", tableRow, "Pascal have (software emulated) Tier 1.0 raytracing support, but only if the card has 6GB of VRAM or more", tooltipAlignment);
382383
return true;
383384
}
384385
else if (featureName == "D3D12_FEATURE_DATA_D3D12_OPTIONS5.RaytracingTier" && archName == "Turing") {
385-
AddCellReal("Tier 1.1 *", tableRow, "Within Turing architecture there are:\nRTX 20 series and Quadro RTX cards with hardware Tier 1.1 support\nGTX 16 series cards with >= 6GB of VRAM with software emulated Tier 1.0 support\nGTX 16 series cards with < 6GB of VRAM with no raytracing support at all");
386+
AddCellReal("Tier 1.1 *", tableRow, "Within Turing architecture there are:\nRTX 20 series and Quadro RTX cards with hardware Tier 1.1 support\nGTX 16 series cards with >= 6GB of VRAM with software emulated Tier 1.0 support\nGTX 16 series cards with < 6GB of VRAM with no raytracing support at all", tooltipAlignment);
386387
return true;
387388
}
388389
else if (featureName == "D3D12_FEATURE_DATA_D3D12_OPTIONS5.RaytracingTier" && archName == "X1") {
389-
AddCellReal("❌ *", tableRow, "X1 supports ray query in hardware,\nbut this capability is not exposed in D3D12,\nsince DXR Tier 1.0 requires callable shaders,\nwhich are unsupported on X1.", "bottomright");
390+
AddCellReal("❌ *", tableRow, "X1 supports ray query in hardware,\nbut this capability is not exposed in D3D12,\nsince DXR Tier 1.0 requires callable shaders,\nwhich are unsupported on X1.", tooltipAlignment);
390391
return true;
391392
}
392393
else if (featureName == "D3D12_FEATURE_DATA_D3D12_OPTIONS7.MeshShaderTier" && archName == "RDNA2") {
393-
AddCellReal(Constants.TrueFalseMappingShort["1"] + "*", tableRow, "RDNA2 iGPUs with 1 WGP don't have mesh shader support");
394+
AddCellReal(Constants.TrueFalseMappingShort["1"] + "*", tableRow, "RDNA2 iGPUs with 1 WGP don't have mesh shader support", tooltipAlignment);
394395
return true;
395396
}
396397
else if (featureName == "D3D12_FEATURE_DATA_D3D12_OPTIONS12.MSPrimitivesPipelineStatisticIncludesCulledPrimitives" && newestDriverReport.D3D12_FEATURE_DATA_D3D12_OPTIONS7.MeshShaderTier == 0) {
397-
AddCellReal("N/A", tableRow, "It is only relevant if Mesh Shaders are supported.", "bottomright");
398+
AddCellReal("N/A", tableRow, "It is only relevant if Mesh Shaders are supported.", tooltipAlignment);
398399
return true;
399400
}
400401
return false;
401402
}
402403

403-
function AddCell(featureRow, archName, featureName) {
404-
if (AddSpecialRowCell(featureRow, archName, featureName)) {
404+
function AddCell(featureRow, archName, featureName, tooltipAlignment) {
405+
if (AddSpecialRowCell(featureRow, archName, featureName, tooltipAlignment)) {
405406
return;
406407
}
407408

@@ -410,7 +411,7 @@ function AddCell(featureRow, archName, featureName) {
410411

411412
let featureValue = newestReportContainer.GetField(featureName);
412413

413-
if (OverrideCell(featureRow, archName, featureName, featureValue, newestDriverReport, newestReportContainer)) {
414+
if (OverrideCell(featureRow, archName, featureName, featureValue, newestDriverReport, newestReportContainer, tooltipAlignment)) {
414415
return
415416
}
416417

@@ -420,22 +421,22 @@ function AddCell(featureRow, archName, featureName) {
420421
function AddSpecialRow(featureRow, featureName) {
421422
if (featureName == "D3D12_FEATURE_DATA_D3D12_OPTIONS19.RasterizerDesc2Supported" || featureName == "D3D12_FEATURE_DATA_D3D12_OPTIONS18.RenderPassesValid") {
422423
// I don't know why, but both D3D12_FEATURE_DATA_D3D12_OPTIONS18 and D3D12_FEATURE_DATA_D3D12_OPTIONS19 were added in the same SDK version
423-
AddCellReal("Always supported *", featureRow, "Starting with Agility SDK 1.610.0, it is always supported, independently of GPU or driver.", "topcenter", ArchToOutputCount());
424+
AddCellReal("Always supported *", featureRow, "Starting with Agility SDK 1.610.0, it is always supported, independently of GPU or driver.", 0.5, ArchToOutputCount());
424425
return true;
425426
}
426427
if (featureName == "D3D12_FEATURE_DATA_ROOT_SIGNATURE.HighestVersion") {
427-
AddCellReal("1.2 *", featureRow, "Starting with Agility SDK 1.610.0, Root Signature 1.2 is always supported, independently of GPU or driver.", "topcenter", ArchToOutputCount());
428+
AddCellReal("1.2 *", featureRow, "Starting with Agility SDK 1.610.0, Root Signature 1.2 is always supported, independently of GPU or driver.", 0.5, ArchToOutputCount());
428429
return true;
429430
}
430431
if (featureName == "D3D12_FEATURE_DATA_D3D12_OPTIONS1.ExpandedComputeResourceStates") {
431-
AddCellReal("Always supported *", featureRow, "Starting with Windows 10 version 1607, it is always supported, independently of GPU or driver.\nAll currently supported Windows versions are newer than Windows 10 version 1607.", "topcenter", ArchToOutputCount());
432+
AddCellReal("Always supported *", featureRow, "Starting with Windows 10 version 1607, it is always supported, independently of GPU or driver.\nAll currently supported Windows versions are newer than Windows 10 version 1607.", 0.5, ArchToOutputCount());
432433
return true;
433434
}
434435

435436
return false;
436437
}
437438

438-
function AddRow(tbody, featureName, featureShortName) {
439+
function AddRow(tbody, featureName, featureShortName, archTooltipAlignments) {
439440
let featureRow = document.createElement("tr");
440441

441442
// Filter out features based on Globals.PropertiesSearchString
@@ -458,9 +459,9 @@ function AddRow(tbody, featureName, featureShortName) {
458459
featureHeader.append(featureShortName);
459460
featureHeader.scope = "row";
460461
if (!featureName.startsWith("Table"))
461-
AddTooltipForTable(featureHeader, featureName, { alignOutsideVertical: true });
462+
AddTooltipForTable(featureHeader, featureName, { alignOutsideVertical: true, tooltipAlignment: 0.0 });
462463
else if (featureName == "TableMarketShare")
463-
AddTooltipForTable(featureHeader, "Market share in the Steam Hardware Survey among DirectX 12 Systems.\nThis is an underestimate and may not be very accurate in general.", { alignOutsideVertical: true });
464+
AddTooltipForTable(featureHeader, "Market share in the Steam Hardware Survey among DirectX 12 Systems.\nThis is an underestimate and may not be very accurate in general.", { alignOutsideVertical: true, tooltipAlignment: 0.0 });
464465

465466
featureRow.appendChild(featureHeader);
466467

@@ -474,21 +475,44 @@ function AddRow(tbody, featureName, featureShortName) {
474475
for (let archName of archs) {
475476
if (!NeedOutputArch(vendor, archName))
476477
continue;
477-
AddCell(featureRow, archName, featureName);
478+
AddCell(featureRow, archName, featureName, archTooltipAlignments.get(archName));
478479
}
479480
tbody.appendChild(featureRow);
480481
}
481482
}
482483

483-
function UpdateTableBody(table) {
484+
function UpdateTableBody(table, archTooltipAlignments) {
484485
let tbody = document.createElement("tbody");
485486

486487
for (let [featureName, featureShortName] of Object.entries(FeatureTableConstants.TableFeaturesShortNames)) {
487-
AddRow(tbody, featureName, featureShortName);
488+
AddRow(tbody, featureName, featureShortName, archTooltipAlignments);
488489
}
489490
table.appendChild(tbody);
490491
}
491492

493+
function UpdateTooltipAlignmentMap()
494+
{
495+
let result = new Map();
496+
let colCount = 1;
497+
for (let [vendor, archs] of Object.entries(ArchClassifier.ArchsPerVendor)) {
498+
for (let a of archs) {
499+
if (!NeedOutputArch(vendor, a))
500+
continue;
501+
++colCount;
502+
}
503+
}
504+
let currentCol = 0;
505+
for (let [vendor, archs] of Object.entries(ArchClassifier.ArchsPerVendor)) {
506+
for (let a of archs) {
507+
if (!NeedOutputArch(vendor, a))
508+
continue;
509+
++currentCol;
510+
result.set(a, currentCol / (colCount - 1));
511+
}
512+
}
513+
return result;
514+
}
515+
492516
function UpdateTable() {
493517
const tableContainer = document.getElementById("FeatureTable");
494518
HTML.ClearElement(tableContainer);
@@ -497,11 +521,13 @@ function UpdateTable() {
497521
tableContainer.appendChild(table);
498522
HTML.ClearElement(table);
499523

524+
let archTooltipAlignments = UpdateTooltipAlignmentMap();
525+
500526
// construct table header with vendor name in the first row and arch name in the second row
501-
UpdateTableHeader(table);
527+
UpdateTableHeader(table, archTooltipAlignments);
502528

503529
// construct table body with all the features
504-
UpdateTableBody(table);
530+
UpdateTableBody(table, archTooltipAlignments);
505531
}
506532

507533
function OverrideSearch() {

0 commit comments

Comments
 (0)