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

Add multiview_data for multiview information #8410

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

z3moon
Copy link
Contributor

@z3moon z3moon commented Feb 4, 2025

Add a varying variable multiview_data for both surface and post-processing shaders. Currently this only works as intended in surface shader, and additional implementation to facilitate it for post-processing will be following.

The multiview_data contains multiview information like whether multiview is enabled for the current material and what the eye index is in that case. This variable is globally available including fragment shaders so that it can be referenced in user shaders in .material files. Also this allows us to directly use the constant variables such as gl_ViewID_OVR for OpenGL and gl_ViewIndex for Vulkan.

Make the preprocessor MATERIAL_FEATURE_LEVEL available for both surface and post-processing shaders, it used to be only available for surface shader, and this will be referenced in post-processing shaders later to support multiview for post-processing.

@z3moon z3moon added the internal Issue/PR does not affect clients label Feb 4, 2025
@z3moon z3moon force-pushed the zm/add-multiview-data branch from a3529be to 4ded5cf Compare February 4, 2025 02:50
Add a varying variable `multiview_data` for both surface and
post-processing shaders. Currently this only works as intended in
surface shader, and additional implementation to facilitate it for
post-processing will be following.

The `multiview_data` contains multiview information like whether
multiview is enabled for the current material and what the eye index is
in that case. This variable is globally available including fragment
shaders so that it can be referenced in user shaders in .material files.
Also this allows us to indirectly reference the constant variables such
as `gl_ViewID_OVR` and `gl_ViewIndex` in a platform-agnostic way.

Make the preprocessor `MATERIAL_FEATURE_LEVEL` available for both
surface and post-processing shaders, it used to be only available for
surface shader, and this will be referenced in post-processing shaders
later to support multiview for post-processing.
@z3moon z3moon force-pushed the zm/add-multiview-data branch from 4ded5cf to 923ac98 Compare February 4, 2025 03:48
Copy link
Contributor

@poweifeng poweifeng left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm but I think this needs Mathias and/or Ben to chime in as well.

// to the fragment shader. `x` means whether multiview is used, `y` means the current view index.
// Neither the multiview feature nor the `flat` keyword is supported in FL0. So, for FL0, declare
// it as a non-flat and non-varying variable and set it to zeros as a placeholder.
#if MATERIAL_FEATURE_LEVEL > 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: why not wrap this in #if defined(VARIANT_HAS_STEREO) && defined(FILAMENT_STEREO_MULTIVIEW) ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as powei says, if multiview/stereo is not enabled, we might as well use a constant and avoid a varying.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see any getter for multiview_data.x we should not let user code access it directly.

Also maybe we should name it something less likely to colide with use variable. Maybe filament_multiview_data.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need multiview_data.x ? if multiview is not enabled, would we be in the defined(VARIANT_HAS_STEREO) && defined(FILAMENT_STEREO_MULTIVIEW) case? In other words, why is multiview_data.x not a compile time option?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pattern should be used for post-processing as well where VARIANT_HAS_STEREO is unavailable unfortunately. So this is a workaround to make this line available for PP. I think I can add FILAMENT_STEREO_MULTIVIEW check though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

multiview_data.x is necessary because VARIANT_HAS_STEREO is unavailable for post-processing where it needs to know whether the current pass is multiview. For example, it's used to calculate the index to the bent normal layers for the SSAO logic that I'm going to add later.

Copy link
Collaborator

@pixelflinger pixelflinger Feb 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, we don't need this for post-process materials for now, because they're not public. This can all be done with a spec-constant and custom variables.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see spec constants in shader files are all const and its value is determined in compile time. E.g., const int BACKEND_FEATURE_LEVEL = SPIRV_CROSS_CONSTANT_ID_0;

However, the value of gl_ViewID_OVR is increasingly changing over each shader execution (from 0 to 3) and needs to be passed/inherited to fragment shader from its corresponding vertex shader. So we cannot achieve this with spec-constant IIUC. (or I might be missing something)

Custom variables look like they work in the same way as varying variables except that they're not flat, which could be slightly worse in performance. Besides, if we put the inheritance logic via custom variable in the NEW post-processing shaders (which contain the multiview = true, field), the same boilerplate code that handles selecting either gl_ViewIndex or gl_ViewID_OVR based on the target api should be added as well.

I personally see using the same pattern here for PP could be better for maintainability, WDYT?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should absolutely add the concept of flat custom variables. So maybe we can start with that as a separate change.

I agree that for maintainability we should do the same thing for postfx, but I do not want to add more variants for all postfx. And I don't really want to have this runtime check either, nor the extra varying.
Since postfx materials are not really public right now, I think it's okay to "hack" this using a custom variable and a custom spec constant. PostProcessManager already does stuff like that for TAA (I mean using spec constants).

We can file a bug to revisit postfx stsereo.

Addtionnaly, I think you should split this change in two. Nobody should be relying on postfx right now, so maybe you can make the change, just for surface materials, so we unblock people depending on it. And we do the postfx fixes as a separate PR. wdyt?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should split this change in two

This works for me. Let me wrap this up and circle back on how to deal with the poxtfx case.

FYI, this approach doesn't add additional variants for postfx. I added separate new materials for multiview, which are mipmapDepthMultiview.mat, saoBentNormalsMultiview.mat, and saoMultiview.mat with multiview = true, in the json section in the file. Only these materials are compiled with the varying variable.

For multiview, one draw call invokes multiple vertex shader executions (2 or 4 times depending on the engine setting) per vertex, and the gl_ViewID_OVR value is set properly by the driver in each execution. What I want to do is to capture the value in each vertex execution and deliver it to the fragment shader. If it's achievable without using varying, it'd be nice. But I don't see how this can be done using spec-constant yet.

#if MATERIAL_FEATURE_LEVEL > 0
LAYOUT_LOCATION(99) flat VARYING ivec2 multiview_data;
#else
ivec2 multiview_data = ivec2(0, 0);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can probably be const

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't put const here because FL0 materials like lib/filamentapp/materials/transparentColor.mat can't be compiled otherwise.

// to the fragment shader. `x` means whether multiview is used, `y` means the current view index.
// Neither the multiview feature nor the `flat` keyword is supported in FL0. So, for FL0, declare
// it as a non-flat and non-varying variable and set it to zeros as a placeholder.
#if MATERIAL_FEATURE_LEVEL > 0
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as powei says, if multiview/stereo is not enabled, we might as well use a constant and avoid a varying.

// Neither the multiview feature nor the `flat` keyword is supported in FL0. So, for FL0, declare
// it as a non-flat and non-varying variable and set it to zeros as a placeholder.
#if MATERIAL_FEATURE_LEVEL > 0
LAYOUT_LOCATION(99) flat VARYING ivec2 multiview_data;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we do that? use a location of 99 ? are you sure it works on ES3.0 and ES3.1 and Vulkan?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I picked this number -1 from LAYOUT_LOCATION(100) out float filament_gl_ClipDistance[2];, assuming it's safer. Let me change it to 12 since it's the next available number.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note that GL_MAX_VARYING_VECTORS minimum value is 15, and GL_MAX_VARYING_COMPONENTS is 60.

Copy link
Collaborator

@pixelflinger pixelflinger Feb 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note that GL_MAX_VARYING_VECTORS minimum value is 15, and GL_MAX_VARYING_COMPONENTS is 60.

This makes me think we might have a problem already. Because materials can have up to 4 custom varyings vectors and the total number of vectors cannot be more than 15.
It looks like the 4 user varying are reserved 0-3 location.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the info! Is there any guidance on how to pick the right available number? or picking 12 would be sufficient?

// to the fragment shader. `x` means whether multiview is used, `y` means the current view index.
// Neither the multiview feature nor the `flat` keyword is supported in FL0. So, for FL0, declare
// it as a non-flat and non-varying variable and set it to zeros as a placeholder.
#if MATERIAL_FEATURE_LEVEL > 0
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see any getter for multiview_data.x we should not let user code access it directly.

Also maybe we should name it something less likely to colide with use variable. Maybe filament_multiview_data.

// to the fragment shader. `x` means whether multiview is used, `y` means the current view index.
// Neither the multiview feature nor the `flat` keyword is supported in FL0. So, for FL0, declare
// it as a non-flat and non-varying variable and set it to zeros as a placeholder.
#if MATERIAL_FEATURE_LEVEL > 0
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need multiview_data.x ? if multiview is not enabled, would we be in the defined(VARIANT_HAS_STEREO) && defined(FILAMENT_STEREO_MULTIVIEW) case? In other words, why is multiview_data.x not a compile time option?

@z3moon z3moon requested a review from pixelflinger February 5, 2025 00:36
Copy link
Member

@bejado bejado left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally LGTM but I think that filament_multiview_data.x could be a compile-time constant instead of a varying. I'm also a bit concerned that we're burning another varying, I think on some platforms we're nearing the limit.

# else
int multiview_view_index = int(gl_ViewID_OVR);
# endif // TARGET_VULKAN_ENVIRONMENT
filament_multiview_data = ivec2(1, int(multiview_view_index));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I don't think you need the int cast here.

Suggested change
filament_multiview_data = ivec2(1, int(multiview_view_index));
filament_multiview_data = ivec2(1, multiview_view_index);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
internal Issue/PR does not affect clients
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants