aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ARMeilleure/State/ExecutionContext.cs2
-rw-r--r--Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueConsumer.cs46
-rw-r--r--Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueCore.cs24
-rw-r--r--Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueProducer.cs52
-rw-r--r--Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferSlot.cs9
-rw-r--r--Ryujinx.HLE/HOS/Services/SurfaceFlinger/IGraphicBufferProducer.cs14
-rw-r--r--Ryujinx.HLE/HOS/Services/SurfaceFlinger/IHOSBinderDriver.cs2
-rw-r--r--Ryujinx.HLE/HOS/Services/SurfaceFlinger/Parcel.cs5
-rw-r--r--Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs2
-rw-r--r--Ryujinx.HLE/HOS/Services/SurfaceFlinger/Types/BufferInfo.cs14
-rw-r--r--Ryujinx.HLE/HOS/Services/SurfaceFlinger/Types/BufferItem.cs (renamed from Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferItem.cs)0
-rw-r--r--Ryujinx.HLE/HOS/Services/Time/Clock/Types/TimeSpanType.cs5
12 files changed, 167 insertions, 8 deletions
diff --git a/ARMeilleure/State/ExecutionContext.cs b/ARMeilleure/State/ExecutionContext.cs
index 866eafbc..8593f41e 100644
--- a/ARMeilleure/State/ExecutionContext.cs
+++ b/ARMeilleure/State/ExecutionContext.cs
@@ -32,6 +32,8 @@ namespace ARMeilleure.State
}
}
+ public static TimeSpan ElapsedTime => _tickCounter.Elapsed;
+
public long TpidrEl0 { get; set; }
public long Tpidr { get; set; }
diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueConsumer.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueConsumer.cs
index 54ba5670..fcbbf5f3 100644
--- a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueConsumer.cs
+++ b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueConsumer.cs
@@ -1,5 +1,6 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Services.SurfaceFlinger.Types;
+using Ryujinx.HLE.HOS.Services.Time.Clock;
using System;
namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
@@ -57,6 +58,18 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
Core.Slots[bufferItem.Slot].NeedsCleanupOnRelease = true;
Core.Slots[bufferItem.Slot].BufferState = BufferState.Acquired;
Core.Slots[bufferItem.Slot].Fence = AndroidFence.NoFence;
+
+ ulong targetFrameNumber = Core.Slots[bufferItem.Slot].FrameNumber;
+
+ for (int i = 0; i < Core.BufferHistory.Length; i++)
+ {
+ if (Core.BufferHistory[i].FrameNumber == targetFrameNumber)
+ {
+ Core.BufferHistory[i].State = BufferState.Acquired;
+
+ break;
+ }
+ }
}
if (bufferItem.AcquireCalled)
@@ -368,5 +381,38 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
return Status.Success;
}
+
+ public Status SetPresentTime(int slot, ulong frameNumber, TimeSpanType presentationTime)
+ {
+ if (slot < 0 || slot >= Core.Slots.Length)
+ {
+ return Status.BadValue;
+ }
+
+ lock (Core.Lock)
+ {
+ if (Core.Slots[slot].FrameNumber != frameNumber)
+ {
+ return Status.StaleBufferSlot;
+ }
+
+ if (Core.Slots[slot].PresentationTime.NanoSeconds == 0)
+ {
+ Core.Slots[slot].PresentationTime = presentationTime;
+ }
+
+ for (int i = 0; i < Core.BufferHistory.Length; i++)
+ {
+ if (Core.BufferHistory[i].FrameNumber == frameNumber)
+ {
+ Core.BufferHistory[i].PresentationTime = presentationTime;
+
+ break;
+ }
+ }
+ }
+
+ return Status.Success;
+ }
}
}
diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueCore.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueCore.cs
index efc25239..70d72c5a 100644
--- a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueCore.cs
+++ b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueCore.cs
@@ -1,6 +1,7 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.HLE.HOS.Services.SurfaceFlinger.Types;
using System;
using System.Collections.Generic;
using System.Threading;
@@ -29,6 +30,9 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
public bool ConsumerControlledByApp;
public uint ConsumerUsageBits;
public List<BufferItem> Queue;
+ public BufferInfo[] BufferHistory;
+ public uint BufferHistoryPosition;
+ public bool EnableExternalEvent;
public readonly object Lock = new object();
@@ -37,6 +41,8 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
public KProcess Owner { get; }
+ public const int BufferHistoryArraySize = 8;
+
public BufferQueueCore(Switch device, KProcess process)
{
Slots = new BufferSlotArray();
@@ -64,6 +70,9 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
_frameAvailableEvent = new KEvent(device.System.KernelContext);
Owner = process;
+
+ BufferHistory = new BufferInfo[BufferHistoryArraySize];
+ EnableExternalEvent = true;
}
public int GetMinUndequeuedBufferCountLocked(bool async)
@@ -129,12 +138,18 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
public void SignalWaitBufferFreeEvent()
{
- _waitBufferFreeEvent.WritableEvent.Signal();
+ if (EnableExternalEvent)
+ {
+ _waitBufferFreeEvent.WritableEvent.Signal();
+ }
}
public void SignalFrameAvailableEvent()
{
- _frameAvailableEvent.WritableEvent.Signal();
+ if (EnableExternalEvent)
+ {
+ _frameAvailableEvent.WritableEvent.Signal();
+ }
}
// TODO: Find an accurate way to handle a regular condvar here as this will wake up unwanted threads in some edge cases.
@@ -201,6 +216,11 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
public void CheckSystemEventsLocked(int maxBufferCount)
{
+ if (!EnableExternalEvent)
+ {
+ return;
+ }
+
bool needBufferReleaseSignal = false;
bool needFrameAvailableSignal = false;
diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueProducer.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueProducer.cs
index 333bffd1..fb5d2194 100644
--- a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueProducer.cs
+++ b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueProducer.cs
@@ -1,7 +1,7 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Kernel.Threading;
-using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
using Ryujinx.HLE.HOS.Services.SurfaceFlinger.Types;
+using Ryujinx.HLE.HOS.Services.Time.Clock;
using System;
using System.Threading;
@@ -92,8 +92,11 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
return Status.BadValue;
}
+ Core.Queue.Clear();
+ Core.FreeAllBuffersLocked();
Core.OverrideMaxBufferCount = bufferCount;
Core.SignalDequeueEvent();
+ Core.SignalWaitBufferFreeEvent();
listener = Core.ConsumerListener;
}
@@ -363,7 +366,9 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
Core.Slots[slot].Fence = input.Fence;
Core.Slots[slot].BufferState = BufferState.Queued;
Core.FrameCounter++;
- Core.Slots[slot].FrameNumber = Core.FrameCounter;
+ Core.Slots[slot].FrameNumber = Core.FrameCounter;
+ Core.Slots[slot].QueueTime = TimeSpanType.FromTimeSpan(ARMeilleure.State.ExecutionContext.ElapsedTime);
+ Core.Slots[slot].PresentationTime = TimeSpanType.Zero;
item.AcquireCalled = Core.Slots[slot].AcquireCalled;
item.Crop = input.Crop;
@@ -381,6 +386,15 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
item.GraphicBuffer.Set(Core.Slots[slot].GraphicBuffer);
item.GraphicBuffer.Object.IncrementNvMapHandleRefCount(Core.Owner);
+ Core.BufferHistoryPosition = (Core.BufferHistoryPosition + 1) % BufferQueueCore.BufferHistoryArraySize;
+
+ Core.BufferHistory[Core.BufferHistoryPosition] = new BufferInfo
+ {
+ FrameNumber = Core.FrameCounter,
+ QueueTime = Core.Slots[slot].QueueTime,
+ State = BufferState.Queued
+ };
+
_stickyTransform = input.StickyTransform;
if (Core.Queue.Count == 0)
@@ -488,6 +502,9 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
case NativeWindowAttribute.MinUnqueuedBuffers:
outValue = Core.GetMinUndequeuedBufferCountLocked(false);
return Status.Success;
+ case NativeWindowAttribute.ConsumerRunningBehind:
+ outValue = Core.Queue.Count > 1 ? 1 : 0;
+ return Status.Success;
case NativeWindowAttribute.ConsumerUsageBits:
outValue = (int)Core.ConsumerUsageBits;
return Status.Success;
@@ -561,6 +578,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
case NativeWindowApi.Camera:
if (Core.ConnectedApi == api)
{
+ Core.Queue.Clear();
Core.FreeAllBuffersLocked();
producerListener = Core.ProducerListener;
@@ -762,5 +780,35 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
{
return Core.GetWaitBufferFreeEvent();
}
+
+ public override Status GetBufferHistory(int bufferHistoryCount, out Span<BufferInfo> bufferInfos)
+ {
+ if (bufferHistoryCount <= 0)
+ {
+ bufferInfos = Span<BufferInfo>.Empty;
+
+ return Status.BadValue;
+ }
+
+ lock (Core.Lock)
+ {
+ bufferHistoryCount = Math.Min(bufferHistoryCount, Core.BufferHistory.Length);
+
+ BufferInfo[] result = new BufferInfo[bufferHistoryCount];
+
+ uint position = Core.BufferHistoryPosition;
+
+ for (uint i = 0; i < bufferHistoryCount; i++)
+ {
+ result[i] = Core.BufferHistory[(position - i) % Core.BufferHistory.Length];
+
+ position--;
+ }
+
+ bufferInfos = result;
+
+ return Status.Success;
+ }
+ }
}
}
diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferSlot.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferSlot.cs
index dbfba0ee..2f17f8a2 100644
--- a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferSlot.cs
+++ b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferSlot.cs
@@ -1,4 +1,5 @@
using Ryujinx.HLE.HOS.Services.SurfaceFlinger.Types;
+using Ryujinx.HLE.HOS.Services.Time.Clock;
namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
{
@@ -12,11 +13,15 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
public bool AcquireCalled;
public bool NeedsCleanupOnRelease;
public bool AttachedByConsumer;
+ public TimeSpanType QueueTime;
+ public TimeSpanType PresentationTime;
public BufferSlot()
{
- GraphicBuffer = new AndroidStrongPointer<GraphicBuffer>();
- BufferState = BufferState.Free;
+ GraphicBuffer = new AndroidStrongPointer<GraphicBuffer>();
+ BufferState = BufferState.Free;
+ QueueTime = TimeSpanType.Zero;
+ PresentationTime = TimeSpanType.Zero;
}
}
}
diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IGraphicBufferProducer.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IGraphicBufferProducer.cs
index 41e21648..3b4996c8 100644
--- a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IGraphicBufferProducer.cs
+++ b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IGraphicBufferProducer.cs
@@ -237,6 +237,18 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
outputParcel.WriteStatus(status);
break;
+ case TransactionCode.GetBufferHistory:
+ int bufferHistoryCount = inputParcel.ReadInt32();
+
+ status = GetBufferHistory(bufferHistoryCount, out Span<BufferInfo> bufferInfos);
+
+ outputParcel.WriteStatus(status);
+
+ outputParcel.WriteInt32(bufferInfos.Length);
+
+ outputParcel.WriteUnmanagedSpan<BufferInfo>(bufferInfos);
+
+ break;
default:
throw new NotImplementedException($"Transaction {(TransactionCode)code} not implemented");
}
@@ -272,5 +284,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
public abstract Status Disconnect(NativeWindowApi api);
public abstract Status SetPreallocatedBuffer(int slot, AndroidStrongPointer<GraphicBuffer> graphicBuffer);
+
+ public abstract Status GetBufferHistory(int bufferHistoryCount, out Span<BufferInfo> bufferInfos);
}
}
diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IHOSBinderDriver.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IHOSBinderDriver.cs
index 5546418f..8ee943df 100644
--- a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IHOSBinderDriver.cs
+++ b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IHOSBinderDriver.cs
@@ -74,7 +74,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
public ResultCode TransactParcelAuto(ServiceCtx context)
{
int binderId = context.RequestData.ReadInt32();
-
+
uint code = context.RequestData.ReadUInt32();
uint flags = context.RequestData.ReadUInt32();
diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/Parcel.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/Parcel.cs
index 3def026b..fbe38c08 100644
--- a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/Parcel.cs
+++ b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/Parcel.cs
@@ -173,6 +173,11 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
public void WriteInt64(long value) => WriteUnmanagedType(ref value);
public void WriteUInt64(ulong value) => WriteUnmanagedType(ref value);
+ public void WriteUnmanagedSpan<T>(ReadOnlySpan<T> value) where T : unmanaged
+ {
+ WriteInplace(MemoryMarshal.Cast<T, byte>(value));
+ }
+
public void WriteUnmanagedType<T>(ref T value) where T : unmanaged
{
WriteInplace(SpanHelpers.AsByteSpan(ref value));
diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs
index 784f8c46..e1eb55ad 100644
--- a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs
+++ b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs
@@ -198,7 +198,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
{
Compose();
- _device.System.SignalVsync();
+ _device.System?.SignalVsync();
_ticks = Math.Min(_ticks - _ticksPerFrame, _ticksPerFrame);
}
diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/Types/BufferInfo.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/Types/BufferInfo.cs
new file mode 100644
index 00000000..12c41b0d
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/Types/BufferInfo.cs
@@ -0,0 +1,14 @@
+using Ryujinx.HLE.HOS.Services.Time.Clock;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger.Types
+{
+ [StructLayout(LayoutKind.Sequential, Size = 0x1C, Pack = 1)]
+ struct BufferInfo
+ {
+ public ulong FrameNumber;
+ public TimeSpanType QueueTime;
+ public TimeSpanType PresentationTime;
+ public BufferState State;
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferItem.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/Types/BufferItem.cs
index 19fc7900..19fc7900 100644
--- a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferItem.cs
+++ b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/Types/BufferItem.cs
diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/Types/TimeSpanType.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/Types/TimeSpanType.cs
index 89497d82..94c1b488 100644
--- a/Ryujinx.HLE/HOS/Services/Time/Clock/Types/TimeSpanType.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/Clock/Types/TimeSpanType.cs
@@ -39,6 +39,11 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
return new TimeSpanType(seconds * NanoSecondsPerSecond);
}
+ public static TimeSpanType FromTimeSpan(TimeSpan timeSpan)
+ {
+ return new TimeSpanType((long)(timeSpan.TotalMilliseconds * 1000000));
+ }
+
public static TimeSpanType FromTicks(ulong ticks, ulong frequency)
{
return FromSeconds((long)ticks / (long)frequency);