זיהוי של ממשק API לעיבוד משחקים ב-Vulkan לעומת OpenGL ES

במהלך פיתוח או אופטימיזציה של משחקי Android, יכול להיות שיהיה לכם שימושי להבין באיזה צינור גרפי המנוע שלכם משתמש. מנועים עשויים לבחור ב-Vulkan או ב-GLES בלי אותות ברורים שנגישים למפתחים. לצערנו, יש מצבים שבהם אי אפשר להסתמך על logcat כדי לוודא שמשחק פועל ב-Vulkan או שהוא עבר באופן אוטומטי ל-OpenGL ES.

במדריך הזה נסביר איך להשתמש ב-Android Performance Analyzer‏ (APA) ובשאילתות SQL מותאמות אישית של Perfetto כדי לזהות באופן חד-משמעי את API העיבוד הפעיל של משחק.

המגבלות של אימות מבוסס-יומן

  • יומנים שמוסרים מהם פרטים: בדרך כלל, בגרסאות build של מוצרים מוסתרים פרטים על טביעות רגל של אתחול וטעינת מנהלי התקנים.
  • תוצאות חיוביות שגויות: חלק ממנועי המשחקים טוענים ספריות של Vulkan ו-OpenGL ES במהלך ההפעלה, ומדפיסים יומני אתחול לשניהם, גם אם בסופו של דבר אחד מהם נכשל ומפעיל חזרה לגרסה קודמת.
  • חזרה שקטה למצב קודם: אם אתחול Vulkan נכשל בגלל בעיות מנהל התקן ספציפיות למכשיר, מנועים חוזרים לעיתים קרובות ל-OpenGL ES בלי להציג שגיאות קריטיות.

מדידה באמצעות APA

באמצעות Android Performance Analyzer, אפשר לתעד מעקב אחר המערכת ולנתח במדויק נתוני פריימים באמצעות שאילתות SQL. כדי למדוד את השימוש ב-Vulkan וב-GLES, צריך לבצע את השלבים הבאים:

  1. לכידת העקבות באמצעות APA: מריצים את המשחק ומשתמשים ב-APA כדי ללכוד עקבות של המערכת במהלך הפלח שרוצים לנתח, למשל נקודה במהלך המשחק שבה יש חשד לירידה בקצב הפריימים. אחרי שהמכשיר מחובר וההקלטה של המעקב מסתיימת, נתוני המעקב נטענים בממשק של APA.

  2. לוחצים על הכרטיסייה SQL ב-APA: כשמסך ניתוח העקבות פתוח, בתפריט הניווט של ממשק המשתמש, לוחצים על הכרטיסייה SQL כדי לפתוח את סביבת מעבד העקבות, שבה אפשר להריץ שאילתות על הנתונים ישירות.

  3. מדביקים את שאילתת ה-SQL הבאה בכרטיסייה APA SQL: מעתיקים את שאילתת ה-SQL הבאה ומדביקים אותה בשדה להזנת קלט של השאילתה. השאילתה הזו סורקת את ה-trace כדי למצוא אירועים של API לציור, כמו eglSwapBuffers, QueuePresentKHR ו-vkQueuePresentKHR. הוא מקבץ אותם לפי שם התהליך ומחשב את מספר קריאות ה-API של הרינדור ואת אחוז ההתפלגות של Vulkan לעומת קריאות הרינדור של OpenGL ES:

    WITH raw_slices AS (
      -- 1. Map each slice (API call) to its corresponding process or package via UTID and UPID
      SELECT
        p.name AS process_name,
        s.name AS slice_name
      FROM slice s
      JOIN thread_track tt ON s.track_id = tt.id
      JOIN thread t USING (utid)
      JOIN process p USING (upid)
      WHERE (s.name LIKE 'eglSwapBuffers%'
        OR s.name IN ('QueuePresentKHR', 'vkQueuePresentKHR'))
        -- Optional: To isolate your game, uncomment the following and filter by package name and thread name:
        -- AND p.name = 'com.example.mygame'
        -- AND t.name = 'RenderThread'
    ),
    process_stats AS (
      -- 2. Aggregate counts per individual process
      SELECT
        process_name,
        SUM(CASE WHEN slice_name LIKE 'eglSwapBuffers%' THEN 1 ELSE 0 END) AS egl_count,
        SUM(CASE WHEN slice_name IN ('QueuePresentKHR', 'vkQueuePresentKHR') THEN 1 ELSE 0 END) AS vulkan_count
      FROM raw_slices
      GROUP BY process_name
    ),
    process_totals AS (
      -- 3. Calculate total counts for denominator calculation
      SELECT
        process_name,
        egl_count,
        vulkan_count,
        (egl_count + vulkan_count) AS total_count
      FROM process_stats
    )
    -- 4. Calculate final percentage shares per row, preventing division by zero errors
    SELECT
      process_name,
      egl_count,
      vulkan_count,
      total_count,
      ROUND(CAST(egl_count AS REAL) * 100 / NULLIF(total_count, 0), 2) AS "egl_percentage(%)",
      ROUND(CAST(vulkan_count AS REAL) * 100 / NULLIF(total_count, 0), 2) AS "vulkan_percentage(%)"
    FROM process_totals
    ORDER BY total_count DESC;
    
  4. להריץ את השאילתה: לוחצים על הלחצן Run Query ליד שדה להזנת קלט. אחרי הרצת השאילתה, מופיעה בחלונית התוצאות טבלה שבה מוצגים שם התהליך (process_name), מספר הפעמים שנעשה שימוש ב-OpenGL ES (‏egl_count), מספר הפעמים שנעשה שימוש ב-Vulkan (‏vulkan_count), המספר הכולל של הפעמים שנעשה שימוש ב-API (‏total_count) ואחוז השימוש בכל API (‏egl_percentage(%) ו-vulkan_percentage(%)).

    צילום מסך שבו מוצגת שאילתת ה-SQL שהופעלה ומדדי ה-API של הרינדור שמוצגים בטבלה

בעיות נפוצות

  • כדי למנוע SurfaceFlinger בלבול: תמיד צריך לצמצם את היקף החיפוש לשרשור האפליקציה של המשחק (RenderThread). תהליכי קומפוזיטור ברמת המערכת, כמו SurfaceFlinger, עשויים להציג רצועות של Vulkan או EGL שמייצגות עיבוד של ממשק המשתמש של המערכת, ולא את צינור העיבוד הפנימי של המשחק. כדי לבודד את המשחק, מבטלים את ההערה של המסננים האופציונליים במשפט WHERE של שאילתת ה-SQL הראשית ומחליפים את 'com.example.mygame' בשם החבילה של המשחק:

    -- AND p.name = 'com.example.mygame'
    -- AND t.name = 'RenderThread'
    
  • תקופת חימום: תמיד צריך להקליט את ה-trace אחרי שהסצנה התלת-ממדית הראשית של המשחק נטענה במלואה. צילום מסך במהלך מסכי פתיחה או מעברים של טעינה עלול להוביל לאתחולים מטעים.

הדרישות לגבי מעקב אחר פטורים בתוכנית LevelUp

אם אתם משתמשים ב-Android Performance Analyzer ‏ (APA) כדי ללכוד נתוני מעקב ולעמוד בדרישות לקבלת פטור מ-LevelUp ב-Google Play Games, יש דרישות חומרה ספציפיות שצריך לעמוד בהן כדי שנתוני המעקב יהיו תקפים.

מומלץ מאוד לתעד את הנתונים באמצעות אחד ממכשירי הייחוס של Level Up.

בנוסף, כדי לוודא שהאימות מדויק, אסור ליצור את ה-trace במכשיר שמשתמש במעבד גרפי מסוג ANGLE. באופן ספציפי, אי אפשר להשתמש במכשירים הבאים כדי לצלם את עקבות הפטור מ-LevelUp:

  • כל מכשיר שבו ספק ה-GPU הוא SLSI (סמסונג), שמשתמש ב-GPU מסוג AMD Xclipse
  • ‫Pixel 11