directx_renderer.rs

   1use std::{collections::HashMap, hash::BuildHasherDefault, sync::Arc};
   2
   3use ::util::ResultExt;
   4use anyhow::{Context, Result};
   5use collections::FxHasher;
   6// #[cfg(not(feature = "enable-renderdoc"))]
   7// use windows::Win32::Graphics::DirectComposition::*;
   8use windows::{
   9    Win32::{
  10        Foundation::{HMODULE, HWND},
  11        Graphics::{
  12            Direct3D::*,
  13            Direct3D11::*,
  14            Dxgi::{Common::*, *},
  15        },
  16    },
  17    core::*,
  18};
  19
  20use crate::*;
  21
  22pub(crate) struct DirectXRenderer {
  23    atlas: Arc<DirectXAtlas>,
  24    devices: DirectXDevices,
  25    context: DirectXContext,
  26    globals: DirectXGlobalElements,
  27    pipelines: DirectXRenderPipelines,
  28    hwnd: HWND,
  29    transparent: bool,
  30}
  31
  32#[derive(Clone)]
  33pub(crate) struct DirectXDevices {
  34    dxgi_factory: IDXGIFactory6,
  35    dxgi_device: IDXGIDevice,
  36    device: ID3D11Device,
  37    device_context: ID3D11DeviceContext,
  38}
  39
  40struct DirectXContext {
  41    swap_chain: IDXGISwapChain1,
  42    back_buffer: [Option<ID3D11RenderTargetView>; 1],
  43    viewport: [D3D11_VIEWPORT; 1],
  44    // #[cfg(not(feature = "enable-renderdoc"))]
  45    // direct_composition: DirectComposition,
  46}
  47
  48struct DirectXRenderPipelines {
  49    shadow_pipeline: PipelineState,
  50    quad_pipeline: PipelineState,
  51    paths_pipeline: PathsPipelineState,
  52    underline_pipeline: PipelineState,
  53    mono_sprites: PipelineState,
  54    poly_sprites: PipelineState,
  55}
  56
  57struct DirectXGlobalElements {
  58    global_params_buffer: [Option<ID3D11Buffer>; 1],
  59    sampler: [Option<ID3D11SamplerState>; 1],
  60    blend_state: ID3D11BlendState,
  61    blend_state_for_pr: ID3D11BlendState,
  62}
  63
  64#[repr(C)]
  65struct DrawInstancedIndirectArgs {
  66    vertex_count_per_instance: u32,
  67    instance_count: u32,
  68    start_vertex_location: u32,
  69    start_instance_location: u32,
  70}
  71
  72// #[cfg(not(feature = "enable-renderdoc"))]
  73// struct DirectComposition {
  74//     comp_device: IDCompositionDevice,
  75//     comp_target: IDCompositionTarget,
  76//     comp_visual: IDCompositionVisual,
  77// }
  78
  79impl DirectXDevices {
  80    pub(crate) fn new() -> Result<Self> {
  81        let dxgi_factory = get_dxgi_factory()?;
  82        let adapter = get_adapter(&dxgi_factory)?;
  83        let (device, device_context) = {
  84            let mut device: Option<ID3D11Device> = None;
  85            let mut context: Option<ID3D11DeviceContext> = None;
  86            get_device(&adapter, Some(&mut device), Some(&mut context))?;
  87            (device.unwrap(), context.unwrap())
  88        };
  89        let dxgi_device: IDXGIDevice = device.cast()?;
  90
  91        Ok(Self {
  92            dxgi_factory,
  93            dxgi_device,
  94            device,
  95            device_context,
  96        })
  97    }
  98}
  99
 100impl DirectXRenderer {
 101    pub(crate) fn new(devices: &DirectXDevices, hwnd: HWND, transparent: bool) -> Result<Self> {
 102        let atlas = Arc::new(DirectXAtlas::new(
 103            devices.device.clone(),
 104            devices.device_context.clone(),
 105        ));
 106        let context = DirectXContext::new(devices, hwnd, transparent)?;
 107        let globals = DirectXGlobalElements::new(&devices.device)?;
 108        let pipelines = DirectXRenderPipelines::new(&devices.device)?;
 109        Ok(DirectXRenderer {
 110            atlas,
 111            devices: devices.clone(),
 112            context,
 113            globals,
 114            pipelines,
 115            hwnd,
 116            transparent,
 117        })
 118    }
 119
 120    pub(crate) fn sprite_atlas(&self) -> Arc<dyn PlatformAtlas> {
 121        self.atlas.clone()
 122    }
 123
 124    pub(crate) fn draw(&mut self, scene: &Scene) -> Result<()> {
 125        pre_draw(
 126            &self.devices.device_context,
 127            &self.globals.global_params_buffer,
 128            &self.context.viewport,
 129            &self.context.back_buffer,
 130            [0.0, 0.0, 0.0, 0.0],
 131            &self.globals.blend_state,
 132        )?;
 133        for batch in scene.batches() {
 134            match batch {
 135                PrimitiveBatch::Shadows(shadows) => self.draw_shadows(shadows),
 136                PrimitiveBatch::Quads(quads) => self.draw_quads(quads),
 137                PrimitiveBatch::Paths(paths) => self.draw_paths(paths),
 138                PrimitiveBatch::Underlines(underlines) => self.draw_underlines(underlines),
 139                PrimitiveBatch::MonochromeSprites {
 140                    texture_id,
 141                    sprites,
 142                } => self.draw_monochrome_sprites(texture_id, sprites),
 143                PrimitiveBatch::PolychromeSprites {
 144                    texture_id,
 145                    sprites,
 146                } => self.draw_polychrome_sprites(texture_id, sprites),
 147                PrimitiveBatch::Surfaces(surfaces) => self.draw_surfaces(surfaces),
 148            }.context(format!("scene too large: {} paths, {} shadows, {} quads, {} underlines, {} mono, {} poly, {} surfaces",
 149                    scene.paths.len(),
 150                    scene.shadows.len(),
 151                    scene.quads.len(),
 152                    scene.underlines.len(),
 153                    scene.monochrome_sprites.len(),
 154                    scene.polychrome_sprites.len(),
 155                    scene.surfaces.len(),))?;
 156        }
 157        unsafe { self.context.swap_chain.Present(0, DXGI_PRESENT(0)) }.ok()?;
 158        Ok(())
 159    }
 160
 161    pub(crate) fn resize(&mut self, new_size: Size<DevicePixels>) -> Result<()> {
 162        unsafe { self.devices.device_context.OMSetRenderTargets(None, None) };
 163        drop(self.context.back_buffer[0].take().unwrap());
 164        unsafe {
 165            self.context.swap_chain.ResizeBuffers(
 166                BUFFER_COUNT as u32,
 167                new_size.width.0 as u32,
 168                new_size.height.0 as u32,
 169                DXGI_FORMAT_B8G8R8A8_UNORM,
 170                DXGI_SWAP_CHAIN_FLAG(0),
 171            )?;
 172        }
 173        let backbuffer = set_render_target_view(
 174            &self.context.swap_chain,
 175            &self.devices.device,
 176            &self.devices.device_context,
 177        )?;
 178        self.context.back_buffer[0] = Some(backbuffer);
 179        self.context.viewport = set_viewport(
 180            &self.devices.device_context,
 181            new_size.width.0 as f32,
 182            new_size.height.0 as f32,
 183        );
 184        Ok(())
 185    }
 186
 187    // #[cfg(not(feature = "enable-renderdoc"))]
 188    // pub(crate) fn update_transparency(
 189    //     &mut self,
 190    //     background_appearance: WindowBackgroundAppearance,
 191    // ) -> Result<()> {
 192    //     // We only support setting `Transparent` and `Opaque` for now.
 193    //     match background_appearance {
 194    //         WindowBackgroundAppearance::Opaque => {
 195    //             if self.transparent {
 196    //                 return Err(anyhow::anyhow!(
 197    //                     "Set opaque backgroud from transparent background, a restart is required. Or, you can open a new window."
 198    //                 ));
 199    //             }
 200    //         }
 201    //         WindowBackgroundAppearance::Transparent | WindowBackgroundAppearance::Blurred => {
 202    //             if !self.transparent {
 203    //                 return Err(anyhow::anyhow!(
 204    //                     "Set transparent backgroud from opaque background, a restart is required. Or, you can open a new window."
 205    //                 ));
 206    //             }
 207    //         }
 208    //     }
 209    //     Ok(())
 210    // }
 211
 212    // #[cfg(feature = "enable-renderdoc")]
 213    pub(crate) fn update_transparency(
 214        &mut self,
 215        background_appearance: WindowBackgroundAppearance,
 216    ) -> Result<()> {
 217        if background_appearance != WindowBackgroundAppearance::Opaque {
 218            Err(anyhow::anyhow!(
 219                "Set transparent background not supported when feature \"enable-renderdoc\" is enabled."
 220            ))
 221        } else {
 222            Ok(())
 223        }
 224    }
 225
 226    fn draw_shadows(&mut self, shadows: &[Shadow]) -> Result<()> {
 227        if shadows.is_empty() {
 228            return Ok(());
 229        }
 230        update_buffer_capacity(
 231            &self.pipelines.shadow_pipeline,
 232            std::mem::size_of::<Shadow>(),
 233            shadows.len(),
 234            &self.devices.device,
 235        )
 236        .map(|input| update_pipeline(&mut self.pipelines.shadow_pipeline, input));
 237        update_buffer(
 238            &self.devices.device_context,
 239            &self.pipelines.shadow_pipeline.buffer,
 240            shadows,
 241        )?;
 242        draw_normal(
 243            &self.devices.device_context,
 244            &self.pipelines.shadow_pipeline,
 245            &self.context.viewport,
 246            &self.globals.global_params_buffer,
 247            D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,
 248            4,
 249            shadows.len() as u32,
 250        )
 251    }
 252
 253    fn draw_quads(&mut self, quads: &[Quad]) -> Result<()> {
 254        if quads.is_empty() {
 255            return Ok(());
 256        }
 257        update_buffer_capacity(
 258            &self.pipelines.quad_pipeline,
 259            std::mem::size_of::<Quad>(),
 260            quads.len(),
 261            &self.devices.device,
 262        )
 263        .map(|input| update_pipeline(&mut self.pipelines.quad_pipeline, input));
 264        update_buffer(
 265            &self.devices.device_context,
 266            &self.pipelines.quad_pipeline.buffer,
 267            quads,
 268        )?;
 269        draw_normal(
 270            &self.devices.device_context,
 271            &self.pipelines.quad_pipeline,
 272            &self.context.viewport,
 273            &self.globals.global_params_buffer,
 274            D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,
 275            4,
 276            quads.len() as u32,
 277        )
 278    }
 279
 280    fn draw_paths(&mut self, paths: &[Path<ScaledPixels>]) -> Result<()> {
 281        if paths.is_empty() {
 282            return Ok(());
 283        }
 284        println!("Drawing {} paths", paths.len());
 285        let mut vertices = Vec::new();
 286        let mut sprites = Vec::with_capacity(paths.len());
 287        let mut draw_indirect_commands = Vec::with_capacity(paths.len());
 288        let mut start_vertex_location = 0;
 289        for (i, path) in paths.iter().enumerate() {
 290            draw_indirect_commands.push(DrawInstancedIndirectArgs {
 291                vertex_count_per_instance: path.vertices.len() as u32,
 292                instance_count: 1,
 293                start_vertex_location,
 294                start_instance_location: i as u32,
 295            });
 296            start_vertex_location += path.vertices.len() as u32;
 297
 298            vertices.extend(path.vertices.iter().map(|v| PathVertex {
 299                xy_position: v.xy_position,
 300                content_mask: ContentMask {
 301                    bounds: path.content_mask.bounds,
 302                },
 303            }));
 304
 305            sprites.push(PathSprite {
 306                bounds: path.bounds,
 307                color: path.color,
 308            });
 309        }
 310
 311        update_paths_buffer_capacity(
 312            &self.pipelines.paths_pipeline,
 313            sprites.len(),
 314            &self.devices.device,
 315        )
 316        .map(|input| update_paths_pipeline_buffer(&mut self.pipelines.paths_pipeline, input));
 317        update_buffer(
 318            &self.devices.device_context,
 319            &self.pipelines.paths_pipeline.buffer,
 320            &sprites,
 321        )?;
 322        update_paths_vertex_capacity(
 323            &mut self.pipelines.paths_pipeline,
 324            vertices.len(),
 325            &self.devices.device,
 326        )
 327        .map(|input| update_paths_pipeline_vertex(&mut self.pipelines.paths_pipeline, input));
 328        update_buffer(
 329            &self.devices.device_context,
 330            &self.pipelines.paths_pipeline.vertex_buffer,
 331            &vertices,
 332        )?;
 333        update_indirect_buffer_capacity(
 334            &self.pipelines.paths_pipeline,
 335            draw_indirect_commands.len(),
 336            &self.devices.device,
 337        )
 338        .map(|input| update_paths_indirect_buffer(&mut self.pipelines.paths_pipeline, input));
 339        update_buffer(
 340            &self.devices.device_context,
 341            &self.pipelines.paths_pipeline.indirect_draw_buffer,
 342            &draw_indirect_commands,
 343        )?;
 344        prepare_indirect_draws(
 345            &self.devices.device_context,
 346            &self.pipelines.paths_pipeline,
 347            &self.context.viewport,
 348            &self.globals.global_params_buffer,
 349            D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST,
 350        )?;
 351
 352        for i in 0..paths.len() {
 353            draw_indirect(
 354                &self.devices.device_context,
 355                &self.pipelines.paths_pipeline.indirect_draw_buffer,
 356                (i * std::mem::size_of::<DrawInstancedIndirectArgs>()) as u32,
 357            );
 358        }
 359        Ok(())
 360    }
 361
 362    fn draw_underlines(&mut self, underlines: &[Underline]) -> Result<()> {
 363        if underlines.is_empty() {
 364            return Ok(());
 365        }
 366        update_buffer_capacity(
 367            &self.pipelines.underline_pipeline,
 368            std::mem::size_of::<Underline>(),
 369            underlines.len(),
 370            &self.devices.device,
 371        )
 372        .map(|input| update_pipeline(&mut self.pipelines.underline_pipeline, input));
 373        update_buffer(
 374            &self.devices.device_context,
 375            &self.pipelines.underline_pipeline.buffer,
 376            underlines,
 377        )?;
 378        draw_normal(
 379            &self.devices.device_context,
 380            &self.pipelines.underline_pipeline,
 381            &self.context.viewport,
 382            &self.globals.global_params_buffer,
 383            D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,
 384            4,
 385            underlines.len() as u32,
 386        )
 387    }
 388
 389    fn draw_monochrome_sprites(
 390        &mut self,
 391        texture_id: AtlasTextureId,
 392        sprites: &[MonochromeSprite],
 393    ) -> Result<()> {
 394        if sprites.is_empty() {
 395            return Ok(());
 396        }
 397        let texture_view = self.atlas.get_texture_view(texture_id);
 398        update_buffer_capacity(
 399            &self.pipelines.mono_sprites,
 400            std::mem::size_of::<MonochromeSprite>(),
 401            sprites.len(),
 402            &self.devices.device,
 403        )
 404        .map(|input| update_pipeline(&mut self.pipelines.mono_sprites, input));
 405        update_buffer(
 406            &self.devices.device_context,
 407            &self.pipelines.mono_sprites.buffer,
 408            sprites,
 409        )?;
 410        draw_with_texture(
 411            &self.devices.device_context,
 412            &self.pipelines.mono_sprites,
 413            &texture_view,
 414            &self.context.viewport,
 415            &self.globals.global_params_buffer,
 416            &self.globals.sampler,
 417            sprites.len() as u32,
 418        )
 419    }
 420
 421    fn draw_polychrome_sprites(
 422        &mut self,
 423        texture_id: AtlasTextureId,
 424        sprites: &[PolychromeSprite],
 425    ) -> Result<()> {
 426        if sprites.is_empty() {
 427            return Ok(());
 428        }
 429        let texture_view = self.atlas.get_texture_view(texture_id);
 430        update_buffer_capacity(
 431            &self.pipelines.poly_sprites,
 432            std::mem::size_of::<PolychromeSprite>(),
 433            sprites.len(),
 434            &self.devices.device,
 435        )
 436        .map(|input| update_pipeline(&mut self.pipelines.poly_sprites, input));
 437        update_buffer(
 438            &self.devices.device_context,
 439            &self.pipelines.poly_sprites.buffer,
 440            sprites,
 441        )?;
 442        draw_with_texture(
 443            &self.devices.device_context,
 444            &self.pipelines.poly_sprites,
 445            &texture_view,
 446            &self.context.viewport,
 447            &self.globals.global_params_buffer,
 448            &self.globals.sampler,
 449            sprites.len() as u32,
 450        )
 451    }
 452
 453    fn draw_surfaces(&mut self, surfaces: &[PaintSurface]) -> Result<()> {
 454        if surfaces.is_empty() {
 455            return Ok(());
 456        }
 457        Ok(())
 458    }
 459}
 460
 461impl DirectXContext {
 462    pub fn new(devices: &DirectXDevices, hwnd: HWND, transparent: bool) -> Result<Self> {
 463        // #[cfg(not(feature = "enable-renderdoc"))]
 464        // let swap_chain = create_swap_chain(&devices.dxgi_factory, &devices.device, transparent)?;
 465        // #[cfg(feature = "enable-renderdoc")]
 466        let swap_chain =
 467            create_swap_chain_default(&devices.dxgi_factory, &devices.device, hwnd, transparent)?;
 468        // #[cfg(not(feature = "enable-renderdoc"))]
 469        // let direct_composition = DirectComposition::new(&devices.dxgi_device, hwnd)?;
 470        // #[cfg(not(feature = "enable-renderdoc"))]
 471        // direct_composition.set_swap_chain(&swap_chain)?;
 472        let back_buffer = [Some(set_render_target_view(
 473            &swap_chain,
 474            &devices.device,
 475            &devices.device_context,
 476        )?)];
 477        let viewport = set_viewport(&devices.device_context, 1.0, 1.0);
 478        set_rasterizer_state(&devices.device, &devices.device_context)?;
 479
 480        Ok(Self {
 481            swap_chain,
 482            back_buffer,
 483            viewport,
 484            // #[cfg(not(feature = "enable-renderdoc"))]
 485            // direct_composition,
 486        })
 487    }
 488}
 489
 490impl DirectXRenderPipelines {
 491    pub fn new(device: &ID3D11Device) -> Result<Self> {
 492        let shadow_pipeline = create_pipieline(
 493            device,
 494            "shadow_vertex",
 495            "shadow_fragment",
 496            std::mem::size_of::<Shadow>(),
 497            32,
 498        )?;
 499        let quad_pipeline = create_pipieline(
 500            device,
 501            "quad_vertex",
 502            "quad_fragment",
 503            std::mem::size_of::<Quad>(),
 504            32,
 505        )?;
 506        // let paths_pipeline = create_pipieline(
 507        //     device,
 508        //     "paths_vertex",
 509        //     "paths_fragment",
 510        //     std::mem::size_of::<PathSprite>(),
 511        //     32,
 512        // )?;
 513        let paths_pipeline = PathsPipelineState::new(device)?;
 514        let underline_pipeline = create_pipieline(
 515            device,
 516            "underline_vertex",
 517            "underline_fragment",
 518            std::mem::size_of::<Underline>(),
 519            32,
 520        )?;
 521        let mono_sprites = create_pipieline(
 522            device,
 523            "monochrome_sprite_vertex",
 524            "monochrome_sprite_fragment",
 525            std::mem::size_of::<MonochromeSprite>(),
 526            32,
 527        )?;
 528        let poly_sprites = create_pipieline(
 529            device,
 530            "polychrome_sprite_vertex",
 531            "polychrome_sprite_fragment",
 532            std::mem::size_of::<PolychromeSprite>(),
 533            32,
 534        )?;
 535
 536        Ok(Self {
 537            shadow_pipeline,
 538            quad_pipeline,
 539            paths_pipeline,
 540            underline_pipeline,
 541            mono_sprites,
 542            poly_sprites,
 543        })
 544    }
 545}
 546
 547// #[cfg(not(feature = "enable-renderdoc"))]
 548// impl DirectComposition {
 549//     pub fn new(dxgi_device: &IDXGIDevice, hwnd: HWND) -> Result<Self> {
 550//         let comp_device = get_comp_device(&dxgi_device)?;
 551//         let comp_target = unsafe { comp_device.CreateTargetForHwnd(hwnd, true) }?;
 552//         let comp_visual = unsafe { comp_device.CreateVisual() }?;
 553
 554//         Ok(Self {
 555//             comp_device,
 556//             comp_target,
 557//             comp_visual,
 558//         })
 559//     }
 560
 561//     pub fn set_swap_chain(&self, swap_chain: &IDXGISwapChain1) -> Result<()> {
 562//         unsafe {
 563//             self.comp_visual.SetContent(swap_chain)?;
 564//             self.comp_target.SetRoot(&self.comp_visual)?;
 565//             self.comp_device.Commit()?;
 566//         }
 567//         Ok(())
 568//     }
 569// }
 570
 571impl DirectXGlobalElements {
 572    pub fn new(device: &ID3D11Device) -> Result<Self> {
 573        let global_params_buffer = unsafe {
 574            let desc = D3D11_BUFFER_DESC {
 575                ByteWidth: std::mem::size_of::<GlobalParams>() as u32,
 576                Usage: D3D11_USAGE_DYNAMIC,
 577                BindFlags: D3D11_BIND_CONSTANT_BUFFER.0 as u32,
 578                CPUAccessFlags: D3D11_CPU_ACCESS_WRITE.0 as u32,
 579                ..Default::default()
 580            };
 581            let mut buffer = None;
 582            device.CreateBuffer(&desc, None, Some(&mut buffer))?;
 583            [buffer]
 584        };
 585
 586        let sampler = unsafe {
 587            let desc = D3D11_SAMPLER_DESC {
 588                Filter: D3D11_FILTER_MIN_MAG_MIP_LINEAR,
 589                AddressU: D3D11_TEXTURE_ADDRESS_WRAP,
 590                AddressV: D3D11_TEXTURE_ADDRESS_WRAP,
 591                AddressW: D3D11_TEXTURE_ADDRESS_WRAP,
 592                MipLODBias: 0.0,
 593                MaxAnisotropy: 1,
 594                ComparisonFunc: D3D11_COMPARISON_ALWAYS,
 595                BorderColor: [0.0; 4],
 596                MinLOD: 0.0,
 597                MaxLOD: D3D11_FLOAT32_MAX,
 598            };
 599            let mut output = None;
 600            device.CreateSamplerState(&desc, Some(&mut output))?;
 601            [output]
 602        };
 603
 604        let blend_state = create_blend_state(device)?;
 605        let blend_state_for_pr = create_blend_state_for_path_raster(device)?;
 606
 607        Ok(Self {
 608            global_params_buffer,
 609            sampler,
 610            blend_state,
 611            blend_state_for_pr,
 612        })
 613    }
 614}
 615
 616#[derive(Debug, Default)]
 617#[repr(C)]
 618struct GlobalParams {
 619    viewport_size: [f32; 2],
 620    _pad: u64,
 621}
 622
 623struct PipelineState {
 624    vertex: ID3D11VertexShader,
 625    fragment: ID3D11PixelShader,
 626    buffer: ID3D11Buffer,
 627    buffer_size: usize,
 628    view: [Option<ID3D11ShaderResourceView>; 1],
 629}
 630
 631struct PathsPipelineState {
 632    vertex: ID3D11VertexShader,
 633    fragment: ID3D11PixelShader,
 634    buffer: ID3D11Buffer,
 635    buffer_size: usize,
 636    vertex_buffer: ID3D11Buffer,
 637    vertex_buffer_size: usize,
 638    indirect_draw_buffer: ID3D11Buffer,
 639    indirect_buffer_size: usize,
 640    view: [Option<ID3D11ShaderResourceView>; 1],
 641    vertex_view: [Option<ID3D11ShaderResourceView>; 1],
 642}
 643
 644impl PathsPipelineState {
 645    fn new(device: &ID3D11Device) -> Result<Self> {
 646        let vertex = {
 647            let shader_blob = shader_resources::build_shader_blob("paths_vertex", "vs_5_0")?;
 648            let bytes = unsafe {
 649                std::slice::from_raw_parts(
 650                    shader_blob.GetBufferPointer() as *mut u8,
 651                    shader_blob.GetBufferSize(),
 652                )
 653            };
 654            create_vertex_shader(device, bytes)?
 655        };
 656        let fragment = {
 657            let shader_blob = shader_resources::build_shader_blob("paths_fragment", "ps_5_0")?;
 658            let bytes = unsafe {
 659                std::slice::from_raw_parts(
 660                    shader_blob.GetBufferPointer() as *mut u8,
 661                    shader_blob.GetBufferSize(),
 662                )
 663            };
 664            create_fragment_shader(device, bytes)?
 665        };
 666        let buffer = create_buffer(device, std::mem::size_of::<PathSprite>(), 32)?;
 667        let view = create_buffer_view(device, &buffer)?;
 668        let vertex_buffer =
 669            create_buffer(device, std::mem::size_of::<PathVertex<ScaledPixels>>(), 32)?;
 670        let vertex_view = create_buffer_view(device, &vertex_buffer)?;
 671        let indirect_draw_buffer = create_indirect_draw_buffer(device, 32)?;
 672        Ok(Self {
 673            vertex,
 674            fragment,
 675            buffer,
 676            buffer_size: 32,
 677            vertex_buffer,
 678            vertex_buffer_size: 32,
 679            indirect_draw_buffer,
 680            indirect_buffer_size: 32,
 681            view,
 682            vertex_view,
 683        })
 684    }
 685}
 686
 687#[derive(Clone, Debug, Eq, PartialEq)]
 688#[repr(C)]
 689struct PathSprite {
 690    bounds: Bounds<ScaledPixels>,
 691    color: Background,
 692}
 693
 694fn get_dxgi_factory() -> Result<IDXGIFactory6> {
 695    #[cfg(debug_assertions)]
 696    let factory_flag = DXGI_CREATE_FACTORY_DEBUG;
 697    #[cfg(not(debug_assertions))]
 698    let factory_flag = 0u32;
 699    unsafe { Ok(CreateDXGIFactory2(factory_flag)?) }
 700}
 701
 702fn get_adapter(dxgi_factory: &IDXGIFactory6) -> Result<IDXGIAdapter1> {
 703    for adapter_index in 0.. {
 704        let adapter: IDXGIAdapter1 = unsafe {
 705            dxgi_factory
 706                .EnumAdapterByGpuPreference(adapter_index, DXGI_GPU_PREFERENCE_MINIMUM_POWER)
 707        }?;
 708        {
 709            let desc = unsafe { adapter.GetDesc1() }?;
 710            println!(
 711                "Select GPU: {}",
 712                String::from_utf16_lossy(&desc.Description)
 713            );
 714        }
 715        // Check to see whether the adapter supports Direct3D 11, but don't
 716        // create the actual device yet.
 717        if get_device(&adapter, None, None).log_err().is_some() {
 718            return Ok(adapter);
 719        }
 720    }
 721
 722    unreachable!()
 723}
 724
 725fn get_device(
 726    adapter: &IDXGIAdapter1,
 727    device: Option<*mut Option<ID3D11Device>>,
 728    context: Option<*mut Option<ID3D11DeviceContext>>,
 729) -> Result<()> {
 730    #[cfg(debug_assertions)]
 731    let device_flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT | D3D11_CREATE_DEVICE_DEBUG;
 732    #[cfg(not(debug_assertions))]
 733    let device_flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
 734    Ok(unsafe {
 735        D3D11CreateDevice(
 736            adapter,
 737            D3D_DRIVER_TYPE_UNKNOWN,
 738            HMODULE::default(),
 739            device_flags,
 740            Some(&[D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_11_1]),
 741            D3D11_SDK_VERSION,
 742            device,
 743            None,
 744            context,
 745        )?
 746    })
 747}
 748
 749// #[cfg(not(feature = "enable-renderdoc"))]
 750// fn get_comp_device(dxgi_device: &IDXGIDevice) -> Result<IDCompositionDevice> {
 751//     Ok(unsafe { DCompositionCreateDevice(dxgi_device)? })
 752// }
 753
 754// fn create_swap_chain(
 755//     dxgi_factory: &IDXGIFactory6,
 756//     device: &ID3D11Device,
 757//     transparent: bool,
 758// ) -> Result<IDXGISwapChain1> {
 759//     let alpha_mode = if transparent {
 760//         DXGI_ALPHA_MODE_PREMULTIPLIED
 761//     } else {
 762//         DXGI_ALPHA_MODE_IGNORE
 763//     };
 764//     let desc = DXGI_SWAP_CHAIN_DESC1 {
 765//         Width: 1,
 766//         Height: 1,
 767//         Format: DXGI_FORMAT_B8G8R8A8_UNORM,
 768//         Stereo: false.into(),
 769//         SampleDesc: DXGI_SAMPLE_DESC {
 770//             Count: 1,
 771//             Quality: 0,
 772//         },
 773//         BufferUsage: DXGI_USAGE_RENDER_TARGET_OUTPUT,
 774//         BufferCount: BUFFER_COUNT as u32,
 775//         // Composition SwapChains only support the DXGI_SCALING_STRETCH Scaling.
 776//         Scaling: DXGI_SCALING_STRETCH,
 777//         SwapEffect: DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL,
 778//         AlphaMode: alpha_mode,
 779//         Flags: 0,
 780//     };
 781//     Ok(unsafe { dxgi_factory.CreateSwapChainForComposition(device, &desc, None)? })
 782// }
 783
 784// #[cfg(feature = "enable-renderdoc")]
 785fn create_swap_chain_default(
 786    dxgi_factory: &IDXGIFactory6,
 787    device: &ID3D11Device,
 788    hwnd: HWND,
 789    _transparent: bool,
 790) -> Result<IDXGISwapChain1> {
 791    use windows::Win32::Graphics::Dxgi::DXGI_MWA_NO_ALT_ENTER;
 792
 793    let desc = DXGI_SWAP_CHAIN_DESC1 {
 794        Width: 1,
 795        Height: 1,
 796        Format: DXGI_FORMAT_B8G8R8A8_UNORM,
 797        Stereo: false.into(),
 798        SampleDesc: DXGI_SAMPLE_DESC {
 799            Count: 1,
 800            Quality: 0,
 801        },
 802        BufferUsage: DXGI_USAGE_RENDER_TARGET_OUTPUT,
 803        BufferCount: BUFFER_COUNT as u32,
 804        Scaling: DXGI_SCALING_STRETCH,
 805        SwapEffect: DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL,
 806        AlphaMode: DXGI_ALPHA_MODE_IGNORE,
 807        Flags: 0,
 808    };
 809    let swap_chain =
 810        unsafe { dxgi_factory.CreateSwapChainForHwnd(device, hwnd, &desc, None, None) }?;
 811    unsafe { dxgi_factory.MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER) }?;
 812    Ok(swap_chain)
 813}
 814
 815fn set_render_target_view(
 816    swap_chain: &IDXGISwapChain1,
 817    device: &ID3D11Device,
 818    device_context: &ID3D11DeviceContext,
 819) -> Result<ID3D11RenderTargetView> {
 820    // In dx11, ID3D11RenderTargetView is supposed to always point to the new back buffer.
 821    // https://stackoverflow.com/questions/65246961/does-the-backbuffer-that-a-rendertargetview-points-to-automagically-change-after
 822    let back_buffer = unsafe {
 823        let resource: ID3D11Texture2D = swap_chain.GetBuffer(0)?;
 824        let mut buffer: Option<ID3D11RenderTargetView> = None;
 825        device.CreateRenderTargetView(&resource, None, Some(&mut buffer))?;
 826        buffer.unwrap()
 827    };
 828    unsafe { device_context.OMSetRenderTargets(Some(&[Some(back_buffer.clone())]), None) };
 829    Ok(back_buffer)
 830}
 831
 832fn set_viewport(
 833    device_context: &ID3D11DeviceContext,
 834    width: f32,
 835    height: f32,
 836) -> [D3D11_VIEWPORT; 1] {
 837    let viewport = [D3D11_VIEWPORT {
 838        TopLeftX: 0.0,
 839        TopLeftY: 0.0,
 840        Width: width,
 841        Height: height,
 842        MinDepth: 0.0,
 843        MaxDepth: 1.0,
 844    }];
 845    unsafe { device_context.RSSetViewports(Some(&viewport)) };
 846    viewport
 847}
 848
 849fn set_rasterizer_state(device: &ID3D11Device, device_context: &ID3D11DeviceContext) -> Result<()> {
 850    let desc = D3D11_RASTERIZER_DESC {
 851        FillMode: D3D11_FILL_SOLID,
 852        CullMode: D3D11_CULL_NONE,
 853        FrontCounterClockwise: false.into(),
 854        DepthBias: 0,
 855        DepthBiasClamp: 0.0,
 856        SlopeScaledDepthBias: 0.0,
 857        DepthClipEnable: true.into(),
 858        ScissorEnable: false.into(),
 859        MultisampleEnable: false.into(),
 860        AntialiasedLineEnable: false.into(),
 861    };
 862    let rasterizer_state = unsafe {
 863        let mut state = None;
 864        device.CreateRasterizerState(&desc, Some(&mut state))?;
 865        state.unwrap()
 866    };
 867    unsafe { device_context.RSSetState(&rasterizer_state) };
 868    Ok(())
 869}
 870
 871// https://learn.microsoft.com/en-us/windows/win32/api/d3d11/ns-d3d11-d3d11_blend_desc
 872fn create_blend_state(device: &ID3D11Device) -> Result<ID3D11BlendState> {
 873    // If the feature level is set to greater than D3D_FEATURE_LEVEL_9_3, the display
 874    // device performs the blend in linear space, which is ideal.
 875    let mut desc = D3D11_BLEND_DESC::default();
 876    desc.RenderTarget[0].BlendEnable = true.into();
 877    desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
 878    desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
 879    desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
 880    desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
 881    desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
 882    desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE;
 883    desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL.0 as u8;
 884    unsafe {
 885        let mut state = None;
 886        device.CreateBlendState(&desc, Some(&mut state))?;
 887        Ok(state.unwrap())
 888    }
 889}
 890
 891fn create_blend_state_for_path_raster(device: &ID3D11Device) -> Result<ID3D11BlendState> {
 892    // If the feature level is set to greater than D3D_FEATURE_LEVEL_9_3, the display
 893    // device performs the blend in linear space, which is ideal.
 894    let mut desc = D3D11_BLEND_DESC::default();
 895    desc.RenderTarget[0].BlendEnable = true.into();
 896    desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
 897    desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
 898    desc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
 899    desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
 900    desc.RenderTarget[0].DestBlend = D3D11_BLEND_ONE;
 901    desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE;
 902    desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL.0 as u8;
 903    unsafe {
 904        let mut state = None;
 905        device.CreateBlendState(&desc, Some(&mut state))?;
 906        Ok(state.unwrap())
 907    }
 908}
 909
 910fn create_pipieline(
 911    device: &ID3D11Device,
 912    vertex_entry: &str,
 913    fragment_entry: &str,
 914    element_size: usize,
 915    buffer_size: usize,
 916) -> Result<PipelineState> {
 917    let vertex = {
 918        let shader_blob = shader_resources::build_shader_blob(vertex_entry, "vs_5_0")?;
 919        let bytes = unsafe {
 920            std::slice::from_raw_parts(
 921                shader_blob.GetBufferPointer() as *mut u8,
 922                shader_blob.GetBufferSize(),
 923            )
 924        };
 925        create_vertex_shader(device, bytes)?
 926    };
 927    let fragment = {
 928        let shader_blob = shader_resources::build_shader_blob(fragment_entry, "ps_5_0")?;
 929        let bytes = unsafe {
 930            std::slice::from_raw_parts(
 931                shader_blob.GetBufferPointer() as *mut u8,
 932                shader_blob.GetBufferSize(),
 933            )
 934        };
 935        create_fragment_shader(device, bytes)?
 936    };
 937    let buffer = create_buffer(device, element_size, buffer_size)?;
 938    let view = create_buffer_view(device, &buffer)?;
 939    Ok(PipelineState {
 940        vertex,
 941        fragment,
 942        buffer,
 943        buffer_size,
 944        view,
 945    })
 946}
 947
 948fn create_vertex_shader(device: &ID3D11Device, bytes: &[u8]) -> Result<ID3D11VertexShader> {
 949    unsafe {
 950        let mut shader = None;
 951        device.CreateVertexShader(bytes, None, Some(&mut shader))?;
 952        Ok(shader.unwrap())
 953    }
 954}
 955
 956fn create_fragment_shader(device: &ID3D11Device, bytes: &[u8]) -> Result<ID3D11PixelShader> {
 957    unsafe {
 958        let mut shader = None;
 959        device.CreatePixelShader(bytes, None, Some(&mut shader))?;
 960        Ok(shader.unwrap())
 961    }
 962}
 963
 964fn create_buffer(
 965    device: &ID3D11Device,
 966    element_size: usize,
 967    buffer_size: usize,
 968) -> Result<ID3D11Buffer> {
 969    let desc = D3D11_BUFFER_DESC {
 970        ByteWidth: (element_size * buffer_size) as u32,
 971        Usage: D3D11_USAGE_DYNAMIC,
 972        BindFlags: D3D11_BIND_SHADER_RESOURCE.0 as u32,
 973        CPUAccessFlags: D3D11_CPU_ACCESS_WRITE.0 as u32,
 974        MiscFlags: D3D11_RESOURCE_MISC_BUFFER_STRUCTURED.0 as u32,
 975        StructureByteStride: element_size as u32,
 976    };
 977    let mut buffer = None;
 978    unsafe { device.CreateBuffer(&desc, None, Some(&mut buffer)) }?;
 979    Ok(buffer.unwrap())
 980}
 981
 982fn create_buffer_view(
 983    device: &ID3D11Device,
 984    buffer: &ID3D11Buffer,
 985) -> Result<[Option<ID3D11ShaderResourceView>; 1]> {
 986    let mut view = None;
 987    unsafe { device.CreateShaderResourceView(buffer, None, Some(&mut view)) }?;
 988    Ok([view])
 989}
 990
 991fn create_indirect_draw_buffer(device: &ID3D11Device, buffer_size: u32) -> Result<ID3D11Buffer> {
 992    // let desc = D3D11_BUFFER_DESC {
 993    //     ByteWidth: std::mem::size_of::<DrawInstancedIndirectArgs>() as u32 * buffer_size,
 994    //     Usage: D3D11_USAGE_DYNAMIC,
 995    //     BindFlags: D3D11_BIND_INDIRECT_DRAW.0 as u32,
 996    //     MiscFlags: D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS.0 as u32,
 997    //     ..Default::default()
 998    // };
 999    let desc = D3D11_BUFFER_DESC {
1000        ByteWidth: std::mem::size_of::<DrawInstancedIndirectArgs>() as u32 * buffer_size,
1001        Usage: D3D11_USAGE_DYNAMIC,
1002        BindFlags: D3D11_BIND_INDEX_BUFFER.0 as u32,
1003        CPUAccessFlags: D3D11_CPU_ACCESS_WRITE.0 as u32,
1004        MiscFlags: D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS.0 as u32,
1005        StructureByteStride: std::mem::size_of::<DrawInstancedIndirectArgs>() as u32,
1006    };
1007    let mut buffer = None;
1008    unsafe { device.CreateBuffer(&desc, None, Some(&mut buffer)) }?;
1009    Ok(buffer.unwrap())
1010}
1011
1012fn update_global_params(
1013    device_context: &ID3D11DeviceContext,
1014    buffer: &[Option<ID3D11Buffer>; 1],
1015    globals: GlobalParams,
1016) -> Result<()> {
1017    let buffer = buffer[0].as_ref().unwrap();
1018    unsafe {
1019        let mut data = std::mem::zeroed();
1020        device_context.Map(buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, Some(&mut data))?;
1021        std::ptr::copy_nonoverlapping(&globals, data.pData as *mut _, 1);
1022        device_context.Unmap(buffer, 0);
1023    }
1024    Ok(())
1025}
1026
1027fn pre_draw(
1028    device_context: &ID3D11DeviceContext,
1029    global_params_buffer: &[Option<ID3D11Buffer>; 1],
1030    view_port: &[D3D11_VIEWPORT; 1],
1031    render_target_view: &[Option<ID3D11RenderTargetView>; 1],
1032    clear_color: [f32; 4],
1033    blend_state: &ID3D11BlendState,
1034) -> Result<()> {
1035    update_global_params(
1036        device_context,
1037        global_params_buffer,
1038        GlobalParams {
1039            viewport_size: [view_port[0].Width, view_port[0].Height],
1040            ..Default::default()
1041        },
1042    )?;
1043    unsafe {
1044        device_context.RSSetViewports(Some(view_port));
1045        device_context.OMSetRenderTargets(Some(render_target_view), None);
1046        device_context.ClearRenderTargetView(render_target_view[0].as_ref().unwrap(), &clear_color);
1047        device_context.OMSetBlendState(blend_state, None, 0xFFFFFFFF);
1048    }
1049    Ok(())
1050}
1051
1052fn update_buffer_capacity(
1053    pipeline: &PipelineState,
1054    element_size: usize,
1055    data_size: usize,
1056    device: &ID3D11Device,
1057) -> Option<(ID3D11Buffer, usize, [Option<ID3D11ShaderResourceView>; 1])> {
1058    if pipeline.buffer_size >= data_size {
1059        return None;
1060    }
1061    println!("buffer too small: {} < {}", pipeline.buffer_size, data_size);
1062    let buffer_size = data_size.next_power_of_two();
1063    println!("New size: {}", buffer_size);
1064    let buffer = create_buffer(device, element_size, buffer_size).unwrap();
1065    let view = create_buffer_view(device, &buffer).unwrap();
1066    Some((buffer, buffer_size, view))
1067}
1068
1069fn update_paths_buffer_capacity(
1070    pipeline: &PathsPipelineState,
1071    data_size: usize,
1072    device: &ID3D11Device,
1073) -> Option<(ID3D11Buffer, usize, [Option<ID3D11ShaderResourceView>; 1])> {
1074    if pipeline.buffer_size >= data_size {
1075        return None;
1076    }
1077    println!(
1078        "Paths buffer too small: {} < {}",
1079        pipeline.buffer_size, data_size
1080    );
1081    let buffer_size = data_size.next_power_of_two();
1082    println!("Paths New size: {}", buffer_size);
1083    let buffer = create_buffer(device, std::mem::align_of::<PathSprite>(), buffer_size).unwrap();
1084    let view = create_buffer_view(device, &buffer).unwrap();
1085    Some((buffer, buffer_size, view))
1086}
1087
1088fn update_paths_vertex_capacity(
1089    pipeline: &PathsPipelineState,
1090    vertex_size: usize,
1091    device: &ID3D11Device,
1092) -> Option<(ID3D11Buffer, usize, [Option<ID3D11ShaderResourceView>; 1])> {
1093    if pipeline.vertex_buffer_size >= vertex_size {
1094        return None;
1095    }
1096    println!(
1097        "Paths vertex buffer too small: {} < {}",
1098        pipeline.vertex_buffer_size, vertex_size
1099    );
1100    let vertex_size = vertex_size.next_power_of_two();
1101    println!("Paths vertex New size: {}", vertex_size);
1102    let buffer = create_buffer(
1103        device,
1104        std::mem::size_of::<PathVertex<ScaledPixels>>(),
1105        vertex_size,
1106    )
1107    .unwrap();
1108    let view = create_buffer_view(device, &buffer).unwrap();
1109    Some((buffer, vertex_size, view))
1110}
1111
1112fn update_indirect_buffer_capacity(
1113    pipeline: &PathsPipelineState,
1114    data_size: usize,
1115    device: &ID3D11Device,
1116) -> Option<(ID3D11Buffer, usize)> {
1117    if pipeline.indirect_buffer_size >= data_size {
1118        return None;
1119    }
1120    println!(
1121        "Indirect buffer too small: {} < {}",
1122        pipeline.indirect_buffer_size, data_size
1123    );
1124    let buffer_size = data_size.next_power_of_two();
1125    println!("Indirect New size: {}", buffer_size);
1126    let buffer = create_indirect_draw_buffer(device, data_size as u32).unwrap();
1127    Some((buffer, buffer_size))
1128}
1129
1130fn update_pipeline(
1131    pipeline: &mut PipelineState,
1132    input: (ID3D11Buffer, usize, [Option<ID3D11ShaderResourceView>; 1]),
1133) {
1134    pipeline.buffer = input.0;
1135    pipeline.buffer_size = input.1;
1136    pipeline.view = input.2;
1137}
1138
1139fn update_paths_pipeline_buffer(
1140    pipeline: &mut PathsPipelineState,
1141    input: (ID3D11Buffer, usize, [Option<ID3D11ShaderResourceView>; 1]),
1142) {
1143    pipeline.buffer = input.0;
1144    pipeline.buffer_size = input.1;
1145    pipeline.view = input.2;
1146}
1147
1148fn update_paths_pipeline_vertex(
1149    pipeline: &mut PathsPipelineState,
1150    input: (ID3D11Buffer, usize, [Option<ID3D11ShaderResourceView>; 1]),
1151) {
1152    pipeline.vertex_buffer = input.0;
1153    pipeline.vertex_buffer_size = input.1;
1154    pipeline.vertex_view = input.2;
1155}
1156
1157fn update_paths_indirect_buffer(pipeline: &mut PathsPipelineState, input: (ID3D11Buffer, usize)) {
1158    pipeline.indirect_draw_buffer = input.0;
1159    pipeline.indirect_buffer_size = input.1;
1160}
1161
1162fn update_buffer<T>(
1163    device_context: &ID3D11DeviceContext,
1164    buffer: &ID3D11Buffer,
1165    data: &[T],
1166) -> Result<()> {
1167    unsafe {
1168        let mut dest = std::mem::zeroed();
1169        device_context.Map(buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, Some(&mut dest))?;
1170        std::ptr::copy_nonoverlapping(data.as_ptr(), dest.pData as _, data.len());
1171        device_context.Unmap(buffer, 0);
1172    }
1173    Ok(())
1174}
1175
1176fn update_indirect_buffer(
1177    device_context: &ID3D11DeviceContext,
1178    buffer: &ID3D11Buffer,
1179    data: &[DrawInstancedIndirectArgs],
1180) -> Result<()> {
1181    unsafe {
1182        let mut dest = std::mem::zeroed();
1183        device_context.Map(buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, Some(&mut dest))?;
1184        std::ptr::copy_nonoverlapping(data.as_ptr(), dest.pData as _, data.len());
1185        device_context.Unmap(buffer, 0);
1186    }
1187    Ok(())
1188}
1189
1190fn prepare_indirect_draws(
1191    device_context: &ID3D11DeviceContext,
1192    pipeline: &PathsPipelineState,
1193    viewport: &[D3D11_VIEWPORT],
1194    global_params: &[Option<ID3D11Buffer>],
1195    topology: D3D_PRIMITIVE_TOPOLOGY,
1196) -> Result<()> {
1197    unsafe {
1198        device_context.VSSetShaderResources(1, Some(&pipeline.vertex_view));
1199        device_context.VSSetShaderResources(2, Some(&pipeline.view));
1200        device_context.PSSetShaderResources(2, Some(&pipeline.view));
1201        device_context.IASetPrimitiveTopology(topology);
1202        device_context.RSSetViewports(Some(viewport));
1203        device_context.VSSetShader(&pipeline.vertex, None);
1204        device_context.PSSetShader(&pipeline.fragment, None);
1205        device_context.VSSetConstantBuffers(0, Some(global_params));
1206        device_context.PSSetConstantBuffers(0, Some(global_params));
1207    }
1208    Ok(())
1209}
1210
1211fn draw_indirect(
1212    device_context: &ID3D11DeviceContext,
1213    indirect_draw_buffer: &ID3D11Buffer,
1214    offset: u32,
1215) {
1216    unsafe {
1217        device_context.DrawInstancedIndirect(indirect_draw_buffer, offset);
1218    }
1219}
1220
1221fn draw_normal(
1222    device_context: &ID3D11DeviceContext,
1223    pipeline: &PipelineState,
1224    viewport: &[D3D11_VIEWPORT],
1225    global_params: &[Option<ID3D11Buffer>],
1226    topology: D3D_PRIMITIVE_TOPOLOGY,
1227    vertex_count: u32,
1228    instance_count: u32,
1229) -> Result<()> {
1230    unsafe {
1231        device_context.VSSetShaderResources(1, Some(&pipeline.view));
1232        device_context.PSSetShaderResources(1, Some(&pipeline.view));
1233        device_context.IASetPrimitiveTopology(topology);
1234        device_context.RSSetViewports(Some(viewport));
1235        device_context.VSSetShader(&pipeline.vertex, None);
1236        device_context.PSSetShader(&pipeline.fragment, None);
1237        device_context.VSSetConstantBuffers(0, Some(global_params));
1238        device_context.PSSetConstantBuffers(0, Some(global_params));
1239
1240        device_context.DrawInstanced(vertex_count, instance_count, 0, 0);
1241    }
1242    Ok(())
1243}
1244
1245fn draw_with_texture(
1246    device_context: &ID3D11DeviceContext,
1247    pipeline: &PipelineState,
1248    texture: &[Option<ID3D11ShaderResourceView>],
1249    viewport: &[D3D11_VIEWPORT],
1250    global_params: &[Option<ID3D11Buffer>],
1251    sampler: &[Option<ID3D11SamplerState>],
1252    instance_count: u32,
1253) -> Result<()> {
1254    unsafe {
1255        device_context.IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
1256        device_context.RSSetViewports(Some(viewport));
1257        device_context.VSSetShader(&pipeline.vertex, None);
1258        device_context.PSSetShader(&pipeline.fragment, None);
1259        device_context.VSSetConstantBuffers(0, Some(global_params));
1260        device_context.PSSetConstantBuffers(0, Some(global_params));
1261        device_context.VSSetShaderResources(1, Some(&pipeline.view));
1262        device_context.PSSetShaderResources(1, Some(&pipeline.view));
1263        device_context.PSSetSamplers(0, Some(sampler));
1264        device_context.VSSetShaderResources(0, Some(texture));
1265        device_context.PSSetShaderResources(0, Some(texture));
1266
1267        device_context.DrawInstanced(4, instance_count, 0, 0);
1268    }
1269    Ok(())
1270}
1271
1272const BUFFER_COUNT: usize = 3;
1273
1274mod shader_resources {
1275    use anyhow::Result;
1276    use windows::Win32::Graphics::Direct3D::{
1277        Fxc::{D3DCOMPILE_DEBUG, D3DCOMPILE_SKIP_OPTIMIZATION, D3DCompileFromFile},
1278        ID3DBlob,
1279    };
1280    use windows_core::{HSTRING, PCSTR};
1281
1282    pub(super) fn build_shader_blob(entry: &str, target: &str) -> Result<ID3DBlob> {
1283        println!("Building shader: {}", entry);
1284        unsafe {
1285            let mut entry = entry.to_owned();
1286            let mut target = target.to_owned();
1287            let mut compile_blob = None;
1288            let mut error_blob = None;
1289            let shader_path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
1290                .join("src/platform/windows/shaders.hlsl")
1291                .canonicalize()
1292                .unwrap();
1293            entry.push_str("\0");
1294            target.push_str("\0");
1295            let entry_point = PCSTR::from_raw(entry.as_ptr());
1296            let target_cstr = PCSTR::from_raw(target.as_ptr());
1297            println!(
1298                "Compiling shader: {} with target: {}",
1299                entry_point.display(),
1300                target_cstr.display()
1301            );
1302            #[cfg(debug_assertions)]
1303            let compile_flag = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
1304            #[cfg(not(debug_assertions))]
1305            let compile_flag = 0;
1306            let ret = D3DCompileFromFile(
1307                &HSTRING::from(shader_path.to_str().unwrap()),
1308                None,
1309                None,
1310                entry_point,
1311                target_cstr,
1312                compile_flag,
1313                0,
1314                &mut compile_blob,
1315                Some(&mut error_blob),
1316            );
1317            println!("Shader compile result: {:?}", ret);
1318            if ret.is_err() {
1319                let Some(error_blob) = error_blob else {
1320                    return Err(anyhow::anyhow!("{ret:?}"));
1321                };
1322                let string_len = error_blob.GetBufferSize();
1323                let error_string_encode = Vec::from_raw_parts(
1324                    error_blob.GetBufferPointer() as *mut u8,
1325                    string_len,
1326                    string_len,
1327                );
1328                let error_string = String::from_utf8_lossy(&error_string_encode);
1329                println!("Shader compile error: {}", error_string);
1330                return Err(anyhow::anyhow!("Compile error: {}", error_string));
1331            }
1332            Ok(compile_blob.unwrap())
1333        }
1334    }
1335}