Merge branch 'master' of https://github.com/Ryujinx/Ryujinx into turbo

This commit is contained in:
unknown 2024-06-03 00:10:41 -03:00
commit 20cd474994
27 changed files with 457 additions and 247 deletions

View file

@ -1,6 +1,8 @@
using System;
namespace Ryujinx.Graphics.GAL namespace Ryujinx.Graphics.GAL
{ {
public interface IImageArray public interface IImageArray : IDisposable
{ {
void SetFormats(int index, Format[] imageFormats); void SetFormats(int index, Format[] imageFormats);
void SetImages(int index, ITexture[] images); void SetImages(int index, ITexture[] images);

View file

@ -1,6 +1,8 @@
using System;
namespace Ryujinx.Graphics.GAL namespace Ryujinx.Graphics.GAL
{ {
public interface ITextureArray public interface ITextureArray : IDisposable
{ {
void SetSamplers(int index, ISampler[] samplers); void SetSamplers(int index, ISampler[] samplers);
void SetTextures(int index, ITexture[] textures); void SetTextures(int index, ITexture[] textures);

View file

@ -66,6 +66,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
Register<CounterEventDisposeCommand>(CommandType.CounterEventDispose); Register<CounterEventDisposeCommand>(CommandType.CounterEventDispose);
Register<CounterEventFlushCommand>(CommandType.CounterEventFlush); Register<CounterEventFlushCommand>(CommandType.CounterEventFlush);
Register<ImageArrayDisposeCommand>(CommandType.ImageArrayDispose);
Register<ImageArraySetFormatsCommand>(CommandType.ImageArraySetFormats); Register<ImageArraySetFormatsCommand>(CommandType.ImageArraySetFormats);
Register<ImageArraySetImagesCommand>(CommandType.ImageArraySetImages); Register<ImageArraySetImagesCommand>(CommandType.ImageArraySetImages);
@ -88,6 +89,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
Register<TextureSetDataSliceRegionCommand>(CommandType.TextureSetDataSliceRegion); Register<TextureSetDataSliceRegionCommand>(CommandType.TextureSetDataSliceRegion);
Register<TextureSetStorageCommand>(CommandType.TextureSetStorage); Register<TextureSetStorageCommand>(CommandType.TextureSetStorage);
Register<TextureArrayDisposeCommand>(CommandType.TextureArrayDispose);
Register<TextureArraySetSamplersCommand>(CommandType.TextureArraySetSamplers); Register<TextureArraySetSamplersCommand>(CommandType.TextureArraySetSamplers);
Register<TextureArraySetTexturesCommand>(CommandType.TextureArraySetTextures); Register<TextureArraySetTexturesCommand>(CommandType.TextureArraySetTextures);

View file

@ -26,6 +26,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
CounterEventDispose, CounterEventDispose,
CounterEventFlush, CounterEventFlush,
ImageArrayDispose,
ImageArraySetFormats, ImageArraySetFormats,
ImageArraySetImages, ImageArraySetImages,
@ -48,6 +49,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
TextureSetDataSliceRegion, TextureSetDataSliceRegion,
TextureSetStorage, TextureSetStorage,
TextureArrayDispose,
TextureArraySetSamplers, TextureArraySetSamplers,
TextureArraySetTextures, TextureArraySetTextures,

View file

@ -0,0 +1,21 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.ImageArray
{
struct ImageArrayDisposeCommand : IGALCommand, IGALCommand<ImageArrayDisposeCommand>
{
public readonly CommandType CommandType => CommandType.ImageArrayDispose;
private TableRef<ThreadedImageArray> _imageArray;
public void Set(TableRef<ThreadedImageArray> imageArray)
{
_imageArray = imageArray;
}
public static void Run(ref ImageArrayDisposeCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
command._imageArray.Get(threaded).Base.Dispose();
}
}
}

View file

@ -0,0 +1,21 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.TextureArray
{
struct TextureArrayDisposeCommand : IGALCommand, IGALCommand<TextureArrayDisposeCommand>
{
public readonly CommandType CommandType => CommandType.TextureArrayDispose;
private TableRef<ThreadedTextureArray> _textureArray;
public void Set(TableRef<ThreadedTextureArray> textureArray)
{
_textureArray = textureArray;
}
public static void Run(ref TextureArrayDisposeCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
command._textureArray.Get(threaded).Base.Dispose();
}
}
}

View file

@ -21,6 +21,12 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
return new TableRef<T>(_renderer, reference); return new TableRef<T>(_renderer, reference);
} }
public void Dispose()
{
_renderer.New<ImageArrayDisposeCommand>().Set(Ref(this));
_renderer.QueueCommand();
}
public void SetFormats(int index, Format[] imageFormats) public void SetFormats(int index, Format[] imageFormats)
{ {
_renderer.New<ImageArraySetFormatsCommand>().Set(Ref(this), index, Ref(imageFormats)); _renderer.New<ImageArraySetFormatsCommand>().Set(Ref(this), index, Ref(imageFormats));

View file

@ -22,6 +22,12 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
return new TableRef<T>(_renderer, reference); return new TableRef<T>(_renderer, reference);
} }
public void Dispose()
{
_renderer.New<TextureArrayDisposeCommand>().Set(Ref(this));
_renderer.QueueCommand();
}
public void SetSamplers(int index, ISampler[] samplers) public void SetSamplers(int index, ISampler[] samplers)
{ {
_renderer.New<TextureArraySetSamplersCommand>().Set(Ref(this), index, Ref(samplers.ToArray())); _renderer.New<TextureArraySetSamplersCommand>().Set(Ref(this), index, Ref(samplers.ToArray()));

View file

@ -1113,6 +1113,15 @@ namespace Ryujinx.Graphics.Gpu.Image
nextNode = nextNode.Next; nextNode = nextNode.Next;
_cacheFromBuffer.Remove(toRemove.Value.Key); _cacheFromBuffer.Remove(toRemove.Value.Key);
_lruCache.Remove(toRemove); _lruCache.Remove(toRemove);
if (toRemove.Value.Key.IsImage)
{
toRemove.Value.ImageArray.Dispose();
}
else
{
toRemove.Value.TextureArray.Dispose();
}
} }
} }
@ -1124,11 +1133,20 @@ namespace Ryujinx.Graphics.Gpu.Image
{ {
List<CacheEntryFromPoolKey> keysToRemove = null; List<CacheEntryFromPoolKey> keysToRemove = null;
foreach (CacheEntryFromPoolKey key in _cacheFromPool.Keys) foreach ((CacheEntryFromPoolKey key, CacheEntry entry) in _cacheFromPool)
{ {
if (key.MatchesPool(pool)) if (key.MatchesPool(pool))
{ {
(keysToRemove ??= new()).Add(key); (keysToRemove ??= new()).Add(key);
if (key.IsImage)
{
entry.ImageArray.Dispose();
}
else
{
entry.TextureArray.Dispose();
}
} }
} }

View file

@ -63,5 +63,9 @@ namespace Ryujinx.Graphics.OpenGL.Image
} }
} }
} }
public void Dispose()
{
}
} }
} }

View file

@ -48,5 +48,9 @@ namespace Ryujinx.Graphics.OpenGL.Image
} }
} }
} }
public void Dispose()
{
}
} }
} }

View file

@ -98,11 +98,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
Logger = parameters.Logger; Logger = parameters.Logger;
TargetApi = parameters.TargetApi; TargetApi = parameters.TargetApi;
AddCapability(Capability.Shader);
AddCapability(Capability.Float64);
SetMemoryModel(AddressingModel.Logical, MemoryModel.GLSL450);
Delegates = new SpirvDelegates(this); Delegates = new SpirvDelegates(this);
} }

View file

@ -43,6 +43,10 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
CodeGenContext context = new(info, parameters, instPool, integerPool); CodeGenContext context = new(info, parameters, instPool, integerPool);
context.AddCapability(Capability.Shader);
context.SetMemoryModel(AddressingModel.Logical, MemoryModel.GLSL450);
context.AddCapability(Capability.GroupNonUniformBallot); context.AddCapability(Capability.GroupNonUniformBallot);
context.AddCapability(Capability.GroupNonUniformShuffle); context.AddCapability(Capability.GroupNonUniformShuffle);
context.AddCapability(Capability.GroupNonUniformVote); context.AddCapability(Capability.GroupNonUniformVote);
@ -51,6 +55,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
context.AddCapability(Capability.ImageQuery); context.AddCapability(Capability.ImageQuery);
context.AddCapability(Capability.SampledBuffer); context.AddCapability(Capability.SampledBuffer);
if (parameters.HostCapabilities.SupportsShaderFloat64)
{
context.AddCapability(Capability.Float64);
}
if (parameters.Definitions.TransformFeedbackEnabled && parameters.Definitions.LastInVertexPipeline) if (parameters.Definitions.TransformFeedbackEnabled && parameters.Definitions.LastInVertexPipeline)
{ {
context.AddCapability(Capability.TransformFeedback); context.AddCapability(Capability.TransformFeedback);
@ -58,7 +67,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
if (parameters.Definitions.Stage == ShaderStage.Fragment) if (parameters.Definitions.Stage == ShaderStage.Fragment)
{ {
if (context.Info.IoDefinitions.Contains(new IoDefinition(StorageKind.Input, IoVariable.Layer))) if (context.Info.IoDefinitions.Contains(new IoDefinition(StorageKind.Input, IoVariable.Layer)) ||
context.Info.IoDefinitions.Contains(new IoDefinition(StorageKind.Input, IoVariable.PrimitiveId)))
{ {
context.AddCapability(Capability.Geometry); context.AddCapability(Capability.Geometry);
} }

View file

@ -8,6 +8,7 @@ namespace Ryujinx.Graphics.Shader.Translation
public readonly bool SupportsGeometryShaderPassthrough; public readonly bool SupportsGeometryShaderPassthrough;
public readonly bool SupportsShaderBallot; public readonly bool SupportsShaderBallot;
public readonly bool SupportsShaderBarrierDivergence; public readonly bool SupportsShaderBarrierDivergence;
public readonly bool SupportsShaderFloat64;
public readonly bool SupportsTextureShadowLod; public readonly bool SupportsTextureShadowLod;
public readonly bool SupportsViewportMask; public readonly bool SupportsViewportMask;
@ -18,6 +19,7 @@ namespace Ryujinx.Graphics.Shader.Translation
bool supportsGeometryShaderPassthrough, bool supportsGeometryShaderPassthrough,
bool supportsShaderBallot, bool supportsShaderBallot,
bool supportsShaderBarrierDivergence, bool supportsShaderBarrierDivergence,
bool supportsShaderFloat64,
bool supportsTextureShadowLod, bool supportsTextureShadowLod,
bool supportsViewportMask) bool supportsViewportMask)
{ {
@ -27,6 +29,7 @@ namespace Ryujinx.Graphics.Shader.Translation
SupportsGeometryShaderPassthrough = supportsGeometryShaderPassthrough; SupportsGeometryShaderPassthrough = supportsGeometryShaderPassthrough;
SupportsShaderBallot = supportsShaderBallot; SupportsShaderBallot = supportsShaderBallot;
SupportsShaderBarrierDivergence = supportsShaderBarrierDivergence; SupportsShaderBarrierDivergence = supportsShaderBarrierDivergence;
SupportsShaderFloat64 = supportsShaderFloat64;
SupportsTextureShadowLod = supportsTextureShadowLod; SupportsTextureShadowLod = supportsTextureShadowLod;
SupportsViewportMask = supportsViewportMask; SupportsViewportMask = supportsViewportMask;
} }

View file

@ -363,6 +363,7 @@ namespace Ryujinx.Graphics.Shader.Translation
GpuAccessor.QueryHostSupportsGeometryShaderPassthrough(), GpuAccessor.QueryHostSupportsGeometryShaderPassthrough(),
GpuAccessor.QueryHostSupportsShaderBallot(), GpuAccessor.QueryHostSupportsShaderBallot(),
GpuAccessor.QueryHostSupportsShaderBarrierDivergence(), GpuAccessor.QueryHostSupportsShaderBarrierDivergence(),
GpuAccessor.QueryHostSupportsShaderFloat64(),
GpuAccessor.QueryHostSupportsTextureShadowLod(), GpuAccessor.QueryHostSupportsTextureShadowLod(),
GpuAccessor.QueryHostSupportsViewportMask()); GpuAccessor.QueryHostSupportsViewportMask());

View file

@ -291,8 +291,9 @@ namespace Ryujinx.Graphics.Vulkan
} }
else else
{ {
PipelineStageFlags stageFlags = _textureArrayRefs[segment.Binding].Stage.ConvertToPipelineStageFlags(); ref var arrayRef = ref _textureArrayRefs[segment.Binding];
_textureArrayRefs[segment.Binding].Array?.QueueWriteToReadBarriers(cbs, stageFlags); PipelineStageFlags stageFlags = arrayRef.Stage.ConvertToPipelineStageFlags();
arrayRef.Array?.QueueWriteToReadBarriers(cbs, stageFlags);
} }
} }
} }
@ -311,8 +312,40 @@ namespace Ryujinx.Graphics.Vulkan
} }
else else
{ {
PipelineStageFlags stageFlags = _imageArrayRefs[segment.Binding].Stage.ConvertToPipelineStageFlags(); ref var arrayRef = ref _imageArrayRefs[segment.Binding];
_imageArrayRefs[segment.Binding].Array?.QueueWriteToReadBarriers(cbs, stageFlags); PipelineStageFlags stageFlags = arrayRef.Stage.ConvertToPipelineStageFlags();
arrayRef.Array?.QueueWriteToReadBarriers(cbs, stageFlags);
}
}
}
for (int setIndex = PipelineBase.DescriptorSetLayouts; setIndex < _program.BindingSegments.Length; setIndex++)
{
var bindingSegments = _program.BindingSegments[setIndex];
if (bindingSegments.Length == 0)
{
continue;
}
ResourceBindingSegment segment = bindingSegments[0];
if (segment.IsArray)
{
if (segment.Type == ResourceType.Texture ||
segment.Type == ResourceType.Sampler ||
segment.Type == ResourceType.TextureAndSampler ||
segment.Type == ResourceType.BufferTexture)
{
ref var arrayRef = ref _textureArrayExtraRefs[setIndex - PipelineBase.DescriptorSetLayouts];
PipelineStageFlags stageFlags = arrayRef.Stage.ConvertToPipelineStageFlags();
arrayRef.Array?.QueueWriteToReadBarriers(cbs, stageFlags);
}
else if (segment.Type == ResourceType.Image || segment.Type == ResourceType.BufferImage)
{
ref var arrayRef = ref _imageArrayExtraRefs[setIndex - PipelineBase.DescriptorSetLayouts];
PipelineStageFlags stageFlags = arrayRef.Stage.ConvertToPipelineStageFlags();
arrayRef.Array?.QueueWriteToReadBarriers(cbs, stageFlags);
} }
} }
} }

View file

@ -2,11 +2,10 @@ 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.Diagnostics;
namespace Ryujinx.Graphics.Vulkan namespace Ryujinx.Graphics.Vulkan
{ {
class ImageArray : IImageArray class ImageArray : ResourceArray, IImageArray
{ {
private readonly VulkanRenderer _gd; private readonly VulkanRenderer _gd;
@ -25,19 +24,11 @@ namespace Ryujinx.Graphics.Vulkan
private HashSet<TextureStorage> _storages; private HashSet<TextureStorage> _storages;
private DescriptorSet[] _cachedDescriptorSets;
private int _cachedCommandBufferIndex; private int _cachedCommandBufferIndex;
private int _cachedSubmissionCount; private int _cachedSubmissionCount;
private ShaderCollection _cachedDscProgram;
private int _cachedDscSetIndex;
private int _cachedDscIndex;
private readonly bool _isBuffer; private readonly bool _isBuffer;
private int _bindCount;
public ImageArray(VulkanRenderer gd, int size, bool isBuffer) public ImageArray(VulkanRenderer gd, int size, bool isBuffer)
{ {
_gd = gd; _gd = gd;
@ -104,12 +95,7 @@ namespace Ryujinx.Graphics.Vulkan
{ {
_cachedCommandBufferIndex = -1; _cachedCommandBufferIndex = -1;
_storages = null; _storages = null;
_cachedDescriptorSets = null; SetDirty(_gd);
if (_bindCount != 0)
{
_gd.PipelineInternal.ForceImageDirty();
}
} }
public void QueueWriteToReadBarriers(CommandBufferScoped cbs, PipelineStageFlags stageFlags) public void QueueWriteToReadBarriers(CommandBufferScoped cbs, PipelineStageFlags stageFlags)
@ -195,7 +181,7 @@ namespace Ryujinx.Graphics.Vulkan
int setIndex, int setIndex,
TextureView dummyTexture) TextureView dummyTexture)
{ {
if (_cachedDescriptorSets != null) if (TryGetCachedDescriptorSets(cbs, program, setIndex, out DescriptorSet[] sets))
{ {
// We still need to ensure the current command buffer holds a reference to all used textures. // We still need to ensure the current command buffer holds a reference to all used textures.
@ -208,12 +194,9 @@ namespace Ryujinx.Graphics.Vulkan
GetBufferViews(cbs); GetBufferViews(cbs);
} }
return _cachedDescriptorSets; return sets;
} }
_cachedDscProgram?.ReleaseManualDescriptorSetCollection(_cachedDscSetIndex, _cachedDscIndex);
var dsc = program.GetNewManualDescriptorSetCollection(cbs.CommandBufferIndex, setIndex, out _cachedDscIndex).Get(cbs);
DescriptorSetTemplate template = program.Templates[setIndex]; DescriptorSetTemplate template = program.Templates[setIndex];
DescriptorSetTemplateWriter tu = templateUpdater.Begin(template); DescriptorSetTemplateWriter tu = templateUpdater.Begin(template);
@ -227,24 +210,9 @@ namespace Ryujinx.Graphics.Vulkan
tu.Push(GetBufferViews(cbs)); tu.Push(GetBufferViews(cbs));
} }
var sets = dsc.GetSets();
templateUpdater.Commit(_gd, device, sets[0]); templateUpdater.Commit(_gd, device, sets[0]);
_cachedDescriptorSets = sets;
_cachedDscProgram = program;
_cachedDscSetIndex = setIndex;
return sets; return sets;
} }
public void IncrementBindCount()
{
_bindCount++;
}
public void DecrementBindCount()
{
int newBindCount = --_bindCount;
Debug.Assert(newBindCount >= 0);
}
} }
} }

View file

@ -180,9 +180,6 @@ namespace Ryujinx.Graphics.Vulkan
pipeline.LogicOpEnable = state.LogicOpEnable; pipeline.LogicOpEnable = state.LogicOpEnable;
pipeline.LogicOp = state.LogicOp.Convert(); pipeline.LogicOp = state.LogicOp.Convert();
pipeline.MinDepthBounds = 0f; // Not implemented.
pipeline.MaxDepthBounds = 0f; // Not implemented.
pipeline.PatchControlPoints = state.PatchControlPoints; pipeline.PatchControlPoints = state.PatchControlPoints;
pipeline.PolygonMode = PolygonMode.Fill; // Not implemented. pipeline.PolygonMode = PolygonMode.Fill; // Not implemented.
pipeline.PrimitiveRestartEnable = state.PrimitiveRestartEnable; pipeline.PrimitiveRestartEnable = state.PrimitiveRestartEnable;
@ -208,17 +205,11 @@ namespace Ryujinx.Graphics.Vulkan
pipeline.StencilFrontPassOp = state.StencilTest.FrontDpPass.Convert(); pipeline.StencilFrontPassOp = state.StencilTest.FrontDpPass.Convert();
pipeline.StencilFrontDepthFailOp = state.StencilTest.FrontDpFail.Convert(); pipeline.StencilFrontDepthFailOp = state.StencilTest.FrontDpFail.Convert();
pipeline.StencilFrontCompareOp = state.StencilTest.FrontFunc.Convert(); pipeline.StencilFrontCompareOp = state.StencilTest.FrontFunc.Convert();
pipeline.StencilFrontCompareMask = 0;
pipeline.StencilFrontWriteMask = 0;
pipeline.StencilFrontReference = 0;
pipeline.StencilBackFailOp = state.StencilTest.BackSFail.Convert(); pipeline.StencilBackFailOp = state.StencilTest.BackSFail.Convert();
pipeline.StencilBackPassOp = state.StencilTest.BackDpPass.Convert(); pipeline.StencilBackPassOp = state.StencilTest.BackDpPass.Convert();
pipeline.StencilBackDepthFailOp = state.StencilTest.BackDpFail.Convert(); pipeline.StencilBackDepthFailOp = state.StencilTest.BackDpFail.Convert();
pipeline.StencilBackCompareOp = state.StencilTest.BackFunc.Convert(); pipeline.StencilBackCompareOp = state.StencilTest.BackFunc.Convert();
pipeline.StencilBackCompareMask = 0;
pipeline.StencilBackWriteMask = 0;
pipeline.StencilBackReference = 0;
pipeline.StencilTestEnable = state.StencilTest.TestEnable; pipeline.StencilTestEnable = state.StencilTest.TestEnable;

View file

@ -3,6 +3,7 @@ using Silk.NET.Vulkan;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.Vulkan namespace Ryujinx.Graphics.Vulkan
@ -15,6 +16,7 @@ namespace Ryujinx.Graphics.Vulkan
private readonly Device _device; private readonly Device _device;
public DescriptorSetLayout[] DescriptorSetLayouts { get; } public DescriptorSetLayout[] DescriptorSetLayouts { get; }
public bool[] DescriptorSetLayoutsUpdateAfterBind { get; }
public PipelineLayout PipelineLayout { get; } public PipelineLayout PipelineLayout { get; }
private readonly int[] _consumedDescriptorsPerSet; private readonly int[] _consumedDescriptorsPerSet;
@ -31,20 +33,37 @@ namespace Ryujinx.Graphics.Vulkan
private struct ManualDescriptorSetEntry private struct ManualDescriptorSetEntry
{ {
public Auto<DescriptorSetCollection> DescriptorSet; public Auto<DescriptorSetCollection> DescriptorSet;
public int CbIndex; public uint CbRefMask;
public int CbSubmissionCount;
public bool InUse; public bool InUse;
public ManualDescriptorSetEntry(Auto<DescriptorSetCollection> descriptorSet, int cbIndex, int cbSubmissionCount, bool inUse) public ManualDescriptorSetEntry(Auto<DescriptorSetCollection> descriptorSet, int cbIndex)
{ {
DescriptorSet = descriptorSet; DescriptorSet = descriptorSet;
CbIndex = cbIndex; CbRefMask = 1u << cbIndex;
CbSubmissionCount = cbSubmissionCount; InUse = true;
InUse = inUse; }
}
private readonly struct PendingManualDsConsumption
{
public FenceHolder Fence { get; }
public int CommandBufferIndex { get; }
public int SetIndex { get; }
public int CacheIndex { get; }
public PendingManualDsConsumption(FenceHolder fence, int commandBufferIndex, int setIndex, int cacheIndex)
{
Fence = fence;
CommandBufferIndex = commandBufferIndex;
SetIndex = setIndex;
CacheIndex = cacheIndex;
fence.Get();
} }
} }
private readonly List<ManualDescriptorSetEntry>[] _manualDsCache; private readonly List<ManualDescriptorSetEntry>[] _manualDsCache;
private readonly Queue<PendingManualDsConsumption> _pendingManualDsConsumptions;
private readonly Queue<int>[] _freeManualDsCacheEntries;
private readonly Dictionary<long, DescriptorSetTemplate> _pdTemplates; private readonly Dictionary<long, DescriptorSetTemplate> _pdTemplates;
private readonly ResourceDescriptorCollection _pdDescriptors; private readonly ResourceDescriptorCollection _pdDescriptors;
@ -70,6 +89,8 @@ namespace Ryujinx.Graphics.Vulkan
_dsCacheCursor = new int[setsCount]; _dsCacheCursor = new int[setsCount];
_manualDsCache = new List<ManualDescriptorSetEntry>[setsCount]; _manualDsCache = new List<ManualDescriptorSetEntry>[setsCount];
_pendingManualDsConsumptions = new Queue<PendingManualDsConsumption>();
_freeManualDsCacheEntries = new Queue<int>[setsCount];
} }
public PipelineLayoutCacheEntry( public PipelineLayoutCacheEntry(
@ -78,7 +99,11 @@ namespace Ryujinx.Graphics.Vulkan
ReadOnlyCollection<ResourceDescriptorCollection> setDescriptors, ReadOnlyCollection<ResourceDescriptorCollection> setDescriptors,
bool usePushDescriptors) : this(gd, device, setDescriptors.Count) bool usePushDescriptors) : this(gd, device, setDescriptors.Count)
{ {
(DescriptorSetLayouts, PipelineLayout) = PipelineLayoutFactory.Create(gd, device, setDescriptors, usePushDescriptors); ResourceLayouts layouts = PipelineLayoutFactory.Create(gd, device, setDescriptors, usePushDescriptors);
DescriptorSetLayouts = layouts.DescriptorSetLayouts;
DescriptorSetLayoutsUpdateAfterBind = layouts.DescriptorSetLayoutsUpdateAfterBind;
PipelineLayout = layouts.PipelineLayout;
_consumedDescriptorsPerSet = new int[setDescriptors.Count]; _consumedDescriptorsPerSet = new int[setDescriptors.Count];
_poolSizes = new DescriptorPoolSize[setDescriptors.Count][]; _poolSizes = new DescriptorPoolSize[setDescriptors.Count][];
@ -133,7 +158,7 @@ namespace Ryujinx.Graphics.Vulkan
_poolSizes[setIndex], _poolSizes[setIndex],
setIndex, setIndex,
_consumedDescriptorsPerSet[setIndex], _consumedDescriptorsPerSet[setIndex],
false); DescriptorSetLayoutsUpdateAfterBind[setIndex]);
list.Add(dsc); list.Add(dsc);
isNew = true; isNew = true;
@ -144,49 +169,99 @@ namespace Ryujinx.Graphics.Vulkan
return list[index]; return list[index];
} }
public Auto<DescriptorSetCollection> GetNewManualDescriptorSetCollection(int commandBufferIndex, int setIndex, out int cacheIndex) public Auto<DescriptorSetCollection> GetNewManualDescriptorSetCollection(CommandBufferScoped cbs, int setIndex, out int cacheIndex)
{ {
int submissionCount = _gd.CommandBufferPool.GetSubmissionCount(commandBufferIndex); FreeCompletedManualDescriptorSets();
var list = _manualDsCache[setIndex] ??= new(); var list = _manualDsCache[setIndex] ??= new();
var span = CollectionsMarshal.AsSpan(list); var span = CollectionsMarshal.AsSpan(list);
for (int index = 0; index < span.Length; index++) Queue<int> freeQueue = _freeManualDsCacheEntries[setIndex];
{
ref ManualDescriptorSetEntry entry = ref span[index];
if (!entry.InUse && (entry.CbIndex != commandBufferIndex || entry.CbSubmissionCount != submissionCount)) // Do we have at least one freed descriptor set? If so, just use that.
if (freeQueue != null && freeQueue.TryDequeue(out int freeIndex))
{ {
ref ManualDescriptorSetEntry entry = ref span[freeIndex];
Debug.Assert(!entry.InUse && entry.CbRefMask == 0);
entry.InUse = true; entry.InUse = true;
entry.CbIndex = commandBufferIndex; entry.CbRefMask = 1u << cbs.CommandBufferIndex;
entry.CbSubmissionCount = submissionCount; cacheIndex = freeIndex;
cacheIndex = index; _pendingManualDsConsumptions.Enqueue(new PendingManualDsConsumption(cbs.GetFence(), cbs.CommandBufferIndex, setIndex, freeIndex));
return entry.DescriptorSet; return entry.DescriptorSet;
} }
}
// Otherwise create a new descriptor set, and add to our pending queue for command buffer consumption tracking.
var dsc = _descriptorSetManager.AllocateDescriptorSet( var dsc = _descriptorSetManager.AllocateDescriptorSet(
_gd.Api, _gd.Api,
DescriptorSetLayouts[setIndex], DescriptorSetLayouts[setIndex],
_poolSizes[setIndex], _poolSizes[setIndex],
setIndex, setIndex,
_consumedDescriptorsPerSet[setIndex], _consumedDescriptorsPerSet[setIndex],
false); DescriptorSetLayoutsUpdateAfterBind[setIndex]);
cacheIndex = list.Count; cacheIndex = list.Count;
list.Add(new ManualDescriptorSetEntry(dsc, commandBufferIndex, submissionCount, inUse: true)); list.Add(new ManualDescriptorSetEntry(dsc, cbs.CommandBufferIndex));
_pendingManualDsConsumptions.Enqueue(new PendingManualDsConsumption(cbs.GetFence(), cbs.CommandBufferIndex, setIndex, cacheIndex));
return dsc; return dsc;
} }
public void UpdateManualDescriptorSetCollectionOwnership(CommandBufferScoped cbs, int setIndex, int cacheIndex)
{
FreeCompletedManualDescriptorSets();
var list = _manualDsCache[setIndex];
var span = CollectionsMarshal.AsSpan(list);
ref var entry = ref span[cacheIndex];
uint cbMask = 1u << cbs.CommandBufferIndex;
if ((entry.CbRefMask & cbMask) == 0)
{
entry.CbRefMask |= cbMask;
_pendingManualDsConsumptions.Enqueue(new PendingManualDsConsumption(cbs.GetFence(), cbs.CommandBufferIndex, setIndex, cacheIndex));
}
}
private void FreeCompletedManualDescriptorSets()
{
FenceHolder signalledFence = null;
while (_pendingManualDsConsumptions.TryPeek(out var pds) && (pds.Fence == signalledFence || pds.Fence.IsSignaled()))
{
signalledFence = pds.Fence; // Already checked - don't need to do it again.
var dequeued = _pendingManualDsConsumptions.Dequeue();
Debug.Assert(dequeued.Fence == pds.Fence);
pds.Fence.Put();
var span = CollectionsMarshal.AsSpan(_manualDsCache[dequeued.SetIndex]);
ref var entry = ref span[dequeued.CacheIndex];
entry.CbRefMask &= ~(1u << dequeued.CommandBufferIndex);
if (!entry.InUse && entry.CbRefMask == 0)
{
// If not in use by any array, and not bound to any command buffer, the descriptor set can be re-used immediately.
(_freeManualDsCacheEntries[dequeued.SetIndex] ??= new()).Enqueue(dequeued.CacheIndex);
}
}
}
public void ReleaseManualDescriptorSetCollection(int setIndex, int cacheIndex) public void ReleaseManualDescriptorSetCollection(int setIndex, int cacheIndex)
{ {
var list = _manualDsCache[setIndex]; var list = _manualDsCache[setIndex];
var span = CollectionsMarshal.AsSpan(list); var span = CollectionsMarshal.AsSpan(list);
span[cacheIndex].InUse = false; span[cacheIndex].InUse = false;
if (span[cacheIndex].CbRefMask == 0)
{
// This is no longer in use by any array, so if not bound to any command buffer, the descriptor set can be re-used immediately.
(_freeManualDsCacheEntries[setIndex] ??= new()).Enqueue(cacheIndex);
}
} }
private static Span<DescriptorPoolSize> GetDescriptorPoolSizes(Span<DescriptorPoolSize> output, ResourceDescriptorCollection setDescriptor, uint multiplier) private static Span<DescriptorPoolSize> GetDescriptorPoolSizes(Span<DescriptorPoolSize> output, ResourceDescriptorCollection setDescriptor, uint multiplier)
@ -291,6 +366,11 @@ namespace Ryujinx.Graphics.Vulkan
_gd.Api.DestroyDescriptorSetLayout(_device, DescriptorSetLayouts[i], null); _gd.Api.DestroyDescriptorSetLayout(_device, DescriptorSetLayouts[i], null);
} }
while (_pendingManualDsConsumptions.TryDequeue(out var pds))
{
pds.Fence.Put();
}
_descriptorSetManager.Dispose(); _descriptorSetManager.Dispose();
} }
} }

View file

@ -1,18 +1,23 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Silk.NET.Vulkan; using Silk.NET.Vulkan;
using System;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
namespace Ryujinx.Graphics.Vulkan namespace Ryujinx.Graphics.Vulkan
{ {
record struct ResourceLayouts(DescriptorSetLayout[] DescriptorSetLayouts, bool[] DescriptorSetLayoutsUpdateAfterBind, PipelineLayout PipelineLayout);
static class PipelineLayoutFactory static class PipelineLayoutFactory
{ {
public static unsafe (DescriptorSetLayout[], PipelineLayout) Create( public static unsafe ResourceLayouts Create(
VulkanRenderer gd, VulkanRenderer gd,
Device device, Device device,
ReadOnlyCollection<ResourceDescriptorCollection> setDescriptors, ReadOnlyCollection<ResourceDescriptorCollection> setDescriptors,
bool usePushDescriptors) bool usePushDescriptors)
{ {
DescriptorSetLayout[] layouts = new DescriptorSetLayout[setDescriptors.Count]; DescriptorSetLayout[] layouts = new DescriptorSetLayout[setDescriptors.Count];
bool[] updateAfterBindFlags = new bool[setDescriptors.Count];
bool isMoltenVk = gd.IsMoltenVk; bool isMoltenVk = gd.IsMoltenVk;
@ -32,10 +37,11 @@ namespace Ryujinx.Graphics.Vulkan
DescriptorSetLayoutBinding[] layoutBindings = new DescriptorSetLayoutBinding[rdc.Descriptors.Count]; DescriptorSetLayoutBinding[] layoutBindings = new DescriptorSetLayoutBinding[rdc.Descriptors.Count];
bool hasArray = false;
for (int descIndex = 0; descIndex < rdc.Descriptors.Count; descIndex++) for (int descIndex = 0; descIndex < rdc.Descriptors.Count; descIndex++)
{ {
ResourceDescriptor descriptor = rdc.Descriptors[descIndex]; ResourceDescriptor descriptor = rdc.Descriptors[descIndex];
ResourceStages stages = descriptor.Stages; ResourceStages stages = descriptor.Stages;
if (descriptor.Type == ResourceType.StorageBuffer && isMoltenVk) if (descriptor.Type == ResourceType.StorageBuffer && isMoltenVk)
@ -52,16 +58,37 @@ namespace Ryujinx.Graphics.Vulkan
DescriptorCount = (uint)descriptor.Count, DescriptorCount = (uint)descriptor.Count,
StageFlags = stages.Convert(), StageFlags = stages.Convert(),
}; };
if (descriptor.Count > 1)
{
hasArray = true;
}
} }
fixed (DescriptorSetLayoutBinding* pLayoutBindings = layoutBindings) fixed (DescriptorSetLayoutBinding* pLayoutBindings = layoutBindings)
{ {
DescriptorSetLayoutCreateFlags flags = DescriptorSetLayoutCreateFlags.None;
if (usePushDescriptors && setIndex == 0)
{
flags = DescriptorSetLayoutCreateFlags.PushDescriptorBitKhr;
}
if (gd.Vendor == Vendor.Intel && hasArray)
{
// Some vendors (like Intel) have low per-stage limits.
// We must set the flag if we exceed those limits.
flags |= DescriptorSetLayoutCreateFlags.UpdateAfterBindPoolBit;
updateAfterBindFlags[setIndex] = true;
}
var descriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo var descriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo
{ {
SType = StructureType.DescriptorSetLayoutCreateInfo, SType = StructureType.DescriptorSetLayoutCreateInfo,
PBindings = pLayoutBindings, PBindings = pLayoutBindings,
BindingCount = (uint)layoutBindings.Length, BindingCount = (uint)layoutBindings.Length,
Flags = usePushDescriptors && setIndex == 0 ? DescriptorSetLayoutCreateFlags.PushDescriptorBitKhr : DescriptorSetLayoutCreateFlags.None, Flags = flags,
}; };
gd.Api.CreateDescriptorSetLayout(device, descriptorSetLayoutCreateInfo, null, out layouts[setIndex]).ThrowOnError(); gd.Api.CreateDescriptorSetLayout(device, descriptorSetLayoutCreateInfo, null, out layouts[setIndex]).ThrowOnError();
@ -82,7 +109,7 @@ namespace Ryujinx.Graphics.Vulkan
gd.Api.CreatePipelineLayout(device, &pipelineLayoutCreateInfo, null, out layout).ThrowOnError(); gd.Api.CreatePipelineLayout(device, &pipelineLayoutCreateInfo, null, out layout).ThrowOnError();
} }
return (layouts, layout); return new ResourceLayouts(layouts, updateAfterBindFlags, layout);
} }
} }
} }

View file

@ -71,244 +71,232 @@ namespace Ryujinx.Graphics.Vulkan
set => Internal.Id4 = (Internal.Id4 & 0xFFFFFFFF) | ((ulong)value << 32); set => Internal.Id4 = (Internal.Id4 & 0xFFFFFFFF) | ((ulong)value << 32);
} }
public float MinDepthBounds
{
readonly get => BitConverter.Int32BitsToSingle((int)((Internal.Id5 >> 0) & 0xFFFFFFFF));
set => Internal.Id5 = (Internal.Id5 & 0xFFFFFFFF00000000) | ((ulong)(uint)BitConverter.SingleToInt32Bits(value) << 0);
}
public float MaxDepthBounds
{
readonly get => BitConverter.Int32BitsToSingle((int)((Internal.Id5 >> 32) & 0xFFFFFFFF));
set => Internal.Id5 = (Internal.Id5 & 0xFFFFFFFF) | ((ulong)(uint)BitConverter.SingleToInt32Bits(value) << 32);
}
public PolygonMode PolygonMode public PolygonMode PolygonMode
{ {
readonly get => (PolygonMode)((Internal.Id6 >> 0) & 0x3FFFFFFF); readonly get => (PolygonMode)((Internal.Id5 >> 0) & 0x3FFFFFFF);
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFC0000000) | ((ulong)value << 0); set => Internal.Id5 = (Internal.Id5 & 0xFFFFFFFFC0000000) | ((ulong)value << 0);
} }
public uint StagesCount public uint StagesCount
{ {
readonly get => (byte)((Internal.Id6 >> 30) & 0xFF); readonly get => (byte)((Internal.Id5 >> 30) & 0xFF);
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFC03FFFFFFF) | ((ulong)value << 30); set => Internal.Id5 = (Internal.Id5 & 0xFFFFFFC03FFFFFFF) | ((ulong)value << 30);
} }
public uint VertexAttributeDescriptionsCount public uint VertexAttributeDescriptionsCount
{ {
readonly get => (byte)((Internal.Id6 >> 38) & 0xFF); readonly get => (byte)((Internal.Id5 >> 38) & 0xFF);
set => Internal.Id6 = (Internal.Id6 & 0xFFFFC03FFFFFFFFF) | ((ulong)value << 38); set => Internal.Id5 = (Internal.Id5 & 0xFFFFC03FFFFFFFFF) | ((ulong)value << 38);
} }
public uint VertexBindingDescriptionsCount public uint VertexBindingDescriptionsCount
{ {
readonly get => (byte)((Internal.Id6 >> 46) & 0xFF); readonly get => (byte)((Internal.Id5 >> 46) & 0xFF);
set => Internal.Id6 = (Internal.Id6 & 0xFFC03FFFFFFFFFFF) | ((ulong)value << 46); set => Internal.Id5 = (Internal.Id5 & 0xFFC03FFFFFFFFFFF) | ((ulong)value << 46);
} }
public uint ViewportsCount public uint ViewportsCount
{ {
readonly get => (byte)((Internal.Id6 >> 54) & 0xFF); readonly get => (byte)((Internal.Id5 >> 54) & 0xFF);
set => Internal.Id6 = (Internal.Id6 & 0xC03FFFFFFFFFFFFF) | ((ulong)value << 54); set => Internal.Id5 = (Internal.Id5 & 0xC03FFFFFFFFFFFFF) | ((ulong)value << 54);
} }
public uint ScissorsCount public uint ScissorsCount
{ {
readonly get => (byte)((Internal.Id7 >> 0) & 0xFF); readonly get => (byte)((Internal.Id6 >> 0) & 0xFF);
set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFFFFFFFF00) | ((ulong)value << 0); set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFFFFFFF00) | ((ulong)value << 0);
} }
public uint ColorBlendAttachmentStateCount public uint ColorBlendAttachmentStateCount
{ {
readonly get => (byte)((Internal.Id7 >> 8) & 0xFF); readonly get => (byte)((Internal.Id6 >> 8) & 0xFF);
set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFFFFFF00FF) | ((ulong)value << 8); set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFFFFF00FF) | ((ulong)value << 8);
} }
public PrimitiveTopology Topology public PrimitiveTopology Topology
{ {
readonly get => (PrimitiveTopology)((Internal.Id7 >> 16) & 0xF); readonly get => (PrimitiveTopology)((Internal.Id6 >> 16) & 0xF);
set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFFFFF0FFFF) | ((ulong)value << 16); set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFFFF0FFFF) | ((ulong)value << 16);
} }
public LogicOp LogicOp public LogicOp LogicOp
{ {
readonly get => (LogicOp)((Internal.Id7 >> 20) & 0xF); readonly get => (LogicOp)((Internal.Id6 >> 20) & 0xF);
set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFFFF0FFFFF) | ((ulong)value << 20); set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFFF0FFFFF) | ((ulong)value << 20);
} }
public CompareOp DepthCompareOp public CompareOp DepthCompareOp
{ {
readonly get => (CompareOp)((Internal.Id7 >> 24) & 0x7); readonly get => (CompareOp)((Internal.Id6 >> 24) & 0x7);
set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFFF8FFFFFF) | ((ulong)value << 24); set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFF8FFFFFF) | ((ulong)value << 24);
} }
public StencilOp StencilFrontFailOp public StencilOp StencilFrontFailOp
{ {
readonly get => (StencilOp)((Internal.Id7 >> 27) & 0x7); readonly get => (StencilOp)((Internal.Id6 >> 27) & 0x7);
set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFFC7FFFFFF) | ((ulong)value << 27); set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFC7FFFFFF) | ((ulong)value << 27);
} }
public StencilOp StencilFrontPassOp public StencilOp StencilFrontPassOp
{ {
readonly get => (StencilOp)((Internal.Id7 >> 30) & 0x7); readonly get => (StencilOp)((Internal.Id6 >> 30) & 0x7);
set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFE3FFFFFFF) | ((ulong)value << 30); set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFE3FFFFFFF) | ((ulong)value << 30);
} }
public StencilOp StencilFrontDepthFailOp public StencilOp StencilFrontDepthFailOp
{ {
readonly get => (StencilOp)((Internal.Id7 >> 33) & 0x7); readonly get => (StencilOp)((Internal.Id6 >> 33) & 0x7);
set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFF1FFFFFFFF) | ((ulong)value << 33); set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFF1FFFFFFFF) | ((ulong)value << 33);
} }
public CompareOp StencilFrontCompareOp public CompareOp StencilFrontCompareOp
{ {
readonly get => (CompareOp)((Internal.Id7 >> 36) & 0x7); readonly get => (CompareOp)((Internal.Id6 >> 36) & 0x7);
set => Internal.Id7 = (Internal.Id7 & 0xFFFFFF8FFFFFFFFF) | ((ulong)value << 36); set => Internal.Id6 = (Internal.Id6 & 0xFFFFFF8FFFFFFFFF) | ((ulong)value << 36);
} }
public StencilOp StencilBackFailOp public StencilOp StencilBackFailOp
{ {
readonly get => (StencilOp)((Internal.Id7 >> 39) & 0x7); readonly get => (StencilOp)((Internal.Id6 >> 39) & 0x7);
set => Internal.Id7 = (Internal.Id7 & 0xFFFFFC7FFFFFFFFF) | ((ulong)value << 39); set => Internal.Id6 = (Internal.Id6 & 0xFFFFFC7FFFFFFFFF) | ((ulong)value << 39);
} }
public StencilOp StencilBackPassOp public StencilOp StencilBackPassOp
{ {
readonly get => (StencilOp)((Internal.Id7 >> 42) & 0x7); readonly get => (StencilOp)((Internal.Id6 >> 42) & 0x7);
set => Internal.Id7 = (Internal.Id7 & 0xFFFFE3FFFFFFFFFF) | ((ulong)value << 42); set => Internal.Id6 = (Internal.Id6 & 0xFFFFE3FFFFFFFFFF) | ((ulong)value << 42);
} }
public StencilOp StencilBackDepthFailOp public StencilOp StencilBackDepthFailOp
{ {
readonly get => (StencilOp)((Internal.Id7 >> 45) & 0x7); readonly get => (StencilOp)((Internal.Id6 >> 45) & 0x7);
set => Internal.Id7 = (Internal.Id7 & 0xFFFF1FFFFFFFFFFF) | ((ulong)value << 45); set => Internal.Id6 = (Internal.Id6 & 0xFFFF1FFFFFFFFFFF) | ((ulong)value << 45);
} }
public CompareOp StencilBackCompareOp public CompareOp StencilBackCompareOp
{ {
readonly get => (CompareOp)((Internal.Id7 >> 48) & 0x7); readonly get => (CompareOp)((Internal.Id6 >> 48) & 0x7);
set => Internal.Id7 = (Internal.Id7 & 0xFFF8FFFFFFFFFFFF) | ((ulong)value << 48); set => Internal.Id6 = (Internal.Id6 & 0xFFF8FFFFFFFFFFFF) | ((ulong)value << 48);
} }
public CullModeFlags CullMode public CullModeFlags CullMode
{ {
readonly get => (CullModeFlags)((Internal.Id7 >> 51) & 0x3); readonly get => (CullModeFlags)((Internal.Id6 >> 51) & 0x3);
set => Internal.Id7 = (Internal.Id7 & 0xFFE7FFFFFFFFFFFF) | ((ulong)value << 51); set => Internal.Id6 = (Internal.Id6 & 0xFFE7FFFFFFFFFFFF) | ((ulong)value << 51);
} }
public bool PrimitiveRestartEnable public bool PrimitiveRestartEnable
{ {
readonly get => ((Internal.Id7 >> 53) & 0x1) != 0UL; readonly get => ((Internal.Id6 >> 53) & 0x1) != 0UL;
set => Internal.Id7 = (Internal.Id7 & 0xFFDFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 53); set => Internal.Id6 = (Internal.Id6 & 0xFFDFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 53);
} }
public bool DepthClampEnable public bool DepthClampEnable
{ {
readonly get => ((Internal.Id7 >> 54) & 0x1) != 0UL; readonly get => ((Internal.Id6 >> 54) & 0x1) != 0UL;
set => Internal.Id7 = (Internal.Id7 & 0xFFBFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 54); set => Internal.Id6 = (Internal.Id6 & 0xFFBFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 54);
} }
public bool RasterizerDiscardEnable public bool RasterizerDiscardEnable
{ {
readonly get => ((Internal.Id7 >> 55) & 0x1) != 0UL; readonly get => ((Internal.Id6 >> 55) & 0x1) != 0UL;
set => Internal.Id7 = (Internal.Id7 & 0xFF7FFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 55); set => Internal.Id6 = (Internal.Id6 & 0xFF7FFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 55);
} }
public FrontFace FrontFace public FrontFace FrontFace
{ {
readonly get => (FrontFace)((Internal.Id7 >> 56) & 0x1); readonly get => (FrontFace)((Internal.Id6 >> 56) & 0x1);
set => Internal.Id7 = (Internal.Id7 & 0xFEFFFFFFFFFFFFFF) | ((ulong)value << 56); set => Internal.Id6 = (Internal.Id6 & 0xFEFFFFFFFFFFFFFF) | ((ulong)value << 56);
} }
public bool DepthBiasEnable public bool DepthBiasEnable
{ {
readonly get => ((Internal.Id7 >> 57) & 0x1) != 0UL; readonly get => ((Internal.Id6 >> 57) & 0x1) != 0UL;
set => Internal.Id7 = (Internal.Id7 & 0xFDFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 57); set => Internal.Id6 = (Internal.Id6 & 0xFDFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 57);
} }
public bool DepthTestEnable public bool DepthTestEnable
{ {
readonly get => ((Internal.Id7 >> 58) & 0x1) != 0UL; readonly get => ((Internal.Id6 >> 58) & 0x1) != 0UL;
set => Internal.Id7 = (Internal.Id7 & 0xFBFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 58); set => Internal.Id6 = (Internal.Id6 & 0xFBFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 58);
} }
public bool DepthWriteEnable public bool DepthWriteEnable
{ {
readonly get => ((Internal.Id7 >> 59) & 0x1) != 0UL; readonly get => ((Internal.Id6 >> 59) & 0x1) != 0UL;
set => Internal.Id7 = (Internal.Id7 & 0xF7FFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 59); set => Internal.Id6 = (Internal.Id6 & 0xF7FFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 59);
} }
public bool DepthBoundsTestEnable public bool DepthBoundsTestEnable
{ {
readonly get => ((Internal.Id7 >> 60) & 0x1) != 0UL; readonly get => ((Internal.Id6 >> 60) & 0x1) != 0UL;
set => Internal.Id7 = (Internal.Id7 & 0xEFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 60); set => Internal.Id6 = (Internal.Id6 & 0xEFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 60);
} }
public bool StencilTestEnable public bool StencilTestEnable
{ {
readonly get => ((Internal.Id7 >> 61) & 0x1) != 0UL; readonly get => ((Internal.Id6 >> 61) & 0x1) != 0UL;
set => Internal.Id7 = (Internal.Id7 & 0xDFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 61); set => Internal.Id6 = (Internal.Id6 & 0xDFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 61);
} }
public bool LogicOpEnable public bool LogicOpEnable
{ {
readonly get => ((Internal.Id7 >> 62) & 0x1) != 0UL; readonly get => ((Internal.Id6 >> 62) & 0x1) != 0UL;
set => Internal.Id7 = (Internal.Id7 & 0xBFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 62); set => Internal.Id6 = (Internal.Id6 & 0xBFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 62);
} }
public bool HasDepthStencil public bool HasDepthStencil
{ {
readonly get => ((Internal.Id7 >> 63) & 0x1) != 0UL; readonly get => ((Internal.Id6 >> 63) & 0x1) != 0UL;
set => Internal.Id7 = (Internal.Id7 & 0x7FFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 63); set => Internal.Id6 = (Internal.Id6 & 0x7FFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 63);
} }
public uint PatchControlPoints public uint PatchControlPoints
{ {
readonly get => (uint)((Internal.Id8 >> 0) & 0xFFFFFFFF); readonly get => (uint)((Internal.Id7 >> 0) & 0xFFFFFFFF);
set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFF00000000) | ((ulong)value << 0); set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFF00000000) | ((ulong)value << 0);
} }
public uint SamplesCount public uint SamplesCount
{ {
readonly get => (uint)((Internal.Id8 >> 32) & 0xFFFFFFFF); readonly get => (uint)((Internal.Id7 >> 32) & 0xFFFFFFFF);
set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFF) | ((ulong)value << 32); set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFF) | ((ulong)value << 32);
} }
public bool AlphaToCoverageEnable public bool AlphaToCoverageEnable
{ {
readonly get => ((Internal.Id9 >> 0) & 0x1) != 0UL; readonly get => ((Internal.Id8 >> 0) & 0x1) != 0UL;
set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFFE) | ((value ? 1UL : 0UL) << 0); set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFFE) | ((value ? 1UL : 0UL) << 0);
} }
public bool AlphaToOneEnable public bool AlphaToOneEnable
{ {
readonly get => ((Internal.Id9 >> 1) & 0x1) != 0UL; readonly get => ((Internal.Id8 >> 1) & 0x1) != 0UL;
set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFFD) | ((value ? 1UL : 0UL) << 1); set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFFD) | ((value ? 1UL : 0UL) << 1);
} }
public bool AdvancedBlendSrcPreMultiplied public bool AdvancedBlendSrcPreMultiplied
{ {
readonly get => ((Internal.Id9 >> 2) & 0x1) != 0UL; readonly get => ((Internal.Id8 >> 2) & 0x1) != 0UL;
set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFFB) | ((value ? 1UL : 0UL) << 2); set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFFB) | ((value ? 1UL : 0UL) << 2);
} }
public bool AdvancedBlendDstPreMultiplied public bool AdvancedBlendDstPreMultiplied
{ {
readonly get => ((Internal.Id9 >> 3) & 0x1) != 0UL; readonly get => ((Internal.Id8 >> 3) & 0x1) != 0UL;
set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFF7) | ((value ? 1UL : 0UL) << 3); set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFF7) | ((value ? 1UL : 0UL) << 3);
} }
public BlendOverlapEXT AdvancedBlendOverlap public BlendOverlapEXT AdvancedBlendOverlap
{ {
readonly get => (BlendOverlapEXT)((Internal.Id9 >> 4) & 0x3); readonly get => (BlendOverlapEXT)((Internal.Id8 >> 4) & 0x3);
set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFCF) | ((ulong)value << 4); set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFCF) | ((ulong)value << 4);
} }
public bool DepthMode public bool DepthMode
{ {
readonly get => ((Internal.Id9 >> 6) & 0x1) != 0UL; readonly get => ((Internal.Id8 >> 6) & 0x1) != 0UL;
set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFBF) | ((value ? 1UL : 0UL) << 6); set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFBF) | ((value ? 1UL : 0UL) << 6);
} }
public bool HasTessellationControlShader; public bool HasTessellationControlShader;
@ -408,8 +396,6 @@ namespace Ryujinx.Graphics.Vulkan
fixed (VertexInputAttributeDescription* pVertexAttributeDescriptions = &Internal.VertexAttributeDescriptions[0]) fixed (VertexInputAttributeDescription* pVertexAttributeDescriptions = &Internal.VertexAttributeDescriptions[0])
fixed (VertexInputAttributeDescription* pVertexAttributeDescriptions2 = &_vertexAttributeDescriptions2[0]) fixed (VertexInputAttributeDescription* pVertexAttributeDescriptions2 = &_vertexAttributeDescriptions2[0])
fixed (VertexInputBindingDescription* pVertexBindingDescriptions = &Internal.VertexBindingDescriptions[0]) fixed (VertexInputBindingDescription* pVertexBindingDescriptions = &Internal.VertexBindingDescriptions[0])
fixed (Viewport* pViewports = &Internal.Viewports[0])
fixed (Rect2D* pScissors = &Internal.Scissors[0])
fixed (PipelineColorBlendAttachmentState* pColorBlendAttachmentState = &Internal.ColorBlendAttachmentState[0]) fixed (PipelineColorBlendAttachmentState* pColorBlendAttachmentState = &Internal.ColorBlendAttachmentState[0])
{ {
var vertexInputState = new PipelineVertexInputStateCreateInfo var vertexInputState = new PipelineVertexInputStateCreateInfo
@ -472,18 +458,13 @@ namespace Ryujinx.Graphics.Vulkan
CullMode = CullMode, CullMode = CullMode,
FrontFace = FrontFace, FrontFace = FrontFace,
DepthBiasEnable = DepthBiasEnable, DepthBiasEnable = DepthBiasEnable,
DepthBiasClamp = DepthBiasClamp,
DepthBiasConstantFactor = DepthBiasConstantFactor,
DepthBiasSlopeFactor = DepthBiasSlopeFactor,
}; };
var viewportState = new PipelineViewportStateCreateInfo var viewportState = new PipelineViewportStateCreateInfo
{ {
SType = StructureType.PipelineViewportStateCreateInfo, SType = StructureType.PipelineViewportStateCreateInfo,
ViewportCount = ViewportsCount, ViewportCount = ViewportsCount,
PViewports = pViewports,
ScissorCount = ScissorsCount, ScissorCount = ScissorsCount,
PScissors = pScissors,
}; };
if (gd.Capabilities.SupportsDepthClipControl) if (gd.Capabilities.SupportsDepthClipControl)
@ -511,19 +492,13 @@ namespace Ryujinx.Graphics.Vulkan
StencilFrontFailOp, StencilFrontFailOp,
StencilFrontPassOp, StencilFrontPassOp,
StencilFrontDepthFailOp, StencilFrontDepthFailOp,
StencilFrontCompareOp, StencilFrontCompareOp);
StencilFrontCompareMask,
StencilFrontWriteMask,
StencilFrontReference);
var stencilBack = new StencilOpState( var stencilBack = new StencilOpState(
StencilBackFailOp, StencilBackFailOp,
StencilBackPassOp, StencilBackPassOp,
StencilBackDepthFailOp, StencilBackDepthFailOp,
StencilBackCompareOp, StencilBackCompareOp);
StencilBackCompareMask,
StencilBackWriteMask,
StencilBackReference);
var depthStencilState = new PipelineDepthStencilStateCreateInfo var depthStencilState = new PipelineDepthStencilStateCreateInfo
{ {
@ -531,12 +506,10 @@ namespace Ryujinx.Graphics.Vulkan
DepthTestEnable = DepthTestEnable, DepthTestEnable = DepthTestEnable,
DepthWriteEnable = DepthWriteEnable, DepthWriteEnable = DepthWriteEnable,
DepthCompareOp = DepthCompareOp, DepthCompareOp = DepthCompareOp,
DepthBoundsTestEnable = DepthBoundsTestEnable, DepthBoundsTestEnable = false,
StencilTestEnable = StencilTestEnable, StencilTestEnable = StencilTestEnable,
Front = stencilFront, Front = stencilFront,
Back = stencilBack, Back = stencilBack,
MinDepthBounds = MinDepthBounds,
MaxDepthBounds = MaxDepthBounds,
}; };
uint blendEnables = 0; uint blendEnables = 0;
@ -591,22 +564,21 @@ namespace Ryujinx.Graphics.Vulkan
} }
bool supportsExtDynamicState = gd.Capabilities.SupportsExtendedDynamicState; bool supportsExtDynamicState = gd.Capabilities.SupportsExtendedDynamicState;
int dynamicStatesCount = supportsExtDynamicState ? 9 : 8; int dynamicStatesCount = supportsExtDynamicState ? 8 : 7;
DynamicState* dynamicStates = stackalloc DynamicState[dynamicStatesCount]; DynamicState* dynamicStates = stackalloc DynamicState[dynamicStatesCount];
dynamicStates[0] = DynamicState.Viewport; dynamicStates[0] = DynamicState.Viewport;
dynamicStates[1] = DynamicState.Scissor; dynamicStates[1] = DynamicState.Scissor;
dynamicStates[2] = DynamicState.DepthBias; dynamicStates[2] = DynamicState.DepthBias;
dynamicStates[3] = DynamicState.DepthBounds; dynamicStates[3] = DynamicState.StencilCompareMask;
dynamicStates[4] = DynamicState.StencilCompareMask; dynamicStates[4] = DynamicState.StencilWriteMask;
dynamicStates[5] = DynamicState.StencilWriteMask; dynamicStates[5] = DynamicState.StencilReference;
dynamicStates[6] = DynamicState.StencilReference; dynamicStates[6] = DynamicState.BlendConstants;
dynamicStates[7] = DynamicState.BlendConstants;
if (supportsExtDynamicState) if (supportsExtDynamicState)
{ {
dynamicStates[8] = DynamicState.VertexInputBindingStrideExt; dynamicStates[7] = DynamicState.VertexInputBindingStrideExt;
} }
var pipelineDynamicStateCreateInfo = new PipelineDynamicStateCreateInfo var pipelineDynamicStateCreateInfo = new PipelineDynamicStateCreateInfo
@ -632,7 +604,6 @@ namespace Ryujinx.Graphics.Vulkan
PDynamicState = &pipelineDynamicStateCreateInfo, PDynamicState = &pipelineDynamicStateCreateInfo,
Layout = PipelineLayout, Layout = PipelineLayout,
RenderPass = renderPass, RenderPass = renderPass,
BasePipelineIndex = -1,
}; };
Result result = gd.Api.CreateGraphicsPipelines(device, cache, 1, &pipelineCreateInfo, null, &pipelineHandle); Result result = gd.Api.CreateGraphicsPipelines(device, cache, 1, &pipelineCreateInfo, null, &pipelineHandle);

View file

@ -17,20 +17,17 @@ namespace Ryujinx.Graphics.Vulkan
public ulong Id4; public ulong Id4;
public ulong Id5; public ulong Id5;
public ulong Id6; public ulong Id6;
public ulong Id7; public ulong Id7;
public ulong Id8; public ulong Id8;
public ulong Id9;
private readonly uint VertexAttributeDescriptionsCount => (byte)((Id6 >> 38) & 0xFF); private readonly uint VertexAttributeDescriptionsCount => (byte)((Id5 >> 38) & 0xFF);
private readonly uint VertexBindingDescriptionsCount => (byte)((Id6 >> 46) & 0xFF); private readonly uint VertexBindingDescriptionsCount => (byte)((Id5 >> 46) & 0xFF);
private readonly uint ColorBlendAttachmentStateCount => (byte)((Id7 >> 8) & 0xFF); private readonly uint ColorBlendAttachmentStateCount => (byte)((Id6 >> 8) & 0xFF);
private readonly bool HasDepthStencil => ((Id7 >> 63) & 0x1) != 0UL; private readonly bool HasDepthStencil => ((Id6 >> 63) & 0x1) != 0UL;
public Array32<VertexInputAttributeDescription> VertexAttributeDescriptions; public Array32<VertexInputAttributeDescription> VertexAttributeDescriptions;
public Array33<VertexInputBindingDescription> VertexBindingDescriptions; public Array33<VertexInputBindingDescription> VertexBindingDescriptions;
public Array16<Viewport> Viewports;
public Array16<Rect2D> Scissors;
public Array8<PipelineColorBlendAttachmentState> ColorBlendAttachmentState; public Array8<PipelineColorBlendAttachmentState> ColorBlendAttachmentState;
public Array9<Format> AttachmentFormats; public Array9<Format> AttachmentFormats;
public uint AttachmentIntegerFormatMask; public uint AttachmentIntegerFormatMask;
@ -45,7 +42,7 @@ namespace Ryujinx.Graphics.Vulkan
{ {
if (!Unsafe.As<ulong, Vector256<byte>>(ref Id0).Equals(Unsafe.As<ulong, Vector256<byte>>(ref other.Id0)) || if (!Unsafe.As<ulong, Vector256<byte>>(ref Id0).Equals(Unsafe.As<ulong, Vector256<byte>>(ref other.Id0)) ||
!Unsafe.As<ulong, Vector256<byte>>(ref Id4).Equals(Unsafe.As<ulong, Vector256<byte>>(ref other.Id4)) || !Unsafe.As<ulong, Vector256<byte>>(ref Id4).Equals(Unsafe.As<ulong, Vector256<byte>>(ref other.Id4)) ||
!Unsafe.As<ulong, Vector128<byte>>(ref Id8).Equals(Unsafe.As<ulong, Vector128<byte>>(ref other.Id8))) !Unsafe.As<ulong, Vector128<byte>>(ref Id7).Equals(Unsafe.As<ulong, Vector128<byte>>(ref other.Id7)))
{ {
return false; return false;
} }
@ -88,8 +85,7 @@ namespace Ryujinx.Graphics.Vulkan
Id5 * 23 ^ Id5 * 23 ^
Id6 * 23 ^ Id6 * 23 ^
Id7 * 23 ^ Id7 * 23 ^
Id8 * 23 ^ Id8 * 23;
Id9 * 23;
for (int i = 0; i < (int)VertexAttributeDescriptionsCount; i++) for (int i = 0; i < (int)VertexAttributeDescriptionsCount; i++)
{ {

View file

@ -0,0 +1,74 @@
using Silk.NET.Vulkan;
using System;
using System.Diagnostics;
namespace Ryujinx.Graphics.Vulkan
{
class ResourceArray : IDisposable
{
private DescriptorSet[] _cachedDescriptorSets;
private ShaderCollection _cachedDscProgram;
private int _cachedDscSetIndex;
private int _cachedDscIndex;
private int _bindCount;
protected void SetDirty(VulkanRenderer gd)
{
ReleaseDescriptorSet();
if (_bindCount != 0)
{
gd.PipelineInternal.ForceTextureDirty();
}
}
public bool TryGetCachedDescriptorSets(CommandBufferScoped cbs, ShaderCollection program, int setIndex, out DescriptorSet[] sets)
{
if (_cachedDescriptorSets != null)
{
_cachedDscProgram.UpdateManualDescriptorSetCollectionOwnership(cbs, _cachedDscSetIndex, _cachedDscIndex);
sets = _cachedDescriptorSets;
return true;
}
var dsc = program.GetNewManualDescriptorSetCollection(cbs, setIndex, out _cachedDscIndex).Get(cbs);
sets = dsc.GetSets();
_cachedDescriptorSets = sets;
_cachedDscProgram = program;
_cachedDscSetIndex = setIndex;
return false;
}
public void IncrementBindCount()
{
_bindCount++;
}
public void DecrementBindCount()
{
int newBindCount = --_bindCount;
Debug.Assert(newBindCount >= 0);
}
private void ReleaseDescriptorSet()
{
if (_cachedDescriptorSets != null)
{
_cachedDscProgram.ReleaseManualDescriptorSetCollection(_cachedDscSetIndex, _cachedDscIndex);
_cachedDescriptorSets = null;
}
}
public void Dispose()
{
ReleaseDescriptorSet();
}
}
}

View file

@ -604,9 +604,14 @@ namespace Ryujinx.Graphics.Vulkan
return _plce.GetNewDescriptorSetCollection(setIndex, out isNew); return _plce.GetNewDescriptorSetCollection(setIndex, out isNew);
} }
public Auto<DescriptorSetCollection> GetNewManualDescriptorSetCollection(int commandBufferIndex, int setIndex, out int cacheIndex) public Auto<DescriptorSetCollection> GetNewManualDescriptorSetCollection(CommandBufferScoped cbs, int setIndex, out int cacheIndex)
{ {
return _plce.GetNewManualDescriptorSetCollection(commandBufferIndex, setIndex, out cacheIndex); return _plce.GetNewManualDescriptorSetCollection(cbs, setIndex, out cacheIndex);
}
public void UpdateManualDescriptorSetCollectionOwnership(CommandBufferScoped cbs, int setIndex, int cacheIndex)
{
_plce.UpdateManualDescriptorSetCollectionOwnership(cbs, setIndex, cacheIndex);
} }
public void ReleaseManualDescriptorSetCollection(int setIndex, int cacheIndex) public void ReleaseManualDescriptorSetCollection(int setIndex, int cacheIndex)

View file

@ -2,11 +2,10 @@ 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.Diagnostics;
namespace Ryujinx.Graphics.Vulkan namespace Ryujinx.Graphics.Vulkan
{ {
class TextureArray : ITextureArray class TextureArray : ResourceArray, ITextureArray
{ {
private readonly VulkanRenderer _gd; private readonly VulkanRenderer _gd;
@ -25,19 +24,11 @@ namespace Ryujinx.Graphics.Vulkan
private HashSet<TextureStorage> _storages; private HashSet<TextureStorage> _storages;
private DescriptorSet[] _cachedDescriptorSets;
private int _cachedCommandBufferIndex; private int _cachedCommandBufferIndex;
private int _cachedSubmissionCount; private int _cachedSubmissionCount;
private ShaderCollection _cachedDscProgram;
private int _cachedDscSetIndex;
private int _cachedDscIndex;
private readonly bool _isBuffer; private readonly bool _isBuffer;
private int _bindCount;
public TextureArray(VulkanRenderer gd, int size, bool isBuffer) public TextureArray(VulkanRenderer gd, int size, bool isBuffer)
{ {
_gd = gd; _gd = gd;
@ -113,12 +104,7 @@ namespace Ryujinx.Graphics.Vulkan
{ {
_cachedCommandBufferIndex = -1; _cachedCommandBufferIndex = -1;
_storages = null; _storages = null;
_cachedDescriptorSets = null; SetDirty(_gd);
if (_bindCount != 0)
{
_gd.PipelineInternal.ForceTextureDirty();
}
} }
public void QueueWriteToReadBarriers(CommandBufferScoped cbs, PipelineStageFlags stageFlags) public void QueueWriteToReadBarriers(CommandBufferScoped cbs, PipelineStageFlags stageFlags)
@ -211,7 +197,7 @@ namespace Ryujinx.Graphics.Vulkan
TextureView dummyTexture, TextureView dummyTexture,
SamplerHolder dummySampler) SamplerHolder dummySampler)
{ {
if (_cachedDescriptorSets != null) if (TryGetCachedDescriptorSets(cbs, program, setIndex, out DescriptorSet[] sets))
{ {
// We still need to ensure the current command buffer holds a reference to all used textures. // We still need to ensure the current command buffer holds a reference to all used textures.
@ -224,12 +210,9 @@ namespace Ryujinx.Graphics.Vulkan
GetBufferViews(cbs); GetBufferViews(cbs);
} }
return _cachedDescriptorSets; return sets;
} }
_cachedDscProgram?.ReleaseManualDescriptorSetCollection(_cachedDscSetIndex, _cachedDscIndex);
var dsc = program.GetNewManualDescriptorSetCollection(cbs.CommandBufferIndex, setIndex, out _cachedDscIndex).Get(cbs);
DescriptorSetTemplate template = program.Templates[setIndex]; DescriptorSetTemplate template = program.Templates[setIndex];
DescriptorSetTemplateWriter tu = templateUpdater.Begin(template); DescriptorSetTemplateWriter tu = templateUpdater.Begin(template);
@ -243,24 +226,9 @@ namespace Ryujinx.Graphics.Vulkan
tu.Push(GetBufferViews(cbs)); tu.Push(GetBufferViews(cbs));
} }
var sets = dsc.GetSets();
templateUpdater.Commit(_gd, device, sets[0]); templateUpdater.Commit(_gd, device, sets[0]);
_cachedDescriptorSets = sets;
_cachedDscProgram = program;
_cachedDscSetIndex = setIndex;
return sets; return sets;
} }
public void IncrementBindCount()
{
_bindCount++;
}
public void DecrementBindCount()
{
int newBindCount = --_bindCount;
Debug.Assert(newBindCount >= 0);
}
} }
} }