mirror of
https://github.com/Ryujinx/Ryujinx.git
synced 2024-11-20 07:14:14 +00:00
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
This commit is contained in:
parent
44d7fcff39
commit
bcb7761eac
6 changed files with 138 additions and 59 deletions
|
@ -20,7 +20,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
{
|
{
|
||||||
int numAcquiredBuffers = 0;
|
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)
|
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;
|
bufferItem = null;
|
||||||
|
|
||||||
|
@ -153,6 +153,8 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
return Status.NoMemory;
|
return Status.NoMemory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Core.UpdateMaxBufferCountCachedLocked(freeSlot);
|
||||||
|
|
||||||
slot = freeSlot;
|
slot = freeSlot;
|
||||||
|
|
||||||
Core.Slots[slot].GraphicBuffer.Set(graphicBuffer);
|
Core.Slots[slot].GraphicBuffer.Set(graphicBuffer);
|
||||||
|
|
|
@ -33,6 +33,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
public BufferInfo[] BufferHistory;
|
public BufferInfo[] BufferHistory;
|
||||||
public uint BufferHistoryPosition;
|
public uint BufferHistoryPosition;
|
||||||
public bool EnableExternalEvent;
|
public bool EnableExternalEvent;
|
||||||
|
public int MaxBufferCountCached;
|
||||||
|
|
||||||
public readonly object Lock = new object();
|
public readonly object Lock = new object();
|
||||||
|
|
||||||
|
@ -71,8 +72,9 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
|
|
||||||
Owner = process;
|
Owner = process;
|
||||||
|
|
||||||
BufferHistory = new BufferInfo[BufferHistoryArraySize];
|
BufferHistory = new BufferInfo[BufferHistoryArraySize];
|
||||||
EnableExternalEvent = true;
|
EnableExternalEvent = true;
|
||||||
|
MaxBufferCountCached = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetMinUndequeuedBufferCountLocked(bool async)
|
public int GetMinUndequeuedBufferCountLocked(bool async)
|
||||||
|
@ -95,6 +97,14 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
return GetMinUndequeuedBufferCountLocked(async);
|
return GetMinUndequeuedBufferCountLocked(async);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void UpdateMaxBufferCountCachedLocked(int slot)
|
||||||
|
{
|
||||||
|
if (MaxBufferCountCached <= slot)
|
||||||
|
{
|
||||||
|
MaxBufferCountCached = slot + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public int GetMaxBufferCountLocked(bool async)
|
public int GetMaxBufferCountLocked(bool async)
|
||||||
{
|
{
|
||||||
int minMaxBufferCount = GetMinMaxBufferCountLocked(async);
|
int minMaxBufferCount = GetMinMaxBufferCountLocked(async);
|
||||||
|
@ -103,7 +113,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
|
|
||||||
if (OverrideMaxBufferCount != 0)
|
if (OverrideMaxBufferCount != 0)
|
||||||
{
|
{
|
||||||
maxBufferCount = OverrideMaxBufferCount;
|
return OverrideMaxBufferCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Preserve all buffers already in control of the producer and the consumer.
|
// 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);
|
Monitor.Wait(Lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SignalIsAbandonedEvent()
|
public void SignalIsAllocatingEvent()
|
||||||
{
|
{
|
||||||
Monitor.PulseAll(Lock);
|
Monitor.PulseAll(Lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WaitIsAbandonedEvent()
|
public void WaitIsAllocatingEvent()
|
||||||
{
|
{
|
||||||
Monitor.Wait(Lock);
|
Monitor.Wait(Lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void FreeBufferLocked(int slot)
|
public void FreeBufferLocked(int slot)
|
||||||
{
|
{
|
||||||
|
Slots[slot].GraphicBuffer.Reset();
|
||||||
|
|
||||||
if (Slots[slot].BufferState == BufferState.Acquired)
|
if (Slots[slot].BufferState == BufferState.Acquired)
|
||||||
{
|
{
|
||||||
Slots[slot].NeedsCleanupOnRelease = true;
|
Slots[slot].NeedsCleanupOnRelease = true;
|
||||||
|
@ -206,9 +218,9 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
|
|
||||||
public void WaitWhileAllocatingLocked()
|
public void WaitWhileAllocatingLocked()
|
||||||
{
|
{
|
||||||
while (IsAbandoned)
|
while (IsAllocating)
|
||||||
{
|
{
|
||||||
WaitIsAbandonedEvent();
|
WaitIsAllocatingEvent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||||
|
using Ryujinx.HLE.HOS.Services.Settings;
|
||||||
using Ryujinx.HLE.HOS.Services.SurfaceFlinger.Types;
|
using Ryujinx.HLE.HOS.Services.SurfaceFlinger.Types;
|
||||||
using Ryujinx.HLE.HOS.Services.Time.Clock;
|
using Ryujinx.HLE.HOS.Services.Time.Clock;
|
||||||
using System;
|
using System;
|
||||||
|
@ -92,9 +93,22 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
return Status.BadValue;
|
return Status.BadValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Core.Queue.Clear();
|
int preallocatedBufferCount = GetPreallocatedBufferCountLocked();
|
||||||
Core.FreeAllBuffersLocked();
|
|
||||||
|
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.OverrideMaxBufferCount = bufferCount;
|
||||||
|
|
||||||
Core.SignalDequeueEvent();
|
Core.SignalDequeueEvent();
|
||||||
Core.SignalWaitBufferFreeEvent();
|
Core.SignalWaitBufferFreeEvent();
|
||||||
|
|
||||||
|
@ -162,8 +176,6 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
height = (uint)Core.DefaultHeight;
|
height = (uint)Core.DefaultHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
Core.Slots[slot].BufferState = BufferState.Dequeued;
|
|
||||||
|
|
||||||
GraphicBuffer graphicBuffer = Core.Slots[slot].GraphicBuffer.Object;
|
GraphicBuffer graphicBuffer = Core.Slots[slot].GraphicBuffer.Object;
|
||||||
|
|
||||||
if (Core.Slots[slot].GraphicBuffer.IsNull
|
if (Core.Slots[slot].GraphicBuffer.IsNull
|
||||||
|
@ -172,7 +184,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
|| graphicBuffer.Format != format
|
|| graphicBuffer.Format != format
|
||||||
|| (graphicBuffer.Usage & usage) != usage)
|
|| (graphicBuffer.Usage & usage) != usage)
|
||||||
{
|
{
|
||||||
if (Core.Slots[slot].GraphicBuffer.IsNull)
|
if (!Core.Slots[slot].IsPreallocated)
|
||||||
{
|
{
|
||||||
slot = BufferSlotArray.InvalidBufferSlot;
|
slot = BufferSlotArray.InvalidBufferSlot;
|
||||||
fence = AndroidFence.NoFence;
|
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;
|
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));
|
Core.CheckSystemEventsLocked(Core.GetMaxBufferCountLocked(async));
|
||||||
}
|
}
|
||||||
|
@ -285,6 +303,8 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
{
|
{
|
||||||
lock (Core.Lock)
|
lock (Core.Lock)
|
||||||
{
|
{
|
||||||
|
Core.WaitWhileAllocatingLocked();
|
||||||
|
|
||||||
Status status = WaitForFreeSlotThenRelock(false, out slot, out Status returnFlags);
|
Status status = WaitForFreeSlotThenRelock(false, out slot, out Status returnFlags);
|
||||||
|
|
||||||
if (status != Status.Success)
|
if (status != Status.Success)
|
||||||
|
@ -299,6 +319,8 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
return Status.Busy;
|
return Status.Busy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Core.UpdateMaxBufferCountCachedLocked(slot);
|
||||||
|
|
||||||
Core.Slots[slot].GraphicBuffer.Set(graphicBuffer);
|
Core.Slots[slot].GraphicBuffer.Set(graphicBuffer);
|
||||||
|
|
||||||
Core.Slots[slot].BufferState = BufferState.Dequeued;
|
Core.Slots[slot].BufferState = BufferState.Dequeued;
|
||||||
|
@ -441,6 +463,12 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
NumPendingBuffers = (uint)Core.Queue.Count
|
NumPendingBuffers = (uint)Core.Queue.Count
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if ((input.StickyTransform & 8) != 0)
|
||||||
|
{
|
||||||
|
output.TransformHint |= NativeWindowTransform.ReturnFrameNumber;
|
||||||
|
output.FrameNumber = Core.Slots[slot].FrameNumber;
|
||||||
|
}
|
||||||
|
|
||||||
_callbackTicket = _nextCallbackTicket++;
|
_callbackTicket = _nextCallbackTicket++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -475,6 +503,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
Core.Slots[slot].FrameNumber = 0;
|
Core.Slots[slot].FrameNumber = 0;
|
||||||
Core.Slots[slot].Fence = fence;
|
Core.Slots[slot].Fence = fence;
|
||||||
Core.SignalDequeueEvent();
|
Core.SignalDequeueEvent();
|
||||||
|
Core.SignalWaitBufferFreeEvent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -550,6 +579,12 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
output.Height = (uint)Core.DefaultHeight;
|
output.Height = (uint)Core.DefaultHeight;
|
||||||
output.TransformHint = Core.TransformHint;
|
output.TransformHint = Core.TransformHint;
|
||||||
output.NumPendingBuffers = (uint)Core.Queue.Count;
|
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;
|
return Status.Success;
|
||||||
default:
|
default:
|
||||||
return Status.BadValue;
|
return Status.BadValue;
|
||||||
|
@ -565,6 +600,8 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
|
|
||||||
lock (Core.Lock)
|
lock (Core.Lock)
|
||||||
{
|
{
|
||||||
|
Core.WaitWhileAllocatingLocked();
|
||||||
|
|
||||||
if (Core.IsAbandoned)
|
if (Core.IsAbandoned)
|
||||||
{
|
{
|
||||||
return Status.Success;
|
return Status.Success;
|
||||||
|
@ -580,13 +617,15 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
{
|
{
|
||||||
Core.Queue.Clear();
|
Core.Queue.Clear();
|
||||||
Core.FreeAllBuffersLocked();
|
Core.FreeAllBuffersLocked();
|
||||||
|
Core.SignalDequeueEvent();
|
||||||
|
|
||||||
producerListener = Core.ProducerListener;
|
producerListener = Core.ProducerListener;
|
||||||
|
|
||||||
Core.ProducerListener = null;
|
Core.ProducerListener = null;
|
||||||
Core.ConnectedApi = NativeWindowApi.NoApi;
|
Core.ConnectedApi = NativeWindowApi.NoApi;
|
||||||
|
|
||||||
Core.SignalDequeueEvent();
|
Core.SignalWaitBufferFreeEvent();
|
||||||
|
Core.SignalFrameAvailableEvent();
|
||||||
|
|
||||||
status = Status.Success;
|
status = Status.Success;
|
||||||
}
|
}
|
||||||
|
@ -599,6 +638,21 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
return status;
|
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)
|
public override Status SetPreallocatedBuffer(int slot, AndroidStrongPointer<GraphicBuffer> graphicBuffer)
|
||||||
{
|
{
|
||||||
if (slot < 0 || slot >= Core.Slots.Length)
|
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].RequestBufferCalled = false;
|
||||||
Core.Slots[slot].AcquireCalled = false;
|
Core.Slots[slot].AcquireCalled = false;
|
||||||
Core.Slots[slot].NeedsCleanupOnRelease = false;
|
Core.Slots[slot].NeedsCleanupOnRelease = false;
|
||||||
|
Core.Slots[slot].IsPreallocated = !graphicBuffer.IsNull;
|
||||||
Core.Slots[slot].FrameNumber = 0;
|
Core.Slots[slot].FrameNumber = 0;
|
||||||
|
|
||||||
Core.Slots[slot].GraphicBuffer.Set(graphicBuffer);
|
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;
|
Core.Slots[slot].GraphicBuffer.Object.Buffer.Usage &= (int)Core.ConsumerUsageBits;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bufferCount = 0;
|
Core.OverrideMaxBufferCount = GetPreallocatedBufferCountLocked();
|
||||||
|
|
||||||
for (int i = 0; i < Core.Slots.Length; i++)
|
|
||||||
{
|
|
||||||
if (!Core.Slots[i].GraphicBuffer.IsNull)
|
|
||||||
{
|
|
||||||
bufferCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Core.OverrideMaxBufferCount = bufferCount;
|
|
||||||
Core.UseAsyncBuffer = false;
|
Core.UseAsyncBuffer = false;
|
||||||
|
|
||||||
bool cleared = false;
|
|
||||||
|
|
||||||
if (!graphicBuffer.IsNull)
|
if (!graphicBuffer.IsNull)
|
||||||
{
|
{
|
||||||
// NOTE: Nintendo set the default width, height and format from the GraphicBuffer..
|
// NOTE: Nintendo set the default width, height and format from the GraphicBuffer..
|
||||||
|
@ -647,30 +690,30 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
}
|
}
|
||||||
else
|
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();
|
allBufferFreed = false;
|
||||||
Core.FreeAllBuffersLocked();
|
|
||||||
Core.SignalDequeueEvent();
|
|
||||||
Core.SignalWaitBufferFreeEvent();
|
|
||||||
Core.SignalFrameAvailableEvent();
|
|
||||||
|
|
||||||
cleared = true;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (allBufferFreed)
|
||||||
|
{
|
||||||
|
Core.Queue.Clear();
|
||||||
|
Core.FreeAllBuffersLocked();
|
||||||
|
Core.SignalDequeueEvent();
|
||||||
|
Core.SignalWaitBufferFreeEvent();
|
||||||
|
Core.SignalFrameAvailableEvent();
|
||||||
|
|
||||||
|
return Status.Success;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The dequeue event must not be signaled two times in case of clean up,
|
Core.SignalDequeueEvent();
|
||||||
// but for some reason, it still signals the wait buffer free event two times...
|
|
||||||
if (!cleared)
|
|
||||||
{
|
|
||||||
Core.SignalDequeueEvent();
|
|
||||||
}
|
|
||||||
|
|
||||||
Core.SignalWaitBufferFreeEvent();
|
Core.SignalWaitBufferFreeEvent();
|
||||||
|
|
||||||
return Status.Success;
|
return Status.Success;
|
||||||
|
@ -702,12 +745,16 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
return Status.BadValue;
|
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);
|
if (Core.Slots[slot].BufferState == BufferState.Free && !Core.Slots[slot].GraphicBuffer.IsNull && !Core.Slots[slot].IsPreallocated)
|
||||||
returnStatus |= Status.ReleaseAllBuffers;
|
{
|
||||||
|
Core.FreeBufferLocked(slot);
|
||||||
|
returnStatus |= Status.ReleaseAllBuffers;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
public bool AttachedByConsumer;
|
public bool AttachedByConsumer;
|
||||||
public TimeSpanType QueueTime;
|
public TimeSpanType QueueTime;
|
||||||
public TimeSpanType PresentationTime;
|
public TimeSpanType PresentationTime;
|
||||||
|
public bool IsPreallocated;
|
||||||
|
|
||||||
public BufferSlot()
|
public BufferSlot()
|
||||||
{
|
{
|
||||||
|
@ -22,6 +23,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
BufferState = BufferState.Free;
|
BufferState = BufferState.Free;
|
||||||
QueueTime = TimeSpanType.Zero;
|
QueueTime = TimeSpanType.Zero;
|
||||||
PresentationTime = TimeSpanType.Zero;
|
PresentationTime = TimeSpanType.Zero;
|
||||||
|
IsPreallocated = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,6 +72,20 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
public uint Height;
|
public uint Height;
|
||||||
public NativeWindowTransform TransformHint;
|
public NativeWindowTransform TransformHint;
|
||||||
public uint NumPendingBuffers;
|
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)
|
public ResultCode AdjustRefcount(int addVal, int type)
|
||||||
|
@ -174,7 +188,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
|
|
||||||
status = QueueBuffer(slot, ref queueInput, out queueOutput);
|
status = QueueBuffer(slot, ref queueInput, out queueOutput);
|
||||||
|
|
||||||
outputParcel.WriteUnmanagedType(ref queueOutput);
|
queueOutput.WriteToParcel(outputParcel);
|
||||||
|
|
||||||
outputParcel.WriteStatus(status);
|
outputParcel.WriteStatus(status);
|
||||||
|
|
||||||
|
@ -214,7 +228,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
|
|
||||||
status = Connect(listener, api, producerControlledByApp, out queueOutput);
|
status = Connect(listener, api, producerControlledByApp, out queueOutput);
|
||||||
|
|
||||||
outputParcel.WriteUnmanagedType(ref queueOutput);
|
queueOutput.WriteToParcel(outputParcel);
|
||||||
|
|
||||||
outputParcel.WriteStatus(status);
|
outputParcel.WriteStatus(status);
|
||||||
|
|
||||||
|
|
|
@ -5,12 +5,14 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
[Flags]
|
[Flags]
|
||||||
enum NativeWindowTransform : uint
|
enum NativeWindowTransform : uint
|
||||||
{
|
{
|
||||||
None = 0,
|
None = 0,
|
||||||
FlipX = 1,
|
FlipX = 1,
|
||||||
FlipY = 2,
|
FlipY = 2,
|
||||||
Rotate90 = 4,
|
Rotate90 = 4,
|
||||||
Rotate180 = FlipX | FlipY,
|
Rotate180 = FlipX | FlipY,
|
||||||
Rotate270 = Rotate90 | Rotate180,
|
Rotate270 = Rotate90 | Rotate180,
|
||||||
InverseDisplay = 8
|
InverseDisplay = 8,
|
||||||
|
NoVSyncCapability = 0x10,
|
||||||
|
ReturnFrameNumber = 0x20
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue