fix(spv-out): OpSourceContinued for large source (gfx-rs#5390)

This commit is contained in:
wicast 2024-04-06 18:00:10 +08:00 committed by Teodor Tanasoaia
parent 911baf3e8c
commit 17ef6cac90
7 changed files with 16165 additions and 2 deletions

View File

@ -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() }
}
}
}

View File

@ -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);

View File

@ -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,

View File

@ -0,0 +1,7 @@
(
spv: (
version: (1, 1),
debug: true,
adjust_coordinate_space: false,
),
)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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!(