mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-22 06:44:14 +00:00
fix(spv-out): OpSourceContinued for large source (gfx-rs#5390)
This commit is contained in:
parent
911baf3e8c
commit
17ef6cac90
@ -10,8 +10,12 @@ pub(super) fn bytes_to_words(bytes: &[u8]) -> Vec<Word> {
|
||||
|
||||
pub(super) fn string_to_words(input: &str) -> Vec<Word> {
|
||||
let bytes = input.as_bytes();
|
||||
let mut words = bytes_to_words(bytes);
|
||||
|
||||
str_bytes_to_words(bytes)
|
||||
}
|
||||
|
||||
pub(super) fn str_bytes_to_words(bytes: &[u8]) -> Vec<Word> {
|
||||
let mut words = bytes_to_words(bytes);
|
||||
if bytes.len() % 4 == 0 {
|
||||
// nul-termination
|
||||
words.push(0x0u32);
|
||||
@ -20,6 +24,21 @@ pub(super) fn string_to_words(input: &str) -> Vec<Word> {
|
||||
words
|
||||
}
|
||||
|
||||
/// split a string into chunks and keep utf8 valid
|
||||
#[allow(unstable_name_collisions)]
|
||||
pub(super) fn string_to_byte_chunks(input: &str, limit: usize) -> Vec<&[u8]> {
|
||||
let mut offset: usize = 0;
|
||||
let mut start: usize = 0;
|
||||
let mut words = vec![];
|
||||
while offset < input.len() {
|
||||
offset = input.floor_char_boundary(offset + limit);
|
||||
words.push(input[start..offset].as_bytes());
|
||||
start = offset;
|
||||
}
|
||||
|
||||
words
|
||||
}
|
||||
|
||||
pub(super) const fn map_storage_class(space: crate::AddressSpace) -> spirv::StorageClass {
|
||||
match space {
|
||||
crate::AddressSpace::Handle => spirv::StorageClass::UniformConstant,
|
||||
@ -107,3 +126,35 @@ pub fn global_needs_wrapper(ir_module: &crate::Module, var: &crate::GlobalVariab
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
||||
///HACK: this is taken from std unstable, remove it when std's floor_char_boundary is stable
|
||||
trait U8Internal {
|
||||
fn is_utf8_char_boundary(&self) -> bool;
|
||||
}
|
||||
|
||||
impl U8Internal for u8 {
|
||||
fn is_utf8_char_boundary(&self) -> bool {
|
||||
// This is bit magic equivalent to: b < 128 || b >= 192
|
||||
(*self as i8) >= -0x40
|
||||
}
|
||||
}
|
||||
|
||||
trait StrUnstable {
|
||||
fn floor_char_boundary(&self, index: usize) -> usize;
|
||||
}
|
||||
|
||||
impl StrUnstable for str {
|
||||
fn floor_char_boundary(&self, index: usize) -> usize {
|
||||
if index >= self.len() {
|
||||
self.len()
|
||||
} else {
|
||||
let lower_bound = index.saturating_sub(3);
|
||||
let new_index = self.as_bytes()[lower_bound..=index]
|
||||
.iter()
|
||||
.rposition(|b| b.is_utf8_char_boundary());
|
||||
|
||||
// SAFETY: we know that the character boundary will be within four bytes
|
||||
unsafe { lower_bound + new_index.unwrap_unchecked() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -43,6 +43,42 @@ impl super::Instruction {
|
||||
instruction
|
||||
}
|
||||
|
||||
pub(super) fn source_continued(source: &[u8]) -> Self {
|
||||
let mut instruction = Self::new(Op::SourceContinued);
|
||||
instruction.add_operands(helpers::str_bytes_to_words(source));
|
||||
instruction
|
||||
}
|
||||
|
||||
pub(super) fn source_auto_continued(
|
||||
source_language: spirv::SourceLanguage,
|
||||
version: u32,
|
||||
source: &Option<DebugInfoInner>,
|
||||
) -> Vec<Self> {
|
||||
let mut instructions = vec![];
|
||||
|
||||
let with_continue = source.as_ref().and_then(|debug_info| {
|
||||
(debug_info.source_code.len() > u16::MAX as usize).then_some(debug_info)
|
||||
});
|
||||
if let Some(debug_info) = with_continue {
|
||||
let mut instruction = Self::new(Op::Source);
|
||||
instruction.add_operand(source_language as u32);
|
||||
instruction.add_operands(helpers::bytes_to_words(&version.to_le_bytes()));
|
||||
|
||||
let words = helpers::string_to_byte_chunks(debug_info.source_code, u16::MAX as usize);
|
||||
instruction.add_operand(debug_info.source_file_id);
|
||||
instruction.add_operands(helpers::str_bytes_to_words(words[0]));
|
||||
instructions.push(instruction);
|
||||
for word_bytes in words[1..].iter() {
|
||||
let instruction_continue = Self::source_continued(word_bytes);
|
||||
instructions.push(instruction_continue);
|
||||
}
|
||||
} else {
|
||||
let instruction = Self::source(source_language, version, source);
|
||||
instructions.push(instruction);
|
||||
}
|
||||
instructions
|
||||
}
|
||||
|
||||
pub(super) fn name(target_id: Word, name: &str) -> Self {
|
||||
let mut instruction = Self::new(Op::Name);
|
||||
instruction.add_operand(target_id);
|
||||
|
@ -1899,7 +1899,7 @@ impl Writer {
|
||||
source_code: debug_info.source_code,
|
||||
source_file_id,
|
||||
});
|
||||
self.debugs.push(Instruction::source(
|
||||
self.debugs.append(&mut Instruction::source_auto_continued(
|
||||
spirv::SourceLanguage::Unknown,
|
||||
0,
|
||||
&debug_info_inner,
|
||||
|
7
naga/tests/in/debug-symbol-large-source.param.ron
Normal file
7
naga/tests/in/debug-symbol-large-source.param.ron
Normal file
@ -0,0 +1,7 @@
|
||||
(
|
||||
spv: (
|
||||
version: (1, 1),
|
||||
debug: true,
|
||||
adjust_coordinate_space: false,
|
||||
),
|
||||
)
|
7440
naga/tests/in/debug-symbol-large-source.wgsl
Normal file
7440
naga/tests/in/debug-symbol-large-source.wgsl
Normal file
File diff suppressed because it is too large
Load Diff
8625
naga/tests/out/spv/debug-symbol-large-source.spvasm
Normal file
8625
naga/tests/out/spv/debug-symbol-large-source.spvasm
Normal file
File diff suppressed because it is too large
Load Diff
@ -886,11 +886,15 @@ fn convert_wgsl() {
|
||||
let inputs = [
|
||||
("debug-symbol-simple", Targets::SPIRV),
|
||||
("debug-symbol-terrain", Targets::SPIRV),
|
||||
("debug-symbol-large-source", Targets::SPIRV),
|
||||
];
|
||||
for &(name, targets) in inputs.iter() {
|
||||
// WGSL shaders lives in root dir as a privileged.
|
||||
let input = Input::new(None, name, "wgsl");
|
||||
let source = input.read_source();
|
||||
|
||||
// crlf will make the large split output different on different platform
|
||||
let source = source.replace('\r', "");
|
||||
match naga::front::wgsl::parse_str(&source) {
|
||||
Ok(mut module) => check_targets(&input, &mut module, targets, Some(&source)),
|
||||
Err(e) => panic!(
|
||||
|
Loading…
Reference in New Issue
Block a user