diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2021-09-28 19:43:40 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-09-29 00:43:40 +0200 |
| commit | f4f496cb48a59aae36e3252baa90396e1bfadd2e (patch) | |
| tree | 5594d76b3f1b552f1fecdeda37bd2f6667781a56 /Ryujinx.Graphics.Nvdec/Image/SurfaceCache.cs | |
| parent | 0d23504e30395ba20d1704da464b41f3fe539062 (diff) | |
NVDEC (H264): Use separate contexts per channel and decode frames in DTS order (#2671)
* Use separate NVDEC contexts per channel (for FFMPEG)
* Remove NVDEC -> VIC frame override hack
* Add missing bottom_field_pic_order_in_frame_present_flag
* Make FFMPEG logging static
* nit: Remove empty lines
* New FFMPEG decoding approach -- call h264_decode_frame directly, trim surface cache to reduce memory usage
* Fix case
* Silence warnings
* PR feedback
* Per-decoder rather than per-codec ownership of surfaces on the cache
Diffstat (limited to 'Ryujinx.Graphics.Nvdec/Image/SurfaceCache.cs')
| -rw-r--r-- | Ryujinx.Graphics.Nvdec/Image/SurfaceCache.cs | 169 |
1 files changed, 96 insertions, 73 deletions
diff --git a/Ryujinx.Graphics.Nvdec/Image/SurfaceCache.cs b/Ryujinx.Graphics.Nvdec/Image/SurfaceCache.cs index c362185f..dc119673 100644 --- a/Ryujinx.Graphics.Nvdec/Image/SurfaceCache.cs +++ b/Ryujinx.Graphics.Nvdec/Image/SurfaceCache.cs @@ -21,7 +21,7 @@ namespace Ryujinx.Graphics.Nvdec.Image public uint ChromaOffset; public int Width; public int Height; - public CodecId CodecId; + public IDecoder Owner; public ISurface Surface; } @@ -34,104 +34,110 @@ namespace Ryujinx.Graphics.Nvdec.Image _gmm = gmm; } - public ISurface Get(IDecoder decoder, CodecId codecId, uint lumaOffset, uint chromaOffset, int width, int height) + public ISurface Get(IDecoder decoder, uint lumaOffset, uint chromaOffset, int width, int height) { - ISurface surface = null; - - // Try to find a compatible surface with same parameters, and same offsets. - for (int i = 0; i < MaxItems; i++) + lock (_pool) { - ref CacheItem item = ref _pool[i]; + ISurface surface = null; - if (item.LumaOffset == lumaOffset && - item.ChromaOffset == chromaOffset && - item.CodecId == codecId && - item.Width == width && - item.Height == height) - { - item.ReferenceCount++; - surface = item.Surface; - MoveToFront(i); - break; - } - } - - // If we failed to find a perfect match, now ignore the offsets. - // Search backwards to replace the oldest compatible surface, - // this avoids thrashing frquently used surfaces. - // Now we need to ensure that the surface is not in use, as we'll change the data. - if (surface == null) - { - for (int i = MaxItems - 1; i >= 0; i--) + // Try to find a compatible surface with same parameters, and same offsets. + for (int i = 0; i < MaxItems; i++) { ref CacheItem item = ref _pool[i]; - if (item.ReferenceCount == 0 && item.CodecId == codecId && item.Width == width && item.Height == height) + if (item.LumaOffset == lumaOffset && + item.ChromaOffset == chromaOffset && + item.Owner == decoder && + item.Width == width && + item.Height == height) { - item.ReferenceCount = 1; - item.LumaOffset = lumaOffset; - item.ChromaOffset = chromaOffset; + item.ReferenceCount++; surface = item.Surface; - - if ((lumaOffset | chromaOffset) != 0) - { - SurfaceReader.Read(_gmm, surface, lumaOffset, chromaOffset); - } - MoveToFront(i); break; } } - } - // If everything else failed, we try to create a new surface, - // and insert it on the pool. We replace the oldest item on the - // pool to avoid thrashing frequently used surfaces. - // If even the oldest item is in use, that means that the entire pool - // is in use, in that case we throw as there's no place to insert - // the new surface. - if (surface == null) - { - if (_pool[MaxItems - 1].ReferenceCount == 0) + // If we failed to find a perfect match, now ignore the offsets. + // Search backwards to replace the oldest compatible surface, + // this avoids thrashing frequently used surfaces. + // Now we need to ensure that the surface is not in use, as we'll change the data. + if (surface == null) { - surface = decoder.CreateSurface(width, height); - - if ((lumaOffset | chromaOffset) != 0) + for (int i = MaxItems - 1; i >= 0; i--) { - SurfaceReader.Read(_gmm, surface, lumaOffset, chromaOffset); - } + ref CacheItem item = ref _pool[i]; - MoveToFront(MaxItems - 1); - ref CacheItem item = ref _pool[0]; - item.Surface?.Dispose(); - item.ReferenceCount = 1; - item.LumaOffset = lumaOffset; - item.ChromaOffset = chromaOffset; - item.Width = width; - item.Height = height; - item.CodecId = codecId; - item.Surface = surface; + if (item.ReferenceCount == 0 && item.Owner == decoder && item.Width == width && item.Height == height) + { + item.ReferenceCount = 1; + item.LumaOffset = lumaOffset; + item.ChromaOffset = chromaOffset; + surface = item.Surface; + + if ((lumaOffset | chromaOffset) != 0) + { + SurfaceReader.Read(_gmm, surface, lumaOffset, chromaOffset); + } + + MoveToFront(i); + break; + } + } } - else + + // If everything else failed, we try to create a new surface, + // and insert it on the pool. We replace the oldest item on the + // pool to avoid thrashing frequently used surfaces. + // If even the oldest item is in use, that means that the entire pool + // is in use, in that case we throw as there's no place to insert + // the new surface. + if (surface == null) { - throw new InvalidOperationException("No free slot on the surface pool."); + if (_pool[MaxItems - 1].ReferenceCount == 0) + { + surface = decoder.CreateSurface(width, height); + + if ((lumaOffset | chromaOffset) != 0) + { + SurfaceReader.Read(_gmm, surface, lumaOffset, chromaOffset); + } + + MoveToFront(MaxItems - 1); + ref CacheItem item = ref _pool[0]; + item.Surface?.Dispose(); + item.ReferenceCount = 1; + item.LumaOffset = lumaOffset; + item.ChromaOffset = chromaOffset; + item.Width = width; + item.Height = height; + item.Owner = decoder; + item.Surface = surface; + } + else + { + throw new InvalidOperationException("No free slot on the surface pool."); + } } - } - return surface; + return surface; + } } public void Put(ISurface surface) { - for (int i = 0; i < MaxItems; i++) + lock (_pool) { - ref CacheItem item = ref _pool[i]; - - if (item.Surface == surface) + for (int i = 0; i < MaxItems; i++) { - item.ReferenceCount--; - Debug.Assert(item.ReferenceCount >= 0); - break; + ref CacheItem item = ref _pool[i]; + + if (item.Surface == surface) + { + item.ReferenceCount--; + Debug.Assert(item.ReferenceCount >= 0); + break; + } } } } @@ -147,5 +153,22 @@ namespace Ryujinx.Graphics.Nvdec.Image _pool[0] = temp; } } + + public void Trim() + { + lock (_pool) + { + for (int i = 0; i < MaxItems; i++) + { + ref CacheItem item = ref _pool[i]; + + if (item.ReferenceCount == 0) + { + item.Surface?.Dispose(); + item = default; + } + } + } + } } } |
