Render Buffer Size larger than Default Framebuffer Size

I’m using an offscreen rendering technique that served me well for many years. My application renders to screen most of the time, but sometimes needs to render to an offscreen buffer. Recently, I wanted to increase that offscreen buffer and noticed that when I exceed the size of the initial OpenGL context (default framebuffer size), then the part that is larger than the context does not get rendered to.

To illustrate the issue, I’m rendering a white shape onto a black background:

  • when I choose a render buffer size smaller or equal than that of the context(1920x1100), e.g. 500x500, all works as expected:
    no_cutoff_500

  • but as soon as I exceed the context size, it’s like my buffer gets culled (here: 1500x1500):

I have tried using an FBO with a texture as render target and also a render buffer, both lead to the same outcome. I have checked the maximum allowable dimensions of the viewport and that of the renderbuffer via glGet - both give me a value far larger of what I’m requesting (32768).

My code for initializing the renderbuffer:

//Initialization:

...
float OFFSCREEN_BUFFER_SIZE = 1500.0f;

glGenRenderbuffers(1, &RBOColorId);
glBindRenderbuffer(GL_RENDERBUFFER, RBOColorId);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB8, OFFSCREEN_BUFFER_SIZE, OFFSCREEN_BUFFER_SIZE);

// create renderbuffer object for depthbuffer
glGenRenderbuffers(1, &RBODepthId);
glBindRenderbuffer(GL_RENDERBUFFER, RBODepthId);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, OFFSCREEN_BUFFER_SIZE, OFFSCREEN_BUFFER_SIZE);

// create a framebuffer object
glGenFramebuffers(1, FBO);
glBindFramebuffer(GL_FRAMEBUFFER, FBO[0]);

// attach colorbuffer image to FBO
glFramebufferRenderbuffer(GL_FRAMEBUFFER,       // 1. fbo target: GL_FRAMEBUFFER
						  GL_COLOR_ATTACHMENT0, // 2. color attachment point
						  GL_RENDERBUFFER,      // 3. rbo target: GL_RENDERBUFFER
						  RBOColorId);          // 4. rbo ID

// attach depthbuffer image to FBO
glFramebufferRenderbuffer(GL_FRAMEBUFFER,       // 1. fbo target: GL_FRAMEBUFFER
						  GL_DEPTH_ATTACHMENT,  // 2. depth attachment point
						  GL_RENDERBUFFER,      // 3. rbo target: GL_RENDERBUFFER
						  RBODepthId);          // 4. rbo ID

// check FBO status
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(status != GL_FRAMEBUFFER_COMPLETE)
	return false; //error
...

And my code for rendering and retrieving the image is:

//Usage:
//Render stuff to default framebuffer.. this works fine
...

glBindRenderbuffer(GL_RENDERBUFFER, RBO[0]);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0, 0, OFFSCREEN_BUFFER_SIZE, OFFSCREEN_BUFFER_SIZE);
glOrtho(0, OFFSCREEN_BUFFER_SIZE, 0, OFFSCREEN_BUFFER_SIZE, -1, 1);
//glGetIntegerv(GL_VIEWPORT, viewport); //returns the correct size of 1500x1500

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

//RENDER some stuff to this renderbuffer
...

//get the frame buffer content and write it to an opencv image
cv::Mat img(OFFSCREEN_BUFFER_SIZE, OFFSCREEN_BUFFER_SIZE, CV_8UC3);

//use fast 4-byte alignment (default anyway) if possible
glPixelStorei(GL_PACK_ALIGNMENT, (img.step & 3) ? 1 : 4);

//set length of one complete row in destination data (doesn't need to equal img.cols)
glPixelStorei(GL_PACK_ROW_LENGTH, img.step/img.elemSize());

glReadBuffer(GL_COLOR_ATTACHMENT0);
glReadPixels(0, 0, OFFSCREEN_BUFFER_SIZE, OFFSCREEN_BUFFER_SIZE, GL_BGR, GL_UNSIGNED_BYTE, img.data);

glBindRenderbuffer(GL_RENDERBUFFER, 0);

cv::Mat imgToShow;
cv::flip(img, imgToShow, 0);
cv::imshow("RenderBuffer", imgToShow);
cv::waitKey(0);

//continue rendering stuff to default framebuffer.. this works fine
...

My question is if this is at all possible? Can I render something thats larger than my screen? If so, what am I doing wrong?

This call should be glBindFramebuffer.

Thank you @GClements - I fixed it in my code. The issue of the cutoff buffer remains though.

I have finally found a solution. I have abandoned my approach and am now back to rendering to a texture. I think that the previous approach really has the aforementioned limitation. The following code below allows rendering to a texture much larger than that of the default framebuffer.

//Initialization:

...
float OFFSCREEN_BUFFER_SIZE = 10000.0f;

glGenTextures(1, &textureId);
glBindTexture(GL_TEXTURE_2D, textureId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); // automatic mipmap generation included in OpenGL v1.4
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, OFFSCREEN_BUFFER_SIZE, OFFSCREEN_BUFFER_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);

// create a normal (no MSAA) FBO to hold a render-to-texture
glGenFramebuffers(1, &FBO);
glBindFramebuffer(GL_FRAMEBUFFER, FBO);

glGenRenderbuffers(1, &RBO);
glBindRenderbuffer(GL_RENDERBUFFER, RBO);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, OFFSCREEN_BUFFER_SIZE, OFFSCREEN_BUFFER_SIZE);
glBindRenderbuffer(GL_RENDERBUFFER, 0);

// attach a texture to FBO color attachement point
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureID, 0);

// attach a rbo to FBO depth attachement point
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, RBO);

// check FBO status
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(status != GL_FRAMEBUFFER_COMPLETE)
	return false; //error
...

And the rendering part:

//Usage:
//Render stuff to default framebuffer.. this works fine
...

glBindFramebuffer(GL_FRAMEBUFFER, FBO);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0, 0, OFFSCREEN_BUFFER_SIZE, OFFSCREEN_BUFFER_SIZE);
glOrtho(0, OFFSCREEN_BUFFER_SIZE, 0, OFFSCREEN_BUFFER_SIZE, -1, 1);
//glGetIntegerv(GL_VIEWPORT, viewport); //returns the correct size of 1500x1500

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

//RENDER some stuff to this renderbuffer
...

//get the frame buffer content and write it to an opencv image
cv::Mat img(OFFSCREEN_BUFFER_SIZE, OFFSCREEN_BUFFER_SIZE, CV_8UC3);

glGetTextureImage(textureId, 0, GL_BGR, GL_UNSIGNED_BYTE, OFFSCREEN_BUFFER_SIZE * OFFSCREEN_BUFFER_SIZE * 3 * 4, img.data);
glBindFramebuffer(GL_FRAMEBUFFER, 0);

cv::Mat imgToShow;
cv::flip(img, imgToShow, 0);
cv::imshow("RenderBuffer", imgToShow);
cv::waitKey(0);

//continue rendering stuff to default framebuffer.. this works fine
...