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