Заполнение MTLBuffer 16-битными числами с плавающей запятой

Я заполняю MTLBuffer векторами float2. Буфер создается и заполняется следующим образом:

struct Particle {
   var position: float2
   ...
}

let particleCount = 100000
let bufferSize = MemoryLayout<Particle>.stride * particleCount
particleBuffer = device.makeBuffer(length: bufferSize)!

var pointer = particleBuffer.contents().bindMemory(to: Particle.self, capacity: particleCount)
pointer = pointer.advanced(by: currentParticles)
pointer.pointee.position = [x, y]

В моем файле Metal доступ к буферу осуществляется следующим образом:

struct Particle {
   float2 position;
   ...
};

kernel void compute(device Particle *particles [[buffer(0)]], … ) 

Мне нужно использовать числа с половинной точностью в вычислительном ядре Metal. На стороне Metal это так же просто, как указать половину2 для типа данных.

Что касается процессора, как лучше всего заполнить буфер числами с половинной точностью?

Я знаю, что вы включили тег swift4, но если вы можете перейти на Swift 5.3 (скачать бета-версию XCode 12.2 от Apple), то, по-видимому, у них уже есть Float16. Ура! hackingwithswift.com/articles/218/whats-new-in-swift-5-3

Pixel 11.10.2020 11:33
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
5
1
522
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Поплавки половинной точности в Swift очень неудобны, так как пока нет типа Float16 (хотя один был предложен), а нестандартный тип __fp16, поддерживаемый Clang, не полностью поддерживается в Swift.

Однако с помощью каламбура и связывания заголовков вы можете собрать воедино работающее решение.

Основной подход таков: в заголовке Objective-C объявите тип half2 с двумя элементами uint16_t. Это будет наш тип хранилища. Также объявите функцию, которая принимает число с плавающей запятой и записывает его, как если бы оно было __fp16 в указатель на uint16_t:

typedef struct {
    uint16_t x, y;
} half2;

static void storeAsF16(float value, uint16_t *_Nonnull pointer) { *(__fp16 *)pointer = value; }

Вернувшись в Swift, вы можете объявить typealias и использовать его в определении структуры частиц:

typealias Half2 = half2

struct Particle {
    var position: Half2
}

(Здесь я набираю тип с нижнего регистра на имя Swiftier; вы можете пропустить это и просто назвать тип Obj-C Half2, если хотите).

Вместо привязки к типу частиц вам нужно будет привязать буфер к вашему полувекторному типу:

var pointer = particleBuffer.contents().bindMemory(to: Half2.self, capacity: particleCount)

Когда мы используем нашу служебную функцию для хранения числа с плавающей запятой, битовый шаблон для соответствующего половинного значения записывается в UInt16:

var x: UInt16 = 0
var y: UInt16 = 0
storeAsF16(1.0, &x) // 0x3c00
storeAsF16(0.5, &y) // 0x3800

Теперь, когда у нас есть правильно сформированные половинные значения в этой паре переменных, мы можем записать их в буфер:

pointer.pointee = Half2(x: x, y: y)

Обратите внимание, что этот подход не является ни переносимым, ни безопасным, особенно потому, что Swift не дает никаких гарантий относительно расположения элементов структуры. Могут быть и другие менее громоздкие подходы; это как раз то, что работало для меня в прошлом.

Другие вопросы по теме

/src: ошибка: не удалось найти исходные файлы для целей: MyKituraAppTests; используйте свойство «путь» в манифесте Swift 4, чтобы установить собственный целевой путь
Сделать текст метки полужирным при касании
Разобрать responseJSON в ObjectMapper
Swift с изображением в фоновом режиме, не меняющимся с подвидом
Swift4: как решить «Неустранимая ошибка: невозможно сформировать диапазон с верхней границей <нижняя граница»? (продолжительность задержки в пользовательском интерфейсе)
Пытаясь разобрать NSArray на строку с разделителем, чтобы быстро создать QR-код
Сопоставьте функцию с глобальной переменной в быстрой ошибке «Инициализатор 'init (_ :)' требует, чтобы '[_]' соответствовало 'LosslessStringConvertible'"
RxAlamofire сделать почтовый вызов с телом json
У меня возникли проблемы с добавлением нескольких маркеров в mapView
Вывод AVFoundation Photo ярче, чем предварительный просмотр в Swift