From 4d02a2d2c0451b4de1f6de3bbce54c457cacebe2 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Sun, 12 Jul 2020 00:07:01 -0300 Subject: New NVDEC and VIC implementation (#1384) * Initial NVDEC and VIC implementation * Update FFmpeg.AutoGen to 4.3.0 * Add nvdec dependencies for Windows * Unify some VP9 structures * Rename VP9 structure fields * Improvements to Video API * XML docs for Common.Memory * Remove now unused or redundant overloads from MemoryAccessor * NVDEC UV surface read/write scalar paths * Add FIXME comments about hacky things/stuff that will need to be fixed in the future * Cleaned up VP9 memory allocation * Remove some debug logs * Rename some VP9 structs * Remove unused struct * No need to compile Ryujinx.Graphics.Host1x with unsafe anymore * Name AsyncWorkQueue threads to make debugging easier * Make Vp9PictureInfo a ref struct * LayoutConverter no longer needs the depth argument (broken by rebase) * Pooling of VP9 buffers, plus fix a memory leak on VP9 * Really wish VS could rename projects properly... * Address feedback * Remove using * Catch OperationCanceledException * Add licensing informations * Add THIRDPARTY.md to release too Co-authored-by: Thog --- Ryujinx.Graphics.Nvdec/Image/SurfaceReader.cs | 133 ++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 Ryujinx.Graphics.Nvdec/Image/SurfaceReader.cs (limited to 'Ryujinx.Graphics.Nvdec/Image/SurfaceReader.cs') diff --git a/Ryujinx.Graphics.Nvdec/Image/SurfaceReader.cs b/Ryujinx.Graphics.Nvdec/Image/SurfaceReader.cs new file mode 100644 index 00000000..a8199932 --- /dev/null +++ b/Ryujinx.Graphics.Nvdec/Image/SurfaceReader.cs @@ -0,0 +1,133 @@ +using Ryujinx.Common; +using Ryujinx.Graphics.Gpu.Memory; +using Ryujinx.Graphics.Texture; +using Ryujinx.Graphics.Video; +using System; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; +using static Ryujinx.Graphics.Nvdec.Image.SurfaceCommon; + +namespace Ryujinx.Graphics.Nvdec.Image +{ + static class SurfaceReader + { + public static void Read(MemoryManager gmm, ISurface surface, uint lumaOffset, uint chromaOffset) + { + int width = surface.Width; + int height = surface.Height; + int stride = surface.Stride; + + ReadOnlySpan luma = gmm.DeviceGetSpan(lumaOffset, GetBlockLinearSize(width, height, 1)); + + ReadLuma(surface.YPlane.AsSpan(), luma, stride, width, height); + + int uvWidth = surface.UvWidth; + int uvHeight = surface.UvHeight; + int uvStride = surface.UvStride; + + ReadOnlySpan chroma = gmm.DeviceGetSpan(chromaOffset, GetBlockLinearSize(uvWidth, uvHeight, 2)); + + ReadChroma(surface.UPlane.AsSpan(), surface.VPlane.AsSpan(), chroma, uvStride, uvWidth, uvHeight); + } + + private static void ReadLuma(Span dst, ReadOnlySpan src, int dstStride, int width, int height) + { + LayoutConverter.ConvertBlockLinearToLinear(dst, width, height, dstStride, 1, 2, src); + } + + private unsafe static void ReadChroma( + Span dstU, + Span dstV, + ReadOnlySpan src, + int dstStride, + int width, + int height) + { + OffsetCalculator calc = new OffsetCalculator(width, height, 0, false, 2, 2); + + if (Sse2.IsSupported) + { + int strideTrunc64 = BitUtils.AlignDown(width * 2, 64); + + int outStrideGap = dstStride - width; + + fixed (byte* dstUPtr = dstU, dstVPtr = dstV, dataPtr = src) + { + byte* uPtr = dstUPtr; + byte* vPtr = dstVPtr; + + for (int y = 0; y < height; y++) + { + calc.SetY(y); + + for (int x = 0; x < strideTrunc64; x += 64, uPtr += 32, vPtr += 32) + { + byte* offset = dataPtr + calc.GetOffsetWithLineOffset64(x); + byte* offset2 = offset + 0x20; + byte* offset3 = offset + 0x100; + byte* offset4 = offset + 0x120; + + Vector128 value = *(Vector128*)offset; + Vector128 value2 = *(Vector128*)offset2; + Vector128 value3 = *(Vector128*)offset3; + Vector128 value4 = *(Vector128*)offset4; + + Vector128 u00 = Sse2.UnpackLow(value, value2); + Vector128 v00 = Sse2.UnpackHigh(value, value2); + Vector128 u01 = Sse2.UnpackLow(value3, value4); + Vector128 v01 = Sse2.UnpackHigh(value3, value4); + + Vector128 u10 = Sse2.UnpackLow(u00, v00); + Vector128 v10 = Sse2.UnpackHigh(u00, v00); + Vector128 u11 = Sse2.UnpackLow(u01, v01); + Vector128 v11 = Sse2.UnpackHigh(u01, v01); + + Vector128 u20 = Sse2.UnpackLow(u10, v10); + Vector128 v20 = Sse2.UnpackHigh(u10, v10); + Vector128 u21 = Sse2.UnpackLow(u11, v11); + Vector128 v21 = Sse2.UnpackHigh(u11, v11); + + Vector128 u30 = Sse2.UnpackLow(u20, v20); + Vector128 v30 = Sse2.UnpackHigh(u20, v20); + Vector128 u31 = Sse2.UnpackLow(u21, v21); + Vector128 v31 = Sse2.UnpackHigh(u21, v21); + + *(Vector128*)uPtr = u30; + *(Vector128*)(uPtr + 16) = u31; + *(Vector128*)vPtr = v30; + *(Vector128*)(vPtr + 16) = v31; + } + + for (int x = strideTrunc64 / 2; x < width; x++, uPtr++, vPtr++) + { + byte* offset = dataPtr + calc.GetOffset(x); + + *uPtr = *offset; + *vPtr = *(offset + 1); + } + + uPtr += outStrideGap; + vPtr += outStrideGap; + } + } + } + else + { + for (int y = 0; y < height; y++) + { + int dstBaseOffset = y * dstStride; + + calc.SetY(y); + + for (int x = 0; x < width; x++) + { + int srcOffset = calc.GetOffset(x); + + dstU[dstBaseOffset + x] = src[srcOffset]; + dstV[dstBaseOffset + x] = src[srcOffset + 1]; + } + } + } + } + } +} -- cgit v1.2.3