Summary
When RiveCanvasRenderer.MatchCanvasResolution is set to true in the inspector, it silently fails to take effect at startup on URP. The render texture is allocated at the panel's logical rect size (e.g. 1920×1080) instead of canvas pixel size, then nearest-neighbor upscaled to the display because RTHandleSystem.Alloc defaults filterMode = FilterMode.Point. At 4K this produces visibly blocky / "8-bit" vector text and aliased diagonal strokes.
A side-by-side at 4K UHD (3840×2160), same scene, same settings, only difference is whether the workaround below is active. Left = bug, right = expected:
Environment
- rive-unity v0.4.2 (latest at time of filing)
- Unity 6000.3.5f2 with URP
- Windows 10/11, D3D11 (also reproduces on D3D12)
- Canvas: ScreenSpaceOverlay
- CanvasScaler: ScaleWithScreenSize, reference 1920×1080, match 0.5
Repro
- URP project with a Canvas (ScreenSpaceOverlay) + CanvasScaler (ScaleWithScreenSize, ref 1920×1080).
- On the same GameObject, add components in this declaration order:
RiveCanvasRenderer → CanvasRendererRawImage → RivePanel. Set MatchCanvasResolution = true.
- Add some
RiveWidgets with vector text.
- Run the game / enter Play mode at a screen resolution higher than the CanvasScaler reference (e.g. 4K display, or Game View set to 4K UHD).
Observed: Vector text and diagonals are heavily aliased / pixelated. Looks like nearest-neighbor upscale.
Expected: Text crisp because the RT should track display resolution.
Confirmation: Manually toggling MatchCanvasResolution off→on in the inspector at runtime fixes it for the rest of the session. Restarting brings the bug back.
Root cause
Component OnEnable order on the same GameObject follows declaration order. With RiveCanvasRenderer declared before RivePanel:
RiveCanvasRenderer.OnEnable (RiveCanvasRenderer.cs:84) calls AttachCanvasProviders(RivePanel).
AttachCanvasProviders early-exits at if (strategy == null) return; (RiveCanvasRenderer.cs:122) because the panel hasn't yet initialised its SimpleRenderTargetStrategy.
RivePanel.OnEnable (RivePanel.cs:367) runs immediately afterwards and calls InitializeDefaultRenderTargetStrategyIfNeeded (line 371), creating the strategy.
- By this point
AttachCanvasProviders has already returned. ExternalPixelSizeProvider is never set, so SimpleRenderTargetStrategy.RefreshRenderTexture falls through to new Vector2Int((int)panel.WidgetContainer.rect.width, (int)panel.WidgetContainer.rect.height) — the panel's logical canvas rect, not the display pixel size.
The result is allocated as an RTHandle via RTHandleSystem.Alloc(...) in UniversalRenderPipelineHandler.AllocateRenderTexture without specifying filterMode, so it inherits the system default FilterMode.Point. Sampling that undersized RT to the on-screen canvas at 4K is therefore nearest-neighbor — hence the visibly blocky output.
The reason "toggle in inspector" or "drop to 1080p then back to 4K" fixes it is that any property change forces AttachCanvasProviders to re-run, by which point the strategy is initialised.
Suggested fix
Any one of:
- Move
if (m_matchCanvasResolution) AttachCanvasProviders(RivePanel); from RiveCanvasRenderer.OnEnable to Start.
- Have
RivePanel eagerly initialise its strategy in Awake rather than OnEnable.
- Have
RivePanel raise an event when its strategy becomes non-null and have RiveCanvasRenderer re-attach there.
- As a defensive measure for the secondary symptom: pass
filterMode: FilterMode.Bilinear in the RTHandleSystem.Alloc call in UniversalRenderPipelineHandler.AllocateRenderTexture (UniversalRenderPipelineHandler.cs:234). The Built-In pipeline handler doesn't have this issue because new RenderTexture(descriptor) defaults to Bilinear, but URP inherits FilterMode.Point from the RTHandle default.
Workaround for users hitting this today
A small static class with a [RuntimeInitializeOnLoadMethod(AfterSceneLoad)] hook that finds every RiveCanvasRenderer and toggles MatchCanvasResolution false→true after scene load. Confirmed fix on our project at 4K, both in editor and in the standalone Steam build:
using Rive.Components;
using UnityEngine;
using UnityEngine.SceneManagement;
public static class RiveCanvasResolutionFix
{
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
private static void Install()
{
SceneManager.sceneLoaded += (scene, mode) => FixScene(scene);
for (int i = 0; i < SceneManager.sceneCount; i++)
FixScene(SceneManager.GetSceneAt(i));
}
private static void FixScene(UnityEngine.SceneManagement.Scene scene)
{
if (!scene.isLoaded) return;
foreach (var root in scene.GetRootGameObjects())
{
foreach (var renderer in root.GetComponentsInChildren<RiveCanvasRenderer>(true))
{
if (!renderer.MatchCanvasResolution) continue;
renderer.MatchCanvasResolution = false;
renderer.MatchCanvasResolution = true;
}
}
}
}
Happy to open a PR if helpful.
Summary
When
RiveCanvasRenderer.MatchCanvasResolutionis set totruein the inspector, it silently fails to take effect at startup on URP. The render texture is allocated at the panel's logical rect size (e.g. 1920×1080) instead of canvas pixel size, then nearest-neighbor upscaled to the display becauseRTHandleSystem.AllocdefaultsfilterMode = FilterMode.Point. At 4K this produces visibly blocky / "8-bit" vector text and aliased diagonal strokes.A side-by-side at 4K UHD (3840×2160), same scene, same settings, only difference is whether the workaround below is active. Left = bug, right = expected:
Environment
Repro
RiveCanvasRenderer→CanvasRendererRawImage→RivePanel. SetMatchCanvasResolution = true.RiveWidgets with vector text.Observed: Vector text and diagonals are heavily aliased / pixelated. Looks like nearest-neighbor upscale.
Expected: Text crisp because the RT should track display resolution.
Confirmation: Manually toggling
MatchCanvasResolutionoff→on in the inspector at runtime fixes it for the rest of the session. Restarting brings the bug back.Root cause
Component
OnEnableorder on the same GameObject follows declaration order. WithRiveCanvasRendererdeclared beforeRivePanel:RiveCanvasRenderer.OnEnable(RiveCanvasRenderer.cs:84) callsAttachCanvasProviders(RivePanel).AttachCanvasProvidersearly-exits atif (strategy == null) return;(RiveCanvasRenderer.cs:122) because the panel hasn't yet initialised itsSimpleRenderTargetStrategy.RivePanel.OnEnable(RivePanel.cs:367) runs immediately afterwards and callsInitializeDefaultRenderTargetStrategyIfNeeded(line 371), creating the strategy.AttachCanvasProvidershas already returned.ExternalPixelSizeProvideris never set, soSimpleRenderTargetStrategy.RefreshRenderTexturefalls through tonew Vector2Int((int)panel.WidgetContainer.rect.width, (int)panel.WidgetContainer.rect.height)— the panel's logical canvas rect, not the display pixel size.The result is allocated as an
RTHandleviaRTHandleSystem.Alloc(...)inUniversalRenderPipelineHandler.AllocateRenderTexturewithout specifyingfilterMode, so it inherits the system defaultFilterMode.Point. Sampling that undersized RT to the on-screen canvas at 4K is therefore nearest-neighbor — hence the visibly blocky output.The reason "toggle in inspector" or "drop to 1080p then back to 4K" fixes it is that any property change forces
AttachCanvasProvidersto re-run, by which point the strategy is initialised.Suggested fix
Any one of:
if (m_matchCanvasResolution) AttachCanvasProviders(RivePanel);fromRiveCanvasRenderer.OnEnabletoStart.RivePaneleagerly initialise its strategy inAwakerather thanOnEnable.RivePanelraise an event when its strategy becomes non-null and haveRiveCanvasRendererre-attach there.filterMode: FilterMode.Bilinearin theRTHandleSystem.Alloccall inUniversalRenderPipelineHandler.AllocateRenderTexture(UniversalRenderPipelineHandler.cs:234). The Built-In pipeline handler doesn't have this issue becausenew RenderTexture(descriptor)defaults toBilinear, but URP inheritsFilterMode.Pointfrom the RTHandle default.Workaround for users hitting this today
A small static class with a
[RuntimeInitializeOnLoadMethod(AfterSceneLoad)]hook that finds everyRiveCanvasRendererand togglesMatchCanvasResolutionfalse→true after scene load. Confirmed fix on our project at 4K, both in editor and in the standalone Steam build:Happy to open a PR if helpful.