Здесь необходимо учесть несколько моментов:
Ваш указатель объекта MTLBuffer не указывает на содержимое объекта
MTLBuffer
это металлический каркасный объект, который управляет буфером памяти на GPU.Адрес, который у вас есть, это просто адрес этого объекта.Для некоторых буферов Metal предоставляет способ доступа к содержимому буфера из CPU, используя метод [MTLBuffer contents]
.contents
возвращает void *
, который вы можете напрямую использовать для чтения и записи из буфера со следующими предостережениями:
Содержимое вашего MTLBuffer не всегда может быть доступно из ЦП
Это зависит от того, на какой платформе вы находитесь.Если вы работаете исключительно на iOS / tvOS, просто создайте свой MTLBuffer
с режимом хранения MTLStorageModeShared
, и все будет в порядке - Metal обеспечит синхронизацию данных, которые вы видите на процессоре, с представлением графического процессора,В MacOS это зависит от того, какой графический процессор вы используете, поэтому здесь есть некоторые дополнительные тонкости.Сейчас я предполагаю, что мы говорим только о iOS / tvOS.
Существует несколько способов объединить Objective-C с кодом C ++
Один из вариантов - создатьФайлы Objective-C ++ (файлы .mm) и поместите весь свой специфичный для Metal код в подкласс в этих файлах .mm.Это позволило бы вам воспользоваться преимуществами ARC (автоматического подсчета ссылок) Objective-C и по-прежнему создавать красивые, обертки C ++.В файле заголовка для вашего класса Objective-C ++ вы должны сделать что-то вроде этого:
class MetalBuffer : GenericBuffer
{
private:
#ifdef __OBJC__
id <MTLBuffer> metalBuffer;
#else
void *internalMetalBuffer;
#endif
}
Это позволит вашим обычным (не Objective-C ++) классам включать заголовок Objective-C ++.Я сделал «специальный» управляемый указатель private
, чтобы никто не пытался получить к нему доступ из-за пределов класса Objective-C ++, поскольку это, очевидно, было бы плохой идеей.
Если этот подход не подходит, вы можете просто делать все на C ++, но тогда вам придется вручную отслеживать ссылки на ваши объекты Objective-C:
Если вывы должны хранить ваши объекты в коде C ++ как пустые указатели, вам потребуется ручной подсчет ссылок
Objective-C использует ARC для отслеживания использования объектов и автоматического освобождения объектов в зависимости от ситуации.Если вы пытаетесь управлять всем этим в C ++, вам нужно будет вручную управлять ссылками на ваши объекты (например, MTLBuffer
и выше).Это делается сообщением ARC о том, что вы хотите привести управляемые объекты Objective-C id
к обычным указателям на Си.
После создания экземпляра MTLBuffer
вы можете использовать CFBridgingRetain()
на своем объекте, который теперь позволяет хранить его как void *
(не путать с захваченным void *
, указывающим на содержимое вашего буфера!) В вашем классе C ++.Когда вы закончите использовать MTLBuffer
, вы можете позвонить CFRelease()
на void *
, чтобы освободить его.Вам не нужно беспокоиться об освобождении буфера contents
- основная память будет освобождена автоматически после освобождения объекта MTLBuffer
(например, при вызове CFRelease()
).
Обратите внимание, что выможно использовать CFBridgingRelease()
, когда вам нужно вызвать функции Objective-C, которые используют ваш объект MTLBuffer
(например, setFragmentBuffer
и т. д.). Думайте о CFBridgingRelease()
как о преобразователе, который возвращает ваш объект обратно в ARC, но учтите, чтоон включает в себя ручную разблокировку, что означает, что как только Металл завершит работу с вашим объектом, он будет автоматически разблокирован.
Если вы хотите, чтобы ваш объект жил за пределами текущего запроса Metal, вы должны сохранить еще один указатель на него, используя CFBridgingRetain()
.
Опять же, это последнее средство - я бы не советовал идти по этому маршруту.
Удачи!