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