เอกสารนี้จะแสดงวิธีเพิ่มประสิทธิภาพของเกมโดยใช้เครื่องมือเพื่อระบุและแก้ไขจุดคอขวดของ CPU และ GPU
การเพิ่มประสิทธิภาพ CPU
หากการวิเคราะห์แสดงให้เห็นว่าเกมขึ้นอยู่กับ CPU คุณจะต้องตรวจสอบเพิ่มเติม ซึ่งต้องระบุเธรดหรือ API ที่เฉพาะเจาะจงซึ่งทำให้เกิดคอขวด และลด FPS
โดยทั่วไปแล้ว โซลูชันแบบครอบจักรวาลมักไม่ได้ผลสำหรับการเพิ่มประสิทธิภาพ CPU แต่คุณต้องระบุปริมาณงานที่ต้องการมากที่สุดตามเกมหรือฉาก แล้ว จึงเพิ่มประสิทธิภาพตรรกะและฟังก์ชันที่เกี่ยวข้อง
เครื่องมือติดตามเวลาของเกมเอนจิน
เครื่องมือต่อไปนี้ช่วยในการวิเคราะห์นี้ได้
ข้อมูลเชิงลึกที่น่าเหลือเชื่อ
ภายในโปรเจ็กต์ Unreal Engine เครื่องมือ Unreal Insight จะช่วยในการวิเคราะห์ ข้อมูลการติดตามเวลาสำหรับแต่ละเธรดที่ประกอบกันเป็นเฟรม
ตัวอย่างเช่น โดยปกติแล้ว GameThread จะใช้สัดส่วนเวลา CPU มากที่สุด ซึ่งส่วนใหญ่เป็นผลมาจากเวลา Tick นอกจากนี้ งานที่เชื่อมโยงกับFActorComponentTickFunctionยังใช้เวลา Tick Time เป็นจำนวนมาก
การเพิ่มประสิทธิภาพ FActorComponentTick จำเป็นต้องยกเว้นการคำนวณและ
ใช้การคัดกรองสำหรับตัวละครและออบเจ็กต์ที่อยู่นอก
ขอบเขตการมองเห็นของกล้อง นอกจากนี้ การใช้ประโยชน์จากภาพเคลื่อนไหวตาม LOD (ระดับรายละเอียด)
ยังช่วยเพิ่มประสิทธิภาพได้อีกด้วย
Unity Profiler (Unity)
การวิเคราะห์โดยใช้ Unity Profiler แสดงให้เห็นว่า Main Thread ใช้เวลามากกว่า 45 มิลลิวินาที โดย PostLateUpdate.FinishFrameRendering ใช้เวลา 16.23 มิลลิวินาที ซึ่งทำให้เป็น การดำเนินการที่ใช้เวลานานที่สุด ภายในนี้ เราพบการเรียกใช้ Inl_RenderCameraStack หลายครั้ง ขอแนะนำให้ตรวจสอบความจำเป็น ของกล้องที่เปิดใช้และเพิ่มประสิทธิภาพตามความเหมาะสม
เครื่องมือสร้างโปรไฟล์ระดับระบบ
ใช้เครื่องมือการสร้างโปรไฟล์ต่อไปนี้
Perfetto
การใช้การติดตาม Perfetto จะช่วยให้คุณกำหนดการกำหนดแกน CPU และรายละเอียดการดำเนินการ ของแต่ละเธรดในอุปกรณ์ที่ใช้ Android ได้ ซึ่งช่วยให้คุณระบุ คอขวดด้านประสิทธิภาพได้โดยการวิเคราะห์ข้อมูลการดำเนินการของเธรด
กรณีค่าใช้จ่ายของ CPU
ร่องรอยระบุว่าภาระงานใน GameThread และ RenderThread ทำให้เกิดความล่าช้าใน QueuePresent ของ RHI Thread ซึ่งนำไปสู่สถานการณ์ที่ CPU ทำงานหนัก โดยอิงตาม VSync
กรณีค่าใช้จ่ายของ GPU
การติดตามระบุว่าการดำเนินการของ GPU เองใช้เวลาเกิน 25 มิลลิวินาที ซึ่งแสดงถึงสถานการณ์ที่ GPU เป็นตัวจำกัดประสิทธิภาพ
Simpleperf
หากต้องการระบุฟังก์ชันที่มีการใช้งาน CPU ปัจจุบันสูงสุด คุณสามารถใช้ simpleperf ได้ ขอแนะนำให้จัดเรียงฟังก์ชันเหล่านี้เพื่อจัดลำดับความสำคัญและแก้ไขฟังก์ชันที่มีการใช้งานสูงสุดก่อน เพื่อให้ได้ผลลัพธ์ที่ดีที่สุด
Simpleperf ช่วยให้คุณตรวจสอบข้อมูลเกี่ยวกับฟังก์ชันที่ใช้เวลา CPU มากที่สุดได้ หากต้องการ
เพิ่มประสิทธิภาพการใช้งาน CPU ให้เริ่มจากฟังก์ชันที่ใช้ CPU มากที่สุด ในตัวอย่างนี้ USkeletalMeshComponent ซึ่งเชื่อมโยงกับภาพเคลื่อนไหวใน ActorComponentTickFunctions ใช้ CPU มากที่สุด
การเพิ่มประสิทธิภาพ GPU
หากการวิเคราะห์แสดงให้เห็นว่าเกมขึ้นอยู่กับ GPU คุณจะต้องตรวจสอบเพิ่มเติม ซึ่งต้องใช้เครื่องมือและเทคนิคต่างๆ ในการเพิ่มประสิทธิภาพ GPU และการวิเคราะห์
หากต้องการเพิ่มประสิทธิภาพ GPU ให้ใช้เครื่องมือแก้ไขข้อบกพร่องของเฟรมเพื่อวิเคราะห์ไปป์ไลน์การแสดงผลและ การเรียกวาดสำหรับแต่ละฉาก นอกจากนี้ คุณต้องเข้าใจสถาปัตยกรรม GPU และลักษณะการทำงานของไปป์ไลน์อย่างละเอียดเพื่อระบุการดำเนินการที่ไม่จำเป็นหรือพื้นที่ที่ต้องเพิ่มประสิทธิภาพ
ส่วนต่อไปนี้จะอธิบายวิธีการและเครื่องมือสำหรับการเพิ่มประสิทธิภาพ GPU
กำจัด RenderPasses ที่ไม่จำเป็น
กำจัด Render Pass ที่ไม่จำเป็นเพื่อปรับปรุงประสิทธิภาพการแสดงผลและลดปริมาณงานของ GPU ซึ่งรวมถึงการส่งผ่านการแสดงผลที่ไม่มีการเรียกใช้การวาดหรือการส่งผ่านการแสดงผลที่ไม่ได้ใช้เอาต์พุตในเฟรมสุดท้าย
ใช้โปรแกรมแก้ไขข้อบกพร่องของ GPU เช่น RenderDoc เพื่อวิเคราะห์ไปป์ไลน์การแสดงผลและ
ระบุโอกาสในการเพิ่มประสิทธิภาพ
ไม่มีการเรียกใช้การวาด: ตรวจสอบว่าการส่งผ่านการแสดงผลมีการเรียกใช้การวาดหรือไม่ หากไม่มีการเรียกใช้การวาด ให้นำการส่งผ่านออก
เอาต์พุตที่ไม่ได้ใช้: ตรวจสอบว่าการส่งผ่านครั้งต่อๆ ไปเข้าถึงหรือแสดงเอาต์พุตของ Render Pass หรือไม่ เช่น สีหรือความลึก หากไม่ถูกต้อง ให้นำบัตรออก
บัตรที่ผสานได้: ระบุบัตรที่ผสานได้โดยทำดังนี้
- เฟรมบัฟเฟอร์หรือไฟล์แนบเดียวกัน
- การดำเนินการโหลดหรือจัดเก็บที่เข้ากันได้
- ไม่มีอุปสรรคด้านทรัพยากร Dependency ระหว่างกัน
ลดการโหลดหรือการดำเนินการของร้านค้า
การดำเนินการโหลดหรือจัดเก็บต้องใช้ทรัพยากรมากเนื่องจากใช้หน่วยความจำจำนวนมาก
ลดการดำเนินการโหลด-จัดเก็บที่ไม่จำเป็น ดำเนินการเหล่านี้เฉพาะเมื่อต้องใช้
ไฟล์แนบภายใน RenderPass หรือแทนที่ด้วยการดำเนินการ Clear หรือ Don't care เพื่อลดค่าใช้จ่าย
วิธีเพิ่มประสิทธิภาพ
ใช้โปรแกรมแก้ไขข้อบกพร่องของ GPU เช่น RenderDoc เพื่อวิเคราะห์ไปป์ไลน์การแสดงผลและ
ระบุโอกาสในการเพิ่มประสิทธิภาพต่อไปนี้
โหลด: หากไฟล์แนบของ Render Pass ไม่ได้ใช้ข้อมูลจาก Pass หรือไฟล์แนบก่อนหน้า ก็ไม่จำเป็นต้องดำเนินการโหลด ในกรณีดังกล่าว การใช้
Don't careหรือClearจะช่วยลดค่าใช้จ่ายได้Store: หากไม่ได้ใช้การแนบ Render Pass หลังจาก Render Pass ปัจจุบัน ก็ไม่จำเป็นต้องดำเนินการ Store ในกรณีดังกล่าว ให้ใช้
Don't careหรือClearแทนที่: พิจารณาว่าการตั้งค่าการโหลดหรือการจัดเก็บปัจจุบันสามารถแทนที่ด้วย
ClearหรือDon't Careโดยไม่ส่งผลกระทบต่อเฟรมสุดท้ายได้หรือไม่
หลีกเลี่ยงการทิ้งเพื่อเปิดใช้ Early-Z
Early-Z ช่วยปรับปรุงประสิทธิภาพบนแพลตฟอร์มอุปกรณ์เคลื่อนที่ อย่างไรก็ตาม discard
คำสั่งภายใน Shader จะปิดใช้ Early-Z โดยอัตโนมัติ หากdiscard
คำสั่งไม่จำเป็น ให้นำออก
การเร่งความเร็ว Early-Z
การเพิ่มประสิทธิภาพนี้ช่วยลดการทำงานของ Fragment Shader และปรับปรุง ประสิทธิภาพของ GPU ได้อย่างมาก
Early-Z การทดสอบความลึกและลายฉลุ
วิธีเพิ่มประสิทธิภาพ
ใช้โปรแกรมแก้ไขข้อบกพร่องของ GPU เช่น RenderDoc เพื่อวิเคราะห์ไปป์ไลน์การแสดงผลและ
ระบุโอกาสในการเพิ่มประสิทธิภาพต่อไปนี้
การใช้
discardใน Fragment Shader: คีย์เวิร์ดdiscardจะป้องกันไม่ให้ GPU ทำการทดสอบความลึกก่อนเวลาอันควร เนื่องจากไม่ทราบล่วงหน้าว่า Fragment จะมองเห็นได้หรือไม่การแก้ไข
gl_FragDepth: การแก้ไขgl_FragDepthแบบไดนามิกจะเปลี่ยนความลึกของเศษส่วน ซึ่งจะปิดใช้การเพิ่มประสิทธิภาพ Early-Z เนื่องจากไม่ทราบความลึกสุดท้ายก่อนการประมวลผลเศษส่วนเปิดใช้ Alpha-to-coverage: เมื่อเปิดใช้ Alpha-to-coverage (มักใช้ในการแสดงผล MSAA) ความครอบคลุมของเศษขึ้นอยู่กับค่า Alpha ซึ่งอาจ ทำให้การทดสอบความลึกช้าลงและปิดใช้ Early-Z
เพิ่มประสิทธิภาพรูปแบบพื้นผิว
การเลือกรูปแบบพื้นผิวที่เหมาะสมจะช่วยลดการใช้หน่วยความจำ เพิ่มประสิทธิภาพแบนด์วิดท์ และปรับปรุงประสิทธิภาพการแสดงผล การใช้รูปแบบที่มีความแม่นยำสูงเกินไปอาจทำให้สิ้นเปลืองทรัพยากร GPU โดยไม่ให้ข้อได้เปรียบด้านภาพ
วิธีเพิ่มประสิทธิภาพ
ใช้โปรแกรมแก้ไขข้อบกพร่องของ GPU เช่น RenderDoc เพื่อวิเคราะห์ไปป์ไลน์การแสดงผลและ
ระบุโอกาสในการเพิ่มประสิทธิภาพต่อไปนี้
- ใช้
D24S8แทนD32S8สำหรับบัฟเฟอร์ความลึกและสเตนซิล: การใช้D24S8สำหรับบัฟเฟอร์ความลึกและสเตนซิลจะช่วยลดการใช้หน่วยความจำลง 20% เมื่อเทียบกับD32S8โดยที่คุณภาพของภาพแทบไม่แตกต่างกันใน แอปพลิเคชันส่วนใหญ่ - ใช้การบีบอัด
ASTCสำหรับพื้นผิวสี: การบีบอัดASTCช่วยลดการใช้งานหน่วยความจำของพื้นผิวได้อย่างมาก โดยลดลงสูงสุด 8 เท่าเมื่อเทียบกับ รูปแบบที่ไม่ได้บีบอัด ในขณะที่ยังคงคุณภาพของภาพไว้สูง - ใช้รูปแบบ Half-Float แทน Full-Float: ใช้
R16FหรือRG16Fเพื่อ ลดแบนด์วิดท์ของหน่วยความจำและการใช้พื้นที่เก็บข้อมูล รูปแบบเหล่านี้เหมาะสำหรับบัฟเฟอร์หลังการประมวลผล
เพิ่มประสิทธิภาพความซับซ้อนของเรขาคณิต
การลดความซับซ้อนทางเรขาคณิตจะช่วยปรับปรุงประสิทธิภาพการแสดงผล โดยเฉพาะใน อุปกรณ์เคลื่อนที่ที่มีความสามารถของ GPU จำกัด ซึ่งรวมถึงการใช้จำนวนจุดยอดและสามเหลี่ยมที่ลดลง การรวมออบเจ็กต์เพื่อลดการเรียกการวาด และการกำจัดรูปทรงเรขาคณิตที่ไม่ได้เรนเดอร์หรือไม่จำเป็น เทคนิคต่างๆ เช่น การลดความซับซ้อนของตาข่าย ระดับรายละเอียด (LOD) และการคัดกรองฟรัสตัมหรือการคัดกรองการบดบังจะช่วย ลดปริมาณงานของ GPU และเพิ่มอัตราเฟรมได้อย่างมาก
วิธีเพิ่มประสิทธิภาพ
ใช้เครื่องมือการจัดทำโปรไฟล์และดีบักเกอร์ GPU เช่น RenderDoc, Android GPU
Inspector หรือเครื่องมือวิเคราะห์ประสิทธิภาพอื่นๆ เพื่อระบุคอขวดด้านประสิทธิภาพที่เกี่ยวข้องกับรูปทรง
ลดจำนวนสามเหลี่ยม: ลดการใช้รูปหลายเหลี่ยม โดยเฉพาะสำหรับวัตถุขนาดเล็กหรือวัตถุที่อยู่ไกล
ใช้ระดับรายละเอียด (LOD): ระบบจะใช้ Mesh ที่เรียบง่ายกว่าโดยอัตโนมัติตามระยะทางของกล้อง
ผสานรวม Mesh ขนาดเล็ก: รวมออบเจ็กต์แบบคงที่เพื่อลดการเรียกวาดและ ค่าใช้จ่ายของ CPU
การคัดกรองฟรัสตัมและการคัดกรองการบดบัง: หลีกเลี่ยงการแสดงผลออบเจ็กต์ที่อยู่นอกมุมมองหรือถูกองค์ประกอบอื่นๆ บดบัง
นำไฟล์แนบที่ไม่จำเป็นออก
ไฟล์แนบของ Render Pass (เช่น สี ความลึก สเตนซิล) จะใช้แบนด์วิดท์หน่วยความจำและทรัพยากร GPU แม้ว่าจะไม่ได้ใช้ก็ตาม การนำไฟล์แนบที่ไม่จำเป็นหรือซ้ำซ้อนออกจะช่วยปรับปรุงประสิทธิภาพและลดการใช้พลังงาน โดยเฉพาะในแพลตฟอร์มอุปกรณ์เคลื่อนที่
วิธีเพิ่มประสิทธิภาพ
ใช้เครื่องมือสร้างโปรไฟล์และดีบักเกอร์ GPU เช่น RenderDoc,
Android GPU Inspector หรือเครื่องมือวิเคราะห์ประสิทธิภาพอื่นๆ เพื่อระบุ
คอขวดด้านประสิทธิภาพที่เกี่ยวข้องกับรูปทรงเรขาคณิต
- ตรวจสอบการใช้งานจริง: มีการเรียก Draw หรือ Shader ที่เขียน หรืออ่านจาก Attachment หรือไม่
- วิเคราะห์เอาต์พุตเฟรม: ใช้
RenderDocหรือยูทิลิตีที่เทียบเท่าเพื่อ พิจารณาว่าไฟล์แนบมีส่วนทำให้เกิดรูปภาพสุดท้ายหรือไม่ - พิจารณาการแนบไฟล์ชั่วคราวหรือไฟล์จำลอง: ควรใช้ไฟล์แนบชั่วคราวหรือการดำเนินการในร้านค้าแบบ "ไม่สนใจ" สำหรับข้อมูลชั่วคราวที่ไม่ต้องใช้พื้นที่เก็บข้อมูลถาวร
เพิ่มประสิทธิภาพความแม่นยำของ Shader
การใช้ความแม่นยำสูงเกินไป (เช่น highp แทน mediump หรือ lowp) ภายใน Shader จะเพิ่มภาระงานของ GPU, การใช้พลังงาน และ แรงดันรีจิสเตอร์ โดยเฉพาะใน GPU ของอุปกรณ์เคลื่อนที่ การใช้ความแม่นยำที่ต่ำที่สุดที่เพียงพอสำหรับตัวแปร (เช่น ตำแหน่ง สี UV) จะช่วยปรับปรุงประสิทธิภาพโดยไม่มีผลกระทบต่อภาพที่สังเกตได้
วิธีเพิ่มประสิทธิภาพ
ใช้เครื่องมือสร้างโปรไฟล์และดีบักเกอร์ GPU เช่น RenderDoc, Android GPU Inspector หรือเครื่องมือวิเคราะห์ประสิทธิภาพอื่นๆ เพื่อระบุคอขวดด้านประสิทธิภาพที่เกี่ยวข้องกับรูปทรงเรขาคณิต
ตรวจสอบโค้ด Shader: ประเมินตัวแปร Shader และยืนยันว่าใช้ความแม่นยำสูงเฉพาะเมื่อจำเป็นเท่านั้น เช่น สำหรับการคำนวณความลึกหรือพื้นที่หน้าจอ ใช้ความแม่นยำระดับปานกลางหรือต่ำสำหรับสี พิกัด UV หรือ ค่าที่ไม่ต้องการความแม่นยำสูง
ใช้โปรแกรมแก้ไขข้อบกพร่องของ GPU: ยูทิลิตีการวินิจฉัย เช่น RenderDoc หรือโปรแกรมสร้างโปรไฟล์ GPU สำหรับอุปกรณ์เคลื่อนที่ (เช่น AGI, Mali/GPU Inspector) จะระบุการใช้รีจิสเตอร์ที่เพิ่มขึ้นหรือการหยุดทำงานของ Shader ที่เชื่อมโยงกับปัญหาความแม่นยำ
เปิดใช้การคัดกรองด้านหลัง
การแสดงผลสามเหลี่ยมที่หันออกจากกล้อง (ด้านหลัง) มักไม่จำเป็นสำหรับออบเจ็กต์ทึบ
วิธีเพิ่มประสิทธิภาพ
การใช้ VK_CULL_MODE_NONE อาจส่งผลเสียต่อประสิทธิภาพเนื่องจากบังคับให้ GPU แสดงทั้งด้านหน้าและด้านหลัง ซึ่งจะเพิ่มภาระงานในการแสดงผล
ลดการแสดงพิกเซลซ้ำในฉาก UI
กำจัดการเรียกใช้การวาดและการส่งผ่านการแสดงผลที่ไม่จำเป็น โดยเฉพาะในฉาก UI เพื่อเพิ่มประสิทธิภาพการแสดงผลและลดปริมาณงานของ GPU เช่น ในฉาก UI ที่ทั้งโลกแสดงผลก่อนที่จะวางซ้อน UI ทั่วทั้งหน้าจอ การแสดงผลโลกจะซ้ำซ้อน
วิธีเพิ่มประสิทธิภาพ
ใช้โปรแกรมแก้ไขข้อบกพร่องของ GPU เช่น RenderDoc เพื่อวิเคราะห์ไปป์ไลน์การแสดงผลและ
ระบุโอกาสในการเพิ่มประสิทธิภาพต่อไปนี้
- ตรวจสอบว่าไม่มีการวาดทับที่มากเกินไป ในบริบทของอินเทอร์เฟซผู้ใช้ ซึ่งอาจมีการแสดงผลทั้งหน้าจอ ให้ตรวจสอบว่าการแสดงผลก่อนหน้า ไม่ได้มีการวาดทับมากเกินความจำเป็น
- เปิดใช้การทดสอบความลึกและการคัดทิ้งเพื่อเพิ่มประสิทธิภาพ
- พิจารณาลำดับการแสดงผลจากด้านหน้าไปด้านหลัง