Sign in to follow this  
Followers 0
Visje

DirectX11 mip mapping

31 posts in this topic

Hey everyone,

I'm working on a game with DirectX11 and I need to apply a mip mapping on my textures when they get far from the camera (I actually have a menu with a lot of textures far from the camera and the mip mapping doesn't seem to be applied because the framerate is quite low...)

I've searched for 3 days how I could do this and I found many solutions but none of them seems to work...

I have this piece of code that create a texture, and I can show you other pieces if required :

[CODE]
D3D11_TEXTURE2D_DESC textureDesc;
ZeroMemory( &textureDesc, sizeof(textureDesc) );
textureDesc.Width = width;
textureDesc.Height = height;
textureDesc.MipLevels = 1;
textureDesc.ArraySize = 1;
textureDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
textureDesc.SampleDesc.Count = 1;
textureDesc.Usage = D3D11_USAGE_DEFAULT;
textureDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
textureDesc.CPUAccessFlags = 0;
textureDesc.MiscFlags = D3D11_RESOURCE_MISC_GENERATE_MIPS;
[/CODE]
When I try to change the MipLevels value to 0 or another value, I get an error...

[b]My question is [/b]: What should I do to get the mip mapping to work ? Do you have any clue, any idea.

Sorry for my average english I'm french [img]http://public.gamedev.net//public/style_emoticons/default/mellow.png[/img]

Thanks a lot !
0

Share this post


Link to post
Share on other sites
@Kauna :
In the Pixel Shader, I'm using this Sampler :
[CODE]
SamplerState simpleSampler : register(s0);
[/CODE]

and later on... in the main of the PS
[CODE]
float4 texelColor = simpleTexture.Sample(simpleSampler, input.tex);
return texelColor;
[/CODE]


@Hodgman :
The error is in french but you may recognize something, here it is :
[i]Exception non gérée à 0x71F9E85C (nvwgf2um.dll) dans Direct3DApp1.exe : 0xC0000005 : Violation d'accès lors de la lecture de l'emplacement 0xCCCCCCCC.[/i]
It says, acces violation while writing at 0xCCCCCCCC Edited by Visje
0

Share this post


Link to post
Share on other sites
[quote]SamplerState simpleSampler : register(s0);[/quote]

Have you defined the sampler in the program side?

Cheers!
0

Share this post


Link to post
Share on other sites
Yep, here it is :

[CODE]
D3D11_SAMPLER_DESC samplerDesc;
ZeroMemory(&samplerDesc, sizeof(samplerDesc));
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
samplerDesc.MaxAnisotropy = 0;
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_BORDER;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_BORDER;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_BORDER;
samplerDesc.MipLODBias = 0.0f;
samplerDesc.MinLOD = 0;
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
samplerDesc.BorderColor[0] = 0.0f;
samplerDesc.BorderColor[1] = 0.0f;
samplerDesc.BorderColor[2] = 0.0f;
samplerDesc.BorderColor[3] = 0.0f;
[/CODE]


Maybe the mipmaps are beeing generated but I can't notice any difference... that should increase the framerate normally :/ Edited by Visje
0

Share this post


Link to post
Share on other sites
Do you check the HRESULT value when trying to create the texture?
It might return failure, and your crash could occur later when you try to use the uninitialized object.

What feature level are you running at?
[url="http://msdn.microsoft.com/en-us/library/windows/desktop/cc627090%28v=vs.85%29.aspx"]http://msdn.microsoft.com/en-us/library/windows/desktop/cc627090%28v=vs.85%29.aspx[/url] lists B8G8R8A8 as optional for auto-generation of mipmaps, though it seems required on feature level 11.. Check the related pages linked at the menu on that page to check your feature level and supported formats.
2

Share this post


Link to post
Share on other sites
I Get the same error with the HRESULT :/

I don't know the feature level i'm running at, actually, what is a "feature level" ?
If I change the format, the colors become very odd depending on the format. Edited by Visje
0

Share this post


Link to post
Share on other sites
If you change B8G8R8A8 to R8G8B8A8, does it work correctly?
If so, the format is the problem.
You can find your feature level by using ID3D11Device::GetFeatureLevel.
0

Share this post


Link to post
Share on other sites
If I change B8G8R8A8 to R8G8B8A8, it works but the colors are all "browny"

My feature level is : D3D_FEATURE_LEVEL_11_0 (45056)
0

Share this post


Link to post
Share on other sites
I see. That means B8G8R8A8 is not supported. When you change to R8G8B8A8 everything blue becomes red, and vice versa, which causes your colors to mismatch. This can however be fixed by changing how you load your source data or how you define your colors.
(In particular .BMP files are usually BGR instead of RGB.. I believe TGA too.. not sure).

A very fast "fix" to test it out is to change your shader that you use to draw the mipmapped resource to return some color.bgra to swizzle the color.

To investigate the format problem more closely, read the introduction here [url="http://msdn.microsoft.com/en-us/library/windows/desktop/ff471325(v=vs.85).aspx"]http://msdn.microsof...5(v=vs.85).aspx[/url] and try the CheckFormatSupport function.
Also, try using the D3D11_CREATE_DEVICE_BGRA_SUPPORT flag ([url="http://msdn.microsoft.com/en-us/library/windows/desktop/ff476107(v=vs.85).aspx"]http://msdn.microsof...7(v=vs.85).aspx[/url]) when creating your device. Edited by Erik Rufelt
0

Share this post


Link to post
Share on other sites
Do you think that the mip mapping will work when the format will be changed ?? Will I be able to change the MipLevels value ?

Thanks a lot for your help :)
0

Share this post


Link to post
Share on other sites
I assumed you had already done that and seen it working with R8G8B8A8. If that's not the case, you're kindof back where you started. [img]http://public.gamedev.net//public/style_emoticons/default/smile.png[/img] But try it out.

The first most important part is to check the HRESULT return code from CreateTexture2D, using if(FAILED(hResult)) error() or similar. If you get an error from that then proceed checking the device format support and options.

If you do not get an error from CreateTexture2D (when MipLevels is 0), then your problem lies elsewhere and you can probably ignore my previous posts. Edited by Erik Rufelt
0

Share this post


Link to post
Share on other sites
I actually already have the "D3D11_CREATE_DEVICE_BGRA_SUPPORT" flag.
I changed the format to R8G8B8A8 and did the quick fix in the Pixel Shader, the game works fine but I still get an error when I set MipLevels to 0, I'll try with the HRESULT.

Just for info, I'm working on a Metro app.
0

Share this post


Link to post
Share on other sites
I did this :
[CODE]
HRESULT hr = m_d3dDevice->CreateTexture2D(
&textureDesc,
&initialData,
&texture2D
);
[/CODE]
but I get an error inside "CreateTexture2D", thus I cannot check the error code of HRESULT :/
0

Share this post


Link to post
Share on other sites
How do you initialize initialData?
D3D is probably expecting you to provide all mip levels, thereby reading past the end of your data.
Skip using initialData and instead upload the first mip-level using UpdateSubResource.
2

Share this post


Link to post
Share on other sites
That's how I initialize initialData :
[CODE]
D3D11_SUBRESOURCE_DATA initialData;
ZeroMemory(&initialData, sizeof(initialData));
initialData.pSysMem = bitmapPixels.get();
initialData.SysMemPitch = width * 4;
initialData.SysMemSlicePitch = 0;
[/CODE]


"Skip using initialData and instead upload the first mip-level using UpdateSubResource." humm... how can I do that ? :s Edited by Visje
0

Share this post


Link to post
Share on other sites
Pass NULL to CreateTexture2D and then call ID3D11DeviceContext::UpdateSubresource: [url="http://msdn.microsoft.com/en-us/library/windows/desktop/ff476486(v=vs.85).aspx"]http://msdn.microsoft.com/en-us/library/windows/desktop/ff476486(v=vs.85).aspx[/url]
Follow the links there and each input is described. Just set the box to (0, width, 0, height, 0, 1) and rowPitch to your sysMemPitch and pass it your data. The subresource should be 0 for the top mip level.
0

Share this post


Link to post
Share on other sites
If your texture is static, you want to create it with D3D11_USAGE_IMMUTABLE and not D3D11_USAGE_DEFAULT.

Also when you create a texture with mipmaps and you want to pass it initialization data, you need to pass an [i]array[/i] of D3D11_SUBRESOURCE_DATA. The array needs 1 element per subresource, where a subresource is either a mip level or an array slice. So if you have 10 mip levels, you'd need to pass an array of 10 with each one having a pointer to the data for that mip level.
0

Share this post


Link to post
Share on other sites
Hi Erik, I passed NULL to CreateTexture2D and all became black as expected, then at each frame I call this codeto render my textures :
[CODE]
m_d3dDeviceContext->UpdateSubresource(
m_constantBuffer.Get(),
0,
nullptr,
&(m_constantBufferData),
0,
0
);
[/CODE]
I don't know if I should put this function just after the createTexture, or if I must change the parameters of it... nvertheless it still is'nt working :/


MJP : I did what you told me but I still got the problem ><, I'm kind of a noob on this one :(
Here's the code if interested :
[CODE]
D3D11_SUBRESOURCE_DATA* initData(new D3D11_SUBRESOURCE_DATA[3 * 3]);
initData[0].pSysMem = bitmapPixels.get();
initData[0].SysMemPitch = width * 4;
initData[0].SysMemSlicePitch = 0;
initData[1].pSysMem = bitmapPixels.get();
initData[1].SysMemPitch = width * 4;
initData[1].SysMemSlicePitch = 0;
initData[2].pSysMem = bitmapPixels.get();
initData[2].SysMemPitch = width * 4;
initData[2].SysMemSlicePitch = 0;


D3D11_TEXTURE2D_DESC textureDesc;
ZeroMemory( &textureDesc, sizeof(textureDesc) );
textureDesc.Width = width;
textureDesc.Height = height;
textureDesc.MipLevels = 0; // PROBLEM WITH THIS
textureDesc.ArraySize = 1;
textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
textureDesc.SampleDesc.Count = 1;
textureDesc.Usage = D3D11_USAGE_IMMUTABLE; // PROBLEM HERE ALSO
textureDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
textureDesc.CPUAccessFlags = 0;
textureDesc.MiscFlags = D3D11_RESOURCE_MISC_GENERATE_MIPS;

HRESULT hr = m_d3dDevice->CreateTexture2D(
&textureDesc,
initData,
&texture2D
);
[/CODE]

Thanks again for your help guys
0

Share this post


Link to post
Share on other sites
Providing data for all mip-levels means you explicitly define exactly what each mip-map should contain. This does not make sense together with D3D11_RESOURCE_MISC_GENERATE_MIPS, as the only time you would ever want to generate mips if when you do not have the mip-maps.
I got the impression that this is what you want, for D3D to automatically generate your mipmaps for you.
This is usually done when you actually render data to your texture render-target, and want the mip-maps auto-generated on the GPU after re-rendering the top level.

There is an easier way to do this when loading textures, by calculating the mips on the CPU, and then pass them in with the init-data. I believe D3DX11CreateTextureFromMemory does this automatically for you, if you can use D3DX11.
[url="http://msdn.microsoft.com/en-us/library/windows/desktop/ff476287(v=vs.85).aspx"]http://msdn.microsof...7(v=vs.85).aspx[/url]

If you do not want to use that function, but do it yourself, there are two ways. You can manually resize your texture to half its size over and over to calculate all the mip-maps, and upload that data to the texture, using either init-data or UpdateSubresource. There is no real difference between init-data and UpdateSubresource if you have a default usage texture, except for that UpdateSubresource lets you update only one particular mip-level (be it the largest or any other).
The other option is to let D3D generate mipmaps with D3D11_RESOURCE_MISC_GENERATE_MIPS.

Using UpdateSubresource you can at any time change a D3D11_USAGE_DEFAULT texture without re-creating the texture.
Is your goal to do this during a game-frame, and automatically have mipmaps generated for your new texture?
Or do you just want to create a texture with mipmaps once that is static until the next time data/levels/other is reloaded?

If you do want the mip-maps auto-generated like that, then create your texture with default usage, mipmap-generation, and 0 as MipLevels, without any initialization data. Then call UpdateSubresource to update mip-level 0 and then call GenerateMips.

UpdateSubresource should be used something like this:
[CODE]
D3D11_BOX box;
box.left = 0;
box.right = width;
box.top = 0;
box.bottom = height;
box.front = 0;
box.back = 1;

deviceContext->UpdateSubresource(
texture2D, // the texture to update
0, // first mip-level
&destBox, // position of the pixels to update in the texture
pixels.Get(), // image data
width * 4, // row pitch
0 // not used for 2D textures
};
[/CODE]

Also, I recommend that you visit the documentation-pages at MSDN or in the documentation that comes with the DirectX SDK, and carefully read through all the documentation for the functions you use. It is immensely helpful and will make you a better programmer. Everything we have said is described in detail on the documentation pages. You are not supposed to know everything by heart, but know where to look it up when you need it. Edited by Erik Rufelt
2

Share this post


Link to post
Share on other sites
Wow big answer there, thanks :) !

"I got the impression that this is what you want, for D3D to automatically generate your mipmaps for you."
- Yep that is exactly what I want.

"I believe D3DX11CreateTextureFromMemory does this automatically for you"
- As I'm doing a Metro application, I can't use this library :/

"The other option is to let D3D generate mipmaps with D3D11_RESOURCE_MISC_GENERATE_MIPS."
- I'll try this one because it's not so different from my base code.

"Is your goal to do this during a game-frame, and automatically have mipmaps generated for your new texture?"
- Yes, as the object get far from the camera I want the mip map to update to a lower resolution texture in the better case

I'll try with the UpdateSubresource method and tell you if all works properly. Thanks again mate :) !
0

Share this post


Link to post
Share on other sites
Okay, I made this :
[CODE]
D3D11_BOX destBox;
destBox.left = 0;
destBox.right = width;
destBox.top = 0;
destBox.bottom = height;
destBox.front = 0;
destBox.back = 1;

std::unique_ptr<byte[]> bitmapPixels(new byte[width * height * 4]);
m_d3dDeviceContext->UpdateSubresource(
this->texture.Get(), // the texture to update
0, // first mip-level
&destBox, // position of the pixels to update in the texture
bitmapPixels.get(), // image data
width * 4, // row pitch
0 // not used for 2D textures
);
m_d3dDeviceContext->GenerateMips(this->textureView.Get());
[/CODE]

It still does'nt work but gives me another error, I'll try to find what's wrong and tell you how it goes. Edited by Visje
0

Share this post


Link to post
Share on other sites
So I've managed to get it to work, the code compiles and the app launches but none of my textures are displayed :/ instead I get some weird white squares (the colored background should also be textured):

[img]http://tof.canardpc.com/view/0b7c0557-a3a7-4730-aed7-0a199b6484a9.jpg[/img]
0

Share this post


Link to post
Share on other sites
Copy paste your entire texture init code as it is now, from where you get your image data to where you call GenerateMips, including the structures you have already shown for the texture description, as they appear now.
0

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  
Followers 0