| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848 |
- using Ryujinx.Common.Memory;
- using Ryujinx.Graphics.Gpu.Image;
- using Ryujinx.Graphics.Gpu.Memory;
- using Ryujinx.Graphics.GAL;
- using Ryujinx.Graphics.Gpu.Shader.DiskCache;
- using Ryujinx.Graphics.Shader;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Numerics;
- using System.Runtime.CompilerServices;
- using System.Runtime.InteropServices;
- namespace Ryujinx.Graphics.Gpu.Shader
- {
- class ShaderSpecializationState
- {
- private const uint ComsMagic = (byte)'C' | ((byte)'O' << 8) | ((byte)'M' << 16) | ((byte)'S' << 24);
- private const uint GfxsMagic = (byte)'G' | ((byte)'F' << 8) | ((byte)'X' << 16) | ((byte)'S' << 24);
- private const uint TfbdMagic = (byte)'T' | ((byte)'F' << 8) | ((byte)'B' << 16) | ((byte)'D' << 24);
- private const uint TexkMagic = (byte)'T' | ((byte)'E' << 8) | ((byte)'X' << 16) | ((byte)'K' << 24);
- private const uint TexsMagic = (byte)'T' | ((byte)'E' << 8) | ((byte)'X' << 16) | ((byte)'S' << 24);
- private const uint PgpsMagic = (byte)'P' | ((byte)'G' << 8) | ((byte)'P' << 16) | ((byte)'S' << 24);
- /// <summary>
- /// Flags indicating GPU state that is used by the shader.
- /// </summary>
- [Flags]
- private enum QueriedStateFlags
- {
- EarlyZForce = 1 << 0,
- PrimitiveTopology = 1 << 1,
- TessellationMode = 1 << 2,
- TransformFeedback = 1 << 3
- }
- private QueriedStateFlags _queriedState;
- private bool _compute;
- private byte _constantBufferUsePerStage;
- /// <summary>
- /// Compute engine state.
- /// </summary>
- public GpuChannelComputeState ComputeState;
- /// <summary>
- /// 3D engine state.
- /// </summary>
- public GpuChannelGraphicsState GraphicsState;
- /// <summary>
- /// Contant buffers bound at the time the shader was compiled, per stage.
- /// </summary>
- public Array5<uint> ConstantBufferUse;
- /// <summary>
- /// Pipeline state captured at the time of shader use.
- /// </summary>
- public ProgramPipelineState? PipelineState;
- /// <summary>
- /// Transform feedback buffers active at the time the shader was compiled.
- /// </summary>
- public TransformFeedbackDescriptor[] TransformFeedbackDescriptors;
- /// <summary>
- /// Flags indicating texture state that is used by the shader.
- /// </summary>
- [Flags]
- private enum QueriedTextureStateFlags
- {
- TextureFormat = 1 << 0,
- SamplerType = 1 << 1,
- CoordNormalized = 1 << 2
- }
- /// <summary>
- /// Reference type wrapping a value.
- /// </summary>
- private class Box<T>
- {
- /// <summary>
- /// Wrapped value.
- /// </summary>
- public T Value;
- }
- /// <summary>
- /// State of a texture or image that is accessed by the shader.
- /// </summary>
- private struct TextureSpecializationState
- {
- // New fields should be added to the end of the struct to keep disk shader cache compatibility.
- /// <summary>
- /// Flags indicating which state of the texture the shader depends on.
- /// </summary>
- public QueriedTextureStateFlags QueriedFlags;
- /// <summary>
- /// Encoded texture format value.
- /// </summary>
- public uint Format;
- /// <summary>
- /// True if the texture format is sRGB, false otherwise.
- /// </summary>
- public bool FormatSrgb;
- /// <summary>
- /// Texture target.
- /// </summary>
- public Image.TextureTarget TextureTarget;
- /// <summary>
- /// Indicates if the coordinates used to sample the texture are normalized or not (0.0..1.0 or 0..Width/Height).
- /// </summary>
- public bool CoordNormalized;
- }
- /// <summary>
- /// Texture binding information, used to identify each texture accessed by the shader.
- /// </summary>
- private struct TextureKey : IEquatable<TextureKey>
- {
- // New fields should be added to the end of the struct to keep disk shader cache compatibility.
- /// <summary>
- /// Shader stage where the texture is used.
- /// </summary>
- public readonly int StageIndex;
- /// <summary>
- /// Texture handle offset in words on the texture buffer.
- /// </summary>
- public readonly int Handle;
- /// <summary>
- /// Constant buffer slot of the texture buffer (-1 to use the texture buffer index GPU register).
- /// </summary>
- public readonly int CbufSlot;
- /// <summary>
- /// Creates a new texture key.
- /// </summary>
- /// <param name="stageIndex">Shader stage where the texture is used</param>
- /// <param name="handle">Texture handle offset in words on the texture buffer</param>
- /// <param name="cbufSlot">Constant buffer slot of the texture buffer (-1 to use the texture buffer index GPU register)</param>
- public TextureKey(int stageIndex, int handle, int cbufSlot)
- {
- StageIndex = stageIndex;
- Handle = handle;
- CbufSlot = cbufSlot;
- }
- public override bool Equals(object obj)
- {
- return obj is TextureKey textureKey && Equals(textureKey);
- }
- public bool Equals(TextureKey other)
- {
- return StageIndex == other.StageIndex && Handle == other.Handle && CbufSlot == other.CbufSlot;
- }
- public override int GetHashCode()
- {
- return HashCode.Combine(StageIndex, Handle, CbufSlot);
- }
- }
- private readonly Dictionary<TextureKey, Box<TextureSpecializationState>> _textureSpecialization;
- private KeyValuePair<TextureKey, Box<TextureSpecializationState>>[] _allTextures;
- private Box<TextureSpecializationState>[][] _textureByBinding;
- private Box<TextureSpecializationState>[][] _imageByBinding;
- /// <summary>
- /// Creates a new instance of the shader specialization state.
- /// </summary>
- private ShaderSpecializationState()
- {
- _textureSpecialization = new Dictionary<TextureKey, Box<TextureSpecializationState>>();
- }
- /// <summary>
- /// Creates a new instance of the shader specialization state.
- /// </summary>
- /// <param name="state">Current compute engine state</param>
- public ShaderSpecializationState(ref GpuChannelComputeState state) : this()
- {
- ComputeState = state;
- _compute = true;
- }
- /// <summary>
- /// Creates a new instance of the shader specialization state.
- /// </summary>
- /// <param name="state">Current 3D engine state</param>
- /// <param name="descriptors">Optional transform feedback buffers in use, if any</param>
- private ShaderSpecializationState(ref GpuChannelGraphicsState state, TransformFeedbackDescriptor[] descriptors) : this()
- {
- GraphicsState = state;
- _compute = false;
- if (descriptors != null)
- {
- TransformFeedbackDescriptors = descriptors;
- _queriedState |= QueriedStateFlags.TransformFeedback;
- }
- }
- /// <summary>
- /// Prepare the shader specialization state for quick binding lookups.
- /// </summary>
- /// <param name="stages">The shader stages</param>
- public void Prepare(CachedShaderStage[] stages)
- {
- _allTextures = _textureSpecialization.ToArray();
- _textureByBinding = new Box<TextureSpecializationState>[stages.Length][];
- _imageByBinding = new Box<TextureSpecializationState>[stages.Length][];
- for (int i = 0; i < stages.Length; i++)
- {
- CachedShaderStage stage = stages[i];
- if (stage?.Info != null)
- {
- var textures = stage.Info.Textures;
- var images = stage.Info.Images;
- var texBindings = new Box<TextureSpecializationState>[textures.Count];
- var imageBindings = new Box<TextureSpecializationState>[images.Count];
- int stageIndex = Math.Max(i - 1, 0); // Don't count VertexA for looking up spec state. No-Op for compute.
- for (int j = 0; j < textures.Count; j++)
- {
- var texture = textures[j];
- texBindings[j] = GetTextureSpecState(stageIndex, texture.HandleIndex, texture.CbufSlot);
- }
- for (int j = 0; j < images.Count; j++)
- {
- var image = images[j];
- imageBindings[j] = GetTextureSpecState(stageIndex, image.HandleIndex, image.CbufSlot);
- }
- _textureByBinding[i] = texBindings;
- _imageByBinding[i] = imageBindings;
- }
- }
- }
- /// <summary>
- /// Creates a new instance of the shader specialization state.
- /// </summary>
- /// <param name="state">Current 3D engine state</param>
- /// <param name="pipelineState">Current program pipeline state</param>
- /// <param name="descriptors">Optional transform feedback buffers in use, if any</param>
- public ShaderSpecializationState(
- ref GpuChannelGraphicsState state,
- ref ProgramPipelineState pipelineState,
- TransformFeedbackDescriptor[] descriptors) : this(ref state, descriptors)
- {
- PipelineState = pipelineState;
- }
- /// <summary>
- /// Creates a new instance of the shader specialization state.
- /// </summary>
- /// <param name="state">Current 3D engine state</param>
- /// <param name="pipelineState">Current program pipeline state</param>
- /// <param name="descriptors">Optional transform feedback buffers in use, if any</param>
- public ShaderSpecializationState(
- ref GpuChannelGraphicsState state,
- ProgramPipelineState? pipelineState,
- TransformFeedbackDescriptor[] descriptors) : this(ref state, descriptors)
- {
- PipelineState = pipelineState;
- }
- /// <summary>
- /// Indicates that the shader accesses the early Z force state.
- /// </summary>
- public void RecordEarlyZForce()
- {
- _queriedState |= QueriedStateFlags.EarlyZForce;
- }
- /// <summary>
- /// Indicates that the shader accesses the primitive topology state.
- /// </summary>
- public void RecordPrimitiveTopology()
- {
- _queriedState |= QueriedStateFlags.PrimitiveTopology;
- }
- /// <summary>
- /// Indicates that the shader accesses the tessellation mode state.
- /// </summary>
- public void RecordTessellationMode()
- {
- _queriedState |= QueriedStateFlags.TessellationMode;
- }
- /// <summary>
- /// Indicates that the shader accesses the constant buffer use state.
- /// </summary>
- /// <param name="stageIndex">Shader stage index</param>
- /// <param name="useMask">Mask indicating the constant buffers bound at the time of the shader compilation</param>
- public void RecordConstantBufferUse(int stageIndex, uint useMask)
- {
- ConstantBufferUse[stageIndex] = useMask;
- _constantBufferUsePerStage |= (byte)(1 << stageIndex);
- }
- /// <summary>
- /// Indicates that a given texture is accessed by the shader.
- /// </summary>
- /// <param name="stageIndex">Shader stage where the texture is used</param>
- /// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
- /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
- /// <param name="descriptor">Descriptor of the texture</param>
- public void RegisterTexture(int stageIndex, int handle, int cbufSlot, Image.TextureDescriptor descriptor)
- {
- Box<TextureSpecializationState> state = GetOrCreateTextureSpecState(stageIndex, handle, cbufSlot);
- state.Value.Format = descriptor.UnpackFormat();
- state.Value.FormatSrgb = descriptor.UnpackSrgb();
- state.Value.TextureTarget = descriptor.UnpackTextureTarget();
- state.Value.CoordNormalized = descriptor.UnpackTextureCoordNormalized();
- }
- /// <summary>
- /// Indicates that a given texture is accessed by the shader.
- /// </summary>
- /// <param name="stageIndex">Shader stage where the texture is used</param>
- /// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
- /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
- /// <param name="format">Maxwell texture format value</param>
- /// <param name="formatSrgb">Whenever the texture format is a sRGB format</param>
- /// <param name="target">Texture target type</param>
- /// <param name="coordNormalized">Whenever the texture coordinates used on the shader are considered normalized</param>
- public void RegisterTexture(
- int stageIndex,
- int handle,
- int cbufSlot,
- uint format,
- bool formatSrgb,
- Image.TextureTarget target,
- bool coordNormalized)
- {
- Box<TextureSpecializationState> state = GetOrCreateTextureSpecState(stageIndex, handle, cbufSlot);
- state.Value.Format = format;
- state.Value.FormatSrgb = formatSrgb;
- state.Value.TextureTarget = target;
- state.Value.CoordNormalized = coordNormalized;
- }
- /// <summary>
- /// Indicates that the format of a given texture was used during the shader translation process.
- /// </summary>
- /// <param name="stageIndex">Shader stage where the texture is used</param>
- /// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
- /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
- public void RecordTextureFormat(int stageIndex, int handle, int cbufSlot)
- {
- Box<TextureSpecializationState> state = GetOrCreateTextureSpecState(stageIndex, handle, cbufSlot);
- state.Value.QueriedFlags |= QueriedTextureStateFlags.TextureFormat;
- }
- /// <summary>
- /// Indicates that the target of a given texture was used during the shader translation process.
- /// </summary>
- /// <param name="stageIndex">Shader stage where the texture is used</param>
- /// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
- /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
- public void RecordTextureSamplerType(int stageIndex, int handle, int cbufSlot)
- {
- Box<TextureSpecializationState> state = GetOrCreateTextureSpecState(stageIndex, handle, cbufSlot);
- state.Value.QueriedFlags |= QueriedTextureStateFlags.SamplerType;
- }
- /// <summary>
- /// Indicates that the coordinate normalization state of a given texture was used during the shader translation process.
- /// </summary>
- /// <param name="stageIndex">Shader stage where the texture is used</param>
- /// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
- /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
- public void RecordTextureCoordNormalized(int stageIndex, int handle, int cbufSlot)
- {
- Box<TextureSpecializationState> state = GetOrCreateTextureSpecState(stageIndex, handle, cbufSlot);
- state.Value.QueriedFlags |= QueriedTextureStateFlags.CoordNormalized;
- }
- /// <summary>
- /// Checks if a given texture was registerd on this specialization state.
- /// </summary>
- /// <param name="stageIndex">Shader stage where the texture is used</param>
- /// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
- /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
- public bool TextureRegistered(int stageIndex, int handle, int cbufSlot)
- {
- return GetTextureSpecState(stageIndex, handle, cbufSlot) != null;
- }
- /// <summary>
- /// Gets the recorded format of a given texture.
- /// </summary>
- /// <param name="stageIndex">Shader stage where the texture is used</param>
- /// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
- /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
- public (uint, bool) GetFormat(int stageIndex, int handle, int cbufSlot)
- {
- TextureSpecializationState state = GetTextureSpecState(stageIndex, handle, cbufSlot).Value;
- return (state.Format, state.FormatSrgb);
- }
- /// <summary>
- /// Gets the recorded target of a given texture.
- /// </summary>
- /// <param name="stageIndex">Shader stage where the texture is used</param>
- /// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
- /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
- public Image.TextureTarget GetTextureTarget(int stageIndex, int handle, int cbufSlot)
- {
- return GetTextureSpecState(stageIndex, handle, cbufSlot).Value.TextureTarget;
- }
- /// <summary>
- /// Gets the recorded coordinate normalization state of a given texture.
- /// </summary>
- /// <param name="stageIndex">Shader stage where the texture is used</param>
- /// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
- /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
- public bool GetCoordNormalized(int stageIndex, int handle, int cbufSlot)
- {
- return GetTextureSpecState(stageIndex, handle, cbufSlot).Value.CoordNormalized;
- }
- /// <summary>
- /// Gets texture specialization state for a given texture, or create a new one if not present.
- /// </summary>
- /// <param name="stageIndex">Shader stage where the texture is used</param>
- /// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
- /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
- /// <returns>Texture specialization state</returns>
- private Box<TextureSpecializationState> GetOrCreateTextureSpecState(int stageIndex, int handle, int cbufSlot)
- {
- TextureKey key = new TextureKey(stageIndex, handle, cbufSlot);
- if (!_textureSpecialization.TryGetValue(key, out Box<TextureSpecializationState> state))
- {
- _textureSpecialization.Add(key, state = new Box<TextureSpecializationState>());
- }
- return state;
- }
- /// <summary>
- /// Gets texture specialization state for a given texture.
- /// </summary>
- /// <param name="stageIndex">Shader stage where the texture is used</param>
- /// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
- /// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
- /// <returns>Texture specialization state</returns>
- private Box<TextureSpecializationState> GetTextureSpecState(int stageIndex, int handle, int cbufSlot)
- {
- TextureKey key = new TextureKey(stageIndex, handle, cbufSlot);
- if (_textureSpecialization.TryGetValue(key, out Box<TextureSpecializationState> state))
- {
- return state;
- }
- return null;
- }
- /// <summary>
- /// Checks if the recorded state matches the current GPU 3D engine state.
- /// </summary>
- /// <param name="channel">GPU channel</param>
- /// <param name="poolState">Texture pool state</param>
- /// <param name="graphicsState">Graphics state</param>
- /// <param name="checkTextures">Indicates whether texture descriptors should be checked</param>
- /// <returns>True if the state matches, false otherwise</returns>
- public bool MatchesGraphics(GpuChannel channel, GpuChannelPoolState poolState, GpuChannelGraphicsState graphicsState, bool checkTextures)
- {
- if (graphicsState.ViewportTransformDisable != GraphicsState.ViewportTransformDisable)
- {
- return false;
- }
- bool thisA2cDitherEnable = GraphicsState.AlphaToCoverageEnable && GraphicsState.AlphaToCoverageDitherEnable;
- bool otherA2cDitherEnable = graphicsState.AlphaToCoverageEnable && graphicsState.AlphaToCoverageDitherEnable;
- if (otherA2cDitherEnable != thisA2cDitherEnable)
- {
- return false;
- }
- if (graphicsState.DepthMode != GraphicsState.DepthMode)
- {
- return false;
- }
- if (graphicsState.AlphaTestEnable != GraphicsState.AlphaTestEnable)
- {
- return false;
- }
- if (graphicsState.AlphaTestEnable &&
- (graphicsState.AlphaTestCompare != GraphicsState.AlphaTestCompare ||
- graphicsState.AlphaTestReference != GraphicsState.AlphaTestReference))
- {
- return false;
- }
- if (!graphicsState.AttributeTypes.AsSpan().SequenceEqual(GraphicsState.AttributeTypes.AsSpan()))
- {
- return false;
- }
- return Matches(channel, poolState, checkTextures, isCompute: false);
- }
- /// <summary>
- /// Checks if the recorded state matches the current GPU compute engine state.
- /// </summary>
- /// <param name="channel">GPU channel</param>
- /// <param name="poolState">Texture pool state</param>
- /// <param name="checkTextures">Indicates whether texture descriptors should be checked</param>
- /// <returns>True if the state matches, false otherwise</returns>
- public bool MatchesCompute(GpuChannel channel, GpuChannelPoolState poolState, bool checkTextures)
- {
- return Matches(channel, poolState, checkTextures, isCompute: true);
- }
- /// <summary>
- /// Fetch the constant buffers used for a texture to cache.
- /// </summary>
- /// <param name="channel">GPU channel</param>
- /// <param name="isCompute">Indicates whenever the check is requested by the 3D or compute engine</param>
- /// <param name="cachedTextureBufferIndex">The currently cached texture buffer index</param>
- /// <param name="cachedSamplerBufferIndex">The currently cached sampler buffer index</param>
- /// <param name="cachedTextureBuffer">The currently cached texture buffer data</param>
- /// <param name="cachedSamplerBuffer">The currently cached sampler buffer data</param>
- /// <param name="cachedStageIndex">The currently cached stage</param>
- /// <param name="textureBufferIndex">The new texture buffer index</param>
- /// <param name="samplerBufferIndex">The new sampler buffer index</param>
- /// <param name="stageIndex">Stage index of the constant buffer</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void UpdateCachedBuffer(
- GpuChannel channel,
- bool isCompute,
- scoped ref int cachedTextureBufferIndex,
- scoped ref int cachedSamplerBufferIndex,
- scoped ref ReadOnlySpan<int> cachedTextureBuffer,
- scoped ref ReadOnlySpan<int> cachedSamplerBuffer,
- scoped ref int cachedStageIndex,
- int textureBufferIndex,
- int samplerBufferIndex,
- int stageIndex)
- {
- bool stageChange = stageIndex != cachedStageIndex;
- if (stageChange || textureBufferIndex != cachedTextureBufferIndex)
- {
- ref BufferBounds bounds = ref channel.BufferManager.GetUniformBufferBounds(isCompute, stageIndex, textureBufferIndex);
- cachedTextureBuffer = MemoryMarshal.Cast<byte, int>(channel.MemoryManager.Physical.GetSpan(bounds.Address, (int)bounds.Size));
- cachedTextureBufferIndex = textureBufferIndex;
- if (samplerBufferIndex == textureBufferIndex)
- {
- cachedSamplerBuffer = cachedTextureBuffer;
- cachedSamplerBufferIndex = samplerBufferIndex;
- }
- }
- if (stageChange || samplerBufferIndex != cachedSamplerBufferIndex)
- {
- ref BufferBounds bounds = ref channel.BufferManager.GetUniformBufferBounds(isCompute, stageIndex, samplerBufferIndex);
- cachedSamplerBuffer = MemoryMarshal.Cast<byte, int>(channel.MemoryManager.Physical.GetSpan(bounds.Address, (int)bounds.Size));
- cachedSamplerBufferIndex = samplerBufferIndex;
- }
- cachedStageIndex = stageIndex;
- }
- /// <summary>
- /// Checks if the recorded state matches the current GPU state.
- /// </summary>
- /// <param name="channel">GPU channel</param>
- /// <param name="poolState">Texture pool state</param>
- /// <param name="checkTextures">Indicates whether texture descriptors should be checked</param>
- /// <param name="isCompute">Indicates whenever the check is requested by the 3D or compute engine</param>
- /// <returns>True if the state matches, false otherwise</returns>
- private bool Matches(GpuChannel channel, GpuChannelPoolState poolState, bool checkTextures, bool isCompute)
- {
- int constantBufferUsePerStageMask = _constantBufferUsePerStage;
- while (constantBufferUsePerStageMask != 0)
- {
- int index = BitOperations.TrailingZeroCount(constantBufferUsePerStageMask);
- uint useMask = isCompute
- ? channel.BufferManager.GetComputeUniformBufferUseMask()
- : channel.BufferManager.GetGraphicsUniformBufferUseMask(index);
- if (ConstantBufferUse[index] != useMask)
- {
- return false;
- }
- constantBufferUsePerStageMask &= ~(1 << index);
- }
- if (checkTextures)
- {
- TexturePool pool = channel.TextureManager.GetTexturePool(poolState.TexturePoolGpuVa, poolState.TexturePoolMaximumId);
- int cachedTextureBufferIndex = -1;
- int cachedSamplerBufferIndex = -1;
- int cachedStageIndex = -1;
- ReadOnlySpan<int> cachedTextureBuffer = Span<int>.Empty;
- ReadOnlySpan<int> cachedSamplerBuffer = Span<int>.Empty;
- foreach (var kv in _allTextures)
- {
- TextureKey textureKey = kv.Key;
- (int textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(textureKey.CbufSlot, poolState.TextureBufferIndex);
- UpdateCachedBuffer(channel,
- isCompute,
- ref cachedTextureBufferIndex,
- ref cachedSamplerBufferIndex,
- ref cachedTextureBuffer,
- ref cachedSamplerBuffer,
- ref cachedStageIndex,
- textureBufferIndex,
- samplerBufferIndex,
- textureKey.StageIndex);
- int packedId = TextureHandle.ReadPackedId(textureKey.Handle, cachedTextureBuffer, cachedSamplerBuffer);
- int textureId = TextureHandle.UnpackTextureId(packedId);
- if (pool.IsValidId(textureId))
- {
- ref readonly Image.TextureDescriptor descriptor = ref pool.GetDescriptorRef(textureId);
- if (!MatchesTexture(kv.Value, descriptor))
- {
- return false;
- }
- }
- }
- }
- return true;
- }
- /// <summary>
- /// Checks if the recorded texture state matches the given texture descriptor.
- /// </summary>
- /// <param name="specializationState">Texture specialization state</param>
- /// <param name="descriptor">Texture descriptor</param>
- /// <returns>True if the state matches, false otherwise</returns>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private bool MatchesTexture(Box<TextureSpecializationState> specializationState, in Image.TextureDescriptor descriptor)
- {
- if (specializationState != null)
- {
- if (specializationState.Value.QueriedFlags.HasFlag(QueriedTextureStateFlags.CoordNormalized) &&
- specializationState.Value.CoordNormalized != descriptor.UnpackTextureCoordNormalized())
- {
- return false;
- }
- }
- return true;
- }
- /// <summary>
- /// Checks if the recorded texture state for a given texture binding matches a texture descriptor.
- /// </summary>
- /// <param name="stage">The shader stage</param>
- /// <param name="index">The texture index</param>
- /// <param name="descriptor">Texture descriptor</param>
- /// <returns>True if the state matches, false otherwise</returns>
- public bool MatchesTexture(ShaderStage stage, int index, in Image.TextureDescriptor descriptor)
- {
- Box<TextureSpecializationState> specializationState = _textureByBinding[(int)stage][index];
- return MatchesTexture(specializationState, descriptor);
- }
- /// <summary>
- /// Checks if the recorded texture state for a given image binding matches a texture descriptor.
- /// </summary>
- /// <param name="stage">The shader stage</param>
- /// <param name="index">The texture index</param>
- /// <param name="descriptor">Texture descriptor</param>
- /// <returns>True if the state matches, false otherwise</returns>
- public bool MatchesImage(ShaderStage stage, int index, in Image.TextureDescriptor descriptor)
- {
- Box<TextureSpecializationState> specializationState = _imageByBinding[(int)stage][index];
- return MatchesTexture(specializationState, descriptor);
- }
- /// <summary>
- /// Reads shader specialization state that has been serialized.
- /// </summary>
- /// <param name="dataReader">Data reader</param>
- /// <returns>Shader specialization state</returns>
- public static ShaderSpecializationState Read(ref BinarySerializer dataReader)
- {
- ShaderSpecializationState specState = new ShaderSpecializationState();
- dataReader.Read(ref specState._queriedState);
- dataReader.Read(ref specState._compute);
- if (specState._compute)
- {
- dataReader.ReadWithMagicAndSize(ref specState.ComputeState, ComsMagic);
- }
- else
- {
- dataReader.ReadWithMagicAndSize(ref specState.GraphicsState, GfxsMagic);
- }
- dataReader.Read(ref specState._constantBufferUsePerStage);
- int constantBufferUsePerStageMask = specState._constantBufferUsePerStage;
- while (constantBufferUsePerStageMask != 0)
- {
- int index = BitOperations.TrailingZeroCount(constantBufferUsePerStageMask);
- dataReader.Read(ref specState.ConstantBufferUse[index]);
- constantBufferUsePerStageMask &= ~(1 << index);
- }
- bool hasPipelineState = false;
- dataReader.Read(ref hasPipelineState);
- if (hasPipelineState)
- {
- ProgramPipelineState pipelineState = default;
- dataReader.ReadWithMagicAndSize(ref pipelineState, PgpsMagic);
- specState.PipelineState = pipelineState;
- }
- if (specState._queriedState.HasFlag(QueriedStateFlags.TransformFeedback))
- {
- ushort tfCount = 0;
- dataReader.Read(ref tfCount);
- specState.TransformFeedbackDescriptors = new TransformFeedbackDescriptor[tfCount];
- for (int index = 0; index < tfCount; index++)
- {
- dataReader.ReadWithMagicAndSize(ref specState.TransformFeedbackDescriptors[index], TfbdMagic);
- }
- }
- ushort count = 0;
- dataReader.Read(ref count);
- for (int index = 0; index < count; index++)
- {
- TextureKey textureKey = default;
- Box<TextureSpecializationState> textureState = new Box<TextureSpecializationState>();
- dataReader.ReadWithMagicAndSize(ref textureKey, TexkMagic);
- dataReader.ReadWithMagicAndSize(ref textureState.Value, TexsMagic);
- specState._textureSpecialization[textureKey] = textureState;
- }
- return specState;
- }
- /// <summary>
- /// Serializes the shader specialization state.
- /// </summary>
- /// <param name="dataWriter">Data writer</param>
- public void Write(ref BinarySerializer dataWriter)
- {
- dataWriter.Write(ref _queriedState);
- dataWriter.Write(ref _compute);
- if (_compute)
- {
- dataWriter.WriteWithMagicAndSize(ref ComputeState, ComsMagic);
- }
- else
- {
- dataWriter.WriteWithMagicAndSize(ref GraphicsState, GfxsMagic);
- }
- dataWriter.Write(ref _constantBufferUsePerStage);
- int constantBufferUsePerStageMask = _constantBufferUsePerStage;
- while (constantBufferUsePerStageMask != 0)
- {
- int index = BitOperations.TrailingZeroCount(constantBufferUsePerStageMask);
- dataWriter.Write(ref ConstantBufferUse[index]);
- constantBufferUsePerStageMask &= ~(1 << index);
- }
- bool hasPipelineState = PipelineState.HasValue;
- dataWriter.Write(ref hasPipelineState);
- if (hasPipelineState)
- {
- ProgramPipelineState pipelineState = PipelineState.Value;
- dataWriter.WriteWithMagicAndSize(ref pipelineState, PgpsMagic);
- }
- if (_queriedState.HasFlag(QueriedStateFlags.TransformFeedback))
- {
- ushort tfCount = (ushort)TransformFeedbackDescriptors.Length;
- dataWriter.Write(ref tfCount);
- for (int index = 0; index < TransformFeedbackDescriptors.Length; index++)
- {
- dataWriter.WriteWithMagicAndSize(ref TransformFeedbackDescriptors[index], TfbdMagic);
- }
- }
- ushort count = (ushort)_textureSpecialization.Count;
- dataWriter.Write(ref count);
- foreach (var kv in _textureSpecialization)
- {
- var textureKey = kv.Key;
- var textureState = kv.Value;
- dataWriter.WriteWithMagicAndSize(ref textureKey, TexkMagic);
- dataWriter.WriteWithMagicAndSize(ref textureState.Value, TexsMagic);
- }
- }
- }
- }
|