Compare commits
3 Commits
Author | SHA1 | Date | |
---|---|---|---|
296c4a3d01 | |||
e7cf4e6eaf | |||
a1a4771ac1 |
@ -48,9 +48,21 @@ namespace ARMeilleure.CodeGen
|
||||
/// <returns>A delegate of type <typeparamref name="T"/> pointing to the mapped function</returns>
|
||||
public T Map<T>()
|
||||
{
|
||||
IntPtr codePtr = JitCache.Map(this);
|
||||
return MapWithPointer<T>(out _);
|
||||
}
|
||||
|
||||
return Marshal.GetDelegateForFunctionPointer<T>(codePtr);
|
||||
/// <summary>
|
||||
/// Maps the <see cref="CompiledFunction"/> onto the <see cref="JitCache"/> and returns a delegate of type
|
||||
/// <typeparamref name="T"/> pointing to the mapped function.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of delegate</typeparam>
|
||||
/// <param name="codePointer">Pointer to the function code in memory</param>
|
||||
/// <returns>A delegate of type <typeparamref name="T"/> pointing to the mapped function</returns>
|
||||
public T MapWithPointer<T>(out IntPtr codePointer)
|
||||
{
|
||||
codePointer = JitCache.Map(this);
|
||||
|
||||
return Marshal.GetDelegateForFunctionPointer<T>(codePointer);
|
||||
}
|
||||
}
|
||||
}
|
@ -191,7 +191,7 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
TranslatedFunction function = Context.Translator.GetOrTranslate(address, GetContext().ExecutionMode);
|
||||
|
||||
return (ulong)function.FuncPtr.ToInt64();
|
||||
return (ulong)function.FuncPointer.ToInt64();
|
||||
}
|
||||
|
||||
public static void InvalidateCacheLine(ulong address)
|
||||
|
@ -745,9 +745,9 @@ namespace ARMeilleure.Translation.PTC
|
||||
bool highCq)
|
||||
{
|
||||
var cFunc = new CompiledFunction(code, unwindInfo, RelocInfo.Empty);
|
||||
var gFunc = cFunc.Map<GuestFunction>();
|
||||
var gFunc = cFunc.MapWithPointer<GuestFunction>(out IntPtr gFuncPointer);
|
||||
|
||||
return new TranslatedFunction(gFunc, callCounter, guestSize, highCq);
|
||||
return new TranslatedFunction(gFunc, gFuncPointer, callCounter, guestSize, highCq);
|
||||
}
|
||||
|
||||
private void UpdateInfo(InfoEntry infoEntry)
|
||||
|
@ -1,6 +1,5 @@
|
||||
using ARMeilleure.Common;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace ARMeilleure.Translation
|
||||
{
|
||||
@ -8,18 +7,18 @@ namespace ARMeilleure.Translation
|
||||
{
|
||||
private readonly GuestFunction _func; // Ensure that this delegate will not be garbage collected.
|
||||
|
||||
public IntPtr FuncPointer { get; }
|
||||
public Counter<uint> CallCounter { get; }
|
||||
public ulong GuestSize { get; }
|
||||
public bool HighCq { get; }
|
||||
public IntPtr FuncPtr { get; }
|
||||
|
||||
public TranslatedFunction(GuestFunction func, Counter<uint> callCounter, ulong guestSize, bool highCq)
|
||||
public TranslatedFunction(GuestFunction func, IntPtr funcPointer, Counter<uint> callCounter, ulong guestSize, bool highCq)
|
||||
{
|
||||
_func = func;
|
||||
FuncPointer = funcPointer;
|
||||
CallCounter = callCounter;
|
||||
GuestSize = guestSize;
|
||||
HighCq = highCq;
|
||||
FuncPtr = Marshal.GetFunctionPointerForDelegate(func);
|
||||
}
|
||||
|
||||
public ulong Execute(State.ExecutionContext context)
|
||||
|
@ -211,7 +211,7 @@ namespace ARMeilleure.Translation
|
||||
|
||||
if (oldFunc != func)
|
||||
{
|
||||
JitCache.Unmap(func.FuncPtr);
|
||||
JitCache.Unmap(func.FuncPointer);
|
||||
func = oldFunc;
|
||||
}
|
||||
|
||||
@ -230,7 +230,7 @@ namespace ARMeilleure.Translation
|
||||
{
|
||||
if (FunctionTable.IsValid(guestAddress) && (Optimizations.AllowLcqInFunctionTable || func.HighCq))
|
||||
{
|
||||
Volatile.Write(ref FunctionTable.GetValue(guestAddress), (ulong)func.FuncPtr);
|
||||
Volatile.Write(ref FunctionTable.GetValue(guestAddress), (ulong)func.FuncPointer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -292,11 +292,11 @@ namespace ARMeilleure.Translation
|
||||
_ptc.WriteCompiledFunction(address, funcSize, hash, highCq, compiledFunc);
|
||||
}
|
||||
|
||||
GuestFunction func = compiledFunc.Map<GuestFunction>();
|
||||
GuestFunction func = compiledFunc.MapWithPointer<GuestFunction>(out IntPtr funcPointer);
|
||||
|
||||
Allocators.ResetAll();
|
||||
|
||||
return new TranslatedFunction(func, counter, funcSize, highCq);
|
||||
return new TranslatedFunction(func, funcPointer, counter, funcSize, highCq);
|
||||
}
|
||||
|
||||
private void BackgroundTranslate()
|
||||
@ -537,7 +537,7 @@ namespace ARMeilleure.Translation
|
||||
|
||||
foreach (var func in functions)
|
||||
{
|
||||
JitCache.Unmap(func.FuncPtr);
|
||||
JitCache.Unmap(func.FuncPointer);
|
||||
|
||||
func.CallCounter?.Dispose();
|
||||
}
|
||||
@ -546,7 +546,7 @@ namespace ARMeilleure.Translation
|
||||
|
||||
while (_oldFuncs.TryDequeue(out var kv))
|
||||
{
|
||||
JitCache.Unmap(kv.Value.FuncPtr);
|
||||
JitCache.Unmap(kv.Value.FuncPointer);
|
||||
|
||||
kv.Value.CallCounter?.Dispose();
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
|
||||
namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
@ -16,6 +17,10 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private bool _hasPendingQuery;
|
||||
private int _queryCount;
|
||||
|
||||
private int[] _queryCountHistory = new int[3];
|
||||
private int _queryCountHistoryIndex;
|
||||
private int _remainingQueries;
|
||||
|
||||
public void RegisterFlush(ulong drawCount)
|
||||
{
|
||||
_lastFlush = Stopwatch.GetTimestamp();
|
||||
@ -27,6 +32,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
public bool RegisterPendingQuery()
|
||||
{
|
||||
_hasPendingQuery = true;
|
||||
_remainingQueries--;
|
||||
|
||||
_queryCountHistory[_queryCountHistoryIndex]++;
|
||||
|
||||
// Interrupt render passes to flush queries, so that early results arrive sooner.
|
||||
if (++_queryCount == InitialQueryCountForFlush)
|
||||
@ -37,6 +45,21 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
return false;
|
||||
}
|
||||
|
||||
public int GetRemainingQueries()
|
||||
{
|
||||
if (_remainingQueries <= 0)
|
||||
{
|
||||
_remainingQueries = 16;
|
||||
}
|
||||
|
||||
if (_queryCount < InitialQueryCountForFlush)
|
||||
{
|
||||
return Math.Min(InitialQueryCountForFlush - _queryCount, _remainingQueries);
|
||||
}
|
||||
|
||||
return _remainingQueries;
|
||||
}
|
||||
|
||||
public bool ShouldFlushQuery()
|
||||
{
|
||||
return _hasPendingQuery;
|
||||
@ -69,5 +92,14 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
return now > _lastFlush + flushTimeout;
|
||||
}
|
||||
|
||||
public void Present()
|
||||
{
|
||||
_queryCountHistoryIndex = (_queryCountHistoryIndex + 1) % 3;
|
||||
|
||||
_remainingQueries = _queryCountHistory.Max() + 10;
|
||||
|
||||
_queryCountHistory[_queryCountHistoryIndex] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
MemoryPropertyFlags.HostCoherentBit |
|
||||
MemoryPropertyFlags.HostCachedBit;
|
||||
|
||||
// Some drivers don't expose a "HostCached" memory type,
|
||||
// so we need those alternative flags for the allocation to succeed there.
|
||||
private const MemoryPropertyFlags DefaultBufferMemoryAltFlags =
|
||||
MemoryPropertyFlags.HostVisibleBit |
|
||||
MemoryPropertyFlags.HostCoherentBit;
|
||||
|
||||
private const MemoryPropertyFlags DeviceLocalBufferMemoryFlags =
|
||||
MemoryPropertyFlags.DeviceLocalBit;
|
||||
|
||||
@ -94,9 +100,21 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
gd.Api.CreateBuffer(_device, in bufferCreateInfo, null, out var buffer).ThrowOnError();
|
||||
gd.Api.GetBufferMemoryRequirements(_device, buffer, out var requirements);
|
||||
|
||||
var allocateFlags = deviceLocal ? DeviceLocalBufferMemoryFlags : DefaultBufferMemoryFlags;
|
||||
MemoryPropertyFlags allocateFlags;
|
||||
MemoryPropertyFlags allocateFlagsAlt;
|
||||
|
||||
var allocation = gd.MemoryAllocator.AllocateDeviceMemory(_physicalDevice, requirements, allocateFlags);
|
||||
if (deviceLocal)
|
||||
{
|
||||
allocateFlags = DeviceLocalBufferMemoryFlags;
|
||||
allocateFlagsAlt = DeviceLocalBufferMemoryFlags;
|
||||
}
|
||||
else
|
||||
{
|
||||
allocateFlags = DefaultBufferMemoryFlags;
|
||||
allocateFlagsAlt = DefaultBufferMemoryAltFlags;
|
||||
}
|
||||
|
||||
var allocation = gd.MemoryAllocator.AllocateDeviceMemory(_physicalDevice, requirements, allocateFlags, allocateFlagsAlt);
|
||||
|
||||
if (allocation.Memory.Handle == 0UL)
|
||||
{
|
||||
|
@ -23,7 +23,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
public int[] AttachmentIndices { get; }
|
||||
|
||||
public int AttachmentsCount { get; }
|
||||
public int MaxColorAttachmentIndex { get; }
|
||||
public int MaxColorAttachmentIndex => AttachmentIndices.Length > 0 ? AttachmentIndices[AttachmentIndices.Length - 1] : -1;
|
||||
public bool HasDepthStencil { get; }
|
||||
public int ColorAttachmentsCount => AttachmentsCount - (HasDepthStencil ? 1 : 0);
|
||||
|
||||
@ -66,8 +66,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
AttachmentSamples = new uint[count];
|
||||
AttachmentFormats = new VkFormat[count];
|
||||
AttachmentIndices = new int[count];
|
||||
MaxColorAttachmentIndex = colors.Length - 1;
|
||||
AttachmentIndices = new int[colorsCount];
|
||||
|
||||
uint width = uint.MaxValue;
|
||||
uint height = uint.MaxValue;
|
||||
|
@ -28,10 +28,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
public readonly bool SupportsExtendedDynamicState;
|
||||
public readonly bool SupportsMultiView;
|
||||
public readonly bool SupportsNullDescriptors;
|
||||
public readonly bool SupportsPreciseOcclusionQueries;
|
||||
public readonly bool SupportsPushDescriptors;
|
||||
public readonly bool SupportsTransformFeedback;
|
||||
public readonly bool SupportsTransformFeedbackQueries;
|
||||
public readonly bool SupportsPreciseOcclusionQueries;
|
||||
public readonly bool SupportsPipelineStatisticsQuery;
|
||||
public readonly bool SupportsGeometryShader;
|
||||
public readonly uint MinSubgroupSize;
|
||||
public readonly uint MaxSubgroupSize;
|
||||
@ -55,6 +56,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
bool supportsTransformFeedback,
|
||||
bool supportsTransformFeedbackQueries,
|
||||
bool supportsPreciseOcclusionQueries,
|
||||
bool supportsPipelineStatisticsQuery,
|
||||
bool supportsGeometryShader,
|
||||
uint minSubgroupSize,
|
||||
uint maxSubgroupSize,
|
||||
@ -77,6 +79,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
SupportsTransformFeedback = supportsTransformFeedback;
|
||||
SupportsTransformFeedbackQueries = supportsTransformFeedbackQueries;
|
||||
SupportsPreciseOcclusionQueries = supportsPreciseOcclusionQueries;
|
||||
SupportsPipelineStatisticsQuery = supportsPipelineStatisticsQuery;
|
||||
SupportsGeometryShader = supportsGeometryShader;
|
||||
MinSubgroupSize = minSubgroupSize;
|
||||
MaxSubgroupSize = maxSubgroupSize;
|
||||
|
@ -27,7 +27,16 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
MemoryRequirements requirements,
|
||||
MemoryPropertyFlags flags = 0)
|
||||
{
|
||||
int memoryTypeIndex = FindSuitableMemoryTypeIndex(_api, physicalDevice, requirements.MemoryTypeBits, flags);
|
||||
return AllocateDeviceMemory(physicalDevice, requirements, flags, flags);
|
||||
}
|
||||
|
||||
public MemoryAllocation AllocateDeviceMemory(
|
||||
PhysicalDevice physicalDevice,
|
||||
MemoryRequirements requirements,
|
||||
MemoryPropertyFlags flags,
|
||||
MemoryPropertyFlags alternativeFlags)
|
||||
{
|
||||
int memoryTypeIndex = FindSuitableMemoryTypeIndex(_api, physicalDevice, requirements.MemoryTypeBits, flags, alternativeFlags);
|
||||
if (memoryTypeIndex < 0)
|
||||
{
|
||||
return default;
|
||||
@ -56,21 +65,35 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
return newBl.Allocate(size, alignment, map);
|
||||
}
|
||||
|
||||
private static int FindSuitableMemoryTypeIndex(Vk api, PhysicalDevice physicalDevice, uint memoryTypeBits, MemoryPropertyFlags flags)
|
||||
private static int FindSuitableMemoryTypeIndex(
|
||||
Vk api,
|
||||
PhysicalDevice physicalDevice,
|
||||
uint memoryTypeBits,
|
||||
MemoryPropertyFlags flags,
|
||||
MemoryPropertyFlags alternativeFlags)
|
||||
{
|
||||
int bestCandidateIndex = -1;
|
||||
|
||||
api.GetPhysicalDeviceMemoryProperties(physicalDevice, out var properties);
|
||||
|
||||
for (int i = 0; i < properties.MemoryTypeCount; i++)
|
||||
{
|
||||
var type = properties.MemoryTypes[i];
|
||||
|
||||
if ((memoryTypeBits & (1 << i)) != 0 && type.PropertyFlags.HasFlag(flags))
|
||||
if ((memoryTypeBits & (1 << i)) != 0)
|
||||
{
|
||||
return i;
|
||||
if (type.PropertyFlags.HasFlag(flags))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
else if (type.PropertyFlags.HasFlag(alternativeFlags))
|
||||
{
|
||||
bestCandidateIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
return bestCandidateIndex;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
protected readonly Device Device;
|
||||
public readonly PipelineCache PipelineCache;
|
||||
|
||||
protected readonly AutoFlushCounter AutoFlush;
|
||||
public readonly AutoFlushCounter AutoFlush;
|
||||
|
||||
protected PipelineDynamicState DynamicState;
|
||||
private PipelineState _newState;
|
||||
@ -1344,8 +1344,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
var dstAttachmentFormats = _newState.Internal.AttachmentFormats.AsSpan();
|
||||
FramebufferParams.AttachmentFormats.CopyTo(dstAttachmentFormats);
|
||||
|
||||
int maxAttachmentIndex = FramebufferParams.MaxColorAttachmentIndex + (FramebufferParams.HasDepthStencil ? 1 : 0);
|
||||
for (int i = FramebufferParams.AttachmentFormats.Length; i <= maxAttachmentIndex; i++)
|
||||
for (int i = FramebufferParams.AttachmentFormats.Length; i < dstAttachmentFormats.Length; i++)
|
||||
{
|
||||
dstAttachmentFormats[i] = 0;
|
||||
}
|
||||
@ -1376,8 +1375,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
for (int i = 0; i < FramebufferParams.AttachmentsCount; i++)
|
||||
{
|
||||
int bindIndex = FramebufferParams.AttachmentIndices[i];
|
||||
|
||||
attachmentDescs[i] = new AttachmentDescription(
|
||||
0,
|
||||
FramebufferParams.AttachmentFormats[i],
|
||||
|
@ -27,14 +27,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
int attachmentCount = 0;
|
||||
int colorCount = 0;
|
||||
int maxColorAttachmentIndex = 0;
|
||||
|
||||
for (int i = 0; i < state.AttachmentEnable.Length; i++)
|
||||
{
|
||||
if (state.AttachmentEnable[i])
|
||||
{
|
||||
maxColorAttachmentIndex = i;
|
||||
|
||||
attachmentFormats[attachmentCount] = gd.FormatCapabilities.ConvertToVkFormat(state.AttachmentFormats[i]);
|
||||
|
||||
attachmentIndices[attachmentCount++] = i;
|
||||
@ -270,7 +267,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
// NOTE: Viewports, Scissors are dynamic.
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
for (int i = 0; i < Constants.MaxRenderTargets; i++)
|
||||
{
|
||||
var blend = state.BlendDescriptors[i];
|
||||
|
||||
@ -293,21 +290,24 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
}
|
||||
|
||||
int maxAttachmentIndex = 0;
|
||||
for (int i = 0; i < 8; i++)
|
||||
int attachmentCount = 0;
|
||||
int maxColorAttachmentIndex = -1;
|
||||
|
||||
for (int i = 0; i < Constants.MaxRenderTargets; i++)
|
||||
{
|
||||
if (state.AttachmentEnable[i])
|
||||
{
|
||||
pipeline.Internal.AttachmentFormats[maxAttachmentIndex++] = gd.FormatCapabilities.ConvertToVkFormat(state.AttachmentFormats[i]);
|
||||
pipeline.Internal.AttachmentFormats[attachmentCount++] = gd.FormatCapabilities.ConvertToVkFormat(state.AttachmentFormats[i]);
|
||||
maxColorAttachmentIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (state.DepthStencilEnable)
|
||||
{
|
||||
pipeline.Internal.AttachmentFormats[maxAttachmentIndex++] = gd.FormatCapabilities.ConvertToVkFormat(state.DepthStencilFormat);
|
||||
pipeline.Internal.AttachmentFormats[attachmentCount++] = gd.FormatCapabilities.ConvertToVkFormat(state.DepthStencilFormat);
|
||||
}
|
||||
|
||||
pipeline.ColorBlendAttachmentStateCount = 8;
|
||||
pipeline.ColorBlendAttachmentStateCount = (uint)(maxColorAttachmentIndex + 1);
|
||||
pipeline.VertexAttributeDescriptionsCount = (uint)Math.Min(Constants.MaxVertexAttributes, state.VertexAttribCount);
|
||||
|
||||
return pipeline;
|
||||
|
@ -14,7 +14,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private CounterQueueEvent _activeConditionalRender;
|
||||
|
||||
private readonly List<BufferedQuery> _pendingQueryCopies;
|
||||
private readonly List<BufferedQuery> _pendingQueryResets;
|
||||
|
||||
private ulong _byteWeight;
|
||||
|
||||
@ -22,7 +21,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
_activeQueries = new List<QueryPool>();
|
||||
_pendingQueryCopies = new();
|
||||
_pendingQueryResets = new List<BufferedQuery>();
|
||||
|
||||
CommandBuffer = (Cbs = gd.CommandBufferPool.Rent()).CommandBuffer;
|
||||
}
|
||||
@ -34,16 +32,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
query.PoolCopy(Cbs);
|
||||
}
|
||||
|
||||
lock (_pendingQueryResets)
|
||||
{
|
||||
foreach (var query in _pendingQueryResets)
|
||||
{
|
||||
query.PoolReset(CommandBuffer);
|
||||
}
|
||||
|
||||
_pendingQueryResets.Clear();
|
||||
}
|
||||
|
||||
_pendingQueryCopies.Clear();
|
||||
}
|
||||
|
||||
@ -238,10 +226,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
Gd.Api.CmdBeginQuery(CommandBuffer, queryPool, 0, Gd.Capabilities.SupportsPreciseOcclusionQueries ? QueryControlFlags.PreciseBit : 0);
|
||||
}
|
||||
|
||||
Gd.ResetCounterPool();
|
||||
|
||||
Restore();
|
||||
}
|
||||
|
||||
public void BeginQuery(BufferedQuery query, QueryPool pool, bool needsReset)
|
||||
public void BeginQuery(BufferedQuery query, QueryPool pool, bool needsReset, bool fromSamplePool)
|
||||
{
|
||||
if (needsReset)
|
||||
{
|
||||
@ -249,9 +239,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
Gd.Api.CmdResetQueryPool(CommandBuffer, pool, 0, 1);
|
||||
|
||||
lock (_pendingQueryResets)
|
||||
if (fromSamplePool)
|
||||
{
|
||||
_pendingQueryResets.Remove(query); // Might be present on here.
|
||||
// Try reset some additional queries in advance.
|
||||
|
||||
Gd.ResetFutureCounters(CommandBuffer, AutoFlush.GetRemainingQueries());
|
||||
}
|
||||
}
|
||||
|
||||
@ -267,14 +259,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_activeQueries.Remove(pool);
|
||||
}
|
||||
|
||||
public void ResetQuery(BufferedQuery query)
|
||||
{
|
||||
lock (_pendingQueryResets)
|
||||
{
|
||||
_pendingQueryResets.Add(query);
|
||||
}
|
||||
}
|
||||
|
||||
public void CopyQueryResults(BufferedQuery query)
|
||||
{
|
||||
_pendingQueryCopies.Add(query);
|
||||
|
@ -18,7 +18,6 @@ namespace Ryujinx.Graphics.Vulkan.Queries
|
||||
private readonly PipelineFull _pipeline;
|
||||
|
||||
private QueryPool _queryPool;
|
||||
private bool _isReset;
|
||||
|
||||
private readonly BufferHolder _buffer;
|
||||
private readonly IntPtr _bufferMap;
|
||||
@ -27,6 +26,7 @@ namespace Ryujinx.Graphics.Vulkan.Queries
|
||||
private bool _isSupported;
|
||||
|
||||
private long _defaultValue;
|
||||
private int? _resetSequence;
|
||||
|
||||
public unsafe BufferedQuery(VulkanRenderer gd, Device device, PipelineFull pipeline, CounterType type, bool result32Bit)
|
||||
{
|
||||
@ -67,8 +67,8 @@ namespace Ryujinx.Graphics.Vulkan.Queries
|
||||
return type switch
|
||||
{
|
||||
CounterType.SamplesPassed => true,
|
||||
CounterType.PrimitivesGenerated => gd.Capabilities.SupportsPipelineStatisticsQuery,
|
||||
CounterType.TransformFeedbackPrimitivesWritten => gd.Capabilities.SupportsTransformFeedbackQueries,
|
||||
CounterType.PrimitivesGenerated => gd.Capabilities.SupportsGeometryShader,
|
||||
_ => false
|
||||
};
|
||||
}
|
||||
@ -92,16 +92,17 @@ namespace Ryujinx.Graphics.Vulkan.Queries
|
||||
public void Reset()
|
||||
{
|
||||
End(false);
|
||||
Begin();
|
||||
Begin(null);
|
||||
}
|
||||
|
||||
public void Begin()
|
||||
public void Begin(int? resetSequence)
|
||||
{
|
||||
if (_isSupported)
|
||||
{
|
||||
_pipeline.BeginQuery(this, _queryPool, !_isReset);
|
||||
bool needsReset = resetSequence == null || _resetSequence == null || resetSequence.Value != _resetSequence.Value;
|
||||
_pipeline.BeginQuery(this, _queryPool, needsReset, _type == CounterType.SamplesPassed && resetSequence != null);
|
||||
}
|
||||
_isReset = false;
|
||||
_resetSequence = null;
|
||||
}
|
||||
|
||||
public unsafe void End(bool withResult)
|
||||
@ -162,13 +163,14 @@ namespace Ryujinx.Graphics.Vulkan.Queries
|
||||
return data;
|
||||
}
|
||||
|
||||
public void PoolReset(CommandBuffer cmd)
|
||||
public void PoolReset(CommandBuffer cmd, int resetSequence)
|
||||
{
|
||||
if (_isSupported)
|
||||
{
|
||||
_api.CmdResetQueryPool(cmd, _queryPool, 0, 1);
|
||||
}
|
||||
_isReset = true;
|
||||
|
||||
_resetSequence = resetSequence;
|
||||
}
|
||||
|
||||
public void PoolCopy(CommandBufferScoped cbs)
|
||||
|
@ -3,6 +3,7 @@ using Silk.NET.Vulkan;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Linq;
|
||||
|
||||
namespace Ryujinx.Graphics.Vulkan.Queries
|
||||
{
|
||||
@ -32,6 +33,8 @@ namespace Ryujinx.Graphics.Vulkan.Queries
|
||||
|
||||
private Thread _consumerThread;
|
||||
|
||||
public int ResetSequence { get; private set; }
|
||||
|
||||
internal CounterQueue(VulkanRenderer gd, Device device, PipelineFull pipeline, CounterType type)
|
||||
{
|
||||
_gd = gd;
|
||||
@ -53,6 +56,24 @@ namespace Ryujinx.Graphics.Vulkan.Queries
|
||||
_consumerThread.Start();
|
||||
}
|
||||
|
||||
public void ResetCounterPool()
|
||||
{
|
||||
ResetSequence++;
|
||||
}
|
||||
|
||||
public void ResetFutureCounters(CommandBuffer cmd, int count)
|
||||
{
|
||||
// Pre-emptively reset queries to avoid render pass splitting.
|
||||
lock (_queryPool)
|
||||
{
|
||||
count = Math.Min(count, _queryPool.Count);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
_queryPool.ElementAt(i).PoolReset(cmd, ResetSequence);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void EventConsumer()
|
||||
{
|
||||
while (!Disposed)
|
||||
@ -106,7 +127,7 @@ namespace Ryujinx.Graphics.Vulkan.Queries
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_pipeline.ResetQuery(query);
|
||||
// The query will be reset when it dequeues.
|
||||
_queryPool.Enqueue(query);
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ namespace Ryujinx.Graphics.Vulkan.Queries
|
||||
|
||||
DrawIndex = drawIndex;
|
||||
|
||||
_counter.Begin();
|
||||
_counter.Begin(_queue.ResetSequence);
|
||||
}
|
||||
|
||||
public Auto<DisposableBuffer> GetBuffer()
|
||||
|
@ -24,6 +24,19 @@ namespace Ryujinx.Graphics.Vulkan.Queries
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetCounterPool()
|
||||
{
|
||||
foreach (var queue in _counterQueues)
|
||||
{
|
||||
queue.ResetCounterPool();
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetFutureCounters(CommandBuffer cmd, int count)
|
||||
{
|
||||
_counterQueues[(int)CounterType.SamplesPassed].ResetFutureCounters(cmd, count);
|
||||
}
|
||||
|
||||
public CounterQueueEvent QueueReport(CounterType type, EventHandler<ulong> resultHandler, bool hostReserved)
|
||||
{
|
||||
return _counterQueues[(int)type].QueueReport(resultHandler, _pipeline.DrawCount, hostReserved);
|
||||
|
@ -9,6 +9,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
Intel,
|
||||
Nvidia,
|
||||
ARM,
|
||||
Broadcom,
|
||||
Qualcomm,
|
||||
Apple,
|
||||
Unknown
|
||||
@ -28,6 +29,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
0x106B => Vendor.Apple,
|
||||
0x10DE => Vendor.Nvidia,
|
||||
0x13B5 => Vendor.ARM,
|
||||
0x14E4 => Vendor.Broadcom,
|
||||
0x8086 => Vendor.Intel,
|
||||
0x5143 => Vendor.Qualcomm,
|
||||
_ => Vendor.Unknown
|
||||
@ -43,6 +45,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
0x106B => "Apple",
|
||||
0x10DE => "NVIDIA",
|
||||
0x13B5 => "ARM",
|
||||
0x14E4 => "Broadcom",
|
||||
0x1AE0 => "Google",
|
||||
0x5143 => "Qualcomm",
|
||||
0x8086 => "Intel",
|
||||
|
@ -162,7 +162,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
if (messageSeverity.HasFlag(DebugUtilsMessageSeverityFlagsEXT.ErrorBitExt))
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Gpu, msg);
|
||||
//throw new Exception(msg);
|
||||
}
|
||||
else if (messageSeverity.HasFlag(DebugUtilsMessageSeverityFlagsEXT.WarningBitExt))
|
||||
{
|
||||
@ -379,14 +378,34 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
SType = StructureType.PhysicalDeviceFeatures2
|
||||
};
|
||||
|
||||
PhysicalDeviceCustomBorderColorFeaturesEXT featuresCustomBorderColorSupported = new PhysicalDeviceCustomBorderColorFeaturesEXT()
|
||||
PhysicalDeviceVulkan11Features supportedFeaturesVk11 = new PhysicalDeviceVulkan11Features()
|
||||
{
|
||||
SType = StructureType.PhysicalDeviceCustomBorderColorFeaturesExt
|
||||
SType = StructureType.PhysicalDeviceVulkan11Features,
|
||||
PNext = features2.PNext
|
||||
};
|
||||
|
||||
features2.PNext = &supportedFeaturesVk11;
|
||||
|
||||
PhysicalDeviceCustomBorderColorFeaturesEXT supportedFeaturesCustomBorderColor = new PhysicalDeviceCustomBorderColorFeaturesEXT()
|
||||
{
|
||||
SType = StructureType.PhysicalDeviceCustomBorderColorFeaturesExt,
|
||||
PNext = features2.PNext
|
||||
};
|
||||
|
||||
if (supportedExtensions.Contains("VK_EXT_custom_border_color"))
|
||||
{
|
||||
features2.PNext = &featuresCustomBorderColorSupported;
|
||||
features2.PNext = &supportedFeaturesCustomBorderColor;
|
||||
}
|
||||
|
||||
PhysicalDeviceTransformFeedbackFeaturesEXT supportedFeaturesTransformFeedback = new PhysicalDeviceTransformFeedbackFeaturesEXT()
|
||||
{
|
||||
SType = StructureType.PhysicalDeviceTransformFeedbackFeaturesExt,
|
||||
PNext = features2.PNext
|
||||
};
|
||||
|
||||
if (supportedExtensions.Contains(ExtTransformFeedback.ExtensionName))
|
||||
{
|
||||
features2.PNext = &supportedFeaturesTransformFeedback;
|
||||
}
|
||||
|
||||
PhysicalDeviceRobustness2FeaturesEXT supportedFeaturesRobustness2 = new PhysicalDeviceRobustness2FeaturesEXT()
|
||||
@ -408,42 +427,49 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
var features = new PhysicalDeviceFeatures()
|
||||
{
|
||||
DepthBiasClamp = true,
|
||||
DepthClamp = true,
|
||||
DualSrcBlend = true,
|
||||
DepthClamp = supportedFeatures.DepthClamp,
|
||||
DualSrcBlend = supportedFeatures.DualSrcBlend,
|
||||
FragmentStoresAndAtomics = true,
|
||||
GeometryShader = supportedFeatures.GeometryShader,
|
||||
ImageCubeArray = true,
|
||||
IndependentBlend = true,
|
||||
LogicOp = supportedFeatures.LogicOp,
|
||||
MultiViewport = true,
|
||||
OcclusionQueryPrecise = supportedFeatures.OcclusionQueryPrecise,
|
||||
MultiViewport = supportedFeatures.MultiViewport,
|
||||
PipelineStatisticsQuery = supportedFeatures.PipelineStatisticsQuery,
|
||||
SamplerAnisotropy = true,
|
||||
ShaderClipDistance = true,
|
||||
ShaderFloat64 = supportedFeatures.ShaderFloat64,
|
||||
ShaderImageGatherExtended = true,
|
||||
ShaderImageGatherExtended = supportedFeatures.ShaderImageGatherExtended,
|
||||
ShaderStorageImageMultisample = supportedFeatures.ShaderStorageImageMultisample,
|
||||
// ShaderStorageImageReadWithoutFormat = true,
|
||||
// ShaderStorageImageWriteWithoutFormat = true,
|
||||
TessellationShader = true,
|
||||
TessellationShader = supportedFeatures.TessellationShader,
|
||||
VertexPipelineStoresAndAtomics = true,
|
||||
RobustBufferAccess = useRobustBufferAccess
|
||||
};
|
||||
|
||||
void* pExtendedFeatures = null;
|
||||
|
||||
var featuresTransformFeedback = new PhysicalDeviceTransformFeedbackFeaturesEXT()
|
||||
{
|
||||
SType = StructureType.PhysicalDeviceTransformFeedbackFeaturesExt,
|
||||
PNext = pExtendedFeatures,
|
||||
TransformFeedback = true
|
||||
};
|
||||
PhysicalDeviceTransformFeedbackFeaturesEXT featuresTransformFeedback;
|
||||
|
||||
pExtendedFeatures = &featuresTransformFeedback;
|
||||
if (supportedExtensions.Contains(ExtTransformFeedback.ExtensionName))
|
||||
{
|
||||
featuresTransformFeedback = new PhysicalDeviceTransformFeedbackFeaturesEXT()
|
||||
{
|
||||
SType = StructureType.PhysicalDeviceTransformFeedbackFeaturesExt,
|
||||
PNext = pExtendedFeatures,
|
||||
TransformFeedback = supportedFeaturesTransformFeedback.TransformFeedback
|
||||
};
|
||||
|
||||
pExtendedFeatures = &featuresTransformFeedback;
|
||||
}
|
||||
|
||||
PhysicalDeviceRobustness2FeaturesEXT featuresRobustness2;
|
||||
|
||||
if (supportedExtensions.Contains("VK_EXT_robustness2"))
|
||||
{
|
||||
var featuresRobustness2 = new PhysicalDeviceRobustness2FeaturesEXT()
|
||||
featuresRobustness2 = new PhysicalDeviceRobustness2FeaturesEXT()
|
||||
{
|
||||
SType = StructureType.PhysicalDeviceRobustness2FeaturesExt,
|
||||
PNext = pExtendedFeatures,
|
||||
@ -466,7 +492,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
SType = StructureType.PhysicalDeviceVulkan11Features,
|
||||
PNext = pExtendedFeatures,
|
||||
ShaderDrawParameters = true
|
||||
ShaderDrawParameters = supportedFeaturesVk11.ShaderDrawParameters
|
||||
};
|
||||
|
||||
pExtendedFeatures = &featuresVk11;
|
||||
@ -527,8 +553,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
PhysicalDeviceCustomBorderColorFeaturesEXT featuresCustomBorderColor;
|
||||
|
||||
if (supportedExtensions.Contains("VK_EXT_custom_border_color") &&
|
||||
featuresCustomBorderColorSupported.CustomBorderColors &&
|
||||
featuresCustomBorderColorSupported.CustomBorderColorWithoutFormat)
|
||||
supportedFeaturesCustomBorderColor.CustomBorderColors &&
|
||||
supportedFeaturesCustomBorderColor.CustomBorderColorWithoutFormat)
|
||||
{
|
||||
featuresCustomBorderColor = new PhysicalDeviceCustomBorderColorFeaturesEXT()
|
||||
{
|
||||
|
@ -271,6 +271,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
supportsTransformFeedback,
|
||||
propertiesTransformFeedback.TransformFeedbackQueries,
|
||||
features2.Features.OcclusionQueryPrecise,
|
||||
supportedFeatures.PipelineStatisticsQuery,
|
||||
supportedFeatures.GeometryShader,
|
||||
propertiesSubgroupSizeControl.MinSubgroupSize,
|
||||
propertiesSubgroupSizeControl.MaxSubgroupSize,
|
||||
@ -589,9 +590,13 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
Vendor = VendorUtils.FromId(properties.VendorID);
|
||||
|
||||
IsAmdWindows = Vendor == Vendor.Amd && RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||
IsIntelWindows = Vendor == Vendor.Intel && RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||
IsTBDR = IsMoltenVk || Vendor == Vendor.Qualcomm || Vendor == Vendor.ARM || Vendor == Vendor.ImgTec;
|
||||
IsAmdWindows = Vendor == Vendor.Amd && OperatingSystem.IsWindows();
|
||||
IsIntelWindows = Vendor == Vendor.Intel && OperatingSystem.IsWindows();
|
||||
IsTBDR = IsMoltenVk ||
|
||||
Vendor == Vendor.Qualcomm ||
|
||||
Vendor == Vendor.ARM ||
|
||||
Vendor == Vendor.Broadcom ||
|
||||
Vendor == Vendor.ImgTec;
|
||||
|
||||
GpuVendor = vendorName;
|
||||
GpuRenderer = Marshal.PtrToStringAnsi((IntPtr)properties.DeviceName);
|
||||
@ -679,6 +684,16 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_counters.Update();
|
||||
}
|
||||
|
||||
public void ResetCounterPool()
|
||||
{
|
||||
_counters.ResetCounterPool();
|
||||
}
|
||||
|
||||
public void ResetFutureCounters(CommandBuffer cmd, int count)
|
||||
{
|
||||
_counters?.ResetFutureCounters(cmd, count);
|
||||
}
|
||||
|
||||
public void BackgroundContextAction(Action action, bool alwaysBackground = false)
|
||||
{
|
||||
action();
|
||||
|
@ -120,7 +120,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
ImageSharingMode = SharingMode.Exclusive,
|
||||
ImageArrayLayers = 1,
|
||||
PreTransform = capabilities.CurrentTransform,
|
||||
CompositeAlpha = CompositeAlphaFlagsKHR.OpaqueBitKhr,
|
||||
CompositeAlpha = ChooseCompositeAlpha(capabilities.SupportedCompositeAlpha),
|
||||
PresentMode = ChooseSwapPresentMode(presentModes, _vsyncEnabled),
|
||||
Clipped = true
|
||||
};
|
||||
@ -188,6 +188,22 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
return availableFormats[0];
|
||||
}
|
||||
|
||||
private static CompositeAlphaFlagsKHR ChooseCompositeAlpha(CompositeAlphaFlagsKHR supportedFlags)
|
||||
{
|
||||
if (supportedFlags.HasFlag(CompositeAlphaFlagsKHR.OpaqueBitKhr))
|
||||
{
|
||||
return CompositeAlphaFlagsKHR.OpaqueBitKhr;
|
||||
}
|
||||
else if (supportedFlags.HasFlag(CompositeAlphaFlagsKHR.PreMultipliedBitKhr))
|
||||
{
|
||||
return CompositeAlphaFlagsKHR.PreMultipliedBitKhr;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CompositeAlphaFlagsKHR.InheritBitKhr;
|
||||
}
|
||||
}
|
||||
|
||||
private static PresentModeKHR ChooseSwapPresentMode(PresentModeKHR[] availablePresentModes, bool vsyncEnabled)
|
||||
{
|
||||
if (!vsyncEnabled && availablePresentModes.Contains(PresentModeKHR.ImmediateKhr))
|
||||
@ -198,10 +214,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
return PresentModeKHR.MailboxKhr;
|
||||
}
|
||||
else if (availablePresentModes.Contains(PresentModeKHR.FifoKhr))
|
||||
{
|
||||
return PresentModeKHR.FifoKhr;
|
||||
}
|
||||
else
|
||||
{
|
||||
return PresentModeKHR.FifoKhr;
|
||||
@ -225,6 +237,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
public unsafe override void Present(ITexture texture, ImageCrop crop, Action swapBuffersCallback)
|
||||
{
|
||||
_gd.PipelineInternal.AutoFlush.Present();
|
||||
|
||||
uint nextImage = 0;
|
||||
|
||||
while (true)
|
||||
|
Reference in New Issue
Block a user