Изображение ядра Metal Compute в масштабе

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

   kernel void testCompute   (texture2d<half, access::read>  inputTexture  [[ texture(0) ]],
                   texture2d<half, access::write> outputTexture [[ texture(1) ]],
                   uint2 gid [[thread_position_in_grid]])
 {
    if ((gid.x >= inputTexture.get_width()) || (gid.y >= inputTexture.get_height())) {
    return;
}

   half4 inputColor = inputTexture.read(gid);

    half4 outputColor = half4(inputColor.r, 0.0, inputColor.b, 1.0);

    outputTexture.write(outputColor, gid);  
}

Предполагает ли приведенный выше вычислительный шейдер равный размер входной и выходной текстуры? Если я использую вершинный и фрагментный шейдер, я могу настроить сэмплер с filter :: linear, и выходная текстура будет масштабирована в соответствии с ее размером. Как добиться того же с помощью вычислительного шейдера?


person Deepak Sharma    schedule 13.04.2018    source источник


Ответы (1)


Вычислительный шейдер не делает никаких предположений о текстурах.

Код вашего приложения определяет размер сетки, над которой работает вычислительный шейдер при ее отправке. Сетка - понятие абстрактное. Это не обязательно связано ни с чем другим. Вам решать, как вы интерпретируете / придаете значение сетке.

Ваш шейдер вызывается один раз для каждой позиции в сетке, и позиция может быть предоставлена ​​шейдерной функции, как вы указали в параметре gid.

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

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

Чтобы выполнить это масштабирование позиции, вы можете использовать размеры двух текстур.

person Ken Thomases    schedule 13.04.2018
comment
По сути, я могу использовать образец вместо чтения, использовать нормализованную систему координат для доступа к текселям, и фильтрация будет простой. Итак, в чем разница между сэмплом и чтением с точки зрения производительности, а также в чем будет улучшение производительности, если я буду использовать вычислительный шейдер вместо вершинных / фрагментных шейдеров? - person Deepak Sharma; 13.04.2018
comment
Для очень простых вещей, таких как простые dowsamples, обычно используются фрагментные шейдеры - вы получаете бесплатный доступ ко многим вещам, которые вам нужно запускать вручную в вычислительных шейдерах. - person solidpixel; 17.04.2018
comment
@solidpixel Есть ли разница в использовании вычислительного шейдера и вызове .sample для текстуры вместо .read, чем в использовании фрагментного шейдера? - person Deepak Sharma; 27.04.2018
comment
Основная проблема с .read заключается в том, что он принимает целочисленные координаты. Если вы хотите уменьшить разрешение, вам нужно вручную прочитать 4 текселя и среднее значение в коде шейдера. Зачем беспокоиться? Просто используйте .sample и линейный фильтр, поддерживаемый оборудованием - при уменьшении масштаба 2: 1 по каждой оси просто поместите точку выборки между 4 текселями, которые вы хотите усреднить. - person solidpixel; 27.04.2018