RenderScript की खास जानकारी

Renderस्क्रिप्ट एक फ़्रेमवर्क है, जो Android. RenderScript मुख्य रूप से डेटा-पैरलल कंप्यूटेशन के साथ इस्तेमाल करने के लिए बनाया गया है, हालांकि सीरियल नंबर के लिए वर्कलोड से भी फ़ायदा हो सकता है. रेंडर स्क्रिप्ट का रनटाइम साथ-साथ चलता है यह सुविधा, मल्टी-कोर सीपीयू और जीपीयू जैसे डिवाइस पर उपलब्ध प्रोसेसर पर काम करती है. इससे आपको काम शेड्यूल करने के बजाय, एल्गोरिदम को बताने पर ध्यान दें. रेंडर स्क्रिप्ट है यह खास तौर पर उन ऐप्लिकेशन के लिए फ़ायदेमंद है जो इमेज प्रोसेसिंग, कंप्यूटेशनल फ़ोटोग्राफ़ी या कंप्यूटर विज़न.

RenderScript के साथ शुरू करने के लिए, आपको दो मुख्य अवधारणाओं को समझना चाहिए:

  • language, C99 से बनाई गई भाषा है. इसकी मदद से, अच्छी परफ़ॉर्मेंस वाले कंप्यूट लिखे जा सकते हैं कोड. RenderScript कर्नेल लिखना कंप्यूट कर्नेल लिखने के लिए इसका इस्तेमाल कैसे करें.
  • control API का इस्तेमाल RenderScript संसाधनों के लाइफ़टाइम को मैनेज करने के लिए किया जाता है और कर्नेल के एक्ज़ीक्यूशन को कंट्रोल कर रही है. यह तीन अलग-अलग भाषाओं में उपलब्ध है: Java, Android में C++ NDK, और C99 से ली गई कर्नेल भाषा है. Java कोड से RenderScript का इस्तेमाल करना और सिंगल-सोर्स रेंडरस्क्रिप्ट में, पहली और तीसरे विकल्प भी हैं.

RenderScript कर्नेल लिखना

RenderScript कर्नेल आम तौर पर, इस.rs <project_root>/src/rs डायरेक्ट्री; हर .rs फ़ाइल को script. हर स्क्रिप्ट में कर्नेल, फ़ंक्शन, और वैरिएबल का अपना सेट होता है. स्क्रिप्ट यह कर सकती है इसमें शामिल हैं:

  • प्राग्मा एलान (#pragma version(1)) जिसमें यह बताया जाता है कि इस स्क्रिप्ट में RenderScript कर्नेल भाषा का इस्तेमाल किया गया है. फ़िलहाल, सिर्फ़ 1 ही मान्य वैल्यू है.
  • एक प्रग्मा एलान (#pragma rs java_package_name(com.example.app)) जो इस स्क्रिप्ट से दिखाई गई Java क्लास के पैकेज का नाम बताता है. ध्यान दें कि आपकी .rs फ़ाइल आपके अनुप्रयोग पैकेज का हिस्सा होनी चाहिए, न कि लाइब्रेरी प्रोजेक्ट पर जाकर.
  • शून्य या उससे ज़्यादा इनवॉइस किए जा सकने वाले फ़ंक्शन. शुरू किया जा सकने वाला फ़ंक्शन, सिंगल-थ्रेड RenderScript है फ़ंक्शन है, जिसे आर्बिट्रेरी आर्ग्युमेंट के साथ अपने Java कोड से कॉल किया जा सकता है. ये अक्सर इन चीज़ों के लिए फ़ायदेमंद होते हैं शुरुआती सेटअप या सीरियल कंप्यूटेशन को बड़ी प्रोसेसिंग पाइपलाइन में डालें.
  • शून्य या उससे ज़्यादा स्क्रिप्ट ग्लोबल. स्क्रिप्ट ग्लोबल, C के ग्लोबल वैरिएबल की तरह ही होता है. आप Java कोड से स्क्रिप्ट ग्लोबल ऐक्सेस करें और इनका इस्तेमाल अक्सर RenderScript को पास करने के लिए पैरामीटर के लिए किया जाता है कर्नेल. स्क्रिप्ट ग्लोबल के बारे में ज़्यादा जानकारी यहां दी गई है.

  • शून्य या उससे ज़्यादा कंप्यूट कर्नेल. कंप्यूट कर्नेल एक फ़ंक्शन है या फ़ंक्शन के ऐसे कलेक्शन को साथ-साथ एक्ज़ीक्यूट करने के लिए, RenderScript रनटाइम को निर्देश दें ट्रैक किया जा सकता है. दो तरह की कंप्यूटिंग कर्नेल: मैपिंग कर्नेल (इन्हें foreach कर्नेल भी कहा जाता है) और रिडक्शन कर्नेल.

    मैपिंग कर्नेल एक पैरलल फ़ंक्शन है, जो एक जैसे डाइमेंशन के Allocations के कलेक्शन पर काम करता है. डिफ़ॉल्ट रूप से, यह प्रोसेस उन डाइमेंशन में हर निर्देशांक के लिए एक बार. आम तौर पर, इसका इस्तेमाल इन कामों के लिए किया जाता है (लेकिन खास तौर पर नहीं) इनपुट Allocations के संग्रह को आउटपुट Allocation एक Element समय.

    • यहां एक सामान्य मैपिंग कर्नेल का उदाहरण दिया गया है:

      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;
      }

      ज़्यादातर मामलों में, यह स्टैंडर्ड C फ़ंक्शन का इस्तेमाल करना होगा. RS_KERNEL प्रॉपर्टी फ़ंक्शन प्रोटोटाइप बताता है कि फ़ंक्शन अमान्य फ़ंक्शन का इस्तेमाल किया जा सकता है. यहां दिए गए कॉन्टेंट के आधार पर, in आर्ग्युमेंट अपने-आप भर जाता है कर्नेल लॉन्च को Allocation इनपुट दिया गया. कॉन्टेंट बनाने तर्क x और y हैं इनके बारे में यहां बताया गया है. कर्नेल से लौटाया गया मान है आउटपुट Allocation में सही जगह पर अपने-आप लिखा जाएगा. डिफ़ॉल्ट रूप से, यह कर्नेल इसके पूरे इनपुट पर चलता है Allocation, Allocation में हर Element के लिए कर्नेल फ़ंक्शन के एक निष्पादन के साथ.

      मैपिंग कर्नेल में, एक या उससे ज़्यादा इनपुट Allocations, एक आउटपुट Allocation या दोनों हो सकते हैं. कॉन्टेंट बनाने RenderScript रनटाइम जांच करके यह पक्का करता है कि सभी इनपुट और आउटपुट आवंटन एक जैसे हैं या नहीं डाइमेंशन और इनपुट और आउटपुट के Element टाइप ऐलोकेशन, कर्नेल के प्रोटोटाइप से मेल खाती है; अगर इनमें से कोई भी जाँच पूरी नहीं होती है, तो RenderScript एक अपवाद देता है.

      ध्यान दें: Android 6.0 (एपीआई लेवल 23) से पहले, मैपिंग कर्नेल एक से ज़्यादा इनपुट Allocation नहीं हैं.

      अगर आपको Allocations से ज़्यादा इनपुट या आउटपुट चाहिए, तो कर्नेल में हैं, तो वे ऑब्जेक्ट rs_allocation स्क्रिप्ट ग्लोबल से बाध्य होने चाहिए और कर्नेल या इन्वोकेबल फ़ंक्शन से ऐक्सेस किया गया हो rsGetElementAt_type() या rsSetElementAt_type() से.

      ध्यान दें: RS_KERNEL एक मैक्रो है आपकी सुविधा के लिए RenderScript द्वारा अपने आप परिभाषित किया गया है:

      #define RS_KERNEL __attribute__((kernel))
      

    रिडक्शन कर्नेल, फ़ंक्शन का एक परिवार है जो इनपुट के कलेक्शन पर काम करता है एक जैसे डाइमेंशन का Allocations. डिफ़ॉल्ट रूप से, इसका accuulator फ़ंक्शन, हर निर्देशांक भी शामिल हैं. आम तौर पर, इसका इस्तेमाल "कम करने" के लिए किया जाता है. हालांकि, खास तौर पर इसका इस्तेमाल नहीं किया जाता एक सिंगल के लिए इनपुट Allocations का कलेक्शन वैल्यू.

    • यहां कम कटौती का एक उदाहरण दिया गया है कर्नेल का इस्तेमाल करता है, जो इसके Elements को जोड़ता है इनपुट:

      #pragma rs reduce(addint) accumulator(addintAccum)
      
      static void addintAccum(int *accum, int val) {
        *accum += val;
      }

      रिडक्शन कर्नेल में एक या उससे ज़्यादा उपयोगकर्ता के लिखे गए फ़ंक्शन होते हैं. #pragma rs reduce का इस्तेमाल, कर्नेल का नाम तय करके उसे तय करने के लिए किया जाता है (इस उदाहरण में addint) और बनाने वाले फ़ंक्शन के नाम और भूमिकाएं कर्नेल को ऊपर करें (इसमें accumulator फ़ंक्शन addintAccum है, इसमें उदाहरण के लिए). ऐसे सभी फ़ंक्शन static होने चाहिए. रिडक्शन कर्नेल हमेशा accumulator फ़ंक्शन होना ज़रूरी है; उसमें अन्य फ़ंक्शन भी हो सकते हैं, कि आप कर्नेल से क्या करवाना चाहते हैं.

      रिडक्शन कर्नेल अक्युमिलेटर फ़ंक्शन में void दिखना चाहिए. साथ ही, इसमें कम से कम यह फ़ंक्शन होना चाहिए दो आर्ग्युमेंट. पहला तर्क (इस उदाहरण में, accum) एक अक्यूम्युलेटर डेटा आइटम और दूसरा (इस उदाहरण में val) है इसे दिए गए इनपुट Allocation के आधार पर अपने आप भरा जाता है कर्नेल लॉन्च. संचय डेटा आइटम को RenderScript रनटाइम के ज़रिए बनाया जाता है; लेखक डिफ़ॉल्ट तौर पर, यह शून्य से शुरू होता है. डिफ़ॉल्ट रूप से, यह कर्नेल इसके पूरे इनपुट पर चलता है Allocation, जिसमें हर बार अक्यूम्युलेटर फ़ंक्शन को एक्ज़िक्यूशन के तौर पर चलाया जाता है Allocation में Element. इन्होंने बदलाव किया है डिफ़ॉल्ट, अक्युमिलेटर डेटा आइटम की आखिरी वैल्यू को कम कर देता है और उसे Java में वापस भेज दिया जाता है. RenderScript रनटाइम जांच करके यह पक्का करता है कि इनपुट ऐलोकेशन का Element टाइप, अक्यूम्युलेटर फ़ंक्शन से मेल खाता है प्रोटोटाइप; अगर यह मेल नहीं खाता है, तो रेंडर स्क्रिप्ट एक अपवाद दिखाता है.

      रिडक्शन कर्नेल में एक या उससे ज़्यादा इनपुट Allocations हैं, लेकिन कोई आउटपुट Allocations नहीं है.

      कम करने वाले कर्नेल के बारे में ज़्यादा जानकारी यहां दी गई है.

      कम करने वाले कर्नेल Android 7.0 (एपीआई लेवल 24) और उसके बाद के वर्शन पर काम करते हैं.

    मैपिंग कर्नेल फ़ंक्शन या रिडक्शन कर्नेल अक्युमिलेटर फ़ंक्शन, निर्देशांकों को ऐक्सेस कर सकते हैं प्रोग्राम चलाने के लिए, खास आर्ग्युमेंट x का इस्तेमाल करें, y और z, जो int या uint32_t टाइप के होने चाहिए. ये आर्ग्युमेंट ज़रूरी नहीं हैं.

    मैपिंग कर्नेल फ़ंक्शन या रिडक्शन कर्नेल अक्युमिलेटर फ़ंक्शन एक वैकल्पिक विशेष तर्क भी ले सकता है, rs_kernel_context टाइप का context. क्वेरी करने के लिए इस्तेमाल किए जाने वाले रनटाइम एपीआई फ़ैमिली ग्रुप को इसकी ज़रूरत होती है मौजूदा एक्ज़ीक्यूशन की कुछ प्रॉपर्टी -- उदाहरण के लिए, rsGetDimX. (context आर्ग्युमेंट, Android 6.0 (एपीआई लेवल 23) और उसके बाद के वर्शन पर उपलब्ध है.)

  • एक वैकल्पिक init() फ़ंक्शन. init() फ़ंक्शन एक खास तरह का है यह रेंडर करने लायक फ़ंक्शन है, जो स्क्रिप्ट के पहली बार इंस्टैंशिएट होने पर चलता है. इससे कुछ लोगों को कंप्यूटेशन की मदद से, स्क्रिप्ट बनाते समय अपने-आप होती है.
  • शून्य या उससे ज़्यादा स्टैटिक स्क्रिप्ट ग्लोबल और फ़ंक्शन. स्टैटिक स्क्रिप्ट ग्लोबल स्क्रिप्ट ग्लोबल, लेकिन Java कोड से इसे ऐक्सेस नहीं किया जा सकता. स्टैटिक फ़ंक्शन, स्टैंडर्ड C होता है फ़ंक्शन जिसे स्क्रिप्ट में किसी भी कर्नेल या इनवोकेबल फ़ंक्शन से कॉल किया जा सकता है, लेकिन वह दिखाया नहीं जाता को आसान बना रहे हैं. अगर किसी स्क्रिप्ट ग्लोबल या फ़ंक्शन को Java कोड से ऐक्सेस करने की ज़रूरत नहीं है, तो इसे static के तौर पर एलान करने की सलाह दी जाती है.

फ़्लोटिंग पॉइंट को सटीक तरीके से सेट करना

स्क्रिप्ट में फ़्लोटिंग पॉइंट के सटीक होने के लेवल को कंट्रोल किया जा सकता है. यह तब फ़ायदेमंद होता है, जब पूर्ण IEEE 754-2008 मानक (डिफ़ॉल्ट रूप से इस्तेमाल किया गया) की ज़रूरत नहीं है. नीचे दिए गए प्रागमा, फ़्लोटिंग पॉइंट प्रिसिज़न के अलग-अलग लेवल:

  • #pragma rs_fp_full (अगर कुछ न बताया गया हो, तो डिफ़ॉल्ट तौर पर): उन ऐप्लिकेशन के लिए जिनके लिए आईईईई 754-2008 स्टैंडर्ड में बताए गए फ़्लोटिंग पॉइंट के सटीक होने की पुष्टि करता है.
  • #pragma rs_fp_relaxed: ऐसे ऐप्लिकेशन के लिए जिन्हें सख्त आईईईई 754-2008 की ज़रूरत नहीं होती साथ ही, कम सटीक जानकारी को भी बर्दाश्त किया जा सकता है. यह मोड, डेनॉर्म के लिए फ़्लश-टू-ज़ीरो को चालू करता है और शून्य की ओर.
  • #pragma rs_fp_imprecise: ऐसे ऐप्लिकेशन के लिए जिनमें सटीक जानकारी नहीं होती ज़रूरतें. इस मोड से, rs_fp_relaxed में सभी चीज़ों को चालू किया जा सकता है. इसके अलावा, फ़ॉलो किया जा रहा है:
    • जिन संक्रियाओं के नतीजे -0.0 के रूप में मिलते हैं, वे इसके बजाय +0.0 दिखा सकते हैं.
    • INF और NAN पर कार्रवाइयां तय नहीं हैं.

ज़्यादातर ऐप्लिकेशन rs_fp_relaxed का इस्तेमाल बिना किसी खराब असर के कर सकते हैं. यह बहुत कुछ आर्किटेक्चर के लिए फ़ायदेमंद है. इसकी वजह यह है कि अतिरिक्त ऑप्टिमाइज़ेशन, आरामदेह सटीक जानकारी (जैसे, SIMD सीपीयू के निर्देश).

Java से RenderScript एपीआई ऐक्सेस करना

RenderScript का इस्तेमाल करने वाले Android ऐप्लिकेशन को डेवलप करते समय, आप Java से इसके API को इसमें ऐक्सेस कर सकते हैं: दो तरीकों में से कोई एक:

ये रहे कुछ बदलाव:

  • अगर आप Support Library API का इस्तेमाल करते हैं, तो आपके ऐप्लिकेशन का RenderScript वाला हिस्सा यह Android 2.3 (एपीआई लेवल 9) और इसके बाद के वर्शन वाले डिवाइसों के साथ काम करता है, भले ही RenderScript इस्तेमाल करती हैं. इससे आपका ऐप्लिकेशन, नेटिव (android.renderscript) एपीआई.
  • रेंडर की कुछ खास सुविधाएं, सपोर्ट लाइब्रेरी एपीआई के ज़रिए उपलब्ध नहीं हैं.
  • अगर Support Library API का इस्तेमाल किया जाता है, तो आपको APK से ज़्यादा बड़े APKs मिलेंगे. अगर नेटिव (android.renderscript) एपीआई का इस्तेमाल किया जाता है.

RenderScript सपोर्ट लाइब्रेरी एपीआई का इस्तेमाल करना

Support Library RenderScript API का इस्तेमाल करने के लिए, आपको अपने डेवलपमेंट को कॉन्फ़िगर करना होगा को ऐक्सेस करने की क्षमता नहीं होती. Android SDK के इन टूल का इस्तेमाल करने की ज़रूरत है ये एपीआई:

  • Android SDK टूल का वर्शन 22.2 या इसके बाद वाला वर्शन
  • Android SDK बिल्ड-टूल में बदलाव का 18.1.0 या इसके बाद वाला वर्शन

ध्यान दें कि Android SDK बिल्ड-टूल 24.0.0 और Android 2.2 से शुरू करके (एपीआई लेवल 8) अब काम नहीं करता.

इन टूल के इंस्टॉल किए गए वर्शन को यहां देखा जा सकता है और उन्हें अपडेट किया जा सकता है: Android SDK मैनेजर.

सपोर्ट लाइब्रेरी RenderScript API का इस्तेमाल करने के लिए:

  1. पक्का करें कि आपके डिवाइस पर Android SDK का ज़रूरी वर्शन इंस्टॉल किया गया हो.
  2. RenderScript सेटिंग को शामिल करने के लिए Android बिल्ड प्रोसेस की सेटिंग अपडेट करें:
    • build.gradle फ़ाइल को अपने ऐप्लिकेशन मॉड्यूल के ऐप्लिकेशन फ़ोल्डर में खोलें.
    • फ़ाइल में ये RenderScript सेटिंग जोड़ें:

      ग्रूवी

              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
                  }
              }
              

      ऊपर दी गई सेटिंग, Android बिल्ड प्रोसेस के खास व्यवहार को कंट्रोल करती हैं:

      • renderscriptTargetApi - बाइट कोड वर्शन को तय करता है, जनरेट किया गया. हमारा सुझाव है कि आप इस वैल्यू को सबसे कम एपीआई लेवल पर सेट करें. आपके इस्तेमाल किए जा रहे सभी फ़ंक्शन और renderscriptSupportModeEnabled को सेट करें true तक. इस सेटिंग के लिए मान्य वैल्यू, कोई भी पूर्णांक वैल्यू होती है लेवल 11 से लेकर हाल ही में रिलीज़ किए गए एपीआई लेवल तक पहुंच सकता है. अगर आपके एसडीके का कम से कम वर्शन है आपके ऐप्लिकेशन मेनिफ़ेस्ट में दर्ज किसी ऐसे मान पर सेट किया गया है, को अनदेखा कर दिया जाता है और बिल्ड फ़ाइल में मौजूद टारगेट वैल्यू का इस्तेमाल, कम से कम SDK टूल का वर्शन.
      • renderscriptSupportModeEnabled - इससे पता चलता है कि अगर डिवाइस चल रहा है, तो बाइटकोड को उसके साथ काम करने वाले वर्शन पर वापस आना चाहिए चालू, टारगेट वर्शन के साथ काम नहीं करता.
  3. RenderScript का इस्तेमाल करने वाली अपनी ऐप्लिकेशन क्लास में, सहायता लाइब्रेरी के लिए एक इंपोर्ट जोड़ें क्लास:

    Kotlin

    import android.support.v8.renderscript.*
    

    Java

    import android.support.v8.renderscript.*;
    

Java या Kotlin कोड से RenderScript का इस्तेमाल करना

Java या Kotlin कोड से RenderScript का इस्तेमाल करना, android.renderscript या android.support.v8.renderscript पैकेज. ज़्यादातर ऐप्लिकेशन में समान बुनियादी उपयोग पैटर्न का पालन किया जाता है:

  1. RenderScript कॉन्टेक्स्ट शुरू करें. create(Context) के साथ बनाया गया RenderScript संदर्भ यह पक्का करता है कि RenderScript का इस्तेमाल किया जा सकता है और यह ऑब्जेक्ट का इस्तेमाल करके, सभी RenderScript ऑब्जेक्ट के लाइफ़टाइम को कंट्रोल कर सकते हैं. आपको कॉन्टेंट के कॉन्टेक्स्ट के बारे में सोचना चाहिए बनाना लंबे समय तक चलने वाला ऑपरेशन बनाना होगा, क्योंकि इससे अलग-अलग हार्डवेयर के हिस्से; वह किसी ऐप्लिकेशन के क्रिटिकल पाथ में नहीं होना चाहिए, अगर किया जा सकता है. आम तौर पर, किसी ऐप्लिकेशन में एक समय पर सिर्फ़ एक RenderScript संदर्भ होगा.
  2. पास दिए जाने के लिए कम से कम एक Allocation बनाएं स्क्रिप्ट. Allocation एक ऐसा RenderScript ऑब्जेक्ट है जो तय सीमा तक डेटा सेव रखने में मदद करता है. स्क्रिप्ट में कर्नेल Allocation लगते हैं ऑब्जेक्ट को उनके इनपुट और आउटपुट के रूप में रखता है और Allocation ऑब्जेक्ट rsGetElementAt_type() और का इस्तेमाल करके कर्नेल में ऐक्सेस किया गया स्क्रिप्ट ग्लोबल के रूप में सीमित होने पर rsSetElementAt_type(). Allocation ऑब्जेक्ट, अरे को Java कोड से RenderScript में पास करने की अनुमति देता है कोड के साथ कोड में भी नहीं हैं. Allocation ऑब्जेक्ट आम तौर पर इनका इस्तेमाल करके बनाए जाते हैं createTyped() या createFromBitmap().
  3. ज़रूरी स्क्रिप्ट बनाएं. दो तरह की स्क्रिप्ट उपलब्ध हैं तो आपके लिए RenderScript का इस्तेमाल करें:
    • ScriptC: ये उपयोगकर्ता की ओर से तय की गई स्क्रिप्ट हैं, जैसा कि ऊपर RenderScript कर्नेल लिखना में बताया गया है. हर स्क्रिप्ट की एक Java क्लास होती है जावा कोड से स्क्रिप्ट को ऐक्सेस करना आसान बनाने के लिए, RenderScript कंपाइलर से दिखाया जाएगा; इस क्लास का नाम ScriptC_filename है. उदाहरण के लिए, अगर मैपिंग कर्नेल invert.rs में मौजूद हैं और RenderScript कॉन्टेक्स्ट पहले से mRenderScript, स्क्रिप्ट को इंस्टैंशिएट करने के लिए Java या Kotlin कोड इस तरह का होगा:

      Kotlin

      val invert = ScriptC_invert(renderScript)
      

      Java

      ScriptC_invert invert = new ScriptC_invert(renderScript);
      
    • ScriptIntrinsic: ये सामान्य ऑपरेशन के लिए, पहले से मौजूद RenderScript कर्नेल हैं, जैसे, गॉसियन ब्लर, कॉन्वोल्यूशन, और इमेज ब्लेंडिंग. ज़्यादा जानकारी के लिए, इसकी सब-क्लास देखें ScriptIntrinsic.
  4. ऐलोकेशन में डेटा का इस्तेमाल करें. createFromBitmap() की मदद से बनाए गए बजट को छोड़कर, किसी ऐलोकेशन में खाली डेटा अपने-आप भर जाता है. ऐसा तब होता है, जब वह ऐसा होता है सबसे पहले बनाया गया. ऐलोकेशन का डेटा अपने-आप भरने के लिए, किसी "कॉपी" का इस्तेमाल करें Allocation में तरीके. "कॉपी" तरीके सिंक्रोनस होते हैं.
  5. सभी ज़रूरी स्क्रिप्ट ग्लोबल सेट करें. आप set_globalname नाम वाली ScriptC_filename क्लास. इसके लिए उदाहरण के लिए, threshold नाम का int वैरिएबल सेट करने के लिए, Java का तरीका set_threshold(int); और सेट करने के लिए lookup नाम वाला एक rs_allocation वैरिएबल, Java का इस्तेमाल करें set_lookup(Allocation) तरीका. set तरीके एसिंक्रोनस होते हैं.
  6. सही कर्नेल और बोले जा सकने वाले फ़ंक्शन लॉन्च करें.

    दिए गए कर्नेल को लॉन्च करने के तरीके ये हैं समान ScriptC_filename क्लास में, इन तरीकों से दिखा रहा है forEach_mappingKernelName() या reduce_reductionKernelName(). ये लॉन्च एसिंक्रोनस होते हैं. कर्नेल के आर्ग्युमेंट के आधार पर, तरीका एक या ज़्यादा आवंटन लेता है और सभी में एक जैसे डाइमेंशन होने चाहिए. डिफ़ॉल्ट रूप से, कर्नेल उन डाइमेंशन में हर निर्देशांक को एक्ज़ीक्यूट करता है; उन निर्देशांकों के किसी सबसेट पर कर्नेल को चलाने के लिए, forEach या reduce तरीके में आखिरी तर्क के तौर पर किसी सही Script.LaunchOptions को पास करें.

    invoke_functionName तरीकों का इस्तेमाल करके, बोले जा सकने वाले फ़ंक्शन लॉन्च करें उसी ScriptC_filename क्लास में दिखता है. ये लॉन्च एसिंक्रोनस होते हैं.

  7. Allocation ऑब्जेक्ट से डेटा वापस पाएं और javaFutureType ऑब्जेक्ट. कार्रवाई करने के लिए किसी Allocation से Java कोड से डेटा ऐक्सेस करते हैं, तो आपको वह डेटा कॉपी करना होगा में से किसी एक "कॉपी" का इस्तेमाल करके Java पर वापस जाएं Allocation में बताया गया तरीका है. रिडक्शन कर्नेल का नतीजा पाने के लिए, आपको javaFutureType.get() तरीका इस्तेमाल करना होगा. "कॉपी" और get() तरीके सिंक्रोनस होते हैं.
  8. RenderScript के कॉन्टेक्स्ट को मिटाएं. आपके पास 'रेंडरस्क्रिप्ट कॉन्टेक्स्ट' को बंद करने का विकल्प होता है destroy() के साथ या RenderScript कॉन्टेक्स्ट की अनुमति देकर जिसे कचरा इकट्ठा करने के लिए इस्तेमाल किया जाता है. ऐसा करने से, इससे जुड़े किसी भी ऑब्जेक्ट का दोबारा इस्तेमाल किया जा सकता है संदर्भ का इस्तेमाल करें.

एसिंक्रोनस एक्ज़ीक्यूशन मॉडल

यह जानकारी forEach, invoke, reduce, और और set विधियां एसिंक्रोनस हैं -- प्रत्येक कार्रवाई का अनुरोध किया गया. हालांकि, हर कार्रवाई को लॉन्च करने के क्रम में, उसे क्रम से लगाया जाता है.

Allocation क्लास में "कॉपी" सुविधा का इस्तेमाल किया जाता है डेटा को कॉपी करने के तरीके और ऐलोकेशन से. "कॉपी" विधि सिंक्रोनस है और उसे किसी भी हैं जो उसी आवंटन को छूते हैं.

दिखाई गई javaFutureType क्लास से मिलती हैं कमी का नतीजा पाने के लिए, get() तरीका. get() है सिंक्रोनस होता है और उसे रिडक्शन (जो एसिंक्रोनस है) के हिसाब से क्रम में लगाया जाता है.

सिंगल-सोर्स रेंडरस्क्रिप्ट

Android 7.0 (एपीआई लेवल 24) में पेश है सिंगल-सोर्स नाम की नई प्रोग्रामिंग सुविधा RenderScript, जिसमें कर्नेल उन स्क्रिप्ट से लॉन्च किए जाते हैं जहां उन्हें तय किया जाता है. ऐसा न करने पर किया जाता है इंटरनेट से मिलता है. फ़िलहाल यह तरीका, मैप करने वाले कर्नेल तक सीमित है, जिन्हें सिर्फ़ "कर्नेल" कहा जाता है कम शब्दों में समझाने के लिए, इस सेक्शन में देखें. इस नई सुविधा से डेटा टाइप का बंटवारा भी किया जा सकता है rs_allocation स्क्रिप्ट के अंदर से. अब यह काम किया जा सकता है पूरे एल्गोरिदम को एक स्क्रिप्ट में लागू करें, भले ही एक से ज़्यादा कर्नेल लॉन्च की ज़रूरत क्यों न हो. दो फ़ायदे हैं: ज़्यादा पढ़ा जा सकने वाला कोड, क्योंकि इससे एल्गोरिदम के लागू होने को एक भाषा; और संभावित रूप से तेज़ कोड, क्योंकि Java और के बीच कम ट्रांज़िशन की वजह से कई कर्नेल लॉन्च में RenderScript.

सिंगल-सोर्स RenderScript में, आप RenderScript कर्नेल लिखना. इसके बाद, आप एक ऐसा फ़ंक्शन लिखते हैं जिसे रोका नहीं जा सकता. लॉन्च करने के लिए, rsForEach(). इस एपीआई का इस्तेमाल करने के लिए, पहले चरण के तौर पर कर्नेल फ़ंक्शन को पैरामीटर और उसके बाद इनपुट और आउटपुट आवंटन. मिलता-जुलता एपीआई rsForEachWithOptions(), टाइप का एक अतिरिक्त आर्ग्युमेंट लेता है rs_script_call_t, जो इनपुट से एलिमेंट के सबसेट के बारे में बताता है और कर्नेल फ़ंक्शन के लिए आउटपुट एलोकेशन, जिन्हें प्रोसेस करना है.

RenderScript कंप्यूटेशन शुरू करने के लिए, आप Java से Invokable फ़ंक्शन को कॉल करते हैं. Java कोड से RenderScript का इस्तेमाल करना में दिया गया तरीका अपनाएं. सही कर्नेल लॉन्च करें चरण में, कॉल करें invoke_function_name() का इस्तेमाल करके, शुरू किया जा सकने वाला फ़ंक्शन, जो पूरे कंप्यूटेशन का इस्तेमाल करें. इसमें कर्नेल लॉन्च करना भी शामिल है.

सेव करने और पास करने के लिए अक्सर बजटों की ज़रूरत होती है एक कर्नेल के लॉन्च से दूसरे में बीच के नतीजे. इन्हें बनाने के लिए rsCreateAllocation(). इस एपीआई का आसानी से इस्तेमाल किया जा सकने वाला एक फ़ॉर्म rsCreateAllocation_<T><W>(…) है. यहां T, एलिमेंट और W एलिमेंट की वेक्टर चौड़ाई है. एपीआई, Google Cloud में आर्ग्युमेंट के तौर पर डाइमेंशन X, Y, और Z. 1D या 2D आवंटन के लिए, Y या Z डाइमेंशन का साइज़ हटाया जाना चाहिए. उदाहरण के लिए, rsCreateAllocation_uchar4(16384) 16384 एलिमेंट, जिनमें से हर एक uchar4 टाइप का है.

बजट का बंटवारा, सिस्टम अपने-आप करता है. आपने लोगों तक पहुंचाया मुफ़्त में उन्हें साफ़ तौर पर रिलीज़ या खाली करने की ज़रूरत नहीं होती. हालांकि, आपके पास कॉल करने का विकल्प है rsClearObject(rs_allocation* alloc) का इस्तेमाल करके बताएं कि अब आपको हैंडल की ज़रूरत नहीं है मौजूदा ऐलोकेशन के लिए alloc, ताकि सिस्टम को जल्द से जल्द संसाधनों का ऐक्सेस मिल सके.

RenderScript कर्नेल लिखना सेक्शन में एक उदाहरण है कर्नेल के ज़रिए दिखाया जाता है. नीचे दिए गए उदाहरण में, किसी इमेज पर एक से ज़्यादा इफ़ेक्ट लागू करने के बारे में बताया गया है, सिंगल-सोर्स RenderScript का इस्तेमाल करके. इसमें एक और कर्नेल, greyscale शामिल होता है, जो एक ब्लैक ऐंड व्हाइट में रंगीन इमेज. इसके बाद, शुरू किया जा सकने वाला एक फ़ंक्शन process() उन दो कर्नेल को लागू करता है इनपुट इमेज में लगातार जोड़ा जाता है और एक आउटपुट इमेज जनरेट होती है. इनपुट और आउटपुट को टाइप के आर्ग्युमेंट के तौर पर पास किया जाता है rs_allocation.

// 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);
}

Java या Kotlin से process() फ़ंक्शन को इस तरह कॉल किया जा सकता है:

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);

इस उदाहरण में दिखाया गया है कि दो कर्नेल लॉन्च वाले एल्गोरिदम को कैसे पूरी तरह से लागू किया जा सकता है में उपलब्ध है. सिंगल-सोर्स के बिना RenderScript के लिए, आपको कर्नेल लॉन्च को अलग करते हुए Java कोड से दोनों कर्नेल लॉन्च करने होंगे पूरे एल्गोरिदम को समझना मुश्किल होता है. न सिर्फ़ सिंगल-सोर्स रेंडर स्क्रिप्ट कोड को पढ़ना आसान होता है, लेकिन यह ट्रांज़िशन को भी खत्म कर देता है कर्नेल लॉन्च में Java और स्क्रिप्ट के बीच फ़र्क़ करें. कुछ बार-बार होने वाले एल्गोरिदम, कर्नेल लॉन्च कर सकते हैं जिससे इस तरह का बदलाव काफ़ी अहम हो जाता है.

स्क्रिप्ट ग्लोबल

स्क्रिप्ट ग्लोबल, एक ऐसी साधारण भाषा है जो static की नहीं है स्क्रिप्ट (.rs) फ़ाइल में ग्लोबल वैरिएबल. स्क्रिप्ट के लिए ग्लोबल नाम var फ़ाइल filename.rs है, तो तरीका get_var इसमें दिखाया गया है क्लास ScriptC_filename. दुनिया भर में const है, ऐसी स्थिति में भी set_var तरीका.

दी गई स्क्रिप्ट ग्लोबल में दो अलग-अलग वैल्यू होती हैं -- Java और एक script वैल्यू भी सेट करें. ये वैल्यू इस तरह से काम करती हैं:

  • अगर var के पास स्क्रिप्ट में स्टैटिक शुरू करने वाला टूल है, तो Java और दोनों में var का शुरुआती मान तय करता है स्क्रिप्ट. नहीं तो, वह शुरुआती वैल्यू शून्य होती है.
  • स्क्रिप्ट में var का ऐक्सेस, उसे पढ़ और लिखता है स्क्रिप्ट मान.
  • get_var तरीका, Java को पढ़ता है वैल्यू.
  • set_var तरीका (अगर यह मौजूद है) यह बताता है कि Java वैल्यू तुरंत सेट करता है और स्क्रिप्ट वैल्यू को लिखता है एसिंक्रोनस तरीके से.

ध्यान दें: इसका मतलब है कि अगर किसी स्क्रिप्ट में स्थैतिक प्रारंभकर्ता, जो Java को नहीं दिखती.

डेप्थ में रिडक्शन कर्नेल

कम करना, डेटा के कलेक्शन को एक साथ जोड़ने की प्रोसेस है वैल्यू. यह समानांतर प्रोग्रामिंग में एक उपयोगी सिद्धांत है, जिसमें फ़ॉलो किया जा रहा है:

  • सारे डेटा पर योग या गुणनफल की गणना करना
  • कंप्यूटिंग लॉजिकल ऑपरेशन (and, or, xor) पूरे डेटा पर
  • आंकड़ों में सबसे छोटी या सबसे बड़ी वैल्यू पता करना
  • डेटा में किसी खास वैल्यू या किसी खास वैल्यू के कोऑर्डिनेट को खोजना

Android 7.0 (एपीआई लेवल 24) और उसके बाद के वर्शन में, RenderScript कम करने वाले कर्नेल के साथ काम करता है. इससे, के सुझाव देते हैं. इनपुट पर रिडक्शन कर्नेल लॉन्च करने के लिए, इनका इस्तेमाल किया जा सकता है: 1, 2 या 3 डाइमेंशन.

ऊपर दिए गए उदाहरण में, एक सामान्य addint रिडक्शन कर्नेल दिखाया गया है. यहां findMinAndMax का ज़्यादा जटिल रिडक्शन कर्नेल दिया गया है जो टेबल में सबसे कम और ज़्यादा से ज़्यादा long वैल्यू की जगह 1-डाइमेंशन 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;
}

ध्यान दें: कम करने के कुछ और उदाहरण दिए गए हैं कर्नेल यहां देखें.

रिडक्शन कर्नेल को चलाने के लिए, RenderScript रनटाइम एक या उससे ज़्यादा बनाता है अक्यूम्युलेटर डेटा नाम के वैरिएबल आइटम का इस्तेमाल करें. RenderScript रनटाइम परफ़ॉर्मेंस को बेहतर बनाने के लिए, इस तरह से क्वेरी के डेटा आइटम की संख्या चुनता है. टाइप कैश मेमोरी में सेव किए गए डेटा आइटम (acumType) को कर्नेल के अक्यूम्युलेटर की मदद से तय किया जाता है फ़ंक्शन -- उस फ़ंक्शन का पहला आर्ग्युमेंट किसी क्रेडिटर डेटा का पॉइंटर होता है आइटम. डिफ़ॉल्ट रूप से, हर कंपनी डेटा आइटम की शुरुआत शून्य से होती है (जैसे, memset तक; हालांकि, कुछ करने के लिए, इनीशियलाइज़र फ़ंक्शन लिखा जा सकता है अलग हैं.

उदाहरण: addint में कर्नेल, अक्यूम्युलेटर डेटा आइटम (int टाइप के) का इस्तेमाल इनपुट को जोड़ने के लिए किया जाता है वैल्यू. कोई इनीशियलाइज़र फ़ंक्शन नहीं होता है, इसलिए हर अक्युमिलेटर डेटा आइटम को शुरू किया जाता है शून्य.

उदाहरण: इसमें findMinAndMax कर्नेल, एक्यूमिलेटर डेटा आइटम (MinAndMax प्रकार के) का इस्तेमाल कम से कम और ज़्यादा से ज़्यादा वैल्यू को ट्रैक करने के लिए किया जाता है मिला है. इन्हें LONG_MAX और पर सेट करने के लिए एक शुरुआती फ़ंक्शन मौजूद है LONG_MIN, क्रमश: और इन वैल्यू की जगह को -1 पर सेट करते हैं, जो यह बताते हैं कि इनपुट के (खाली) हिस्से में असल में वैल्यू मौजूद नहीं हैं प्रोसेस किया गया.

Renderस्क्रिप्ट आपके अक्युमिलेटर फ़ंक्शन को एक बार, इनपुट. आम तौर पर, आपके फ़ंक्शन को किसी न किसी तरह से अक्युमिलेटर डेटा आइटम अपडेट करना चाहिए .

उदाहरण: addint में कर्नेल, अक्यूम्युलेटर फ़ंक्शन किसी इनपुट एलिमेंट की वैल्यू को अक्यूम्युलेटर में जोड़ता है डेटा आइटम.

उदाहरण: इसमें findMinAndMax कर्नेल, एक्यूमिलेटर फ़ंक्शन यह देखने के लिए जांच करता है कि इनपुट एलिमेंट का मान कम से कम वैल्यू से कम या उसके बराबर है या नहीं क्यूमिलेटर डेटा आइटम में रिकॉर्ड की गई वैल्यू और/या तय की गई ज़्यादा से ज़्यादा वैल्यू से ज़्यादा या उसके बराबर यह, क्यूमुलेटर डेटा आइटम में रिकॉर्ड की गई वैल्यू को अपडेट करता है. साथ ही, यह अक्युमिलेटर डेटा आइटम को अपडेट करता है उसी के हिसाब से.

इनपुट में हर कोऑर्डिनेट के लिए, एक बार अक्यूम्युलेटर फ़ंक्शन को कॉल करने के बाद, RenderScript को को अक्युलेटर को जोड़ना चाहिए डेटा आइटम को एक साथ एक संचय डेटा आइटम में बदल देता है. आप चाहें तो एक कॉम्बिनर, लिख सकते हैं फ़ंक्शन का इस्तेमाल करें. अगर अक्यूम्युलेटर फ़ंक्शन में एक इनपुट और कोई खास आर्ग्युमेंट नहीं होता है, तो आपको कंबाइनर लिखने की ज़रूरत नहीं होती है फ़ंक्शन; Renderस्क्रिप्ट, अक्युमिलेटर डेटा को इकट्ठा करने के लिए अक्यूम्युलेटर फ़ंक्शन का इस्तेमाल करेगा आइटम. (अगर यह डिफ़ॉल्ट तरीका वह नहीं है जो आप चाहते हैं.)

उदाहरण: addint में कर्नेल के लिए, कोई कंबाइनर फ़ंक्शन नहीं है, इसलिए अक्यूम्युलेटर फ़ंक्शन का इस्तेमाल किया जाएगा. यह है सही व्यवहार नहीं होगा, क्योंकि अगर हम वैल्यू के कलेक्शन को दो हिस्सों में बांटते हैं, और उन दो भागों में अलग-अलग मानों को जोड़ें, उन दोनों योगों को जोड़ना समान है पूरे संग्रह को जोड़कर.

उदाहरण: इसमें findMinAndMax कर्नेल, कंबाइनर फ़ंक्शन यह देखने के लिए जांच करता है कि "स्रोत" में रिकॉर्ड किया गया कम से कम मान अक्यूम्युलेटर डेटा आइटम *val, "डेस्टिनेशन" में रिकॉर्ड किए गए कम से कम मान से कम है अक्यूम्युलेटर डेटा आइटम *accum और अपडेट *accum उसी के हिसाब से. यह सबसे बड़ी वैल्यू के लिए भी इसी तरह काम करता है. यह *accum को अपडेट करेगा इस स्थिति तक पहुंच सकता है कि अगर सभी इनपुट वैल्यू इकट्ठा की जातीं, तो *accum के बजाय कुछ *accum में और कुछ को *val.

सभी संचयकर्ता डेटा आइटम के मिल जाने के बाद, RenderScript यह तय करता है कि जावा पर वापस लौटने में कमी का परिणाम. आप एक आउटकन्वर्ज़नर लिख सकते हैं फ़ंक्शन का इस्तेमाल करें. अगर आप चाहें, तो आपको आउटकन्वर्टर फ़ंक्शन लिखने की ज़रूरत नहीं है रिडक्शन के नतीजे के तौर पर मिले-जुले अक्युमिलेटर डेटा आइटम की फ़ाइनल वैल्यू.

उदाहरण: addint कर्नेल में, कोई आउटकन्वर्टर फ़ंक्शन नहीं होता. संयुक्त डेटा आइटम का अंतिम मान कुल योग होता है इनपुट के सभी एलिमेंट, जो वह मान है जिसे हम लौटाना चाहते हैं.

उदाहरण: इसमें findMinAndMax कर्नेल, आउट-कन्वर्टर फ़ंक्शन कम से कम स्थानों को होल्ड करने के लिए int2 परिणाम मान को शुरू करता है और यह ज़्यादा से ज़्यादा वैल्यू को क्रेडिट देने वाले सभी डेटा आइटम के कॉम्बिनेशन से मिलता है.

रिडक्शन कर्नेल लिखना

#pragma rs reduce, रिडक्शन कर्नेल को इसके हिसाब से तय करता है इसके नाम के साथ-साथ, उन फ़ंक्शन के नाम और भूमिकाएं भी तय करते हुए कर्नेल को ऊपर ले जाएं. ऐसे सभी फ़ंक्शन static. रिडक्शन कर्नेल के लिए, हमेशा accumulator की ज़रूरत होती है फ़ंक्शन; इस बात पर निर्भर करते हुए कि कुछ या सभी फ़ंक्शन को छोड़ा जा सकता है, करने के लिए कर्नेल.

#pragma rs reduce(kernelName) \
  initializer(initializerName) \
  accumulator(accumulatorName) \
  combiner(combinerName) \
  outconverter(outconverterName)

#pragma में दिए गए आइटम का मतलब यह है:

  • reduce(kernelName) (ज़रूरी): इससे पता चलता है कि रिडक्शन कर्नेल परिभाषित किया जा रहा है. लागू किए गए Java तरीके reduce_kernelName से, कर्नेल.
  • initializer(initializerName) (ज़रूरी नहीं): यह बताता है कि इस रिडक्शन कर्नेल के लिए, इनीशियलाइज़र फ़ंक्शन का इस्तेमाल करें. जब आप कर्नेल को लॉन्च करते हैं, तो RenderScript कॉल इस फ़ंक्शन को हर अक्यूम्युलेटर डेटा आइटम के लिए एक बार सबमिट किया जाएगा. कॉन्टेंट बनाने फ़ंक्शन को इस तरह से परिभाषित करें:

    static void initializerName(accumType *accum) { … }

    accum इस फ़ंक्शन के लिए, अक्युमिलेटर डेटा आइटम का पॉइंटर है शुरू करें.

    अगर आपने इनिशलाइज़र फ़ंक्शन नहीं दिया है, तो RenderScript हर कैंपेन को शुरू करता है डेटा आइटम की वैल्यू शून्य पर सेट हो जाती है (जैसे कि memset तक), यह मानते हुए कि शुरू करने के लिए कोई वैल्यू दी गई थी फ़ंक्शन मौजूद है, जो इस तरह दिखता है:

    static void initializerName(accumType *accum) {
      memset(accum, 0, sizeof(*accum));
    }
  • accumulator(accumulatorName) अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है (ज़रूरी): इसके लिए अक्यूम्युलेटर फ़ंक्शन का नाम बताता है रिडक्शन कर्नेल. जब आप कर्नेल को लॉन्च करते हैं, तो RenderScript कॉल इस फ़ंक्शन को इनपुट में हर निर्देशांक के लिए एक बार, किसी न किसी तरीके से, इनपुट के हिसाब से डेटा आइटम को इकट्ठा करता है. फ़ंक्शन इस तरह परिभाषित होना चाहिए:

    static void accumulatorName(accumType *accum,
                                in1Type in1, …, inNType inN
                                [, specialArguments]) { … }
    

    accum इस फ़ंक्शन के लिए, अक्युमिलेटर डेटा आइटम का पॉइंटर है बदलें. in1 से inN तक, एक या ज़्यादा तर्क हैं जो कर्नेल लॉन्च में पास किए गए इनपुट के आधार पर अपने-आप भर दिए जाते हैं, एक आर्ग्युमेंट हर इनपुट के लिए. अक्यूम्युलेटर फ़ंक्शन इनमें से कोई भी खास आर्ग्युमेंट ले सकता है.

    कई इनपुट वाले कर्नेल का एक उदाहरण dotProduct है.

  • combiner(combinerName)

    (ज़रूरी नहीं): इसके लिए कंबाइनर फ़ंक्शन का नाम बताता है रिडक्शन कर्नेल. रेंडर करने से पहले, अक्यूम्युलेटर फ़ंक्शन को कॉल करने के बाद इनपुट में हर निर्देशांक के लिए एक बार, यह फ़ंक्शन को कई सभी मेमोरी आइटम को एक साथ जोड़ने के लिए, ज़रूरत के हिसाब से समय कैश मेमोरी में सेव किया गया डेटा आइटम. फ़ंक्शन इस तरह से तय होना चाहिए:

    static void combinerName(accumType *accum, const accumType *other) { … }

    accum, "डेस्टिनेशन" का पॉइंटर है इसके लिए अक्युमिलेटर डेटा आइटम फ़ंक्शन का इस्तेमाल करें. other, "सोर्स" की ओर पॉइंटर है अक्यूम्युलेटर डेटा आइटम ताकि इस फ़ंक्शन को "संयुक्त रूप से" *accum में.

    ध्यान दें: ऐसा किया जा सकता है *accum, *other या दोनों को शुरू किया जा चुका है, लेकिन कभी शुरू नहीं किया गया कोअक्यूम्युलेटर फ़ंक्शन में पास किया गया है; इसका मतलब है कि एक या दोनों को कभी अपडेट नहीं किया गया है . उदाहरण के लिए, findMinAndMax कर्नेल, कंबाइनर फ़ंक्शन fMMCombiner idx < 0 की जांच करता है, क्योंकि यह ऐसे एक्यूमिलेटर डेटा आइटम को दिखाता है जिसकी वैल्यू INITVAL होती है.

    अगर कंबाइनर फ़ंक्शन उपलब्ध नहीं कराया जाता है, तो RenderScript इस जगह सेट करते समय, यह देखते हुए कि कंबाइनर फ़ंक्शन मौजूद है जो इस तरह दिखता है:

    static void combinerName(accumType *accum, const accumType *other) {
      accumulatorName(accum, *other);
    }

    अगर कर्नेल में एक से ज़्यादा इनपुट हैं, तो इनपुट डेटा के लिए कंबाइनर फ़ंक्शन ज़रूरी है टाइप, अक्युमिलेटर डेटा टाइप से अलग है या अगर अक्यूम्युलेटर फ़ंक्शन किसी एक तरह का काम करता है या ज़्यादा खास तर्क शामिल करें.

  • outconverter(outconverterName) अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है (ज़रूरी नहीं): इसके लिए आउटकन्वर्टर फ़ंक्शन का नाम बताता है रिडक्शन कर्नेल. RenderScript के बाद सभी अक्यूमुलेटर को जोड़ता है डेटा आइटम है, तो यह इस फ़ंक्शन को कम करने के विकल्प का इस्तेमाल करें. फ़ंक्शन इस तरह से तय होना चाहिए शामिल करें:

    static void outconverterName(resultType *result, const accumType *accum) { … }

    result, नतीजे में मिलने वाले डेटा आइटम का पॉइंटर है (तय किया गया है, लेकिन शुरू नहीं किया गया है) के परिणाम के साथ इस फ़ंक्शन को शुरू करने के लिए कमी. resultType उस डेटा आइटम का प्रकार है, जो एक जैसा नहीं होना चाहिए को ac आपकाType के तौर पर इस्तेमाल किया जाना चाहिए. accum, फ़ाइनल अक्युमिलेटर डेटा आइटम का पॉइंटर है इसकी गिनती कॉम्बिनर फ़ंक्शन से की जाती है.

    अगर कोई आउट-कन्वर्ज़नर फ़ंक्शन उपलब्ध नहीं कराया जाता है, तो RenderScript फ़ाइनल अक्यूम्युलेटर को कॉपी करता है डेटा आइटम को परिणाम डेटा आइटम से जोड़ते हुए, यह मानते हुए कि कोई बाहरी रूपांतरणकर्ता फ़ंक्शन था ऐसा दिखता है:

    static void outconverterName(accumType *result, const accumType *accum) {
      *result = *accum;
    }

    अगर आपको इंक्यूलेटर के डेटा टाइप से अलग तरह का नतीजा चाहिए, तो आउटकन्वर्टर फ़ंक्शन ज़रूरी है.

ध्यान दें कि कर्नेल में कई इनपुट टाइप, एक अक्युमिलेटर डेटा आइटम टाइप, और एक नतीजा टाइप है, जिनमें से किसी को भी एक जैसा नहीं होना चाहिए. उदाहरण के लिए, findMinAndMax कर्नेल, इनपुट long टाइप, अक्यूम्युलेटर डेटा आइटम का टाइप MinAndMax, और नतीजा टाइप int2 सभी अलग हैं.

आपको क्या नहीं लगता?

आपको किसी भी दिया गया कर्नेल लॉन्च. इस बात की कोई गारंटी नहीं है कि एक या एक से ज़्यादा इनपुट से, इतने ही अक्युमिलेटर डेटा आइटम बनेंगे.

आपको उस क्रम पर भरोसा नहीं करना चाहिए जिसमें RenderScript, शुरू करने वाले को कॉल करता है, और कंबाइनर फ़ंक्शन; साथ ही, इनमें से कुछ के नाम भी रखे जा सकते हैं. इस बात की कोई गारंटी नहीं है कि एक ही इनपुट वाले एक कर्नेल के दो लॉन्च एक ही क्रम में होंगे. सिर्फ़ गारंटी है कि सिर्फ़ इनिशलाइज़र फ़ंक्शन में, शुरू नहीं किया गया अक्युमिलेटर कभी भी दिखेगा डेटा आइटम. उदाहरण के लिए:

  • इस बात की कोई गारंटी नहीं है कि सभी संग्रहकर्ता डेटा आइटम को अक्यूम्युलेटर फ़ंक्शन को कॉल किया जाता है, हालांकि इसे सिर्फ़ शुरू किए गए अक्युमिलेटर पर ही कॉल किया जाएगा डेटा आइटम.
  • इस बात की कोई गारंटी नहीं है कि इनपुट एलिमेंट, अक्यूमिलेटर में किस क्रम में पास किए जाएंगे फ़ंक्शन का इस्तेमाल करना होगा.
  • इस बात की कोई गारंटी नहीं है कि अक्यूम्युलेटर फ़ंक्शन को सभी इनपुट एलिमेंट के लिए कॉल किया गया है कंबाइनर फ़ंक्शन को कॉल करने से पहले.

इसका एक नतीजा यह होता है कि findMinAndMax कर्नेल डेटरमिनिस्टिक नहीं है: अगर इनपुट में एक ही बार में एक से ज़्यादा बार आए हैं कम से कम या ज़्यादा से ज़्यादा मान सेट करते हैं, तो आपको यह जानने का कोई तरीका नहीं है कि कर्नेल के ज़रिए कौनसी गतिविधि ढूंढें.

आपको किस चीज़ की गारंटी देनी होगी?

क्योंकि RenderScript सिस्टम कई अलग-अलग तरीकों से, आपको कुछ नियमों का पालन करना होगा, ताकि यह पक्का किया जा सके कि आपका कर्नेल आपके मनमुताबिक. इन नियमों का पालन न करने पर, हो सकता है कि आपको गलत नतीजे दिखें, रनटाइम से जुड़ी गड़बड़ियों के बारे में बताना चाहिए.

नीचे दिए गए नियमों में अक्सर यह कहा गया है कि दो संचय डेटा आइटम में " एक ही मान" के साथ दिखाया जाता है. इसका क्या अर्थ है? यह इस बात पर निर्भर करता है कि आप कर्नेल से क्या करवाना चाहते हैं. इसके लिए जैसे गणितीय छोटा करके addint लिखना, आम तौर पर सही होता है "एक जैसे" के लिए का मतलब गणितीय समानता से है. "कोई भी चुनें" के लिए ऐसे खोजो जैसे findMinAndMax ("न्यूनतम और इनपुट की ज़्यादा से ज़्यादा वैल्यू"), जहां एक जैसे इनपुट को एक से ज़्यादा बार शामिल किया जा सकता है वैल्यू, किसी दी गई इनपुट वैल्यू की सभी जगहों को "एक जैसा" माना जाना चाहिए. आप लिख सकते हैं "सबसे बाईं और सबसे ज़्यादा इनपुट वैल्यू की जगह का पता लगाने" के लिए मिलता-जुलता कर्नेल जहां (जैसे) स्थान पर एक समान कम से कम मान की तुलना में स्थान 100 पर एक कम से कम मान को प्राथमिकता दी जाती है 200; इस कर्नेल के लिए, "वही" का मतलब एक समान जगह की जानकारी होगी, न कि सिर्फ़ एक जैसी value है और अक्यूम्युलेटर और कंबाइनर फ़ंक्शन ऐसे होने चाहिए यह findMinAndMax से अलग है.

इनीशियलाइज़र फ़ंक्शन को एक आइडेंटिटी वैल्यू बनानी चाहिए. इसका मतलब है कि अगर I और A, अक्युमिलेटर डेटा आइटम शुरू किए गए हैं शुरू करने वाले फ़ंक्शन से होता है और I को कभी भी अक्यूमुलेटर फ़ंक्शन (लेकिन A हो सकता है), फिर
  • combinerName(&A, &I) को यह करना चाहिए A को अभी जैसा रहने दें
  • combinerName(&I, &A) को यह करना चाहिए I को A की तरह अभी रहने दें

उदाहरण: addint में कर्नेल के तौर पर, एक अक्युमिलेटर डेटा आइटम शून्य पर शुरू किया जाता है. इसके लिए कंबाइनर फ़ंक्शन कर्नेल जोड़ करता है; जोड़ने के लिए आइडेंटिटी वैल्यू, शून्य है.

उदाहरण के लिए: findMinAndMax में कर्नेल, एक अक्युमिलेटर डेटा आइटम शुरू किया गया है INITVAL तक.

  • fMMCombiner(&A, &I), A को छोड़ देता है, क्योंकि I INITVAL है.
  • fMMCombiner(&I, &A) सेट I A को, क्योंकि I INITVAL है.

इसलिए, INITVAL वाकई एक आइडेंटिटी वैल्यू है.

कंब्यूटर फ़ंक्शन कम्यूटेटिव होना चाहिए. इसका मतलब है कि अगर A और B, अक्युमिलेटर डेटा आइटम शुरू किए गए हैं शुरुआती फ़ंक्शन से पास किया जा सकता है और हो सकता है कि इसे अक्यूम्युलेटर फ़ंक्शन शून्य पर भेजा गया हो या ज़्यादा बार, तो combinerName(&A, &B) को A को उसी मान पर सेट करें वह combinerName(&B, &A) B को सेट करता है.

उदाहरण: addint में कर्नेल, कंबाइनर फ़ंक्शन, दो अक्युमिलेटर डेटा आइटम वैल्यू जोड़ता है; इसके अलावा कम्यूटेटिव.

उदाहरण: findMinAndMax कर्नेल में, fMMCombiner(&A, &B) और A = minmax(A, B) और minmax क्रमिक रूप से इस्तेमाल होते हैं, इसलिए fMMCombiner भी ऐसा ही है.

कॉम्बिनर फ़ंक्शन असोसिएशन होना चाहिए. इसका मतलब है कि अगर A, B, और C इनीशियलाइज़र फ़ंक्शन से शुरू किए गए अक्यूम्युलेटर डेटा आइटम और जिन्हें पास किया जा सकता है फिर, नीचे दिए गए दो कोड क्रमों को, इन दो कोड क्रमों को A को उसी मान पर सेट करें:

  • combinerName(&A, &B);
    combinerName(&A, &C);
    
  • combinerName(&B, &C);
    combinerName(&A, &B);
    

उदाहरण: addint कर्नेल में, कंबाइनर फ़ंक्शन, दो अक्युमिलेटर डेटा आइटम की वैल्यू जोड़ता है:

  • 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
    

जोड़ साम्यिक होता है और इसलिए कंबाइनर फ़ंक्शन भी होता है.

उदाहरण: findMinAndMax कर्नेल में,

fMMCombiner(&A, &B)
इसके समान है
A = minmax(A, B)
इसलिए, इन दोनों क्रमों को

  • 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 असोसिएटिव है और fMMCombiner भी जुड़ा है.

अक्यूम्युलेटर फ़ंक्शन और कंबाइनर फ़ंक्शन को एक साथ बेसिक नियमों का पालन करना चाहिए फ़ोल्ड करने का नियम. इसका मतलब है कि अगर A और B, इनऐक्टिव डेटा आइटम हैं, A इनिशलाइज़र फ़ंक्शन से शुरू किया गया और हो सकता है कि इसे अक्यूम्युलेटर फ़ंक्शन में पास किया गया हो शून्य या उससे ज़्यादा बार, B को शुरू नहीं किया गया है और आर्ग अक्यूम्युलेटर को किए गए किसी खास कॉल के लिए, इनपुट आर्ग्युमेंट और खास आर्ग्युमेंट की सूची फ़ंक्शन है, तो नीचे दिए गए दो कोड क्रमों को A सेट करना होगा उसी वैल्यू पर करें:

  • accumulatorName(&A, args);  // statement 1
    
  • initializerName(&B);        // statement 2
    accumulatorName(&B, args);  // statement 3
    combinerName(&A, &B);       // statement 4
    

उदाहरण: addint कर्नेल में, किसी इनपुट वैल्यू V के लिए:

  • स्टेटमेंट 1 और A += V एक जैसे हैं
  • स्टेटमेंट 2 और B = 0 एक जैसे हैं
  • स्टेटमेंट 3, B += V के जैसा है, जो B = V जैसा ही है
  • स्टेटमेंट 4, A += B के जैसा है, जो A += V जैसा ही है

कथन 1 और 4 A को समान मान पर सेट करते हैं, और इसलिए यह कर्नेल फ़ोल्डिंग का बेसिक नियम.

उदाहरण: किसी इनपुट के लिए, findMinAndMax कर्नेल में X कोऑर्डिनेट पर वैल्यू V:

  • स्टेटमेंट 1 और A = minmax(A, IndexedVal(V, X)) एक जैसे हैं
  • स्टेटमेंट 2 और B = INITVAL एक जैसे हैं
  • स्टेटमेंट 3 इसके जैसा है
    B = minmax(B, IndexedVal(V, X))
    
    अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है क्योंकि B शुरुआती वैल्यू है. इसलिए, यह इसके बराबर है
    B = IndexedVal(V, X)
    
  • स्टेटमेंट 4 इसके जैसा है
    A = minmax(A, B)
    
    अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है जो इसके समान है
    A = minmax(A, IndexedVal(V, X))
    

कथन 1 और 4 A को समान मान पर सेट करते हैं, और इसलिए यह कर्नेल फ़ोल्डिंग का बेसिक नियम.

Java कोड से रिडक्शन कर्नेल को कॉल करना

kernelName नाम के रिडक्शन कर्नेल के लिए, जिसे फ़ाइल filename.rs है, तो दस्तावेज़ में तीन विधियां क्लास ScriptC_filename:

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);

यहां addint कर्नेल को कॉल करने के कुछ उदाहरण दिए गए हैं:

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();

पहले तरीके में एक इनपुट Allocation आर्ग्युमेंट है कर्नेल के अक्यूम्युलेटर में हर इनपुट आर्ग्युमेंट के लिए फ़ंक्शन के तौर पर दिखता है. RenderScript रनटाइम जांच करके यह पक्का करता है कि सभी इनपुट ऐलोकेशन के डाइमेंशन एक जैसे हैं. साथ ही, इनमें से हर एक का Element टाइप इनपुट ऐलोकेशन, अक्यूम्युलेटर के इनपुट आर्ग्युमेंट से मेल खाता है फ़ंक्शन का प्रोटोटाइप. अगर इनमें से कोई भी जांच पूरी नहीं हो पाती है, तो रेंडर स्क्रिप्ट में एक अपवाद होता है. कॉन्टेंट बनाने कर्नेल उन डाइमेंशन में हर निर्देशांक पर काम करता है.

दूसरा तरीका और पहला तरीका, दोनों एक ही हैं. हालांकि, दूसरे तरीके और तर्क sc, जिसका इस्तेमाल कर्नेल निष्पादन को निर्देशांक.

तीसरा तरीका और पहला तरीका, दोनों एक ही हैं. हालांकि, आवंटन इनपुट के बजाय, इसे Java अरे इनपुट की ज़रूरत होती है. यह एक सुविधा है, इससे आपको साफ़ तौर पर, आवंटन बनाने और डेटा को कॉपी करने के लिए, कोड लिखने की ज़रूरत नहीं पड़ती. किसी Java कलेक्शन से निकाला जा सकता है. हालांकि, 1 के बजाय 3 तरीके का इस्तेमाल करने से कोड की परफ़ॉर्मेंस के बारे में ज़्यादा जानें. हर इनपुट अरे के लिए, तीसरा तरीका कुछ समय के लिए सही Element टाइप के साथ 1-डाइमेंशन वाला ऐलोकेशन और setAutoPadding(boolean) चालू हो जाता है और अरे को असाइन करें, जैसे कि Allocation के copyFrom() तरीके से. इसके बाद, यह मेथड 1 को कॉल करता है और कुछ समय के लिए आवंटन.

नोट: अगर आपका ऐप्लिकेशन एक जैसी अरे या एक ही डाइमेंशन और एलिमेंट टाइप के अलग-अलग अरे के साथ, आपको बेहतर बनाने की सुविधा मिलती है विज्ञापनों की परफ़ॉर्मेंस तय करने के लिए, ऐसा करने के लिए, आपने तीसरे तरीके का इस्तेमाल किया है.

javaFutureType, परावर्तित कमी विधियों का रिटर्न प्रकार, ScriptC_filename में स्टैटिक नेस्ट की गई क्लास क्लास. यह कमी से आने वाले समय के नतीजे दिखाता है कर्नेल रन. दौड़ने का वास्तविक परिणाम प्राप्त करने के लिए, कॉल करें उस क्लास की get() तरीका, जो कोई वैल्यू दिखाता है का टाइप javaresultsType है. get() सिंक्रोनस है.

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() { … }
  }
}

javaresultsType का पता लगाने के लिए, इस पैरामीटर के resultType का इस्तेमाल किया जाता है आउट कन्वर्टर फ़ंक्शन. जब तक कि resultType एक साइन नहीं किया गया टाइप (स्केलर, वेक्टर या अरे), javaनतीजेType सीधे तौर पर संबंधित हैं Java का टाइप. अगर resultType एक साइन नहीं किया गया प्रकार है और उसका बड़ा Java साइन किया गया टाइप है, तो javaresultType है कि बड़ा Java साइन किया गया टाइप; नहीं तो, यह सीधे संबंधित Java टाइप. उदाहरण के लिए:

  • अगर resultType int, int2 या int[15] है, तो इसके बाद, javaनतीजेType int, Int2, हैं. या int[]. resultType के सभी मान दिखाए जा सकते हैं JavaScript के नतीजे टाइप के हिसाब से.
  • अगर resultType uint, uint2 या uint[15] है, तो इसके बाद, javaनतीजेType long, Long2, हैं. या long[]. resultType के सभी मान दिखाए जा सकते हैं JavaScript के नतीजे टाइप के हिसाब से.
  • अगर resultType ulong, ulong2 है, तो या ulong[15], फिर javaresultsType long, Long2 या long[] है. यहां कुछ वैल्यू दी गई हैं resultType का है जिसे javaresultsType के ज़रिए नहीं दिखाया जा सकता.

javaFutureType, आगे मिलने वाले नतीजों के टाइप से जुड़ा है outconversioner के resultType में फ़ंक्शन का इस्तेमाल करना चाहिए.

  • अगर resultType कोई सरणी प्रकार नहीं है, तो javaFutureType result_resultType है.
  • अगर resultType प्रकार memberType के सदस्यों के साथ लंबाई Count की श्रेणी है, तो javaFutureType resultArrayCount_memberType है.

उदाहरण के लिए:

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() { … }
  }
}

अगर javaresultsType एक ऑब्जेक्ट टाइप है (इसमें अरे टाइप भी शामिल है), तो हर कॉल चुने गए इंस्टेंस पर javaFutureType.get() को सेट करने पर, नतीजे के तौर पर वही दिखेगा ऑब्जेक्ट है.

अगर javaresultType को resultType प्रकार के सभी मान नहीं दिखा सकता है और रिडक्शन कर्नेल से, एक ऐसी वैल्यू जनरेट होती है जिसे दिखाया नहीं जा सकता. फिर javaFutureType.get() एक अपवाद दिखाता है.

तीसरा तरीका और devecSiInXType

devecSiInXType, Java का वह टाइप है जो संबंधित आर्ग्युमेंट का inXType अक्यूम्युलेटर फ़ंक्शन का इस्तेमाल करना चाहिए. जब तक कि inXType साइन नहीं किया गया टाइप या वेक्टर टाइप, devecSiInXType सीधे तौर पर संबंधित Java है टाइप करें. अगर inXType एक साइन नहीं किया गया स्केलर टाइप है, तो devecSiInXType इसी तरह के साइन किए गए स्केलर टाइप से सीधे तौर पर जुड़ा Java टाइप साइज़. अगर inXType एक साइन किया गया वेक्टर टाइप है, तो devecSiInXType Java है वेक्टर कॉम्पोनेंट टाइप के हिसाब से सीधे तौर पर टाइप करना होता है. अगर inXType को साइन नहीं किया गया है, तो वेक्टर टाइप, तो devecSiInXType वह Java टाइप है जो सीधे तौर पर साइन किए गए स्केलर टाइप का साइज़, वेक्टर कॉम्पोनेंट टाइप के साइज़ के बराबर होता है. उदाहरण के लिए:

  • अगर inXType को int पर सेट किया गया है, तो devecSiInXType int है.
  • अगर inXType को int2 पर सेट किया गया है, तो devecSiInXType int है. यह अरे फ़्लैट किया गया रिप्रज़ेंटेशन है: इसमें आवंटन के रूप में, कई स्केलर एलिमेंट में दो कॉम्पोनेंट वेक्टर होते हैं एलिमेंट. यह Allocation के copyFrom() वाले तरीके की तरह ही काम करता है.
  • अगर inXType को uint है, तो deviceSiInXType int है. Java श्रेणी में, हस्ताक्षर किए गए मान को आवंटन में एक जैसा बिटपैटर्न. यह copyFrom() की तरह ही होता है Allocation काम करता है.
  • अगर inXType को uint2 है, तो deviceSiInXType int है. यह int2 और uint का मिला-जुला रूप है हैंडल किए जाते हैं: अरे एक फ़्लैट रेप्रज़ेंटेशन है और Java अरे की हस्ताक्षर की हुई वैल्यू हैं रेंडर स्क्रिप्ट के बिना हस्ताक्षर वाले एलिमेंट वैल्यू के तौर पर समझा जाता है.

ध्यान दें कि तीसरे तरीके में, इनपुट के टाइप को अलग तरीके से हैंडल किया जाता है से ज़्यादा नतीजे टाइप:

  • स्क्रिप्ट का वेक्टर इनपुट Java की ओर से फ़्लैट होता है, जबकि स्क्रिप्ट का वेक्टर परिणाम ऐसा नहीं होता.
  • स्क्रिप्ट का बिना हस्ताक्षर वाला इनपुट, Java पर उसी साइज़ के साइन किए गए इनपुट के रूप में दिखाया जाता है साइड में देखी जा सकती है, जबकि स्क्रिप्ट के बिना हस्ताक्षर वाले नतीजे को Java पर किनारे (ulong के मामले को छोड़कर).

रिडक्शन कर्नेल के उदाहरण

#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];
}

अतिरिक्त कोड सैंपल

BasicRenderScript, RenderScriptIntrinsic, और हैलो कंप्यूट इन सैंपल से, इस पेज पर बताए गए एपीआई के इस्तेमाल के बारे में जानकारी मिलती है.