Skip to content

Commit

Permalink
feat: Add option to disable WebGL rendering (#2134)
Browse files Browse the repository at this point in the history
- Advanced Settings section in the Settings menu, with an option to
disable WebGL
- Read from the server config for default values
  - web.webgl: default setting for WebGL being enabled or not
  - web.webgl.editable: disallow the user from enabling WebGL
- Contextual Help item to add more info
- Tested by adding the following to the deephaven.prop config:
```
web.webgl=false
web.webgl.editable=false
client.configuration.list=java.version,deephaven.version,barrage.version,http.session.durationMs,file.separator,web.storage.layout.directory,web.storage.notebook.directory,web.webgl,web.webgl.editable
```
---------

Co-authored-by: Don <dsmmcken@gmail.com>
  • Loading branch information
mofojed and dsmmcken authored Jul 11, 2024
1 parent 232fb4d commit 011eb33
Show file tree
Hide file tree
Showing 14 changed files with 212 additions and 17 deletions.
10 changes: 10 additions & 0 deletions packages/app-utils/src/storage/LocalWorkspaceStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ export class LocalWorkspaceStorage implements WorkspaceStorage {
defaultNotebookSettings: {
isMinimapEnabled: false,
},
webgl: true,
webglEditable: true,
};
const serverSettings = {
defaultDateTimeFormat: serverConfigValues?.get('dateTimeFormat'),
Expand Down Expand Up @@ -109,6 +111,14 @@ export class LocalWorkspaceStorage implements WorkspaceStorage {
) as boolean,
}
: undefined,
webgl: LocalWorkspaceStorage.getBooleanServerConfig(
serverConfigValues,
'web.webgl'
),
webglEditable: LocalWorkspaceStorage.getBooleanServerConfig(
serverConfigValues,
'web.webgl.editable'
),
};

const keys = Object.keys(serverSettings) as Array<keyof typeof settings>;
Expand Down
30 changes: 25 additions & 5 deletions packages/chart/src/Chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,23 +41,29 @@ import useChartTheme from './useChartTheme';

const log = Log.module('Chart');

type FormatterSettings = ColumnFormatSettings &
type ChartSettings = ColumnFormatSettings &
DateTimeFormatSettings & {
decimalFormatOptions?: DecimalColumnFormatterOptions;
integerFormatOptions?: IntegerColumnFormatterOptions;
webgl?: boolean;
};

interface ChartProps {
model: ChartModel;
theme: ChartTheme;
settings: FormatterSettings;

/** User settings that are relevant to the chart, e.g. formatter settings */
settings: ChartSettings;

isActive: boolean;
Plotly: typeof Plotly;
containerRef?: React.RefObject<HTMLDivElement>;
onDisconnect: () => void;
onReconnect: () => void;
onUpdate: (obj: { isLoading: boolean }) => void;
onError: (error: Error) => void;

/** Called when the settings for the ChartModel are changed */
onSettingsChanged: (settings: Partial<ChartModelSettings>) => void;
}

Expand Down Expand Up @@ -91,6 +97,7 @@ class Chart extends Component<ChartProps, ChartState> {
showTimeZone: false,
showTSeparator: true,
formatter: [],
webgl: true,
},
Plotly,
onDisconnect: (): void => undefined,
Expand Down Expand Up @@ -195,7 +202,7 @@ class Chart extends Component<ChartProps, ChartState> {

componentDidUpdate(prevProps: ChartProps): void {
const { isActive, model, settings, theme } = this.props;
this.updateFormatterSettings(settings as FormatterSettings);
this.updateFormatterSettings(settings);

if (model !== prevProps.model) {
this.unsubscribe(prevProps.model);
Expand Down Expand Up @@ -239,6 +246,8 @@ class Chart extends Component<ChartProps, ChartState> {

integerFormatOptions: IntegerColumnFormatterOptions;

webgl?: boolean;

rect?: DOMRect;

ranges?: unknown;
Expand Down Expand Up @@ -612,10 +621,10 @@ class Chart extends Component<ChartProps, ChartState> {

initFormatter(): void {
const { settings } = this.props;
this.updateFormatterSettings(settings as FormatterSettings);
this.updateFormatterSettings(settings);
}

updateFormatterSettings(settings: FormatterSettings): void {
updateFormatterSettings(settings: ChartSettings): void {
const columnFormats = FormatterUtils.getColumnFormats(settings);
const dateTimeFormatterOptions =
FormatterUtils.getDateTimeFormatterOptions(settings);
Expand All @@ -633,6 +642,11 @@ class Chart extends Component<ChartProps, ChartState> {
this.integerFormatOptions = integerFormatOptions;
this.updateFormatter();
}

if (this.webgl !== settings.webgl) {
this.webgl = settings.webgl;
this.updateRenderOptions();
}
}

updateFormatter(): void {
Expand All @@ -647,6 +661,12 @@ class Chart extends Component<ChartProps, ChartState> {
model.setFormatter(formatter);
}

updateRenderOptions(): void {
const { model } = this.props;
const renderOptions = { webgl: this.webgl };
model.setRenderOptions(renderOptions);
}

updateDimensions(): void {
const rect = this.getPlotRect();
const { Plotly: PlotlyProp } = this.props;
Expand Down
17 changes: 17 additions & 0 deletions packages/chart/src/ChartModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ import type { Layout, Data } from 'plotly.js';
import { FilterColumnMap, FilterMap } from './ChartUtils';

export type ChartEvent = CustomEvent;

export type RenderOptions = {
/** Allow WebGL as an option. Defaults to `true`, explicitly set to `false` to disable. */
webgl?: boolean;
};

/**
* Model for a Chart
* All of these methods should return very quickly.
Expand Down Expand Up @@ -41,8 +47,11 @@ class ChartModel {

listeners: ((event: ChartEvent) => void)[];

/** Formatter settings for the chart, such as how to format dates and numbers */
formatter?: Formatter;

renderOptions?: RenderOptions;

rect?: DOMRect;

isDownsamplingDisabled: boolean;
Expand Down Expand Up @@ -86,6 +95,14 @@ class ChartModel {
this.formatter = formatter;
}

/**
* Set additional options for rendering the chart
* @param renderOptions Options for rendering the chart
*/
setRenderOptions(renderOptions: RenderOptions): void {
this.renderOptions = renderOptions;
}

/**
* Disable downsampling
* @param isDownsamplingDisabled True if downsampling should be disabled
Expand Down
21 changes: 14 additions & 7 deletions packages/chart/src/ChartUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -681,17 +681,22 @@ class ChartUtils {
* Converts the Iris plot style into a plotly chart type
* @param plotStyle The plotStyle to use, see dh.plot.SeriesPlotStyle
* @param isBusinessTime If the plot is using business time for an axis
* @param allowWebGL If WebGL is allowedd
*/
getPlotlyChartType(
plotStyle: DhType.plot.SeriesPlotStyle,
isBusinessTime: boolean
isBusinessTime: boolean,
allowWebGL = true
): PlotType | undefined {
const { dh } = this;
switch (plotStyle) {
case dh.plot.SeriesPlotStyle.SCATTER:
case dh.plot.SeriesPlotStyle.LINE:
// scattergl mode is more performant, but doesn't support the rangebreaks we need for businessTime calendars
return !isBusinessTime && IS_WEBGL_SUPPORTED ? 'scattergl' : 'scatter';
// scattergl mode is more performant (usually), but doesn't support the rangebreaks we need for businessTime calendars
// In some cases, WebGL is less performant (like in virtual desktop environments), so we also allow the option of the user explicitly disabling it even if it's supported
return !isBusinessTime && IS_WEBGL_SUPPORTED && allowWebGL
? 'scattergl'
: 'scatter';
case dh.plot.SeriesPlotStyle.BAR:
case dh.plot.SeriesPlotStyle.STACKED_BAR:
return 'bar';
Expand Down Expand Up @@ -871,7 +876,8 @@ class ChartUtils {
series: DhType.plot.Series,
axisTypeMap: AxisTypeMap,
seriesVisibility: boolean | 'legendonly',
showLegend: boolean | null = null
showLegend: boolean | null = null,
allowWebGL = true
): Partial<PlotData> {
const {
name,
Expand All @@ -888,7 +894,7 @@ class ChartUtils {
const isBusinessTime = sources.some(
source => source.axis?.businessCalendar
);
const type = this.getChartType(plotStyle, isBusinessTime);
const type = this.getChartType(plotStyle, isBusinessTime, allowWebGL);
const mode = this.getPlotlyChartMode(
plotStyle,
isLinesVisible ?? undefined,
Expand Down Expand Up @@ -1019,7 +1025,8 @@ class ChartUtils {

getChartType(
plotStyle: DhType.plot.SeriesPlotStyle,
isBusinessTime: boolean
isBusinessTime: boolean,
allowWebGL = true
): PlotType | undefined {
const { dh } = this;
switch (plotStyle) {
Expand All @@ -1028,7 +1035,7 @@ class ChartUtils {
// plot.ly to calculate the bins and sum values, just convert it to a bar chart
return 'bar';
default:
return this.getPlotlyChartType(plotStyle, isBusinessTime);
return this.getPlotlyChartType(plotStyle, isBusinessTime, allowWebGL);
}
}

Expand Down
12 changes: 10 additions & 2 deletions packages/chart/src/FigureChartModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import type {
DateTimeColumnFormatter,
Formatter,
} from '@deephaven/jsapi-utils';
import ChartModel, { ChartEvent } from './ChartModel';
import ChartModel, { ChartEvent, RenderOptions } from './ChartModel';
import ChartUtils, {
AxisTypeMap,
ChartModelSettings,
Expand Down Expand Up @@ -219,7 +219,8 @@ class FigureChartModel extends ChartModel {
series,
axisTypeMap,
ChartUtils.getSeriesVisibility(series.name, this.settings),
showLegend
showLegend,
this.renderOptions?.webgl ?? true
);

this.seriesDataMap.set(series.name, seriesData);
Expand Down Expand Up @@ -535,6 +536,13 @@ class FigureChartModel extends ChartModel {
this.resubscribe();
}

setRenderOptions(renderOptions: RenderOptions): void {
super.setRenderOptions(renderOptions);

// Reset all the series to re-render them with the correct rendering options
this.initAllSeries();
}

setDownsamplingDisabled(isDownsamplingDisabled: boolean): void {
super.setDownsamplingDisabled(isDownsamplingDisabled);

Expand Down
66 changes: 66 additions & 0 deletions packages/code-studio/src/settings/AdvancedSectionContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React, { useCallback } from 'react';
import { useDispatch } from 'react-redux';
import {
Content,
ContextualHelp,
Heading,
Switch,
Text,
} from '@deephaven/components';
import { getWebGL, getWebGLEditable, updateSettings } from '@deephaven/redux';
import { useAppSelector } from '@deephaven/dashboard';

function AdvancedSectionContent(): JSX.Element {
const dispatch = useDispatch();
const webgl = useAppSelector(getWebGL);
const webglEditable = useAppSelector(getWebGLEditable);

const handleWebglChange = useCallback(
newValue => {
dispatch(updateSettings({ webgl: newValue }));
},
[dispatch]
);

const helpText = webglEditable ? (
<Text>
WebGL in most cases has significant performance improvements, particularly
when plotting large datasets. However, in some environments (such as
remote desktop environments), WebGL may not use hardware acceleration and
have degraded performance. If you are experiencing issues with WebGL, you
can disable it here.
</Text>
) : (
<Text>
WebGL is disabled by your system administrator. Contact your system
administrator to enable.
</Text>
);

return (
<>
<div className="app-settings-menu-description">
Advanced settings here. Be careful!
</div>

<div className="form-row mb-3 pl-1">
<Switch
isSelected={webgl}
isDisabled={!webglEditable}
onChange={handleWebglChange}
marginEnd="size-0"
>
Enable WebGL
</Switch>
<ContextualHelp variant="info" marginTop="size-50">
<Heading>Enable WebGL</Heading>
<Content>
<Text>{helpText}</Text>
</Content>
</ContextualHelp>
</div>
</>
);
}

export default AdvancedSectionContent;
29 changes: 28 additions & 1 deletion packages/code-studio/src/settings/SettingsMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
vsPaintcan,
dhUserIncognito,
dhUser,
vsTools,
} from '@deephaven/icons';
import {
Button,
Expand Down Expand Up @@ -38,6 +39,7 @@ import {
getFormattedPluginInfo,
getFormattedVersionInfo,
} from './SettingsUtils';
import AdvancedSectionContent from './AdvancedSectionContent';

interface SettingsMenuProps {
serverConfigValues: ServerConfigValues;
Expand Down Expand Up @@ -68,6 +70,8 @@ export class SettingsMenu extends Component<

static THEME_SECTION_KEY = 'SettingsMenu.theme';

static ADVANCED_SECTION_KEY = 'SettingsMenu.advanced';

static focusFirstInputInContainer(container: HTMLDivElement | null): void {
const input = container?.querySelector('input, select, textarea');
if (input) {
Expand Down Expand Up @@ -289,14 +293,37 @@ export class SettingsMenu extends Component<
)}
title={
<>
<FontAwesomeIcon icon={vsRecordKeys} transform="grow-2" />{' '}
<FontAwesomeIcon
icon={vsRecordKeys}
transform="grow-2"
className="mr-2"
/>
Keyboard Shortcuts
</>
}
onToggle={this.handleSectionToggle}
>
<ShortcutSectionContent />
</SettingsMenuSection>
<SettingsMenuSection
sectionKey={SettingsMenu.ADVANCED_SECTION_KEY}
isExpanded={this.isSectionExpanded(
SettingsMenu.ADVANCED_SECTION_KEY
)}
title={
<>
<FontAwesomeIcon
icon={vsTools}
transform="grow-4"
className="mr-2"
/>
Advanced
</>
}
onToggle={this.handleSectionToggle}
>
<AdvancedSectionContent />
</SettingsMenuSection>

<div className="app-settings-footer">
<div className="app-settings-footer-section">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,4 +166,7 @@
var(--dh-color-visual-gray) 5%,
transparent
);

/* Switch */
--dh-toggle-switch-bg: var(--dh-color-gray-500);
}
Loading

0 comments on commit 011eb33

Please sign in to comment.