You might have an advantage since you're using OpenGL. Forgive me if this doesn't make sense, it has been a while since I played with raw OpenGL, so I hope everything I know hasn't been deprecated!
First of all, try doing it the sloppy way (draw the whole screen, then do your magic with the black-blocking objects). See how it hits performance. It probably won't. My games tend to fail to become completed because I burn out worrying about all the poor pixels being blitted only to be snuffed out by rgb(0,0,0). Wait until it takes a bite out of your performance, then evolve out of the naive approach.
“We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%.” - Donald Knuth
Now, more helpfully
, you could try a couple of things. You might try figuring out how many spotlights are visible to your viewport (a series of inexpensive AABB tests) then adjust your blitting code so you can tell it do only draw "(x,y)-(width,height)" of the screen. If you've ever done dirty-rectangles, that shouldn't be too awkward. You're really just replacing (0,0)-(SCREEN_W, SCREEN_H) with parameters (x, y)-(w,h). Then you can get away with only drawing the inscribed circle with black outside after plopping down potentially visible areas.
Other-otherwise, maybe there is some simple OpenGL magic where you can just let the system cull the quads you want hidden. I know scissor test can block out a rectangle at a time, is there some sort of scissor-buffer for arbitrary shapes?
Good luck, be sure to throw up a screenshot!
Rob