using Ryujinx.Common.Memory; using Ryujinx.Graphics.Video; using System; using System.Runtime.InteropServices; namespace Ryujinx.Graphics.Nvdec.Vp9.Types { internal struct Surface : ISurface { public ArrayPtr YBuffer; public ArrayPtr UBuffer; public ArrayPtr VBuffer; public readonly unsafe Plane YPlane => new((IntPtr)YBuffer.ToPointer(), YBuffer.Length); public readonly unsafe Plane UPlane => new((IntPtr)UBuffer.ToPointer(), UBuffer.Length); public readonly unsafe Plane VPlane => new((IntPtr)VBuffer.ToPointer(), VBuffer.Length); public readonly FrameField Field => FrameField.Progressive; public int Width { get; } public int Height { get; } public int AlignedWidth { get; } public int AlignedHeight { get; } public int Stride { get; } public int UvWidth { get; } public int UvHeight { get; } public int UvAlignedWidth { get; } public int UvAlignedHeight { get; } public int UvStride { get; } public bool HighBd { get; } private readonly IntPtr _pointer; public Surface(int width, int height) { HighBd = false; const int Border = 32; const int SsX = 1; const int SsY = 1; int alignedWidth = (width + 7) & ~7; int alignedHeight = (height + 7) & ~7; int yStride = ((alignedWidth + 2 * Border) + 31) & ~31; int yplaneSize = (alignedHeight + 2 * Border) * yStride; int uvWidth = alignedWidth >> SsX; int uvHeight = alignedHeight >> SsY; int uvStride = yStride >> SsX; int uvBorderW = Border >> SsX; int uvBorderH = Border >> SsY; int uvplaneSize = (uvHeight + 2 * uvBorderH) * uvStride; int frameSize = (HighBd ? 2 : 1) * (yplaneSize + 2 * uvplaneSize); IntPtr pointer = Marshal.AllocHGlobal(frameSize); _pointer = pointer; Width = width; Height = height; AlignedWidth = alignedWidth; AlignedHeight = alignedHeight; Stride = yStride; UvWidth = (width + SsX) >> SsX; UvHeight = (height + SsY) >> SsY; UvAlignedWidth = uvWidth; UvAlignedHeight = uvHeight; UvStride = uvStride; ArrayPtr NewPlane(int start, int size, int planeBorder) { return new ArrayPtr(pointer + start + planeBorder, size - planeBorder); } YBuffer = NewPlane(0, yplaneSize, (Border * yStride) + Border); UBuffer = NewPlane(yplaneSize, uvplaneSize, (uvBorderH * uvStride) + uvBorderW); VBuffer = NewPlane(yplaneSize + uvplaneSize, uvplaneSize, (uvBorderH * uvStride) + uvBorderW); } public readonly void Dispose() { Marshal.FreeHGlobal(_pointer); } } }