Ryujinx/src/Ryujinx.Graphics.Gpu/Image/TextureManager.cs

592 lines
22 KiB
C#
Raw Normal View History

using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Engine.Types;
using Ryujinx.Graphics.Gpu.Shader;
2019-10-13 08:02:07 +02:00
using System;
namespace Ryujinx.Graphics.Gpu.Image
{
/// <summary>
/// Texture manager.
/// </summary>
2019-12-31 23:09:49 +01:00
class TextureManager : IDisposable
2019-10-13 08:02:07 +02:00
{
private readonly GpuContext _context;
private readonly GpuChannel _channel;
2019-10-13 08:02:07 +02:00
private readonly TextureBindingsManager _cpBindingsManager;
private readonly TextureBindingsManager _gpBindingsManager;
private readonly TextureBindingsArrayCache _bindingsArrayCache;
private readonly TexturePoolCache _texturePoolCache;
private readonly SamplerPoolCache _samplerPoolCache;
2019-10-13 08:02:07 +02:00
private readonly Texture[] _rtColors;
private readonly ITexture[] _rtHostColors;
private readonly bool[] _rtColorsBound;
private Texture _rtDepthStencil;
private ITexture _rtHostDs;
private bool _rtDsBound;
public int ClipRegionWidth { get; private set; }
public int ClipRegionHeight { get; private set; }
/// <summary>
/// The scaling factor applied to all currently bound render targets.
/// </summary>
public float RenderTargetScale { get; private set; } = 1f;
/// <summary>
/// Creates a new instance of the texture manager.
/// </summary>
/// <param name="context">GPU context that the texture manager belongs to</param>
/// <param name="channel">GPU channel that the texture manager belongs to</param>
public TextureManager(GpuContext context, GpuChannel channel)
2019-10-13 08:02:07 +02:00
{
_context = context;
_channel = channel;
2019-10-13 08:02:07 +02:00
[Ryujinx.Graphics.Gpu] Address dotnet-format issues (#5367) * dotnet format style --severity info Some changes were manually reverted. * dotnet format analyzers --serverity info Some changes have been minimally adapted. * Restore a few unused methods and variables * Silence dotnet format IDE0060 warnings * Silence dotnet format IDE0052 warnings * Address dotnet format CA1816 warnings * Address or silence dotnet format CA1069 warnings * Address or silence dotnet format CA2211 warnings * Address remaining dotnet format analyzer warnings * Address review comments * Address most dotnet format whitespace warnings * Apply dotnet format whitespace formatting A few of them have been manually reverted and the corresponding warning was silenced * Format if-blocks correctly * Run dotnet format whitespace after rebase * Run dotnet format style after rebase * Another rebase, another dotnet format run * Run dotnet format style after rebase * Run dotnet format after rebase and remove unused usings - analyzers - style - whitespace * Disable 'prefer switch expression' rule * Add comments to disabled warnings * Remove a few unused parameters * Replace MmeShadowScratch with Array256<uint> * Simplify properties and array initialization, Use const when possible, Remove trailing commas * Start working on disabled warnings * Fix and silence a few dotnet-format warnings again * Run dotnet format after rebase * Address IDE0251 warnings * Silence IDE0060 in .editorconfig * Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas" This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e. * dotnet format whitespace after rebase * First pass of dotnet format * Add unsafe dotnet format changes * Fix typos * Add trailing commas * Disable formatting for FormatTable * Address review feedback
2023-07-02 02:47:54 +02:00
TexturePoolCache texturePoolCache = new(context);
SamplerPoolCache samplerPoolCache = new(context);
_bindingsArrayCache = new TextureBindingsArrayCache(context, channel);
_cpBindingsManager = new TextureBindingsManager(context, channel, _bindingsArrayCache, texturePoolCache, samplerPoolCache, isCompute: true);
_gpBindingsManager = new TextureBindingsManager(context, channel, _bindingsArrayCache, texturePoolCache, samplerPoolCache, isCompute: false);
_texturePoolCache = texturePoolCache;
_samplerPoolCache = samplerPoolCache;
2019-10-13 08:02:07 +02:00
_rtColors = new Texture[Constants.TotalRenderTargets];
_rtHostColors = new ITexture[Constants.TotalRenderTargets];
_rtColorsBound = new bool[Constants.TotalRenderTargets];
}
2019-10-13 08:02:07 +02:00
/// <summary>
/// Sets the texture and image bindings for the compute pipeline.
/// </summary>
/// <param name="bindings">Bindings for the active shader</param>
public void SetComputeBindings(CachedShaderBindings bindings)
{
_cpBindingsManager.SetBindings(bindings);
2019-10-13 08:02:07 +02:00
}
/// <summary>
/// Sets the texture and image bindings for the graphics pipeline.
/// </summary>
/// <param name="bindings">Bindings for the active shader</param>
public void SetGraphicsBindings(CachedShaderBindings bindings)
2019-10-13 08:02:07 +02:00
{
_gpBindingsManager.SetBindings(bindings);
2019-10-13 08:02:07 +02:00
}
/// <summary>
/// Sets the texture constant buffer index on the compute pipeline.
/// </summary>
/// <param name="index">The texture constant buffer index</param>
public void SetComputeTextureBufferIndex(int index)
2019-10-13 08:02:07 +02:00
{
_cpBindingsManager.SetTextureBufferIndex(index);
}
2019-10-13 08:02:07 +02:00
/// <summary>
/// Sets the texture constant buffer index on the graphics pipeline.
/// </summary>
/// <param name="index">The texture constant buffer index</param>
public void SetGraphicsTextureBufferIndex(int index)
{
_gpBindingsManager.SetTextureBufferIndex(index);
}
2019-10-13 08:02:07 +02:00
/// <summary>
/// Sets the current sampler pool on the compute pipeline.
/// </summary>
/// <param name="gpuVa">The start GPU virtual address of the sampler pool</param>
/// <param name="maximumId">The maximum ID of the sampler pool</param>
2019-12-30 18:44:22 +01:00
/// <param name="samplerIndex">The indexing type of the sampler pool</param>
public void SetComputeSamplerPool(ulong gpuVa, int maximumId, SamplerIndex samplerIndex)
{
_cpBindingsManager.SetSamplerPool(gpuVa, maximumId, samplerIndex);
}
2019-10-13 08:02:07 +02:00
/// <summary>
/// Sets the current sampler pool on the graphics pipeline.
/// </summary>
/// <param name="gpuVa">The start GPU virtual address of the sampler pool</param>
/// <param name="maximumId">The maximum ID of the sampler pool</param>
2019-12-30 18:44:22 +01:00
/// <param name="samplerIndex">The indexing type of the sampler pool</param>
public void SetGraphicsSamplerPool(ulong gpuVa, int maximumId, SamplerIndex samplerIndex)
{
_gpBindingsManager.SetSamplerPool(gpuVa, maximumId, samplerIndex);
2019-10-13 08:02:07 +02:00
}
/// <summary>
/// Sets the current texture pool on the compute pipeline.
/// </summary>
/// <param name="gpuVa">The start GPU virtual address of the texture pool</param>
/// <param name="maximumId">The maximum ID of the texture pool</param>
public void SetComputeTexturePool(ulong gpuVa, int maximumId)
2019-10-13 08:02:07 +02:00
{
_cpBindingsManager.SetTexturePool(gpuVa, maximumId);
}
2019-10-13 08:02:07 +02:00
/// <summary>
/// Sets the current texture pool on the graphics pipeline.
/// </summary>
/// <param name="gpuVa">The start GPU virtual address of the texture pool</param>
/// <param name="maximumId">The maximum ID of the texture pool</param>
public void SetGraphicsTexturePool(ulong gpuVa, int maximumId)
{
_gpBindingsManager.SetTexturePool(gpuVa, maximumId);
2019-10-13 08:02:07 +02:00
}
/// <summary>
/// Check if a texture's scale must be updated to match the configured resolution scale.
/// </summary>
/// <param name="texture">The texture to check</param>
/// <returns>True if the scale needs updating, false if the scale is up to date</returns>
[Ryujinx.Graphics.Gpu] Address dotnet-format issues (#5367) * dotnet format style --severity info Some changes were manually reverted. * dotnet format analyzers --serverity info Some changes have been minimally adapted. * Restore a few unused methods and variables * Silence dotnet format IDE0060 warnings * Silence dotnet format IDE0052 warnings * Address dotnet format CA1816 warnings * Address or silence dotnet format CA1069 warnings * Address or silence dotnet format CA2211 warnings * Address remaining dotnet format analyzer warnings * Address review comments * Address most dotnet format whitespace warnings * Apply dotnet format whitespace formatting A few of them have been manually reverted and the corresponding warning was silenced * Format if-blocks correctly * Run dotnet format whitespace after rebase * Run dotnet format style after rebase * Another rebase, another dotnet format run * Run dotnet format style after rebase * Run dotnet format after rebase and remove unused usings - analyzers - style - whitespace * Disable 'prefer switch expression' rule * Add comments to disabled warnings * Remove a few unused parameters * Replace MmeShadowScratch with Array256<uint> * Simplify properties and array initialization, Use const when possible, Remove trailing commas * Start working on disabled warnings * Fix and silence a few dotnet-format warnings again * Run dotnet format after rebase * Address IDE0251 warnings * Silence IDE0060 in .editorconfig * Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas" This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e. * dotnet format whitespace after rebase * First pass of dotnet format * Add unsafe dotnet format changes * Fix typos * Add trailing commas * Disable formatting for FormatTable * Address review feedback
2023-07-02 02:47:54 +02:00
private static bool ScaleNeedsUpdated(Texture texture)
{
return texture != null && !(texture.ScaleMode == TextureScaleMode.Blacklisted || texture.ScaleMode == TextureScaleMode.Undesired) && texture.ScaleFactor != GraphicsConfig.ResScale;
}
/// <summary>
/// Sets the render target color buffer.
/// </summary>
/// <param name="index">The index of the color buffer to set (up to 8)</param>
/// <param name="color">The color buffer texture</param>
/// <returns>True if render target scale must be updated.</returns>
public bool SetRenderTargetColor(int index, Texture color)
2019-10-13 08:02:07 +02:00
{
bool hasValue = color != null;
bool changesScale = (hasValue != (_rtColors[index] != null)) || (hasValue && RenderTargetScale != color.ScaleFactor);
if (_rtColors[index] != color)
{
if (_rtColorsBound[index])
{
_rtColors[index]?.SignalModifying(false);
}
else
{
_rtColorsBound[index] = true;
}
if (color != null)
{
color.SynchronizeMemory();
color.SignalModifying(true);
}
_rtColors[index] = color;
}
return changesScale || ScaleNeedsUpdated(color);
}
/// <summary>
/// Sets the render target depth-stencil buffer.
/// </summary>
/// <param name="depthStencil">The depth-stencil buffer texture</param>
/// <returns>True if render target scale must be updated.</returns>
public bool SetRenderTargetDepthStencil(Texture depthStencil)
{
bool hasValue = depthStencil != null;
bool changesScale = (hasValue != (_rtDepthStencil != null)) || (hasValue && RenderTargetScale != depthStencil.ScaleFactor);
if (_rtDepthStencil != depthStencil)
{
if (_rtDsBound)
{
_rtDepthStencil?.SignalModifying(false);
}
else
{
_rtDsBound = true;
}
if (depthStencil != null)
{
depthStencil.SynchronizeMemory();
depthStencil.SignalModifying(true);
}
_rtDepthStencil = depthStencil;
}
return changesScale || ScaleNeedsUpdated(depthStencil);
}
/// <summary>
/// Sets the host clip region, which should be the intersection of all render target texture sizes.
/// </summary>
/// <param name="width">Width of the clip region, defined as the minimum width across all bound textures</param>
/// <param name="height">Height of the clip region, defined as the minimum height across all bound textures</param>
public void SetClipRegion(int width, int height)
{
ClipRegionWidth = width;
ClipRegionHeight = height;
}
/// <summary>
/// Gets the first available bound colour target, or the depth stencil target if not present.
/// </summary>
/// <returns>The first bound colour target, otherwise the depth stencil target</returns>
public Texture GetAnyRenderTarget()
{
return _rtColors[0] ?? _rtDepthStencil;
}
/// <summary>
/// Updates the Render Target scale, given the currently bound render targets.
/// This will update scale to match the configured scale, scale textures that are eligible but not scaled,
/// and propagate blacklisted status from one texture to the ones bound with it.
/// </summary>
/// <param name="singleUse">If this is not -1, it indicates that only the given indexed target will be used.</param>
public void UpdateRenderTargetScale(int singleUse)
{
// Make sure all scales for render targets are at the highest they should be. Blacklisted targets should propagate their scale to the other targets.
bool mismatch = false;
bool blacklisted = false;
bool hasUpscaled = false;
bool hasUndesired = false;
float targetScale = GraphicsConfig.ResScale;
void ConsiderTarget(Texture target)
{
[Ryujinx.Graphics.Gpu] Address dotnet-format issues (#5367) * dotnet format style --severity info Some changes were manually reverted. * dotnet format analyzers --serverity info Some changes have been minimally adapted. * Restore a few unused methods and variables * Silence dotnet format IDE0060 warnings * Silence dotnet format IDE0052 warnings * Address dotnet format CA1816 warnings * Address or silence dotnet format CA1069 warnings * Address or silence dotnet format CA2211 warnings * Address remaining dotnet format analyzer warnings * Address review comments * Address most dotnet format whitespace warnings * Apply dotnet format whitespace formatting A few of them have been manually reverted and the corresponding warning was silenced * Format if-blocks correctly * Run dotnet format whitespace after rebase * Run dotnet format style after rebase * Another rebase, another dotnet format run * Run dotnet format style after rebase * Run dotnet format after rebase and remove unused usings - analyzers - style - whitespace * Disable 'prefer switch expression' rule * Add comments to disabled warnings * Remove a few unused parameters * Replace MmeShadowScratch with Array256<uint> * Simplify properties and array initialization, Use const when possible, Remove trailing commas * Start working on disabled warnings * Fix and silence a few dotnet-format warnings again * Run dotnet format after rebase * Address IDE0251 warnings * Silence IDE0060 in .editorconfig * Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas" This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e. * dotnet format whitespace after rebase * First pass of dotnet format * Add unsafe dotnet format changes * Fix typos * Add trailing commas * Disable formatting for FormatTable * Address review feedback
2023-07-02 02:47:54 +02:00
if (target == null)
{
return;
}
float scale = target.ScaleFactor;
switch (target.ScaleMode)
{
case TextureScaleMode.Blacklisted:
mismatch |= scale != 1f;
blacklisted = true;
break;
case TextureScaleMode.Eligible:
mismatch = true; // We must make a decision.
break;
case TextureScaleMode.Undesired:
hasUndesired = true;
mismatch |= scale != 1f || hasUpscaled; // If another target is upscaled, scale this one up too.
break;
case TextureScaleMode.Scaled:
hasUpscaled = true;
mismatch |= hasUndesired || scale != targetScale; // If the target scale has changed, reset the scale for all targets.
break;
}
}
if (singleUse != -1)
{
// If only one target is in use (by a clear, for example) the others do not need to be checked for mismatching scale.
ConsiderTarget(_rtColors[singleUse]);
}
else
{
foreach (Texture color in _rtColors)
{
ConsiderTarget(color);
}
}
ConsiderTarget(_rtDepthStencil);
mismatch |= blacklisted && hasUpscaled;
if (blacklisted || (hasUndesired && !hasUpscaled))
{
targetScale = 1f;
}
if (mismatch)
{
if (blacklisted)
{
// Propagate the blacklisted state to the other textures.
foreach (Texture color in _rtColors)
{
color?.BlacklistScale();
}
_rtDepthStencil?.BlacklistScale();
}
else
{
// Set the scale of the other textures.
foreach (Texture color in _rtColors)
{
color?.SetScale(targetScale);
}
_rtDepthStencil?.SetScale(targetScale);
}
}
RenderTargetScale = targetScale;
2019-10-13 08:02:07 +02:00
}
/// <summary>
/// Gets a texture and a sampler from their respective pools from a texture ID and a sampler ID.
/// </summary>
/// <param name="textureId">ID of the texture</param>
/// <param name="samplerId">ID of the sampler</param>
public (Texture, Sampler) GetGraphicsTextureAndSampler(int textureId, int samplerId)
{
return _gpBindingsManager.GetTextureAndSampler(textureId, samplerId);
}
/// <summary>
/// Commits bindings on the compute pipeline.
/// </summary>
/// <param name="specState">Specialization state for the bound shader</param>
/// <returns>True if all bound textures match the current shader specialization state, false otherwise</returns>
public bool CommitComputeBindings(ShaderSpecializationState specState)
2019-10-13 08:02:07 +02:00
{
// Every time we switch between graphics and compute work,
// we must rebind everything.
// Since compute work happens less often, we always do that
// before and after the compute dispatch.
_texturePoolCache.Tick();
_samplerPoolCache.Tick();
_cpBindingsManager.Rebind();
bool result = _cpBindingsManager.CommitBindings(specState);
_gpBindingsManager.Rebind();
return result;
2019-10-13 08:02:07 +02:00
}
/// <summary>
/// Commits bindings on the graphics pipeline.
/// </summary>
/// <param name="specState">Specialization state for the bound shader</param>
GPU: Rebind RTs if scale changes when binding textures (#6493) This fixes a longstanding issue with resolution scale that could result in flickering graphics, typically the first frame something is drawn, or on camera cuts in cutscenes. The root cause of the issue is that texture scale can be changed when binding textures or images. This typically happens because a texture becomes a view of a larger texture, such as a 400x225 texture becoming a view of a 800x450 texture with two levels. If the 400x225 texture is bound as a render target and has state [1x Undesired], but the storage texture is [2x Scaled], the render target texture's scale is changed to [2x Scaled] to match its new storage. This means the scale changed after the render target state was processed... This can cause a number of issues. When render target state is processed, texture scales are examined and potentially changed so that they are all the same value. If one texture is scaled, all textures must be. If one texture is blacklisted from scaling, all of them must be. This results in a single resolution scale value being assigned to the TextureManager, which also scales the scissor and viewport values. If the scale is chosen as 1x, and a later texture binding changes one of the textures to be 2x, the scale in TextureManager no longer matches all of the bound textures. What's worse, the scales in these textures could mismatch entirely. This typically results in the support buffer scale, viewport and scissor being wrong for at least one of the bound render targets. This PR fixes the issue by re-evaluating render target state if any scale mismatches the expected scale after texture bindings happen. This can actually cause scale to change again, so it must loop back to perform texture bindings again. This can happen as many times as it needs to, but I don't expect it to happen more than once. Problematic bindings will just result in a blacklist, which will propagate to other bound targets.
2024-03-14 23:59:09 +01:00
/// <param name="scaleMismatch">True if there is a scale mismatch in the render targets, indicating they must be re-evaluated</param>
/// <returns>True if all bound textures match the current shader specialization state, false otherwise</returns>
GPU: Rebind RTs if scale changes when binding textures (#6493) This fixes a longstanding issue with resolution scale that could result in flickering graphics, typically the first frame something is drawn, or on camera cuts in cutscenes. The root cause of the issue is that texture scale can be changed when binding textures or images. This typically happens because a texture becomes a view of a larger texture, such as a 400x225 texture becoming a view of a 800x450 texture with two levels. If the 400x225 texture is bound as a render target and has state [1x Undesired], but the storage texture is [2x Scaled], the render target texture's scale is changed to [2x Scaled] to match its new storage. This means the scale changed after the render target state was processed... This can cause a number of issues. When render target state is processed, texture scales are examined and potentially changed so that they are all the same value. If one texture is scaled, all textures must be. If one texture is blacklisted from scaling, all of them must be. This results in a single resolution scale value being assigned to the TextureManager, which also scales the scissor and viewport values. If the scale is chosen as 1x, and a later texture binding changes one of the textures to be 2x, the scale in TextureManager no longer matches all of the bound textures. What's worse, the scales in these textures could mismatch entirely. This typically results in the support buffer scale, viewport and scissor being wrong for at least one of the bound render targets. This PR fixes the issue by re-evaluating render target state if any scale mismatches the expected scale after texture bindings happen. This can actually cause scale to change again, so it must loop back to perform texture bindings again. This can happen as many times as it needs to, but I don't expect it to happen more than once. Problematic bindings will just result in a blacklist, which will propagate to other bound targets.
2024-03-14 23:59:09 +01:00
public bool CommitGraphicsBindings(ShaderSpecializationState specState, out bool scaleMismatch)
2019-10-13 08:02:07 +02:00
{
_texturePoolCache.Tick();
_samplerPoolCache.Tick();
bool result = _gpBindingsManager.CommitBindings(specState);
2019-10-13 08:02:07 +02:00
GPU: Rebind RTs if scale changes when binding textures (#6493) This fixes a longstanding issue with resolution scale that could result in flickering graphics, typically the first frame something is drawn, or on camera cuts in cutscenes. The root cause of the issue is that texture scale can be changed when binding textures or images. This typically happens because a texture becomes a view of a larger texture, such as a 400x225 texture becoming a view of a 800x450 texture with two levels. If the 400x225 texture is bound as a render target and has state [1x Undesired], but the storage texture is [2x Scaled], the render target texture's scale is changed to [2x Scaled] to match its new storage. This means the scale changed after the render target state was processed... This can cause a number of issues. When render target state is processed, texture scales are examined and potentially changed so that they are all the same value. If one texture is scaled, all textures must be. If one texture is blacklisted from scaling, all of them must be. This results in a single resolution scale value being assigned to the TextureManager, which also scales the scissor and viewport values. If the scale is chosen as 1x, and a later texture binding changes one of the textures to be 2x, the scale in TextureManager no longer matches all of the bound textures. What's worse, the scales in these textures could mismatch entirely. This typically results in the support buffer scale, viewport and scissor being wrong for at least one of the bound render targets. This PR fixes the issue by re-evaluating render target state if any scale mismatches the expected scale after texture bindings happen. This can actually cause scale to change again, so it must loop back to perform texture bindings again. This can happen as many times as it needs to, but I don't expect it to happen more than once. Problematic bindings will just result in a blacklist, which will propagate to other bound targets.
2024-03-14 23:59:09 +01:00
scaleMismatch = UpdateRenderTargets();
return result;
}
/// <summary>
/// Returns a texture pool from the cache, with the given address and maximum id.
/// </summary>
/// <param name="poolGpuVa">GPU virtual address of the texture pool</param>
/// <param name="maximumId">Maximum ID of the texture pool</param>
/// <returns>The texture pool</returns>
public TexturePool GetTexturePool(ulong poolGpuVa, int maximumId)
{
ulong poolAddress = _channel.MemoryManager.Translate(poolGpuVa);
TexturePool texturePool = _texturePoolCache.FindOrCreate(_channel, poolAddress, maximumId, _bindingsArrayCache);
return texturePool;
2019-10-13 08:02:07 +02:00
}
/// <summary>
/// Gets a texture descriptor used on the compute pipeline.
/// </summary>
/// <param name="poolGpuVa">GPU virtual address of the texture pool</param>
/// <param name="bufferIndex">Index of the constant buffer with texture handles</param>
/// <param name="maximumId">Maximum ID of the texture pool</param>
/// <param name="handle">Shader "fake" handle of the texture</param>
/// <param name="cbufSlot">Shader constant buffer slot of the texture</param>
/// <returns>The texture descriptor</returns>
public TextureDescriptor GetComputeTextureDescriptor(ulong poolGpuVa, int bufferIndex, int maximumId, int handle, int cbufSlot)
{
return _cpBindingsManager.GetTextureDescriptor(poolGpuVa, bufferIndex, maximumId, 0, handle, cbufSlot);
}
/// <summary>
/// Gets a texture descriptor used on the graphics pipeline.
/// </summary>
/// <param name="poolGpuVa">GPU virtual address of the texture pool</param>
/// <param name="bufferIndex">Index of the constant buffer with texture handles</param>
/// <param name="maximumId">Maximum ID of the texture pool</param>
/// <param name="stageIndex">Index of the shader stage where the texture is bound</param>
/// <param name="handle">Shader "fake" handle of the texture</param>
/// <param name="cbufSlot">Shader constant buffer slot of the texture</param>
/// <returns>The texture descriptor</returns>
public TextureDescriptor GetGraphicsTextureDescriptor(
ulong poolGpuVa,
int bufferIndex,
int maximumId,
int stageIndex,
int handle,
int cbufSlot)
{
return _gpBindingsManager.GetTextureDescriptor(poolGpuVa, bufferIndex, maximumId, stageIndex, handle, cbufSlot);
}
/// <summary>
/// Update host framebuffer attachments based on currently bound render target buffers.
/// </summary>
GPU: Rebind RTs if scale changes when binding textures (#6493) This fixes a longstanding issue with resolution scale that could result in flickering graphics, typically the first frame something is drawn, or on camera cuts in cutscenes. The root cause of the issue is that texture scale can be changed when binding textures or images. This typically happens because a texture becomes a view of a larger texture, such as a 400x225 texture becoming a view of a 800x450 texture with two levels. If the 400x225 texture is bound as a render target and has state [1x Undesired], but the storage texture is [2x Scaled], the render target texture's scale is changed to [2x Scaled] to match its new storage. This means the scale changed after the render target state was processed... This can cause a number of issues. When render target state is processed, texture scales are examined and potentially changed so that they are all the same value. If one texture is scaled, all textures must be. If one texture is blacklisted from scaling, all of them must be. This results in a single resolution scale value being assigned to the TextureManager, which also scales the scissor and viewport values. If the scale is chosen as 1x, and a later texture binding changes one of the textures to be 2x, the scale in TextureManager no longer matches all of the bound textures. What's worse, the scales in these textures could mismatch entirely. This typically results in the support buffer scale, viewport and scissor being wrong for at least one of the bound render targets. This PR fixes the issue by re-evaluating render target state if any scale mismatches the expected scale after texture bindings happen. This can actually cause scale to change again, so it must loop back to perform texture bindings again. This can happen as many times as it needs to, but I don't expect it to happen more than once. Problematic bindings will just result in a blacklist, which will propagate to other bound targets.
2024-03-14 23:59:09 +01:00
/// <returns>True if there is a scale mismatch in the render targets, indicating they must be re-evaluated</returns>
public bool UpdateRenderTargets()
2019-10-13 08:02:07 +02:00
{
bool anyChanged = false;
GPU: Rebind RTs if scale changes when binding textures (#6493) This fixes a longstanding issue with resolution scale that could result in flickering graphics, typically the first frame something is drawn, or on camera cuts in cutscenes. The root cause of the issue is that texture scale can be changed when binding textures or images. This typically happens because a texture becomes a view of a larger texture, such as a 400x225 texture becoming a view of a 800x450 texture with two levels. If the 400x225 texture is bound as a render target and has state [1x Undesired], but the storage texture is [2x Scaled], the render target texture's scale is changed to [2x Scaled] to match its new storage. This means the scale changed after the render target state was processed... This can cause a number of issues. When render target state is processed, texture scales are examined and potentially changed so that they are all the same value. If one texture is scaled, all textures must be. If one texture is blacklisted from scaling, all of them must be. This results in a single resolution scale value being assigned to the TextureManager, which also scales the scissor and viewport values. If the scale is chosen as 1x, and a later texture binding changes one of the textures to be 2x, the scale in TextureManager no longer matches all of the bound textures. What's worse, the scales in these textures could mismatch entirely. This typically results in the support buffer scale, viewport and scissor being wrong for at least one of the bound render targets. This PR fixes the issue by re-evaluating render target state if any scale mismatches the expected scale after texture bindings happen. This can actually cause scale to change again, so it must loop back to perform texture bindings again. This can happen as many times as it needs to, but I don't expect it to happen more than once. Problematic bindings will just result in a blacklist, which will propagate to other bound targets.
2024-03-14 23:59:09 +01:00
float expectedScale = RenderTargetScale;
bool scaleMismatch = false;
2019-10-13 08:02:07 +02:00
Texture dsTexture = _rtDepthStencil;
ITexture hostDsTexture = null;
if (dsTexture != null)
2019-10-13 08:02:07 +02:00
{
hostDsTexture = dsTexture.HostTexture;
if (!_rtDsBound)
{
dsTexture.SignalModifying(true);
_rtDsBound = true;
}
}
2019-10-13 08:02:07 +02:00
if (_rtHostDs != hostDsTexture)
{
_rtHostDs = hostDsTexture;
2019-10-13 08:02:07 +02:00
anyChanged = true;
GPU: Rebind RTs if scale changes when binding textures (#6493) This fixes a longstanding issue with resolution scale that could result in flickering graphics, typically the first frame something is drawn, or on camera cuts in cutscenes. The root cause of the issue is that texture scale can be changed when binding textures or images. This typically happens because a texture becomes a view of a larger texture, such as a 400x225 texture becoming a view of a 800x450 texture with two levels. If the 400x225 texture is bound as a render target and has state [1x Undesired], but the storage texture is [2x Scaled], the render target texture's scale is changed to [2x Scaled] to match its new storage. This means the scale changed after the render target state was processed... This can cause a number of issues. When render target state is processed, texture scales are examined and potentially changed so that they are all the same value. If one texture is scaled, all textures must be. If one texture is blacklisted from scaling, all of them must be. This results in a single resolution scale value being assigned to the TextureManager, which also scales the scissor and viewport values. If the scale is chosen as 1x, and a later texture binding changes one of the textures to be 2x, the scale in TextureManager no longer matches all of the bound textures. What's worse, the scales in these textures could mismatch entirely. This typically results in the support buffer scale, viewport and scissor being wrong for at least one of the bound render targets. This PR fixes the issue by re-evaluating render target state if any scale mismatches the expected scale after texture bindings happen. This can actually cause scale to change again, so it must loop back to perform texture bindings again. This can happen as many times as it needs to, but I don't expect it to happen more than once. Problematic bindings will just result in a blacklist, which will propagate to other bound targets.
2024-03-14 23:59:09 +01:00
if (dsTexture != null && dsTexture.ScaleFactor != expectedScale)
{
scaleMismatch = true;
}
2019-10-13 08:02:07 +02:00
}
for (int index = 0; index < _rtColors.Length; index++)
2019-10-13 08:02:07 +02:00
{
Texture texture = _rtColors[index];
ITexture hostTexture = null;
if (texture != null)
{
hostTexture = texture.HostTexture;
if (!_rtColorsBound[index])
{
texture.SignalModifying(true);
_rtColorsBound[index] = true;
}
}
2019-10-13 08:02:07 +02:00
if (_rtHostColors[index] != hostTexture)
2019-10-13 08:02:07 +02:00
{
_rtHostColors[index] = hostTexture;
2019-10-13 08:02:07 +02:00
anyChanged = true;
GPU: Rebind RTs if scale changes when binding textures (#6493) This fixes a longstanding issue with resolution scale that could result in flickering graphics, typically the first frame something is drawn, or on camera cuts in cutscenes. The root cause of the issue is that texture scale can be changed when binding textures or images. This typically happens because a texture becomes a view of a larger texture, such as a 400x225 texture becoming a view of a 800x450 texture with two levels. If the 400x225 texture is bound as a render target and has state [1x Undesired], but the storage texture is [2x Scaled], the render target texture's scale is changed to [2x Scaled] to match its new storage. This means the scale changed after the render target state was processed... This can cause a number of issues. When render target state is processed, texture scales are examined and potentially changed so that they are all the same value. If one texture is scaled, all textures must be. If one texture is blacklisted from scaling, all of them must be. This results in a single resolution scale value being assigned to the TextureManager, which also scales the scissor and viewport values. If the scale is chosen as 1x, and a later texture binding changes one of the textures to be 2x, the scale in TextureManager no longer matches all of the bound textures. What's worse, the scales in these textures could mismatch entirely. This typically results in the support buffer scale, viewport and scissor being wrong for at least one of the bound render targets. This PR fixes the issue by re-evaluating render target state if any scale mismatches the expected scale after texture bindings happen. This can actually cause scale to change again, so it must loop back to perform texture bindings again. This can happen as many times as it needs to, but I don't expect it to happen more than once. Problematic bindings will just result in a blacklist, which will propagate to other bound targets.
2024-03-14 23:59:09 +01:00
if (texture != null && texture.ScaleFactor != expectedScale)
{
scaleMismatch = true;
}
2019-10-13 08:02:07 +02:00
}
}
2019-10-13 08:02:07 +02:00
if (anyChanged)
{
_context.Renderer.Pipeline.SetRenderTargets(_rtHostColors, _rtHostDs);
2019-10-13 08:02:07 +02:00
}
GPU: Rebind RTs if scale changes when binding textures (#6493) This fixes a longstanding issue with resolution scale that could result in flickering graphics, typically the first frame something is drawn, or on camera cuts in cutscenes. The root cause of the issue is that texture scale can be changed when binding textures or images. This typically happens because a texture becomes a view of a larger texture, such as a 400x225 texture becoming a view of a 800x450 texture with two levels. If the 400x225 texture is bound as a render target and has state [1x Undesired], but the storage texture is [2x Scaled], the render target texture's scale is changed to [2x Scaled] to match its new storage. This means the scale changed after the render target state was processed... This can cause a number of issues. When render target state is processed, texture scales are examined and potentially changed so that they are all the same value. If one texture is scaled, all textures must be. If one texture is blacklisted from scaling, all of them must be. This results in a single resolution scale value being assigned to the TextureManager, which also scales the scissor and viewport values. If the scale is chosen as 1x, and a later texture binding changes one of the textures to be 2x, the scale in TextureManager no longer matches all of the bound textures. What's worse, the scales in these textures could mismatch entirely. This typically results in the support buffer scale, viewport and scissor being wrong for at least one of the bound render targets. This PR fixes the issue by re-evaluating render target state if any scale mismatches the expected scale after texture bindings happen. This can actually cause scale to change again, so it must loop back to perform texture bindings again. This can happen as many times as it needs to, but I don't expect it to happen more than once. Problematic bindings will just result in a blacklist, which will propagate to other bound targets.
2024-03-14 23:59:09 +01:00
return scaleMismatch;
2019-10-13 08:02:07 +02:00
}
/// <summary>
/// Update host framebuffer attachments based on currently bound render target buffers.
/// </summary>
/// <remarks>
/// All color attachments will be unbound.
/// </remarks>
public void UpdateRenderTargetDepthStencil()
{
[Ryujinx.Graphics.Gpu] Address dotnet-format issues (#5367) * dotnet format style --severity info Some changes were manually reverted. * dotnet format analyzers --serverity info Some changes have been minimally adapted. * Restore a few unused methods and variables * Silence dotnet format IDE0060 warnings * Silence dotnet format IDE0052 warnings * Address dotnet format CA1816 warnings * Address or silence dotnet format CA1069 warnings * Address or silence dotnet format CA2211 warnings * Address remaining dotnet format analyzer warnings * Address review comments * Address most dotnet format whitespace warnings * Apply dotnet format whitespace formatting A few of them have been manually reverted and the corresponding warning was silenced * Format if-blocks correctly * Run dotnet format whitespace after rebase * Run dotnet format style after rebase * Another rebase, another dotnet format run * Run dotnet format style after rebase * Run dotnet format after rebase and remove unused usings - analyzers - style - whitespace * Disable 'prefer switch expression' rule * Add comments to disabled warnings * Remove a few unused parameters * Replace MmeShadowScratch with Array256<uint> * Simplify properties and array initialization, Use const when possible, Remove trailing commas * Start working on disabled warnings * Fix and silence a few dotnet-format warnings again * Run dotnet format after rebase * Address IDE0251 warnings * Silence IDE0060 in .editorconfig * Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas" This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e. * dotnet format whitespace after rebase * First pass of dotnet format * Add unsafe dotnet format changes * Fix typos * Add trailing commas * Disable formatting for FormatTable * Address review feedback
2023-07-02 02:47:54 +02:00
new Span<ITexture>(_rtHostColors).Clear();
_rtHostDs = _rtDepthStencil?.HostTexture;
_context.Renderer.Pipeline.SetRenderTargets(_rtHostColors, _rtHostDs);
}
/// <summary>
/// Marks all currently bound render target textures as modified, and also makes them be set as modified again on next use.
/// </summary>
public void RefreshModifiedTextures()
{
Texture dsTexture = _rtDepthStencil;
if (dsTexture != null && _rtDsBound)
{
dsTexture.SignalModifying(false);
_rtDsBound = false;
}
for (int index = 0; index < _rtColors.Length; index++)
{
Texture texture = _rtColors[index];
if (texture != null && _rtColorsBound[index])
{
texture.SignalModifying(false);
_rtColorsBound[index] = false;
}
}
}
/// <summary>
/// Forces the texture and sampler pools to be re-loaded from the cache on next use.
/// </summary>
public void ReloadPools()
{
_cpBindingsManager.ReloadPools();
_gpBindingsManager.ReloadPools();
}
/// <summary>
/// Forces all textures, samplers, images and render targets to be rebound the next time
/// CommitGraphicsBindings is called.
/// </summary>
public void Rebind()
2019-10-13 08:02:07 +02:00
{
_gpBindingsManager.Rebind();
2019-10-13 08:02:07 +02:00
for (int index = 0; index < _rtHostColors.Length; index++)
{
_rtHostColors[index] = null;
}
_rtHostDs = null;
2019-10-13 08:02:07 +02:00
}
/// <summary>
/// Disposes the texture manager.
2019-12-31 23:09:49 +01:00
/// It's an error to use the texture manager after disposal.
/// </summary>
public void Dispose()
{
// Textures are owned by the texture cache, so we shouldn't dispose the texture pool cache.
_samplerPoolCache.Dispose();
for (int i = 0; i < _rtColors.Length; i++)
{
if (_rtColorsBound[i])
{
_rtColors[i]?.DecrementReferenceCount();
}
_rtColors[i] = null;
2019-12-31 23:09:49 +01:00
}
if (_rtDsBound)
{
_rtDepthStencil?.DecrementReferenceCount();
}
_rtDepthStencil = null;
2019-12-31 23:09:49 +01:00
}
2019-10-13 08:02:07 +02:00
}
}