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;