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

В двух словах о том, что такое 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 List
pDeviceContext->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 List
D2D1_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 я не нашёл. А у нас тут вполне подробно и кратко, и каждая статья — на определённую тему. Можно даже сказать — экспресс-курс.

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

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