If i render the level using only a single texture2d its pretty damn fast but for using multiple texture what I did is take all the triangles using the same textures and collecting them on startup. When im done loading and start to draw I loop in each of those triangles list, set the texture in my effect, fill the vertexbuffer and draw the primitives.
thx
for (i = 0; i < r_bsp.polygoneCollections.Length; i++)
{
if (r_bsp.polygoneCollections

continue;
texture = Bitmap.textures

Quake.effect.Parameters["UserTexture"].SetValue(texture);
Quake.effect.Begin();
foreach (EffectPass pass in Quake.effect.CurrentTechnique.Passes)
{
pass.Begin();
int numvertexes = r_bsp.polygoneCollections

vertexBuffer = new VertexBuffer(
Quake.graphics.GraphicsDevice,
VertexPositionTexture.SizeInBytes * numvertexes,
ResourceUsage.None,
ResourceManagementMode.Automatic);
vertexBuffer.SetData<VertexPositionTexture>(r_bsp.polygoneCollections

graphics.GraphicsDevice.Vertices[0].SetSource(vertexBuffer, 0, VertexPositionTexture.SizeInBytes);
graphics.GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, r_bsp.polygoneCollections

vertexBuffer.Dispose(); // If i dont do this the memory fill like mad and drop, repeat.....
pass.End();
}
Quake.effect.End();
}