সিঙ্ক্রোনাইজেশন ফ্রেমওয়ার্ক

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

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

এছাড়াও, সিঙ্ক্রোনাইজেশন ফ্রেমওয়ার্ক, ইমপ্লিমেন্টারদেরকে তাদের নিজস্ব হার্ডওয়্যার কম্পোনেন্টে সিঙ্ক্রোনাইজেশন রিসোর্স ব্যবহার করতে দেয়। সবশেষে, ফ্রেমওয়ার্কটি ডিবাগিংয়ে সাহায্য করার জন্য গ্রাফিক্স পাইপলাইন সম্পর্কে দৃশ্যমানতা প্রদান করে।

স্পষ্ট সিঙ্ক্রোনাইজেশন

এক্সপ্লিসিট সিঙ্ক করার সুবিধা গ্রাফিক্স বাফারের প্রোডিউসার ও কনজিউমারকে বাফার ব্যবহার করা শেষ হলে সিগন্যাল পাঠাতে দেয়। স্পষ্ট সিঙ্ক্রোনাইজেশন কার্নেল-স্পেসে প্রয়োগ করা হয়।

স্পষ্ট সিঙ্ক করার সুবিধার মধ্যে এগুলি অন্তর্ভুক্ত:

  • ডিভাইসগুলির মধ্যে আচরণের পার্থক্য কম
  • ডিবাগিং সংক্রান্ত আরও ভাল সহায়তা
  • উন্নত টেস্টিং মেট্রিক

সিঙ্ক ফ্রেমওয়ার্কে তিন ধরনের অবজেক্ট আছে:

  • sync_timeline
  • sync_pt
  • sync_fence

sync_timeline

sync_timeline হল একটি একঘেয়েভাবে ক্রমবর্ধমান টাইমলাইন যা বিক্রেতাদের প্রতিটি ড্রাইভার ইনস্ট্যান্সের জন্য প্রয়োগ করা উচিত, যেমন একটি GL কনটেক্সট, ডিসপ্লে কন্ট্রোলার বা 2D ব্লিটার। sync_timeline counts নির্দিষ্ট হার্ডওয়্যারের জন্য কার্নেলে জমা দেওয়া জব। sync_timeline অপারেশনের ক্রম নিশ্চিত করে এবং হার্ডওয়্যার-নির্দিষ্ট প্রয়োগ চালু করে।

sync_timeline প্রয়োগ করার সময় এইসব নির্দেশিকা অনুসরণ করুন:

  • ডিবাগিং সহজ করতে, সব ড্রাইভার, টাইমলাইন ও ফেন্সের জন্য সহায়ক নাম দিন।
  • ডিবাগিং আউটপুট আরও সহজে পড়ার উপযোগী করতে টাইমলাইনে timeline_value_str এবং pt_value_str অপারেটর প্রয়োগ করুন।
  • প্রয়োজন হলে, GL লাইব্রেরির মতো ইউজারস্পেস লাইব্রেরিকে ব্যক্তিগত টাইমলাইন ডেটা অ্যাক্সেস করার অনুমতি দিতে driver_data ফিল প্রয়োগ করুন। data_driver ভেন্ডরদের অপরিবর্তনীয় sync_fence ও sync_pts সম্পর্কে তথ্য পাস করতে দেয়, যার ভিত্তিতে কমান্ড লাইন তৈরি করা হয়।
  • ব্যবহারকারী স্পেসকে স্পষ্টভাবে কোনও ফেঞ্চ তৈরি বা সিগন্যাল করার অনুমতি দেবেন না। স্পষ্টভাবে সিগন্যাল/ফেন্স তৈরি করলে পরিষেবা-বঞ্চিত হওয়ার মতো আক্রমণ হয় যা পাইপলাইন ফাংশনালিটি বন্ধ করে দেয়।
  • sync_timeline, sync_pt বা sync_fence এলিমেন্ট স্পষ্টভাবে অ্যাক্সেস করবেন না। API সব প্রয়োজনীয় ফাংশন প্রদান করে।

sync_pt

sync_pt হল একটি একক ভ্যালু বা পয়েন্ট যা sync_timeline-এ থাকে। একটি পয়েন্টের তিনটি অবস্থা থাকে: অ্যাক্টিভ, সিগন্যাল করা ও সমস্যা। পয়েন্ট অ্যাক্টিভ স্টেট থেকে শুরু হয় এবং সিগন্যাল বা সমস্যার স্টেটে ট্রানজিট হয়। যেমন, কোনও ইমেজ কনজিউমার যখন আর কোনও বাফার চায় না, তখন একটি sync_pt সিগন্যাল দেওয়া হয় যাতে ইমেজ প্রডিউসার বুঝতে পারে যে বাফারে আবার লেখা যেতে পারে।

sync_fence

sync_fence হল sync_pt ভ্যালুর একটি সংগ্রহ যেগুলির প্রায়শই আলাদা sync_timeline পেরেন্ট থাকে (যেমন ডিসপ্লে কন্ট্রোলার এবং GPU-এর জন্য)। sync_fence, sync_pt এবং sync_timeline হল প্রধান প্রিমিটিভ যা ড্রাইভার এবং ইউজারস্পেস তাদের ডিপেন্ডেন্সি কমিউনিকেট করার জন্য ব্যবহার করে। কোনও ফেন্স সিগন্যাল করা হলে, ফেন্সের আগে ইস্যু করা সব কমান্ড সম্পূর্ণ হয়ে যায়, কারণ কার্নেল ড্রাইভার বা হার্ডওয়্যার ব্লক কমান্ডগুলি নির্দিষ্ট ক্রমে এক্সিকিউট করে।

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

sync_pt ভ্যালুর মতো ফেন্স, অ্যাক্টিভ শুরু করে এবং তাদের পয়েন্টের স্ট্যাটাসের উপর ভিত্তি করে স্ট্যাটাস পরিবর্তন করে। সব sync_pt ভ্যালু সিগন্যাল করা হলে, sync_fence সিগন্যাল করা হয়। একটি sync_pt-এ সমস্যা সংক্রান্ত স্ট্যাটাস থাকলে, সম্পূর্ণ sync_fence-এ সমস্যা সংক্রান্ত স্ট্যাটাস থাকে।

sync_fence-এ মেম্বারশিপ, ফেন্স তৈরি করার পরে পরিবর্তন করা যায় না। একটি ফেঞ্চে একাধিক পয়েন্ট পেতে, মার্জ করা হয়। দুটি আলাদা ফেঞ্চের পয়েন্টকে তৃতীয় ফেঞ্চে যোগ করা হয়। যদি সেইসব পয়েন্টের মধ্যে একটিকে মূল জিওফেন্সে সিগন্যাল করা হয় এবং অন্যটিকে না করা হয়, তাহলে তৃতীয় জিওফেন্সকেও সিগন্যাল করা হবে না।

স্পষ্ট সিঙ্ক্রোনাইজেশন প্রয়োগ করতে, নিম্নলিখিত তথ্য প্রদান করুন:

  • একটি কার্নেল-স্পেস সাবসিস্টেম যা নির্দিষ্ট হার্ডওয়্যার ড্রাইভারের জন্য সিঙ্ক ফ্রেমওয়ার্ক ইমপ্লিমেন্ট করে। যেসব ড্রাইভারকে ফেন্স-অ্যাওয়ার হতে হয়, সেগুলি সাধারণত হার্ডওয়্যার কম্পোজার (HWC)-এর সাথে অ্যাক্সেস বা কমিউনিকেট করে। গুরুত্বপূর্ণ ফাইলের মধ্যে এগুলি পড়ে:
    • মূল প্রয়োগ:
      • kernel/common/include/linux/sync.h
      • kernel/common/drivers/base/sync.c
    • kernel/common/Documentation/sync.txt-এ ডকুমেন্টেশন
    • কার্নেল স্পেসের সাথে যোগাযোগ করার জন্য লাইব্রেরি platform/system/core/libsync
  • হার্ডওয়্যার অ্যাবস্ট্রাকশন লেয়ার (HAL)-এ validateDisplay() এবং presentDisplay() ফাংশনে প্যারামিটার হিসেবে ভেন্ডরকে উপযুক্ত সিঙ্ক্রোনাইজেশন ফেন্স প্রদান করতে হবে।
  • দুটি বেড়া-সম্পর্কিত GL এক্সটেনশন (EGL_ANDROID_native_fence_sync এবং EGL_ANDROID_wait_sync) এবং গ্রাফিক্স ড্রাইভারে বেড়া সংক্রান্ত সহায়তা।

কেস স্টাডি: ডিসপ্লে ড্রাইভার প্রয়োগ করা

সিঙ্ক্রোনাইজেশন ফাংশন কাজ করে এমন API ব্যবহার করতে, ডিসপ্লে বাফার ফাংশন আছে এমন ডিসপ্লে ড্রাইভার ডেভেলপ করুন। সিনক্রোনাইজেশন ফ্রেমওয়ার্ক আসার আগে, এই ফাংশন dma-buf অবজেক্ট পেত, সেইসব বাফার ডিসপ্লেতে রাখত এবং বাফার দেখা গেলে ব্লক করত। যেমন:

/*
 * assumes buffer is ready to be displayed.  returns when buffer is no longer on
 * screen.
 */
void display_buffer(struct dma_buf *buffer);

সিঙ্ক্রোনাইজেশন ফ্রেমওয়ার্কের সাথে, display_buffer ফাংশন আরও জটিল। ডিসপ্লেতে বাফার রাখার সময়, বাফারটি একটি ফেন্সের সাথে যুক্ত থাকে যা নির্দেশ করে যে বাফারটি কখন রেডি হবে। আপনি কিউতে রাখতে পারেন এবং বেড়া সরিয়ে দেওয়ার পরে কাজ শুরু করতে পারেন।

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

/*
 * displays buffer when fence is signaled.  returns immediately with a fence
 * that signals when buffer is no longer displayed.
 */
struct sync_fence* display_buffer(struct dma_buf *buffer, struct sync_fence
*fence);

সিঙ্ক ইন্টিগ্রেশন

এই বিভাগে ব্যাখ্যা করা হয়েছে যে কীভাবে কার্নেল-স্পেস সিঙ্ক ফ্রেমওয়ার্ককে Android ফ্রেমওয়ার্কের ইউজারস্পেস পার্ট এবং একে অপরের সাথে যোগাযোগ করতে হবে এমন ড্রাইভারের সাথে ইন্টিগ্রেট করতে হয়। কার্নেল-স্পেস অবজেক্টকে ইউজারস্পেসে ফাইল ডেসক্রিপটর হিসেবে দেখানো হয়।

ইন্টিগ্রেশন কনভেনশন

Android HAL ইন্টারফেস কনভেনশন অনুসরণ করুন:

  • API যদি এমন কোনও ফাইল ডেসক্রিপটর প্রদান করে যা sync_pt-কে রেফার করে, তাহলে API ব্যবহার করে ভেন্ডরের ড্রাইভার বা HAL-কে অবশ্যই ফাইল ডেসক্রিপটর বন্ধ করতে হবে।
  • ভেন্ডর ড্রাইভার বা HAL যদি কোনও API ফাংশনে sync_pt সহ একটি ফাইল ডেসক্রিপ্টর পাস করে, তাহলে ভেন্ডর ড্রাইভার বা HAL অবশ্যই ফাইল ডেসক্রিপ্টরটি বন্ধ করবে না।
  • ফেন্স ফাইল ডেসক্রিপটর ব্যবহার করা চালিয়ে যেতে, ভেন্ডর ড্রাইভার বা HAL-কে অবশ্যই ডেসক্রিপটর ডুপ্লিকেট করতে হবে।

BufferQueue-এর মধ্য দিয়ে যাওয়ার সময় প্রতিবারই একটি ফেন্স অবজেক্টের নাম পরিবর্তন করা হয়। কার্নেল ফেন্স সাপোর্ট ফেন্সের নাম স্ট্রিং হিসেবে রাখার অনুমতি দেয়, তাই সিঙ্ক ফ্রেমওয়ার্ক উইন্ডোর নাম ও বাফার ইনডেক্স ব্যবহার করে যা ফেন্সের নাম দেওয়ার জন্য সারিবদ্ধ করা হচ্ছে, যেমন SurfaceView:0। এটি ডেডলকের সোর্স শনাক্ত করার জন্য ডিবাগিংয়ের ক্ষেত্রে সহায়ক কারণ নামগুলি /d/sync-এর আউটপুট এবং ত্রুটির প্রতিবেদনে দেখা যায়।

ANativeWindow ইন্টিগ্রেশন

ANativeWindow-এ ফেন্স সংক্রান্ত তথ্য আছে। dequeueBuffer, queueBuffer ও cancelBuffer-এর ফেঞ্চ প্যারামিটার আছে।

OpenGL ES ইন্টিগ্রেশন

OpenGL ES সিঙ্ক ইন্টিগ্রেশন দুটি EGL এক্সটেনশনের উপর নির্ভর করে:

  • EGL_ANDROID_native_fence_sync, EGLSyncKHR অবজেক্টে নেটিভ Android ফেন্স ফাইল ডেসক্রিপ্টর র‍্যাপ বা তৈরি করার একটি উপায় প্রদান করে।
  • EGL_ANDROID_wait_sync CPU-সাইডের পরিবর্তে GPU-সাইড স্টল করার অনুমতি দেয় যার ফলে GPU-কে EGLSyncKHR-এর জন্য অপেক্ষা করতে হয়। EGL_ANDROID_wait_sync এক্সটেনশনটি EGL_KHR_wait_sync এক্সটেনশনের মতোই।

এইসব এক্সটেনশন আলাদা আলাদাভাবে ব্যবহার করতে, সংশ্লিষ্ট কার্নেল সহায়তার সাথে EGL_ANDROID_native_fence_sync এক্সটেনশন প্রয়োগ করুন। এরপর, আপনার ড্রাইভে EGL_ANDROID_wait_sync এক্সটেনশন চালু করুন। এক্সটেনশনে EGL_ANDROID_native_fence_sync আলাদা নেটিভ ফেন্স EGLSyncKHR অবজেক্ট টাইপ থাকে। এর ফলে, আগে থেকে থাকা EGLSyncKHR অবজেক্টের ধরনের ক্ষেত্রে প্রযোজ্য এক্সটেনশন EGL_ANDROID_native_fence অবজেক্টের ক্ষেত্রে প্রযোজ্য নাও হতে পারে, এর ফলে অবাঞ্ছিত ইন্টার‍্যাকশন এড়ানো যায়।

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

  • সঠিক ফেন্স ফাইল ডেসক্রিপ্টর একটি EGLSyncKHR অবজেক্টে আগে থেকে থাকা নেটিভ Android ফেন্স ফাইল ডেসক্রিপ্টরকে র‍্যাপ করে।
  • -1, EGLSyncKHR অবজেক্ট থেকে একটি নেটিভ Android ফেন্স ফাইল ডেসক্রিপটর তৈরি করে।

নেটিভ Android ফেঞ্চ ফাইল ডেসক্রিপ্টর থেকে EGLSyncKHR অবজেক্ট এক্সট্র্যাক্ট করতে DupNativeFenceFD() ফাংশন কল ব্যবহার করুন। এটি সেট করা অ্যাট্রিবিউট কোয়েরি করার মতো একই ফলাফল দেয়, কিন্তু প্রাপক যে ফেন্স বন্ধ করে দেন সেই কনভেনশন মেনে চলে (তাই ডুপ্লিকেট অপারেশন)। অবশেষে, EGLSyncKHR অবজেক্ট ধ্বংস করলে ইন্টার্নাল ফেন্স অ্যাট্রিবিউট বন্ধ হয়ে যায়।

হার্ডওয়্যার কম্পোজার ইন্টিগ্রেশন

HWC তিন ধরনের সিঙ্ক ফেন্স ম্যানেজ করে:

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