Как преобразовать существующую текстуру OpenGL в текстуру металла

Я работаю над разработкой некоторых подключаемых модулей FxPlug для Motion и FCP X. В конечном итоге я бы хотел, чтобы они отображались в Metal, поскольку Apple отказывается от OpenGL.

В настоящее время я использую CoreImage, и хотя я смог использовать функциональность CoreImage для обработки металла вне FxPlug SDK, FxPlug предоставляет мне только фрейм в виде текстуры OpenGL. Я пробовал просто передать это в фильтр CoreImage, но в итоге получаю такую ​​ошибку:

Cannot render image (with an input GL texture) using a metal-DG context.

После небольшого исследования я обнаружил, что я предположительно могу использовать CVPixelBuffers для обмена текстурами между два, но после попытки написать код с использованием этого метода в течение некоторого времени я пришел к убеждению, что это было предназначено как способ ЗАПИСАТЬ (например, создать с нуля) в общий буфер, но не конвертировать между ними. Хотя это может быть неверно, я не могу найти способ заставить существующую текстуру GL существовать в CVPixelBuffer.

TL; DR: Я нашел способы получить результирующую текстуру Metal или OpenGL ИЗ CVPixelBuffer, но я не могу найти способ создать CVPixelBuffer из существующей текстуры OpenGL. Мое сердце не настроено на этот метод, поскольку моя конечная цель - просто преобразовать из OpenGL в Metal, а затем обратно в OpenGL (в идеале эффективным способом).

Кто-нибудь еще нашел способ работы с FxPlug with Metal? Есть ли хороший способ преобразовать текстуру OpenGL в Metal / CVPixelBuffer?


person mredig    schedule 18.12.2018    source источник
comment
Вы можете создать общую текстуру и использовать OpenGL для копирования из предоставленной FxPlug текстуры OpenGL в эту общую текстуру, использовать Metal, чтобы делать все, что вы хотите сделать с общей текстурой, а затем использовать OpenGL, чтобы скопировать ее обратно в FxPlug- при условии текстуры.   -  person Ken Thomases    schedule 18.12.2018
comment
Думаю, моя проблема будет в том, что я не знаю, как скопировать это в общую текстуру. У вас есть образец кода? FxTexture предоставляет (GLuint)textureId; и (GLenum)target;, и я не нашел способа использовать ни один из них для копирования в CVPixelBuffer.   -  person mredig    schedule 20.12.2018


Ответы (1)


Я написал FxPlug, который использует как текстуры OpenGL, так и текстуры металла. То, что вы ищете, - это IOSurface. Это текстуры, которые можно использовать как с Metal, так и с OpenGL, хотя у них есть некоторые ограничения. Таким образом, если у вас уже есть текстура Metal или OpenGL, вы должны скопировать ее в IOSurface, чтобы использовать с другой системой.

Чтобы создать IOSurface, вы можете использовать CVPixelBuffers (включив kCVPixelBufferKey ) или вы можете создать его напрямую, используя класс IOSurface, определенный в <IOSurface/IOSurfaceObjC.h>.

Когда у вас есть IOSurface, вы можете скопировать в него текстуру OpenGL, получив текстуру OpenGL из IOSurface через CGLTexImageIOSurface2D() (определенную в <OpenGL/CGLIOSurface.h>). Затем вы берете эту текстуру и используете ее как фоновую текстуру для FBO. Вы можете, например, нарисовать в нем текстурированный четырехугольник, используя вход FxTexture в качестве текстуры. Не забудьте позвонить glFlush(), когда закончите!

Затем возьмите IOSurface и создайте из него MTLTexture с помощью -[MTLDevice newTextureWithDescriptor:ioSurface:plane:] (описано здесь). Вы хотите создать выходной IOSurface для рисования, а также создать MTLTexture из него. Сделайте рендеринг металла на выходе MTLTexture. Затем возьмите выходной файл IOSurface и создайте из него текстуру OpenGL с помощью CGLTexImageIOSurface2D(). Теперь скопируйте эту текстуру OpenGL в выходной файл FxTexture, используя ее в качестве основы для FBO с текстурой или любым другим способом, который вы предпочитаете.

Как видите, обратная сторона этого заключается в том, что для каждого рендеринга требуется 2 копии - 1 входных данных в IOSurface и 1 выходных IOSurface в выходную текстуру, которую предоставляет вам приложение. Другой недостаток заключается в том, что, вероятно, все это спорный вопрос, поскольку, поскольку Apple публично объявила о прекращении поддержки OpenGL, они, вероятно, уже работают над решением на основе Metal. Делать все самостоятельно, возможно, потребует дополнительной работы. (Хотя положительным моментом является то, что вы можете использовать тот же код в других хост-приложениях, которые поддерживают только OpenGL.)

person user1118321    schedule 22.01.2019
comment
Я предполагаю, что, начиная с FxTexture, предоставленного хост-приложением, это будет включать в себя то, что вы сказали о копировании текстуры в IOSurface. Потребуется ли для этого вообще использование CVPixelBuffer в этом сценарии? И еще кое-что, что мне было интересно, имеет ли дублирование текстуры какое-либо снижение производительности, или металл в целом компенсирует это? - person mredig; 22.01.2019
comment
Да, вам нужно скопировать inputImage, отправленный вашему -renderOutput:withInput:withInfo: методу. Это потребует использования IOSurface, который вы можете создать с помощью CVPixelBuffer, если хотите, но вы также можете создать его без CVPixelBuffer. - person user1118321; 22.01.2019
comment
В примере кода Apple описан способ: developer.apple.com/documentation/metal/ - person Aliaksandr Andrashuk; 15.12.2020