I handle animation by, at start up, drawing each animation frame to a different surface.
eg: Something like GroundSurfaces: array[0..2] of TDirectDrawSurface.

So, if you have a FrameIndex variable like you normally would, you just use that value to get the proper surface.
This way you never have to loop through all the tiles again, which is the main fps killer. Normally, the only Surfaces that would need to be redrawn will be those with tiles, sprites, etc that move around, but if you only have around 10 moving sprites, thats a hell of a lot quicker to loop through then a 100x100xEachLayer tile map everyframe.

And of course, animation would also have to be timebased, lol at 1000+ fps the animation might be little too fast

and don't forget to clip the drawing to the screen WxH with something like:
Draw(0,0,rect(offx,offy,screenW+offx,screenH+offy) , Surface, true);
no point in drawing what you can't see