{"id":13731938,"url":"https://github.com/polymonster/pmfx-shader","last_synced_at":"2025-05-08T06:30:45.666Z","repository":{"id":37493142,"uuid":"195820234","full_name":"polymonster/pmfx-shader","owner":"polymonster","description":"Cross platform shader system for HLSL, GLSL, Metal and SPIR-V.","archived":false,"fork":false,"pushed_at":"2024-06-21T11:22:49.000Z","size":28460,"stargazers_count":339,"open_issues_count":0,"forks_count":10,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-08-04T02:10:37.671Z","etag":null,"topics":["gles","glsl","hlsl","metal","nvn","pssl","shader-compiler","shader-reflection","spirv","uber-shader","webgl"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/polymonster.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"license.md","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":"2019-07-08T13:43:01.000Z","updated_at":"2024-07-20T13:20:42.000Z","dependencies_parsed_at":"2024-06-22T04:11:37.946Z","dependency_job_id":"6fa86eac-d527-4cd4-b68a-455e03428cef","html_url":"https://github.com/polymonster/pmfx-shader","commit_stats":null,"previous_names":[],"tags_count":39,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/polymonster%2Fpmfx-shader","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/polymonster%2Fpmfx-shader/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/polymonster%2Fpmfx-shader/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/polymonster%2Fpmfx-shader/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/polymonster","download_url":"https://codeload.github.com/polymonster/pmfx-shader/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224707552,"owners_count":17356352,"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":["gles","glsl","hlsl","metal","nvn","pssl","shader-compiler","shader-reflection","spirv","uber-shader","webgl"],"created_at":"2024-08-03T02:01:41.948Z","updated_at":"2025-05-08T06:30:45.653Z","avatar_url":"https://github.com/polymonster.png","language":"Python","funding_links":[],"categories":["ComputerGraphics \u0026\u0026 Shadingv","Python","Graphics"],"sub_categories":["Google Analytics"],"readme":"# pmfx-shader\n\n[![tests](https://github.com/polymonster/pmfx-shader/actions/workflows/tests.yaml/badge.svg)](https://github.com/polymonster/pmfx-shader/actions/workflows/tests.yaml)[![release](https://github.com/polymonster/pmfx-shader/actions/workflows/release.yaml/badge.svg)](https://github.com/polymonster/pmfx-shader/actions/workflows/release.yaml)\n\nA cross platform shader system with multi-threaded offline compilation or platform shader source code generation. Output json reflection info and `.h` or `.rs` code generation with your shader structs, fx-like techniques and compile time branch evaluation via (uber-shader) \"permutations\". Version 1.0 is now in maintenence mode and Version 2.0 is in progress which aims to offer wider support for more modern GPU features.\n\n## Supported Targets\n\n- HLSL Shader Model 6 (pmfx -v2)\n- HLSL Shader Model 3+\n- GLSL 330+\n- GLES 300+ (WebGL 2.0)\n- GLSL 200 (compatibility)\n- GLES (WebGL 1.0) (compatibility)\n- SPIR-V. (Vulkan, OpenGL)\n- Metal 1.0+ (macOS, iOS, tvOS)\n- PSSL\n- NVN (Nintendo Switch)\n\n(compatibility) platforms for older hardware might not support all pmfx features and may have missing legacy features.\n\n## Dependencies\n\nWindows users need [vcredist 2013](https://www.microsoft.com/en-us/download/confirmation.aspx?id=40784) for the glsl/spirv validator.\n\n## Console Platforms\n\nCompilation for Orbis is supported but you will need the SDK's installed and the environment variables set.\n\nFor NVN there is an [executable](https://github.com/polymonster/pmfx-shader/tree/master/bin/nvn) included to compile to `nvn_glsc` but it will require the `NvnGlslc32.dll` to be installed along with the SDK.\n\n## Usage\n\nYou can use from source by cloning this repository and build `pmfx.py`, or install the latest packaged [release](https://github.com/polymonster/pmfx-shader/releases) if you do not need access to the source code.\n\n```text\npy -3 pmfx.py -help (windows)\npython3 pmfx.py -help (macos/linux)\n\n--------------------------------------------------------------------------------\npmfx shader (v2.0) -------------------------------------------------------------\n--------------------------------------------------------------------------------\ncommandline arguments:\n    -v1 compile using pmfx version 1 (legacy) will use v2 otherwise\n    -num_threads 4 (default) \u003csupply threadpool size\u003e\n    -shader_platform \u003chlsl, glsl, gles, spirv, metal, pssl, nvn\u003e\n    -shader_version (optional) \u003cshader version unless overridden in technique\u003e\n        hlsl: 3_0, 4_0 (default), 5_0, 6_0 [-v2]\n        glsl: 200, 330 (default), 420, 450\n        gles: 100, 300, 310, 350\n        spirv: 420 (default), 450\n        metal: 2.0 (default)\n        nvn: (glsl)\n    -metal_sdk [metal only] \u003ciphoneos, macosx, appletvos\u003e\n    -metal_min_os (optional) [metal only] \u003c9.0 - 13.0 (ios), 10.11 - 10.15 (macos)\u003e\n    -nvn_exe [nvn only] \u003cpath to execulatble that can compile glsl to nvn glslc\u003e\n    -extensions (optional) [glsl/gles only] \u003clist of glsl extension strings separated by spaces\u003e\n    -nvn_extensions (optional) [nvn only] \u003clist of nvn glsl extension strings separated by spaces\u003e\n    -i \u003clist of input files or directories separated by spaces\u003e\n    -o \u003coutput dir for shaders\u003e\n    -t \u003coutput dir for temp files\u003e\n    -h (optional) \u003coutput dir header file with shader structs\u003e\n    -d (optional) generate debuggable shader\n    -f (optional) force build / compile even if dependencies are up-to-date\n    -rs (optional) \u003coutput dir for rust crate with shader structs\u003e [-v2]\n    -root_dir (optional) \u003cdirectory\u003e sets working directory here\n    -source (optional) (generates platform source into -o no compilation)\n    -stage_in \u003c0, 1\u003e (optional) [metal only] (default 1)\n        uses stage_in for metal vertex buffers, 0 uses raw buffers\n    -cbuffer_offset (optional) [metal only] (default 4)\n        specifies an offset applied to cbuffer locations to avoid collisions with vertex buffers\n    -texture_offset (optional) [vulkan only] (default 32)\n        specifies an offset applied to texture locations to avoid collisions with buffers\n    -v_flip (optional) [glsl only] (inserts glsl uniform to conditionally flip verts in the y axis)\n    -args (optional) anything passed after this will be forward to the platform specific compiler\n         for example for fxc.exe /Zpr or dxc.exe -Zpr etc.. check the compiler help for options\n--------------------------------------------------------------------------------\n```\n\n## Versions\n\nThere are 2 code paths supported by pmfx, this is in an effort to keep up-to-date with modern graphics API's but also offer backward comptibility support to older graphics API's, mobile and web platforms.\n\n- [Version 1](https://github.com/polymonster/pmfx-shader#version-1) - (bindful render model, techniques, macro based cross platform shaders)\n- [Version 2](https://github.com/polymonster/pmfx-shader#version-2) - (bindless render model, pipelines, descriptors, SPIR-V based cross-compilation)\n\n## Version 1\n\nCompile with the `-v1` flag to select version 1.\n\nA single file does all the shader parsing and code generation. Simple syntax changes are handled through macros and defines found in [platform](https://github.com/polymonster/pmfx-shader/tree/master/platform), so it is simple to add new features or change things to behave how you like. More complex differences between shader languages are handled through code-generation.\n\nThis is a small part of the larger [pmfx](https://github.com/polymonster/pmtech/wiki/Pmfx) system found in [pmtech](https://github.com/polymonster/pmtech), it has been moved into a separate repository to be used with other projects, if you are interested to see how pmfx shaders are integrated please take a look [here](https://github.com/polymonster/pmtech).\n\n### Compiling Examples\n\nTake a look at the example [code](https://github.com/polymonster/pmfx-shader/tree/master/examples/v1).\n\n```text\n// metal macos\npython3 pmfx.py -v1 -shader_platform metal -metal_sdk macosx -metal_min_os 10.14 -shader_version 2.2 -i examples/v1 -o output/bin -h output/structs -t output/temp\n\n// metal ios\npython3 pmfx.py -v1 -shader_platform metal -metal_sdk iphoneos -metal_min_os 0.9 -shader_version 2.2 -i examples/v1 -o output/bin -h output/structs -t output/temp\n\n// spir-v vulkan\npython3 pmfx.py -v1 -shader_platform spirv -i examples/v1 -o output/bin -h output/structs -t output/temp\n\n// hlsl d3d11\npy -3 pmfx.py -v1 -shader_platform hlsl -shader_version 5_0 -i examples/v1 -o output/bin -h output/structs -t output/temp\n\n// glsl\npython3 pmfx.py -v1 -shader_platform glsl -shader_version 330 -i examples/v1 -o output/bin -h output/structs -t output/temp\n\n// gles\npython3 pmfx.py -v1 -shader_platform gles -shader_version 320 -i examples/v1 -o output/bin -h output/structs -t output/temp\n```\n\n### Version 1 shader language\n\nUse mostly HLSL syntax for shaders, with some small differences:\n\n#### Always use structs for inputs and outputs\n\n```hlsl\nstruct vs_input\n{\n    float4 position : POSITION;\n};\n\nstruct vs_output\n{\n    float4 position : SV_POSITION0;\n};\n\nvs_output vs_main( vs_input input )\n{\n    vs_output output;\n\n    output.position = input.position;\n\n    return output;\n}\n```\n\n#### Supported semantics and sizes\n\npmfx will generate an input layout for you in the json reflection info, containing the stride of the vertex layout and the byte offsets to each of the elements. If you choose to use this, pmfx will assume the following sizes for semantics:\n\n```hlsl\nPOSITION     // 32bit float\nTEXCOORD     // 32bit float\nNORMAL       // 32bit float\nTANGENT      // 32bit float\nBITANGENT    // 32bit float\nBLENDWEIGHTS // 32bit float\nCOLOR        // 8bit unsigned int\nBLENDINDICES // 8bit unsigned int\n```\n\n#### Shader resources\n\nDue to fundamental differences accross shader languages, shader resource declarations and access have a syntax unique to pmfx. Define a block of shader_resources to allow global textures or buffers as supported in HLSL and GLSL.\n\n```c\nshader_resources\n{\n    texture_2d( diffuse_texture, 0 );\n    texture_2dms( float4, 2, texture_msaa_2, 0 );\n};\n```\n\n#### Resource types\n\n```c\n// cbuffers are the same as regular hlsl\ncbuffer per_view : register(b0)\n{\n    float4x4 view_matrix;\n};\n\n// texture types\ntexture_2d( sampler_name, layout_index );\ntexture_2dms( type, samples, sampler_name, layout_index );\ntexture_2d_array( sampler_name, layout_index );\ntexture_cube( sampler_name, layout_index );\ntexture_cube_array( sampler_name, layout_index ); // requires sm 4+, gles 400+\ntexture_3d( sampler_name, layout_index );\ntexture_2d_external( sampler_name, layout_index ); // gles specific extension\n\n// depth formats are required for sampler compare ops\ndepth_2d( sampler_name, layout_index );\ndepth_2d_array( sampler_name, layout_index );\ndepth_cube( sampler_name, layout_index );\ndepth_cube_array( sampler_name, layout_index );\n\n// compute shader texture types\ntexture_2d_r( image_name, layout_index );\ntexture_2d_w( image_name, layout_index );\ntexture_2d_rw( image_name, layout_index );\ntexture_3d_r( image_name, layout_index );\ntexture_3d_w( image_name, layout_index );\ntexture_3d_rw( image_name, layout_index );\ntexture_2d_array_r( image_name, layout_index );\ntexture_2d_array_w( image_name, layout_index );\ntexture_2d_array_rw( image_name, layout_index );\n\n// compute shader buffer types\nstructured_buffer( type, name, index );\nstructured_buffer_rw( type, name, index );\natomic_counter(name, index);\n\n// bindless resouce tables\n// name, type, dimension, register, space\ntexture2d_table(texture0, float4, [], 0, 0);\ncbuffer_table(constant_buffer0, data, [], 1, 0);\nsampler_state_table(sampler0, [], 0);\n\n// smapler type\nsampler_state(sampler0, 0);\n```\n\n#### Accessing resources\n\nTextures and samplers are combined when using a binding renderer model. a `texture_2d` declares a texture and a sampler on the corresponding texture and sampler register index which is passed into the macro. The `sample_texture` can be used to sample textures of varying dimensions.\n\n```c\n// sample texture\nfloat4 col = sample_texture( diffuse_texture, texcoord.xy );\nfloat4 cube = sample_texture( cubemap_texture, normal.xyz );\nfloat4 msaa_sample = sample_texture_2dms( msaa_texture, x, y, fragment );\nfloat4 level = sample_texture_level( texture, texcoord.xy, mip_level);\nfloat4 array = sample_texture_array( texture, texcoord.xy, array_slice);\nfloat4 array_level = sample_texture_array_level( texture, texcoord.xy, array_slice, mip_level);\n\n// sample compare\nfloat shadow = sample_depth_compare( shadow_map, texcoord.xy, compare_ref);\nfloat shadow_array = sample_depth_compare_array( shadow_map, texcoord.xy, array_slice, compare_ref);\nfloat cube_shadow = sample_depth_compare_cube( shadow_map, texcoord.xyz, compare_ref);\nfloat cube_shadow_array = sample_depth_compare_cube_array( shadow_map, texcoord.xyz, array_slice, compare_ref);\n\n// compute rw texture\nfloat4 rwtex = read_texture( tex_rw, gid );\nwrite_texture(rwtex, val, gid);\n\n// compute structured buffer\nstruct val = structured_buffer[gid]; // read\nstructured_buffer[gid] = val;        // write\n\n// read type!\n// glsl expects ivec (int) to be pass to imageLoad, hlsl and metal require uint...\n// there is a `read` type you can use to be platform safe\nread3 read_coord = read3(x, y, z);\nread_texture( tex_rw, read_coord );\n```\n\n### Atomic Operations\n\nSupport for glsl, hlsl and metal compatible atomics and memory barriers is available. The atomic_counter resource type is a RWStructuredBuffer\u003cuint\u003e in hlsl, a atomic_uint read/write buffer in Metal and a uniform atomic_uint in GLSL.\n\n```hlsl\n// types\natomic_uint u;\natomic_int i;\n\n// operations\natomic_load(atomic, original)\natomic_store(atomic, value)\natomic_increment(atomic, original)\natomic_decrement(atomic, original)\natomic_add(atomic, value, original)\natomic_subtract(atomic, value, original)\natomic_min(atomic, value, original)\natomic_max(atomic, value, original)\natomic_and(atomic, value, original)\natomic_or(atomic, value, original)\natomic_xor(atomic, value, original)\natomic_exchange(atomic, value, original)\nthreadgroup_barrier()\ndevice_barrier()\n\n// usage\nshader_resources\n{\n    atomic_counter(counter, 0); // counter bound to index 0\n}\n\n// increments counter and stores the original value in 'index'\nuint index = 0;\natomic_increment(counter, index);\n```\n\n#### Includes\n\nInclude files are supported even though some shader platforms or versions may not support them natively.\n\n```c\n#include \"libs/lighting.pmfx\"\n#include \"libs/skinning.pmfx\"\n#include \"libs/globals.pmfx\"\n#include \"libs/sdf.pmfx\"\n#include \"libs/area_lights.pmfx\"\n```\n\n#### Extensions\n\nTo enable glsl extensions you can pass a list of strings to the `-extensions` commandline argument. The glsl extension will be inserted to the top of the generated code with `: require` set:\n\n```text\n-extensions GL_OES_EGL_image_external GL_OES_get_program_binary\n```\n\n## Unique pmfx features\n\n### GLES 2.0 / GLSL 2.0 cbuffers\n\ncbuffers are emulated for older glsl versions, a cbuffer is packed into a single float4 array. The uniform float4 array (`glUniform4fv`) is named after the cbuffer, you can find the uniform location from this name using `glUniformLocation`. The count of the float4 array is the number of members the cbuffer where float4 and float4x4 are supported and float4x4 count for 4 array elements. You can use the generated c++ structs from pmfx to create a coherent copy of the uniform data on the cpu. GLES 2.0 / GLSL 2.0 cbuffers\n\n### cbuffer_offset / texture_offset\n\nHLSL has different registers for textures, vertex buffers, cbuffers and un-ordered access views. Metal and Vulkan have some differences where the register indices are shared across different resource types. To avoid collisions in different API backends you can supply offsets using the following command line options.\n\nMetal: -cbuffer_offset (cbuffers start binding at this offset to allow vertex buffers to be bound to the slots prior to these offsets)\n\nVulkan: -texture_offset (textures start binding at this point allowing uniform buffers to bind to the prior slots)\n\n### v_flip\n\nOpenGL has different viewport co-ordinates to texture coordinate so when rendering to the backbuffer vs rendering into a render target you can get output results that are flipped in the y-axis, this can propagate it's way far into a code base with conditional \"v_flips\" happening during different render passes.\n\nTo solve this issue in a cross platform way, pmfx will expose a uniform bool called \"v_flip\" in all gl vertex shaders, this allows you to conditionally flip the y-coordinate when rendering to the backbuffer or not.\n\nTo make this work make sure you also change the winding glFrontFace(GL_CCW) to glFrontFace(GL_CW).\n\n### cbuffer padding\n\nHLSL/Direct3D requires cbuffers to be padded to 16 bytes alignment, pmfx allows you to create cbuffers with any size and will pad the rest out for you.\n\n### Techniques\n\nSingle .pmfx file can contain multiple shader functions so you can share functionality, you can define a block of [jsn](https://github.com/polymonster/jsn) in the shader to configure techniques. (jsn is a more lenient and user friendly data format similar to json).\n\nSimply specify `vs`, `ps` or `cs` to select which function in the source to use for that shader stage. If no pmfx: json block is found you can still supply `vs_main` and `ps_main` which will be output as a technique named \"default\".\n\n```jsonnet\npmfx:\n{\n    gbuffer: {\n        vs: vs_main\n        ps: ps_gbuffer\n    }\n\n    zonly: {\n        vs: vs_main_zonly\n        ps: ps_null\n    }\n}\n```\n\nYou can also use json to specify technique constants with range and ui type.. so you can later hook them into a gui:\n\n```jsonnet\nconstants:\n{\n    albedo: {\n        type: float4, widget: colour, default: [1.0, 1.0, 1.0, 1.0]\n    }\n    roughness: {\n        type: float, widget: slider, min: 0, max: 1, default: 0.5\n    }\n    reflectivity: {\n        type: float, widget: slider, min: 0, max: 1, default: 0.3\n    }\n}\n```\n\n![pmfx constants](https://github.com/polymonster/polymonster.github.io/raw/master/assets/wiki/pmfx-material.png)\n\nAccess to technique constants is done with m_prefix.\n\n```hlsl\nps_output ps_main(vs_output input)\n{\n    float4 col = m_albedo;\n}\n```\n\n### Permutations\n\nPermutations provide an uber shader style compile time branch evaluation to generate optimal shaders but allowing for flexibility to share code as much as possible. The pmfx block is used here again, you can specify permutations inside a technique.\n\n```yaml\npermutations:\n{\n    SKINNED: [31, [0,1]]\n    INSTANCED: [30, [0,1]]\n    UV_SCALE: [1, [0,1]]\n}\n```\n\nThe first parameter is a bit shift that we can check.. so skinned is 1\u003c\u003c31 and uv scale is 1\u003c\u003c1. The second value is number of options, so in the above example we just have on or off, but you could have a quality level 0-5 for instance.\n\nTo insert a compile time evaluated branch in code, use a colon after if / else\n\n```c++\nif:(SKINNED)\n{\n    float4 sp = skin_pos(input.position, input.blend_weights, input.blend_indices);\n    output.position = mul( sp, vp_matrix );\n}\nelse:\n{\n    output.position = mul( input.position, wvp );\n}\n```\n\nFor each permutation a shader is generated with the technique plus the permutation id. The id is generated from the values passed in the permutation object.\n\nAdding permutations can cause the number of generated shaders to grow exponentially, pmfx will detect redundant shader combinations using md5 hashing, to re-use duplicate permutation combinations and avoid un-necessary compilation.\n\n### C++ Header\n\nAfter compilation a header is output for each .pmfx file containing c struct declarations for the cbuffers, technique constant buffers and vertex inputs. You can use these sturcts to fill buffers in your c++ code and use sizeof for buffer update calls in your graphics api.\n\nIt also contains defines for the shader permutation id / flags that you can check and test against to select the correct shader permutations for a draw call (ie. skinned, instanced, etc).\n\n```c++\nnamespace debug\n{\n    struct per_pass_view\n    {\n        float4x4 view_projection_matrix;\n        float4x4 view_matrix;\n    };\n    struct per_pass_view_2d\n    {\n        float4x4 projection_matrix;\n        float4 user_data;\n    };\n    #define OMNI_SHADOW_SKINNED 2147483648\n    #define OMNI_SHADOW_INSTANCED 1073741824\n    #define FORWARD_LIT_SKINNED 2147483648\n    #define FORWARD_LIT_INSTANCED 1073741824\n    #define FORWARD_LIT_UV_SCALE 2\n    #define FORWARD_LIT_SSS 4\n    #define FORWARD_LIT_SDF_SHADOW 8\n}\n```\n\nA full example output c++ header can be viewed [here](https://github.com/polymonster/pmfx-shader/blob/master/examples/outputs/v1_header.json).\n\n### JSON Reflection Info\n\nEach .pmfx file comes along with a json file containing reflection info. This info contains the locations textures / buffers are bound to, the size of structs, vertex layout description and more, at this point please remember the output reflection info is fully compliant json, and not lightweight jsn.. this is because of the more widespread support of json.\n\n```json\n\"texture_sampler_bindings\": [\n    {\n        \"name\": \"gbuffer_albedo\",\n        \"data_type\": \"float4\",\n        \"fragments\": 1,\n        \"type\": \"texture_2d\",\n        \"unit\": 0\n    }]\n\n\"vs_inputs\": [\n    {\n        \"name\": \"position\",\n        \"semantic_index\": 0,\n        \"semantic_id\": 1,\n        \"size\": 16,\n        \"element_size\": 4,\n        \"num_elements\": 4,\n        \"offset\": 0\n    }]\n```\n\nYou can take a look at a full example output file included with this repositiory [here](https://github.com/polymonster/pmfx-shader/blob/master/examples/outputs/v1_info.json).\n\n## Version 2\n\nVersion 2 is currently work in progress, HLSL is used as the authorting shader language and SPIRV-cross is used to cross compile to other platforms.\n\nUse `.hlsl` files and hlsl source code, create a `.pmfx` which can create pipelines from small amount of meta data:\n\n```jsonnet\nimport other_files.pmfx\n{\n    // include shader source files\n    include: [\n        \"imdraw.hlsl\"\n    ]\n\n    // create pipelines\n    pipelines: {\n        imdraw_2d: {\n            vs: vs_2d\n            ps: ps_main\n            push_constants: [\"view_push_constants\"]\n            topology: \"LineList\"\n        }\n    }\n}\n```\n\nPipeline states can be specified and included in `.pmfx` files:\n\n```jsonnet\ndepth_stencil_states: {\n    depth_test_less: {\n        depth_enabled: true\n        depth_write_mask: All\n        depth_func: Less\n    }\n}\nraster_states: {\n    wireframe: {\n        fill_mode: Wireframe\n        depth_bias: -5\n    }\n    cull_back: {\n        cull_mode: Back\n    }\n}\npipelines: {\n    imdraw_mesh: {\n        depth_stencil_state: \"depth_test_less\"\n    }\n}\n```\n\nYou can specify textures or render targets:\n\n```jsonnet\ntextures: {\n    main_colour: {\n        ratio: {\n            window: \"main_window\",\n            scale: 1.0\n        }\n        format: RGBA8n\n        usage: [ShaderResource, RenderTarget]\n        samples: 8\n    }\n    main_depth(main_colour): {\n        format: D24nS8u\n        usage: [ShaderResource, DepthStencil]\n    }\n}\n```\n\nYou can `views` that can act as a render pass with custom data, you can extend these objects to contain custom data such as cameras or render functions to hook into your own engines or entity component systems:\n\n```jsonnet\nviews: {\n    main_view: {\n        render_target: [\n            \"main_colour\"\n        ]\n        clear_colour: [0.45, 0.55, 0.60, 1.0]\n        depth_stencil: [\n            \"main_depth\"\n        ]\n        clear_depth: 1.0\n        viewport: [0.0, 0.0, 1.0, 1.0, 0.0, 1.0]\n        camera: \"main_camera\"\n    }\n    main_view_no_clear(main_view): {\n        clear_colour: null\n        clear_depth: null\n    }\n}\n```\n\n`render_graphs` can be used to supply a collection of views with dependencies which can then be used to generate execution order and resource state transitions.\n\n```jsonnet\nrender_graphs: {\n    mesh_debug: {\n        grid: {\n            view: \"main_view\"\n            pipelines: [\"imdraw_3d\"]\n            function: \"render_grid\"\n        }\n        meshes: {\n            view: \"main_view_no_clear\"\n            pipelines: [\"mesh_debug\"]\n            function: \"render_meshes\"\n            depends_on: [\"grid\"]\n        }\n        wireframe: {\n            view: \"main_view_no_clear\"\n            pipelines: [\"wireframe_overlay\"]\n            function: \"render_meshes\"\n            depends_on: [\"meshes\", \"grid\"]\n        }\n    }\n}\n```\n\n`pmfx` supplies a framework and a schema to configure render state, it will still be down to you to implement that data in a graphics API or engine. If you want to take a look at an example project of how to use these features my graphics engine [hotline](https://github.com/polymonster/hotline) implemenents the feature set and utilises [serde](https://github.com/serde-rs/serde) to deserialise the output `json` directly into rust structures.\n\nFull [documentation](https://github.com/polymonster/pmfx-shader/blob/master/docs/v2.pmfx_doc) for pipeline specification is provided.\n\n### Building\n\nCompilation is simple with command line args as so:\n\n```text\npy -3 pmfx.py -shader_platform hlsl -shader_version 6_0 -i examples/v2/ -o build/data/shaders -t build/temp/shaders\n```\n\n### Examples\n\nTake a look at the example [code](https://github.com/polymonster/pmfx-shader/tree/master/examples/v2).\n\n### Output\n\nCompiled shaders and reflection information will be emitted to your chosen `-o` outout directory, Each `.pmfx` file will create a directory which it will compile shader binaries into. Shader compilation is minimised and reduced within single `.pmfx` files by sharing and re-using binaries which are identical across different shader permitations or stages.\n\nPipeline layout, descriptor bindings and vertex layout can be automatically generated based on resource usage inside shaders, the whole pipeline is exported as `.json` along with the built shaders. Hashes for the various pieces of the render pipline states are stored so you can quickly check for pipelines that may need rebuilding as part of a hot reloading process.\n\n```json\n\"imdraw_2d\": {\n    \"0\": {\n        \"vs\": \"vs_2d.vsc\",\n        \"ps\": \"ps_main.psc\",\n        \"push_constants\": [\n            \"view_push_constants\"\n        ],\n        \"topology\": \"LineList\",\n        \"vs_hash:\": 2752841994,\n        \"vertex_layout\": [\n            {\n                \"name\": \"position\",\n                \"semantic\": \"POSITION\",\n                \"index\": 0,\n                \"format\": \"RG32f\",\n                \"aligned_byte_offset\": 0,\n                \"input_slot\": 0,\n                \"input_slot_class\": \"PerVertex\",\n                \"step_rate\": 0\n            },\n            {\n                \"name\": \"colour\",\n                \"semantic\": \"TEXCOORD\",\n                \"index\": 0,\n                \"format\": \"RGBA32f\",\n                \"aligned_byte_offset\": 8,\n                \"input_slot\": 0,\n                \"input_slot_class\": \"PerVertex\",\n                \"step_rate\": 0\n        }\n    ],\n    \"error_code\": 0,\n    \"ps_hash:\": 2326464525,\n    \"pipeline_layout\": {\n        \"bindings\": [],\n        \"push_constants\": [\n            {\n                \"shader_register\": 0,\n                \"register_space\": 0,\n                \"binding_type\": \"ConstantBuffer\",\n                \"visibility\": \"Vertex\",\n                \"num_values\": 16\n            }\n        ],\n        \"static_samplers\": []\n    },\n    \"hash\": 3046174282\n    }\n}\n```\n\nYou can take a look an example output `json` reflection file included in this repository [here](https://github.com/polymonster/pmfx-shader/blob/master/examples/outputs/v2_info.json).\n\n### Touch\n\nWhen building pipeline, descriptor or vertex layouts, `pmfx` will detect which resources you are using, when debugging you may comment out or remove references to used resources and this may cause knock on issues with the associated slots and layouts you expect in your graphics engine. You can use the `pmfx_touch` macro to ensure that a reosurce type is included in a particular layout to avoid this issue without throwing a warning.\n\n```hlsl\nstruct cbuffer_struct {\n    float4x4 world_matrix;\n};\nConstantBuffer\u003ccbuffer_struct\u003e unused_cbuffer : register(b0);\n\nvs_output vs_test_use_cbuffer_unscoped() {\n    vs_output output = vs_output_default();\n\n    // ..\n\n    pmfx_touch(unused_cbuffer);\n\n    return output;\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpolymonster%2Fpmfx-shader","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpolymonster%2Fpmfx-shader","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpolymonster%2Fpmfx-shader/lists"}