Графический рендеринг: кодер команды рендеринга

В этой главе описываются, как создать и работать с MTLRenderCommandEncoder и MTLParallelRenderCommandEncoder объекты, использующиеся для кодирования команд рендеринга графики в буфер команд. MTLRenderCommandEncoder команды описывают конвейер рендеринга графики, как замечено на рисунке 5-1.

  Конвейер рендеринга графики металла рисунка 5-1

A MTLRenderCommandEncoder объект представляет единственный кодер команды рендеринга. A MTLParallelRenderCommandEncoder объект позволяет единственной передаче рендеринга быть поврежденной во много отдельные MTLRenderCommandEncoder объекты, каждый из которых может быть присвоен различному потоку. Команды от различных кодеров команды рендеринга тогда объединены в цепочку вместе и выполнены в непротиворечивом, предсказуемом порядке, как описано в Многократных Потоках для Передачи Рендеринга.

Создавая и Используя кодер команды рендеринга

Для создания инициализируйте и используйте единственный кодер команды рендеринга:

  1. Создайте a MTLRenderPassDescriptor объект определить набор присоединений, служащих местом назначения рендеринга для графических команд в буфере команд для той передачи рендеринга. Как правило, Вы создаете a MTLRenderPassDescriptor возразите один раз и повторное использование это каждый раз, когда Ваше приложение представляет кадр. Посмотрите Создание Дескриптора Передачи Рендеринга.

  2. Создайте a MTLRenderCommandEncoder объект путем вызова renderCommandEncoderWithDescriptor: метод MTLCommandBuffer с указанным рендерингом передают дескриптор. Посмотрите Используя Дескриптор Передачи Рендеринга для Создания Кодера Команды Рендеринга.

  3. Создайте a MTLRenderPipelineState объект определить состояние конвейера рендеринга графики (включая программы построения теней, смешивание, мультивыборку и тестирование видимости) для один или больше рисует вызовы. Для использования этого конвейерного состояния рендеринга для рисования примитивов вызовите setRenderPipelineState: метод MTLRenderCommandEncoder. Для получения дополнительной информации посмотрите Создание Конвейерного состояния Рендеринга.

  4. Текстуры набора, буферы и сэмплеры, которые будут использоваться кодером команды рендеринга, как описано в Указании Ресурсов для Кодера Команды Рендеринга.

  5. Вызвать MTLRenderCommandEncoder методы для указания дополнительного состояния стандартной функции, включая глубину и состояние шаблона, как объяснено в Операциях состояния Стандартной функции.

  6. Наконец, вызвать MTLRenderCommandEncoder методы для рисования графических примитивов, как описано в Рисовании Геометрических Примитивов.

Создание дескриптора передачи рендеринга

A MTLRenderPassDescriptor объект представляет место назначения для закодированных команд рендеринга, которое является набором присоединений. Свойства дескриптора передачи рендеринга могут включать массив до четырех присоединений для цветных пиксельных данных, одного присоединения для пиксельных данных глубины и одного присоединения для пиксельных данных шаблона. renderPassDescriptor удобный метод создает a MTLRenderPassDescriptor объект с цветом, глубиной и присоединяемыми свойствами шаблона с присоединяемым состоянием по умолчанию. visibilityResultBuffer свойство указывает буфер, где устройство может обновить, чтобы указать, передают ли какие-либо выборки глубину и получают тесты с помощью шаблона — для подробных данных, посмотрите Операции состояния Стандартной функции.

Каждое отдельное присоединение, включая текстуру, которая будет записана в, представлено присоединяемым дескриптором. Для присоединяемого дескриптора формат пикселя связанной текстуры должен быть выбран соответственно для хранения цвета, глубины или данных шаблона. Для цветного присоединяемого дескриптора, MTLRenderPassColorAttachmentDescriptor, используйте цветной-renderable формат пикселя. Для присоединяемого дескриптора глубины, MTLRenderPassDepthAttachmentDescriptor, используйте формат пикселя глубины-renderable, такой как MTLPixelFormatDepth32Float. Для присоединяемого дескриптора шаблона, MTLRenderPassStencilAttachmentDescriptor, используйте формат пикселя шаблона-renderable, такой как MTLPixelFormatStencil8.

Объем памяти, который текстура фактически использует на пиксель на устройстве, не всегда соответствует размер формата пикселя текстуры в Металлическом коде платформы, потому что устройство добавляет дополнение для выравнивания или других целей. Посмотрите Металлическую Ссылку Констант для того, сколько памяти фактически используется для каждого формата пикселя.

Ограничения на размер и число присоединений описаны в Металлических Возможностях и Ограничениях.

Загрузка и действия хранилища

loadAction и storeAction свойства присоединяемого дескриптора указывают действие, выполняющееся или в запуске или в конце передачи рендеринга. (Для MTLParallelRenderCommandEncoder, загрузка и действия хранилища происходят на границах полной команды, не для каждого из MTLRenderCommandEncoder объекты. Для получения дополнительной информации посмотрите Многократные Потоки для Передачи Рендеринга.)

Возможный loadAction значения включают:

  • MTLLoadActionClear, который пишет то же значение в каждый пиксель в указанном присоединяемом дескрипторе. Для большего количества подробности об этом действии посмотрите Указание Ясного Действия Загрузки.

  • MTLLoadActionLoad, который сохраняет существующее содержание текстуры.

  • MTLLoadActionDontCare, который позволяет каждому пикселю в присоединении брать любое значение в начале передачи рендеринга.

Если Ваше приложение представит все пиксели присоединения для данного кадра, используйте действие загрузки по умолчанию MTLLoadActionDontCare. MTLLoadActionDontCare действие позволяет GPU избегать загружать существующее содержание текстуры, гарантируя лучшую производительность. Иначе, можно использовать MTLLoadActionClear действие для очистки предыдущего содержания присоединения, или MTLLoadActionLoad действие для сохранения их. MTLLoadActionClear действие также избегает загружать существующее содержание текстуры, но оно несет расходы заполнения места назначения со сплошным цветом.

Возможный storeAction значения включают:

  • MTLStoreActionStore, который сохраняет конечные результаты передачи рендеринга в присоединение.

  • MTLStoreActionMultisampleResolve, то, которое разрешает мультидемонстрационные данные от цели рендеринга в единственные демонстрационные значения, хранит их в текстуре, указанной присоединяемым свойством resolveTexture, и оставляет содержание присоединения неопределенным. Для получения дополнительной информации посмотрите Пример: Создание Дескриптора Передачи Рендеринга для Мультивыбранного Рендеринга.

  • MTLStoreActionDontCare, который оставляет присоединение в неопределенном состоянии после того, как передача рендеринга будет завершена. Это может улучшить производительность, поскольку она позволяет реализации избежать любой работы, необходимой для сохранения результатов рендеринга.

Для цветных присоединений, MTLStoreActionStore действие является действием хранилища по умолчанию, потому что приложения почти всегда сохраняют значения итогового цвета в присоединении в конце рендеринга передачи. Для глубины и присоединений шаблона, MTLStoreActionDontCare действие хранилища по умолчанию, потому что те присоединения обычно не должны быть сохранены после того, как передача рендеринга завершена.

Указание ясного действия загрузки

Если loadAction свойство присоединяемого дескриптора установлено в MTLLoadActionClear, тогда очищающееся значение записано в каждый пиксель в указанном присоединяемом дескрипторе в начале передачи рендеринга. Очищающееся свойство значения зависит от типа присоединения.

  • Для MTLRenderPassColorAttachmentDescriptor, clearColor содержит a MTLClearColor значение, состоящее из четырех двойной точности компоненты RGBA с плавающей точкой и использующееся для очистки цветного присоединения. MTLClearColorMake функция создает ясную ценность цвета от красного, зеленого, синего цвета, и альфа-компоненты. Ясный цвет по умолчанию (0.0, 0.0, 0.0, 1.0), или непрозрачный черный цвет.

  • Для MTLRenderPassDepthAttachmentDescriptor, clearDepth содержит одну двойную точность значение очистки с плавающей точкой в диапазоне [0.0, 1.0], который используется для очистки присоединения глубины. Значение по умолчанию 1.0.

  • Для MTLRenderPassStencilAttachmentDescriptor, clearStencil содержит одно 32-разрядное целое без знака, использующееся для очистки присоединения шаблона. Значение по умолчанию 0.

Пример: создание дескриптора передачи рендеринга с действиями загрузки и хранилища

Перечисление 5-1 создает простой дескриптор передачи рендеринга с присоединениями глубины и цветом. Во-первых, два объекта текстуры создаются, один с цветным-renderable форматом пикселя и другим с форматом пикселя глубины. Затем renderPassDescriptor удобный метод MTLRenderPassDescriptor создает дескриптор передачи рендеринга по умолчанию. Тогда к цвету и присоединениям глубины получают доступ через свойства MTLRenderPassDescriptor. Текстуры и действия установлены в colorAttachments[0], который представляет первое цветное присоединение (в индексе 0 в массиве) и присоединение глубины.

Перечисление 5-1  , создающее дескриптор передачи рендеринга с присоединениями цвета и глубины

MTLTextureDescriptor *colorTexDesc = [MTLTextureDescriptor
           texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm
           width:IMAGE_WIDTH height:IMAGE_HEIGHT mipmapped:NO];
id <MTLTexture> colorTex = [gDevice newTextureWithDescriptor:colorTexDesc];
 
MTLTextureDescriptor *depthTexDesc = [MTLTextureDescriptor
           texture2DDescriptorWithPixelFormat:MTLPixelFormatDepth32Float
           width:IMAGE_WIDTH height:IMAGE_HEIGHT mipmapped:NO];
id <MTLTexture> depthTex = [gDevice newTextureWithDescriptor:depthTexDesc];
 
MTLRenderPassDescriptor *renderPassDesc = [MTLRenderPassDescriptor renderPassDescriptor];
renderPassDesc.colorAttachments[0].texture = colorTex;
renderPassDesc.colorAttachments[0].loadAction = MTLLoadActionClear;
renderPassDesc.colorAttachments[0].storeAction = MTLStoreActionStore;
renderPassDesc.colorAttachments[0].clearColor = MTLClearColorMake(0.0,1.0,0.0,1.0);
 
renderPassDesc.depthAttachment.texture = depthTex;
renderPassDesc.depthAttachment.loadAction = MTLLoadActionClear;
renderPassDesc.depthAttachment.storeAction = MTLStoreActionStore;
renderPassDesc.depthAttachment.clearDepth = 1.0;

Пример: создание дескриптора передачи рендеринга для мультивыбранного рендеринга

Использовать MTLStoreActionMultisampleResolve действие, необходимо установить texture свойство к текстуре мультидемонстрационного типа, и resolveTexture свойство будет содержать результат мультидемонстрационной работы решения. (Если texture не поддерживает мультивыборку, тогда результат мультидемонстрационного действия решения не определен.) resolveLevel, resolveSlice, и resolveDepthPlane свойства могут также использоваться для мультидемонстрационной работы решения для указания уровня множественного отображения, части куба и плоскости глубины мультидемонстрационной текстуры, соответственно. В большинстве случаев, значения по умолчанию для resolveLevel, resolveSlice, и resolveDepthPlane применимы. В Перечислении 5-2 присоединение первоначально создается и затем loadAction, storeAction, texture, и resolveTexture свойства установлены поддерживать мультидемонстрационное решение.

  Свойства установки перечисления 5-2 для присоединения с мультидемонстрационным решением

MTLTextureDescriptor *colorTexDesc = [MTLTextureDescriptor
           texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm
           width:IMAGE_WIDTH height:IMAGE_HEIGHT mipmapped:NO];
id <MTLTexture> colorTex = [gDevice newTextureWithDescriptor:colorTexDesc];
 
MTLTextureDescriptor *msaaTexDesc = [MTLTextureDescriptor
           texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm
           width:IMAGE_WIDTH height:IMAGE_HEIGHT mipmapped:NO];
msaaTexDesc.textureType = MTLTextureType2DMultisample;
msaaTexDesc.sampleCount = sampleCount;  //  must be > 1
id <MTLTexture> msaaTex = [gDevice newTextureWithDescriptor:msaaTexDesc];
 
MTLRenderPassDescriptor *renderPassDesc = [MTLRenderPassDescriptor renderPassDescriptor];
renderPassDesc.colorAttachments[0].texture = msaaTex;
renderPassDesc.colorAttachments[0].resolveTexture = colorTex;
renderPassDesc.colorAttachments[0].loadAction = MTLLoadActionClear;
renderPassDesc.colorAttachments[0].storeAction = MTLStoreActionMultisampleResolve;
renderPassDesc.colorAttachments[0].clearColor = MTLClearColorMake(0.0,1.0,0.0,1.0);

Используя дескриптор передачи рендеринга для создания кодера команды рендеринга

После того, как Вы создадите дескриптор передачи рендеринга и укажете его свойства, используйте renderCommandEncoderWithDescriptor: метод a MTLCommandBuffer объект создать кодер команды рендеринга, как показано в Перечислении 5-3.

Перечисление 5-3  , создающее кодер команды рендеринга с дескриптором передачи рендеринга

id <MTLRenderCommandEncoder> renderCE = [commandBuffer
                    renderCommandEncoderWithDescriptor:renderPassDesc];

Отображение представленного содержания с базовой анимацией

Базовая Анимация определяет CAMetalLayer класс, разработанный для специализированного поведения поддержанного уровнем представления, содержание которого представляется с помощью Металла. A CAMetalLayer объект представляет информацию о геометрии содержания (позиция и размер), его визуальные атрибуты (цвет фона, граница и тень), и ресурсы, используемые Металлом для представления содержания в цветном присоединении. Это также инкапсулирует синхронизацию представления содержания так, чтобы содержание могло быть выведено на экран, как только это доступно или в требуемое время. (Для получения дополнительной информации о Базовой Анимации, см. Базовое Руководство по программированию Анимации и Базовую Поваренную книгу Анимации.)

Базовая Анимация также определяет CAMetalDrawable протокол для объектов, которые являются визуализуемыми ресурсами. CAMetalDrawable протокол расширяется MTLDrawable и продает объект, соответствующий MTLTexture протокол, таким образом, это может использоваться в качестве места назначения для рендеринга команд. Представлять в a CAMetalLayer объект, необходимо получить новое CAMetalDrawable объект для каждой передачи рендеринга, доберитесь MTLTexture возразите, что это продает, и используйте ту текстуру для создания цветного присоединения. В отличие от цветных присоединений, создание и уничтожение глубины или присоединения шаблона являются дорогостоящими. Если Вы нуждаетесь или в глубине или получаете присоединения с помощью шаблона, создаете их один раз и затем снова используете их каждый раз, когда кадр представляется.

Как правило, Вы используете layerClass метод для обозначения CAMetalLayer как отступающий тип слоя для Вашего собственного подкласса UIView, как показано в Перечислении 5-4. Иначе, можно создать a CAMetalLayer с init метод и включает уровень в существующее представление.

Перечисление 5-4  Используя CAMetalLayer как отступающий уровень для подкласса UIView

+ (id) layerClass {
    return [CAMetalLayer class];
}

Для отображения содержания, представленного Металлом в уровне, необходимо получить визуализуемый ресурс (a CAMetalDrawable объект) от CAMetalLayer возразите и затем используйте тот ресурс в качестве цветного присоединения в Вашем конвейере рендеринга. Сделать это, Вы первые свойства набора CAMetalLayer объект, которые описывают drawable ресурсы, которые он продает, затем вызовите nextDrawable метод каждый раз Вы начинаете представлять новый кадр. Если CAMetalLayer свойства не установлены, nextDrawable сбои вызова метода. Следующий CAMetalLayer свойства описывают drawable объект:

Если nextDrawable метод успешно выполняется, он возвращает a CAMetalDrawable объект со следующими свойствами только для чтения:

Для отображения содержания drawable объекта после, рендеринг завершен, необходимо представить его Базовой Анимации путем вызова drawable объекта present метод. Для синхронизации представления drawable с завершением буфера команд, ответственного за его рендеринг, можно вызвать любого presentDrawable: или presentDrawable:atTime: удобный метод для aMTLCommandBuffer объект. Эти методы используют запланированный обработчик (см. Регистрирующиеся Блоки Обработчика для Выполнения Буфера команд) вызывать drawable’s present метод, покрывающий большинство сценариев. presentDrawable:atTime: когда drawable представлено, метод обеспечивает дальнейшее управление.

Создание конвейерного состояния рендеринга

Использовать a MTLRenderCommandEncoder объект закодировать команды рендеринга, необходимо сначала указать a MTLRenderPipelineState объект определить состояние графики для любого рисует вызовы. Конвейерный объект состояния рендеринга является долгосрочным постоянным объектом, который может быть создан за пределами кодера команды рендеринга, кэшировался заранее и снова использовал через несколько кодеров команды рендеринга. Когда описание того же набора состояния графики, многократное использование ранее создаваемого конвейерного объекта состояния рендеринга могут избежать дорогих операций, переоценивающих и переводящих указанное состояние в команды GPU.

Конвейерное состояние рендеринга является неизменным объектом. Для создания конвейерного состояния рендеринга Вы сначала создаете и конфигурируете непостоянное MTLRenderPipelineDescriptor объект, описывающий атрибуты конвейерного состояния рендеринга. Затем Вы используете дескриптор для создания a MTLRenderPipelineState объект.

Создание и конфигурирование конвейерного дескриптора рендеринга

Для создания конвейерного состояния рендеринга сначала создайте a MTLRenderPipelineDescriptor объект, имеющий свойства, описывающие графику, представляющую конвейер, утверждает, что Вы хотите использовать во время передачи рендеринга, как изображено на рисунке 5-2. colorAttachments свойство нового MTLRenderPipelineDescriptor объект содержит массив MTLRenderPipelineColorAttachmentDescriptor объекты и каждый дескриптор представляют цветное присоединяемое состояние, указывающее операции смешения и факторы для того присоединения, как детализировано в Конфигурировании Смешивающий Конвейерный Присоединяемый Дескриптор Рендеринга. Присоединяемый дескриптор также указывает формат пикселя присоединения, которое должно соответствовать формат пикселя для текстуры конвейерного дескриптора рендеринга с соответствующим присоединяемым индексом, или ошибка происходит.

Рисунок 5-2  , создающий конвейерное состояние рендеринга из дескриптора

Установите эти свойства для MTLRenderPipelineDescriptor объект:

  • Установите depthAttachmentPixelFormat свойство для соответствия формата пикселя для текстуры depthAttachment в MTLRenderPassDescriptor.

  • Установите stencilAttachmentPixelFormat свойство для соответствия формата пикселя для текстуры stencilAttachment в MTLRenderPassDescriptor.

  • Для указания вершины или программы построения теней фрагмента в конвейерном состоянии рендеринга установите vertexFunction или fragmentFunction свойство, соответственно. Установка fragmentFunction к nil отключает растеризацию пикселей в указанное цветное присоединение, обычно использующееся для рендеринга только для глубины или для вывода данных в буферный объект от вершинного шейдера.

  • Если вершинный шейдер имеет параметр с входными атрибутами на вершину, установите vertexDescriptor свойство для описания организации данных вершины в том параметре, как описано в Дескрипторе Вершины для Организации Данных.

  • Значение по умолчанию YES для rasterizationEnabled свойство достаточно для большинства типичных задач рендеринга. Использовать только этап вершины графического конвейера (например, для сбора данных, преобразованных в вершинный шейдер), устанавливают это свойство в NO.

  • Если присоединяемая мультивыборка поддержек (т.е. присоединение является a MTLTextureType2DMultisample введите текстуру), тогда многократные выборки могут быть созданы на пиксель. Чтобы определить как объединение фрагментов для предоставления пиксельной страховой защиты используйте следующий MTLRenderPipelineDescriptor свойства.

    • sampleCount свойство определяет число выборок для каждого пикселя. Когда MTLRenderCommandEncoder создается, sampleCount поскольку текстуры для всех присоединений должны соответствовать это sampleCount свойство. Если присоединение не может поддерживать мультивыборку, то sampleCount 1, который является также значением по умолчанию.

    • Если alphaToCoverageEnabled установлен в YES, тогда вывод фрагмента альфа-канала для colorAttachments[0] читается и используется для определения маски покрытия.

    • Если alphaToOneEnabled установлен в YES, тогда фрагмент альфа-канала оценивает за colorAttachments[0] вызываются к 1,0, который является самым большим представимым значением. (Другие присоединения незатронуты.)

Создание конвейерного состояния рендеринга от дескриптора

После создания конвейерного дескриптора рендеринга и указания его свойств, используйте его для создания MTLRenderPipelineState объект. Поскольку создание конвейерного состояния рендеринга может потребовать дорогой оценки состояния графики и возможной компиляции указанных графических программ построения теней, можно использовать или блокирование или асинхронный метод запланировать такую работу в пути который лучшие адаптации проект приложения.

  • Для синхронного создания конвейерного объекта состояния рендеринга вызовите любого newRenderPipelineStateWithDescriptor:error: или newRenderPipelineStateWithDescriptor:options:reflection:error: метод a MTLDevice объект. В то время как Металл оценивает информацию о состоянии графики дескриптора и компилирует код программы построения теней для создания конвейерного объекта состояния, эти методы блокируют текущий поток.

  • Для асинхронного создания конвейерного объекта состояния рендеринга вызовите любого newRenderPipelineStateWithDescriptor:completionHandler: или newRenderPipelineStateWithDescriptor:options:completionHandler: метод a MTLDevice объект. Эти методы сразу возвращаются — Металл асинхронно оценивает информацию о состоянии графики дескриптора и компилирует код программы построения теней для создания конвейерного объекта состояния, затем вызывает обработчик завершения для обеспечения нового MTLRenderPipelineState объект.

Когда Вы создаете a MTLRenderPipelineState объект можно также принять решение создать отражательные данные, показывающие подробные данные функции программы построения теней конвейера и ее параметров. newRenderPipelineStateWithDescriptor:options:reflection:error: и newRenderPipelineStateWithDescriptor:options:completionHandler: методы предоставляют эти данные. Избегите получать отражательные данные, если они не будут использоваться. Для получения дополнительной информации о том, как проанализировать отражательные данные, посмотрите Определение Функциональных Подробных данных во Время выполнения.

После создания a MTLRenderPipelineState объект, вызовите setRenderPipelineState: метод MTLRenderCommandEncoder для соединения рендеринга конвейерно обрабатывают состояние с кодером команды для использования в рендеринге.

Перечисление 5-5 демонстрирует создание конвейерного вызванного объекта состояния рендеринга pipeline.

Перечисление 5-5  , создающее простое конвейерное состояние

MTLRenderPipelineDescriptor *renderPipelineDesc =
                             [[MTLRenderPipelineDescriptor alloc] init];
renderPipelineDesc.vertexFunction = vertFunc;
renderPipelineDesc.fragmentFunction = fragFunc;
renderPipelineDesc.colorAttachments[0].pixelFormat = MTLPixelFormatRGBA8Unorm;
 
// Create MTLRenderPipelineState from MTLRenderPipelineDescriptor
NSError *errors = nil;
id <MTLRenderPipelineState> pipeline = [device
         newRenderPipelineStateWithDescriptor:renderPipelineDesc error:&errors];
assert(pipeline && !errors);
 
// Set the pipeline state for MTLRenderCommandEncoder
[renderCE setRenderPipelineState:pipeline];

Переменные vertFunc и fragFunc функции программы построения теней, указанные как свойства конвейерного вызванного дескриптора состояния рендеринга renderPipelineDesc. Вызов newRenderPipelineStateWithDescriptor:error: метод MTLDevice возразите синхронно использует конвейерный дескриптор состояния для создания конвейерного объекта состояния рендеринга. Вызов setRenderPipelineState: метод MTLRenderCommandEncoder указывает MTLRenderPipelineState возразите для использования с кодером команды рендеринга.

Конфигурирование смешивающий конвейерный присоединяемый дескриптор рендеринга

Смешивание использует высоконастраиваемую работу смешения для смешивания вывода, возвращенного функцией фрагмента (источник) с пиксельными значениями в присоединении (место назначения). Операции смешения определяют, как источник и целевые значения объединены с факторами смешения.

Для конфигурирования смешивания для цветного присоединения установите следующий MTLRenderPipelineColorAttachmentDescriptor свойства:

  • Чтобы позволить смешаться, установить blendingEnabled к YES. Смешивание отключено по умолчанию.

  • writeMask идентифицирует, какие цветовые каналы смешиваются. Значение по умолчанию MTLColorWriteMaskAll позволяет всем цветовым каналам быть смешанными.

  • rgbBlendOperation и alphaBlendOperation отдельно присвойте операции смешения для RGB и данных фрагмента Альфы с a MTLBlendOperation значение. Значение по умолчанию для обоих свойств MTLBlendOperationAdd.

  • sourceRGBBlendFactor, sourceAlphaBlendFactor, destinationRGBBlendFactor, и destinationAlphaBlendFactor присвойте источник и целевые факторы смешения.

Понимание смешивающихся факторов и операций

Четыре фактора смешения относятся к постоянному значению совмещенного цвета: MTLBlendFactorBlendColor, MTLBlendFactorOneMinusBlendColor, MTLBlendFactorBlendAlpha, и MTLBlendFactorOneMinusBlendAlpha. Вызовите setBlendColorRed:green:blue:alpha: метод MTLRenderCommandEncoder указать постоянный цвет и альфа-значения, используемые с этими факторами смешения, как описано в Операциях состояния Стандартной функции.

Некоторые операции смешения комбинируют значения фрагмента путем умножения исходных значений на источник MTLBlendFactor значение (сократил SBF), умножая целевые значения на целевой фактор смешения (DBF), и комбинируя результаты с помощью арифметики, обозначенной MTLBlendOperation значение. (Если работа смешения также MTLBlendOperationMin или MTLBlendOperationMax, SBF и факторы смешения DBF проигнорированы.), Например, MTLBlendOperationAdd для обоих rgbBlendOperation и alphaBlendOperation свойства определяют следующую аддитивную работу смешения для значений Альфы и RGB:

  • RGB = (Source.rgb * sourceRGBBlendFactor) + (Dest.rgb * destinationRGBBlendFactor)

  • Альфа = (Source.a * sourceAlphaBlendFactor) + (Dest.a * destinationAlphaBlendFactor)

В поведении смешения по умолчанию источник полностью перезаписывает место назначения. Это поведение эквивалентно установке обоих sourceRGBBlendFactor и sourceAlphaBlendFactor к MTLBlendFactorOne, и destinationRGBBlendFactor и destinationAlphaBlendFactor к MTLBlendFactorZero. Это поведение выражено математически как:

  • RGB = (Source.rgb * 1.0) + (Dest.rgb * 0.0)

  • A = (Source.a * 1.0) + (Dest.a * 0.0)

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

  • RGB = (Source.rgb * 1.0) + (Dest.rgb * (1 - Source.a))

  • A = (Source.a * 1.0) + (Dest.a * (1 - Source.a))

Используя пользовательскую конфигурацию смешивания

Перечисление 5-6 показывает код для пользовательской конфигурации смешивания, с помощью работы смешения MTLBlendOperationAdd, исходный фактор смешения MTLBlendFactorOne, и целевой фактор смешения MTLBlendFactorOneMinusSourceAlpha. colorAttachments[0] a MTLRenderPipelineColorAttachmentDescriptor объект со свойствами, указывающими смешивающуюся конфигурацию.

Перечисление 5-6  , указывающее пользовательскую конфигурацию смешивания

MTLRenderPipelineDescriptor *renderPipelineDesc = 
                             [[MTLRenderPipelineDescriptor alloc] init];
renderPipelineDesc.colorAttachments[0].blendingEnabled = YES; 
renderPipelineDesc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd;
renderPipelineDesc.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd;
renderPipelineDesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorOne;
renderPipelineDesc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne;
renderPipelineDesc.colorAttachments[0].destinationRGBBlendFactor = 
       MTLBlendFactorOneMinusSourceAlpha;
renderPipelineDesc.colorAttachments[0].destinationAlphaBlendFactor = 
       MTLBlendFactorOneMinusSourceAlpha;

NSError *errors = nil;
id <MTLRenderPipelineState> pipeline = [device 
         newRenderPipelineStateWithDescriptor:renderPipelineDesc error:&errors];

Указание ресурсов для кодера команды рендеринга

MTLRenderCommandEncoder методы, обсужденные в этом разделе, указывают ресурсы, использующиеся в качестве параметров за вершину и функции программы построения теней фрагмента, указанные vertexFunction и fragmentFunction свойства в a MTLRenderPipelineState объект. Эти методы присваивают ресурс программы построения теней (буферы, текстуры и сэмплеры) к соответствующему табличному индексу параметра (atIndex) в кодере команды рендеринга, как показано на рисунке 5-3.

  Таблицы параметра рисунка 5-3 для кодера команды рендеринга

Следующий setVertex* методы присваивают один или несколько ресурсов соответствующим параметрам функции вершинного шейдера.

Они setFragment* методы так же присваивают один или несколько ресурсов соответствующим параметрам функции программы построения теней фрагмента.

Существует максимум 31 записи в буферной таблице параметра, 31 записи в таблице параметра текстуры и 16 записей в таблице параметра состояния сэмплера.

Спецификаторы атрибута, указывающие расположения ресурса в Металлическом исходном коде языка штриховки, должны соответствовать табличные индексы параметра в Металлических методах платформы. В Перечислении 5-7, два буфера (posBuf и texCoordBuf) с индексами 0 и 1, соответственно, определяются для вершинного шейдера.

  Платформа металла перечисления 5-7: указание ресурсов для функции вершины

[renderEnc setVertexBuffer:posBuf offset:0 atIndex:0];
[renderEnc setVertexBuffer:texCoordBuf offset:0 atIndex:1];

В Перечислении 5-8 функциональная подпись имеет соответствующие параметры со спецификаторами атрибута buffer(0) и buffer(1).

  Металл перечисления 5-8 штриховка языка: соответствие аргументов функции вершины табличные индексы параметра платформы

vertex VertexOutput metal_vert(float4 *posData [[ buffer(0) ]],
                               float2 *texCoordData [[ buffer(1) ]])

Точно так же в Перечислении 5-9, буфере, текстуре и сэмплере (fragmentColorBuf, shadeTex, и sampler, соответственно), все с индексом 0, определяются для программы построения теней фрагмента.

  Платформа металла перечисления 5-9: указание ресурсов для функции фрагмента

[renderEnc setFragmentBuffer:fragmentColorBuf offset:0 atIndex:0];
[renderEnc setFragmentTexture:shadeTex atIndex:0];
[renderEnc setFragmentSamplerState:sampler atIndex:0];

В Перечислении 5-10 функциональная подпись имеет соответствующие параметры со спецификаторами атрибута buffer(0), texture(0), и sampler(0), соответственно.

  Металл перечисления 5-10 штриховка языка: соответствие аргументов функции фрагмента табличные индексы параметра платформы

fragment float4 metal_frag(VertexOutput in [[stage_in]],
                           float4 *fragColorData [[ buffer(0) ]],
                           texture2d<float> shadeTexValues [[ texture(0) ]],
                           sampler samplerValues [[ sampler(0) ]] )

Дескриптор вершины для организации данных

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

В Металлическом коде языка штриховки вводы на вершину (такие как скаляры или векторы целого числа или значений с плавающей точкой) могут быть организованы в одной структуре, которая может быть передана в одном параметре, объявляющемся с [[ stage_in ]] спецификатор атрибута, как замечено в VertexInput структура для функции вершины в качестве примера vertexMath в Перечислении 5-11. Каждое поле входной структуры на вершину имеет [[ attribute(index) ]] спецификатор, указывающий индекс в таблице параметра атрибута вершины.

  Металл перечисления 5-11 штриховка языка: вводы функции вершины с индексами атрибута

struct VertexInput {
    float2    position [[ attribute(0) ]];
    float4    color    [[ attribute(1) ]];
    float2    uv1      [[ attribute(2) ]];
    float2    uv2      [[ attribute(3) ]];
};

struct VertexOutput {
    float4 pos [[ position ]];
    float4 color;
};

vertex VertexOutput vertexMath(VertexInput in [[ stage_in ]])
{
  VertexOutput out;
  out.pos = float4(in.position.x, in.position.y, 0.0, 1.0);

  float sum1 = in.uv1.x + in.uv2.x;
  float sum2 = in.uv1.y + in.uv2.y;
  out.color = in.color + float4(sum1, sum2, 0.0f, 0.0f);
  return out;
}

Для обращения к вводу функции программы построения теней от Металлического кода платформы опишите a MTLVertexDescriptor возразите и затем набор это как vertexDescriptor свойство MTLRenderPipelineState. MTLVertexDescriptor имеет два свойства: attributes и layouts.

attributes свойство MTLVertexDescriptor a MTLVertexAttributeDescriptorArray объект, определяющий, как каждый атрибут вершины организован в буфере, отображающемся на аргументе функции вершины. attributes свойство может доступ к поддержке к многократным атрибутам (таким как координаты вершины, поверхность normals и координаты текстуры), которые чередованы в том же буфере. Порядок элементов в коде языка штриховки не должен быть сохранен в буфере в коде платформы. Каждый дескриптор атрибута вершины в массиве имеет следующие свойства, предоставляющие информацию функции вершинного шейдера, чтобы определить местоположение и загрузить данные параметра:

  • bufferIndex, который является индексом к буферной таблице параметра, указывающей который MTLBuffer получен доступ. Буферная таблица параметра обсуждена в Указании Ресурсов для Кодера Команды Рендеринга.

  • format, который указывает, как данные должны быть интерпретированы в коде платформы. Если тип данных не является точным соответствием типа, он может быть преобразован или расширен. Например, если тип языка штриховки half4 и платформа format MTLVertexFormatFloat2, тогда, когда данные используются в качестве параметра функции вершины, они могут быть преобразованы от плавания до половины и расширены с двух до четырех элементов (с 0,0, 1.0 в последних двух элементах).

  • offset, который указывает, где данные могут быть найдены от запуска вершины.

Рисунок 5-4 иллюстрирует a MTLVertexAttributeDescriptorArray в Металлическом коде платформы, реализующем чередованный буфер, соответствующий вводу к функции вершины vertexMath в штриховке язык кодируют в Перечислении 5-11.

  Буферная организация рисунка 5-4 с дескрипторами атрибута вершины

Перечисление 5-12 показывает Металлический код платформы, соответствующий чередованному буферу, показанному на рисунке 5-4.

  Платформа металла перечисления 5-12: Используя дескриптор вершины для доступа к чередованным данным

id <MTLFunction> vertexFunc = [library newFunctionWithName:@"vertexMath"];            
MTLRenderPipelineDescriptor* pipelineDesc =      
                             [[MTLRenderPipelineDescriptor alloc] init];
MTLVertexDescriptor* vertexDesc = [[MTLVertexDescriptor alloc] init];

vertexDesc.attributes[0].format = MTLVertexFormatFloat2;
vertexDesc.attributes[0].bufferIndex = 0;
vertexDesc.attributes[0].offset = 0;
vertexDesc.attributes[1].format = MTLVertexFormatFloat4;
vertexDesc.attributes[1].bufferIndex = 0;
vertexDesc.attributes[1].offset = 2 * sizeof(float);  // 8 bytes
vertexDesc.attributes[2].format = MTLVertexFormatFloat2;
vertexDesc.attributes[2].bufferIndex = 0;
vertexDesc.attributes[2].offset = 8 * sizeof(float);  // 32 bytes
vertexDesc.attributes[3].format = MTLVertexFormatFloat2;
vertexDesc.attributes[3].bufferIndex = 0;
vertexDesc.attributes[3].offset = 6 * sizeof(float);  // 24 bytes
vertexDesc.layouts[0].stride = 10 * sizeof(float);    // 40 bytes
vertexDesc.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex;

pipelineDesc.vertexDescriptor = vertexDesc;
pipelineDesc.vertexFunction = vertFunc;

Каждый MTLVertexAttributeDescriptor объект в attributes массив MTLVertexDescriptor объект соответствует индексируемому элементу структуры в VertexInput в функции программы построения теней. attributes[1].bufferIndex = 0 указывает использование буфера в индексе 0 в таблице параметра. (В этом примере, каждом MTLVertexAttributeDescriptor имеет то же bufferIndex, таким образом, каждый обращается к тому же буферу вершины в индексе 0 в таблице параметра.) offset значения указывают расположение данных в вершине, таким образом, attributes[1].offset = 2 * sizeof(float) определяет местоположение запуска соответствующих данных 8 байтов от запуска буфера. format значения выбраны для соответствия типа данных в функции программы построения теней, таким образом, attributes[1].format = MTLVertexFormatFloat4 указывает использование четырех значений с плавающей точкой.

layouts свойство MTLVertexDescriptor a MTLVertexBufferLayoutDescriptorArray. Для каждого MTLVertexBufferLayoutDescriptor в layouts, свойства указывают, как вершина и приписывает данные, выбираются от соответствия MTLBuffer в таблице параметра, когда Металл рисует примитивы. (Для больше при рисовании примитивов, посмотрите Рисующие Геометрические Примитивы.) stepFunction свойство MTLVertexBufferLayoutDescriptor определяет, выбрать ли данные атрибута для каждой вершины для некоторого числа экземпляров, или только один раз. Если stepFunction установлен выбрать данные атрибута для некоторого числа экземпляров, тогда stepRate свойство MTLVertexBufferLayoutDescriptor определяет сколько экземпляров. stride свойство указывает расстояние между данными двух вершин в байтах.

Рисунок 5-5 изображает MTLVertexBufferLayoutDescriptor это соответствует коду в Перечислении 5-12. layouts[0] указывает, как данные вершины выбираются от соответствующего индекса 0 в буферной таблице параметра. layouts[0].stride указывает расстояние 40 байтов между данными двух вершин. Значение layouts[0].stepFunction, MTLVertexStepFunctionPerVertex, указывает, что данные атрибута выбираются для каждой вершины при рисовании. Если значение stepFunction MTLVertexStepFunctionPerInstance, stepRate свойство определяет, как часто выбираются данные атрибута. Например, если stepRate 1, данные выбираются для каждого экземпляра; если stepRate 2, для каждых двух экземпляров, и т.д.

  Буферная организация рисунка 5-5 с буферными дескрипторами расположения вершины

Выполнение операций кодера команды рендеринга стандартной функции

Используйте их MTLRenderCommandEncoder методы для установки значений состояния графики стандартной функции:

Используйте следующий MTLRenderCommandEncoder методы для кодирования команд изменения состояния стандартной функции:

Работа с системами координат области просмотра и пикселя

Металл определяет свою систему Normalized Device Coordinate (NDC) как 2x2x1 куб с его центром в (0, 0, 0.5). Левые и нижняя часть для x и y, соответственно, системы NDC указаны как-1. Право и вершина для x и y, соответственно, системы NDC указаны как +1.

Область просмотра указывает трансформацию от NDC до координат окна. Металлическая область просмотра является 3D трансформацией, указанной setViewport: метод MTLRenderCommandEncoder. Источник координат окна находится в верхнем левом углу.

В Металле пиксельные центры смещаются (0.5, 0.5). Например, пиксель в источнике имеет свой центр в (0.5, 0.5); центр смежного пикселя с его правой стороны от него (1.5, 0.5). Это - также истина для текстур.

Выполнение операций глубины и шаблона

Глубина и операции шаблона являются операциями фрагмента, которые Вы указываете следующим образом:

  1. Укажите пользовательское MTLDepthStencilDescriptor объект, содержащий настройки для состояния глубины/шаблона. Создание пользовательского MTLDepthStencilDescriptor объект может потребовать создания один или два MTLStencilDescriptor объекты, которые применимы к обращенным к передней стороне примитивам и обращенным к задней стороне примитивам.

  2. Создайте a MTLDepthStencilState объект путем вызова newDepthStencilStateWithDescriptor: метод MTLDevice с глубиной/шаблоном утверждают дескриптор.

  3. Для установки состояния глубины/шаблона вызовите setDepthStencilState: метод MTLRenderCommandEncoder с MTLDepthStencilState.

  4. Если тест шаблона используется, вызвать setStencilReferenceValue: указать ссылочное значение шаблона.

Если тест глубины включен, конвейерное состояние рендеринга должно включать присоединение глубины для поддержки записи значения глубины. Для выполнения теста шаблона конвейерное состояние рендеринга должно включать присоединение шаблона. Для конфигурирования присоединений посмотрите Создание и Конфигурирование Конвейерного Дескриптора Рендеринга.

Если Вы будете изменять состояние глубины/шаблона регулярно, то можно хотеть снова использовать объект дескриптора состояния, изменяя его значения свойств по мере необходимости для создания большего количества объектов состояния.

Используйте свойства a MTLDepthStencilDescriptor возразите следующим образом для установки состояния шаблона и глубины:

  • Чтобы позволить писать глубину оценивают присоединению глубины, устанавливают depthWriteEnabled к YES.

  • depthCompareFunction указывает, как выполняется тест глубины. Если значение глубины фрагмента не проходит тест глубины, фрагмент отбрасывается. Например, обычно используемый MTLCompareFunctionLess функционируйте значения фрагмента причин, которые являются еще дальше от средства просмотра, чем (ранее записаны) значение пиксельной глубины, чтобы не пройти тест глубины; т.е. фрагмент считают закрытым более ранним значением глубины.

  • frontFaceStencil и backFaceStencil свойства каждый указывает отдельное MTLStencilDescriptor объект для передней стороны - и обращенные к задней стороне примитивы. Для использования того же шаблона утверждают и для передней стороны - и для обращенных к задней стороне примитивов, можно присвоить то же MTLStencilDescriptor обоим frontFaceStencil и backFaceStencil свойства. Для явного отключения теста шаблона для одного или обеих поверхностей установите соответствующее свойство в nil, значение по умолчанию.

Явное отключение состояния шаблона не необходимо. Металл определяет, разрешить ли тест шаблона на основе того, сконфигурирован ли дескриптор шаблона для допустимой работы шаблона.

Перечисление 5-13 показывает пример создания и использования a MTLDepthStencilDescriptor объект для создания a MTLDepthStencilState объект, тогда использующийся с кодером команды рендеринга. В этом примере к состоянию шаблона для обращенных к передней стороне примитивов получают доступ от frontFaceStencil свойство глубины/шаблона утверждает дескриптор. Тест шаблона явно отключен для обращенных к задней стороне примитивов.

  Создание перечисления 5-13 и Используя Дескриптор Глубины/Шаблона

MTLDepthStencilDescriptor *dsDesc = [[MTLDepthStencilDescriptor alloc] init];
if (dsDesc == nil)
     exit(1);   //  if the descriptor could not be allocated
dsDesc.depthCompareFunction = MTLCompareFunctionLess;
dsDesc.depthWriteEnabled = YES;
 
dsDesc.frontFaceStencil.stencilCompareFunction = MTLCompareFunctionEqual;
dsDesc.frontFaceStencil.stencilFailureOperation = MTLStencilOperationKeep;
dsDesc.frontFaceStencil.depthFailureOperation = MTLStencilOperationIncrementClamp;
dsDesc.frontFaceStencil.depthStencilPassOperation =
                          MTLStencilOperationIncrementClamp;
dsDesc.frontFaceStencil.readMask = 0x1;
dsDesc.frontFaceStencil.writeMask = 0x1;
dsDesc.backFaceStencil = nil;
id <MTLDepthStencilState> dsState = [device
                          newDepthStencilStateWithDescriptor:dsDesc];
 
[renderEnc setDepthStencilState:dsState];
[renderEnc setStencilReferenceValue:0xFF];

Следующие свойства определяют тест шаблона в MTLStencilDescriptor:

  • readMask битовая маска; GPU вычисляет поразрядный AND этой маски и со ссылочным значением шаблона и с сохраненным значением шаблона. Тест шаблона является сравнением между получающимся ссылочным значением маскированным и хранимой суммой маскированной.

  • writeMask битовая маска, ограничивающая, какие значения шаблона записаны в присоединение шаблона операциями шаблона.

  • stencilCompareFunction указывает, как тест шаблона выполняется для фрагментов. В Перечислении 5-13 функция сравнения шаблона MTLCompareFunctionEqual, если ссылочное значение маскированное равно значению шаблона маскированному, уже сохраненному в расположении фрагмента, таким образом, тест шаблона передает.

  • stencilFailureOperation, depthFailureOperation, и depthStencilPassOperation укажите, что сделать к значению шаблона, сохраненному в присоединении шаблона для трех различных тестовых результатов: если тест шаблона перестал работать, если тестовые передачи шаблона и глубина тестируют сбои, или если и шаблон и тесты глубины успешно выполняются, соответственно. В предыдущем примере значение шаблона неизменно (MTLStencilOperationKeep) если тест шаблона перестал работать, но он постепенно увеличивается, если тест шаблона передает, если значение шаблона уже не является возможным максимумом (MTLStencilOperationIncrementClamp).

Рисование геометрических примитивов

После установления конвейерного состояния и состояния стандартной функции можно вызвать следующий MTLRenderCommandEncoder методы для рисования геометрических примитивов. Они рисуют ссылочные ресурсы методов (такие как буферы, содержащие координаты вершины, координаты текстуры, поверхность normals и другие данные) выполнить конвейер с функциями программы построения теней и другим состоянием, с которым Вы ранее установили MTLRenderCommandEncoder.

Для каждого примитивного упомянутого выше метода рендеринга первое входное значение определяет тип примитива с одним из MTLPrimitiveType значения. Другие входные значения определяют, какие вершины используются для сборки примитивов. Для всех этих методов, instanceStart входное значение определяет первую инстанцию для рисования, и instanceCount входное значение определяет сколько экземпляров для рисования.

Как ранее обсуждено, setTriangleFillMode: определяет, представляются ли треугольники, как заполнено или каркас, и setCullMode: и setFrontFacingWinding: настройки определяют, отбирает ли GPU треугольники во время рендеринга. Для получения дополнительной информации посмотрите Операции состояния Стандартной функции).

При рендеринге a MTLPrimitiveTypePoint примитивный, код языка программы построения теней для функции вершины должен обеспечить [[ point_size ]] атрибут или размер точки не определен. Для получения дополнительной информации на всех Металлических атрибутах точки языка штриховки, посмотрите Металлическое Руководство по Языку Штриховки.

Окончание передачи рендеринга

Для завершения передачи рендеринга вызвать endEncoding на кодере команды рендеринга. После окончания предыдущего кодера команды можно создать новый кодер команды любого типа для кодирования дополнительных команд в буфер команд.

Пример кода: рисование треугольника

Следующие шаги, проиллюстрированные в Перечислении 5-14, описывают основную процедуру для рендеринга треугольника.

  1. Создайте a MTLCommandQueue и используйте его для создания a MTLCommandBuffer.

  2. Создайте a MTLRenderPassDescriptor это указывает набор присоединений, служащих местом назначения для закодированных команд рендеринга в буфере команд.

    В этом примере только первое цветное присоединение устанавливается и используется. (Переменная currentTexture как предполагается, содержит a MTLTexture это используется для цветного присоединения.) Тогда MTLRenderPassDescriptor используется для создания нового MTLRenderCommandEncoder.

  3. Создайте два MTLBuffer объекты, posBuf и colBuf, и вызовите newBufferWithBytes:length:options: для копирования координаты вершины и вершины окрашивают данные, posData и colData, соответственно, в буферный накопитель.

  4. Вызовите setVertexBuffer:offset:atIndex: метод MTLRenderCommandEncoder дважды указать координаты и цвета.

    atIndex входное значение setVertexBuffer:offset:atIndex: метод соответствует атрибуту buffer(atIndex) в исходном коде функции вершины.

  5. Создайте a MTLRenderPipelineDescriptor и установите вершину и функции фрагмента в конвейерном дескрипторе:

    • Создайте a MTLLibrary с исходным кодом от progSrc, который, как предполагается, является строкой, содержащей Металлический исходный код шейдера.

    • Тогда вызовите newFunctionWithName: метод MTLLibrary создать MTLFunction vertFunc это представляет вызванную функцию hello_vertex и создать MTLFunction fragFunc это представляет вызванную функцию hello_fragment.

    • Наконец, установите vertexFunction и fragmentFunction свойства MTLRenderPipelineDescriptor с ними MTLFunction объекты.

  6. Создайте a MTLRenderPipelineState от MTLRenderPipelineDescriptor путем вызова newRenderPipelineStateWithDescriptor:error: или похожий метод MTLDevice. Тогда setRenderPipelineState: метод MTLRenderCommandEncoder использует создаваемое конвейерное состояние для рендеринга.

  7. Вызовите drawPrimitives:vertexStart:vertexCount: метод MTLRenderCommandEncoder добавлять команды для выполнения рендеринга заполненного треугольника (тип MTLPrimitiveTypeTriangle).

  8. Вызовите endEncoding метод для окончания кодирования для этой передачи рендеринга. И вызовите commit метод MTLCommandBuffer выполнить команды на устройстве.

  Код металла перечисления 5-14 для рисования треугольника

id <MTLDevice> device = MTLCreateSystemDefaultDevice();
 
id <MTLCommandQueue> commandQueue = [device newCommandQueue];
id <MTLCommandBuffer> commandBuffer = [commandQueue commandBuffer];
 
MTLRenderPassDescriptor *renderPassDesc
                               = [MTLRenderPassDescriptor renderPassDescriptor];
renderPassDesc.colorAttachments[0].texture = currentTexture;
renderPassDesc.colorAttachments[0].loadAction = MTLLoadActionClear;
renderPassDesc.colorAttachments[0].clearColor = MTLClearColorMake(0.0,1.0,1.0,1.0);
id <MTLRenderCommandEncoder> renderEncoder =
           [commandBuffer renderCommandEncoderWithDescriptor:renderPassDesc];
 
static const float posData[] = {
        0.0f, 0.33f, 0.0f, 1.f,
        -0.33f, -0.33f, 0.0f, 1.f,
        0.33f, -0.33f, 0.0f, 1.f,
};
static const float colData[] = {
        1.f, 0.f, 0.f, 1.f,
        0.f, 1.f, 0.f, 1.f,
        0.f, 0.f, 1.f, 1.f,
};
id <MTLBuffer> posBuf = [device newBufferWithBytes:posData
        length:sizeof(posData) options:nil];
id <MTLBuffer> colBuf = [device newBufferWithBytes:colorData
        length:sizeof(colData) options:nil];
[renderEncoder setVertexBuffer:posBuf offset:0 atIndex:0];
[renderEncoder setVertexBuffer:colBuf offset:0 atIndex:1];
 
NSError *errors;
id <MTLLibrary> library = [device newLibraryWithSource:progSrc options:nil
                           error:&errors];
id <MTLFunction> vertFunc = [library newFunctionWithName:@"hello_vertex"];
id <MTLFunction> fragFunc = [library newFunctionWithName:@"hello_fragment"];
MTLRenderPipelineDescriptor *renderPipelineDesc
                                   = [[MTLRenderPipelineDescriptor alloc] init];
renderPipelineDesc.vertexFunction = vertFunc;
renderPipelineDesc.fragmentFunction = fragFunc;
renderPipelineDesc.colorAttachments[0].pixelFormat = currentTexture.pixelFormat;
id <MTLRenderPipelineState> pipeline = [device
             newRenderPipelineStateWithDescriptor:renderPipelineDesc error:&errors];
[renderEncoder setRenderPipelineState:pipeline];
[renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle
               vertexStart:0 vertexCount:3];
[renderEncoder endEncoding];
[commandBuffer commit];

В перечислении 5-14, a MTLFunction объект представляет вызванную функцию программы построения теней hello_vertex. setVertexBuffer:offset:atIndex: метод MTLRenderCommandEncoder используется для указания ресурсов вершины (в этом случае, два буферных объекта), которые передаются как параметры в hello_vertex. atIndex входное значение setVertexBuffer:offset:atIndex: метод соответствует атрибуту buffer(atIndex) в исходном коде функции вершины, как показано в Перечислении 5-15.

Перечисление 5-15  соответствующее объявление функции программы построения теней

vertex VertexOutput hello_vertex(
                    const global float4 *pos_data [[ buffer(0) ]],
                    const global float4 *color_data [[ buffer(1) ]])
{
    ...
}

Кодирование единственной передачи рендеринга Используя многократные потоки

В некоторых случаях производительность Вашего приложения может быть ограничена рабочей нагрузкой единственного CPU кодирования команд для единственной передачи рендеринга. Однако попытка обойти это узкое место путем разделения рабочей нагрузки на многократные передачи рендеринга, закодированные на многократных потоках ЦП, может также неблагоприятно повлиять на производительность, потому что каждая передача рендеринга требует, чтобы ее собственное промежуточное присоединяемое хранилище и действия загрузки сохранили целевое содержание рендеринга.

Вместо этого используйте a MTLParallelRenderCommandEncoder объект, управляющий многократным подчиненным MTLRenderCommandEncoder объекты, совместно использующие тот же буфер команд и представляющие дескриптор передачи. Параллельный кодер команды рендеринга гарантирует, чтобы присоединяемая загрузка и действия хранилища произошли только в запуске и конце всей передачи рендеринга, не в запуске и конце каждого подчиненного набора кодера команды рендеринга команд. С этой архитектурой можно присвоить каждого MTLRenderCommandEncoder возразите против его собственного потока параллельно безопасным и очень производительным способом.

Для создания параллельного кодера команды рендеринга используйте parallelRenderCommandEncoderWithDescriptor: метод a MTLCommandBuffer объект. Для создания подчиненных кодеров команды рендеринга вызовите renderCommandEncoder метод MTLParallelRenderCommandEncoder возразите один раз для каждого потока ЦП, от которого Вы хотите выполнить кодирование команды. Все подчиненные кодеры команды, создаваемые из того же параллельного кодера команды рендеринга, кодируют команды к тому же буферу команд. Команды кодируются к буферу команд в порядке, в котором создаются кодеры команды рендеринга. Для окончания кодирования для определенного кодера команды рендеринга вызовите endEncoding метод MTLRenderCommandEncoder. После окончания кодирования на всех кодерах команды рендеринга, создаваемых параллельным кодером команды рендеринга вызовите endEncoding метод MTLParallelRenderCommandEncoder закончить передачу рендеринга.

Перечисление 5-16 показывает MTLParallelRenderCommandEncoder создание три MTLRenderCommandEncoder объекты: rCE1, rCE2, и rCE3.

Перечисление 5-16  параллельный кодер рендеринга с тремя кодерами команды рендеринга

MTLRenderPassDescriptor *renderPassDesc 
                     = [MTLRenderPassDescriptor renderPassDescriptor];
renderPassDesc.colorAttachments[0].texture = currentTexture;
renderPassDesc.colorAttachments[0].loadAction = MTLLoadActionClear;
renderPassDesc.colorAttachments[0].clearColor = MTLClearColorMake(0.0,0.0,0.0,1.0);

id <MTLParallelRenderCommandEncoder> parallelRCE = [commandBuffer 
                     parallelRenderCommandEncoderWithDescriptor:renderPassDesc];
id <MTLRenderCommandEncoder> rCE1 = [parallelRCE renderCommandEncoder];
id <MTLRenderCommandEncoder> rCE2 = [parallelRCE renderCommandEncoder];
id <MTLRenderCommandEncoder> rCE3 = [parallelRCE renderCommandEncoder];

//  not shown: rCE1, rCE2, and rCE3 call methods to encode graphics commands
//
//  rCE1 commands are processed first, because it was created first
//  even though rCE2 and rCE3 end earlier than rCE1
[rCE2 endEncoding];
[rCE3 endEncoding];
[rCE1 endEncoding];

//  all MTLRenderCommandEncoders must end before MTLParallelRenderCommandEncoder
[parallelRCE endEncoding];

Порядок, в котором кодеры команды вызывают endEncoding не относится к порядку, в котором команды кодируются и добавляются к MTLCommandBuffer. Для MTLParallelRenderCommandEncoder, MTLCommandBuffer всегда содержит команды в порядке, что подчиненные кодеры команды рендеринга создавались, как замечено на рисунке 5-6.

  Упорядочивание рисунка 5-6 кодеров команды рендеринга в параллельной передаче рендеринга