Sign in to follow this  
MMoi

[D3DM] Texture and memory

Recommended Posts

Hi all, this is my first post on the GameDev forums, so first of all... nice to meet you ! After quite a long time using the resources and articles on this site, a problem drove me to register on few of the best dev community sites, in my quest for information (which is quite tricky to find when you work on windows mobile). the problem In my 3d engine, each texture creation reserves 3 times the space it should need in memory. Hypotheses - 3d engine based on Loulou's YesEngine (here, in French : http://loulou.developpez.com) - Runs on Windows Mobile 6.1 with Direct 3d Mobile (D3D subset) - Windows Mobile is much restrictive concerning virtual memory (32MB against desktop's 2GB), so the heap is full pretty fast. 1st step: texture creation
	IRscTextureBase* GDirect3DMRenderer::CreateTexture(const TVector2I& Size, TPixelFormat Format, unsigned long Flags) const
	{
		// mip level detection and auto creation detection
		bool HasMipmaps  = (Flags & TEX_NOMIPMAP) != 0;

		bool AutoMipmaps = false;		// no auto mipmaping on D3DM
		unsigned long Usage = m_SurfCaps_Texture;		// let the texture be locked

		// create texture
		LPDIRECT3DMOBILETEXTURE Texture = NULL;
		HRESULT hr;
		if ( FAILED ( hr = D3DMXCreateTexture(m_Device, Size.x, Size.y, 0, Usage, CD3DMEnum::Get(Format), m_SurfCaps_Pool, &Texture) ) )		
			throw CD3DMException(_T("D3DXCreateTexture"), _T("CreateTexture"));

		return new CD3DMTexture(Size, Format, HasMipmaps, AutoMipmaps, Usage, Texture);
	}
D3DMXCreateTexture reserves memory space (ok), but new CD3DMTexture (simple object to encapsulate my D3DM texture) does the same ! We exit the function with 2 spaces reserved in memory instead of one. reference :
class CD3DMTexture : public IRscTextureBase
    {
    public :
        CD3DMTexture(const TVector2I& Size, TPixelFormat Format, bool HasMipmaps, bool AutoMipmaps, unsigned long Usage, IDirect3DMobileTexture* Texture);

		// GET D3D TEXTURE
		IDirect3DMobileTexture* GetDxTexture() const;

    private :
		// UPDATE PIXELS
        virtual void Update(const CRectangle& Rect);

        // COPY PIXELS TO LOCKED SURFACE
        void UpdateSurface(const D3DMLOCKED_RECT& LockedRect, const CRectangle& Rect);

        // DATA
		CSmartPtr<IDirect3DMobileTexture , CResourceCOM > m_Texture;		// D3D texture pointer
		unsigned long m_Usage;
    };

// constructor implementation
CD3DMTexture::CD3DMTexture(const TVector2I& Size, TPixelFormat Format, bool HasMipmaps, bool AutoMipmaps, unsigned long Usage, IDirect3DMobileTexture* Texture) :
IRscTextureBase(Size, Format, HasMipmaps, AutoMipmaps),
m_Usage		(Usage),
m_Texture   (Texture)
{
}
2d step : texture update A lot of devices (let's say Omnia) don't allow texture locking, thus we're forced to use surface locking, and then copy pixels from one surface to another... as follows :
void CD3DMTexture::Update(const CRectangle& Rect)
{
    Assert(CRectangle(0, 0, m_Size.x, m_Size.y).Intersects(Rect) == INT_IN);

	if (m_Format == m_Data.GetFormat() && (m_Usage & D3DMUSAGE_LOCKABLE) )		// if pixel format is the same, simple copy (if texture lockable)
    {
        // lock texture
        D3DMLOCKED_RECT LockedRect;
        RECT Lock = {Rect.Left(), Rect.Top(), Rect.Right(), Rect.Bottom()};
        m_Texture->LockRect(0, &LockedRect, &Lock, 0);	

        // copy pixels
        UpdateSurface(LockedRect, Rect);

        // unlock texture
        m_Texture->UnlockRect(0);
    }
    else
    {
        // get device
		CSmartPtr<IDirect3DMobileDevice, CResourceCOM> Device;
        m_Texture->GetDevice(&GetPtr(Device));

        // create texture in memory
		CSmartPtr<IDirect3DMobileSurface, CResourceCOM> Src;
		HRESULT res = Device->CreateImageSurface(Rect.Width(), Rect.Height(), CD3DMEnum::Get(m_Data.GetFormat()), &GetPtr(Src));		
		if (FAILED(res))		// CreateOffscreenPlainSurface not available in D3DM 
		{
            throw CD3DMException(_T("CreateImageSurface"), _T("CD3DMTexture::Update"));
		}

        // lock temp texture
        D3DMLOCKED_RECT LockedRect;
        Src->LockRect(&LockedRect, NULL, 0);

        // copy pixels
        UpdateSurface(LockedRect, Rect);

        // unlock texture
        Src->UnlockRect();
        // get 0 level surface of the texture
		CSmartPtr<IDirect3DMobileSurface, CResourceCOM> Dest;
        m_Texture->GetSurfaceLevel(0, &GetPtr(Dest));
		
        // copy to destination surface
        RECT DestRect = {Rect.Left(), Rect.Top(), Rect.Right(), Rect.Bottom()};
        if (FAILED(D3DMXLoadSurfaceFromSurface(Dest, NULL, &DestRect, Src, NULL, NULL, D3DMX_DEFAULT, 0)))
            throw CD3DMException(_T("D3DXLoadSurfaceFromSurface"), _T("CD3DMTexture::Update"));			
    }
}
Src surface reserves the space needed during CreateImageSurface, then free it when we exit the brackets where it's defined (thanks smart pointer). However, Dest does also a reservation about the same size during D3DMXLoadSurfaceFromSurface... but doesn't release it when the smart pointer is freed ! Conclusion We have 3 times the needed space reserved by a texture, that other components of the program won't be able to use. With 32MB of virtual memory, I guess you already figured how painful it may be ! There shall be some stuff I messed up, or maybe is it due to the implementation of the YesEngine (encapsulating the D3D texture for instance ?) creating some conflict with D3DM data types... anyway... Help ! Thanks for your help, may you be WM developer or not (it's after all only a subset of Windows API and DirectX ;) ) ps: see here for more information about the well named "WM virtual memory monster" (and thanks a lot to it's author) http://www.codeproject.com/KB/mobile/VirtualMemory.aspx edit : did I messed up with the "code" markup ? :( [Edited by - MMoi on August 18, 2009 7:00:56 PM]

Share this post


Link to post
Share on other sites
Hello, and welcome to GDNet!

1: What is the value of m_SurfCaps_Pool when you create the texture? In particular, is it D3DPOOL_MANAGED (or mobile equivalent)?

2: You don't seem to release the "Src" surface in your Update method. This will linger in memory until you exit the app. EDIT: Missed the smart pointer.

As for the code formatting, see the forum faq. I recommend using the [ source ] tags to keep your code in nice scrollable boxes.

Share this post


Link to post
Share on other sites
You haven't posted the CD3DMTexture constructor code, so I can't tell if there's a reason it's allocating more memory or not.

At the end of CD3DMTexture::Update it looks like you're adding a reference to the dest texture, by calling GetSurfaceLevel twice but only releasing once.

Share this post


Link to post
Share on other sites
Thanks for your replies :)

Nik02 :
- m_SurfCaps_Pool is D3DMPOOL_SYSTEMMEM on my device (neither D3DMPOOL_MANAGED nor D3DMPOOL_VIDEOMEM are available on this device).

Thanks for the source formatting.. i'll edit that.

ET3D :
- sorry I'll add it right away in the first post... pretty simple constructor, though. Note that even if I take off the m_Texture part of this constructor, it still reserves space in the memory.

- sorry for the last part of the code... it's one of my numerous tests I forgot to get rid with when posting. I was trying to get the surface again, so it would maybe point on the lastly reserved space, and then force the release... no effect, still. I'll delete that irrelevant part.

Share this post


Link to post
Share on other sites
If you have confirmed beyond any doubt that your code isn't causing leaks (allocating but not releasing), the driver or firmware might have a bug. Obviously, there's very little you can do if this is the case, other than giving the device manufacturer a report and waiting for them to act on it.

It is not rare that computer firmware or driver have bugs. This is even more true in case of mobile devices, where the act of writing drivers isn't as straightforward as for desktop machine hardware.

That said, usually the device manufacturers do their best to screen out the bugs with biggest impact to app developers before they ship. This is why statistically the error is usually in the application code rather than driver/firmware.

Share this post


Link to post
Share on other sites
Ok, thanks for the answer. Thus I gonna try as following

- Create a small sample program to check if the same problem occurs without DLLs and stuffs around

- Try to use this test program on a Sony Xperia (the problem is that the Xperia D3DM driver is really poor - no Z Buffer support for instance ! - so I have to take time for caps adaptation)

- If the 1st doesn't work properly but the second does, I'd send a request to Samsung.

Thanks for your answer, I'll give some report about this problem later (may help someone one day)

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