@@ -93,6 +93,7 @@ use core::{
9393use arrayvec:: ArrayVec ;
9494use thiserror:: Error ;
9595
96+ use wgpu_hal:: ShouldBeNonZeroExt ;
9697use wgt:: error:: { ErrorType , WebGpuError } ;
9798
9899use crate :: {
@@ -504,7 +505,7 @@ impl RenderBundleEncoder {
504505 buffer_id,
505506 index_format,
506507 offset,
507- size,
508+ size : size . map ( NonZeroU64 :: get ) ,
508509 } ) ;
509510 }
510511}
@@ -602,13 +603,14 @@ fn set_pipeline(
602603 Ok ( ( ) )
603604}
604605
606+ // This function is duplicative of `render::set_index_buffer`.
605607fn set_index_buffer (
606608 state : & mut State ,
607609 buffer_guard : & crate :: storage:: Storage < Fallible < Buffer > > ,
608610 buffer_id : id:: Id < id:: markers:: Buffer > ,
609611 index_format : wgt:: IndexFormat ,
610612 offset : u64 ,
611- size : Option < NonZeroU64 > ,
613+ size : Option < wgt :: BufferSizeOrZero > ,
612614) -> Result < ( ) , RenderBundleErrorInner > {
613615 let buffer = buffer_guard. get ( buffer_id) . get ( ) ?;
614616
@@ -620,28 +622,27 @@ fn set_index_buffer(
620622 buffer. same_device ( & state. device ) ?;
621623 buffer. check_usage ( wgt:: BufferUsages :: INDEX ) ?;
622624
623- let end = match size {
624- Some ( s) => offset + s. get ( ) ,
625- None => buffer. size ,
626- } ;
625+ let end = buffer. resolve_binding_size ( offset, size) ?;
626+
627627 state
628628 . buffer_memory_init_actions
629629 . extend ( buffer. initialization_status . read ( ) . create_action (
630630 & buffer,
631- offset..end,
631+ offset..end. get ( ) ,
632632 MemoryInitKind :: NeedsInitializedMemory ,
633633 ) ) ;
634- state. set_index_buffer ( buffer, index_format, offset..end) ;
634+ state. set_index_buffer ( buffer, index_format, offset..end. get ( ) ) ;
635635 Ok ( ( ) )
636636}
637637
638+ // This function is duplicative of `render::set_vertex_buffer`.
638639fn set_vertex_buffer (
639640 state : & mut State ,
640641 buffer_guard : & crate :: storage:: Storage < Fallible < Buffer > > ,
641642 slot : u32 ,
642643 buffer_id : id:: Id < id:: markers:: Buffer > ,
643644 offset : u64 ,
644- size : Option < NonZeroU64 > ,
645+ size : Option < wgt :: BufferSizeOrZero > ,
645646) -> Result < ( ) , RenderBundleErrorInner > {
646647 let max_vertex_buffers = state. device . limits . max_vertex_buffers ;
647648 if slot >= max_vertex_buffers {
@@ -662,18 +663,16 @@ fn set_vertex_buffer(
662663 buffer. same_device ( & state. device ) ?;
663664 buffer. check_usage ( wgt:: BufferUsages :: VERTEX ) ?;
664665
665- let end = match size {
666- Some ( s) => offset + s. get ( ) ,
667- None => buffer. size ,
668- } ;
666+ let end = buffer. resolve_binding_size ( offset, size) ?;
667+
669668 state
670669 . buffer_memory_init_actions
671670 . extend ( buffer. initialization_status . read ( ) . create_action (
672671 & buffer,
673- offset..end,
672+ offset..end. get ( ) ,
674673 MemoryInitKind :: NeedsInitializedMemory ,
675674 ) ) ;
676- state. vertex [ slot as usize ] = Some ( VertexState :: new ( buffer, offset..end) ) ;
675+ state. vertex [ slot as usize ] = Some ( VertexState :: new ( buffer, offset..end. get ( ) ) ) ;
677676 Ok ( ( ) )
678677}
679678
@@ -965,10 +964,14 @@ impl RenderBundle {
965964 size,
966965 } => {
967966 let buffer = buffer. try_raw ( snatch_guard) ?;
968- let bb = hal:: BufferBinding {
969- buffer,
970- offset : * offset,
971- size : * size,
967+ let bb = unsafe {
968+ // SAFETY: The binding size was checked against the buffer size
969+ // in `set_index_buffer` and again in `IndexState::flush`.
970+ hal:: BufferBinding :: new_unchecked (
971+ buffer,
972+ * offset,
973+ size. expect ( "size was resolved in `RenderBundleEncoder::finish`" ) ,
974+ )
972975 } ;
973976 unsafe { raw. set_index_buffer ( bb, * index_format) } ;
974977 }
@@ -979,10 +982,14 @@ impl RenderBundle {
979982 size,
980983 } => {
981984 let buffer = buffer. try_raw ( snatch_guard) ?;
982- let bb = hal:: BufferBinding {
983- buffer,
984- offset : * offset,
985- size : * size,
985+ let bb = unsafe {
986+ // SAFETY: The binding size was checked against the buffer size
987+ // in `set_vertex_buffer` and again in `VertexState::flush`.
988+ hal:: BufferBinding :: new_unchecked (
989+ buffer,
990+ * offset,
991+ size. expect ( "size was resolved in `RenderBundleEncoder::finish`" ) ,
992+ )
986993 } ;
987994 unsafe { raw. set_vertex_buffer ( * slot, bb) } ;
988995 }
@@ -1131,6 +1138,9 @@ crate::impl_trackable!(RenderBundle);
11311138/// [`RenderBundleEncoder::finish`] records the currently set index buffer here,
11321139/// and calls [`State::flush_index`] before any indexed draw command to produce
11331140/// a `SetIndexBuffer` command if one is necessary.
1141+ ///
1142+ /// Binding ranges must be validated against the size of the buffer before
1143+ /// being stored in `IndexState`.
11341144#[ derive( Debug ) ]
11351145struct IndexState {
11361146 buffer : Arc < Buffer > ,
@@ -1152,13 +1162,21 @@ impl IndexState {
11521162 /// Generate a `SetIndexBuffer` command to prepare for an indexed draw
11531163 /// command, if needed.
11541164 fn flush ( & mut self ) -> Option < ArcRenderCommand > {
1165+ // This was all checked before, but let's check again just in case.
1166+ let binding_size = self
1167+ . range
1168+ . end
1169+ . checked_sub ( self . range . start )
1170+ . filter ( |_| self . range . end <= self . buffer . size )
1171+ . expect ( "index range must be contained in buffer" ) ;
1172+
11551173 if self . is_dirty {
11561174 self . is_dirty = false ;
11571175 Some ( ArcRenderCommand :: SetIndexBuffer {
11581176 buffer : self . buffer . clone ( ) ,
11591177 index_format : self . format ,
11601178 offset : self . range . start ,
1161- size : wgt :: BufferSize :: new ( self . range . end - self . range . start ) ,
1179+ size : Some ( binding_size ) ,
11621180 } )
11631181 } else {
11641182 None
@@ -1174,6 +1192,9 @@ impl IndexState {
11741192/// calls this type's [`flush`] method just before any draw command to
11751193/// produce a `SetVertexBuffer` commands if one is necessary.
11761194///
1195+ /// Binding ranges must be validated against the size of the buffer before
1196+ /// being stored in `VertexState`.
1197+ ///
11771198/// [`flush`]: IndexState::flush
11781199#[ derive( Debug ) ]
11791200struct VertexState {
@@ -1183,6 +1204,9 @@ struct VertexState {
11831204}
11841205
11851206impl VertexState {
1207+ /// Create a new `VertexState`.
1208+ ///
1209+ /// The `range` must be contained within `buffer`.
11861210 fn new ( buffer : Arc < Buffer > , range : Range < wgt:: BufferAddress > ) -> Self {
11871211 Self {
11881212 buffer,
@@ -1195,13 +1219,20 @@ impl VertexState {
11951219 ///
11961220 /// `slot` is the index of the vertex buffer slot that `self` tracks.
11971221 fn flush ( & mut self , slot : u32 ) -> Option < ArcRenderCommand > {
1222+ let binding_size = self
1223+ . range
1224+ . end
1225+ . checked_sub ( self . range . start )
1226+ . filter ( |_| self . range . end <= self . buffer . size )
1227+ . expect ( "vertex range must be contained in buffer" ) ;
1228+
11981229 if self . is_dirty {
11991230 self . is_dirty = false ;
12001231 Some ( ArcRenderCommand :: SetVertexBuffer {
12011232 slot,
12021233 buffer : self . buffer . clone ( ) ,
12031234 offset : self . range . start ,
1204- size : wgt :: BufferSize :: new ( self . range . end - self . range . start ) ,
1235+ size : Some ( binding_size ) ,
12051236 } )
12061237 } else {
12071238 None
@@ -1565,7 +1596,7 @@ where
15651596pub mod bundle_ffi {
15661597 use super :: { RenderBundleEncoder , RenderCommand } ;
15671598 use crate :: { id, RawString } ;
1568- use core:: { convert:: TryInto , slice} ;
1599+ use core:: { convert:: TryInto , num :: NonZeroU64 , slice} ;
15691600 use wgt:: { BufferAddress , BufferSize , DynamicOffset , IndexFormat } ;
15701601
15711602 /// # Safety
@@ -1624,7 +1655,7 @@ pub mod bundle_ffi {
16241655 slot,
16251656 buffer_id,
16261657 offset,
1627- size,
1658+ size : size . map ( NonZeroU64 :: get ) ,
16281659 } ) ;
16291660 }
16301661
0 commit comments