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 let mut vertices = Vec::new();
285 let mut sprites = Vec::with_capacity(paths.len());
286 let mut draw_indirect_commands = Vec::with_capacity(paths.len());
287 let mut start_vertex_location = 0;
288 for (i, path) in paths.iter().enumerate() {
289 draw_indirect_commands.push(DrawInstancedIndirectArgs {
290 vertex_count_per_instance: path.vertices.len() as u32,
291 instance_count: 1,
292 start_vertex_location,
293 start_instance_location: i as u32,
294 });
295 start_vertex_location += path.vertices.len() as u32;
296
297 vertices.extend(path.vertices.iter().map(|v| PathVertex {
298 xy_position: v.xy_position,
299 content_mask: ContentMask {
300 bounds: path.content_mask.bounds,
301 },
302 }));
303
304 sprites.push(PathSprite {
305 bounds: path.bounds,
306 color: path.color,
307 });
308 }
309
310 update_paths_buffer_capacity(
311 &self.pipelines.paths_pipeline,
312 sprites.len(),
313 &self.devices.device,
314 )
315 .map(|input| update_paths_pipeline_buffer(&mut self.pipelines.paths_pipeline, input));
316 update_buffer(
317 &self.devices.device_context,
318 &self.pipelines.paths_pipeline.buffer,
319 &sprites,
320 )?;
321 update_paths_vertex_capacity(
322 &mut self.pipelines.paths_pipeline,
323 vertices.len(),
324 &self.devices.device,
325 )
326 .map(|input| update_paths_pipeline_vertex(&mut self.pipelines.paths_pipeline, input));
327 update_buffer(
328 &self.devices.device_context,
329 &self.pipelines.paths_pipeline.vertex_buffer,
330 &vertices,
331 )?;
332 update_indirect_buffer_capacity(
333 &self.pipelines.paths_pipeline,
334 draw_indirect_commands.len(),
335 &self.devices.device,
336 )
337 .map(|input| update_paths_indirect_buffer(&mut self.pipelines.paths_pipeline, input));
338 update_buffer(
339 &self.devices.device_context,
340 &self.pipelines.paths_pipeline.indirect_draw_buffer,
341 &draw_indirect_commands,
342 )?;
343 prepare_indirect_draws(
344 &self.devices.device_context,
345 &self.pipelines.paths_pipeline,
346 &self.context.viewport,
347 &self.globals.global_params_buffer,
348 D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST,
349 )?;
350
351 for i in 0..paths.len() {
352 draw_indirect(
353 &self.devices.device_context,
354 &self.pipelines.paths_pipeline.indirect_draw_buffer,
355 (i * std::mem::size_of::<DrawInstancedIndirectArgs>()) as u32,
356 );
357 }
358 Ok(())
359 }
360
361 fn draw_underlines(&mut self, underlines: &[Underline]) -> Result<()> {
362 if underlines.is_empty() {
363 return Ok(());
364 }
365 update_buffer_capacity(
366 &self.pipelines.underline_pipeline,
367 std::mem::size_of::<Underline>(),
368 underlines.len(),
369 &self.devices.device,
370 )
371 .map(|input| update_pipeline(&mut self.pipelines.underline_pipeline, input));
372 update_buffer(
373 &self.devices.device_context,
374 &self.pipelines.underline_pipeline.buffer,
375 underlines,
376 )?;
377 draw_normal(
378 &self.devices.device_context,
379 &self.pipelines.underline_pipeline,
380 &self.context.viewport,
381 &self.globals.global_params_buffer,
382 D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,
383 4,
384 underlines.len() as u32,
385 )
386 }
387
388 fn draw_monochrome_sprites(
389 &mut self,
390 texture_id: AtlasTextureId,
391 sprites: &[MonochromeSprite],
392 ) -> Result<()> {
393 if sprites.is_empty() {
394 return Ok(());
395 }
396 let texture_view = self.atlas.get_texture_view(texture_id);
397 update_buffer_capacity(
398 &self.pipelines.mono_sprites,
399 std::mem::size_of::<MonochromeSprite>(),
400 sprites.len(),
401 &self.devices.device,
402 )
403 .map(|input| update_pipeline(&mut self.pipelines.mono_sprites, input));
404 update_buffer(
405 &self.devices.device_context,
406 &self.pipelines.mono_sprites.buffer,
407 sprites,
408 )?;
409 draw_with_texture(
410 &self.devices.device_context,
411 &self.pipelines.mono_sprites,
412 &texture_view,
413 &self.context.viewport,
414 &self.globals.global_params_buffer,
415 &self.globals.sampler,
416 sprites.len() as u32,
417 )
418 }
419
420 fn draw_polychrome_sprites(
421 &mut self,
422 texture_id: AtlasTextureId,
423 sprites: &[PolychromeSprite],
424 ) -> Result<()> {
425 if sprites.is_empty() {
426 return Ok(());
427 }
428 let texture_view = self.atlas.get_texture_view(texture_id);
429 update_buffer_capacity(
430 &self.pipelines.poly_sprites,
431 std::mem::size_of::<PolychromeSprite>(),
432 sprites.len(),
433 &self.devices.device,
434 )
435 .map(|input| update_pipeline(&mut self.pipelines.poly_sprites, input));
436 update_buffer(
437 &self.devices.device_context,
438 &self.pipelines.poly_sprites.buffer,
439 sprites,
440 )?;
441 draw_with_texture(
442 &self.devices.device_context,
443 &self.pipelines.poly_sprites,
444 &texture_view,
445 &self.context.viewport,
446 &self.globals.global_params_buffer,
447 &self.globals.sampler,
448 sprites.len() as u32,
449 )
450 }
451
452 fn draw_surfaces(&mut self, surfaces: &[PaintSurface]) -> Result<()> {
453 if surfaces.is_empty() {
454 return Ok(());
455 }
456 Ok(())
457 }
458}
459
460impl DirectXContext {
461 pub fn new(devices: &DirectXDevices, hwnd: HWND, transparent: bool) -> Result<Self> {
462 // #[cfg(not(feature = "enable-renderdoc"))]
463 // let swap_chain = create_swap_chain(&devices.dxgi_factory, &devices.device, transparent)?;
464 // #[cfg(feature = "enable-renderdoc")]
465 let swap_chain =
466 create_swap_chain_default(&devices.dxgi_factory, &devices.device, hwnd, transparent)?;
467 // #[cfg(not(feature = "enable-renderdoc"))]
468 // let direct_composition = DirectComposition::new(&devices.dxgi_device, hwnd)?;
469 // #[cfg(not(feature = "enable-renderdoc"))]
470 // direct_composition.set_swap_chain(&swap_chain)?;
471 let back_buffer = [Some(set_render_target_view(
472 &swap_chain,
473 &devices.device,
474 &devices.device_context,
475 )?)];
476 let viewport = set_viewport(&devices.device_context, 1.0, 1.0);
477 set_rasterizer_state(&devices.device, &devices.device_context)?;
478
479 Ok(Self {
480 swap_chain,
481 back_buffer,
482 viewport,
483 // #[cfg(not(feature = "enable-renderdoc"))]
484 // direct_composition,
485 })
486 }
487}
488
489impl DirectXRenderPipelines {
490 pub fn new(device: &ID3D11Device) -> Result<Self> {
491 let shadow_pipeline = create_pipieline(
492 device,
493 "shadow_vertex",
494 "shadow_fragment",
495 std::mem::size_of::<Shadow>(),
496 32,
497 )?;
498 let quad_pipeline = create_pipieline(
499 device,
500 "quad_vertex",
501 "quad_fragment",
502 std::mem::size_of::<Quad>(),
503 32,
504 )?;
505 // let paths_pipeline = create_pipieline(
506 // device,
507 // "paths_vertex",
508 // "paths_fragment",
509 // std::mem::size_of::<PathSprite>(),
510 // 32,
511 // )?;
512 let paths_pipeline = PathsPipelineState::new(device)?;
513 let underline_pipeline = create_pipieline(
514 device,
515 "underline_vertex",
516 "underline_fragment",
517 std::mem::size_of::<Underline>(),
518 32,
519 )?;
520 let mono_sprites = create_pipieline(
521 device,
522 "monochrome_sprite_vertex",
523 "monochrome_sprite_fragment",
524 std::mem::size_of::<MonochromeSprite>(),
525 32,
526 )?;
527 let poly_sprites = create_pipieline(
528 device,
529 "polychrome_sprite_vertex",
530 "polychrome_sprite_fragment",
531 std::mem::size_of::<PolychromeSprite>(),
532 32,
533 )?;
534
535 Ok(Self {
536 shadow_pipeline,
537 quad_pipeline,
538 paths_pipeline,
539 underline_pipeline,
540 mono_sprites,
541 poly_sprites,
542 })
543 }
544}
545
546// #[cfg(not(feature = "enable-renderdoc"))]
547// impl DirectComposition {
548// pub fn new(dxgi_device: &IDXGIDevice, hwnd: HWND) -> Result<Self> {
549// let comp_device = get_comp_device(&dxgi_device)?;
550// let comp_target = unsafe { comp_device.CreateTargetForHwnd(hwnd, true) }?;
551// let comp_visual = unsafe { comp_device.CreateVisual() }?;
552
553// Ok(Self {
554// comp_device,
555// comp_target,
556// comp_visual,
557// })
558// }
559
560// pub fn set_swap_chain(&self, swap_chain: &IDXGISwapChain1) -> Result<()> {
561// unsafe {
562// self.comp_visual.SetContent(swap_chain)?;
563// self.comp_target.SetRoot(&self.comp_visual)?;
564// self.comp_device.Commit()?;
565// }
566// Ok(())
567// }
568// }
569
570impl DirectXGlobalElements {
571 pub fn new(device: &ID3D11Device) -> Result<Self> {
572 let global_params_buffer = unsafe {
573 let desc = D3D11_BUFFER_DESC {
574 ByteWidth: std::mem::size_of::<GlobalParams>() as u32,
575 Usage: D3D11_USAGE_DYNAMIC,
576 BindFlags: D3D11_BIND_CONSTANT_BUFFER.0 as u32,
577 CPUAccessFlags: D3D11_CPU_ACCESS_WRITE.0 as u32,
578 ..Default::default()
579 };
580 let mut buffer = None;
581 device.CreateBuffer(&desc, None, Some(&mut buffer))?;
582 [buffer]
583 };
584
585 let sampler = unsafe {
586 let desc = D3D11_SAMPLER_DESC {
587 Filter: D3D11_FILTER_MIN_MAG_MIP_LINEAR,
588 AddressU: D3D11_TEXTURE_ADDRESS_WRAP,
589 AddressV: D3D11_TEXTURE_ADDRESS_WRAP,
590 AddressW: D3D11_TEXTURE_ADDRESS_WRAP,
591 MipLODBias: 0.0,
592 MaxAnisotropy: 1,
593 ComparisonFunc: D3D11_COMPARISON_ALWAYS,
594 BorderColor: [0.0; 4],
595 MinLOD: 0.0,
596 MaxLOD: D3D11_FLOAT32_MAX,
597 };
598 let mut output = None;
599 device.CreateSamplerState(&desc, Some(&mut output))?;
600 [output]
601 };
602
603 let blend_state = create_blend_state(device)?;
604 let blend_state_for_pr = create_blend_state_for_path_raster(device)?;
605
606 Ok(Self {
607 global_params_buffer,
608 sampler,
609 blend_state,
610 blend_state_for_pr,
611 })
612 }
613}
614
615#[derive(Debug, Default)]
616#[repr(C)]
617struct GlobalParams {
618 viewport_size: [f32; 2],
619 _pad: u64,
620}
621
622struct PipelineState {
623 vertex: ID3D11VertexShader,
624 fragment: ID3D11PixelShader,
625 buffer: ID3D11Buffer,
626 buffer_size: usize,
627 view: [Option<ID3D11ShaderResourceView>; 1],
628}
629
630struct PathsPipelineState {
631 vertex: ID3D11VertexShader,
632 fragment: ID3D11PixelShader,
633 buffer: ID3D11Buffer,
634 buffer_size: usize,
635 vertex_buffer: ID3D11Buffer,
636 vertex_buffer_size: usize,
637 indirect_draw_buffer: ID3D11Buffer,
638 indirect_buffer_size: usize,
639 view: [Option<ID3D11ShaderResourceView>; 1],
640 vertex_view: [Option<ID3D11ShaderResourceView>; 1],
641}
642
643impl PathsPipelineState {
644 fn new(device: &ID3D11Device) -> Result<Self> {
645 let vertex = {
646 let shader_blob = shader_resources::build_shader_blob("paths_vertex", "vs_5_0")?;
647 let bytes = unsafe {
648 std::slice::from_raw_parts(
649 shader_blob.GetBufferPointer() as *mut u8,
650 shader_blob.GetBufferSize(),
651 )
652 };
653 create_vertex_shader(device, bytes)?
654 };
655 let fragment = {
656 let shader_blob = shader_resources::build_shader_blob("paths_fragment", "ps_5_0")?;
657 let bytes = unsafe {
658 std::slice::from_raw_parts(
659 shader_blob.GetBufferPointer() as *mut u8,
660 shader_blob.GetBufferSize(),
661 )
662 };
663 create_fragment_shader(device, bytes)?
664 };
665 let buffer = create_buffer(device, std::mem::size_of::<PathSprite>(), 32)?;
666 let view = create_buffer_view(device, &buffer)?;
667 let vertex_buffer =
668 create_buffer(device, std::mem::size_of::<PathVertex<ScaledPixels>>(), 32)?;
669 let vertex_view = create_buffer_view(device, &vertex_buffer)?;
670 let indirect_draw_buffer = create_indirect_draw_buffer(device, 32)?;
671 Ok(Self {
672 vertex,
673 fragment,
674 buffer,
675 buffer_size: 32,
676 vertex_buffer,
677 vertex_buffer_size: 32,
678 indirect_draw_buffer,
679 indirect_buffer_size: 32,
680 view,
681 vertex_view,
682 })
683 }
684}
685
686#[derive(Clone, Debug, Eq, PartialEq)]
687#[repr(C)]
688struct PathSprite {
689 bounds: Bounds<ScaledPixels>,
690 color: Background,
691}
692
693fn get_dxgi_factory() -> Result<IDXGIFactory6> {
694 #[cfg(debug_assertions)]
695 let factory_flag = DXGI_CREATE_FACTORY_DEBUG;
696 #[cfg(not(debug_assertions))]
697 let factory_flag = 0u32;
698 unsafe { Ok(CreateDXGIFactory2(factory_flag)?) }
699}
700
701fn get_adapter(dxgi_factory: &IDXGIFactory6) -> Result<IDXGIAdapter1> {
702 for adapter_index in 0.. {
703 let adapter: IDXGIAdapter1 = unsafe {
704 dxgi_factory
705 .EnumAdapterByGpuPreference(adapter_index, DXGI_GPU_PREFERENCE_MINIMUM_POWER)
706 }?;
707 {
708 let desc = unsafe { adapter.GetDesc1() }?;
709 println!(
710 "Select GPU: {}",
711 String::from_utf16_lossy(&desc.Description)
712 );
713 }
714 // Check to see whether the adapter supports Direct3D 11, but don't
715 // create the actual device yet.
716 if get_device(&adapter, None, None).log_err().is_some() {
717 return Ok(adapter);
718 }
719 }
720
721 unreachable!()
722}
723
724fn get_device(
725 adapter: &IDXGIAdapter1,
726 device: Option<*mut Option<ID3D11Device>>,
727 context: Option<*mut Option<ID3D11DeviceContext>>,
728) -> Result<()> {
729 #[cfg(debug_assertions)]
730 let device_flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT | D3D11_CREATE_DEVICE_DEBUG;
731 #[cfg(not(debug_assertions))]
732 let device_flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
733 Ok(unsafe {
734 D3D11CreateDevice(
735 adapter,
736 D3D_DRIVER_TYPE_UNKNOWN,
737 HMODULE::default(),
738 device_flags,
739 Some(&[D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_11_1]),
740 D3D11_SDK_VERSION,
741 device,
742 None,
743 context,
744 )?
745 })
746}
747
748// #[cfg(not(feature = "enable-renderdoc"))]
749// fn get_comp_device(dxgi_device: &IDXGIDevice) -> Result<IDCompositionDevice> {
750// Ok(unsafe { DCompositionCreateDevice(dxgi_device)? })
751// }
752
753// fn create_swap_chain(
754// dxgi_factory: &IDXGIFactory6,
755// device: &ID3D11Device,
756// transparent: bool,
757// ) -> Result<IDXGISwapChain1> {
758// let alpha_mode = if transparent {
759// DXGI_ALPHA_MODE_PREMULTIPLIED
760// } else {
761// DXGI_ALPHA_MODE_IGNORE
762// };
763// let desc = DXGI_SWAP_CHAIN_DESC1 {
764// Width: 1,
765// Height: 1,
766// Format: DXGI_FORMAT_B8G8R8A8_UNORM,
767// Stereo: false.into(),
768// SampleDesc: DXGI_SAMPLE_DESC {
769// Count: 1,
770// Quality: 0,
771// },
772// BufferUsage: DXGI_USAGE_RENDER_TARGET_OUTPUT,
773// BufferCount: BUFFER_COUNT as u32,
774// // Composition SwapChains only support the DXGI_SCALING_STRETCH Scaling.
775// Scaling: DXGI_SCALING_STRETCH,
776// SwapEffect: DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL,
777// AlphaMode: alpha_mode,
778// Flags: 0,
779// };
780// Ok(unsafe { dxgi_factory.CreateSwapChainForComposition(device, &desc, None)? })
781// }
782
783// #[cfg(feature = "enable-renderdoc")]
784fn create_swap_chain_default(
785 dxgi_factory: &IDXGIFactory6,
786 device: &ID3D11Device,
787 hwnd: HWND,
788 _transparent: bool,
789) -> Result<IDXGISwapChain1> {
790 use windows::Win32::Graphics::Dxgi::DXGI_MWA_NO_ALT_ENTER;
791
792 let desc = DXGI_SWAP_CHAIN_DESC1 {
793 Width: 1,
794 Height: 1,
795 Format: DXGI_FORMAT_B8G8R8A8_UNORM,
796 Stereo: false.into(),
797 SampleDesc: DXGI_SAMPLE_DESC {
798 Count: 1,
799 Quality: 0,
800 },
801 BufferUsage: DXGI_USAGE_RENDER_TARGET_OUTPUT,
802 BufferCount: BUFFER_COUNT as u32,
803 Scaling: DXGI_SCALING_STRETCH,
804 SwapEffect: DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL,
805 AlphaMode: DXGI_ALPHA_MODE_IGNORE,
806 Flags: 0,
807 };
808 let swap_chain =
809 unsafe { dxgi_factory.CreateSwapChainForHwnd(device, hwnd, &desc, None, None) }?;
810 unsafe { dxgi_factory.MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER) }?;
811 Ok(swap_chain)
812}
813
814fn set_render_target_view(
815 swap_chain: &IDXGISwapChain1,
816 device: &ID3D11Device,
817 device_context: &ID3D11DeviceContext,
818) -> Result<ID3D11RenderTargetView> {
819 // In dx11, ID3D11RenderTargetView is supposed to always point to the new back buffer.
820 // https://stackoverflow.com/questions/65246961/does-the-backbuffer-that-a-rendertargetview-points-to-automagically-change-after
821 let back_buffer = unsafe {
822 let resource: ID3D11Texture2D = swap_chain.GetBuffer(0)?;
823 let mut buffer: Option<ID3D11RenderTargetView> = None;
824 device.CreateRenderTargetView(&resource, None, Some(&mut buffer))?;
825 buffer.unwrap()
826 };
827 unsafe { device_context.OMSetRenderTargets(Some(&[Some(back_buffer.clone())]), None) };
828 Ok(back_buffer)
829}
830
831fn set_viewport(
832 device_context: &ID3D11DeviceContext,
833 width: f32,
834 height: f32,
835) -> [D3D11_VIEWPORT; 1] {
836 let viewport = [D3D11_VIEWPORT {
837 TopLeftX: 0.0,
838 TopLeftY: 0.0,
839 Width: width,
840 Height: height,
841 MinDepth: 0.0,
842 MaxDepth: 1.0,
843 }];
844 unsafe { device_context.RSSetViewports(Some(&viewport)) };
845 viewport
846}
847
848fn set_rasterizer_state(device: &ID3D11Device, device_context: &ID3D11DeviceContext) -> Result<()> {
849 let desc = D3D11_RASTERIZER_DESC {
850 FillMode: D3D11_FILL_SOLID,
851 CullMode: D3D11_CULL_NONE,
852 // CullMode: D3D11_CULL_BACK,
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::size_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}