METAL SHADING LANGUAGE · BÖLÜM 5
Fonksiyon ve Değişken Bildirimleri
ASIL METİN Apple — Metal Shading Language Specification, Sürüm 4
Bu bölüm, fonksiyonları, argümanları ve değişkenleri nasıl bildirdiğinizi açıklar. Ayrıca fonksiyonlara, argümanlara ve değişkenlere kısıtlamalar belirtmek için öznitelikleri nasıl sıklıkla kullandığınızı da ayrıntılı biçimde ele alır.
5.1 Fonksiyonlar
[[vertex]]veyavertex(Bkz. bölüm 5.1.1)[[fragment]]veyafragment(Bkz. bölüm 5.1.2)[[kernel]]veyakernel(Bkz. bölüm 5.1.3)[[visible]](Bkz. bölüm 5.1.4)[[stitchable]](Bkz. bölüm 5.1.5)[[intersection(…)]](Bkz. bölüm 5.1.6)[[object]](Bkz. bölüm 5.1.7)[[mesh]](Bkz. bölüm 5.1.8)
namespace outer {
[[kernel]] void functionA() { … }
namespace inner {
[[kernel]] void functionB() { … }
}
}
Metal 1 ve sonrası, tüm işletim sistemleri için kernel, vertex ve fragment özniteliklerini destekler. Metal 2.3 ve sonrası C++ özniteliklerini destekler.
Bir fonksiyonu Metal API tarafından erişilebilir hale getirmek için, fonksiyonun başına bu fonksiyon özniteliklerinden birini ekleyin; bu işlem onu nitelikli bir fonksiyon haline getirir. Kernel, vertex ve fragment fonksiyonları birbirlerini çağıramaz; aksi halde derleme hatası oluşur. Ancak [[visible]] özniteliğini kullanan diğer fonksiyonları çağırabilirler. Ayrıca intersect() çağrısı yaparak [[intersection(…)]] özniteliğine sahip fonksiyonları da çağırabilirler (bkz. bölüm 6.18.2).
Metal 2.1 ve daha önceki sürümlerde Metal derleyicisi, kernel, vertex ve fragment fonksiyonları için namespace tanımlayıcılarını yok sayar. Metal 2.2 ve sonrasında ise bir namespace içinde nitelikli bir fonksiyon bildirirseniz, Metal Framework API içinde ona her başvurduğunuzda fonksiyon adının yanında namespace tanımlayıcısını da eklemeniz gerekir. Bu örnek, farklı namespace'ler içinde iki kernel fonksiyonu bildirir.
Bir namespace içindeki fonksiyona başvurmak için fonksiyon adının önüne namespace tanımlayıcısını ve ardından iki nokta üst üste (::) ekleyin.
Benzer şekilde, iç içe namespace içindeki bir fonksiyona başvururken fonksiyon adının önüne tüm namespace'leri sırasıyla ekleyin ve her birini iki nokta üst üste ile ayırın.
5.1.1 Vertex Fonksiyonları
vertex (veya Metal 2.3 ve sonrasında [[vertex]]) özniteliğini yalnızca bir grafik fonksiyonu için bildirebilirsiniz. Metal, vertex akışındaki her vertex için bir vertex fonksiyonu çalıştırır ve vertex başına çıktı üretir.
vertex void my_vertex_func(…) { … }
[[vertex]] void vertex_func2(…) { … }
Bir vertex fonksiyonu için dönüş türü, fonksiyonun ürettiği çıktıyı tanımlar. Vertex fonksiyonu çıktı üretmiyorsa void döndürmelidir ve yalnızca rasterization devre dışı bırakılmış bir render pipeline içinde kullanılabilir.
5.1.1.1 Tessellation Sonrası Vertex Fonksiyonları
Tüm işletim sistemleri: Metal 1.2 ve sonrası tessellation sonrası vertex fonksiyonlarını (patch özniteliği) destekler.
Tessellation sonrası vertex fonksiyonunun girdileri şunları içerir:
- Patch başına veri
- Patch kontrol noktası verisi
- Tessellator aşaması çıktısı (patch üzerindeki normalize edilmiş vertex konumu)
Tessellation sonrası vertex fonksiyonu, sabit işlevli tessellator tarafından patch üzerinde üretilen her yüzey örneği için vertex verisini hesaplar.
Tessellation sonrası vertex fonksiyonu, tessellated üçgenler için nihai vertex verisini üretir. Örneğin, işlenen geometriye ek ayrıntı eklemek için (örneğin displacement mapping değerleri), tessellation sonrası vertex fonksiyonu bir dokuyu örnekleyerek vertex konumunu bir displacement değeri ile değiştirebilir.
Tessellation sonrası vertex fonksiyonu çalıştıktan sonra tessellated ilkel öğeler rasterize edilir.
Tessellation sonrası vertex fonksiyonu, normal vertex fonksiyonu özniteliği kullanılarak tanımlanan bir vertex fonksiyonudur.
macOS için [[patch(patch-type, N)]] özniteliği hem patch türünü (patch-type ya quad ya da triangle) hem de patch içindeki kontrol noktası sayısını belirtmelidir (N değeri 0 ile 32 arasında olmalıdır). iOS için patch-type belirtmek zorunludur ancak kontrol noktası sayısı isteğe bağlıdır.
Eğer tessellation sonrası vertex fonksiyonunda kontrol noktası sayısı belirtilmişse, bu sayı drawPatches veya drawIndexedPatches API’sine sağlanan kontrol noktası sayısıyla aynı olmalıdır.
Örnek:
[[patch(quad)]]
[[vertex]] vertex_output
my_post_tessellation_vertex(…)
{ … }
[[patch(quad, 16)]]
[[vertex]] vertex_output
my_bezier_vertex(…)
{ … }
5.1.2 Fragment Fonksiyonları
[[fragment]]
void my_fragment_func(…)
{ … }
fragment
void my_fragment_func2(…)
{ … }
[[early_fragment_tests]]
fragment float4
my_fragment(…)
{ … }
fragment veya (Metal 2.3’ten itibaren) [[fragment]] özniteliğini yalnızca bir grafik fonksiyonu için bildirebilirsiniz. Metal, fragment akışındaki her fragment ve onunla ilişkili veriler için bir fragment fonksiyonu çalıştırır ve fragment başına çıktı üretir.
Grafik fonksiyonları için dönüş türü, fonksiyonun ürettiği çıktının vertex başına mı yoksa fragment başına mı olduğunu belirler. Eğer fragment fonksiyonu çıktı üretmiyorsa void döndürür.
Fragment fonksiyonu çalıştırılmadan önce fragment testlerinin gerçekleştirilmesini istemek için fragment fonksiyonu ile birlikte [[early_fragment_tests]] fonksiyon özniteliğini kullanın.
[[early_fragment_tests]] özniteliği ile bildirilen fragment fonksiyonunun dönüş türü bir depth veya stencil değeri içeriyorsa bu bir hatadır; yani dönüş türü [[depth(depth_argument)]] veya [[stencil]] özniteliği ile bildirilen bir öğe içeriyorsa hata oluşur.
Ayrıca fragment fonksiyonu olmayan herhangi bir fonksiyon ile [[early_fragment_tests]] özniteliğini kullanmak da hatadır.
5.1.3 Compute Fonksiyonları (Kernel)
[[max_total_threads_per_threadgroup(x)]]
kernel void my_kernel(…)
{ … }
Bir compute fonksiyonu (kernel olarak da adlandırılır), 1‑, 2‑ veya 3 boyutlu bir ızgara üzerinde çalıştırılan veri paralel bir fonksiyondur.
[[kernel]]
void my_kernel(…) { … }
kernel
void my_kernel2(…) { … }
kernel veya [[kernel]] özniteliği ile bildirilen fonksiyonlar void döndürmelidir.
Bir kernel fonksiyonu ile [[max_total_threads_per_threadgroup]] fonksiyon özniteliğini kullanarak threadgroup başına maksimum thread sayısını belirtebilirsiniz. Değer 32 bit içine sığmalıdır.
Eğer [[max_total_threads_per_threadgroup]] değeri [MTLDevice maxThreadsPerThreadgroup] özelliğinden büyükse compute pipeline durumunun oluşturulması başarısız olur.
Metal 4 ve sonrasında bir kernel fonksiyonu ile [[required_threads_per_threadgroup]] fonksiyon özniteliğini kullanarak threadgroup başına thread sayısını belirtebilirsiniz. Değer 32 bit içine sığmalıdır. Eğer [[required_threads_per_threadgroup]] değeri ayarlanmışsa ve [MTLDevice requiredThreadsPerThreadgroup] özelliği de ayarlanmışsa, bu değerlerin aynı olması gerekir; aksi halde compute pipeline durumunun oluşturulması başarısız olur.
Visible Fonksiyonlar
[[visible]] özniteliğine sahip bir fonksiyon Metal framework API’den görünür durumdadır; yani onun için bir MTLFunction nesnesi elde edebilirsiniz.
Bir visible fonksiyonun adresini almak ve görünür bir fonksiyon işaretçisi elde etmek geçerlidir. Görünür fonksiyon işaretçilerini visible_function_table türü ile kullanabilirsiniz (bölüm 2.15). Diğer fonksiyonlar doğrudan bir visible fonksiyonu çağırabilir.
Bir visible fonksiyonun, diğer nitelikli fonksiyonlar gibi, kendi çeviri birimine ayrıldığını unutmayın. Bir fonksiyon doğrudan bir visible fonksiyonu çağırdığında onu pipeline descriptor içinde geçirin.
[[visible]] float my_visible(device int *data, int data_offset) { … }
Stitchable Fonksiyonlar
[[stitchable]] özniteliğine sahip bir fonksiyon MTLFunctionStitchingGraph içinde kullanılabilir. [[stitchable]] özniteliği [[visible]] anlamını da içerir; yani stitchable fonksiyonlar visible fonksiyonların kullanılabildiği her yerde kullanılabilir.
Derleyici stitchable fonksiyonlar için ek metadata üretir, böylece bu fonksiyonlar MTLFunctionStitchingGraph içinde kullanılabilir. Bu metadata fonksiyonun kod boyutunu artırır.
[[stitchable]] float my_func(device float *data, texture2d<float> tex) { … }
Tüm işletim sistemleri: Metal 2.4 ve sonrası [[stitchable]] fonksiyonlarını destekler.
Intersection Fonksiyonları
Tüm işletim sistemleri: Metal 2.3 ve sonrası [[intersection(primitive_type, intersection_tags…)]] fonksiyonlarını destekler.
Bu öznitelik kullanılarak ışın izleme (ray tracing) için özel bir intersection fonksiyonu bildirebilirsiniz. Shader intersect() çağırdığında (bkz. bölüm 6.18) Metal intersection fonksiyonlarını çağırarak olası bir ışın kesişiminin geçerli olup olmadığını veya gezinmenin devam edip etmeyeceğini belirler.
Intersection fonksiyonları yeni ışınlar başlatamaz.
Intersection Fonksiyonu Primitive Türleri
| Primitive türü | Açıklama |
|---|---|
triangle |
Varsayılan üçgen kesişim testini genişleten bir intersection fonksiyonunu belirtir. |
bounding_box |
Bir ışın bir bounding box ile kesiştiğinde çalışan bir intersection fonksiyonunu belirtir. |
curve |
Metal 3.1 ve sonrasında desteklenir. Varsayılan eğri kesişim testini genişletir. |
Örnek:
bool triangleIntersectionFunction(...) { … }
primitive_type ve intersection_tags, izin verilen giriş ve çıkış özniteliklerini kontrol eder (bkz. Bölüm 5.2.3.7).
Kısıtlamalar:
deviceveconstantadres alanlarından gelen buffer argümanları desteklenir.- Texture argümanları doğrudan desteklenmez, ancak texture’lar bir argument buffer kullanılarak geçirilebilir.
- Threadgroup belleği desteklenmez.
threadgroup_barriervesimdgroup_barrierdesteklenmez; kullanılması tanımsız davranışa yol açar.- Intersection fonksiyonları, intersection işlemini başlatan thread ile aynı SIMD‑group içinde çalışabilir veya çalışmayabilir.
Eğer acceleration structure traversal bir prosedürel box primitive bulur ve intersection fonksiyonu bir triangle tester ise (veya tam tersi), davranış tanımsızdır.
Object Fonksiyonları
[[object]] özniteliğine sahip bir fonksiyon mesh pipeline içinde bir object fonksiyonudur. Bir object fonksiyonu, 1‑, 2‑ veya 3 boyutlu bir compute ızgarası üzerinde çalışan veri paralel bir fonksiyondur ve veri payload’u ile ikinci bir mesh aşamasına compute ızgaraları başlatabilir.
Object fonksiyonları void döndürmelidir.
[[payload]] özniteliği, mesh shader’a salt okunur buffer olarak aktarılan bir buffer’ı etiketler ve fonksiyon başına yalnızca bir kez belirtilebilir.
Threadgroup başına maksimum thread sayısını belirtmek için [[max_total_threads_per_threadgroup]] fonksiyon özniteliğini kullanabilirsiniz (32 bit değer).
Ayrıca mesh grid başına maksimum threadgroup sayısını belirtmek için [[max_total_threadgroups_per_mesh_grid(size)]] kullanılabilir.
Örnek:
#define kMeshThreadgroups 32
struct ObjectOutput {
// Kullanıcı tanımlı payload; her mesh threadgroup için bir giriş.
// Bu bir dizidir çünkü veri mesh grid tarafından paylaşılır.
float value[kMeshThreadgroups];
};
[[object, max_total_threadgroups_per_mesh_grid(kMeshThreadgroups)]]
void objectShader(uint threadgroup_size [[threads_per_threadgroup]],
uint lane [[thread_index_in_threadgroup]],
object_data ObjectOutput& output [[payload]],
mesh_grid_properties mgp)
{ … }
Tüm işletim sistemleri: Metal 3 ve sonrası [[object]] fonksiyonlarını destekler.
Mesh Fonksiyonları
[[mesh]] özniteliğine sahip bir fonksiyon mesh pipeline içinde bir mesh fonksiyonudur. Bir mesh fonksiyonu, rasterization pipeline’a geometrinin bir bölümünü temsil eden bir mesh nesnesi isteğe bağlı olarak aktarabilen veri paralel bir fonksiyondur. Eğer hiçbir mesh nesnesi aktarılmazsa rasterization devre dışı bırakılır.
Mesh fonksiyonları void döndürmelidir.
Threadgroup başına maksimum thread sayısını belirtmek için mesh fonksiyonu ile birlikte [[max_total_threads_per_threadgroup]] özniteliğini kullanabilirsiniz.
Örnek:
struct vertex_t {
float4 clip_pos [[position]];
float3 world_pos;
float3 color;
// diğer kullanıcı tanımlı özellikler
};
struct primitive_t {
float3 normal;
};
// Bir küpü dışa aktarabilen bir mesh bildirimi.
using cube_mesh_t = metal::mesh<vertex_t, primitive_t,
8, // köşeler
6*2, // yüzler
metal::topology::triangle>;
struct view_info_t {
float4x4 view_proj;
};
struct cube_info_t {
float4x3 world;
float3 color;
};
[[mesh, max_total_threads_per_threadgroup(12)]]
void cube_stage(cube_mesh_t output,
const object_data cube_info_t &cube [[payload]],
constant view_info_t &view [[buffer(0)]],
uint gid [[threadgroup_position_in_grid]],
uint lane [[thread_index_in_threadgroup]])
{ … }
Tüm işletim sistemleri: Metal 3 ve sonrası [[mesh]] fonksiyonlarını destekler.
Tile Shading Fonksiyonları
Bir tile shading fonksiyonu, grafik işlemleriyle birlikte satır içi çalışabilen ve Tile‑Based Deferred Rendering (TBDR) mimarisinden yararlanabilen özel bir compute kernel veya fragment fonksiyonu türüdür.
TBDR ile komutlar büyük bir liste birikene kadar tamponda tutulur. Donanım framebuffer’ı tile’lara böler ve her tile içinde yalnızca görünür olan primitive’leri işler.
Tile shading fonksiyonları, render işleminin ortasında compute işlemlerinin gerçekleşmesine izin verir; böylece bellek gidiş‑gelişleri azalır ve yüksek bant genişliğine sahip yerel bellek kullanılır.
Bir tile fonksiyonu, dispatch adı verilen bir thread kümesi başlatır. Bu thread’ler threadgroup’lar ve grid’ler halinde düzenlenir. Thread’ler bir render pass içinde herhangi bir noktada ve gerektiği kadar sık başlatılabilir.
Tile fonksiyonları render işlemleriyle senkronize çalışır: Bir tile fonksiyonu, kendisinden önceki tüm draw çağrıları tamamlanmadan çalışmaz ve sonraki draw çağrıları da tile fonksiyonu bitmeden çalışmaz.
iOS: Metal 2 ve sonrası tile fonksiyonlarını destekler.
macOS: Metal 2.3 ve sonrası tile fonksiyonlarını destekler.
GPU’lar her tile’ı ve her dispatch’i her zaman tamamlanana kadar işler. Bir sonraki tile işlenmeden önce, bir tile için tüm draw ve dispatch işlemleri gönderim sırasında başlatılır.
Tile fonksiyonları 32 KB threadgroup belleğine erişebilir. Bu bellek imageblock depolama ve threadgroup depolama arasında bölünebilir. (Threadgroup bellek boyutu hakkında daha fazla bilgi için bkz. bölüm 4.4.) Imageblock boyutu tile genişliğine, tile yüksekliğine ve her örneğin bit derinliğine bağlıdır. Render pass ekleri (örtük imageblock düzeni kullanır; bkz. bölüm 5.6.3.1) veya fonksiyon içinde bildirilen yapılar (açık imageblock düzeni kullanır; bkz. bölüm 5.6.3.2) örneklerin bit derinliğini belirler. Kernel fonksiyonlarının threadgroup_imageblock adres alanını nasıl kullandığı hakkında daha fazla bilgi için bkz. bölüm 4.5.
5.1.10 Host Name Özniteliği
Tüm işletim sistemleri: Metal 2.2 ve sonrası host name özniteliğini destekler.
Metal 2.2 ve sonrasında, Metal Framework API’nin nitelikli bir fonksiyona başvurmak için kullandığı varsayılan adı geçersiz kılabilirsiniz. Fonksiyon bildirimine [[host_name(name)]] özniteliğini ekleyin; burada name, Metal Framework API’nin fonksiyon adına başvurmak için kullanacağı string literal değeridir. Farklı fonksiyonlara aynı adı verirseniz derleyici derleme zamanında hata üretir.
Örneğin:
// Metal API adı abc
[[host_name("abc")]] [[kernel]] void funcA() {}
// Metal API adı xyz
[[host_name("xyz")]] [[kernel]] void funcX() {}
5.1.11 Template Nitelikli Fonksiyonlar
Tüm işletim sistemleri: Metal 2.2 ve sonrası template nitelikli fonksiyonları destekler.
Metal 2.2 ve sonrasında, nitelikli fonksiyon (örneğin vertex, fragment, visible ve kernel fonksiyonları) bildirimleri için şablonlar kullanabilirsiniz. Derleyiciyi belirli bir özelleştirme için kod üretmeye zorlamak amacıyla şablonu açıkça örneklemeniz gerekir.
Örnek:
template<typename T>
kernel void bar(device T *x) { … }
// [T = int] ile bar<T>'nin açık özelleştirmesi
template kernel void bar(device int *);
Bir özelleştirme için farklı bir ad sağlamak amacıyla [[host_name(name)]] özniteliği kullanılmadıkça derleyici tüm özelleştirmelere aynı adı verir.
template [[host_name("bar_int")]] kernel void bar(device int *);
// [T = float] ile bar<T>'nin açık özelleştirmesi
// host_name "bar_float"
template [[host_name("bar_float")]] kernel void bar(device float *);
5.1.12 Kullanıcı Açıklama Özniteliği
Tüm OS: Metal 4 ve sonrasında kullanıcı açıklama özniteliği desteklenir.
Bir nitelikli fonksiyonu bir ad ile açıklayabilir ve Metal Framework yansıma API’sini kullanarak bu adı arayabilirsiniz. Bir fonksiyonla ilişkilendirmek istediğiniz açıklama string olmak üzere, nitelikli bir fonksiyona [[user_annotation("string")]] özniteliğini ekleyin.
user_annotation özniteliğini şablonlu bir nitelikli fonksiyona eklediğinizde, bu özelleştirme üzerinde bir user_annotation özniteliği kullanarak geçersiz kılmadığınız sürece tüm örneklemeler bu açıklamayı devralır.
Örnek:
[[user_annotation("basecase"), kernel]] void funcB() { … }
template<typename T> [[user_annotation("Tcase"), kernel]]
void funcTmpl(device T *x) { … }
// user_annotation'dan devral
template [[host_name("funcImplInt"), kernel]]
void funcImpl(device int* x) { … }
// user_annotation'ı geçersiz kıl
template [[host_name("funcImplFloat"),
user_annotation("FPoverride"),
kernel]]
void funcImpl(device float* x) { … }
funcB için Metal Framework API kullanılarak açıklama arandığında basecase değeri elde edilir. funcImplInt için Tcase, funcImplFloat için ise FPoverride değeri elde edilir.
5.2 Fonksiyon Argümanları ve Değişkenler
Grafik (vertex veya fragment) ve kernel fonksiyonlarına yönelik çoğu giriş ve çıkış argümanlar aracılığıyla aktarılır. (Sabit adres alanında başlatılmış değişkenler ve program kapsamı içinde bildirilen sampler'lar argüman olarak geçirilmesi gerekmeyen giriş ve çıkışlardır.)
Metal 3.1 ve sonrasında, kernel, mesh ve object shader'lar için program kapsamı içinde bildirilen yerleşik giriş değişkenleri sağlanır; böylece bunları argüman olarak geçirmek gerekmez. Bu durum, bunları bir dinamik kütüphanede veya ayrı derlenmiş bir ikili fonksiyonda kullanmadığınız sürece geçerlidir.
Metal 3.2 ve sonrasında, Apple silicon için yerleşik giriş değişkenleri bir dinamik kütüphanede veya ayrı derlenmiş bir ikili fonksiyonda da kullanılabilir.
Metal 3.2 ve sonrasında, program kapsamında device, constant ve threadgroup buffer'lar, texture'lar ve sampler'lar bildirebilirsiniz (bkz. bölüm 5.9). Bunları bir shader içinde argüman olarak geçirirken olduğu gibi, farklı global değişkenlerin alias yapmadığını varsayamazsınız. Metal bunları otomatik olarak ayarlayamadığından bağlama indekslerini belirtmeniz gerekir.
Olası argüman/kaynak türleri şunlardır:
- Device buffer — device adres alanındaki herhangi bir veri türüne işaretçi veya referans (bkz. bölüm 2.8).
- Constant buffer — constant adres alanındaki herhangi bir veri türüne işaretçi veya referans (bkz. bölüm 2.8).
- Bir texture nesnesi (bkz. bölüm 2.9) veya texture dizisi.
- Bir
texture_buffernesnesi (bkz. bölüm 2.9.1) veya texture buffer dizisi. - Bir sampler nesnesi (bkz. bölüm 2.10) veya sampler dizisi.
- Bir threadgroup içinde iş parçacıkları arasında paylaşılan buffer — yalnızca kernel fonksiyonlarının argümanı olarak kullanılabilen
threadgroupadres alanındaki bir türe işaretçi. - Bir imageblock (bkz. bölüm 2.11).
- Bir argument buffer (bkz. bölüm 2.13).
- Kernel fonksiyonları için bir visible function table (bkz. bölüm 2.15). Metal 2.4 ve sonrasında visible function table'lar grafik fonksiyonlarında da kullanılabilir.
- Kernel fonksiyonları için bir intersection function table (bkz. bölüm 2.17.3).
- Intersection fonksiyonları için bir acceleration structure (bkz. bölüm 6.18.1).
- Bir tensor (bkz. bölüm 2.21).
- Öğeleri buffer, texture veya texture buffer olan bir yapı.
Bir grafik veya kernel fonksiyonuna argüman değeri olarak belirtilen buffer'lar (device) alias yapamaz; yani argüman değeri olarak geçirilen bir buffer, aynı grafik veya kernel fonksiyonunun başka bir argümanına geçirilen başka bir buffer ile örtüşemez.
Grafik ve kernel fonksiyonlarına size_t, ptrdiff_t türünde veya bu yerleşik skaler türlerden biri olarak bildirilen üyeler içeren bir yapı ve/veya union türünde argümanlar bildiremezsiniz.
Argümanlar genellikle kullanım şekillerine rehberlik etmek amacıyla özniteliklerle belirtilir. Öznitelikler şunları belirtmek için kullanılır:
- Argümanın kaynak konumu (bkz. bölüm 5.2.1).
- Sabit işlevli ve programlanabilir pipeline aşamaları arasında iletişimi destekleyen yerleşik değişkenler (bkz. bölüm 5.2.3).
- Vertex fonksiyonundan fragment fonksiyonuna pipeline boyunca hangi verilerin gönderildiği (bkz. bölüm 5.2.4).
Her argüman için, argüman tarafından kullanılan buffer, texture veya sampler'ın konumunu belirlemek amacıyla isteğe bağlı olarak bir öznitelik belirtilebilir. Metal framework API bu özniteliği konumu belirlemek için kullanır.
Grafik ve kernel fonksiyonlarına verilen argümanlar aşağıdakilerden herhangi biri olabilir:
- Device buffer'lar, constant buffer'lar,
acceleration_struct<…>,intersection_function_table<…>ve tensor'lar:[[buffer(index)]] - Texture'lar (texture buffer'lar dahil):
[[texture(index)]] - Sampler'lar:
[[sampler(index)]] - Threadgroup buffer'lar:
[[threadgroup(index)]]
Örnek:
[[kernel]] void
add_vectors(const device float4 *inA [[buffer(0)]],
const device float4 *inB [[buffer(1)]],
device float4 *out [[buffer(2)]],
uint id [[thread_position_in_grid]])
{
out[id] = inA[id] + inB[id];
}
Birden fazla kaynak türü içeren örnek:
[[kernel]] void
my_kernel(texture2d<float> img [[texture(0)]],
sampler sam [[sampler(1)]])
{ … }
Başka bir örnek:
kernel void
my_kernel(texture2d<half> src,
texture2d<half, access::write> dst,
sampler s,
device myUserInfo *u)
{ … }
İndeks değeri, atanmış bir buffer, texture veya sampler argümanının konumunu tanımlayan işaretsiz bir tamsayıdır (texture buffer, özel bir texture türüdür). Öznitelik, argüman veya değişken adından sonra gelmelidir.
Konum indeksleri belirtilmezse, Metal derleyicisi bunları ilk kullanılabilir konum indeksini kullanarak atar.
Örnek:
src→ texture indeksi 0dst→ texture indeksi 1s→ sampler indeksi 0u→ buffer indeksi 0
Açık ve örtük indekslerin karışık kullanıldığı örnek:
kernel void
my_kernel(texture2d<half> src [[texture(0)]],
sampler s,
device myUserInfo *u,
device float *f [[buffer(10)]])
{ … }
Fonksiyon sabitleri (bölüm 5.8) kullanılarak indeksler atanırken, derleyici bu girdileri indeks atarken dikkate almaz. Diğer argümanlar ilk kullanılabilir indeksi alır.
Her öznitelik grubu (buffer, threadgroup, texture, sampler) bir kaynak grubunu temsil eder. İndeks değerleri her kaynak grubu içinde benzersiz olmalıdır. Aynı indekse sahip birden fazla argüman derleme hatası üretir; ancak bunlar bir fonksiyon sabiti özniteliği ile bildirilmişse bu durum istisnadır (bkz. bölüm 5.8.1).
5.2.1.1 Kaynaklar ve Device Belleğe Çıktılar İçeren Vertex Fonksiyonu Örneği
Aşağıdaki örnek, render_vertex adlı bir vertex fonksiyonudur. Bu fonksiyon, device özniteliği ile belirtilmiş bir fonksiyon argümanı olan xform_output dizisi içinde device belleğe çıktı verir.
struct VertexOutput {
float4 position [[position]];
float4 color;
float2 texcoord;
};
struct VertexInput {
float4 position;
float3 normal;
float2 texcoord;
};
constexpr constant uint MAX_LIGHTS = 4;
struct LightDesc {
uint num_lights;
float4 light_position[MAX_LIGHTS];
float4 light_color[MAX_LIGHTS];
float4 light_attenuation_factors[MAX_LIGHTS];
};
vertex void
render_vertex(const device VertexInput* v_in [[buffer(0)]],
constant float4x4& mvp_matrix [[buffer(1)]],
constant LightDesc& light_desc [[buffer(2)]],
device VertexOutput* xform_output [[buffer(3)]],
uint v_id [[vertex_id]])
{
VertexOutput v_out;
v_out.position = v_in[v_id].position * mvp_matrix;
v_out.color = do_lighting(v_in[v_id].position,
v_in[v_id].normal,
light_desc);
v_out.texcoord = v_in[v_id].texcoord;
// Konumu bir buffer'a yaz
xform_output[v_id] = v_out;
}
Fragment fonksiyonunda buffer'lara (device bellek) ve texture'lara yapılan yükleme ve depolama işlemleri sırasızdır. Bir buffer veya texture için kullanılan [[raster_order_group(index)]] özniteliği, aynı (x, y) piksel koordinatı ve örneğe eşlenen farklı primitiflerden gelen örtüşen fragment'lar için erişim sırasını garanti eder.
[[raster_order_group(index)]] özniteliği şu durumlarda belirtilebilir:
- Device bellekteki bir texture
- Device bellekte bildirilen bir buffer
Bu öznitelik yapılar veya sınıflarla kullanılamaz.
[[raster_order_group(index)]] ile örtüşen erişimleri işaretleyen fragment fonksiyon çağrıları, geometri gönderim sırasıyla aynı sırada yürütülür.
Örnek:
fragment void
my_fragment(texture2d<float, access::read_write> texA
[[raster_order_group(0), texture(0)]],
...)
{
// clr üzerinde işlemler yap
clr = …;
texA.write(clr, coord);
}
Bir argument buffer için, [[raster_order_group(index)]] özniteliği bir yapı içindeki buffer veya texture üyesi üzerinde kullanılabilir.
5.2.2 Vertex Başına Girdileri Konumlandırma Öznitelikleri
Örnek vertex girdi öznitelikleri:
float4 position [[attribute(0)]];
float3 normal [[attribute(1)]];
half4 color [[attribute(2)]];
half2 texcoord [[attribute(3)]];
Destekleyici yapı örnekleri:
constexpr constant uint MAX_LIGHTS = 4;
struct LightDesc {
uint num_lights;
float4 light_position[MAX_LIGHTS];
float4 light_color[MAX_LIGHTS];
float4 light_attenuation_factors[MAX_LIGHTS];
};
constexpr sampler s = sampler(coord::normalized,
address::clamp_to_zero,
filter::linear);
Vertex fonksiyonu örneği:
vertex VertexOutput
render_vertex(VertexInput v_in [[stage_in]],
constant float4x4& mvp_matrix [[buffer(1)]],
constant LightDesc& lights [[buffer(2)]],
uint v_id [[vertex_id]])
Bir vertex fonksiyonu, vertex ve instance kimliklerini kullanarak argüman olarak geçirilen buffer'ları indeksleyerek vertex başına girdileri okuyabilir. Ayrıca [[stage_in]] özniteliğini kullanarak vertex başına girdileri bildirebilir ve bunları argüman olarak geçirebilirsiniz.
[[stage_in]] ile bildirilen vertex başına girdiler için her eleman, vertex öznitelik konumunu [[attribute(index)]] kullanarak belirtmelidir.
İndeks değeri, atanmış vertex giriş konumunu tanımlar. Metal API bu özniteliği vertex buffer konumunu belirlemek ve buffer kaynağı, veri biçimi ve stride gibi vertex verilerini tanımlamak için kullanır.
Bir vertex girdi yapısına vertex özniteliklerinin atanmasına örnek:
struct VertexInput {
float4 position [[attribute(0)]];
float3 normal [[attribute(1)]];
};
struct VertexInput2 {
half4 color;
half2 texcoord[4];
};
uint num_lights;
float4 light_position[MAX.LIGHTS];
float4 light_color[MAX.LIGHTS];
float4 light_attenuation_factors[MAX.LIGHTS];
};
constexpr sampler s = sampler(
coord::normalized,
address::clamp_to_zero,
filter::linear);
vertex VertexOutput
render_vertex(VertexInput v_in [[stage_in]],
VertexInput2 v_in2 [[buffer(0)]],
constant float4x4& mvp_matrix [[buffer(1)]],
constant LightDesc& lights [[buffer(2)]],
uint v_id [[vertex_id]])
{
Bir post-tessellation vertex fonksiyonu, patch başına ve patch kontrol noktası verilerini okuyabilir. Post-tessellation vertex fonksiyonu, patch kontrol noktası verisini aşağıdaki şablon türü olarak belirtir:
Burada T kullanıcı tarafından tanımlanmış bir yapıdır. T içindeki her eleman [[attribute(index)]] kullanarak bir öznitelik konumu belirtmelidir.
Tüm OS: Metal 1.2 ve sonrasında patch kontrol noktası şablon türleri desteklenir.
patch_control_point<T> türü şu üye fonksiyonları destekler:
constexpr size_t size() const;— patch içindeki kontrol noktalarının sayısını döndürür.constexpr const_reference operator[](size_t pos) const;—postarafından belirtilen belirli bir patch kontrol noktası için veriyi döndürür.
Örnek
int3 patchParam [[attribute(0)]];
float3 P [[attribute(1)]];
float3 P1 [[attribute(2)]];
float3 P2 [[attribute(3)]];
float2 vSegments [[attribute(4)]];
};
struct PerPatchData {
float4 patchConstant [[attribute(5)]];
float4 someOtherPatchConstant [[attribute(6)]];
};
struct PatchData {
struct ControlPoint {
patch_control_point<ControlPoint> cp; // Kontrol noktası verisi
PerPatchData patchData; // Patch başına veri
};
[[patch(quad)]]
vertex VertexOutput
post_tess_vertex_func(PatchData input [[stage_in]], ...)
{ ... }
Bazı grafik işlemleri sabit işlevli pipeline aşamalarında gerçekleşir ve grafik fonksiyonlarına değer sağlamaları veya grafik fonksiyonlarından değer almaları gerekir. Yerleşik giriş ve çıkış değişkenleri, grafik (vertex ve fragment) fonksiyonları ile sabit işlevli grafik pipeline aşamaları arasında değerleri iletmek için kullanılır. Grafik fonksiyonlarının argümanları ve dönüş türü ile birlikte kullanılan öznitelikler, bu yerleşik değişkenleri tanımlamak için kullanılır.
Tablo 5.2, bir vertex fonksiyonunun argümanları için belirtilebilen yerleşik öznitelikleri ve bunların kullanılabileceği karşılık gelen veri türlerini listeler.
Tablo 5.2. Vertex Fonksiyonu Girdi Argümanları için Öznitelikler
| Öznitelik | Karşılık Gelen Veri Türleri | Açıklama |
|---|---|---|
| amplification_count | ushort veya uint | Her bir köşe örneği için üretilen çıktı köşelerinin sayısı. [[amplification_count]] için varsayılan değer 1’dir; bu da köşe çoğaltmanın devre dışı olduğunu gösterir. |
| amplification_id | ushort veya uint | Viewport ve render target dizi indeksleri için dizi indeks ofset eşlemeleri; çoğaltılmış bir köşenin farklı bir viewport ve render target’a yönlendirilmesini sağlar. [[amplification_id]] değeri [0, amplification_count) aralığındadır. |
| base_instance | ushort veya uint | Her örnek tanımlayıcısına, örnek başına veriyi okumadan önce eklenen temel örnek değeri. |
| base_vertex | ushort veya uint | Her köşe tanımlayıcısına, köşe başına veriyi okumadan önce eklenen temel köşe değeri. |
| instance_id | ushort veya uint | Örnek başına tanımlayıcı; eğer belirtilmişse temel örnek değerini içerir. [[instance_id]] bildirimi için tür uint ise, [[base_instance]] bildirimi için tür uint veya ushort olmalıdır. [[instance_id]] bildirimi için tür ushort ise, [[base_instance]] bildirimi için tür ushort olmalıdır. |
| vertex_id | ushort veya uint | Köşe başına tanımlayıcı; eğer belirtilmişse temel köşe değerini içerir. [[vertex_id]] bildirimi için tür uint ise, [[base_vertex]] bildirimi için tür uint veya ushort olmalıdır. [[vertex_id]] bildirimi için tür ushort ise, [[base_vertex]] bildirimi için tür ushort olmalıdır. |
5.2.3.2 Tessellation Sonrası Köşe Fonksiyonu Girdi Öznitelikleri
Tablo 5.3, tessellation sonrası bir köşe fonksiyonunun argümanları için belirtilebilen yerleşik öznitelikleri ve bunlarla kullanılabilen karşılık gelen veri türlerini listeler.
Tüm OS: Metal 1.2 ve sonrası, Tablo 5.3’teki tüm öznitelikleri destekler.
Tablo 5.3. Tessellation Sonrası Köşe Fonksiyonu Girdi Argümanları için Öznitelikler
| Öznitelik | Karşılık Gelen Veri Türleri | Açıklama |
|---|---|---|
| base_instance | ushort veya uint | Her örnek tanımlayıcısına, örnek başına veriyi okumadan önce eklenen temel örnek değeri. |
| instance_id | ushort veya uint | Örnek başına tanımlayıcı; eğer belirtilmişse temel örnek değerini içerir. [[instance_id]] bildirimi için tür uint ise, [[base_instance]] bildirimi için tür uint veya ushort olmalıdır. [[instance_id]] bildirimi için tür ushort ise, [[base_instance]] bildirimi için tür ushort olmalıdır. |
| clip_distance | float veya float[n] | Köşeden kırpma düzlemine olan mesafe. n değeri derleme zamanında bilinmelidir. |
| patch_id | ushort veya uint | Patch tanımlayıcısı. |
| position_in_patch | float2 veya float3 | Değerlendirilen patch üzerindeki konumu tanımlar. Quad patch’ler için float2 olmalıdır. Triangle patch’ler için float3 olmalıdır. |
5.2.3.3 Köşe Fonksiyonu Çıktı Öznitelikleri
Tablo 5.4, bir köşe fonksiyonunun dönüş türü veya bir köşe fonksiyonunun döndürdüğü bir yapının üyeleri için belirtilebilen yerleşik öznitelikleri (ve bunlara karşılık gelen veri türlerini) listeler.
Tüm OS: Aksi belirtilmedikçe Metal 1 ve sonrası, Tablo 5.4’teki tüm öznitelikleri destekler.
Tablo 5.4. Köşe Fonksiyonu Dönüş Türü için Öznitelikler
| Öznitelik | Karşılık Gelen Veri Türleri | Açıklama |
|---|---|---|
| clip_distance | float veya float[n] | Köşeden kırpma düzlemine olan mesafe. |
| invariant | Uygulanamaz; [[position]] ile kullanılır |
Çıktı konumunu işaretler; böylece birden fazla köşe shader’ında çıktı konumunu hesaplamak için kullanılan işlem dizisi aynıysa, bu köşe shader’ları tarafından hesaplanan sonuç konumunun aynı değer olma olasılığı yüksektir. Kullanıcıların -fpreserve-invariance parametresini iletmesini gerektirir. |
| point_size | float | Bir nokta primitifinin boyutu. |
| render_target_array_index | uchar, ushort veya uint | Şunlardan birine başvuran dizi indeksi: (1) bir texture array’in dizi dilimi, (2) bir 3D texture’ın belirli bir derinliğindeki veri, (3) bir cubemap’in yüzü veya (4) bir cubemap array’in belirli bir dizi dilimindeki belirli bir yüz. |
| viewport_array_index | uchar, ushort veya uint | Primitifin viewport (ve scissor rectangle) indeks değeri. |
| shared | Uygulanamaz | Mevcutsa, her amplification_id için çıktı aynı değere sahiptir. |
Bir cubemap, her yüz için bir tane olmak üzere altı katmanlı bir render target array olarak temsil edilir ve [[render_target_array_index]] yüz indeksidir; bu değer 0 ile 5 arasındadır. Bir cubemap array için [[render_target_array_index]] şu şekilde hesaplanır:
array_slice_index * 6 + face_index
Bir primitif içindeki her köşe için aynı [[render_target_array_index]] değerini döndürmelisiniz. Değerler farklıysa davranış ve fragment fonksiyonuna iletilen değer tanımsızdır. Aynı davranış tessellation tarafından üretilen primitifler için de geçerlidir. Eğer [[render_target_array_index]] sınır dışındaysa (yani renderTargetArrayLength değerine eşit veya ondan büyükse), donanım bu değeri 0 olarak yorumlar. Fragment fonksiyonu girdisi olarak [[render_target_array_index]] hakkında daha fazla bilgi için Bölüm 5.2.3.4’e bakın.
[[viewport_array_index]], birden fazla etkin viewport ve scissor rectangle arasından bir viewport ve scissor rectangle belirtmeyi sağlar. Köşe fonksiyonu [[viewport_array_index]] belirtmezse, çıktı viewport dizi indeksi değeri 0 olur. Daha fazla bilgi için Bölüm 5.10’a bakın.
[[invariant]], birden fazla fonksiyon geçişinde kullanılan kayan nokta matematiğinin her geçiş için tam olarak eşleşen bir köşe konumu üretmesi gerektiğini belirtir. [[invariant]], yalnızca bir köşe fonksiyonunda konum için ([[position]] özniteliğine sahip alanlar) kullanılabilir ve çıktının hesaplama sonucunun değişmez olduğunu belirtir.
Derleyiciler iOS 14 ve macOS 11 öncesinde olduğunda, hesaplama büyük olasılıkla (ancak garanti edilmez) değişmezdir. Artık -fpreserve-invariance seçeneği iletildiğinde veya çalışma zamanı derlemesi için Metal API üzerinden MTLCompilerOptions üzerinde preserveInvariance ayarlandığında bu hesaplamanın değişmez olması garanti edilir. Seçenekler iletilmezse [[invariant]] özniteliğinin yok sayıldığını unutmayın.
Bu konum değişmezliği, shadow volumes veya z-prepass gibi teknikler için kritik öneme sahiptir.
Bir köşe fonksiyonunun dönüş türü void değilse, köşe konumunu içermelidir. Köşe dönüş türü float4 ise, bu her zaman köşe konumunu ifade eder ve [[position]] özniteliği belirtilmemelidir. Köşe dönüş türü bir yapı ise, [[position]] özniteliğiyle bildirilen bir eleman içermelidir.
Örnek Köşe Fonksiyonu
struct VertexOutput {
float4 position [[position]];
float4 color;
float2 texcoord;
};
vertex VertexOutput
process_vertex(...)
{
VertexOutput v_out;
// Köşe başına çıktıyı hesapla.
...
return v_out;
}
Eğer köşe çoğaltma etkinse ve bir köşe çıktı değişkeni her [[amplification_id]] özniteliği için aynı değere sahipse, köşe çıktısı shared olarak kabul edilir. Paylaşılan bir köşe çıktısı, sınırlı bir kaynak olan tek bir varying çıktı yuvasını kullanabilir. Paylaşılan olmayan köşe çıktıları birden fazla varying çıktı yuvası tüketir.
Metal framework çağrısı [MTLRenderPipelineDescriptor maxVertexAmplificationCount], çoğaltılmış veriyi fragment fonksiyonu çağrılarına aktarmak için kullanılabilecek varying yuvalarının sayısını döndürür; bu da toplam kullanılabilir varying yuvalarının sayısını etkiler.
Varsayılan olarak, [[position]] özniteliğine sahip olanlar dışında tüm yerleşik köşe çıktıları shared durumundadır. Varsayılan olarak diğer tüm köşe çıktıları shared değildir. Çıktının açıkça shared olduğunu belirtmek için bir köşe çıktı değişkeni ile [[shared]] özniteliğini kullanın.
Shader derleyicisi bir köşe çıktı değişkeninin her amplification_id için aynı değere sahip olduğunu çıkarabiliyorsa, derleyici bu köşe çıktısını shared olarak işaretleyebilir.
Derleyici aşağıdaki durumların herhangi birinde köşe çıktılarını shared olarak işaretleyemeyebilir:
- Çıktı değeri
[[amplification_id]]değerine bağlıysa. - Bir atomic read-modify-write işlemi çıktı değerini döndürüyorsa.
- Shader, çıktı değerini volatile bellekten yüklüyorsa.
Tablo 5.5, bir fragment fonksiyonunun argümanları için belirtilebilen yerleşik öznitelikleri ve bunların karşılık gelen veri türlerini listeler.
Bir köşe fonksiyonunun dönüş türü void değilse, köşe konumunu içermelidir. Köşe dönüş türü float4 ise, bu her zaman köşe konumunu ifade eder (ve [[position]] özniteliğinin belirtilmesine gerek yoktur). Köşe dönüş türü bir yapı ise, [[position]] özniteliğiyle bildirilen bir eleman içermelidir.
Tablo 5.5. Fragment Fonksiyonu Girdi Argümanları için Öznitelikler
| Öznitelik | Karşılık Gelen Veri Türleri | Açıklama |
|---|---|---|
| amplification_count | ushort veya uint | Her köşe örneği için üretilen çıktı köşelerinin sayısı. |
| amplification_id | ushort veya uint | Viewport ve render target dizi indeksleri için dizi indeks ofset eşlemeleri; çoğaltılmış bir köşenin farklı bir viewport ve render target’a yönlendirilmesini sağlar. |
| barycentric_coord | float, float2 veya float3 | Barycentric koordinatları. |
| color(m) | floatn, halfn, intn, uintn, shortn veya ushortn (m derleme zamanında bilinir) |
Bir renk ekinden okunan girdi değeri. m indeksi, hangi renk ekinden okunacağını belirtir. |
| front_facing | bool | Fragment’in öne bakan bir primitif’e ait olması durumunda true olur. |
| point_coord | float2 | Bir nokta primitifinin üzerinde 0.0 ile 1.0 arasında değişen iki boyutlu koordinatlar; fragment’in nokta primitif içindeki konumunu belirtir. |
| position | float4 | Fragment için pencereye göreli (x, y, z, 1/w) koordinat değerlerini tanımlar. |
| primitive_id | uint | Barycentric koordinatlarla birlikte kullanılan primitif başına tanımlayıcı. |
| render_target_array_index | uchar, ushort veya uint | Bir cubemap’in yüzüne, bir 3D texture’ın belirli bir derinliğindeki veriye, bir texture array’in dizi dilimine veya bir cubemap array’in dilim/yüzüne başvurur. Bir cubemap için değer 0–5’tir. Bir cubemap array için: array_slice_index * 6 + face_index. |
| sample_id | uint | O anda işlenen örnek numarası. |
| sample_mask | uint | Çoklu örnekleme rasterizasyonu sırasında fragment’i üreten primitif tarafından kapsanan örnek kümesi. |
| post_depth_coverage | uint | Çoklu örnekleme rasterizasyonu sırasında erken depth ve stencil testlerinden sonra kapsanan örnek kümesi. early_fragment_tests özniteliğini gerektirir. |
| thread_index_in_quadgroup | ushort veya uint | Bir quad-group içindeki bir iş parçacığının skaler indeksi. |
| thread_index_in_simdgroup | ushort veya uint | Bir SIMD-group içindeki bir iş parçacığının skaler indeksi. |
| threads_per_simdgroup | ushort veya uint | Bir SIMD-group’un iş parçacığı yürütme genişliği. |
| viewport_array_index | uint | Primitifin viewport (ve scissor rectangle) indeks değeri. |
Bir fragment fonksiyonuna girdi olarak [[position]] özniteliğiyle bildirilen bir değişken yalnızca center_no_perspective örnekleme ve enterpolasyon özniteliği ile bildirilebilir (bkz. Bölüm 5.4).
[[color(m)]] için m, bir fragment fonksiyonunda birden fazla renk ekine erişirken (okuma veya yazma) renk eki indeksini belirtmek için kullanılır.
Fragment fonksiyonundaki [[render_target_array_index]] değeri, belirtilen değer aralık dışında olsa bile, köşe fonksiyonundan yazılan değerle aynıdır.
[[amplification_count]] için varsayılan değer 1’dir; bu da köşe çoğaltmanın devre dışı olduğunu gösterir.
[[amplification_id]] değeri [0, amplification_count) aralığında olmalıdır.
Belirli bir [[amplification_id]] öznitelik değeri için, [[viewport_array_index]] ve [[render_target_array_index]] yerleşik fragment girdi değerleri, karşılık gelen MTLVertexAmplificationViewMapping yapısının sağladığı değerlere eklenir (ofset uygulanır).
Aşağıdaki örnek, hem köşe fonksiyonu dönüş türü hem de fragment fonksiyonu girdi türü olan MyVertexOut yapısını tanımlar. MyVertexOut, position ve ampData üyelerini çoğaltmak için amp_id girdi argümanı üzerinde [[amplification_id]] özniteliğini kullanır. [[shared]] özniteliğinin kullanımı, Bölüm 5.2.3.3’te açıklandığı gibi, köşe çoğaltma altında tüm varying’ler için texcoord üyesinin aynı değere sahip olmasını açıkça garanti eder.
myVertex köşe fonksiyonunda, [[amplification_id]] ve [[amplification_count]] öznitelikleri köşe çoğaltma için köşe fonksiyonu girdi değişkenlerini belirtir; ayrıntılar Bölüm 5.2.3.1’de verilmiştir. Shader derleyicisi, normal üyesinin her [[amplification_id]] için aynı değere sahip olduğunu çıkarır; bu nedenle derleyici bunu köşe çıktısında shared olarak işaretler.
myFragment fragment fonksiyonunda aynı [[amplification_id]] ve [[amplification_count]] öznitelikleri fragment fonksiyonu girdi değişkenlerini belirtir. Köşe çoğaltma etkinse, amp_id hangi viewport dizi indeksinin (viewportArrayIndexOffset üyesi) seçileceğini belirleyen eşlemeyi (MTLVertexAmplificationViewMapping yapısı) belirler.
[[sample_mask]] özniteliği bir fragment fonksiyonu girdisi için yalnızca bir kez bildirilebilir.
[[viewport_array_index]] hakkında daha fazla bilgi için Bölüm 5.10’a bakın.
struct MyVertexIn {
float4 position [[attribute(0)]];
float3 normal [[attribute(1)]];
float3 tangent [[attribute(2)]];
float2 texcoord [[attribute(3)]];
};
struct MyVertexOut {
float4 position [[position]];
float3 normal;
float3 tangent;
float3 bitangent;
float2 texcoord [[shared]]; // Açıkça paylaşılan
float ampData;
ushort viewport [[viewport_array_index]]; // Dolaylı olarak paylaşılan
};
constexpr ushort MAX_AMP = 2;
vertex MyVertexOut myVertex(
MyVertexIn in [[stage_in]],
constant float4x4 view_proj[MAX_AMP],
constant float data[MAX_AMP],
ushort amp_id [[amplification_id]],
ushort amp_count [[amplification_count]],
...)
{
MyVertexOut vert;
// Çoğaltıldığı çıkarılmış
vert.position = view_proj[amp_id] * in.position;
vert.normal = in.normal; // Paylaşılan olduğu çıkarılmış
vert.tangent = ...;
vert.bitangent = ...;
vert.texcoord = ...;
vert.ampData = data[amp_id]; // Paylaşılan değil
vert.viewport = 1;
return vert;
}
fragment float4 myFragment(
MyVertexOut in [[stage_in]],
ushort amp_id [[amplification_id]],
ushort amp_count [[amplification_count]],
...)
{
// MTLVertexAmplificationViewMapping = {{1,3},{2,4}} için
// amp_id == 0 olduğunda, in.viewport == 2
// amp_id == 1 olduğunda, in.viewport == 3
ushort viewport = in.viewport;
...
}
[[barycentric_coord]] özniteliği ile bildirilen bir fragment fonksiyonu girdisi yalnızca center_perspective (varsayılan) veya center_no_perspective örnekleme ve enterpolasyon öznitelikleriyle birlikte bildirilebilir. Barysentirik koordinatlar ve piksel başına primitive kimliği, aşağıdaki örneklerde gösterildiği gibi düzenlenmiş yapılar içinde fragment fonksiyonu girdisi olarak aktarılabilir:
struct FragmentInput0 {
uint primitive_id [[primitive_id]];
// [[center_perspective]] varsayılandır, bu nedenle yazılmayabilir.
float3 barycentric_coord [[barycentric_coord, center_perspective]];
};
struct FragmentInput1 {
uint primitive_id [[primitive_id]];
float2 linear_barycentric_coord [[barycentric_coord, center_no_perspective]];
};
Barysentirik koordinatları ve piksel başına primitive kimliğini saklayarak, shader'ınız çizilen bir primitive’in köşelerini fragment aşaması içinde manuel olarak okuyup enterpole edebilir veya bu enterpolasyonu ayrı bir geçişe erteleyebilir. Gecikmeli enterpolasyon senaryosunda, geometri geçişi sırasında önceden kırpılmış barysentirik koordinatlar dahil olmak üzere yüzey verilerinin asgari bir kümesini depolamak için ince bir tampon kullanabilirsiniz. Daha sonraki bir aşamada, primitive kimliği verilerinden özgün köşe indekslerini yeniden oluşturmak ve barysentirik koordinatları bu köşe indeksleriyle ilişkilendirmek için yeterli veriye sahip olmanız gerekir.
fragment float4 frag(float3 coord [[barycentric_coord]]) { ... }
- Bir nokta çizildiğinde,
coord.yzdeğerifloat2(0.0f)olur. - Bir doğru çizildiğinde,
coord.zdeğeri0.0folur.
barycentric_coord özniteliği, primitive’in boyutundan daha fazla bileşene sahip bir giriş argümanına (veya bir argüman alanına) uygulandığında, kalan elemanlar 0.0f ile başlatılır.
barycentric_coord özniteliği, primitive’in boyutundan daha az bileşene sahip bir giriş argümanına (veya bir argüman alanına) uygulandığında, kalan elemanlar göz ardı edilir.
Fragment Fonksiyonu Tile Girdi Öznitelikleri
Tablo 5.6, bir fragment fonksiyonuna girdi olan tile argümanları için belirtilebilecek öznitelikleri listeler. [[pixel_position_in_tile]] ve [[pixels_per_tile]] bildirimleri için kullanılan veri tipleri eşleşmelidir.
Fragment Fonksiyonu Tile Girdi Argümanları İçin Öznitelikler
pixel_position_in_tile
Veri tipleri: ushort2 veya uint2
Açıklama: Tile içindeki fragment’in (x, y) konumu.
pixels_per_tile
Veri tipleri: ushort2 veya uint2
Açıklama: Tile’ın piksel cinsinden (width, height) değeri.
color(m)
Tüm işletim sistemleri: Metal 1 ve sonrası.
color(m), index(i)
Tüm işletim sistemleri: Metal 1.2 ve sonrası.
depth(depth_argument)
Tüm işletim sistemleri: Metal 1 ve sonrası.
Render hedefi dizi indeksi; bir cubemap yüzünü, bir 3D dokunun belirli bir derinliğindeki veriyi, bir texture dizisinin bir dilimini veya bir cubemap dizisinin bir dilimini ya da yüzünü ifade eder. Bir cubemap için render hedefi dizi indeksi yüz indeksidir ve 0 ile 5 arasında bir değerdir. Bir cubemap dizisi için render hedefi dizi indeksi şu şekilde hesaplanır:
array slice index * 6 + face index
macOS: Metal 2.3 ve sonrası Tablo 5.6’daki tüm öznitelikleri destekler.
iOS: Metal 2 ve sonrası Tablo 5.6’daki tüm öznitelikleri destekler.
[[tile_index]] değeri [0, n) aralığındadır; burada n, render hedefindeki tile sayısını ifade eder.
5.2.3.5 Fragment Fonksiyonu Çıktı Öznitelikleri
Bir fragment fonksiyonunun dönüş tipi, fragment başına çıktıyı tanımlar. Bir fragment fonksiyonunun bir veya daha fazla render hedefi renk değeri, bir derinlik değeri, bir örnekleme kapsama maskesi veya bir stencil referans değeri çıktısı verebileceğini belirtmek için Tablo 5.7’de listelenen öznitelikleri kullanmanız gerekir. Eğer derinlik değeri fragment fonksiyonu tarafından verilmezse, rasterizer tarafından üretilen derinlik değeri derinlik ekine yazılır.
Fragment Fonksiyonu Dönüş Tipleri İçin Öznitelikler
color(m)
Veri tipleri: floatn, halfn, intn, uintn, shortn veya ushortn
Açıklama: Bir renk eki için çıktı renk değeri. m renk eki indeksidir ve derleme zamanında bilinmelidir. i indeksi, belirli bir renk eki için fragment fonksiyonu tarafından üretilen bir veya daha fazla rengi belirtmek için kullanılabilir ve karıştırma (blend) denklemi için girdi görevi görür.
depth(depth_argument)
Veri tipi: float
Açıklama: depth_argument tarafından belirtilen fonksiyon kullanılarak verilen derinlik değeri.
sample_mask
Veri tipi: uint
Açıklama: Kapsama maskesi.
stencil
Veri tipi: uint
Açıklama: Bir stencil testinde kullanılacak stencil referans değeri.
Bir fragment fonksiyonunda yalnızca tek bir renk eki varsa, [[color(m)]] isteğe bağlıdır. [[color(m)]] belirtilmezse ek indeksi 0 olur. Birden fazla renk eki belirtilmişse, tüm renk değerleri için [[color(m)]] belirtilmelidir.
Eğer öznitelikte index(i) belirtilmezse varsayılan indeks 0 olur. index(i) belirtilmişse i değerinin derleme zamanında bilinmesi gerekir.
depth(depth_argument) ile işaretlenen fragment çıktısı, depth_argument ayarıyla çelişen bir değer üretirse uygulamanız öngörülemeyen sonuçlar gösterebilir.
Fragment fonksiyonu stencil değerini vermiyorsa, MTLRenderCommandEncoder sınıfının setStencilReferenceValue: veya setStencilFrontReferenceValue:backReferenceValue: yöntemi stencil referans değerini ayarlayabilir.
Fragment çıktısı için renk eki indeksi m, fragment girdisi için kullanılan [[color(m)]] ile aynı şekilde belirtilir. Karıştırma için aynı renk eki indeksini kullanan fragment fonksiyonu dönüş tipindeki birden fazla eleman aynı veri tipiyle bildirilmelidir.
Bir fragment fonksiyonu özel bir derinlik değeri yazıyorsa, depth_argument parametresini any, greater veya less olarak belirtin. Bu ayar, fragment çıktısındaki depth(depth_argument) özniteliğinin derleyicinin ürettiği varsayılan derinlik değeriyle nasıl etkileşeceğini kontrol eder.
- any — Herhangi bir değeri kabul eder.
- greater — Yalnızca varsayılan derinlikten daha büyük değerleri kabul eder.
- less — Yalnızca varsayılan derinlikten daha küçük değerleri kabul eder.
Fragment tabanlı tile shading fonksiyonlarında [[stencil]] özniteliğini kullanamazsınız. [[stencil]] özniteliği [[early_fragment_tests]] fonksiyon özniteliği ile uyumlu değildir.
Aşağıdaki örnek, renk eki indekslerinin nasıl belirtilebileceğini gösterir. clr_f içine yazılan renk değerleri renk eki indeksi 0’a, clr_i renk eki indeksi 1’e ve clr_ui renk eki indeksi 2’ye yazılır.
// Color attachment 0
float4 clr_f [[color(0)]];
// Color attachment 1
int4 clr_i [[color(1)]];
Bir renk eki indeksi hem fragment fonksiyonunun girdisi hem de çıktısı olarak kullanılıyorsa, bu renk eki indeksiyle bildirilen giriş argümanı ve çıktı ile ilişkili veri tipleri eşleşmelidir.
Kernel Fonksiyonu Çalışma Modeli
Bir kernel fonksiyonu çalıştırılmak üzere gönderildiğinde, N bir, iki veya üç olmak üzere N boyutlu bir thread ızgarası üzerinde yürütülür. Bir thread, bu ızgaradaki her nokta için çalışan kernel fonksiyonunun bir örneğidir ve thread_position_in_grid bu ızgara içindeki konumunu tanımlar.
Bir hesaplama birimi içinde, bir threadgroup yürütme için birden fazla daha küçük gruba bölünür. Hesaplama biriminin yürütme genişliği threads_per_simdgroup olarak adlandırılır ve bu daha küçük grubun önerilen boyutunu belirler. En iyi performans için threadgroup içindeki toplam thread sayısını threads_per_simdgroup değerinin katı yapın.
Threadgroup’lara ızgara içinde benzersiz bir konum atanır (threadgroup_position_in_grid). Thread’lere ise bir threadgroup içinde benzersiz bir konum atanır (thread_position_in_threadgroup). Bir thread’in threadgroup içindeki benzersiz skaler indeksi thread_index_in_threadgroup ile verilir.
Her thread’in ızgara içindeki konumu ve threadgroup içindeki konumu N boyutlu demetlerdir. Threadgroup’lara da thread’lere benzer bir yaklaşımla konum atanır. Thread’ler bir threadgroup’a atanır ve threadgroup içindeki konumları, o boyuttaki threadgroup boyutundan bir eksik değere kadar sıfırdan başlayan bileşenlere sahip olur.
Bir kernel fonksiyonu çalıştırılmak üzere gönderildiğinde, threadgroup sayısı ve threadgroup boyutu belirtilir ya da ızgaradaki thread sayısı ve threadgroup boyutu belirtilir.
Örneğin, (Wx, Wy) threadgroup sayısına ve (Sx, Sy) threadgroup boyutuna sahip 2B bir ızgara kullanan bir kernel fonksiyonunun yürütülmesi durumunu ele alalım. (wx, wy) her threadgroup’un ızgara içindeki konumu (threadgroup_position_in_grid) ve (lx, ly) her thread’in threadgroup içindeki konumu (thread_position_in_threadgroup) olsun.
MyFragmentOutput f;
...
f.clr_f = ...;
...
return f;
(Gx, Gy) = (Wx * Sx, Wy * Sy)
Tile fonksiyonu dışındaki durumlarda, threadgroup içindeki thread indeksi (thread_index_in_threadgroup) şu şekilde belirlenir:
ly * Sx + lx
Bir tile fonksiyonunda thread indeksi, lx ve ly değerlerinden doğrusal bir eşleme ile elde edilmez. Bir tile fonksiyonundaki her thread’in [0, Sx * Sy) aralığında benzersiz bir indeks alması garanti edilir.
Bir threadgroup içinde thread’ler uygulamaya bağlı bir biçimde SIMD-group’lara bölünür. Bir SIMD-group içindeki herhangi bir thread kendi SIMD lane kimliğini ve hangi SIMD-group’a ait olduğunu sorgulayabilir.
Kernel Fonksiyonu Girdi Argümanları İçin Öznitelikler
Tablo 5.8, bir kernel fonksiyonunun argümanları için belirtilebilecek yerleşik öznitelikleri ve bunların kullanılabileceği karşılık gelen veri tiplerini listeler. Metal 3.1 ve sonrasında, bu yerleşik öznitelikler kernel bağlamında kullanılmak üzere global (program kapsamlı) değişkenler üzerinde de belirtilebilir.
dispatch_quadgroups_per_threadgroup
macOS: Metal 2.1 ve sonrası
iOS: Metal 2 ve sonrası
dispatch_simdgroups_per_threadgroup
macOS: Metal 2 ve sonrası
iOS: Metal 2.2 ve sonrası
dispatch_threads_per_threadgroup
Tüm işletim sistemleri: Metal 1 ve sonrası
Açıklama: Dispatch sırasında belirtilen thread’ler için bir threadgroup’un thread yürütme genişliği.
grid_origin
Tüm işletim sistemleri: Metal 1.2 ve sonrası
Açıklama: Thread başına stage‑in verisi okuyan compute thread’lerinin başlatıldığı ızgaranın başlangıç noktası (offset).
Ek kernel öznitelikleri şunları içerir:
quadgroup_index_in_threadgroup— bir threadgroup içindeki quad-group’un skaler indeksi.quadgroups_per_threadgroup— bir threadgroup’un quad-group yürütme genişliği.simdgroup_index_in_threadgroup— bir threadgroup içindeki SIMD-group’un skaler indeksi.simdgroups_per_threadgroup— bir threadgroup’un SIMD-group yürütme genişliği.thread_execution_width— bir SIMD-group’un thread yürütme genişliği (Metal 3 itibarıyla kullanım dışı; yerinethreads_per_simdgroupkullanın).thread_index_in_quadgroup— bir quad-group içindeki thread’in skaler indeksi.thread_index_in_simdgroup— bir SIMD-group içindeki thread’in skaler indeksi.thread_index_in_threadgroup— bir threadgroup içindeki thread’in skaler indeksi.thread_position_in_grid— yürütme ızgarasındaki bir thread’in konumu.thread_position_in_threadgroup— bir threadgroup içindeki thread’in konumu.
Öznitelik — Karşılık Gelen Veri Tipleri — Açıklama
ushort veya uint
Bir SIMD-group içindeki thread’in skaler indeksi.
ushort veya uint
Bir threadgroup içindeki thread’in skaler indeksi.
ushort, ushort2, ushort3, uint, uint2 veya uint3
Thread’in N boyutlu bir thread ızgarası içindeki konumu.
ushort, ushort2, ushort3, uint, uint2 veya uint3
Thread’in bir threadgroup içindeki benzersiz konumu.
Thread ve Grid Öznitelikleri
threadgroup_position_in_grid
Tüm işletim sistemleri: Metal 1 ve sonrası
Bir threadgroup’un bir ızgara içindeki benzersiz konumu.
threadgroups_per_grid
Tüm işletim sistemleri: Metal 1 ve sonrası
Bir ızgara içindeki threadgroup sayısı.
threads_per_grid
Tüm işletim sistemleri: Metal 1 ve sonrası
Izgara boyutu.
threads_per_simdgroup
macOS: Metal 2 ve sonrası
iOS: Metal 2.2 ve sonrası
Bir SIMD-group’un (hesaplama birimi) thread yürütme genişliği.
threads_per_threadgroup
Tüm işletim sistemleri: Metal 1 ve sonrası
Bir threadgroup’un thread yürütme genişliği.
Platform Destek Notları
- macOS: Metal 2 ve sonrası SIMD-group özniteliklerini destekler. Metal 2.1 ve sonrası quadgroup özniteliklerini destekler. Metal 1 ve sonrası diğer öznitelikleri destekler.
- iOS: Metal 2 ve sonrası SIMD-group ve quad-group özniteliklerini destekler. Metal 1 ve sonrası diğer tüm öznitelikleri destekler.
- Tüm işletim sistemleri: Metal 3.1 ve sonrası global (program kapsamlı) değişkenleri destekler. Bu öznitelikler, dinamik bir kütüphanede veya ayrı derlenmiş bir ikili fonksiyonda kullanılmadıkları sürece belirtilebilir. Metal 3.2 ve sonrasında, Apple silicon için global değişkenler dinamik bir kütüphanede veya ayrı derlenmiş bir ikili fonksiyonda da kullanılabilir.
SIMD-group ve Quad-group Davranışı
Standart Metal compute fonksiyonları için (tile fonksiyonları hariç) SIMD-group’lar doğrusal ve tek boyutludur. Threadgroup’lar ise çok boyutlu olabilir.
Bir threadgroup içindeki SIMD-group sayısı ([[simdgroups_per_threadgroup]]), threadgroup içindeki toplam thread sayısının ([[threads_per_threadgroup]]) SIMD-group boyutuna ([[threads_per_simdgroup]]) bölünmesiyle elde edilir:
simdgroups_per_threadgroup = ceil(threads_per_threadgroup / threads_per_simdgroup)
Benzer şekilde, bir threadgroup içindeki quad-group sayısı (quadgroups_per_threadgroup), threadgroup içindeki toplam thread sayısının 4’e bölünmesiyle elde edilir; 4, bir quad-group’un thread yürütme genişliğidir:
quadgroups_per_threadgroup = ceil(threads_per_threadgroup / 4)
Tile fonksiyonları için thread’ler 2 × 2 quad şeklinde düzenlenir. Threadgroup sayısının (Wx, Wy) olduğu 2B bir ızgara için simdgroups_per_threadgroup şu şekilde hesaplanır:
simdgroups_per_threadgroup = ceil(Wx / 2) * 2 * ceil(Wy / 2) * 2 / threads_per_simdgroup
[[dispatch_simdgroups_per_threadgroup]] ve [[dispatch_quadgroups_per_threadgroup]] değerleri de dispatch sırasında belirtilen thread’ler için benzer şekilde hesaplanır.
SIMD-group’lar bir threadgroup içinde eşzamanlı olarak yürütülür ve threadgroup bariyer işlemleri olmadığı sürece birbirlerine göre bağımsız şekilde ilerler.
Bir SIMD-group içindeki thread indeksi ([[thread_index_in_simdgroup]]) 0 ile SIMD-group boyutu − 1 arasında bir değerdir (dahil).
Bir quad-group içindeki thread indeksi ([[thread_index_in_quadgroup]]) 0 ile 3 arasında bir değerdir (dahil).
Değişken Threadgroup Boyutları
Metal 2 ve sonrasında, ızgaradaki thread sayısının threadgroup içindeki thread sayısının katı olması gerekmez. Bu nedenle belirli bir threadgroup’un gerçek boyutu, dispatch sırasında belirtilen boyuttan daha küçük olabilir.
[[threads_per_threadgroup]], kernel’i çalıştıran belirli bir threadgroup için gerçek threadgroup boyutunu belirtir.[[dispatch_threads_per_threadgroup]], dispatch zamanında ayarlanan threadgroup boyutunu belirtir.
Tür Gereksinimleri
Aşağıdakileri bildirmek için kullanılan tip:
[[thread_position_in_grid]][[threads_per_grid]][[thread_position_in_threadgroup]][[threads_per_threadgroup]][[threadgroup_position_in_grid]][[dispatch_threads_per_threadgroup]][[threadgroups_per_grid]]
skaler tür veya vektör türü olmalıdır. Bir vektör türü kullanılırsa, vektör bileşenlerinin sayısı eşleşmelidir.
[[thread_position_in_grid]]ve[[threads_per_grid]]tanımlamak için kullanılan veri türleri eşleşmelidir.Aşağıdakileri tanımlamak için kullanılan veri türleri:
[[thread_position_in_threadgroup]][[threads_per_threadgroup]][[dispatch_threads_per_threadgroup]]
eşleşmelidir.
Eğer
[[thread_position_in_threadgroup]]türüuint,uint2veyauint3ise,[[thread_index_in_threadgroup]]türüuintolmalıdır.
Tile Fonksiyonu Hesaplamaları
simdgroups_per_threadgroup = ceil(Wx / 2) * ceil(Wy / 2) * 4 / threads_per_simdgroup
quadgroups_per_threadgroup = ceil(Wx / 2) * 2 * ceil(Wy / 2) * 2 / 4
quadgroups_per_threadgroup = ceil(Wx / 2) * ceil(Wy / 2)
Kernel Fonksiyonu Nitelikleri Hakkında Notlar
Aşağıdakileri tanımlamak için kullanılan türler ushort veya uint olmalı ve birbirleriyle eşleşmelidir:
[[thread_index_in_simdgroup]][[threads_per_simdgroup]][[simdgroup_index_in_threadgroup]][[simdgroups_per_threadgroup]][[dispatch_simdgroups_per_threadgroup]][[quadgroup_index_in_threadgroup]][[quadgroups_per_threadgroup]][[dispatch_quadgroups_per_threadgroup]]
[[threads_per_simdgroup]]ve[[thread_execution_width]], aynı kavrama karşılık gelen takma adlardır.
Tablo 5.9 — Kernel Fonksiyonu Tile Girdi Argümanları için Nitelikler
render_target_array_index
Veri türleri: uchar, ushort veya uint
Render hedefi dizi indeksi şu öğelere karşılık gelir:
- bir cubemap yüzü
- bir 3D dokunun belirli bir derinliğindeki veri
- bir doku dizisinin dizi dilimi
- bir cubemap dizisinin dizi dilimi veya yüzü
Bir cubemap için render hedefi dizi indeksi yüz indeksidir (0–5).
Bir cubemap dizisi için:
array slice index * 6 + face index
Platform Desteği
- macOS: Metal 2.3 ve sonrası Tablo 5.9’daki tüm nitelikleri destekler.
- iOS: Metal 2 ve sonrası Tablo 5.9’daki tüm nitelikleri destekler.
5.2.3.7 Kesişim Fonksiyonu Girdi Nitelikleri
Tablo 5.10, özel bir kesişim fonksiyonunun argümanları için belirtilebilen yerleşik nitelikleri listeler (bkz. Bölüm 5.1.6).
Bazı nitelikler yalnızca primitive_type ve intersection_tags için belirli değerler kullanıldığında kullanılabilir.
Örnek: intersection_tags içinde instancing bulunuyorsa instance_id kullanılabilir.
Herhangi bir kısıtlama nitelik açıklamalarında listelenmiştir.
Tablo 5.10 — Kesişim Fonksiyonu Girdi Argümanları için Nitelikler
min_distance
Tür: float
Işının minimum mesafesi.
payload
Tür: Kullanıcı tanımlı tür
Referans ile aktarılır.
instance_id
Türler: ushort, uint veya array_ref<uint>
Her örnek için tanımlayıcı.
intersection_tags içinde instancing bulunuyorsa kullanılabilir.
Metal 3.1 ve sonrasında, intersection_tags içinde max_levels<Count> bulunuyorsa tür array_ref<uint> olmalıdır. Aksi durumda ushort veya uint olur.
origin
Tür: float3
Nesne uzayında ışın başlangıç noktası.
direction
Tür: float3
Nesne uzayında ışın yönü.
max_distance
Tür: float
Referans ile aktarılır. Mevcut en yakın kesişimin maksimum mesafesini döndürür.
Intersector bu değeri ışının maksimum mesafesi ile başlatır. Kesişimler bulundukça değer azalır.
geometry_id
Tür: ushort veya uint
Geometri başına tanımlayıcı.
primitive_id
Tür: ushort veya uint
Primitive başına tanımlayıcı. Eğriler için bu değer eğri segment indeksidir.
world_space_origin
Tür: float3
Dünya uzayındaki başlangıç noktası.
intersection_tags içinde world_space_data bulunuyorsa kullanılabilir.
world_space_direction
Tür: float3
Dünya uzayındaki yön.
intersection_tags içinde world_space_data bulunuyorsa kullanılabilir.
barycentric_coord
Tür: float2
Barycentrik koordinatlar. Aşağıdaki durumlarda kullanılabilir:
primitive_typetriangle iseintersection_tagsiçinde triangle_data bulunuyorsa
front_facing
Tür: bool
Üçgenin ön yüzü ışının başlangıç noktasından görünüyorsa true olur.
intersection_tags içinde triangle_data bulunuyorsa kullanılabilir.
distance
Tür: float
Üçgen kesişiminde ışın boyunca olan mesafe.
primitive_type triangle ise kullanılabilir.
opaque
Tür: bool
Primitive’in opak kabul edilip edilmeyeceğini belirtir.
primitive_type bounding_box ise kullanılabilir.
instance_intersection_function_table_offset
Tür: ushort veya uint
Kesişim örneğini seçmek için kullanılan kesişim fonksiyonu tablosuna olan ofset.
geometry_intersection_function_table_offset
Tür: ushort veya uint
Kesişim örneğini seçmek için kullanılan geometri nesnesi içindeki ofset.
motion_start_time
Tüm işletim sistemleri: Metal 2.4 ve sonrası
Tür: float
Bu geometri için hareket başlangıç zamanı.
intersection_tags içinde primitive_motion bulunuyorsa kullanılabilir.
motion_end_time
Tüm işletim sistemleri: Metal 2.4 ve sonrası
Tür: float
Bu geometri için hareket bitiş zamanı.
intersection_tags içinde primitive_motion bulunuyorsa kullanılabilir.
key_frame_count
Tüm işletim sistemleri: Metal 2.4 ve sonrası
Tür: ushort veya uint
Anahtar kare sayısı.
intersection_tags içinde primitive_motion bulunuyorsa kullanılabilir.
object_to_world_transform
Tüm işletim sistemleri: Metal 2.4 ve sonrası
Tür: float4x3
Nesne uzayından dünya uzayına dönüşüm matrisi.
intersection_tags içinde aşağıdakiler bulunuyorsa kullanılabilir:
- instancing
- world_space_data
intersection_tags içinde instance_motion bulunuyorsa matris zamana bağlı olarak enterpole edilir.
world_to_object_transform
Tüm işletim sistemleri: Metal 2.4 ve sonrası
Tür: float4x3
Dünya uzayından nesne uzayına dönüşüm matrisi.
intersection_tags içinde aşağıdakiler bulunuyorsa kullanılabilir:
- instancing
- world_space_data
intersection_tags içinde instance_motion bulunuyorsa matris zamana bağlı olarak enterpole edilir.
curve_parameter
Tüm işletim sistemleri: Metal 3.1 ve sonrası
Tür: float
Eğri segmenti boyunca kesişime karşılık gelen konumu yeniden oluşturmak için eğri temel fonksiyonlarına geçirilen değer.
Işın bir eğri uç kapağı veya dirseği ile kesiştiğinde bu değer tam olarak 0.0F veya 1.0F olur.
intersection_tags içinde curve_data bulunuyorsa kullanılabilir.
function_id
Tüm işletim sistemleri: Metal 4 ve sonrası
Tür: ushort veya uint
GPU tarafından çağrılacak kesişim fonksiyonunu belirlemek için kullanılan indeksi belirtir.
intersection_tags içinde intersection_function_buffer bulunuyorsa kullanılabilir.
primitive_data
Tüm işletim sistemleri: Metal 3 ve sonrası
Tür: const device T* veya const device T&
device adres uzayında aktarılan, primitive başına salt okunur veri.
user_data_buffer
Tüm işletim sistemleri: Metal 4 ve sonrası
Tür: const device T* veya const device T&
intersection_tags aşağıdakileri içerdiğinde aktarılan kullanıcı verisi:
- intersection_function_buffer
- user_data
Barycentrik Nitelik Enterpolasyonu
Köşe nitelikleri v0, v1 ve v2 için, belirtilen barycentrik noktadaki nitelik değeri:
v1 * barycentric_coord.x + v2 * barycentric_coord.y + v0 * (1.0f - (barycentric_coord.x + barycentric_coord.y))
Payload Türü Gereksinimleri
[[payload]] niteliğine sahip bir parametrenin türü şu biçimde olmalıdır:
ray_data T &
Kesişim fonksiyonlarına referans ile aktarılır ve ray_data adres uzayında ayrılır.
Payload türü T şunları içerebilir:
- tamsayı türleri
- vektör türleri
- yapılar veya union’lar (
atomic<T>veimageblock<T>hariç) - bu türlerin dizileri
5.2.3.8 Kesişim Fonksiyonu Çıktı Nitelikleri
Tablo 5.11, aşağıdaki türde bir fonksiyonun dönüş türü için belirtilebilen yerleşik nitelikleri listeler:
[[intersection(primitive_type, intersection_tags...)]]
fonksiyonu.
Tablo 5.11 — Kesişim Dönüş Türleri için Nitelikler
accept_intersection
Tür: bool
True ise bu primitive bir sonraki onaylanmış çarpışma olur. En yakın çarpışma ise intersect() fonksiyonundan döndürülür.
continue_search
Tür: bool
Çarpışma kabul edilirse ([[accept_intersection]] == true), bu değer aramanın devam edip etmeyeceğini belirtir.
- true ise
intersect()daha yakın bir çarpışma aramaya devam eder. - false ise başka arama yapılmaz ve mevcut en yakın çarpışma döndürülür.
Varsayılan değer: true.
True döndürülse bile, accept_any_intersection() true ise onaylanmış bir çarpışma aramayı hemen durdurur.
distance
Tür: float
Bir bounding box içinde bulunan çarpışma için ışın boyunca olan mesafeyi döndürür.
Çarpışma reddedilirse ([[accept_intersection]] == false), bu dönüş değeri yok sayılır.
primitive_type bounding_box ise kullanılabilir.
Üçgen kesişim fonksiyonları için gerekli olan tek dönüş değeri [[accept_intersection]] niteliğidir. Fonksiyon bir nitelik olmadan bool döndürüyorsa bunun [[accept_intersection]] olduğu varsayılır.
[[distance]] değerinin [[min_distance]] değerinden büyük veya eşit olması, [[max_distance]] değerinden küçük veya eşit olması ve özel primitive’in bounding box’ı içinde (dahil) bulunması gerekir; aksi durumda sonuçlar tanımsızdır. Eğer [[distance]] değeri [[max_distance]] değeriyle aynıysa, bu çarpışmanın kabul edilmesi aynı mesafedeki önceki çarpışmaya göre öncelik kazanır.
Işın payload’unda yapılan herhangi bir değişiklik, kesişim fonksiyonunun nasıl döndüğünden bağımsız olarak geçerli olur. Reddedilen primitive’ler, gelecekteki kesişim shader iş parçacıkları tarafından gözlemlenebilen bellek yan etkilerine sahip olabilir.
Cihaz belleğine yazma işlemleri, primitive reddedilse bile gerçekleşir. Bu yazmalar, olağan bellek tutarlılığı ve eşzamanlılık kuralları aracılığıyla diğer iş parçacıkları tarafından görülebilir (şu anda yalnızca atomikler tutarlı olacaktır ve yalnızca gevşek tutarlılık desteklenmektedir).
Işın primitive’in bounding box’ı ile kesişmese bile kesişim fonksiyonları çağrılabilir. Örneğin uygulamalar birden fazla primitive’i tek bir hızlandırma yaprağı düğümünde gruplayabilir.
struct IntersectionResult {
bool continueSearch [[continue_search]];
bool accept [[accept_intersection]];
float distance [[distance]];
};
[[intersection(bounding_box)]]
IntersectionResult sphereIntersectionFunction(
float3 origin [[origin]],
float3 direction [[direction]],
uint primitiveIndex [[primitive_id]],
ray_data float2& resources [[payload]],
float min_distance [[min_distance]],
float max_distance [[max_distance]])
{ … }
5.2.3.9 Object Fonksiyonu Girdi Nitelikleri
Tüm işletim sistemleri: Metal 3.1 ve sonrasında, dinamik bir kütüphane veya ayrı derlenmiş ikili fonksiyon kullanılırken hariç olmak üzere bu nitelikleri global değişkenlerde belirtebilirsiniz.
Object fonksiyonları, bir kernel fonksiyonu ile aynı yürütme modelini kullanır (bkz. bölüm 5.2.3.6); burada fonksiyon N boyutlu bir iş parçacığı ızgarası üzerinde çalışır. Object fonksiyonu argümanları sampler’lar, texture’lar, mesh_grid_properties türünde argümanlar ve device, constant ve threadgroup adres uzayındaki buffer’lar olabilir.
Object fonksiyonları, kernel fonksiyonunun yerleşik niteliklerinin bir alt kümesini ve [[amplification_count]] ile [[payload]] niteliklerini destekler. [[amplification_count]] niteliğinin anlamı, bölüm 5.2.3.1 Vertex Function Input Attributes kısmındaki ile aynıdır.
Tablo 5.12, bir object fonksiyonunun argümanları için belirtilebilen yerleşik nitelikleri ve kullanılabilecekleri karşılık gelen veri türlerini listeler. Metal 3.1 ve sonrası, Tablo 5.12’deki yerleşik nitelikleri program kapsamındaki değişkenlerde belirtmenize olanak tanır; amplification_count ve payload hariç.
Aşağıda bir bounding box için kesişim fonksiyonuna ait bir örnek bulunmaktadır.
Tablo 5.12. Object Fonksiyonu için Nitelikler
amplification_count
Veri türleri: ushort veya uint
Açıklama: Her köşe örneği için üretilen çıktı köşelerinin sayısı.
dispatch_quadgroups_per_threadgroup
Veri türleri: ushort veya uint
Açıklama: Dispatch sırasında belirtilen bir threadgroup’un quad-group yürütme genişliği.
dispatch_simdgroups_per_threadgroup
Veri türleri: ushort veya uint
Açıklama: Dispatch sırasında belirtilen bir threadgroup’un SIMD-group yürütme genişliği.
dispatch_threads_per_threadgroup
Veri türleri: ushort, ushort2, ushort3, uint, uint2 veya uint3
Açıklama: Dispatch sırasında belirtilen iş parçacıkları için bir threadgroup’un iş parçacığı yürütme genişliği.
payload
Veri türleri: object_data adres uzayında kullanıcı tanımlı T türüne işaretçi veya l-value referansı
Açıklama: Payload, object shader’dan mesh shader’a aktarılan veridir. Payload işaretçisi veya referansı threadgroup içindeki tüm iş parçacıkları için aynıdır. Object fonksiyonuna girişte payload belleğinin başlatılmamış olduğu varsayılır.
quadgroup_index_in_threadgroup
Veri türleri: ushort veya uint
Açıklama: Bir threadgroup içindeki quad-group’un skaler indeksi.
quadgroups_per_threadgroup
Veri türleri: ushort veya uint
Açıklama: Bir threadgroup’un quad-group yürütme genişliği.
simdgroup_index_in_threadgroup
Veri türleri: ushort veya uint
Açıklama: Bir threadgroup içindeki SIMD-group’un skaler indeksi.
thread_index_in_quadgroup
Veri türleri: ushort veya uint
Açıklama: Bir quad-group içindeki iş parçacığının skaler indeksi.
thread_index_in_simdgroup
Veri türleri: ushort veya uint
Açıklama: Bir SIMD-group içindeki iş parçacığının skaler indeksi.
thread_index_in_threadgroup
Veri türleri: ushort veya uint
Açıklama: Bir threadgroup içindeki iş parçacığının skaler indeksi.
thread_position_in_threadgroup
Veri türleri: ushort, ushort2, ushort3, uint, uint2 veya uint3
Açıklama: Bir threadgroup içindeki iş parçacığının benzersiz konumu.
threadgroup_position_in_grid
Veri türleri: ushort, ushort2, ushort3, uint, uint2 veya uint3
Açıklama: Bir ızgara içindeki threadgroup’un benzersiz konumu.
threadgroups_per_grid
Veri türleri: ushort, ushort2, ushort3, uint, uint2 veya uint3
Açıklama: Bir ızgaradaki threadgroup sayısı.
thread_position_in_grid
Veri türleri: ushort, ushort2, ushort3, uint, uint2 veya uint3
Açıklama: N boyutlu bir iş parçacığı ızgarasında iş parçacığının konumu.
threads_per_simdgroup
Veri türleri: ushort veya uint
Açıklama: Bir SIMD-group’un iş parçacığı yürütme genişliği.
Object Fonksiyonu Nitelikleri için Kısıtlamalar
Object fonksiyonu nitelikleri, kernel fonksiyonu nitelikleriyle aynı kısıtlamalara sahiptir:
[[thread_position_in_grid]],[[threads_per_grid]],[[thread_position_in_threadgroup]],[[threads_per_threadgroup]],[[threadgroup_position_in_grid]],[[dispatch_threads_per_threadgroup]]ve[[threadgroups_per_grid]]bildiriminde kullanılan tür skaler bir tür veya vektör türü olmalıdır. Eğer vektör türü kullanılıyorsa, bu argümanların bildiriminde kullanılan vektör türlerinin bileşen sayılarının eşleşmesi gerekir.[[thread_position_in_grid]]ve[[threads_per_grid]]bildiriminde kullanılan veri türlerinin eşleşmesi gerekir.[[thread_position_in_threadgroup]],[[threads_per_threadgroup]]ve[[dispatch_threads_per_threadgroup]]bildiriminde kullanılan veri türlerinin eşleşmesi gerekir.- Eğer
[[thread_position_in_threadgroup]]türüuint,uint2veyauint3ise,[[thread_index_in_threadgroup]]türüuintolmalıdır. [[thread_index_in_simdgroup]],[[threads_per_simdgroup]],[[simdgroup_index_in_threadgroup]],[[simdgroups_per_threadgroup]],[[dispatch_simdgroups_per_threadgroup]],[[quadgroup_index_in_threadgroup]],[[quadgroups_per_threadgroup]]ve[[dispatch_quadgroups_per_threadgroup]]bildiriminde kullanılan türlerushortveyauintolmalıdır. Bu yerleşik değişkenleri bildirmek için kullanılan türlerin eşleşmesi gerekir.
Tüm işletim sistemleri: Metal 3.1 ve sonrasında, dinamik bir kütüphanede veya ayrı derlenmiş bir ikili fonksiyonda kullanılması durumu hariç olmak üzere, bu öznitelikleri global değişkenler üzerinde belirtebilirsiniz.
Mesh Fonksiyonları
Mesh fonksiyonları, yürütmenin N boyutlu bir thread ızgarası üzerinde gerçekleştiği kernel fonksiyonuyla aynı yürütme modelini kullanır (bkz. bölüm 5.2.3.6).
Mesh fonksiyonu argümanları; sampler'lar, texture'lar, mesh<V, P, NV, NP, t> türündeki argümanlar ve device ile constant adres alanlarındaki buffer'ları içerebilir.
Eğer mesh fonksiyonunda mesh<V, P, NV, NP, t> türünde bir argüman varsa, bu argüman dışa aktarılacak mesh'i temsil eden belleğe yönelik opak bir handle'a işaret eder. Bu argümanın referans verdiği temel bellek, belirli bir threadgroup içindeki thread'ler arasında paylaşılır.
Mesh fonksiyonları, kernel fonksiyonunun yerleşik özniteliklerinin bir alt kümesini ve ayrıca [[amplification_count]], [[amplification_id]] ve [[payload]] özniteliklerini destekler. [[amplification_count]] ve [[amplification_id]] özniteliklerinin anlamları bölüm 5.2.3.1 Vertex Function Input Attributes ile aynıdır.
Metal 3.1 ve sonrasında, Tablo 5.13'te listelenen yerleşik öznitelikler sağlanır. amplification_count, amplification_id ve payload hariç olmak üzere bu öznitelikleri program kapsamındaki değişkenlerde belirtebilirsiniz.
Tablo 5.13. Mesh Fonksiyonu için Öznitelikler
amplification_count
Veri türleri: ushort veya uint
Açıklama: Her primitive örneği için üretilen çıktı vertex sayısı.
amplification_id
Veri türleri: ushort veya uint
Açıklama: Viewport ve render target dizi indeksleri için dizi indeks ofset eşlemeleri; bu sayede çoğaltılmış bir vertex farklı bir viewport ve render target'a yönlendirilebilir.
dispatch_quadgroups_per_threadgroup
Veri türleri: ushort veya uint
Açıklama: Dispatch sırasında belirtilen bir threadgroup'un quad-group yürütme genişliği.
dispatch_simdgroups_per_threadgroup
Veri türleri: ushort veya uint
Açıklama: Dispatch sırasında belirtilen bir threadgroup'un SIMD-group yürütme genişliği.
dispatch_threads_per_threadgroup
Veri türleri: ushort, ushort2, ushort3, uint, uint2 veya uint3
Açıklama: Dispatch sırasında belirtilen thread'ler için bir threadgroup'un thread yürütme genişliği.
payload
Veri türleri: object_data adres alanındaki kullanıcı tanımlı T için işaretçi veya l-value referansı (const nitelikli)
Açıklama: Payload, object shader'dan mesh shader'a aktarılan veridir. Payload işaretçisi veya referansı mesh ızgarasındaki tüm thread'ler için aynıdır. Payload belleği mesh fonksiyonu içinde salt okunurdur.
quadgroups_per_threadgroup
Veri türleri: ushort veya uint
Açıklama: Bir threadgroup'un quad-group yürütme genişliği.
simdgroup_index_in_threadgroup
Veri türleri: ushort veya uint
Açıklama: Bir threadgroup içindeki bir SIMD-group'un skaler indeksi.
simdgroups_per_threadgroup
Veri türleri: ushort veya uint
Açıklama: Bir threadgroup'un SIMD-group yürütme genişliği.
thread_index_in_quadgroup
Veri türleri: ushort veya uint
Açıklama: Bir quad-group içindeki bir thread'in skaler indeksi.
thread_index_in_simdgroup
Veri türleri: ushort veya uint
Açıklama: Bir SIMD-group içindeki bir thread'in skaler indeksi.
thread_index_in_threadgroup
Veri türleri: ushort veya uint
Açıklama: Bir threadgroup içindeki bir thread'in skaler indeksi.
thread_position_in_grid
Veri türleri: ushort, ushort2, ushort3, uint, uint2 veya uint3
Açıklama: Bir thread'in N boyutlu thread ızgarasındaki konumu.
thread_position_in_threadgroup
Veri türleri: ushort, ushort2, ushort3, uint, uint2 veya uint3
Açıklama: Bir thread'in threadgroup içindeki benzersiz konumu.
threadgroup_position_in_grid
Veri türleri: ushort, ushort2, ushort3, uint, uint2 veya uint3
Açıklama: Bir threadgroup'un bir ızgara içindeki benzersiz konumu.
threads_per_grid
Veri türleri: ushort, ushort2, ushort3, uint, uint2 veya uint3
Açıklama: Izgara boyutu.
threads_per_simdgroup
Veri türleri: ushort veya uint
Açıklama: Bir SIMD-group'un thread yürütme genişliği.
threads_per_threadgroup
Veri türleri: ushort, ushort2, ushort3, uint, uint2 veya uint3
Açıklama: Bir threadgroup'un thread yürütme genişliği.
Mesh Fonksiyonu Öznitelikleri için Kısıtlamalar
Mesh fonksiyonu öznitelikleri, kernel fonksiyonu öznitelikleriyle aynı kısıtlamalara sahiptir:
[[thread_position_in_grid]],[[threads_per_grid]],[[thread_position_in_threadgroup]],[[threads_per_threadgroup]],[[threadgroup_position_in_grid]],[[dispatch_threads_per_threadgroup]]ve[[threadgroups_per_grid]]bildiriminde kullanılan tür skaler veya vektör türü olmalıdır. Eğer vektör türü kullanılıyorsa, bileşen sayılarının eşleşmesi gerekir.[[thread_position_in_grid]]ve[[threads_per_grid]]bildiriminde kullanılan veri türlerinin eşleşmesi gerekir.[[thread_position_in_threadgroup]],[[threads_per_threadgroup]]ve[[dispatch_threads_per_threadgroup]]bildiriminde kullanılan veri türlerinin eşleşmesi gerekir.- Eğer
[[thread_position_in_threadgroup]]türüuint,uint2veyauint3ise,[[thread_index_in_threadgroup]]türüuintolmalıdır. [[thread_index_in_simdgroup]],[[threads_per_simdgroup]],[[simdgroup_index_in_threadgroup]],[[simdgroups_per_threadgroup]],[[dispatch_simdgroups_per_threadgroup]],[[quadgroup_index_in_threadgroup]],[[quadgroups_per_threadgroup]]ve[[dispatch_quadgroups_per_threadgroup]]bildiriminde kullanılan türlerushortveyauintolmalıdır ve bu yerleşik değişkenler için kullanılan türlerin eşleşmesi gerekir.
Stage Input
Vertex fonksiyonu çıktısı ve rasterizer tarafından üretilen fragment'ler, bir fragment fonksiyonuna fragment başına girişler haline gelir. [[stage_in]] özniteliği fragment başına girişleri bir araya getirebilir.
Bir vertex fonksiyonu, vertex ve instance kimliklerini kullanarak argüman olarak geçirilen buffer'lar içinde indeksleme yaparak vertex başına girişleri okuyabilir. Vertex başına girişleri bir araya getirip bunları bir vertex fonksiyonuna argüman olarak iletmek için girişleri [[stage_in]] özniteliği ile bildirin.
Bir kernel fonksiyonu, grid içindeki thread konumu veya threadgroup içindeki thread konumu kimliklerini kullanarak argüman olarak geçirilen buffer veya texture'larda indeksleme yaparak thread başına girişleri okur. Buna ek olarak, thread başına girişler [[stage_in]] özniteliği ile bildirilerek argüman olarak da geçirilebilir.
Bir vertex, fragment veya kernel fonksiyonunda [[stage_in]] özniteliği ile yalnızca bir argüman bildirebilirsiniz.
[[stage_in]] özniteliği ile bildirilen kullanıcı tanımlı bir yapı için, yapının üyeleri şunlar olabilir:
- Skaler bir tamsayı veya kayan noktalı değer.
- Tamsayı veya kayan noktalı değerlerden oluşan bir vektör.
- Fragment fonksiyonu girdisi için bir
interpolant<T, P>değeri.
stage_in özniteliğini kullanarak, packed vektörler, matrisler, yapılar, bit alanları, bir türe referanslar veya işaretçiler ya da skaler, vektör veya matris dizileri olan yapı üyelerini bildiremezsiniz.
float4 position [[position]];
float4 color;
float2 texcoord;
};
struct VertexInput {
float4 position [[attribute(0)]];
float3 normal [[attribute(1)]];
half4 color [[attribute(2)]];
half2 texcoord [[attribute(3)]];
};
constexpr constant uint MAX_LIGHTS = 4;
struct LightDesc {
uint num_lights;
float4 light_position[MAX_LIGHTS];
float4 light_color[MAX_LIGHTS];
float4 light_attenuation_factors[MAX_LIGHTS];
};
constexpr sampler s = sampler(
coord::normalized,
address::clamp_to_zero,
filter::linear
);
5.2.4.1 Vertex Fonksiyonu Çıkış Örneği
Aşağıdaki örnek, stage_in özniteliğini kullanarak vertex başına girişlerin nasıl iletileceğini gösterir.
struct VertexOutput {
float4 position [[position]];
float4 color;
float2 texcoord;
};
struct VertexInputData {
float4 position;
float3 normal;
float2 texcoord;
};
constexpr constant uint MAX_LIGHTS = 4;
struct LightDesc {
uint num_lights;
float4 light_position[MAX_LIGHTS];
float4 light_color[MAX_LIGHTS];
float4 light_attenuation_factors[MAX_LIGHTS];
};
constexpr sampler s = sampler(
coord::normalized,
address::clamp_to_edge,
filter::linear
);
vertex VertexOutput2
render_vertex(
VertexInput v_in [[stage_in]],
constant float4x4& mvp_matrix [[buffer(1)]],
constant LightDesc& lights [[buffer(2)]],
uint v_id [[vertex_id]])
{
VertexOutput v_out;
v_out.position = v_in.position * mvp_matrix;
v_out.color = do_lighting(v_in.position, v_in.normal, lights);
…
return v_out;
}
5.2.4.2 Fragment Fonksiyonu Giriş Örneği
Bölüm 5.2.3.3'teki bir örnek daha önce process_vertex adlı vertex fonksiyonunu tanıtır; bu fonksiyon her vertex için bir VertexOutput yapısı döndürür. Aşağıdaki örnekte process_vertex çıktısı, render_pixel adlı bir fragment fonksiyonuna giriş olacak şekilde boru hattına aktarılır; bu nedenle fragment fonksiyonunun ilk argümanı [[stage_in]] özniteliğini ve gelen VertexOutput türünü kullanır.
(render_pixel içinde, imgA ve imgB 2D texture'ları bölüm 6.12.3'te tanıtılan yerleşik sample fonksiyonunu çağırır.)
struct VertexOutput2 {
constant float4x4& mvp_matrix [[buffer(1)]],
constant LightDesc& lights [[buffer(2)]],
uint v_id [[vertex_id]])
{
VertexOutput v_out;
v_out.position = v_in[v_id].position * mvp_matrix;
v_out.color = do_lighting(v_in[v_id].position,
v_in[v_id].normal, lights);
v_out.texcoord = v_in[v_id].texcoord;
return v_out;
}
fragment float4
render_pixel(VertexOutput2 input [[stage_in]],
texture2d<float> imgA [[texture(0)]],
texture2d<float> imgB [[texture(1)]])
{
float4 tex_clr0 = imgA.sample(s, input.texcoord);
float4 tex_clr1 = imgB.sample(s, input.texcoord);
// Rengi hesapla.
float4 clr = compute_color(tex_clr0, tex_clr1, …);
return clr;
}
Aşağıdaki örnek, thread başına girişleri geçirmek için stage_in özniteliğinin nasıl kullanılacağını gösterir. Bir kernel fonksiyonundaki stage_in özniteliği, fonksiyon içinde thread başına girişleri bildirmek için kullanılan veri türü ile bu girişleri depolamak için kullanılan gerçek veri türünü birbirinden ayırmanıza olanak tanır.
5.2.4.3 Kernel Fonksiyonu Thread Başına Giriş Örneği
struct PerThreadInput {
float4 a [[attribute(0)]];
float3 b [[attribute(1)]];
half4 c [[attribute(2)]];
half2 d [[attribute(3)]];
};
kernel void
my_kernel(PerThreadInput thread_input [[stage_in]],
device float *ptr [[buffer(0)]])
{
extern constant float4 a;
static constant float4 b; // Burada static bir hatadır.
static float c; // Burada static bir hatadır.
}
5.3 Depolama Sınıfı Belirleyicileri
Metal, static ve extern depolama sınıfı belirleyicilerini destekler. Metal, thread_local depolama sınıfı belirleyicisini desteklemez.
extern depolama sınıfı belirleyicisini yalnızca program kapsamındaki fonksiyonlar ve değişkenler için veya bir fonksiyon içinde bildirilen değişkenler için kullanabilirsiniz. static depolama sınıfı belirleyicisi yalnızca program kapsamındaki device değişkenleri içindir (bkz. Bölüm 4.2) ve bir grafik veya kernel fonksiyonu içinde bildirilen değişkenler için kullanılamaz.
extern constant float4 noise_table[256];
static constant float4 color_table[256] = {…}; // Burada static kullanılabilir.
extern void my_foo(texture2d<float> img);
extern void my_bar(device float *a);
[[kernel]] void
my_kernel(texture2d<float> img [[texture(0)]],
device float *ptr [[buffer(0)]])
{
…
my_foo(img);
…
my_bar(ptr);
…
}
5.4 Sampling ve Interpolation Öznitelikleri
Sampling ve interpolation öznitelikleri, interpolant<T,P> türündeki üyeler hariç olmak üzere stage_in özniteliği ile bildirilen fragment fonksiyonu girişleriyle kullanılır. Bu öznitelik, fragment fonksiyonunun hangi örnekleme yöntemini kullandığını ve interpolasyonun nasıl gerçekleştirileceğini belirler; buna perspektif düzeltmeli interpolasyon, doğrusal interpolasyon veya interpolasyon yapılmaması dahil olabilir.
Sampling ve interpolation özniteliği, türü skaler veya vektör olan herhangi bir stage_in yapı üyesi üzerinde belirtilebilir.
Desteklenen öznitelikler:
center_perspectivecenter_no_perspectivecentroid_perspectivecentroid_no_perspectivesample_perspectivesample_no_perspectiveflat
center_perspective, aşağıdaki istisnalar dışında varsayılan sampling ve interpolation özniteliğidir:
[[position]]özniteliğine sahip bir değişken için tek geçerli sampling ve interpolation özniteliğicenter_no_perspective'tir.- Bir tamsayı değişkeni için tek geçerli sampling ve interpolation özniteliği
flat'tir.
Bir perspektif özniteliği (center_perspective, centroid_perspective veya sample_perspective), bir primitive üzerindeki değerlerin perspektif doğrulamalı şekilde enterpole edildiğini belirtir.
Bir perspektif olmayan öznitelik (center_no_perspective, centroid_no_perspective veya sample_no_perspective), bir primitive üzerindeki değerlerin ekran koordinatlarında doğrusal olarak enterpole edildiğini belirtir.
Center öznitelik varyantları (center_perspective ve center_no_perspective), örneklemenin her pikselin merkezini kullanmasına neden olur.
Sampling öznitelik varyantları (sample_perspective ve sample_no_perspective), interpolasyonun piksel merkezi yerine bir örnek konumunda yapılmasına neden olur. Bu özniteliklerden biri kullanıldığında, bu değişkenleri kullanan fragment fonksiyonu (veya fragment fonksiyonundaki kod blokları) fragment başına değil örnek başına çalıştırılır.
Eğer bir centroid öznitelik varyantı belirtilmişse (centroid_perspective ve centroid_no_perspective), örneklenen interpolasyon noktası hem primitive'in içinde hem de pikselin centroid'inde olmalıdır.
Kullanıcı tanımlı bir yapının üyeleri için interpolasyon belirtme örneği:
struct FragmentInput {
float4 pos [[center_no_perspective]];
float4 color [[center_perspective]];
float2 texcoord;
int index [[flat]];
float f [[sample_perspective]];
interpolant<float4, interpolation::perspective> icolor;
};
Metal 2.4 ve sonraki sürümlerde, örnekleme ve enterpolasyon özniteliği, türü bir yapı olan herhangi bir stage_in yapı üyesi üzerinde de belirtilebilir. Yapı içindeki tüm üyeler belirtilen örnekleme ve enterpolasyon niteleyicilerini devralır.
Örnekleme ve enterpolasyon niteleyicilerinin devralındığı bir yapı içindeki alan bildirimleri yalnızca aşağıdaki durumlardan biri doğruysa geçerlidir:
- Alan bildirimi, devralınan ile aynı örnekleme ve enterpolasyon niteleyicilerine sahiptir.
- Alanın türü, devralınan niteleyicilerle uyumludur.
Yapı türleri üzerinde enterpolasyon belirtme örneği:
struct VOut {
float4 pos [[position]];
};
struct POut {
float4 color0;
float4 color1;
};
[[mesh]] void mesh_function(mesh<VOut, POut, 3, 1, topology::triangle> m)
{
}
struct FragmentInput {
VOut vin;
POut pin [[center_perspective]];
};
[[fragment]] float4
my_fragment(float2 tex_coord [[stage_in]],
texture2d<float> img [[texture(0)]],
sampler s [[sampler(0)]],
float4 framebuffer [[color(0)]])
{
return c = mix(img.sample(s, tex_coord), framebuffer, mix_factor);
}
5.5 Parça-Başına Fonksiyon ve Örnek-Başına Fonksiyon
Genellikle fragment fonksiyonunu parça-başına (per-fragment) yürütürsünüz. Örnekleme özniteliği, fragment girdisi enterpolasyonunun örnek-başına mı yoksa parça-başına mı olduğunu belirler. Benzer şekilde, [[sample_id]] özniteliği mevcut örnek indeksini tanımlar ve [[color(m)]] özniteliği hedef fragment rengini veya (çok örneklemeli bir renk eklentisi için) örnek renk değerini tanımlar.
Bu özniteliklerden herhangi birini fragment fonksiyonunda bağımsız değişkenlerle birlikte kullanırsanız, fragment fonksiyonu piksel-başına yerine örnek-başına çalıştırılabilir. Gerçekleştirim, yalnızca örnek-başına değerlere bağlı olan kodu örnek-başına yürütmeye karar verebilir; fragment fonksiyonunun geri kalanı ise parça-başına çalıştırılır.
Yalnızca örnek erişimi belirtilmiş girdiler (veya [[sample_id]] ya da [[color(m)]] özniteliği ile bildirilenler) parça-başına ve örnek-başına çağrılar arasında farklılık gösterir; diğer girdiler yine piksel merkezinde enterpolasyon yapılır.
5.6 Imageblock'lar
Bu bölüm ve alt bölümleri, imageblock'lar için çeşitli öznitelikleri açıklar. Bunlar arasında, bir fragment fonksiyonu için açık bir imageblock yerleşimi ile giriş ve çıkış imageblock'larını belirten [[imageblock_data(type)]] özniteliği de bulunur.
5.6.1 Ana ve Görünüm Imageblock'larının Veri Üyelerini Eşleştirme
Bir fragment fonksiyonu için imageblock veri türünün bir veri üyesi için öznitelik adı belirtmek amacıyla [[user(name)]] özniteliğini kullanabilirsiniz.
Fragment fonksiyonunda belirtilen imageblock yapısı, ana açık imageblock yapısının bir alt kümesi ise, fragment fonksiyonunda kullanılan imageblock yapısında bildirilen veri üyeleri ile ana açık imageblock yapısında bildirilen karşılık gelen veri üyelerini eşleştirmek için aşağıdaki kurallar uygulanır:
[[user(name)]]ile verilen her öznitelik adı, imageblock içindeki her veri üyesi için benzersiz olmalıdır.[[user(name)]]ile verilen öznitelik adı, ana açık imageblock yapısında bildirilen bir veri üyesi ile eşleşmelidir ve bunların ilişkili veri türleri de aynı olmalıdır.[[user(name)]]özniteliği belirtilmemişse, fragment fonksiyonu için imageblock veri türünde bildirilen veri üyesi adı ve türü ile ana imageblock yapısındaki veri üyesi adı ve türü eşleşmelidir. Ayrıca veri üyesi, görünüm veya ana imageblock yapısında bulunan iç içe geçmiş bir yapı içinde yer alamaz.
[[user(name)]] özniteliğinin kullanıldığı örnek:
// Açık yerleşimli imageblock veri ana yapısı.
struct IM {
rgba8unorm<half4> a [[user(my_a), raster_order_group(0)]];
rgb9e5<float4> b [[user(my_b), raster_order_group(0)]];
int c [[user(my_c), raster_order_group(0)]];
float d [[user(my_d), raster_order_group(0)]];
};
// Giriş için görünüm yapısı.
struct IVIn {
rgb9e5<float4> x [[user(my_b)]]; // IM::b ile eşleşir
float y [[user(my_d)]]; // IM::d ile eşleşir
};
// Çıkış için görünüm yapısı.
struct IVOut {
int z [[user(my_c)]]; // IM::c ile eşleşir
};
// Fragment dönüş yapısı.
struct FragOut {
IVOut i [[imageblock_data(IM)]];
};
[[fragment]] FragOut
my_fragment(IVIn i [[imageblock_data(IM)]], …)
{
}
[[user(name)]] özniteliği olmadan örnek:
struct IM {
int c;
};
struct IVIn {
rgb9e5<float4> b; // IM::b ile eşleşir
float d; // IM::d ile eşleşir
};
struct IVOut {
int c; // IM::c ile eşleşir
};
struct FragOut {
IVOut i [[imageblock_data(IM)]];
};
fragment FragOut
my_fragment(IVIn i [[imageblock_data(IM)]], …)
{
FragOut fragOut;
… = i.b;
… = i.d;
fragOut.i.c = …;
return fragOut;
}
İç içe geçmiş yapılar da kullanılabilir:
struct A {
rgba8unorm<half4> a [[user(A_a)]];
rgb9e5<float4> b [[user(A_b)]];
};
struct B {
int a [[user(B_a), raster_order_group(1)]];
float b [[user(B_b), raster_order_group(2)]];
};
struct IM {
A a [[user(A), raster_order_group(0)]];
B b [[user(B)]];
};
struct IVIn {
A x [[user(A)]]; // IM::a ile eşleşir
};
struct IVOut {
B y [[user(B)]]; // IM::b ile eşleşir
rgb9e5<float4> z [[user(A_b)]]; // IM::A::b ile eşleşir
};
Bir görünüm yapısının her alanı tam olarak bir ana yapı alanına karşılık gelmelidir. Ana yapı alanı, üst seviye bir yapı alanına veya iç içe geçmiş bir yapı içindeki bir alana işaret edebilir. İki veya daha fazla görünüm yapısı alanının aynı ana yapı alanına takma ad (alias) vermesi geçersizdir.
struct M {
struct A {
int a [[user(x)]];
} b [[user(y), raster_order_group(0)]];
};
struct V {
int a [[user(x)]];
M::A b [[user(y)]]; // Geçersiz: b, a ile alias oluşturur
};
fragment void
f(V i [[imageblock_data(M)]])
{
…
}
5.6.2 Imageblock'lar ve Raster Order Groups
Açık imageblock türlerinde [[color(n)]] özniteliği ile bildirilen veri üyeleri bulunamaz.
Bir kernel fonksiyonunda, imageblock veri üyeleri üzerinde belirtilen [[raster_order_group(index)]] özniteliği yok sayılır.
Bir fragment fonksiyonunda, ana açık imageblock veri yapısının veri üyeleri için [[raster_order_group(index)]] özniteliğini belirtmeniz gerekir.
Ana açık imageblock yapısı, yapı türünde veri üyeleri içeriyorsa, [[raster_order_group(index)]] özniteliğini ya iç içe yapının tüm veri üyeleri için ya da doğrudan iç içe yapı için belirtebilirsiniz.
Örnek:
struct S {
rgb9e5<half3> normal;
float factor;
};
struct gBufferData {
S s [[raster_order_group(1)]];
rgb11b10f<half3> lighting [[raster_order_group(2)]];
};
Yanlış kullanım örneği:
struct S {
rgb9e5<half3> normal [[raster_order_group(0)]];
float factor [[raster_order_group(1)]];
};
struct IM {
half3 color [[raster_order_group(0)]];
S s[2]; // Derleme hatası
rgb11b10f<half3> lighting [[raster_order_group(2)]];
};
5.6.3 Fragment Fonksiyonları için Imageblock Yerleşimleri
Dizi olarak bildirilen veri üyeleri, dizinin tüm elemanları için tek bir raster order group ile ilişkilendirilir.
Bir yapı dizisi için raster order group belirtme örneği:
struct S {
rgb9e5<half3> normal;
float factor;
};
struct IM {
half3 color [[raster_order_group(0)]];
S s [[raster_order_group(1)]][2];
rgb11b10f<half3> lighting [[raster_order_group(2)]];
};
Imageblock'lar iki şekilde bildirilebilir:
- Bir renk eklentisi olarak; bu durumda imageblock'un depolama yerleşimi fragment fonksiyonunda bilinmez. Bu yöntem örtük imageblock yerleşimi kullanır.
- Fragment fonksiyonunun imageblock'un depolama yerleşimini açıkça belirttiği bir yapı olarak. Bu yöntem açık imageblock yerleşimi kullanır.
5.6.3.1 Fragment Fonksiyonları için Örtük Imageblock Yerleşimi
(macOS: Apple silicon için Metal 2.3 ve sonrası imageblock desteği sağlar.)
Bir fragment fonksiyonunda imageblock verisine (bir piksel ile ilişkili imageblock içindeki tüm veri üyeleri) erişebilirsiniz. Metal, renk eklentilerinin davranışıyla eşleşen örtük bir imageblock oluşturur (fragment fonksiyonuna giriş ve çıkış için). Bu modda, fragment fonksiyonunda açıklanan renk eklentileri ile ilişkili türler ALU türleridir (yani fragment fonksiyonunda hesaplama yapmak için kullanılan türlerdir). Metal çalışma zamanı gerçek piksel depolama biçimini tanımlar.
Imageblock verisine renk eklentileri olarak erişirken, bölüm 2.7'de açıklanan piksel depolama türlerini imageblock slice yapısı içinde bildiremezsiniz.
T türünde örtük yerleşime sahip bir imageblock veri düzeni için T, aşağıdakilerden birini sağlayan üyelerden oluşan bir yapıdır:
- Bu listedeki kısıtları sağlayan üyelere sahip bir yapı türü.
- Skaler veya vektör, tamsayı veya kayan noktalı veri türü.
- Bölüm 2.7'de açıklanan piksel veri türlerinden biri.
- Bu türlerden oluşan bir dizi.
- Ya da bu türlerle oluşturulmuş bir yapı.
- Bir renk eklentisine sahip olmak (bkz. bölüm 5.2.3.4'teki Tablo 5.5'te açıklanan
[[color(m)]]özniteliği). Renk indeksim,Tyapısının her üyesi (ve alt üyesi) için benzersiz olmalıdır.
5.6.3.2 Fragment Fonksiyonları için Açık Imageblock Yerleşimi
Açık yerleşime sahip imageblock verisinin yerleşimi, renk eklentilerinde olduğu gibi çalışma zamanı tarafından değil, gölgelendirici fonksiyon içinde bildirilir. Açık yerleşim için imageblock verisini bir yapı olarak tanımlarsınız.
Parça-başına imageblock verisinin her veri üyesi bu yapı içinde bildirilebilir.
Imageblock yapısının veri üyeleri, yapı içinde bildirilen her veri üyesi türü için uygun hizalama kurallarını kullanarak gerçek yapı yerleşimini ve boyutunu belirler.
Bir fragment fonksiyonu, parça-başına imageblock verisindeki bir veya daha fazla veri üyesini okuyabilir ve yine parça-başına imageblock verisindeki bir veya daha fazla veri üyesine yazabilir. Fragment fonksiyonuna giriş ve çıkış imageblock verisini bir yapı olarak bildirebilirsiniz.
Giriş ve çıkış imageblock yapıları şu biçimlerden biri olabilir:
- Tamamen açık imageblock yapısı (ana açık imageblock yapısı olarak adlandırılır), veya
- Ana açık imageblock yapısının bir alt kümesi (imageblock görünüm yapısı olarak adlandırılır).
İkinci durumda, fragment fonksiyonu üzerinde belirtilen giriş ve çıkış imageblock veri yapısı ile birlikte [[imageblock_data(type)]] özniteliğini kullanırsınız; burada type, tamamen açık imageblock veri yapısını belirtir.
Eğer giriş bağımsız değişkeni veya çıkış yapı elemanı üzerinde type olmadan [[imageblock_data]] özniteliğini belirtirseniz, varsayılan olarak fragment fonksiyonu giriş veya çıkış için ana açık imageblock veri yapısını kullanır.
Örnek
struct I {
float c [[color(0)]];
};
struct FragOut {
float c [[color(0)]];
I i [[imageblock_data]];
};
[[fragment]] FragOut
my_fragment(I i [[imageblock_data]])
{
FragOut fragOut;
...
return fragOut;
}
Fragment fonksiyonları hem örtük bir imageblock'a hem de açık bir imageblock'a ayrı giriş bağımsız değişkenleri olarak veya dönüş yapısı içindeki alanlar olarak erişebilir.
Varsayılan olarak açık imageblock depolaması, örtük imageblock depolamasından ayrıdır. Açık ve örtük imageblock arasında depolama paylaşmak için 5.6.5 bölümüne bakın.
imageblock<T> türü (<metal_imageblocks> başlık dosyasında tanımlıdır) yalnızca kernel fonksiyonunda bildirilen bağımsız değişkenler için veya kernel fonksiyonu tarafından çağrılan kullanıcı fonksiyonlarında kullanılabilir. Yalnızca bir kernel fonksiyonunun imageblock<T> türünde bildirilen bir bağımsız değişkeni olabilir.
Bir imageblock içindeki veriler yalnızca aynı threadgroup içindeki iş parçacıkları tarafından görülebilir.
Bir kernel fonksiyonuna verilen bu imageblock bağımsız değişkeni aşağıdaki şablon türü olarak bildirilir:
class imageblock_layout_explicit;
class imageblock_layout_implicit;
template<typename T, typename L>
struct imageblock;
Aşağıdaki kısıtlamalarla birlikte:
Tbir yapıdır;Tüyeleri aşağıdakilerden herhangi biri olabilir:- skalerler
- vektörler ve packed vektörler
- piksel veri türleri
- elemanları bu listedeki türlerden biri olan bir dizi
- üyeleri bu listedeki türlerden biri olan bir yapı
L, yaimageblock_layout_explicitya daimageblock_layout_implicitolur.
5.6.5 Açık ve Örtük Imageblock'ların Alias Kullanımı
Örtük yerleşime sahip bir imageblock için (imageblock_layout_implicit), yapıdaki her üyenin bir renk eklentisi olabilir (bkz. bölüm 5.2.3.4'teki Tablo 5.5'te açıklanan [[color(m)]] özniteliği). Renk indeksi m, T yapısının her üyesi (ve alt üyesi) için benzersiz olmalıdır.
Bir imageblock yerleşimi belirtmezseniz, derleyici yerleşimi T temelinde çıkarır. Eğer T, örtük veya açık bir imageblock ile uyumlu değilse derleme hatası oluşur.
Hem açık hem de örtük imageblock'lar bir kernel fonksiyonuna bağımsız değişken olarak verilebilir. Bu durum, açık ve örtük imageblock yapılarını fragment ve kernel fonksiyonları arasında paylaşmayı da kolaylaştırır.
Varsayılan olarak açık imageblock depolaması, örtük imageblock depolamasından ayrıdır. Açık ve örtük imageblock arasında depolama paylaşmak için 5.6.5 bölümüne bakın.
Varsayılan olarak açık ve örtük imageblock'lar alias oluşturmaz. Açık imageblock tahsisini örtük imageblock ile tamamen veya kısmen alias yapmak için aşağıdaki öznitelikleri kullanabilirsiniz:
[[alias_implicit_imageblock]]— açık imageblock tahsisinin örtük imageblock ile tamamen alias oluşturduğunu belirtir.[[alias_implicit_imageblock_color(n)]]— açık imageblock tahsisinin,color(n)ile belirtilen belirli bir renk eklentisinden başlayarak örtük imageblock ile alias oluşturduğunu belirtir.
Eğer n, bildirilen en küçük ve en büyük eklentiler arasında olup tanımlanmamış bir eklentiye işaret ederse derleme zamanında hata oluşur. Eğer n, bildirilen eklenti sayısını aşarsa derleme başarılı olur ancak öznitelik yok sayılır.
Bir kernel veya fragment fonksiyonu, alias yapılmış imageblock veri üyelerini açık imageblock ve ona bağlı üye fonksiyonları kullanarak değiştirirse, açık imageblock üzerinden alias yapılmış örtük imageblock veri üyelerine erişmenin davranışı tanımsızdır.
Örnek
struct I {
rgba8unorm<half4> a;
rgb9e5<float4> b;
int c;
float d;
};
struct FragOut {
float4 finalColor [[color(0)]];
I i [[imageblock_data, alias_implicit_imageblock_color(1)]];
};
[[fragment]] FragOut
my_fragment(I i [[imageblock_data]], ...)
{
FragOut fragOut;
...
return fragOut;
}
5.6.6 Imageblock'lar ve Function Constant'lar
Bir imageblock yapısının veri üyeleri ile [[function_constant(name)]] özniteliğini, fragment veya kernel fonksiyonuna giriş olarak ya da bu fonksiyonlardan dönen çıkış olarak kullanmayın.
5.7 Grafik Fonksiyonu — İmza Eşleştirme
Bir grafik fonksiyonu imzası, bir grafik fonksiyonuna giriş olan veya ondan çıkış olarak dönen parametrelerin listesidir.
Bir vertex fonksiyonu ile fragment fonksiyonu arasında iki tür veri aktarabilirsiniz:
- kullanıcı tanımlı değişkenler
- yerleşik değişkenler
Bir fragment fonksiyonuna örnek başına girişleri [[stage_in]] niteliği ile tanımlayabilirsiniz. Bunlar ilişkili bir vertex fonksiyonu tarafından üretilir.
Yerleşik değişkenleri 5.2.3 bölümünde tanımlanan niteliklerden biriyle tanımlayabilirsiniz.
Örnekler şunlardır:
[[position]],[[point_size]]veya[[clip_distance]]ile belirtilen vertex fonksiyonu çıktısı.[[point_coord]],[[front_facing]],[[sample_id]]veya[[sample_mask]]ile belirtilen rasterizer çıktısı.[[color]]kullanılarak framebuffer renk değerine referans veren bir fragment fonksiyonu girdisi.
Her zaman [[position]] niteliğini belirten bir yerleşik değişken döndürün. [[point_size]] veya [[clip_distance]] niteliğine sahip yerleşik değişkenler için, bu nitelik aynı zamanda karşılık gelen vertex fonksiyonu çıktısını da belirtmelidir. Eğer bunlar kullanılır ve bir fragment fonksiyonunda okunursa, shader tanımsız davranış sergiler.
Ayrıca rasterizer çıktısı olan veya framebuffer renk değerlerine referans veren yerleşik değişkenleri, uygun niteliği kullanarak fragment fonksiyonu girdisi olarak da tanımlayabilirsiniz.
Herhangi bir kullanıcı tanımlı değişken için bir nitelik adı belirtmek amacıyla [[user(name)]] niteliği sözdizimini de kullanabilirsiniz.
Vertex — Fragment İmza Eşleşmesi
Bir vertex fonksiyonu ile bir fragment fonksiyonunun imzaları aşağıdaki koşullar sağlanıyorsa eşleşmiş sayılır.
[[stage_in]] ile tanımlanan bir fragment fonksiyonu argümanı için, ilişkili türdeki her öğe aşağıdakilerden biri olabilir:
- Rasterizer tarafından üretilmiş bir yerleşik değişken
- Fragment fonksiyonuna girdi olarak geçirilen bir framebuffer renk değeri
- Bir vertex fonksiyonu tarafından üretilmiş kullanıcı kaynaklı bir çıktı
Rasterizer tarafından üretilen yerleşik değişkenler veya framebuffer renk değerleri için, vertex dönüş türündeki öğelerle eşleşen bir tür ilişkilendirme zorunluluğu yoktur.
Kullanıcı tarafından üretilen çıktılar için aşağıdaki kurallar geçerlidir:
[[user(name)]]kullanarak bir nitelik adı belirtirseniz, bu nitelik adı vertex fonksiyonunun dönüş türündeki bir öğe ile eşleşmelidir.[[user(name)]]belirtmezseniz, argüman adı ve türleri eşleşmelidir.- Her iki durumda da karşılık gelen veri türleri eşleşmelidir veya fragment fonksiyonu argüman türü
interpolant<T, P>olmalıdır; buradaT, vertex dönüş türündeki öğe türüdür.
Uyumlu İmza Örneği
struct VertexOutput {
float4 position [[position]];
float3 normal;
float2 texcoord;
};
vertex VertexOutput
my_vertex(...)
{
VertexOutput v;
...
return v;
}
fragment float4
my_fragment(VertexOutput f [[stage_in]], ...)
{
float4 clr;
...
return clr;
}
Başka bir uyumlu örnek:
fragment float4
my_fragment2(VertexOutput f [[stage_in]],
bool is_front_face [[front_facing]], ...)
{
float4 clr;
...
return clr;
}
Başka Bir Uyumlu İmza Örneği
struct FragInput {
float3 frag_normal [[user(normal)]];
float4 position [[position]];
float4 framebuffer_color [[color(0)]];
bool is_front_face [[front_facing]];
};
fragment float4
my_fragment(FragInput f [[stage_in]], ...)
{
float4 clr;
...
return clr;
}
Uyumsuz İmza Örneği (Tür Uyumsuzluğu)
VertexOutput içindeki normal veri türü (float3), FragInput içindeki normal türü (half3) ile eşleşmez.
struct VertexOutput {
float4 position [[position]];
float3 normal;
float2 texcoord;
};
struct FragInput {
float4 position [[position]];
half3 normal;
};
Uyumsuz İmza Örneği (Nitelik Adı Uyumsuzluğu)
VertexOutput içindeki normal için nitelik indeksi (normal), FragInput içindeki indeks (foo) ile eşleşmez.
struct VertexOutput {
float4 position [[position]];
float3 normal [[user(normal)]];
float2 texcoord [[user(texturecoord)]];
};
struct FragInput {
float3 normal [[user(foo)]];
float4 position [[position]];
};
vertex VertexOutput
my_vertex_shader(...)
{
VertexOutput v;
...
return v;
}
fragment float4
my_fragment_shader(FragInput f [[stage_in]], ...)
{
float4 clr;
...
return clr;
}
5.7.2 Mesh – Fragment İmza Eşleşmesi
Mesh fonksiyonundan fragment fonksiyonuna mesh<V, P, NV, NP, t> türündeki vertex (V) ve primitive (P) üzerinden iki tür veri aktarabilirsiniz:
- kullanıcı tanımlı değişkenler
- yerleşik değişkenler
vertex (V) içinde tanımlanan vertex başına mesh çıktıları her zaman enterpolasyona tabi tutulur; buna karşılık primitive (P) içinde tanımlanan primitive başına mesh çıktıları hiçbir zaman enterpolasyona tabi tutulmaz.
Bu fark nedeniyle, kullanıcı tarafından üretilen çıktılar için imza eşleşmesi kuralları 5.7.1 bölümünde açıklananlardan farklı şekilde uyarlanmıştır.
Verilen bir fragment girdisi, vertex (V) ve primitive (P) içindeki kullanıcı kaynaklı bir mesh çıktısı ile şu koşullarda eşleşir:
[[user(name)]]kullanarak bir nitelik adı belirtirseniz, bu nitelik adı mesh çıktı dönüş türündeki bir öğe ile eşleşmelidir.[[user(name)]]belirtmezseniz, argüman adı ve türleri eşleşmelidir.
Her iki durumda da karşılık gelen veri türleri eşleşmelidir veya fragment fonksiyonu argüman türü interpolant<T, P> olmalıdır; burada T, vertex dönüş türündeki öğe türüdür.
Bir mesh fonksiyonu ile fragment fonksiyonu, kullanıcı tarafından üretilmiş mesh çıktılarıyla kullanıcı tarafından üretilmiş girdiler açısından aşağıdaki durumlarda eşleşen imzalara sahiptir:
- Düz (flat) enterpolasyon kullanan kullanıcı kaynaklı bir fragment girdisi için, eşleşen bir primitive başına mesh çıktısı vardır ve bu çıktı fragment girdisine enterpolasyon uygulanmadan aktarılır.
- Düz olmayan (non-flat) enterpolasyon kullanan kullanıcı kaynaklı bir fragment girdisi için, eşleşen bir vertex başına mesh çıktısı vardır ve bu çıktı primitive boyunca düz olmayan vertex çıktılarıyla aynı yöntemle enterpole edilir.
5.8 Program Kapsamlı Fonksiyon Sabitleri
Tüm OS sürümleri: Metal 1.2 ve sonrası fonksiyon sabitlerini destekler.
Metal 2 ve sonrasında bir fonksiyon sabitini şu amaçlarla kullanabilirsiniz:
- bir kaynağın bağlama numarasını belirtmek (bkz. bölüm 5.8.1.4)
color()veyaraster_order_groupnitelikleri için indeksi belirtmek (bölüm 5.8.1.5)- bir yapı öğesinin isteğe bağlı olduğunu belirtmek (bölüm 5.8.1.6)
Fonksiyon sabitleri, bir fonksiyonun birden fazla varyantının oluşturulmasını sağlar.
Fonksiyon sabitleri kullanılmadan, farklı özellikleri etkinleştirmek amacıyla farklı ön işlemci makro tanımlarıyla aynı fonksiyonu birçok kez derleyebilirsiniz (bir ubershader). Ubershader'lar için ön işlemci makrolarını çevrimdışı derleme ile kullanmak çok sayıda varyant oluşmasına ve gölgelendirme fonksiyonu kütüphanesi varlıklarının boyutunda önemli bir artışa yol açabilir.
Fonksiyon sabitleri, ön işlemci makrolarıyla benzer kullanım kolaylığı sağlar ancak belirli varyantların üretilmesini pipeline durumunun oluşturulması aşamasına taşır; böylece varyantları çevrimdışı derlemek zorunda kalmazsınız.
5.8.1 Program Kapsamlı Fonksiyon Sabitlerini Belirtme
Aşağıdaki nitelikle bildirilen (veya başlatılan) program kapsamlı değişkenler fonksiyon sabitleridir.
Fonksiyon sabitleri şu amaçlarla kullanılabilir:
Derlenecek kod yollarını kontrol etmek.
Bir fonksiyonun isteğe bağlı argümanlarını belirtmek (grafik, kernel veya kullanıcı fonksiyonları).
[[stage_in]]niteliğine sahip bir yapının isteğe bağlı öğelerini belirtmek.Eşleşen bir primitive başına mesh çıktısı vardır ve çıktı enterpolasyon uygulanmadan fragment girdisine aktarılır.
Eşleşen bir vertex başına mesh çıktısı vardır ve çıktı enterpole edilir.
[[function_constant(index)]]
index değeri 0 ile 65535 arasında olmalıdır.
Fonksiyon sabitlerini Metal fonksiyon kaynak kodunda başlatmazsınız. Bunun yerine, Metal API içinde MTLFunctionDescriptor kullanarak özelleştirilmiş bir fonksiyon (MTLFunction) oluştururken değerlerini belirtirsiniz. index değeri, çalışma zamanında fonksiyon sabiti değişkenine (adı yerine) referans verebilen bir konum indeksini belirtir.
Örnekler
constant int a [[function_constant(0)]];
constant bool b [[function_constant(2)]];
Fonksiyon sabitleri yalnızca skaler veya vektör türü olabilir. Bir fonksiyon sabiti için kullanıcı tanımlı bir tür veya bir skaler ya da vektör türünden dizi kullanmak derleme hatasıyla sonuçlanır.
Fonksiyon sabitleri a ve b değerlerini render veya compute pipeline durumunun oluşturulması sırasında belirlersiniz.
Fonksiyon sabitlerini ayrıca constant adres alanında bildirilen program kapsamlı değişkenleri başlatmak için de kullanabilirsiniz.
Örnekler
constant int a [[function_constant(0)]];
constant bool b [[function_constant(2)]];
constant bool c = ((a == 1) && b);
constant int d = (a * 4);
Bir fonksiyon sabitinin tanımlanmış ve kullanılabilir olup olmadığını belirlemek için aşağıdaki yerleşik fonksiyonu kullanabilirsiniz. name, fonksiyon sabiti değişkenine karşılık gelir.
bool is_function_constant_defined(name)
Fonksiyon sabiti değişkeni tanımlıysa true, aksi halde false döndürür.
Eğer bir fonksiyon sabiti değişkeninin değeri pipeline durumu oluşturulurken tanımlanmazsa ve render veya compute pipeline durumu ile belirtilen grafik ya da kernel fonksiyonu bu fonksiyon sabitlerini kullanıyorsa, is_function_constant_defined(name) false döndürür.
5.8.1.1 Derlenecek Kod Yollarını Kontrol Etmek İçin Fonksiyon Sabitleri
Fonksiyon sabitleri için ön işlemci makroları kullanan aşağıdaki fonksiyonu ele alalım:
float4 position [[position]];
float4 color;
};
struct VertexInput {
float4 position [[attribute(0)]];
float4 offset [[attribute(1)]];
float4 color [[attribute(2)]];
};
struct VertexOutput {
vertex VertexOutput
myVertex(VertexInput vIn [[stage_in]])
{
VertexOutput vOut;
vOut.position = vIn.position;
#ifdef OFFSET.DEFINED
vOut.position += vIn.offset;
#endif
#ifdef COLOR.DEFINED
vOut.color = vIn.color;
#else
vOut.color = float4(0.0f);
#endif
return vOut;
}
Fonksiyon sabiti değişkenleri kullanılarak yazılmış karşılık gelen fonksiyon şöyledir:
constant bool offset_defined [[function_constant(0)]];
constant bool color_defined [[function_constant(1)]];
vertex VertexOutput
myVertex(VertexInput vIn [[stage_in]])
{
VertexOutput vOut;
vOut.position = vIn.position;
if (offset_defined)
vOut.position += vIn.offset;
if (color_defined)
vOut.color = vIn.color;
else
vOut.color = float4(0.0f);
return vOut;
}
Bir grafik, kernel veya başka bir kullanıcı fonksiyonuna ait bir argümanı [[function_constant(name)]] niteliğiyle bildirerek bu argümanın isteğe bağlı olduğunu belirtebilirsiniz.
name niteliği bir fonksiyon sabiti değişkenine referans verir. name tarafından verilen fonksiyon sabiti değişkeninin değeri sıfırdan farklı veya true ise (pipeline durumu oluşturulurken belirlenir), argüman bildirimi fonksiyon imzasında yer alır. name tarafından verilen fonksiyon sabiti değişkeninin değeri 0 veya false ise, argüman fonksiyon imzasında bildirilmez.
Eğer name, tanımlanmamış bir fonksiyon sabiti değişkenine referans veriyorsa (pipeline durumu oluşturulurken belirlenir), davranış is_function_constant_defined(name) değerinin false olmasıyla aynıdır.
Aşağıdaki fragment fonksiyonunu düşünün; fonksiyon bildiriminde ön işlemci makroları kullanmaktadır:
fragment half4
myFragment(
constant GlobalUniformData *globalUniform [[buffer(0)]],
constant RenderUniformData.ModelWithLightmap *renderUniform [[buffer(1)]],
constant MaterialUniformData *materialUniform [[buffer(2)]],
texture2d<float> DiffuseTexture [[texture(0)]],
texture2d<float> LightmapTexture [[texture(1)]],
texture2d<float> FogTexture [[texture(3)]],
#ifdef MED.QUALITY
texture2d<float> LookupTexture [[texture(4)]],
#endif
#ifdef REALTIME.SHADOW
texture2d<float> RealtimeShadowMapTexture [[texture(10)]],
#endif
sampler DiffuseTextureSampler [[sampler(0)]],
sampler LightmapTextureSampler [[sampler(1)]],
sampler FogTextureSampler [[sampler(3)]],
#ifdef MED.QUALITY
sampler LookupTextureSampler [[sampler(4)]],
#endif
#ifdef REALTIME.SHADOW
sampler RealtimeShadowMapTextureSampler [[sampler(10)]],
#endif
VertexOutput fragIn [[stage_in]]
)
Aşağıda #ifdef ifadeleri yerine fonksiyon sabitleri kullanılarak yeniden yazılmış karşılık gelen fragment fonksiyonu yer almaktadır:
constant bool realtime_shadow [[function_constant(0)]];
constant bool med_quality [[function_constant(1)]];
constant bool med_quality_defined =
is_function_constant_defined(med_quality);
constant bool realtime_shadow_defined =
is_function_constant_defined(realtime_shadow);
fragment half4
myFragment(
constant GlobalUniformData *globalUniform [[buffer(0)]],
constant RenderUniformData.ModelWithLightmap *renderUniform [[buffer(1)]],
constant MaterialUniformData *materialUniform [[buffer(2)]],
texture2d<float> DiffuseTexture [[texture(0)]],
texture2d<float> LightmapTexture [[texture(1)]],
texture2d<float> FogTexture [[texture(3)]],
texture2d<float> LookupTexture [[texture(4),
function_constant(med_quality_defined)]],
texture2d<float> RealtimeShadowMapTexture [[texture(10),
function_constant(realtime_shadow_defined)]],
sampler DiffuseTextureSampler [[sampler(0)]],
sampler LightmapTextureSampler [[sampler(1)]],
sampler FogTextureSampler [[sampler(3)]],
sampler LookupTextureSampler [[sampler(4),
function_constant(med_quality_defined)]],
sampler RealtimeShadowMapTextureSampler [[sampler(10),
function_constant(realtime_shadow_defined)]],
VertexOutput fragIn [[stage_in]]
)
Aşağıda, bir fonksiyonun argümanlarıyla birlikte fonksiyon sabitlerinin nasıl kullanılacağını gösteren başka bir örnek verilmiştir:
constant bool hasInputBuffer [[function_constant(0)]];
kernel void kernelOptionalBuffer(
device int *input [[buffer(0), function_constant(hasInputBuffer)]],
device int *output [[buffer(1)]],
uint tid [[thread_position_in_grid]])
{
if (hasInputBuffer)
output[tid] = inputA[0] * tid;
else
output[tid] = tid;
}
5.8.1.3 Girdi Birleştirme Yapısının Öğeleri İçin Fonksiyon Sabitleri
[[function_constant(name)]] niteliğini kullanarak bir girdi birleştirme yapısının ([[stage_in]] niteliği ile bildirilen) öğelerini isteğe bağlı olarak belirtebilirsiniz.
name tarafından verilen fonksiyon sabiti değişkeninin değeri sıfırdan farklı veya true ise (render veya compute pipeline durumu oluşturulurken belirlenir), yapıdaki öğe fonksiyon imzasında bildirilir. Değer 0 veya false ise, öğe yapıda bildirilmez.
Örnek
constant bool offset_defined [[function_constant(0)]];
constant bool color_defined [[function_constant(1)]];
struct VertexInput {
float4 position [[attribute(0)]];
float4 offset [[attribute(1), function_constant(offset_defined)]];
float4 color [[attribute(2), function_constant(color_defined)]];
};
vertex VertexOutput myVertex(VertexInput vIn [[stage_in]]) { vOut.position = vIn.position;
if (offset_defined)
vOut.position += vIn.offset;
if (color_defined)
vOut.color = vIn.color;
else
vOut.color = float4(0.0f);
return vOut;
}
---
## 5.8.1.4 Kaynak Bağlamaları için Function Constant’lar
Bir grafik veya kernel fonksiyonuna verilen ve bir kaynak (**buffer, texture veya sampler**) olan argüman, bağlama numarasını belirtmek için bir function constant kullanabilir. Function constant **skaler bir tamsayı türünde** olmalıdır.
constant int indexA [[function_constant(0)]];
constant int indexB = indexA + 2;
constant int indexC [[function_constant(1)]];
constant int indexD [[function_constant(2)]];
[[kernel]] void my_kernel(
constant UserParams& params [[buffer(indexA)]],
device T *p [[buffer(indexB)]],
texture2d<float> texA [[texture(indexC)]],
sampler s [[sampler(indexD)]], ...)
{ ... }
Tüm işletim sistemleri: Metal 2 ve sonrası, bir color attachment veya raster order group öznitelik indeksini belirtmek için function constant kullanılmasını destekler.
[[color(n)]] veya [[raster_order_group(index)]] indeksi de bir function constant olabilir. Kullanılan function constant skaler bir tamsayı türünde olmalıdır.
constant int colorAttachment0 [[function_constant(0)]];
constant int colorAttachment1 [[function_constant(1)]];
constant int group0 [[function_constant(2)]];
struct FragmentOutput {
float4 color0 [[color(colorAttachment0)]];
float4 color1 [[color(colorAttachment1)]];
};
[[fragment]] FragmentOutput
my_fragment(texture2d<float> texA [[texture(0), raster_order_group(group0)]], ...)
{ ... }
5.8.1.6 Bir Yapının Elemanları ile Function Constant Kullanımı
Tüm işletim sistemleri: Metal 2 ve sonrası, bir yapı elemanının isteğe bağlı olduğunu belirtmek için function constant kullanılmasını destekler.
Bir yapı elemanının isteğe bağlı olduğunu belirtmek için, bir grafik veya kullanıcı fonksiyonunun dönüş türü olan ya da bir kernel, grafik veya kullanıcı fonksiyonuna değer olarak argüman şeklinde geçirilen bir yapının elemanlarıyla birlikte [[function_constant(name)]] özniteliğini belirtebilirsiniz.
Davranış, [[stage_in]] özniteliğine sahip elemanlar için kullanılan function constant’lara benzerdir.
name ile verilen function constant değişkeninin değeri sıfırdan farklı veya true ise, yapı içindeki eleman fonksiyon imzasında bildirilmiş kabul edilir. Değer 0 veya false ise, bu eleman yapıda bildirilmiş olarak kabul edilmez.
Eğer name, tanımlanmamış bir function constant değişkenine başvuruyorsa, davranış is_function_constant_defined(name) fonksiyonunun false döndürmesiyle aynıdır.
5.9 Program Kapsamında Global Yerleşik Değişkenler ve Bağlamalar
Metal 3.1 ve sonrası sürümlerde, Tablo 5.8’de tanımlanan öznitelikleri kullanarak global değişkenler tanımlayabilir ve bunları bir kernel (tile dâhil), mesh veya object bağlamında kullanabilirsiniz.
Global değişkenler bir dinamik kütüphanede veya ayrı derlenmiş bir ikili fonksiyonda kullanılamaz.
Metal 3.2 ve sonrası sürümlerde, Apple silicon için bir dinamik kütüphanede veya ayrı derlenmiş bir ikili fonksiyonda global değişkenler kullanabilirsiniz.
uint2 gid [[thread_position_in_grid]];
float4 get_color(texture2d<float> texInput, sampler s) {
return texInput.sample(s, float2(gid));
}
[[kernel]] void my_kernel(texture2d<float> texInput, sampler s, ...) {
auto color = get_color(texInput, s);
}
Metal 3.2 ve sonrası sürümlerde program kapsamında device, constant ve threadgroup buffer’lar, texture’lar ve sampler’lar bildirebilirsiniz.
Bir shader içinde argüman olarak geçirilmesine kıyasla, farklı global değişkenlerin alias içermediğini varsayamazsınız. Bu nedenle bağlama indekslerini açıkça belirtmelisiniz; çünkü sistem bunları otomatik olarak ayarlayamaz.
device void * constant b_d [[buffer(0)]];
constant void * constant b_c [[buffer(1)]];
threadgroup void * constant b_t [[threadgroup(2)]];
texture2d<float> constant t [[texture(0)]];
sampler constant s [[sampler(0)]];
constant array<sampler, 4> ss [[sampler(1)]];
Global bağlamaları external linkage ile bildirmek mümkündür, ancak bunları kaynak bağlamasıyla birlikte açıklamalı ve tam bir türe sahip olmasını sağlamalısınız. Bildirim ile tanımın bağlama ve tür bilgileri aynı olmalıdır.
// Bildirim
extern constant texture2d<float> t [[texture(0)]];
// Tanım
constant texture2d<float> t [[texture(0)]];
Aynı türü ve bağlama indeksini paylaşıyorlarsa bir kaynağı birden fazla global değişkene bağlayabilirsiniz.
constant texture2d<float, access::write> t_w_1 [[texture(1)]];
// geçerli
constant texture2d<float, access::write> t_w_2 [[texture(1)]];
// geçersiz!
constant texture2d<float, access::read_write> t_w_3 [[texture(1)]];
5.10 Primitive Başına Viewport ve Scissor Rectangle İndeksi
macOS: Metal 2 ve sonrası viewport_array_index özniteliğini destekler.
iOS: Metal 2.1 ve sonrası viewport_array_index özniteliğini destekler.
[[viewport_array_index]] özniteliği, hem vertex çıktısı hem de fragment girdisi olarak yerleşik değişkenleri destekler.
[[viewport_array_index]] ile vertex fonksiyonunun çıktısı, setViewports:count: ve setScissorRects:count: framework çağrılarıyla belirtilen dizilerden rasterization viewport’unu ve scissor rectangle’ı belirler.
Vertex fonksiyon çıktısının [[viewport_array_index]] için sınırlandırılmamış değeri, değer aralık dışında olsa bile fragment fonksiyonuna girdi olarak sağlanır.
Sınırlandırılmamış bir [[viewport_array_index]] değeri ile fragment fonksiyonunun davranışı uygulamaya bağlıdır:
- Metal, iletilen değerden bağımsız olarak her primitive’i viewport/scissor rectangle 0’a çizebilir.
- Metal, n’inci viewport/scissor rectangle’a çizebilir; burada n, sınırlandırılmış değerdir.
Bu özelliği desteklemeyen donanım, yalnızca bir viewport ve bir scissor rectangle’a izin veriliyormuş gibi davranır; bu nedenle [[viewport_array_index]] için değer 0 olur.
[[viewport_array_index]] bir post-tessellation vertex fonksiyonunda belirtilebilir, ancak tessellation factor buffer içinde belirtilemez.
[[viewport_array_index]] özniteliğini fragment fonksiyon girdisi olarak belirtmek, kullanılabilir giriş derleme bileşenlerinin sayısından düşülür.
Bir primitive içindeki her vertex için [[viewport_array_index]] değerinin aynı olması gerekir. Değerler farklıysa davranış ve fragment fonksiyonuna iletilen değer tanımsızdır. Aynı davranış tessellation tarafından üretilen primitive’ler için de geçerlidir.
5.11 Ek Kısıtlamalar
MSL fonksiyonları ve argümanları şu ek kısıtlamalara sahiptir:
- Bir vertex fonksiyonundan bir buffer’a yapılan yazmaların, belirli bir primitive’in ilişkili fragment fonksiyonu tarafından yapılan okumalarda görünür olması garanti edilmez.
- Bir vertex fonksiyonu bir veya daha fazla buffer veya texture’a yazma işlemi yapıyorsa, dönüş türü
voidolmalıdır. - Bir vertex veya fragment fonksiyonunun dönüş türü; packed vector türü, matris türü, yapı türü, referans veya pointer olan bir eleman içeremez.
stage_inözniteliğiyle bildirilen bir fragment fonksiyonunun giriş sayısı sınırlıdır. Bu sınırlar farklı feature set’ler için değişir. Metal Feature Set Tables, sınırları Implementation Limits by GPU Family başlığı altında listeler.- Bir grafik veya kernel fonksiyonuna verilen argümanların türü türetilmiş bir sınıf olamaz. Ayrıca
stage_inözniteliğiyle bildirilen bir grafik fonksiyonu argümanının türü de türetilmiş bir sınıf olamaz.
BELİRTİMDE KOMŞULARI
BELİRTİMİN TAMAMI
- 1. Giriş2.921
- 2. Veri Türleri10.929
- 3. Operatörler1.638
- 4. Adres Alanları1.217
- 5. Fonksiyon ve Değişken Bildirimleri14.679
- 6. Metal Standart Kütüphanesi18.632
- 7. Metal Performans Primitifleri2.111
- 8. Sayısal Uyumluluk2.554
- 9. Ek273
BU SAYFA HAKKINDA
- Çeviri hatası bildire-posta