However, there are two drawbacks to my current implementation:
1) Memory waste. I preallocate vertex and index buffers large enough to hold 80 tiles for each texture. Since I have no where near 80 tiles per texture currently, I'm wasting a good bit of memory here. Fortunately, this is an easy problem to solve. Once I have premade maps, I can store in the map file the size that each buffer needs to be. When in the map editor, I can implement a shrink function that will resize all the buffers to be as small as possible once I'm done editing them.
This fix, however, leads me into my second big drawback:
2) Code complexity. The naive implementation is so much more straightforward than my current rendering scheme. All I'd need to do would be store each tile in a list, and have tiles either hold or be paired with an index into the texture buffer. If I want to remove a tile from the map, all I have to do is remove it from the list. If I want to edit a tile, I can do it without mucking about in the master vertex buffer. And, most importantly, if I want to change the texture on a tile, I just need to change a single integer. If I want to do that now, I need to remove the verts corresponding to the tile from the current buffer, find the buffer for the new texture, and add the tile into that buffer. Then I need to tell all the tiles from the old buffer that a tile has been removed, so they can get their new vert buffer index.
Of course, this would mean every frame I'd need to walk the list, set the appropriate vertex/index stream and texture, and call DrawUP for that single tile. Or, if all those draw calls are too expensive, I could walk the list each from, copy each tiles verts and indices into a master buffer similar to how it's set up now, and send off those batched vertices for drawing. Probably faster than drawing each tile with its own Draw call, but I still have the overhead of walking the list and copying vertices and indices each frame.
So, I need to do some profiling and see if the time I save using precomputed batched vertex and index buffers is really worth the hoops I need to jump through in the code. Fun, fun!