LINUX.ORG.RU

Аллокация памяти в Vulkan API с VK_EXT_external_memory_host расширением выводит ErrorOutOfDeviceMemory

 , , , ,


0

1

имеется арч, nvidia gtx1650, nvidia-465 drivers, vulkan 1.2.
имеется код, которым я хочу экспортировать картинку из Xorg на GPU через расширение VK_EXT_external_memory_host. Данное расширение поддержано в указанных драйверах. Однако получаю ошибку ErrorOutOfDeviceMemory.

Полный лог выполнения программы.

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

и еще — драйвер моей видяхи не предоставляет доступной памяти с нужными memoryTypeIndex и флагом { DeviceLocal }, тоесть есть память которая только { HostVisible | HostCoherent }, ну или с добавлением { HostCached }.

решение такое

★★

Последнее исправление: safocl (всего исправлений: 1)

Ответ на: комментарий от safocl

Кроме того что картиночка в host-памяти должна иметь выровненный базовый адрес на определенное число (что-то типа к 128/256/512/1024 байт), так еще может быть что надо чтоб и каждая строка картиночки тоже была выровнена, минимум к 4-м байтам.

Возможно также, что .flags у vk::ImageCreateInfo нужно инициализировать как-то по-другому.

nikitos ★★★
()
Последнее исправление: nikitos (всего исправлений: 2)
Ответ на: комментарий от nikitos

Возможно также, что .flags у vk::ImageCreateInfo нужно инициализировать как-то по-другому.

дак дело то в том, что до ошибка никак не связана с созданием image — аллокация памяти отдельно делается и только после привязывается к VK-объекту

safocl ★★
() автор топика
Ответ на: комментарий от Stil

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

при чем по идее у меня так или иначе выравнивание виртуальной памяти в 4КБ — как раз минимально допустимое выравнивание для такой аллокации...

safocl ★★
() автор топика
Ответ на: комментарий от safocl

А, ну да. Твой поинтер как аллоцирован?

https://github.com/KhronosGroup/Vulkan-Guide/blob/master/chapters/extensions/external.md

Если поинтер изначально не в гпу памяти – оно не взлетит. Эти импорты нужны для интеропа между апишками в пределах драйвера

Stil ★★★★★
()
Ответ на: комментарий от Stil

тут нет того расширения которое я использую — VK_EXT_external_memory_host — оно позволяет «This extension enables an application to import host allocations and host mapped foreign device memory to Vulkan memory objects.»

safocl ★★
() автор топика

мне кажется я понял в чем проблема — похоже она в выделенной памяти — vkImportMemoryHostPointerInfoEXT структура требует, что бы поинтер переданный в нее указывал на область памяти размером ровно столько байт, сколько указано после в выделении vkAllocateMemory() — а он для данного случая должен быть кратным значению выравнивания.

То есть, при импорте он пытается всю память начиная от адреса указателя скопировать размером, которое указано в аллокации. Но я выделяю память не кратно значению выравнивания, а получается обычно чуть меньше, из-за чего vulkan api начинает использовать чужую память за пределами того куска памяти, которое было выделено под image.

Надо попробовать выделять память кратно значению выравнивания.

safocl ★★
() автор топика
Ответ на: комментарий от safocl

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

safocl ★★
() автор топика

Твой сэмпл валится не на аллокации (импорте) памяти. А на выходе (по нажатию q по окошку цвета детской неожиданности). Конкретнее – в деструкторе структуры core::renderer::VulkanGraphicRender::CreateInfo. Разбирайся с xcb – вулкан тут не причём. Либо, если это что-то нвидиа-специфичное, выкладывай плиз coredump, ибо без дебугера, мне лично, влом разбираться, что там теоретически может пойти не так.

VK_INSTANCE_LAYERS="VK_LAYER_KHRONOS_validation" ./vulkan_xcb 
Discrete GPU is : AMD RADV ICELAND (ACO)

1354X716

B8G8R8A8Srgb
SrgbNonlinear
B8G8R8A8Unorm
SrgbNonlinear

Immediate
Mailbox
Present mode is Mailbox
VUID-VkSwapchainCreateInfoKHR-minImageCount-01271(ERROR / SPEC): msgNum: -511412493 - Validation Error: [ VUID-VkSwapchainCreateInfoKHR-minImageCount-01271 ] Object 0: handle = 0x55ea99352b30, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0xe18476f3 | vkCreateSwapchainKHR() called with minImageCount = 0, which is outside the bounds returned by vkGetPhysicalDeviceSurfaceCapabilitiesKHR() (i.e. minImageCount = 3, maxImageCount = 0). The Vulkan spec states: minImageCount must be greater than or equal to the value returned in the minImageCount member of the VkSurfaceCapabilitiesKHR structure returned by vkGetPhysicalDeviceSurfaceCapabilitiesKHR for the surface (https://github.com/KhronosGroup/Vulkan-Docs/search?q=)VUID-VkSwapchainCreateInfoKHR-minImageCount-01271)
    Objects: 1
        [0] 0x55ea99352b30, type: 3, name: NULL

Swapchain is created

Command buffer count :5

Image count : 5
free(): invalid pointer
Аварийный останов (стек памяти сброшен на диск)
robus ★★★★★
()
Ответ на: комментарий от robus

да это все не важно... завершение проги может какими угодно ошибками освобождения сыпать — ничего плахого не случится...

safocl ★★
() автор топика

Сейчас, глянув код в адекватном состоянии, вместо утреннего тупняка, вижу в чём там может быть проблема. Почему бы не выделять shmem того размера, который указан в VkMemoryRequirements (после vkGetImageMemoryRequirements)? На сколько я вижу, в твоём коде именно ты управляешь количеством выделенной памяти в том месте, а не xcb. Т.е. там, где posix::SharedMemory::Shared Window::getOffscreenShmImageData( posix::SharedMemory::Shared shm )

const std::uint32_t imageSize = windowGeometry.height * windowGeometry.width * 4;

    shm->reinit( imageSize );

станет чем-то вроде

std::uint32_t imageSize = windowGeometry.height * windowGeometry.width * 4;
const double k = static_cast< double >( imageSize ) / static_cast< double >( align );
imageSize = align * std::ceil ( k );

    shm->reinit( imageSize );

Алсо auto allocSize = ( pixmapDataSize / allocAligment + 1 ) * allocAligment; -> auto allocSize = allocAligment * std::ceil ( static_cast< double > ( pixmapDataSize ) / static_cast<double> ( allocAligment ) );, иначе всегда будешь создавать VkDeviceMemory большего размера, чем нужно (даже если всё ок по выравниванию).

robus ★★★★★
()
Последнее исправление: robus (всего исправлений: 1)
Ответ на: комментарий от safocl

Сорри. Это вообще не из той ветки код был :D

robus ★★★★★
()
Ответ на: комментарий от robus

Алсо auto allocSize = ( pixmapDataSize / allocAligment + 1 ) * allocAligment; -> auto allocSize = allocAligment * std::ceil ( static_cast< double > ( pixmapDataSize ) / static_cast<double> ( allocAligment ) );

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

сейчас исправил на такой код:

auto allocSize = ( pixmapDataSize / allocAlignment ) * allocAlignment;

if ( allocSize < pixmapDataSize )
    allocSize += allocAlignment;


а так на сколько я уже понял — по крайней мере на nvidia для импорта извне в vulkan api доступен только vkBuffer... — для него не нужно сразу размер вычислять как под хранение определенного image.
Хранение image потому что производится не обязательно тривиальным способом, с разными значениями его параметров это может быть как более компактный вид, так и более расширенный.

safocl ★★
() автор топика
Последнее исправление: safocl (всего исправлений: 1)
Ответ на: комментарий от robus

Почему бы не выделять shmem того размера, который указан в VkMemoryRequirements (после vkGetImageMemoryRequirements)?

вот тут тогда следующий вопрос возникает — не будет ли пустое место в конце? Ведь вся память из pixmap poiner будет инициализировать vkImage, но она будет не полностью заполнена данными pixmap.

safocl ★★
() автор топика
Ответ на: комментарий от robus

станет чем-то вроде

но да — так и придется делать, поскольку pointer, который передается в vk::ImportMemoryHostPointerInfoEXT обязан содержать данные размером кратным минимальному выравниванию.

safocl ★★
() автор топика
Ответ на: комментарий от safocl

в таком случае размер не будет кратен значению align

Будет. Сначала вычислится static_cast< double > ( pixmapDataSize ) / static_cast<double> ( allocAligment ) Это некоторое дробное значение. Потом от него возьмётся std::ceil. Будет ближайшее к этой дроби целое (хотя и тип будет double по прежнему) не меньшее её. Потом это целое домножится на allocAligment.

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

Проще говоря, формат и тайлинг должен совпадать у VkImage и у xcb-шного pixmap. ЕМНИП VK_EXT_image_drm_format_modifier как раз про это.

Алсо, посоветую использовать vulkan.h вместо vulkan.hpp – он гораздо лучше документирован.

robus ★★★★★
()
Ответ на: комментарий от safocl

вот тут тогда следующий вопрос возникает — не будет ли пустое место в конце

Выравнивание про это и есть. Например, согласно стандарту glsl,

layout(std140, binding = 3) uniform VectorsUBO
{
  vec3 pos;
  vec3 scale;
  vec4 quaternion;
};

Первые 12 байт – 3 4-байтных значения, образующих вектор pos;

Далее 4 байта – не определено чего. Выравнивание.

Далее 12 байт – 3 4-байтных значения, образующих вектор scale;

Далее 4 байта – не определено чего. Выравнивание.

Далее 16 байт – 4 4-байтных значения, образующих вектор quaternion;

Итого 48 байт.

Так же и с VkImage, я полагаю. В конце просто непонятно что. Потому, что размер должен быть кратен выравниванию.

robus ★★★★★
()
Ответ на: комментарий от robus

ЕМНИП VK_EXT_image_drm_format_modifier как раз про это.

ага — но у меня нету такого расширения в драйвере...

safocl ★★
() автор топика
Ответ на: комментарий от robus

Алсо, посоветую использовать vulkan.h вместо vulkan.hpp – он гораздо лучше документирован.

хмм... ну это просто одно и тоже — все документированное из сишного api полностью совпадает с плюсовым.
плюсовый api просто обертка над сишным — путем автообертывания плюсового кода в сишный.

safocl ★★
() автор топика
Ответ на: комментарий от robus

да я это все понимаю, однако я же буду полностью передавать всю память на копирование (переиспользование) — не получится ли так, что она будет в конце копироваться с пустыми значениями или еще хуже с мусором?

safocl ★★
() автор топика
Ответ на: комментарий от safocl

да — все теперь работает — сделал выделения памяти кратно выравниванию, указываю этот размер в структуре выделения памяти vulkan и все отлично теперь — картинки импортятся в vulkan api

safocl ★★
() автор топика
Ответ на: комментарий от safocl

Тем, что если pixmapDataSize поделится нацело на выравнивание, ты всё равно единичку добавишь. Я предлагаю способ через std::ceil который более адекватно работает.

robus ★★★★★
()
Ответ на: комментарий от anonymous

ceil не может быть constexpr

Прямо как allocAlignment. Который строго не constexpr ;)

robus ★★★★★
()
Ответ на: комментарий от safocl

Если поделится нацело, твой способ добавит лишние allocAlignment байт. А оно обязательно поделится если в xcbWrapper-е будешь выравнивание учитывать.

robus ★★★★★
()
Ответ на: комментарий от robus

если в xcbWrapper-е будешь выравнивание учитывать.

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

safocl ★★
() автор топика
Ответ на: комментарий от anonymous

ну в общем ок ок — я попробую именно так сделать))

safocl ★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.