From 2401c37a7fb93c2bb1483582e707801d77c37d84 Mon Sep 17 00:00:00 2001 From: adelikat Date: Wed, 1 Apr 2020 18:58:08 -0500 Subject: [PATCH] delete ScreenArranger and move the relevant logic to MelonDS, and simplify, also use a pre-allocated buffer instead of making a new one every time --- BizHawk.Emulation.Common/ScreenArranger.cs | 126 ------------------ .../Nintendo/NDS/MelonDS_VideoProvider.cs | 33 +++-- 2 files changed, 23 insertions(+), 136 deletions(-) delete mode 100644 BizHawk.Emulation.Common/ScreenArranger.cs diff --git a/BizHawk.Emulation.Common/ScreenArranger.cs b/BizHawk.Emulation.Common/ScreenArranger.cs deleted file mode 100644 index 623a7905a3..0000000000 --- a/BizHawk.Emulation.Common/ScreenArranger.cs +++ /dev/null @@ -1,126 +0,0 @@ -using System; -using System.Diagnostics; - -namespace BizHawk.Emulation.Common -{ - public unsafe class VideoScreen - { - public VideoScreen(int* buffer, int width, int height) - { - Buffer = buffer; - Width = width; - Height = height; - } - - public int* Buffer { get; } - public int Width { get; } - public int Height { get; } - - public int Length => Width * Height; - } - - /// Provides a way to arrange displays inside a frame buffer. - public static class ScreenArranger - { - /// this is taken as an assumption to allow for simpler algorithms; in the future this may need to be rethought (e.g. for 3DS) - [Conditional("DEBUG")] - private static void DebugAssertScreenDimensionsMatch(int lengthA, int lengthB) - { - if (lengthA != lengthB) throw new ArgumentException(); - } - - [Conditional("DEBUG")] - private static void DebugAssertPreallocatedBufferSize(int expected, int preallocLength) - { - if (preallocLength != expected) throw new Exception(); - } - - public static unsafe int[] UprightStack(VideoScreen forTop, VideoScreen forBottom, int gapLineCount = 0) - { - DebugAssertScreenDimensionsMatch(forTop.Width, forBottom.Width); - var outputWidth = forTop.Width; - - var gapStartOffset = forTop.Length; - var screen2StartOffset = gapStartOffset + gapLineCount * outputWidth; - var bufferLength = screen2StartOffset + forBottom.Height * outputWidth; - var prealloc = new int[bufferLength]; //TODO actually take a `ref int[] prealloc` (or an int* maybe?) - DebugAssertPreallocatedBufferSize(bufferLength, prealloc.Length); - - for (var i = 0; i < gapStartOffset; i++) prealloc[i] = forTop.Buffer[i]; // copy top screen - // don't bother writing into the gap - for (int i = 0, l = forBottom.Length; i < l; i++) prealloc[screen2StartOffset + i] = forBottom.Buffer[i]; // copy bottom screen - return prealloc; - } - - /// Simply populates a buffer with a single screen - public static unsafe int[] Copy(VideoScreen screen) - { - var bufferLength = screen.Length; - var prealloc = new int[bufferLength]; //TODO actually take a `ref int[] prealloc` (or an int* maybe?) - DebugAssertPreallocatedBufferSize(bufferLength, prealloc.Length); - - for (var i = 0; i < bufferLength; i++) prealloc[i] = screen.Buffer[i]; - return prealloc; - } - - public static unsafe int[] UprightSideBySide(VideoScreen forLeft, VideoScreen forRight, int gapLineCount = 0) - { - DebugAssertScreenDimensionsMatch(forLeft.Height, forRight.Height); - var outputHeight = forLeft.Height; - - var rightOffsetHztl = forLeft.Width + gapLineCount; - var outputWidth = rightOffsetHztl + forRight.Width; - var bufferLength = outputHeight * outputWidth; // which = `forLeft.Length + outputHeight * gapLineCount + forRight.Length` - var prealloc = new int[bufferLength]; //TODO actually take a `ref int[] prealloc` (or an int* maybe?) - DebugAssertPreallocatedBufferSize(bufferLength, prealloc.Length); - - for (var y = 0; y < outputHeight; y++) - { - for (int x = 0, w = forLeft.Width; x < w; x++) prealloc[y * outputWidth + x] = forLeft.Buffer[y * w + x]; // copy this row of the left screen - // don't bother writing into the gap - for (int x = 0, w = forRight.Width; x < w; x++) prealloc[y * outputWidth + rightOffsetHztl + x] = forRight.Buffer[y * w + x]; // copy this row of the right screen - } - return prealloc; - } - - public static unsafe int[] Rotate90Stack(VideoScreen forLeft, VideoScreen forRight, int gapLineCount = 0) - { - DebugAssertScreenDimensionsMatch(forLeft.Width, forRight.Width); - var outputHeight = forLeft.Width; - - var rightOffsetHztl = forLeft.Height + gapLineCount; - var outputWidth = rightOffsetHztl + forRight.Height; - var bufferLength = outputHeight * outputWidth; // which = `forLeft.Length + outputHeight * gapLineCount + forRight.Length` - var prealloc = new int[bufferLength]; //TODO actually take a `ref int[] prealloc` (or an int* maybe?) - DebugAssertPreallocatedBufferSize(bufferLength, prealloc.Length); - - for (var y = 0; y < outputHeight; y++) - { - for (int x = 0, w = forLeft.Height; x < w; x++) prealloc[y * outputWidth + x] = forLeft.Buffer[(x + 1) * outputHeight - y]; // copy and rotate this column of the top screen to the left of the output - // don't bother writing into the gap - for (int x = 0, w = forRight.Height; x < w; x++) prealloc[y * outputWidth + rightOffsetHztl + x] = forRight.Buffer[(x + 1) * outputHeight - y]; // copy and rotate this column of the bottom screen to the right of the output - } - return prealloc; - } - - public static unsafe int[] Rotate270Stack(VideoScreen forLeft, VideoScreen forRight, int gapLineCount = 0) - { - DebugAssertScreenDimensionsMatch(forLeft.Width, forRight.Width); - var outputHeight = forLeft.Width; - - var rightOffsetHztl = forLeft.Height + gapLineCount; - var outputWidth = rightOffsetHztl + forRight.Height; - var bufferLength = outputHeight * outputWidth; // which = `forLeft.Length + outputHeight * gapLineCount + forRight.Length` - var prealloc = new int[bufferLength]; //TODO actually take a `ref int[] prealloc` (or an int* maybe?) - DebugAssertPreallocatedBufferSize(bufferLength, prealloc.Length); - - for (var y = 0; y < outputHeight; y++) - { - for (int x = 0, w = forLeft.Height; x < w; x++) prealloc[y * outputWidth + x] = forLeft.Buffer[(w - x - 1) * outputHeight + y]; // copy and rotate this column of the bottom screen to the left of the output - // don't bother writing into the gap - for (int x = 0, w = forRight.Height; x < w; x++) prealloc[y * outputWidth + rightOffsetHztl + x] = forRight.Buffer[(w - x - 1) * outputHeight + y]; // copy and rotate this column of the top screen to the right of the output - } - return prealloc; - } - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS_VideoProvider.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS_VideoProvider.cs index 9ff0f14ddc..3897a9a1b4 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS_VideoProvider.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS_VideoProvider.cs @@ -1,5 +1,4 @@ -using System; -using System.Runtime.InteropServices; +using System.Runtime.InteropServices; using BizHawk.Emulation.Common; @@ -23,19 +22,33 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS private static extern int* GetTopScreenBuffer(); [DllImport(dllPath)] private static extern int* GetBottomScreenBuffer(); - [DllImport(dllPath)] - private static extern int GetScreenBufferSize(); // BizHawk needs to be able to modify the buffer when loading savestates. - private int[] _buffer; + private const int SingleScreenLength = 256 * 192; + private readonly int[] _buffer = new int[256 * 192 * 2]; private bool _getNewBuffer = true; + public int[] GetVideoBuffer() { - if (!_getNewBuffer) return _buffer; - _getNewBuffer = false; - return _buffer = ScreenArranger.UprightStack(TopScreen, BottomScreen, 0); + if (_getNewBuffer) + { + _getNewBuffer = false; + PopulateBuffer(); + } + + return _buffer; + } + + private void PopulateBuffer() + { + var top = GetTopScreenBuffer(); + var bottom = GetBottomScreenBuffer(); + + for (var i = 0; i < SingleScreenLength; i++) + { + _buffer[i] = top[i]; + _buffer[SingleScreenLength + i] = bottom[i]; + } } - private VideoScreen TopScreen => new VideoScreen(GetTopScreenBuffer(), 256, 192); - private VideoScreen BottomScreen => new VideoScreen(GetBottomScreenBuffer(), 256, 192); } }