RenderScript, yoğun bilgi işlem gerektiren görevleri yüksek performansla çalıştırmak için kullanılan Android RenderScript, seri işleme olsa da öncelikli olarak veriye paralel hesaplama için tasarlanmıştır. fayda sağlayabilir. RenderScript çalışma zamanı paralel hale gelir çok çekirdekli CPU ve GPU'lar gibi, cihazdaki işlemcilerde çalışabilir. Bu da işleri programlamak yerine algoritmaları ifade etmeye odaklanmanızı sağlar. RenderScript: özellikle de görüntü işleme, hesaplamalı fotoğrafçılık veya bilgisayar vizyonu.
RenderScript'i kullanmaya başlarken anlamanız gereken iki temel kavram vardır:
- Dil de yüksek performanslı bilgi işlem yazmak için C99 tabanlı bir dildir girin. Bir RenderScript Kernel'in yazılması, işlem çekirdekleri yazmak için nasıl kullanılacağını öğreneceğiz.
- control API, RenderScript kaynaklarının kullanım ömrünü yönetmek için kullanılır ve nasıl yapıldığını göstereceğim. Üç farklı dilde kullanılabilir: Java, Android'de C++ NDK ve C99 türetilmiş çekirdek dilinin kendisidir. Java Code'dan RenderScript'i kullanma ve Tek Kaynaklı RenderScript, birinci ve üçüncü kaynak seçenekleri vardır.
RenderScript Kernel Yazma
RenderScript çekirdeği genellikle bir .rs
<project_root>/src/rs
dizini; her .rs
dosyasına bir
script olarak ayarlayın. Her komut dosyası kendi çekirdek, işlev ve değişkenleri grubunu içerir. Bir komut dosyası
içerir:
#pragma version(1)
Bu komut dosyasında kullanılan RenderScript çekirdek dili. Şu anda tek geçerli değer 1'dir.- Şu pragma beyanını (
#pragma rs java_package_name(com.example.app)
) bu komut dosyasından yansıtılan Java sınıflarının paket adını tanımlar..rs
dosyanızın, uygulama paketinizin bir parçası olması gerektiğini ve üzerine konuşacağız. - Sıfır veya daha fazla çağrılanabilir işlev. Çağrılabilir işlev, tek iş parçacıklı bir RenderScript işlevinden birini çağırabilirsiniz. Bunlar çoğu zaman ilk kurulum veya seri hesaplamalar için kullanılabilecektir.
Sıfır veya daha fazla komut dosyası global. Genel komut dosyası, C'deki genel değişkene benzer. Şunları yapabilirsiniz: komut dosyası global dosyalarına Java kodundan erişebilirsiniz. Bunlar genellikle RenderScript'e parametre iletmek için kullanılır çekirdekleri hakkında daha fazla bilgi edinin. Komut dosyası global işlevleri burada daha ayrıntılı olarak açıklanmıştır.
Sıfır veya daha fazla işlem çekirdeği. İşlem çekirdeği, bir işlevdir RenderScript çalışma zamanını paralel olarak yürütülmesi için yönlendirebileceğiniz fonksiyonlar veya koleksiyon veri kümesi genelinde kullanılır. İki tür bilgi işlem vardır çekirdekler: eşleme çekirdekleri (foreach çekirdekleri olarak da adlandırılır) ve azaltma çekirdekleridir.
Eşleme çekirdeği, aynı boyutlardaki
Allocations
koleksiyonunda çalışan paralel bir işlevdir. Varsayılan olarak, koordinat için yalnızca bir kez kullanmanız gerekir. Normalde (ancak özel olarak değil)Allocations
girişi koleksiyonunuAllocation
için birElement
çıkışı, gerekir.Aşağıda basit bir eşleme çekirdeği örneği verilmiştir:
uchar4 RS_KERNEL invert(uchar4 in, uint32_t x, uint32_t y) { uchar4 out = in; out.r = 255 - in.r; out.g = 255 - in.g; out.b = 255 - in.b; return out; }
Bu, çoğu bakımdan standart C ile aynıdır. işlevini kullanın.
RS_KERNEL
özelliği fonksiyon prototipi, fonksiyonun bir çağrılabilir.in
bağımsız değişkeni,Allocation
girişi, çekirdek lansmanına geçti. İlgili içeriği oluşturmak için kullanılanx
vey
bağımsız değişkenleri aşağıda ele alınmıştır. Çekirdekten döndürülen değerAllocation
çıkışında uygun konuma otomatik olarak yazılır. Varsayılan olarak bu çekirdek, girişin tamamında çalıştırılırAllocation
:Allocation
içinde herElement
için çekirdek işlevi bir kez yürütülür.Eşleme çekirdeğinde bir veya daha fazla giriş (
Allocations
), tek bir çıkış (Allocation
) veya her ikisi birden bulunabilir. İlgili içeriği oluşturmak için kullanılan Tüm giriş ve çıkış ayırmalarının aynı olduğundan emin olmak için RenderScript çalışma zamanı kontrolleri veElement
giriş ve çıkış türlerinin Ayırmalar, çekirdeğin prototipiyle eşleşir; bunlardan biri başarısız olursa RenderScript bir istisna oluşturur.NOT: Android 6.0'dan (API düzeyi 23) önce bir eşleme çekirdeği birden fazla
Allocation
girişi yok.Şundan daha fazla giriş veya çıkışa ihtiyacınız varsa:
Allocations
bu nesnelerrs_allocation
komut dosyası global değerlerine bağlı olmalıdır ve çekirdek veya çağrılabilir bir işlevden erişilebilirrsGetElementAt_type()
veyarsSetElementAt_type()
üzerinden.NOT:
RS_KERNEL
, bir makrodur RenderScript tarafından otomatik olarak tanımlanır:#define RS_KERNEL __attribute__((kernel))
Azaltma çekirdeği, giriş koleksiyonu üzerinde çalışan bir işlev ailesidir.
Allocations
tane aynı boyutta. Varsayılan olarak toplayıcı işlevi her seferinde bir kez yürütülür koordinasyonu sağlamasıdır. Genellikle (ancak özel olarak değil) "daha az" CANNOT TRANSLATE tek bir girişeAllocations
girişi koleksiyonu değer.Burada basit bir azaltmaörnek görebilirsiniz çekirdek
Elements
giriş:#pragma rs reduce(addint) accumulator(addintAccum) static void addintAccum(int *accum, int val) { *accum += val; }
İndirme çekirdeği, kullanıcı tarafından yazılan bir veya daha fazla işlevden oluşur.
#pragma rs reduce
, çekirdeği adını belirterek tanımlamak için kullanılır (bu örnekteaddint
) ve önemli işlevleri sağlayan işlevlerin (biraccumulator
işleviaddintAccum
, bu örnekte örneğine bakın). Bu tür işlevlerin tümüstatic
olmalıdır. Her zaman bir azaltma çekirdeğiaccumulator
işlevi gerektirir; bağlı olarak başka işlevleri de istediğinize karar verin.İndirgeme çekirdeği toplayıcı işlevi,
void
değerini döndürmeli ve en az içermelidir kullanabilirsiniz. İlk bağımsız değişken (bu örnekteaccum
), bir toplayıcı veri öğesi, ikincisi (bu örnekteval
) iseAllocation
tarafından iletilen girişe göre otomatik olarak dolduruldu lansman sonrasında gerçekleşebilir. Toplayıcı veri öğesi, RenderScript çalışma zamanı tarafından oluşturulur; - sıfır olarak başlatılır. Varsayılan olarak bu çekirdek, girişin tamamında çalıştırılırAllocation
, toplayıcı fonksiyonu her başına bir defa yürütülürAllocation
içindeElement
. Ölçüt varsayılan değer, toplayıcı veri öğesinin son değeri, indirgenir ve Java'ya döndürülür. RenderScript çalışma zamanı, giriş ayırma işlevininElement
türünün toplayıcı işlevinin prototip oluşturabilirsiniz. eşleşmiyorsa RenderScript bir istisna uygular.Azaltma çekirdeğinde bir veya daha fazla giriş
Allocations
var ancakAllocations
çıkışı yok.Azaltma çekirdekleri burada daha ayrıntılı bir şekilde açıklanmaktadır.
Azaltma çekirdekleri, Android 7.0 (API düzeyi 24) ve sonraki sürümlerde desteklenir.
Eşleme çekirdek işlevi veya indirgeme çekirdeği toplayıcı işlevi koordinatlara erişebilir
x
özel bağımsız değişkenleri kullanılarak mevcut yürütmeniny
vez
,int
veyauint32_t
türünde olmalıdır. Bu bağımsız değişkenler isteğe bağlıdır.Eşleme çekirdeği işlevi veya indirgeme çekirdeği toplayıcı işlevi, isteğe bağlı özel bağımsız değişkeni de alabilir rs_kernel_context türünde
context
. Sorgulamada kullanılan çalışma zamanı API'leri ailesi için gereklidir. geçerli yürütmenin belirli özelliklerini kullanabilirsiniz. Örneğin, rsGetDimX. (context
bağımsız değişkeni, Android 6.0 (API düzeyi 23) ve sonraki sürümlerde kullanılabilir.)- İsteğe bağlı bir
init()
işlevi.init()
işlevi, komut dosyası ilk kez örneklendirildiğinde RenderScript'in çalıştırdığı çalıştırılabilir bir işlevdir. Bu şekilde bazı komut dosyası oluşturulurken otomatik olarak gerçekleşmesini sağlar. - Sıfır veya daha fazla statik komut dosyası genel öğesi ve işlevi. Statik bir genel komut dosyası,
komut dosyası global olarak çalıştırılması gerekir. Tek fark, bu komut dosyasına Java kodundan erişilememesidir. Statik fonksiyonlar standart bir C'dir.
komut dosyasındaki herhangi bir çekirdekten veya çağrılabilir işlevden çağrılabilen, ancak kullanıma sunulmayan fonksiyon
hoşuma gidiyor. Bir komut dosyasına veya işlevine Java kodundan erişilmesi gerekmiyorsa
static
olarak belirtilmesi önemle tavsiye edilir.
Kayan nokta hassasiyetini ayarlama
Bir komut dosyasında gerekli kayan nokta kesinliğini kontrol edebilirsiniz. Bu, şu durumlarda yararlıdır: tam IEEE 754-2008 standardı (varsayılan olarak kullanılır) gerekli değildir. Aşağıdaki pragmalar farklı seviyede kayan nokta hassasiyeti:
#pragma rs_fp_full
(hiçbir şey belirtilmezse varsayılan): IEEE 754-2008 standardı tarafından belirtilen kayan nokta hassasiyeti.#pragma rs_fp_relaxed
: Katı IEEE 754-2008 gerektirmeyen uygulamalar için daha az kesinliğe tolerans gösterebilir. Bu mod, değerler için sıfıra boşaltmayı etkinleştirir. sıfıra doğru yuvarlayın.#pragma rs_fp_imprecise
: En yüksek hassasiyete sahip olmayan uygulamalar için gereksinimlerini karşılayın. Bu modrs_fp_relaxed
takip etmek için:- -0,0 ile sonuçlanan işlemler, bunun yerine +0.0 sonucunu döndürebilir.
- INF ve NAN üzerindeki işlemler tanımlanmamıştır.
Çoğu uygulamada rs_fp_relaxed
yan etkisi olmadan kullanılabilir. Bu, size
Yalnızca esnek yapılandırma ile kullanılabilen ek optimizasyonlar nedeniyle bazı mimarilerde faydalıdır.
(SIMD CPU talimatları gibi).
Java'dan RenderScript API'lerine erişme
RenderScript kullanan bir Android uygulaması geliştirirken, API'ye Java'dan erişebilirsiniz. şu iki yöntemden birini kullanabilirsiniz:
android.renderscript
- Bu sınıf paketindeki API'ler: Android 3.0 (API düzeyi 11) ve sonraki sürümleri çalıştıran cihazlarda kullanılabilir.android.support.v8.renderscript
- Bu paketteki API'ler: Destek Kitaplığı'nı seçin. daha yüksek.
Bunun karşılığında yapılabilecekler şunlardır:
- Destek Kitaplığı API'lerini kullanırsanız uygulamanızın RenderScript kısmı
RenderScript'ten bağımsız olarak Android 2.3 (API düzeyi 9) ve sonraki sürümleri çalıştıran cihazlarla uyumludur.
özellikleri inceleyelim. Bu, uygulamanızın
yerel (
android.renderscript
) API'ler. - Belirli RenderScript özellikleri, Destek Kitaplığı API'leri üzerinden kullanılamaz.
- Destek Kitaplığı API'lerini kullanırsanız
yerel (
android.renderscript
) API'leri kullanıyorsanız.
RenderScript Destek Kitaplığı API'lerini kullanma
Destek Kitaplığı RenderScript API'lerini kullanmak için geliştirmenizi yapılandırmanız gerekir ortamını bozar. Aşağıdaki Android SDK araçları, şu API'leri kullanın:
- Android SDK Araçları düzeltme 22.2 veya üstü
- Android SDK Derleme araçları düzeltmesi 18.1.0 veya üstü
Android SDK Derleme Araçları 24.0.0, Android 2.2'den başlayarak (API düzeyi 8) artık desteklenmiyor.
Bu araçların yüklü sürümlerini şurada kontrol edebilir ve güncelleyebilirsiniz: Android SDK Yöneticisi.
Destek Kitaplığı RenderScript API'lerini kullanmak için:
- Gerekli Android SDK sürümünün yüklü olduğundan emin olun.
- Android derleme işleminin ayarlarını RenderScript ayarlarını içerecek şekilde güncelleyin:
- Uygulama modülünüzün uygulama klasöründe
build.gradle
dosyasını açın. - Aşağıdaki RenderScript ayarlarını dosyaya ekleyin:
Eski
android { compileSdkVersion 33 defaultConfig { minSdkVersion 9 targetSdkVersion 19 renderscriptTargetApi 18 renderscriptSupportModeEnabled true } }
Kotlin
android { compileSdkVersion(33) defaultConfig { minSdkVersion(9) targetSdkVersion(19) renderscriptTargetApi = 18 renderscriptSupportModeEnabled = true } }
Yukarıda listelenen ayarlar, Android derleme işlemindeki belirli davranışı kontrol eder:
renderscriptTargetApi
- Olacak bayt kodu sürümünü belirtir elde edilir. Bu değeri, sunabileceğiniz en düşük API seviyesine ayarlamanızı öneririz. verenderscriptSupportModeEnabled
olarak ayarlayın. Hedef:true
. Bu ayar için geçerli değerler tam sayı değerleridir 11'den en son yayınlanan API düzeyine yükseldi. Minimum SDK sürümünüz belirtilenden farklı bir değere ayarlanmışsa, bu değer yok sayılır ve derleme dosyasındaki hedef değer, SDK sürümü.renderscriptSupportModeEnabled
- Oluşturulan cihazın çalıştığı cihazda bayt kodunun uyumlu bir sürüme geri dönmesi gerekir , hedef sürümü desteklemiyor.
- Uygulama modülünüzün uygulama klasöründe
- RenderScript kullanan uygulama sınıflarınızda Destek Kitaplığı için bir içe aktarma ekleyin
sınıflar:
Kotlin
import android.support.v8.renderscript.*
Java
import android.support.v8.renderscript.*;
Java veya Kotlin Kodundan RenderScript'i kullanma
Java veya Kotlin kodundan RenderScript'i kullanmak
android.renderscript
veya android.support.v8.renderscript
paketi. En sık
aynı temel kullanım modelini kullanır:
- Bir RenderScript bağlamı başlatın.
create(Context)
ile oluşturulanRenderScript
bağlamı, RenderScript'in kullanılabilmesini sağlar ve nesnesini ifade eder. Bağlamı göz önünde bulundurmalısınız. farklı platformlarda kaynak oluşturabileceği için, sürecin donanım parçaları; uygulamanın kritik yolunda hiç yer almamalıdır. yapmasını sağlar. Genellikle, bir uygulamanın aynı anda yalnızca tek bir RenderScript bağlamı olur. - Bir
Allocation
komut dosyası.Allocation
, aşağıdakileri sağlayan bir RenderScript nesnesidir: depolama alanı sunar. Komut dosyalarındaki çekirdeklerAllocation
alır nesnelerini giriş ve çıkışı olarak kullanır.Allocation
nesne isersGetElementAt_type()
ve kullanılan çekirdeklerde erişildi Komut dosyası genelleri olarak bağlandığındarsSetElementAt_type()
.Allocation
nesne, dizilerin Java kodundan RenderScript'e aktarılmasına izin verir ve tam tersi de geçerlidir.Allocation
nesneleri genelliklecreateTyped()
veyacreateFromBitmap()
. - Gerekli komut dosyalarını oluşturun. İki tür komut dosyası vardır
aşağıdaki adımları uygulayın:
- ScriptC: Bunlar, yukarıdaki RenderScript Kernel'i Yazma bölümünde açıklanan kullanıcı tanımlı komut dosyalarıdır. Her komut dosyasının bir Java sınıfı vardır
JavaScript kodundan komut dosyasına erişimi kolaylaştırmak için RenderScript derleyicisi tarafından yansıtılmıştır;
bu sınıfın adı
ScriptC_filename
. Örneğin, eşleme çekirdeği yukarıdakilerinvert.rs
konumunda bulunuyordu ve RenderScript bağlamı zaten şurada bulunuyordu:mRenderScript
, komut dosyasını örneklendirmek için kullanılacak Java veya Kotlin kodu şöyle olur:Kotlin
val invert = ScriptC_invert(renderScript)
Java
ScriptC_invert invert = new ScriptC_invert(renderScript);
- ScriptIntrinsic: Bunlar, genel işlemler için yerleşik RenderScript çekirdekleridir.
örneğin Gauss bulanıklığı, konvolüsyon ve görüntü karıştırma gibi yöntemler yer alır. Daha fazla bilgi için
ScriptIntrinsic
- ScriptC: Bunlar, yukarıdaki RenderScript Kernel'i Yazma bölümünde açıklanan kullanıcı tanımlı komut dosyalarıdır. Her komut dosyasının bir Java sınıfı vardır
JavaScript kodundan komut dosyasına erişimi kolaylaştırmak için RenderScript derleyicisi tarafından yansıtılmıştır;
bu sınıfın adı
- Tahsisleri veriyle doldurun.
createFromBitmap()
ile oluşturulan Ayırmalar hariç olmak üzere, bir ayırma olduğunda boş verilerle doldurulur oluşturulmalıdır. Ayırmayı doldurmak için, "kopyalama" öğelerinden birini kullanınAllocation
içinde farklı yöntemler kullanır. "Kopya" eş zamanlı olduğundan emin olun. - Gerekli komut dosyası global değerlerini ayarlayın. Şuradaki yöntemleri kullanarak geneller ayarlayabilirsiniz:
set_globalname
adlı aynıScriptC_filename
sınıfı. Örneğin, Örneğin,threshold
adlı birint
değişkeni ayarlamak için Java yöntemiset_threshold(int)
; Okuyucu Gelirleri Yöneticisi'nilookup
adlı birrs_allocation
değişkeni kullanıyorsanız yöntemset_lookup(Allocation)
.set
yöntemleri eşzamansızlardır. - Uygun çekirdekleri ve çağrılabilir işlevleri başlatın.
Belirli bir çekirdeği başlatma yöntemleri şunlardır: adlı yöntemlere sahip aynı
ScriptC_filename
sınıfında yansıtılıyorforEach_mappingKernelName()
veyareduce_reductionKernelName()
. Bu lansmanlar eşzamansızdır. Çekirdekteki bağımsız değişkenlere bağlı olarak yöntemi bir veya daha fazla Ayırma alır ve bunların tümü aynı boyutlara sahip olmalıdır. Varsayılan olarak çekirdek bu boyutlardaki her koordinat üzerinde yürütülür; bir çekirdeği yürütmek için bu koordinatların bir alt kümesi üzerindeforEach
veyareduce
yöntemine son bağımsız değişken olarak uygun birScript.LaunchOptions
geçirin.invoke_functionName
yöntemlerini kullanarak çağrılabilir işlevleri başlatın aynıScriptC_filename
sınıfında yansıtılır. Bu lansmanlar eşzamansızdır. Allocation
nesneden veri alma ve javaFutureType nesneleri. Bu amaçla Java kodundan birAllocation
üzerindeki verilere eriştiğinizde bu verileri kopyalamanız gerekir "kopya"dan birini kullanarak Java'ya geri dönün. yöntemlerine göz atın.Allocation
Azaltma çekirdeğinin sonucunu almak içinjavaFutureType.get()
yöntemini kullanmanız gerekir. "Kopya" veget()
yöntemleri eşzamanlı.- RenderScript bağlamını ayrıntılarıyla inceleyin. RenderScript bağlamını kaldırabilirsiniz
destroy()
ile veya RenderScript bağlamına izin vererek çöp toplamasına izin vermeyecek. Bu, söz konusu cihaza ait nesnelerin daha sonra kullanılmasına bağlam bilgisi sunar.
Eşzamansız yürütme modeli
Yansıtılan forEach
, invoke
, reduce
,
ve set
yöntemleri eşzamansızdır. Her biri,
istenen işlem. Ancak her bir işlem, kullanıma sunuldukları sırayla serileştirilir.
Allocation
sınıfı "kopya" özelliğini sağlar veri kopyalama yöntemleri
arasında yer alır. Bir "kopya" eşzamanlı olup bu yöntemden herhangi biri
içeren, aynı Ayırmaya dokunan yukarıdaki eşzamansız işlemlerin sayısı.
Yansıtılan javaFutureType sınıfları,
bir get()
yöntemidir. get()
eşzamanlıdır ve azaltmaya (eşzamansız) göre serileştirilir.
Tek Kaynaklı RenderScript
Android 7.0 (API düzeyi 24), Tek Kaynak adlı yeni bir programlama özelliğini kullanıma sunuyor.
RenderScript: Çekirdeklerin
başka bir şey var. Şu anda bu yaklaşım, yalnızca "çekirdek" olarak adlandırılan çekirdeklerin eşleştirilmesiyle sınırlıdır.
kısa ve öz yazımlara dikkat edin. Bu yeni özellik,
rs_allocation
komutunu çalıştırın. Artık proje yönetimiyle ilgili
birden fazla çekirdek başlatması gerekse bile algoritmanın tamamını yalnızca bir komut dosyası içinde uygulayabilir.
Bunun iki avantajı vardır: daha okunaklı bir kod, çünkü bir algoritmanın
bir dil; ve büyük olasılıkla daha hızlı kod yazmanızı sağlar. Bunun nedeni, Java ile
RenderScript'i birden fazla çekirdek lansmanında kullanın.
Tek Kaynaklı RenderScript'te, çekirdekleri konusunda açıklandığı gibi yazarsınız
RenderScript Kernel yazma. Ardından,
Bunları başlatmak için rsForEach()
. Bu API, ilk olarak bir çekirdek işlevini alır ve
parametresi ve ardından giriş ve çıkış ayırmaları gelir. Benzer bir API
rsForEachWithOptions()
, şu türde ekstra bir bağımsız değişken alır
rs_script_call_t
: Bu, girişteki öğelerin bir alt kümesini belirtir ve
çekirdek işlevinin işleyeceği çıkış tahsisatlarını belirleyin.
RenderScript hesaplamasını başlatmak için Java'dan çağrılabilir işlevi çağırırsınız.
Java Code'dan RenderScript'i kullanma bölümündeki adımları uygulayın.
Uygun çekirdekleri başlatma adımında, şunu çağırın:
başlatılacak olan invoke_function_name()
kullanarak
tüm hesaplamayı ele alacağız.
Paydaşlar genellikle değişiklikleri kaydedip iletmek için
ara sonuçlar elde edilir. Bunları şununla oluşturabilirsiniz:
rsCreateAllocation() gibidir. Bu API'nin kullanımı kolay bir biçimi
rsCreateAllocation_<T><W>(…)
'dir. Burada T, öğenin veri türüdür.
öğesi ve W, öğenin vektör genişliğidir. API, boyutları
X, Y ve Z boyutlarını bağımsız değişken olarak ayarlar. 1D veya 2D ayırmalarda Y veya Z boyutunun boyutu
atlanır. Örneğin, rsCreateAllocation_uchar4(16384)
, şunun 1D tahsisini oluşturur:
Her biri uchar4
türünde 16384 öğe.
Ayırma işlemleri, sistem tarafından otomatik olarak yönetilir. Siz
bunları açıkça serbest bırakmanız veya serbest bırakmanız gerekmez. Ancak,
Herkese açık kullanıcı adına artık ihtiyacınız olmadığını belirtmek için rsClearObject(rs_allocation* alloc)
Temel tahsise alloc
,
Böylece sistem, kaynakları olabildiğince erken serbest bırakabilir.
RenderScript Kernel Yazma bölümü,
bir çekirdeğin oluşturulması gerekir. Aşağıdaki örnek, bir resme birden fazla efekt uygulayacak şekilde
tek Kaynaklı RenderScript kullanarak. greyscale
adlı başka bir çekirdek içerir. Bu da
siyah beyaza dönüştürebilirsiniz. Çağrı yapılabilir process()
işlevi, ardından bu iki çekirdeği uygular
art arda bir giriş görüntüsüne ekler ve bir çıkış resmi üretir. Hem giriş hem de için ayırmalar
çıkış,
rs_allocation
değerleridir.
// File: singlesource.rs #pragma version(1) #pragma rs java_package_name(com.android.rssample) static const float4 weight = {0.299f, 0.587f, 0.114f, 0.0f}; uchar4 RS_KERNEL invert(uchar4 in, uint32_t x, uint32_t y) { uchar4 out = in; out.r = 255 - in.r; out.g = 255 - in.g; out.b = 255 - in.b; return out; } uchar4 RS_KERNEL greyscale(uchar4 in) { const float4 inF = rsUnpackColor8888(in); const float4 outF = (float4){ dot(inF, weight) }; return rsPackColorTo8888(outF); } void process(rs_allocation inputImage, rs_allocation outputImage) { const uint32_t imageWidth = rsAllocationGetDimX(inputImage); const uint32_t imageHeight = rsAllocationGetDimY(inputImage); rs_allocation tmp = rsCreateAllocation_uchar4(imageWidth, imageHeight); rsForEach(invert, inputImage, tmp); rsForEach(greyscale, tmp, outputImage); }
process()
işlevini Java veya Kotlin'den şu şekilde çağırabilirsiniz:
Kotlin
val RS: RenderScript = RenderScript.create(context) val script = ScriptC_singlesource(RS) val inputAllocation: Allocation = Allocation.createFromBitmapResource( RS, resources, R.drawable.image ) val outputAllocation: Allocation = Allocation.createTyped( RS, inputAllocation.type, Allocation.USAGE_SCRIPT or Allocation.USAGE_IO_OUTPUT ) script.invoke_process(inputAllocation, outputAllocation)
Java
// File SingleSource.java RenderScript RS = RenderScript.create(context); ScriptC_singlesource script = new ScriptC_singlesource(RS); Allocation inputAllocation = Allocation.createFromBitmapResource( RS, getResources(), R.drawable.image); Allocation outputAllocation = Allocation.createTyped( RS, inputAllocation.getType(), Allocation.USAGE_SCRIPT | Allocation.USAGE_IO_OUTPUT); script.invoke_process(inputAllocation, outputAllocation);
Bu örnek, iki çekirdek lansmanı içeren bir algoritmanın tam olarak nasıl uygulanabileceğini gösterir pek çok dili vardır. Tek Kaynaksız çekirdek lansmanlarını birbirinden ayırarak her iki çekirdeği de Java kodundan başlatmanız algoritmanın tamamını anlamayı zorlaştırabilir. Yalnızca Tek Kaynaklı RenderScript kodunun okunması daha kolaydır; ayrıca, arasında 300.000'e ulaşır. Bazı yinelemeli algoritmalar çekirdekleri başlatabilir bu tür bir geçişin ek yükünü de oldukça önemli hale getiriyor.
Komut Dosyası Genelleri
Global komut dosyası, static
dışındaki normal bir komut dosyasıdır
komut dosyası (.rs
) dosyasındaki genel değişken. Komut dosyası için
var global olarak tanımlanmıştır
filename.rs
dosyasında
get_var
yöntemi
ScriptC_filename
sınıfı. Global
const
ise bir
yöntem set_var
.
Belirli bir komut dosyasının iki ayrı değeri vardır: Java değer ve script değeri girin. Bu değerler şu şekilde çalışır:
- var değişkeni, komut dosyasında statik bir başlatıcıya sahipse , hem Java'da hem de komut dosyası. Aksi takdirde, bu başlangıç değeri sıfır olur.
- Komut dosyası içindeki var öğesine erişir ve komut dosyası değerini ekleyin.
get_var
yöntemi, Java değer.set_var
yöntemi (varsa) Java değerini anında belirtir ve komut dosyası değerini yazar eşzamansız olarak kaydedin.
NOT: Bu, harici kaynaklardaki tüm komut dosyasında statik başlatıcıyı kullanarak, JavaScript tarafından görülemez.
Çekirdekleri Derinlemesine Azaltma
Azaltma, veri koleksiyonunu tek bir veride birleştirme işlemidir değer. Bu, paralel programlamada takip etmek için:
- tüm veriler üzerinden toplam veya çarpım
- mantıksal işlemleri hesaplama (
and
,or
,xor
) tüm verilere göre - verilerdeki minimum veya maksimum değeri bulmak
- belirli bir değeri veya verilerdeki belirli bir değerin koordinatını aramak
RenderScript, Android 7.0 (API düzeyi 24) ve sonraki sürümlerde daha verimli şekilde kullanabilirsiniz. Şu girişlerde azaltma çekirdeklerini başlatabilirsiniz: 1, 2 veya 3 boyut
Yukarıdaki örnekte, basit bir addint azaltma çekirdeği gösterilmektedir.
Burada, daha karmaşık bir findMinAndMax azaltma çekirdeği verilmiştir
minimum ve maksimum long
değerlerinin konumlarını bulan bir
1 boyutlu Allocation
:
#define LONG_MAX (long)((1UL << 63) - 1) #define LONG_MIN (long)(1UL << 63) #pragma rs reduce(findMinAndMax) \ initializer(fMMInit) accumulator(fMMAccumulator) \ combiner(fMMCombiner) outconverter(fMMOutConverter) // Either a value and the location where it was found, or INITVAL. typedef struct { long val; int idx; // -1 indicates INITVAL } IndexedVal; typedef struct { IndexedVal min, max; } MinAndMax; // In discussion below, this initial value { { LONG_MAX, -1 }, { LONG_MIN, -1 } } // is called INITVAL. static void fMMInit(MinAndMax *accum) { accum->min.val = LONG_MAX; accum->min.idx = -1; accum->max.val = LONG_MIN; accum->max.idx = -1; } //---------------------------------------------------------------------- // In describing the behavior of the accumulator and combiner functions, // it is helpful to describe hypothetical functions // IndexedVal min(IndexedVal a, IndexedVal b) // IndexedVal max(IndexedVal a, IndexedVal b) // MinAndMax minmax(MinAndMax a, MinAndMax b) // MinAndMax minmax(MinAndMax accum, IndexedVal val) // // The effect of // IndexedVal min(IndexedVal a, IndexedVal b) // is to return the IndexedVal from among the two arguments // whose val is lesser, except that when an IndexedVal // has a negative index, that IndexedVal is never less than // any other IndexedVal; therefore, if exactly one of the // two arguments has a negative index, the min is the other // argument. Like ordinary arithmetic min and max, this function // is commutative and associative; that is, // // min(A, B) == min(B, A) // commutative // min(A, min(B, C)) == min((A, B), C) // associative // // The effect of // IndexedVal max(IndexedVal a, IndexedVal b) // is analogous (greater . . . never greater than). // // Then there is // // MinAndMax minmax(MinAndMax a, MinAndMax b) { // return MinAndMax(min(a.min, b.min), max(a.max, b.max)); // } // // Like ordinary arithmetic min and max, the above function // is commutative and associative; that is: // // minmax(A, B) == minmax(B, A) // commutative // minmax(A, minmax(B, C)) == minmax((A, B), C) // associative // // Finally define // // MinAndMax minmax(MinAndMax accum, IndexedVal val) { // return minmax(accum, MinAndMax(val, val)); // } //---------------------------------------------------------------------- // This function can be explained as doing: // *accum = minmax(*accum, IndexedVal(in, x)) // // This function simply computes minimum and maximum values as if // INITVAL.min were greater than any other minimum value and // INITVAL.max were less than any other maximum value. Note that if // *accum is INITVAL, then this function sets // *accum = IndexedVal(in, x) // // After this function is called, both accum->min.idx and accum->max.idx // will have nonnegative values: // - x is always nonnegative, so if this function ever sets one of the // idx fields, it will set it to a nonnegative value // - if one of the idx fields is negative, then the corresponding // val field must be LONG_MAX or LONG_MIN, so the function will always // set both the val and idx fields static void fMMAccumulator(MinAndMax *accum, long in, int x) { IndexedVal me; me.val = in; me.idx = x; if (me.val <= accum->min.val) accum->min = me; if (me.val >= accum->max.val) accum->max = me; } // This function can be explained as doing: // *accum = minmax(*accum, *val) // // This function simply computes minimum and maximum values as if // INITVAL.min were greater than any other minimum value and // INITVAL.max were less than any other maximum value. Note that if // one of the two accumulator data items is INITVAL, then this // function sets *accum to the other one. static void fMMCombiner(MinAndMax *accum, const MinAndMax *val) { if ((accum->min.idx < 0) || (val->min.val < accum->min.val)) accum->min = val->min; if ((accum->max.idx < 0) || (val->max.val > accum->max.val)) accum->max = val->max; } static void fMMOutConverter(int2 *result, const MinAndMax *val) { result->x = val->min.idx; result->y = val->max.idx; }
NOT: Kısaltmalarla ilgili başka örnekler de vardır. çekirdekleri burada bulabilirsiniz.
Bir azaltma çekirdeği çalıştırmak için RenderScript çalışma zamanı bir veya daha fazla
toplayıcı verisi adı verilen değişkenler
öğeler indirimin durumunu korur. RenderScript çalışma zamanı
Toplayıcı veri öğelerinin sayısını, performansı en üst düzeye çıkaracak şekilde seçer. Tür
biri (accumType), çekirdeğin toplayıcı gücü tarafından belirlenir
işlev -- Bu işlevin ilk bağımsız değişkeni, toplayıcı verisine ilişkin bir işaretçidir
öğe. Varsayılan olarak, her toplayıcı veri öğesi sıfıra ayarlanır (sanki
memset
tarafından); ancak, bir şeyler yapmak için başlatıcı işlevi yazabilirsiniz
yardımcı olur.
Örnek: addint
toplayıcı veri öğeleri (int
türünde) giriş toplamak için kullanılır
değerler. Başlatıcı işlevi olmadığından her toplayıcı veri öğesi
sıfır.
Örnek:
findMinAndMax çekirdeği, toplayıcı veri öğeleri
(MinAndMax
türü) minimum ve maksimum değerleri izlemek için kullanılır
bulundu. Bunları LONG_MAX
olarak ayarlamak için bir başlatıcı işlevi vardır ve
Sırasıyla LONG_MIN
; ve bu değerlerin konumlarını -1 olarak ayarlamaktır. Bu şekilde,
Bu değerler, son 50 güne ait girişin (boş)
işlendi.
RenderScript, toplayıcı işlevinizi girdi. Genellikle, fonksiyonunuz toplayıcı veri öğesini bir şekilde güncellemelidir girişe göre değişir.
Örnek: addint toplayıcı fonksiyonu, bir giriş Öğesinin değerini toplayıcıya ekler. veri öğesine dokunun.
Örnek: findMinAndMax çekirdeği, toplayıcı işlevi bir giriş Öğesinin değerinin minimum değerden küçük veya bu değere eşit olup olmadığını kontrol eder toplayıcı veri öğesinde kaydedilen değer ve/veya maksimum değerden büyük ya da bu değere eşit değer, toplayıcı veri öğesine kaydedilir ve toplayıcı veri öğesini günceller buna göre hazırlar.
Toplayıcı işlevi, girişlerdeki her koordinat için bir kez çağrıldıktan sonra, RenderScript, toplayıcı veri öğelerini tek bir toplayıcı veri öğesinde toplar. Bir reklam birleştirici oluşturabilirsiniz. işlevini kullanın. Toplayıcı işlevinde tek bir giriş varsa ve özel bağımsız değişkenler yoksa birleştirici yazmanız gerekmez fonksiyon; RenderScript, toplayıcı verilerini bir araya getirmek için toplayıcı işlevini kullanır. öğeler. (Varsayılan davranış sizin için aynı değilse birleştirici işlevi de gerekir.)
Örnek: addint yoksa birleştirici işlevi yoktur, bu nedenle toplayıcı işlevi kullanılacaktır. Bu doğru davranış olmalıdır, çünkü bir değer koleksiyonunu iki parçaya bölersek ve bu iki parçadaki değerleri ayrı ayrı toplayın, bu iki toplamı toplamak bir durum vardır.
Örnek:
findMinAndMax çekirdeği, birleştirici işlevi
minimum değerin "kaynak"ta kaydedilip kaydedilmediğini kontrol eder toplayıcı verileri
*val
öğesi, "hedef" sütununda kaydedilen minimum değerden düşük
*accum
veri öğesini toplar ve *accum
günceller
buna göre hazırlar. Maksimum değer için de aynı işi yapar. Bu güncelleme *accum
bu durumda, tüm giriş değerlerinin tamamı toplanmış olsaydı
*accum
ve bazılarının *accum
içine girmek yerine
*val
.
Tüm toplayıcı veri öğeleri birleştirildikten sonra RenderScript, azalması oldu. Bir dönüştürücü yazabilirsiniz. işlevini kullanın. İsterseniz dış dönüştürücü işlevi yazmanıza gerek azaltmanın sonucu olacak şekilde birleştirilmiş veri öğelerinin son değeri.
Örnek: addint çekirdeğinde, dış dönüştürücü işlevi yoktur. Birleştirilmiş veri öğelerinin nihai değeri, Bu, döndürmek istediğimiz değerdir.
Örnek:
findMinAndMax çekirdeği, dış dönüştürücü işlevi
en düşük ve en düşük konumlarını tutmak için bir int2
sonuç değerini başlatır
tüm toplayıcı veri öğelerinin kombinasyonundan elde edilen maksimum değerlere
İndirgeme çekirdeği yazma
#pragma rs reduce
, bir azaltma çekirdeğini şu şekilde tanımlar:
işlevlerinin adlarını ve rollerini belirterek
yükseltmeye çalışıyor. Bu tür işlevlerin tümü
static
İndirme çekirdeği için her zaman accumulator
gerekir
fonksiyon; istediğinize bağlı olarak, diğer işlevlerin bazılarını veya tümünü çıkarabilirsiniz
çekirdeğine sahip olduğunu varsayalım.
#pragma rs reduce(kernelName) \ initializer(initializerName) \ accumulator(accumulatorName) \ combiner(combinerName) \ outconverter(outconverterName)
#pragma
içindeki öğelerin anlamı aşağıdaki gibidir:
reduce(kernelName)
(zorunlu): Kısaltma çekirdeğinin tanımlanmaktadır. Yansıtılmış bir Java yöntemireduce_kernelName
kernel'e gidin.initializer(initializerName)
(isteğe bağlı): ilkleştirici işlevi hakkında daha fazla bilgi edinin. Çekirdeği başlattığınızda RenderScript, Bu işlevi her bir toplayıcı veri öğesi için bir kez kullanın. İlgili içeriği oluşturmak için kullanılan fonksiyonu şu şekilde tanımlanmalıdır:static void initializerName(accumType *accum) { … }
accum
, bu işlev için toplayıcı veri öğesine işaret eden bir işarettir. ilk kullanıma hazırla.Başlatıcı işlevi sağlamazsanız RenderScript her toplayıcıyı başlatır veri öğesini sıfıra ayarlayarak (
memset
gibi) ve bir başlatıcı varmış gibi davranarak işlevi şu şekilde görünür:static void initializerName(accumType *accum) { memset(accum, 0, sizeof(*accum)); }
accumulator(accumulatorName)
. (zorunlu): Bu öğe için toplayıcı işlevinin adını belirtir indirme çekirdeğidir. Çekirdeği başlattığınızda RenderScript, Bu işlev, girişlerdeki her koordinat için bir kez olmak üzere, bir öğeyi bir şekilde toplayıcı veri öğesine bakar. İşlev şu şekilde tanımlanmalıdır:static void accumulatorName(accumType *accum, in1Type in1, …, inNType inN [, specialArguments]) { … }
accum
, bu işlev için toplayıcı veri öğesine işaret eden bir işarettir. değiştirebilirsiniz.in1
ileinN
aralığındaki değişkenler bir veya daha fazla bağımsız değişkendir çekirdek lansmanına iletilen girişlere göre otomatik olarak doldurulur, bir bağımsız değişken kullanabilirsiniz. Toplayıcı işlevi, isteğe bağlı olarak özel bağımsız değişkenlerden herhangi birini alabilir.Birden çok girişe sahip bir çekirdek:
dotProduct
.combiner(combinerName)
(isteğe bağlı): Bu öğe için birleştirici işlevinin adını belirtir indirme çekirdeğidir. RenderScript, toplayıcı işlevini çağırdıktan sonra her koordinat için bir kez çalıştırıldığında, bu fonksiyonu tüm toplayıcı veri öğelerini tek bir veri altında birleştirmek için biriken veri öğesidir. İşlev aşağıdaki gibi tanımlanmalıdır:
static void combinerName(accumType *accum, const accumType *other) { … }
accum
, bir "hedefe" işaret eder bunun için toplayıcı veri öğesi işlevini kullanın.other
, bir "kaynağa" işaret eden öğedir toplayıcı veri öğesi fonksiyonun "kombinasyonu" olarak*accum
konumuna eklendi.NOT: Bu işlem
*accum
,*other
veya her ikisinin de başlatıldığını ancak hiç başlatılmadığını toplayıcı işlevine aktarılmıştır; diğer bir deyişle, bu kullanıcılardan biri veya her ikisi de giriş verisine göre değiştirirsiniz. Örneğin, findMinAndMax çekirdeği, birleştiricifMMCombiner
işlevi açıkçaidx < 0
değerini kontrol eder, çünkü değeri INITVAL olan bir toplayıcı veri öğesini belirtir.Birleştirici işlevi sağlamazsanız RenderScript, yerde, aşağıdaki gibi bir birleştirici işlevi varmış gibi davranır:
static void combinerName(accumType *accum, const accumType *other) { accumulatorName(accum, *other); }
Giriş verilerinde birden fazla giriş varsa birleştirici işlevi zorunludur. type, toplayıcı veri türüyle aynı değilse veya toplayıcı fonksiyonu veya daha fazla özel bağımsız değişken kullanabilirsiniz.
outconverter(outconverterName)
. (isteğe bağlı): Bunun için dış dönüştürücü işlevinin adını belirtir indirme çekirdeğidir. RenderScript, toplam girdi parçasının iki veri öğesi kullanıyorsanız, ilgili değişkenin sonucunu belirlemek için kısaltması için de bunu yapabilirsiniz. İşlev aşağıdaki gibi tanımlanmalıdır: bu:static void outconverterName(resultType *result, const accumType *accum) { … }
result
, sonuç veri öğesine işaret eden bir öğedir (ayrılmış ancak başlatılmamış. tarafından oluşturulan bu işlevin sonucuyla başlatılması için) azaltmayı öğreteceğim. resultType, söz konusu veri öğesinin türüdür ve aynı olması gerekmez. accumType olarak değiştirin.accum
, nihai toplayıcı veri öğesine işaret eden bir işaretçidir birleştirici işlev tarafından hesaplanan.Bir dış dönüştürücü işlevi sağlamazsanız RenderScript nihai toplayıcıyı kopyalar veri öğesini sonuç veri öğesine bağlayacak şekilde, dönüşüm gerçekleştiren bir işlev varmış gibi davranarak şöyle görünür:
static void outconverterName(accumType *result, const accumType *accum) { *result = *accum; }
Toplayıcı veri türünden farklı bir sonuç türü istiyorsanız dış dönüştürücü işlevi zorunludur.
Çekirdeğin giriş türleri, toplayıcı veri öğesi türü ve sonuç türü olduğunu unutmayın.
Bunların hiçbirinin aynı olması gerekmez. Örneğin,
findMinAndMax çekirdeğinin temel değerini
long
, toplayıcı veri öğesi türü MinAndMax
ve sonuç
int2
türlerinin hepsi farklı.
Ne olduğunu varsayamazsınız?
Bir veri kümesi için RenderScript tarafından oluşturulan toplayıcı veri öğelerinin sayısını gerçekten çok daha iyidir. Aynı çekirdekteki iki lansmanın aynı girişler, aynı sayıda toplayıcı veri öğesi oluşturur.
RenderScript'in başlatıcıyı, toplayıcıyı ve diğer öğeleri çağırdığı sıraya güvenmemeniz gerekir. birleştirici işlevleri; hatta bazılarını paralel olarak çağırabilir. Projenin gidişatı boyunca aynı girişle aynı çekirdekten iki başlatma aynı sırayı takip eder. Tek yalnızca başlatıcı işlevinin başlatılmamış bir toplayıcıyı göreceğinin garantisi yoktur. veri öğesine dokunun. Örnek:
- Toplayıcı veri öğelerinin toplayıcı işlevi çağrılır, ancak yalnızca başlatılmış bir toplayıcıda çağrılır veri öğesine dokunun.
- Giriş öğelerinin toplayıcıya aktarılma sırasına dair herhangi bir garanti verilmez. işlevini kullanın.
- Toplayıcı işlevinin tüm giriş öğeleri için çağrıldığının garantisi yoktur işlevi çağrılmadan önce kullanılır.
Bunun sonuçlarından biri, findMinAndMax çekirdek deterministik değil: Giriş, aynı çekirdeğin hangi gerçekleşmeye başladığını bulabilirsiniz.
Neyi garanti etmelisiniz?
Çünkü RenderScript sistemi bir çekirdeği pek çok çekirdeğinizin davrandığından emin olmak için belirli kurallara istediğiniz gibi değiştirebilirsiniz. Bu kurallara uymazsanız hatalı sonuçlar alabilirsiniz, veya çalışma zamanı hataları olabilir.
Aşağıdaki kurallar genellikle iki toplayıcı veri öğesinin " aynı değere sahip". Bu ne anlama geliyor? Bu, çekirdeğin ne yapmasını istediğinize bağlıdır. Örneğin, addint gibi matematiksel bir indirgeme; bu genellikle "aynı" için ilk adımıdır. "Herhangi birini seçin" seçeneği için böyle ara findMinAndMax ("Minimum ve maksimum giriş değerleri"). Burada aynı giriş birden fazla kez olabilir. değerleri varsa belirli bir giriş değerinin tüm konumları "aynı" kabul edilmelidir. Örneğin, "leftmost minimum ve maksimum giriş değerlerinin konumunu bul" komutuna benzer bir çekirdek Bu örnekte, 100 numaralı konumdaki minimum değer, o konumdaki aynı minimum değere tercih edilir. 200; bu çekirdek için "aynı" yalnızca özdeş konum anlamına gelir. aynı değer ve toplayıcı ile birleştirici fonksiyonlarının findMinAndMax için olanlardan farklıdır.
Başlatıcı işlevi, bir kimlik değeri oluşturmalıdır. Yani,I
ve A
toplayıcı veri öğeleri başlatıldıysa
ilkleştirici işlevi tarafından gerçekleştirilmiştir ve I
,
toplayıcı fonksiyonu (ancak A
kullanılmış olabilir)
Örnek: addint bir toplayıcı veri öğesi sıfıra başlatılır. Bunun için birleştirici işlevi kernel, ekleme işlemi gerçekleştirir; sıfır, toplamanın özdeşlik değeridir.
Örnek: findMinAndMax
bir toplayıcı veri öğesi başlatıldı
INITVAL
konumuna kadar.
fMMCombiner(&A, &I)
,A
değerini aynı bırakır, çünküI
INITVAL
.fMMCombiner(&I, &A)
,I
ayarladıI
INITVAL
olduğundanA
adresine.
Dolayısıyla, INITVAL
gerçekten bir kimlik değeridir.
Birleştirici işlevi değişen olmalıdır. Yani,
A
ve B
toplayıcı veri öğeleri başlatıldıysa
Başlatıcı işlevi tarafından oluşturulur ve bu, toplayıcı işlevi sıfıra iletilmiş olabilir
veya daha çok kez teslim etmek için combinerName(&A, &B)
A
öğesini aynı değere ayarla
bu combinerName(&B, &A)
B
öğesini ayarlar.
Örnek: addint birleştirici işlevi, iki toplayıcı veri öğesi değerini ekler; ekleme değişmeli.
Örnek: findMinAndMax çekirdeğinde,
fMMCombiner(&A, &B)
ile aynı
A = minmax(A, B)
ve minmax
değişkendir
fMMCombiner
da aynı.
Birleştirici işlevi ilişkisel olmalıdır. Yani,
A
, B
ve C
ise
başlatıcı işlevi tarafından başlatılan ve iletilmiş olabilecek toplayıcı veri öğeleri
ekleme işlevine sıfır veya daha fazla kez eklemeniz gerekiyorsa aşağıdaki iki kod dizisi
A
öğesini aynı değere ayarlayın:
combinerName(&A, &B); combinerName(&A, &C);
combinerName(&B, &C); combinerName(&A, &B);
Örnek: addint çekirdeğinde birleştirici işlevi, iki toplayıcı veri öğesi değerini ekler:
A = A + B A = A + C // Same as // A = (A + B) + C
B = B + C A = A + B // Same as // A = A + (B + C) // B = B + C
Toplama ilişkilendirmeyle ilişkilidir, dolayısıyla birleştirici işlevi de ilişkiseldir.
Örnek: findMinAndMax çekirdeğinde,
fMMCombiner(&A, &B)şununla aynı:
A = minmax(A, B)Bu iki dizi
A = minmax(A, B) A = minmax(A, C) // Same as // A = minmax(minmax(A, B), C)
B = minmax(B, C) A = minmax(A, B) // Same as // A = minmax(A, minmax(B, C)) // B = minmax(B, C)
minmax
ilişkilendirici olduğundan fMMCombiner
de ilişkilidir.
Toplayıcı işlevi ve birleştirici işlevi birlikte, temel
katlama kuralına bakın. Yani A
ve B
toplayıcı veri öğeleridir, A
ise
başlatıcı işlevi tarafından başlatıldı ve toplayıcı işlevine iletilmiş olabilir
veya daha fazla kez, B
başlatılmadı ve bağımsız değişkenler
toplayıcıya yapılan belirli bir çağrı için giriş bağımsız değişkenlerinin ve özel bağımsız değişkenlerin listesi
işlevinde, aşağıdaki iki kod dizisi A
değerini ayarlamalıdır
aynı değere:
accumulatorName(&A, args); // statement 1
initializerName(&B); // statement 2 accumulatorName(&B, args); // statement 3 combinerName(&A, &B); // statement 4
Örnek: addint çekirdeğinde, V giriş değeri için:
- İfade 1,
A += V
ile aynı - İfade 2,
B = 0
ile aynı - İfade 3,
B += V
ile aynı olup bu ifadeB = V
ile aynıdır - İfade 4,
A += B
ile aynı olup bu ifadeA += V
ile aynıdır
İfade 1 ve 4, A
öğesini aynı değere ayarladığından bu çekirdek
temel katlama kuralı.
Örnek: findMinAndMax çekirdeğinde bir giriş için X koordinatındaki V değeri:
- İfade 1,
A = minmax(A, IndexedVal(V, X))
ile aynı - İfade 2,
B = INITVAL
ile aynı - İfade 3, aynı
B = minmax(B, IndexedVal(V, X))
. Bu, B başlangıç değeri olduğu içinB = IndexedVal(V, X)
- İfade 4,
A = minmax(A, B)
. Bu, ile aynıA = minmax(A, IndexedVal(V, X))
İfade 1 ve 4, A
öğesini aynı değere ayarladığından bu çekirdek
temel katlama kuralı.
Java kodundan bir azaltma çekirdeği çağırma
Şurada tanımlanan kernelName adlı bir azaltma çekirdeği için
filename.rs
dosyasında belirtilen üç yöntem vardır:
ScriptC_filename
. sınıf:
Kotlin
// Function 1 fun reduce_kernelName(ain1: Allocation, …, ainN: Allocation): javaFutureType // Function 2 fun reduce_kernelName(ain1: Allocation, …, ainN: Allocation, sc: Script.LaunchOptions): javaFutureType // Function 3 fun reduce_kernelName(in1: Array<devecSiIn1Type>, …, inN: Array<devecSiInNType>): javaFutureType
Java
// Method 1 public javaFutureType reduce_kernelName(Allocation ain1, …, Allocation ainN); // Method 2 public javaFutureType reduce_kernelName(Allocation ain1, …, Allocation ainN, Script.LaunchOptions sc); // Method 3 public javaFutureType reduce_kernelName(devecSiIn1Type[] in1, …, devecSiInNType[] inN);
Aşağıda, addint çekirdeğini çağırmaya ilişkin bazı örnekler verilmiştir:
Kotlin
val script = ScriptC_example(renderScript) // 1D array // and obtain answer immediately val input1 = intArrayOf(…) val sum1: Int = script.reduce_addint(input1).get() // Method 3 // 2D allocation // and do some additional work before obtaining answer val typeBuilder = Type.Builder(RS, Element.I32(RS)).apply { setX(…) setY(…) } val input2: Allocation = Allocation.createTyped(RS, typeBuilder.create()).also { populateSomehow(it) // fill in input Allocation with data } val result2: ScriptC_example.result_int = script.reduce_addint(input2) // Method 1 doSomeAdditionalWork() // might run at same time as reduction val sum2: Int = result2.get()
Java
ScriptC_example script = new ScriptC_example(renderScript); // 1D array // and obtain answer immediately int input1[] = …; int sum1 = script.reduce_addint(input1).get(); // Method 3 // 2D allocation // and do some additional work before obtaining answer Type.Builder typeBuilder = new Type.Builder(RS, Element.I32(RS)); typeBuilder.setX(…); typeBuilder.setY(…); Allocation input2 = createTyped(RS, typeBuilder.create()); populateSomehow(input2); // fill in input Allocation with data ScriptC_example.result_int result2 = script.reduce_addint(input2); // Method 1 doSomeAdditionalWork(); // might run at same time as reduction int sum2 = result2.get();
1. yöntemde bir giriş Allocation
bağımsız değişkeni vardır
çekirdeğin toplayıcısındaki her giriş bağımsız değişkeni
işlevi hakkında daha fazla bilgi edinin. RenderScript çalışma zamanı, tüm giriş ayırmalarının sağlandığından
sahip olması ve her birinin Element
türünde olması
giriş ayırmaları, toplayıcının karşılık gelen giriş bağımsız değişkenininkiyle eşleşir
fonksiyonun prototipini oluşturur. Bu kontrollerden herhangi biri başarısız olursa RenderScript bir istisna uygular. İlgili içeriği oluşturmak için kullanılan
bu boyutlardaki her koordinat üzerinde yürütülür.
2. Yöntem, 1. Yöntem ile aynıdır ancak 2. Yöntem
sc
bağımsız değişkeni, çekirdek yürütme işlemini
koordinatlar.
3. Yöntem,
ayırma girdileri yerine Java dizisi girişleri alır. Bu, kullanıcılara
sizi, açıkça bir Ayırma oluşturmak ve verileri buna kopyalamak için kod yazma zahmetinden kurtarır
dizesinden oluşur. Ancak Yöntem 1 yerine 3. Yöntem kullanıldığında
hakkında daha fazla bilgi edinin. Her giriş dizisi için 3. Yöntem, her bir giriş dizisi için
Uygun Element
türünde 1 Boyutlu Ayırma ve
setAutoPadding(boolean)
etkinleştirilir ve diziyi
Ayırma: Allocation
için uygun copyFrom()
yöntemini kullanarak ayırma. Daha sonra 1. Yöntemi çağırarak bu geçici
Ayırmalar.
NOT: Uygulamanız veya aynı boyutlara ve Öğe türüne sahip farklı dizilerle gösterilebilir. oluşturmak yerine, ayırmaları kendiniz oluşturmanız, doldurmanız ve yeniden kullanmanız, 3. Yöntem'i kullanın.
JavaFutureType:
yansıtılan indirgeme yöntemlerinin dönüş türü,
ScriptC_filename
içindeki iç içe yerleştirilmiş statik sınıf
sınıfını kullanır. Bir azalmanın gelecekteki sonucunu temsil eder
oluşturmanız gerekir. Çalıştırmanın asıl sonucunu almak için
söz konusu sınıfın get()
yöntemi; bu yöntem bir değer döndürür
javaResultType türünde. get()
eşzamanlı.
Kotlin
class ScriptC_filename(rs: RenderScript) : ScriptC(…) { object javaFutureType { fun get(): javaResultType { … } } }
Java
public class ScriptC_filename extends ScriptC { public static class javaFutureType { public javaResultType get() { … } } }
javaResultType, sonucun sonuç türünden outconverter fonksiyonu. resultType, bir imzasız tür (skalar, vektör veya dizi), javaResultType doğrudan Java türü. resultType, imzasız bir türse ve daha büyük bir Java imzalı tür varsa javaResultType daha büyük olan Java imzalı türüdür; Aksi takdirde, doğrudan girin. Örnek:
- resultType,
int
,int2
veyaint[15]
ise javaResultType iseint
,Int2
olur, veyaint[]
. Tüm resultType değerleri temsil edilebilir javaResultType tarafından oluşturulur. - resultType,
uint
,uint2
veyauint[15]
ise bu durumda javaResultType değerilong
,Long2
, veyalong[]
. Tüm resultType değerleri temsil edilebilir javaResultType tarafından oluşturulur. - resultType ise
ulong
,ulong2
ise veyaulong[15]
, ardından javaResultTypelong
,Long2
veyalong[]
. Bu özellikte belirli değerler javaResultType ile temsil edilemeyen resultType.
javaFutureType, ilgili değişkene karşılık gelen gelecekteki sonuç türüdür outconverter'ın resultType işlevine ekleyin.
- resultType bir dizi türü değilse javaFutureType
şu anda
result_resultType
. - resultType, memberType türündeki üyelere sahip bir Count uzunluk dizisiyse:
javaFutureType,
resultArrayCount_memberType
olur.
Örnek:
Kotlin
class ScriptC_filename(rs: RenderScript) : ScriptC(…) { // for kernels with int result object result_int { fun get(): Int = … } // for kernels with int[10] result object resultArray10_int { fun get(): IntArray = … } // for kernels with int2 result // note that the Kotlin type name "Int2" is not the same as the script type name "int2" object result_int2 { fun get(): Int2 = … } // for kernels with int2[10] result // note that the Kotlin type name "Int2" is not the same as the script type name "int2" object resultArray10_int2 { fun get(): Array<Int2> = … } // for kernels with uint result // note that the Kotlin type "long" is a wider signed type than the unsigned script type "uint" object result_uint { fun get(): Long = … } // for kernels with uint[10] result // note that the Kotlin type "long" is a wider signed type than the unsigned script type "uint" object resultArray10_uint { fun get(): LongArray = … } // for kernels with uint2 result // note that the Kotlin type "Long2" is a wider signed type than the unsigned script type "uint2" object result_uint2 { fun get(): Long2 = … } // for kernels with uint2[10] result // note that the Kotlin type "Long2" is a wider signed type than the unsigned script type "uint2" object resultArray10_uint2 { fun get(): Array<Long2> = … } }
Java
public class ScriptC_filename extends ScriptC { // for kernels with int result public static class result_int { public int get() { … } } // for kernels with int[10] result public static class resultArray10_int { public int[] get() { … } } // for kernels with int2 result // note that the Java type name "Int2" is not the same as the script type name "int2" public static class result_int2 { public Int2 get() { … } } // for kernels with int2[10] result // note that the Java type name "Int2" is not the same as the script type name "int2" public static class resultArray10_int2 { public Int2[] get() { … } } // for kernels with uint result // note that the Java type "long" is a wider signed type than the unsigned script type "uint" public static class result_uint { public long get() { … } } // for kernels with uint[10] result // note that the Java type "long" is a wider signed type than the unsigned script type "uint" public static class resultArray10_uint { public long[] get() { … } } // for kernels with uint2 result // note that the Java type "Long2" is a wider signed type than the unsigned script type "uint2" public static class result_uint2 { public Long2 get() { … } } // for kernels with uint2[10] result // note that the Java type "Long2" is a wider signed type than the unsigned script type "uint2" public static class resultArray10_uint2 { public Long2[] get() { … } } }
javaResultType bir nesne türüyse (dizi türü dahil) her çağrı
aynı örnekte javaFutureType.get()
değerine ayarlanırsa aynı
nesnesini tanımlayın.
javaResultType, resultType türündeki tüm değerleri ve bir
indirgeme çekirdeği temsil edilemeyen bir değer üretir,
sonra javaFutureType.get()
bir istisna yapar.
3. Yöntem ve devecSiInXType
devecSiInXType, karşılık gelen bağımsız değişkenin inXType toplayıcı işlevi. inXType imzasız tür veya vektör türündeyse devecSiInXType, kendisi için doğrudan karşılık gelen Java türü. inXType işaretsiz bir skaler türse devecSiInXType Doğrudan aynının işaretli skaler türüne karşılık gelen Java türü seçin. inXType işaretli bir vektör türüyse devecSiInXType, Java'dır. doğrudan vektör bileşeni türüne karşılık gelen türe karşılık gelir. inXType imzalanmamış bir vektör türüne karşılık gelen Java türüdür, devecSiInXType ise doğrudan vektör bileşen türüyle aynı boyutta imzalanmış skaler tür. Örnek:
- inXType değeri
int
ise devecSiInXType şu andaint
. - inXType değeri
int2
ise devecSiInXTypeint
. Dizi, düzleştirilmiş bir temsildir: Dizi, iki kat daha fazla Ayırma 2 bileşenli vektöre sahip olduğundan birçok skaler Öğe Öğeler. Bu,Allocation
içincopyFrom()
yöntemlerinin çalışma biçimiyle aynıdır. - inXType değeri
uint
ise deviceSiInXType değeriint
. Java dizisindeki imzalı bir değer, aynı bit kalıbına sahip olması gerekir. Bu,copyFrom()
öğesinin çalışma yöntemidir.Allocation
- inXType değeri
uint2
ise deviceSiInXType değeriint
. Bu,int2
veuint
yöntemlerinin kombinasyonudur. işlenir: Dizi, düzleştirilmiş bir gösterimdir ve Java dizisi imzalı değerleri değeri olarak yorumlanır.
3. Yöntem için giriş türlerinin farklı şekilde işlendiğini unutmayın. şu sonuç türlerinden birini kullanıyor:
- Bir komut dosyasının vektör girişi Java tarafında düzleştirilirken, komut dosyasının vektör sonucu aynı değildir.
- Bir komut dosyasının imzasız girişi, Java'da aynı boyutta imzalı bir giriş olarak gösterilir
bir komut dosyasının imzasız sonucu, Java dili için genişletilmiş imzalı bir tür olarak temsil edilir
tarafından sağlanır (
ulong
durumu hariç).
Daha fazla azaltma çekirdekleri
#pragma rs reduce(dotProduct) \ accumulator(dotProductAccum) combiner(dotProductSum) // Note: No initializer function -- therefore, // each accumulator data item is implicitly initialized to 0.0f. static void dotProductAccum(float *accum, float in1, float in2) { *accum += in1*in2; } // combiner function static void dotProductSum(float *accum, const float *val) { *accum += *val; }
// Find a zero Element in a 2D allocation; return (-1, -1) if none #pragma rs reduce(fz2) \ initializer(fz2Init) \ accumulator(fz2Accum) combiner(fz2Combine) static void fz2Init(int2 *accum) { accum->x = accum->y = -1; } static void fz2Accum(int2 *accum, int inVal, int x /* special arg */, int y /* special arg */) { if (inVal==0) { accum->x = x; accum->y = y; } } static void fz2Combine(int2 *accum, const int2 *accum2) { if (accum2->x >= 0) *accum = *accum2; }
// Note that this kernel returns an array to Java #pragma rs reduce(histogram) \ accumulator(hsgAccum) combiner(hsgCombine) #define BUCKETS 256 typedef uint32_t Histogram[BUCKETS]; // Note: No initializer function -- // therefore, each bucket is implicitly initialized to 0. static void hsgAccum(Histogram *h, uchar in) { ++(*h)[in]; } static void hsgCombine(Histogram *accum, const Histogram *addend) { for (int i = 0; i < BUCKETS; ++i) (*accum)[i] += (*addend)[i]; } // Determines the mode (most frequently occurring value), and returns // the value and the frequency. // // If multiple values have the same highest frequency, returns the lowest // of those values. // // Shares functions with the histogram reduction kernel. #pragma rs reduce(mode) \ accumulator(hsgAccum) combiner(hsgCombine) \ outconverter(modeOutConvert) static void modeOutConvert(int2 *result, const Histogram *h) { uint32_t mode = 0; for (int i = 1; i < BUCKETS; ++i) if ((*h)[i] > (*h)[mode]) mode = i; result->x = mode; result->y = (*h)[mode]; }
Ek kod örnekleri
BasicRenderScript, RenderScriptIntrinsic, ve Merhaba Compute örnekler, bu sayfada ele alınan API'lerin kullanımını daha ayrıntılı şekilde gösterir.