GLSL - ประกาศตัวแปรโกลบอลนอกขอบเขตฟังก์ชั่นหลัก


12

ช่วยประกาศตัวแปรนอกขอบเขตหน้าที่หลักของคุณใน GLSL หรือไม่? ตัวแปรเหล่านี้กลับมาใช้ซ้ำได้จริงและมีประสิทธิภาพมากขึ้นหรือไม่

นี่คือรหัสคำถาม:

varying vec2 vposition;
uniform float seed;
uniform float top;
uniform float bottom;
uniform float phi;
uniform float theta;
uniform float scaledPI;
uniform float yn;
uniform float ym;
uniform float rx;
uniform float ry;
uniform float radius;

const float PI = 3.141592653589793238462643383;

float left;
float right;
float mscaled;
float xn;
float xm;
void main() {
    float t = vposition.y * yn + ym;

    if(t <= 0.0 || t >= PI){
        left = phi - PI;
        right = phi + PI;
    }else{
        mscaled = scaledPI / (1 - abs(Math.cos(theta)));
        mscaled = mscaled < PI ? mscaled : PI;
        left = phi - mscaled;
        right = phi + mscaled;
    }
    xn = (left - right) / ((-rx / 2.0) - (rx / 2.0));
    xm = left - ((-rx/2.0) * xn);
    float p = vposition.x * xn + xm;

    vec3 coords = vec3( sin(p) * sin(t), cos(t), cos(p) * sin(t) );
    float nv = surface( vec4( coords, seed ) );
    gl_FragColor = vec4( vec3( nv, nv, nv ), 1.0 );
}

3
คำถามนี้ทำให้เกิดความสับสน GLSL ไม่มีลูปหลัก คุณหมายถึงmain()ฟังก์ชั่นหรือไม่ คุณค่าของคุณคือตัวแปรทั่วโลก(ชุดเครื่องแบบหรือแอตทริบิวต์ใน GLSL parlance) หรือค่าคงที่หรือไม่?
Sean Middleditch

คุณช่วยโพสต์โค้ดเพื่อเป็นตัวอย่างของสิ่งที่คุณกำลังพูดถึงได้หรือไม่?
นาธานรีด

ฉันอัปเดตคำถามด้วยรหัส
RodgerDodger

@ user1286792: นั่นไม่ได้เปลี่ยนความจริงที่ว่า GLSL ไม่ได้มีวงหลัก ยังไม่ชัดเจนว่าคุณกำลังพูดถึงเรื่องอะไร คุณคิดว่าอะไรจะถูกบันทึกโดยการทำเช่นนี้?
Nicol Bolas

@NicolBolas ฉันได้อัปเดตคำถามให้ชัดเจนยิ่งขึ้น หวังว่ามันจะมีประโยชน์สำหรับใครบางคนในอนาคต
RodgerDodger

คำตอบ:


33

ฉันคิดว่าฉันได้สิ่งที่คุณต้องการถาม ฉันถือว่าความกังวลหลักของคุณคือตัวแปรที่ไม่สม่ำเสมอที่กำหนดไว้นอกmain():

float left;
float right;
float mscaled;
float xn;
float xm;

ลองมาดูกันว่า GPU และ GLSL ทำงานอย่างไร GPU ไม่มีสแต็กหรือบันทึกการเปิดใช้งานการโทร ไม่มีวิธีจำลองขอบเขตหรือตัวแปรในท้องถิ่นใน GLSL เหมือนกับคอมไพเลอร์ C ที่สามารถทำได้บน CPU ส่วนใหญ่ สิ่งที่มีอยู่ทั้งหมดคือรีจิสเตอร์ซึ่งเป็นรีจิสเตอร์ที่เหมือนกันอินพุตอินเตอรเฟสของ shader สเตอรเอาตพุตและไฟลลงทะเบียนโลคัลที่ไมซ้ำกัน

กล่าวอีกนัยหนึ่งเมื่อไม่มีสิ่งใดเช่นฟังก์ชั่นหรือกองซ้อนหรือกองตัวแปรทั้งหมดที่ประกาศอยู่ที่ใดก็ได้ในการลงทะเบียน ไม่ว่าพวกเขาจะอยู่ในขอบเขตบางส่วนใน GLSL หรือทั่วโลกต่อไฟล์ทั้งหมดก็ไม่ต่างอะไร พวกเขาแค่ลงทะเบียน

อย่างไรก็ตามตัวจัดสรรการลงทะเบียนไม่ได้เป็นส่วนหนึ่งของมาตรฐาน GLSL การใช้งาน OpenGL ที่แตกต่างกันอาจมีระดับคุณภาพที่แตกต่างกันเมื่อพูดถึงการแปลงรหัส GLSL ระดับสูงเป็นรหัสเครื่องระดับต่ำที่ GPU เข้าใจ หนึ่งในส่วนที่มีความซับซ้อนมากขึ้นของคอมไพเลอร์ (GLSL หรืออื่น ๆ ) คือการจัดสรรลงทะเบียน นี่เป็นส่วนหนึ่งของคอมไพเลอร์ที่กำหนดว่าการลงทะเบียนตัวแปรที่กำหนดไว้ตรงไหน C ค่อนข้างยากกว่าปกติเนื่องจากต้องจัดการกับไฟล์ register ขนาดเล็กมาก (โดยเฉพาะบน x86) และต้องจัดการกับ register spilling (ย้ายตัวแปรไปยัง stack) และ aliasing (บันทึกตัวแปรกลับไปที่ RAM ก่อนเรียกฟังก์ชัน) และ คำสั่งแบบคี่ซึ่งต้องการเอาต์พุตจะอยู่ใน register เฉพาะ (x86's)idivตัวอย่าง) GPU มีไฟล์ register ขนาดใหญ่ ish เนื่องจากไม่มี stack หรือ heap ดังนั้นตัวจัดสรรสามารถทำได้ง่ายกว่า

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

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

โดยทั่วไปฉันขอแนะนำให้เก็บตัวแปรทั้งหมดเป็นภาษาท้องถิ่น ให้คำจำกัดความใกล้เคียงกับการใช้ตัวแปรตามความเหมาะสม สิ่งนี้ใช้ได้กับทุกภาษาโปรแกรมไม่ใช่เฉพาะ GLSL ฉันขอแนะนำให้ทำ const "ตัวแปร" ทุกครั้งในทุกกรณีที่คุณสามารถทำได้ อาจเป็นคำแนะนำสำหรับคอมไพเลอร์ที่มีความสามารถน้อยกว่าซึ่งการปรับให้เหมาะสมบางอย่างเป็นไปได้และที่สำคัญกว่านั้นคือทำให้รหัสของคุณจัดทำเอกสารด้วยตนเองได้ดีขึ้นและง่ายต่อการบำรุงรักษา

และแน่นอนนี่คือหน้าที่ของคุณ "เพียงแค่โปรไฟล์เพื่อทดสอบและหาคำแนะนำอย่างแน่นอน" เขียน shader ของคุณด้วยและไม่ต้องกลมกลืนและโพรไฟล์ของคุณ คำแนะนำในการปฏิบัติงานใด ๆ และทั้งหมดออนไลน์ควรได้รับความเชื่อถือและสันนิษฐานว่าอาจได้รับการคาดการณ์ล่วงหน้าหรือล้าสมัย


นั่นคือสิ่งที่ฉันหมายถึง คุณตอบคำถามของฉันอย่างสมบูรณ์และอธิบายสิ่งที่ฉันถามได้ดีกว่า
RodgerDodger

1
ที่จริงบางครั้งการประกาศอาร์เรย์เป็น const แทนที่จะไม่ใช่ const จะทำให้ shader ทั้งหมดช้าลง (มากช้ากว่า) ฉันสังเกตเห็นปัญหานั้นใน GTX 460 ของฉัน
ธารา

ฉันเพิ่งกำจัดข้อผิดพลาดแปลก ๆ และสงสัยอย่างมากว่ามันเป็น Adreno GPU (OpenGL ES 3.1) ไม่สามารถรวบรวม shader ได้เนื่องจากมีการประกาศตัวแปรนอกหลัก
comodoro

หนึ่งในคำตอบที่ละเอียดที่สุดที่ฉันเคยเห็น - ทำได้ดีมาก!
duhaime

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