স্বয়ংচালিত প্রদর্শন প্রক্সি পরিষেবা

এই সাধারণ কাঠামো পরিষেবা বিক্রেতা প্রক্রিয়াগুলিকে libgui লিঙ্ক না করে HAL বাস্তবায়নে SurfaceFlinger/EGL ব্যবহার করতে দেয়। AOSP এই পরিষেবার ডিফল্ট বাস্তবায়ন প্রদান করে, যা সম্পূর্ণরূপে কার্যকরী। যাইহোক, বিক্রেতাকে অবশ্যই তাদের প্ল্যাটফর্মে এই পরিষেবাটি প্রদানের জন্য APIs প্রয়োগ করতে হবে।

package android.frameworks.automotive.display@1.0;

import android.hardware.graphics.bufferqueue@2.0::IGraphicBufferProducer;

interface IAutomotiveDisplayProxyService {
    /**
     * Gets an IGraphicBufferProducer instance from the service.
     *
     * @param  id   Target's stable display identifier
     *
     * @return igbp Returns an IGraphicBufferProducer object, that can be
     *              converted to an ANativeWindow object.
     */
    getIGraphicBufferProducer(uint64_t id) generates (IGraphicBufferProducer igbp);

    /**
     * Sets the ANativeWindow, which is associated with the
     * IGraphicBufferProducer, to be visible and to take over the display.
     *
     * @param  id      Target display ID
     *
     * @return success Returns true on success.
     */
    showWindow(uint64_t id) generates (bool success);

    /**
     * Sets the ANativeWindow, which is associated with the
     * IGraphicBufferProducer, to be invisible and to release the control
     * over display.
     *
     * @param  id      Target display ID
     *
     * @return success Returns true on success.
     */
    hideWindow(uint64_t id) generates (bool success);

    /**
     * Returns the stable identifiers of all available displays.
     *
     * @return ids A list of stable display identifiers.
     */
    getDisplayIdList() generates (vec<uint64_t> ids);

    /**
     * Returns the descriptor of the target display.
     *
     * @param  id    Stable ID of a target display.
     * @return cfg   DisplayConfig of the active display.
     * @return state Current state of the active display.
     */
    getDisplayInfo(uint64_t id) generates (HwDisplayConfig cfg, HwDisplayState state);
}

এই পরিষেবাটি ব্যবহার করতে:

  1. IAutomotiveDisplayProxyService পান।
    android::sp<IAutomotiveDisplayProxyService> windowProxyService =
        IAutomotiveDisplayProxyService::getService("default");
    if (windowProxyService == nullptr) {
        LOG(ERROR) << "Cannot use AutomotiveDisplayProxyService. Exiting.";
        return 1;
    }
  2. রেজোলিউশন নির্ধারণ করতে পরিষেবা থেকে একটি সক্রিয় প্রদর্শন তথ্য পুনরুদ্ধার করুন।
    // We use the first display in the list as the primary.
    pWindowProxy->getDisplayInfo(displayId, [this](auto dpyConfig, auto dpyState) {
        DisplayConfig *pConfig = (DisplayConfig*)dpyConfig.data();
        mWidth = pConfig->resolution.getWidth();
        mHeight = pConfig->resolution.getHeight();
    
        ui::DisplayState* pState = (ui::DisplayState*)dpyState.data();
        if (pState->orientation != ui::ROTATION_0 &&
            pState->orientation != ui::ROTATION_180) {
            // rotate
            std::swap(mWidth, mHeight);
        }
    
        LOG(DEBUG) << "Display resolution is " << mWidth << " x " << mHeight;
    });
  3. IAutomotiveDisplayProxyService থেকে একটি হার্ডওয়্যার IGraphicBufferProducer (বা, HIDL GraphicBufferProducer (HGBP) পুনরুদ্ধার করুন:
    mGfxBufferProducer = pWindowProxy->getIGraphicBufferProducer(displayId);
    if (mGfxBufferProducer == nullptr) {
        LOG(ERROR) << "Failed to get IGraphicBufferProducer from "
                   << "IAutomotiveDisplayProxyService.";
        return false;
    }
  4. API libbufferqueueconverter ব্যবহার করে একটি পুনরুদ্ধার করা HGBP থেকে একটি SurfaceHolder পান:
    mSurfaceHolder = getSurfaceFromHGBP(mGfxBufferProducer);
    if (mSurfaceHolder == nullptr) {
        LOG(ERROR) << "Failed to get a Surface from HGBP.";
        return false;
    }
  5. API libbufferqueueconverter ব্যবহার করে একটি SurfaceHolder একটি নেটিভ উইন্ডোতে রূপান্তর করুন:
    mWindow = getNativeWindow(mSurfaceHolder.get());
    if (mWindow == nullptr) {
        LOG(ERROR) << "Failed to get a native window from Surface.";
        return false;
    }
  6. একটি নেটিভ উইন্ডো সহ একটি EGL উইন্ডো পৃষ্ঠ তৈরি করুন এবং তারপর রেন্ডার করুন:
    // Set up our OpenGL ES context associated with the default display
    mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    if (mDisplay == EGL_NO_DISPLAY) {
        LOG(ERROR) << "Failed to get egl display";
        return false;
    }
    ...
    
    // Create the EGL render target surface
    mSurface = eglCreateWindowSurface(mDisplay, egl_config, mWindow, nullptr);
    if (mSurface == EGL_NO_SURFACE) {
        LOG(ERROR) << "eglCreateWindowSurface failed.";
        return false;
    }
    ...
  7. স্ক্রিনে রেন্ডার করা দৃশ্য প্রদর্শন করতে IAutomotiveDisplayProxyService::showWindow() কল করুন। এই পরিষেবাটির সর্বোচ্চ অগ্রাধিকার রয়েছে এবং তাই, সর্বদা বর্তমান মালিকের কাছ থেকে পর্দার নিয়ন্ত্রণ নেয়:
    mAutomotiveDisplayProxyService->showWindow();

আরো বাস্তবায়নের বিশদ বিবরণের জন্য $ANDROID_BUILD_TOP/packages/services/Car/evs/sampleDriver/service.cpp এবং GlWrapper.cpp দেখুন।

একটি EVS HAL বাস্তবায়নের জন্য নিচের বোল্ডে প্রদর্শিত অতিরিক্ত লাইব্রেরি প্রয়োজন।

cc_binary {
    name: "android.hardware.automotive.evs@1.1-sample",

    vendor: true,

    srcs: [
        ...
    ],

    shared_libs: [
        ...
        "libbufferqueueconverter",
        "android.hidl.token@1.0-utils",
        "android.frameworks.automotive.display@1.0",
        "android.hardware.graphics.bufferqueue@1.0",
        "android.hardware.graphics.bufferqueue@2.0",
    ],

মাল্টি-ডিসপ্লে সমর্থন

ডিভাইস গণনা প্রদর্শন এবং প্রদর্শন তথ্য পুনরুদ্ধার

ক্যামেরা ডিভাইস গণনার মতো, EVS ফ্রেমওয়ার্ক উপলব্ধ প্রদর্শনগুলি গণনা করার একটি পদ্ধতি প্রদান করে। স্ট্যাটিক ডিসপ্লে আইডেন্টিফায়ার একটি টাইপ-লং আইডেন্টিফায়ার, নিচের বাইটে ডিসপ্লে পোর্টের তথ্য এবং উপরের বিটে Extended Display IDentification Data এনকোড করে। IAutomotiveDisplayProxyService::getDisplayIdList() ভৌত স্থানীয় ডিসপ্লেগুলির ডিসপ্লে আইডিগুলির একটি তালিকা প্রদান করে, যেগুলি EVS পরিষেবাতে উপলব্ধ, এবং IEvsEnumerator::getDisplayIdList() ডিসপ্লে পোর্টগুলির একটি তালিকা প্রদান করে যা সনাক্ত করা ডিসপ্লেগুলির সাথে সংযুক্ত রয়েছে৷ তালিকার প্রথম আইডি সর্বদা প্রাথমিক প্রদর্শনের হয়।

interface IEvsEnumerator extends @1.0::IEvsEnumerator {
    ...
    /**
     * Returns a list of all EVS displays available to the system
     *
     * @return displayIds Identifiers of available displays.
     */
    getDisplayIdList() generates (vec<uint8_t> displayIds);
};

টার্গেট ডিসপ্লে ডিভাইস খুলুন

EVS অ্যাপটি একটি টার্গেট ডিসপ্লে পোর্ট নম্বর সহ IEvsEnumerator::openDisplay_1_1() কল করে:

android::sp<IEvsDisplay> pDisplay = pEvs->openDisplay_1_1(displayId);
if (pDisplay.get() == nullptr) {
    LOG(ERROR) << "EVS Display unavailable. Exiting.";
    return 1;
}

দ্রষ্টব্য: এক সময়ে শুধুমাত্র একটি একক ডিসপ্লে ব্যবহার করা যেতে পারে, যার মানে বর্তমান EVS ক্লায়েন্ট তার ডিসপ্লে হারায় যখন অন্য EVS ক্লায়েন্ট ডিসপ্লে খোলার অনুরোধ করে, এমনকি যখন তারা একই না হয়।