Как извлечь данные текстуры с помощью Vulkan API на уровне расширения/драйвера?

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

  1. Создайте промежуточный буфер.

  2. Приложение копирует данные пикселей в промежуточный буфер:

    void* hostData;
    vkMapMemory(device, stagingBufferMemory, 0, imageSize, 0, &data);  // Map GPU memory to host and copy data
    memcpy(data, srcPixels, static_cast<size_t>(imageSize));
    vkUnmapMemory(device, stagingBufferMemory);
  1. Создайте VkImage (еще один VkDeviceMemory).

  2. Переведите макет VkImage в оптимальный макет для графического процессора.

  3. Скопируйте промежуточный буфер (линейные данные) в VkImage, используя:

vkCmdCopyBufferToImage(commandBuffer, stagingBuffer, VkImage, etc...)

  1. Переведите макет VkImage в оптимальный макет для графического процессора.

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

Может ли кто-нибудь, знакомый с GFXR или RenderDoc, объяснить их общую методологию этого процесса?

Спасибо за ваше время.

С наилучшими пожеланиями,

«нет никакой гарантии, что приложение вызовет vkUnmapMemory, поскольку оно может отображать ее бесконечно». Приложения должны сохранять отображение такой памяти неопределенно долго.

Nicol Bolas 20.05.2024 08:02

@NicolBolas Я не понимаю твоего комментария. Большинство приложений будут вызывать vkUnmapMemory сразу после копирования буфера. Почему вы говорите иначе?

gmmo 20.05.2024 18:42

Потому что они не должны. Сопоставленная отображаемая память ничего не делает. Это не мешает графическому процессору получить к нему доступ (Vulkan — это не OpenGL, и даже GL теперь может получить доступ к отображаемой памяти). Это не вызывает проблем с производительностью. Единственное, что он делает, это занимает место в вашем 64-битном адресном пространстве, которого вам никогда не будет не хватать в реальных приложениях. Таким образом, нет причин отключать отображаемую память. Просто держите его на карте все время. Это то, что делает большинство приложений.

Nicol Bolas 20.05.2024 18:44

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

Nicol Bolas 20.05.2024 18:45

Поскольку «формат, дружественный к графическому процессору», представляет собой прямую загрузку в часть этого макета, это невозможно. ЦП не может напрямую отображать макеты TILED_OPTIMAL, поскольку макет определяется реализацией. Это вариант использования, в котором всегда необходимо использовать промежуточное хранение, чтобы обеспечить доступность процессора.

solidpixel 21.05.2024 23:48

Другие вещи, о которых стоит подумать: * Вас волнуют визуализированные текстуры? (Возможно, это вообще не API на стороне ЦП, кроме буфера команд) * Заботитесь ли вы о правильной обработке форматов с псевдонимами? (Вычислительный шейдер записывает данные INT32, которые волшебным образом превращаются, например, в сжатые изображения BC7 при доступе через другой ImageView).

solidpixel 21.05.2024 23:51

@solidpixel Я хотел бы знать основную идею RenderDoc или GFXR, поскольку они это делают. Тем не менее, копаться в тысячах строк кода и, возможно, десятилетие разработки — это не то, что нужно, чтобы понять, что алгоритм тоже не является чем-то простым.

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

Ответы 1

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

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

То, как это работает, зависит от ОС, но хуки всегда присутствуют.

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

Но это не значит, что это легко.

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

Но это не значит, что невозможно узнать, когда произошли изменения.

Поскольку операции Vulkan выполняются асинхронно относительно операций хоста, если хост записывает данные в часть памяти, должна быть некоторая синхронизация между записью в эту память и любым чтением из нее. vkQueueSubmit может справиться с этим неявно, при условии, что записи хоста сами синхронизируются с вызовом хоста vkQueueSubmit. Но это не обязательно; пакет работы может ожидать события, установленного хостом. Это событие будет иметь барьер памяти, чтобы сделать байты, записанные хостом, доступными для графического процессора.

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

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