Results 1 to 13 of 13

Thread: Can anyone help me? Baffling tech problem.

  1. #1
    Senior Member
    Join Date
    Jul 2004
    Posts
    804

    Default Can anyone help me? Baffling tech problem.

    Hi Everyone,

    Years ago when XP came out, Hamsterball manifested a bizarre load error, only on XP. The problem manifested during texture load-- I am using the pure DirectX helper code to load images, and somehow it bombs out.

    After tweaking it a bit, I fixed it so it didn't happen on XP any more and all was well.

    However, now it's happening on Vista. Same problem, same place. My problem is, it only happens on SOME Vista, and, not any copy of Vista I try it on.

    This is a bit of a desperation move, but I hoped if I posted the code here, some DirectX guru could look at it and suddenly say, hey, you're not supposed to use that function in that way.

    So here's the code. If I eliminate the mipmap stuff, it seems to work fine. With mipmaps, it will return DX errors (and give the user a "can't load texture") frequently. And the error is always DX_ERR_UNKNOWN.

    Any help gets you a free copy of your choice of Raptisoft game, including the next one.

    Here's the code:


    Code:
    Texture::Texture(Graphics *theGraphics, char *theFilename)
    {
    	mGraphics=theGraphics;
    	mHasAlpha=false;
    	mHasMip=false;
    	mPointFilter=false;
    
    	mTexture=NULL;
    	mFilename=NULL;
    
    	char aFilename[MAX_PATH];
    	char aPath[3][MAX_PATH];
    
    	sprintf(aPath[0],"textures\\");
    	sprintf(aPath[1],"");
    	sprintf(aPath[2],"");
    
    	if (mGraphics->mSubstituteDirectory)
    	{
    		sprintf(aPath[0],"%s\\",mGraphics->mSubstituteDirectory);
    		sprintf(aPath[1],"textures\\");
    	}
    
    	int aStartPath=0;
    
    	//
    	// Look for a mipmap version of the texture...
    	// if no -mip1 file exists, then it's just 'alone'
    	//
    
    	bool aFound=false;
    	bool aFoundMip=false;
    
    	char aMipFilename[MAX_PATH];
    	char aMipExtension[MAX_PATH];
    	strcpy(aMipFilename,theFilename);
    	for (int aCount=0;aCount<strlen(aMipFilename);aCount++)
    	{
    		if (aMipFilename[aCount]=='.')
    		{
    			strcpy(aMipExtension,&aMipFilename[aCount+1]);
    			aMipFilename[aCount]=0;
    		}
    	}
    
    	for (int aCount=0;aCount<3;aCount++)
    	{
    		sprintf(aFilename,"%s%s-mip1.%s",aPath[aStartPath],aMipFilename,aMipExtension);
    		if (access(aFilename,0)==0) aFoundMip=true;
    
    		sprintf(aFilename,"%s%s",aPath[aStartPath],theFilename);
    		if (access(aFilename,0)==0)
    		{
    			aFound=true;
    			break;
    		}
    
    		aStartPath++;
    		if (aStartPath>3) aStartPath=0;
    	}
    
    
    	//
    	// Okay: We crash here.  We crash on CreateTextureFromFileA, when we have a widescreen
    	// monitor.  Why is this?  This is BULLSHIT.
    	//
    
    	HRESULT aResult=D3DXCreateTextureFromFileA(mGraphics->mDevice,aFilename,&mTexture);
    	if (FAILED(aResult)) 
    	{
    		aResult=D3DXCreateTextureFromFileA(mGraphics->mDevice,aFilename,&mTexture);
    		if (FAILED(aResult)) 
    		{
    			switch (aResult)
    			{
    			case D3DERR_NOTAVAILABLE: gOut.Out("D3DERR_NOTAVAILABLE");
    			case D3DERR_OUTOFVIDEOMEMORY: gOut.Out("D3DERR_OUTOFVIDEOMEMORY");
    			case D3DERR_INVALIDCALL: gOut.Out("D3DERR_OUTOFVIDEOMEMORY");
    			case D3DXERR_INVALIDDATA: gOut.Out("D3DXERR_INVALIDDATA");
    			case E_OUTOFMEMORY: gOut.Out("E_OUTOFMEMORY");
    			}
    
    			MessageBox(0,theFilename,"TEXTURE LOAD FAILED!",MB_OK);
    			mTexture=NULL;
    		}
    	}
    
    	D3DFORMAT aFormat;
    	if (mTexture!=NULL)
    	{
    		D3DSURFACE_DESC aDesc;
    		mTexture->GetLevelDesc(0,&aDesc);
    
    		aFormat=aDesc.Format;
    	
    		switch (aDesc.Format)
    		{
    		case D3DFMT_A8R8G8B8:
    		case D3DFMT_A4R4G4B4:
    		case D3DFMT_A8R3G3B2:
    			mHasAlpha=true;
    			break;
    		}
    		mWidth=aDesc.Width;
    		mHeight=aDesc.Height;
    	
    		mFilename=new char[strlen(theFilename)+1];
    		strcpy(mFilename,theFilename);
    		mReference=1;
    	}
    
    	mMipCount=0;
    	if (aFoundMip)
    	{
    		//
    		// Buggy?
    		// We seem to have a load problem that *seems* to be mipmap related.
    		// It's very weird.  Checking into it.  At the moment, it looks like
    		// leaving out the mipmaps just makes things magically work.
    		//
    
    
    
    
    		//
    		// Okay... we found mipmaps!
    		// So, we're gonna make a new texture, first,
    		// just to see if we can...
    		//
    		mTexture->Release();
    		mTexture=NULL;
    
    		D3DXCreateTextureFromFileA(mGraphics->mDevice,aFilename,&mMip[0]);
    		int aMipLevels=1;
    		for (int aCount=1;aCount<20;aCount++)
    		{
    			char aMipFN[MAX_PATH];
    			sprintf(aMipFN,"%s%s-mip%d.%s",aPath[aStartPath],aMipFilename,aCount,aMipExtension);
    			if (access(aMipFN,0)==0)
    			{
    				HRESULT aResult=D3DXCreateTextureFromFileA(mGraphics->mDevice,aMipFN,&mMip[aCount]);
    				if (FAILED(aResult))
    				{
    					HRESULT aResult=D3DXCreateTextureFromFileA(mGraphics->mDevice,aMipFN,&mMip[aCount]);
    					if (FAILED(aResult))
    					{
    						switch (aResult)
    						{
    						case D3DERR_NOTAVAILABLE: gOut.Out("D3DERR_NOTAVAILABLE");
    						case D3DERR_OUTOFVIDEOMEMORY: gOut.Out("D3DERR_OUTOFVIDEOMEMORY");
    						case D3DERR_INVALIDCALL: gOut.Out("D3DERR_OUTOFVIDEOMEMORY");
    						case D3DXERR_INVALIDDATA: gOut.Out("D3DXERR_INVALIDDATA");
    						case E_OUTOFMEMORY: gOut.Out("E_OUTOFMEMORY");
    						}
    			
    						MessageBox(0,theFilename,"TEXTURE LOAD FAILED!",MB_OK);
    						mTexture=NULL;
    						return;
    					}
    				}
    				aMipLevels++;
    			}
    			else break;
    		}
    
    		HRESULT aResult=theGraphics->mDevice->CreateTexture(mWidth,mHeight,aMipLevels, 0,aFormat, D3DPOOL_MANAGED, &mTexture);
    		if (FAILED(aResult))
    		{
    			aResult=theGraphics->mDevice->CreateTexture(mWidth,mHeight,aMipLevels, 0,aFormat, D3DPOOL_MANAGED, &mTexture);
    			if (FAILED(aResult)) 
    			{
    				switch (aResult)
    				{
    				case D3DERR_NOTAVAILABLE: gOut.Out("D3DERR_NOTAVAILABLE");
    				case D3DERR_OUTOFVIDEOMEMORY: gOut.Out("D3DERR_OUTOFVIDEOMEMORY");
    				case D3DERR_INVALIDCALL: gOut.Out("D3DERR_OUTOFVIDEOMEMORY");
    				case D3DXERR_INVALIDDATA: gOut.Out("D3DXERR_INVALIDDATA");
    				case E_OUTOFMEMORY: gOut.Out("E_OUTOFMEMORY");
    				}
    	
    				MessageBox(0,theFilename,"TEXTURE LOAD FAILED!",MB_OK);
    				mTexture=NULL;
    				return;
    			}
    		}
    
    		IDirect3DSurface8 *aDest[20];
    		IDirect3DSurface8 *aSrc[20];
    
    		for (int aCount=0;aCount<aMipLevels;aCount++)
    		{
    			aDest[aCount]=NULL;
    			aSrc[aCount]=NULL;
    
    			mTexture->GetSurfaceLevel(aCount,&aDest[aCount]);
    			mMip[aCount]->GetSurfaceLevel(0,&aSrc[aCount]);
    
    			D3DSURFACE_DESC aDesc;
    			mTexture->GetLevelDesc(aCount,&aDesc);
    
    			//
    			// A note to myself:
    			// Putting a rect into CopyRects, instead of just using the
    			// null pointer that's supposed to indicate 'copy the whole surface'
    			// seems to have cleaned up the vista crash.  We'll see how it pans out.
    			//
    
    			RECT aSrcRc={0,0,aDesc.Width,aDesc.Height};
    			POINT aDestPt;
    			aDestPt.x=0;
    			aDestPt.y=0;
    
    			HRESULT aResult;
    			if (aSrc[aCount] && aDest[aCount]) 
    			{
    				aResult=theGraphics->mDevice->CopyRects(aSrc[aCount],&aSrcRc,1,aDest[aCount],&aDestPt);
    				if (!SUCCEEDED(aResult)) 
    				{
    					char eString[256];
    					D3DXGetErrorString(aResult,eString,255);
    					gOut.Out("Error %s [%d,%d]*******************************************************",eString,aDesc.Width,aDesc.Height);
    
    				}
    			}
    		}
    
    		mHasMip=true;
    		mMipCount=aMipLevels;
    	}
    
    }
    As you might be able to tell from the comments, I have made a couple 'fixes' that seemed to fix the problem (passing NULL pointers to D3DX code seemed to irritate Vista, for instance)... but none of them fix it completely.

    Thanks again, anyone who can help.

  2. #2
    Moderator
    Join Date
    Jul 2004
    Posts
    3,898

    Default

    Intel video cards maybe? I trace most of my DX_ERR_UNKNOWN returns to intel video card drivers coded by blind monkeys.

  3. #3
    chillypacman
    Guest

    Default

    Quote Originally Posted by cliffski View Post
    Intel video cards maybe? I trace most of my DX_ERR_UNKNOWN returns to intel video card drivers coded by blind monkeys.
    Intel cards have a habit of misreporting their capabilities to directx so it might be there.

    This is BULLSHIT.
    It's bullshit until you realize what's going wrong

  4. #4
    Senior Member
    Join Date
    Feb 2005
    Posts
    2,239

    Default

    I have a Vista laptop with Intel GMA X3100 graphics. PM me if you need anything testing.
    Dr Mal: Practice of Horror PC | Mac
    Crime Solitaire PC | Mac | iOS
    Magicville: Art of Magic PC | Mac
    Desktop Gaming Ltd | Facebook | YouTube | Twitter

  5. #5
    Senior Member
    Join Date
    Oct 2005
    Location
    Montreal, Quebec
    Posts
    812

    Default

    Possibly the driver (or the card, or both) isn't able to create mipmaps and is bombing out somewhere in the process. It's probably the blind monkey thing, as it should be able to create them but probably has a bug.
    "Don't lose your loose change."
    Jason Maskell, Tamed Tornado Software

  6. #6
    Senior Member
    Join Date
    Jul 2004
    Location
    Isle of Wight, UK
    Posts
    3,863

    Default

    A wild guess. It's crashing because internally the driver is reporting the back display buffer format has an alpha channel, which is not and never has been allowed.

    Note that this is not the same thing as the back buffer format. They added all that checkdeviceformat stuff to protect against this.

    It might be worth adding some debug code just to check this, but I'm not sure if you'll be able to do much about it if it is this.
    Regards,
    Paul Johnson

    [Great BIG War Game: iOS | Android] [Great Little War Game: iOS | Android] [Fruit Blitz: iOS | Android] [Yachty Deluxe: iOS | Android]

  7. #7
    Junior Member
    Join Date
    Feb 2006
    Posts
    6

    Default

    Quote Originally Posted by Raptisoft View Post
    Hi Everyone,

    So here's the code. If I eliminate the mipmap stuff, it seems to work fine. With mipmaps, it will return DX errors (and give the user a "can't load texture") frequently. And the error is always DX_ERR_UNKNOWN.
    A couple questions.

    1) What file format are you loading?

    2) If you can repro this (on someone else's machine), can you turn on d3d debug runtimes and capture the debug spew during texture creation. You might also try running the game under Pix for Windows on the repro machine to see the api calls that d3dx is making (and their result codes).

    3) Can you get the dxdiag output on the machine(s) that fail? Is it possibly a case of d3d devices that cannot create non-power-of-two mipmap chains?

    4) Which mip code do you remove to make it work?


    pb

  8. #8
    Junior Member
    Join Date
    May 2008
    Posts
    2

    Default

    Shot in the dark this....

    From the D3D docs on D3DXCreateTextureFromFile it mentions:

    "When loading images into mipmapped textures, some devices are unable to go to a 1x1 image and this function will fail. If this happens, the images need to be loaded manually."

    Calling D3DXCreateTextureFromFile is equivalent to calling:

    D3DXCreateTextureFromFileEx(pDevice, pSrcFile, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, ppTexture);

    I you look at the documentation for this function you'll notice that it passes in D3DX_DEFAULT to the miplevels parameter. This results in D3D trying to create a texture with full mip-chain down to 1x1. Which as the docs suggest can fail on some devices.

    So from your code, my guess would be either:

    1) You've run into a driver/device that are unable to go to a 1x1 image (as the docs suggests). This would imply you shouldn't attempt to create a full-mip chain and stop at 2x2, 4x4 etc instead.

    2) You run out of resource memory because each and every mip-image you are currently attempting to load is also telling D3D to allocate and create a full mip chain down to 1x1.

    If you are going to do manual mip-level loading yourself, then you're probably better off calling D3DXCreateTextureFromFileEx instead and pass in a 1 to the miplevels parameter, to ensure you're only allocating and creating a single mip-level.

    Cheers
    -Pete

  9. #9
    Senior Member
    Join Date
    Jul 2004
    Posts
    804

    Default

    Hm,

    I am intrigued by this mipmap thing... as far as I knew, I was creating them manually, and thus they'd never get down to 1x1... are you telling me that code is automatically making its own mipmaps? It doesn't SEEM to be-- if I delete the mipmap files from the texture folder, then the game's visuals are quite degraded and pixellized at a distance.


    --John

  10. #10
    Senior Member
    Join Date
    Jul 2004
    Location
    Isle of Wight, UK
    Posts
    3,863

    Default

    If you pass a zero in for the number of levels, it will create them even if they're empty waiting your data. It depends on how you're creating em.

    I would suggest working out the number of levels you really need based on their dimensions, then subtract 5 from that to stop them going below 32x32 which seems to be a magic numbers. Even X360 can't deal with smaller than that for some reason.
    Regards,
    Paul Johnson

    [Great BIG War Game: iOS | Android] [Great Little War Game: iOS | Android] [Fruit Blitz: iOS | Android] [Yachty Deluxe: iOS | Android]

  11. #11
    Junior Member
    Join Date
    May 2008
    Posts
    2

    Default

    When you call D3DXCreateTextureFromFile d3d is loading the image file and creating a texture of its size with a full mip-chain down to 1x1.

    You can verify this by calling GetLevelCount() on the resulting texture to tell you how many mip-levels have been created.

    Just for kicks I tried this out on the DXSDK/Samples/C++/Direct3D/Tutorials/Tut05_Textures sample. For the 256x256 banana texture you get 9 mip levels, i.e: 256x256, 128x128, 64x64, 32x32, 16x16, 8x8, 4x4, 2x2 and 1x1.

    If I replace the D3DXCreateTextureFromFile with a call to

    D3DXCreateTextureFromFileEx(
    g_pd3dDevice, "banana.bmp",
    D3DX_DEFAULT, D3DX_DEFAULT,
    1, // only 1 mip level please... if it's 0 or D3DX_DEFAULT - you get full mipchain
    0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, &g_pTexture);

    you only get 1 mip level.

    -Pete

  12. #12
    Senior Member
    Join Date
    Jul 2004
    Posts
    804

    Default

    Mips down to 1x1 was the problem.

    Petei, PM me if you want an unlock code.

  13. #13
    Senior Member
    Join Date
    Sep 2004
    Location
    London, UK
    Posts
    228

    Default

    Nice to see a new poster helping an oldie out I stay clear of Directx for the most part, but an interesting read nevertheless

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •