Dies liegt im Wesentlichen daran, dass nicht alle GPUs Funktionsaufrufe unterstützen können - und selbst wenn dies möglich ist, können Funktionsaufrufe sehr langsam sein oder Einschränkungen aufweisen, z. B. eine sehr geringe Stapeltiefe.
Shader-Code und GPU-Computing-Code scheinen überall Funktionsaufrufe zu haben, aber unter normalen Umständen sind sie alle zu 100% vom Compiler eingebettet. Der von der GPU ausgeführte Maschinencode enthält Verzweigungen und Schleifen, jedoch keine Funktionsaufrufe. Rekursive Funktionsaufrufe können jedoch aus offensichtlichen Gründen nicht eingebunden werden. (Es sei denn, einige der Argumente sind Konstanten für die Kompilierungszeit, sodass der Compiler sie falten und den gesamten Aufrufbaum einbinden kann.)
Um echte Funktionsaufrufe zu implementieren, benötigen Sie einen Stack. In den meisten Fällen wird für Shader-Code überhaupt kein Stapel verwendet. GPUs verfügen über große Registerdateien, und Shader können alle ihre Daten die ganze Zeit über in Registern speichern. Es ist schwierig, einen Stapel zum Laufen zu bringen, weil (a) Sie viel Stapelplatz benötigen würden, um all die vielen Verzerrungen, die gleichzeitig im Flug sein können, unterzubringen, und (b) das GPU-Speichersystem für das Zusammenfügen vieler Stapel optimiert ist von Speicher-Transaktionen, um einen hohen Durchsatz zu erzielen, aber dies geht zu Lasten der Latenz, so dass ich vermute, dass Stapeloperationen wie das Speichern / Wiederherstellen lokaler Variablen furchtbar langsam wären.
In der Vergangenheit waren Funktionsaufrufe auf Hardwareebene auf der GPU nicht besonders nützlich, da es sinnvoller war, alles im Compiler zu integrieren. GPU-Architekten haben sich also nicht darauf konzentriert, sie schnell zu machen. Wahrscheinlich könnten einige andere Kompromisse eingegangen werden, wenn in Zukunft effiziente Hardware-Level-Aufrufe erforderlich sind, aber (wie bei allem im Engineering) werden die Kosten woanders anfallen.
Was Raytracing anbelangt, besteht die Art und Weise, wie Menschen normalerweise mit solchen Dingen umgehen, darin, Warteschlangen von Strahlen zu erstellen, die gerade verfolgt werden. Anstatt sich zu wiederholen, fügen Sie einen Strahl zu einer Warteschlange hinzu, und auf der oberen Ebene befindet sich irgendwo eine Schleife, die so lange verarbeitet wird, bis alle Warteschlangen leer sind. Wenn Sie jedoch von einem klassischen rekursiven Raytracer ausgehen, muss Ihr Rendering-Code erheblich umstrukturiert werden. Weitere Informationen finden Sie in folgendem Artikel: Wavefront Path Tracing .