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\$
0
\$\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,
        })))
    }
}
```
| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.