From 89318d1bc01c2c8baaa0fd789980d60234e1dd53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Furby=E2=84=A2?= Date: Mon, 20 Jul 2026 22:56:03 -0700 Subject: [PATCH] [VtArray] Add zero-copy withUnsafeBufferPointer and single-copy buffer init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a borrowing withUnsafeBufferPointer(_:) to the VtArray protocols, backed by cdata() so the read never detaches the copy-on-write storage, and an init(_: UnsafeBufferPointer) that assigns a contiguous buffer in a single copy rather than element-by-element push_backs. The initializer is the write-side complement of cdata()'s zero-copy reads. Signed-off-by: Furby™ --- SwiftUsd.docc/AboutThisRepo/ChangeLog.md | 4 + source/SwiftOverlay/VtArray.h | 47 ++++ source/SwiftOverlay/VtArrayProtocol.swift | 292 ++++++++++++++++++---- 3 files changed, 297 insertions(+), 46 deletions(-) create mode 100644 source/SwiftOverlay/VtArray.h diff --git a/SwiftUsd.docc/AboutThisRepo/ChangeLog.md b/SwiftUsd.docc/AboutThisRepo/ChangeLog.md index 5ad1547638..c724c156ba 100644 --- a/SwiftUsd.docc/AboutThisRepo/ChangeLog.md +++ b/SwiftUsd.docc/AboutThisRepo/ChangeLog.md @@ -11,6 +11,10 @@ Changes to SwiftUsd ``` } +### TBD +Released TBD, based on OpenUSD TBD +- Add zero-copy `VtArray` reads via `withUnsafeBufferPointer(_:)` and single-copy construction from an `UnsafeBufferPointer` + ### 8.0.0 Released 2026-07-22, based on OpenUSD v26.08 - Add support for writing, distributing, and using OpenUSD plugins in Swift/C++ with Swift Package Manager diff --git a/source/SwiftOverlay/VtArray.h b/source/SwiftOverlay/VtArray.h new file mode 100644 index 0000000000..815239e2d7 --- /dev/null +++ b/source/SwiftOverlay/VtArray.h @@ -0,0 +1,47 @@ +//===----------------------------------------------------------------------===// +// This source file is part of github.com/apple/SwiftUsd +// +// Copyright © 2025 Apple Inc. and the SwiftUsd project authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 +//===----------------------------------------------------------------------===// + +#ifndef SWIFTUSD_SWIFTOVERLAY_VTARRAY_H +#define SWIFTUSD_SWIFTOVERLAY_VTARRAY_H + +#include +#include "pxr/base/vt/array.h" + +namespace __Overlay { + // expose `assign` in a way Swift will import. VtArray uses copy-on-write + // storage, so this constructs the array with a single copy of the source + // range, rather than the element-by-element push_back the Collection + // initializer falls back to. + // + // Swift 6.3 fixes https://github.com/swiftlang/swift/pull/82161, but on Swift 6.1 and Swift 6.2, + // templated methods taking pointers without nullability annotations are assumed to be non-null, + // and templated methods taking pointers with nullability annotations aren't imported. So, + // use ptrdiff_t instead + template + inline void VtArray_assign(VtArray& array, ptrdiff_t frontPtr, ptrdiff_t backPtr) { + using Element = typename VtArray::ElementType; + static_assert(std::is_same_v>); + const Element* front = reinterpret_cast(frontPtr); + const Element* back = reinterpret_cast(backPtr); + array.assign(front, back); + } +} + +#endif // SWIFTUSD_SWIFTOVERLAY_VTARRAY_H diff --git a/source/SwiftOverlay/VtArrayProtocol.swift b/source/SwiftOverlay/VtArrayProtocol.swift index ddac442e0f..114ac311ad 100644 --- a/source/SwiftOverlay/VtArrayProtocol.swift +++ b/source/SwiftOverlay/VtArrayProtocol.swift @@ -106,12 +106,21 @@ extension __Overlay { associatedtype ElementType func __beginUnsafe() -> UnsafePointer? func __endUnsafe() -> UnsafePointer? + + func __cdataUnsafe() -> UnsafePointer? + func size() -> Int + + mutating func __assign(_ p: UnsafeBufferPointer) } } extension __Overlay.VtArray_Sequence where Element == Self.ElementType { public func makeIterator() -> __Overlay.VtArray_Sequence_Iterator { .init(begin: __beginUnsafe(), end: __endUnsafe(), s: self) } + + public borrowing func withUnsafeBufferPointer(_ code: (UnsafeBufferPointer) throws(E) -> T) throws(E) -> T { + try code(UnsafeBufferPointer(start: __cdataUnsafe(), count: size())) + } } extension __Overlay { @@ -132,65 +141,256 @@ extension __Overlay { } } -extension pxr.VtBoolArray: __Overlay.VtArrayProtocol {} -extension pxr.VtDoubleArray: __Overlay.VtArrayProtocol {} -extension pxr.VtFloatArray: __Overlay.VtArrayProtocol {} -extension pxr.VtHalfArray: __Overlay.VtArrayProtocol {} +extension __Overlay.VtArrayProtocol { + public init(_ buffer: UnsafeBufferPointer) { + self.init() + self.__assign(buffer) + } +} -extension pxr.VtCharArray: __Overlay.VtArrayProtocol {} -extension pxr.VtUCharArray: __Overlay.VtArrayProtocol {} -extension pxr.VtShortArray: __Overlay.VtArrayProtocol {} -extension pxr.VtUShortArray: __Overlay.VtArrayProtocol {} -extension pxr.VtIntArray: __Overlay.VtArrayProtocol {} -extension pxr.VtUIntArray: __Overlay.VtArrayProtocol {} -extension pxr.VtInt64Array: __Overlay.VtArrayProtocol {} -extension pxr.VtUInt64Array: __Overlay.VtArrayProtocol {} +extension pxr.VtBoolArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} +extension pxr.VtDoubleArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} +extension pxr.VtFloatArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} +extension pxr.VtHalfArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} -extension pxr.VtVec4iArray: __Overlay.VtArrayProtocol {} -extension pxr.VtVec3iArray: __Overlay.VtArrayProtocol {} -extension pxr.VtVec2iArray: __Overlay.VtArrayProtocol {} +extension pxr.VtCharArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} +extension pxr.VtUCharArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} +extension pxr.VtShortArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} +extension pxr.VtUShortArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} +extension pxr.VtIntArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} +extension pxr.VtUIntArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} +extension pxr.VtInt64Array: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} +extension pxr.VtUInt64Array: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} -extension pxr.VtVec4hArray: __Overlay.VtArrayProtocol {} -extension pxr.VtVec3hArray: __Overlay.VtArrayProtocol {} -extension pxr.VtVec2hArray: __Overlay.VtArrayProtocol {} +extension pxr.VtVec4iArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} +extension pxr.VtVec3iArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} +extension pxr.VtVec2iArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} -extension pxr.VtVec4fArray: __Overlay.VtArrayProtocol {} -extension pxr.VtVec3fArray: __Overlay.VtArrayProtocol {} -extension pxr.VtVec2fArray: __Overlay.VtArrayProtocol {} +extension pxr.VtVec4hArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} +extension pxr.VtVec3hArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} +extension pxr.VtVec2hArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} -extension pxr.VtVec4dArray: __Overlay.VtArrayProtocol {} -extension pxr.VtVec3dArray: __Overlay.VtArrayProtocol {} -extension pxr.VtVec2dArray: __Overlay.VtArrayProtocol {} +extension pxr.VtVec4fArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} +extension pxr.VtVec3fArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} +extension pxr.VtVec2fArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} -extension pxr.VtMatrix4fArray: __Overlay.VtArrayProtocol {} -extension pxr.VtMatrix3fArray: __Overlay.VtArrayProtocol {} -extension pxr.VtMatrix2fArray: __Overlay.VtArrayProtocol {} +extension pxr.VtVec4dArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} +extension pxr.VtVec3dArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} +extension pxr.VtVec2dArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} -extension pxr.VtMatrix4dArray: __Overlay.VtArrayProtocol {} -extension pxr.VtMatrix3dArray: __Overlay.VtArrayProtocol {} -extension pxr.VtMatrix2dArray: __Overlay.VtArrayProtocol {} +extension pxr.VtMatrix4fArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} +extension pxr.VtMatrix3fArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} +extension pxr.VtMatrix2fArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} -extension pxr.VtRange3fArray: __Overlay.VtArrayProtocol {} -extension pxr.VtRange3dArray: __Overlay.VtArrayProtocol {} -extension pxr.VtRange2fArray: __Overlay.VtArrayProtocol {} -extension pxr.VtRange2dArray: __Overlay.VtArrayProtocol {} -extension pxr.VtRange1fArray: __Overlay.VtArrayProtocol {} -extension pxr.VtRange1dArray: __Overlay.VtArrayProtocol {} +extension pxr.VtMatrix4dArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} +extension pxr.VtMatrix3dArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} +extension pxr.VtMatrix2dArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} + +extension pxr.VtRange3fArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} +extension pxr.VtRange3dArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} +extension pxr.VtRange2fArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} +extension pxr.VtRange2dArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} +extension pxr.VtRange1fArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} +extension pxr.VtRange1dArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} -extension pxr.VtIntervalArray: __Overlay.VtArrayProtocol {} -extension pxr.VtRect2iArray: __Overlay.VtArrayProtocol {} +extension pxr.VtIntervalArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} +extension pxr.VtRect2iArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} // VtStringArray gains Codable conformance in Codable.swift, // but it can't satisfy the requirements that ElementType is Codable // because std.string isn't Codable -extension pxr.VtStringArray: __Overlay.VtArray_WithoutCodableProtocol {} -extension pxr.VtTokenArray: __Overlay.VtArrayProtocol {} +extension pxr.VtStringArray: __Overlay.VtArray_WithoutCodableProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} +extension pxr.VtTokenArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} -extension pxr.VtQuathArray: __Overlay.VtArrayProtocol {} -extension pxr.VtQuatfArray: __Overlay.VtArrayProtocol {} -extension pxr.VtQuatdArray: __Overlay.VtArrayProtocol {} -extension pxr.VtQuaternionArray: __Overlay.VtArrayProtocol {} +extension pxr.VtQuathArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} +extension pxr.VtQuatfArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} +extension pxr.VtQuatdArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} +extension pxr.VtQuaternionArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} -extension Overlay.SdfAssetPath_VtArray: __Overlay.VtArrayProtocol {} +extension Overlay.SdfAssetPath_VtArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +} -extension pxr.VtTimeCodeArray: __Overlay.VtArrayProtocol {} \ No newline at end of file +extension pxr.VtTimeCodeArray: __Overlay.VtArrayProtocol { + public mutating func __assign(_ p: UnsafeBufferPointer) { + __Overlay.VtArray_assign(&self, Int(bitPattern: p.baseAddress), Int(bitPattern: p.baseAddress.map { $0 + p.count })) + } +}