Direct2D #13. Command Lists. Запись графических команд

от автора

Всех горячо приветствую! Темы, как я говорил, пошли несложные, да и у меня достаточно энергии, так что держите новую тему.

В двух словах о том, что такое Command Lists. Раньше все графические команды выполнялись по завершении рисования (EndDraw), но может быть такая ситуация: есть функция, в ней рендер мира, но всё в одной функции — довольно так себе. Вы же можете, например, отрисовывать разные локации, и многие сразу задумаются о том, чтобы использовать разные функции — что совершенно правильно. Но было бы неплохо создать массив команд, чтобы вместо функций просто оперировать массивом, а также такой массив не привязан к разрешению.

Кроме этого, захотелось бы нам ещё применить к нему эффекты из прошлой статьи или создать узор. И, кроме всего этого, нам бы ещё сделать оптимизацию. Вот до массива мы использовали 50 команд снова и снова, тратили ресурсы CPU на расчёт, а поместили в массив — один раз потратили ресурсы, и теперь просто и легко отправляем всё в GPU.

И этот инструмент уже существует, отвечая на все вышеописанные запросы и называется Command List, ну или лист команд. Поддерживается с Windows 8.

Это очень интересный инструмент, при грамотном подходе позволяющий снизить нагрузку на CPU, но не на GPU.

Прежде чем перейти к примерам, важно сказать, что Command List наследуется от ID2D1Image со всеми вытекающими: он может быть входом для эффекта, источником для ID2D1ImageBrush и аргументом для DrawImage.

Также важно, что Command List не хранит копию ресурсов, а лишь ссылки на них. А отсюда вытекает следующее:

  1. Ресурсы должны существовать в момент воспроизведения Command List. Если вы удалите битмап до воспроизведения — будет ошибка.

  2. Изменение ресурса после записи отразится на воспроизведении.

  3. Command List сам по себе занимает мало памяти — он хранит только инструкции и ссылки, а не сами данные.

  4. Все ресурсы создаются и уничтожаются вне Command List.

Собственно, пример создания (разумеется, через DeviceContext):

ComPtr<ID2D1CommandList> pCommandList;HRESULT hr = pDeviceContext->CreateCommandList(&pCommandList);if (FAILED(hr)) {    // Обработка ошибки}

Собственно, ничего сложного. Теперь — как записать команды (набросок кода):

// Устанавливаем Command List как цельpDeviceContext->SetTarget(pCommandList.Get());// Начинаем рисование - все команды будут записаны в Command ListpDeviceContext->BeginDraw();// ... здесь ваши команды рисования ...pDeviceContext->DrawRectangle(...);pDeviceContext->FillGeometry(...);pDeviceContext->DrawText(...);pDeviceContext->EndDraw();

Ну и потом не забудьте восстановить цель рендера.
ВАЖНО! Без закрытия Command List нельзя использовать:

pCommandList->Close();

Разумеется, после закрытия добавлять команды уже нельзя. Теперь, чтобы воспроизвести содержимое Command List, достаточно написать:

pDeviceContext->BeginDraw();// Рисуем Command List в указанной позицииpDeviceContext->DrawImage(pCommandList.Get());// Или со смещениемD2D1_POINT_2F offset = D2D1::Point2F(100.0f, 50.0f);pDeviceContext->DrawImage(pCommandList.Get(), offset);pDeviceContext->EndDraw();

Пример создания кисти-узора на основе Command List:

// 1. Создаём Command List с узоромComPtr<ID2D1CommandList> pPatternList;pDC->CreateCommandList(&pPatternList);ComPtr<ID2D1Image> pOldTarget;pDC->GetTarget(&pOldTarget);pDC->SetTarget(pPatternList.Get());pDC->BeginDraw();// Рисуем элемент узора (например, ромб)DrawMyPatternElement(pDC);pDC->EndDraw();pPatternList->Close();pDC->SetTarget(pOldTarget.Get());// 2. Создаём Image Brush из Command ListD2D1_IMAGE_BRUSH_PROPERTIES imageBrushProps = D2D1::ImageBrushProperties(    D2D1::RectF(0, 0, 50, 50)  // область узора);D2D1_BRUSH_PROPERTIES brushProps = D2D1::BrushProperties(1.0f);ComPtr<ID2D1ImageBrush> pPatternBrush;pDC->CreateImageBrush(    pPatternList.Get(),    imageBrushProps,    brushProps,    &pPatternBrush);// 3. Используем кисть для заливкиpDC->BeginDraw();pDC->FillEllipse(D2D1::Ellipse(D2D1::Point2F(400, 300), 150, 100), pPatternBrush.Get());pDC->EndDraw();

Так как всё это мы уже проходили, особо пояснять нечего. Тема, как видите, несложная, отсюда и короткая, но важная. А лепить что-то ещё я решил, что не стоит.

Вообще, если поискать в интернете, прям подробных книг по Direct2D я не нашёл. А у нас тут вполне подробно и кратко, и каждая статья — на определённую тему. Можно даже сказать — экспресс-курс.

Всем спокойной ночи или удачного дня, и удачи!

При желании материально поддержать перевод и структурирование информации — средства можете отправить через сбор в ЮМани.

ссылка на оригинал статьи https://habr.com/ru/articles/1053608/