~raph/dx11-toy

be579a7c81d437ada2f92491c0b421320ab3cf81 — Raph Levien 2 years ago 478830a
Draw triangle

Get a triangle drawn.
3 files changed, 252 insertions(+), 4 deletions(-)

M Cargo.toml
M src/d3d11.rs
M src/main.rs
M Cargo.toml => Cargo.toml +2 -1
@@ 7,5 7,6 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
winapi = { version = "0.3.7", features = ["d3d11", "dxgi1_2", "libloaderapi", "winerror", "winuser"] }
winapi = { version = "0.3.7", features = ["d3d11", "d3dcompiler", "dxgi1_2",
    "libloaderapi", "winerror", "winuser"] }
wio = "0.2.2"

M src/d3d11.rs => src/d3d11.rs +175 -1
@@ 1,6 1,6 @@
use std::ptr::{null, null_mut};

use winapi::um::{d3d11, d3dcommon};
use winapi::um::{d3d11, d3dcommon, d3dcompiler};

use wio::com::ComPtr;



@@ 10,6 10,11 @@ pub struct D3D11Device(ComPtr<d3d11::ID3D11Device>);
pub struct D3D11DeviceContext(ComPtr<d3d11::ID3D11DeviceContext>);
pub struct D3D11Texture2D(pub ComPtr<d3d11::ID3D11Texture2D>);
pub struct D3D11RenderTargetView(pub ComPtr<d3d11::ID3D11RenderTargetView>);
pub struct D3D11Buffer(ComPtr<d3d11::ID3D11Buffer>);
pub struct D3DBlob(ComPtr<d3dcommon::ID3DBlob>);
pub struct D3D11VertexShader(ComPtr<d3d11::ID3D11VertexShader>);
pub struct D3D11PixelShader(ComPtr<d3d11::ID3D11PixelShader>);
pub struct D3D11InputLayout(ComPtr<d3d11::ID3D11InputLayout>);

impl D3D11Device {
    // This function only supports a fraction of available options.


@@ 51,12 56,181 @@ impl D3D11Device {
            wrap(hr, ptr, D3D11RenderTargetView)
        }
    }

    /// Create a buffer from data.
    ///
    /// This method doesn't expose all possible options and is not
    /// suitable for creating an uninitialized buffer.
    pub fn create_buffer_from_data<T>(
        &self,
        data: &[T],
        usage: d3d11::D3D11_USAGE,
        bind_flags: u32,
        cpu_access_flags: u32,
        misc_flags: u32,
        is_srv: bool,
    ) -> Result<D3D11Buffer, Error> {
        unsafe {
            let mut ptr = null_mut();
            let size = std::mem::size_of_val(data);
            // TODO: this should probably be try_from
            assert!(size <= 0xffff_ffff);
            let byte_stride = if is_srv { std::mem::size_of::<T>() } else { 0 };
            assert!(byte_stride <= 0xffff_ffff);
            let desc = d3d11::D3D11_BUFFER_DESC {
                ByteWidth: size as u32,
                Usage: usage,
                BindFlags: bind_flags,
                CPUAccessFlags: cpu_access_flags,
                MiscFlags: misc_flags,
                StructureByteStride: byte_stride as u32,
            };
            let srd = d3d11::D3D11_SUBRESOURCE_DATA {
                pSysMem: data.as_ptr() as *const _,
                SysMemPitch: 0,
                SysMemSlicePitch: 0,
            };
            let hr = self.0.CreateBuffer(&desc, &srd, &mut ptr);
            wrap(hr, ptr, D3D11Buffer)
        }
    }

    pub fn create_vertex_shader(&self, shader: &D3DBlob) -> Result<D3D11VertexShader, Error> {
        unsafe {
            let mut ptr = null_mut();
            let hr = self.0.CreateVertexShader(
                shader.0.GetBufferPointer(),
                shader.0.GetBufferSize(),
                null_mut(),
                &mut ptr,
            );
            wrap(hr, ptr, D3D11VertexShader)
        }
    }

    pub fn create_pixel_shader(&self, shader: &D3DBlob) -> Result<D3D11PixelShader, Error> {
        unsafe {
            let mut ptr = null_mut();
            let hr = self.0.CreatePixelShader(
                shader.0.GetBufferPointer(),
                shader.0.GetBufferSize(),
                null_mut(),
                &mut ptr,
            );
            wrap(hr, ptr, D3D11PixelShader)
        }
    }

    pub fn create_input_layout(
        &self,
        descs: &[d3d11::D3D11_INPUT_ELEMENT_DESC],
        bytecode: &D3DBlob,
    ) -> Result<D3D11InputLayout, Error> {
        unsafe {
            assert!(descs.len() <= 0xffff_ffff);
            let mut ptr = null_mut();
            let hr = self.0.CreateInputLayout(
                descs.as_ptr(),
                descs.len() as u32,
                bytecode.0.GetBufferPointer(),
                bytecode.0.GetBufferSize(),
                &mut ptr,
            );
            wrap(hr, ptr, D3D11InputLayout)
        }
    }
}

impl D3D11DeviceContext {
    /// Sets a single render target, no stencil.
    pub fn set_render_target(&mut self, rtv: &D3D11RenderTargetView) {
        unsafe {
            let rtvs = [rtv.0.as_raw()];
            self.0.OMSetRenderTargets(1, rtvs.as_ptr(), null_mut());
        }
    }

    /// Sets a single viewport.
    pub fn set_viewport(&mut self, viewport: &d3d11::D3D11_VIEWPORT) {
        unsafe {
            self.0.RSSetViewports(1, viewport);
        }
    }

    pub fn clear_render_target_view(&mut self, rtv: &mut D3D11RenderTargetView, color: &[f32; 4]) {
        unsafe {
            self.0.ClearRenderTargetView(rtv.0.as_raw(), color);
        }
    }

    pub fn vs_set_shader(&mut self, shader: &D3D11VertexShader) {
        unsafe {
            self.0.VSSetShader(shader.0.as_raw(), null(), 0);
        }
    }

    pub fn ps_set_shader(&mut self, shader: &D3D11PixelShader) {
        unsafe {
            self.0.PSSetShader(shader.0.as_raw(), null(), 0);
        }
    }

    pub fn ia_set_vertex_buffer(&mut self, buf: &D3D11Buffer) {
        let stride = std::mem::size_of::<[f32; 3]>();
        let bufs = [buf.0.as_raw()];
        let strides = [stride as u32];
        let offsets = [0];
        unsafe {
            self.0
                .IASetVertexBuffers(0, 1, bufs.as_ptr(), strides.as_ptr(), offsets.as_ptr());
        }
    }

    pub fn ia_set_primitive_topology(&mut self, topology: d3d11::D3D11_PRIMITIVE_TOPOLOGY) {
        unsafe {
            self.0.IASetPrimitiveTopology(topology);
        }
    }

    pub fn ia_set_input_layout(&mut self, layout: &D3D11InputLayout) {
        unsafe {
            self.0.IASetInputLayout(layout.0.as_raw());
        }
    }

    pub fn draw(&mut self, count: u32, start: u32) {
        unsafe {
            self.0.Draw(count, start);
        }
    }
}

impl D3DBlob {
    pub fn compile_shader(
        hlsl: &str,
        target: &str,
        entry: &str,
        flags: u32,
    ) -> Result<D3DBlob, Error> {
        let target = [target, "\0"].concat();
        let entry = [entry, "\0"].concat();
        unsafe {
            let mut ptr = null_mut();
            let hr = d3dcompiler::D3DCompile(
                hlsl.as_ptr() as *const _,
                hlsl.len(),
                null(),
                null(),
                d3dcompiler::D3D_COMPILE_STANDARD_FILE_INCLUDE,
                entry.as_ptr() as *const _,
                target.as_ptr() as *const _,
                flags,
                0,
                &mut ptr,
                null_mut(),
            );
            //println!("blob: {} bytes", (*ptr).GetBufferSize());
            wrap(hr, ptr, D3DBlob)
        }
    }
}

M src/main.rs => src/main.rs +75 -2
@@ 2,6 2,9 @@ use std::ptr::{null, null_mut};

use winapi::shared::dxgi::DXGI_SWAP_EFFECT_FLIP_DISCARD;
use winapi::shared::{dxgi1_2, dxgiformat, dxgitype, minwindef};
use winapi::shared::dxgiformat::DXGI_FORMAT_R32G32B32_FLOAT;
use winapi::um::d3dcommon::D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
use winapi::um::d3d11::D3D11_INPUT_PER_VERTEX_DATA;
use winapi::um::{wingdi, winuser};

use wio::wide::ToWide;


@@ 10,6 13,22 @@ mod d3d11;
mod dxgi;
mod util;

use d3d11::D3DBlob;

const VERTEX_SHADER_HLSL: &str = r#"
float4 main( float4 pos : POSITION ) : SV_POSITION
{
	return pos;
}
"#;

const PIXEL_SHADER_HLSL: &str = r#"
float4 main() : SV_TARGET
{
	return float4(1.0f, 1.0f, 1.0f, 1.0f);
}
"#;

fn main() {
    unsafe {
        let class_name = "dx11".to_wide_null();


@@ 44,7 63,7 @@ fn main() {
            null_mut(),
        );

        let (d3d_device, mut d3d_device_context) = d3d11::D3D11Device::create().unwrap();
        let (d3d_device, mut device_context) = d3d11::D3D11Device::create().unwrap();
        let dxgi_factory = dxgi::DXGIFactory2::create().unwrap();
        let desc = dxgi1_2::DXGI_SWAP_CHAIN_DESC1 {
            Width: 0,


@@ 67,9 86,63 @@ fn main() {
            .create_swapchain_for_hwnd(&d3d_device, hwnd, &desc)
            .unwrap();

        let vertex_shader_bc =
            D3DBlob::compile_shader(VERTEX_SHADER_HLSL, "vs_5_0", "main", 0).unwrap();
        let vertex_shader = d3d_device.create_vertex_shader(&vertex_shader_bc).unwrap();
        let pixel_shader_bc =
            D3DBlob::compile_shader(PIXEL_SHADER_HLSL, "ps_5_0", "main", 0).unwrap();
        let pixel_shader = d3d_device.create_pixel_shader(&pixel_shader_bc).unwrap();

        let ieds = [
            winapi::um::d3d11::D3D11_INPUT_ELEMENT_DESC {
                SemanticName: "POSITION\0".as_ptr() as *const _,
                SemanticIndex: 0,
                Format: DXGI_FORMAT_R32G32B32_FLOAT,
                InputSlot: 0,
                AlignedByteOffset: 0,
                InputSlotClass: D3D11_INPUT_PER_VERTEX_DATA,
                InstanceDataStepRate: 0,
            },
        ];
        let input_layout = d3d_device.create_input_layout(&ieds, &vertex_shader_bc).unwrap();

        device_context.vs_set_shader(&vertex_shader);
        device_context.ps_set_shader(&pixel_shader);
        device_context.ia_set_input_layout(&input_layout);

        let viewport = winapi::um::d3d11::D3D11_VIEWPORT {
            TopLeftX: 0.,
            TopLeftY: 0.,
            Width: 800., // TODO set dynamically
            Height: 600., // TODO set dynamically
            MinDepth: 0.,
            MaxDepth: 0.,
        };
        device_context.set_viewport(&viewport);

        let buf = swap_chain.get_buffer(0).unwrap();
        let mut rtv = d3d_device.create_render_target_view(&buf).unwrap();
        d3d_device_context.clear_render_target_view(&mut rtv, &[0.0, 0.2, 0.4, 1.0]);
        device_context.set_render_target(&rtv);
        device_context.clear_render_target_view(&mut rtv, &[0.0, 0.2, 0.4, 1.0]);

        let vertices = [
            [0.0f32, 0.5f32, 0.0f32],
            [0.45f32, -0.5f32, 0.0f32],
            [-0.45f32, -0.5f32, 0.0f32],
        ];
        let vertex_buf = d3d_device
            .create_buffer_from_data(
                &vertices,
                winapi::um::d3d11::D3D11_USAGE_DEFAULT,
                winapi::um::d3d11::D3D11_BIND_VERTEX_BUFFER,
                0,
                0,
                false,
            )
            .unwrap();
        device_context.ia_set_vertex_buffer(&vertex_buf);
        device_context.ia_set_primitive_topology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
        device_context.draw(3, 0);

        swap_chain.present(1, 0).unwrap();
        // Show window after first present to avoid flash of background color.