Having read through Mark Alexander's knowledge base article, 'Optimising Your Games', the segment on changing the blend mode and its effect on speed stood out to me.
The crux of it being that Game Maker: Studio automatically batches together draw calls whenever possible, but as a matter of function it cannot do this when the blend mode needs to be changed. And in the case of instances with different blending, each object ends up as its own draw call, slowing things down considerably.
This made me think of possibility of sticking all objects of a specific blend mode on a specific depth and then placing objects on the depths below and above it in order to set and reset the blend mode and speed up rendering. I then wondered if this was even necessary, or if GM simply compared the current blend mode state to the desired one when executing the 'draw_set_blend_mode' function, thus rendering my optimisation useless.
This called for a test...
The Test Outline:
'obj_control' generates 4000 instances of 'obj_sprite' at random positions in its creation code.
It also records the maximum fps in a global variable for viewing in the debug window. Recording the minimum FPS would also have been prudent, but that would have required addtional work to have it only begin updating after the game has bypassed the initial few seconds of start-up lag.
'obj_sprite' draws itself, and depending on the sub-test, applies a set or random blend mode first.
'obj_block' fufills the purpose of setting the blend mode once for all instances of 'obj_sprite', potentially allowing for faster drawing.
It also blocks off the top right of the screen so that the debug info remains visible (consider that a small gripe). That in turn means there's a few duplicate instances of it, but since we have 4000 instances of 'obj_sprite' that's a few drops in the ocean.
I then tested the program in various configurations, and made a note of the maximum fps returned. Some varation existed between different runs of the exact same code, so consider the results accurate to around 10fps lower.
The Results (w/4000 objects):
Switching blend modes is indeed 'slow as all heck', breaking any kind of batching on the part of the game. Interestingly setting the blend mode to the existing blend mode drops the fps by a fifth, but is still sigificantly faster than switching the blend mode. Is this the result of the way GM queries the blend mode before changing? I can only assume GM is checking first before making that chance, hence the huge FPS boost.
My original idea of using two objects acting as buffers between different depth ranges, allowing those ranges to always be set to a specific blend mode still appears to have merit. Which, honestly, is a bit disappointing. It's a pretty cumbersome system to use. But it is also by a margin the fastest.
As you might have already thought, using 'with(obj_sprite) draw_self();' after having set the desired blend mode was also an option, however it only resulted in an fps of 305. This is an improvement, and if you're opposed to using special blend mode setting objects, having a control object is certainly a step up. However it still remains marginally slower, which might make the difference for games that need to be heavily optimised to run well on the target system.
TL;DR: Whatever you choose to do, keep objects with blend modes grouped at the same depths or FACE THE WRATH OF TERRIBLE SLOWDOWN.