OpenGL ES 3.1-এ স্ক্রিপ্ট স্থানান্তর করুন

কাজের চাপের জন্য যেখানে GPU কম্পিউট আদর্শ, রেন্ডারস্ক্রিপ্ট স্ক্রিপ্টগুলিকে OpenGL ES (GLES) তে স্থানান্তরিত করার ফলে কোটলিন, জাভা, বা NDK ব্যবহার করে GPU হার্ডওয়্যারের সুবিধা নিতে পারবেন। রেন্ডারস্ক্রিপ্ট স্ক্রিপ্ট প্রতিস্থাপন করতে OpenGL ES 3.1 কম্পিউট শেডার ব্যবহার করতে সাহায্য করার জন্য একটি উচ্চ-স্তরের ওভারভিউ অনুসরণ করা হয়েছে।

GLES সূচনা

একটি রেন্ডারস্ক্রিপ্ট প্রসঙ্গ অবজেক্ট তৈরি করার পরিবর্তে, EGL ব্যবহার করে একটি GLES অফস্ক্রিন প্রসঙ্গ তৈরি করতে নিম্নলিখিত পদক্ষেপগুলি সম্পাদন করুন:

  1. ডিফল্ট ডিসপ্লে পান

  2. GLES সংস্করণ নির্দিষ্ট করে ডিফল্ট ডিসপ্লে ব্যবহার করে EGL শুরু করুন।

  3. EGL_PBUFFER_BIT এর সারফেস টাইপ সহ একটি EGL কনফিগারেশন বেছে নিন।

  4. একটি EGL প্রসঙ্গ তৈরি করতে প্রদর্শন এবং কনফিগারেশন ব্যবহার করুন।

  5. eglCreatePBufferSurface দিয়ে অফস্ক্রিন পৃষ্ঠ তৈরি করুন। প্রসঙ্গটি শুধুমাত্র গণনার জন্য ব্যবহার করা হলে, এটি একটি তুচ্ছ ছোট (1x1) পৃষ্ঠ হতে পারে।

  6. রেন্ডার থ্রেড তৈরি করুন এবং রেন্ডার থ্রেডে eglMakeCurrent কল করুন ডিসপ্লে, সারফেস, এবং EGL কনটেক্সট সহ থ্রেডের সাথে GL প্রসঙ্গ আবদ্ধ করতে।

নমুনা অ্যাপটি দেখায় কিভাবে GLSLImageProcessor.kt এ GLES প্রসঙ্গ শুরু করতে হয়। আরও জানতে, EGLSurfaces এবং OpenGL ES দেখুন।

GLES ডিবাগ আউটপুট

OpenGL থেকে দরকারী ত্রুটিগুলি পাওয়া ডিবাগ লগিং সক্ষম করতে একটি এক্সটেনশন ব্যবহার করে যা একটি ডিবাগ আউটপুট কলব্যাক সেট করে। SDK থেকে এটি করার পদ্ধতি, glDebugMessageCallbackKHR , কখনই প্রয়োগ করা হয়নি, এবং একটি ব্যতিক্রম নিক্ষেপ করে। নমুনা অ্যাপটিতে NDK কোড থেকে কলব্যাকের জন্য একটি মোড়ক রয়েছে।

GLES বরাদ্দ

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

GLES সম্পদ GLES এর মধ্যে বরাদ্দ করা হয়। অন্যান্য অ্যান্ড্রয়েড উপাদানগুলির সাথে ইন্টারঅ্যাক্ট করার সময় মেমরি কপি ওভারহেড এড়াতে, KHR চিত্রগুলির জন্য একটি এক্সটেনশন রয়েছে যা চিত্র ডেটার 2D অ্যারে ভাগ করে নেওয়ার অনুমতি দেয়৷ এই এক্সটেনশনটি Android 8.0 দিয়ে শুরু হওয়া Android ডিভাইসগুলির জন্য প্রয়োজন৷ গ্রাফিক্স-কোর অ্যান্ড্রয়েড জেটপ্যাক লাইব্রেরিতে পরিচালিত কোডের মধ্যে এই ছবিগুলি তৈরি করা এবং একটি বরাদ্দ করা HardwareBuffer ম্যাপ করার জন্য সমর্থন অন্তর্ভুক্ত রয়েছে:

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]
    )!!
}

দুর্ভাগ্যবশত, এটি একটি কম্পিউট শেডারের জন্য সরাসরি বাফারে লেখার জন্য প্রয়োজনীয় অপরিবর্তনীয় স্টোরেজ টেক্সচার তৈরি করে না। KHR Image কম্পিউট শেডার দ্বারা ব্যবহৃত স্টোরেজ টেক্সচার কপি করতে নমুনাটি glCopyTexSubImage2D ব্যবহার করে। যদি OpenGL ড্রাইভার EGL ইমেজ স্টোরেজ এক্সটেনশন সমর্থন করে, তাহলে সেই এক্সটেনশনটি কপি এড়াতে একটি শেয়ার্ড অপরিবর্তনীয় স্টোরেজ টেক্সচার তৈরি করতে ব্যবহার করা যেতে পারে।

GLSL কম্পিউট শেডারে রূপান্তর

আপনার রেন্ডারস্ক্রিপ্ট স্ক্রিপ্টগুলি GLSL কম্পিউট শেডারে রূপান্তরিত হয়েছে৷

একটি GLSL কম্পিউট শেডার লিখুন

OpenGL ES-এ, কম্পিউট শেডারগুলি OpenGL শেডিং ল্যাঙ্গুয়েজ (GLSL) এ লেখা হয়।

স্ক্রিপ্ট বিশ্বব্যাপী অভিযোজন

স্ক্রিপ্ট গ্লোবালের বৈশিষ্ট্যের উপর ভিত্তি করে, আপনি হয় ইউনিফর্ম বা ইউনিফর্ম বাফার অবজেক্ট ব্যবহার করতে পারেন গ্লোবালের জন্য যেগুলি শেডারের মধ্যে পরিবর্তন করা হয়নি:

  • ইউনিফর্ম বাফার : পুশ ধ্রুবক সীমার চেয়ে বড় আকারের ঘন ঘন পরিবর্তিত স্ক্রিপ্ট গ্লোবালগুলির জন্য প্রস্তাবিত৷

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

গণনা চালান

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

কম্পিউট প্রোগ্রাম তৈরি করুন এবং শুরু করুন

কম্পিউট প্রোগ্রাম তৈরি করা এবং আরম্ভ করা অন্য যেকোনো GLES শেডারের সাথে কাজ করার সাথে অনেক মিল রয়েছে।

  1. প্রোগ্রাম এবং এর সাথে যুক্ত কম্পিউট শেডার তৈরি করুন।

  2. শেডারের উত্সটি সংযুক্ত করুন, শেডারটি কম্পাইল করুন (এবং সংকলনের ফলাফলগুলি পরীক্ষা করুন)।

  3. শেডার সংযুক্ত করুন, প্রোগ্রামটি লিঙ্ক করুন এবং প্রোগ্রামটি ব্যবহার করুন।

  4. যেকোনো ইউনিফর্ম তৈরি করুন, শুরু করুন এবং আবদ্ধ করুন।

একটি গণনা শুরু করুন

কম্পিউট শেডারগুলি একটি বিমূর্ত 1D, 2D বা 3D স্পেসের মধ্যে কাজ করে একটি সিরিজের ওয়ার্কগ্রুপের মধ্যে, যেগুলিকে শেডার সোর্স কোডের মধ্যে সংজ্ঞায়িত করা হয় এবং শেডারের জ্যামিতির পাশাপাশি ন্যূনতম আহ্বানের আকারকে উপস্থাপন করে৷ নিম্নলিখিত শেডারটি একটি 2D চিত্রে কাজ করে এবং দুটি মাত্রায় কাজের গ্রুপগুলিকে সংজ্ঞায়িত করে:

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;

ওয়ার্কগ্রুপগুলি GL_MAX_COMPUTE_SHARED_MEMORY_SIZE দ্বারা সংজ্ঞায়িত মেমরি শেয়ার করতে পারে, যা কমপক্ষে 32 KB এবং সুসংগত মেমরি অ্যাক্সেস প্রদান করতে memoryBarrierShared() ব্যবহার করতে পারে।

ওয়ার্কগ্রুপের আকার নির্ধারণ করুন

এমনকি যদি আপনার সমস্যা স্থান 1 এর ওয়ার্কগ্রুপ আকারের সাথে ভাল কাজ করে, একটি উপযুক্ত ওয়ার্কগ্রুপ সাইজ সেট করা কম্পিউট শেডারকে সমান্তরাল করার জন্য গুরুত্বপূর্ণ। আকার খুব ছোট হলে, GPU ড্রাইভার আপনার গণনাকে যথেষ্ট সমান্তরাল নাও করতে পারে, উদাহরণস্বরূপ। আদর্শভাবে, এই মাপগুলি প্রতি-GPU-তে টিউন করা উচিত, যদিও যুক্তিসঙ্গত ডিফল্টগুলি বর্তমান ডিভাইসগুলিতে যথেষ্ট ভাল কাজ করে, যেমন শেডার স্নিপেটে 8x8 ওয়ার্কগ্রুপের আকার।

একটি GL_MAX_COMPUTE_WORK_GROUP_COUNT আছে, কিন্তু তা যথেষ্ট; স্পেসিফিকেশন অনুযায়ী তিনটি অক্ষে এটি কমপক্ষে 65535 হতে হবে।

শেডার প্রেরণ করুন

গণনা চালানোর চূড়ান্ত ধাপ হল glDispatchCompute এর মতো একটি ডিসপ্যাচ ফাংশন ব্যবহার করে শেডার পাঠানো। প্রেরণ ফাংশন প্রতিটি অক্ষের জন্য ওয়ার্কগ্রুপের সংখ্যা নির্ধারণের জন্য দায়ী:

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
)

মান ফেরত দিতে, প্রথমে একটি মেমরি বাধা ব্যবহার করে কম্পিউট অপারেশন শেষ হওয়ার জন্য অপেক্ষা করুন:

GLES31.glMemoryBarrier(GLES31.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT)

একাধিক কার্নেল একসাথে চেইন করতে, (উদাহরণস্বরূপ, ScriptGroup ব্যবহার করে কোড স্থানান্তর করতে), একাধিক প্রোগ্রাম তৈরি এবং প্রেরণ এবং মেমরি বাধাগুলির সাথে আউটপুটে তাদের অ্যাক্সেস সিঙ্ক্রোনাইজ করুন।

নমুনা অ্যাপ্লিকেশন দুটি গণনা কাজ প্রদর্শন করে:

  • HUE ঘূর্ণন: একটি একক গণনা শেডার সহ একটি গণনা কাজ৷ কোড নমুনার জন্য GLSLImageProcessor::rotateHue দেখুন।
  • ব্লার: একটি আরও জটিল কম্পিউট টাস্ক যা ক্রমানুসারে দুটি কম্পিউট শেডার নির্বাহ করে। কোড নমুনার জন্য GLSLImageProcessor::blur দেখুন।

মেমরি বাধা সম্পর্কে আরও জানতে, দৃশ্যমানতা নিশ্চিত করার পাশাপাশি ভাগ করা ভেরিয়েবলগুলি পড়ুন।