none
DirectXのReset処理 RRS feed

  • 質問

  • はじめまして、こんにちは

    VS2013を利用してDirectX9を使ったActiveXとして2Dの画像を表示するプログラムを作成しています。

    プログラムそのものはVS2005のころから使われていた古いプログラムで

    今まで表示に使っていた画像サイズが1種類でしたが、今度2種類のサイズに対応することになりました。

    画像サイズを変更するにあたり、

    ・リソースの開放

    ・Reset関数を呼び出す

    ・リソースの再取得

    を行って、表示そのものは正常に出来ているようなのですが

    この処理を何度も繰り返していると、メモリがどんどん増えていくようです。

    明示的にCreateTexture、CreateVertexBuffer、CreateOffscreenPlainSurface

    で取得した領域は正しく開放できている気がするのですが(試しに未開放にしたらResetがエラーになりました)

    メモリやリソース開放に関して何か気をつけないといけないことはありますでしょうか。

    宜しくお願いします。

    • 移動 星 睦美 2016年3月2日 4:49 Visual Studio 共通 から
    2016年2月8日 4:40

すべての返信

  • 明示的にCreateTexture、CreateVertexBuffer、CreateOffscreenPlainSurfaceで取得した領域は正しく開放できている気がするのですが(試しに未開放にしたらResetがエラーになりました)メモリやリソース開放に関して何か気をつけないといけないことはありますでしょうか。

    具体的なことはコードを見ないことにはわかりません。

    ただし「気がする」レベルではダメでしょう。IDirect3DTexture9、IDirect3DVertexBuffer9、IDirect3DSurface9などは正しく管理する必要があります。これに関しては適切にReleaseを呼び出すように作られたライブラリがあるのでそれを使うべきです。VS2013であれば新たに追加されたMicrosoft::WRL::ComPtrがおすすめですが、それ以外にもCComPtr_com_ptr_tなどもあります。その他のメモリなどに関してもunique_ptrなどを使用して確実に解放されるコーディングをすることをお勧めします。

    またC++言語は急速に進化しているため最新のコンパイラーを使用することをお勧めします。具体的には現時点ではVisual Studio 2015 Update1です。

    2016年2月8日 4:55
  • 早速のご回答ありがとうございます。

    書き方が悪くて申し訳ありません。開放処理は確実に実行されます。

    「気がする」と書いたのは、こちらが意図していない所で参照カウンタとかがインクリメントされていたとすると

    開放処理を実行しても実際は開放されない場合とかがありそうさなので「気がする」としてしまいました。

    ご指摘事項は、ご最もだと思います。ご指摘ありがとうございます。

    2016年2月8日 5:32
  • 書き方が悪くて申し訳ありません。開放処理は確実に実行されます。

    確実に実行されているのであれば問題ありません、よかったですね。

    …と言ったところで、なんらかの解放漏れがあるからメモリがどんどん増えている、だからこそ質問されたのではありませんか? 先日もDirectXとOpenCVとの違いこそありますが、同じ変数に2度代入してしまったために最初に代入したオブジェクトが解放されていないという問題がありました(メモリ容量の使用量の削減メモリを削減したい)。こういった行為を開発者の努力でカバーするのではなく、ライブラリによって未然に防ぐことをお勧めします。

    で、結局のところ、質問者さんが自身のプログラムには問題はありませんと宣言してしまうと何も解決できなくなってしまうのですが…?

    2016年2月8日 5:51
  • そうですね。よく考えてから質問します。

    ありがとうございました。

    2016年2月8日 7:18
  • 2D画像表示になぜDirect3Dが必要となるのか不明ですが、パフォーマンス向上のためでしょうか?

    もしWindows XP対応が不要で、Vista以降をターゲットとすることができるのであれば、Direct2Dを使って書き直すことをお勧めします。Direct3Dは自力でCOMコンポーネントを使ったアプリケーションをデバッグできる能力がない開発者にとっては相当に厳しいAPIです。Direct2DもCOMの初心者には難しい部類に入りますが、Direct3Dよりはマシだと思います。MFCによるラッパーもあります。

    Windows SDKに統合される以前、旧バージョンのDirectX SDKでは、DirectXコントロールパネルにてDirect3D 9のデバッグランタイムを有効にすることでリソースリークのチェックなどを行なう診断機能を使うことができましたが、VS 2013付属のWindows SDK 8.1にはDirect3D 9デバッグ用の機能は付いていません(Direct3D 10/11であればデバッグ用フラグを付けて初期化することはできますが)。

    Direct3D デバッグ情報の有効化 (Direct3D 9)

    Direct3D SDK Debug Layer Tricks - Games for Windows and the DirectX SDK - Site Home - MSDN Blogs

    Direct3D 9は互換性の維持が必要とされる案件でもないかぎり、今後は使用しないほうがよいレガシーAPIです。VS 2012以降はすでに最低限の開発のみが許可されているといったレベルでしかありません。

    2016年2月8日 14:23
  • もしWindows XP対応が不要で、Vista以降をターゲットとすることができるのであれば、Direct2Dを使って書き直すことをお勧めします。

    脱線してしまって申し訳ありませんが興味本位で質問です。Direct2Dの初期化今昔の記事によりますとDirect2Dの初期化は大変で結局Direct3D11の初期化を必要とするとのことですが、それでもお勧めということなのでしょうか?

    追記

    2D画像表示になぜDirect3Dが必要となるのか不明ですが、パフォーマンス向上のためでしょうか?

    質問文に「プログラムそのものはVS2005のころから使われていた古いプログラムで」とあるので、作られた当時はWinXPなども動作対象に含まれていた等が理由ではないでしょうか?

    • 編集済み 佐祐理 2016年2月9日 0:48
    2016年2月8日 21:31
  • アドバイスありがとうございます。

    ご質問の通り、パフォーマンス向上のためです。

    小さめの画像をフルHDくらいに拡大する時に

    GDIで単純に拡大すると画像が荒くなってしまったので、SetStretchBltModeにHALFTONEを

    指定してみたところ、画像は綺麗になりましたが、処理に時間がかかりすぎてしまいました。

    OSに関しましては、ほとんどはWindows7以降にはなってきましたが、

    まだまだWindows XPも現役な状態です。

    あれから少し考えまして、簡単(?)なソースコードを作成してテストをしてみました。

    それでもやはりメモリが増えていくのですが

    そのソースコードを見ていただくことは可能でしょうか。

    2016年2月9日 0:39
  • 仕事であれば仕方ない場面もあると思いますが、早めにXPは手放したほうがよいかと。
    なお、Direct3D 9をどうしても使いたいのであれば、旧DirectX SDK June 2010をインストールして、DirectXコントロールパネルからDirect3D 9のデバッグランタイムを有効にしてからアプリケーションをデバッグ実行してみてください。リソースリークなどの原因特定の手がかりとなる情報がIDE出力ウィンドウに表示されるようになります。診断メッセージの出力レベルもDirectXコントロールパネルで変更できます。デバッグが済んだらリテールランタイムに戻すことを忘れないように。
    ちなみに最新のVC2010ランタイムがインストールされている環境に後から旧DirectX SDKをインストールしようとすると、S1023エラーが発生してインストールできないことがあります。その場合は自分でWeb検索して解決策を探してください。
    ソースコードの公開はお勤めの会社の守秘義務に抵触しない範囲であれば別にかまわないと思いますが、問題になっているのはリソースリークなので、断片だけ提示されても原因特定や解決には至らない可能性もあります。
    • 編集済み sygh 2016年2月9日 5:37
    2016年2月9日 3:17
  • 旧DirectX SDK June 2010はインストールしてみたのですが、windows7の開発環境では、有効になりませんでした。

    以下がソースコードになります。
    ソースそのものはnet上にサンプルとしてあげたあったものに対して
    若干手を加えた形になっています。

    このコードをそのままコンパイルして実行すると
    起動当初は、メモリが増えていきますが
    その後は2時間くらい見てもメモリは増えていかないので
    そこで安定していると考えています。

    プログラムは
    WM_TIMERのイベントでResetを実行するようになっており
    コメントアウトしてあるSetTimerを有効にすると
    動作を始めて24時間近くたった今も微量ながら増え続けています。

    もし、何かお気づきの点があればご指摘いただけるとうれしいです。
    宜しくお願いいたします。


    #pragma comment(lib, "user32.lib")
    #pragma comment(lib, "dxguid.lib")
    #pragma comment(lib, "d3d9.lib")

    #include <windows.h>
    #include <tchar.h>
    #include <d3d9.h>
    #include <math.h>


    struct CUSTOMVERTEX{  
        float x, y, z; // 頂点座標
        float rhw;     // 除算数
        DWORD dwColor; // 頂点の色
        float u, v;    // テクスチャ座標
    };

    #define FVF_CUSTOM ( D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1 )

    TCHAR gName[100] = _T("サンプルプログラム");

    float g_t = 0 ;
    CUSTOMVERTEX g_CurV[4];
    IDirect3DVertexBuffer9* g_pVertex;
    LPDIRECT3D9 g_pD3D;
    LPDIRECT3DDEVICE9 g_pD3DDev;
    D3DPRESENT_PARAMETERS d3dpp ;

    int    makeVertex() {
        // 頂点バッファの作成
        if(FAILED(g_pD3DDev->CreateVertexBuffer( sizeof(CUSTOMVERTEX)*4, D3DUSAGE_WRITEONLY, FVF_CUSTOM, D3DPOOL_MANAGED, &g_pVertex, NULL))){
            return -1;
        }
        return    0 ;
    }
    // 虹色関数
    DWORD RainbowRGB(DWORD num){
        #define RAINBOWVAL(C) ((DWORD)((C>=1024) ?0 : (C<256) ? C : (C>768) ? (1023-C) : 255))
        DWORD R = num%1536;
        DWORD G = ((num%1536)+1024)%1536;
        DWORD B = ((num%1536)+ 512)%1536;
        return 0xff000000 + (RAINBOWVAL(R)<<16) + (RAINBOWVAL(G)<<8) + RAINBOWVAL(B);
    }


    // 頂点回転関数
    void SetPos(float Cx, float Cy, float r, float ratio, float Ix, float Iy, float *Ox, float *Oy){
        *Ox = Cx + ratio*(Ix*cos(r) - Iy*sin(r));
        *Oy = Cy + ratio*(Ix*sin(r) + Iy*cos(r));
    }


    // ウィンドウプロシージャ
    LRESULT CALLBACK WndProc(HWND hWnd, UINT mes, WPARAM wParam, LPARAM lParam){
        if(mes == WM_DESTROY || mes == WM_CLOSE ) {PostQuitMessage(0); return 0;}
        if(mes == WM_TIMER ) {
            HRESULT hr ;
            g_t = 0 ;
            /*
            g_pVertex->Release();
            g_pVertex = NULL ;
            */
            hr = g_pD3DDev->Reset( &d3dpp ) ;
            if ( FAILED( hr ) ) {
                MessageBox( hWnd,"err","", MB_OK ) ;
                return hr;
            }
    //        makeVertex() ;
        }
        return DefWindowProc(hWnd, mes, wParam, lParam);
    }


    int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
    {
        // アプリケーションの初期化
        MSG msg; HWND hWnd;
        WNDCLASSEX wcex ={sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW, WndProc, 0, 0, hInstance, NULL, NULL,
                                    (HBRUSH)(COLOR_WINDOW+1), NULL, (TCHAR*)gName, NULL};
        if(!RegisterClassEx(&wcex))
            return 0;

        int    w=640,h=480 ;
        if(!(hWnd = CreateWindow(gName, gName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, w, h,
                                        NULL, NULL, hInstance, NULL)))
            return 0;

        // Direct3Dの初期化
        if( !(g_pD3D = Direct3DCreate9( D3D_SDK_VERSION )) ) return 0;

    /*
       D3DPRESENT_PARAMETERS d3dpp = {0,0,D3DFMT_UNKNOWN,0,D3DMULTISAMPLE_NONE,0,
                                                          D3DSWAPEFFECT_DISCARD,NULL,TRUE,0,D3DFMT_UNKNOWN,0,0};
    */
        D3DDISPLAYMODE d3ddm ;
        HRESULT hr ;
        hr = IDirect3D9_GetAdapterDisplayMode(g_pD3D, D3DADAPTER_DEFAULT, &d3ddm);

        ZeroMemory(&d3dpp, sizeof(d3dpp) ) ;
        d3dpp.Flags                        = D3DPRESENTFLAG_VIDEO ;
        d3dpp.Windowed                    = TRUE ;
        d3dpp.hDeviceWindow                = hWnd ;
        d3dpp.BackBufferWidth            = w ;
        d3dpp.BackBufferHeight            = h ;
        d3dpp.SwapEffect                = D3DSWAPEFFECT_COPY ;
        d3dpp.MultiSampleType            = D3DMULTISAMPLE_NONE ;
        d3dpp.PresentationInterval        = D3DPRESENT_INTERVAL_DEFAULT ;
        d3dpp.BackBufferFormat            = d3ddm.Format ;
        d3dpp.BackBufferCount            = 1 ;
        d3dpp.EnableAutoDepthStencil    = FALSE ;
        if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &g_pD3DDev ) ) )
        if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pD3DDev ) ) )
        if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &g_pD3DDev ) ) )
        if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pD3DDev ) ) )
        {
            g_pD3D->Release();
            return 0;
        }

        ShowWindow(hWnd, nCmdShow);

    //    SetTimer(hWnd, 1, 1000, NULL);

        // 頂点(初期位置)の設定
        float Ratio = 1.0f;
        float width = 240.0f * Ratio;
        float height = 180.0f * Ratio;
        CUSTOMVERTEX v[4]=
        {  
            { width/2, -height/2, 0.0f, 1.0f, 0x00000000, 0.0f, 0.0f},
            { width/2,  height/2, 0.0f, 1.0f, 0x000000ff, 0.0f, 1.0f},
            {-width/2, -height/2, 0.0f, 1.0f, 0x00000300, 1.0f, 0.0f},
            {-width/2,  height/2, 0.0f, 1.0f, 0x00000400, 1.0f, 1.0f}
        };

        makeVertex() ;

        float Cx, Cy ;
        DWORD Rainbow = 0;
        memcpy(g_CurV, v, sizeof(CUSTOMVERTEX)*4);

        // メッセージ ループ
        int i;
        do{
            Sleep(1);
            if( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ){ DispatchMessage(&msg);}
            // 頂点位置と色の計算(適当な計算です)
            // 頂点情報CurVを確定するのが目的
            g_t += 0.03146f/2;
            Ratio = 1.5f+cos(g_t);
            SetPos(320, 240, g_t*1.23, Ratio, 64, 64, &Cx, &Cy);
            for(i=0; i<4; i++){
                SetPos(Cx, Cy, g_t, Ratio, v[i].x, v[i].y, &g_CurV[i].x, &g_CurV[i].y);
                g_CurV[i].dwColor = RainbowRGB(v[i].dwColor+(Rainbow++)*(i+1));
            }

            // 頂点バッファに頂点を書き込みできた時にだけ描画
            void *pData;
            if(SUCCEEDED(g_pVertex->Lock(0, sizeof(CUSTOMVERTEX)*4, (void**)&pData, 0))){
                memcpy(pData, g_CurV, sizeof(CUSTOMVERTEX)*4);
                g_pVertex->Unlock();

                // Direct3Dの処理
                g_pD3DDev->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );
                g_pD3DDev->BeginScene();

                // 描画
                g_pD3DDev->SetStreamSource(0, g_pVertex, 0, sizeof(CUSTOMVERTEX));
                g_pD3DDev->SetFVF(FVF_CUSTOM);
                g_pD3DDev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);

                g_pD3DDev->EndScene();
                g_pD3DDev->Present( NULL, NULL, NULL, NULL );
            }
        }while(msg.message != WM_QUIT);

        g_pVertex->Release();
        g_pD3DDev->Release();
        g_pD3D->Release();

        return 0;
    }

        
    2016年2月9日 7:23
  • Windows 7でもDirectXデバッグランタイムを有効にすることはできます。何を根拠として「有効にできませんでした」と判断されたのでしょうか?

    DirectX SDKインストール後、スタートメニューの「Microsoft DirectX SDK (June 2010)」の配下に「DirectX Control Panel」という項目が追加されますが、そちらは試されましたか?

    Visual Studio 2013のインストール後に旧DX SDKをインストールした場合、デバッグランタイムがうまく有効化できないのかもしれません。リリースされた順序、すなわち旧DX SDKをインストールした後でVS 2013をインストールするとうまくいく可能性があります。

    なお、提示されたコードを、手元にあるWindows 8.1とVisual Studio 2013で動作確認してみましたが、今のところ特にリークらしい現象は確認できませんでした。

    もしかすると、Windows 7環境ではIDirect3DDevice9::SetStreamSource()で頂点バッファがデバイスにセットされたまま(参照カウントが増加したまま)になっていることが原因となっている可能性もあります。とりあえず下記のコードを代わりに試してみてください。

    ちなみにテストに使用しているハードウェア(グラフィックスカード? オンボード? CPU統合型GPU?)は何ですか? ドライバーにバグがある可能性も捨てきれないので、ドライバーは極力最新版に更新しておいたほうがよいです。

    それと、理解されているとは思いますが、デバイスロスト・デバイスリセットの際に解放+再作成する必要があるのは、D3DPOOL_DEFAULTで作成されたリソースのみです。D3DPOOL_MANAGEDを使って作成したリソースは、解放+再作成をする必要がありません。こういったつまらないリソース管理の裏事情に頭を悩ませないで済むよう、早めにXPを捨ててDirect2Dに移行することをお勧めします。

    //#pragma comment(lib, "dxguid.lib")
    #pragma comment(lib, "d3d9.lib")
    
    #ifdef _DEBUG
    #define D3D_DEBUG_INFO
    #endif
    
    #include <d3d9.h>
    #include <tchar.h>
    #include <crtdbg.h>
    #include <cmath>
    
    struct CUSTOMVERTEX
    {
      float x, y, z; // 頂点座標。
      float rhw; // 同次座標 W の逆数。
      DWORD dwColor; // 頂点の色。
      float u, v; // テクスチャ座標。
    
      static const DWORD FVF = (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1);
    };
    
    namespace
    {
      float g_t = 0;
      IDirect3D9* g_pD3D;
      IDirect3DDevice9* g_pD3DDev;
      IDirect3DVertexBuffer9* g_pVertex;
      D3DPRESENT_PARAMETERS g_d3dpp;
      UINT_PTR g_resetTimerId = 0;
      const UINT VertexBufferElemCount = 4;
    }
    
    template<typename T> void SafeRelease(T*& p)
    {
      if (p)
      {
        p->Release();
        p = nullptr;
      }
    }
    
    // 頂点バッファの作成。
    HRESULT MakeVertexBuffer()
    {
      _ASSERTE(g_pD3DDev != nullptr);
      _ASSERTE(g_pVertex == nullptr);
    #if 0
      const UINT bufElemCount = VertexBufferElemCount;
    #else
      const UINT bufElemCount = 512; // リソースリークの確認用。
    #endif
      // D3DPOOL_MANAGED であればデバイスロスト・デバイスリセット時の再作成は不要。
      // ただし Direct3D 9Ex では D3DPOOL_MANAGED を使用することはできない。
      return g_pD3DDev->CreateVertexBuffer(sizeof(CUSTOMVERTEX) * bufElemCount,
        D3DUSAGE_WRITEONLY, CUSTOMVERTEX::FVF, D3DPOOL_MANAGED, &g_pVertex, nullptr);
    }
    
    inline DWORD RAINBOWVAL(DWORD c) { return static_cast<DWORD>((c >= 1024) ? 0 : (c < 256) ? c : (c > 768) ? (1023 - c) : 255); }
    
    // 虹色関数。
    DWORD RainbowRGB(DWORD num)
    {
      DWORD R = num % 1536;
      DWORD G = ((num % 1536) + 1024) % 1536;
      DWORD B = ((num % 1536) + 512) % 1536;
      return 0xff000000 + (RAINBOWVAL(R) << 16) + (RAINBOWVAL(G) << 8) + RAINBOWVAL(B);
    }
    
    // 頂点回転関数。
    void SetPos(float Cx, float Cy, float r, float ratio, float Ix, float Iy, float *Ox, float *Oy)
    {
      *Ox = Cx + ratio * (Ix * cos(r) - Iy * sin(r));
      *Oy = Cy + ratio * (Ix * sin(r) + Iy * cos(r));
    }
    
    // ウィンドウプロシージャ。
    LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
      switch (msg)
      {
      case WM_DESTROY:
      case WM_CLOSE:
        ::PostQuitMessage(0);
        return 0;
      case WM_TIMER:
        if (wParam == g_resetTimerId)
        {
          HRESULT hr;
          g_t = 0;
          SafeRelease(g_pVertex);
          hr = g_pD3DDev->Reset(&g_d3dpp);
          if (FAILED(hr))
          {
            ::MessageBox(hWnd, _T("Failed to reset Direct3D device!!"), _T("Error"), MB_OK | MB_ICONERROR);
            return 0;
          }
          if (FAILED(MakeVertexBuffer()))
          {
            ::MessageBox(hWnd, _T("Failed to create vertex buffer!!"), _T("Error"), MB_OK | MB_ICONERROR);
            return 0;
          }
          return 0;
        }
        break;
      default:
        break;
      }
      return ::DefWindowProc(hWnd, msg, wParam, lParam);
    }
    
    int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
    {
      const TCHAR MyWindowClassName[] = _T("MySampleAppWndClass");
      const TCHAR MyWindowTitle[] = _T("サンプルプログラム");
    
      // アプリケーションの初期化。
      const WNDCLASSEX wcex =
      {
        sizeof(WNDCLASSEX),
        CS_HREDRAW | CS_VREDRAW,
        WndProc,
        0, 0,
        hInstance, nullptr, nullptr,
        reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1), nullptr, MyWindowClassName, nullptr };
      if (!::RegisterClassEx(&wcex))
      {
        return -1;
      }
    
      const int w = 640, h = 480;
      HWND hWnd = ::CreateWindow(wcex.lpszClassName, MyWindowTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, w, h,
        nullptr, nullptr, hInstance, nullptr);
      if (!hWnd)
      {
        goto e_Exit;
      }
    
      // Direct3D の初期化。
      g_pD3D = ::Direct3DCreate9(D3D_SDK_VERSION);
      if (!g_pD3D)
      {
        ::MessageBox(hWnd, _T("Failed to create Direct3D!!"), _T("Error"), MB_OK | MB_ICONERROR);
        goto e_Exit;
      }
    
      {
        D3DDISPLAYMODE d3ddm = {};
        HRESULT hr = IDirect3D9_GetAdapterDisplayMode(g_pD3D, D3DADAPTER_DEFAULT, &d3ddm);
    
        ZeroMemory(&g_d3dpp, sizeof(g_d3dpp));
        g_d3dpp.Flags = D3DPRESENTFLAG_VIDEO;
        g_d3dpp.Windowed = TRUE;
        g_d3dpp.hDeviceWindow = hWnd;
        g_d3dpp.BackBufferWidth = w;
        g_d3dpp.BackBufferHeight = h;
        g_d3dpp.SwapEffect = D3DSWAPEFFECT_COPY;
        g_d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
        g_d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
        g_d3dpp.BackBufferFormat = d3ddm.Format;
        g_d3dpp.BackBufferCount = 1;
        g_d3dpp.EnableAutoDepthStencil = FALSE;
      }
      if (
        FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &g_d3dpp, &g_pD3DDev)) &&
        FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &g_d3dpp, &g_pD3DDev)) &&
        FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &g_d3dpp, &g_pD3DDev)) &&
        FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &g_d3dpp, &g_pD3DDev))
        )
      {
        ::MessageBox(hWnd, _T("Failed to create Direct3D device!!"), _T("Error"), MB_OK | MB_ICONERROR);
        goto e_Exit;
      }
    
      if (FAILED(MakeVertexBuffer()))
      {
        ::MessageBox(hWnd, _T("Failed to create vertex buffer!!"), _T("Error"), MB_OK | MB_ICONERROR);
        goto e_Exit;
      }
    
      ::ShowWindow(hWnd, nCmdShow);
    
      {
        const UINT_PTR DesiredTimerID = 1;
        g_resetTimerId = ::SetTimer(hWnd, DesiredTimerID, 1000, nullptr);
      }
    
      {
        // 頂点(初期位置)の設定。
        float Ratio = 1.0f;
        const float width = 240.0f * Ratio;
        const float height = 180.0f * Ratio;
        const CUSTOMVERTEX v[VertexBufferElemCount] =
        {
          { +width / 2, -height / 2, 0.0f, 1.0f, 0x00000000, 0.0f, 0.0f },
          { +width / 2, +height / 2, 0.0f, 1.0f, 0x000000ff, 0.0f, 1.0f },
          { -width / 2, -height / 2, 0.0f, 1.0f, 0x00000300, 1.0f, 0.0f },
          { -width / 2, +height / 2, 0.0f, 1.0f, 0x00000400, 1.0f, 1.0f },
        };
    
        CUSTOMVERTEX CurV[VertexBufferElemCount] = {};
    
        memcpy(CurV, v, sizeof(CUSTOMVERTEX) * VertexBufferElemCount);
    
        // メッセージ ループ。
        MSG msg = {};
        do
        {
          ::Sleep(1);
          if (::PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
          {
            ::DispatchMessage(&msg);
          }
          // 頂点位置と色の計算(適当な計算です)。
          // 頂点情報 CurV を確定するのが目的。
          g_t += 0.03146f / 2;
          Ratio = 1.5f + cos(g_t);
          float Cx = 0, Cy = 0;
          SetPos(320, 240, g_t * 1.23f, Ratio, 64, 64, &Cx, &Cy);
          DWORD Rainbow = 0;
          for (int i = 0; i < VertexBufferElemCount; ++i)
          {
            SetPos(Cx, Cy, g_t, Ratio, v[i].x, v[i].y, &CurV[i].x, &CurV[i].y);
            CurV[i].dwColor = RainbowRGB(v[i].dwColor + (Rainbow++) * (i + 1));
          }
    
          // 頂点バッファに頂点情報を書き込みできた時にだけ描画。
          void* pData = nullptr;
          if (SUCCEEDED(g_pVertex->Lock(0, sizeof(CUSTOMVERTEX) * VertexBufferElemCount, &pData, 0)))
          {
            memcpy(pData, CurV, sizeof(CUSTOMVERTEX) * VertexBufferElemCount);
            g_pVertex->Unlock();
    
            g_pD3DDev->Clear(0, nullptr, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 255), 1.0f, 0);
            if (SUCCEEDED(g_pD3DDev->BeginScene()))
            {
              // 描画。
              g_pD3DDev->SetStreamSource(0, g_pVertex, 0, sizeof(CUSTOMVERTEX));
              g_pD3DDev->SetFVF(CUSTOMVERTEX::FVF);
              g_pD3DDev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
    
    #if 1
              // 頂点ストリームのスロットを解放。
              g_pD3DDev->SetStreamSource(0, nullptr, 0, 0);
    #endif
    
              g_pD3DDev->EndScene();
              g_pD3DDev->Present(nullptr, nullptr, nullptr, nullptr);
            }
          }
        } while (msg.message != WM_QUIT);
      }
    
    e_Exit:
      SafeRelease(g_pVertex);
      SafeRelease(g_pD3DDev);
      SafeRelease(g_pD3D);
    
      if (g_resetTimerId != 0)
      {
        ::KillTimer(hWnd, g_resetTimerId);
        g_resetTimerId = 0;
      }
      if (hWnd)
      {
        ::DestroyWindow(hWnd);
        hWnd = nullptr;
      }
      ::UnregisterClass(wcex.lpszClassName, wcex.hInstance);
    
      return 0;
    }
    

    • 編集済み sygh 2016年2月9日 14:30
    2016年2月9日 12:12
  • 描画更新と、タイマーによる削除・再生成が排他制御されていないため
    Lock~Unlockまでのわずかな間にReleaseをしてしまったときだけ
    削除が失敗してるのではないでしょうか?

    2016年2月9日 15:46
  • Direct3D描画とWM_TIMERハンドラーはともにUIスレッドで実行されるので、別に排他制御は要らないかと。シングルスレッドなので描画中はメッセージ処理されません。逆もしかりです。
    また、Direct3D 9〜11ではGPUで使用中のリソースを破棄しようとすると、使用が終わるまでCPUを待たせる同期処理をドライバー側で行なってくれることになっています。
    • 編集済み sygh 2016年2月10日 2:47
    2016年2月9日 17:30
  • ご回答ありがとうございます。

    アドバイスいただいた処理を追加して、確認してみます。

    >何を根拠として「有効にできませんでした」と判断されたのでしょうか?

    についてですが、DirectX SDKをインストールしてコントロールパネルも起動できています。

    デバッグ・リリースの切替のラジオボタンも表示されるのですが、デバッグを選択して「OK」しても

    コントロールパネルを再度起動すると状態が反映されていないため

    有効にできないと判断しました。

    ドライバなどについては、全く構成の違う3つのPCでメモリの増加が確認できているので、PC固有の問題ではないと考えています。

    windows8以降というのは確認してませんでした。こちらでも確認してます。

    ありがとうございます。

    2016年2月10日 0:11
  • DirectXコントロールパネルが正常に状態を保存していないようだ、ということですね。どうも正しくインストールされていないように思われます。Visual Studioをインストールしていない環境にまずDirectX SDK June 2010をインストールしてから、Visual Studio 2013をインストールしてみてください。リリースされた順序ではなく、逆順で開発環境やSDKをインストールしてしまうとおかしくなることが多いです。

    ハードウェア環境については、全く構成の違う3つのPCで現象を確認できているとのことですが、具体的にどう違うのかが分からないと正しく判断できません。ハードウェアは違うけれど実は同じベンダーで同じバージョンのドライバーを使っているということはないですか? まずdxdiagでハードウェアとドライバーのバージョンを調べてみてください。

    また、提示されたコードを見る限り、UnicodeバージョンではなくANSIマルチバイトバージョンのCRTを使用されているようですが、Unicodeバージョンを使うようにしてみてください。おそらく今回の現象とは関係ないとは思うのですが……
    • 編集済み sygh 2016年2月10日 3:24
    2016年2月10日 3:08
  • 遅くなって申し訳ありません。現状報告です。

    こちらでもサンプルプログラムでメモリが増加しないことを確認できました。

    実際のプログラムにも同様の処理を反映させてみたところ、
    メモリの増加が緩やかになった気がするものの
    収まっておらず少し絶望しましたが、
    テクスチャに対してSetTextureしてることに気づき同様に
    SetTexture( 0, NULL )
    としたところまだ30分程度ですが、今のところメモリの増加は見られません。

    また経過報告いたします。
    ありがとうございました。


    • 編集済み 700354056 2016年2月10日 14:06
    2016年2月10日 14:06
  • 問題解決につながりそうで何よりです。ちなみに参考になった投稿には「投票」ボタンで投票をお願いします。

    なお、何度かお願いしていますが、せっかくなのでテストに使用されたグラフィックスハードウェアとドライバーのバージョンに関してもこの場でご提示ください。詳しい情報が記載されていれば、今後この質問スレッドが他の開発者の手助けになることがあるかもしれません。

    当方でもいくつかの環境で試してみましたが、NVIDIA環境ではやはり現象を再現できませんでした。ただ、Intel HD Graphicsではどうやらリソースリークらしき現象が起こるようです。

    • Windows 8.1 x64, NVIDIA GeForce GTX 760 4GB, WHQL Driver 361.43
    • Windows 7 SP1 PU x64, NVIDIA Quadro 2000, WHQL Driver 353.90
    • Windows 7 SP1 PU x64, Intel HD Graphics 4400, WHQL Driver 10.18.14.4294

    どうやらドライバーによっては IDirect3DDevice9::SetStreamSource() や IDirect3DDevice9::SetTexture() によってデバイスがリソースハンドルを掴んだままになるものがあるようです。NVIDIAのDirect3D/OpenGLドライバーはわりと堅実な構造になっていて頑丈なのですが、AMD/Intelのドライバーはかなり雑な造りです。

    Direct3D 9はレガシーながら広く使われているAPIなので、D3D9ドライバー自体は今後もメンテナンスはされると思いますが、すでにメインストリームサポートではなく、また今回の不具合は一応回避策があるようなので、Intelに不具合報告しても、バグではなく仕様だということでとりあってもらえない可能性が高いです。やはりDirect2Dに移行することを強くお勧めします。

    • 編集済み sygh 2016年2月10日 16:14
    2016年2月10日 15:53
  • いただいたソースコードの投稿に投票させていただきました。

    一晩立った経過ですが、今までとは違い明らかに改善の兆しがあります。
    ですが、まだ微妙に増えているようにも見えます。

    少し不思議なのは、アドバイスもいただきましたが
    D3DPOOL_MANAGEDを使用すればリセット時の開放は不要と
    思ってました。
    それを考えてサンプルソースはD3DPOOL_MANAGEDだったのですが
    それでもリークしてしまうとするとResetが原因とはいえ、
    Reset時に処理が不要なリソースの使い方が問題ということになり
    原因調査が発散してしまいそうです。

    あれからサンプルコードに
    CreateTextureとCreateOffscreenPlainSurfaceも加えて
    実行していますが
    そちらは全く増えていないので
    実プログラムの方でもこれで安定してくれることを願うばかりです。

    ドライバに関してですが
    ご指摘の通り、今確認に使用している環境は
    ・Windows 7 SP1 CPU x64
    ・Intel(R) HD Graphics 5000
    ・バージョン 10.18.10.3643
    で、Intelのドライバでした。
    2016年2月11日 1:58
  • 投票いただきありがとうございます。

    IDirect3DDevice9::SetStreamSource() や SetTexture() を使ってスロットをクリアしてから、リソースの解放、デバイスの Reset() とリソースの再作成を行なうように変更することで、実プログラムでも改善は確認できたが、まだ完全ではなさそうだ、ということですね。

    ちなみに、

    「D3DPOOL_MANAGEDを使用する場合、デバイスロスト・デバイスリセット時の解放+再作成は不要」

    「D3DPOOL_DEFAULTを使用する場合、デバイスロスト・デバイスリセット時の解放+再作成が必要」

    というのは確かな仕様です。MANAGEDの場合はシステムメモリ側に必ずリソースのマスターデータを持っていて、必要に応じてVRAMにコピーを配置して高速化を図るようにドライバー側が面倒をみてくれます。デバイスをリセットするときもドライバー側で復帰してくれます。一方、DEFAULTの場合はリソースの作成先は完全にドライバー任せで、システムメモリ上に作成されることもあるし、VRAM上に作成されることもあります。デバイスをリセットするときは必ず明示的に解放と再作成を行なう必要があります。

    詳しくは「D3DPOOL」の説明をもう一度しっかり読んでください。

    したがって、少なくとも提示された検証用のサンプルコードでは、D3DPOOL_MANAGEDを使うかぎりIDirect3DVertexBuffer9の明示的な解放と再作成は必要ありません。ですが、COMのRelease()メソッドというのは、

    まず参照カウントを1つ減らす。参照カウントがゼロになった場合、メモリを解放する

    という仕組みになっています。なので、たとえRelease()を実行したからといって、必ずしもメモリが解放されるとはかぎりません。つまり、Intel環境においては、修正前のコードはRelease()によって内部参照カウントを減らしただけで、実際にはメモリが解放されておらず、

    g_pVertex->Release();
    g_pVertex = NULL;

    というコードによってリソースリークが発生してしまっていた、ということです。その後に新たな頂点バッファを再作成しているので、当然その先はどんどんメモリ使用量が増えていってしまいます。これはD3DPOOL_MANAGEDであろうがD3DPOOL_DEFAULTであろうが関係ありません。

    なお、もし実プログラムでのメモリリークが完全に解消されない場合、もしかするとDirect3Dリソースに関係のない別のメモリ確保処理が原因となっている可能性もあります。問題の切り分けのために、まずNVIDIA環境を用意してテストしてみてください。もしNVIDIA環境ではリークがまったく発生しないのであれば、IntelのD3D9ドライバー実装に起因するコードがリークを引き起こしているとみなせるため、ドライバーを更新したりDirect3Dリソースの管理を見直したりすることで改善される可能性が高くなります。

    もしNVIDIA環境を用意できず、また実プログラムのコードを開示できないのであれば、せめて実プログラムに使用しているすべてのDirect3Dインターフェイスとメソッドを開示してください。目隠しされている状態では正しい道筋の判断ができません。ちなみに、ActiveXコントロール上でDirect3Dを使用しているとのことですが、そのActiveXコントロールのホスト側(ActiveXコントロールを作成して利用する側)はどんなアプリケーションですか? Direct3DデバッグランタイムおよびCRTデバッグランタイムを使い、アプリケーションに対してデバッガーを適切にアタッチすれば、メモリリークを起こしているのがどの部分なのか特定しやすくなります。また、何度も説明しているように、DirectX SDK June 2010をインストールした後でVisual Studio 2013をインストールし、さらにドライバーを最新版に更新して、正常かつ適切なDirect3D 9デバッグ環境を準備してから開発を始めることを強くお勧めします。「急がば回れ」ということわざを思い出してください。焦って解決しようとするとロクなことになりません。

    それと、説明していませんでしたが「Windows 7 SP1 PU x64」における「PU」というのは、Platform Updateの意味です。Windows 7 SP1用プラットフォーム更新プログラム「KB2670838」を適用している、ということを意味しています。決して「CPU」をtypoしたわけではありません。

    また、「全く構成の違う3つのPCでメモリの増加が確認できている」ということでしたが、結局そのPCというのは実は3台ともIntelグラフィックス環境だった、ということでしょうか? 質問するときは必ず正確な情報を開示するようにしてください。出し惜しみも厳禁です。十分な知識や経験がない場合は早計な自己判断をせず、有識者に判断をゆだねて従うことが解決への近道になります。

    • 編集済み sygh 2016年2月11日 6:37
    2016年2月11日 5:15
  • いろいろアドバイスありがとうございます。

    サンプルプログラムの件ですが
    メモリをピーク値で確認してしまっていて
    安定していと思ったのは勘違いだったかもしれません。
    現在ご提示いただいたコードで再度確認中です。

    全てのインターフェースとメソッドを開示の点については
    おっしゃるとおりと思います。
    言い訳にしかなりませんが、
    簡単なプログラムを作成して確認しようとした際に
    まずは1つずつと考えて最初の
    Vertexの処理をいれただけでリークらしき兆候が見れたのでそれを
    そのまま送ってしまいました。
    最新のNVIDIAの環境は今すぐには難しそうです。
    再度サンプルを作成しますので
    判断していただけるとうれしいです。

    D3DPOOL_MANAGEDの件ですが
    最初のサンプルプログラムでは、D3DPOOL_MANAGEDを使っていて
    リセット前の開放・作成処理をコメントアウトしてあったと思います。
    この状態でもメモリは増えていたので、TextureやVertexなどの管理と
    リークの関連は薄いと考えていました。

    確認したPCの情報です。
    PC1
    ・windows 7 SP1 PUなし 32bit(でした、すみません)
    ・Intel(R) HD Graphics 5000
    ・バージョン 10.18.10.3643

    PC2
    ・windows 7 SP1 PUあり 64bit
    ・Intel(R) HD Graphics Family
    ・バージョン 10.18.10.3325

    PC3
    ・windows XP SP3 32bit
    ・NVIDIA Geforce GTS 450
    ・バージョン 6.14.12.6658

    PC3でもこれからサンプルプログラムを実行してみます。

    2016年2月11日 7:45
  • メモリ使用量の増減は「プライベート ワーキング セット」で確認するようにしてください。Windows XPの場合は、タスクマネージャーではなくパフォーマンスモニターを使って確認したほうがよいです。

    安定していたと思ったのは勘違いだったかもしれません」というのは、いったいどの話ですか?

    このコードをそのままコンパイルして実行すると

    起動当初は、メモリが増えていきますが

    その後は2時間くらい見てもメモリは増えていかないので

    そこで安定していると考えています。

    という記述のことでしょうか?

    少なくとも「IDirect3DDevice9::SetStreamSource() や SetTexture() を使ってスロットをクリアすることで、サンプルプログラムだけでなく実プログラムでもリーク現象に関して一定の改善がみられた」ということに関しては間違いないですか? それとも、それすらも勘違いだったということですか?

    また、D3DPOOL_MANAGEDの話に関しては、確かに最初に提示されていたテスト用サンプルコードではD3DPOOL_MANAGEDを使ったうえでリセット前後におけるリソースの解放と再作成はコメントアウトされていて、リセットを行なうだけでリーク現象が発生していた、ということなので、リセット前後におけるリソース解放+再作成の有無が問題となっているわけではない、という見解は確かに正しいと思います。自分も少し深読みしすぎていたようです、申し訳ありません。

    現在得られている知見を要約すると、「Intel環境では、たとえD3DPOOL_MANAGEDを使って、リソースの復元をドライバー任せにしていても、デバイスのリセット前にスロットを解放していなければリソースリークする」ということですね。Intel環境だと、リセット直前にデバイスのスロットにセットされていたリソースに関与していた何らかのメモリが適切に解放されず放置されてしまっているのだと思われます。

    とにかく、できるかぎり誤解のない正確な表現を使ってください。MSDNフォーラムはコミュニティの善意やボランティア精神のもとに成り立っている無償のサービスなので、質問する側も正確な情報を開示してコミュニティに貢献するという意識を持っていただきたいです。

    なお、NVIDIA GeForce GTS 450に対応したWindows XP向けドライバーの最新版は361.75です。ありがたいことに、NVIDIAは2016年に入ってもまだXP向けドライバーもメンテナンスしてくれています。お使いのドライバーは2011年頃にリリースされた266.58であり、かなり古いバージョンです。何度も説明していますが、少なくともドライバーくらいは最新版に更新して環境を整える努力をしてください。GeForce GTS 450自体は古い製品ですが、DirectX 11対応世代のFermiアーキテクチャなので、比較対象としては十分使えるハードウェアだと思います。

    • 編集済み sygh 2016年2月11日 12:55
    2016年2月11日 11:55
  • いろいろと申し訳ありません。

    勘違いの可能性が高いのは
    「こちらでもサンプルプログラムでメモリが増加しないことを確認できました。」
    の発言です。このとき、ピークワーキングセットをみて発言していました。
    一番最初にお送りしたサンプルプログラムの方は
    間違いなく「プライベート ワーキング セット」で確認しております。
    実プログラムでは改善が見られているように思えるのですが
    適当なことを言ってもご迷惑をおかけするので
    もう少しじっくり確かめてから再度報告させてください。

    プログラムではなくドライバの不良の可能性もあるということで
    XPの方はご指摘のように新しいバージョンをインストールします。

    アドバイスをいただいている方には、本当に感謝の念しかありません。
    ありがとうございます。
    2016年2月11日 14:10
  • こちらでもIntel HD Graphics 4400環境で再テストしてみましたが、スロットをクリアする処理を入れただけではメモリ増加現象に歯止めがかからないようです。NVIDIA環境ではやはり安定しています。

    時間のあるときにIntelドライバーを最新版に更新して、こちらでも再検証してみます。

    2016年2月12日 17:12
  • 検証ありがとうございます。

    36時間ほど動かしてみました。
    こちらでも同様な状況で
    HD Graphics 5000でサンプルプログラムが20MB増加で現在も増量中
    NVIDIA Geforce GTS 450の方は、400KBほど増加していて
    先程まで眺めていましたが1時間に4K単位くらいの割合で
    増加している様に見えます。
    今までとの比較をみたかったのでまだ最新のドライバには更新していません。

    Resetを呼び出すには何か作法か条件があるような気がしてきました。
    2016年2月13日 5:09
  • あまり大した情報はありませんが…

    Intel HD Graphicsが怪しいという流れのようなので、手元のSurfacePro(Windows 8.1、Intel HD Graphics 4000)で確認してみました。

    700354056さんの挙げられたサンプルプログラムですが、確認にあたってリークが顕在化するようにIDirect3DDevice9::CreateVertexBuffer()にて指定するサイズを1024倍してみました。それほど長時間実行したわけではありませんが、Private Bytesが次第に増加し、その後12MB→20MB→12MBと増減を繰り返していました。
    このPrivate BytesについてDebugging Tools for Windowsのgflagsumdhでメモリ確保元を確認してみましたが、そもそもリークと呼べるほどのメモリ確保を行っているモジュールが存在していませんでした。(確保量で+64KB程度、とても数MBのメモリリークにつながるようなものではありませんでした。)

    調査はここまでですが、ここから推測できるのは私が観測したこの増減はLow-fragmentation Heapによりプロセスヒープに割り当ては行われているものの使われていないメモリではないか? ということと、元質問のリークはWindows 8.1では解消されているWindows 7での問題か? という辺りでしょうか。
    まずはWindows 7でも同様の調査を行ってみることをお勧めします。

    2016年2月15日 6:11
  • Intelドライバーを最新の10.18.14.4332に更新して試してみましたが、やはりメモリ増加現象は発生します。

    どうもIDirect3DDevice9::DrawPrimitive()呼び出しの有無が現象に関係しているように思われます。ドローコールがなければ描画することができないので、現実的にはDrawPrimitive()呼び出しを削除するというわけにはいきませんが。他のDrawPrimitiveUP()メソッドなどに関しては調査していません。

    なお、Reset()メソッドはそもそも定期的に呼び出すような類のものではなく、デバイスロスト時、バックバッファのリサイズ時、フルスクリーン/ウィンドウモード切り替え時などの限られたタイミングで呼び出すものなので、もし24時間365日再起動なしで稼働し続けなければならないというような厳しい要求がないのであれば、

    「ウィンドウクライアント領域のサイズを定期的にチェックするなりして、前回と変化のあったときだけD3DPRESENT_PARAMETERS::BackBufferWidthとD3DPRESENT_PARAMETERS::BackBufferHeightをゼロに設定してからResetする」

    というように回避する方向で進めたほうが現実的かもしれません。

    ちなみに実プログラムのほうではデバイスロスト対策(TestCooperativeLevelメソッドによる協調レベルのチェックなど)は行なっていますよね? Direct3D 9はWindowsキー+Lキーなどで簡単にデバイスロストします。やはり自分としてはXPを捨ててDirect2Dに移行することを強くお勧めします。

    そのほか、英語ですが、Intelグラフィックスドライバーのバグレポートを提出できる開発者向けサイトもあります。本件はアプリケーションサイドで調査可能な範疇をすでに超えているように思われるため、もしどうしても納得のいくまで調査したいのであれば、こちらに直接問い合わせてみたほうがよいかと。

    Graphics Driver Bug Reporting

    もし本当にドライバーのバグであるならば、アプリケーション側での回避策が存在するとは限りませんし、たとえ回避できたとしても別のバージョンのドライバーでは通用しない可能性だってあります。また、Windows XP向けのドライバーサポートはすでに終了しているため、仮にドライバーのバグだったとして、新しいバージョンで修正されるとしても、XP環境では依然として問題が残ることになります。

    • 編集済み sygh 2016年2月15日 16:18
    2016年2月15日 15:40
  • おはようございます。

    皆様方、 有用な情報・貴重なアドバイスありがとうございます。
    情報いただいたツールを試して確認してみます。
    デバイスロスト対策はしております。
    このプログラムのためだけにXPを捨ててくださいとは
    とても言えませんが、
    連続運用するならXPは使わないでください程度は
    許してもらえる気がします。

    まずは、ツールでの確認をいたします。
    ありがとうございます。
    2016年2月17日 1:18