উন্নত রেন্ডারস্ক্রিপ্ট

যেহেতু রেন্ডারস্ক্রিপ্ট ব্যবহার করে এমন অ্যাপ্লিকেশনগুলি এখনও অ্যান্ড্রয়েড ভিএম-এর ভিতরে চলে, তাই আপনার কাছে পরিচিত সমস্ত ফ্রেমওয়ার্ক API-এ অ্যাক্সেস রয়েছে তবে উপযুক্ত হলে রেন্ডারস্ক্রিপ্ট ব্যবহার করতে পারেন। ফ্রেমওয়ার্ক এবং রেন্ডারস্ক্রিপ্ট রানটাইমের মধ্যে এই মিথস্ক্রিয়াকে সহজতর করার জন্য, কোডের দুটি স্তরের মধ্যে যোগাযোগ এবং মেমরি পরিচালনার সুবিধার্থে কোডের একটি মধ্যবর্তী স্তরও উপস্থিত রয়েছে। এই দস্তাবেজটি কোডের এই বিভিন্ন স্তরের পাশাপাশি Android VM এবং RenderScript রানটাইমের মধ্যে কীভাবে মেমরি ভাগ করা হয় সে সম্পর্কে আরও বিশদে যায়।

রেন্ডারস্ক্রিপ্ট রানটাইম স্তর

আপনার রেন্ডারস্ক্রিপ্ট কোড একটি কমপ্যাক্ট এবং সু-সংজ্ঞায়িত রানটাইম স্তরে সংকলিত এবং কার্যকর করা হয়েছে। রেন্ডারস্ক্রিপ্ট রানটাইম এপিআইগুলি নিবিড় গণনার জন্য সমর্থন অফার করে যা বহনযোগ্য এবং একটি প্রসেসরে উপলব্ধ কোরের পরিমাণে স্বয়ংক্রিয়ভাবে মাপযোগ্য।

দ্রষ্টব্য: এনডিকে-তে স্ট্যান্ডার্ড সি ফাংশনগুলি অবশ্যই একটি সিপিইউতে চালানোর নিশ্চয়তা দিতে হবে, তাই রেন্ডারস্ক্রিপ্ট এই লাইব্রেরিগুলি অ্যাক্সেস করতে পারে না, কারণ রেন্ডারস্ক্রিপ্ট বিভিন্ন ধরণের প্রসেসরে চালানোর জন্য ডিজাইন করা হয়েছে।

আপনি আপনার অ্যান্ড্রয়েড প্রকল্পের src/ ডিরেক্টরিতে .rs এবং .rsh ফাইলগুলিতে আপনার রেন্ডারস্ক্রিপ্ট কোড সংজ্ঞায়িত করুন৷ কোডটি llvm কম্পাইলার দ্বারা অন্তর্বর্তী বাইটকোডে কম্পাইল করা হয়েছে যা একটি Android বিল্ডের অংশ হিসাবে চলে। যখন আপনার অ্যাপ্লিকেশনটি একটি ডিভাইসে চলে, তখন ডিভাইসে থাকা অন্য llvm কম্পাইলার দ্বারা বাইটকোডটি মেশিন কোডে কম্পাইল করা হয় (মাত্র-সময়ে)। মেশিন কোডটি ডিভাইসের জন্য অপ্টিমাইজ করা হয়েছে এবং ক্যাশে করা হয়েছে, তাই রেন্ডারস্ক্রিপ্ট সক্রিয় অ্যাপ্লিকেশনের পরবর্তী ব্যবহারগুলি বাইটকোডকে পুনরায় কম্পাইল করে না।

রেন্ডারস্ক্রিপ্ট রানটাইম লাইব্রেরির কিছু মূল বৈশিষ্ট্যের মধ্যে রয়েছে:

  • মেমরি বরাদ্দ অনুরোধ বৈশিষ্ট্য
  • অনেক সাধারণ রুটিনের ওভারলোডেড সংস্করণ টাইপ করা স্কেলার এবং ভেক্টর উভয় সহ গণিত ফাংশনের একটি বড় সংগ্রহ। পারমাণবিক গাণিতিক এবং তুলনা ফাংশনগুলির পাশাপাশি যোগ, গুণন, ডট পণ্য এবং ক্রস পণ্যের মতো অপারেশনগুলি উপলব্ধ।
  • আদিম ডেটা টাইপ এবং ভেক্টর, ম্যাট্রিক্স রুটিন এবং তারিখ এবং সময় রুটিনগুলির জন্য রূপান্তর রুটিন
  • রেন্ডারস্ক্রিপ্ট সিস্টেমকে সমর্থন করার জন্য ডেটা প্রকার এবং কাঠামো যেমন দুই-, তিন- বা চার-ভেক্টর সংজ্ঞায়িত করার জন্য ভেক্টর প্রকার।
  • লগিং ফাংশন

উপলব্ধ ফাংশন সম্পর্কে আরও তথ্যের জন্য RenderScript রানটাইম API রেফারেন্স দেখুন।

প্রতিফলিত স্তর

প্রতিফলিত স্তর হল ক্লাসের একটি সেট যা অ্যান্ড্রয়েড বিল্ড টুল অ্যান্ড্রয়েড ফ্রেমওয়ার্ক থেকে রেন্ডারস্ক্রিপ্ট রানটাইমে অ্যাক্সেসের অনুমতি দেওয়ার জন্য তৈরি করে। এই স্তরটি পদ্ধতি এবং কনস্ট্রাক্টরও প্রদান করে যা আপনাকে আপনার রেন্ডারস্ক্রিপ্ট কোডে সংজ্ঞায়িত পয়েন্টারগুলির জন্য মেমরি বরাদ্দ এবং কাজ করার অনুমতি দেয়। নিম্নলিখিত তালিকাটি প্রতিফলিত হওয়া প্রধান উপাদানগুলিকে বর্ণনা করে:

  • আপনার তৈরি করা প্রতিটি .rs ফাইল project_root/gen/package/name/ScriptC_ renderscript_filename টাইপের ScriptC নামের একটি ক্লাসে তৈরি হয়। এই ফাইলটি আপনার .rs ফাইলের .java সংস্করণ, যা আপনি Android ফ্রেমওয়ার্ক থেকে কল করতে পারেন৷ এই ক্লাসে .rs ফাইল থেকে প্রতিফলিত নিম্নলিখিত আইটেমগুলি রয়েছে:
    • নন-স্ট্যাটিক ফাংশন
    • নন-স্ট্যাটিক, গ্লোবাল রেন্ডারস্ক্রিপ্ট ভেরিয়েবল। প্রতিটি ভেরিয়েবলের জন্য অ্যাক্সেসর পদ্ধতি তৈরি করা হয়, তাই আপনি অ্যান্ড্রয়েড ফ্রেমওয়ার্ক থেকে রেন্ডারস্ক্রিপ্ট ভেরিয়েবল পড়তে এবং লিখতে পারেন। যদি রেন্ডারস্ক্রিপ্ট রানটাইম স্তরে একটি গ্লোবাল ভেরিয়েবল শুরু করা হয়, তবে সেই মানগুলি Android ফ্রেমওয়ার্ক স্তরে সংশ্লিষ্ট মানগুলি শুরু করতে ব্যবহৃত হয়। যদি গ্লোবাল ভেরিয়েবলগুলি const হিসাবে চিহ্নিত করা হয়, তাহলে একটি set পদ্ধতি তৈরি হয় না। আরো বিস্তারিত জানার জন্য এখানে দেখুন.

    • গ্লোবাল পয়েন্টার
  • project_root/gen/package/name/ScriptField_struct_name নামে একটি struct তার নিজস্ব ক্লাসে প্রতিফলিত হয়, যা Script.FieldBase প্রসারিত করে। এই ক্লাসটি struct এর একটি অ্যারের প্রতিনিধিত্ব করে, যা আপনাকে এই struct এর এক বা একাধিক উদাহরণের জন্য মেমরি বরাদ্দ করতে দেয়।

ফাংশন

project_root/gen/package/name/ScriptC_renderscript_filename এ অবস্থিত ফাংশনগুলি স্ক্রিপ্ট ক্লাসে প্রতিফলিত হয়। উদাহরণস্বরূপ, যদি আপনি আপনার রেন্ডারস্ক্রিপ্ট কোডে নিম্নলিখিত ফাংশনটি সংজ্ঞায়িত করেন:

void touch(float x, float y, float pressure, int id) {
    if (id >= 10) {
        return;
    }

    touchPos[id].x = x;
    touchPos[id].y = y;
    touchPressure[id] = pressure;
}

তারপর নিম্নলিখিত জাভা কোড উত্পন্ন হয়:

public void invoke_touch(float x, float y, float pressure, int id) {
    FieldPacker touch_fp = new FieldPacker(16);
    touch_fp.addF32(x);
    touch_fp.addF32(y);
    touch_fp.addF32(pressure);
    touch_fp.addI32(id);
    invoke(mExportFuncIdx_touch, touch_fp);
}

ফাংশনের রিটার্ন মান থাকতে পারে না, কারণ রেন্ডারস্ক্রিপ্ট সিস্টেমটি অ্যাসিঙ্ক্রোনাস করার জন্য ডিজাইন করা হয়েছে। যখন আপনার অ্যান্ড্রয়েড ফ্রেমওয়ার্ক কোড রেন্ডারস্ক্রিপ্টে কল করে, কলটি সারিবদ্ধ হয় এবং সম্ভব হলে তা চালানো হয়। এই সীমাবদ্ধতা রেন্ডারস্ক্রিপ্ট সিস্টেমকে ধ্রুবক বাধা ছাড়াই কাজ করতে দেয় এবং দক্ষতা বাড়ায়। যদি ফাংশনগুলিকে রিটার্ন মান থাকার অনুমতি দেওয়া হয়, তাহলে মানটি ফেরত না আসা পর্যন্ত কলটি ব্লক হয়ে যাবে।

আপনি যদি রেন্ডারস্ক্রিপ্ট কোডটি অ্যান্ড্রয়েড ফ্রেমওয়ার্কে একটি মান ফেরত পাঠাতে চান তবে rsSendToClient() ফাংশনটি ব্যবহার করুন।

ভেরিয়েবল

সমর্থিত প্রকারের ভেরিয়েবলগুলি স্ক্রিপ্ট ক্লাসে প্রতিফলিত হয়, project_root/gen/package/name/ScriptC_renderscript_filename এ অবস্থিত। প্রতিটি ভেরিয়েবলের জন্য অ্যাক্সেসর পদ্ধতির একটি সেট তৈরি করা হয়। উদাহরণস্বরূপ, যদি আপনি আপনার রেন্ডারস্ক্রিপ্ট কোডে নিম্নলিখিত ভেরিয়েবলটি সংজ্ঞায়িত করেন:

uint32_t unsignedInteger = 1;

তারপর নিম্নলিখিত জাভা কোড উত্পন্ন হয়:

private long mExportVar_unsignedInteger;
public void set_unsignedInteger(long v){
    mExportVar_unsignedInteger = v;
    setVar(mExportVarIdx_unsignedInteger, v);
}

public long get_unsignedInteger(){
    return mExportVar_unsignedInteger;
}
  

কাঠামো

<project_root>/gen/com/example/renderscript/ScriptField_struct_name এ অবস্থিত কাঠামোগুলি তাদের নিজস্ব ক্লাসে প্রতিফলিত হয়। এই শ্রেণীটি struct এর একটি অ্যারের প্রতিনিধিত্ব করে এবং আপনাকে একটি নির্দিষ্ট সংখ্যক struct s-এর জন্য মেমরি বরাদ্দ করতে দেয়। উদাহরণস্বরূপ, যদি আপনি নিম্নলিখিত struct সংজ্ঞায়িত করেন:

typedef struct Point {
    float2 position;
    float size;
} Point_t;

তারপর নিচের কোডটি ScriptField_Point.java এ তৈরি হয়:

package com.example.android.rs.hellocompute;

import android.renderscript.*;
import android.content.res.Resources;

  /**
  * @hide
  */
public class ScriptField_Point extends android.renderscript.Script.FieldBase {

    static public class Item {
        public static final int sizeof = 12;

        Float2 position;
        float size;

        Item() {
            position = new Float2();
        }
    }

    private Item mItemArray[];
    private FieldPacker mIOBuffer;
    public static Element createElement(RenderScript rs) {
        Element.Builder eb = new Element.Builder(rs);
        eb.add(Element.F32_2(rs), "position");
        eb.add(Element.F32(rs), "size");
        return eb.create();
    }

    public  ScriptField_Point(RenderScript rs, int count) {
        mItemArray = null;
        mIOBuffer = null;
        mElement = createElement(rs);
        init(rs, count);
    }

    public  ScriptField_Point(RenderScript rs, int count, int usages) {
        mItemArray = null;
        mIOBuffer = null;
        mElement = createElement(rs);
        init(rs, count, usages);
    }

    private void copyToArray(Item i, int index) {
        if (mIOBuffer == null) mIOBuffer = new FieldPacker(Item.sizeof * getType().getX()/* count
        */);
        mIOBuffer.reset(index * Item.sizeof);
        mIOBuffer.addF32(i.position);
        mIOBuffer.addF32(i.size);
    }

    public void set(Item i, int index, boolean copyNow) {
        if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
        mItemArray[index] = i;
        if (copyNow)  {
            copyToArray(i, index);
            mAllocation.setFromFieldPacker(index, mIOBuffer);
        }
    }

    public Item get(int index) {
        if (mItemArray == null) return null;
        return mItemArray[index];
    }

    public void set_position(int index, Float2 v, boolean copyNow) {
        if (mIOBuffer == null) mIOBuffer = new FieldPacker(Item.sizeof * getType().getX()/* count */);
        if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
        if (mItemArray[index] == null) mItemArray[index] = new Item();
        mItemArray[index].position = v;
        if (copyNow) {
            mIOBuffer.reset(index * Item.sizeof);
            mIOBuffer.addF32(v);
            FieldPacker fp = new FieldPacker(8);
            fp.addF32(v);
            mAllocation.setFromFieldPacker(index, 0, fp);
        }
    }

    public void set_size(int index, float v, boolean copyNow) {
        if (mIOBuffer == null) mIOBuffer = new FieldPacker(Item.sizeof * getType().getX()/* count */);
        if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
        if (mItemArray[index] == null) mItemArray[index] = new Item();
        mItemArray[index].size = v;
        if (copyNow)  {
            mIOBuffer.reset(index * Item.sizeof + 8);
            mIOBuffer.addF32(v);
            FieldPacker fp = new FieldPacker(4);
            fp.addF32(v);
            mAllocation.setFromFieldPacker(index, 1, fp);
        }
    }

    public Float2 get_position(int index) {
        if (mItemArray == null) return null;
        return mItemArray[index].position;
    }

    public float get_size(int index) {
        if (mItemArray == null) return 0;
        return mItemArray[index].size;
    }

    public void copyAll() {
        for (int ct = 0; ct < mItemArray.length; ct++) copyToArray(mItemArray[ct], ct);
        mAllocation.setFromFieldPacker(0, mIOBuffer);
    }

    public void resize(int newSize) {
        if (mItemArray != null)  {
            int oldSize = mItemArray.length;
            int copySize = Math.min(oldSize, newSize);
            if (newSize == oldSize) return;
            Item ni[] = new Item[newSize];
            System.arraycopy(mItemArray, 0, ni, 0, copySize);
            mItemArray = ni;
        }
        mAllocation.resize(newSize);
        if (mIOBuffer != null) mIOBuffer = new FieldPacker(Item.sizeof * getType().getX()/* count */);
    }
}

রেন্ডারস্ক্রিপ্ট রানটাইম দ্বারা অনুরোধ করা স্ট্রাকটগুলির জন্য মেমরি বরাদ্দ করার জন্য এবং মেমরিতে struct সাথে ইন্টারঅ্যাক্ট করার সুবিধা হিসাবে জেনারেট করা কোডটি আপনাকে প্রদান করা হয়েছে। প্রতিটি struct এর ক্লাস নিম্নলিখিত পদ্ধতি এবং কনস্ট্রাক্টর সংজ্ঞায়িত করে:

  • ওভারলোডেড কনস্ট্রাক্টর যা আপনাকে মেমরি বরাদ্দ করতে দেয়। ScriptField_ struct_name (RenderScript rs, int count) কনস্ট্রাক্টর আপনাকে count প্যারামিটারের সাথে মেমরি বরাদ্দ করতে চান এমন কাঠামোর সংখ্যা নির্ধারণ করতে দেয়। ScriptField_ struct_name (RenderScript rs, int count, int usages) কনস্ট্রাক্টর একটি অতিরিক্ত প্যারামিটার সংজ্ঞায়িত করে, usages , যা আপনাকে এই মেমরি বরাদ্দের মেমরি স্পেস নির্দিষ্ট করতে দেয়। চারটি মেমরি স্পেস সম্ভাবনা আছে:
    • USAGE_SCRIPT : স্ক্রিপ্ট মেমরি স্পেস বরাদ্দ করে। এটি ডিফল্ট মেমরি স্পেস যদি আপনি একটি মেমরি স্পেস নির্দিষ্ট না করেন।
    • USAGE_GRAPHICS_TEXTURE : GPU এর টেক্সচার মেমরির জায়গা বরাদ্দ করে।
    • USAGE_GRAPHICS_VERTEX : GPU এর ভার্টেক্স মেমরি স্পেসে বরাদ্দ করে।
    • USAGE_GRAPHICS_CONSTANTS : GPU-এর ধ্রুবক মেমরি স্পেস বরাদ্দ করে যা বিভিন্ন প্রোগ্রাম অবজেক্ট দ্বারা ব্যবহৃত হয়।

    আপনি bitwise OR অপারেটর ব্যবহার করে একাধিক মেমরি স্পেস নির্দিষ্ট করতে পারেন। এটি করা রেন্ডারস্ক্রিপ্ট রানটাইমকে সূচিত করে যে আপনি নির্দিষ্ট মেমরি স্পেসে ডেটা অ্যাক্সেস করতে চান। নিম্নলিখিত উদাহরণটি স্ক্রিপ্ট এবং ভার্টেক্স মেমরি স্পেস উভয় ক্ষেত্রেই একটি কাস্টম ডেটা টাইপের জন্য মেমরি বরাদ্দ করে:

    কোটলিন

    val touchPoints: ScriptField_Point = ScriptField_Point(
            myRenderScript,
            2,
            Allocation.USAGE_SCRIPT or Allocation.USAGE_GRAPHICS_VERTEX
    )

    জাভা

    ScriptField_Point touchPoints = new ScriptField_Point(myRenderScript, 2,
            Allocation.USAGE_SCRIPT | Allocation.USAGE_GRAPHICS_VERTEX);
  • একটি স্ট্যাটিক নেস্টেড ক্লাস, Item , আপনাকে অবজেক্ট আকারে struct এর একটি উদাহরণ তৈরি করতে দেয়। এই নেস্টেড ক্লাসটি উপযোগী যদি এটি আপনার অ্যান্ড্রয়েড কোডে struct সাথে কাজ করার জন্য আরও বোধগম্য হয়। যখন আপনি অবজেক্টটি ম্যানিপুলেট করা শেষ করেন, আপনি set(Item i, int index, boolean copyNow) কল করে বস্তুটিকে বরাদ্দকৃত মেমরিতে পুশ করতে পারেন এবং Item অ্যারেতে পছন্দসই অবস্থানে সেট করতে পারেন। RenderScript রানটাইম স্বয়ংক্রিয়ভাবে নতুন লিখিত মেমরি অ্যাক্সেস আছে.
  • একটি কাঠামোতে প্রতিটি ক্ষেত্রের মান পেতে এবং সেট করার জন্য অ্যাক্সেসর পদ্ধতি। আপনি পড়তে বা লিখতে চান এমন অ্যারেতে struct নির্দিষ্ট করার জন্য এই অ্যাক্সেসর পদ্ধতিগুলির প্রতিটিতে একটি index প্যারামিটার রয়েছে। প্রতিটি সেটার পদ্ধতিতে একটি copyNow প্যারামিটার রয়েছে যা রেন্ডারস্ক্রিপ্ট রানটাইমের সাথে এই মেমরিটি অবিলম্বে সিঙ্ক করবে কিনা তা নির্দিষ্ট করে। সিঙ্ক করা হয়নি এমন কোনো মেমরি সিঙ্ক করতে, copyAll() কল করুন।
  • createElement() পদ্ধতি মেমরিতে struct-এর একটি বিবরণ তৈরি করে। এই বিবরণটি এক বা একাধিক উপাদান নিয়ে গঠিত মেমরি বরাদ্দ করতে ব্যবহৃত হয়।
  • resize() অনেকটা C-তে একটি realloc() এর মতো কাজ করে, যা আপনাকে পূর্বে তৈরি করা বর্তমান মান বজায় রেখে পূর্বে বরাদ্দ করা মেমরি প্রসারিত করতে দেয়।
  • copyAll() ফ্রেমওয়ার্ক লেভেলে রেন্ডারস্ক্রিপ্ট রানটাইমে সেট করা মেমরিকে সিঙ্ক্রোনাইজ করে। আপনি যখন একজন সদস্যকে একটি সেট অ্যাক্সেসর পদ্ধতিতে কল করেন, তখন একটি ঐচ্ছিক copyNow বুলিয়ান প্যারামিটার থাকে যা আপনি নির্দিষ্ট করতে পারেন। আপনি মেথড কল করার সময় true সুনির্দিষ্ট করা মেমরিকে সিঙ্ক্রোনাইজ করে। যদি আপনি মিথ্যা উল্লেখ করেন, আপনি একবার copyAll() কল করতে পারেন এবং এটি এখনও সিঙ্ক্রোনাইজ করা হয়নি এমন সমস্ত বৈশিষ্ট্যের জন্য মেমরি সিঙ্ক্রোনাইজ করে।

পয়েন্টার

project_root/gen/package/name/ScriptC_renderscript_filename অবস্থিত গ্লোবাল পয়েন্টারগুলি স্ক্রিপ্ট ক্লাসে প্রতিফলিত হয়। আপনি একটি struct বা সমর্থিত RenderScript প্রকারের যেকোনো একটি পয়েন্টার ঘোষণা করতে পারেন, কিন্তু একটি struct পয়েন্টার বা নেস্টেড অ্যারে ধারণ করতে পারে না। উদাহরণস্বরূপ, যদি আপনি একটি struct এবং int32_t নিম্নলিখিত পয়েন্টার সংজ্ঞায়িত করেন

typedef struct Point {
    float2 position;
    float size;
} Point_t;

Point_t *touchPoints;
int32_t *intPointer;

তারপর নিম্নলিখিত জাভা কোড উত্পন্ন হয়:

private ScriptField_Point mExportVar_touchPoints;
public void bind_touchPoints(ScriptField_Point v) {
    mExportVar_touchPoints = v;
    if (v == null) bindAllocation(null, mExportVarIdx_touchPoints);
    else bindAllocation(v.getAllocation(), mExportVarIdx_touchPoints);
}

public ScriptField_Point get_touchPoints() {
    return mExportVar_touchPoints;
}

private Allocation mExportVar_intPointer;
public void bind_intPointer(Allocation v) {
    mExportVar_intPointer = v;
    if (v == null) bindAllocation(null, mExportVarIdx_intPointer);
    else bindAllocation(v, mExportVarIdx_intPointer);
}

public Allocation get_intPointer() {
    return mExportVar_intPointer;
}
  

একটি get পদ্ধতি এবং bind_ pointer_name নামে একটি বিশেষ পদ্ধতি (একটি set() পদ্ধতির পরিবর্তে) তৈরি করা হয়। bind_ pointer_name পদ্ধতি আপনাকে Android VM-এ রেন্ডারস্ক্রিপ্ট রানটাইমে বরাদ্দ করা মেমরিকে আবদ্ধ করতে দেয় (আপনি আপনার .rs ফাইলে মেমরি বরাদ্দ করতে পারবেন না)। আরও তথ্যের জন্য, বরাদ্দকৃত মেমরির সাথে কাজ করা দেখুন।

মেমরি বরাদ্দ APIs

যে অ্যাপ্লিকেশনগুলি রেন্ডারস্ক্রিপ্ট ব্যবহার করে সেগুলি এখনও Android VM-এ চলে৷ প্রকৃত রেন্ডারস্ক্রিপ্ট কোড, যদিও, নেটিভভাবে চলে এবং Android VM-এ বরাদ্দ করা মেমরিতে অ্যাক্সেসের প্রয়োজন। এটি সম্পন্ন করতে, আপনাকে অবশ্যই রেন্ডারস্ক্রিপ্ট রানটাইমে VM-এ বরাদ্দ করা মেমরি সংযুক্ত করতে হবে। এই প্রক্রিয়া, যাকে বাইন্ডিং বলা হয়, RenderScript রানটাইমকে মেমরির সাথে নির্বিঘ্নে কাজ করার অনুমতি দেয় যা এটি অনুরোধ করে কিন্তু স্পষ্টভাবে বরাদ্দ করতে পারে না। শেষ ফলাফলটি মূলত একই রকম যেমন আপনি C-তে malloc কল করেছেন। অতিরিক্ত সুবিধা হল যে Android VM আবর্জনা সংগ্রহের পাশাপাশি রেন্ডারস্ক্রিপ্ট রানটাইম স্তরের সাথে মেমরি শেয়ার করতে পারে। বাইন্ডিং শুধুমাত্র গতিশীলভাবে বরাদ্দ করা মেমরির জন্য প্রয়োজনীয়। কম্পাইলের সময় আপনার রেন্ডারস্ক্রিপ্ট কোডের জন্য স্ট্যাটিকভাবে বরাদ্দ করা মেমরি স্বয়ংক্রিয়ভাবে তৈরি হয়। মেমরি বরাদ্দ কিভাবে ঘটে সে সম্পর্কে আরও তথ্যের জন্য চিত্র 1 দেখুন।

এই মেমরি বরাদ্দকরণ সিস্টেমকে সমর্থন করার জন্য, API এর একটি সেট রয়েছে যা Android VM কে মেমরি বরাদ্দ করতে এবং একটি malloc কলের অনুরূপ কার্যকারিতা অফার করতে দেয়। এই ক্লাসগুলি মূলত বর্ণনা করে যে কীভাবে মেমরি বরাদ্দ করা উচিত এবং বরাদ্দ করাও করা উচিত। এই ক্লাসগুলি কীভাবে কাজ করে তা আরও ভালভাবে বোঝার জন্য, একটি সাধারণ malloc কলের সাথে সম্পর্কিত যেটি এইরকম দেখতে পারে সেগুলি সম্পর্কে চিন্তা করা দরকারী:

array = (int *)malloc(sizeof(int)*10);

malloc কল দুটি ভাগে বিভক্ত করা যেতে পারে: বরাদ্দ করা মেমরির আকার ( sizeof(int) ), সেই মেমরির কত ইউনিট বরাদ্দ করা উচিত (10)। অ্যান্ড্রয়েড ফ্রেমওয়ার্ক এই দুটি অংশের জন্য ক্লাস এবং সেইসাথে malloc প্রতিনিধিত্ব করার জন্য একটি ক্লাস প্রদান করে।

Element ক্লাস malloc কলের ( sizeof(int) ) অংশকে প্রতিনিধিত্ব করে এবং একটি মেমরি বরাদ্দের একটি ঘরকে এনক্যাপসুলেট করে, যেমন একটি একক ফ্লোট মান বা একটি কাঠামো। Type ক্লাস Element এবং বরাদ্দ করার জন্য উপাদানের পরিমাণ (আমাদের উদাহরণে 10) অন্তর্ভুক্ত করে। আপনি Element s এর অ্যারে হিসাবে একটি Type কথা ভাবতে পারেন। Allocation শ্রেণী একটি প্রদত্ত Type উপর ভিত্তি করে প্রকৃত মেমরি বরাদ্দ করে এবং প্রকৃত বরাদ্দকৃত মেমরির প্রতিনিধিত্ব করে।

বেশিরভাগ পরিস্থিতিতে, আপনাকে সরাসরি এই মেমরি বরাদ্দ API কল করতে হবে না। প্রতিফলিত লেয়ার ক্লাসগুলি স্বয়ংক্রিয়ভাবে এই APIগুলি ব্যবহার করার জন্য কোড তৈরি করে এবং মেমরি বরাদ্দ করার জন্য আপনাকে যা করতে হবে তা হল একটি কনস্ট্রাক্টরকে কল করা যা প্রতিফলিত স্তর ক্লাসগুলির মধ্যে একটিতে ঘোষণা করা হয় এবং তারপর রেন্ডারস্ক্রিপ্টে ফলাফলের মেমরি Allocation আবদ্ধ করে৷ এমন কিছু পরিস্থিতিতে রয়েছে যেখানে আপনি এই ক্লাসগুলি সরাসরি আপনার নিজের মেমরি বরাদ্দ করতে ব্যবহার করতে চান, যেমন একটি সংস্থান থেকে একটি বিটম্যাপ লোড করা বা যখন আপনি আদিম প্রকারের পয়েন্টারগুলির জন্য মেমরি বরাদ্দ করতে চান। আপনি রেন্ডারস্ক্রিপ্ট বিভাগে বরাদ্দকরণ এবং বাঁধাই মেমরিতে এটি কীভাবে করবেন তা দেখতে পারেন। নিম্নলিখিত সারণী তিনটি মেমরি ম্যানেজমেন্ট ক্লাসকে আরও বিস্তারিতভাবে বর্ণনা করে:

অ্যান্ড্রয়েড অবজেক্ট টাইপ বর্ণনা
Element

একটি উপাদান একটি মেমরি বরাদ্দের একটি কক্ষকে বর্ণনা করে এবং এর দুটি রূপ থাকতে পারে: মৌলিক বা জটিল।

একটি মৌলিক উপাদানে যেকোনো বৈধ রেন্ডারস্ক্রিপ্ট ডেটা টাইপের ডেটার একটি একক উপাদান থাকে। মৌলিক উপাদান ডেটা প্রকারের উদাহরণগুলির মধ্যে রয়েছে একটি একক float মান, একটি float4 ভেক্টর, বা একটি একক RGB-565 রঙ।

জটিল উপাদানগুলিতে মৌলিক উপাদানগুলির একটি তালিকা থাকে এবং আপনি আপনার রেন্ডারস্ক্রিপ্ট কোডে ঘোষণা করেন এমন struct থেকে তৈরি করা হয়। উদাহরণস্বরূপ, একটি বরাদ্দে মেমরিতে ক্রমানুসারে সাজানো একাধিক struct থাকতে পারে। প্রতিটি স্ট্রাকটকে তার নিজস্ব উপাদান হিসাবে বিবেচনা করা হয়, সেই স্ট্রাকটের মধ্যে প্রতিটি ডেটা টাইপের পরিবর্তে।

Type

একটি প্রকার একটি মেমরি বরাদ্দ টেমপ্লেট এবং একটি উপাদান এবং এক বা একাধিক মাত্রা নিয়ে গঠিত। এটি মেমরির লেআউট বর্ণনা করে (মূলত Element s এর একটি অ্যারে) কিন্তু এটি যে ডেটা বর্ণনা করে তার জন্য মেমরি বরাদ্দ করে না।

একটি প্রকার পাঁচটি মাত্রা নিয়ে গঠিত: X, Y, Z, LOD (বিস্তারিত স্তর), এবং মুখ (একটি ঘনক মানচিত্রের)। আপনি উপলব্ধ মেমরির সীমাবদ্ধতার মধ্যে যেকোন ইতিবাচক পূর্ণসংখ্যা মানের X,Y,Z মাত্রা সেট করতে পারেন। একটি একক মাত্রা বরাদ্দের একটি X মাত্রা শূন্যের চেয়ে বেশি যেখানে Y এবং Z মাত্রাগুলি উপস্থিত নয় তা নির্দেশ করার জন্য শূন্য। উদাহরণস্বরূপ, x=10, y=1 এর একটি বরাদ্দ দ্বিমাত্রিক এবং x=10, y=0 একটি মাত্রিক বলে বিবেচিত হয়। LOD এবং মুখের মাত্রা বর্তমান বা উপস্থিত নয় তা নির্দেশ করার জন্য বুলিয়ান।

Allocation

একটি বরাদ্দ মেমরির বর্ণনার উপর ভিত্তি করে অ্যাপ্লিকেশনগুলির জন্য মেমরি প্রদান করে যা একটি Type দ্বারা উপস্থাপিত হয়। বরাদ্দ করা মেমরি একই সাথে অনেক মেমরি স্পেসে বিদ্যমান থাকতে পারে। যদি মেমরিটি একটি স্পেসে পরিবর্তন করা হয়, তাহলে আপনাকে অবশ্যই মেমরিটিকে স্পষ্টভাবে সিঙ্ক্রোনাইজ করতে হবে, যাতে এটি বিদ্যমান অন্য সমস্ত স্পেসে আপডেট করা হয়।

বরাদ্দ ডেটা দুটি প্রাথমিক উপায়ে একটিতে আপলোড করা হয়: টাইপ চেক করা এবং টাইপ আনচেক করা হয়েছে৷ সাধারণ অ্যারের জন্য রয়েছে copyFrom() ফাংশন যা অ্যান্ড্রয়েড সিস্টেম থেকে একটি অ্যারে নেয় এবং নেটিভ লেয়ার মেমরি স্টোরে কপি করে। আনচেক করা ভেরিয়েন্টগুলি অ্যান্ড্রয়েড সিস্টেমকে স্ট্রাকচারের অ্যারেগুলির উপর কপি করার অনুমতি দেয় কারণ এটি স্ট্রাকচার সমর্থন করে না। উদাহরণস্বরূপ, যদি একটি বরাদ্দ থাকে যা n ফ্লোটের একটি অ্যারে, একটি ফ্লোট[n] অ্যারে বা একটি byte[n*4] অ্যারেতে থাকা ডেটা অনুলিপি করা যেতে পারে।

মেমরি নিয়ে কাজ করা

নন-স্ট্যাটিক, গ্লোবাল ভেরিয়েবল যা আপনি আপনার রেন্ডারস্ক্রিপ্টে ঘোষণা করেন সেগুলি কম্পাইলের সময় মেমরি বরাদ্দ করা হয়। আপনি Android ফ্রেমওয়ার্ক স্তরে তাদের জন্য মেমরি বরাদ্দ না করে সরাসরি আপনার রেন্ডারস্ক্রিপ্ট কোডে এই ভেরিয়েবলগুলির সাথে কাজ করতে পারেন৷ অ্যান্ড্রয়েড ফ্রেমওয়ার্ক লেয়ারেরও এই ভেরিয়েবলগুলিতে অ্যাক্সেস রয়েছে প্রদত্ত অ্যাক্সেসর পদ্ধতিগুলির সাথে যা প্রতিফলিত স্তর ক্লাসে তৈরি হয়। যদি এই ভেরিয়েবলগুলি RenderScript রানটাইম স্তরে আরম্ভ করা হয়, তাহলে সেই মানগুলি Android ফ্রেমওয়ার্ক স্তরে সংশ্লিষ্ট মানগুলি শুরু করতে ব্যবহৃত হয়। যদি গ্লোবাল ভেরিয়েবলগুলি const হিসাবে চিহ্নিত করা হয়, তাহলে একটি set পদ্ধতি তৈরি হয় না। আরো বিস্তারিত জানার জন্য এখানে দেখুন.

দ্রষ্টব্য: আপনি যদি নির্দিষ্ট রেন্ডারস্ক্রিপ্ট স্ট্রাকচার ব্যবহার করেন যাতে পয়েন্টার থাকে, যেমন rs_program_fragment এবং rs_allocation , তাহলে আপনাকে প্রথমে সংশ্লিষ্ট Android ফ্রেমওয়ার্ক ক্লাসের একটি অবজেক্ট পেতে হবে এবং তারপরে রেন্ডারস্ক্রিপ্ট রানটাইমের সাথে মেমরিকে আবদ্ধ করতে সেই কাঠামোর জন্য set পদ্ধতিতে কল করতে হবে। আপনি রেন্ডারস্ক্রিপ্ট রানটাইম স্তরে এই কাঠামোগুলি সরাসরি ম্যানিপুলেট করতে পারবেন না। এই বিধিনিষেধটি ব্যবহারকারী-সংজ্ঞায়িত কাঠামোর ক্ষেত্রে প্রযোজ্য নয় যেগুলিতে পয়েন্টার রয়েছে, কারণ সেগুলি প্রথম স্থানে প্রতিফলিত স্তর শ্রেণিতে রপ্তানি করা যায় না। একটি কম্পাইলার ত্রুটি উত্পন্ন হয় যদি আপনি একটি নন-স্ট্যাটিক, গ্লোবাল স্ট্রাকট ঘোষণা করার চেষ্টা করেন যাতে একটি পয়েন্টার থাকে।

রেন্ডারস্ক্রিপ্টের পয়েন্টারগুলির জন্যও সমর্থন রয়েছে, তবে আপনাকে অবশ্যই আপনার অ্যান্ড্রয়েড ফ্রেমওয়ার্ক কোডে মেমরিটি স্পষ্টভাবে বরাদ্দ করতে হবে। আপনি যখন আপনার .rs ফাইলে একটি গ্লোবাল পয়েন্টার ঘোষণা করেন, আপনি উপযুক্ত প্রতিফলিত স্তর শ্রেণীর মাধ্যমে মেমরি বরাদ্দ করেন এবং সেই মেমরিটিকে নেটিভ রেন্ডারস্ক্রিপ্ট স্তরে আবদ্ধ করেন। আপনি অ্যান্ড্রয়েড ফ্রেমওয়ার্ক লেয়ারের পাশাপাশি রেন্ডারস্ক্রিপ্ট লেয়ার থেকে এই মেমরির সাথে ইন্টারঅ্যাক্ট করতে পারেন, যা আপনাকে সবচেয়ে উপযুক্ত লেয়ারে ভেরিয়েবল পরিবর্তন করার নমনীয়তা প্রদান করে।

রেন্ডারস্ক্রিপ্টে গতিশীল মেমরি বরাদ্দ করা এবং বাঁধাই করা

গতিশীল মেমরি বরাদ্দ করতে, আপনাকে একটি Script.FieldBase ক্লাসের কন্সট্রাকটরকে কল করতে হবে, যা সবচেয়ে সাধারণ উপায়। একটি বিকল্প হ'ল ম্যানুয়ালি একটি Allocation তৈরি করা, যা আদিম টাইপ পয়েন্টারগুলির মতো জিনিসগুলির জন্য প্রয়োজনীয়। আপনি একটি Script.FieldBase ক্লাস কনস্ট্রাক্টর ব্যবহার করা উচিত যখনই সরলতার জন্য উপলব্ধ। একটি মেমরি বরাদ্দ পাওয়ার পর, রেন্ডারস্ক্রিপ্ট রানটাইমে বরাদ্দ করা মেমরিকে আবদ্ধ করতে পয়েন্টারের প্রতিফলিত bind পদ্ধতিতে কল করুন।

নীচের উদাহরণটি একটি আদিম টাইপ পয়েন্টার, intPointer এবং একটি struct, touchPoints এর জন্য একটি পয়েন্টার উভয়ের জন্য মেমরি বরাদ্দ করে। এটি রেন্ডারস্ক্রিপ্টের সাথে মেমরিকে আবদ্ধ করে:

কোটলিন

private lateinit var myRenderScript: RenderScript
private lateinit var script: ScriptC_example
private lateinit var resources: Resources

public fun init(rs: RenderScript, res: Resources) {
    myRenderScript = rs
    resources = res

    // allocate memory for the struct pointer, calling the constructor
    val touchPoints = ScriptField_Point(myRenderScript, 2)

    // Create an element manually and allocate memory for the int pointer
    val intPointer: Allocation = Allocation.createSized(myRenderScript, Element.I32(myRenderScript), 2)

    // create an instance of the RenderScript, pointing it to the bytecode resource
    script = ScriptC_point(myRenderScript/*, resources, R.raw.example*/)

    // bind the struct and int pointers to the RenderScript
    script.bind_touchPoints(touchPoints)
    script.bind_intPointer(intPointer)

   ...
}

জাভা

private RenderScript myRenderScript;
private ScriptC_example script;
private Resources resources;

public void init(RenderScript rs, Resources res) {
    myRenderScript = rs;
    resources = res;

    // allocate memory for the struct pointer, calling the constructor
    ScriptField_Point touchPoints = new ScriptField_Point(myRenderScript, 2);

    // Create an element manually and allocate memory for the int pointer
    intPointer = Allocation.createSized(myRenderScript, Element.I32(myRenderScript), 2);

    // create an instance of the RenderScript, pointing it to the bytecode resource
    script = new ScriptC_example(myRenderScript, resources, R.raw.example);

    // bind the struct and int pointers to the RenderScript
    script.bind_touchPoints(touchPoints);
    script.bind_intPointer(intPointer);

   ...
}

পড়া এবং স্মৃতিতে লেখা

আপনি রেন্ডারস্ক্রিপ্ট রানটাইম এবং অ্যান্ড্রয়েড ফ্রেমওয়ার্ক লেয়ারে স্ট্যাটিক এবং গতিশীলভাবে বরাদ্দকৃত মেমরি পড়তে এবং লিখতে পারেন।

স্থিতিশীলভাবে বরাদ্দ করা মেমরি রেন্ডারস্ক্রিপ্ট রানটাইম স্তরে একমুখী যোগাযোগ সীমাবদ্ধতার সাথে আসে। যখন রেন্ডারস্ক্রিপ্ট কোড একটি ভেরিয়েবলের মান পরিবর্তন করে, তখন দক্ষতার উদ্দেশ্যে এটি অ্যান্ড্রয়েড ফ্রেমওয়ার্ক স্তরের সাথে যোগাযোগ করা হয় না। অ্যান্ড্রয়েড ফ্রেমওয়ার্ক থেকে সেট করা শেষ মানটি একটি get পদ্ধতিতে কল করার সময় সর্বদা ফেরত দেওয়া হয়। যাইহোক, যখন Android ফ্রেমওয়ার্ক কোড একটি পরিবর্তনশীল পরিবর্তন করে, তখন সেই পরিবর্তনটি RenderScript রানটাইমে স্বয়ংক্রিয়ভাবে বা পরবর্তী সময়ে সিঙ্ক্রোনাইজ করা যেতে পারে। আপনি যদি রেন্ডারস্ক্রিপ্ট রানটাইম থেকে অ্যান্ড্রয়েড ফ্রেমওয়ার্ক লেয়ারে ডেটা পাঠাতে চান, আপনি এই সীমাবদ্ধতা কাটিয়ে উঠতে rsSendToClient() ফাংশন ব্যবহার করতে পারেন।

গতিশীলভাবে বরাদ্দ করা মেমরির সাথে কাজ করার সময়, রেন্ডারস্ক্রিপ্ট রানটাইম স্তরে যেকোন পরিবর্তনগুলিকে Android ফ্রেমওয়ার্ক স্তরে প্রচার করা হয় যদি আপনি এর সম্পর্কিত পয়েন্টার ব্যবহার করে মেমরি বরাদ্দ পরিবর্তন করেন। অ্যান্ড্রয়েড ফ্রেমওয়ার্ক লেয়ারে একটি অবজেক্ট পরিবর্তন করা অবিলম্বে প্রচার করে যা রেন্ডারস্ক্রিপ্ট রানটাইম স্তরে ফিরে আসে।

বিশ্বব্যাপী ভেরিয়েবল পড়া এবং লেখা

বিশ্বব্যাপী ভেরিয়েবল পড়া এবং লেখা একটি সহজবোধ্য প্রক্রিয়া। আপনি Android ফ্রেমওয়ার্ক স্তরে অ্যাক্সেসর পদ্ধতিগুলি ব্যবহার করতে পারেন বা রেন্ডারস্ক্রিপ্ট কোডে সরাসরি সেট করতে পারেন৷ মনে রাখবেন যে আপনি আপনার রেন্ডারস্ক্রিপ্ট কোডে যে কোনও পরিবর্তন করেছেন তা আবার Android ফ্রেমওয়ার্ক স্তরে প্রচারিত হয় না (আরো বিশদ বিবরণের জন্য এখানে দেখুন)।

উদাহরণস্বরূপ, rsfile.rs নামের একটি ফাইলে ঘোষিত নিম্নোক্ত স্ট্রাকট দেওয়া হয়েছে:

typedef struct Point {
    int x;
    int y;
} Point_t;

Point_t point;

আপনি rsfile.rs এ সরাসরি এভাবে struct-এর মান নির্ধারণ করতে পারেন। এই মানগুলি Android ফ্রেমওয়ার্ক স্তরে প্রচারিত হয় না:

point.x = 1;
point.y = 1;

আপনি এইভাবে অ্যান্ড্রয়েড ফ্রেমওয়ার্ক স্তরে স্ট্রাকটে মান নির্ধারণ করতে পারেন। এই মানগুলি রেন্ডারস্ক্রিপ্ট রানটাইম স্তরে অ্যাসিঙ্ক্রোনাসভাবে প্রচারিত হয়:

কোটলিন

val script: ScriptC_rsfile = ...

...

script._point = ScriptField_Point.Item().apply {
    x = 1
    y = 1
}

জাভা

ScriptC_rsfile script;

...

Item i = new ScriptField_Point.Item();
i.x = 1;
i.y = 1;
script.set_point(i);

আপনি আপনার রেন্ডারস্ক্রিপ্ট কোডের মানগুলি এইভাবে পড়তে পারেন:

rsDebug("Printing out a Point", point.x, point.y);

আপনি নিম্নলিখিত কোড সহ Android ফ্রেমওয়ার্ক স্তরের মানগুলি পড়তে পারেন। মনে রাখবেন যে এই কোডটি শুধুমাত্র একটি মান প্রদান করে যদি একটি Android ফ্রেমওয়ার্ক স্তরে সেট করা থাকে। আপনি একটি নাল পয়েন্টার ব্যতিক্রম পাবেন যদি আপনি শুধুমাত্র রেন্ডারস্ক্রিপ্ট রানটাইম স্তরে মান সেট করেন:

কোটলিন

Log.i("TAGNAME", "Printing out a Point: ${mScript._point.x} ${mScript._point.y}")
println("${point.x} ${point.y}")

জাভা

Log.i("TAGNAME", "Printing out a Point: " + script.get_point().x + " " + script.get_point().y);
System.out.println(point.get_x() + " " + point.get_y());

বিশ্বব্যাপী পয়েন্টার পড়া এবং লেখা

ধরে নিই যে মেমরিটি অ্যান্ড্রয়েড ফ্রেমওয়ার্ক স্তরে বরাদ্দ করা হয়েছে এবং রেন্ডারস্ক্রিপ্ট রানটাইমের সাথে আবদ্ধ, আপনি সেই পয়েন্টারের জন্য get এবং set পদ্ধতি ব্যবহার করে অ্যান্ড্রয়েড ফ্রেমওয়ার্ক স্তর থেকে মেমরি পড়তে এবং লিখতে পারেন। রেন্ডারস্ক্রিপ্ট রানটাইম স্তরে, আপনি স্বাভাবিক হিসাবে পয়েন্টার সহ মেমরিতে পড়তে এবং লিখতে পারেন এবং পরিবর্তনগুলি স্ট্যাটিকভাবে বরাদ্দ করা মেমরির বিপরীতে Android ফ্রেমওয়ার্ক স্তরে প্রচারিত হয়।

উদাহরণস্বরূপ, rsfile.rs নামের একটি ফাইলের একটি struct নিম্নলিখিত পয়েন্টার দেওয়া হয়েছে:

typedef struct Point {
    int x;
    int y;
} Point_t;

Point_t *point;

ধরে নিচ্ছি আপনি ইতিমধ্যেই অ্যান্ড্রয়েড ফ্রেমওয়ার্ক স্তরে মেমরি বরাদ্দ করেছেন, আপনি স্বাভাবিক হিসাবে struct মানগুলি অ্যাক্সেস করতে পারেন। আপনি এর পয়েন্টার ভেরিয়েবলের মাধ্যমে স্ট্রাকটে যে কোনও পরিবর্তন করেন তা স্বয়ংক্রিয়ভাবে অ্যান্ড্রয়েড ফ্রেমওয়ার্ক স্তরে উপলব্ধ হয়:

কোটলিন

point[index].apply {
    x = 1
    y = 1
}

জাভা

point[index].x = 1;
point[index].y = 1;

আপনি অ্যান্ড্রয়েড ফ্রেমওয়ার্ক স্তরেও পয়েন্টারে মান পড়তে এবং লিখতে পারেন:

কোটলিন

val i = ScriptField_Point.Item().apply {
    x = 100
    y = 100
}
val p = ScriptField_Point(rs, 1).apply {
    set(i, 0, true)
}
script.bind_point(p)

p.get_x(0)            //read x and y from index 0
p.get_y(0)

জাভা

ScriptField_Point p = new ScriptField_Point(rs, 1);
Item i = new ScriptField_Point.Item();
i.x=100;
i.y = 100;
p.set(i, 0, true);
script.bind_point(p);

p.get_x(0);            //read x and y from index 0
p.get_y(0);

একবার মেমরি ইতিমধ্যেই আবদ্ধ হয়ে গেলে, প্রতিবার যখন আপনি একটি মান পরিবর্তন করবেন তখন আপনাকে রেন্ডারস্ক্রিপ্ট রানটাইমে মেমরিটিকে রিবাইন্ড করতে হবে না।