@@ -297,37 +297,85 @@ function datasize(layout::LayoutStrategy, type::SPIRType)
297297 dataoffset (layout, type, lastindex (members)) + datasize (layout, members[end ])
298298 end
299299 end
300- value:: Int
300+ return value:: Int
301301end
302302
303303function dataoffset (layout:: VulkanLayout , type:: SPIRType , i:: Integer )
304+ istype (type, SPIR_TYPE_STRUCT) || return next_offset (layout, type, i, 0 , 0 )
305+ offset = start = 0
306+ for j in 2 : i
307+ start = offset + datasize (layout, type. struct. members[j - 1 ])
308+ offset = next_offset (layout, type, j, start, start)
309+ end
310+ return offset
311+ end
312+
313+ const STRADDLE_ADJUSTMENT_CANDIDATE_OFFSETS = 0 : 15
314+ straddle_adjustment_offset_to_mask (offset:: Int ) = UInt16 (1 ) << offset
315+ straddle_adjustment_is_offset_in_mask (mask:: UInt16 , offset:: Integer ) = ((mask << (15 - offset)) >> 15 ) == 1
316+
317+ function compatible_straddle_adjustments (alignment:: Integer )
318+ compatible = 0x0000
319+ for offset in STRADDLE_ADJUSTMENT_CANDIDATE_OFFSETS
320+ preserves_alignment (offset, alignment) || continue
321+ compatible |= straddle_adjustment_offset_to_mask (offset)
322+ end
323+ return compatible
324+ end
325+
326+ preserves_alignment (offset:: Integer , alignment:: Integer ) = offset % alignment == 0
327+
328+ function get_fitting_straddle_adjustments (layout:: VulkanLayout , type:: SPIRType , adjustments:: UInt16 , outer_offset:: Integer )
329+ if istype (type, SPIR_TYPE_VECTOR)
330+ n = datasize (layout, type)
331+ for offset in STRADDLE_ADJUSTMENT_CANDIDATE_OFFSETS
332+ edge = (outer_offset + offset) % 16 + n
333+ if n < 16
334+ edge < 16 && continue
335+ else
336+ (outer_offset + offset) % 16 == 0 && continue
337+ end
338+ adjustments &= ~ straddle_adjustment_offset_to_mask (offset)
339+ end
340+ elseif istype (type, SPIR_TYPE_STRUCT)
341+ for (i, member) in enumerate (type. struct. members)
342+ offset = dataoffset (layout, type, i)
343+ adjustments &= get_fitting_straddle_adjustments (layout, member, adjustments, outer_offset + offset)
344+ end
345+ end
346+ return adjustments
347+ end
348+
349+ function next_offset (layout:: VulkanLayout , type:: SPIRType , i:: Integer , from:: Integer , outer:: Integer )
304350 @match type. typename begin
305351 & SPIR_TYPE_ARRAY => (i - 1 ) * stride (layout, type)
306352 & SPIR_TYPE_STRUCT => begin
307353 i == 1 && return 0
308354 (; members) = type. struct
309- member_type = members[i]
310- req_alignment = alignment (layout, member_type)
311- prevloc = dataoffset (layout, type, i - 1 ) + datasize (layout, members[i - 1 ])
312- offset = align (prevloc, req_alignment)
313- if istype (member_type, SPIR_TYPE_VECTOR)
314- # Prevent vectors from straddling improperly, as defined per the specification.
315- n = datasize (layout, member_type)
316- if n > 16 || offset % 16 + n > 16
317- offset = align (offset, 16 )
318- end
319- end
320- prev_member_type = members[i - 1 ]
321- @match prev_member_type. typename begin
355+ prev = members[i - 1 ]
356+ @when & SPIR_TYPE_MATRIX || & SPIR_TYPE_ARRAY || & SPIR_TYPE_STRUCT = prev. typename begin
322357 # Advance an offset to have some padding in accordance with the specification:
323358 # The `Offset` decoration of a member must not place it between the end of a structure,
324359 # an array or a matrix and the next multiple of the alignment of that structure, array or matrix.
325360 # https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap15.html#interfaces-resources-layout
326- & SPIR_TYPE_MATRIX || & SPIR_TYPE_ARRAY || & SPIR_TYPE_STRUCT => align (offset, alignment (layout, prev_member_type))
327- _ => offset
361+ from = align (from, alignment (layout, prev))
362+ end
363+ member = members[i]
364+ req_alignment = alignment (layout, member)
365+ offset = align (from, req_alignment)
366+ # Prevent vectors from straddling improperly, as defined per the specification.
367+ compatible = compatible_straddle_adjustments (req_alignment)
368+ adjustments = get_fitting_straddle_adjustments (layout, member, compatible, offset)
369+ @assert adjustments != = 0x0000
370+ adjustment = 0
371+ for offset in STRADDLE_ADJUSTMENT_CANDIDATE_OFFSETS
372+ straddle_adjustment_is_offset_in_mask (adjustments, offset) || continue
373+ adjustment = offset
374+ break
328375 end
376+ return offset + adjustment
329377 end
330- _ => 0
378+ _ => error (type . typename)
331379 end
332380end
333381
@@ -518,3 +566,49 @@ function dataoffset(tmeta::TypeMetadata, type::SPIRType, i)
518566 has_decoration (decs, DecorationOffset) || error (" Missing offset declaration for member " , i, " on " , t)
519567 decs. offset
520568end
569+
570+ show_offsets (layout:: LayoutStrategy , @nospecialize (T)) = show_offsets (stdout , layout, T)
571+ function show_offsets (io:: IO , layout:: LayoutStrategy , @nospecialize (T), depth:: Int = 0 , outer:: Int = 0 , is_new_struct:: Bool = false )
572+ type = layout[T]
573+ istype (type, SPIR_TYPE_STRUCT) || return
574+ ! is_new_struct && print (io, " " ^ depth)
575+ printstyled (io, " struct" ; color = :yellow )
576+ printstyled (io, ' ' , nameof (T); color = 134 )
577+ printstyled (io, " ($(type. struct. uuid) )" ; color = :light_black )
578+ println (io)
579+ start = 0
580+ previous_offset = previous_size = 0
581+ for i in 1 : fieldcount (T)
582+ subT = fieldtype (T, i)
583+ member = layout[subT]
584+ offset = next_offset (layout, type, i, start, outer)
585+ size = datasize (layout, member)
586+ padding = i == 1 ? 0 : offset - (previous_offset + previous_size)
587+ start = offset + size
588+ outer += padding
589+ print (io, " " ^ (depth + 1 ))
590+ printstyled (io, fieldname (T, i); color = :light_black )
591+ printstyled (io, " ::" ; color = 176 )
592+ if istype (member, SPIR_TYPE_STRUCT)
593+ show_offsets (io, layout, subT, depth + 1 , outer, true )
594+ printstyled (io, " $offset " ; color = :cyan )
595+ print (io, " → " )
596+ printstyled (io, " $(offset + size) " ; color = 134 )
597+ printstyled (io, " ($(outer) → $(outer + size) )" ; color = :light_black )
598+ println (io)
599+ else
600+ printstyled (io, subT; color = :yellow )
601+ printstyled (io, " $offset " ; color = :cyan )
602+ print (io, " → " )
603+ printstyled (io, " $(offset + size) " ; color = 134 )
604+ printstyled (io, " ($(outer) → $(outer + size) )" ; color = :light_black )
605+ println (io)
606+ show_offsets (io, layout, subT, depth + 1 , outer, false )
607+ end
608+ outer += size
609+ previous_offset = offset
610+ previous_size = size
611+ end
612+ printstyled (io, " " ^ depth, " end" ; color = :yellow )
613+ end
614+
0 commit comments