gpu_set_blendmode(bm_normal);
pal_swap_batch_begin(spr_roof_palette, false);
for (var i = array_length(decorations) -1; i >= 0; --i) {
	with (decorations[i]){
		pal_swap_batch_pack_data(palette_index,1);
		Draw();
	}
}
pal_swap_batch_end();
gpu_set_blendmode(bm_normal);

// Fragment Shader: shd_pal_swapper_batch.fsh
#define Transparent vec4(0.0, 0.0, 0.0, 0.0)
#define Tolerance 0.004 
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
varying float v_fPaletteId; // <-- Receives palette index from vertex shader
uniform sampler2D u_palTexture;
uniform vec4 u_Uvs;
uniform vec2 u_pixelSize;
// uniform float u_paletteId; // <-- This uniform is NO LONGER USED
vec4 findAltColor(vec4 inCol, vec2 corner)
{
    if(inCol.a == 0.0) return Transparent;
    
    float dist;
    vec2 testPos;
    vec4 leftCol;
    for(float i = corner.y; i < u_Uvs.w; i += u_pixelSize.y)
    {
        testPos = vec2(corner.x, i);
        leftCol = texture2D(u_palTexture, testPos);
        
        dist = distance(leftCol, inCol);
        if(dist < Tolerance)
        {
            // Use the varying v_fPaletteId instead of the uniform
            testPos = vec2(corner.x + u_pixelSize.x * floor(v_fPaletteId + 1.0), i);
            return mix(texture2D(u_palTexture, vec2(testPos.x - u_pixelSize.x, testPos.y)), texture2D(u_palTexture, testPos), fract(v_fPaletteId));
        }
    }
    return inCol;
}
void main()
{
    vec4 col = texture2D(gm_BaseTexture, v_vTexcoord);
    
    // Use this instead of DoAlphaTest for clarity and compatibility
    if (col.a < 0.005) discard;
    col = findAltColor(col, u_Uvs.xy);
    gl_FragColor = v_vColour * col;
}

// Vertex Shader: shd_pal_swapper_batch.vsh
attribute vec3 in_Position;      // (x,y,z)
attribute vec4 in_Colour;        // (r,g,b,a) -> image_blend, image_alpha
attribute vec2 in_Texcoord;      // (u,v)
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
varying float v_fPaletteId;      // The palette index, passed to the fragment shader
void main()
{
    gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * vec4(in_Position.xy, 0.0, 1.0);
    v_vTexcoord = in_Texcoord;
    
    // --- NEW 5/3 BIT UNPACKING ---
    
    // 1. Get the packed 0-255 integer value from the alpha channel
    float packed_value = in_Colour.a * 255.0;
    
    // 2. Unpack the palette index (high 5 bits) by integer division by 8 (2^3)
    v_fPaletteId = floor(packed_value / 8.0);
    
    // 3. Unpack the alpha level (low 3 bits) using modulo 8, then normalize it to 0.0-1.0
    //    We divide by 7.0 because the range is 0-7.
    float final_alpha = mod(packed_value, 8.0) / 7.0;
    
    // 4. Pass the full RGB tint from image_blend and the unpacked alpha to the fragment shader
    v_vColour = vec4(in_Colour.rgb, final_alpha);
}

#macro rps_type_standard 0
#macro rps_type_html5_sprite 1
#macro rps_type_html5_surface 2

// Find your existing pal_swap_init_system and replace it with this one.

///@func pal_swap_init_system(shader, [batch_shader], [html5 sprite shader], [html5 surface shader])
function pal_swap_init_system(_shader = shd_pal_swapper, _batch_shader = shd_pal_swapper_batch, _html5_sprite_shader = shd_pal_html_sprite, _html5_surface_shader = shd_pal_html_surface) {

	var _swapper = {
		// Existing properties
		shader: noone,
		html5: false,
		html5_sprite: noone,
		html5_surface: noone,
		texel_size: [0],
		uvs: [0],
		index: [0], // For old system
		texture: [0],
		layer_data: {},
		
		// New property for batched system
		shader_batch: noone,
	}

	_swapper.html5 = os_browser != browser_not_a_browser;
	
	// --- New Batched Shader Init ---
	// Just store a reference to the shader asset itself.
	_swapper.shader_batch = _batch_shader;
	
	// --- Existing Logic (Unchanged) ---
	// We get the uniform locations from the OLD shader, but we can reuse them
	// for the NEW shader since the uniform names are identical.
	if(!_swapper.html5) {
		_swapper.shader = _shader;
		_swapper.texel_size[rps_type_standard] = shader_get_uniform(_shader, "u_pixelSize");
		_swapper.uvs[rps_type_standard] = shader_get_uniform(_shader, "u_Uvs");
		_swapper.index[rps_type_standard] = shader_get_uniform(_shader, "u_paletteId");
		_swapper.texture[rps_type_standard] = shader_get_sampler_index(_shader, "u_palTexture");
	} else {
		// ... (rest of the HTML5 logic is unchanged)
		if(_html5_sprite_shader == undefined || _html5_surface_shader == undefined) {
			show_message("Must provide pal_swap_init_system() with 2 additional arguments for HTML5 Compatible Sprite and Surface Shaders");
			game_end();
		}
		_swapper.html5_sprite = _html5_sprite_shader;
		_swapper.html5_surface = _html5_surface_shader;
	
		_swapper.texel_size[rps_type_html5_sprite] = shader_get_uniform(_html5_sprite_shader, "u_pixelSize");
		_swapper.uvs[rps_type_html5_sprite] = shader_get_uniform(_html5_sprite_shader, "u_Uvs");
		_swapper.index[rps_type_html5_sprite] = shader_get_uniform(_html5_sprite_shader, "u_paletteId");
		_swapper.texture[rps_type_html5_sprite] = shader_get_sampler_index(_html5_sprite_shader, "u_palTexture");
	
		_swapper.texel_size[rps_type_html5_surface] = shader_get_uniform(_html5_surface_shader, "u_pixelSize");
		_swapper.uvs[rps_type_html5_surface] = shader_get_uniform(_html5_surface_shader, "u_Uvs");
		_swapper.index[rps_type_html5_surface] = shader_get_uniform(_html5_surface_shader, "u_paletteId");
		_swapper.texture[rps_type_html5_surface] = shader_get_sampler_index(_html5_surface_shader, "u_palTexture");
	}
	
	global.retro_pal_swapper = _swapper;
}

pal_swap_init_system();
	
///@func pal_swap_set(palette_sprite_index, palette_index, palette is surface);
function pal_swap_set(_pal_sprite, _pal_index, _is_surface) {
	
	var _swapper = global.retro_pal_swapper;
	
	if(_pal_index == 0) exit;

	var _mode = rps_type_standard;
	
	if(!_is_surface) {   
		//Using a sprite based palette
		if(_swapper.html5)	{
			shader_set(_swapper.html5_sprite);
			_mode = rps_type_html5_sprite;
		} else shader_set(_swapper.shader);

		var _tex = sprite_get_texture(_pal_sprite, 0),
				_UVs = sprite_get_uvs(_pal_sprite, 0);
	  texture_set_stage(_swapper.texture[_mode], _tex);
    
	  var _texel_x = texture_get_texel_width(_tex),
	      _texel_y = texture_get_texel_height(_tex),
	      _texel_hx = _texel_x * 0.5,
	      _texel_hy = _texel_y * 0.5;
    
	  shader_set_uniform_f(_swapper.texel_size[_mode], _texel_x, _texel_y);
	  shader_set_uniform_f(_swapper.uvs[_mode], _UVs[0] + _texel_hx, _UVs[1] + _texel_hy, _UVs[2], _UVs[3]);
	  shader_set_uniform_f(_swapper.index[_mode], _pal_index);
	} else {   
		//Using a surface based palette
		if(_swapper.html5) {
			shader_set(_swapper.html5_surface);
			_mode = rps_type_html5_surface;
		}	else shader_set(_swapper.shader);
    
		var _tex = surface_get_texture(_pal_sprite);
    
	  texture_set_stage(_swapper.texture[_mode], _tex);
    
	  var _texel_x = texture_get_texel_width(_tex),
	      _texel_y = texture_get_texel_height(_tex),
	      _texel_hx = _texel_x * 0.5,
	      _texel_hy = _texel_y * 0.5;
		shader_set_uniform_f(_swapper.texel_size[_mode], _texel_x, _texel_y);
	  shader_set_uniform_f(_swapper.uvs[_mode], _texel_hx, _texel_hy, 1.0 + _texel_hx, 1.0 + _texel_hy);
	  shader_set_uniform_f(_swapper.index[_mode], _pal_index);
	}
}

/// @func pal_swap_reset();
function pal_swap_reset() {
	//Resets the shader
	if(shader_current() != -1){
		shader_reset();
	}
}


///@func pal_swap_layer_init();  
// Should be called once before setting up any layers to pal swap.
// This should be done on room start
function pal_swap_layer_init() {
	global.retro_pal_swapper.layer_data = {};
}

// @func pal_swap_set_layer(pal_sprite, pal_index, layer_index, pal_is_surface)
//draws the specified layer using the specified palette in the specified event.
function pal_swap_set_layer(_pal_sprite, _pal_index, _layer_index, _pal_is_surface) {
	global.retro_pal_swapper.layer_data[$ _layer_index] = {sprite: _pal_sprite, index: _pal_index, is_surf: _pal_is_surface};
}

function pal_swap_enable_layer(_layer_index) {
  if(!layer_exists(_layer_index)) return;

  var _onLayerBegin = method({layer: _layer_index}, function(){
    if(event_type == ev_draw) {
        var _data = global.retro_pal_swapper.layer_data[$ layer];
        if(_data == undefined) return;
        
        pal_swap_set(_data.sprite,_data.index,_data.is_surf);
    }
  });
  
  layer_script_begin(_layer_index, _onLayerBegin);
  
  layer_script_end(_layer_index,function() {
    if(event_type == ev_draw) {
        pal_swap_reset();
    }
  });
}

/// @func pal_swap_batch_pack_data(palette_index, alpha)
/// @desc Packs palette (0-31) and alpha (0-7) data into image_alpha.
/// @param {Integer} palette_index  The palette index (now 0-31).
/// @param {Real}    alpha          The transparency (0.0 - 1.0).
function pal_swap_batch_pack_data(_palette_index, _alpha) {
    // Convert your 0.0-1.0 alpha into our new 0-7 scale for packing
    var _alpha_level = floor(clamp(_alpha, 0.0, 1.0) * 7);

    // Clamp the palette index to the new 0-31 range
    var _pal_idx = clamp(_palette_index, 0, 31);
    
    // --- The Packing Logic ---
    // We shift the palette index by 3 bits to make room for the 3 bits of alpha data.
    var _packed_value = (_pal_idx << 3) | _alpha_level;
    
    // Set the final image_alpha (this line remains the same)
    image_alpha = _packed_value / 255.0;
}
/// @func pal_swap_batch_begin(palette_sprite, is_surface)
/// @desc Sets the batched shader and palette texture. Call ONCE at the start of a layer/batch.
function pal_swap_batch_begin(_pal_sprite, _is_surface) {
	var _swapper = global.retro_pal_swapper;
	
	// Set the new batched shader
	shader_set(_swapper.shader_batch);
    
	// We'll reuse the uniform locations from the original setup.
	// We just need to know which mode we're in (standard, html5_sprite, etc.)
	// For simplicity, this example assumes non-HTML5.
	var _mode = rps_type_standard; 
	// Add HTML5 logic here if you need it for the batched shader.
	
	var _tex;
	if (!_is_surface) {
		_tex = sprite_get_texture(_pal_sprite, 0);
		var _UVs = sprite_get_uvs(_pal_sprite, 0);
		var _texel_x = texture_get_texel_width(_tex);
		var _texel_y = texture_get_texel_height(_tex);
		// Reuse the uniform locations from the original system
		shader_set_uniform_f(_swapper.texel_size[_mode], _texel_x, _texel_y);
		shader_set_uniform_f(_swapper.uvs[_mode], _UVs[0] + _texel_x*0.5, _UVs[1] + _texel_y*0.5, _UVs[2], _UVs[3]);
	} else {
		_tex = surface_get_texture(_pal_sprite);
		var _texel_x = texture_get_texel_width(_tex);
		var _texel_y = texture_get_texel_height(_tex);
		// Reuse the uniform locations from the original system
		shader_set_uniform_f(_swapper.texel_size[_mode], _texel_x, _texel_y);
		shader_set_uniform_f(_swapper.uvs[_mode], _texel_x*0.5, _texel_y*0.5, 1.0 + _texel_x*0.5, 1.0 + _texel_y*0.5);
	}
	
	// Reuse the texture sampler location from the original system
	texture_set_stage(_swapper.texture[_mode], _tex);
}

/// @func pal_swap_batch_end()
/// @desc Resets the shader. Call ONCE at the end of a layer/batch.
function pal_swap_batch_end() {
	pal_swap_reset();
}

///@func pal_swap_batch_enable_layer(layer_index)
/// @desc Sets up a layer to use the high-performance batched shader.
function pal_swap_batch_enable_layer(_layer_index) {
	if(!layer_exists(_layer_index)) return;

	var _onLayerBegin = method({layer: _layer_index}, function() {
		if(event_type == ev_draw) {
			var _data = global.retro_pal_swapper.layer_data[$ layer];
			if (_data == undefined) return;
			pal_swap_batch_begin(_data.sprite, _data.is_surf);
		}
	});
  
	var _onLayerEnd = function() {
		if(event_type == ev_draw) {
			pal_swap_batch_end();
		}
	};
	
	layer_script_begin(_layer_index, _onLayerBegin);
	layer_script_end(_layer_index, _onLayerEnd);
}

Win32 function failed: HRESULT: 0x887a0005

Call: GR_D3D_Device->CreateBlendState at line 468 in file \StateManagerM.cpp
Device lost - reason: 0x887a0006

I get this error when trying to use batched shader and game crashes. Why is it happening?