Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
30afa6c
base for wgsl writer
Kbz-8 Apr 14, 2025
bc546c4
removing garbage file
Kbz-8 Apr 14, 2025
bfcd013
adding sanitazation
Kbz-8 Apr 14, 2025
83e6832
working on external statements ci skip
Kbz-8 Apr 14, 2025
82e9ea5
working on external implementation
Kbz-8 Apr 14, 2025
b922d20
working on wgsl backend
Kbz-8 Apr 15, 2025
329249a
adding binding shift to groups
Kbz-8 Apr 17, 2025
49dc8c5
adding some tests
Kbz-8 Apr 24, 2025
f22dcc8
ading tests
Kbz-8 Apr 27, 2025
bb6a9d1
adding tests
Kbz-8 May 18, 2025
11577b7
working on a rebase
Kbz-8 Aug 28, 2025
9b61a03
fixing rebase, fixing unary management, bitwise operators and unit te…
Kbz-8 Aug 28, 2025
a807be0
fixing unit tests, adding type constants, early depth tests, depth wr…
Kbz-8 Aug 30, 2025
b31ac16
pushing a lot of work
Kbz-8 Sep 7, 2025
7e83fe6
adding swizzle assignment removal transformer
Kbz-8 Sep 14, 2025
b46a1f2
fixing codestyle consistency
Kbz-8 Sep 15, 2025
7a7499f
documenting failing WGSL tests, fixing some
Kbz-8 Sep 15, 2025
f0f9d1d
removing merge trashes from gitignore
Kbz-8 Sep 15, 2025
36df049
Merge branch 'main' into main
SirLynix Sep 15, 2025
b3ee2c1
fixing after-merge compilation issues
Kbz-8 Sep 15, 2025
da0e678
fixing all unit tests
Kbz-8 Sep 15, 2025
2e7a582
removing unused nazara's xmake repo
Kbz-8 Sep 15, 2025
bc91adb
removing test example
Kbz-8 Sep 16, 2025
fbb63a4
adding debug logging to CI
Kbz-8 Sep 16, 2025
bc39710
adding missing tests (woops)
Kbz-8 Sep 16, 2025
76ed51d
adding inout implementation of WgslWriter
Kbz-8 Sep 16, 2025
c18c495
adding SamplerType splitting in function calls and function parameters
Kbz-8 Sep 16, 2025
9d059de
implementing missing tests, fixing binding array texture support, fix…
Kbz-8 Sep 16, 2025
af23bc0
removing texture 1d array from wgsl, fixing texture sampling functions
Kbz-8 Sep 16, 2025
c9a3bfd
fixing arrays of textures test
Kbz-8 Sep 16, 2025
be783fd
fixing access member tests
Kbz-8 Sep 16, 2025
67e9430
adding matrix inverse helper
Kbz-8 Sep 17, 2025
61e54b6
fixing desc attributes, adding wgsl to CLI
Kbz-8 Sep 17, 2025
e68e962
adding WGSL to readme
Kbz-8 Sep 17, 2025
9f82312
removing invalid and unused statements and attributes
Kbz-8 Sep 17, 2025
df7cd8e
begenning builtin emulations
Kbz-8 Sep 18, 2025
164dd64
adding unsupported builtin emulation, fixing interpolate attribute
Kbz-8 Sep 20, 2025
e907419
fixing intrinsic test
Kbz-8 Sep 20, 2025
3564db1
adding WgslWritter to CNZSL API
Kbz-8 Oct 2, 2025
3024473
working on std140 for uniform buffers; ci skip
Kbz-8 Oct 8, 2025
cf09fc1
working on std140 layout emulation for uniform structs
Kbz-8 Oct 8, 2025
7683108
adding uniformtostd140 AST transformer
Kbz-8 Oct 12, 2025
6484aec
adding Std140 emulation transformer base
Kbz-8 Oct 13, 2025
7eccc66
Merge branch 'main' into main
SirLynix Oct 14, 2025
cb9ad72
adding helper striding struct to std140 emulator
Kbz-8 Oct 15, 2025
142b0ed
fixing not ansi C comments
Kbz-8 Nov 14, 2025
7e73b40
Merge branch 'main' into main
Kbz-8 Nov 14, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .gdb_history
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
b nzsl::WgslWriter::Visit(Ast::AccessIndexExpression&)
b nzsl::WgslWriter::Visit(nzsl::Ast::AccessIndexExpression&)
run /tmp/tes/main.nzsl --compile=wgsl -o /tmp/tes/
p m_currentState->std140EmulationState
n
n
p m_currentState->std140EmulationState
n
n
n
p m_currentState->std140EmulationState
q
run ~/Downloads/tes/main.nzsl --compile=wgsl -o @stdout
bt
q
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ jobs:

# Setup compilation mode and install project dependencies
- name: Configure xmake and install dependencies
run: xmake config --plat=${{ matrix.confs.plat }} --arch=${{ matrix.confs.arch }} --kind=${{ matrix.kind }} --mode=${{ matrix.confs.mode }} ${{ env.ADDITIONAL_CONF }} --ccache=n --yes
run: xmake config -vD --plat=${{ matrix.confs.plat }} --arch=${{ matrix.confs.arch }} --kind=${{ matrix.kind }} --mode=${{ matrix.confs.mode }} ${{ env.ADDITIONAL_CONF }} --ccache=n --yes

# Save dependencies
- name: Save cached xmake dependencies
Expand Down
32 changes: 18 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

# Nazara Shading Language (NZSL)

NZSL is a shader language inspired by Rust and C++ which compiles to GLSL or SPIR-V (without depending on SPIRV-Cross).
NZSL is a shader language inspired by Rust and C++ which compiles to GLSL, WGSL or SPIR-V (without depending on SPIRV-Cross).

### Why a new shader language?

Expand Down Expand Up @@ -48,25 +48,26 @@ fn main(input: VertOut) -> FragOut

You can find precompiled binaries in the [releases](https://github.com/NazaraEngine/ShaderLang/releases).

NZSL is designed to be embedded in a game engine / game / graphics application that uses GLSL / SPIR-V for its shaders.
NZSL is designed to be embedded in a game engine / game / graphics application that uses GLSL / WGSL / SPIR-V for its shaders.

You can use it to generate GLSL, GLSL ES and SPIR-V in two non-exclusive ways:
You can use it to generate GLSL, GLSL ES, WGSL and SPIR-V in two non-exclusive ways:

1) Using the offline NZSL compiler (nzslc) ahead of time, in a way similar to glslang or glslc today.
2) Use NZSL as a library in your application to compile shaders in a dynamic way, just as they're needed (which can be used to benefit from supported extensions to improve generation).

### Offline compilation

There are two binary tools you can use:
- **nzslc**: shader compiler, for compiling nzsl files to binary nzsl or directly to GLSL/SPIR-V.
- **nzslc**: shader compiler, for compiling nzsl files to binary nzsl or directly to GLSL/WGSL/SPIR-V.
- **nzsla**: shader archiver, store and compress all your compiled shaders in a single file.

**nzslc example usage:**

- Validating shader: `nzslc file.nzsl`
- Compile a shader to GLSL: `nzslc --compile=glsl file.nzsl`
- Compile a shader to SPIR-V: `nzslc --compile=spv file.nzsl`
- Compile a shader using modules to both GLSL and SPIR-V header includable version: `nzslc --module module_file.nzsl --module module_folder/ --compile=glsl-header,spv-header file.nzsl`
- Compile a shader to GLSL: `nzsl --compile=glsl file.nzsl`
- Compile a shader to WGSL: `nzsl --compile=wgsl file.nzsl`
- Compile a shader to SPIR-V: `nzsl --compile=spv file.nzsl`
- Compile a shader using modules to GLSL, WGSL and SPIR-V header includable version: `nzsl --module module_file.nzsl --module module_folder/ --compile=glsl-header,wgsl-header,spv-header file.nzsl`

Run `nzslc -h` to see all supported options.

Expand All @@ -86,6 +87,7 @@ Run `nzsla -h` to see all supported options.
#include <NZSL/Parser.hpp>
#include <NZSL/GlslWriter.hpp>
#include <NZSL/SpirvWriter.hpp>
#include <NZSL/WgslWriter.hpp>

int main()
{
Expand All @@ -98,10 +100,14 @@ int main()
nzsl::GlslWriter glslWriter;
nzsl::GlslWriter::Output output = glslWriter.Generate(shaderAst);
// output.code contains GLSL that can directly be used by OpenGL

nzsl::WgslWriter wgslWriter;
nzsl::WgslWriter::Output output = wgslWriter.Generate(shaderAst);
// output.code contains WGSL that can directly be used by WebGPU (or any native implementation)
}
```

The library contains a lot of options to customize the generation process (target SPIR-V/GLSL version, GLSL ES, gl_Position.y flipping, gl_Position.z remapping to match Vulkan semantics, supported OpenGL extensions, etc.).
The library contains a lot of options to customize the generation process (target SPIR-V/GLSL version, GLSL ES, gl_Position.y flipping, gl_Position.z remapping to match Vulkan semantics, supported OpenGL extensions, supported WebGPU features, etc.).

## Integration

Expand Down Expand Up @@ -136,13 +142,11 @@ At one of my previous working place we were using huge HLSL-derived shaders with

NZSL is designed to be small, fast and easy to debug, for example NZSL to GLSL retains a lot of the source code information which could be lost during SSA (SPIR-V) translation, even with debug symbols enabled.

## Is there a DXIL/WGSL backend?

Not yet, as I don't target Direct3D or WebGPU yet.

DXIL is not very different from SPIR-V and WGSL looks a lot like NZSL so it should be quite easy to add, though.
## Is there a DXIL backend?

See [this issue](https://github.com/NazaraEngine/ShaderLang/issues/13) for WGSL.
Not yet, as I don't target Direct3D yet.\
DXIL is not very different from SPIR-V so it should be quite easy to add, though.\
Note that [Shader Model 7 will accept SPIR-V](https://devblogs.microsoft.com/directx/directx-adopting-spir-v/) so NZSL will be usable with Direct3D.

## Are there limitations?

Expand Down
1 change: 1 addition & 0 deletions include/CNZSL/CNZSL.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@
#include <CNZSL/Parser.h>
#include <CNZSL/Serializer.h>
#include <CNZSL/SpirvWriter.h>
#include <CNZSL/WgslWriter.h>

#endif /* CNZSL_CNZSL_H */
1 change: 1 addition & 0 deletions include/CNZSL/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

Copyright (C) 2024 Jérôme "SirLynix" Leclercq (lynix680@gmail.com)
2024 REMqb (remqb at remqb dot fr)
2025 kbz_8 (contact@kbz8.me)

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
Expand Down
71 changes: 71 additions & 0 deletions include/CNZSL/WgslWriter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
Copyright (C) 2025 kbz_8 ( contact@kbz8.me )
This file is part of the "Nazara Shading Wgsluage - C Binding" project
For conditions of distribution and use, see copyright notice in Config.hpp
*/

#pragma once

#ifndef CNZSL_WGSLWRITER_H
#define CNZSL_WGSLWRITER_H

#include <CNZSL/Config.h>
#include <CNZSL/Module.h>
#include <CNZSL/ShaderStageType.h>
#include <CNZSL/BackendParameters.h>
#include <stddef.h>

#ifdef __cplusplus
extern "C"
{
#endif

typedef struct nzslWgslWriter nzslWgslWriter;
typedef struct nzslWgslOutput nzslWgslOutput;
typedef int (*nzslWgslWriterFeatureSupportCallback)(const char*);

typedef struct
{
nzslWgslWriterFeatureSupportCallback featuresCallback;
} nzslWgslWriterEnvironment;

CNZSL_API nzslWgslWriter* nzslWgslWriterCreate(void);
CNZSL_API void nzslWgslWriterDestroy(nzslWgslWriter* writerPtr);

CNZSL_API nzslWgslOutput* nzslWgslWriterGenerate(nzslWgslWriter* writerPtr, nzslModule* modulePtr, const nzslBackendParameters* backendParametersPtr);

/**
* Gets the last error message set by the last operation to this writer
*
* @param writerPtr
* @returns null-terminated error string
*/
CNZSL_API const char* nzslWgslWriterGetLastError(const nzslWgslWriter* writerPtr);

CNZSL_API void nzslWgslWriterSetEnv(nzslWgslWriter* writerPtr, const nzslWgslWriterEnvironment* env);

CNZSL_API void nzslWgslOutputDestroy(nzslWgslOutput* outputPtr);
CNZSL_API const char* nzslWgslOutputGetCode(const nzslWgslOutput* outputPtr, size_t* length);

/**
* As Wgsl does not support combined image samplers, those have to be
* splitted into texture and samplers, shifting the bindings in a given set.
*
* Returns the new binding assigned to a NZSL binding in a given set.
*
* @param output
* @param bindingName
* @return new binding or 0 if not found
*/
CNZSL_API unsigned int nzslWgslOutputGetBindingRemap(const nzslWgslOutput* outputPtr, unsigned int set, unsigned int binding);

CNZSL_API int nzslWgslOutputGetUsesDrawParameterBaseInstanceUniform(const nzslWgslOutput* outputPtr);
CNZSL_API int nzslWgslOutputGetUsesDrawParameterBaseVertexUniform(const nzslWgslOutput* outputPtr);
CNZSL_API int nzslWgslOutputGetUsesDrawParameterDrawIndexUniform(const nzslWgslOutput* outputPtr);

#ifdef __cplusplus
}
#endif

#endif /* CNZSL_WGSLWRITER_H */

3 changes: 3 additions & 0 deletions include/NZSL/Ast/Cloner.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ namespace nzsl::Ast
ModulePtr Clone(const Module& module);
StatementPtr Clone(const Statement& statement);

StructDescription Clone(const StructDescription& desc);

Cloner& operator=(const Cloner&) = delete;
Cloner& operator=(Cloner&&) = delete;

Expand Down Expand Up @@ -101,6 +103,7 @@ namespace nzsl::Ast
inline ExpressionPtr Clone(const Expression& node);
inline ModulePtr Clone(const Module& module);
inline StatementPtr Clone(const Statement& node);
inline StructDescription Clone(const StructDescription& desc);
}

#include <NZSL/Ast/Cloner.inl>
Expand Down
6 changes: 6 additions & 0 deletions include/NZSL/Ast/Cloner.inl
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,10 @@ namespace nzsl::Ast
Cloner cloner;
return cloner.Clone(node);
}

inline StructDescription Clone(const StructDescription& desc)
{
Cloner cloner;
return cloner.Clone(desc);
}
}
50 changes: 50 additions & 0 deletions include/NZSL/Ast/Transformations/Std140EmulationTransformer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (C) 2025 kbz_8 (contact@kbz8.me)
// This file is part of the "Nazara Shading Language" project
// For conditions of distribution and use, see copyright notice in Config.hpp

#pragma once

#ifndef NZSL_AST_TRANSFORMATIONS_STD140EMULATION_HPP
#define NZSL_AST_TRANSFORMATIONS_STD140EMULATION_HPP

#include <NZSL/Ast/Transformations/Transformer.hpp>
#include <unordered_map>

namespace nzsl::Ast
{
class NZSL_API Std140EmulationTransformer final : public Transformer
{
public:
struct Options;

Std140EmulationTransformer() = default;

inline bool Transform(Module& module, TransformerContext& context, std::string* error = nullptr);
bool Transform(Module& module, TransformerContext& context, const Options& options, std::string* error = nullptr);

struct Options
{
};

private:
using Transformer::Transform;

ExpressionTransformation Transform(AccessFieldExpression&& accessFieldExpr) override;
ExpressionTransformation Transform(AccessIndexExpression&& accessIndexExpr) override;
StatementTransformation Transform(DeclareStructStatement&& declStruct) override;

DeclareStructStatementPtr DeclareStride16PrimitiveHelper(PrimitiveType type, std::size_t moduleIndex, SourceLocation sourceLocation);
bool ComputeStructDeclarationPadding(StructDescription& desc, const SourceLocation& sourceLocation) const;
FieldOffsets ComputeStructFieldOffsets(const StructDescription& desc, const SourceLocation& sourceLocation) const;
bool HandleStd140Propagation(MultiStatementPtr& multiStatement, std::size_t structIndex, SourceLocation sourceLocation, bool shouldExport);

std::unordered_map<std::size_t /*structIndex*/, std::size_t /*newStructIndex*/> m_structStd140Map;
std::unordered_map<PrimitiveType, std::size_t /* structIndex */> m_stride16Structs;
const Options* m_options;
};
}

#include <NZSL/Ast/Transformations/Std140EmulationTransformer.inl>

#endif // NZSL_AST_TRANSFORMATIONS_STD140EMULATION_HPP

Empty file.
7 changes: 7 additions & 0 deletions include/NZSL/Ast/Transformations/SwizzleTransformer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,21 @@ namespace nzsl::Ast
struct Options
{
bool removeScalarSwizzling = false;
bool removeSwizzleAssigment = false;
};

private:
using Transformer::Transform;

ExpressionTransformation Transform(SwizzleExpression&& swizzle) override;
ExpressionTransformation Transform(AssignExpression&& assign) override;

void PushAssignment(AssignExpression* assign) noexcept;
void PopAssignment() noexcept;

std::vector<AssignExpression*> m_assignmentStack;
const Options* m_options;
bool m_inAssignmentLhs = false;
};
}

Expand Down
42 changes: 42 additions & 0 deletions include/NZSL/Ast/Transformations/UniformStructToStd140.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright (C) 2025 kbz_8 (contact@kbz8.me)
// This file is part of the "Nazara Shading Language" project
// For conditions of distribution and use, see copyright notice in Config.hpp

#pragma once

#ifndef NZSL_AST_TRANSFORMATIONS_UNIFORMSTRUCTTOSTD140_HPP
#define NZSL_AST_TRANSFORMATIONS_UNIFORMSTRUCTTOSTD140_HPP

#include <NZSL/Ast/Transformations/Transformer.hpp>

namespace nzsl::Ast
{
class NZSL_API UniformStructToStd140Transformer final : public Transformer
{
public:
struct Options;

UniformStructToStd140Transformer() = default;

inline bool Transform(Module& module, TransformerContext& context, std::string* error = nullptr);
bool Transform(Module& module, TransformerContext& context, const Options& options, std::string* error = nullptr);

struct Options
{
bool cloneStructIfUsedElsewhere = true;
};

private:
using Transformer::Transform;

StatementTransformation Transform(DeclareExternalStatement&& declExternal) override;
StatementTransformation Transform(DeclareStructStatement&& declStruct) override;

const Options* m_options;
std::unordered_map<std::size_t /*structIndex*/, std::size_t /*newStructIndex*/> m_structRemap;
};
}

#include <NZSL/Ast/Transformations/UniformStructToStd140.inl>

#endif // NZSL_AST_TRANSFORMATIONS_UNIFORMSTRUCTTOSTD140_HPP
11 changes: 11 additions & 0 deletions include/NZSL/Ast/Transformations/UniformStructToStd140.inl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (C) 2025 kbz_8 (contact@kbz8.me)
// This file is part of the "Nazara Shading Language" project
// For conditions of distribution and use, see copyright notice in Config.hpp

namespace nzsl::Ast
{
inline bool UniformStructToStd140Transformer::Transform(Module& module, TransformerContext& context, std::string* error)
{
return Transform(module, context, {}, error);
}
}
Loading
Loading