A pair of texture resources is created with the following surface format D3DFMT_R32, as follows:
V_RETURN( D3DXCreateTexture(g_pd3dDevice, g_rastWidth,g_rastHeight,1,D3DUSAGE_RENDERTARGET,D3DFMT_R32F,D3DPOOL_DEFAULT,&g_offTextFLT[0]));
V_RETURN( D3DXCreateTexture(g_pd3dDevice, g_rastWidth,g_rastHeight,1,D3DUSAGE_RENDERTARGET,D3DFMT_R32F,D3DPOOL_DEFAULT,&g_offTextFLT[1]));
These are intermeidate surfaces used to classify model data parameters, as scaled floating point values. A pair is defined to serve as alternating buffers in an optional median filter scheme. In multiple passes, they alternate as an input texture and rendertarget for optional multiple passes of median filtering, but this filtering is optional. The original (or median filtered) R32F texture is then used in a final rendering pass as one input to a classification shader, and the final output is a D3DFMT_A8R8G8B8 surface that is persisted by saving the final render target as follows:
D3DXSaveSurfaceToFile(g_outputGx,D3DXIFF_PNG ,g_offSurfRGBA, NULL,NULL); (This is the final stage D3DFMT_A8R8G8B8 / RGBA final surface, not the intermediate R32F surface.)
All that works as expected, and the R32F surface encoding is as expected, scaled floats into the R channel, used as an input in the final stage shader.
The R32F intermediate surfaces are useful in another process, so I wanted to add persistence of the intermediate surfaces as R32 surfaces.
if(g_r32Out){
g_offTextFLT[curFLTSurf]->GetSurfaceLevel(0,&g_offSurfFLT[curFLTSurf]);
D3DXSaveSurfaceToFile(g_outputGx,D3DXIFF_PNG ,g_offSurfFLT[curFLTSurf], NULL,NULL);
}
(I also tried the D3DXSaveTextureToFIle variant, same results as below.)
The above results in a .PNG file, but with the following unexpected characteristics when examined with
D3DXIMAGE_INFO fInfo;
D3DXGetImageInfoFromFile(g_R32File,&fInfo);
=> fInfo.Format isD3DFMT_A16B16G16R16, with the R channel now stored as unsigned Int16 in a 64 bit pixel format. (???)
A managed alternative to access the same PNG gives yet another result:
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.UriSource = new Uri(file);
bi.CreateOptions = BitmapCreateOptions.PreservePixelFormat;
bi.EndInit();
=> bi.Format = pbgra32
Not a whole lot of "PreservePixelFormat' going on there. A conversion to the preferred format was perfromed, and is now 32 bit pixels.
I've also tried this variant,
Stream imageStreamSource = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read);
PngBitmapDecoder decoder = new PngBitmapDecoder(imageStreamSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
BitmapSource bi = decoder.Frames[0];
=> bi.Format = rgba64.
Which is at least consistant-ish with the unmanaged attempt.
My conclusion is:
1] The BitmapImage 'PreservePixelFormat' option is being ignored, but the PngBitmapDecoder "PreservePixelFormat' option is being honored.
2] The output PNG pixel format really is rgba64 / D3DFORMAT_A16B16G16R16 64 bit pixels.
3] What happened to the original D3DFORMAT_R32F? My guess is, the D3DXSaveSurfaceToFile(g_outputGx,D3DXIFF_PNG ,g_offSurfFLT[curFLTSurf], NULL,NULL) method is doing the conversion on the source R32F surface when it outputs the PNG, but I don't know why.
There is one additional oddity. The original R32F encoding encodes the available model field data as normalized floats between 0.0(= DMIN) and 1.0 (= DMAX), while 'missing' field data is encoded as -1.0. A 'preview' window in the managed/WPF app displays these intermediate R32F surfaces. Without any special effect, they appear as varying shades of CYAN (the BGA channels are maxed, and the R channel varies), which is expected. By applying a simple pixel shader/effect as follows, these can be made to cosmetically appear as greyscale.
sampler2D input : register(s0);
float4 main(float2 uv : TEXCOORD) : COLOR
{
float4 Color;
Color=tex2D(input,uv.xy);
if(Color.r<0.0)
{
Color = float4(0,0,0,0);
}
else
{
Color.g=Color.r;
Color.b=Color.r;
Color.a=1.0;
}
return Color;
}
This works as expected...which is unexpected. Where is the original encoding of the signed value in the R channel coming from, if the channel has been converted to unsigned R16? Has the original R32F encoding across the floating point range [-1.0, 0.0-1.0] been re-encoded as signed 16 bit [65535, 0 - 32767] ? Examining the data with BitConverter in the PngBitmpaDecoder variant shows the R channel values varying between 0 and 65535, but with values > 32767 other than 65535. So, whatever implicit rescaling of the R32F channel that has occurred isn't clear. There should be lots of pixels with (Color.r < 0.0) if some implicit cast is being done from unsigned to signed, and yet the only pixels that trigger the 'if(Color.r<0.0)' above are those originally encoded as -1.0 in the R32F surface, ie, now with R16 value 65535.
reguarda,
Frediano