aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThog <me@thog.eu>2020-06-02 17:58:19 +0200
committerGitHub <noreply@github.com>2020-06-02 17:58:19 +0200
commitbcb7761eacaf9e40cc506648fec1eed58c23eff0 (patch)
tree49bf2ccffab602324d7977c8d3ba83c7393098b3
parent44d7fcff399888d311f61772a53146d924ee5b62 (diff)
SurfaceFlinger: fix some bugs (#1262)
* SurfaceFlinger: fix some bugs This fixes some bugs in the current implementation and make it closer to the real implementation. * Fix align of some variables
-rw-r--r--Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueConsumer.cs6
-rw-r--r--Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueCore.cs26
-rw-r--r--Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueProducer.cs127
-rw-r--r--Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferSlot.cs2
-rw-r--r--Ryujinx.HLE/HOS/Services/SurfaceFlinger/IGraphicBufferProducer.cs18
-rw-r--r--Ryujinx.HLE/HOS/Services/SurfaceFlinger/NativeWindowTransform.cs16
6 files changed, 137 insertions, 58 deletions
diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueConsumer.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueConsumer.cs
index fcbbf5f3..0465cfcc 100644
--- a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueConsumer.cs
+++ b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueConsumer.cs
@@ -20,7 +20,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
{
int numAcquiredBuffers = 0;
- for (int i = 0; i < Core.Slots.Length; i++)
+ for (int i = 0; i < Core.MaxBufferCountCached; i++)
{
if (Core.Slots[i].BufferState == BufferState.Acquired)
{
@@ -28,7 +28,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
}
}
- if (numAcquiredBuffers >= Core.MaxAcquiredBufferCount + 1)
+ if (numAcquiredBuffers > Core.MaxAcquiredBufferCount)
{
bufferItem = null;
@@ -153,6 +153,8 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
return Status.NoMemory;
}
+ Core.UpdateMaxBufferCountCachedLocked(freeSlot);
+
slot = freeSlot;
Core.Slots[slot].GraphicBuffer.Set(graphicBuffer);
diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueCore.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueCore.cs
index 7386bafc..0b529a0e 100644
--- a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueCore.cs
+++ b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueCore.cs
@@ -33,6 +33,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
public BufferInfo[] BufferHistory;
public uint BufferHistoryPosition;
public bool EnableExternalEvent;
+ public int MaxBufferCountCached;
public readonly object Lock = new object();
@@ -71,8 +72,9 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
Owner = process;
- BufferHistory = new BufferInfo[BufferHistoryArraySize];
- EnableExternalEvent = true;
+ BufferHistory = new BufferInfo[BufferHistoryArraySize];
+ EnableExternalEvent = true;
+ MaxBufferCountCached = 0;
}
public int GetMinUndequeuedBufferCountLocked(bool async)
@@ -95,6 +97,14 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
return GetMinUndequeuedBufferCountLocked(async);
}
+ public void UpdateMaxBufferCountCachedLocked(int slot)
+ {
+ if (MaxBufferCountCached <= slot)
+ {
+ MaxBufferCountCached = slot + 1;
+ }
+ }
+
public int GetMaxBufferCountLocked(bool async)
{
int minMaxBufferCount = GetMinMaxBufferCountLocked(async);
@@ -103,7 +113,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
if (OverrideMaxBufferCount != 0)
{
- maxBufferCount = OverrideMaxBufferCount;
+ return OverrideMaxBufferCount;
}
// Preserve all buffers already in control of the producer and the consumer.
@@ -163,18 +173,20 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
Monitor.Wait(Lock);
}
- public void SignalIsAbandonedEvent()
+ public void SignalIsAllocatingEvent()
{
Monitor.PulseAll(Lock);
}
- public void WaitIsAbandonedEvent()
+ public void WaitIsAllocatingEvent()
{
Monitor.Wait(Lock);
}
public void FreeBufferLocked(int slot)
{
+ Slots[slot].GraphicBuffer.Reset();
+
if (Slots[slot].BufferState == BufferState.Acquired)
{
Slots[slot].NeedsCleanupOnRelease = true;
@@ -206,9 +218,9 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
public void WaitWhileAllocatingLocked()
{
- while (IsAbandoned)
+ while (IsAllocating)
{
- WaitIsAbandonedEvent();
+ WaitIsAllocatingEvent();
}
}
diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueProducer.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueProducer.cs
index fb5d2194..3f1eaafe 100644
--- a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueProducer.cs
+++ b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueProducer.cs
@@ -1,5 +1,6 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.HLE.HOS.Services.Settings;
using Ryujinx.HLE.HOS.Services.SurfaceFlinger.Types;
using Ryujinx.HLE.HOS.Services.Time.Clock;
using System;
@@ -92,9 +93,22 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
return Status.BadValue;
}
- Core.Queue.Clear();
- Core.FreeAllBuffersLocked();
+ int preallocatedBufferCount = GetPreallocatedBufferCountLocked();
+
+ if (preallocatedBufferCount <= 0)
+ {
+ Core.Queue.Clear();
+ Core.FreeAllBuffersLocked();
+ }
+ else if (preallocatedBufferCount < bufferCount)
+ {
+ Logger.PrintError(LogClass.SurfaceFlinger, "Not enough buffers. Try with more pre-allocated buffers");
+
+ return Status.Success;
+ }
+
Core.OverrideMaxBufferCount = bufferCount;
+
Core.SignalDequeueEvent();
Core.SignalWaitBufferFreeEvent();
@@ -162,8 +176,6 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
height = (uint)Core.DefaultHeight;
}
- Core.Slots[slot].BufferState = BufferState.Dequeued;
-
GraphicBuffer graphicBuffer = Core.Slots[slot].GraphicBuffer.Object;
if (Core.Slots[slot].GraphicBuffer.IsNull
@@ -172,7 +184,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|| graphicBuffer.Format != format
|| (graphicBuffer.Usage & usage) != usage)
{
- if (Core.Slots[slot].GraphicBuffer.IsNull)
+ if (!Core.Slots[slot].IsPreallocated)
{
slot = BufferSlotArray.InvalidBufferSlot;
fence = AndroidFence.NoFence;
@@ -194,9 +206,15 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
}
}
+ Core.Slots[slot].BufferState = BufferState.Dequeued;
+
+ Core.UpdateMaxBufferCountCachedLocked(slot);
+
fence = Core.Slots[slot].Fence;
- Core.Slots[slot].Fence = AndroidFence.NoFence;
+ Core.Slots[slot].Fence = AndroidFence.NoFence;
+ Core.Slots[slot].QueueTime = TimeSpanType.Zero;
+ Core.Slots[slot].PresentationTime = TimeSpanType.Zero;
Core.CheckSystemEventsLocked(Core.GetMaxBufferCountLocked(async));
}
@@ -285,6 +303,8 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
{
lock (Core.Lock)
{
+ Core.WaitWhileAllocatingLocked();
+
Status status = WaitForFreeSlotThenRelock(false, out slot, out Status returnFlags);
if (status != Status.Success)
@@ -299,6 +319,8 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
return Status.Busy;
}
+ Core.UpdateMaxBufferCountCachedLocked(slot);
+
Core.Slots[slot].GraphicBuffer.Set(graphicBuffer);
Core.Slots[slot].BufferState = BufferState.Dequeued;
@@ -441,6 +463,12 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
NumPendingBuffers = (uint)Core.Queue.Count
};
+ if ((input.StickyTransform & 8) != 0)
+ {
+ output.TransformHint |= NativeWindowTransform.ReturnFrameNumber;
+ output.FrameNumber = Core.Slots[slot].FrameNumber;
+ }
+
_callbackTicket = _nextCallbackTicket++;
}
@@ -475,6 +503,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
Core.Slots[slot].FrameNumber = 0;
Core.Slots[slot].Fence = fence;
Core.SignalDequeueEvent();
+ Core.SignalWaitBufferFreeEvent();
}
}
@@ -550,6 +579,12 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
output.Height = (uint)Core.DefaultHeight;
output.TransformHint = Core.TransformHint;
output.NumPendingBuffers = (uint)Core.Queue.Count;
+
+ if (NxSettings.Settings.TryGetValue("nv!nvn_no_vsync_capability", out object noVSyncCapability) && (bool)noVSyncCapability)
+ {
+ output.TransformHint |= NativeWindowTransform.NoVSyncCapability;
+ }
+
return Status.Success;
default:
return Status.BadValue;
@@ -565,6 +600,8 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
lock (Core.Lock)
{
+ Core.WaitWhileAllocatingLocked();
+
if (Core.IsAbandoned)
{
return Status.Success;
@@ -580,13 +617,15 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
{
Core.Queue.Clear();
Core.FreeAllBuffersLocked();
+ Core.SignalDequeueEvent();
producerListener = Core.ProducerListener;
Core.ProducerListener = null;
Core.ConnectedApi = NativeWindowApi.NoApi;
- Core.SignalDequeueEvent();
+ Core.SignalWaitBufferFreeEvent();
+ Core.SignalFrameAvailableEvent();
status = Status.Success;
}
@@ -599,6 +638,21 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
return status;
}
+ private int GetPreallocatedBufferCountLocked()
+ {
+ int bufferCount = 0;
+
+ for (int i = 0; i < Core.Slots.Length; i++)
+ {
+ if (Core.Slots[i].IsPreallocated)
+ {
+ bufferCount++;
+ }
+ }
+
+ return bufferCount;
+ }
+
public override Status SetPreallocatedBuffer(int slot, AndroidStrongPointer<GraphicBuffer> graphicBuffer)
{
if (slot < 0 || slot >= Core.Slots.Length)
@@ -613,6 +667,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
Core.Slots[slot].RequestBufferCalled = false;
Core.Slots[slot].AcquireCalled = false;
Core.Slots[slot].NeedsCleanupOnRelease = false;
+ Core.Slots[slot].IsPreallocated = !graphicBuffer.IsNull;
Core.Slots[slot].FrameNumber = 0;
Core.Slots[slot].GraphicBuffer.Set(graphicBuffer);
@@ -622,21 +677,9 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
Core.Slots[slot].GraphicBuffer.Object.Buffer.Usage &= (int)Core.ConsumerUsageBits;
}
- int bufferCount = 0;
-
- for (int i = 0; i < Core.Slots.Length; i++)
- {
- if (!Core.Slots[i].GraphicBuffer.IsNull)
- {
- bufferCount++;
- }
- }
-
- Core.OverrideMaxBufferCount = bufferCount;
+ Core.OverrideMaxBufferCount = GetPreallocatedBufferCountLocked();
Core.UseAsyncBuffer = false;
- bool cleared = false;
-
if (!graphicBuffer.IsNull)
{
// NOTE: Nintendo set the default width, height and format from the GraphicBuffer..
@@ -647,30 +690,30 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
}
else
{
- foreach (BufferItem item in Core.Queue)
+ bool allBufferFreed = true;
+
+ for (int i = 0; i < Core.Slots.Length; i++)
{
- if (item.Slot >= BufferSlotArray.NumBufferSlots)
+ if (!Core.Slots[i].GraphicBuffer.IsNull)
{
- Core.Queue.Clear();
- Core.FreeAllBuffersLocked();
- Core.SignalDequeueEvent();
- Core.SignalWaitBufferFreeEvent();
- Core.SignalFrameAvailableEvent();
-
- cleared = true;
-
+ allBufferFreed = false;
break;
}
}
- }
- // The dequeue event must not be signaled two times in case of clean up,
- // but for some reason, it still signals the wait buffer free event two times...
- if (!cleared)
- {
- Core.SignalDequeueEvent();
+ if (allBufferFreed)
+ {
+ Core.Queue.Clear();
+ Core.FreeAllBuffersLocked();
+ Core.SignalDequeueEvent();
+ Core.SignalWaitBufferFreeEvent();
+ Core.SignalFrameAvailableEvent();
+
+ return Status.Success;
+ }
}
+ Core.SignalDequeueEvent();
Core.SignalWaitBufferFreeEvent();
return Status.Success;
@@ -702,12 +745,16 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
return Status.BadValue;
}
- for (int slot = maxBufferCount; slot < Core.Slots.Length; slot++)
+
+ if (maxBufferCount < Core.MaxBufferCountCached)
{
- if (!Core.Slots[slot].GraphicBuffer.IsNull)
+ for (int slot = maxBufferCount; slot < Core.MaxBufferCountCached; slot++)
{
- Core.FreeBufferLocked(slot);
- returnStatus |= Status.ReleaseAllBuffers;
+ if (Core.Slots[slot].BufferState == BufferState.Free && !Core.Slots[slot].GraphicBuffer.IsNull && !Core.Slots[slot].IsPreallocated)
+ {
+ Core.FreeBufferLocked(slot);
+ returnStatus |= Status.ReleaseAllBuffers;
+ }
}
}
diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferSlot.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferSlot.cs
index 2f17f8a2..fb84934a 100644
--- a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferSlot.cs
+++ b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferSlot.cs
@@ -15,6 +15,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
public bool AttachedByConsumer;
public TimeSpanType QueueTime;
public TimeSpanType PresentationTime;
+ public bool IsPreallocated;
public BufferSlot()
{
@@ -22,6 +23,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
BufferState = BufferState.Free;
QueueTime = TimeSpanType.Zero;
PresentationTime = TimeSpanType.Zero;
+ IsPreallocated = false;
}
}
}
diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IGraphicBufferProducer.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IGraphicBufferProducer.cs
index 3b4996c8..450d21a2 100644
--- a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IGraphicBufferProducer.cs
+++ b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IGraphicBufferProducer.cs
@@ -72,6 +72,20 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
public uint Height;
public NativeWindowTransform TransformHint;
public uint NumPendingBuffers;
+ public ulong FrameNumber;
+
+ public void WriteToParcel(Parcel parcel)
+ {
+ parcel.WriteUInt32(Width);
+ parcel.WriteUInt32(Height);
+ parcel.WriteUnmanagedType(ref TransformHint);
+ parcel.WriteUInt32(NumPendingBuffers);
+
+ if (TransformHint.HasFlag(NativeWindowTransform.ReturnFrameNumber))
+ {
+ parcel.WriteUInt64(FrameNumber);
+ }
+ }
}
public ResultCode AdjustRefcount(int addVal, int type)
@@ -174,7 +188,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
status = QueueBuffer(slot, ref queueInput, out queueOutput);
- outputParcel.WriteUnmanagedType(ref queueOutput);
+ queueOutput.WriteToParcel(outputParcel);
outputParcel.WriteStatus(status);
@@ -214,7 +228,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
status = Connect(listener, api, producerControlledByApp, out queueOutput);
- outputParcel.WriteUnmanagedType(ref queueOutput);
+ queueOutput.WriteToParcel(outputParcel);
outputParcel.WriteStatus(status);
diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/NativeWindowTransform.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/NativeWindowTransform.cs
index 650fe3c6..66482b12 100644
--- a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/NativeWindowTransform.cs
+++ b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/NativeWindowTransform.cs
@@ -5,12 +5,14 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
[Flags]
enum NativeWindowTransform : uint
{
- None = 0,
- FlipX = 1,
- FlipY = 2,
- Rotate90 = 4,
- Rotate180 = FlipX | FlipY,
- Rotate270 = Rotate90 | Rotate180,
- InverseDisplay = 8
+ None = 0,
+ FlipX = 1,
+ FlipY = 2,
+ Rotate90 = 4,
+ Rotate180 = FlipX | FlipY,
+ Rotate270 = Rotate90 | Rotate180,
+ InverseDisplay = 8,
+ NoVSyncCapability = 0x10,
+ ReturnFrameNumber = 0x20
}
}