Sign in to follow this  
Nesta

DirectX 9 - Troubles with VOLUME texture rendering

Recommended Posts

Hello everyone. I have problems rendering VOLUME texture using DirectX 9. Below is the description: 1. As an input data I have the collection of frames which are used for building of volume texture. 2. If there are too many frames or if they are to wide or high I simply delete some of them from collection and also decrease their size (let's call this operation "scaling"). To identify if there are to many frames or not I retrieve the size of available video memory and also properties of the graphic card (MaxTextureWidth and MaxTextureHeight fields from D3DCAPS9 are used for this purpose). 3. Than I create volume texture which is based on "scaled" data. I pass corresponding "scaled" width, height and depth. And now where the problems arises. IDirect3DDevice9::CreateVolumeTexture() returns S_OK but blank white screen is displayed while rendering. Event if I fill the texture with invalid data at least the background must be black but it's also white. I performed some experiments and discovered that if I increase "scaling" coefficient (i.e. remove more frames from source collection and perform higher scaling for each of them) everything works fine, the texture is rendered like expected. I have some question regarding to this issue: a) Why CreateVolumeTexture() returns S_OK even in case when it's not able to successfully create texture? b) Are there any other ways to check if texture has been successfully created? Maybe IDirect3DDevice or IDirect3DVolumeTexture have appropriate methods for this? c) Another detail. Everything works fine on my machine with normal "scaling" coefficient and with increased one. But on machine of my colleague the problem arises when normal "scaling" coefficient is used. When I remove more frames from source collection everything works fine even on his computer. d) And the most interesting. Couple months ago his machine was able to render the same texture normally with normal "scaling" coefficient. We have automatic Windows update enabled (we use Windows XP Professional). Is there a possibility that the latest updates somehow corrupted behavior of DirectX 9? Any ideas? Please ask me for details if I haven't clarified something. Thanks.

Share this post


Link to post
Share on other sites
I also thought about driver bug but 2 months ago everything worked fine and the system was not reinstalled and drivers were not updated either. An only updates both of us had are only related to automated Windows updates.

Share this post


Link to post
Share on other sites
Quote:
Original post by Nesta
I also thought about driver bug but 2 months ago everything worked fine and the system was not reinstalled and drivers were not updated either. An only updates both of us had are only related to automated Windows updates.
Are you sure there wasn't a driver update as part of windows update? Do the Debug Runtimes say anything? Do you get the same behaviour with the reference rasterizer?

Share this post


Link to post
Share on other sites
Thanks for informing me about Debug Runtime. I didn't know about this tool before. I will try it right now and say what happens.

Share this post


Link to post
Share on other sites
Debug Runtime really helped me. I was not able to fix that particular bug but it helped me to fix couple others. Really useful tool. Thanks I will continue investigating this bug and see if Debug Runtime can help me in it.

Share this post


Link to post
Share on other sites
I used Debug Runtime and discovered than during the call of code:
m_pId3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, trianglesCount);

I see following lines in Debug Output:
Direct3D9: (ERROR) :All POOL_MANAGED resources in this device freed. No further video memory available.
Direct3D9: (ERROR) :The resource manager failed to promote or update a dirty texture. The texture will be disabled.

The same lines also appear when I call
m_pId3dDevice->ValidateDevice(&outValue)

The most interesting thing is that ValidateDevice() call returns S_OK, outValue is always '1'.

Does anybody know why in this case neither DrawPrimitive() nor ValidateDevice() function return any kind of D3D_ERROR? These functions always return success.

Thanks

Share this post


Link to post
Share on other sites
Quote:
Original post by Nesta
I see following lines in Debug Output:
Direct3D9: (ERROR) :All POOL_MANAGED resources in this device freed. No further video memory available.
Direct3D9: (ERROR) :The resource manager failed to promote or update a dirty texture. The texture will be disabled.
That error means: "I needed to create a resource in video memory for rendering, but there wasn't enough video memory. I purged all other D3DPOOL_MANAGED resources from video memory, but there still wasn't enough left over."

I would assume this happens because the frontbuffer, z-buffer, and other default pool resources are in video memory, and/or the GetAvailableTextureMem() function doesn't return video memory directly, meaning you've created a resource that's too large to fit in VRAM at the moment, but is probably big enough to fit in VRAM if there was nothing else there.

As for ways to detect this - good question. I've asked about this on the Microsoft DirectX newsgroups, lets see if Microsoft have any suggestions...

Share this post


Link to post
Share on other sites
Thanks for your help. I really appreciate it.
It really seems logical that rendering fails because I try to use more memory than my graphic card can offer because when I apply "scaling" to the source volume everything works fine. If you can get more information about detecting of allocating to much space, please share it in this topic.

I have another question regarding to this situation. As I mentioned in previous posts, DirectX writes the corresponding message to Debug Output when I call m_pId3dDevice->DrawPrimitive(). While the result of this function execution is S_OK. So my code "thinks" everything works fine while it's not so. Is there any way I can retrieve this information from DirectX to be able at least to rebuild my volume in such case? I tried m_pId3dDevice->ValidateDevice() but it also returns S_OK.

Thanks everyone for help.

Share this post


Link to post
Share on other sites
Well, I haven't had any updates on the DirectX newsgroups so I looked into this a bit further.

DrawPrimitive doesn't return an error because the bit of code that uploads the resources to video memory is a void function. I can only assume it's an internal function that's never supposed to fail. The function goes through all bound textures and if they're in the managed pool, it tries to create a copy of the resource in the default pool. If that fails, then it just tells the driver that no texture is bound in that stage (Hence "The texture will be disabled").

ValidateDevice doesn't report an error because it only reports errors from the driver, and it's the D3D layer that tries and fails to create the default pool texture - the driver just sees that there's no texture bound in that stage and carries on to check other things.

Unfortunately, the only other function I can see that creates the default pool copy is IDirect3DResource9::PreLoad - which is also a void function, so there's no way to tell if it fails from there.

The only suggestion I have is creating the volume texture in the default pool yourself, thus bypassing the resource manager completely. That looks like the only way to get this working - CreateVolumeTexture will fail if the texture can't be created in the default pool.

Share this post


Link to post
Share on other sites
Steve's idea of creating the texture in default memory is good. I think you don't have to keep it there, either. You can create it, if creation fails scale it and create again, until you succeed. Then delete it and recreate as managed. As long as you don't create any default pool resources after that, I think things should work.

Another idea you can try is using a dynamic texture. There's a chance that'd be streamed directly from system RAM, instead of fully loaded onto the card, and therefore work (although more slowly than an on-card texture). That could allow you to use a larger texture than would fit on the card. It'd still be in the default pool, and therefore suffer from not being managed by Direct3D.

Last idea is to split that texture. Since I don't know how you use it, I can't tell if that's practical, but if you're only using a subset of the "frames" each frame and your shader will be able to access all you need even if they're not all in one texture, then splitting into several textures with different frames (with overlap, if necessary to get it to work right) will mean that you'll have smaller textures than Direct3D's texture management could work with, loading the ones you need.

BTW, as mentioned in another thread on the subject, reading "Resource Management Best Practices" in the DX docs is a good idea. Won't help greatly with your situation, but if you haven't read it, it's good material.

Share this post


Link to post
Share on other sites
Thank you guys for your replies.

I will try to create texture using D3DPOOL_DEFAULT and will see what happens. The workaround I've implemented for now is to make a screenshot of the rendering panel and to analyze it's background. I know that background must be black but when rendering fails it turns white or other color. If I see that scene background is not black I perform scaling and recreate it. I know it might seem the ugliest solution ever but at least in this case user will still be able to see the volume instead of blank white scene.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this