{"id":15137861,"url":"https://github.com/bevyengine/naga_oil","last_synced_at":"2025-05-14T20:09:09.015Z","repository":{"id":55874281,"uuid":"521886609","full_name":"bevyengine/naga_oil","owner":"bevyengine","description":null,"archived":false,"fork":false,"pushed_at":"2025-04-28T08:49:41.000Z","size":401,"stargazers_count":161,"open_issues_count":29,"forks_count":45,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-04-28T10:02:43.792Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bevyengine.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-08-06T08:12:05.000Z","updated_at":"2025-04-28T08:49:44.000Z","dependencies_parsed_at":"2023-02-16T01:50:18.332Z","dependency_job_id":"1c20a288-6226-425a-afc9-936aae810cd0","html_url":"https://github.com/bevyengine/naga_oil","commit_stats":{"total_commits":181,"total_committers":14,"mean_commits":"12.928571428571429","dds":"0.13259668508287292","last_synced_commit":"797bf597a00d79739c593d8c5c3caa549445e05f"},"previous_names":["bevyengine/naga_oil"],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bevyengine%2Fnaga_oil","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bevyengine%2Fnaga_oil/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bevyengine%2Fnaga_oil/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bevyengine%2Fnaga_oil/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bevyengine","download_url":"https://codeload.github.com/bevyengine/naga_oil/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254219374,"owners_count":22034397,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-09-26T07:02:51.686Z","updated_at":"2025-05-14T20:09:08.996Z","avatar_url":"https://github.com/bevyengine.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"Naga Organised Integration Library (`naga-oil`) is a crate for combining and manipulating shaders.\r\n\r\n- `compose` presents a modular shader composition framework\r\n- `prune` strips shaders down to required parts\r\n\r\nand probably less useful externally:\r\n- `derive` allows importing of items from multiple shaders into a single shader\r\n- `redirect` modifies a shader by substituting function calls and modifying bindings\r\n\r\n# Compose\r\n\r\nthe compose module allows construction of shaders from modules (which are themselves shaders).\r\n\r\nit does this by treating shaders as modules, and \r\n- building each module independently to naga IR\r\n- creating \"header\" files for each supported language, which are used to build dependent modules/shaders\r\n- making final shaders by combining the shader IR with the IR for imported modules\r\n\r\nfor multiple small shaders with large common imports, this can be faster than parsing the full source for each shader, and it allows for constructing shaders in a cleaner modular manner with better scope control.\r\n\r\n## imports\r\n\r\nshaders can be added to the composer as modules. this makes their types, constants, variables and functions available to modules/shaders that import them. note that importing a module will affect the final shader's global state if the module defines globals variables with bindings.\r\n\r\nmodules may include a `#define_import_path` directive that names the module:\r\n\r\n```wgsl\r\n#define_import_path my_module\r\n\r\nfn my_func() -\u003e f32 {\r\n\treturn 1.0;\r\n}\r\n```\r\n\r\nalternatively the module name can be specified as an argument to `Composer::add_composable_module`.\r\n\r\nshaders can then import the module with an `#import` directive (with an optional `as` name) :\r\n\r\n```wgsl\r\n#import my_module;\r\n#import my_other_module as mod2;\r\n\r\nfn main() -\u003e f32 {\r\n    let x = my_module::my_func();\r\n    let y = mod2::my_other_func();\r\n    return x*y;\r\n}\r\n```\r\n\r\nor import a comma-separated list of individual items :\r\n\r\n```wgsl\r\n#import my_module::{my_func, my_const}\r\n\r\nfn main() -\u003e f32 {\r\n    return my_func(my_const);\r\n}\r\n```\r\n\r\nSome rust-style import syntax is supported, and items can be directly imported using the fully qualified item name :\r\n\r\n```wgsl\r\n#import my_package::{\r\n    first_module::{item_one as item, item_two}, \r\n    second_module::submodule,\r\n}\r\n\r\nfn main() -\u003e f32 {\r\n    return item + item_two + submodule::subitem + my_package::third_module::item;\r\n}\r\n```\r\n\r\n`module::self` and `module::*` are not currently supported. \r\n\r\nimports can be nested - modules may import other modules, but not recursively. when a new module is added, all its `#import`s must already have been added.\r\nthe same module can be imported multiple times by different modules in the import tree.\r\nthere is no overlap of namespaces, so the same function names (or type, constant, or variable names) may be used in different modules.\r\n\r\nnote: the final shader will include the required dependencies (bindings, globals, consts, other functions) of any imported items that are used, but will not include the rest of the imported module. \r\n\r\n## overriding functions\r\n\r\nvirtual functions can be declared with the `virtual` keyword:\r\n```glsl\r\n    virtual fn point_light(world_position: vec3\u003cf32\u003e) -\u003e vec3\u003cf32\u003e { ... }\r\n```\r\nvirtual functions defined in imported modules can then be overridden using the `override` keyword:\r\n\r\n```wgsl\r\n#import bevy_pbr::lighting as Lighting\r\n\r\noverride fn Lighting::point_light (world_position: vec3\u003cf32\u003e) -\u003e vec3\u003cf32\u003e {\r\n    let original = Lighting::point_light(world_position);\r\n    let quantized = vec3\u003cu32\u003e(original * 3.0);\r\n    return vec3\u003cf32\u003e(quantized) / 3.0;\r\n}\r\n```\r\n\r\noverrides must either be declared in the top-level shader, or the module containing the override must be imported as an `additional_import` in a `Composer::add_composable_module` or `Composer::make_naga_module` call. using `#import` to import a module with overrides will not work due to tree-shaking.\r\n\r\noverride function definitions cause *all* calls to the original function in the entire shader scope to be replaced by calls to the new function, with the exception of calls within the override function itself.\r\n\r\nthe function signature of the override must match the base function. \r\n\r\noverrides can be specified at any point in the final shader's import tree. \r\n\r\nmultiple overrides can be applied to the same function. for example, given :\r\n- a module `a` containing a function `f`, \r\n- a module `b` that imports `a`, and containing an `override a::f` function, \r\n- a module `c` that imports `a` and `b`, and containing an `override a::f` function,\r\n\r\nthen `b` and `c` both specify an override for `a::f`. \r\n\r\nthe `override fn a::f` declared in module `b` may call to `a::f` within its body.\r\n\r\nthe `override fn a::f` declared in module `c` may call to `a::f` within its body, but the call will be redirected to `b::f`.\r\n\r\nany other calls to `a::f` (within modules `a` or `b`, or anywhere else) will end up redirected to `c::f`.\r\n\r\nin this way a chain or stack of overrides can be applied.\r\n\r\ndifferent overrides of the same function can be specified in different import branches. the final stack will be ordered based on the first occurrence of the override in the import tree (using a depth first search). \r\n\r\nnote that imports into a module/shader are processed in order, but are processed before the body of the current shader/module regardless of where they occur in that module, so there is no way to import a module containing an override and inject a call into the override stack prior to that imported override. you can instead create two modules each containing an override and import them into a parent module/shader to order them as required.\r\n\r\noverride functions can currently only be defined in wgsl.\r\n\r\nif the `override_any` crate feature is enabled, then the `virtual` keyword is not required for the function being overridden.\r\n\r\n## languages\r\n\r\nmodules can we written in GLSL or WGSL. shaders with entry points can be imported as modules (provided they have a `#define_import_path` directive). entry points are available to call from imported modules either via their name (for WGSL) or via `module::main` (for GLSL).\r\n\r\nfinal shaders can also be written in GLSL or WGSL. for GLSL users must specify whether the shader is a vertex shader or fragment shader via the ShaderType argument (GLSL compute shaders are not supported).\r\n\r\n## preprocessing\r\n\r\nwhen generating a final shader or adding a composable module, a set of `shader_def` string/value pairs must be provided. The value can be a bool (`ShaderDefValue::Bool`), an i32 (`ShaderDefValue::Int`) or a u32 (`ShaderDefValue::UInt`).\r\n\r\nthese allow conditional compilation of parts of modules and the final shader. conditional compilation is performed with `#if` / `#ifdef` / `#ifndef`, `#else` and `#endif` preprocessor directives:\r\n\r\n```wgsl\r\nfn get_number() -\u003e f32 {\r\n    #ifdef BIG_NUMBER\r\n        return 999.0;\r\n    #else\r\n        return 0.999;\r\n    #endif\r\n}\r\n```\r\nthe `#ifdef` directive matches when the def name exists in the input binding set (regardless of value). the `#ifndef` directive is the reverse.\r\n\r\nthe `#if` directive requires a def name, an operator, and a value for comparison:\r\n- the def name must be a provided `shader_def` name. \r\n- the operator must be one of `==`, `!=`, `\u003e=`, `\u003e`, `\u003c`, `\u003c=`\r\n- the value must be an integer literal if comparing to a `ShaderDefValue::Int` or `ShaderDefValue::Uint`, or `true` or `false` if comparing to a `ShaderDef::Bool`.\r\n\r\nshader defs can also be used in the shader source with `#SHADER_DEF` or `#{SHADER_DEF}`, and will be substituted for their value.\r\n\r\nthe preprocessor branching directives (`ifdef`, `ifndef` and `if`) can be prefixed with `#else` to create more complex control flows:\r\n\r\n```wgsl\r\nfn get_number() -\u003e f32 {\r\n    #ifdef BIG_NUMBER\r\n        return 999.0;\r\n    #else if USER_NUMBER \u003e 1\r\n        return f32(#USER_NUMBER)\r\n    #else\r\n        return 0.999;\r\n    #endif\r\n}\r\n```\r\n\r\nshader defs can be created or overridden at the start of the top-level shader with the `#define` directive:\r\n```wgsl\r\n#define USER_NUMBER 42\r\n```\r\nthe created value will default to `true` if not specified.\r\n\r\n## error reporting\r\n\r\ncodespan reporting for errors is available using the error `emit_to_string` method. this requires validation to be enabled, which is true by default. `Composer::non_validating()` produces a non-validating composer that is not able to give accurate error reporting.\r\n\r\n# prune\r\n\r\n- strips dead code and bindings from shaders based on specified required output. intended to be used for building reduced depth and/or normal shaders from arbitrary vertex/fragment shaders.\r\n\r\nproper docs tbd\r\n\r\n# redirect\r\n\r\n- redirects function calls\r\n- wip: rebinds global bindings\r\n- todo one day: translate between uniform, texture and buffer accesses so shaders written for direct passes can be used in indirect\r\n\r\nproper docs tbd\r\n\r\n# derive\r\n\r\n- builds a single self-contained naga module out of parts of one or more existing modules\r\n\r\nproper docs tbd\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbevyengine%2Fnaga_oil","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbevyengine%2Fnaga_oil","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbevyengine%2Fnaga_oil/lists"}