C# OpenGL Hook Swapbuffer添加插值帧

dohp0rv5  于 5个月前  发布在  C#
关注(0)|答案(1)|浏览(55)

我试图运行一个游戏在60 fps而不是30。游戏是锁定到30 fps,所以唯一的方法,我可以达到60 fps是与帧插值。
对于插值部分,我将使用OpenCV,我发现this pretty good article
这款游戏使用OpenGL。经过一番研究,我发现抓取屏幕的最佳方法是挂钩SwapBuffer函数。所以我选择挂钩游戏抓取屏幕并将其发送到其他应用程序,该应用程序将以真实的时间传输游戏,顺便添加插值帧以达到60 FPS(如果您有更好的想法,我完全开放!)
我开始写我的新DLL。我用C#编码,我选择了EasyHook来注入我的DLL。
Hooking工作得很好,现在很酷=D。
然而,我现在卡住了,因为我完全不知道如何从游戏中抓取屏幕。
我尝试使用OpenGL.NetSharpGL,但我不知道如何获取实际的OpenGL上下文来使用glReadPixel!
下面是我的实际代码:

using System;
using System.Runtime.InteropServices;

namespace Hook
{
    public class ServerInterface : MarshalByRefObject
    {
        public void IsInstalled(int clientPID)
        {
            Console.WriteLine("This programm has injected dll into process {0}.\r\n", clientPID);
        }

        public void ReportMessage(int clientPID, string message)
        {
            Console.WriteLine(message);
        }

        public void ReportException(Exception e)
        {
            Console.WriteLine("The target process has reported an error:\r\n" + e.ToString());
        }

        public void Ping()
        {
            Console.WriteLine("Ping !");
        }
    }

    //Point d'entrée
    public class InjectionEntryPoint : EasyHook.IEntryPoint
    {
        //Serveur :
        ServerInterface server = null;

        public InjectionEntryPoint(EasyHook.RemoteHooking.IContext context, string channelName)
        {
            //Constructeur
            //Objectif : vérifier si la communication entre les deux programmes peut etre établit
            server = EasyHook.RemoteHooking.IpcConnectClient<ServerInterface>(channelName);
            server.Ping();

        }

        public void Run(EasyHook.RemoteHooking.IContext context, string channelName)
        {

            try
            {
                var SwapBuffersHook = EasyHook.LocalHook.Create(EasyHook.LocalHook.GetProcAddress("opengl32.dll", "wglSwapBuffers"), new SwapBuffers_Delegate(SwapBuffers_Hook), this);
                SwapBuffersHook.ThreadACL.SetExclusiveACL(new Int32[] { 0 });
                server.ReportMessage(EasyHook.RemoteHooking.GetCurrentProcessId(), "SwapBuffers Hooked");
            }
            catch (Exception ExtInfo)
            {
                server.ReportException(ExtInfo);
                return;
            }

            server.IsInstalled(EasyHook.RemoteHooking.GetCurrentProcessId());

            EasyHook.RemoteHooking.WakeUpProcess();

            //Waiting years
            while( true)
            {
                System.Threading.Thread.Sleep(10000);
            }

            // Finalise cleanup of hooks
            EasyHook.LocalHook.Release();

        }

        //Deleguate
        [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
        delegate IntPtr SwapBuffers_Delegate(IntPtr hdc);

        //Original
        [DllImport("opengl32.dll", CharSet = CharSet.Unicode, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
        static extern IntPtr wglSwapBuffers(IntPtr hdc);

        //Hook function
        public IntPtr SwapBuffers_Hook(IntPtr hdc)
        {

            server.ReportMessage(EasyHook.RemoteHooking.GetCurrentProcessId(),  "I'm in SwapBuffers =DDDD");

            //Here I need to grab frames

            //Return
            return wglSwapBuffers(hdc);
        }
    }
}

字符串

np8igboo

np8igboo1#

我怀疑你能提高游戏的FPS。顺便说一下,有一些可能性。
你所做的是正确的方法,你只是错过了GL代码来创建要显示的中间框架(我建议使用当前GL上下文在进程中创建它)。
问题是当SwapBuffers命令被执行时,视频帧被显示出来。这是你挂起的命令,但是问问你自己和程序:为什么SwapBuffers每秒被调用30次?
如果答案是“因为应用程序使用计时器挂起执行”,那么您就不能简单地解决这个问题:您的钩子必须与应用程序一起工作,因此您需要了解应用程序是如何休眠的。
如果答案是“Because the application is taking advantage of WGL_EXT_swap_control”,那么你有一种可能性:

  • 设置wglSwapIntervalEXT(1)(因为应用程序已经调用了wglSwapIntervalEXT(2)来获得与V-Sync同步的30 FPS。可能只需要一次
  • 在你的钩子中,抓取两个帧,然后在每隔一个帧插入它们(这就是你的问题)。在每次钩子执行时,你需要渲染插入的帧,然后交换;然后渲染下一个原始帧,然后交换。

如何创建插值帧?如果你是通过CPU做的,使用glReadPixels和后台缓冲区(GL_BACK)作为读帧缓冲区(使用glDrawBuffers)。这将下载帧缓冲区绑定的内容。然后使用混合方程获得插值像素。

相关问题