İçeriğe atla

toprak.run/apple/metal/08-sayisal-uyumluluk

METAL SHADING LANGUAGE · BÖLÜM 8

Sayısal Uyumluluk

ASIL METİN Apple — Metal Shading Language Specification, Sürüm 4

Bu bölüm, Metal'in matematiksel işlemlerde doğruluk açısından kayan noktalı sayıları nasıl temsil ettiğini kapsar. Metal, IEEE 754 standardının bir alt kümesiyle uyumludur.

8.1 INF, NaN ve Denormal Sayılar

INF, tek duyarlıklı, yarı duyarlıklı ve brain kayan noktalı sayılar için desteklenmelidir.

NaN değerleri, tek duyarlıklı, yarı duyarlıklı ve brain kayan noktalı sayılar için desteklenmelidir (fast math devre dışıyken). Fast math etkinse, NaN veya INF (girdi ya da çıktı olarak) işleme davranışı tanımsızdır. Signaling NaN değerleri desteklenmez.

Aritmetik işlemlere girdi olarak verilen veya çıktı olarak üretilen denormal tek duyarlıklı, yarı duyarlıklı ya da brain kayan noktalı sayılar sıfıra yuvarlanabilir.

8.2 Yuvarlama Modu

Tek duyarlıklı, yarı duyarlıklı ve brain kayan noktalı işlemler için round ties to even veya round toward zero yuvarlama modlarından biri desteklenebilir.

8.3 Kayan Noktalı İstisnalar

Metal'de kayan noktalı istisnalar devre dışıdır.

8.4 ULP'ler ve Bağıl Hata

Tablo 8.1, tek duyarlıklı kayan noktalı temel aritmetik işlemlerinin ve matematik fonksiyonlarının ULP değerleri cinsinden verilen minimum doğruluğunu açıklar. Bir aritmetik işlemin ULP değerini hesaplamak için kullanılan referans değer, sonsuz hassasiyetteki sonuçtur.

Tablo 8.1. Tek Duyarlıklı Kayan Noktalı İşlemler ve Fonksiyonların Doğruluğu

Matematik fonksiyonu Minimum doğruluk
x + y Doğru yuvarlanmış
x - y Doğru yuvarlanmış
x * y Doğru yuvarlanmış
acos ≤ 4 ulp
acosh ≤ 4 ulp
asin ≤ 4 ulp
asinh ≤ 4 ulp
atan ≤ 5 ulp
atan2 ≤ 6 ulp
atanh ≤ 5 ulp
ceil Doğru yuvarlanmış
copysign 0 ulp
cos ≤ 4 ulp
cosh ≤ 4 ulp
cospi ≤ 4 ulp
exp ≤ 4 ulp
exp2 ≤ 4 ulp
exp10 ≤ 4 ulp
fabs 0 ulp
fdim Doğru yuvarlanmış
floor Doğru yuvarlanmış
fma Doğru yuvarlanmış
fmax 0 ulp
fmin 0 ulp
fmod 0 ulp
fract Doğru yuvarlanmış
frexp 0 ulp
ldexp Doğru yuvarlanmış
log10 ≤ 4 ulp
modf 0 ulp
nextafter 0 ulp
pow ≤ 16 ulp
powr ≤ 16 ulp
rint Doğru yuvarlanmış
round Doğru yuvarlanmış
rsqrt Doğru yuvarlanmış
sin ≤ 4 ulp
sincos ≤ 4 ulp
sinh ≤ 4 ulp
sinpi ≤ 4 ulp
sqrt Doğru yuvarlanmış
tan ≤ 6 ulp
tanpi ≤ 6 ulp
tanh ≤ 5 ulp
trunc Doğru yuvarlanmış

Tablo 8.2. Fast Math Etkinleştirildiğinde Tek Duyarlıklı İşlemler ve Fonksiyonların Doğruluğu

Matematik fonksiyonu Minimum doğruluk
x / y y alanı 2⁻¹²⁶ ile 2¹²⁶ arasındayken ≤ 2.5 ulp
acos(x) x alanı [-1, 1] içindeyken ≤ 5 ulp
acosh(x) log(x + sqrt(x * x − 1.0)) olarak uygulanır
asin(x) x alanı [-1, 1] ve
asinh(x) log(x + sqrt(x * x + 1.0)) olarak uygulanır
atan(x) ≤ 5 ulp
atan2(y, x) atan(y/x) ve ±M.PI.F kullanılarak parçalı uygulama
cosh(x) 0.5 * (exp(x) + exp(-x)) olarak uygulanır
exp(x) ≤ 3 + floor(fabs(2 * x)) ulp
exp2(x) ≤ 3 + floor(fabs(2 * x)) ulp
exp10(x) exp2(x * log2(10)) olarak uygulanır
cos(x) [-π, π] aralığında hata ≤ 2⁻¹³
cospi(x) [-1, 1] aralığında hata ≤ 2⁻¹³
log10(x) log2(x) * log10(2) olarak uygulanır
pow(x, y) exp2(y * log2(x)) olarak uygulanır; x = 0 ve y = 0 için tanımsız
powr(x, y) exp2(y * log2(x)) olarak uygulanır; x = 0 ve y = 0 için tanımsız
sinh(x) 0.5 * (exp(x) − exp(-x)) olarak uygulanır
sincos(x) sin(x) ve cos(x) için tanımlanan ULP değerleri
tan(x) sin(x) * (1.0 / cos(x)) olarak uygulanır
rsqrt ≤ 2 ulp
sqrt(x) özel durumlar doğru şekilde ele alınarak x * rsqrt(x) olarak uygulanır

ceil, copysign, fdim, floor, fma, fract, frexp, ilogb, ldexp, modf, rint, round ve trunc gibi ek fonksiyonlar belirtilen şekilde doğru yuvarlanmış veya 0 ulp doğruluğuna sahiptir.

8.5 Fast Math Davranışı

Her ne kadar bireysel matematik işlemlerinin ve fonksiyonlarının hassasiyeti Tablo 8.1–8.5'te belirtilmiş olsa da, fast math modundaki Metal derleyicisi (bkz. bölüm 1.6.5) kayan noktalı işlemlerin yeniden ilişkilendirilmesi gibi optimizasyonlar yapabilir. Bu optimizasyonlar sonuçları önemli ölçüde değiştirebilir.

Yeniden ilişkilendirme şu durumlara neden olabilir:

  • Sıfırın işaretini değiştirmek veya yok saymak
  • Argümanların ve sonuçların NaN veya ±INF olmadığını varsaymak
  • Alt taşma veya üst taşma oluşturmak ya da engellemek
  • Hassas yuvarlama davranışına dayanan kodları bozmak (örneğin (x + 2^52) - 2^52)

ULP Tanımı

Eğer x, ardışık iki sonlu kayan noktalı sayı a ve b arasında yer alan bir gerçek sayıysa (ve bunlardan birine eşit değilse), o zaman:

ulp(x) = |b − a|

Aksi halde ulp(x), x'e en yakın olan ve birbirine eşit olmayan iki sonlu kayan noktalı sayı arasındaki mesafedir. Ek olarak:

ulp(NaN) = NaN

Bir sonuç yuvarlamadan önce subnormal ise sıfıra yuvarlanabilir. İşlenen değerler sıfıra yuvarlanırsa, sıfırın işareti tanımsızdır.


8.6 Kayan Nokta ve Tamsayı İçin Dönüştürme Kuralları

Bir kayan nokta türünden bir tamsayıya dönüştürme yapılırken round toward zero yuvarlama modu kullanılır.

Kayan nokta veya tamsayı türlerinden kayan nokta türlerine yapılan dönüştürmeler şu yuvarlama modlarını kullanabilir:

  • round ties to even
  • round toward zero

Ek kurallar:

  • half ve bfloat türlerinden float türüne dönüşümler kayıpsızdır.
  • float türünden half veya bfloat türüne dönüşümler mantisayı round ties to even kullanarak yuvarlar.
  • float'tan half'a dönüştürme yapılırken oluşabilecek denormal sayılar sıfıra yuvarlanmayabilir.
  • NaN bir tamsayıya dönüştürülürse sonuçtaki tamsayı 0 olur.

8.7 Doku Adresleme ve Dönüştürme Kuralları

Aşağıdaki fonksiyonlara verilen doku koordinatları INF veya NaN olamaz:

  • sample
  • sample_compare
  • gather
  • gather_compare
  • read
  • write

Davranış kuralları:

  • Sınır dışı bir doku okuma işlemi, her bileşen için varsayılan değeri döndürür (bkz. bölüm 6.12).
  • Metal, sınır dışı doku yazma işlemlerini yok sayar.

Bir multisample resolve işlemi yapılırken bu dönüştürme kuralları uygulanmaz.


8.7.1 Normalize Edilmiş Tamsayı Piksel Veri Türleri İçin Dönüştürme Kuralları

Bu bölüm, normalize edilmiş tamsayı piksel veri türleri ile kayan nokta değerleri arasındaki dönüşümü açıklar.

8‑, 10‑ veya 16‑bit normalize edilmiş işaretsiz tamsayı piksel değerlerine sahip dokular için sample ve read fonksiyonları değerleri aşağıdaki aralıktaki normalize edilmiş kayan nokta değerlerine dönüştürür:

[0.0 … 1.0]

8‑ veya 16‑bit normalize edilmiş işaretli tamsayı değerlerine sahip dokular için dönüşüm aşağıdaki aralıktaki normalize edilmiş kayan nokta değerlerini üretir:

[-1.0 … 1.0]

Bu dönüştürme kurallarının hassasiyeti, belirtilen köşe durumları dışında ≤ 1.5 ulp olacak şekilde garanti edilir.

Tablo 8.6. Normalize Edilmiş Bir Float Değerine Dönüştürme

Kaynak tür Dönüştürme kuralı Köşe durumları
1‑bit normalize edilmiş işaretsiz tamsayı float(c) 0 → 0.0, 1 → 1.0
2‑bit normalize edilmiş işaretsiz tamsayı float(c) / 3.0 0 → 0.0, 3 → 1.0
4‑bit normalize edilmiş işaretsiz tamsayı float(c) / 15.0 0 → 0.0, 15 → 1.0
5‑bit normalize edilmiş işaretsiz tamsayı float(c) / 31.0 0 → 0.0, 31 → 1.0
6‑bit normalize edilmiş işaretsiz tamsayı float(c) / 63.0 0 → 0.0, 63 → 1.0
8‑bit normalize edilmiş işaretsiz tamsayı float(c) / 255.0 0 → 0.0, 255 → 1.0
10‑bit normalize edilmiş işaretsiz tamsayı float(c) / 1023.0 0 → 0.0, 1023 → 1.0
16‑bit normalize edilmiş işaretsiz tamsayı float(c) / 65535.0 0 → 0.0, 65535 → 1.0
8‑bit normalize edilmiş işaretli tamsayı max(-1.0, float(c)/127.0) -128 ve -127 → -1.0; 0 → 0.0; 127 → 1.0
16‑bit normalize edilmiş işaretli tamsayı max(-1.0, float(c)/32767.0) -32768 ve -32767 → -1.0; 0 → 0.0; 32767 → 1.0

Normalize edilmiş işaretsiz tamsayı biçimlerine sahip dokular için write fonksiyonları kayan nokta değerlerini tekrar 8‑ veya 16‑bit işaretsiz tamsayılara dönüştürür.

Normalize edilmiş işaretli tamsayı biçimlerine sahip dokular için write fonksiyonları kayan nokta değerlerini 8‑ veya 16‑bit işaretli tamsayılara dönüştürür.

Fast math'in dönüştürme işlemlerinin doğruluğunu değiştirmediğine dikkat edilmelidir.

NaN değerleri sıfıra dönüştürülür.

Kayan nokta değerlerinden normalize edilmiş tamsayı değerlere dönüşümler Tablo 8.7'de listelendiği şekilde gerçekleştirilir.

Tablo 8.7. Kayan Noktadan Normalize Edilmiş Tamsayı Değerine Dönüştürme

1‑bit normalize edilmiş işaretsiz tamsayı

x = min(max(f, 0.0), 1.0)
i0:0 = intRTNE(x)

2‑bit normalize edilmiş işaretsiz tamsayı

x = min(max(f * 3.0, 0.0), 3.0)
i1:0 = intRTNE(x)

4‑bit normalize edilmiş işaretsiz tamsayı

x = min(max(f * 15.0, 0.0), 15.0)
i3:0 = intRTNE(x)

5‑bit normalize edilmiş işaretsiz tamsayı

x = min(max(f * 31.0, 0.0), 31.0)
i4:0 = intRTNE(x)

6‑bit normalize edilmiş işaretsiz tamsayı

x = min(max(f * 63.0, 0.0), 63.0)
i5:0 = intRTNE(x)

8‑bit normalize edilmiş işaretsiz tamsayı

x = min(max(f * 255.0, 0.0), 255.0)
i7:0 = intRTNE(x)

10‑bit normalize edilmiş işaretsiz tamsayı

x = min(max(f * 1023.0, 0.0), 1023.0)
i9:0 = intRTNE(x)

Yarı duyarlıklı kayan noktalı piksel renk değerlerine sahip dokular için half'tan float'a dönüşümler kayıpsızdır. Float'tan half'a dönüşümler mantisayı round ties to even yuvarlama modunu kullanarak yuvarlar. Float'tan half'a dönüştürme sırasında oluşabilecek half veri türüne ait denormal sayılar sıfıra yuvarlanmayabilir. Bir float NaN değeri half türünde uygun bir NaN'e dönüştürülebilir veya sıfıra yuvarlanabilir. Bir float INF değeri half türünde uygun bir INF'e dönüştürülmelidir.

8.7.3 Tek Duyarlıklı Kayan Noktalı Piksel Veri Türü İçin Dönüştürme Kuralları

Tek duyarlıklı kayan noktalı piksel renk değerlerine sahip dokuların okunması ve yazılması için aşağıdaki kurallar geçerlidir:

  • NaN değerleri bir NaN değerine dönüştürülebilir veya sıfıra yuvarlanabilir.
  • INF değerleri korunmalıdır.
  • Denormal sayılar sıfıra yuvarlanabilir.
  • Diğer tüm değerler korunmalıdır.

8.7.4 10‑ ve 11‑bit Kayan Noktalı Piksel Veri Türü İçin Dönüştürme Kuralları

Bu kayan nokta biçimleri üs için 5 bit kullanır; 10‑bit kayan nokta türlerinde 5 bit mantisa, 11‑bit kayan nokta türlerinde 6 bit mantisa bulunur ve her iki tür için ek bir gizli bit vardır. İşaret biti yoktur. 10‑ ve 11‑bit kayan nokta türleri denormal değerleri korur.

  • Üs ve mantisa 0 ise kayan nokta değeri 0.0 olur.
  • Üs 31 ve mantisa != 0 ise sonuçtaki kayan nokta değeri NaN olur.
  • Üs 31 ve mantisa 0 ise sonuçtaki kayan nokta değeri pozitif sonsuzluk olur.
  • 0 <= exponent <= 31 ise kayan nokta değeri şöyledir:
2 ^ (exponent - 15) * (1 + mantissa / N)
  • Üs 0 ve mantisa != 0 ise kayan nokta değeri bir denormal sayıdır:
2 ^ (exponent - 14) * (mantissa / N)

Mantisa 5 bit ise N = 32 olur. Mantisa 6 bit ise N = 64 olur.

10‑ veya 11‑bit kayan noktalı piksel veri türünden half veya tek duyarlıklı kayan nokta değerine dönüşüm kayıpsızdır. Half veya tek duyarlıklı kayan nokta değerinden 10‑ veya 11‑bit kayan nokta değerine dönüşüm ≤ 0.5 ULP olmalıdır. Bu kayan nokta türleri için sıfırdan küçük bir değerle sonuçlanan herhangi bir işlem sıfıra sınırlandırılır.

8.7.5 5‑bit Üslü 9‑bit Kayan Noktalı Piksel Veri Türü İçin Dönüştürme Kuralları

RGB9E5_SharedExponent ortak üs kullanan kayan nokta biçimi üs için 5 bit ve mantisa için 9 bit kullanır. İşaret biti yoktur.

Bu biçimden half veya tek duyarlıklı kayan nokta değerine dönüşüm kayıpsızdır ve her renk kanalı için şu şekilde hesaplanır:

2 ^ (shared exponent – 15) * (mantissa / 512)

Half veya tek duyarlıklı kayan noktalı RGB renk değerinden bu biçime dönüşüm aşağıdaki şekilde gerçekleştirilir. Burada:

  • N, bileşen başına mantisa bit sayısıdır (9)
  • B, üs bias değeridir (15)
  • Emax, izin verilen maksimum biaslı üs değeridir (31)

Sınırlandırma

rc = max(0, min(sharedexpmax, r))
gc = max(0, min(sharedexpmax, g))
bc = max(0, min(sharedexpmax, b))

En büyük sınırlandırılmış bileşeni belirleme

maxc = max(rc, gc, bc)

Ön paylaşılmış üs hesaplama

expp = max(-B - 1, floor(log2(maxc)) + 1 + B)

İyileştirilmiş paylaşılmış üs hesaplama

maxs = floor((maxc / 2^(expp - B - N) + 0.5f))
exps = expp, if 0 <= maxs < 2^N
exps = expp + 1, if maxs = 2^N

Tamsayı mantisaları hesaplama

rs = floor(rc / 2^(exps - B - N) + 0.5f)
gs = floor(gc / 2^(exps - B - N) + 0.5f)
bs = floor(bc / 2^(exps - B - N) + 0.5f)

Burada:

sharedexpmax = ((2^N - 1) / 2^N) * 2^(Emax - B)

Half veya tek duyarlıklı kayan noktalı renk değerlerinden MTLPixelFormatRGB9E5Float ortak üs kayan nokta değerine dönüşüm ≤ 0.5 ULP doğruluğundadır.

8.7.6 İşaretli ve İşaretsiz Tamsayı Piksel Veri Türleri İçin Dönüştürme Kuralları

8‑ veya 16‑bit işaretli ya da işaretsiz tamsayı piksel değerlerine sahip dokular için doku örnekleme ve okuma fonksiyonları işaretli veya işaretsiz 32‑bit tamsayı piksel değeri döndürür. Bu bölümde açıklanan dönüşümlerin doğru şekilde doyurulmuş (saturated) olması gerekir.

Bu tamsayı dokularına yapılan yazma işlemleri Tablo 8.8'de listelenen dönüşümlerden birini gerçekleştirir.

Tablo 8.8. Tamsayı Piksel Veri Türleri Arasındaki Dönüşüm

32‑bit işaretli tamsayı → 8‑bit işaretli tamsayı

result = convert_char_saturate(val)

32‑bit işaretli tamsayı → 16‑bit işaretli tamsayı

result = convert_short_saturate(val)

32‑bit işaretsiz tamsayı → 8‑bit işaretsiz tamsayı

result = convert_uchar_saturate(val)

32‑bit işaretsiz tamsayı → 16‑bit işaretsiz tamsayı

result = convert_ushort_saturate(val)

Bir sRGB dokusundan örnekleme yapılırken sRGB uzayından doğrusal uzaya dönüşüm otomatik olarak gerçekleştirilir. sRGB'den doğrusal RGB'ye dönüşüm, sampler içinde belirtilen filtre uygulanmadan önce yapılır. Doku bir alpha kanalı içeriyorsa alpha verisi doğrusal renk uzayında saklanır.

Bir sRGB dokusuna yazılırken doğrusal uzaydan sRGB uzayına dönüşüm otomatik olarak yapılır. Doku bir alpha kanalı içeriyorsa alpha verisi doğrusal renk uzayında saklanır.

sRGB → Doğrusal RGB Dönüşümü

Normalize edilmiş 8‑bit işaretsiz tamsayı sRGB renk değeri bir kayan noktalı doğrusal RGB renk değerine (c) dönüştürülürken:

if (c <= 0.04045)
    result = c / 12.92;
else
    result = powr((c + 0.055) / 1.055, 2.4);

Yukarıdaki dönüşümün hassasiyeti, result değerinin tekrar normalleştirilmemiş bir sRGB değerine (8‑bit işaretsiz tamsayıya yuvarlama yapılmadan) dönüştürülmesiyle elde edilen sonsuz hassasiyetteki kayan noktalı değer ile orijinal sRGB 8‑bit işaretsiz tamsayı değeri arasındaki farkın ≤ 0.5 olmasını garanti etmelidir.

Doğrusal RGB → sRGB Dönüşümü

Bir doğrusal RGB kayan noktalı renk değeri (c) değerini normalize edilmiş 8‑bit işaretsiz tamsayı sRGB değerine dönüştürmek için:

if (isnan(c)) c = 0.0;
if (c > 1.0)
    c = 1.0;
else if (c < 0.0)
    c = 0.0;
else if (c < 0.0031308)
    c = 12.92 * c;
else
    c = 1.055 * powr(c, 1.0/2.4) - 0.055;

// Tamsayı ölçeğine dönüştür
c = c * 255.0;

// Tamsayıya dönüştür
c = c + 0.5;

// Ondalık kesir kısmını at
// Kalan kayan noktalı (tamsayı değerli) değeri bir tamsayıya dönüştür

Yukarıdaki dönüşümün hassasiyeti korunmalıdır.