Skip to content
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

Add software rendering flag for Windows #1445

Merged
merged 3 commits into from
Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
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
23 changes: 23 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,28 @@ Defaults to enabled.

---

### credential.guiSoftwareRendering

Force the use of software rendering for GUI prompts.

This is currently only applicable on Windows.

#### Example

```shell
git config --global credential.guiSoftwareRendering true
```

Defaults to false (use hardware acceleration where available).

> [!NOTE]
> Windows on ARM devices defaults to using software rendering to work around a
> known Avalonia issue: <https://github.com/AvaloniaUI/Avalonia/issues/10405>

**Also see: [GCM_GUI_SOFTWARE_RENDERING][gcm-gui-software-rendering]**

---

### credential.autoDetectTimeout

Set the maximum length of time, in milliseconds, that GCM should wait for a
Expand Down Expand Up @@ -978,6 +1000,7 @@ Defaults to disabled.
[gcm-github-authmodes]: environment.md#GCM_GITHUB_AUTHMODES
[gcm-gitlab-authmodes]:environment.md#GCM_GITLAB_AUTHMODES
[gcm-gui-prompt]: environment.md#GCM_GUI_PROMPT
[gcm-gui-software-rendering]: environment.md#GCM_GUI_SOFTWARE_RENDERING
[gcm-http-proxy]: environment.md#GCM_HTTP_PROXY-deprecated
[gcm-interactive]: environment.md#GCM_INTERACTIVE
[gcm-msauth-flow]: environment.md#GCM_MSAUTH_FLOW
Expand Down
31 changes: 31 additions & 0 deletions docs/environment.md
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,36 @@ Defaults to enabled.

---

### GCM_GUI_SOFTWARE_RENDERING

Force the use of software rendering for GUI prompts.

This is currently only applicable on Windows.

#### Example

##### Windows

```batch
SET GCM_GUI_SOFTWARE_RENDERING=1
```

##### macOS/Linux

```bash
export GCM_GUI_SOFTWARE_RENDERING=1
```

Defaults to false (use hardware acceleration where available).

> [!NOTE]
> Windows on ARM devices defaults to using software rendering to work around a
> known Avalonia issue: <https://github.com/AvaloniaUI/Avalonia/issues/10405>

**Also see: [credential.guiSoftwareRendering][credential-guisoftwarerendering]**

---

### GCM_AUTODETECT_TIMEOUT

Set the maximum length of time, in milliseconds, that GCM should wait for a
Expand Down Expand Up @@ -1111,6 +1141,7 @@ Defaults to disabled.
[credential-githubauthmodes]: configuration.md#credentialgitHubAuthModes
[credential-gitlabauthmodes]: configuration.md#credentialgitLabAuthModes
[credential-guiprompt]: configuration.md#credentialguiprompt
[credential-guisoftwarerendering]: configuration.md#credentialguisoftwarerendering
[credential-httpproxy]: configuration.md#credentialhttpProxy-deprecated
[credential-interactive]: configuration.md#credentialinteractive
[credential-namespace]: configuration.md#credentialnamespace
Expand Down
7 changes: 7 additions & 0 deletions src/shared/Core/ApplicationBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using GitCredentialManager.UI;

namespace GitCredentialManager
{
Expand Down Expand Up @@ -74,6 +75,12 @@ public Task<int> RunAsync(string[] args)
Context.Trace.WriteLine("Tracing of secrets is enabled. Trace output may contain sensitive information.");
}

// Set software rendering if defined in settings
if (Context.Settings.UseSoftwareRendering)
{
AvaloniaUi.Initialize(win32SoftwareRendering: true);
}

return RunInternalAsync(args);
}

Expand Down
2 changes: 2 additions & 0 deletions src/shared/Core/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ public static class EnvironmentVariables
public const string OAuthClientAuthHeader = "GCM_OAUTH_USE_CLIENT_AUTH_HEADER";
public const string OAuthDefaultUserName = "GCM_OAUTH_DEFAULT_USERNAME";
public const string GcmDevUseLegacyUiHelpers = "GCM_DEV_USELEGACYUIHELPERS";
public const string GcmGuiSoftwareRendering = "GCM_GUI_SOFTWARE_RENDERING";
}

public static class Http
Expand Down Expand Up @@ -160,6 +161,7 @@ public static class Credential
public const string UiHelper = "uiHelper";
public const string DevUseLegacyUiHelpers = "devUseLegacyUiHelpers";
public const string MsAuthUseDefaultAccount = "msauthUseDefaultAccount";
public const string GuiSoftwareRendering = "guiSoftwareRendering";

public const string OAuthAuthenticationModes = "oauthAuthModes";
public const string OAuthClientId = "oauthClientId";
Expand Down
16 changes: 16 additions & 0 deletions src/shared/Core/PlatformUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,22 @@ public static bool IsDevBox()
#endif
}

/// <summary>
/// Returns true if the current process is running on an ARM processor.
/// </summary>
/// <returns>True if ARM(v6,hf) or ARM64, false otherwise</returns>
public static bool IsArm()
{
switch (RuntimeInformation.OSArchitecture)
{
case Architecture.Arm:
case Architecture.Arm64:
return true;
default:
return false;
}
}

public static bool IsWindowsBrokerSupported()
{
if (!IsWindows())
Expand Down
21 changes: 21 additions & 0 deletions src/shared/Core/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,11 @@ public interface ISettings : IDisposable
/// </summary>
bool UseMsAuthDefaultAccount { get; }

/// <summary>
/// True if software rendering should be used for graphical user interfaces, false otherwise.
/// </summary>
bool UseSoftwareRendering { get; }

/// <summary>
/// Get TRACE2 settings.
/// </summary>
Expand Down Expand Up @@ -559,6 +564,22 @@ public bool IsInteractionAllowed
KnownGitCfg.Credential.Trace,
out value) && !value.IsFalsey();

public bool UseSoftwareRendering
{
get
{
// WORKAROUND: Some Windows ARM devices have a graphics driver issue that causes transparent windows
// when using hardware rendering. Until this is fixed, we will default to software rendering on these
// devices. Users can always override this setting back to HW-accelerated rendering if they wish.
bool defaultValue = PlatformUtils.IsWindows() && PlatformUtils.IsArm();

return TryGetSetting(KnownEnvars.GcmGuiSoftwareRendering,
KnownGitCfg.Credential.SectionName,
KnownGitCfg.Credential.GuiSoftwareRendering,
out string str) ? str.ToBooleanyOrDefault(defaultValue) : defaultValue;
}
}

public Trace2Settings GetTrace2Settings()
{
var settings = new Trace2Settings();
Expand Down
42 changes: 31 additions & 11 deletions src/shared/Core/UI/AvaloniaUi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Threading;
using GitCredentialManager.Interop.Windows.Native;
using GitCredentialManager.UI.Controls;
Expand All @@ -15,6 +14,24 @@ namespace GitCredentialManager.UI
public static class AvaloniaUi
{
private static bool _isAppStarted;
private static bool _win32SoftwareRendering;

/// <summary>
/// Configure the Avalonia application.
/// </summary>
/// <param name="win32SoftwareRendering">True to enable software rendering on Windows, false otherwise.</param>
/// <remarks>
/// This must be invoked before the Avalonia application loop has started.
/// </remarks>
public static void Initialize(bool win32SoftwareRendering)
{
if (_isAppStarted)
{
throw new InvalidOperationException("Setup must be called before the Avalonia application is started.");
}

_win32SoftwareRendering = win32SoftwareRendering;
}

public static Task ShowViewAsync(Func<Control> viewFunc, WindowViewModel viewModel, IntPtr parentHandle, CancellationToken ct) =>
ShowWindowAsync(() => new DialogWindow(viewFunc()), viewModel, parentHandle, ct);
Expand Down Expand Up @@ -46,22 +63,25 @@ public static Task ShowWindowAsync(Func<Window> windowFunc, object dataContext,
// This action only returns on our dispatcher shutdown.
Dispatcher.MainThread.Post(appCancelToken =>
{
AppBuilder.Configure<AvaloniaApp>()
var appBuilder = AppBuilder.Configure<AvaloniaApp>();

#if NETFRAMEWORK
// Set custom rendering options and modes if required
if (PlatformUtils.IsWindows() && _win32SoftwareRendering)
{
appBuilder.With(new Win32PlatformOptions
{ RenderingMode = new[] { Win32RenderingMode.Software } });
}
#endif

appBuilder
#if NETFRAMEWORK
.UseWin32()
.UseSkia()
#else
.UsePlatformDetect()
#endif
.LogToTrace()
// Workaround https://github.com/AvaloniaUI/Avalonia/issues/10296
// by always setting a application lifetime.
.SetupWithLifetime(
new ClassicDesktopStyleApplicationLifetime
{
ShutdownMode = ShutdownMode.OnExplicitShutdown
}
);
.LogToTrace();

appInitialized.Set();

Expand Down
2 changes: 2 additions & 0 deletions src/shared/TestInfrastructure/Objects/TestSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ ProxyConfiguration ISettings.GetProxyConfiguration()

bool ISettings.UseMsAuthDefaultAccount => UseMsAuthDefaultAccount;

bool ISettings.UseSoftwareRendering => false;

#endregion

#region IDisposable
Expand Down
Loading