C# Opengl Hook Swapbuffer 添加插值帧

问题描述 投票:0回答:1

我尝试以 60 fps 而不是 30 帧运行游戏。游戏锁定为 30 fps,因此我能达到 60 fps 的唯一方法是使用帧插值。

对于插值部分,我将使用 OpenCV,我发现这篇非常好的文章

本游戏使用OpenGL。经过一番研究,我发现抓取屏幕的最好方法是hook 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);
        }
    }
}
c# opengl hook screenshot interpolation
1个回答
0
投票

我怀疑你能否提高游戏的FPS。顺便说一句,有一些可能性。

你正在做的事情是正确的。您只是错过了创建要显示的中间帧的 GL 代码(我建议使用当前的 GL 上下文在进程中创建它)。

问题在于执行

SwapBuffers
命令时会显示视频帧。这是您挂钩的,但问问自己和程序:为什么
SwapBuffers
每秒被调用 30 次?

如果答案是“因为应用程序使用计时器暂停执行”,那么您无法轻松解决它:您的钩子必须与应用程序一起工作,因此您需要了解应用程序如何休眠。

如果答案是“因为应用程序正在利用 WGL_EXT_swap_control”,那么您有一种可能性:

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

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

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.