Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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: 11 additions & 4 deletions src/renderer/webgl/shaders/TilemapGPULayer-frag.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,25 @@ module.exports = [
'#pragma phaserTemplate(features)',
'#ifdef GL_FRAGMENT_PRECISION_HIGH',
'precision highp float;',
'#define DATA_PRECISION highp',
'#else',
'precision mediump float;',
'#define DATA_PRECISION mediump',
'#endif',
'/* Redefine MAX_ANIM_FRAMES to support animations with different frame numbers. */',
'#define MAX_ANIM_FRAMES 0',
'#pragma phaserTemplate(fragmentDefine)',
'uniform vec2 uResolution;',
'uniform sampler2D uMainSampler;',
'uniform sampler2D uLayerSampler;',
'uniform DATA_PRECISION sampler2D uLayerSampler;',
'uniform vec2 uMainResolution;',
'uniform vec2 uLayerResolution;',
'uniform float uTileColumns;',
'uniform vec4 uTileWidthHeightMarginSpacing;',
'uniform float uAlpha;',
'uniform float uTime;',
'#if MAX_ANIM_FRAMES > 0',
'uniform sampler2D uAnimSampler;',
'uniform DATA_PRECISION sampler2D uAnimSampler;',
'uniform vec2 uAnimResolution;',
'#endif',
'varying vec2 outTexCoord;',
Expand All @@ -31,9 +33,14 @@ module.exports = [
'{',
' return uMainResolution;',
'}',
'vec4 texelBytes (vec4 texel)',
'{',
' return floor(texel * 255.0 + 0.5);',
'}',
'float floatTexel (vec4 texel)',
'{',
' return texel.r * 255.0 + (texel.g * 255.0 * 256.0) + (texel.b * 255.0 * 256.0 * 256.0) + (texel.a * 255.0 * 256.0 * 256.0 * 256.0);',
' vec4 bytes = texelBytes(texel);',
' return bytes.r + (bytes.g * 256.0) + (bytes.b * 256.0 * 256.0) + (bytes.a * 256.0 * 256.0 * 256.0);',
'}',
'struct Tile',
'{',
Expand All @@ -50,7 +57,7 @@ module.exports = [
' vec2 tile = floor(texelCoord);',
' vec2 uv = fract(texelCoord);',
' uv.y = 1.0 - uv.y;',
' vec4 texel = texture2D(uLayerSampler, (tile + 0.5) / uLayerResolution) * 255.0;',
' vec4 texel = texelBytes(texture2D(uLayerSampler, (tile + 0.5) / uLayerResolution));',
' float flags = texel.a;',
' /* Check for empty tile flag in bit 28. */',
' if (flags == 16.0)',
Expand Down
29 changes: 25 additions & 4 deletions src/renderer/webgl/shaders/src/TilemapGPULayer.frag
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@

#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#define DATA_PRECISION highp
#else
precision mediump float;
#define DATA_PRECISION mediump
#endif

/* Redefine MAX_ANIM_FRAMES to support animations with different frame numbers. */
Expand All @@ -18,7 +20,16 @@ precision mediump float;

uniform vec2 uResolution;
uniform sampler2D uMainSampler;
uniform sampler2D uLayerSampler;
// The layer and animation samplers carry packed integer data (tile indices and
// flag bits), not colour, so they need more than the default sampler precision.
// GLSL ES 1.00 declares fragment shader samplers `lowp` by default (spec 4.5.3),
// which only guarantees 8-bit absolute precision. A driver that takes that
// literally decodes the layer texel a fraction below its true byte value, which
// is enough to break the exact comparisons that read the flag bits out of it.
// Observed on Adreno 740/750 (Galaxy S23 / S23 Ultra / Z Fold 7), where every
// empty tile failed its `flags == 16.0` test and drew tile 0 of the tileset over
// the layers beneath it.
uniform DATA_PRECISION sampler2D uLayerSampler;
uniform vec2 uMainResolution;
uniform vec2 uLayerResolution;
uniform float uTileColumns;
Expand All @@ -27,7 +38,7 @@ uniform float uAlpha;
uniform float uTime;

#if MAX_ANIM_FRAMES > 0
uniform sampler2D uAnimSampler;
uniform DATA_PRECISION sampler2D uAnimSampler;
uniform vec2 uAnimResolution;
#endif

Expand All @@ -42,10 +53,20 @@ vec2 getTexRes ()
return uMainResolution;
}

// Snap a UNORM8 texel back to the exact 0-255 byte values it was uploaded with.
// The channels below are weighted by powers of 256, so a fetch that is off by a
// fraction of a byte becomes an error of hundreds in the decoded value.
vec4 texelBytes (vec4 texel)
{
return floor(texel * 255.0 + 0.5);
}

// Convert a vec4 texel to a float.
float floatTexel (vec4 texel)
{
return texel.r * 255.0 + (texel.g * 255.0 * 256.0) + (texel.b * 255.0 * 256.0 * 256.0) + (texel.a * 255.0 * 256.0 * 256.0 * 256.0);
vec4 bytes = texelBytes(texel);

return bytes.r + (bytes.g * 256.0) + (bytes.b * 256.0 * 256.0) + (bytes.a * 256.0 * 256.0 * 256.0);
}

struct Tile
Expand All @@ -67,7 +88,7 @@ Tile getLayerData (vec2 coord)
// Invert Y, as textures are flipped in GL.
uv.y = 1.0 - uv.y;

vec4 texel = texture2D(uLayerSampler, (tile + 0.5) / uLayerResolution) * 255.0;
vec4 texel = texelBytes(texture2D(uLayerSampler, (tile + 0.5) / uLayerResolution));

float flags = texel.a;

Expand Down