Как быстро стереть огромный блок видеопамяти в 32-битной сборке

Я пытаюсь создать свой собственный простой движок 3D-рендеринга в сборке полностью с нуля. Итак, я запускаю его из DOS, переключаюсь на 32-битный PM и все такое...

Наконец-то я получил работающие преобразования с проекцией и каркасным рендерингом, но столкнулся с очень тривиальной проблемой. После рендеринга моей сцены LFB необходимо очистить, чтобы следующий кадр я мог снова нарисовать там.

Но использование цикла rep stosd или простого цикла mov-loop очень медленное, и мой FPS падает буквально до 10 с 60+.

Я использую высокое разрешение 1280x1024 пикселей с 4 байтами на пиксель, поэтому мне нужно установить 1280 * 1024 = 1310720 dwords = 5242880 байтов на ноль, начиная с адреса 0xFC000000.

Есть ли способ заставить память мгновенно стереть себя? (Я хочу сохранить это разрешение)


person Segy    schedule 15.05.2019    source источник
comment
Вы можете найти сравнение различных подходов в этом ответе.   -  person zx485    schedule 15.05.2019
comment
Обратите внимание, что LFB, размещенный на вашей видеокарте, но отображенный в адресное пространство памяти ЦП, может быть значительно медленнее, чем память хоста. Очистка обычно выполняется локально на графическом процессоре, что не является подходом, который вы используете.   -  person Jester    schedule 15.05.2019
comment
@Jester, так ты пытаешься мне сказать, что это возможно только с GPU?   -  person Segy    schedule 15.05.2019
comment
Если у вас есть драйвер VBE/AF для вашей карты, вы можете попробовать использовать прямоугольную заливку. В противном случае, возможно, просто повторная инициализация того же графического режима может быть вариантом.   -  person Jester    schedule 15.05.2019
comment
Я работаю в PM, где я не могу использовать прерывания. Нет, у меня нет драйвера VBE/AF, но я посмотрю на него.   -  person Segy    schedule 15.05.2019
comment
VBE предоставляет интерфейс защищенного режима (но известно, что он содержит ошибки на реальном оборудовании).   -  person Jester    schedule 15.05.2019
comment
Ваша видеопамять отображается как WC (запись-объединение) или UC (некэшируемая)? Если это WC, то movnti должен разрешать потоковые хранилища, которые выполняют пакетную передачу 64 байтов по шине PCIe (если у вас есть внешний графический процессор). Или, если вы можете использовать регистры XMM, movntps для 16 байтов на инструкцию. Я думал, что rep stos также будет эффективно работать с памятью WC, а вы говорите, что это медленно. Так что, возможно, ваша видеопамять настроена как некэшируемая, или я ошибаюсь насчет rep stosd.   -  person Peter Cordes    schedule 15.05.2019
comment
нет единого ответа, который работает везде, задействовано множество факторов, а не только видеокарта.   -  person old_timer    schedule 15.05.2019
comment
Здесь, наверное, что-то другое. Даже если вы используете старую видеокарту PCI, вы должны получить около 25 кадров в секунду, просто стирая экран с помощью REP STOSD, и около 17 кадров в секунду при комбинированном стирании и рендеринге, при условии, что рендеринг кадра занимает 17 мс (60 кадров в секунду).   -  person Ross Ridge    schedule 15.05.2019
comment
Re: ваш конкретный вопрос: нет, вы не можете приказать ОЗУ стереть себя, будь то видео ОЗУ или обычная ОЗУ, подключенная к ЦП. Некоторые ЦП имеют специальную инструкцию для обнуления полной строки кэша, например. PowerPC работает, но не стандартный x86. У AMD есть инструкция CLZERO x86. Но это всего 64 байта за раз, и на самом деле это не ускорит работу по сравнению с использованием movnt хранилищ. Чтобы работать намного быстрее, вам нужно сообщить графическому процессору обнулить видеопамять, особенно если у вас есть дискретная графическая карта (а не iGPU, использующая ту же DRAM, что и ядра ЦП). Поэтому вам, возможно, придется писать драйверы графического процессора, а не просто сохранять их в памяти.   -  person Peter Cordes    schedule 16.05.2019


Ответы (1)


Если у вас есть только SSE, вы можете использовать pxor с movntps для выполнения 16 байтов за раз. Если у вас есть доступный SSE2, вы можете делать 16 байтов за раз с помощью pxor и movdqu (или более быстрого movdqa, если выровнено до 16 байтов). Если доступны инструкции AVX512, вы также можете использовать vpxor с регистром xmm и movntps с соответствующими регистрами zmm, чтобы получить 64 байта.

Если вы хотите использовать инструкции SSE и/или AVX512, вам необходимо установить некоторые регистры управления :

mov eax, cr0
and ax, 0xFFFB      ;clear coprocessor emulation CR0.EM
or ax, 0x2          ;set coprocessor monitoring  CR0.MP
mov cr0, eax
mov eax, cr4
or ax, 3 << 9       ;set CR4.OSFXSR and CR4.OSXMMEXCPT at the same time
mov cr4, eax
person 0x777C    schedule 16.05.2019
comment
Вы утверждаете, что обычный цикл с использованием mov [edi], eax быстрее, чем rep stosd? Очевидно, что это неверно для больших массивов в памяти с обратной записью и сомнительно для видеопамяти. Intel, начиная с PPro (P6 uarch), имеет микрокод быстрых строк для rep stos и rep movs, внутренне используя более широкие хранилища. Если вы не можете использовать регистры XMM (например, в коде ядра), rep movs обычно является лучшим выбором для современных процессоров, особенно Intel после IvyBridge, который добавил функцию ERMSB. Расширенный REP MOVSB ​​для memcpy - person Peter Cordes; 16.05.2019
comment
Пример: ядро ​​Linux использует rep movsd для его внутренней 32-битной реализации memcpy в string_32.h. Если бы цикл был быстрее, он бы использовал его. - person Peter Cordes; 16.05.2019
comment
vzeroall не принимает операнд: он обнуляет все регистры xmm/ymm/zmm. Для этой цели было бы более эффективно vpxor xmm0, xmm0, xmm0 обнулить только X/Y/ZMM0. Кроме того, SSE2 передает 128 битов за раз, а не байтов. - person Peter Cordes; 16.05.2019
comment
Я внес некоторые исправления и добавил некоторые пояснения. @PeterCordes Я много работал с rep, он просто не быстрый, современные процессоры не утруждают себя его оптимизацией, потому что компиляторы больше не генерируют его. - person 0x777C; 16.05.2019
comment
repne scasb и repe cmpsb (очень) медленные, но rep movs и rep stos быстро (для больших выровненных блоков). У них есть значительные накладные расходы при запуске (пока IceLake не добавит функцию быстрого короткого повторения), но они намного лучше, чем 32-битные mov для больших memset или memcpy. В руководстве Intel по оптимизации обсуждаются компромиссы. Вы совершенно не правы насчет того, что процессоры не удосужились оптимизировать их: IvyBridge добавил функцию ERMSB, и, как я уже сказал, IceLake добавит функцию быстрого короткого повторения. - person Peter Cordes; 16.05.2019
comment
Re: ваше обновление: rep stosd обычно хуже, чем хорошо оптимизированный цикл SIMD, но намного лучше, чем скалярный 32-битный цикл mov. (nvm, это ты уже удалил). - person Peter Cordes; 16.05.2019
comment
Если у вас есть AVX, вам нужно использовать vpxor xmm0,xmm0,xmm0, а не pxor xmm0,xmm0, чтобы обнулить регистр YMM. Устаревшее кодирование SSE оставляет старшие 128 бит без изменений. А для ZMM вам нужен AVX512, а не просто AVX. И movntps доступен (и это хорошая идея), начиная с SSE1; вам не нужен AVX для этого. - person Peter Cordes; 16.05.2019
comment
Кроме того, чтобы использовать SSE или AVX в автономном ядре, OP необходимо будет установить несколько битов в управляющих регистрах, иначе инструкции SSE и AVX будут ошибочными. (Так Intel избегает проблемы скрытого повреждения данных нового архитектурного состояния для кода пользовательского пространства, работающего в старых ОС.) - person Peter Cordes; 16.05.2019
comment
@PeterCordes Как дела? - person 0x777C; 16.05.2019
comment
Это уже не совсем неправильно, но вы сразу переходите от SSE к AVX512, не упоминая широко доступный AVX, и не упоминаете movntps для SSE1. Кроме того, обнуление регистра ZMM по-прежнему лучше всего выполнять с помощью vpxor xmm0, xmm0, xmm0 в кодировке VEX, а не более длинного EVEX vpxorq, если только это не один из zmm16..31 (Is vxorps- обнуление на AMD Jaguar/Bulldozer/Zen быстрее с регистрами xmm, чем ymm?). Но OP пишет 32-битный код, поэтому в любом случае доступны только zmm0..7. И, конечно же, AVX512 NT хранит vmovntps. - person Peter Cordes; 16.05.2019