2017-05-09 7 views
2

30の代わりに60Fpsでゲームを実行しようとしています。ゲームは30fpsにロックされているので、60fpsに達する唯一の方法はフレーム補間です。補間フレームを追加するOpenGLフックスワップバッファ

補間部分については、OpenCVを使用するつもりですが、this pretty good articleが見つかりました。

このゲームではOpenGLを使用しています。いくつかの調査の後、私は、画面をつかむための最良の方法はSwapBuffer関数をフックすることであることが分かった。だから私は、画面をつかむためにゲームをフックし、リアルタイムでゲームをストリーミングするように他のアプリに送ります。そして、60 FPSに達するように補間フレームを追加します(あなたが良いアイデアを持っているなら、 open!)

新しいdllを書き始めました。私はC#でコーディングしていますが、EasyHookを選択してDLLを挿入しました。

フックがうまくいきました。

しかし、私は今、ゲームからスクリーンを取得する方法が全くわからないために立ち往生しています。

私はOpenGL.NetSharpGLを使ってみましたが、glReadPixelを使うためにどのように実際のOpenGLコンテキストを取得すると思いますか?私はあなたがゲームのFPSを増やすことができます疑う

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); 
     } 
    } 
} 
+0

また、コンテキスト作成プロセスにフックして情報を保存することもできます。しかし、既にバッファスワッププロセスに関わっているので、バッファスワップを実行するスレッドに正しいOpenGLコンテキストがすでにバインドされていてはいけませんか? – BDL

答えて

0

は、ここに私の実際のコードです。ところで、いくつかの可能性があります。

あなたは何をしていますか正しい方法です。表示される中間フレームを作成するには、GLコードが欠けているだけです(現在のGLコンテキストを使用して、インプロセスで作成することをお勧めします)。

SwapBuffersコマンドを実行すると、ビデオフレームが表示されるという問題があります。これはあなたのフックですが、自分自身とプログラムに尋ねます:SwapBuffersが毎秒30回呼び出されるのはなぜですか?

答えが「アプリケーションがタイマーを使用して実行を中断するため」であれば、簡単に解決できません。アプリケーションと連携して動作する必要があるため、アプリケーションのスリープ状態を理解する必要があります。

あなたは一つの可能​​性持っているよりも、「アプリケーションがWGL_EXT_swap_controlの利点を取っているので、」answeの場合:アプリケーションは、(2)30を取得するためにwglSwapIntervalEXTを求めているので、

  • セットwglSwapIntervalEXT(1)( FPSはV-Syncと同期しました。おそらくこれは一度だけ必要です
  • フックでは、2つのフレームをつかんで1フレームおきに補間するので(あなたの質問)、フックを実行するたびに、スワップし、次に元のフレームをレンダリングしてからスワップします。

補間フレームの作成方法は? CPUを使用している場合は、glReadPixelsをバックバッファ(GL_BACK)とともに読み取りフレームバッファ(glDrawBuffersを使用)として使用します。これにより、バインドされたフレームバッファのコンテンツがダウンロードされます。次に、ブレンディング方程式を使用して補間ピクセルを取得します。

関連する問題