D3DX11CreateShaderResourceViewFromFile fails to load sRGB textures correctly?

Started by
7 comments, last by mattropo1is 12 years, 3 months ago
I've got a block of code that's loading what I'm pretty sure is an sRGB jpg (as the file properties on it say it is enocded sRGB color format, and I selected the sRGB profile when saving it in Photoshop) that I wish to use as a texture.


hResult = D3DX11CreateShaderResourceViewFromFile( pd3dDevice, pFilename, NULL, NULL, &pTextureResourceView, NULL );
pTextureResourceView->GetDesc( &desc );
desc.Format;


When i run the above code on my texture, it always loads as DXGI_FORMAT_R8G8B8A8_UNORM, not DXGI_FORMAT_R8G8B8A8_UNORM_SRGB as I would expect. Further, when I use the texture, it's washed out (too bright) as if it's been loaded as RGB. If I do a pow(sampleColor, 2.2) in the pixel shader, then the color looks right.

Am I missing something on loading the texture correctly to get it to recognize it as sRGB?
Advertisement
Yeah, it won't load as an sRGB format by default. You have to instruct the function to load it using an sRGB format (and not convert it) using the loadInfo parameter. Something like this should work:

D3DX11_IMAGE_LOAD_INFO loadInfo;
loadInfo.Width = D3DX11_DEFAULT;
loadInfo.Height = D3DX11_DEFAULT;
loadInfo.Depth = D3DX11_DEFAULT;
loadInfo.FirstMipLevel = D3DX11_DEFAULT;
loadInfo.MipLevels = D3DX11_DEFAULT;
loadInfo.Usage = D3D11_USAGE_IMMUTABLE;
loadInfo.BindFlags = D3D11_BIND_SHADER_RESOURCE;
loadInfo.CpuAccessFlags = 0;
loadInfo.MiscFlags = 0;
loadInfo.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
loadInfo.Filter = D3DX11_FILTER_SRGB_IN | D3DX11_FILTER_SRGB_OUT | D3DX11_FILTER_NONE ;
loadInfo.MipFilter = D3DX11_DEFAULT;
loadInfo.pSrcInfo = NULL;
D3DX11CreateShaderResourceViewFromFile(pd3dDEvice, pFilename, &loadInfo, NULL, &pTextureResourceView, NULL);

Yeah, it won't load as an sRGB format by default. You have to instruct the function to load it using an sRGB format (and not convert it) using the loadInfo parameter. Something like this should work:

D3DX11_IMAGE_LOAD_INFO loadInfo;
loadInfo.Width = D3DX11_DEFAULT;
loadInfo.Height = D3DX11_DEFAULT;
loadInfo.Depth = D3DX11_DEFAULT;
loadInfo.FirstMipLevel = D3DX11_DEFAULT;
loadInfo.MipLevels = D3DX11_DEFAULT;
loadInfo.Usage = D3D11_USAGE_IMMUTABLE;
loadInfo.BindFlags = D3D11_BIND_SHADER_RESOURCE;
loadInfo.CpuAccessFlags = 0;
loadInfo.MiscFlags = 0;
loadInfo.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
loadInfo.Filter = D3DX11_FILTER_SRGB_IN | D3DX11_FILTER_SRGB_OUT | D3DX11_FILTER_NONE ;
loadInfo.MipFilter = D3DX11_DEFAULT;
loadInfo.pSrcInfo = NULL;
D3DX11CreateShaderResourceViewFromFile(pd3dDEvice, pFilename, &loadInfo, NULL, &pTextureResourceView, NULL);



Thanks. Yes, this does get the desired result for this file, but the problem is that this code *forces* the jpg into sRGB space (it does look correct). But what I want is for D3DX11CreateShaderResourceViewFromFile to create the *correct* resource view based on what the texture file *says* it is.

If the texture is not sRGB (i.e. normal map/albieto/etc), then it should load as the RGBA8_UNORM. If it IS saved sRGB, then I'd want the RGBA8_UNORM_SRGB version...
Any ideas on that one?
As far as I know the D3DX loader won't attempt to interpret any metadata in image file, so you would have to interpret it yourself or use some other means of providing metadata. In general formats like JPEG and TIFF don't really provide you with enough metadata to make proper decisions about how to handle them, so you will probably have to resort to adding your own metadata at some point. The loader will properly handle DDS files, so you also have the option of creating a preprocessing pipeline that converts and compresses your textures in advance so that you don't need to do anything fancy at load time (or using a plugin for your content creation software that will save as DDS).
But what I want is for D3DX11CreateShaderResourceViewFromFile to create the *correct* resource view based on what the texture file *says* it is.
Anything with "D3DX" or "Create...FromFile" in the name is just a utility to help you get started, not actually a real part of D3D. It's kinda expected that at some point you'll out-grow these functions and have to create your own versions.

What a generic image file (like a JPEG) says about it's colour-space is very unreliable. A large number of JPEGs will not say anything about sRGB, but nonetheless contain sRGB data -- for example, your web-browser will simply assume that every JPEG/PNG/GIF/BMP/etc that it loads is actually in sRGB-space, regardless of what the meta-data says, because sRGB is the standard colour-space for images on the internet.

If the texture is not sRGB (i.e. normal map/albieto/etc), then it should load as the RGBA8_UNORM. If it IS saved sRGB, then I'd want the RGBA8_UNORM_SRGB version...
Any ideas on that one?[/quote]Don't use JPEG files; use DDS files, or create your own texture format with similar capabilities to DDS.

Albedo textures generally are stored in sRGB, because they contain colour information that was authored on a monitor (and that monitor should be calibrated to be displaying an sRGB signal).
Only "data" textures are generally not RGB, like normal-maps, because they contain mathematical data that wasn't authored by-eye on a monitor. These kinds of textures should never be stored as JPEG anyway, as lossy JPEG compression is based around preserving perceptual error in colour images (and colour images can be assumed to be sRGB), not data images.

... The loader will properly handle DDS files, so you also have the option of creating a preprocessing pipeline that converts and compresses your textures in advance so that you don't need to do anything fancy at load time (or using a plugin for your content creation software that will save as DDS).


I have Photohop cs5, and used the nVidia dds plugin to save the file. I had Photoshop set to sRGB space, and when I went to save using the nVidia DDS plugin, it didn't show any obvious checkboxes to create an sRGB dds texture. I saved it, and the D3DX11CreateShaderResourceViewFromFile still created the non-sRGB UNORM texture.

Have you gotten D3DX11CreateShaderResourceViewFromFile to properly return an sRGB texture? What was your tool/process for creating the sRGB texture?
M
The Nvidia plugin is rather old, which means it probably uses the old version of DDS. The older version was meant for D3D7-D3D9, which didn't include sRGB formats (in D3D9 sRGB conversion was a sampler state). So you may be out of luck on that one.

What we do at work for texture assets is the artists author a text file (either manually or through an importing tool) which contains a path to the actual image file, and a bunch of other metadata. This metadata includes things such as whether it needs mipmaps generated, the color space, whether it's a normal map/spec map/color map, compression options, etc. Then when that texture needs to get processed for a material our build pipeline handles mip generation, compression, and format conversion and saves out the result as a DDS file (using the updated DDS spec created for D3D10). Then at runtime we just have D3DX11CreateShaderResourceViewFromFile load the DDS file as a texture, and it's good to go.

By now you should be common theme here, which is that properly handling textures is a major pain in the ass. :P
AFAIK JPEGs always use an implicit 2.2 gamma correction and not a sRGB encoding (cf. http://en.wikipedia....standard_gammas).
sRGB is not exactly 2.2 gamma but a piecewise combination of a linear function in the low intensities and a 2.4 power function (http://en.wikipedia.org/wiki/SRGB).
Loading JPEGs as sRGB will yield a slightly wrong result but still better than assuming linear space anyway...

I had to write quite a complicated image loader routine to handle the different color spaces, gamma corrections and sRGB settings, but I never used [color="#1C2837"]D3DX11CreateShaderResourceViewFromFile() for the reasons you described here.
[color="#1c2837"]
[color=#1C2837][size=2]If you like, y[color="#1c2837"]ou can take a look at the DX10 SDK file "D3DX_DXGIFormatConvert.inl" for insights on their sRGB / linear space conversion routines...
Well, after much investigation and experimentation - it comes down to much of what has been said.
-The internal DX texture functions do NOT seem to understand or honor sRGB/gamma properly in png/jpg/dds files. The DX functions pretty much just load things assuming they are non-sRGB into unorm/standard rgb component internal formats.
-The nvidia photoshop dds plugin doesn't seem to mark things as sRGB properly. Sadly, this doesn't really matter as it's probably not honored anyway.
-You will have to have some sort of meta-data file, or a policy, that tells you which files need to be created using an sRGB texture surface/buffer.
-Make sure your content generation tools are outputing to sRGB. Adobe has a color space setting for this. Some tools do NOT have sRGB output. Make sure you can get your favorite content into the sRGB format you want before you make the jump.
-If you wish to use DX texture loading routines, you need to use the sRGB load flags on D3DXGetImageInfoFromFile() (i.e. D3DX11_IMAGE_LOAD_INFO Info.Filter = D3DX11_FILTER_NONE | D3DX11_FILTER_SRGB_IN | D3DX11_FILTER_SRGB_OUT). This preforms the correct interpretation of the data.
-Both your back buffer AND the textures need to be a DXGI_FORMAT_xxxx_SRGB format type.
-There are very few DXGI_FORMAT_xxxx_SRGB formats. Only 6 to be exact, and 4 are BCx compressed types. If you're not very careful, odds are very good you'll pay for painful load-time conversion because most of the old formats are ARGB, but the SRGB formats are RGBA. If you're looking for single-channel formats - you'll be sorely dissappointed.
-It's useful at first to change your pixel shader to do an pow(2.2) on each pixel (using the old textures) to see what you SHOULD be getting. Then, convert the textures and make the format and loading changes, then compare the results. They should look nearly the same.

It certainly does appear that at some point, you'll likely want to come up with your own texture format or get by using some extra meta-data file to specify whether the image is sRGB (diffuse channels, etc), or not (normal maps, data maps, etc).

Thanks for the help.

This topic is closed to new replies.

Advertisement