Intel HD onboard chips can play OA on 1080 fine (in the hundreds),
Mine can't (HD3000). At least not always and not if I want to play with guaranteed smoothness.
Had to settle on 1024x768 (also, nice square aspect "as it was meant to play")
I never profiled this, but I suspect that the problem is with rocket trails and other effects that give spikes in overdraw.
and the old video cards I have would struggle with the texture uploading bandwidth for the DRR'd framebuffer.
Hmm, it depends on the definition of "old", then.
It seems my collection of old video cards falls into a different range.
The oldest I have, and that's GF FX 5200, which has *only* twice the fill rate of an GF 2 MX 400 (reeeeally pathetic) but supports FBO just fine, and having that support means almost zero extra cost, there is no "uploading". You attach a texture to FBO, render into it, then switch back to frame buffer, bind that texture and voila.
For older video cards, as I said, the uploading cost is... I once made a nifty bloom & fake HDR post-processing that worked on a GF 2 MX 400, and it achieved 75 FPS at 640x480 (250 FPS without it), and it worked by glCopyTexSubImage2d().
See the demo here (will not work in windowed mode if window wider than 1024)
So if, say, you use DRR to protect from overdraw spikes and only activate downsampling during frame rate drops (explosions & other effects galore)
and you only use render resolutions of 512x384 or below, then still DRR will work and will help,
even on a GeForce 2.
DRR not possible on Voodoo2, but then I have no idea how to make a renderer supporting
that. I loved that card and lament the fact I don't have it anymore, but... Yeah, too too non-standard.
the framebuffer objects (FBOs) would be initialized (i.e. create 8 or more FBOs where lower resolution FBO would be 32x32 pixels in size, second one would be 64x64, etc until 2048x2048 or maximum the graphic card can have
First, 256x256 is the sane lower limit and I only use it for emergencies (see below)
Second, you ideally begin with *just one* FBO that equals the screen resolution (say, a 640x480 texture). It is
very hard to find a card that doesn't support NPOT (non-power-of-2) textures. I only have one, GF FX 5200.
An important detail: either do not issue buffer clearing commands without glScissor, or clear the buffer by rendering a blank quad. I learned this the hard way. Otherwise you get performance loss for clearing the parts not in use.
Third, you create larger FBOs on demand when your load balancer finally decides that yes, supersampling is viable. Because a 2048x2048 FBO is 32 megabytes of video memory. Not exactly much, but still.
If the video card has enough memory, then creating a new FBO takes 10 miliseconds or less, not really noticeable.
So, you begin with 640x480, then create a second FBO of 1280x960 and then maybe a 2048x1440. More samples than that are... a bit meaningless IMHO.
The thing to watch out for:
- sometimes FBO creation fails without reason and you have to fall back to the existing smaller one.
- maximum FBO size reported by OpenGL does NOT guarantee that your video driver can really create one that huge. My GTX 460 was reporting, like, 8k x 8k but could fail as early as 6k x 6k. This failure may result in a freeze of 100..150 miliseconds.
-this above decision selects the appropriate FBO as our rendering target (this is really one OpenGL call to make and a fast one as well) - following this rendering happens as usual without any changes
Yes, and as far as I can see, FBO switching has no measurable cost.
glBindFramebuffer(GL_FRAMEBUFFER_EXT, MyFBOHandle);
FBOs are during their entire lifecycle stored in video card memory and each of them can be used as a texture when drawing primitives by simply using glBind(TEXTURE_2D, FBO_id); - again, one command and a fast one as well to perform (no need for transfers from CPU or similar)
Exactly.
Just, ahem, do not forget to unbind the FBO first: glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
-as the FBOs are basically textures the appropriate one is used as the texture when our postprocessing 'quad' is drawn, UV coordinates for the texture-to-quad mapping would probably be the same for all the FBOs
Not, because you want to use only a part of any given FBO (glViewport() + glScissor()) to achieve smooth resolution manipulation.
But still very simple and straightforward.
P.S. Oh, ah, and FBO isn't its texture. FBO to texture is exactly like a GLSL program object to a fragment shader object and creation is quite similar. You create a bog-standard texture, you create a special depth buffer texture of identical dimensions, then you create a FBO and attach both textures to it as attachments.
See my function (testing for a specific video driver quirk) that goes full circle: creating, binding, deleting:
procedure TestOpenGlQuirkNo2;
//FBO supports GL_RGB8 and GL_RGBA16 but not GL_RGBA8
//Found on: GeForce FX 5200
//Detected by: failing to create a 256x256 FBO with a GL_RGBA8 color buffer
function TryCreateFbo(cbf: GLuint; txt: string): boolean;
var db, fbo, cb: GLuint;
begin
if Mother^.Debug.Verbose then AddLog(' Creating a FBO with %0 color buffer...',[txt]);
glGenRenderbuffers(1, @db);
CheckGlError;
glBindRenderbuffer(GL_RENDERBUFFER_EXT, db);
CheckGlError;
glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, 256, 256);
CheckGlError;
glGenTextures(1, @cb);
CheckGlError;
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, cb);
CheckGlError;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D ( GL_TEXTURE_2D, 0, cbf, 256, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, NIL);
CheckGlError;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
CheckGlError;
glGenFramebuffers(1, @fbo);
glBindFramebuffer(GL_FRAMEBUFFER_EXT, fbo);
CheckGlError;
glBindTexture(GL_TEXTURE_2D, Mother^.GAPI.StubTexture); //bind a safe non-used texture
glFramebufferTexture2D(
//GL_DRAW_FRAMEBUFFER
GL_FRAMEBUFFER_EXT
, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, cb, 0);
CheckGlError;
glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, db);
CheckGlError(true);
Result:= GL_FRAMEBUFFER_COMPLETE_EXT = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
CheckGlError;
glDeleteFramebuffers(1, @fbo);
CheckGlError;
glDeleteTextures(1, @cb);
CheckGlError;
glDeleteRenderbuffers(1, @db);
CheckGlError;
if Mother^.Debug.Verbose then AddLog(' ..result=%0',[Result]);
end;
begin
if OpenGLQuirkFboCantGL_RGBA8 in Mother^.GAPI.QuirksTested then Exit; //already tested
try
if Mother^.Debug.Verbose then AddLog('This video card haven''t yet been tested for OpenGL quirk #2. Trying to detect it...');
if TryCreateFbo(GL_RGBA16, 'GL_RGBA16') and not TryCreateFbo(GL_RGBA8, 'GL_RGBA8')
then Mother^.GAPI.Quirks+= [OpenGLQuirkFboCantGL_RGBA8];
if Mother^.Debug.Verbose then AddLog('The quirk is marked as checked. Detected=%0', [OpenGLQuirkFboCantGL_RGBA8 in Mother^.GAPI.Quirks]);
Mother^.GAPI.QuirksTested+= [OpenGLQuirkFboCantGL_RGBA8];
except
Die(RuEn(
'Сбой при проверке OpenGL на глюк №2 (FBO не может работать с 8-битным цветовым буфером с альфа-каналом)',
'Failed to test for OpenGL quirk #2 (FBO cannot work with 8-bit RGBA color buffer)'
));
end;
end;