using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.Gpu.Image; using System; using System.Collections.Concurrent; namespace Ryujinx.Graphics.Gpu { using Texture = Image.Texture; /// /// GPU image presentation window. /// public class Window { private readonly GpuContext _context; /// /// Texture presented on the window. /// private struct PresentationTexture { /// /// Texture information. /// public TextureInfo Info { get; } /// /// Texture crop region. /// public ImageCrop Crop { get; } /// /// Texture acquire callback. /// public Action AcquireCallback { get; } /// /// Texture release callback. /// public Action ReleaseCallback { get; } /// /// User defined object, passed to the various callbacks. /// public object UserObj { get; } /// /// Creates a new instance of the presentation texture. /// /// Information of the texture to be presented /// Texture crop region /// Texture acquire callback /// Texture release callback /// User defined object passed to the release callback, can be used to identify the texture public PresentationTexture( TextureInfo info, ImageCrop crop, Action acquireCallback, Action releaseCallback, object userObj) { Info = info; Crop = crop; AcquireCallback = acquireCallback; ReleaseCallback = releaseCallback; UserObj = userObj; } } private readonly ConcurrentQueue _frameQueue; /// /// Creates a new instance of the GPU presentation window. /// /// GPU emulation context public Window(GpuContext context) { _context = context; _frameQueue = new ConcurrentQueue(); } /// /// Enqueues a frame for presentation. /// This method is thread safe and can be called from any thread. /// When the texture is presented and not needed anymore, the release callback is called. /// It's an error to modify the texture after calling this method, before the release callback is called. /// /// CPU virtual address of the texture data /// Texture width /// Texture height /// Texture stride for linear texture, should be zero otherwise /// Indicates if the texture is linear, normally false /// GOB blocks in the Y direction, for block linear textures /// Texture format /// Texture format bytes per pixel (must match the format) /// Texture crop region /// Texture acquire callback /// Texture release callback /// User defined object passed to the release callback public void EnqueueFrameThreadSafe( ulong address, int width, int height, int stride, bool isLinear, int gobBlocksInY, Format format, int bytesPerPixel, ImageCrop crop, Action acquireCallback, Action releaseCallback, 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, acquireCallback, releaseCallback, userObj)); } /// /// Presents a texture on the queue. /// If the queue is empty, then no texture is presented. /// /// Callback method to call when a new texture should be presented on the screen public void Present(Action swapBuffersCallback) { _context.AdvanceSequence(); if (_frameQueue.TryDequeue(out PresentationTexture pt)) { pt.AcquireCallback(_context, pt.UserObj); Texture texture = _context.Methods.TextureManager.FindOrCreateTexture(pt.Info, TextureSearchFlags.WithUpscale); texture.SynchronizeMemory(); _context.Renderer.Window.Present(texture.HostTexture, pt.Crop); swapBuffersCallback(); pt.ReleaseCallback(pt.UserObj); } } } }