{ "cells": [ { "cell_type": "markdown", "id": "30dbb7d1", "metadata": {}, "source": [ "# CrossTL PBR Showcase\n", "\n", "This notebook translates one CrossGL PBR shader into multiple GPU targets from the local checkout. It intentionally avoids installing `crosstl` from PyPI so the generated output reflects the code in this repository.\n" ] }, { "cell_type": "code", "execution_count": 1, "id": "5dabc6e5", "metadata": { "execution": { "iopub.execute_input": "2026-06-23T12:17:47.018990Z", "iopub.status.busy": "2026-06-23T12:17:47.018724Z", "iopub.status.idle": "2026-06-23T12:17:47.030644Z", "shell.execute_reply": "2026-06-23T12:17:47.030308Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Repository root: local checkout\n", "CrossTL import: crosstl/__init__.py\n", "Shader source: demos/readme/showcase_pbr.cgl\n" ] } ], "source": [ "from pathlib import Path\n", "import sys\n", "from IPython.display import Markdown, display\n", "\n", "\n", "def find_repo_root(start: Path) -> Path:\n", " for candidate in [start, *start.parents]:\n", " if (candidate / \"crosstl\").is_dir() and (candidate / \"setup.py\").exists():\n", " return candidate\n", " raise RuntimeError(\"Run this notebook from inside the CrossTL repository checkout.\")\n", "\n", "\n", "REPO_ROOT = find_repo_root(Path.cwd().resolve())\n", "if str(REPO_ROOT) not in sys.path:\n", " sys.path.insert(0, str(REPO_ROOT))\n", "\n", "import crosstl\n", "\n", "SOURCE_PATH = REPO_ROOT / \"demos\" / \"readme\" / \"showcase_pbr.cgl\"\n", "import_path = Path(crosstl.__file__).resolve()\n", "try:\n", " import_display = import_path.relative_to(REPO_ROOT)\n", "except ValueError:\n", " import_display = import_path\n", "\n", "print(\"Repository root: local checkout\")\n", "print(f\"CrossTL import: {import_display}\")\n", "print(f\"Shader source: {SOURCE_PATH.relative_to(REPO_ROOT)}\")\n" ] }, { "cell_type": "markdown", "id": "a9944977", "metadata": {}, "source": [ "## Source Shader\n", "\n", "The demo source uses the current CrossGL struct-return stage style. That shape gives graphics backends explicit input/output structs and avoids stale global-stage syntax." ] }, { "cell_type": "code", "execution_count": 2, "id": "c640cd73", "metadata": { "execution": { "iopub.execute_input": "2026-06-23T12:17:47.031937Z", "iopub.status.busy": "2026-06-23T12:17:47.031834Z", "iopub.status.idle": "2026-06-23T12:17:47.035287Z", "shell.execute_reply": "2026-06-23T12:17:47.035058Z" } }, "outputs": [ { "data": { "text/markdown": [ "```cpp\n", "shader ShowcasePBRShader {\n", " const float PI = 3.14159265359;\n", " const float EPSILON = 0.0001;\n", " const int MAX_LIGHTS = 4;\n", "\n", " struct VertexInput {\n", " vec3 position;\n", " vec3 normal;\n", " vec3 tangent;\n", " vec2 texCoord;\n", " }\n", "\n", " struct VertexOutput {\n", " vec3 worldPosition;\n", " vec3 worldNormal;\n", " vec3 worldTangent;\n", " vec3 worldBitangent;\n", " vec2 uv;\n", " vec4 position;\n", " }\n", "\n", " struct FragmentInput {\n", " vec3 worldPosition;\n", " vec3 worldNormal;\n", " vec3 worldTangent;\n", " vec3 worldBitangent;\n", " vec2 uv;\n", " }\n", "\n", " struct FragmentOutput {\n", " vec4 color;\n", " }\n", "\n", " float distributionGGX(vec3 normal, vec3 halfVector, float roughness) {\n", " float alpha = roughness * roughness;\n", " float alpha2 = alpha * alpha;\n", " float ndoth = max(dot(normal, halfVector), 0.0);\n", " float denom = ndoth * ndoth * (alpha2 - 1.0) + 1.0;\n", " return alpha2 / max(PI * denom * denom, EPSILON);\n", " }\n", "\n", " float geometrySchlickGGX(float ndotv, float roughness) {\n", " float k = (roughness + 1.0) * (roughness + 1.0) / 8.0;\n", " return ndotv / max(ndotv * (1.0 - k) + k, EPSILON);\n", " }\n", "\n", " float geometrySmith(vec3 normal, vec3 viewDir, vec3 lightDir, float roughness) {\n", " float ndotv = max(dot(normal, viewDir), 0.0);\n", " float ndotl = max(dot(normal, lightDir), 0.0);\n", " return geometrySchlickGGX(ndotv, roughness) * geometrySchlickGGX(ndotl, roughness);\n", " }\n", "\n", " vec3 fresnelSchlick(float cosTheta, vec3 baseReflectance) {\n", " return baseReflectance + (vec3(1.0) - baseReflectance) * pow(max(1.0 - cosTheta, 0.0), 5.0);\n", " }\n", "\n", " vertex {\n", " uniform mat4 modelMatrix;\n", " uniform mat4 viewProjectionMatrix;\n", " uniform mat3 normalMatrix;\n", "\n", " VertexOutput main(VertexInput input) {\n", " VertexOutput output;\n", " vec4 worldPosition = modelMatrix * vec4(input.position, 1.0);\n", " output.worldPosition = worldPosition.xyz;\n", " output.worldNormal = normalize(normalMatrix * input.normal);\n", " output.worldTangent = normalize(normalMatrix * input.tangent);\n", " output.worldBitangent = normalize(cross(output.worldNormal, output.worldTangent));\n", " output.uv = input.texCoord;\n", " output.position = viewProjectionMatrix * worldPosition;\n", " return output;\n", " }\n", " }\n", "\n", " fragment {\n", " uniform sampler2D albedoMap;\n", " uniform sampler2D normalMap;\n", " uniform sampler2D metallicRoughnessMap;\n", " uniform vec3 cameraPosition;\n", " uniform vec3 lightPositions[MAX_LIGHTS];\n", " uniform vec3 lightColors[MAX_LIGHTS];\n", " uniform int activeLightCount;\n", " uniform vec3 baseColor;\n", " uniform float metallicFactor;\n", " uniform float roughnessFactor;\n", "\n", " vec3 decodeNormal(vec3 encodedNormal, mat3 tangentFrame) {\n", " vec3 tangentNormal = encodedNormal * 2.0 - 1.0;\n", " return normalize(tangentFrame * tangentNormal);\n", " }\n", "\n", " FragmentOutput main(FragmentInput input) {\n", " FragmentOutput output;\n", " mat3 tangentFrame = mat3(\n", " normalize(input.worldTangent),\n", " normalize(input.worldBitangent),\n", " normalize(input.worldNormal)\n", " );\n", " vec3 normal = decodeNormal(texture(normalMap, input.uv).rgb, tangentFrame);\n", " vec3 viewDir = normalize(cameraPosition - input.worldPosition);\n", " vec3 albedo = texture(albedoMap, input.uv).rgb * baseColor;\n", " vec3 materialSample = texture(metallicRoughnessMap, input.uv).rgb;\n", " float metallic = clamp(materialSample.b * metallicFactor, 0.0, 1.0);\n", " float roughness = clamp(materialSample.g * roughnessFactor, 0.04, 1.0);\n", " vec3 baseReflectance = mix(vec3(0.04), albedo, metallic);\n", " vec3 radianceSum = vec3(0.0);\n", "\n", " for (int i = 0; i < MAX_LIGHTS; i++) {\n", " if (i >= activeLightCount) {\n", " break;\n", " }\n", " vec3 lightVector = lightPositions[i] - input.worldPosition;\n", " float distanceSq = max(dot(lightVector, lightVector), EPSILON);\n", " vec3 lightDir = normalize(lightVector);\n", " vec3 halfVector = normalize(viewDir + lightDir);\n", " float attenuation = 1.0 / distanceSq;\n", " vec3 radiance = lightColors[i] * attenuation;\n", "\n", " float normalDistribution = distributionGGX(normal, halfVector, roughness);\n", " float geometry = geometrySmith(normal, viewDir, lightDir, roughness);\n", " vec3 fresnel = fresnelSchlick(max(dot(halfVector, viewDir), 0.0), baseReflectance);\n", " vec3 diffuseShare = (vec3(1.0) - fresnel) * (1.0 - metallic);\n", " vec3 numerator = normalDistribution * geometry * fresnel;\n", " float denominator = max(4.0 * max(dot(normal, viewDir), 0.0) * max(dot(normal, lightDir), 0.0), EPSILON);\n", " vec3 specular = numerator / denominator;\n", " float ndotl = max(dot(normal, lightDir), 0.0);\n", " radianceSum += (diffuseShare * albedo / PI + specular) * radiance * ndotl;\n", " }\n", "\n", " vec3 ambient = albedo * 0.03;\n", " vec3 color = ambient + radianceSum;\n", " color = color / (color + vec3(1.0));\n", " color = pow(color, vec3(1.0 / 2.2));\n", " output.color = vec4(color, 1.0);\n", " return output;\n", " }\n", " }\n", "}\n", "\n", "```" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "source_code = SOURCE_PATH.read_text(encoding=\"utf-8\")\n", "assert \"shader ShowcasePBRShader\" in source_code\n", "assert \"VertexOutput main(VertexInput input)\" in source_code\n", "assert \"FragmentOutput main(FragmentInput input)\" in source_code\n", "assert \"texture(albedoMap, input.uv)\" in source_code\n", "\n", "display(Markdown(f\"\"\"```cpp\n", "{source_code}\n", "```\"\"\"))\n" ] }, { "cell_type": "markdown", "id": "1a2d6c52", "metadata": {}, "source": [ "## Translate To Showcase Backends\n", "\n", "This cell translates the same source file to graphics, compute-oriented, browser, and interchange targets. The assertions are deliberately concrete: if a backend regresses to malformed stage signatures or stale texture lowering, the notebook fails instead of displaying misleading output." ] }, { "cell_type": "code", "execution_count": 3, "id": "b1112148", "metadata": { "execution": { "iopub.execute_input": "2026-06-23T12:17:47.036437Z", "iopub.status.busy": "2026-06-23T12:17:47.036335Z", "iopub.status.idle": "2026-06-23T12:17:48.387534Z", "shell.execute_reply": "2026-06-23T12:17:48.387173Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Translated and validated:\n", "metal 162 lines\n", "directx 139 lines\n", "opengl 137 lines\n", "vulkan 665 lines\n", "cuda 3625 lines\n", "hip 3610 lines\n", "slang 137 lines\n", "wgsl 147 lines\n", "webgl 138 lines\n" ] } ], "source": [ "BACKENDS = {\n", " \"metal\": \"cpp\",\n", " \"directx\": \"hlsl\",\n", " \"opengl\": \"glsl\",\n", " \"vulkan\": \"text\",\n", " \"cuda\": \"cuda\",\n", " \"hip\": \"cpp\",\n", " \"slang\": \"hlsl\",\n", " \"wgsl\": \"wgsl\",\n", " \"webgl\": \"glsl\",\n", "}\n", "\n", "generated = {}\n", "for backend in BACKENDS:\n", " generated[backend] = crosstl.translate(str(SOURCE_PATH), backend=backend)\n", " assert generated[backend].strip(), f\"{backend} produced empty output\"\n", "\n", "metal_code = generated[\"metal\"]\n", "assert \"vertex VertexOutput vertex_main\" in metal_code\n", "assert \"fragment FragmentOutput\" in metal_code\n", "assert \"texture2d albedoMap\" in metal_code\n", "assert \".sample(\" in metal_code\n", "assert \"gl_Position\" not in metal_code\n", "\n", "hlsl_code = generated[\"directx\"]\n", "assert \"VertexOutput VSMain(VertexInput input)\" in hlsl_code\n", "assert \"FragmentOutput PSMain(FragmentInput input)\" in hlsl_code\n", "assert \"Texture2D albedoMap\" in hlsl_code\n", "assert \".Sample(\" in hlsl_code\n", "\n", "glsl_code = generated[\"opengl\"]\n", "assert \"#version 450 core\" in glsl_code\n", "assert \"uniform sampler2D albedoMap\" in glsl_code\n", "assert \"texture(albedoMap\" in glsl_code\n", "\n", "slang_code = generated[\"slang\"]\n", "assert \"Sampler2D albedoMap\" in slang_code\n", "assert \"[shader(\\\"fragment\\\")]\" in slang_code\n", "\n", "wgsl_code = generated[\"wgsl\"]\n", "assert \"@vertex\" in wgsl_code\n", "assert \"@fragment\" in wgsl_code\n", "\n", "print(\"Translated and validated:\")\n", "for backend, code in generated.items():\n", " print(f\"{backend:<8} {len(code.splitlines()):>5} lines\")\n" ] }, { "cell_type": "markdown", "id": "5271c7ae", "metadata": {}, "source": [ "## Metal Output\n", "\n", "The Metal output should have concrete stage signatures, `[[stage_in]]` inputs, `[[position]]`/`[[color(0)]]` outputs, and native texture sampling. This is the path that exposed the stale notebook output before." ] }, { "cell_type": "code", "execution_count": 4, "id": "67ca4623", "metadata": { "execution": { "iopub.execute_input": "2026-06-23T12:17:48.389104Z", "iopub.status.busy": "2026-06-23T12:17:48.388847Z", "iopub.status.idle": "2026-06-23T12:17:48.391482Z", "shell.execute_reply": "2026-06-23T12:17:48.391255Z" } }, "outputs": [ { "data": { "text/markdown": [ "```cpp\n", "\n", "#include \n", "using namespace metal;\n", "\n", "__attribute__((unused)) constant float PI = 3.14159265359;\n", "__attribute__((unused)) constant float EPSILON = 0.0001;\n", "__attribute__((unused)) constant int MAX_LIGHTS = 4;\n", "\n", "struct VertexInput {\n", " float3 position [[attribute(0)]];\n", " float3 normal [[attribute(1)]];\n", " float3 tangent [[attribute(2)]];\n", " float2 texCoord [[attribute(3)]];\n", "};\n", "struct VertexOutput {\n", " float3 worldPosition;\n", " float3 worldNormal;\n", " float3 worldTangent;\n", " float3 worldBitangent;\n", " float2 uv;\n", " float4 position [[position]];\n", "};\n", "struct FragmentInput {\n", " float3 worldPosition;\n", " float3 worldNormal;\n", " float3 worldTangent;\n", " float3 worldBitangent;\n", " float2 uv;\n", "};\n", "struct FragmentOutput {\n", " float4 color [[color(0)]];\n", "};\n", "float distributionGGX(float3 normal, float3 halfVector, float roughness) {\n", " float alpha = roughness * roughness;\n", " float alpha2 = alpha * alpha;\n", " float ndoth = max(dot(normal, halfVector), 0.0);\n", " float denom = ndoth * ndoth * (alpha2 - 1.0) + 1.0;\n", " return alpha2 / max(PI * denom * denom, EPSILON);\n", "}\n", "\n", "float geometrySchlickGGX(float ndotv, float roughness) {\n", " float k = (roughness + 1.0) * (roughness + 1.0) / 8.0;\n", " return ndotv / max(ndotv * (1.0 - k) + k, EPSILON);\n", "}\n", "\n", "float geometrySmith(float3 normal, float3 viewDir, float3 lightDir,\n", " float roughness) {\n", " float ndotv = max(dot(normal, viewDir), 0.0);\n", " float ndotl = max(dot(normal, lightDir), 0.0);\n", " return geometrySchlickGGX(ndotv, roughness) *\n", " geometrySchlickGGX(ndotl, roughness);\n", "}\n", "\n", "float3 fresnelSchlick(float cosTheta, float3 baseReflectance) {\n", " return baseReflectance +\n", " (float3(1.0) - baseReflectance) * pow(max(1.0 - cosTheta, 0.0), 5.0);\n", "}\n", "\n", "// Vertex Shader\n", "vertex VertexOutput vertex_main(VertexInput input [[stage_in]],\n", " constant float4x4 &modelMatrix [[buffer(0)]],\n", " constant float4x4 &viewProjectionMatrix\n", " [[buffer(1)]],\n", " constant float3x3 &normalMatrix [[buffer(2)]],\n", " constant float3 &cameraPosition [[buffer(3)]],\n", " constant float3 *lightPositions [[buffer(4)]],\n", " constant float3 *lightColors [[buffer(5)]],\n", " constant int &activeLightCount [[buffer(6)]],\n", " constant float3 &baseColor [[buffer(7)]],\n", " constant float &metallicFactor [[buffer(8)]],\n", " constant float &roughnessFactor [[buffer(9)]],\n", " texture2d albedoMap [[texture(0)]],\n", " texture2d normalMap [[texture(1)]],\n", " texture2d metallicRoughnessMap\n", " [[texture(2)]]) {\n", " VertexOutput output;\n", " float4 worldPosition = modelMatrix * float4(input.position, 1.0);\n", " output.worldPosition = worldPosition.xyz;\n", " output.worldNormal = normalize(normalMatrix * input.normal);\n", " output.worldTangent = normalize(normalMatrix * input.tangent);\n", " output.worldBitangent =\n", " normalize(cross(output.worldNormal, output.worldTangent));\n", " output.uv = input.texCoord;\n", " output.position = viewProjectionMatrix * worldPosition;\n", " return output;\n", "}\n", "\n", "float3 decodeNormal(float3 encodedNormal, float3x3 tangentFrame) {\n", " float3 tangentNormal = encodedNormal * float3(2.0) - float3(1.0);\n", " return normalize(tangentFrame * tangentNormal);\n", "}\n", "\n", "// Fragment Shader\n", "fragment FragmentOutput\n", "fragment_main(FragmentInput input [[stage_in]],\n", " constant float4x4 &modelMatrix [[buffer(0)]],\n", " constant float4x4 &viewProjectionMatrix [[buffer(1)]],\n", " constant float3x3 &normalMatrix [[buffer(2)]],\n", " constant float3 &cameraPosition [[buffer(3)]],\n", " constant float3 *lightPositions [[buffer(4)]],\n", " constant float3 *lightColors [[buffer(5)]],\n", " constant int &activeLightCount [[buffer(6)]],\n", " constant float3 &baseColor [[buffer(7)]],\n", " constant float &metallicFactor [[buffer(8)]],\n", " constant float &roughnessFactor [[buffer(9)]],\n", " texture2d albedoMap [[texture(0)]],\n", " texture2d normalMap [[texture(1)]],\n", " texture2d metallicRoughnessMap [[texture(2)]]) {\n", " FragmentOutput output;\n", " float3x3 tangentFrame =\n", " float3x3(normalize(input.worldTangent), normalize(input.worldBitangent),\n", " normalize(input.worldNormal));\n", " float3 normal = decodeNormal(\n", " normalMap\n", " .sample(sampler(mag_filter::linear, min_filter::linear), input.uv)\n", " .rgb,\n", " tangentFrame);\n", " float3 viewDir = normalize(cameraPosition - input.worldPosition);\n", " float3 albedo =\n", " albedoMap\n", " .sample(sampler(mag_filter::linear, min_filter::linear), input.uv)\n", " .rgb *\n", " baseColor;\n", " float3 materialSample =\n", " metallicRoughnessMap\n", " .sample(sampler(mag_filter::linear, min_filter::linear), input.uv)\n", " .rgb;\n", " float metallic = clamp(materialSample.b * metallicFactor, 0.0, 1.0);\n", " float roughness = clamp(materialSample.g * roughnessFactor, 0.04, 1.0);\n", " float3 baseReflectance = mix(float3(0.04), albedo, metallic);\n", " float3 radianceSum = float3(0.0);\n", " for (int i = 0; i < MAX_LIGHTS; ++i) {\n", " if (i >= activeLightCount) {\n", " break;\n", " }\n", " float3 lightVector = lightPositions[i] - input.worldPosition;\n", " float distanceSq = max(dot(lightVector, lightVector), EPSILON);\n", " float3 lightDir = normalize(lightVector);\n", " float3 halfVector = normalize(viewDir + lightDir);\n", " float attenuation = 1.0 / distanceSq;\n", " float3 radiance = lightColors[i] * float3(attenuation);\n", " float normalDistribution = distributionGGX(normal, halfVector, roughness);\n", " float geometry = geometrySmith(normal, viewDir, lightDir, roughness);\n", " float3 fresnel =\n", " fresnelSchlick(max(dot(halfVector, viewDir), 0.0), baseReflectance);\n", " float3 diffuseShare = (float3(1.0) - fresnel) * float3((1.0 - metallic));\n", " float3 numerator = float3(normalDistribution * geometry) * fresnel;\n", " float denominator = max(4.0 * max(dot(normal, viewDir), 0.0) *\n", " max(dot(normal, lightDir), 0.0),\n", " EPSILON);\n", " float3 specular = numerator / float3(denominator);\n", " float ndotl = max(dot(normal, lightDir), 0.0);\n", " radianceSum +=\n", " (diffuseShare * albedo / PI + specular) * radiance * float3(ndotl);\n", " }\n", " float3 ambient = albedo * float3(0.03);\n", " float3 color = ambient + radianceSum;\n", " color = color / (color + float3(1.0));\n", " color = pow(color, float3(1.0 / 2.2));\n", " output.color = float4(color, 1.0);\n", " return output;\n", "}\n", "\n", "```" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "display(Markdown(f\"\"\"```cpp\n", "{generated['metal']}\n", "```\"\"\"))\n" ] }, { "cell_type": "markdown", "id": "585223b1", "metadata": {}, "source": [ "## DirectX And OpenGL Output\n", "\n", "These two outputs show the same shader lowering to HLSL semantics and GLSL stage guards." ] }, { "cell_type": "code", "execution_count": 5, "id": "1f633de6", "metadata": { "execution": { "iopub.execute_input": "2026-06-23T12:17:48.392586Z", "iopub.status.busy": "2026-06-23T12:17:48.392494Z", "iopub.status.idle": "2026-06-23T12:17:48.394953Z", "shell.execute_reply": "2026-06-23T12:17:48.394707Z" } }, "outputs": [ { "data": { "text/markdown": [ "### DirectX / HLSL\n", "```hlsl\n", "\n", "static const float PI = 3.14159265359;\n", "static const float EPSILON = 0.0001;\n", "static const int MAX_LIGHTS = 4;\n", "\n", "struct VertexInput\n", "{\n", " float3 position : POSITION;\n", " float3 normal : TEXCOORD0;\n", " float3 tangent : TEXCOORD1;\n", " float2 texCoord : TEXCOORD2;\n", "};\n", "struct VertexOutput\n", "{\n", " float3 worldPosition : TEXCOORD0;\n", " float3 worldNormal : TEXCOORD1;\n", " float3 worldTangent : TEXCOORD2;\n", " float3 worldBitangent : TEXCOORD3;\n", " float2 uv : TEXCOORD4;\n", " float4 position : SV_Position;\n", "};\n", "struct FragmentInput\n", "{\n", " float3 worldPosition : TEXCOORD0;\n", " float3 worldNormal : TEXCOORD1;\n", " float3 worldTangent : TEXCOORD2;\n", " float3 worldBitangent : TEXCOORD3;\n", " float2 uv : TEXCOORD4;\n", "};\n", "struct FragmentOutput\n", "{\n", " float4 color : SV_TARGET;\n", "};\n", "float4x4 modelMatrix;\n", "float4x4 viewProjectionMatrix;\n", "float3x3 normalMatrix;\n", "Texture2D albedoMap : register(t0);\n", "SamplerState albedoMapSampler : register(s0);\n", "Texture2D normalMap : register(t1);\n", "SamplerState normalMapSampler : register(s1);\n", "Texture2D metallicRoughnessMap : register(t2);\n", "SamplerState metallicRoughnessMapSampler : register(s2);\n", "float3 cameraPosition;\n", "float3 lightPositions[MAX_LIGHTS];\n", "float3 lightColors[MAX_LIGHTS];\n", "int activeLightCount;\n", "float3 baseColor;\n", "float metallicFactor;\n", "float roughnessFactor;\n", "float distributionGGX(float3 normal, float3 halfVector, float roughness)\n", "{\n", " float alpha = (roughness * roughness);\n", " float alpha2 = (alpha * alpha);\n", " float ndoth = max(dot(normal, halfVector), 0.0);\n", " float denom = (((ndoth * ndoth) * (alpha2 - 1.0)) + 1.0);\n", " return (alpha2 / max(((PI * denom) * denom), EPSILON));\n", "}\n", "\n", "float geometrySchlickGGX(float ndotv, float roughness)\n", "{\n", " float k = (((roughness + 1.0) * (roughness + 1.0)) / 8.0);\n", " return (ndotv / max(((ndotv * (1.0 - k)) + k), EPSILON));\n", "}\n", "\n", "float geometrySmith(float3 normal, float3 viewDir, float3 lightDir, float roughness)\n", "{\n", " float ndotv = max(dot(normal, viewDir), 0.0);\n", " float ndotl = max(dot(normal, lightDir), 0.0);\n", " return (geometrySchlickGGX(ndotv, roughness) * geometrySchlickGGX(ndotl, roughness));\n", "}\n", "\n", "float3 fresnelSchlick(float cosTheta, float3 baseReflectance)\n", "{\n", " return (baseReflectance + ((float3(1.0, 1.0, 1.0) - baseReflectance) * pow(max((1.0 - cosTheta), 0.0), 5.0)));\n", "}\n", "\n", "// Vertex Shader\n", "VertexOutput VSMain(VertexInput input)\n", "{\n", " VertexOutput output;\n", " float4 worldPosition = mul(modelMatrix, float4(input.position, 1.0));\n", " output.worldPosition = worldPosition.xyz;\n", " output.worldNormal = normalize(mul(normalMatrix, input.normal));\n", " output.worldTangent = normalize(mul(normalMatrix, input.tangent));\n", " output.worldBitangent = normalize(cross(output.worldNormal, output.worldTangent));\n", " output.uv = input.texCoord;\n", " output.position = mul(viewProjectionMatrix, worldPosition);\n", " return output;\n", "}\n", "\n", "float3 decodeNormal(float3 encodedNormal, float3x3 tangentFrame)\n", "{\n", " float3 tangentNormal = ((encodedNormal * 2.0) - 1.0);\n", " return normalize(mul(tangentFrame, tangentNormal));\n", "}\n", "\n", "// Fragment Shader\n", "FragmentOutput PSMain(FragmentInput input)\n", "{\n", " FragmentOutput output;\n", " float3x3 tangentFrame =\n", " float3x3(normalize(input.worldTangent), normalize(input.worldBitangent), normalize(input.worldNormal));\n", " float3 normal = decodeNormal(normalMap.Sample(normalMapSampler, input.uv).rgb, tangentFrame);\n", " float3 viewDir = normalize((cameraPosition - input.worldPosition));\n", " float3 albedo = (albedoMap.Sample(albedoMapSampler, input.uv).rgb * baseColor);\n", " float3 materialSample = metallicRoughnessMap.Sample(metallicRoughnessMapSampler, input.uv).rgb;\n", " float metallic = clamp((materialSample.b * metallicFactor), 0.0, 1.0);\n", " float roughness = clamp((materialSample.g * roughnessFactor), 0.04, 1.0);\n", " float3 baseReflectance = lerp(float3(0.04, 0.04, 0.04), albedo, metallic);\n", " float3 radianceSum = float3(0.0, 0.0, 0.0);\n", " for (int i = 0; (i < MAX_LIGHTS); ++i)\n", " {\n", " if ((i >= activeLightCount))\n", " {\n", " break;\n", " }\n", " float3 lightVector = (lightPositions[i] - input.worldPosition);\n", " float distanceSq = max(dot(lightVector, lightVector), EPSILON);\n", " float3 lightDir = normalize(lightVector);\n", " float3 halfVector = normalize((viewDir + lightDir));\n", " float attenuation = (1.0 / distanceSq);\n", " float3 radiance = (lightColors[i] * attenuation);\n", " float normalDistribution = distributionGGX(normal, halfVector, roughness);\n", " float geometry = geometrySmith(normal, viewDir, lightDir, roughness);\n", " float3 fresnel = fresnelSchlick(max(dot(halfVector, viewDir), 0.0), baseReflectance);\n", " float3 diffuseShare = ((float3(1.0, 1.0, 1.0) - fresnel) * (1.0 - metallic));\n", " float3 numerator = ((normalDistribution * geometry) * fresnel);\n", " float denominator = max(((4.0 * max(dot(normal, viewDir), 0.0)) * max(dot(normal, lightDir), 0.0)), EPSILON);\n", " float3 specular = (numerator / denominator);\n", " float ndotl = max(dot(normal, lightDir), 0.0);\n", " radianceSum += (((((diffuseShare * albedo) / PI) + specular) * radiance) * ndotl);\n", " }\n", " float3 ambient = (albedo * 0.03);\n", " float3 color = (ambient + radianceSum);\n", " color = (color / (color + float3(1.0, 1.0, 1.0)));\n", " color = pow(color, float3((1.0 / 2.2), (1.0 / 2.2), (1.0 / 2.2)));\n", " output.color = float4(color, 1.0);\n", " return output;\n", "}\n", "\n", "```" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/markdown": [ "### OpenGL / GLSL\n", "```glsl\n", "#version 450 core\n", "const float PI = 3.14159265359;\n", "const float EPSILON = 0.0001;\n", "const int MAX_LIGHTS = 4;\n", "\n", "#ifdef GL_VERTEX_SHADER\n", "in vec3 position;\n", "in vec3 normal;\n", "in vec3 tangent;\n", "in vec2 texCoord;\n", "#endif\n", "#ifdef GL_VERTEX_SHADER\n", "out vec3 worldPosition;\n", "out vec3 worldNormal;\n", "out vec3 worldTangent;\n", "out vec3 worldBitangent;\n", "out vec2 uv;\n", "out vec4 out_position;\n", "#endif\n", "#ifdef GL_FRAGMENT_SHADER\n", "in vec3 in_worldPosition;\n", "in vec3 in_worldNormal;\n", "in vec3 in_worldTangent;\n", "in vec3 in_worldBitangent;\n", "in vec2 in_uv;\n", "#endif\n", "#ifdef GL_FRAGMENT_SHADER\n", "layout(location = 0) out vec4 out_color;\n", "#endif\n", "struct FragmentOutput {\n", " vec4 color;\n", "};\n", "\n", "uniform mat4 modelMatrix;\n", "uniform mat4 viewProjectionMatrix;\n", "uniform mat3 normalMatrix;\n", "layout(binding = 0) uniform sampler2D albedoMap;\n", "layout(binding = 1) uniform sampler2D normalMap;\n", "layout(binding = 2) uniform sampler2D metallicRoughnessMap;\n", "uniform vec3 cameraPosition;\n", "uniform vec3 lightPositions[MAX_LIGHTS];\n", "uniform vec3 lightColors[MAX_LIGHTS];\n", "uniform int activeLightCount;\n", "uniform vec3 baseColor;\n", "uniform float metallicFactor;\n", "uniform float roughnessFactor;\n", "float distributionGGX(vec3 normal, vec3 halfVector, float roughness) {\n", " float alpha = (roughness * roughness);\n", " float alpha2 = (alpha * alpha);\n", " float ndoth = max(dot(normal, halfVector), 0.0);\n", " float denom = (((ndoth * ndoth) * (alpha2 - 1.0)) + 1.0);\n", " return (alpha2 / max(((PI * denom) * denom), EPSILON));\n", "}\n", "\n", "float geometrySchlickGGX(float ndotv, float roughness) {\n", " float k = (((roughness + 1.0) * (roughness + 1.0)) / 8.0);\n", " return (ndotv / max(((ndotv * (1.0 - k)) + k), EPSILON));\n", "}\n", "\n", "float geometrySmith(vec3 normal, vec3 viewDir, vec3 lightDir, float roughness) {\n", " float ndotv = max(dot(normal, viewDir), 0.0);\n", " float ndotl = max(dot(normal, lightDir), 0.0);\n", " return (geometrySchlickGGX(ndotv, roughness) *\n", " geometrySchlickGGX(ndotl, roughness));\n", "}\n", "\n", "vec3 fresnelSchlick(float cosTheta, vec3 baseReflectance) {\n", " return (baseReflectance + ((vec3(1.0) - baseReflectance) *\n", " pow(max((1.0 - cosTheta), 0.0), 5.0)));\n", "}\n", "\n", "#ifdef GL_VERTEX_SHADER\n", "// Vertex Shader\n", "void main() {\n", " vec4 worldPosition_ = (modelMatrix * vec4(position, 1.0));\n", " worldPosition = worldPosition_.xyz;\n", " worldNormal = normalize((normalMatrix * normal));\n", " worldTangent = normalize((normalMatrix * tangent));\n", " worldBitangent = normalize(cross(worldNormal, worldTangent));\n", " uv = texCoord;\n", " out_position = (viewProjectionMatrix * worldPosition_);\n", " return;\n", "}\n", "\n", "#endif\n", "#ifdef GL_FRAGMENT_SHADER\n", "// Fragment Shader\n", "vec3 decodeNormal(vec3 encodedNormal, mat3 tangentFrame) {\n", " vec3 tangentNormal = ((encodedNormal * 2.0) - 1.0);\n", " return normalize((tangentFrame * tangentNormal));\n", "}\n", "\n", "void main() {\n", " mat3 tangentFrame =\n", " mat3(normalize(in_worldTangent), normalize(in_worldBitangent),\n", " normalize(in_worldNormal));\n", " vec3 normal = decodeNormal(texture(normalMap, in_uv).rgb, tangentFrame);\n", " vec3 viewDir = normalize((cameraPosition - in_worldPosition));\n", " vec3 albedo = (texture(albedoMap, in_uv).rgb * baseColor);\n", " vec3 materialSample = texture(metallicRoughnessMap, in_uv).rgb;\n", " float metallic = clamp((materialSample.b * metallicFactor), 0.0, 1.0);\n", " float roughness = clamp((materialSample.g * roughnessFactor), 0.04, 1.0);\n", " vec3 baseReflectance = mix(vec3(0.04), albedo, metallic);\n", " vec3 radianceSum = vec3(0.0);\n", " for (int i = 0; (i < MAX_LIGHTS); (++i)) {\n", " if ((i >= activeLightCount)) {\n", " break;\n", " }\n", " vec3 lightVector = (lightPositions[i] - in_worldPosition);\n", " float distanceSq = max(dot(lightVector, lightVector), EPSILON);\n", " vec3 lightDir = normalize(lightVector);\n", " vec3 halfVector = normalize((viewDir + lightDir));\n", " float attenuation = (1.0 / distanceSq);\n", " vec3 radiance = (lightColors[i] * attenuation);\n", " float normalDistribution = distributionGGX(normal, halfVector, roughness);\n", " float geometry = geometrySmith(normal, viewDir, lightDir, roughness);\n", " vec3 fresnel =\n", " fresnelSchlick(max(dot(halfVector, viewDir), 0.0), baseReflectance);\n", " vec3 diffuseShare = ((vec3(1.0) - fresnel) * (1.0 - metallic));\n", " vec3 numerator = ((normalDistribution * geometry) * fresnel);\n", " float denominator = max(((4.0 * max(dot(normal, viewDir), 0.0)) *\n", " max(dot(normal, lightDir), 0.0)),\n", " EPSILON);\n", " vec3 specular = (numerator / denominator);\n", " float ndotl = max(dot(normal, lightDir), 0.0);\n", " radianceSum +=\n", " (((((diffuseShare * albedo) / PI) + specular) * radiance) * ndotl);\n", " }\n", " vec3 ambient = (albedo * 0.03);\n", " vec3 color = (ambient + radianceSum);\n", " color = (color / (color + vec3(1.0)));\n", " color = pow(color, vec3((1.0 / 2.2)));\n", " out_color = vec4(color, 1.0);\n", " return;\n", "}\n", "\n", "#endif\n", "\n", "```" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "display(Markdown(f\"\"\"### DirectX / HLSL\n", "```hlsl\n", "{generated['directx']}\n", "```\"\"\"))\n", "display(Markdown(f\"\"\"### OpenGL / GLSL\n", "```glsl\n", "{generated['opengl']}\n", "```\"\"\"))\n" ] }, { "cell_type": "markdown", "id": "6a5bbb5b", "metadata": {}, "source": [ "## Full Backend Matrix\n", "\n", "The remaining targets are summarized with short previews to keep the notebook readable while still proving that each translation path produces output from the same source." ] }, { "cell_type": "code", "execution_count": 6, "id": "e859fac4", "metadata": { "execution": { "iopub.execute_input": "2026-06-23T12:17:48.396100Z", "iopub.status.busy": "2026-06-23T12:17:48.396002Z", "iopub.status.idle": "2026-06-23T12:17:48.402769Z", "shell.execute_reply": "2026-06-23T12:17:48.402489Z" } }, "outputs": [ { "data": { "text/markdown": [ "| Backend | Lines | Key signal |\n", "|---|---:|---|\n", "| `metal` | 162 | vertex/fragment Metal stage functions |\n", "| `directx` | 139 | VSMain/PSMain with HLSL semantics |\n", "| `opengl` | 137 | GLSL 450 stage guards |\n", "| `vulkan` | 665 | SPIR-V assembly entry points |\n", "| `cuda` | 3625 | CUDA helper and kernel-oriented output |\n", "| `hip` | 3610 | HIP helper and kernel-oriented output |\n", "| `slang` | 137 | Slang shader attributes and samplers |\n", "| `wgsl` | 147 | WGSL vertex/fragment entry points |\n", "| `webgl` | 138 | GLSL ES/WebGL-compatible output |" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/markdown": [ "### vulkan\n", "```text\n", "; SPIR-V\n", "; Version: 1.0\n", "; Generator: Khronos SPIR-V Tools Assembler; 0\n", "; Bound: 452\n", "; Schema: 0\n", " OpCapability Shader\n", " %1 = OpExtInstImport \"GLSL.std.450\"\n", " OpMemoryModel Logical GLSL450\n", " OpEntryPoint Vertex %2 \"main\" %CrossGL_vertex_output_main_worldPosition %CrossGL_vertex_output_main_worldNormal %CrossGL_vertex_output_main_worldTangent %CrossGL_vertex_output_main_worldBitangent %CrossGL_vertex_output_main_uv %gl_Position %CrossGL_vertex_input_input_position %CrossGL_vertex_input_input_normal %CrossGL_vertex_input_input_tangent %CrossGL_vertex_input_input_texCoord\n", " OpEntryPoint Fragment %13 \"main\" %CrossGL_fragment_output_main_color %CrossGL_fragment_input_input_worldPosition %CrossGL_fragment_input_input_worldNormal %CrossGL_fragment_input_input_worldTangent %CrossGL_fragment_input_input_worldBitangent %CrossGL_fragment_input_input_uv\n", " OpExecutionMode %13 OriginUpperLeft\n", " OpName %VertexInput \"VertexInput\"\n", " OpMemberName %VertexInput 0 \"position\"\n", " OpMemberName %VertexInput 1 \"normal\"\n", " OpMemberName %VertexInput 2 \"tangent\"\n", " OpMemberName %VertexInput 3 \"texCoord\"\n", " OpName %VertexOutput \"VertexOutput\"\n", " OpMemberName %VertexOutput 0 \"worldPosition\"\n", " OpMemberName %VertexOutput 1 \"worldNormal\"\n", " OpMemberName %VertexOutput 2 \"worldTangent\"\n", " OpMemberName %VertexOutput 3 \"worldBitangent\"\n", " OpMemberName %VertexOutput 4 \"uv\"\n", " OpMemberName %VertexOutput 5 \"position\"\n", " OpName %FragmentInput \"FragmentInput\"\n", " OpMemberName %FragmentInput 0 \"worldPosition\"\n", " OpMemberName %FragmentInput 1 \"worldNormal\"\n", " OpMemberName %FragmentInput 2 \"worldTangent\"\n", " OpMemberName %FragmentInput 3 \"worldBitangent\"\n", " OpMemberName %FragmentInput 4 \"uv\"\n", " OpName %FragmentOutput \"FragmentOutput\"\n", " OpMemberName %FragmentOutput 0 \"color\"\n", " OpName %PI \"PI\"\n", " OpName %EPSILON \"EPSILON\"\n", " OpName %MAX_LIGHTS \"MAX_LIGHTS\"\n", " OpName %normal \"normal\"\n", " OpName %halfVector \"halfVector\"\n", "// ... (665 total lines)\n", "```" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/markdown": [ "### slang\n", "```hlsl\n", "static const float PI = 3.14159265359;\n", "static const float EPSILON = 0.0001;\n", "static const int MAX_LIGHTS = 4;\n", "\n", "struct VertexInput\n", "{\n", " float3 position : POSITION;\n", " float3 normal : TEXCOORD0;\n", " float3 tangent : TEXCOORD1;\n", " float2 texCoord : TEXCOORD2;\n", "};\n", "\n", "struct VertexOutput\n", "{\n", " float3 worldPosition : TEXCOORD0;\n", " float3 worldNormal : TEXCOORD1;\n", " float3 worldTangent : TEXCOORD2;\n", " float3 worldBitangent : TEXCOORD3;\n", " float2 uv : TEXCOORD4;\n", " float4 position : SV_Position;\n", "};\n", "\n", "struct FragmentInput\n", "{\n", " float3 worldPosition : TEXCOORD0;\n", " float3 worldNormal : TEXCOORD1;\n", " float3 worldTangent : TEXCOORD2;\n", " float3 worldBitangent : TEXCOORD3;\n", " float2 uv : TEXCOORD4;\n", "};\n", "\n", "struct FragmentOutput\n", "{\n", " float4 color : SV_Target;\n", "};\n", "\n", "// ... (137 total lines)\n", "```" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/markdown": [ "### wgsl\n", "```wgsl\n", "// Generated by CrossGL for WebGPU WGSL\n", "\n", "struct VertexInput {\n", " @location(0) position: vec3,\n", " @location(1) normal: vec3,\n", " @location(2) tangent: vec3,\n", " @location(3) texCoord: vec2,\n", "};\n", "\n", "struct VertexOutput {\n", " @location(0) worldPosition: vec3,\n", " @location(1) worldNormal: vec3,\n", " @location(2) worldTangent: vec3,\n", " @location(3) worldBitangent: vec3,\n", " @location(4) uv: vec2,\n", " @builtin(position) position: vec4,\n", "};\n", "\n", "struct FragmentInput {\n", " @location(0) worldPosition: vec3,\n", " @location(1) worldNormal: vec3,\n", " @location(2) worldTangent: vec3,\n", " @location(3) worldBitangent: vec3,\n", " @location(4) uv: vec2,\n", "};\n", "\n", "struct FragmentOutput {\n", " @location(0) color: vec4,\n", "};\n", "\n", "const PI: f32 = 3.14159265359;\n", "const EPSILON: f32 = 0.0001;\n", "const MAX_LIGHTS: i32 = 4;\n", "\n", "@group(0) @binding(0)\n", "var modelMatrix: mat4x4;\n", "// ... (147 total lines)\n", "```" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/markdown": [ "### webgl\n", "```glsl\n", "#version 300 es\n", "precision highp float;\n", "precision highp int;\n", "const float PI = 3.14159265359;\n", "const float EPSILON = 0.0001;\n", "const int MAX_LIGHTS = 4;\n", "\n", "#ifdef GL_VERTEX_SHADER\n", "in vec3 position;\n", "in vec3 normal;\n", "in vec3 tangent;\n", "in vec2 texCoord;\n", "#endif\n", "#ifdef GL_VERTEX_SHADER\n", "out vec3 worldPosition;\n", "out vec3 worldNormal;\n", "out vec3 worldTangent;\n", "out vec3 worldBitangent;\n", "out vec2 uv;\n", "out vec4 out_position;\n", "#endif\n", "#ifdef GL_FRAGMENT_SHADER\n", "in vec3 worldPosition;\n", "in vec3 worldNormal;\n", "in vec3 worldTangent;\n", "in vec3 worldBitangent;\n", "in vec2 uv;\n", "#endif\n", "#ifdef GL_FRAGMENT_SHADER\n", "layout(location = 0) out vec4 out_color;\n", "#endif\n", "struct FragmentOutput {\n", " vec4 color;\n", "};\n", "\n", "uniform mat4 modelMatrix;\n", "// ... (138 total lines)\n", "```" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/markdown": [ "### cuda\n", "```cuda\n", "#include \n", "#include \n", "#include \n", "__device__ inline float cgl_float3_dot(float3 lhs, float3 rhs) {\n", " return (lhs.x * rhs.x) + (lhs.y * rhs.y) + (lhs.z * rhs.z);\n", "}\n", "\n", "__device__ inline float3 cgl_float3_sub(float3 lhs, float3 rhs) {\n", " return make_float3((lhs.x - rhs.x), (lhs.y - rhs.y), (lhs.z - rhs.z));\n", "}\n", "\n", "__device__ inline float3 cgl_float3_mul_scalar(float3 lhs, float rhs) {\n", " return make_float3((lhs.x * rhs), (lhs.y * rhs), (lhs.z * rhs));\n", "}\n", "\n", "__device__ inline float3 cgl_float3_add(float3 lhs, float3 rhs) {\n", " return make_float3((lhs.x + rhs.x), (lhs.y + rhs.y), (lhs.z + rhs.z));\n", "}\n", "\n", "__device__ inline float cgl_float3_length(float3 value) {\n", " return sqrtf((value.x * value.x) + (value.y * value.y) + (value.z * value.z));\n", "}\n", "\n", "__device__ inline float3 cgl_float3_normalize(float3 value) {\n", " float inv_length = 1.0f / cgl_float3_length(value);\n", " return make_float3((value.x * inv_length), (value.y * inv_length),\n", " (value.z * inv_length));\n", "}\n", "\n", "__device__ inline float3 cgl_float3_cross(float3 lhs, float3 rhs) {\n", " return make_float3((lhs.y * rhs.z - lhs.z * rhs.y),\n", " (lhs.z * rhs.x - lhs.x * rhs.z),\n", " (lhs.x * rhs.y - lhs.y * rhs.x));\n", "}\n", "\n", "__device__ inline float3 cgl_float3_sub_scalar(float3 lhs, float rhs) {\n", "// ... (3625 total lines)\n", "```" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/markdown": [ "### hip\n", "```cpp\n", "#include \n", "#include \n", "#include \n", "#include \n", "#include \n", "__device__ inline float cgl_float3_dot(float3 lhs, float3 rhs) {\n", " return (lhs.x * rhs.x) + (lhs.y * rhs.y) + (lhs.z * rhs.z);\n", "}\n", "\n", "__device__ inline float3 cgl_float3_sub(float3 lhs, float3 rhs) {\n", " return make_float3((lhs.x - rhs.x), (lhs.y - rhs.y), (lhs.z - rhs.z));\n", "}\n", "\n", "__device__ inline float3 cgl_float3_mul_scalar(float3 lhs, float rhs) {\n", " return make_float3((lhs.x * rhs), (lhs.y * rhs), (lhs.z * rhs));\n", "}\n", "\n", "__device__ inline float3 cgl_float3_add(float3 lhs, float3 rhs) {\n", " return make_float3((lhs.x + rhs.x), (lhs.y + rhs.y), (lhs.z + rhs.z));\n", "}\n", "\n", "__device__ inline float cgl_float3_length(float3 value) {\n", " return sqrtf((value.x * value.x) + (value.y * value.y) + (value.z * value.z));\n", "}\n", "\n", "__device__ inline float3 cgl_float3_normalize(float3 value) {\n", " float inv_length = 1.0f / cgl_float3_length(value);\n", " return make_float3((value.x * inv_length), (value.y * inv_length),\n", " (value.z * inv_length));\n", "}\n", "\n", "__device__ inline float3 cgl_float3_cross(float3 lhs, float3 rhs) {\n", " return make_float3((lhs.y * rhs.z - lhs.z * rhs.y),\n", " (lhs.z * rhs.x - lhs.x * rhs.z),\n", " (lhs.x * rhs.y - lhs.y * rhs.x));\n", "}\n", "// ... (3610 total lines)\n", "```" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "def preview(code: str, max_lines: int = 36) -> str:\n", " lines = code.splitlines()\n", " head = \"\\n\".join(lines[:max_lines])\n", " if len(lines) > max_lines:\n", " return f\"{head}\\n// ... ({len(lines)} total lines)\"\n", " return head\n", "\n", "rows = [\"| Backend | Lines | Key signal |\", \"|---|---:|---|\"]\n", "signals = {\n", " \"metal\": \"vertex/fragment Metal stage functions\",\n", " \"directx\": \"VSMain/PSMain with HLSL semantics\",\n", " \"opengl\": \"GLSL 450 stage guards\",\n", " \"vulkan\": \"SPIR-V assembly entry points\",\n", " \"cuda\": \"CUDA helper and kernel-oriented output\",\n", " \"hip\": \"HIP helper and kernel-oriented output\",\n", " \"slang\": \"Slang shader attributes and samplers\",\n", " \"wgsl\": \"WGSL vertex/fragment entry points\",\n", " \"webgl\": \"GLSL ES/WebGL-compatible output\",\n", "}\n", "for backend, code in generated.items():\n", " rows.append(f\"| `{backend}` | {len(code.splitlines())} | {signals[backend]} |\")\n", "\n", "display(Markdown(\"\\n\".join(rows)))\n", "\n", "for backend in [\"vulkan\", \"slang\", \"wgsl\", \"webgl\", \"cuda\", \"hip\"]:\n", " language = BACKENDS[backend]\n", " display(Markdown(f\"\"\"### {backend}\n", "```{language}\n", "{preview(generated[backend])}\n", "```\"\"\"))\n" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.20" } }, "nbformat": 4, "nbformat_minor": 5 }