diff --git a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
index f15f8885..91cadde3 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
@@ -35,7 +35,7 @@ namespace Ryujinx.Graphics.Gpu.Image
private readonly TextureBindingInfo[][] _textureBindings;
private readonly TextureBindingInfo[][] _imageBindings;
- private struct TextureStatePerStage
+ private struct TextureState
{
public ITexture Texture;
public ISampler Sampler;
@@ -45,10 +45,12 @@ namespace Ryujinx.Graphics.Gpu.Image
public int InvalidatedSequence;
public Texture CachedTexture;
public Sampler CachedSampler;
+ public int ScaleIndex;
+ public TextureUsageFlags UsageFlags;
}
- private TextureStatePerStage[] _textureState;
- private TextureStatePerStage[] _imageState;
+ private TextureState[] _textureState;
+ private TextureState[] _imageState;
private int[] _textureBindingsCount;
private int[] _imageBindingsCount;
@@ -83,8 +85,8 @@ namespace Ryujinx.Graphics.Gpu.Image
_textureBindings = new TextureBindingInfo[stages][];
_imageBindings = new TextureBindingInfo[stages][];
- _textureState = new TextureStatePerStage[InitialTextureStateSize];
- _imageState = new TextureStatePerStage[InitialImageStateSize];
+ _textureState = new TextureState[InitialTextureStateSize];
+ _imageState = new TextureState[InitialImageStateSize];
_textureBindingsCount = new int[stages];
_imageBindingsCount = new int[stages];
@@ -230,18 +232,18 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Updates the texture scale for a given texture or image.
///
/// Start GPU virtual address of the pool
- /// The related texture binding
+ /// The related texture usage flags
/// The texture/image binding index
/// The active shader stage
/// True if the given texture has become blacklisted, indicating that its host texture may have changed.
- private bool UpdateScale(Texture texture, TextureBindingInfo binding, int index, ShaderStage stage)
+ private bool UpdateScale(Texture texture, TextureUsageFlags usageFlags, int index, ShaderStage stage)
{
float result = 1f;
bool changed = false;
- if ((binding.Flags & TextureUsageFlags.NeedsScaleValue) != 0 && texture != null)
+ if ((usageFlags & TextureUsageFlags.NeedsScaleValue) != 0 && texture != null)
{
- if ((binding.Flags & TextureUsageFlags.ResScaleUnsupported) != 0)
+ if ((usageFlags & TextureUsageFlags.ResScaleUnsupported) != 0)
{
changed = texture.ScaleMode != TextureScaleMode.Blacklisted;
texture.BlacklistScale();
@@ -469,6 +471,7 @@ namespace Ryujinx.Graphics.Gpu.Image
for (int index = 0; index < textureCount; index++)
{
TextureBindingInfo bindingInfo = _textureBindings[stageIndex][index];
+ TextureUsageFlags usageFlags = bindingInfo.Flags;
(int textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(bindingInfo.CbufSlot, _textureBufferIndex);
@@ -487,7 +490,7 @@ namespace Ryujinx.Graphics.Gpu.Image
samplerId = TextureHandle.UnpackSamplerId(packedId);
}
- ref TextureStatePerStage state = ref _textureState[bindingInfo.Binding];
+ ref TextureState state = ref _textureState[bindingInfo.Binding];
if (!poolModified &&
state.TextureHandle == textureId &&
@@ -499,6 +502,18 @@ namespace Ryujinx.Graphics.Gpu.Image
// The texture is already bound.
state.CachedTexture.SynchronizeMemory();
+ if ((state.ScaleIndex != index || state.UsageFlags != usageFlags) &&
+ UpdateScale(state.CachedTexture, usageFlags, index, stage))
+ {
+ ITexture hostTextureRebind = state.CachedTexture.GetTargetTexture(bindingInfo.Target);
+
+ state.Texture = hostTextureRebind;
+ state.ScaleIndex = index;
+ state.UsageFlags = usageFlags;
+
+ _context.Renderer.Pipeline.SetTexture(bindingInfo.Binding, hostTextureRebind);
+ }
+
continue;
}
@@ -522,12 +537,14 @@ namespace Ryujinx.Graphics.Gpu.Image
{
if (state.Texture != hostTexture)
{
- if (UpdateScale(texture, bindingInfo, index, stage))
+ if (UpdateScale(texture, usageFlags, index, stage))
{
hostTexture = texture?.GetTargetTexture(bindingInfo.Target);
}
state.Texture = hostTexture;
+ state.ScaleIndex = index;
+ state.UsageFlags = usageFlags;
_context.Renderer.Pipeline.SetTexture(bindingInfo.Binding, hostTexture);
}
@@ -589,6 +606,8 @@ namespace Ryujinx.Graphics.Gpu.Image
for (int index = 0; index < imageCount; index++)
{
TextureBindingInfo bindingInfo = _imageBindings[stageIndex][index];
+ TextureUsageFlags usageFlags = bindingInfo.Flags;
+ int scaleIndex = baseScaleIndex + index;
(int textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(bindingInfo.CbufSlot, _textureBufferIndex);
@@ -597,7 +616,7 @@ namespace Ryujinx.Graphics.Gpu.Image
int packedId = TextureHandle.ReadPackedId(bindingInfo.Handle, cachedTextureBuffer, cachedSamplerBuffer);
int textureId = TextureHandle.UnpackTextureId(packedId);
- ref TextureStatePerStage state = ref _imageState[bindingInfo.Binding];
+ ref TextureState state = ref _imageState[bindingInfo.Binding];
bool isStore = bindingInfo.Flags.HasFlag(TextureUsageFlags.ImageStore);
@@ -606,12 +625,28 @@ namespace Ryujinx.Graphics.Gpu.Image
state.CachedTexture != null &&
state.CachedTexture.InvalidatedSequence == state.InvalidatedSequence)
{
+ Texture cachedTexture = state.CachedTexture;
+
// The texture is already bound.
- state.CachedTexture.SynchronizeMemory();
+ cachedTexture.SynchronizeMemory();
if (isStore)
{
- state.CachedTexture?.SignalModified();
+ cachedTexture?.SignalModified();
+ }
+
+ if ((state.ScaleIndex != index || state.UsageFlags != usageFlags) &&
+ UpdateScale(state.CachedTexture, usageFlags, scaleIndex, stage))
+ {
+ ITexture hostTextureRebind = state.CachedTexture.GetTargetTexture(bindingInfo.Target);
+
+ Format format = bindingInfo.Format == 0 ? cachedTexture.Format : bindingInfo.Format;
+
+ state.Texture = hostTextureRebind;
+ state.ScaleIndex = scaleIndex;
+ state.UsageFlags = usageFlags;
+
+ _context.Renderer.Pipeline.SetImage(bindingInfo.Binding, hostTextureRebind, format);
}
continue;
@@ -649,12 +684,14 @@ namespace Ryujinx.Graphics.Gpu.Image
if (state.Texture != hostTexture)
{
- if (UpdateScale(texture, bindingInfo, baseScaleIndex + index, stage))
+ if (UpdateScale(texture, usageFlags, scaleIndex, stage))
{
hostTexture = texture?.GetTargetTexture(bindingInfo.Target);
}
state.Texture = hostTexture;
+ state.ScaleIndex = scaleIndex;
+ state.UsageFlags = usageFlags;
Format format = bindingInfo.Format;