Improved and simplified window texture presentation
This commit is contained in:
parent
b2b2e04669
commit
16d88c21fc
11 changed files with 137 additions and 497 deletions
|
@ -2,11 +2,7 @@ namespace Ryujinx.Graphics.GAL
|
|||
{
|
||||
public interface IWindow
|
||||
{
|
||||
void Present();
|
||||
|
||||
void QueueTexture(ITexture texture, ImageCrop crop, object context);
|
||||
|
||||
void RegisterTextureReleaseCallback(TextureReleaseCallback callback);
|
||||
void Present(ITexture texture, ImageCrop crop);
|
||||
|
||||
void SetSize(int width, int height);
|
||||
}
|
||||
|
|
|
@ -76,8 +76,6 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
|||
state.RegisterCallback(MethodOffset.UniformBufferBindFragment, UniformBufferBindFragment);
|
||||
}
|
||||
|
||||
public Image.Texture GetTexture(ulong address) => _textureManager.Find2(address);
|
||||
|
||||
private void UpdateState(GpuState state)
|
||||
{
|
||||
// Shaders must be the first one to be updated if modified, because
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.GAL.Texture;
|
||||
using Ryujinx.Graphics.Gpu.Engine;
|
||||
using Ryujinx.Graphics.Gpu.Image;
|
||||
using Ryujinx.Graphics.Gpu.Memory;
|
||||
using Ryujinx.Graphics.Gpu.State;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu
|
||||
|
@ -24,6 +21,8 @@ namespace Ryujinx.Graphics.Gpu
|
|||
|
||||
public DmaPusher DmaPusher { get; }
|
||||
|
||||
public Window Window { get; }
|
||||
|
||||
internal int SequenceNumber { get; private set; }
|
||||
|
||||
private Lazy<Capabilities> _caps;
|
||||
|
@ -44,6 +43,8 @@ namespace Ryujinx.Graphics.Gpu
|
|||
|
||||
DmaPusher = new DmaPusher(this);
|
||||
|
||||
Window = new Window(this);
|
||||
|
||||
_caps = new Lazy<Capabilities>(GetCapabilities);
|
||||
}
|
||||
|
||||
|
@ -52,37 +53,6 @@ namespace Ryujinx.Graphics.Gpu
|
|||
SequenceNumber++;
|
||||
}
|
||||
|
||||
public ITexture GetTexture(
|
||||
ulong address,
|
||||
int width,
|
||||
int height,
|
||||
int stride,
|
||||
bool isLinear,
|
||||
int gobBlocksInY,
|
||||
Format format,
|
||||
int bytesPerPixel)
|
||||
{
|
||||
FormatInfo formatInfo = new FormatInfo(format, 1, 1, bytesPerPixel);
|
||||
|
||||
TextureInfo info = new TextureInfo(
|
||||
address,
|
||||
width,
|
||||
height,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
stride,
|
||||
isLinear,
|
||||
gobBlocksInY,
|
||||
1,
|
||||
1,
|
||||
Target.Texture2D,
|
||||
formatInfo);
|
||||
|
||||
return Methods.GetTexture(address)?.HostTexture;
|
||||
}
|
||||
|
||||
private Capabilities GetCapabilities()
|
||||
{
|
||||
return Renderer.GetCapabilities();
|
||||
|
|
|
@ -335,18 +335,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
return true;
|
||||
}
|
||||
|
||||
if (_info.FormatInfo.Format == Format.R8G8B8A8Srgb &&
|
||||
info.FormatInfo.Format == Format.R8G8B8A8Unorm && !strict)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_info.FormatInfo.Format == Format.R8G8B8A8Unorm &&
|
||||
info.FormatInfo.Format == Format.R8G8B8A8Srgb && !strict)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return _info.FormatInfo.Format == info.FormatInfo.Format;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
private ITexture[] _rtHostColors;
|
||||
private ITexture _rtHostDs;
|
||||
|
||||
private ConcurrentRangeList<Texture> _textures;
|
||||
private RangeList<Texture> _textures;
|
||||
|
||||
private AutoDeleteCache _cache;
|
||||
|
||||
|
@ -39,7 +39,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
|
||||
_rtHostColors = new ITexture[Constants.TotalRenderTargets];
|
||||
|
||||
_textures = new ConcurrentRangeList<Texture>();
|
||||
_textures = new RangeList<Texture>();
|
||||
|
||||
_cache = new AutoDeleteCache();
|
||||
}
|
||||
|
@ -561,28 +561,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
info.SwizzleA);
|
||||
}
|
||||
|
||||
public Texture Find2(ulong address)
|
||||
{
|
||||
Texture[] ts = _textures.FindOverlaps(address, 1);
|
||||
|
||||
if (ts.Length == 2)
|
||||
{
|
||||
return ts[1];
|
||||
}
|
||||
|
||||
if (ts.Length == 0)
|
||||
{
|
||||
ts = _textures.FindOverlaps(address - 1, 2);
|
||||
}
|
||||
|
||||
if (ts.Length == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return ts[0];
|
||||
}
|
||||
|
||||
public void Flush()
|
||||
{
|
||||
foreach (Texture texture in _cache)
|
||||
|
|
|
@ -1,208 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
class ConcurrentRangeList<T> where T : IRange<T>
|
||||
{
|
||||
private List<T> _items;
|
||||
|
||||
public ConcurrentRangeList()
|
||||
{
|
||||
_items = new List<T>();
|
||||
}
|
||||
|
||||
public void Add(T item)
|
||||
{
|
||||
lock (_items)
|
||||
{
|
||||
int index = BinarySearch(item.Address);
|
||||
|
||||
if (index < 0)
|
||||
{
|
||||
index = ~index;
|
||||
}
|
||||
|
||||
_items.Insert(index, item);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Remove(T item)
|
||||
{
|
||||
lock (_items)
|
||||
{
|
||||
int index = BinarySearch(item.Address);
|
||||
|
||||
if (index >= 0)
|
||||
{
|
||||
while (index > 0 && _items[index - 1].Address == item.Address)
|
||||
{
|
||||
index--;
|
||||
}
|
||||
|
||||
while (index < _items.Count)
|
||||
{
|
||||
if (_items[index].Equals(item))
|
||||
{
|
||||
_items.RemoveAt(index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_items[index].Address > item.Address)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public T FindFirstOverlap(T item)
|
||||
{
|
||||
return FindFirstOverlap(item.Address, item.Size);
|
||||
}
|
||||
|
||||
public T FindFirstOverlap(ulong address, ulong size)
|
||||
{
|
||||
lock (_items)
|
||||
{
|
||||
int index = BinarySearch(address, size);
|
||||
|
||||
if (index < 0)
|
||||
{
|
||||
return default(T);
|
||||
}
|
||||
|
||||
return _items[index];
|
||||
}
|
||||
}
|
||||
|
||||
public T[] FindOverlaps(T item)
|
||||
{
|
||||
return FindOverlaps(item.Address, item.Size);
|
||||
}
|
||||
|
||||
public T[] FindOverlaps(ulong address, ulong size)
|
||||
{
|
||||
List<T> overlapsList = new List<T>();
|
||||
|
||||
ulong endAddress = address + size;
|
||||
|
||||
lock (_items)
|
||||
{
|
||||
foreach (T item in _items)
|
||||
{
|
||||
if (item.Address >= endAddress)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (item.OverlapsWith(address, size))
|
||||
{
|
||||
overlapsList.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return overlapsList.ToArray();
|
||||
}
|
||||
|
||||
public T[] FindOverlaps(ulong address)
|
||||
{
|
||||
List<T> overlapsList = new List<T>();
|
||||
|
||||
lock (_items)
|
||||
{
|
||||
int index = BinarySearch(address);
|
||||
|
||||
if (index >= 0)
|
||||
{
|
||||
while (index > 0 && _items[index - 1].Address == address)
|
||||
{
|
||||
index--;
|
||||
}
|
||||
|
||||
while (index < _items.Count)
|
||||
{
|
||||
T overlap = _items[index++];
|
||||
|
||||
if (overlap.Address != address)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
overlapsList.Add(overlap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return overlapsList.ToArray();
|
||||
}
|
||||
|
||||
private int BinarySearch(ulong address)
|
||||
{
|
||||
int left = 0;
|
||||
int right = _items.Count - 1;
|
||||
|
||||
while (left <= right)
|
||||
{
|
||||
int range = right - left;
|
||||
|
||||
int middle = left + (range >> 1);
|
||||
|
||||
T item = _items[middle];
|
||||
|
||||
if (item.Address == address)
|
||||
{
|
||||
return middle;
|
||||
}
|
||||
|
||||
if (address < item.Address)
|
||||
{
|
||||
right = middle - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
left = middle + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return ~left;
|
||||
}
|
||||
|
||||
private int BinarySearch(ulong address, ulong size)
|
||||
{
|
||||
int left = 0;
|
||||
int right = _items.Count - 1;
|
||||
|
||||
while (left <= right)
|
||||
{
|
||||
int range = right - left;
|
||||
|
||||
int middle = left + (range >> 1);
|
||||
|
||||
T item = _items[middle];
|
||||
|
||||
if (item.OverlapsWith(address, size))
|
||||
{
|
||||
return middle;
|
||||
}
|
||||
|
||||
if (address < item.Address)
|
||||
{
|
||||
right = middle - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
left = middle + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return ~left;
|
||||
}
|
||||
}
|
||||
}
|
94
Ryujinx.Graphics.Gpu/Window.cs
Normal file
94
Ryujinx.Graphics.Gpu/Window.cs
Normal file
|
@ -0,0 +1,94 @@
|
|||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.GAL.Texture;
|
||||
using Ryujinx.Graphics.Gpu.Image;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu
|
||||
{
|
||||
public class Window
|
||||
{
|
||||
private GpuContext _context;
|
||||
|
||||
private struct PresentationTexture
|
||||
{
|
||||
public TextureInfo Info { get; }
|
||||
public ImageCrop Crop { get; }
|
||||
public Action<object> Callback { get; }
|
||||
public object UserObj { get; }
|
||||
|
||||
public PresentationTexture(
|
||||
TextureInfo info,
|
||||
ImageCrop crop,
|
||||
Action<object> callback,
|
||||
object userObj)
|
||||
{
|
||||
Info = info;
|
||||
Crop = crop;
|
||||
Callback = callback;
|
||||
UserObj = userObj;
|
||||
}
|
||||
}
|
||||
|
||||
private ConcurrentQueue<PresentationTexture> _frameQueue;
|
||||
|
||||
public Window(GpuContext context)
|
||||
{
|
||||
_context = context;
|
||||
|
||||
_frameQueue = new ConcurrentQueue<PresentationTexture>();
|
||||
}
|
||||
|
||||
public void EnqueueFrameThreadSafe(
|
||||
ulong address,
|
||||
int width,
|
||||
int height,
|
||||
int stride,
|
||||
bool isLinear,
|
||||
int gobBlocksInY,
|
||||
Format format,
|
||||
int bytesPerPixel,
|
||||
ImageCrop crop,
|
||||
Action<object> callback,
|
||||
object userObj)
|
||||
{
|
||||
FormatInfo formatInfo = new FormatInfo(format, 1, 1, bytesPerPixel);
|
||||
|
||||
TextureInfo info = new TextureInfo(
|
||||
address,
|
||||
width,
|
||||
height,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
stride,
|
||||
isLinear,
|
||||
gobBlocksInY,
|
||||
1,
|
||||
1,
|
||||
Target.Texture2D,
|
||||
formatInfo);
|
||||
|
||||
_frameQueue.Enqueue(new PresentationTexture(info, crop, callback, userObj));
|
||||
}
|
||||
|
||||
public void Present(Action swapBuffersCallback)
|
||||
{
|
||||
_context.AdvanceSequence();
|
||||
|
||||
if (_frameQueue.TryDequeue(out PresentationTexture pt))
|
||||
{
|
||||
Image.Texture texture = _context.Methods.TextureManager.FindOrCreateTexture(pt.Info);
|
||||
|
||||
texture.SynchronizeMemory();
|
||||
|
||||
_context.Renderer.Window.Present(texture.HostTexture, pt.Crop);
|
||||
|
||||
swapBuffersCallback();
|
||||
|
||||
pt.Callback(pt.UserObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
using OpenTK.Graphics.OpenGL;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics.OpenGL
|
||||
{
|
||||
|
@ -13,53 +12,19 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
private int _width;
|
||||
private int _height;
|
||||
|
||||
private int _resizeWidth;
|
||||
private int _resizeHeight;
|
||||
|
||||
private bool _sizeChanged;
|
||||
|
||||
private object _resizeLocker;
|
||||
|
||||
private int _blitFramebufferHandle;
|
||||
private int _copyFramebufferHandle;
|
||||
|
||||
private int _screenTextureHandle;
|
||||
|
||||
private TextureReleaseCallback _release;
|
||||
|
||||
private struct PresentationTexture
|
||||
{
|
||||
public TextureView Texture { get; }
|
||||
|
||||
public ImageCrop Crop { get; }
|
||||
|
||||
public object Context { get; }
|
||||
|
||||
public PresentationTexture(TextureView texture, ImageCrop crop, object context)
|
||||
{
|
||||
Texture = texture;
|
||||
Crop = crop;
|
||||
Context = context;
|
||||
}
|
||||
}
|
||||
|
||||
private Queue<PresentationTexture> _textures;
|
||||
|
||||
public Window()
|
||||
{
|
||||
_width = NativeWidth;
|
||||
_height = NativeHeight;
|
||||
|
||||
_resizeLocker = new object();
|
||||
|
||||
_textures = new Queue<PresentationTexture>();
|
||||
}
|
||||
|
||||
public void Present()
|
||||
public void Present(ITexture texture, ImageCrop crop)
|
||||
{
|
||||
GL.Disable(EnableCap.FramebufferSrgb);
|
||||
TextureView view = (TextureView)texture;
|
||||
|
||||
CopyTextureFromQueue();
|
||||
GL.Disable(EnableCap.FramebufferSrgb);
|
||||
|
||||
int oldReadFramebufferHandle = GL.GetInteger(GetPName.ReadFramebufferBinding);
|
||||
int oldDrawFramebufferHandle = GL.GetInteger(GetPName.DrawFramebufferBinding);
|
||||
|
@ -67,52 +32,10 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, 0);
|
||||
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, GetCopyFramebufferHandleLazy());
|
||||
|
||||
GL.ReadBuffer(ReadBufferMode.ColorAttachment0);
|
||||
|
||||
GL.Clear(ClearBufferMask.ColorBufferBit);
|
||||
|
||||
int windowWidth = _width;
|
||||
int windowHeight = _height;
|
||||
|
||||
GL.BlitFramebuffer(
|
||||
0,
|
||||
0,
|
||||
windowWidth,
|
||||
windowHeight,
|
||||
0,
|
||||
0,
|
||||
windowWidth,
|
||||
windowHeight,
|
||||
ClearBufferMask.ColorBufferBit,
|
||||
BlitFramebufferFilter.Linear);
|
||||
|
||||
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, oldReadFramebufferHandle);
|
||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, oldDrawFramebufferHandle);
|
||||
|
||||
GL.Enable(EnableCap.FramebufferSrgb);
|
||||
}
|
||||
|
||||
private void CopyTextureFromQueue()
|
||||
{
|
||||
if (!_textures.TryDequeue(out PresentationTexture presentationTexture))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TextureView texture = presentationTexture.Texture;
|
||||
ImageCrop crop = presentationTexture.Crop;
|
||||
object context = presentationTexture.Context;
|
||||
|
||||
int oldReadFramebufferHandle = GL.GetInteger(GetPName.ReadFramebufferBinding);
|
||||
int oldDrawFramebufferHandle = GL.GetInteger(GetPName.DrawFramebufferBinding);
|
||||
|
||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, GetCopyFramebufferHandleLazy());
|
||||
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, GetBlitFramebufferHandleLazy());
|
||||
|
||||
GL.FramebufferTexture(
|
||||
FramebufferTarget.ReadFramebuffer,
|
||||
FramebufferAttachment.ColorAttachment0,
|
||||
texture.Handle,
|
||||
view.Handle,
|
||||
0);
|
||||
|
||||
GL.ReadBuffer(ReadBufferMode.ColorAttachment0);
|
||||
|
@ -124,7 +47,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
if (crop.Left == 0 && crop.Right == 0)
|
||||
{
|
||||
srcX0 = 0;
|
||||
srcX1 = texture.Width;
|
||||
srcX1 = view.Width;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -135,7 +58,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
if (crop.Top == 0 && crop.Bottom == 0)
|
||||
{
|
||||
srcY0 = 0;
|
||||
srcY1 = texture.Height;
|
||||
srcY1 = view.Height;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -173,126 +96,25 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, oldReadFramebufferHandle);
|
||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, oldDrawFramebufferHandle);
|
||||
|
||||
texture.Release();
|
||||
|
||||
Release(context);
|
||||
}
|
||||
|
||||
public void QueueTexture(ITexture texture, ImageCrop crop, object context)
|
||||
{
|
||||
if (texture == null)
|
||||
{
|
||||
Release(context);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
TextureView textureView = (TextureView)texture;
|
||||
|
||||
textureView.Acquire();
|
||||
|
||||
_textures.Enqueue(new PresentationTexture(textureView, crop, context));
|
||||
}
|
||||
|
||||
public void RegisterTextureReleaseCallback(TextureReleaseCallback callback)
|
||||
{
|
||||
_release = callback;
|
||||
GL.Enable(EnableCap.FramebufferSrgb);
|
||||
}
|
||||
|
||||
public void SetSize(int width, int height)
|
||||
{
|
||||
lock (_resizeLocker)
|
||||
{
|
||||
_resizeWidth = width;
|
||||
_resizeHeight = height;
|
||||
|
||||
_sizeChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void Release(object context)
|
||||
{
|
||||
if (_release != null)
|
||||
{
|
||||
_release(context);
|
||||
}
|
||||
}
|
||||
|
||||
private int GetBlitFramebufferHandleLazy()
|
||||
{
|
||||
int handle = _blitFramebufferHandle;
|
||||
|
||||
if (handle == 0)
|
||||
{
|
||||
handle = GL.GenFramebuffer();
|
||||
|
||||
_blitFramebufferHandle = handle;
|
||||
}
|
||||
|
||||
return handle;
|
||||
_width = width;
|
||||
_height = height;
|
||||
}
|
||||
|
||||
private int GetCopyFramebufferHandleLazy()
|
||||
{
|
||||
int handle = _copyFramebufferHandle;
|
||||
|
||||
void GenerateAndBindTexture()
|
||||
{
|
||||
int textureHandle = GenerateWindowTexture();
|
||||
|
||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, handle);
|
||||
|
||||
GL.FramebufferTexture(
|
||||
FramebufferTarget.Framebuffer,
|
||||
FramebufferAttachment.ColorAttachment0,
|
||||
textureHandle,
|
||||
0);
|
||||
|
||||
_screenTextureHandle = textureHandle;
|
||||
}
|
||||
|
||||
if (handle == 0)
|
||||
{
|
||||
handle = GL.GenFramebuffer();
|
||||
|
||||
_copyFramebufferHandle = handle;
|
||||
|
||||
GenerateAndBindTexture();
|
||||
}
|
||||
else if (_sizeChanged)
|
||||
{
|
||||
GL.DeleteTexture(_screenTextureHandle);
|
||||
|
||||
lock (_resizeLocker)
|
||||
{
|
||||
_width = _resizeWidth;
|
||||
_height = _resizeHeight;
|
||||
|
||||
_sizeChanged = false;
|
||||
}
|
||||
|
||||
GenerateAndBindTexture();
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
private int GenerateWindowTexture()
|
||||
{
|
||||
int handle = GL.GenTexture();
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, handle);
|
||||
|
||||
GL.TexImage2D(
|
||||
TextureTarget.Texture2D,
|
||||
0,
|
||||
PixelInternalFormat.Rgba8,
|
||||
_width,
|
||||
_height,
|
||||
0,
|
||||
PixelFormat.Rgba,
|
||||
PixelType.UnsignedByte,
|
||||
IntPtr.Zero);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Gpu;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -295,11 +295,6 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||
|
||||
_bufferQueue[slot].State = BufferState.Acquired;
|
||||
|
||||
Rect crop = _bufferQueue[slot].Crop;
|
||||
|
||||
bool flipX = _bufferQueue[slot].Transform.HasFlag(HalTransform.FlipX);
|
||||
bool flipY = _bufferQueue[slot].Transform.HasFlag(HalTransform.FlipY);
|
||||
|
||||
Format format = ConvertColorFormat(_bufferQueue[slot].Data.Buffer.Surfaces[0].ColorFormat);
|
||||
|
||||
int bytesPerPixel =
|
||||
|
@ -310,7 +305,20 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||
|
||||
// Note: Rotation is being ignored.
|
||||
|
||||
ITexture texture = context.Device.Gpu.GetTexture(
|
||||
Rect cropRect = _bufferQueue[slot].Crop;
|
||||
|
||||
bool flipX = _bufferQueue[slot].Transform.HasFlag(HalTransform.FlipX);
|
||||
bool flipY = _bufferQueue[slot].Transform.HasFlag(HalTransform.FlipY);
|
||||
|
||||
ImageCrop crop = new ImageCrop(
|
||||
cropRect.Left,
|
||||
cropRect.Right,
|
||||
cropRect.Top,
|
||||
cropRect.Bottom,
|
||||
flipX,
|
||||
flipY);
|
||||
|
||||
context.Device.Gpu.Window.EnqueueFrameThreadSafe(
|
||||
fbAddr,
|
||||
fbWidth,
|
||||
fbHeight,
|
||||
|
@ -318,24 +326,15 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||
false,
|
||||
gobBlocksInY,
|
||||
format,
|
||||
bytesPerPixel);
|
||||
|
||||
_renderer.Window.RegisterTextureReleaseCallback(ReleaseBuffer);
|
||||
|
||||
ImageCrop imageCrop = new ImageCrop(
|
||||
crop.Left,
|
||||
crop.Right,
|
||||
crop.Top,
|
||||
crop.Bottom,
|
||||
flipX,
|
||||
flipY);
|
||||
|
||||
_renderer.Window.QueueTexture(texture, imageCrop, slot);
|
||||
bytesPerPixel,
|
||||
crop,
|
||||
ReleaseBuffer,
|
||||
slot);
|
||||
}
|
||||
|
||||
private void ReleaseBuffer(object context)
|
||||
private void ReleaseBuffer(object slot)
|
||||
{
|
||||
ReleaseBuffer((int)context);
|
||||
ReleaseBuffer((int)slot);
|
||||
}
|
||||
|
||||
private void ReleaseBuffer(int slot)
|
||||
|
|
|
@ -122,6 +122,11 @@ namespace Ryujinx.HLE
|
|||
Gpu.DmaPusher.DispatchCalls();
|
||||
}
|
||||
|
||||
public void PresentFrame(Action swapBuffersCallback)
|
||||
{
|
||||
Gpu.Window.Present(swapBuffersCallback);
|
||||
}
|
||||
|
||||
internal void Unload()
|
||||
{
|
||||
FileSystem.Dispose();
|
||||
|
|
|
@ -294,7 +294,7 @@ namespace Ryujinx.Ui
|
|||
|
||||
private new void RenderFrame()
|
||||
{
|
||||
_renderer.Window.Present();
|
||||
_device.PresentFrame(SwapBuffers);
|
||||
|
||||
_device.Statistics.RecordSystemFrameTime();
|
||||
|
||||
|
@ -312,8 +312,6 @@ namespace Ryujinx.Ui
|
|||
|
||||
_titleEvent = true;
|
||||
|
||||
SwapBuffers();
|
||||
|
||||
_device.System.SignalVsync();
|
||||
|
||||
_device.VsyncEvent.Set();
|
||||
|
|
Loading…
Reference in a new issue