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