<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:dw="https://www.dreamwidth.org">
  <id>tag:dreamwidth.org,2021-01-19:3740325</id>
  <title>amarao</title>
  <subtitle>amarao</subtitle>
  <author>
    <name>amarao</name>
  </author>
  <link rel="alternate" type="text/html" href="https://amarao.dreamwidth.org/"/>
  <link rel="self" type="text/xml" href="https://amarao.dreamwidth.org/data/atom"/>
  <updated>2021-03-17T14:37:48Z</updated>
  <dw:journal username="amarao" type="personal"/>
  <entry>
    <id>tag:dreamwidth.org,2021-01-19:3740325:6977</id>
    <link rel="alternate" type="text/html" href="https://amarao.dreamwidth.org/6977.html"/>
    <link rel="self" type="text/xml" href="https://amarao.dreamwidth.org/data/atom/?itemid=6977"/>
    <title>фреймворк моей мечты</title>
    <published>2021-03-17T14:36:53Z</published>
    <updated>2021-03-17T14:37:48Z</updated>
    <category term="equart"/>
    <category term="rust"/>
    <dw:security>public</dw:security>
    <dw:reply-count>1</dw:reply-count>
    <content type="html">&lt;p&gt;Ну чем не ZX-Spectrum? Это целиком весь main.rs, который мигает разноцветным экраном. Обратите внимание на отсутствие event loop'а и прочей ерунды.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;use lib::EasyScreen;

fn main(){
    let screen = EasyScreen::new();
    let mut c = 0;
    loop{
        c+=1;
        screen.fill(c);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;https://github.com/amarao/equart/blob/switching_to_sdl/src/main.rs&lt;/p&gt;

&lt;p&gt;Рисование я начну писать после того, как доделаю всякие put_pixel и т.д. Алсо, не реализовать ли мне спектрумовский circle, который умел рисовать муары при углах больше 3 радиан?&lt;/p&gt;
&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=amarao&amp;ditemid=6977" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2021-01-19:3740325:6661</id>
    <link rel="alternate" type="text/html" href="https://amarao.dreamwidth.org/6661.html"/>
    <link rel="self" type="text/xml" href="https://amarao.dreamwidth.org/data/atom/?itemid=6661"/>
    <title>Абсолютный, грандиозный успех!</title>
    <published>2021-03-16T21:54:45Z</published>
    <updated>2021-03-16T21:54:45Z</updated>
    <category term="rust"/>
    <category term="equart"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">Итог:&lt;br /&gt;render fps: 2400 fps&lt;br /&gt;draw fps: 60 fps&lt;br /&gt;cpu use: 120%&lt;br /&gt;&lt;br /&gt;или&lt;br /&gt;&lt;br /&gt;render fps: 2100 fps&lt;br /&gt;draw fps: 310 fps&lt;br /&gt;cpu use: 200%&lt;br /&gt;&lt;br /&gt;lockless rendering. Один тред считает в цикле (тупо fill новым цветом, 100% CPU в треде), второй это читает и выводит, либо asap (310 fps, 100% CPU в треде), либо по vsync (60 fps, 20% CPU в треде).&lt;br /&gt;&lt;br /&gt;Сам код - я на питоне бы не смог написать короче. 55 строк вся библиотека (и то, я не уверен, что нужно руками clone делать). ... Уверен, вся библиотека 47 строк.&lt;br /&gt;&lt;br /&gt;&lt;a href="https://github.com/amarao/equart/tree/switching_to_sdl/src"&gt;https://github.com/amarao/equart/tree/switching_to_sdl/src&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Это просто счастье какое-то! Наконец-таки, у моего нового быстрого компьютера появился новый быстрый код!&lt;br /&gt;&lt;br /&gt;Ближайший роадмп: сделать инверсию (вынести SDL в тред, в main сделать только рисование), чтобы остался только init_graphics()...&lt;br /&gt;&lt;br /&gt;Заметим, этот же алгоритм идеально режется на параллельны треды. Каждому свой диапазон значений считать, а вывод - в общий буффер, и всё. Сравните это со старой версией (piston) - 1200+ строк, в которых ад и погибель с message'ами и копированиями буферов.&lt;br /&gt;&lt;br /&gt;AtomicU32 вместе с Arc и Ordering::Relaxed звучит как читерство. Слишком просто, слишком волшебно, слишком легко.&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=amarao&amp;ditemid=6661" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2021-01-19:3740325:6507</id>
    <link rel="alternate" type="text/html" href="https://amarao.dreamwidth.org/6507.html"/>
    <link rel="self" type="text/xml" href="https://amarao.dreamwidth.org/data/atom/?itemid=6507"/>
    <title>Shared memory crazy fast</title>
    <published>2021-03-16T14:51:29Z</published>
    <updated>2021-03-16T14:54:37Z</updated>
    <category term="rust"/>
    <category term="equart"/>
    <dw:security>public</dw:security>
    <dw:reply-count>1</dw:reply-count>
    <content type="html">&lt;p&gt;Итог трёх дней моей возни с проблемой... Грандиозный успех safe and sound Rust'а.&lt;/p&gt;

&lt;p&gt;Предистория: Я решил-таки сделать себе в программе рисования удобно, как было на zx-spectrum. То есть - программа рисования рисует себе в цикле, когда нужно точечки на экран ставит, точечки появляются на экране и остаются там пока программа не перезапишет. Никаких спецусилий, никаких event loop'ов и т.д.&lt;/p&gt;

&lt;p&gt;Я хотел иметь то же самое в условиях оконного отображения. Оконное отображение - это event loop, надо реагировать на кнопочки и команды выхода. Если мы в цикле 10с считаем Солнышко Лиссажу, то мы 10с не реагируем на кнопки (aka зависли). Классические подходы: резать задачу на кусочки и перемежать их с ответом на event loop. Плюсы: относительно просто. Минусы - не ясно где резать, можно промахнуться с отправкой отрисованного и получить лаг на экране. Второй подход: соседний тред, который шлёт мелкие сообщения об обновлениях, основной тред рисует их на экране и отвечает за кнопки. Плюсы: если сообщения мелкие, практически гарантировано можно успеть ответить на event. Минусы: безумные накладные расходы на сообщения, проблема "очереди" (либо блокирующая, либо память течёт). В целом, если точки генерируются достаточно быстро, то снова та же проблема "когда прекратить принимать сообщения и отправлять кадр на рендеринг"?&lt;/p&gt;

&lt;p&gt;Моя идея: shared область памяти, в которую рисующий (считающий) тред пишет непрерывно (как хочет), а отображающий заглядывает для обновления текстуры. Схватил текстуру, отобразил в буффер, дальше библиотека SDL (да и любая другая) с режимом vsync вернёт управление как только будет отрисован кадр на экране. Ляпота, да?&lt;/p&gt;

&lt;p&gt;Только была пробелма: Rust не любит двойной доступ к памяти. Это тот самый danger quadrant, где конкуретный read и write.&lt;/p&gt;

&lt;p&gt;В процессе я нырнул глубоко в unsafe, прочитал много про pointer'ы, в целом стал лучше понимать rust.&lt;/p&gt;

&lt;p&gt;итог: код без атомиков (я себе таки его написал прямо сейчас) не работает от слова вообще. Один тред пишет, второй наслаждается кешем процессора.&lt;/p&gt;

&lt;p&gt;Код с атомиками я сначала написал ужасно, с двойным указателем в один и тот же slice, отдаваемый в разные треды. unsafe, unsound and dangerous. Но он работал с офигенной скоростью в 13.5 ГБ/с (в режиме максимального congestion, когда один тред непрерывно меняет ячейку, а второй непрерывно её читает).&lt;/p&gt;

&lt;p&gt;Мне сказали "переходи на arc". Для меня было открытием, что atomic позволяет сделать store для значения на non-mut ref, но я пошёл и написал. Стало порядка 9ГБ/с.&lt;/p&gt;

&lt;p&gt;И тут мне сказали про Arc&amp;lt;[AtomicU32]&amp;gt;. Это было безумие! У меня скорость стала ещё выше - 17.5ГБ/с. Я подозреваю, что это подозрительно близко к скорости моей памяти (25.5ГБ/с в один канал), и, возможно, ограничена скоростью IPI (который как раз кеши процессорам и инвалидирует).&lt;/p&gt;

&lt;p&gt;При этом в коде 0 unsafe!!! Я писаю кипятком.&lt;/p&gt;

&lt;p&gt;А ещё я проверил насколько проверка индексов всё тормозит. Ответ: мало тормозит. около 0.2с (с 9.9s на 10 прогонов полного цикла по u32 до 9.7s), и оно того не стоит.&lt;/p&gt;

&lt;p&gt;Фух. Сейчас я пойду приделывать это всё в свой основной проект. Подумав головой, я хочу сделать хитрое - засунуть рисовалку в дополнительный тред, а в основном оставить только код рисования.&lt;/p&gt;

&lt;p&gt;Чтобы было так:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;fn main(){
   let mut screen = Screen::new();
   for i in foo(){
      screen.put_pixel(x, y);
   }
   screen.done();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;А всякая SDL'ная фигня была в этом самом screen::new().&lt;/p&gt;

&lt;p&gt;Это будет моя спектрумовская мечта. Берёшь и рисуешь, no thinking required. Я думаю, она много кому понравится как библиотека, хотя рисковать делать библиотеку пока я не готов (вероятнее всего, задумаюсь, по результатам успеха).&lt;/p&gt;

&lt;p&gt;Proof-of-concept: https://github.com/amarao/rust_dual/blob/arc/src/main.rs&lt;/p&gt;
&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=amarao&amp;ditemid=6507" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2021-01-19:3740325:5861</id>
    <link rel="alternate" type="text/html" href="https://amarao.dreamwidth.org/5861.html"/>
    <link rel="self" type="text/xml" href="https://amarao.dreamwidth.org/data/atom/?itemid=5861"/>
    <title>Я не уверен, что это хорошо, но меня прёт</title>
    <published>2021-03-14T19:34:52Z</published>
    <updated>2021-03-14T19:34:52Z</updated>
    <category term="equart"/>
    <category term="rust"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">&lt;pre&gt;&lt;code&gt;pub struct Screen{
    bytes: Vec&amp;lt;std::sync::atomic::AtomicU32&amp;gt;,
    width: u32,
    height: u32
}

impl Screen {
    pub fn copy_to_buffer&amp;lt;T&amp;gt;(&amp;amp;self, target: &amp;amp;mut [T]) -&amp;gt; Result&amp;lt;(), &amp;amp;'static str&amp;gt;
    where T: bytemuck::Pod{
        if self.bytes.len() != target.len(){
            return Err("Size of target should be the same as source.")
        }
        let target_u32: &amp;amp;mut [u32] = bytemuck::cast_slice_mut(target);
        for idx in 0..self.bytes.len(){
            target_u32[idx] = self.bytes[idx].load(Relaxed);
        }
        Ok(())
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Так сказать, "а что, так можно было"?&lt;/p&gt;

&lt;p&gt;Если мне сейчас удастся малой кровью сделать его мутабельным (я верю в тебя, атомик) и пропихнуть между тредами, то это же просто праздник какой-то. У меня будет шаренная между тредами память с Relaxed моделью, в которой в одном треде я мирно делаю copy_to_buffer&lt;u8&gt; (для нужд рендеринга в текстуру), а в другом я в него делаю set_pixel/get_pixel, которые работают со скоростью mov для u32.&lt;/u8&gt;&lt;/p&gt;

&lt;p&gt;Что мне нужен атомик, меня уговорили на форуме, пригрозив, что без атомика компилятор может просто соптимизировать повторный доступ к непоменявшимся (с его точки зрения) данным.&lt;/p&gt;

&lt;p&gt;Бенчмарк показал, что запись в атомик в Relaxed занимает столько же времени, как и в обычный u32.&lt;/p&gt;
&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=amarao&amp;ditemid=5861" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2021-01-19:3740325:1733</id>
    <link rel="alternate" type="text/html" href="https://amarao.dreamwidth.org/1733.html"/>
    <link rel="self" type="text/xml" href="https://amarao.dreamwidth.org/data/atom/?itemid=1733"/>
    <title>отставить opengl</title>
    <published>2021-02-20T22:08:57Z</published>
    <updated>2021-02-20T22:10:24Z</updated>
    <category term="sdl"/>
    <category term="equart"/>
    <category term="2d"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">Я потыкался-потыкался и обнаружил, что есть же sdl, и её биндинги для rust'а. А у него (неё?) есть window().into_canvas(), которая, в свою очередь, чистой воды 2D (то, что мне и нужно).&lt;br /&gt;&lt;br /&gt;Сейчас попытаюсь отбенчмаркать, может ли оно выдержать честные 60FPS в фулскрине с поточечным рисованием.&lt;br /&gt;Не выдерживает. 15 fps для FullHD, 8 fps для 2560x1440. Но, это worst case (draw_point для каждой точки экрана каждого кадра). Интересно, что в отличие от piston, оно супер-мега smooth, даже не смотря на эти 15.&lt;br /&gt;&lt;br /&gt;Моя реальная задача-то - не рисовать безумно быстро, а обновлять экран по мере надобности, и не страдать при этом из-за тяжёлой математики.&lt;br /&gt;&lt;br /&gt;Каждется, SDL - это реальное решение.&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=amarao&amp;ditemid=1733" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2021-01-19:3740325:984</id>
    <link rel="alternate" type="text/html" href="https://amarao.dreamwidth.org/984.html"/>
    <link rel="self" type="text/xml" href="https://amarao.dreamwidth.org/data/atom/?itemid=984"/>
    <title>рисование из Rust</title>
    <published>2021-02-15T09:17:16Z</published>
    <updated>2021-02-15T09:17:16Z</updated>
    <category term="rust"/>
    <category term="equart"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">Полировка QuadTree идёт, в принципе, люди с форума предложили использовать переменные сборки для управления кодом (сейчас у меня важные константы производительности просто константами в коде, но для некоторых значений может быть специфичный, более быстрый код).&lt;br /&gt;&lt;br /&gt;Но параллельно меня продолжает смущать глубокая некрасивость в районе piston'а. Я добился на нём некоторой скорости рисования, но очень дорогой ценой. У меня идёт двойное копирование (кто-то это может назвать "двойной буфферизацией"), и мне оно не нравится. Ещё там шути что в районе текстур, и вообще, я чувствую себя слегка заброшенным, потому что документации по сущностям piston почти нет, там сквозят нюансы opengl, но они не полностью применимы.&lt;br /&gt;&lt;br /&gt;Так что я начинаю думать о переезде на что-то другое. wayland пока что звучит слишком радикально (я домашнюю машину ещё не перевёл), а вот vulkan можно считать состоявшимся и готовым к использованию. Мне хочется найти какой-то компромисс между понятностью того, как оно всё работает, и минимальным количеством низкоуровневых деталей с которыми надо возиться. Ну и быстро рисовать. Раньше на компьютере 10-летней давности у меня ещё были excuses по производительности; на новом их нет. Должно быть 2560x1440@60FPS без лагов и с плавной визуализацией прогресса (пока считаются медленные формулы).&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=amarao&amp;ditemid=984" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
</feed>
