วิธีแก้ปัญหาสำหรับการสูญเสียบริบท OpenGL เมื่อ Android หยุดชั่วคราว


40

เอกสาร Android พูดว่า:

มีสถานการณ์ที่บริบทการแสดงผล EGL จะหายไป สิ่งนี้มักจะเกิดขึ้นเมื่ออุปกรณ์ตื่นนอนหลังจากเข้านอน เมื่อบริบท EGL หายไปทรัพยากร OpenGL ทั้งหมด (เช่นพื้นผิว) ที่เชื่อมโยงกับบริบทนั้นจะถูกลบโดยอัตโนมัติ เพื่อให้การเรนเดอร์เป็นไปอย่างถูกต้อง renderer ต้องสร้างรีซอร์สที่สูญหายซึ่งยังคงต้องการอยู่ วิธี onSurfaceCreated (GL10, EGLConfig) เป็นสถานที่ที่สะดวกในการทำเช่นนี้

แต่การต้องโหลดพื้นผิวทั้งหมดในบริบท OpenGL นั้นเป็นทั้งความเจ็บปวดและเจ็บประสบการณ์การเล่นเกมของผู้ใช้เมื่อเข้าสู่แอพอีกครั้งหลังจากหยุดชั่วคราว ฉันรู้ว่า "Angry Birds" จะหลีกเลี่ยงสิ่งนี้ฉันกำลังมองหาคำแนะนำเกี่ยวกับวิธีการทำเช่นเดียวกัน?

ฉันกำลังทำงานกับ Android NDK r5 (รุ่น CrystaX) ฉันพบแฮ็คที่เป็นไปได้ในปัญหานี้ แต่ฉันพยายามหลีกเลี่ยงการสร้าง SDK แบบกำหนดเองทั้งหมด


การนอนหลับและตื่นขึ้นก็อ้างถึงอุปกรณ์ดังนั้นในขณะที่ผู้ใช้เพียงแค่หยุดเกมของคุณชั่วคราวหรือเปลี่ยนกระบวนการมันควรจะหลวมบริบท EGL
Ali1S232

คำตอบ:


22

Replica Island มีรุ่นแก้ไข GLSurfaceView ที่เกี่ยวข้องกับปัญหานี้ (และทำงานได้กับ Android รุ่นก่อนหน้า) ตามที่Chris Pruett :

โดยทั่วไปฉันแฮ็กอัล GLSurfaceView ดั้งเดิมเพื่อแก้ไขปัญหาที่เฉพาะเจาะจงมาก: ฉันต้องการไปที่กิจกรรมต่าง ๆ ภายในแอพของฉันโดยไม่ละทิ้งสถานะ OpenGL ทั้งหมดของฉัน การเปลี่ยนแปลงที่สำคัญคือการแยก EGLS พื้นผิวออกจาก EGLContext และเพื่อละทิ้งอดีตที่อยู่ห่างออกไปบน Pause () แต่เก็บไว้ที่หลังจนกว่าบริบทจะหายไปอย่างชัดเจน การใช้งานเริ่มต้นของ GLSurfaceView (ซึ่งฉันไม่ได้เขียน) จะโยนสถานะ GL ทั้งหมดออกไปเมื่อกิจกรรมถูกหยุดชั่วคราวและเรียกใช้งานบนurururCreated () เมื่อดำเนินการต่อ นั่นหมายความว่าเมื่อกล่องโต้ตอบโผล่ขึ้นมาในเกมของฉันการปิดมันทำให้เกิดความล่าช้าเนื่องจากพื้นผิวทั้งหมดต้องถูกโหลดใหม่

คุณควรใช้ GLSurfaceView ที่เป็นค่าเริ่มต้น หากคุณต้องมีฟังก์ชั่นเดียวกับที่มีอยู่คุณสามารถดูได้ที่ของฉัน แต่ทำในสิ่งที่ฉันได้สัมผัสข้อผิดพลาดของไดรเวอร์ที่น่ากลัวในโทรศัพท์มือถือบางรุ่น (ดูความคิดเห็นที่ยาวมาก ๆ ใกล้กับจุดสิ้นสุดของไฟล์นั้น) และคุณสามารถหลีกเลี่ยงความยุ่งเหยิงทั้งหมดได้เพียงแค่ใช้ค่าเริ่มต้น

แก้ไข: ฉันเพิ่งรู้ว่าคุณโพสต์ลิงก์ไปยังแฮ็คที่คล้ายกันแล้ว ฉันไม่คิดว่าจะมีวิธีแก้ปัญหาใด ๆ ในตัวก่อนรวงผึ้ง Replica Island เป็นเกมยอดนิยมที่ใช้งานได้กับอุปกรณ์หลายชนิดและคุณอาจพบว่าการใช้งานและความคิดเห็นของ Chris มีประโยชน์


1
หลังจากลองใช้วิธีการต่าง ๆ เพื่อหลีกเลี่ยงปัญหานี้ฉันตัดสินใจว่าทางออกที่ดีที่สุดคือเพียงแค่ทำการรีแอพใหม่เพื่อสร้างบริบทขึ้นมาใหม่ นี่เป็นวิธีที่สิ้นเปลือง แต่ดูเหมือนว่าจะไม่มีทางออกใด ๆ ที่ดีcode.google.com/p/android/issues/detail?id=12774
Nick Gotch

9

ฉันต้องการเพิ่มคำตอบอีกครั้งสำหรับเรื่องนี้ที่ส่งผ่านมาให้ฉันหนึ่งหรือสองปีโดย Chris Pruett (เกาะ Replica, Wind-Up Knight, ฯลฯ ) มีประโยชน์อย่างยิ่งที่นี่ในปี 2013 เนื่องจาก setPreserveEglContextOnPause (จริง) ดูเหมือนจะใช้ไม่ได้กับ 4.3 (ฉันอาจจะผิดเกี่ยวกับเรื่องนี้ แต่นั่นเป็นลักษณะที่ฉันในขณะนี้เมื่อฉันอัปเดตรหัสเกมที่สัมผัสล่าสุดในปี 2011)

โดยทั่วไปเคล็ดลับคือการแยก GLSurfaceView ของคุณออกจากลำดับชั้นการดูจาก onPause () ของกิจกรรมของคุณ เนื่องจากไม่ได้อยู่ในลำดับชั้นการดู ณ จุด onPause () ที่ทำงานบริบทจะไม่ถูกทำลาย

ดังนั้นกิจกรรมของคุณ onPause () ควรมีลักษณะดังนี้:

@Override
public void onPause() {
    view.setVisibility(View.GONE);
    super.onPause();
    ...
}

และคุณกู้คืน GLSurfaceView เป็นลำดับชั้นไม่ใช่จาก onResume () แต่จาก onWindowFocusChanged ():

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    if (hasFocus && view.getVisibility() == View.GONE) {
         view.setVisibility(View.VISIBLE);
    }
    ...
}

โปรดทราบว่าคุณไม่เคยเรียกใช้ onPause () และ onResume () ของ GLSurfaceView และนี่เป็น SDK อย่างเป็นทางการของ GLSurfaceView ไม่จำเป็นต้องมีรุ่นทดแทนอื่น ๆ


ในความเป็นจริงวิธีการนี้ดูเหมือนจะไม่ทำงาน Chris Pruett ใช้ร่วมกับ Unity เป็นไปได้ไหมที่วิธีแก้ปัญหานี้ไม่ทำงานในโปรเจคท้องถิ่น แต่ไม่เรียก GLView.onPause () ดูเหมือนว่าจะใช้งานได้! มีคนอื่นที่สามารถยืนยันสิ่งนี้ได้หรือไม่?
sjkm

มันใช้งานได้สำหรับฉันกำหนดเป้าหมายที่ Android 2.2 OpenGl ES 2 ไม่แน่ใจว่ามันทำงานบนอุปกรณ์อื่นได้อย่างไร ฉันมีโทรศัพท์ LG G2 D802 ไม่มีใครรู้ว่านี่เป็นทางออกทั่วไปหรือไม่?
Pixel

7

<พูดจาโผงผาง> ฉันใช้เวลาจำนวนมากกับปัญหานี้ฉันลองใช้วิธีแก้ปัญหาที่แตกต่างกันมากมายและไม่มีใครทำงานมาจนถึงทุกวันนี้ฉันคิดว่านี่เป็นหนึ่งในการตัดสินใจออกแบบที่แย่ที่สุดที่ฉันเคยเห็น แต่มาจากทีม Android ที่ฉันไม่ แปลกใจจริงๆ </ คุยโว>

ดังนั้นทางออกคือการย้ายสมาชิก eglContext ขึ้นไปและทำให้มันคงที่ (ทั่วโลก) ดังนั้นมันจะไม่ถูกทำลายจากนั้นคุณเพียงแค่ต้องตรวจสอบว่ามันเป็นโมฆะหรือไม่ก่อนที่จะสร้างมันอีกครั้ง

จนถึงขณะนี้โซลูชันนี้ใช้งานได้สำหรับเราและเราไม่สนใจว่าจะใช้งานกับอุปกรณ์ 2005 ได้หรือไม่


4

ใช้ honeycomb API มีตัวเลือกที่จะรักษาบริบท OGL ของคุณ มิฉะนั้นคุณจะต้องโหลดบริบทของคุณใหม่ ไม่ยากหรือเจ็บปวด

คุณต้องเข้าใจว่ามีสองกรณี (Android 2.1):

  • Screen Pause: แอปพลิเคชันของคุณจะมีการแฮ็กหน้าหนึ่ง => พร้อมเสมอ
  • แอปพลิเคชันหยุดชั่วคราว: มีแอปพลิเคชั่นด้านหน้าอื่น => ไม่มีวิธีแก้ไข

หมายเหตุ: android gpus รุ่นเก่าไม่รองรับหลายบริบท ดังนั้นบริบท opengl จะหายไปเมื่อคุณเปลี่ยนไปใช้แอปพลิเคชันอื่น => ไม่มีวิธีแก้ปัญหา (คุณสามารถแฮ็กเพื่อรักษาบริบทของคุณบนหน้าจอหยุดชั่วคราว)

หมายเหตุ 2: ฟังก์ชัน HoneyComb คือ setPreserveEGLContextOnPause


1
ฉันกำลังย้ายเกม C ++ ไปยัง Android NDK ซึ่งไม่ได้ออกแบบมาเพื่อโหลดบริบทอย่างง่ายดายดังนั้นอย่างน้อยสำหรับฉันมันค่อนข้างยาก ความยากลำบากกันการโหลดพื้นผิวจะแนะนำความล่าช้าซึ่งไม่ปรากฏบนอุปกรณ์อื่น ๆ ของเรา (iPhone, PSP, DS, ฯลฯ ) ดีใจที่ได้ยินรังผึ้งแก้ไขปัญหานี้ แต่น่าเสียดายที่เราต้องสนับสนุน 2.1+
นิก Gotch

1
นี่ไม่ได้ตอบคำถามของเขาเลย
notlesh

1
หากคุณไม่เข้าใจคุณจะทำไม่ได้
Ellis

2

คำตอบบางส่วนของที่นี่มีความเหมาะสมสำหรับการใช้ OpenGL ES ในช่วงต้น อุปกรณ์ GLES แรกรองรับบริบทเดียวเท่านั้นดังนั้น GLSurfaceView ได้รับการออกแบบเพื่อละทิ้งสถานะที่ก้าวร้าว การโน้มน้าวใจ GLSurfaceView ให้ทำอย่างอื่นไม่ใช่เรื่องง่าย

สำหรับ Android รุ่นล่าสุด (อาจเป็นอะไรก็ได้ที่ใช้ GLES 2.x) คำตอบที่ดีที่สุดคือการใช้ SurfaceView แบบธรรมดาและจัดการ EGL และเธรดของคุณเอง คุณสามารถค้นหาตัวอย่างหลายตัวอย่างของ GLES ที่ใช้กับ SurfaceView แบบธรรมดาในGrafikaรวมถึงไลบรารีของคลาสแบบง่ายสำหรับการสร้างและทำลายบริบท EGL

มันเป็นแนวปฏิบัติที่ดีในการยกเลิกการโหลดสถานะเมื่อแอปเข้าสู่พื้นหลัง แต่สำหรับตัวอย่างจาก Chris Pruett - ที่แอปยังอยู่ในเบื้องหน้า แต่กิจกรรมที่โฮสต์ GLSurfaceView ถูกเปลี่ยนจาก - ไม่มีค่าในการฉีกขาด ตามบริบท

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.