В DirectX приложениях не отображается геометрия, которая рисуется из буфера stream output посредством функции D3D11DeviceContext::DrawAuto() Примеры: -Renga (не отображаются различные линии) -Тестовая программа https://gitlab.eterfund.ru/wine/wine-etersoft-devel/tree/master/Renga/bug_16351/DirectX%2011%20Engine%20VS2017/x64/Release (не отображается обводка куба) Если правильно понял, то вот эта функция в wine https://gitlab.eterfund.ru/wine/wine-rebased/blob/rebased/dlls/d3d11/device.c#L1225 Очевидно не реализована Пробовал в тестовой программе менять вызов DrawAuto() на Draw() - тогда всё работает в wine (и c opengl, и с vulkan, и с dxvk). В связи с этим пробовал уже в wine внутри d3d11_device_context_DrawAuto вызывать d3d11_device_context_Draw(). В тестовой программе заработало только с opengl, в renga стали отображаться линии, но расположены неправильно. Также интересно взглянуть на DXVK. Там реализована DrawAuto() https://github.com/doitsujin/dxvk/blob/master/src/d3d11/d3d11_context.cpp#L939 Но с dxvk в renga и в тестовой программе всё равно не работает отрисовка. Возможно стоит в wine сделать что-то аналогочное dxvk? Через wined3d_device_context_draw_indirect например? Еще интересный факт. Заявлено что в dxvk 1.1.1 пофиксили DrawAuto() https://github.com/doitsujin/dxvk/releases?page=5#:~:text=incorrect%20behaviour%20of-,DrawAuto,-with%20a%20non Я пробовал ставить предыдущую (без фикса) версию 1.0.3. И на ней тестовая программа работала правильно (обводка отображается). Ренгу протестировать не получилось, т.к. не хочет создаваться проект.
(Ответ Олег Никулин на комментарий #0) > Я пробовал ставить предыдущую (без фикса) версию 1.0.3. И на ней тестовая > программа работала правильно (обводка отображается). Ренгу протестировать не > получилось, т.к. не хочет создаваться проект. В DXVK DrawAuto() перестает работать в версии 1.4.4. На версии 1.4.3 в renga нормально работает создание проекта и все линии корректно отображаются. P.S. renga с dxvk работает только на версии wine с патчем child window rendering https://gitlab.eterfund.ru/owl2/wine-rebased/tree/child-window-patch без патча падает при инициализации графики, это отдельная проблема
(In reply to Олег Никулин from comment #0) > В DirectX приложениях не отображается геометрия, которая рисуется из буфера > stream output посредством функции D3D11DeviceContext::DrawAuto() > > Примеры: > -Renga (не отображаются различные линии) > -Тестовая программа > https://gitlab.eterfund.ru/wine/wine-etersoft-devel/tree/master/Renga/ > bug_16351/DirectX%2011%20Engine%20VS2017/x64/Release (не отображается > обводка куба) > > Если правильно понял, то вот эта функция в wine > https://gitlab.eterfund.ru/wine/wine-rebased/blob/rebased/dlls/d3d11/device. > c#L1225 > Очевидно не реализована > > Пробовал в тестовой программе менять вызов DrawAuto() на Draw() - тогда всё > работает в wine (и c opengl, и с vulkan, и с dxvk). В связи с этим пробовал > уже в wine внутри d3d11_device_context_DrawAuto вызывать > d3d11_device_context_Draw(). В тестовой программе заработало только с > opengl, в renga стали отображаться линии, но расположены неправильно. Это очень странное поведение. Не пробовали выяснить, с чем связно то, что при вызове из тестовой программы ::Draw() работает, а при вызове ::Draw() из ::DrawAuto() - нет? > Также интересно взглянуть на DXVK. Там реализована DrawAuto() > https://github.com/doitsujin/dxvk/blob/master/src/d3d11/d3d11_context. > cpp#L939 > Но с dxvk в renga и в тестовой программе всё равно не работает отрисовка. > Возможно стоит в wine сделать что-то аналогочное dxvk? Через > wined3d_device_context_draw_indirect например? > > Еще интересный факт. Заявлено что в dxvk 1.1.1 пофиксили DrawAuto() > https://github.com/doitsujin/dxvk/releases?page=5#:~: > text=incorrect%20behaviour%20of-,DrawAuto,-with%20a%20non > Я пробовал ставить предыдущую (без фикса) версию 1.0.3. И на ней тестовая > программа работала правильно (обводка отображается). Ренгу протестировать не > получилось, т.к. не хочет создаваться проект. Проблемы, вызванные использованием DXVK, никакого отношения к Wine не имеют и должны быть сообщены разработчикам DXVK.
(Ответ Dmitry Timoshkov на комментарий #2) > Это очень странное поведение. Не пробовали выяснить, с чем связно то, что > при вызове из тестовой программы ::Draw() работает, а при вызове ::Draw() > из ::DrawAuto() - нет? Не знаю. Могу только предположить про аргументы функций: https://learn.microsoft.com/en-us/windows/win32/api/d3d11/nf-d3d11-id3d11devicecontext-draw В Draw() надо передавать количество вершин сколько нужно отрисовать, и индекс вершины с которой начинать. Мне в тестовой программе точное количество неизвестно, поэтому указываю с запасом 128 (получается больше чем фактическое число вершин в буфере), индекс 0. А в DrawAuto() ничего передавать не надо, по идее она должна сама определять количество вершин. Когда я в wine вывывал Draw внутри DrawAuto, я также передавал количество 128 и индекс 0. Может как-то с этим связано? Хотя всё равно странно, т.к. в итоге у меня вызовы к Draw() одинаковые должны получаться.
(In reply to Олег Никулин from comment #3) > (Ответ Dmitry Timoshkov на комментарий #2) > > Это очень странное поведение. Не пробовали выяснить, с чем связно то, что > > при вызове из тестовой программы ::Draw() работает, а при вызове ::Draw() > > из ::DrawAuto() - нет? > Не знаю. Могу только предположить про аргументы функций: > https://learn.microsoft.com/en-us/windows/win32/api/d3d11/nf-d3d11- > id3d11devicecontext-draw > В Draw() надо передавать количество вершин сколько нужно отрисовать, и > индекс вершины с которой начинать. Мне в тестовой программе точное > количество неизвестно, поэтому указываю с запасом 128 (получается больше чем > фактическое число вершин в буфере), индекс 0. А в DrawAuto() ничего > передавать не надо, по идее она должна сама определять количество вершин. > Когда я в wine вывывал Draw внутри DrawAuto, я также передавал количество > 128 и индекс 0. > Может как-то с этим связано? Хотя всё равно странно, т.к. в итоге у меня > вызовы к Draw() одинаковые должны получаться. Получается, что ::DrawAuto() должен знать или уметь вычислять правильное количество вершин, ассоциированное с текущим контекстом. Видимо нужно понять, как это делать. Можно предположить, что на стороне wined3d это известно.
(Ответ Олег Никулин на комментарий #0) > Пробовал в тестовой программе менять вызов DrawAuto() на Draw() - тогда всё > работает в wine (и c opengl, и с vulkan, и с dxvk). В связи с этим пробовал > уже в wine внутри d3d11_device_context_DrawAuto вызывать > d3d11_device_context_Draw() По ошибке тестировал не на той версии wine. Сейчас заново проверил: вызов Draw() вместо DrawAuto() работает. Но нужно определять количество вершин для отрисовки. Я для теста сделал константу 128, но это не вариант, т.к. если в буфере больше вершин, то часть геометрии не будет отрисована, а если меньше, то может рисоваться "мусор", оставшийся в буфере с прошлых кадров.
Пытаюсь найти способ определить количество вершин в stream output, которые нужно отрисовать drawauto(). Насколько я понимаю, нужен быть некий счетчик, который увеличивается на 1 каждый раз когда в stream output помещается новая вершина, и сбрасывается после вызова drawAuto(). Беру stream output через context->state->stream_output[0]->buffer Почему-то buffer всегда NULL. Через wined3d_device_context_get_stream_output() тоже. Еще есть такое понятие как transform feedback https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_transform_feedback.html похоже на аналог stream output в вулкане. И в wine он тоже используется, но я пока плохо понимаю как и для чего. Думаю надо смотреть в его сторону.
В вулкане есть функция vkCmdDrawIndirectByteCountEXT, которая работает аналогично обычному DrawIndirect, но количество вершин предполагается брать из transform feedback. Причем делается "without CPU intervention", сразу на видеокарте, прямо как в DirectX-овском DrawAuto(). Кажется это ровно то что на нужно. Пытаюсь сделать чтобы vkCmdDrawIndirectByteCountEXT использовалась при вызове DrawAuto(). Многое скопировал по аналогии с вызовом vkCmdDrawIndirect. В качестве буфера передаю stream_output. При запуске программы, использующей drawAuto(), происходит ошибка Unhandled page fault на строке wined3d_device_context_reference_resource(context, &state->stream_output[0].buffer->resource);
(Ответ Олег Никулин на комментарий #7) > В качестве буфера передаю stream_output. > При запуске программы, использующей drawAuto(), происходит ошибка Unhandled > page fault на строке > wined3d_device_context_reference_resource(context, > &state->stream_output[0].buffer->resource); stream_output[0].buffer в этот момент уже NULL, и вообще здесь нужен не stream output, а буфер который устанавливался через IASetVertexBuffers. Это поправил https://gitlab.eterfund.ru/owl2/wine-rebased/commit/4b20a72f26e15ba8a3a323b70716337870d33700 В тестовой программе отрисовка через drawAuto заработала. Но работает ужасно медленно, на глаз 2-3 фпс примерно. Также проверил в Renga. Тоже медленно работает, к тому же не вся геометрия рисуется корректно: поверх черных линий накладываются желтые, иногда отображается мусор (линии, которых быть не должно). Так что пока результат не особо удачный
Повторно тестирую. Тестовая программа лежит в /var/ftp/tmp/owl2/bug16697 Должен отображаться куб с красной обводкой по контуру (так в windows 10). Release_draw - для отрисовки обводки используется функция Draw() Release_drawauto - для отрисовки обводки используется функция DrawAuto() Других отличий нет. Проверил на alt p10, на видеокартах nvidia gtx 1050ti с драйверами nvidia 550 и noveau, а также на встройке amd ryzen 5600g с драйвером amdgpu. Тестировал в версиях wine rebased-etersoft-8.8 и rebased-etersoft-8.9. В 9.0 тестировал только amdgpu, результат аналогичен 8.9 Результаты: Release_drawauto: Обводка не отображается независимо от версии wine и используемого драйвера(т.к. функция не реализована). Release_draw, Драйвер nvidia 550: rebased-etersoft-8.8: обводка отображается, но не чисто красным, а с вкраплениями цвета куба. rebased-etersoft-8.9: в приложении черный экран, в консоли ошибки err:d3d:wined3d_context_vk_submit_command_buffer Failed to submit command buffer 0000000001004060, vr VK_ERROR_DEVICE_LOST. Release_draw, Драйвер nouveau: rebased-etersoft-8.8: в приложении черный экран, через пару секунд после запуска само закрывается (ошибок в консоли нет). rebased-etersoft-8.9: то же самое. Release_draw, Драйвер amdgpu: rebased-etersoft-8.8: обводка корректно отображается. rebased-etersoft-8.9: вместо обводки отображается другая геометрия (торчит сверху куба). Как видно, результаты зависят от используемого драйвера и видеокарты. Также, что-то поменялось между wine 8.8 и 8.9, что негативно влияет на результат. Полностью корректное отображение только на версии 8.8 с драйвером amdgpu.
(Ответ Олег Никулин на комментарий #9) > Также, что-то поменялось между wine 8.8 и 8.9, что негативно влияет на > результат. > Полностью корректное отображение только на версии 8.8 с драйвером amdgpu. Через bisect нашел, что стало хуже в коммите e2c30c8d460301b1e151d4fc092faf8c3abda5cd "Update vkd3d to bb680e73de4ac22700ec89b1f466eea8da0a2120"
Проверил в winehq 9.20. DrawAuto() не работает. Draw() с драйвером amdgpu работает корректно (другие драйверы не тестировал). Также дополнил багу на winehq https://bugs.winehq.org/show_bug.cgi?id=55458
Нашел в wine-staging старый патч, который реализует DrawAuto для deferred context: https://gitlab.winehq.org/wine/wine-staging/-/blob/d13e9fa487997b8eb22874a5fb1aab90aa7cd09f/patches/d3d11-Deferred_Context/0027-d3d11-Implement-DrawAuto-for-deferred-contexts.patch В актуальном на данный момент wine-staging этого патча уже нет, и к актуальному wine (9.0) он не применим.
(In reply to Олег Никулин from comment #12) > Нашел в wine-staging старый патч, который реализует DrawAuto для deferred > context: > https://gitlab.winehq.org/wine/wine-staging/-/blob/ > d13e9fa487997b8eb22874a5fb1aab90aa7cd09f/patches/d3d11-Deferred_Context/0027- > d3d11-Implement-DrawAuto-for-deferred-contexts.patch > В актуальном на данный момент wine-staging этого патча уже нет, и к > актуальному wine (9.0) он не применим. Этот патч сложно назвать реализацией, он ничего не делает.
Поизучал функцию vulkan vkCmdDrawIndirectByteCountEXT (своего рода аналог DrawAuto в vulkan) и как её надо использовать. Вкратце: 1. Указать буфер transform feedback: vkCmdBindTransformFeedbackBuffersEXT 2. Включить transform feedback: vkCmdBeginTransformFeedbackEXT 3. Отрисовать всё что нужно при помощи обычных команд, например, vkCmdDraw Результат будет записан в буфер transform feedback, указанный ранее 4. Остановить transform feedback: vkCmdEndTransformFeedbackEXT 5. Отрисовать содержимое transform feedback буфера: vkCmdDrawIndirectByteCountEXT Хороший пример: https://paminerva.github.io/docs/LearnVulkan/02.D-Transform-Feedback Кажется в wine уже есть почти всё нужное (шаги 1, 2, 3, 4). Снова попробовал сделать DrawAuto в wine через функцию vkCmdDrawIndirectByteCountEXT. Небольшой прогресс есть. Патч приложу к баге. Проверял только на видеокарте amd (amdgpu). В wine 9.0 в тестовой программе появляется геометрия, но отображается некорректно (также, как если в тестовой программе заменить вызов DrawAuto на Draw. Если те же изменения применить к wine 8.9, то DrawAuto корректно работает в тестовой программе, и проблем с производительностью не наблюдается. При вызове vkCmdBindTransformFeedbackBuffersEXT нужно указывать stride (размер в байтах одной вершины). Сейчас у меня фиксированно прописано 24 байта (верно для тестовой программы). Нужно вместо этого определять размер stride. И нужно будет протестировать с другими драйверами и в других программах (Renga).
Created attachment 6763 [details] Попытка реализации DrawAuto через vkCmdDrawIndexedIndirect
(In reply to Олег Никулин from comment #14) > Поизучал функцию vulkan vkCmdDrawIndirectByteCountEXT (своего рода аналог > DrawAuto в vulkan) и как её надо использовать. > Вкратце: > 1. Указать буфер transform feedback: vkCmdBindTransformFeedbackBuffersEXT > 2. Включить transform feedback: vkCmdBeginTransformFeedbackEXT > 3. Отрисовать всё что нужно при помощи обычных команд, например, vkCmdDraw > Результат будет записан в буфер transform feedback, указанный ранее > 4. Остановить transform feedback: vkCmdEndTransformFeedbackEXT > 5. Отрисовать содержимое transform feedback буфера: > vkCmdDrawIndirectByteCountEXT > > Хороший пример: > https://paminerva.github.io/docs/LearnVulkan/02.D-Transform-Feedback > > Кажется в wine уже есть почти всё нужное (шаги 1, 2, 3, 4). MSDN описание ID3D11DeviceContext::DrawAuto(): https://learn.microsoft.com/en-us/windows/win32/api/d3d11/nf-d3d11-id3d11devicecontext-drawauto В Wine методы классов d3d11 - это обертки вокруг вызовов dlls/wined3d, соответственно ::DrawAuto() нужно реализовать не в терминах Vulkan API, а как метод d3d11, вызывающий wined3d API. Внутри же wined3d есть несколько разных бэкендов и Vulkan всего лишь один из них.
А как это реализовано в dxvk?
(Ответ Dmitry Timoshkov на комментарий #17) > А как это реализовано в dxvk? В dxvk тоже сделано через vkCmdDrawIndirectByteCountEXT.
Created attachment 6765 [details] Патч DrawAuto 2
(Ответ Олег Никулин на комментарий #14) > При вызове vkCmdBindTransformFeedbackBuffersEXT нужно указывать stride > (размер в байтах одной вершины). Сейчас у меня фиксированно прописано 24 > байта (верно для тестовой программы). Нужно вместо этого определять размер > stride. Нашел как это сделать. См. "Патч DrawAuto 2". Размер stride передается приложением в функцию directx IASetVertexBuffers. Туда же передается offset, который тоже нужно указывать при вызове vkCmdDrawIndirectByteCountEXT. Нужно было только найти, откуда потом (при вызове vkCmdDrawIndirectByteCountEXT) брать эти параметры. Проверил отрисовку через DrawAuto в тестовой программе и в Renga. В wine-8.8 и wine-9.0 с обновленным патчем. Драйвер amdgpu. В 9.0 в обеих программах геометрия через DrawAuto отображается некорректно (рисуется не то и не там где надо). В 8.8 в обеих программах геометрия через DrawAuto отображается корректно. Нужно детально разобраться, почему в версиях после 8.8 перестает нормально работать. (Ответ Dmitry Timoshkov на комментарий #16) > В Wine методы классов d3d11 - это обертки вокруг вызовов dlls/wined3d, > соответственно ::DrawAuto() нужно реализовать не в терминах Vulkan API, > а как метод d3d11, вызывающий wined3d API. Внутри же wined3d есть несколько > разных бэкендов и Vulkan всего лишь один из них. У меня вроде так и сделано. Метод d3d11 вызывает wined3d API. Но Vulkan - единственный бэкэнд, при использовании которого будет работать DrawAuto. Возможно в OpenGL тоже получится сделать, т.к. там тоже есть transform feedback.
(Ответ Олег Никулин на комментарий #10) > (Ответ Олег Никулин на комментарий #9) > > Также, что-то поменялось между wine 8.8 и 8.9, что негативно влияет на > > результат. > > Полностью корректное отображение только на версии 8.8 с драйвером amdgpu. > Через bisect нашел, что стало хуже в коммите > e2c30c8d460301b1e151d4fc092faf8c3abda5cd > "Update vkd3d to bb680e73de4ac22700ec89b1f466eea8da0a2120" Этот коммит есть в ветке rebased-etersoft-8.9, но его нет в ветке rebased-etersoft. Заново сделал bisect в ветке rebased-etersoft. Тут проблемным оказался 3c186a5ed0d1932349b96b7897cae0851718a2b1 "vkd3d: Import upstream release 1.9." Причем до этого есть коммит "vkd3d: Import upstream release 1.7.", а import vkd3d 1.8 нет. То есть перешли с 1.7 сразу на 1.9. Полагаю перестало работать в vkd3d 1.8, т.к. "Update vkd3d to bb680e73de4ac22700ec89b1f466eea8da0a2120" относится к vkd3d 1.8.
Проверил тестовую программу Release_draw и Renga с драйверами nouveau, nvidia 550 и amdgpu. Видеокарты gtx 1050ti и встройка ryzen 5600g. renderer=vulkan. Делал две сборки wine. Первая - по состоянию на коммит 3c186a5ed0d1932349b96b7897cae0851718a2b1 "vkd3d: Import upstream release 1.9." Условно назову ее wine-vkd3d-1.9 Вторая - по состоянию на предыдущий коммит 3b5aef662f80e944555797b1616bc911a3518029. Условно назову ее wine-vkd3d-1.7 nouveau: wine-vkd3d-1.9: в Release_draw черный экран, через пару секунд после запуска сама закрывается (ошибок в консоли нет); Renga падает при построении стены wine-vkd3d-1.7: то же самое. Дополнительно проверил nouveau в wine-9.0: Release_draw работает, но обводка куба отображается некорректно; Renga работает. В какой версии wine nouveau начинает нормально работать еще не выяснил. nvidia 550: wine-vkd3d-1.9: Release_draw виснет; Renga виснет при построении стены. И там и там ошибка VK_ERROR_DEVICE_LOST. wine-vkd3d-1.7: Release_draw работает, обводка куба отображается с некорректным цветом; Renga работает. amdgpu: wine-vkd3d-1.9: Release_draw работает, обводка куба отображается некорректно; Renga работает. wine-vkd3d-1.7: Release_draw программа работает, обводка куба отображается полностью корректно; Renga работает. Также попробовал применить патч drawauto_wip2.patch к wine-vkd3d-1.7: nouveau: не проверить, т.к. ни тестовая программа, ни Renga нормально не работают. nvidia 550: в Release_drawauto обводка куба отображается с некорректным цветом; В Renga линии при построении стен отображаются некорретным цветом и будто накладываются друг на друга. amdgpu: в Release_drawauto обводка куба отображается полностью корректно; В Renga линии при построении стен отображаются полностью корректно. Итого: Начиная с коммита 3c186a5ed0d1932349b96b7897cae0851718a2b1 "vkd3d: Import upstream release 1.9." появились проблемы с зависанием при использовании драйвера nvidia 550, а также проблема с отображением обводки в тестовой программе. Но даже до этого коммита, полностью корректного отображения в тестовой программе и в Renga получилось добиться только при использовании драйвера amdgpu.
Проверил тестовую программу в префиксе с dxvk, драйвер nvidia 550. И до, и после коммита 3c186a5ed0d "vkd3d: Import upstream release 1.9." обводка куба отображается с некорректным цветом - также как без dxvk до коммита. То, что просто wine и wine + dxvk дают одинаковый неправильный результат, наводит на мысль, что это именно драйвер nvidia такой проблемный. Также, касательно ошибки VK_ERROR_DEVICE_LOST, можно найти упоминания, что старые версии драйвера nvidia более стабильны https://github.com/doitsujin/dxvk/issues/1791 https://forums.developer.nvidia.com/t/vk-error-device-lost-in-many-game-titles/164513/30 Хотя там не совсем наш случай. У нас ошибка VK_ERROR_DEVICE_LOST при вызове vkQueueSubmit
Created attachment 6770 [details] Патч DrawAuto 3
(Ответ Олег Никулин на комментарий #23) > Проверил тестовую программу в префиксе с dxvk, драйвер nvidia 550. > И до, и после коммита 3c186a5ed0d "vkd3d: Import upstream release 1.9." > обводка куба отображается с некорректным цветом - также как без dxvk до > коммита. > То, что просто wine и wine + dxvk дают одинаковый неправильный результат, > наводит на мысль, что это именно драйвер nvidia такой проблемный. Проверил Renga и тестовую программу в профексе с dxvk в wine-9.0.19-eter0.p10.1 (до реверта child window патча), драйвер nvidia 550. Как ни странно, в Renga функция DrawAuto() показала корректный результат, а в тестовой программе - нет. Получается, тестовая программа не совсем верно отражает проблему в Renga. Пытаюсь дальше починить DrawAuto в wine. На коммите 3b5aef66, без dxvk: Посмотрел ошибки vulkan validation layers при работе Renga (для этого нужно объявить переменную окружения VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation). Была ошибка VUID-vkCmdDrawIndirectByteCountEXT-counterBuffer-02290 - исправил путем добавления бита VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT при создании буфера. Затем появилась ошибка VUID-vkCmdBeginTransformFeedbackEXT-firstCounterBuffer-09630 - исправил, указав количество буферов = 1 при вызове функции vkCmdBeginTransformFeedbackEXT. Во время отрисовки в Renga теперь нет ошибок vulkan validation layers, однако с драйвером nvidia визуально ничего не поменялось, функция DrawAuto() всё равно дает некорректный результат.