Определение функций в C++AMP

Я пытаюсь написать фильтр свертки, который использует конкретную функцию, чтобы определить точный выходной цвет пикселя. Кто-нибудь знает, возможно ли определить функцию, которую можно использовать в parallel_for_each блок?

2 ответа

Решение

Функция должна следовать ряду правил для успешной компиляции с помощью restrict(amp). Первый, как упомянуто в разделе parallel_for_each(), включает функции, которые он вызывает. Они должны быть видны во время генерации кода и также должны быть помечены как restrict(amp). Если вы не используете генерацию временного кода ссылки, это по существу означает, что они должны находиться в одном и том же файле.cpp к моменту компиляции, возможно, из заголовочного файла, включенного в этот файл.cpp. Если вы используете / ltcg при компиляции обоих файлов.cpp (того, который вызывает функцию, и того, кто ее реализует), а также при компоновке, то вы можете сохранить вызывающую и вызываемую функции в отдельных файлах.

C++ AMP-совместимая функция или лямбда может использовать только C++ AMP-совместимые типы, которые включают следующее:

  • ИНТ
  • без знака int
  • поплавок
  • двойной
  • Массивы в стиле C: int, unsigned int, float или double
  • concurrency:: array_view или ссылки на параллелизм:: массив
  • структуры, содержащие только C++ AMP-совместимые типы

Это означает, что некоторые типы данных запрещены:

  • bool (может использоваться для локальных переменных в лямбде)
  • голец
  • короткая
  • долго долго
  • неподписанные версии выше

Ссылки и указатели (на совместимый тип) могут использоваться локально, но не могут быть захвачены лямбда-выражением. Указатели на функции, указатель на указатель и т. П. Недопустимы; ни статические, ни глобальные переменные.

Классы должны соответствовать большему количеству правил, если вы хотите использовать их экземпляры. У них не должно быть виртуальных функций или виртуального наследования. Конструкторы, деструкторы и другие не виртуальные функции разрешены. Все переменные-члены должны быть совместимых типов, которые, конечно, могут включать экземпляры других классов, если эти классы соответствуют одним и тем же правилам.

Фактический код в вашей функции, совместимой с усилителем, не выполняется на процессоре и поэтому не может делать некоторые вещи, к которым вы могли бы привыкнуть:

  • рекурсия
  • указатель литья
  • использование виртуальных функций
  • новый или удалить
  • RTTI или динамическое литье

Вот пример, который делает именно то, что вы пытаетесь сделать, я думаю, но не использует тайлинг. shift Параметр - это размер (радиус) маски квадратного пикселя. В этом примере я не пытаюсь вычислять новые значения для элементов, расположенных так близко к краю массива. Чтобы не тратить нити на эти элементы там, где нет работы, parallel_for_each занимает степень, которая shift * 2 элементы меньше, чем массив. Исправленный индекс, idcрегулирует idx значение, основанное на степени, чтобы обратиться к правильному элементу.

void MatrixSingleGpuExample(const int rows, const int cols, const int shift)
{
    //  Initialize matrices

    std::vector<float> vA(rows * cols);
    std::vector<float> vC(rows * cols);
    std::iota(vA.begin(), vA.end(), 0.0f);

    //  Calculation

    accelerator_view view = accelerator(accelerator::default_accelerator).default_view;
    double time = TimeFunc(view, [&]()
    {
        array_view<const float, 2> a(rows, cols, vA); 
        array_view<float, 2> c(rows, cols, vC);
        c.discard_data();

        extent<2> ext(rows - shift * 2, cols - shift * 2);
        parallel_for_each(view, ext, [=](index<2> idx) restrict(amp)
        {
            index<2> idc(idx[0] + shift, idx[1] + shift);
            c[idc] = WeightedAverage(idc, a, shift);
        });
        c.synchronize();
    });
}

float WeightedAverage(index<2> idx, const array_view<const float, 2>& data, int shift) 
    restrict(amp)
{
    if (idx[1] < shift || idx[1] >= data.extent[1] - shift)
        return 0.0f;
    float max = fast_math::sqrtf((float)(shift * shift * 2));
    float avg = 0.0;
    float n = 0.0f;
    for (int i = -shift; i <= shift; ++i)
        for (int j = -shift; j <= shift; ++j)
        {
            int row = idx[0] + i;
            int col = idx[1] + i;
            float scale = 1 - fast_math::sqrtf((float)((i * i) * (j * j))) / max;
            avg += data(row,col) * scale;
            n += 1.0f;
        }
    avg /= n;
    return avg;
}

Да, вам нужно аннотировать сигнатуру функции с помощью restrict(amp) или restrict(cpu, amp), если вы хотите иметь возможность вызывать ту же функцию из кода ЦП. См. Документы MSDN по ограничению.

Другие вопросы по тегам