   Pos resource leak? - Solved
  I created this simple DirectX program in VC++. It simulates a grid with moving nodes. Basically like the grid on Geometry Wars.The problem is that it will either crash or become very slow at random times while moving the grid around and I am wondering if this is because of a resource leak. On a side note, nothing keeps the nodes from going way off the screen if that may be a problem. Here is the compiled program and the code:EXE: http://host-a.net/yo1dog/DirectX_GRID.zip// include the basic windows header files and the Direct3D header file#include <windows.h>#include <windowsx.h>#include <Math.h>#include <d3d9.h>#include <d3dx9.h>#define WINDOWED false// include the Direct3D Library file#pragma comment (lib, "d3d9.lib")#pragma comment (lib, "d3dx9.lib")// global declarationsLPDIRECT3D9 d3d;// the pointer to our Direct3D interfaceLPDIRECT3DDEVICE9 d3ddev;    // the pointer to the device classLPDIRECT3DVERTEXBUFFER9 v_buffer = NULL;    // the pointer to the vertex bufferLPD3DXFONT dxfont;    // the pointer to the font object#define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)#define KEY_UP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1) // define the screen resolution#define SCREEN_WIDTH  ((WINDOWED)? 800 : 1680)#define SCREEN_HEIGHT ((WINDOWED)? 600 : 1050)#define CUSTOMFVF (D3DFVF_XYZRHW | D3DFVF_DIFFUSE)struct Vertex{    float x, y, z, rhw;    // from the D3DFVF_XYZRHW flag    DWORD color;    // from the D3DFVF_DIFFUSE flag};// function prototypesvoid initD3D(HWND hWnd);    // sets up and initializes Direct3Dvoid render_frame(void);    // renders a single framevoid cleanD3D(void);    // closes Direct3D and releases memoryvoid init_graphics(void);    // 3D declarationsvoid init(void);void run(void);void updateVertices(void);void createExplotion(float, float, float, int);void createImplotion(float, float, float, int);//===================================================#define WIDTHSCREEN_WIDTH#define HEIGHTSCREEN_HEIGHT#define s20#define w(int)(WIDTH/s + 1)#define h(int)(HEIGHT/s + 1)#define nw*h#define nl((w - 1)*2*h + (h - 1)*2*w + 8 + w*4 + h*4)// |inner  |   |   outer    |#define ELASTIC0.2#define FRICTION0.1float grid[n][4];//Position   0: X Pos,  1: Y Pos,  2: Orig X Pos,  3: Orig Y Posbool gridA[n];//Active (run calculations)float gridT[n];//Angle of motionfloat gridV[n][3];//Velocity   0: X Vel,  1: Y Vel,  2: Velint gridC[n][4];//Color   0: Red,  1: Blue,  2: Green,  3: Alpha#define gridColor D3DCOLOR_ARGB(0, 0, 255, 0)Vertex vertices;#define XOFFSET(int)((SCREEN_WIDTH - WIDTH)/2);#define YOFFSET(int)((SCREEN_HEIGHT - HEIGHT)/2);int mx = 0, my = 0;//===================================================// the WindowProc function prototypeLRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);// the entry point for any Windows programint WINAPI WinMain(HINSTANCE hInstance,    HINSTANCE hPrevInstance,    LPSTR lpCmdLine,    int nCmdShow){    HWND hWnd;    WNDCLASSEX wc;    ZeroMemory(&wc, sizeof(WNDCLASSEX));    wc.cbSize = sizeof(WNDCLASSEX);    wc.style = CS_HREDRAW | CS_VREDRAW;    wc.lpfnWndProc = WindowProc;    wc.hInstance = hInstance;    wc.hCursor = LoadCursor(NULL, IDC_ARROW);if (WINDOWED) wc.hbrBackground = (HBRUSH)COLOR_WINDOW;    wc.lpszClassName = (LPCSTR)"WindowClass";    RegisterClassEx(&wc);if (WINDOWED)    hWnd = CreateWindowEx(NULL, (LPCSTR)"WindowClass", (LPCSTR)"Our First Direct3D Program", WS_OVERLAPPEDWINDOW, 300, 300, SCREEN_WIDTH, SCREEN_HEIGHT, NULL, NULL, hInstance, NULL);elsehWnd = CreateWindowEx(NULL, (LPCSTR)"WindowClass", (LPCSTR)"Our First Direct3D Program", WS_EX_TOPMOST | WS_POPUP, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, NULL, NULL, hInstance, NULL);    ShowWindow(hWnd, nCmdShow);init();    // set up and initialize Direct3D    initD3D(hWnd);    // enter the main loop:    MSG msg;    while(true)    {   while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))   {  TranslateMessage(&msg);  DispatchMessage(&msg);   }   if(msg.message == WM_QUIT)  break;POINT cursorPos;   GetCursorPos(&cursorPos);mx = cursorPos.x - XOFFSET;   my = cursorPos.y - YOFFSET;//Render a frame   render_frame();// check the 'escape' keyif (KEY_DOWN(VK_ESCAPE))PostMessage(hWnd, WM_DESTROY, 0, 0);    }    // clean up DirectX and COM    cleanD3D();    return msg.wParam;}// this is the main message handler for the programLRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){    switch(message)    {   case WM_DESTROY:  { PostQuitMessage(0); return 0;  } break;    }    return DefWindowProc (hWnd, message, wParam, lParam);}// this function initializes and prepares Direct3D for usevoid initD3D(HWND hWnd){    d3d = Direct3DCreate9(D3D_SDK_VERSION);    // create the Direct3D interface    D3DPRESENT_PARAMETERS d3dpp;    // create a struct to hold various device information    ZeroMemory(&d3dpp, sizeof(d3dpp));    // clear out the struct for used3dpp.Windowed = WINDOWED;    // program windowed, not fullscreen    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;    // discard old frames    d3dpp.hDeviceWindow = hWnd;    // set the window to be used by Direct3D//Fullscreend3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;    // set the back buffer format to 32-bit    d3dpp.BackBufferWidth = SCREEN_WIDTH;    // set the width of the buffer    d3dpp.BackBufferHeight = SCREEN_HEIGHT;    // set the height of the buffer    // create a device class using this information and information from the d3dpp stuct    d3d->CreateDevice(D3DADAPTER_DEFAULT,  D3DDEVTYPE_HAL,  hWnd,  D3DCREATE_SOFTWARE_VERTEXPROCESSING,  &d3dpp,  &d3ddev);//create font classD3DXCreateFont(d3ddev,    // the D3D Device24,    // font height of 300,    // default font widthFW_BOLD,    // font weight1,    // not using MipLevelsfalse,    // italic fontDEFAULT_CHARSET,    // default character setOUT_DEFAULT_PRECIS,    // default OutputPrecision,DEFAULT_QUALITY,    // default QualityDEFAULT_PITCH | FF_DONTCARE,    // default pitch and family(LPCSTR)"Arial",    // use Facename Arial&dxfont);    // the font object//no ambient light (NEW)d3ddev->SetRenderState(D3DRS_AMBIENT,RGB(0,0,0));//lighting enabled (NEW)d3ddev->SetRenderState(D3DRS_LIGHTING,true);d3ddev->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE);d3ddev->SetRenderState(D3DRS_ZENABLE,D3DZB_TRUE);}// this is the function used to render a single framevoid render_frame(void){    // clear the window to a deep blue    d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);run();updateVertices();init_graphics();    d3ddev->BeginScene();    // begins the 3D scene    // do 3D rendering on the back buffer here// select which vertex format we are using   d3ddev->SetFVF(CUSTOMFVF);// select the vertex buffer to display   d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(Vertex));// copy the vertex buffer to the back buffer   d3ddev->DrawPrimitive(D3DPT_LINELIST, 0, nl/2);// create a RECT to contain the text    static RECT textbox; SetRect(&textbox, 0, 0, 640, 480);// draw the Hello World text    dxfont->DrawTextA(NULL,  "Space - Create Explotion\nCtrl - Create Implotion\nI - Hide this\nHold Shift to amplify effect",  91,  &textbox,  DT_LEFT | DT_TOP,  D3DCOLOR_ARGB(200, 255, 0, 0));    d3ddev->EndScene();    // ends the 3D scene    d3ddev->Present(NULL, NULL, NULL, NULL);    // displays the created frame}// this is the function that cleans up Direct3D and COMvoid cleanD3D(void){v_buffer->Release();    // close and release the vertex buffer    d3ddev->Release();    // close and release the 3D device    d3d->Release();    // close and release Direct3D}void init_graphics(void){// create the vertex and store the pointer into v_buffer, which is created globally    d3ddev->CreateVertexBuffer(nl*sizeof(Vertex), 0, CUSTOMFVF, D3DPOOL_MANAGED, &v_buffer, NULL);    VOID* pVoid;    // the void pointer    v_buffer->Lock(0, 0, (void**)&pVoid, 0);    // lock the vertex buffer    memcpy(pVoid, vertices, sizeof(vertices));    // copy the vertices to the locked buffer    v_buffer->Unlock();    // unlock the vertex buffer}void init(void){for (int y=0; y < h; y++){for (int x=0; x < w; x++){int i = x + y*w;grid[0] = x*s;//X posgrid[1] = y*s;//Y posgrid[2] = x*s;//Original X posgrid[3] = y*s;//Original Y posgridA = false;//ActivegridT = 0;//Angle of motiongridV[0] = 0;//X VelgridV[1] = 0;//Y VelgridV[2] = 0;//Vel}}}void updateVertices(){//Updates vertices[] array with grid array}void run(void){//Code for moving the nodes//only deals with the grid arrays so problem can't be here//Note: nothing keeps the nodes from going way off the screen}void createExplotion(float xx, float yy, float p, int r){//More code for moving nodes//only deals with the grid arrays so problem can't be here}void createImplotion(float xx, float yy, float p, int r){//More code for moving nodes//only deals with the grid arrays so problem can't be here}[Edited by - yo1dog on May 18, 2009 7:43:15 PM]
  Can't really follow that much code thrown at me at once, but it sure looks like you are iterating through all your vertices and changing them every single frame. That can't be very efficient at all.Are you sure your doing something you can't accomplish with a transformation matrix?;  There is indeed a resource leak. In your render_frame() function, which is called every frame, you call init_graphics(). Here, you call CreateVertexBuffer() which allocates a D3D vertex buffer - which you never release. That is, every time you call CreateVertexBuffer, you overwrite the contents of the v_buffer without releasing it (by calling Release()) - this means you have leaked memory.The net effect is that every single frame you are allocating a large object but never releasing it.You should call Release() on v_buffer before overwriting the pointer. Ideally, you shouldn't be creating a new vertex buffer per frame anyway - that's bound to be slow. Create the vertex buffer once when you initialise D3D - and just reuse the same buffer. The size of your vertex buffer doesn't change, so there's no need to constantly recreate it.Also: Don't mix spaces and tabs! Pick one and stick to it - your code indentation is all over the place.   ;Quote:Original post by Sc4FreakThere is indeed a resource leak. In your render_frame() function, which is called every frame, you call init_graphics(). Here, you call CreateVertexBuffer() which allocates a D3D vertex buffer - which you never release. That is, every time you call CreateVertexBuffer, you overwrite the contents of the v_buffer without releasing it (by calling Release()) - this means you have leaked memory.The net effect is that every single frame you are allocating a large object but never releasing it.You should call Release() on v_buffer before overwriting the pointer. Ideally, you shouldn't be creating a new vertex buffer per frame anyway - that's bound to be slow. Create the vertex buffer once when you initialise D3D - and just reuse the same buffer. The size of your vertex buffer doesn't change, so there's no need to constantly recreate it.Also: Don't mix spaces and tabs! Pick one and stick to it - your code indentation is all over the place.I think I follow what you mean... This was my first attempt at DirectX as you can probably tell.As for the spaces and tabs, VC++ can be weird sometimes and turns my tabs into spaces. I will clean that up.   ;  OK, so I got rid of the init_graphics method, Created the buffer in the init_D3D method, and wrote to the buffer at the end of the updateVertices method.So I create the buffer once and rewrite it every frame.Thanks for the help!   