1use alloc::{
2 borrow::Cow,
3 boxed::Box,
4 string::{String, ToString as _},
5 sync::Arc,
6 vec::Vec,
7};
8use core::{marker::PhantomData, mem::ManuallyDrop, num::NonZeroU32};
9
10use arrayvec::ArrayVec;
11use naga::error::ShaderError;
12use thiserror::Error;
13use wgt::error::{ErrorType, WebGpuError};
14
15pub use crate::pipeline_cache::PipelineCacheValidationError;
16use crate::{
17 binding_model::{CreateBindGroupLayoutError, CreatePipelineLayoutError, PipelineLayout},
18 command::ColorAttachmentError,
19 device::{Device, DeviceError, MissingDownlevelFlags, MissingFeatures, RenderPassContext},
20 id::{PipelineCacheId, PipelineLayoutId, ShaderModuleId},
21 resource::{InvalidResourceError, Labeled, TrackingData},
22 resource_log, validation, Label,
23};
24
25#[derive(Debug)]
29pub(crate) struct LateSizedBufferGroup {
30 pub(crate) shader_sizes: Vec<wgt::BufferAddress>,
32}
33
34#[allow(clippy::large_enum_variant)]
35pub enum ShaderModuleSource<'a> {
36 #[cfg(feature = "wgsl")]
37 Wgsl(Cow<'a, str>),
38 #[cfg(feature = "glsl")]
39 Glsl(Cow<'a, str>, naga::front::glsl::Options),
40 #[cfg(feature = "spirv")]
41 SpirV(Cow<'a, [u32]>, naga::front::spv::Options),
42 Naga(Cow<'static, naga::Module>),
43 #[doc(hidden)]
46 Dummy(PhantomData<&'a ()>),
47}
48
49#[derive(Clone, Debug)]
50#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
51pub struct ShaderModuleDescriptor<'a> {
52 pub label: Label<'a>,
53 #[cfg_attr(feature = "serde", serde(default))]
54 pub runtime_checks: wgt::ShaderRuntimeChecks,
55}
56
57pub type ShaderModuleDescriptorPassthrough<'a> =
58 wgt::CreateShaderModuleDescriptorPassthrough<'a, Label<'a>>;
59
60#[derive(Debug)]
61pub struct ShaderModule {
62 pub(crate) raw: ManuallyDrop<Box<dyn hal::DynShaderModule>>,
63 pub(crate) device: Arc<Device>,
64 pub(crate) interface: Option<validation::Interface>,
65 pub(crate) label: String,
67}
68
69impl Drop for ShaderModule {
70 fn drop(&mut self) {
71 resource_log!("Destroy raw {}", self.error_ident());
72 let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
74 unsafe {
75 self.device.raw().destroy_shader_module(raw);
76 }
77 }
78}
79
80crate::impl_resource_type!(ShaderModule);
81crate::impl_labeled!(ShaderModule);
82crate::impl_parent_device!(ShaderModule);
83crate::impl_storage_item!(ShaderModule);
84
85impl ShaderModule {
86 pub(crate) fn raw(&self) -> &dyn hal::DynShaderModule {
87 self.raw.as_ref()
88 }
89
90 pub(crate) fn finalize_entry_point_name(
91 &self,
92 stage_bit: wgt::ShaderStages,
93 entry_point: Option<&str>,
94 ) -> Result<String, validation::StageError> {
95 match &self.interface {
96 Some(interface) => interface.finalize_entry_point_name(stage_bit, entry_point),
97 None => entry_point
98 .map(|ep| ep.to_string())
99 .ok_or(validation::StageError::NoEntryPointFound),
100 }
101 }
102}
103
104#[derive(Clone, Debug, Error)]
106#[non_exhaustive]
107pub enum CreateShaderModuleError {
108 #[cfg(feature = "wgsl")]
109 #[error(transparent)]
110 Parsing(#[from] ShaderError<naga::front::wgsl::ParseError>),
111 #[cfg(feature = "glsl")]
112 #[error(transparent)]
113 ParsingGlsl(#[from] ShaderError<naga::front::glsl::ParseErrors>),
114 #[cfg(feature = "spirv")]
115 #[error(transparent)]
116 ParsingSpirV(#[from] ShaderError<naga::front::spv::Error>),
117 #[error("Failed to generate the backend-specific code")]
118 Generation,
119 #[error(transparent)]
120 Device(#[from] DeviceError),
121 #[error(transparent)]
122 Validation(#[from] ShaderError<naga::WithSpan<naga::valid::ValidationError>>),
123 #[error(transparent)]
124 MissingFeatures(#[from] MissingFeatures),
125 #[error(
126 "Shader global {bind:?} uses a group index {group} that exceeds the max_bind_groups limit of {limit}."
127 )]
128 InvalidGroupIndex {
129 bind: naga::ResourceBinding,
130 group: u32,
131 limit: u32,
132 },
133}
134
135impl WebGpuError for CreateShaderModuleError {
136 fn webgpu_error_type(&self) -> ErrorType {
137 let e: &dyn WebGpuError = match self {
138 Self::Device(e) => e,
139 Self::MissingFeatures(e) => e,
140
141 Self::Generation => return ErrorType::Internal,
142
143 Self::Validation(..) | Self::InvalidGroupIndex { .. } => return ErrorType::Validation,
144 #[cfg(feature = "wgsl")]
145 Self::Parsing(..) => return ErrorType::Validation,
146 #[cfg(feature = "glsl")]
147 Self::ParsingGlsl(..) => return ErrorType::Validation,
148 #[cfg(feature = "spirv")]
149 Self::ParsingSpirV(..) => return ErrorType::Validation,
150 };
151 e.webgpu_error_type()
152 }
153}
154
155#[derive(Clone, Debug)]
157#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
158pub struct ProgrammableStageDescriptor<'a, SM = ShaderModuleId> {
159 pub module: SM,
161 pub entry_point: Option<Cow<'a, str>>,
168 pub constants: naga::back::PipelineConstants,
176 pub zero_initialize_workgroup_memory: bool,
181}
182
183pub type ResolvedProgrammableStageDescriptor<'a> =
185 ProgrammableStageDescriptor<'a, Arc<ShaderModule>>;
186
187pub type ImplicitBindGroupCount = u8;
189
190#[derive(Clone, Debug, Error)]
191#[non_exhaustive]
192pub enum ImplicitLayoutError {
193 #[error("The implicit_pipeline_ids arg is required")]
194 MissingImplicitPipelineIds,
195 #[error("Missing IDs for deriving {0} bind groups")]
196 MissingIds(ImplicitBindGroupCount),
197 #[error("Unable to reflect the shader {0:?} interface")]
198 ReflectionError(wgt::ShaderStages),
199 #[error(transparent)]
200 BindGroup(#[from] CreateBindGroupLayoutError),
201 #[error(transparent)]
202 Pipeline(#[from] CreatePipelineLayoutError),
203}
204
205impl WebGpuError for ImplicitLayoutError {
206 fn webgpu_error_type(&self) -> ErrorType {
207 let e: &dyn WebGpuError = match self {
208 Self::MissingImplicitPipelineIds | Self::MissingIds(_) | Self::ReflectionError(_) => {
209 return ErrorType::Validation
210 }
211 Self::BindGroup(e) => e,
212 Self::Pipeline(e) => e,
213 };
214 e.webgpu_error_type()
215 }
216}
217
218#[derive(Clone, Debug)]
220#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
221pub struct ComputePipelineDescriptor<
222 'a,
223 PLL = PipelineLayoutId,
224 SM = ShaderModuleId,
225 PLC = PipelineCacheId,
226> {
227 pub label: Label<'a>,
228 pub layout: Option<PLL>,
230 pub stage: ProgrammableStageDescriptor<'a, SM>,
232 pub cache: Option<PLC>,
234}
235
236pub type ResolvedComputePipelineDescriptor<'a> =
238 ComputePipelineDescriptor<'a, Arc<PipelineLayout>, Arc<ShaderModule>, Arc<PipelineCache>>;
239
240#[derive(Clone, Debug, Error)]
241#[non_exhaustive]
242pub enum CreateComputePipelineError {
243 #[error(transparent)]
244 Device(#[from] DeviceError),
245 #[error("Unable to derive an implicit layout")]
246 Implicit(#[from] ImplicitLayoutError),
247 #[error("Error matching shader requirements against the pipeline")]
248 Stage(#[from] validation::StageError),
249 #[error("Internal error: {0}")]
250 Internal(String),
251 #[error("Pipeline constant error: {0}")]
252 PipelineConstants(String),
253 #[error(transparent)]
254 MissingDownlevelFlags(#[from] MissingDownlevelFlags),
255 #[error(transparent)]
256 InvalidResource(#[from] InvalidResourceError),
257}
258
259impl WebGpuError for CreateComputePipelineError {
260 fn webgpu_error_type(&self) -> ErrorType {
261 let e: &dyn WebGpuError = match self {
262 Self::Device(e) => e,
263 Self::InvalidResource(e) => e,
264 Self::MissingDownlevelFlags(e) => e,
265 Self::Implicit(e) => e,
266 Self::Stage(e) => e,
267 Self::Internal(_) => return ErrorType::Internal,
268 Self::PipelineConstants(_) => return ErrorType::Validation,
269 };
270 e.webgpu_error_type()
271 }
272}
273
274#[derive(Debug)]
275pub struct ComputePipeline {
276 pub(crate) raw: ManuallyDrop<Box<dyn hal::DynComputePipeline>>,
277 pub(crate) layout: Arc<PipelineLayout>,
278 pub(crate) device: Arc<Device>,
279 pub(crate) _shader_module: Arc<ShaderModule>,
280 pub(crate) late_sized_buffer_groups: ArrayVec<LateSizedBufferGroup, { hal::MAX_BIND_GROUPS }>,
281 pub(crate) label: String,
283 pub(crate) tracking_data: TrackingData,
284}
285
286impl Drop for ComputePipeline {
287 fn drop(&mut self) {
288 resource_log!("Destroy raw {}", self.error_ident());
289 let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
291 unsafe {
292 self.device.raw().destroy_compute_pipeline(raw);
293 }
294 }
295}
296
297crate::impl_resource_type!(ComputePipeline);
298crate::impl_labeled!(ComputePipeline);
299crate::impl_parent_device!(ComputePipeline);
300crate::impl_storage_item!(ComputePipeline);
301crate::impl_trackable!(ComputePipeline);
302
303impl ComputePipeline {
304 pub(crate) fn raw(&self) -> &dyn hal::DynComputePipeline {
305 self.raw.as_ref()
306 }
307}
308
309#[derive(Clone, Debug, Error)]
310#[non_exhaustive]
311pub enum CreatePipelineCacheError {
312 #[error(transparent)]
313 Device(#[from] DeviceError),
314 #[error("Pipeline cache validation failed")]
315 Validation(#[from] PipelineCacheValidationError),
316 #[error(transparent)]
317 MissingFeatures(#[from] MissingFeatures),
318}
319
320impl WebGpuError for CreatePipelineCacheError {
321 fn webgpu_error_type(&self) -> ErrorType {
322 let e: &dyn WebGpuError = match self {
323 Self::Device(e) => e,
324 Self::Validation(e) => e,
325 Self::MissingFeatures(e) => e,
326 };
327 e.webgpu_error_type()
328 }
329}
330
331#[derive(Debug)]
332pub struct PipelineCache {
333 pub(crate) raw: ManuallyDrop<Box<dyn hal::DynPipelineCache>>,
334 pub(crate) device: Arc<Device>,
335 pub(crate) label: String,
337}
338
339impl Drop for PipelineCache {
340 fn drop(&mut self) {
341 resource_log!("Destroy raw {}", self.error_ident());
342 let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
344 unsafe {
345 self.device.raw().destroy_pipeline_cache(raw);
346 }
347 }
348}
349
350crate::impl_resource_type!(PipelineCache);
351crate::impl_labeled!(PipelineCache);
352crate::impl_parent_device!(PipelineCache);
353crate::impl_storage_item!(PipelineCache);
354
355impl PipelineCache {
356 pub(crate) fn raw(&self) -> &dyn hal::DynPipelineCache {
357 self.raw.as_ref()
358 }
359}
360
361#[derive(Clone, Debug)]
363#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
364#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
365pub struct VertexBufferLayout<'a> {
366 pub array_stride: wgt::BufferAddress,
368 pub step_mode: wgt::VertexStepMode,
370 pub attributes: Cow<'a, [wgt::VertexAttribute]>,
372}
373
374#[derive(Clone, Debug)]
376#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
377pub struct VertexState<'a, SM = ShaderModuleId> {
378 pub stage: ProgrammableStageDescriptor<'a, SM>,
380 pub buffers: Cow<'a, [VertexBufferLayout<'a>]>,
382}
383
384pub type ResolvedVertexState<'a> = VertexState<'a, Arc<ShaderModule>>;
386
387#[derive(Clone, Debug)]
389#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
390pub struct FragmentState<'a, SM = ShaderModuleId> {
391 pub stage: ProgrammableStageDescriptor<'a, SM>,
393 pub targets: Cow<'a, [Option<wgt::ColorTargetState>]>,
395}
396
397pub type ResolvedFragmentState<'a> = FragmentState<'a, Arc<ShaderModule>>;
399
400#[derive(Clone, Debug)]
402#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
403pub struct RenderPipelineDescriptor<
404 'a,
405 PLL = PipelineLayoutId,
406 SM = ShaderModuleId,
407 PLC = PipelineCacheId,
408> {
409 pub label: Label<'a>,
410 pub layout: Option<PLL>,
412 pub vertex: VertexState<'a, SM>,
414 #[cfg_attr(feature = "serde", serde(default))]
416 pub primitive: wgt::PrimitiveState,
417 #[cfg_attr(feature = "serde", serde(default))]
419 pub depth_stencil: Option<wgt::DepthStencilState>,
420 #[cfg_attr(feature = "serde", serde(default))]
422 pub multisample: wgt::MultisampleState,
423 pub fragment: Option<FragmentState<'a, SM>>,
425 pub multiview: Option<NonZeroU32>,
428 pub cache: Option<PLC>,
430}
431
432pub type ResolvedRenderPipelineDescriptor<'a> =
434 RenderPipelineDescriptor<'a, Arc<PipelineLayout>, Arc<ShaderModule>, Arc<PipelineCache>>;
435
436#[derive(Clone, Debug)]
437#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
438pub struct PipelineCacheDescriptor<'a> {
439 pub label: Label<'a>,
440 pub data: Option<Cow<'a, [u8]>>,
441 pub fallback: bool,
442}
443
444#[derive(Clone, Debug, Error)]
445#[non_exhaustive]
446pub enum ColorStateError {
447 #[error("Format {0:?} is not renderable")]
448 FormatNotRenderable(wgt::TextureFormat),
449 #[error("Format {0:?} is not blendable")]
450 FormatNotBlendable(wgt::TextureFormat),
451 #[error("Format {0:?} does not have a color aspect")]
452 FormatNotColor(wgt::TextureFormat),
453 #[error("Sample count {0} is not supported by format {1:?} on this device. The WebGPU spec guarantees {2:?} samples are supported by this format. With the TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES feature your device supports {3:?}.")]
454 InvalidSampleCount(u32, wgt::TextureFormat, Vec<u32>, Vec<u32>),
455 #[error("Output format {pipeline} is incompatible with the shader {shader}")]
456 IncompatibleFormat {
457 pipeline: validation::NumericType,
458 shader: validation::NumericType,
459 },
460 #[error("Invalid write mask {0:?}")]
461 InvalidWriteMask(wgt::ColorWrites),
462}
463
464#[derive(Clone, Debug, Error)]
465#[non_exhaustive]
466pub enum DepthStencilStateError {
467 #[error("Format {0:?} is not renderable")]
468 FormatNotRenderable(wgt::TextureFormat),
469 #[error("Format {0:?} does not have a depth aspect, but depth test/write is enabled")]
470 FormatNotDepth(wgt::TextureFormat),
471 #[error("Format {0:?} does not have a stencil aspect, but stencil test/write is enabled")]
472 FormatNotStencil(wgt::TextureFormat),
473 #[error("Sample count {0} is not supported by format {1:?} on this device. The WebGPU spec guarantees {2:?} samples are supported by this format. With the TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES feature your device supports {3:?}.")]
474 InvalidSampleCount(u32, wgt::TextureFormat, Vec<u32>, Vec<u32>),
475}
476
477#[derive(Clone, Debug, Error)]
478#[non_exhaustive]
479pub enum CreateRenderPipelineError {
480 #[error(transparent)]
481 ColorAttachment(#[from] ColorAttachmentError),
482 #[error(transparent)]
483 Device(#[from] DeviceError),
484 #[error("Unable to derive an implicit layout")]
485 Implicit(#[from] ImplicitLayoutError),
486 #[error("Color state [{0}] is invalid")]
487 ColorState(u8, #[source] ColorStateError),
488 #[error("Depth/stencil state is invalid")]
489 DepthStencilState(#[from] DepthStencilStateError),
490 #[error("Invalid sample count {0}")]
491 InvalidSampleCount(u32),
492 #[error("The number of vertex buffers {given} exceeds the limit {limit}")]
493 TooManyVertexBuffers { given: u32, limit: u32 },
494 #[error("The total number of vertex attributes {given} exceeds the limit {limit}")]
495 TooManyVertexAttributes { given: u32, limit: u32 },
496 #[error("Vertex buffer {index} stride {given} exceeds the limit {limit}")]
497 VertexStrideTooLarge { index: u32, given: u32, limit: u32 },
498 #[error("Vertex attribute at location {location} stride {given} exceeds the limit {limit}")]
499 VertexAttributeStrideTooLarge {
500 location: wgt::ShaderLocation,
501 given: u32,
502 limit: u32,
503 },
504 #[error("Vertex buffer {index} stride {stride} does not respect `VERTEX_STRIDE_ALIGNMENT`")]
505 UnalignedVertexStride {
506 index: u32,
507 stride: wgt::BufferAddress,
508 },
509 #[error("Vertex attribute at location {location} has invalid offset {offset}")]
510 InvalidVertexAttributeOffset {
511 location: wgt::ShaderLocation,
512 offset: wgt::BufferAddress,
513 },
514 #[error("Two or more vertex attributes were assigned to the same location in the shader: {0}")]
515 ShaderLocationClash(u32),
516 #[error("Strip index format was not set to None but to {strip_index_format:?} while using the non-strip topology {topology:?}")]
517 StripIndexFormatForNonStripTopology {
518 strip_index_format: Option<wgt::IndexFormat>,
519 topology: wgt::PrimitiveTopology,
520 },
521 #[error("Conservative Rasterization is only supported for wgt::PolygonMode::Fill")]
522 ConservativeRasterizationNonFillPolygonMode,
523 #[error(transparent)]
524 MissingFeatures(#[from] MissingFeatures),
525 #[error(transparent)]
526 MissingDownlevelFlags(#[from] MissingDownlevelFlags),
527 #[error("Error matching {stage:?} shader requirements against the pipeline")]
528 Stage {
529 stage: wgt::ShaderStages,
530 #[source]
531 error: validation::StageError,
532 },
533 #[error("Internal error in {stage:?} shader: {error}")]
534 Internal {
535 stage: wgt::ShaderStages,
536 error: String,
537 },
538 #[error("Pipeline constant error in {stage:?} shader: {error}")]
539 PipelineConstants {
540 stage: wgt::ShaderStages,
541 error: String,
542 },
543 #[error("In the provided shader, the type given for group {group} binding {binding} has a size of {size}. As the device does not support `DownlevelFlags::BUFFER_BINDINGS_NOT_16_BYTE_ALIGNED`, the type must have a size that is a multiple of 16 bytes.")]
544 UnalignedShader { group: u32, binding: u32, size: u64 },
545 #[error("Using the blend factor {factor:?} for render target {target} is not possible. Only the first render target may be used when dual-source blending.")]
546 BlendFactorOnUnsupportedTarget {
547 factor: wgt::BlendFactor,
548 target: u32,
549 },
550 #[error("Pipeline expects the shader entry point to make use of dual-source blending.")]
551 PipelineExpectsShaderToUseDualSourceBlending,
552 #[error("Shader entry point expects the pipeline to make use of dual-source blending.")]
553 ShaderExpectsPipelineToUseDualSourceBlending,
554 #[error("{}", concat!(
555 "At least one color attachment or depth-stencil attachment was expected, ",
556 "but no render target for the pipeline was specified."
557 ))]
558 NoTargetSpecified,
559 #[error(transparent)]
560 InvalidResource(#[from] InvalidResourceError),
561}
562
563impl WebGpuError for CreateRenderPipelineError {
564 fn webgpu_error_type(&self) -> ErrorType {
565 let e: &dyn WebGpuError = match self {
566 Self::Device(e) => e,
567 Self::InvalidResource(e) => e,
568 Self::MissingFeatures(e) => e,
569 Self::MissingDownlevelFlags(e) => e,
570
571 Self::Internal { .. } => return ErrorType::Internal,
572
573 Self::ColorAttachment(_)
574 | Self::Implicit(_)
575 | Self::ColorState(_, _)
576 | Self::DepthStencilState(_)
577 | Self::InvalidSampleCount(_)
578 | Self::TooManyVertexBuffers { .. }
579 | Self::TooManyVertexAttributes { .. }
580 | Self::VertexStrideTooLarge { .. }
581 | Self::UnalignedVertexStride { .. }
582 | Self::InvalidVertexAttributeOffset { .. }
583 | Self::ShaderLocationClash(_)
584 | Self::StripIndexFormatForNonStripTopology { .. }
585 | Self::ConservativeRasterizationNonFillPolygonMode
586 | Self::Stage { .. }
587 | Self::UnalignedShader { .. }
588 | Self::BlendFactorOnUnsupportedTarget { .. }
589 | Self::PipelineExpectsShaderToUseDualSourceBlending
590 | Self::ShaderExpectsPipelineToUseDualSourceBlending
591 | Self::NoTargetSpecified
592 | Self::PipelineConstants { .. }
593 | Self::VertexAttributeStrideTooLarge { .. } => return ErrorType::Validation,
594 };
595 e.webgpu_error_type()
596 }
597}
598
599bitflags::bitflags! {
600 #[repr(transparent)]
601 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
602 pub struct PipelineFlags: u32 {
603 const BLEND_CONSTANT = 1 << 0;
604 const STENCIL_REFERENCE = 1 << 1;
605 const WRITES_DEPTH = 1 << 2;
606 const WRITES_STENCIL = 1 << 3;
607 }
608}
609
610#[derive(Clone, Copy, Debug)]
612pub struct VertexStep {
613 pub stride: wgt::BufferAddress,
615
616 pub last_stride: wgt::BufferAddress,
618
619 pub mode: wgt::VertexStepMode,
621}
622
623impl Default for VertexStep {
624 fn default() -> Self {
625 Self {
626 stride: 0,
627 last_stride: 0,
628 mode: wgt::VertexStepMode::Vertex,
629 }
630 }
631}
632
633#[derive(Debug)]
634pub struct RenderPipeline {
635 pub(crate) raw: ManuallyDrop<Box<dyn hal::DynRenderPipeline>>,
636 pub(crate) device: Arc<Device>,
637 pub(crate) layout: Arc<PipelineLayout>,
638 pub(crate) _shader_modules: ArrayVec<Arc<ShaderModule>, { hal::MAX_CONCURRENT_SHADER_STAGES }>,
639 pub(crate) pass_context: RenderPassContext,
640 pub(crate) flags: PipelineFlags,
641 pub(crate) strip_index_format: Option<wgt::IndexFormat>,
642 pub(crate) vertex_steps: Vec<VertexStep>,
643 pub(crate) late_sized_buffer_groups: ArrayVec<LateSizedBufferGroup, { hal::MAX_BIND_GROUPS }>,
644 pub(crate) label: String,
646 pub(crate) tracking_data: TrackingData,
647}
648
649impl Drop for RenderPipeline {
650 fn drop(&mut self) {
651 resource_log!("Destroy raw {}", self.error_ident());
652 let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
654 unsafe {
655 self.device.raw().destroy_render_pipeline(raw);
656 }
657 }
658}
659
660crate::impl_resource_type!(RenderPipeline);
661crate::impl_labeled!(RenderPipeline);
662crate::impl_parent_device!(RenderPipeline);
663crate::impl_storage_item!(RenderPipeline);
664crate::impl_trackable!(RenderPipeline);
665
666impl RenderPipeline {
667 pub(crate) fn raw(&self) -> &dyn hal::DynRenderPipeline {
668 self.raw.as_ref()
669 }
670}