среда, 24 февраля 2016 г.

Vulkan API, Fundamentals

16 февраля произошло значимое событие, наконец-то была релизнута спецификация графического API Vulkan и были выпущены первые драйвера.
Более подробную информацию об этом можно найти на сайте Хроноса:
https://www.khronos.org/vulkan/
Там собраны ссылки на основные ресурсы по Вулкану - драйвера, доки, демки.

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

В связи с этим я решил попытаться разобраться с этим API, начав не с критики демок, а с фундаментальных понятий нового API, хорошо описанных в спецификации Вулкана:
https://www.khronos.org/registry/vulkan/specs/1.0/pdf/vkspec.pdf

Для себя я набросал черновик перевода одноименной главы спецификации, перевод некоторых участков, без знания контекста, пока затруднен, но возможно это окажется кому-то полезным. Любые комментарии и исправления категорически приветствуются.

И так, начнем, Vulkan, Fundamentals...




Execution Model.

API Vulkan предоставляет одно или несколько устройств (device) для каждое из них имеет одну или более очередей (queues), которые обрабатываются независимо (асинхронно) друг от друга. Очереди, поддерживаемые устройствами разделяются на семейства (families), каждое из которых поддерживает один или несколько типов функциональности и может содержать несколько очередей с подобными характеристиками. Очереди внутри одного семейства считаются совместимыми друг с другом и работа произведенная над одной очередью может быть выполнена над любой из очередей внутри этого семейства. В спецификации определено 4 типа функциональности, которую поддерживают очереди: graphics, compute, transfer и sparse memory management.

Память устройства управляется напрямую приложением. Каждое устройство может объявлять одну или более куч памяти, представляющих разные области памяти. Память может быть либо локальной для устройства либо локальной для хоста, но всегда видимая для устройства. Выделяемая память определяется типом памяти и в зависимости от имплементации может быть “device local” - память физически подключена к устройству, “device local, host visible” - физическая память устройства, видимая хосту, и “host local, host visible” - локальная память хоста, видимая как хосту так и устройству. Так же это может быть одна куча, которая может быть использована для различных целей.

Приложение для Vulkan контролируют набор устройств через предоставление командных буферов (command buffers), в которых хранятся записанные команды устройства, вызванные через библиотеку Vulkan. Содержание командных буферов является специфическим для оборудования и не прозрачно для приложения. Единожды созданный буфер может быть неоднократно отправлен в очередь для исполнения.  Множество командных буферов может быть сформировано приложением в разных потоках.

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

Queue Operation.

Vulkan предоставляет интерфейс к  “execution engines” устройства. Команды записываются в командный буфер перед началом выполнения и затем они отправляются в очередь для выполнения. Командные буферы, отправленные в одну очередь проигрывают команды в порядке в котором они были записаны, как внутри так и за границами командного буфера. Работа выполняемая этими командами соответствует порядку определяемому явными и неявными зависимостями, как описано ниже. Задачи отправленные в отдельные очереди могут выполняться в любом порядке, если не указано обратное, поэтому приложение при необходимости должно явно синхронизировать работу между очередями.

Для контроля относительного порядка выполнения внутри очереди и между множеством очередей Вулкан предоставляет несколько примитивов синхронизации, которые включают в себя семафоры (semaphores), события (events), барьеры (pipeline barriers) и преграды (fences). Это подробно рассматривается в главе “Synchronization and Cache Control”. В общих чертах, семафоры используются для синхронизации между очередями или между крупными частями одной очереди, события и барьеры используются для синхронизации работы внутри командного буфера или последовательности командных буферов внутри одной очереди. И преграды используются для синхронизации работы между устройством и хостом.

Задания, отправляемые в очередь, имеют вид vkQueue* (vkQueueSubmit, vkQueueBindSparse и т.д.) и обычно принимают список семафоров при которых начинается выполнение заданий и список семафоров, сигнализирующих о завершении работы. Если семафоры не заданны, то выполнение командных буферов из нескольких очередей выполняется через vkQueueSubmit, эта команда может перекрывать (не не менять порядок).
Пока не совсем понятно о чем речь ======
Операции биндинга выполняемые через команду vkQueueBindSparse из нескольких пакетов могут изменить порядок или перекрываться. Представление командных буферов и операций “sparse binding” могут быть заменены или их порядок может быть изменен операциями другого типа.

Команды в командном буфере могут выполнять действия (draw, dispatch, clear, copy, query/timestamp operations, begin/end subpass operations), устанавливать состояния (bind pipelines, descriptor sets, and buffers, set dynamic state, push constants, set render pass/subpass state) или выполнять синхронизацию (set/wait events, pipeline barrier, render pass/subpass dependencies). Некоторые команды могут выполнять сразу несколько задач, к примеру, команды установки состояний обновляют текущее состояние командного буфера. Так же некоторые команды действия (draw/dispatch) делают это на основе текущего состояния командного буфера, они производят запись в аттачменты фрэймбуфера, буферы данных, буферы изображения или в пул очередей. Если синхронизация не задана явно, то порядок выполнения и результат могут быть не определены.

Внутри одного прохода рендера гарантирован порядок выполнения следующих вызовов API:
• depth bounds test
• stencil test, stencil op and stencil write
• depth test and depth write
• occlusion queries
• blending, logic op and color write

При этом API сортирует операции работы с примитивами в следующей очередности:
• First, by the action command that generates them.
• Second, by the order they are processed by primitive assembly.

Внутри этой очередности примитивы так же сортируются по:
• Third, by an implementation-dependent ordering of new primitives generated by tessellation, if a tessellation shader is active.
• Fourth, by the order new primitives are generated by geometry shading, if geometry shading is active.
• Fifth, by an implementation-dependent ordering of primitives generated due to the polygon mode.

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

Object Model

Все сущности Вулкана представлены объектами, на уровне API все объекты определяются по их хэндлам. Существует два класса хэндлов: диспетчеризируемые и не диспетчиризируемые (dispatchable и non-dispatchable). Dispatchable типы хэндлов это указатель, который используется слоем в качестве части команды API, и таким образом каждая команда API принимает этот тип в качестве первого параметра. Каждый объект данного типа имеет уникальное значение хэндла.

Non-dispatchable тип хэндла это 64-битное целое, чье значение зависит от реализации и может явно кодировать информацию об объекте а не через через указатель на структуру. Объекты данного типа могут не иметь уникального значения.
Все объекты созданные или аллоцированные через VkDevice (те. где VkDevice идет первым параметром) являются приватными для данного устройства и не должны использоваться другими устройствами.

Object Lifetime

Объекты создаются или аллоцируются через команды vkCreate* и vkAllocate* соответственно. Единожды созданные эти структуры остаются неизменными, в то время как содержимое некоторых типов объектов может изменяться. Объекты удаляются через vkDestroy* и vkFree* соответственно.

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

Следующие типы объектов используются будучи переданными в команду Вулкана и больше не доступны из объекта в котором они были созданы. Они могут быть удалены в любое время, так как больше не используются в API.
• VkShaderModule
• VkPipelineCache
• VkPipelineLayout

Объекты типа VkDescriptorSetLayout могут быть доступны из команд, которые оперируют над выделенными наборами дескрипторов, используя данный лайаут и теми наборами дескрипторов, которые не должны обновляться через vkUpdateDescriptorSets  после того как лайаут был уничтожен. Во всех остальных случаях лайуты наборов дескриптеров могут быть удалены в любое время и не используются командами API. Приложение так же обязано не удалять любые типы объектов, пока они используются устройством (к примеру - через буферы выполнения).

Следующие типы объектов не могут быть удалены пока они используются выполняющимся командным буфером:
VkEvent,  VkQueryPool, VkBuffer, VkBufferView, VkImage, VkImageView, VkPipeline, VkSampler, VkDescriptorPool, VkFramebuffer, VkRenderPass, VkCommandPool, VkDeviceMemory, VkDescriptorSet.

Объекты, которые можно удалять когда работа в очереди с этим объектом завершена:

VkFence, VkSemaphore, VkCommandBuffer, VkCommandPool

В общем, объекты могут быть уничтожены или освобождены в любом порядке, даже если он используется другим объектом. Пока этот объект используется его нельзя больше никак использовать, кроме удаления или сброса. Если объект был сброшен, то н может вновь использоваться как-будто он никогда не использовал удаляемый объект. Исключением является пул объектов.

Объекты типа VkCommandPool являются родителями для объектов типа VkCommandBuffer. Объекты типа VkDescriptorPool - родители для VkDescriptorSet. VkDevice - родитель для кучи объектов (для всех, которые принимают VkDevice как параметр для их создания).

Следующие объекты Вулкана имеют определенные ограничения на время удаления:
• VkQueue - не могут быть уничтожены явно, уничтожаются вместе с объектом  VkDevice, для которого они были созданы.
• Уничтожение пула объектов неявно освобождает все аллоцированные объекты в этом пуле. В частности, уничтожение VkCommandPool освобождает все объекты VkCommandBuffer которые были аллоцированы из него и уничтожение VkDescriptorPool освобождает все созданные объекты VkDescriptorSet.
• VkDevice может быть удален когда все объекты VkQueue находятся в состоянии ожидания и все объекты созданные из них удалены, это включает в себя следующие объекты:

VkFence, VkSemaphore, VkEvent, VkQueryPool, VkBuffer, VkBufferView, VkImage, VkImageView, VkShaderModule, VkPipelineCache, VkPipeline, VkPipelineLayout, VkSampler, VkDescriptorSetLayout, VkDescriptorPool, VkFramebuffer, VkRenderPass, VkCommandPool, VkCommandBuffer, VkDeviceMemory.

• VkPhysicalDevice - нельзя удалить явно, удаляется вместе с соответствующим VkInstance.
• VkInstance - может быть удален когда все объекты VkDevice созданные для любого из VkPhysicalDevice были удалены.

Errors

Вулкан это уровень ядра, потому проверка ошибок там минимальна. Проверка валидности использования API возложена на пользователя через “Validation Layer” который может быть активирован для отладки приложения.

Не смотря на то, что Вулкан не предназначен для перехвата некорректного использования функций, некоторые из них все же возвращают коды ошибок, которые могут быть одной из двух категорий:
• Коды успешного выполнения (коды ошибок не могут иметь негативного значения)
• Ошибки времени выполнения (все коды ошибки имеют отрицательное значение)
Все коды ошибок представлены через VkResult, возможные значения:
typedef enum VkResult {
VK_SUCCESS = 0,
VK_NOT_READY = 1,
VK_TIMEOUT = 2,
VK_EVENT_SET = 3,
VK_EVENT_RESET = 4,
VK_INCOMPLETE = 5,
VK_ERROR_OUT_OF_HOST_MEMORY = -1,
VK_ERROR_OUT_OF_DEVICE_MEMORY = -2,
VK_ERROR_INITIALIZATION_FAILED = -3,
VK_ERROR_DEVICE_LOST = -4,
VK_ERROR_MEMORY_MAP_FAILED = -5,
VK_ERROR_LAYER_NOT_PRESENT = -6,
VK_ERROR_EXTENSION_NOT_PRESENT = -7,
VK_ERROR_FEATURE_NOT_PRESENT = -8,
VK_ERROR_INCOMPATIBLE_DRIVER = -9,
VK_ERROR_TOO_MANY_OBJECTS = -10,
VK_ERROR_FORMAT_NOT_SUPPORTED = -11,
} VkResult;

SUCCESS CODES
• VK_SUCCESS - команда выполнена успешно
• VK_NOT_READY -  барьер или очередь не была завершена
• VK_TIMEOUT - операция ожидания не была завершена в указанное время
• VK_EVENT_SET - событие произошло
• VK_EVENT_RESET - событие не произошло
• VK_INCOMPLETE - возвращаемый массив слишком мал для результата

ERROR CODES
• VK_ERROR_OUT_OF_HOST_MEMORY - ошибка выделения памяти хостом.
• VK_ERROR_OUT_OF_DEVICE_MEMORY - ошибка выделения памяти устройством.
• VK_ERROR_INITIALIZATION_FAILED - инициализация объекта не может быть завершена.
• VK_ERROR_DEVICE_LOST - логическое или физическое устройство было потеряно.
• VK_ERROR_MEMORY_MAP_FAILED - отображение объекта памяти провалилось.
• VK_ERROR_LAYER_NOT_PRESENT - запрашиваемый слой не существует или не может быть загружен.
• VK_ERROR_EXTENSION_NOT_PRESENT - расширение не поддерживается..
• VK_ERROR_FEATURE_NOT_PRESENT - функция не поддерживается.
• VK_ERROR_INCOMPATIBLE_DRIVER - запрашиваемая версия Вулкана не поддерживается драйвером.
• VK_ERROR_TOO_MANY_OBJECTS - было создано слишком много объектов данного типа.
• VK_ERROR_FORMAT_NOT_SUPPORTED - данный формат не поддерживается устройством.

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

Threading Behavior

Производительность Вулкана может быть повышена при использовании многопоточности, все команды могут быть вызваны из нескольких потоков, однако параметры должны быть синхронизированы между потоками, такие параметры называют “Externally Synchronized Parameters”.

Существует так же множество неизменяемых объектов (immutable object types), это означает что объект не может быть изменен после создания. Для таких типов объектов не нужна внешняя синхронизация, кроме случая когда нужно избежать удаления объекта пока он используется в другом потоке. В особых случаях, некоторые изменяемые параметры объектов могут иметь внутреннюю синхронизацию. Ниже приводятся списки параметров, нуждающихся во внешней синхронизации:

Externally Synchronized Parameters
• The instance parameter in vkDestroyInstance
• The device parameter in vkDestroyDevice
• The queue parameter in vkQueueSubmit
• The fence parameter in vkQueueSubmit
• The memory parameter in vkFreeMemory
• The memory parameter in vkMapMemory
• The memory parameter in vkUnmapMemory
• The buffer parameter in vkBindBufferMemory
• The image parameter in vkBindImageMemory
• The queue parameter in vkQueueBindSparse
• The fence parameter in vkQueueBindSparse
• The fence parameter in vkDestroyFence
• The semaphore parameter in vkDestroySemaphore
• The event parameter in vkDestroyEvent
• The event parameter in vkSetEvent
• The event parameter in vkResetEvent
• The queryPool parameter in vkDestroyQueryPool
• The buffer parameter in vkDestroyBuffer
• The bufferView parameter in vkDestroyBufferView
• The image parameter in vkDestroyImage
• The imageView parameter in vkDestroyImageView
• The shaderModule parameter in vkDestroyShaderModule
• The pipelineCache parameter in vkDestroyPipelineCache
• The dstCache parameter in vkMergePipelineCaches
• The pipeline parameter in vkDestroyPipeline
• The pipelineLayout parameter in vkDestroyPipelineLayout
• The sampler parameter in vkDestroySampler
• The descriptorSetLayout parameter in vkDestroyDescriptorSetLayout
• The descriptorPool parameter in vkDestroyDescriptorPool
• The descriptorPool parameter in vkResetDescriptorPool
• The descriptorPool member of the pAllocateInfo parameter in vkAllocateDescriptorSets
• The descriptorPool parameter in vkFreeDescriptorSets
• The framebuffer parameter in vkDestroyFramebuffer
• The renderPass parameter in vkDestroyRenderPass
• The commandPool parameter in vkDestroyCommandPool
• The commandPool parameter in vkResetCommandPool
• The commandPool member of the pAllocateInfo parameter in vkAllocateCommandBuffers
• The commandPool parameter in vkFreeCommandBuffers
• The commandBuffer parameter in vkBeginCommandBuffer
• The commandBuffer parameter in vkEndCommandBuffer
• The commandBuffer parameter in vkResetCommandBuffer
• The commandBuffer parameter in vkCmdBindPipeline
• The commandBuffer parameter in vkCmdSetViewport
• The commandBuffer parameter in vkCmdSetScissor
• The commandBuffer parameter in vkCmdSetLineWidth
• The commandBuffer parameter in vkCmdSetDepthBias
• The commandBuffer parameter in vkCmdSetBlendConstants
• The commandBuffer parameter in vkCmdSetDepthBounds
• The commandBuffer parameter in vkCmdSetStencilCompareMask
• The commandBuffer parameter in vkCmdSetStencilWriteMask
• The commandBuffer parameter in vkCmdSetStencilReference
• The commandBuffer parameter in vkCmdBindDescriptorSets
• The commandBuffer parameter in vkCmdBindIndexBuffer
• The commandBuffer parameter in vkCmdBindVertexBuffers
• The commandBuffer parameter in vkCmdDraw
• The commandBuffer parameter in vkCmdDrawIndexed
• The commandBuffer parameter in vkCmdDrawIndirect
• The commandBuffer parameter in vkCmdDrawIndexedIndirect
• The commandBuffer parameter in vkCmdDispatch
• The commandBuffer parameter in vkCmdDispatchIndirect
• The commandBuffer parameter in vkCmdCopyBuffer
• The commandBuffer parameter in vkCmdCopyImage
• The commandBuffer parameter in vkCmdBlitImage
• The commandBuffer parameter in vkCmdCopyBufferToImage
• The commandBuffer parameter in vkCmdCopyImageToBuffer
• The commandBuffer parameter in vkCmdUpdateBuffer
• The commandBuffer parameter in vkCmdFillBuffer
• The commandBuffer parameter in vkCmdClearColorImage
• The commandBuffer parameter in vkCmdClearDepthStencilImage
• The commandBuffer parameter in vkCmdClearAttachments
• The commandBuffer parameter in vkCmdResolveImage
• The commandBuffer parameter in vkCmdSetEvent
• The commandBuffer parameter in vkCmdResetEvent
• The commandBuffer parameter in vkCmdWaitEvents
• The commandBuffer parameter in vkCmdPipelineBarrier
• The commandBuffer parameter in vkCmdBeginQuery
• The commandBuffer parameter in vkCmdEndQuery
• The commandBuffer parameter in vkCmdResetQueryPool
• The commandBuffer parameter in vkCmdWriteTimestamp
• The commandBuffer parameter in vkCmdCopyQueryPoolResults
• The commandBuffer parameter in vkCmdPushConstants
• The commandBuffer parameter in vkCmdBeginRenderPass
• The commandBuffer parameter in vkCmdNextSubpass
• The commandBuffer parameter in vkCmdEndRenderPass
• The commandBuffer parameter in vkCmdExecuteCommands

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

Externally Synchronized Parameter Lists
• Each element of the pWaitSemaphores member of each element of the pSubmits parameter in vkQueueSubmit
• Each element of the pSignalSemaphores member of each element of the pSubmits parameter in vkQueueSubmit
• Each element of the pWaitSemaphores member of each element of the pBindInfo parameter in vkQueueBindSparse
• Each element of the pSignalSemaphores member of each element of the pBindInfo parameter in vkQueueBindSparse
• The buffer member of each element of the pBufferBinds member of each element of the pBindInfo parameter in vkQueueBindSparse
• The image member of each element of the pImageOpaqueBinds member of each element of the pBindInfo parameter in vkQueueBindSparse
• The image member of each element of the pImageBinds member of each element of the pBindInfo parameter in vkQueueBindSparse
• Each element of the pFences parameter in vkResetFences
• Each element of the pDescriptorSets parameter in vkFreeDescriptorSets
• The dstSet member of each element of the pDescriptorWrites parameter in vkUpdateDescriptorSets
• The dstSet member of each element of the pDescriptorCopies parameter in vkUpdateDescriptorSets
• Each element of the pCommandBuffers parameter in vkFreeCommandBuffers

В дополнение, существуют так же некоторые неявные параметры, которые так же требуют внешней синхронизации. к примеру, все параметры commandBuffer, которые требуют внешней синхронизации подразумевают что commandPool, который передавался в них при создании так же требует внешней синхронизации:

Implicit Externally Synchronized Parameters
• All VkQueue objects created from device in vkDeviceWaitIdle
• Any VkDescriptorSet objects allocated from descriptorPool in vkResetDescriptorPool
• The VkCommandPool that commandBuffer was allocated from, in vkCmdBindPipeline
• The VkCommandPool that commandBuffer was allocated from, in vkCmdSetViewport
• The VkCommandPool that commandBuffer was allocated from, in vkCmdSetScissor
• The VkCommandPool that commandBuffer was allocated from, in vkCmdSetLineWidth
• The VkCommandPool that commandBuffer was allocated from, in vkCmdSetDepthBias
• The VkCommandPool that commandBuffer was allocated from, in vkCmdSetBlendConstants
• The VkCommandPool that commandBuffer was allocated from, in vkCmdSetDepthBounds
• The VkCommandPool that commandBuffer was allocated from, in vkCmdSetStencilCompareMask
• The VkCommandPool that commandBuffer was allocated from, in vkCmdSetStencilWriteMask
• The VkCommandPool that commandBuffer was allocated from, in vkCmdSetStencilReference
• The VkCommandPool that commandBuffer was allocated from, in vkCmdBindDescriptorSets
• The VkCommandPool that commandBuffer was allocated from, in vkCmdBindIndexBuffer
• The VkCommandPool that commandBuffer was allocated from, in vkCmdBindVertexBuffers
• The VkCommandPool that commandBuffer was allocated from, in vkCmdDraw
• The VkCommandPool that commandBuffer was allocated from, in vkCmdDrawIndexed
• The VkCommandPool that commandBuffer was allocated from, in vkCmdDrawIndirect
• The VkCommandPool that commandBuffer was allocated from, in vkCmdDrawIndexedIndirect
• The VkCommandPool that commandBuffer was allocated from, in vkCmdDispatch
• The VkCommandPool that commandBuffer was allocated from, in vkCmdDispatchIndirect
• The VkCommandPool that commandBuffer was allocated from, in vkCmdCopyBuffer
• The VkCommandPool that commandBuffer was allocated from, in vkCmdCopyImage
• The VkCommandPool that commandBuffer was allocated from, in vkCmdBlitImage
• The VkCommandPool that commandBuffer was allocated from, in vkCmdCopyBufferToImage
• The VkCommandPool that commandBuffer was allocated from, in vkCmdCopyImageToBuffer
• The VkCommandPool that commandBuffer was allocated from, in vkCmdUpdateBuffer
• The VkCommandPool that commandBuffer was allocated from, in vkCmdFillBuffer
• The VkCommandPool that commandBuffer was allocated from, in vkCmdClearColorImage
• The VkCommandPool that commandBuffer was allocated from, in vkCmdClearDepthStencilImage
• The VkCommandPool that commandBuffer was allocated from, in vkCmdClearAttachments
• The VkCommandPool that commandBuffer was allocated from, in vkCmdResolveImage
• The VkCommandPool that commandBuffer was allocated from, in vkCmdSetEvent
• The VkCommandPool that commandBuffer was allocated from, in vkCmdResetEvent
• The VkCommandPool that commandBuffer was allocated from, in vkCmdWaitEvents
• The VkCommandPool that commandBuffer was allocated from, in vkCmdPipelineBarrier
• The VkCommandPool that commandBuffer was allocated from, in vkCmdBeginQuery
• The VkCommandPool that commandBuffer was allocated from, in vkCmdEndQuery
• The VkCommandPool that commandBuffer was allocated from, in vkCmdResetQueryPool
• The VkCommandPool that commandBuffer was allocated from, in vkCmdWriteTimestamp
• The VkCommandPool that commandBuffer was allocated from, in vkCmdCopyQueryPoolResults
• The VkCommandPool that commandBuffer was allocated from, in vkCmdPushConstants
• The VkCommandPool that commandBuffer was allocated from, in vkCmdBeginRenderPass
• The VkCommandPool that commandBuffer was allocated from, in vkCmdNextSubpass
• The VkCommandPool that commandBuffer was allocated from, in vkCmdEndRenderPass
• The VkCommandPool that commandBuffer was allocated from, in vkCmdExecuteCommands

Common Object Types

Offsets - используются для задания координат пикселя изображения или фреймбуфера:
typedef struct VkOffset2D {
int32_t x;
int32_t y;
} VkOffset2D;
typedef struct VkOffset3D {
int32_t x;
int32_t y;
int32_t z;
} VkOffset3D;

Rectangles - используется для описания прямоугольного блока пикселей:
typedef struct VkRect2D {
VkOffset2D offset;
VkExtent2D extent;
} VkRect2D;

2 комментария:

  1. Спасибо за перевод! Мне Vulkan очень нравится, можно управлять памятью видеокартой через VkAllocate* и VkFree*. То есть если память компьютера закончилась, можно на видеокарте хранить данные. Можно реально запилить приложение, которое будет использовать исключительно память видеокарты.
    Это второе API, где я вижу такую возможность. Это не было в OpenCL, OpenGL, DirectX. Почему второе? Потому что впервые это появилось в Metal от Apple.

    В вулкане тебе дается API для работы с шейдерным конвеером и устройствами. Вся графика делается шейдерами, а всё что дает Vulkan это управление устройствами и пайплайном. В OpenGL есть готовые функции и многие шейдеры писать не нужно, но если нужно, то можно на GLSL написать. В Vulkan вместо glsl язык SPIR-V, основанный на C++14 для написания шейдров. Шейдеры компилируются предварительно, через этот инструмент https://vulkan.lunarg.com/doc/view/1.0.39.1/windows/s.., а не в реальтайме, через функции OpenGL. Vulkan гораздо минималистичен. Кстати для тех, кто с OpenGL переезжает на Vulkan, может переконвертировать glsl шейдеры в spirv https://github.com/KhronosGroup/glslang

    ОтветитьУдалить
    Ответы
    1. Пожалуйста, хотя вроде в сети есть уже более качественный и полный перевод.
      В остальном - можно, но с кучей проблем.
      Как хранилище - можно, но чтоб использовать придется копировать данные между device/host, так и раньше (лет 5 наверное уже) можно было делать во всех API.
      То же касается и пайплайна - сейчас в любом GAPI вся работа выполняется в шейдерах, пайплайн отвечает лишь за работу с ресурсами. Вулкан просто переложил всю работу по многопоточности и синхронизации на разработчика. Это как плюс так и минус, в лучшем случае можно получить 10% прирост производительности и снижение нагрузки на CPU, в худшем - огрести кучу проблем и дроп производительности.
      На счет шейдеров - с таким же успехом можно использовать spir-V шейдера в OpenGL, или сконвертировать HLSL шейдер в GLSL/SPIR-V, но там столько ограничений, что иногда проще написать новый шейдер, просто скопипастив в него нужные функции.
      Вообщем, желаю успехов в изучении, благо с момента написания этого перевода появилось огромное количество туториалов и обсуждений, а так же людей, которые это уже попробовали руками и нахватались шишек. Хотя как по мне - на текущий момент Вулкан все еще очень сырой.

      Удалить