PDA

View Full Version : [D3D] Converting TBitmap to Direct3dTexture8



chronozphere
05-05-2006, 04:17 PM
Hi guys. 8)

What is the best/easiest way to convert a TBitmap to a Direct3dTexture8 object. I prefer to store the texture in D3DPOOL_DEFAULT.

And is there a way to convert it back to a TBitmap.

Thanx in advance. ;)

cronodragon
13-10-2006, 03:36 AM
Hi! I use this function in DX9 (maybe there is a version in DX8):


D3DXCreateTextureFromFileInMemory
Creates a texture from a file in memory.

HRESULT D3DXCreateTextureFromFileInMemory(
LPDIRECT3DDEVICE9 pDevice,
LPCVOID pSrcData,
UINT SrcDataSize,
LPDIRECT3DTEXTURE9 * ppTexture
);


I have used it to load bitmap files, but I think you could save the bitmap to a memory stream instead of a file stream, and use this function.

For me it's very useful since I can read bitmaps from disk and network... but I have found it's not thread safe. It seems that if the texture is too big it will be left for later conversion, and there is no way to know when the texture is ready :x The only way around is waiting some time.

tpascal
13-10-2006, 05:16 PM
You can create a empty dx texture and then get a pointer to the texture surface so you can read/write directly the pixels:

//-------
var
texture:IDirect3DTexture8; //dx texture.
B:tbitmap; //bitmap.
rrect: tD3DLOCKED_RECT; //for lock a rectangular surface in the texture.
.
.
//create a empty texture with the dimension and parameters we want:
D3DDEV8.CreateTexture( b.width,b.height,1,0, D3DFMT_A1R5G5B5, D3DPOOL_MANAGED, texture)); //change D3DFMT_A1R5G5B5 for the pixel format you want.

//Lock and get texture surface object

Texture.LockRect(0, rrect, Nil, 0);

//Now you can read/write texture pixels accesing the surface pointer found at "rrect.pBits".

//put bitmap pixels, P is a pointer to the bitmap pixels.

Move(p^, rrect.pBits^, blocksize);

Texture.UnlockRect(0); //it is very important to unlock when we are done.

//---------------------------------

For get a TBitmap pixels in delphi I use Tbitmap.ScanLine[Row] which return a pointer to that row of pixels; i normally do a loop for get tbitmap pixels row by row.

Be sure bitmap pixel format is the same as teh texture pixel format used when created;

Note that in some olds videocards Dx textures width/height must have to be power of two; also is a god advice to querry the videocard maximun texture size allowed (old videocard acept max 512x512 texture sizes), using the CAPs from D3DDEV8.


good luck.

tp.

cronodragon
13-10-2006, 05:21 PM
Having things on D3DPOOL_MANAGED is not recomended for optimization, since there are two copies that will be maintained, one in system memory and another in D3DPOOL_DEFAULT pool. This results in a redundant memory copy operation that consumes CPU time and wastes memory bandwidth.

tpascal
13-10-2006, 06:07 PM
Having things on D3DPOOL_MANAGED is not recomended for optimization, since there are two copies that will be maintained, one in system memory and another in D3DPOOL_DEFAULT pool. This results in a redundant memory copy operation that consumes CPU time and wastes memory bandwidth.


Your post sound like D3DPOOL_MANAGED should not be used at all becouse it is a "waste" of memory and bandwidth.

But actually i think that is the preffered way; check this webite about a explanation about dx resources:

http://www.toymaker.info/Games/html/d3d_resources.html

D3DPOOL_MANAGED has two great adventage:- You can get a pointer to acces directly the texture surfaces (so you can read/write on in which is the point of this original tread question.) and also you dont need to recreate the textures when the device got "lost"; not necesarry it is always that easy to load again the textures from disk, textures could have been stored in resources game data files where one have to parse the file to gent into the texture chunk, etc; so that is why not always people is using "LoadTextureFromFile" but they need a way to load texture from memory coze teh texture data got there in a different way.

Of course, if for your app all your textures can be loaded using "LoadTextureFromFile" and you never need to get acces to it then D3DPOOL_DEFAULT is your best choice.


tp.

cronodragon
13-10-2006, 06:39 PM
No, I'm just taking that information from a document of ATI about optimizations in DX9:

http://www.ati.com/developer/dx9/ATI-DX9_Optimization.pdf

That's why it's *not recommended*, doesn't mean that it shouldn't be used at all. And as you pointed out that's the method to lock the texture.

In my opinion if the texture is going to be updated in a single batch, it's better using D3DXCreateTextureFromFileInMemory. Working with .bmp files in memory is easy with Delphi's class TBitmap.

Just take that in mind when doing optimizations.

tpascal
13-10-2006, 07:55 PM
Hey, thank you for the link, very useful info there; hope those advices found there are not exclusivily for ATI cards.

Just for the record, the part you quoted is from page 7 but it refer about index and vertex buffers creations:



Buffers Creating efficient vertex and index buffers Dynamic vertex and index buffers always have to be created in D3DPOOL_DEFAULT memory pool. If they are allocated in D3DPOOL_MANAGED memory pool, two copies of the buffers will be maintained – one in the system memory and another in D3DPOOL_DEFAULT pool. Whenever a managed buffer is locked and written to, the application gets a pointer to system memory copy, which will be copied to D3DPOOL_DEFAULT pool buffer instance once the buffer is unlocked. This results in a redundant memory copy operation that consumes CPU time and wastes memory bandwidth.


Wich i am agree, for a game your are rendering your scene several frames per second sending your triagles to your vertex/index buffers (writing), so if they where created in managed pool then two copies of your rendering scenes are happening one in system memory and another one in card memory; and i dont see the point to get able to edit the system memory scene buffer copy you just had rendered, people should send the already finished scene to the vertex/index buffer in first place.

But that is not the case for managed pool created textures; when you render your scene the texture data used is the one already stored in card memory, the copy from system memory is not used just becouse your are rendering triangles, the texture system memory is copied to card memory only when you lock (edit the texture), for changing the pixels (if you are doing that every frame then that is another History); so if you use D3DPOOL_MANAGED for create your texture for load the data manually just one time when your application start then you will not get any perfomance penalty when rendering scenes and you will get the adventage of not having to recreate the texture when the device gets lost.

cronodragon
13-10-2006, 08:03 PM
But, a second copy in system memory might not be necessary in all cases, specially if just loading the texture once. In such case, it would be better the method to load directly.

Another case is when the texture is modified unfrequently, why having a backup copy all the time? Then it would be better to create a TBitmap just when needed and passing it with a memory stream to the method that loads files in memory.

And textures and vertex buffer can be restored manually, instead of relying on DX... but, anyway, it's a matter of optimization that must be adjusted to every specific case. :D

tpascal
13-10-2006, 09:56 PM
Nice debate huh, :lol:



But, a second copy in system memory might not be necessary in all cases, specially if just loading the texture once. In such case, it would be better the method to load directly.


Ok, I just want to be clear that i am not saying the people should alway have to create textures in managed pool, using default pool or managed pool mostly depend on what you say "a second copy in system memory might not be necessary in all cases", if you never need a secound copy or if you preffer to have your own second copy in tbitmaps object, if you never need to make changes in the texture or if you dont have any problem re-loading the data from file or from stream when the device is lost then YES, you dont need a secound copy and dont use managed pool.

But i am going to tell you why most the time I dont use loadtexturefromFile / loadtexturefromstream / loadtexturefromresource etc, myself, not becouse there is somthing wrong, it is just becouse it only works for the picture fileformat (with header) it is supported in the function; but how about when the texture is a format not supported?, there are several cases when you need to define and put manually the pixels into dx textures..if the texture is in some compressed way (ziped, zlib) or in format not supported by default.

When I learned Directx was becouse i was needing to do a Mod tools for a popular game called Tomb Raider, where for every level/stage in the game there is one big file of about 6-10MB, where it is stored all models, animations, texures, triggers, characters sounds, lighting objects, world geometry, etc.etc, so every chunk have to be parsed to get to the next chunk, for the texture chunk you dont get several bmp files embeded, no, no,no, you get a big raw pixels data with not heading in the format of 5,5,5,1 bits per pixel (rgba in 16 bits); later in anothers chunk is found a special table of texture description where tells the fragments into that raw data. So the way I put those textures in dx is using a function where i can pass a memory pointer for the fragment raw data and defining manually the pixel format and block size for every texture;

For some games and real projects (even yours) you dont always going to have different 4000 bmps (or whatever) textures files for been loaded one by one, and neither you are not going to have one big bmp of 512x2340480 size file in disk for been loaded in just one dx texture; neither your want to have all textures loaded in memory all at the same time, so in those cases you will want to be able to open your texture data resource, and gets able to define needed textures passing memory block chunks; heck even some people uses a texture memory manager that uses cached textures and release textures not used or not longer needed in that stage of the game etc;

sorry for the rant.

see ya

tp.


Ps.
In case you are wondering about my Tomb raider Mod tool: www.dxtre3d.com

cronodragon
13-10-2006, 10:17 PM
That's right, you have more control over the format of the texture (structure and color depth), but on the other hand that's something most people just escape from. In all the examples about locking textures I've seen people use only one format, usually the ARGB, which is faster to use, and so they don't have to mess with the bits. So is a power that is simply wasted because it is impractical to write the same image processing routine for several formats at the same time.

And, TBitmap could be inherited to create any customized formats... unfortunately the ScanLine[] property of TBitmap isn't implemented in TGraphic, making it harder to read JPG, PNG, and other thrid party graphic format classes out there. But that doesn't stop anyone from working with other formats with TBitmap.

Your editor is very cool! I'm creating one that is similar (based on box elements), but is simplier. I have to make a new version with the enhancements I'm doing in my game engine.

http://www.teleportmedia.com/imagenes/contenido/rwbuilder.jpg

I made an algorithm to create those box elements using only 12 parameters to define the shape of the box. The idea is to create those boxes from code too.

Clootie
13-10-2006, 10:39 PM
Just wanted to add: in whole your discussion you are treating video memory as "infinite". But what will happen when you try to create too many textures in POOL_DEFAULT? Hint: it will fail, but MANAGED textures will be created and D3D runtime will guarantire what managed textures will always be usable by applicaiton and in any time.

I mean if you want to manage textures by yourself - it's fine. But you should be aware about much more stuff in exhange of smallter application memory footprint. But if you limited by system memory - most probably all your system copies of manages textures will be flushed to swap file after some time - so they will not reduce perfromance in any way.

tpascal
14-10-2006, 12:51 AM
Ok, what i am going to say is just a technique that some people could found useful, it is not a "the best and only way" to works with texture data; and even it is not needed if your app/game dosent use big amount textures memory.


You are right, in games once the texture is loaded is not needed to read the pixels back to memory, Ok then, but i still have the problem how to put in dx the textures when they are not stored in individual files, you see, for my game i have about 15 levels/stages, for stage 1 i have about 30 512x512 textures pages for my world geometry, I am using lightmaps so i have anothers 25 512x512 textures pages for lightmaps, i am also using bump maps in some textures so i also have 20 more 512x512 textures pages with dot3 pixels data for doing bumpmap effect, this es just for the world geomwtry, but I also have about 30 textures pages for Models (characters, baddies, weapons, pickables etc), I also have about 15 textures pages for things likes skybox, particles (fire, spark, snow, rain) animated textures etc, an finally i have about 10 more textures pages for 2d stufs like fonts, message boxes, icons, etc;...and there is another set textures package like that for next level/stage in the game, so do you think is a good idea to have every 512x512 texture page i need in a individual file disk?, i would preffer to put all this well ordered by stage in one texture resource file.

It is not the same to destroy and then read 130 or more textures files one by one from disk than instead keeping opened one texture resource file and read in memory in one operation one chunk of 130*256*256*pixelsize bytes; and then update the 130 dx textures from that block memory. If you need to load several textures every time the user uses ALT+TAB from switch from application (so the device was lost) or you character go forward/backward between stages so you need to load another set of textures then destroying and loading one by one from disk is very noticiable.



And, TBitmap could be inherited to create any customized formats... unfortunately the ScanLine[] property of TBitmap isn't implemented in TGraphic, making it harder to read JPG, PNG, and other thrid party graphic format classes out there. But that doesn't stop anyone from working with other formats with TBitmap.


I am using a free units called graphicsEX, when included in your Units clause then the Timage class is expanded for open much more file formats, like tga,png,jpg,pcx,psp, etc, then i can use:

var
I:timage;
a:bitmap;
.
.

i:=timage.create(sender);
i.loadfromfile('mytexture.psp');
a.bitmap:=tbitmap.create;
a.PixelFormat:=pf24bit;
a.bitmap.width:=I.Picture.Graphic.Width;
a.bitmap.Height:=I.Picture.Graphic.Height;
a.Canvas.Draw(0,0,I.Picture.Graphic);
i.free;

That way wahtever file format in whatever color depth was opened is converted into a tbitmap in 24 bits color format.

of course this is only for my tools, so the user can create content using what ever picture file format they want, but when i compile the content in the playable game data I always save it for my required game engine texture, which is raw rgba headerless data, most the time in 16 bits color coze i dont have lastest top noch ATI videocard that run faster with 32 bits dept color data.




I made an algorithm to create those box elements using only 12 parameters to define the shape of the box. The idea is to create those boxes from code too.


hey, somthing like that i am doing too, drawing the world using some kind parameterized boxes, the geometry will looks kind "cubic" but it will help me a lot to do faster and acurate collision, coz for at every position my characters is located I can easily know in what Box with what parameter it is collisionating; :-) i am not ready yet to use those phisics engine from today for checking colision against a soup of triangles.

It is your editor for a 3d engine?, what kind of world partioned technque are you using?, BSP, Portals, octrees etc?, do you have a bigger picture of your editor? :-), it looks very very very nice.



[quote]
But what will happen when you try to create too many textures in POOL_DEFAULT?
[\quote]

Hey Clotie, i was thinking POOL_Default mean "keep just one copy in whatever place is currently best, in videomemory if there is available or in system memory if not videomemory available"; i did not know that the resource creation can fail if there is not video memory available when POOL_Default was used.

cronodragon
14-10-2006, 03:54 PM
But what will happen when you try to create too many textures in POOL_DEFAULT?

Hey Clotie, i was thinking POOL_Default mean "keep just one copy in whatever place is currently best, in videomemory if there is available or in system memory if not videomemory available"; i did not know that the resource creation can fail if there is not video memory available when POOL_Default was used.

I thought the same. But I think Clootie is right, DX help says: "Resources are placed in the memory pool most appropriate for the set of usages requested for the given resource. This is usually video memory, including both local video memory and AGP memory. The D3DPOOL_DEFAULT pool is separate from D3DPOOL_MANAGED and D3DPOOL_SYTEMMEM, and it specifies that the resource is placed in the preferred memory for device access. Note that D3DPOOL_DEFAULT never indicates that either D3DPOOL_MANAGED or D3DPOOL_SYSTEMMEM should be chosen as the memory pool type for this resource."

By the way, D3DXCreateTextureFromFileInMemoryEx also has a lot of interesting parameters that could be very helpful:


HRESULT D3DXCreateTextureFromFileInMemoryEx(
LPDIRECT3DDEVICE9 pDevice,
LPCVOID pSrcData,
UINT SrcDataSize,
UINT Width,
UINT Height,
UINT MipLevels,
DWORD Usage,
D3DFORMAT Format,
D3DPOOL Pool,
DWORD Filter,
DWORD MipFilter,
D3DCOLOR ColorKey,
D3DXIMAGE_INFO * pSrcInfo,
PALETTEENTRY * pPalette,
LPDIRECT3DTEXTURE9 * ppTexture
);

For example, Width and Height allows you to define the final size of the texture. This is helpful to optimize texture depending on the capacity of the graphic device.


It is your editor for a 3d engine?, what kind of world partioned technque are you using?, BSP, Portals, octrees etc?, do you have a bigger picture of your editor? Smile, it looks very very very nice.

I'm making a 3D/2D engine, and I'm using it to make this editor. But the editor is part of another project, that is an RPG maker. The camera view is the usual top-down view of RPGs, so the partition might be by map sections. First I have to make a new version to integrate months of additions to the engine, i.e. I'm not using Delphi's VCL anymore, instead I made a GUI system that can be customized. I will take some larger screenshots when I have the new version, which I think will be much better in many ways.

Thanks for the information about GraphicEx. I'll check it out.

Clootie
15-10-2006, 01:36 PM
Good article about resource creation flags: Resource Management Best Practices @ MSDN (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/Resource_Management_Best_Practices.asp)

There is another interesting flag for D3DXCreatetexture: D3DX_SKIP_DDS_MIP_LEVELS. It can be used to skip mip levels when loading a DDS file: D3DX_SKIP_DDS_MIP_LEVELS(levels, filter: DWORD). So on cards with low amount of video memory you can just pass something like D3DX_SKIP_DDS_MIP_LEVELS(2, D3DX_FILTER_BOX) to load mipmap levels (or automatically generate them if not available) only from 3-rd one and up.