Определение структур в каркасе "Яблоки"
Я играю с Metal для iOS, делая небольшую игру. В одном из моих шейдеров ядра (в моих файлах.metal). Я определяю структуру для хранения некоторых метаданных для части игрового процесса.
Структура выглядит так:
struct ColorSetup {
float4 color;
float4 degradationColor;
float degradationRate;
};
Это прекрасно работает, но когда я пытаюсь добавить больше полей в мою структуру, например:
struct ColorSetup {
float4 color;
float4 degradationColor;
float4 threshholdColor;
float degradationRate;
};
Код плохо себя ведет и, кажется, не может использовать некоторые поля. На данный момент новые поля не используются. Моей первой мыслью было то, что это было связано с выравниванием памяти структуры. У меня сложилось впечатление, что компилятор добавит правильное заполнение, но все же попытался правильно выровнять размер структуры (упорядочив поля по убыванию и выровняв структуру по 48 и 64 байтам), но без каких-либо успех. Я также попытался использовать упакованные типы данных, чтобы избежать проблем с выравниванием, но безуспешно.
Я знаю, что логика верна, поскольку я написал ту же логику без использования структуры, а затем перенес ее на использование структуры для хранения данных с точно таким же поведением. Но в этот момент добавление любых полей нарушает его. Кроме того, сохранение исходной структуры, но с использованием упакованных типов данных также нарушает ее аналогичным образом.
struct ColorSetup {
packed_float4 color;
packed_float4 degradationColor;
float degradationRate;
};
Так что это определенно похоже на проблему с макетом памяти, но мне неясно, как ее решить, не обходя проблему.
Любые мысли или идеи, которые я могу попробовать?
Редактировать:
Данные не передаются в мой вычислительный шейдер через MTLBuffer, а просто определяются в постоянном пространстве памяти в файле.metal следующим образом:
constant ColorSetup redColor = {
.color = red,
.degradationColor = white,
.degradationRate = 0.0035
};
Изменить 2:
Попытка описать некоторые результаты и то, что на самом деле делает код.
Рассматриваемая функция, которая разбивает, - это метод, который предполагает затухание цветов на основе значений, представленных в этой структуре.
float4 degrade(float4 color, ColorSetup colorSetup, ColorLimit colorLimit) {
float4 targetColor = colorSetup.degradationColor;
float rate = colorSetup.degradationRate;
if (colorLimit.degradationThreshold.r < color.r && colorLimit.degradationThreshold.g < color.g && colorLimit.degradationThreshold.b < color.b) {
targetColor = colorSetup.degradationColor;
} else {
targetColor = colorSetup.color;
}
int r = (color.r - targetColor.r) < 0 ? 1 : -1;
int g = (color.g - targetColor.g) < 0 ? 1 : -1;
int b = (color.b - targetColor.b) < 0 ? 1 : -1;
float4 newColor = float4(color.r + float(r)*rate, color.g + float(g)*rate, color.b + float(b)*rate, 1);
return normalizeColor(newColor);
}
Эта функция работает, как и ожидалось, когда у меня есть структура, определенная как:
struct ColorSetup {
float4 color;
float4 degradationColor;
float degradationRate;
};
Если я добавлю к нему число с плавающей точкой (даже если я его нигде не читаю, и это не является частью какого-либо расчета. Это просто, чтобы попытаться выяснить, где находится ошибка).
struct ColorSetup {
float4 color;
float4 degradationColor;
float degradationRate;
float padding;
};
На этом этапе все еще работает просто отлично, если я не укажу новый float в конструкции как таковой.
constant ColorSetup redColor = {
.color = red,
.degradationColor = white,
.degradationRate = 0.0035,
};
Но если я сделаю это:
constant ColorSetup redColor = {
.color = red,
.degradationColor = white,
.degradationRate = 0.0035,
.padding = 0
};
Вышеуказанная функция перестает работать, и цвета больше не блекнут.
Еще одно интересное наблюдение, если я использую int вместо этого все работает:
struct ColorSetup {
float4 color;
float4 degradationColor;
float degradationRate;
int padding;
};