Komut dosyalarını OpenGL ES 3.1'e taşıma

GPU bilgi işlemesinin ideal olduğu iş yükleri için RenderScript komut dosyalarını OpenGL ES'ye (GLES) taşımak, Kotlin, Java veya NDK kullanılarak yazılan uygulamaların GPU donanımından yararlanmasını sağlar. RenderScript komut dosyalarını değiştirmek için OpenGL ES 3.1 işlem gölgelendiricilerini kullanmanıza yardımcı olmak üzere üst düzey bir genel bakış aşağıda verilmiştir.

GLES Başlatma

RenderScript bağlam nesnesi oluşturmak yerine, EGL kullanarak bir GLES ekran dışı bağlamı oluşturmak için aşağıdaki adımları uygulayın:

  1. Varsayılan görüntüyü alma

  2. GLES sürümünü belirterek, varsayılan ekranı kullanarak EGL'yi başlatın.

  3. Yüzey türü EGL_PBUFFER_BIT olan bir EGL yapılandırması seçin.

  4. EGL bağlamı oluşturmak için ekran ve yapılandırmayı kullanın.

  5. eglCreatePBufferSurface ile ekran dışı yüzeyi oluşturun. Bağlam yalnızca hesaplama için kullanılacaksa çok küçük (1x1) bir yüzey olabilir.

  6. GL bağlamını iş parçacığına bağlamak için görüntü, yüzey ve EGL bağlamıyla oluşturma iş parçacığını oluşturun ve oluşturma ileti dizisinde eglMakeCurrent çağrısı yapın.

Örnek uygulama, GLSLImageProcessor.kt'te GLES bağlamının nasıl başlatılacağını göstermektedir. Daha fazla bilgi edinmek için bkz. EGLSurfaces ve OpenGL ES.

GLES hata ayıklama çıkışı

OpenGL'den faydalı hatalar almak, hata ayıklama çıkışı geri çağırmasını ayarlayan hata ayıklama günlük kaydını etkinleştirmek için bir uzantı kullanır. Bu işlemi SDK'dan (glDebugMessageCallbackKHR) yapma yöntemi daha önce hiç uygulanmamıştır ve bu nedenle bir istisna ortaya çıkar. Örnek uygulama, NDK kodundan geri çağırma için bir sarmalayıcı içerir.

GLES Ayırmaları

RenderScript Ayırma işlemi, Sabit depolama dokusuna veya Gölgeleme Depolama Arabellek Nesnesi'ne taşınabilir. Salt okunur görüntüler için, filtrelemeye olanak tanıyan bir Örnekleyici Nesne kullanabilirsiniz.

GLES kaynakları GLES içinde ayrılır. Diğer Android bileşenleriyle etkileşim kurarken bellekte ek yükten kaçınmak için 2D görüntü verisi dizilerinin paylaşılmasına olanak tanıyan bir KHR Images uzantısı bulunmaktadır. Bu uzantı, Android 8.0 ile başlayan Android cihazlar için zorunludur. graphics-core Android Jetpack kitaplığı, bu görüntüleri yönetilen kod içinde oluşturma ve bunları ayrılmış bir HardwareBuffer ile eşleme desteği içerir:

val outputBuffers = Array(numberOfOutputImages) {
  HardwareBuffer.create(
    width, height, HardwareBuffer.RGBA_8888, 1,
    HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE
  )
}
val outputEGLImages = Array(numberOfOutputImages) { i ->
    androidx.opengl.EGLExt.eglCreateImageFromHardwareBuffer(
        display,
        outputBuffers[i]
    )!!
}

Ne yazık ki bu, işlem gölgelendiricisinin doğrudan arabelleğe yazması için gereken sabit depolama dokusunu oluşturmaz. Örnekte, işlem gölgelendiricisi tarafından kullanılan depolama dokusunu KHR Image'e kopyalamak için glCopyTexSubImage2D kullanılır. OpenGL sürücüsü EGL Image Storage uzantısını destekliyorsa bu uzantı, kopyadan kaçınmak amacıyla paylaşılan bir sabit depolama dokusu oluşturmak için kullanılabilir.

GLSL hesaplama gölgelendiricilerine dönüştürme

RenderScript komut dosyalarınız GLSL hesaplama gölgelendiricilerine dönüştürülür.

GLSL hesaplama gölgelendiricisi yazma

OpenGL ES'de,hesaplama gölgelendiricileri OpenGL Gölgeleme Dili (GLSL) ile yazılır.

Komut dosyası genellerinin uyarlanması

Genel komut dosyası genellerinin özelliklerine bağlı olarak, gölgelendiricide değiştirilmemiş geneller için üniformalar veya tek tip tampon nesneler kullanabilirsiniz:

  • Tek tip arabellek: Aktarım sabit sınırından daha büyük boyutlardaki ve sık değiştirilen komut dosyası genelleri için önerilir.

Gölgelendiricide değiştirilen global kitleler için Sabit depolama dokusu veya Gölgelendirici Depolama Arabellek Nesnesi kullanabilirsiniz.

Hesaplamaları Yürütme

İşlem gölgelendiriciler, grafik ardışık düzeninin bir parçası değildir; genel amaçlıdır ve son derece paralelleştirilebilir işleri hesaplamak için tasarlanmıştır. Bu şekilde, çalışma biçimleri üzerinde daha fazla kontrol sahibi olursunuz ancak işinizin paralelliğini biraz daha iyi anlamanız gerekir.

İşlem programını oluşturma ve başlatma

İşlem programını oluşturma ve başlatma, diğer herhangi bir GLES gölgelendiriciyle çalışmayla bağlantılı birçok ortak özelliğe sahiptir.

  1. Programı ve programla ilişkili işlem gölgelendiricisini oluşturun.

  2. Gölgelendirici kaynağını ekleyin, gölgelendiriciyi derleyin (ve derlemenin sonuçlarını kontrol edin).

  3. Gölgelendiriciyi takın, programı bağlayın ve programı kullanın.

  4. Üniformaları oluşturun, başlatın ve bağlayın.

Hesaplama başlatma

Hesap gölgelendiriciler, gölgelendirici kaynak kodu içinde tanımlanmış bir çalışma grubu dizisi üzerinde soyut 1D, 2D veya 3D alan içinde çalışır ve minimum çağrı boyutunu ve gölgelendiricinin geometrisini temsil eder. Aşağıdaki gölgelendirici bir 2D görüntü üzerinde çalışır ve çalışma gruplarını iki boyutta tanımlar:

private const val WORKGROUP_SIZE_X = 8
private const val WORKGROUP_SIZE_Y = 8
private const val ROTATION_MATRIX_SHADER =
    """#version 310 es
    layout (local_size_x = $WORKGROUP_SIZE_X, local_size_y = $WORKGROUP_SIZE_Y, local_size_z = 1) in;

Çalışma grupları, GL_MAX_COMPUTE_SHARED_MEMORY_SIZE ile tanımlanan belleği paylaşabilir. Bu boyut, en az 32 KB'tır ve tutarlı bellek erişimi sağlamak için memoryBarrierShared()'den yararlanabilir.

Çalışma grubu boyutunu tanımlama

Sorunlu alanınız 1'lik çalışma grubu boyutlarıyla iyi sonuç veriyor olsa bile işlem gölgelendiricisini paralel yapmak için uygun bir çalışma grubu boyutu ayarlamak önemlidir. Örneğin, boyut çok küçükse GPU sürücüsü, işlemlerinizi yeterince paralel yapmayabilir. İdeal olarak bu boyutların GPU'ya göre ayarlanması gerekir. Ancak, gölgelendirici snippet'indeki 8x8 çalışma grubu boyutu gibi uygun varsayılan ayarlar mevcut cihazlarda yeterince iyi sonuç verir.

Bir GL_MAX_COMPUTE_WORK_GROUP_COUNT var, ancak bu büyüktür; spesifikasyona göre üç eksende de en az 65535 olmalıdır.

Gölgelendiriciyi gönder

Hesaplamaları yürütmenin son adımı, gölgelendiriciyi glDispatchCompute gibi dağıtım işlevlerinden birini kullanarak dağıtmaktır. Dağıtım işlevi her eksen için çalışma grubu sayısını ayarlamaktan sorumludur:

GLES31.glDispatchCompute(
  roundUp(inputImage.width, WORKGROUP_SIZE_X),
  roundUp(inputImage.height, WORKGROUP_SIZE_Y),
  1 // Z workgroup size. 1 == only one z level, which indicates a 2D kernel
)

Değeri döndürmek için önce işlem işleminin bellek bariyeri kullanarak tamamlanmasını bekleyin:

GLES31.glMemoryBarrier(GLES31.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT)

Birden çok çekirdeği birbirine bağlamak için (örneğin, ScriptGroup kullanarak kod taşımak) birden çok program oluşturup dağıtın ve bunların çıkışa erişimini bellek bariyerleriyle senkronize edin.

Örnek uygulamada iki işlem görevi gösterilmektedir:

  • HUE rotasyonu: Tek bir gölgelendiriciye sahip bir işlem görevi. Kod örneği için GLSLImageProcessor::rotateHue sayfasını inceleyin.
  • Bulanıklaştırma: Sırayla iki hesaplama gölgelendirmesi yürüten daha karmaşık bir işlem görevi. Kod örneği için GLSLImageProcessor::blur adresine göz atın.

Bellek bariyerleri hakkında daha fazla bilgi edinmek için Görünürlüğü sağlama ve Paylaşılan değişkenler konularına bakın.