Jump to content
  • Advertisement
Sign in to follow this  
jazzboysc

[DX10]How to create a DX10 texture object from system raw data?

This topic is 2305 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi guys, I try to use D3DX10CreateTextureFromMemory() to create a DX10 texture from my system mem raw data(which is stored in my RGBA 4bytes unsgined char buffer). But the API always return failed.Seems like it only accepts an image file format in system memory(bmp,jpg,png...). So which API could I use to create a DX10 texture and upload my custom image data?

Share this post


Link to post
Share on other sites
Advertisement
Use the CreateTexture* method of the device interface, Map() it, write data to the mapped pointer, Unmap() it. Alternatively, CreateTexture* takes a pointer (pInitialData parameter) with which you can specify the initial resource data.

Share this post


Link to post
Share on other sites
[source lang='c++']
uint texels[width*height]; // 32-bit texels used as initial data; fill this array before calling CreateTexture
//...
D3D10_TEXTURE2D_DESC tDesc; // fill with apt values; be sure to use same width and height as the initial data size
//...
D3D10_SUBRESOURCE_DATA initialData;
initialData.pSysMem = (void*)&texels[0]; // you want to use the texel array as the data
initialData.SysMemPitch = sizeof(uint) * width; // distance between two adjacent lines of texels in memory
initialData.SysMemSlicePitch = 0; // slice pitch is meaningless for 2d textures, but could be width*height*sizeof(texel) if this was a volume
ID3D10Texture2D *pTexture; // though smart pointer is recommended here
HRESULT hr = pDevice->CreateTexture2D(&tDesc, &initialData, &pTexture);
[/source]

Share this post


Link to post
Share on other sites
When you use Map, you get the Pitch from the system instead of defining it yourself. Pitch is greater than or equal to width*sizeof(texel), so you should not assume anything about it. Instead, copy width*sizeof(texel) texels at a time and find each individual scanline pointer by using pitch*y.

Share this post


Link to post
Share on other sites
Also note that if you want to use a manually-filled mip chain as an initial data, you need to define an initial data structure for each of the mip levels separately. The initial data parameter of CreateTexture* expects an array of D3D10_SUBRESOURCE_DATA structs if the texture descriptor asks for more than one mip level to be created.

Share this post


Link to post
Share on other sites
Hi Nik02,
Thanks for your help.
I tried your approach but ended up with function call [size=2]CreateTexture2D() fails. The debug output is:

D3D10: ERROR: ID3D10Device::CreateTexture2D: pInitialData[5].pSysMem cannot be NULL. [ STATE_CREATION ERROR #100: CREATETEXTURE2D_INVALIDINITIALDATA ]

D3D10: ERROR: ID3D10Device::CreateTexture2D: pInitialData[6].pSysMem cannot be NULL. [ STATE_CREATION ERROR #100: CREATETEXTURE2D_INVALIDINITIALDATA ]
[size=2]

D3D10: ERROR: ID3D10Device::CreateTexture2D: pInitialData[6].SysMemPitch cannot be 0 [ STATE_CREATION ERROR #100: CREATETEXTURE2D_INVALIDINITIALDATA ]
[size=2]

D3D10: ERROR: ID3D10Device::CreateTexture2D: pInitialData[9].pSysMem cannot be NULL. [ STATE_CREATION ERROR #100: CREATETEXTURE2D_INVALIDINITIALDATA ]
[size=2]

First-chance exception at 0x7676b9bc in mexplorer.exe: Microsoft C++ exception: _com_error at memory location 0x012df3b4..
[size=2]

D3D10: ERROR: ID3D10Device::CreateTexture2D: Returning E_INVALIDARG, meaning invalid parameters were passed. [ STATE_CREATION ERROR #104: CREATETEXTURE2D_INVALIDARG_RETURN ]
[size=2]

..\..\micaps\render\directx\mgral_directx.cpp(339): iD3dDevice_->CreateTexture2D(&texDesc, &initialData, &pTexture) hr=E_INVALIDARG (0x80070057)


The input texels is an array of the type unsigned char (MGRALubyte), of length 4*width*height. That is the RGBA component of a texel is represented by 4 unsigned chars. So in my code (attatched at the end of this post), I allocated another array and convert each texel of the input array to the new array. Then I followed your code.


MGRALuint mgral_directx::generateTexture(MGRALvoid *pixels, MGRALsizei *w, MGRALsizei *h)
{
UINT width = *w, height = *h;
UINT *texels, *pt, r, g, b, a;
MGRALubyte *pp;
texels = (UINT *)malloc(width*height*sizeof(UINT));
if ( texels == NULL )
return 0;
// 32-bit texels used as initial data; fill this array
// before calling CreateTexture2D
pt = texels; pp = (MGRALubyte *)pixels;
for ( int i = 0; i < height; i++ )
for ( int j = 0; j < width; j++ ) {
r = UINT(*pp++);
g = UINT(*pp++);
b = UINT(*pp++);
a = UINT(*pp++);
*pt++ = r<<24 | g<<16 | b<<8 | a;
}
D3D10_TEXTURE2D_DESC texDesc;
ZeroMemory(&texDesc, sizeof(D3D10_TEXTURE2D_DESC));
texDesc.Width = width;
texDesc.Height = height;
// To generate mipmap levels automatically, set the number of mipmap levels to 0.
texDesc.MipLevels = 0;
texDesc.ArraySize = 1;
texDesc.Format = DXGI_FORMAT_R8G8B8A8_UINT;
DXGI_SAMPLE_DESC sampleDesc;
texDesc.SampleDesc.Count = 1;
texDesc.SampleDesc.Quality = 0;
texDesc.Usage = D3D10_USAGE_IMMUTABLE;
texDesc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
texDesc.CPUAccessFlags = 0;
texDesc.MiscFlags = 0;

D3D10_SUBRESOURCE_DATA initialData;
initialData.pSysMem = (void *)texels;
// distance between two adjacent lines of texels in memory
initialData.SysMemPitch = width*sizeof(UINT);
// slice pitch is meaningless for 2d textures, but could be
// width*height*sizeof(texel) if this was a 3d volume
initialData.SysMemSlicePitch = 0;
ID3D10Texture2D *pTexture=NULL;
HR(iD3dDevice_->CreateTexture2D(&texDesc, &initialData, &pTexture));
free(texels);
return (MGRALuint)pTexture;
}

Share this post


Link to post
Share on other sites
You are asking the driver to allocate the mip chain to the texture (by setting the texDesc.MipLevels to 0). Thus, you should supply the initial data of the texture as an array of D3D10_SUBRESOURCE_DATA structures.

To determine the number of needed mip levels for a given width and height, create a loop in which you divide width and height by 2 at each iteration, and keep both at least at 1 (because width or height cannot be 0 on any mip level). When both width and height are 1, the number of iterations that the loop ran until that point represents the number of mip levels given initial width and height.

That said:

If you want to make this easier, first create the texture (and mip levels) without specifying initial data. Then fill the first mip level with UpdateSubresource or Map/Unmap. Finally, you can call D3DX10FilterTexture to fill the rest of the mip levels automatically. This means that the texture cannot be allocated as immutable, though.

Share this post


Link to post
Share on other sites

You are asking the driver to allocate the mip chain to the texture (by setting the texDesc.MipLevels to 0). Thus, you should supply the initial data of the texture as an array of D3D10_SUBRESOURCE_DATA structures.

To determine the number of needed mip levels for a given width and height, create a loop in which you divide width and height by 2 at each iteration, and keep both at least at 1 (because width or height cannot be 0 on any mip level). When both width and height are 1, the number of iterations that the loop ran until that point represents the number of mip levels given initial width and height.

That said:

If you want to make this easier, first create the texture (and mip levels) without specifying initial data. Then fill the first mip level with UpdateSubresource or Map/Unmap. Finally, you can call D3DX10FilterTexture to fill the rest of the mip levels automatically. This means that the texture cannot be allocated as immutable, though.


Thanks a lot, Nik02.
I changed the mipmap level field "[size="2"]MipLevels" from 0 to 1 and it works. Actually my texture is 3200 pixels wide plus 1600 pixels high. I wonder if this large size results in performance issue if only one mipmap level is given. In addition, does Direc3D require the texture size to be the power of 2 like OpenGL?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!