Wednesday, 3 September 2014

Delve Into Video Memory

I must have spent at least four hours hunting for a simple way to read the current used video memory from my system. I must have done everything at least once. Using the legacy DirectX API, created an OpenGL context to grab it that way, tapped into the WINAPI, used DxDiag, used DXGI and everything in between. You would think this relatively common requirement would be a simple DirectX command, but no, it's wrapped in mystery and riddled with dead-ends. After completely failing in this, I decided on a different approach and used GPU-Z window alongside the loading process and watched for video memory spikes that way. Can't waste days writing a robust video memory monitor when I have game engines to write.  If anyone has some 'working' code in C++ that can detect the 'remaining' (not total) amount of video memory on NVIDIA and AMD machines, please do post.

On proceeding the old fashioned way, I did uncover one crucial fact, which lead to a 400MB+ saving on one of my standalone levels. A cheeky claim, as it turns out when you encrypt media, it does not remember it was loaded, and subsequently loads it in again for any other entity that needs the reference. This would include entities of the same type, and more crucially light map textures. My run this morning crashed out at 1GB of video memory, my new test loaded, ran and leveled off at 805MB (673MB when divide all textures by 32) video memory (which included a large uncompressed Church texture which gobbled 128MB all by itself) :)  This brief journey puts me in a position where I can load in a lightmapped standalone level now, which is great!

There are still many targets for video memory savings here, and each site needs close study to get the best use of available budget. For now I will finish off my making some new entity asset conversions and then resume Thursday with more winning video saving antics.  Sorry for the lack of images, some days are nothing but words and deeds ;)

31 comments:

  1. (Sorry for the lack of images) Not a problem,although i dont understand a lot of the information.I find it interesting trying to find out what it means.

    ReplyDelete
  2. hey lee my brother who has been writting game engines in c++ for over 20 years suggested this page http://msdn.microsoft.com/en-us/library/bb174526(v=VS.85).aspx

    ReplyDelete
  3. http://developer.download.nvidia.com/opengl/specs/GL_NVX_gpu_memory_info.txt
    http://www.opengl.org/registry/specs/ATI/meminfo.txt

    ReplyDelete
  4. GL_NVX_gpu_memory_info needs OpenGL, Reloaded uses DirectX. DXGI only reports total video memory, not 'usage' which is the value I need. Keep 'em coming :)

    ReplyDelete
    Replies
    1. I would still think that you could query the video card for what's available even if the interface is through OpenGL, but I could be wrong. I think it's worth a try.

      Delete
  5. Tried for 2 hours, no joy. I initialized via InitGlut but the value simply returned zero. If anyone can find code which works from DirectX app but uses the OpenGL mem read, send it along!

    ReplyDelete
    Replies
    1. If I get some time I'll try a few things and see if I can find something that works. But if you read a lot of the posts on this subject you'll see that most suggest that this is not necessary to know this anyway. Is like I've been saying that you shouldn't really run out if the driver resorts to system memory. So, knowing this value is not really that important.

      Delete
    2. Using managed textures (texture back-ups in system memory) will decrease available system memory, which is something I want to avoid. Knowing the value will allow the use of dynamic texture resizing to allow more textures to be used without worrying about running out of physical video memory.

      Delete
  6. Probably won't help, but might be useful :)
    http://gamedev.stackexchange.com/questions/4383/how-do-i-query-available-video-memory-using-directx

    ReplyDelete
  7. DX7's GetAvailableVidMem() : We are DX9

    WMI (Windows Management Interface) has a similar result to the above : Not on W7

    DxDiag uses both to give a better result : Returns total, not current usage

    D3D9 has a GetAvailableTextureMemory() function, but can only be used on Windows Vista/7 : Returns total, not current usage

    ReplyDelete
    Replies
    1. Dammit, sorry about that :/
      I found this link too:
      http://stackoverflow.com/questions/427707/report-direct3d-memory-usage
      It suggests using DirectDraw to somehow retrieve the vram usage, but it makes it clear that's not an accurate way of getting the information, so probably not much help either - It does give a good explanation of why retrieving video memory usage isn't easier though :)

      Delete
    2. It has to be a C++ code snippet. I already have an external tool called GPU-Z to read the value outside of Reloaded, but I need Reloaded engine itself to trace the usage.

      Delete
  8. Here is an example comment about this topic:

    "This is a fairly common question and the basic answer is "You Don't" [smile]

    "What do you want to do with this value? The memory managment system is a complex beast and trying to second guess it by micro-managment on your part is unlikely to yield good results for you. Leave the API, XPDM and driver to handle the finer details."

    You see?

    ReplyDelete
    Replies
    1. I want to monitor overall video memory usage as the engine loads in resources, determine if some parts are using too much proportionally and head-off scenarios where too much video memory is being used. Using a system memory back-up is not an option (managed) as I also want to retain as much system memory as possible (and don't want copies of all the textures). Most people can create their games with a specific texture budget in mind, with a game creator your end user could sit there dropping in 64MB textured entities all day long and there needs to be a control here.

      Delete
  9. You can use the EVGA Precision tool to display on screen how much VRAM is currently in use. See this screenshot here: http://mjblosser.com/evga.jpg

    ReplyDelete
    Replies
    1. Thanks Mark. I use GPU-Z which has a sensor for video memory used. I just need that same value in the engine itself so I can assign resource loads with apparent video memory usage (to help optimizing).

      Delete
  10. You could try PIX

    http://tomtech999.wordpress.com/2011/09/07/debugging-directx-applications-with-pix-for-windows/

    ReplyDelete
    Replies
    1. Needs to be a C++ code snippet I can integrate into the engine itself.

      Delete
  11. All sounds good, Lee :) Unfortunately I don't believe there is a way to get the current used video memory. You're supposed to only load a sensible amount of stuff into video memory and then leave it up to the driver to handle it efficiently.

    ReplyDelete
    Replies
    1. If I could convince Reloaded users that a sensible limit has been reached and they can no longer add anything new to their level I would not be very popular. My plan is to dynamically reduce texture sizes as more textures crowd into the video memory itself. Using the system memory as a cache back-up is not an option as I need system memory for other things (many other things).

      Delete
  12. There is a simple DirectX command "D3DKMTQueryStatistics"
    Here is a link with some info.
    http://forum.sysinternals.com/topic26875_post131430.html

    ReplyDelete
    Replies
    1. Isn't that only for Windows 8?

      Delete
    2. I think it works on Windows 7 or later, check this link
      It is C++ code
      https://bitbucket.org/mozilla/projects-ionmonkey/src/5cfb73435e06/gfx/thebes/gfxWindowsPlatform.cpp

      Delete
    3. Just ran a search for the "gdi32.dll" and its on my Windows 7 machine.

      Delete
    4. Ah ok cool well maybe that'll help Lee.

      Delete
    5. Hmm...great link there!! Looks like it's the same hook that GPU-Z uses, which is perfect. Will spend an hour and see where the code takes me...

      Delete
    6. Yep, this one did it. I will make a blog post today about the whole solution for other would-be DirectX9 coders looking for this most valuable method :)

      Delete
  13. More info on this link
    http://processhacker.sourceforge.net/forums/viewtopic.php?t=325

    ReplyDelete
    Replies
    1. Found more info
      http://processhacker.sourceforge.net/doc/d3dkmt_8h_source.html

      Delete
  14. How much memory could be saved by using PNG's instead of DDS? I can have the same image saved in each format and the DDS will be around 16Mb, whereas, the PNG will be 1-2Mb. If we could use those instead, I think that would help things along.

    ReplyDelete
    Replies
    1. In the case of PNG, file size does not denote memory used. It will uncompress into X8R8G8B8 when loaded. DDS is the best with DXT1 compression in hardware. Also looking at L8 format to see if there is a saving there for lightmaps (pity they don't have an 8-bit compressed surface) :) I might also explore putting four lightmaps into one texture (R,G,B,A) and DXT5 compression. Early days yet...

      Delete