Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[axmol-2.0] Support GLES3/OpenGL3 #1279

Closed
20 tasks done
halx99 opened this issue Jul 17, 2023 · 29 comments
Closed
20 tasks done

[axmol-2.0] Support GLES3/OpenGL3 #1279

halx99 opened this issue Jul 17, 2023 · 29 comments

Comments

@halx99
Copy link
Collaborator

halx99 commented Jul 17, 2023

Released

UPDATE

GLES3/OpenGL3 support was moved to milestone 2.0, and still support GLES2.0 for old android device and android simulator marketplace of china

workflow

  1. Write shader language by ESSL 310 or GLSL 450
  2. Add all shader files into project_root/Source/shaders, default shader file extensions: vertex(.vert, .vsh), fragment(.frag, .fsh)
  3. Engine will auto add shader files as glscc compiling files
  4. glscc compile source shaders to target platforms: Desktop GL(GLSL330), GLES3(ESSL300), GLES2(GLSL100), Apple Metal(MSL)
  5. Engine auto sync compiled runtime shader folder(${CMAKE_BINARY_DIR}/runtime/axslc) to target app app_res_root/axslc, and app_res_root/axslc will be added to search path by engine FileUtils implementation.
  6. Start app, load compiled shaders from app_res_root/axslc by shader name.

checklist

  • Mesh instancing draw, implemented by @DelinWorks and adpte metal backend by @halx99
  • axmolengine/glslcc 1.9.0 by @halx99
  • AXGLSLCC.cmake cmake tool by @halx99
  • Migrate engine shaders to ESSL 310 for glslcc spirv happy to compile them to target platforms: ESSL 300, GLES 330, MSL
  • Shader migrate tool: amol-migrate-1.1 by @delin and @halx99, because glslcc(spirv-cross) only accept ESSL310 or GLSL450 as input shader.
  • Android: switch GLES loader to glad for auto loading GLES3 APIs , i.e. glDrawElementsInstanced
  • OpenGL UBO support by @delin @halx99
  • Metal load compiled binary shader files (sgs format specified by glslcc) by @halx99
  • Since use glslcc, the thirdparty glsl-optimizer can be removed, and it's not support compile essl 3.1 to msl, not compatible with new shader workflow.
  • Auto sync compiled shaders ${CMAKE_BINARY_DIR}/runtime/axslc to apps by @halx99
    • win32/linux, use symlink
    • winuwp
    • android
    • macos/ios/tvos, draft works, waiting cmake patch by @halx99 to be merge by kitware
  • Migrate all tests shaders for making cpp_tests works on new shaders
  • Engine Material load needs reimplement due to shader load flow changed
  • Refactor shader load managment: ProgramManager support load cusom shader program immediately and improve register mechanism
  • Text rendering, SDF outline support
  • Remove mat3->mat4 convert, instead, provide math::Mat3 to initialize a GPU layout compatible mat3, both GL3/GLES3/Metal have same mat3 layout, identical to mat3x4
  • Check cpp-tests
  • GLESv2 compatible

Compatibility

  • Since shaders needs compiled by glslcc offline, no longer support embed c++ shaders
  • Don't worry, all changes are in dev branch, and will take long time, the main is the lts for 1.0.x currently. even through, we want merge dev in to main in the future, but before that, we will create a lts branch 1.0.x

New shader looks like

vertex shader:

#version 310 es

layout(location = 0) in vec4 a_position;
layout(location = 1) in vec2 a_texCoord;

layout(location = 0) out vec2 v_texCoord;

layout(std140) uniform vs_ub {
    mat4 u_MVPMatrix;
};

void main()
{
    gl_Position = u_MVPMatrix * a_position;
    v_texCoord = a_texCoord;
}

fragment shader:

#version 310 es
precision highp float;
precision highp int;

layout(location = 0) in vec2 v_texCoord;
layout(binding = 0) uniform sampler2D u_tex0;
layout(location = 0) out vec4 FragColor;

void main()
{
    FragColor =  texture(u_tex0, v_texCoord);
}

Notes

  • all non-sampler uniforms must in uniform block, because glslcc(spirv) limits
  • recommanded use macro for layout location to ensure them are same between vert and frag shader, oterwise, metal render will crash due to layout location between vert and frag shader mismatch
layout(location = POSITION) in vec4 a_position;
layout(location = TEXCOORD0) in vec2 a_texCoord;

layout(location = TEXCOORD0) out vec2 v_texCoord;

layout(std140) uniform vs_ub {
    mat4 u_MVPMatrix;
};

void main()
{
    gl_Position = u_MVPMatrix * a_position;
    v_texCoord = a_texCoord;
}
#version 310 es
precision highp float;
precision highp int;

layout(location = TEXCOORD0) in vec2 v_texCoord;
uniform sampler2D u_tex0;
layout(location = SV_Target0) out vec4 FragColor;

void main()
{
    FragColor =  texture(u_tex0, v_texCoord);
}

Shader syntax migrate summary

  • both vertex & fragment shader should insert version decl #version 310 es in header
  • fragment shader needs precision decls for float & int
  • the quailfier attribute in vertex shader change to in
  • the qualifier varying in vertex shader change to out
  • the quaifier varying in fragment shader change to in
  • the gl_FragColor need replaced by a defined out vec4 variable in fragment shader

Shader restrict or recommands

  • please only write 1 uniform block per shader stage, multi uniform blocks not implemented in metal backend

performance preview (release build)

axmol-dev:
image

axmol-main:
image

cocos2dx-3.17.1
image

@halx99 halx99 added this to the 1.1.x milestone Jul 17, 2023
@halx99 halx99 changed the title Upgrade shader workflow to GLES3/OpenGL3 [WIP] Upgrade shader workflow to GLES3/OpenGL3 Jul 17, 2023
@halx99 halx99 pinned this issue Jul 17, 2023
@halx99 halx99 mentioned this issue Jul 17, 2023
4 tasks
@solan-solan
Copy link
Contributor

solan-solan commented Jul 17, 2023

Remove glsl-optimizer please at the final step. Really, it is not good that axmol does not support glsl 1.0 at all. Is there some other game engine that supports only glsl 3.0 specification? Why such limitation?
There were customers on the forum that goes from cocos to axmol. And I am one of them. It is more simple if there is opportunity to migrate custom shaders one by one, and check that everything works after each shader. Think please that shaders could not be debuged. Since that, if you really decided to reject glsl 1.0, please don't do it right away.
Besides, can I have sub directories inside project_root/Source/shaders?
And such question, how glsl 1.0 will be restricted on Android? glslcc can not compile it?
And guys, why so importance to delete things that worked many years before? Is it somehow interferers with new platforms? Embedded to c++ shader feature was very good and were achieved using glsl optimizer for ios/Mac.
And one more. How shaders could be compiled offline if they depend from macroses which passed in runtime? Or I missed something?

@halx99 halx99 added the pinned label Jul 18, 2023
@DelinWorks
Copy link
Contributor

@solan-solan I don't think we're dropping support for gles 1.0 , just creating a new version of the engine that supports gles 3.0, if you want to migrate right away just pick the gles 1.0 version, otherwise you have to manually change your project to work with gles 3.0

@solan-solan
Copy link
Contributor

@DelinWorks @halx99
Clarify please the following. If I properly understand, glslcc will compile shaders to spir-v in build time. What will happen with macroses? What if the certain macroses should be configured for some shaders in runtime in the game, like in my case? Does this spir-v will be converted back to the platform shader language in runtime where it could be configured?

@halx99
Copy link
Collaborator Author

halx99 commented Jul 18, 2023

The glslcc use spirv-cross decompile spirv-bytecode to MSL(metal), ESSL300(GLES), GLSL330(OpenGL)

@halx99
Copy link
Collaborator Author

halx99 commented Jul 18, 2023

glslcc compile workflow:

input shader(ESSL310/GLSL450)
  --> spirv byte code
       --> MSL for ios/macos/tvos
       --> ESSL300 for GLES3
       --> GLSL330 for DesktopGL

@rh101
Copy link
Contributor

rh101 commented Jul 18, 2023

What if the certain macroses should be configured for some shaders in runtime in the game, like in my case?

Any chance you can show an example of your current usage related to macros and shaders?

@DelinWorks
Copy link
Contributor

@DelinWorks @halx99 Clarify please the following. If I properly understand, glslcc will compile shaders to spir-v in build time. What will happen with macroses? What if the certain macroses should be configured for some shaders in runtime in the game, like in my case? Does this spir-v will be converted back to the platform shader language in runtime where it could be configured?

You can still use defines in your shaders, then you can pass your shader as a custom shader and it will be compiled as a user shader WITH your defines set by the C compiler. use R() when using preprocessor strings.

@solan-solan
Copy link
Contributor

@DelinWorks
Thanks, I asked exactly about defines in custom shaders

@halx99
Ok, looks like my understanding of this workflow corresponds to your indication. But I just wanted to clarify if I could adjust shaders in runtime with defines, like it was before

@rh101
My usage is the similar as it is in axmol now for 3d models. For example there is one pbr shader for 3d models in my project. There are some texture slots in it (like Ambient Occlusion, etc. ), which closed with define, since they should not be used for some models (there are no such textures for these models, and I do not desire to make it for them). Such a way, my code constructs the final shader after checking some props of model from json.
I can provide this shader code if you are interested in as is, since I found it in internet and just adapted to axmol

@rh101
Copy link
Contributor

rh101 commented Jul 18, 2023

I can provide this shader code if you are interested in as is, since I found it in internet and just adapted to axmol

That would be good. I was just curious to know how you were using the shaders with macros in order to understand why it would be an issue to move to the new shaders.

@solan-solan
Copy link
Contributor

in order to understand why it would be an issue to move to the new shaders

I was confused with compile word. Looks like defines could be stored to spir-v intermediate language, and no issue exists. Ok I will attach this shader in discussion a little later when will be near pc.

@halx99
Copy link
Collaborator Author

halx99 commented Jul 18, 2023

Looks like defines could be stored to spir-v intermediate

do you know how to do?

@halx99
Copy link
Collaborator Author

halx99 commented Jul 18, 2023

currently compiled shaders not contains any preprocesser checks, I don't know how to reserve #if checks

@rh101
Copy link
Contributor

rh101 commented Jul 18, 2023

Looking through the glslcc usage docs, there is this command line argument:

-D --defines(=Defines) - Preprocessor definitions, seperated by comma or ';'

Doesn't that apply to the input shader file? The output file would be the result of whatever the result of the defines is. Is that how it works?

For example, input shader would have a section like this:

#ifdef USE_NORMAL_MAPPING
attribute vec3 a_tangent;
attribute vec3 a_binormal;
#endif

If USE_NORMAL_MAPPING is passed to glslcc via the -D switch, then the code inside the define block would be processed to the output shader, and if USE_NORMAL_MAPPING is not passed, then it would not be included in the processing to the output shader. This should work, right? If it does work, then we just need to have a way to pass defines to the glslcc processor via cmake for the custom shaders.

@solan-solan is this what you require?

@solan-solan
Copy link
Contributor

solan-solan commented Jul 18, 2023

@halx99
Spir-v is some intermediate bytecode. I doubt that this possible

@rh101

is this what you require?

This argument will be applied in build time anyway. I do not know which shaders I need in build time. These data's should be parsed from json according to my architecture.

Think please to save old shader approach equally with new one. Shader compiling does not touch performance. It all have affect just while init application

@rh101
Copy link
Contributor

rh101 commented Jul 18, 2023

This argument will be applied in build time anyway. I do not know which shaders I need in build time. These data's should be parsed from json according to my architecture.

You mention that you do not know what shaders to use at build time, but I don't see that as a problem at all. If all shaders exist with the application, then at runtime you select which one to use based on some condition (for instance, your json data). Isn't this what you need?

If that is not what you mean, then I will wait till you show an example of this so I can understand what is going on.

I do now notice in your previous post where you mention that you "construct" the shader at runtime, but I've never seen this use case at all. Is this something that is commonly done? Is there any reason why you cannot provide all the shader combinations at build time, and then select which one you need at runtime?

@solan-solan
Copy link
Contributor

@rh101
I can adjust to a lot of things. Maybe i will do it after these changes also. But, take in account please, that my code (bad it or good) was based on engine architecture as it was and features, that engine provided.
One time I decided that this usage of shader is good and convenient and wasted many time for implementation.
And I asked simple question. Why was it needed to remove old shader approach. Or do you know each usage which customer can imagine?!

Really no complaints) It is everything up to you, but your change killed one of use cases.

Is this something that is commonly done?

I do not know.

Is there any reason why you cannot provide all the shader combinations at build time, and then select which one you need at runtime?

There are many different settings in my shaders, and many different models with many different settings. It is general system which supposed to be extended, and controlled with json to simplify certain shader creation.

@DelinWorks
Copy link
Contributor

why not use uniforms?

@delin
Copy link

delin commented Jul 18, 2023

@halx99

OpenGL UBO support by @delin

maybe you mean @DelinWorks? )

@solan-solan
Copy link
Contributor

solan-solan commented Jul 18, 2023

@DelinWorks
Defines can change code, but uniforms only data's.
For example my shader can apply wind affect to some object. Wind effect is a couple of additional lines which can be commented by define. And if you have many different such settings, it is good to think about some general system
The next example. I have one level where 3 point lights and second level where 4 point lights. Should I pass it via uniform? In fact it will hit performance, since for statement has bad optimization on gpu. Take a look that previouse shaders has light sources number as define

@DelinWorks
Copy link
Contributor

then I don't see why @rh101 suggestion doesn't work out for you. You're effectively combining shaders into a single file, why not make a shader do one thing and load them at runtime based on what you need since now you don't have to write a shader for each platform you can just make shaders like wind1.frag wind2.frag wind3.frag that are written in gles 310 compliant shader code and that's it.

@DelinWorks
Copy link
Contributor

although I do agree with you with branching being bad in gpus, I think that splitting them is way better, but doesn't glslcc support define that @rh101 found out? maybe it could be easy to implement.

@solan-solan
Copy link
Contributor

solan-solan commented Jul 18, 2023

although I do agree with you with branching being bad in gpus, I think that splitting them is way better, but doesn't glslcc support define that @rh101 found out? maybe it could be easy to implement.

If I have five light sources on the third level and so on?

You're effectively combining shaders into a single file, why not make a shader do one thing and load them at runtime based on what you need since now you don't have to write a shader for each platform you can just make shaders like wind1.frag wind2.frag wind3.frag that are written in gles 310 compliant shader code and that's it.

Effectively combine - is restriction for game design and implementation approach. Imho

And now I do not need to write shader for each platform also. It is not understandable why this well tested feature should be removed

@rh101
Copy link
Contributor

rh101 commented Jul 19, 2023

  • Engine auto sync compiled runtime shader folder(${CMAKE_BINARY_DIR}/runtime/axslc) to target app app_res_root/axslc, and app_res_root/axslc will be added to search path by engine FileUtils implementation.

  • Start app, load compiled shaders from app_res_root/axslc by shader name.

The following is just a suggestion:

Is it at all possible to modify this to add a sub-directory to the shader file lookup? What I mean is that the converted shaders would be stored in app_res_root/axslc/shaders instead of app_res_root/axslc. The app_res_root/axslc is still added to the search list, so as an example, to load a shader, you would use shaders/shaderfile_fs etc.

This way the filenames would not pollute the root search path, and it also makes it easier to override existing shaders at runtime. For example, if all shaders exist in app_res_root/axslc/shaders with app_res_root/axslc in the search path, and we want to override an existing shader (example, 3D_color_fs), then the app does the following:

First, app creates directory in the write path (let's say it's called "dlc" for downloadable content, with a "shaders" sub-dir in it), and then we download a new file named 3D_color_fs to it. In this example, the new file will be dlc/shaders/3D_color_fs.

Next the app calls FileUtils::addSearchPath(std::string_view searchpath, const bool front) with front set to true, so it would be:
FileUtils::getInstance()->addSearchPath("dlc", true);

This way, when code tries to load shaders/3D_color_fs, it will find the new version of it in the dlc/shaders/ folder, instead of using the one that exists in app_res_root/axslc/shaders/.

This is actually more for custom shaders than the default shaders contained in Axmol. It saves us from forcing the user to download an entirely new release (APK/Installer etc) just to update a few resources, since the app can do it at runtime by using downloadable content.

I realise this can be done without the shaders sub-directory too, but it means all shader lookup would be at the root level, and I'm not sure if that would cause any issues in the future.

@halx99 halx99 changed the title [WIP] Upgrade shader workflow to GLES3/OpenGL3 [WIP][axmol-1.1] Upgrade GL to GLES3/OpenGL3 Jul 19, 2023
@halx99
Copy link
Collaborator Author

halx99 commented Jul 19, 2023

The user can download shader files to writeablepath/any-folder-name, and add it to front searchpaths

@rh101
Copy link
Contributor

rh101 commented Jul 19, 2023

The user can download shader files to writeablepath/any-folder-name, and add it to front searchpaths

I understand, so all shaders will be referenced at root level as shaderfilename_[fs][vs]. As I mentioned in my previous post, it was just a suggestion to add them to ashaders sub-folder purely as a way of organising them, but it's definitely not necessary in any way.

@halx99
Copy link
Collaborator Author

halx99 commented Jul 19, 2023

builtin shaders use root level, app shaders can be relative path, no limitation axslc/custom, then user can register shader by name custom/xxx_vs, custom/xxx_fs without add search path in develop term

@rh101
Copy link
Contributor

rh101 commented Jul 19, 2023

builtin shaders use root level, app shaders can be relative path, no limitation axslc/custom

That would be good!

@halx99
Copy link
Collaborator Author

halx99 commented Jul 19, 2023

builtin shaders use root level, app shaders can be relative path, no limitation axslc/custom, then user can register shader by name custom/xxx_vs, custom/xxx_fs without add search path in develop term

done by: ac073ee

@halx99
Copy link
Collaborator Author

halx99 commented Jul 28, 2023

FYI
Ready to preview for anyone who is interested: https://github.com/axmolengine/axmol/releases/tag/v1.1.0-preview2

@halx99 halx99 changed the title [WIP][axmol-1.1] Upgrade GL to GLES3/OpenGL3 [WIP][axmol-2.0] Upgrade GL to GLES3/OpenGL3 Aug 11, 2023
@halx99 halx99 changed the title [WIP][axmol-2.0] Upgrade GL to GLES3/OpenGL3 [WIP][axmol-2.0] Support GLES3/OpenGL3 Aug 14, 2023
@halx99 halx99 changed the title [WIP][axmol-2.0] Support GLES3/OpenGL3 [axmol-2.0] Support GLES3/OpenGL3 Sep 4, 2023
@halx99 halx99 closed this as completed Sep 10, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants