สิ่งที่ทำให้การแตกสาขาใน GLSL ขึ้นอยู่กับรุ่นของ GPU และเวอร์ชั่นของไดรเวอร์ OpenGL
GPUs ส่วนใหญ่ดูเหมือนจะมีรูปแบบการทำงาน "เลือกหนึ่งในสองค่า" ที่ไม่มีค่าใช้จ่ายในการแยกสาขา:
n = (a==b) ? x : y;
และบางครั้งก็มีสิ่งที่ชอบ:
if(a==b) {
n = x;
m = y;
} else {
n = y;
m = x;
}
จะลดลงเป็นการดำเนินการเลือกค่าบางอย่างโดยไม่มีการลงโทษจากการแตกสาขา
GPU / ไดร์เวอร์บางตัวมีโทษเล็กน้อยสำหรับผู้ดำเนินการเปรียบเทียบระหว่างสองค่า แต่ทำงานได้เร็วกว่าเมื่อเปรียบเทียบกับศูนย์
มันอาจจะเร็วกว่าที่จะทำ:
gl_FragColor.xyz = ((tmp1 - tmp2) != vec3(0.0)) ? E : tmp1;
แทนที่จะเปรียบเทียบ(tmp1 != tmp2)
โดยตรงแต่นี่ขึ้นอยู่กับ GPU และไดรเวอร์ดังนั้นหากคุณไม่ได้กำหนดเป้าหมายเป็น GPU ที่เฉพาะเจาะจงมากและไม่มีใครแนะนำให้ใช้การดำเนินการเปรียบเทียบและปล่อยให้การเพิ่มประสิทธิภาพของงานกับไดรเวอร์ OpenGL เป็นไปได้ และรวดเร็วขึ้นด้วยวิธีที่ง่ายและอ่านง่ายขึ้น
"สาขา" ไม่ใช่สิ่งเลวร้ายเสมอไป ตัวอย่างเช่น GPU SGX530 ที่ใช้ใน OpenPandora เครื่องวัดขนาด 2x นี้ (30ms):
lowp vec3 E = texture2D(s_texture0, v_texCoord[0]).xyz;
lowp vec3 D = texture2D(s_texture0, v_texCoord[1]).xyz;
lowp vec3 F = texture2D(s_texture0, v_texCoord[2]).xyz;
lowp vec3 H = texture2D(s_texture0, v_texCoord[3]).xyz;
lowp vec3 B = texture2D(s_texture0, v_texCoord[4]).xyz;
if ((D - F) * (H - B) == vec3(0.0)) {
gl_FragColor.xyz = E;
} else {
lowp vec2 p = fract(pos);
lowp vec3 tmp1 = p.x < 0.5 ? D : F;
lowp vec3 tmp2 = p.y < 0.5 ? H : B;
gl_FragColor.xyz = ((tmp1 - tmp2) != vec3(0.0)) ? E : tmp1;
}
สิ้นสุดเร็วกว่า shader ที่เทียบเท่านี้ (80ms):
lowp vec3 E = texture2D(s_texture0, v_texCoord[0]).xyz;
lowp vec3 D = texture2D(s_texture0, v_texCoord[1]).xyz;
lowp vec3 F = texture2D(s_texture0, v_texCoord[2]).xyz;
lowp vec3 H = texture2D(s_texture0, v_texCoord[3]).xyz;
lowp vec3 B = texture2D(s_texture0, v_texCoord[4]).xyz;
lowp vec2 p = fract(pos);
lowp vec3 tmp1 = p.x < 0.5 ? D : F;
lowp vec3 tmp2 = p.y < 0.5 ? H : B;
lowp vec3 tmp3 = D == F || H == B ? E : tmp1;
gl_FragColor.xyz = tmp1 == tmp2 ? tmp3 : E;
คุณไม่มีทางรู้ล่วงหน้าว่าคอมไพเลอร์ GLSL หรือ GPU เฉพาะจะทำงานได้อย่างไรจนกว่าคุณจะทำการทดสอบ
หากต้องการเพิ่มจุด (ถึงแม้ว่าฉันยังไม่มีหมายเลขกำหนดเวลาจริงและรหัส shader ที่จะนำเสนอให้คุณในส่วนนี้) ปัจจุบันฉันใช้เป็นฮาร์ดแวร์ทดสอบปกติของฉัน:
- กราฟิก Intel HD 3000
- กราฟิก Intel HD 405
- nVidia GTX 560M
- nVidia GTX 960
- AMD Radeon R7 260X
- nVidia GTX 1050
ในฐานะที่เป็นรุ่นที่แตกต่างกันทั่วไป GPU เพื่อทดสอบ
ทดสอบแต่ละรายการด้วย Windows, Linux กรรมสิทธิ์และไดรเวอร์โอเพ่นซอร์ส OpenGL & OpenCL
และทุกครั้งที่ฉันพยายามที่จะเพิ่มประสิทธิภาพ GLSL shader แบบไมโคร (ตามตัวอย่าง SGX530 ด้านบน) หรือการดำเนินการ OpenCL สำหรับหนึ่งใน GPU / ไดรเวอร์คอมโบโดยเฉพาะ ฉันก็จบลงด้วยประสิทธิภาพที่มากกว่าหนึ่งใน GPU / ไดรเวอร์อื่น ๆ
ดังนั้นนอกเหนือจากการลดความซับซ้อนทางคณิตศาสตร์ในระดับสูงอย่างชัดเจน(เช่น: แปลงหน่วยงานที่เหมือนกัน 5 หน่วยให้เป็นส่วนกลับเดี่ยวและ 5 หน่วยแทน) และลดการค้นหาพื้นผิว / แบนด์วิดท์มันน่าจะเป็นการเสียเวลาของคุณ
GPU ทุกตัวนั้นแตกต่างจากตัวอื่น ๆ
หากคุณกำลังทำงานโดยเฉพาะกับ (a) เกมคอนโซลที่มี GPU เฉพาะนี่จะเป็นเรื่องที่แตกต่างออกไป
ด้านอื่น ๆ (มีความสำคัญน้อยกว่าสำหรับผู้พัฒนาเกมขนาดเล็ก แต่ยังคงเป็นที่น่าประทับใจ) ในแง่นี้ก็คือไดรเวอร์ GPU ของคอมพิวเตอร์หนึ่งวันอาจแทนที่ shaders ของคุณได้อย่างเงียบ ๆ ( หากเกมของคุณเป็นที่นิยมพอ ) การทำเช่นนั้นใช้ได้สำหรับคุณทั้งหมด
พวกเขาจะทำเช่นนี้สำหรับเกมยอดนิยมที่มักใช้เป็นเกณฑ์มาตรฐาน
หรือถ้าคุณให้ผู้เล่นของคุณเข้าถึง shaders เพื่อให้พวกเขาสามารถแก้ไขตัวเองได้อย่างง่ายดายบางคนอาจบีบ FPS พิเศษบางอย่างเพื่อผลประโยชน์ของตนเอง
ตัวอย่างเช่นมี shader & texture pack ที่ทำให้แฟน ๆ หลงลืมเพื่อเพิ่มอัตราเฟรมบนฮาร์ดแวร์ที่เล่นไม่ได้
และในที่สุดเมื่อ shader ของคุณซับซ้อนพอเกมของคุณเกือบจะเสร็จและคุณเริ่มการทดสอบกับฮาร์ดแวร์ที่แตกต่างกันคุณจะยุ่งพอเพียงแค่กำหนด shaders ของคุณให้ทำงานได้กับ GPU ทุกประเภทเนื่องจากข้อบกพร่องต่าง ๆ ที่คุณไม่เคยทำ มีเวลาในการปรับให้เหมาะสมกับระดับนั้น