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