0
\$\begingroup\$

I am trying to create a ID3D11Texture2D from a RgbaImage loaded from a .jpg. The below code produces no errors. However, the texture is black when it is actually rendered. I know the standard way to load textures is through the DirectXTex library, but I was having issues linking with it and can't find any premade Rust bindings.

  • Should the below code/settings work to create a working ID3D11Texture2D?
  • Is there a way to view the contents of a ID3D11Texture2D in order to debug?
  • Are there DirectXTex bindings for Rust?
fn load_resource_from_file(device: &Device, path: &Path) -> error::Result<Texture> {
    unsafe {
        let image = Reader::open(path)?.decode()?.to_rgba();

        let mut sample_desc = dxgitype::DXGI_SAMPLE_DESC::default();
        sample_desc.Count = 1;
        sample_desc.Quality = 0;

        let mut desc = d3d11::D3D11_TEXTURE2D_DESC::default();
        desc.Width = image.width();
        desc.Height = image.height();
        desc.MipLevels = 1;
        desc.ArraySize = 1;
        desc.Format = dxgiformat::DXGI_FORMAT_R8G8B8A8_UINT;
        desc.Usage = d3d11::D3D11_USAGE_DEFAULT;
        desc.SampleDesc = sample_desc;
        desc.BindFlags = d3d11::D3D11_BIND_SHADER_RESOURCE;
        desc.CPUAccessFlags = 0;
        desc.MiscFlags = 0;

        let mut data = d3d11::D3D11_SUBRESOURCE_DATA::default();
        data.SysMemPitch = (image.sample_layout().width_stride * mem::size_of::<Rgba<u8>>()) as u32;
        let buffer: Vec<u8> = image.into_raw();
        data.pSysMem = buffer.as_ptr() as *const _;
        data.SysMemSlicePitch = buffer.len() as u32;

        let mut texture = ptr::null_mut();
        device.as_ref().CreateTexture2D(
            &desc,
            &data,
            &mut texture,
        ).result()?;
        let texture = NonNull::new(texture).ok_or(null_ptr_err!())?;

        drop(buffer);

        let mut resource_view = ptr::null_mut();
        device.as_ref().CreateShaderResourceView(
            &**texture.as_ref() as *const d3d11::ID3D11Resource as *mut _,
            ptr::null(),
            &mut resource_view,
        ).result()?;
        let resource_view = NonNull::new(resource_view).ok_or(null_ptr_err!())?;

        Ok( Texture(Arc::new(TextureInner {
            texture,
            resource_view,
        })))
    }
}
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Finally figured it out. Rather than DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UNORM is required. Fixing this fixed the black texture. However, there are some other problems with my code.

  • The different strides are already multiplied by the size of the pixel. I don't know what happens if you use a non-u8 image format.
  • height_stride should be used instead of width_stride. Confusingly, height_stride is the stride between different heights, aka the width+padding. I assume this is different for column-major images.

I would still appreciate a way to view the contents of a ID3D11Texture2D, as well as a solid answer on whether or not there are existing bindings to DirectXTex.

Final Code:

fn load_resource_from_file(device: &Device, path: &Path) -> error::Result<Texture> {
    unsafe {
        let image = Reader::open(path)?.decode()?.to_rgba();

        let mut sample_desc = dxgitype::DXGI_SAMPLE_DESC::default();
        sample_desc.Count = 1;
        sample_desc.Quality = 0;

        let mut desc = d3d11::D3D11_TEXTURE2D_DESC::default();
        desc.Width = image.width();
        desc.Height = image.height();
        desc.MipLevels = 1;
        desc.ArraySize = 1;
        desc.Format = dxgiformat::DXGI_FORMAT_R8G8B8A8_UNORM;
        desc.Usage = d3d11::D3D11_USAGE_DEFAULT;
        desc.SampleDesc = sample_desc;
        desc.BindFlags = d3d11::D3D11_BIND_SHADER_RESOURCE;
        desc.CPUAccessFlags = 0;
        desc.MiscFlags = 0;

        let mut data = d3d11::D3D11_SUBRESOURCE_DATA::default();
        data.SysMemPitch = image.sample_layout().height_stride.max(
            image.sample_layout().width_stride
        ) as u32;
        let buffer: Vec<u8> = image.into_raw();
        data.pSysMem = buffer.as_ptr() as *const _;

        let mut texture = ptr::null_mut();
        device.as_ref().CreateTexture2D(
            &desc,
            &data,
            &mut texture,
        ).result()?;
        let texture = NonNull::new(texture).ok_or(null_ptr_err!())?;

        drop(buffer);

        let mut resource_view = ptr::null_mut();
        device.as_ref().CreateShaderResourceView(
            &**texture.as_ref() as *const d3d11::ID3D11Resource as *mut _,
            ptr::null(),
            &mut resource_view,
        ).result()?;
        let resource_view = NonNull::new(resource_view).ok_or(null_ptr_err!())?;

        Ok( Texture(Arc::new(TextureInner {
            texture,
            resource_view,
        })))
    }
}
```
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .