Skip to content

Commit

Permalink
Workaround for a bug in Adreno's shader compiler
Browse files Browse the repository at this point in the history
At least some adreno compilers don't like returning an element of a
UBO array that is a structure in the vertex shader.
To work this around we have to copy the each of the structure fields.

Fixes #6355
  • Loading branch information
pixelflinger committed Dec 14, 2022
1 parent aa5504a commit ee6612e
Show file tree
Hide file tree
Showing 13 changed files with 69 additions and 53 deletions.
1 change: 1 addition & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ A new header is inserted each time a *tag* is created.
- web: added TypeScript definition for `Engine.destroy`
- materials: `getNormalizedViewportCoord()` now returns the logical (i.e. user) viewport
normalized position and keeps z reversed [⚠️ **Recompile Materials**]
- backend: workaround Adreno shader compiler bug (#6355) [⚠️ **Recompile Materials**]

## v1.30.0

Expand Down
2 changes: 2 additions & 0 deletions libs/filamat/src/shaders/CodeGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -662,9 +662,11 @@ io::sstream& CodeGenerator::generateCommon(io::sstream& out, ShaderStage stage)

switch (stage) {
case ShaderStage::VERTEX:
out << SHADERS_COMMON_INSTANCING_GLSL_DATA;
out << SHADERS_COMMON_SHADOWING_GLSL_DATA;
break;
case ShaderStage::FRAGMENT:
out << SHADERS_COMMON_INSTANCING_GLSL_DATA;
out << SHADERS_COMMON_SHADOWING_GLSL_DATA;
out << SHADERS_COMMON_SHADING_FS_DATA;
out << SHADERS_COMMON_GRAPHICS_FS_DATA;
Expand Down
2 changes: 1 addition & 1 deletion libs/gltfio/materials/volume.mat.in
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ fragment {
material.metallic = materialParams.metallicFactor;
material.transmission = materialParams.transmissionFactor;
material.absorption = materialParams.volumeAbsorption;
material.thickness = materialParams.volumeThicknessFactor * getObjectUniforms().userData;
material.thickness = materialParams.volumeThicknessFactor * getObjectUserData();
material.ior = materialParams.ior;

material.emissive = vec4(materialParams.emissiveStrength *
Expand Down
1 change: 1 addition & 0 deletions shaders/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ set(SHADERS
src/brdf.fs
src/common_defines.glsl
src/common_getters.glsl
src/common_instancing.glsl
src/common_graphics.fs
src/common_lighting.fs
src/common_material.fs
Expand Down
35 changes: 35 additions & 0 deletions shaders/src/common_instancing.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//------------------------------------------------------------------------------
// Instancing
// ------------------------------------------------------------------------------------------------

PerRenderableData object_uniforms;

void initObjectUniforms(out PerRenderableData p) {
#if defined(MATERIAL_HAS_INSTANCES)
// the material manages instancing, all instances share the same uniform block.
p = objectUniforms.data[0];
#else
// automatic instancing was used, each instance has its own uniform block.

// We're copying each field separately to workaround an issue in some Adreno drivers
// that fail on non-const array access in a UBO. Accessing the fields works however.
// e.g.: this fails `p = objectUniforms.data[instance_index];`
p.worldFromModelMatrix = objectUniforms.data[instance_index].worldFromModelMatrix;
p.worldFromModelNormalMatrix = objectUniforms.data[instance_index].worldFromModelNormalMatrix;
p.morphTargetCount = objectUniforms.data[instance_index].morphTargetCount;
p.flagsChannels = objectUniforms.data[instance_index].flagsChannels;
p.objectId = objectUniforms.data[instance_index].objectId;
p.userData = objectUniforms.data[instance_index].userData;
#endif
}

//------------------------------------------------------------------------------
// Instance access
//------------------------------------------------------------------------------

#if defined(MATERIAL_HAS_INSTANCES)
/** @public-api */
int getInstanceIndex() {
return instance_index;
}
#endif
2 changes: 1 addition & 1 deletion shaders/src/depth_main.fs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ void main() {
fragColor.xy = computeDepthMomentsVSM(depth);
fragColor.zw = computeDepthMomentsVSM(-1.0 / depth); // requires at least RGBA16F
#elif defined(VARIANT_HAS_PICKING)
outPicking.x = getObjectUniforms().objectId;
outPicking.x = object_uniforms.objectId;
outPicking.y = floatBitsToUint(vertex_position.z / vertex_position.w);
#else
// that's it
Expand Down
19 changes: 4 additions & 15 deletions shaders/src/getters.fs
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
//------------------------------------------------------------------------------
// Instance access
// Uniforms access
//------------------------------------------------------------------------------

#if defined(MATERIAL_HAS_INSTANCES)
/** @public-api */
int getInstanceIndex() {
return instance_index;
/** sort-of public */
float getObjectUserData() {
return object_uniforms.userData;
}
#endif

//------------------------------------------------------------------------------
// Attributes access
Expand Down Expand Up @@ -142,12 +140,3 @@ highp vec4 getCascadeLightSpacePosition(uint cascade) {

#endif

PerRenderableData getObjectUniforms() {
#if defined(MATERIAL_HAS_INSTANCES)
// the material manages instancing, all instances share the same uniform block.
return objectUniforms.data[0];
#else
// automatic instancing was used, each instance has its own uniform block.
return objectUniforms.data[instance_index];
#endif
}
38 changes: 11 additions & 27 deletions shaders/src/getters.vs
Original file line number Diff line number Diff line change
@@ -1,36 +1,20 @@
//------------------------------------------------------------------------------
// Instance access
//------------------------------------------------------------------------------

#if defined(MATERIAL_HAS_INSTANCES)
/** @public-api */
int getInstanceIndex() {
return instance_index;
}
#endif

//------------------------------------------------------------------------------
// Uniforms access
//------------------------------------------------------------------------------

PerRenderableData getObjectUniforms() {
#if defined(MATERIAL_HAS_INSTANCES)
// the material manages instancing, all instances share the same uniform block.
return objectUniforms.data[0];
#else
// automatic instancing was used, each instance has its own uniform block.
return objectUniforms.data[instance_index];
#endif
}

/** @public-api */
mat4 getWorldFromModelMatrix() {
return getObjectUniforms().worldFromModelMatrix;
return object_uniforms.worldFromModelMatrix;
}

/** @public-api */
mat3 getWorldFromModelNormalMatrix() {
return getObjectUniforms().worldFromModelNormalMatrix;
return object_uniforms.worldFromModelNormalMatrix;
}

/** sort-of public */
float getObjectUserData() {
return object_uniforms.userData;
}

//------------------------------------------------------------------------------
Expand Down Expand Up @@ -94,7 +78,7 @@ void skinPosition(inout vec3 p, const uvec4 ids, const vec4 weights) {

void morphPosition(inout vec4 p) {
ivec3 texcoord = ivec3(getVertexIndex() % MAX_MORPH_TARGET_BUFFER_WIDTH, getVertexIndex() / MAX_MORPH_TARGET_BUFFER_WIDTH, 0);
uint c = getObjectUniforms().morphTargetCount;
uint c = object_uniforms.morphTargetCount;
for (uint i = 0u; i < c; ++i) {
float w = morphingUniforms.weights[i][0];
if (w != 0.0) {
Expand All @@ -107,7 +91,7 @@ void morphPosition(inout vec4 p) {
void morphNormal(inout vec3 n) {
vec3 baseNormal = n;
ivec3 texcoord = ivec3(getVertexIndex() % MAX_MORPH_TARGET_BUFFER_WIDTH, getVertexIndex() / MAX_MORPH_TARGET_BUFFER_WIDTH, 0);
uint c = getObjectUniforms().morphTargetCount;
uint c = object_uniforms.morphTargetCount;
for (uint i = 0u; i < c; ++i) {
float w = morphingUniforms.weights[i][0];
if (w != 0.0) {
Expand All @@ -127,7 +111,7 @@ vec4 getPosition() {

#if defined(VARIANT_HAS_SKINNING_OR_MORPHING)

if ((getObjectUniforms().flagsChannels & FILAMENT_OBJECT_MORPHING_ENABLED_BIT) != 0u) {
if ((object_uniforms.flagsChannels & FILAMENT_OBJECT_MORPHING_ENABLED_BIT) != 0u) {
#if defined(LEGACY_MORPHING)
pos += morphingUniforms.weights[0] * mesh_custom0;
pos += morphingUniforms.weights[1] * mesh_custom1;
Expand All @@ -138,7 +122,7 @@ vec4 getPosition() {
#endif
}

if ((getObjectUniforms().flagsChannels & FILAMENT_OBJECT_SKINNING_ENABLED_BIT) != 0u) {
if ((object_uniforms.flagsChannels & FILAMENT_OBJECT_SKINNING_ENABLED_BIT) != 0u) {
skinPosition(pos.xyz, mesh_bone_indices, mesh_bone_weights);
}

Expand Down
4 changes: 2 additions & 2 deletions shaders/src/light_directional.fs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ void evaluateDirectionalLight(const MaterialInputs material,

Light light = getDirectionalLight();

uint channels = getObjectUniforms().flagsChannels & 0xFFu;
uint channels = object_uniforms.flagsChannels & 0xFFu;
if ((light.channels & channels) == 0u) {
return;
}
Expand All @@ -60,7 +60,7 @@ void evaluateDirectionalLight(const MaterialInputs material,
visibility = shadow(true, light_shadowMap, cascade, shadowPosition, 0.0f);
}
if ((frameUniforms.directionalShadows & 0x2u) != 0u && visibility > 0.0) {
if ((getObjectUniforms().flagsChannels & FILAMENT_OBJECT_CONTACT_SHADOWS_BIT) != 0u) {
if ((object_uniforms.flagsChannels & FILAMENT_OBJECT_CONTACT_SHADOWS_BIT) != 0u) {
ssContactShadowOcclusion = screenSpaceContactShadow(light.l);
}
}
Expand Down
4 changes: 2 additions & 2 deletions shaders/src/light_punctual.fs
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ void evaluatePunctualLights(const MaterialInputs material,

uint index = froxel.recordOffset;
uint end = index + froxel.count;
uint channels = getObjectUniforms().flagsChannels & 0xFFu;
uint channels = object_uniforms.flagsChannels & 0xFFu;

// Iterate point lights
for ( ; index < end; index++) {
Expand Down Expand Up @@ -225,7 +225,7 @@ void evaluatePunctualLights(const MaterialInputs material,
shadowPosition, light.zLight);
}
if (light.contactShadows && visibility > 0.0) {
if ((getObjectUniforms().flagsChannels & FILAMENT_OBJECT_CONTACT_SHADOWS_BIT) != 0u) {
if ((object_uniforms.flagsChannels & FILAMENT_OBJECT_CONTACT_SHADOWS_BIT) != 0u) {
visibility *= 1.0 - screenSpaceContactShadow(light.l);
}
}
Expand Down
2 changes: 2 additions & 0 deletions shaders/src/main.fs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ void blendPostLightingColor(const MaterialInputs material, inout vec4 color) {
void main() {
filament_lodBias = frameUniforms.lodBias;

initObjectUniforms(object_uniforms);

// See shading_parameters.fs
// Computes global variables we need to evaluate material and lighting
computeShadingParams();
Expand Down
10 changes: 6 additions & 4 deletions shaders/src/main.vs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ void main() {
instance_index = gl_InstanceID;
#endif

initObjectUniforms(object_uniforms);

// Initialize the inputs to sensible default values, see material_inputs.vs
#if defined(USE_OPTIMIZED_DEPTH_VERTEX_SHADER)

Expand Down Expand Up @@ -41,7 +43,7 @@ void main() {
toTangentFrame(mesh_tangents, material.worldNormal, vertex_worldTangent.xyz);

#if defined(VARIANT_HAS_SKINNING_OR_MORPHING)
if ((getObjectUniforms().flagsChannels & FILAMENT_OBJECT_MORPHING_ENABLED_BIT) != 0u) {
if ((object_uniforms.flagsChannels & FILAMENT_OBJECT_MORPHING_ENABLED_BIT) != 0u) {
#if defined(LEGACY_MORPHING)
vec3 normal0, normal1, normal2, normal3;
toTangentFrame(mesh_custom4, normal0);
Expand All @@ -59,7 +61,7 @@ void main() {
#endif
}

if ((getObjectUniforms().flagsChannels & FILAMENT_OBJECT_SKINNING_ENABLED_BIT) != 0u) {
if ((object_uniforms.flagsChannels & FILAMENT_OBJECT_SKINNING_ENABLED_BIT) != 0u) {
skinNormal(material.worldNormal, mesh_bone_indices, mesh_bone_weights);
skinNormal(vertex_worldTangent.xyz, mesh_bone_indices, mesh_bone_weights);
}
Expand All @@ -77,7 +79,7 @@ void main() {
toTangentFrame(mesh_tangents, material.worldNormal);

#if defined(VARIANT_HAS_SKINNING_OR_MORPHING)
if ((getObjectUniforms().flagsChannels & FILAMENT_OBJECT_MORPHING_ENABLED_BIT) != 0u) {
if ((object_uniforms.flagsChannels & FILAMENT_OBJECT_MORPHING_ENABLED_BIT) != 0u) {
#if defined(LEGACY_MORPHING)
vec3 normal0, normal1, normal2, normal3;
toTangentFrame(mesh_custom4, normal0);
Expand All @@ -95,7 +97,7 @@ void main() {
#endif
}

if ((getObjectUniforms().flagsChannels & FILAMENT_OBJECT_SKINNING_ENABLED_BIT) != 0u) {
if ((object_uniforms.flagsChannels & FILAMENT_OBJECT_SKINNING_ENABLED_BIT) != 0u) {
skinNormal(material.worldNormal, mesh_bone_indices, mesh_bone_weights);
}
#endif
Expand Down
2 changes: 1 addition & 1 deletion shaders/src/shading_unlit.fs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ vec4 evaluateMaterial(const MaterialInputs material) {
visibility = shadow(true, light_shadowMap, cascade, shadowPosition, 0.0f);
}
if ((frameUniforms.directionalShadows & 0x2u) != 0u && visibility > 0.0) {
if ((getObjectUniforms().flagsChannels & FILAMENT_OBJECT_CONTACT_SHADOWS_BIT) != 0u) {
if ((object_uniforms.flagsChannels & FILAMENT_OBJECT_CONTACT_SHADOWS_BIT) != 0u) {
visibility *= (1.0 - screenSpaceContactShadow(frameUniforms.lightDirection));
}
}
Expand Down

0 comments on commit ee6612e

Please sign in to comment.