mirror of
https://git.naxdy.org/Mirror/Ryujinx.git
synced 2025-01-12 21:59:12 +00:00
Minor fixes, reduce amount of bindless updates, initialize table, new bindless indexed modes, etc
This commit is contained in:
parent
53440e2e21
commit
dd9134f5f5
19 changed files with 443 additions and 80 deletions
|
@ -85,6 +85,11 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const int DriverReservedUniformBuffer = 0;
|
public const int DriverReservedUniformBuffer = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Number of the uniform buffer reserved by the driver to store texture binding handles.
|
||||||
|
/// </summary>
|
||||||
|
public const int DriverReserveTextureBindingsBuffer = 2;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Maximum size that an storage buffer is assumed to have when the correct size is unknown.
|
/// Maximum size that an storage buffer is assumed to have when the correct size is unknown.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -87,14 +87,22 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// Sets a bit to 0.
|
/// Sets a bit to 0.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="bit">Index of the bit</param>
|
/// <param name="bit">Index of the bit</param>
|
||||||
public void Clear(int bit)
|
/// <returns>True if the bit was set, false otherwise</returns>
|
||||||
|
public bool Clear(int bit)
|
||||||
{
|
{
|
||||||
int wordIndex = bit / IntSize;
|
int wordIndex = bit / IntSize;
|
||||||
int wordBit = bit & IntMask;
|
int wordBit = bit & IntMask;
|
||||||
|
|
||||||
ulong wordMask = 1UL << wordBit;
|
ulong wordMask = 1UL << wordBit;
|
||||||
|
|
||||||
|
if ((_masks[wordIndex] & wordMask) == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
_masks[wordIndex] &= ~wordMask;
|
_masks[wordIndex] &= ~wordMask;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -214,6 +214,8 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// <param name="endAddress">End address of the region of the pool that has been modified, exclusive</param>
|
/// <param name="endAddress">End address of the region of the pool that has been modified, exclusive</param>
|
||||||
protected void UpdateModifiedEntries(ulong address, ulong endAddress)
|
protected void UpdateModifiedEntries(ulong address, ulong endAddress)
|
||||||
{
|
{
|
||||||
|
// TODO: Remove this method (it's unused now).
|
||||||
|
|
||||||
int startId = (int)((address - Address) / DescriptorSize);
|
int startId = (int)((address - Address) / DescriptorSize);
|
||||||
int endId = (int)((endAddress - Address + (DescriptorSize - 1)) / DescriptorSize) - 1;
|
int endId = (int)((endAddress - Address + (DescriptorSize - 1)) / DescriptorSize) - 1;
|
||||||
|
|
||||||
|
@ -228,6 +230,18 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
_maximumAccessedId = Math.Max(_maximumAccessedId, endId);
|
_maximumAccessedId = Math.Max(_maximumAccessedId, endId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates a entry that has been modified.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">Pool entry index</param>
|
||||||
|
protected void UpdateModifiedEntry(int id)
|
||||||
|
{
|
||||||
|
ModifiedEntries.Set(id);
|
||||||
|
|
||||||
|
_minimumAccessedId = Math.Min(_minimumAccessedId, id);
|
||||||
|
_maximumAccessedId = Math.Max(_maximumAccessedId, id);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Forces all entries as modified, to be updated if any shader uses bindless textures.
|
/// Forces all entries as modified, to be updated if any shader uses bindless textures.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -146,6 +146,29 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sampler with the specified ID, and return true or false depending on the sampler entry being modified or not since the last call.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">ID of the texture</param>
|
||||||
|
/// <param name="sampler">Sampler with the specified ID</param>
|
||||||
|
/// <returns>True if the sampler entry was modified since the last call, false otherwise</returns>
|
||||||
|
public bool TryGetBindlessSampler(int id, out Sampler sampler)
|
||||||
|
{
|
||||||
|
if ((uint)id < Items.Length)
|
||||||
|
{
|
||||||
|
if (ModifiedEntries.Clear(id))
|
||||||
|
{
|
||||||
|
sampler = Items[id] ?? GetValidated(id);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sampler = null;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the sampler at the given <paramref name="id"/> from the cache,
|
/// Gets the sampler at the given <paramref name="id"/> from the cache,
|
||||||
/// or creates a new one if not found.
|
/// or creates a new one if not found.
|
||||||
|
@ -174,8 +197,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
{
|
{
|
||||||
ulong endAddress = address + size;
|
ulong endAddress = address + size;
|
||||||
|
|
||||||
UpdateModifiedEntries(address, endAddress);
|
|
||||||
|
|
||||||
for (; address < endAddress; address += DescriptorSize)
|
for (; address < endAddress; address += DescriptorSize)
|
||||||
{
|
{
|
||||||
int id = (int)((address - Address) / DescriptorSize);
|
int id = (int)((address - Address) / DescriptorSize);
|
||||||
|
@ -192,10 +213,16 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateModifiedEntry(id);
|
||||||
|
|
||||||
sampler.Dispose();
|
sampler.Dispose();
|
||||||
|
|
||||||
Items[id] = null;
|
Items[id] = null;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdateModifiedEntry(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ using Ryujinx.Graphics.Gpu.Memory;
|
||||||
using Ryujinx.Graphics.Gpu.Shader;
|
using Ryujinx.Graphics.Gpu.Shader;
|
||||||
using Ryujinx.Graphics.Shader;
|
using Ryujinx.Graphics.Shader;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Numerics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
@ -61,6 +61,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
private int _samplerPoolSequence;
|
private int _samplerPoolSequence;
|
||||||
|
|
||||||
private BindlessTextureFlags[] _bindlessTextureFlags;
|
private BindlessTextureFlags[] _bindlessTextureFlags;
|
||||||
|
private uint[] _bindlessIndexedBuffersMask;
|
||||||
|
|
||||||
private int _textureBufferIndex;
|
private int _textureBufferIndex;
|
||||||
|
|
||||||
|
@ -97,6 +98,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
_imageState = new TextureState[InitialImageStateSize];
|
_imageState = new TextureState[InitialImageStateSize];
|
||||||
|
|
||||||
_bindlessTextureFlags = new BindlessTextureFlags[stages];
|
_bindlessTextureFlags = new BindlessTextureFlags[stages];
|
||||||
|
_bindlessIndexedBuffersMask = new uint[stages];
|
||||||
|
|
||||||
for (int stage = 0; stage < stages; stage++)
|
for (int stage = 0; stage < stages; stage++)
|
||||||
{
|
{
|
||||||
|
@ -115,6 +117,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
_imageBindings = bindings.ImageBindings;
|
_imageBindings = bindings.ImageBindings;
|
||||||
|
|
||||||
_bindlessTextureFlags = bindings.BindlessTextureFlags;
|
_bindlessTextureFlags = bindings.BindlessTextureFlags;
|
||||||
|
_bindlessIndexedBuffersMask = bindings.BindlessIndexedBuffersMask;
|
||||||
|
|
||||||
SetMaxBindings(bindings.MaxTextureBinding, bindings.MaxImageBinding);
|
SetMaxBindings(bindings.MaxTextureBinding, bindings.MaxImageBinding);
|
||||||
}
|
}
|
||||||
|
@ -366,14 +369,14 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
specStateMatches &= CommitTextureBindings(texturePool, samplerPool, ShaderStage.Compute, 0, poolModified, specState);
|
specStateMatches &= CommitTextureBindings(texturePool, samplerPool, ShaderStage.Compute, 0, poolModified, specState);
|
||||||
specStateMatches &= CommitImageBindings(texturePool, ShaderStage.Compute, 0, poolModified, specState);
|
specStateMatches &= CommitImageBindings(texturePool, ShaderStage.Compute, 0, poolModified, specState);
|
||||||
|
|
||||||
if (_bindlessTextureFlags[0].HasFlag(BindlessTextureFlags.BindlessNvn))
|
if (_bindlessTextureFlags[0].HasFlag(BindlessTextureFlags.BindlessFull))
|
||||||
{
|
|
||||||
CommitBindlessResources(texturePool, ShaderStage.Compute, 0);
|
|
||||||
}
|
|
||||||
else if (_bindlessTextureFlags[0].HasFlag(BindlessTextureFlags.BindlessFull))
|
|
||||||
{
|
{
|
||||||
texturePool.LoadAll(_context.Renderer, _samplerPool);
|
texturePool.LoadAll(_context.Renderer, _samplerPool);
|
||||||
}
|
}
|
||||||
|
else if ((_bindlessTextureFlags[0] & BindlessTextureFlags.BindlessNvnAny) != 0)
|
||||||
|
{
|
||||||
|
CommitBindlessResources(texturePool, ShaderStage.Compute, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -384,14 +387,14 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
specStateMatches &= CommitTextureBindings(texturePool, samplerPool, stage, stageIndex, poolModified, specState);
|
specStateMatches &= CommitTextureBindings(texturePool, samplerPool, stage, stageIndex, poolModified, specState);
|
||||||
specStateMatches &= CommitImageBindings(texturePool, stage, stageIndex, poolModified, specState);
|
specStateMatches &= CommitImageBindings(texturePool, stage, stageIndex, poolModified, specState);
|
||||||
|
|
||||||
if (_bindlessTextureFlags[stageIndex].HasFlag(BindlessTextureFlags.BindlessNvn))
|
if (_bindlessTextureFlags[stageIndex].HasFlag(BindlessTextureFlags.BindlessFull))
|
||||||
{
|
|
||||||
CommitBindlessResources(texturePool, stage, stageIndex);
|
|
||||||
}
|
|
||||||
else if (_bindlessTextureFlags[stageIndex].HasFlag(BindlessTextureFlags.BindlessFull))
|
|
||||||
{
|
{
|
||||||
texturePool.LoadAll(_context.Renderer, _samplerPool);
|
texturePool.LoadAll(_context.Renderer, _samplerPool);
|
||||||
}
|
}
|
||||||
|
else if ((_bindlessTextureFlags[stageIndex] & BindlessTextureFlags.BindlessNvnAny) != 0)
|
||||||
|
{
|
||||||
|
CommitBindlessResources(texturePool, stage, stageIndex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -783,11 +786,89 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int index = 0; index < 32; index++)
|
BindlessTextureFlags flags = _bindlessTextureFlags[stageIndex];
|
||||||
{
|
uint buffersMask = _bindlessIndexedBuffersMask[stageIndex];
|
||||||
int wordOffset = 8 + index * 2;
|
|
||||||
|
|
||||||
int packedId = ReadConstantBuffer<int>(stageIndex, _textureBufferIndex, wordOffset);
|
while (buffersMask != 0)
|
||||||
|
{
|
||||||
|
int bufferIndex = BitOperations.TrailingZeroCount(buffersMask);
|
||||||
|
|
||||||
|
buffersMask &= ~(1u << bufferIndex);
|
||||||
|
|
||||||
|
if (bufferIndex == Constants.DriverReserveTextureBindingsBuffer)
|
||||||
|
{
|
||||||
|
if (flags.HasFlag(BindlessTextureFlags.BindlessNvnCombined))
|
||||||
|
{
|
||||||
|
CommitBindlessResourcesNvnCombined(pool, stageIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags.HasFlag(BindlessTextureFlags.BindlessNvnSeparateTexture))
|
||||||
|
{
|
||||||
|
CommitBindlessResourcesNvnSeparateTexture(pool, stageIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags.HasFlag(BindlessTextureFlags.BindlessNvnSeparateSampler))
|
||||||
|
{
|
||||||
|
CommitBindlessResourcesNvnSeparateSampler(pool, stageIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ulong size = _isCompute
|
||||||
|
? _channel.BufferManager.GetComputeUniformBufferSize(bufferIndex)
|
||||||
|
: _channel.BufferManager.GetGraphicsUniformBufferSize(stageIndex, bufferIndex);
|
||||||
|
|
||||||
|
ReadOnlySpan<int> cbData = GetConstantBufferRange<int>(stageIndex, bufferIndex, 0, (int)(size / sizeof(int)));
|
||||||
|
|
||||||
|
for (int index = 0; index < cbData.Length; index += 2)
|
||||||
|
{
|
||||||
|
int packedId = cbData[index];
|
||||||
|
int highWord = cbData[index + 1];
|
||||||
|
|
||||||
|
if (highWord != 1)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int textureId = TextureHandle.UnpackTextureId(packedId);
|
||||||
|
int samplerId;
|
||||||
|
|
||||||
|
if (_samplerIndex == SamplerIndex.ViaHeaderIndex)
|
||||||
|
{
|
||||||
|
samplerId = textureId;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
samplerId = TextureHandle.UnpackSamplerId(packedId);
|
||||||
|
}
|
||||||
|
|
||||||
|
pool.UpdateBindlessCombined(_context.Renderer, samplerPool, textureId, samplerId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ensures that the texture bindings are visible to the host GPU.
|
||||||
|
/// Note: this actually performs the binding using the host graphics API.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pool">The current texture pool</param>
|
||||||
|
/// <param name="stageIndex">The stage number of the specified shader stage</param>
|
||||||
|
private void CommitBindlessResourcesNvnCombined(TexturePool pool, int stageIndex)
|
||||||
|
{
|
||||||
|
var samplerPool = _samplerPool;
|
||||||
|
|
||||||
|
ReadOnlySpan<int> cbData = GetConstantBufferRange<int>(stageIndex, Constants.DriverReserveTextureBindingsBuffer, 8, 32);
|
||||||
|
|
||||||
|
for (int index = 0; index < cbData.Length; index += 2)
|
||||||
|
{
|
||||||
|
int packedId = cbData[index];
|
||||||
|
int highWord = cbData[index + 1];
|
||||||
|
|
||||||
|
if (highWord != 1)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
int textureId = TextureHandle.UnpackTextureId(packedId);
|
int textureId = TextureHandle.UnpackTextureId(packedId);
|
||||||
int samplerId;
|
int samplerId;
|
||||||
|
@ -801,38 +882,76 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
samplerId = TextureHandle.UnpackSamplerId(packedId);
|
samplerId = TextureHandle.UnpackSamplerId(packedId);
|
||||||
}
|
}
|
||||||
|
|
||||||
Texture texture = pool.Get(textureId);
|
pool.UpdateBindlessCombined(_context.Renderer, samplerPool, textureId, samplerId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (texture == null)
|
/// <summary>
|
||||||
|
/// Ensures that the texture bindings are visible to the host GPU.
|
||||||
|
/// Note: this actually performs the binding using the host graphics API.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pool">The current texture pool</param>
|
||||||
|
/// <param name="stageIndex">The stage number of the specified shader stage</param>
|
||||||
|
private void CommitBindlessResourcesNvnSeparateTexture(TexturePool pool, int stageIndex)
|
||||||
|
{
|
||||||
|
ReadOnlySpan<int> cbData = GetConstantBufferRange<int>(stageIndex, Constants.DriverReserveTextureBindingsBuffer, 90, 128);
|
||||||
|
|
||||||
|
for (int index = 0; index < cbData.Length; index += 2)
|
||||||
|
{
|
||||||
|
int packedId = cbData[index];
|
||||||
|
int highWord = cbData[index + 1];
|
||||||
|
|
||||||
|
if (highWord != 1)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (texture.Target == Target.TextureBuffer)
|
int textureId = TextureHandle.UnpackTextureId(packedId);
|
||||||
|
|
||||||
|
pool.UpdateBindlessCombined(_context.Renderer, null, textureId, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ensures that the texture bindings are visible to the host GPU.
|
||||||
|
/// Note: this actually performs the binding using the host graphics API.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pool">The current texture pool</param>
|
||||||
|
/// <param name="stageIndex">The stage number of the specified shader stage</param>
|
||||||
|
private void CommitBindlessResourcesNvnSeparateSampler(TexturePool pool, int stageIndex)
|
||||||
|
{
|
||||||
|
var samplerPool = _samplerPool;
|
||||||
|
if (samplerPool == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadOnlySpan<int> cbData = GetConstantBufferRange<int>(stageIndex, Constants.DriverReserveTextureBindingsBuffer, 346, 32);
|
||||||
|
|
||||||
|
for (int index = 0; index < cbData.Length; index += 2)
|
||||||
|
{
|
||||||
|
int packedId = cbData[index];
|
||||||
|
int highWord = cbData[index + 1];
|
||||||
|
|
||||||
|
if (highWord != 1)
|
||||||
{
|
{
|
||||||
// Ensure that the buffer texture is using the correct buffer as storage.
|
continue;
|
||||||
// Buffers are frequently re-created to accomodate larger data, so we need to re-bind
|
}
|
||||||
// to ensure we're not using a old buffer that was already deleted.
|
|
||||||
TextureBindingInfo bindingInfo = new(texture.Target, texture.Format, 0, 0, 0, TextureUsageFlags.None);
|
int samplerId;
|
||||||
ulong address = texture.Range.GetSubRange(0).Address;
|
|
||||||
ulong size = texture.Size;
|
if (_samplerIndex == SamplerIndex.ViaHeaderIndex)
|
||||||
_channel.BufferManager.SetBufferTextureStorage(texture.HostTexture, address, size, bindingInfo, texture.Format, false, textureId);
|
{
|
||||||
|
samplerId = TextureHandle.UnpackTextureId(packedId);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Sampler sampler = samplerPool?.Get(samplerId);
|
samplerId = TextureHandle.UnpackSamplerId(packedId);
|
||||||
|
}
|
||||||
|
|
||||||
if (sampler == null)
|
if (samplerPool.TryGetBindlessSampler(samplerId, out Sampler sampler))
|
||||||
{
|
{
|
||||||
continue;
|
_context.Renderer.Pipeline.RegisterBindlessSampler(samplerId, sampler.GetHostSampler(null));
|
||||||
}
|
|
||||||
|
|
||||||
_context.Renderer.Pipeline.RegisterBindlessTextureAndSampler(
|
|
||||||
textureId,
|
|
||||||
texture.HostTexture,
|
|
||||||
texture.ScaleFactor,
|
|
||||||
samplerId,
|
|
||||||
sampler.GetHostSampler(texture));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -842,15 +961,18 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="stageIndex">Index of the shader stage where the constant buffer belongs</param>
|
/// <param name="stageIndex">Index of the shader stage where the constant buffer belongs</param>
|
||||||
/// <param name="bufferIndex">Index of the constant buffer to read from</param>
|
/// <param name="bufferIndex">Index of the constant buffer to read from</param>
|
||||||
/// <param name="elementIndex">Index of the element on the constant buffer</param>
|
/// <param name="startIndex">Index of the first element on the constant buffer</param>
|
||||||
|
/// <param name="count">Number of elements to access</param>
|
||||||
/// <returns>The value at the specified buffer and offset</returns>
|
/// <returns>The value at the specified buffer and offset</returns>
|
||||||
private unsafe T ReadConstantBuffer<T>(int stageIndex, int bufferIndex, int elementIndex) where T : unmanaged
|
private unsafe ReadOnlySpan<T> GetConstantBufferRange<T>(int stageIndex, int bufferIndex, int startIndex, int count) where T : unmanaged
|
||||||
{
|
{
|
||||||
ulong baseAddress = _isCompute
|
ulong baseAddress = _isCompute
|
||||||
? _channel.BufferManager.GetComputeUniformBufferAddress(bufferIndex)
|
? _channel.BufferManager.GetComputeUniformBufferAddress(bufferIndex)
|
||||||
: _channel.BufferManager.GetGraphicsUniformBufferAddress(stageIndex, bufferIndex);
|
: _channel.BufferManager.GetGraphicsUniformBufferAddress(stageIndex, bufferIndex);
|
||||||
|
|
||||||
return _channel.MemoryManager.Physical.Read<T>(baseAddress + (ulong)elementIndex * (ulong)sizeof(T));
|
int typeSize = sizeof(T);
|
||||||
|
|
||||||
|
return MemoryMarshal.Cast<byte, T>(_channel.MemoryManager.Physical.GetSpan(baseAddress + (ulong)(startIndex * typeSize), count * typeSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -236,27 +236,83 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
while ((id = ModifiedEntries.GetNextAndClear()) >= 0)
|
while ((id = ModifiedEntries.GetNextAndClear()) >= 0)
|
||||||
{
|
{
|
||||||
Texture texture = Items[id] ?? GetValidated(id);
|
UpdateBindlessInternal(renderer, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (texture != null)
|
/// <summary>
|
||||||
|
/// Updates the bindless texture with the given pool ID, if the pool entry has been modified since the last call.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="renderer">Renderer of the current GPU context</param>
|
||||||
|
/// <param name="samplerPool">Optional sampler pool. If null, the sampler ID is ignored</param>
|
||||||
|
/// <param name="textureId">ID of the texture</param>
|
||||||
|
/// <param name="samplerId">ID of the sampler</param>
|
||||||
|
public void UpdateBindlessCombined(IRenderer renderer, SamplerPool samplerPool, int textureId, int samplerId)
|
||||||
|
{
|
||||||
|
if ((uint)textureId >= Items.Length)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Items[textureId]?.SynchronizeMemory();
|
||||||
|
|
||||||
|
bool textureModified = ModifiedEntries.Clear(textureId);
|
||||||
|
|
||||||
|
if (samplerPool != null)
|
||||||
|
{
|
||||||
|
bool samplerModified = samplerPool.TryGetBindlessSampler(samplerId, out Sampler sampler);
|
||||||
|
|
||||||
|
if (sampler == null)
|
||||||
{
|
{
|
||||||
if (texture.Target == Target.TextureBuffer)
|
if (textureModified)
|
||||||
{
|
{
|
||||||
_channel.BufferManager.SetBufferTextureStorage(
|
UpdateBindlessInternal(renderer, textureId);
|
||||||
texture.HostTexture,
|
}
|
||||||
texture.Range.GetSubRange(0).Address,
|
}
|
||||||
texture.Size,
|
else if (textureModified || samplerModified)
|
||||||
default,
|
{
|
||||||
0,
|
Texture texture = Items[textureId] ?? GetValidated(textureId);
|
||||||
false,
|
|
||||||
id);
|
if (texture != null)
|
||||||
|
{
|
||||||
|
if (texture.Target != Target.TextureBuffer)
|
||||||
|
{
|
||||||
|
renderer.Pipeline.RegisterBindlessTextureAndSampler(
|
||||||
|
textureId,
|
||||||
|
texture.HostTexture,
|
||||||
|
texture.ScaleFactor,
|
||||||
|
samplerId,
|
||||||
|
sampler.GetHostSampler(null));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
renderer.Pipeline.RegisterBindlessTexture(id, texture.HostTexture, texture.ScaleFactor);
|
renderer.Pipeline.RegisterBindlessSampler(samplerId, sampler.GetHostSampler(null));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (textureModified)
|
||||||
|
{
|
||||||
|
UpdateBindlessInternal(renderer, textureId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the bindless texture with the given pool ID.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="renderer">Renderer of the current GPU context</param>
|
||||||
|
/// <param name="id">ID of the texture</param>
|
||||||
|
private void UpdateBindlessInternal(IRenderer renderer, int id)
|
||||||
|
{
|
||||||
|
Texture texture = Items[id] ?? GetValidated(id);
|
||||||
|
|
||||||
|
if (texture != null)
|
||||||
|
{
|
||||||
|
if (texture.Target != Target.TextureBuffer)
|
||||||
|
{
|
||||||
|
renderer.Pipeline.RegisterBindlessTexture(id, texture.HostTexture, texture.ScaleFactor);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -431,8 +487,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
ulong endAddress = address + size;
|
ulong endAddress = address + size;
|
||||||
|
|
||||||
UpdateModifiedEntries(address, endAddress);
|
|
||||||
|
|
||||||
for (; address < endAddress; address += DescriptorSize)
|
for (; address < endAddress; address += DescriptorSize)
|
||||||
{
|
{
|
||||||
int id = (int)((address - Address) / DescriptorSize);
|
int id = (int)((address - Address) / DescriptorSize);
|
||||||
|
@ -451,6 +505,8 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateModifiedEntry(id);
|
||||||
|
|
||||||
if (texture.HasOneReference())
|
if (texture.HasOneReference())
|
||||||
{
|
{
|
||||||
_channel.MemoryManager.Physical.TextureCache.AddShortCache(texture, ref cachedDescriptor);
|
_channel.MemoryManager.Physical.TextureCache.AddShortCache(texture, ref cachedDescriptor);
|
||||||
|
@ -461,6 +517,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
texture.DecrementReferenceCount(this, id);
|
texture.DecrementReferenceCount(this, id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdateModifiedEntry(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -429,6 +429,27 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
return _gpUniformBuffers[stage].Buffers[index].Address;
|
return _gpUniformBuffers[stage].Buffers[index].Address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the size of the compute uniform buffer currently bound at the given index.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">Index of the uniform buffer binding</param>
|
||||||
|
/// <returns>The uniform buffer size, or an undefined value if the buffer is not currently bound</returns>
|
||||||
|
public ulong GetComputeUniformBufferSize(int index)
|
||||||
|
{
|
||||||
|
return _cpUniformBuffers.Buffers[index].Size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the size of the graphics uniform buffer currently bound at the given index.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stage">Index of the shader stage</param>
|
||||||
|
/// <param name="index">Index of the uniform buffer binding</param>
|
||||||
|
/// <returns>The uniform buffer size, or an undefined value if the buffer is not currently bound</returns>
|
||||||
|
public ulong GetGraphicsUniformBufferSize(int stage, int index)
|
||||||
|
{
|
||||||
|
return _gpUniformBuffers[stage].Buffers[index].Size;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the bounds of the uniform buffer currently bound at the given index.
|
/// Gets the bounds of the uniform buffer currently bound at the given index.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -18,6 +18,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
public BufferDescriptor[][] StorageBufferBindings { get; }
|
public BufferDescriptor[][] StorageBufferBindings { get; }
|
||||||
|
|
||||||
public BindlessTextureFlags[] BindlessTextureFlags { get; }
|
public BindlessTextureFlags[] BindlessTextureFlags { get; }
|
||||||
|
public uint[] BindlessIndexedBuffersMask { get; }
|
||||||
|
|
||||||
public int MaxTextureBinding { get; }
|
public int MaxTextureBinding { get; }
|
||||||
public int MaxImageBinding { get; }
|
public int MaxImageBinding { get; }
|
||||||
|
@ -37,6 +38,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
StorageBufferBindings = new BufferDescriptor[stageCount][];
|
StorageBufferBindings = new BufferDescriptor[stageCount][];
|
||||||
|
|
||||||
BindlessTextureFlags = new BindlessTextureFlags[stageCount];
|
BindlessTextureFlags = new BindlessTextureFlags[stageCount];
|
||||||
|
BindlessIndexedBuffersMask = new uint[stageCount];
|
||||||
|
|
||||||
int maxTextureBinding = -1;
|
int maxTextureBinding = -1;
|
||||||
int maxImageBinding = -1;
|
int maxImageBinding = -1;
|
||||||
|
@ -100,6 +102,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
StorageBufferBindings[i] = stage.Info.SBuffers.ToArray();
|
StorageBufferBindings[i] = stage.Info.SBuffers.ToArray();
|
||||||
|
|
||||||
BindlessTextureFlags[i] = stage.Info.BindlessTextureFlags;
|
BindlessTextureFlags[i] = stage.Info.BindlessTextureFlags;
|
||||||
|
BindlessIndexedBuffersMask[i] = stage.Info.BindlessIndexedBuffersMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
MaxTextureBinding = maxTextureBinding;
|
MaxTextureBinding = maxTextureBinding;
|
||||||
|
|
|
@ -189,6 +189,11 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||||
/// Flags indicating if and how bindless texture accesses were translated for the shader stage.
|
/// Flags indicating if and how bindless texture accesses were translated for the shader stage.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public BindlessTextureFlags BindlessTextureFlags;
|
public BindlessTextureFlags BindlessTextureFlags;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Bit mask indicating which constant buffers are accessed on the shader using indexing to load texture handles.
|
||||||
|
/// </summary>
|
||||||
|
public uint BindlessIndexedBuffersMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly DiskCacheGuestStorage _guestStorage;
|
private readonly DiskCacheGuestStorage _guestStorage;
|
||||||
|
@ -805,6 +810,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||||
images,
|
images,
|
||||||
dataInfo.Stage,
|
dataInfo.Stage,
|
||||||
dataInfo.BindlessTextureFlags,
|
dataInfo.BindlessTextureFlags,
|
||||||
|
dataInfo.BindlessIndexedBuffersMask,
|
||||||
dataInfo.GeometryVerticesPerPrimitive,
|
dataInfo.GeometryVerticesPerPrimitive,
|
||||||
dataInfo.GeometryMaxOutputVertices,
|
dataInfo.GeometryMaxOutputVertices,
|
||||||
dataInfo.ThreadsPerInputPrimitive,
|
dataInfo.ThreadsPerInputPrimitive,
|
||||||
|
@ -836,6 +842,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||||
ImagesCount = (ushort)info.Images.Count,
|
ImagesCount = (ushort)info.Images.Count,
|
||||||
Stage = info.Stage,
|
Stage = info.Stage,
|
||||||
BindlessTextureFlags = info.BindlessTextureFlags,
|
BindlessTextureFlags = info.BindlessTextureFlags,
|
||||||
|
BindlessIndexedBuffersMask = info.BindlessIndexedBuffersMask,
|
||||||
GeometryVerticesPerPrimitive = (byte)info.GeometryVerticesPerPrimitive,
|
GeometryVerticesPerPrimitive = (byte)info.GeometryVerticesPerPrimitive,
|
||||||
GeometryMaxOutputVertices = (ushort)info.GeometryMaxOutputVertices,
|
GeometryMaxOutputVertices = (ushort)info.GeometryMaxOutputVertices,
|
||||||
ThreadsPerInputPrimitive = (ushort)info.ThreadsPerInputPrimitive,
|
ThreadsPerInputPrimitive = (ushort)info.ThreadsPerInputPrimitive,
|
||||||
|
|
|
@ -5,7 +5,10 @@ namespace Ryujinx.Graphics.Shader
|
||||||
None = 0,
|
None = 0,
|
||||||
|
|
||||||
BindlessConverted = 1 << 0,
|
BindlessConverted = 1 << 0,
|
||||||
BindlessNvn = 1 << 1,
|
BindlessNvnCombined = 1 << 1,
|
||||||
BindlessFull = 1 << 2,
|
BindlessNvnSeparateTexture = 1 << 2,
|
||||||
|
BindlessNvnSeparateSampler = 1 << 3,
|
||||||
|
BindlessFull = 1 << 4,
|
||||||
|
BindlessNvnAny = BindlessNvnCombined | BindlessNvnSeparateTexture | BindlessNvnSeparateSampler,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
public static void Declare(CodeGenContext context, StructuredProgramInfo info)
|
public static void Declare(CodeGenContext context, StructuredProgramInfo info)
|
||||||
{
|
{
|
||||||
context.AppendLine(context.TargetApi == TargetApi.Vulkan ? "#version 460 core" : "#version 450 core");
|
context.AppendLine(context.TargetApi == TargetApi.Vulkan ? "#version 460 core" : "#version 450 core");
|
||||||
context.AppendLine("#extension GL_ARB_bindless_texture : enable");
|
|
||||||
context.AppendLine("#extension GL_ARB_gpu_shader_int64 : enable");
|
context.AppendLine("#extension GL_ARB_gpu_shader_int64 : enable");
|
||||||
|
|
||||||
if (context.HostCapabilities.SupportsShaderBallot)
|
if (context.HostCapabilities.SupportsShaderBallot)
|
||||||
|
@ -36,6 +35,10 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
{
|
{
|
||||||
context.AppendLine("#extension GL_EXT_nonuniform_qualifier : enable");
|
context.AppendLine("#extension GL_EXT_nonuniform_qualifier : enable");
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.AppendLine("#extension GL_ARB_bindless_texture : enable");
|
||||||
|
}
|
||||||
|
|
||||||
if (context.Definitions.Stage == ShaderStage.Compute)
|
if (context.Definitions.Stage == ShaderStage.Compute)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
uint Helper_GetBindlessTextureIndex(int nvHandle)
|
uint Helper_GetBindlessTextureIndex(int nvHandle)
|
||||||
{
|
{
|
||||||
int id = nvHandle & 0xfffff;
|
int id = nvHandle & 0xfffff;
|
||||||
return bindless_table[id >> 8].x | uint(id & 0xff);
|
return bindless_table.table[id >> 8].x | uint(id & 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint Helper_GetBindlessSamplerIndex(int nvHandle)
|
uint Helper_GetBindlessSamplerIndex(int nvHandle)
|
||||||
{
|
{
|
||||||
int id = (nvHandle >> 20) & 0xfff;
|
int id = (nvHandle >> 20) & 0xfff;
|
||||||
return bindless_table[id >> 8].y | uint(id & 0xff);
|
return bindless_table.table[id >> 8].y | uint(id & 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
float Helper_GetBindlessScale(int nvHandle)
|
float Helper_GetBindlessScale(int nvHandle)
|
||||||
{
|
{
|
||||||
return bindless_scales[Helper_GetBindlessTextureIndex(nvHandle)];
|
return bindless_scales.scales[Helper_GetBindlessTextureIndex(nvHandle)];
|
||||||
}
|
}
|
|
@ -11,6 +11,12 @@ namespace Ryujinx.Graphics.Shader
|
||||||
public const int NvnBaseInstanceByteOffset = 0x644;
|
public const int NvnBaseInstanceByteOffset = 0x644;
|
||||||
public const int NvnDrawIndexByteOffset = 0x648;
|
public const int NvnDrawIndexByteOffset = 0x648;
|
||||||
|
|
||||||
|
public const int NvnTextureCbSlot = 2;
|
||||||
|
public const int NvnSeparateTextureBindingsStartByteOffset = 0x168;
|
||||||
|
public const int NvnSeparateTextureBindingsEndByteOffset = 0x568;
|
||||||
|
public const int NvnSeparateSamplerBindingsStartByteOffset = 0x568;
|
||||||
|
public const int NvnSeparateSamplerBindingsEndByteOffset = 0x668;
|
||||||
|
|
||||||
public const int VkConstantBufferSetIndex = 0;
|
public const int VkConstantBufferSetIndex = 0;
|
||||||
public const int VkStorageBufferSetIndex = 1;
|
public const int VkStorageBufferSetIndex = 1;
|
||||||
public const int VkTextureSetIndex = 2;
|
public const int VkTextureSetIndex = 2;
|
||||||
|
|
|
@ -12,6 +12,7 @@ namespace Ryujinx.Graphics.Shader
|
||||||
|
|
||||||
public ShaderStage Stage { get; }
|
public ShaderStage Stage { get; }
|
||||||
public BindlessTextureFlags BindlessTextureFlags { get; }
|
public BindlessTextureFlags BindlessTextureFlags { get; }
|
||||||
|
public uint BindlessIndexedBuffersMask { get; }
|
||||||
public int GeometryVerticesPerPrimitive { get; }
|
public int GeometryVerticesPerPrimitive { get; }
|
||||||
public int GeometryMaxOutputVertices { get; }
|
public int GeometryMaxOutputVertices { get; }
|
||||||
public int ThreadsPerInputPrimitive { get; }
|
public int ThreadsPerInputPrimitive { get; }
|
||||||
|
@ -29,6 +30,7 @@ namespace Ryujinx.Graphics.Shader
|
||||||
TextureDescriptor[] images,
|
TextureDescriptor[] images,
|
||||||
ShaderStage stage,
|
ShaderStage stage,
|
||||||
BindlessTextureFlags bindlessTextureFlags,
|
BindlessTextureFlags bindlessTextureFlags,
|
||||||
|
uint bindlessIndexedBuffersMask,
|
||||||
int geometryVerticesPerPrimitive,
|
int geometryVerticesPerPrimitive,
|
||||||
int geometryMaxOutputVertices,
|
int geometryMaxOutputVertices,
|
||||||
int threadsPerInputPrimitive,
|
int threadsPerInputPrimitive,
|
||||||
|
@ -46,6 +48,7 @@ namespace Ryujinx.Graphics.Shader
|
||||||
|
|
||||||
Stage = stage;
|
Stage = stage;
|
||||||
BindlessTextureFlags = bindlessTextureFlags;
|
BindlessTextureFlags = bindlessTextureFlags;
|
||||||
|
BindlessIndexedBuffersMask = bindlessIndexedBuffersMask;
|
||||||
GeometryVerticesPerPrimitive = geometryVerticesPerPrimitive;
|
GeometryVerticesPerPrimitive = geometryVerticesPerPrimitive;
|
||||||
GeometryMaxOutputVertices = geometryMaxOutputVertices;
|
GeometryMaxOutputVertices = geometryMaxOutputVertices;
|
||||||
ThreadsPerInputPrimitive = threadsPerInputPrimitive;
|
ThreadsPerInputPrimitive = threadsPerInputPrimitive;
|
||||||
|
|
|
@ -14,6 +14,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
public readonly ShaderStage Stage;
|
public readonly ShaderStage Stage;
|
||||||
public readonly ref FeatureFlags UsedFeatures;
|
public readonly ref FeatureFlags UsedFeatures;
|
||||||
public readonly ref BindlessTextureFlags BindlessTextureFlags;
|
public readonly ref BindlessTextureFlags BindlessTextureFlags;
|
||||||
|
public readonly ref uint BindlessIndexedBuffersMask;
|
||||||
public readonly ref bool BindlessTexturesAllowed;
|
public readonly ref bool BindlessTexturesAllowed;
|
||||||
|
|
||||||
public TransformContext(
|
public TransformContext(
|
||||||
|
@ -27,6 +28,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
ShaderStage stage,
|
ShaderStage stage,
|
||||||
ref FeatureFlags usedFeatures,
|
ref FeatureFlags usedFeatures,
|
||||||
ref BindlessTextureFlags bindlessTextureFlags,
|
ref BindlessTextureFlags bindlessTextureFlags,
|
||||||
|
ref uint bindlessIndexedBuffersMask,
|
||||||
ref bool bindlessTexturesAllowed)
|
ref bool bindlessTexturesAllowed)
|
||||||
{
|
{
|
||||||
Hfm = hfm;
|
Hfm = hfm;
|
||||||
|
@ -39,6 +41,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
Stage = stage;
|
Stage = stage;
|
||||||
UsedFeatures = ref usedFeatures;
|
UsedFeatures = ref usedFeatures;
|
||||||
BindlessTextureFlags = ref bindlessTextureFlags;
|
BindlessTextureFlags = ref bindlessTextureFlags;
|
||||||
|
BindlessIndexedBuffersMask = ref bindlessIndexedBuffersMask;
|
||||||
BindlessTexturesAllowed = ref bindlessTexturesAllowed;
|
BindlessTexturesAllowed = ref bindlessTexturesAllowed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
context.ResourceManager,
|
context.ResourceManager,
|
||||||
context.TargetApi,
|
context.TargetApi,
|
||||||
ref context.BindlessTextureFlags,
|
ref context.BindlessTextureFlags,
|
||||||
|
ref context.BindlessIndexedBuffersMask,
|
||||||
context.BindlessTexturesAllowed,
|
context.BindlessTexturesAllowed,
|
||||||
context.GpuAccessor.QueryTextureBufferIndex());
|
context.GpuAccessor.QueryTextureBufferIndex());
|
||||||
|
|
||||||
|
@ -784,6 +785,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
ResourceManager resourceManager,
|
ResourceManager resourceManager,
|
||||||
TargetApi targetApi,
|
TargetApi targetApi,
|
||||||
ref BindlessTextureFlags bindlessTextureFlags,
|
ref BindlessTextureFlags bindlessTextureFlags,
|
||||||
|
ref uint bindlessIndexedBuffersMask,
|
||||||
bool bindlessTexturesAllowed,
|
bool bindlessTexturesAllowed,
|
||||||
int textureBufferIndex)
|
int textureBufferIndex)
|
||||||
{
|
{
|
||||||
|
@ -797,9 +799,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
{
|
{
|
||||||
resourceManager.EnsureBindlessBinding(targetApi, texOp.Type, texOp.Inst.IsImage());
|
resourceManager.EnsureBindlessBinding(targetApi, texOp.Type, texOp.Inst.IsImage());
|
||||||
|
|
||||||
if (IsIndexedAccess(resourceManager, texOp, textureBufferIndex))
|
if (IsIndexedAccess(resourceManager, texOp, ref bindlessTextureFlags, ref bindlessIndexedBuffersMask, textureBufferIndex))
|
||||||
{
|
{
|
||||||
bindlessTextureFlags |= BindlessTextureFlags.BindlessNvn;
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -865,7 +866,12 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsIndexedAccess(ResourceManager resourceManager, TextureOperation texOp, int textureBufferIndex)
|
private static bool IsIndexedAccess(
|
||||||
|
ResourceManager resourceManager,
|
||||||
|
TextureOperation texOp,
|
||||||
|
ref BindlessTextureFlags bindlessTextureFlags,
|
||||||
|
ref uint bindlessIndexedBuffersMask,
|
||||||
|
int textureBufferIndex)
|
||||||
{
|
{
|
||||||
// Try to detect a indexed access.
|
// Try to detect a indexed access.
|
||||||
// The access is considered indexed if the handle is loaded with a LDC instruction
|
// The access is considered indexed if the handle is loaded with a LDC instruction
|
||||||
|
@ -875,6 +881,70 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (handleAsgOp.Inst == Instruction.BitwiseOr)
|
||||||
|
{
|
||||||
|
if (IsCbLoadOrCb(resourceManager, handleAsgOp.GetSource(0), ref bindlessTextureFlags, out int ldc0CbSlot, textureBufferIndex) &&
|
||||||
|
IsCbLoadOrCb(resourceManager, handleAsgOp.GetSource(1), ref bindlessTextureFlags, out int ldc1CbSlot, textureBufferIndex))
|
||||||
|
{
|
||||||
|
bindlessIndexedBuffersMask |= (1u << ldc0CbSlot) | (1u << ldc1CbSlot);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (IsCbLoad(resourceManager, handleAsgOp, out int cbSlot))
|
||||||
|
{
|
||||||
|
bindlessTextureFlags |= BindlessTextureFlags.BindlessNvnCombined;
|
||||||
|
bindlessIndexedBuffersMask |= 1u << cbSlot;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsCbLoadOrCb(
|
||||||
|
ResourceManager resourceManager,
|
||||||
|
Operand operand,
|
||||||
|
ref BindlessTextureFlags bindlessTextureFlags,
|
||||||
|
out int cbSlot,
|
||||||
|
int textureBufferIndex)
|
||||||
|
{
|
||||||
|
cbSlot = 0;
|
||||||
|
|
||||||
|
if (operand.Type == OperandType.ConstantBuffer)
|
||||||
|
{
|
||||||
|
cbSlot = operand.GetCbufSlot();
|
||||||
|
|
||||||
|
if (cbSlot == textureBufferIndex && textureBufferIndex == Constants.NvnTextureCbSlot)
|
||||||
|
{
|
||||||
|
int cbOffset = operand.GetCbufOffset();
|
||||||
|
|
||||||
|
if (cbOffset >= Constants.NvnSeparateTextureBindingsStartByteOffset / 4 &&
|
||||||
|
cbOffset < Constants.NvnSeparateTextureBindingsEndByteOffset / 4)
|
||||||
|
{
|
||||||
|
bindlessTextureFlags |= BindlessTextureFlags.BindlessNvnSeparateTexture;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (cbOffset >= Constants.NvnSeparateSamplerBindingsStartByteOffset / 4 &&
|
||||||
|
cbOffset < Constants.NvnSeparateSamplerBindingsEndByteOffset / 4)
|
||||||
|
{
|
||||||
|
bindlessTextureFlags |= BindlessTextureFlags.BindlessNvnSeparateSampler;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return operand.AsgOp is Operation operation && IsCbLoad(resourceManager, operation, out cbSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsCbLoad(ResourceManager resourceManager, Operation handleAsgOp, out int cbSlot)
|
||||||
|
{
|
||||||
|
cbSlot = 0;
|
||||||
|
|
||||||
if (handleAsgOp.Inst != Instruction.Load || handleAsgOp.StorageKind != StorageKind.ConstantBuffer)
|
if (handleAsgOp.Inst != Instruction.Load || handleAsgOp.StorageKind != StorageKind.ConstantBuffer)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -883,8 +953,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
Operand ldcSrc0 = handleAsgOp.GetSource(0);
|
Operand ldcSrc0 = handleAsgOp.GetSource(0);
|
||||||
|
|
||||||
return ldcSrc0.Type == OperandType.Constant &&
|
return ldcSrc0.Type == OperandType.Constant &&
|
||||||
resourceManager.TryGetConstantBufferSlot(ldcSrc0.Value, out int cbSlot) &&
|
resourceManager.TryGetConstantBufferSlot(ldcSrc0.Value, out cbSlot);
|
||||||
cbSlot == textureBufferIndex;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -265,6 +265,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
HelperFunctionManager hfm = new(funcs, Definitions.Stage);
|
HelperFunctionManager hfm = new(funcs, Definitions.Stage);
|
||||||
|
|
||||||
BindlessTextureFlags bindlessTextureFlags = BindlessTextureFlags.None;
|
BindlessTextureFlags bindlessTextureFlags = BindlessTextureFlags.None;
|
||||||
|
uint bindlessIndexedBuffersMask = 0;
|
||||||
bool bindlessTexturesAllowed = true;
|
bool bindlessTexturesAllowed = true;
|
||||||
|
|
||||||
for (int i = 0; i < functions.Length; i++)
|
for (int i = 0; i < functions.Length; i++)
|
||||||
|
@ -302,6 +303,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
Definitions.Stage,
|
Definitions.Stage,
|
||||||
ref usedFeatures,
|
ref usedFeatures,
|
||||||
ref bindlessTextureFlags,
|
ref bindlessTextureFlags,
|
||||||
|
ref bindlessIndexedBuffersMask,
|
||||||
ref bindlessTexturesAllowed);
|
ref bindlessTexturesAllowed);
|
||||||
|
|
||||||
Optimizer.RunPass(context);
|
Optimizer.RunPass(context);
|
||||||
|
@ -319,6 +321,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
resourceManager,
|
resourceManager,
|
||||||
usedFeatures,
|
usedFeatures,
|
||||||
bindlessTextureFlags,
|
bindlessTextureFlags,
|
||||||
|
bindlessIndexedBuffersMask,
|
||||||
clipDistancesWritten);
|
clipDistancesWritten);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -330,6 +333,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
ResourceManager resourceManager,
|
ResourceManager resourceManager,
|
||||||
FeatureFlags usedFeatures,
|
FeatureFlags usedFeatures,
|
||||||
BindlessTextureFlags bindlessTextureFlags,
|
BindlessTextureFlags bindlessTextureFlags,
|
||||||
|
uint bindlessIndexedBuffersMask,
|
||||||
byte clipDistancesWritten)
|
byte clipDistancesWritten)
|
||||||
{
|
{
|
||||||
var sInfo = StructuredProgram.MakeStructuredProgram(
|
var sInfo = StructuredProgram.MakeStructuredProgram(
|
||||||
|
@ -354,6 +358,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
resourceManager.GetImageDescriptors(),
|
resourceManager.GetImageDescriptors(),
|
||||||
originalDefinitions.Stage,
|
originalDefinitions.Stage,
|
||||||
bindlessTextureFlags,
|
bindlessTextureFlags,
|
||||||
|
bindlessIndexedBuffersMask,
|
||||||
geometryVerticesPerPrimitive,
|
geometryVerticesPerPrimitive,
|
||||||
originalDefinitions.MaxOutputVertices,
|
originalDefinitions.MaxOutputVertices,
|
||||||
originalDefinitions.ThreadsPerInputPrimitive,
|
originalDefinitions.ThreadsPerInputPrimitive,
|
||||||
|
@ -586,6 +591,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
resourceManager,
|
resourceManager,
|
||||||
FeatureFlags.None,
|
FeatureFlags.None,
|
||||||
BindlessTextureFlags.None,
|
BindlessTextureFlags.None,
|
||||||
|
0,
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -683,6 +689,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
resourceManager,
|
resourceManager,
|
||||||
FeatureFlags.RtLayer,
|
FeatureFlags.RtLayer,
|
||||||
BindlessTextureFlags.None,
|
BindlessTextureFlags.None,
|
||||||
|
0,
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ using Ryujinx.Graphics.GAL;
|
||||||
using Silk.NET.Vulkan;
|
using Silk.NET.Vulkan;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.Design;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
@ -270,25 +271,26 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
bbiDsc.UpdateBufferImage(0, 0, i, bufferView, DescriptorType.StorageTexelBuffer);
|
bbiDsc.UpdateBufferImage(0, 0, i, bufferView, DescriptorType.StorageTexelBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
btDsc.UpdateImage(0, 2, i, default, DescriptorType.SampledImage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < _samplerRefs.Length; i++)
|
for (int i = 0; i < _samplerRefs.Length; i++)
|
||||||
{
|
{
|
||||||
var sampler = _samplerRefs[i];
|
var sampler = _samplerRefs[i];
|
||||||
if (sampler != null)
|
var sd = new DescriptorImageInfo()
|
||||||
{
|
{
|
||||||
var sd = new DescriptorImageInfo()
|
Sampler = sampler?.Get(cbs).Value ?? default
|
||||||
{
|
};
|
||||||
Sampler = sampler.Get(cbs).Value
|
|
||||||
};
|
|
||||||
|
|
||||||
if (sd.Sampler.Handle == 0)
|
if (sd.Sampler.Handle == 0)
|
||||||
{
|
{
|
||||||
sd.Sampler = dummySampler.GetSampler().Get(cbs).Value;
|
sd.Sampler = dummySampler.GetSampler().Get(cbs).Value;
|
||||||
}
|
|
||||||
|
|
||||||
bsDsc.UpdateImage(0, 0, i, sd, DescriptorType.Sampler);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bsDsc.UpdateImage(0, 0, i, sd, DescriptorType.Sampler);
|
||||||
}
|
}
|
||||||
|
|
||||||
_pipelineLayout = plce.PipelineLayout;
|
_pipelineLayout = plce.PipelineLayout;
|
||||||
|
|
|
@ -108,7 +108,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
// All bindless resources have the update after bind flag set,
|
// All bindless resources have the update after bind flag set,
|
||||||
// this is required for Intel, otherwise it just crashes when binding the descriptor sets
|
// this is required for Intel, otherwise it just crashes when binding the descriptor sets
|
||||||
// for bindless resources (maybe because it is above the limit?)
|
// for bindless resources (maybe because it is above the limit?)
|
||||||
bool updateAfterBind = setIndex >= PipelineBase.BindlessBufferTextureSetIndex;
|
bool updateAfterBind = setIndex >= PipelineBase.BindlessTexturesSetIndex;
|
||||||
|
|
||||||
var dsc = _gd.DescriptorSetManager.AllocateDescriptorSet(
|
var dsc = _gd.DescriptorSetManager.AllocateDescriptorSet(
|
||||||
_gd.Api,
|
_gd.Api,
|
||||||
|
|
Loading…
Reference in a new issue