// Assemble lists of the valid buffer configurations, along with the // possibilities for multisample coverage antialiasing, if any. void getPossibleConfigs(GraphicsContext* gc, BufferConfigList& colorConfigs, BufferConfigList& depthConfigs, vector<int>& coverageConfigs) { int maxSamples = 0; int coverageSampleConfigs = 0; unsigned contextID = gc->getState()->getContextID(); colorConfigs.push_back(BufferConfig("RGBA8", GL_RGBA8, 8)); depthConfigs.push_back(BufferConfig("D24", GL_DEPTH_COMPONENT24, 24)); FBOExtensions* fboe = FBOExtensions::instance(contextID, true); if (!fboe->isSupported()) return; if (fboe->isMultisampleSupported()) glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSamples); // isMultisampleCoverageSupported if (isGLExtensionSupported(contextID, "GL_NV_framebuffer_multisample_coverage")) { glGetIntegerv(GL_MAX_MULTISAMPLE_COVERAGE_MODES_NV, &coverageSampleConfigs); coverageConfigs.resize(coverageSampleConfigs * 2 + 4); glGetIntegerv(GL_MULTISAMPLE_COVERAGE_MODES_NV, &coverageConfigs[0]); } if (isGLExtensionSupported(contextID, "GL_ARB_depth_buffer_float")) depthConfigs.push_back(BufferConfig("D32F", GL_DEPTH_COMPONENT32F, 32)); else if (isGLExtensionSupported(contextID, "GL_NV_depth_buffer_float")) depthConfigs.push_back(BufferConfig("D32F", GL_DEPTH_COMPONENT32F_NV, 32)); }
bool checkFramebufferStatus(GraphicsContext* gc, bool silent = false) { State& state = *gc->getState(); unsigned contextID = state.getContextID(); FBOExtensions* fboe = FBOExtensions::instance(contextID, true); switch(fboe->glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT)) { case GL_FRAMEBUFFER_COMPLETE_EXT: break; case GL_FRAMEBUFFER_UNSUPPORTED_EXT: if (!silent) cout << "Unsupported framebuffer format\n"; return false; case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: if (!silent) cout << "Framebuffer incomplete, missing attachment\n"; return false; case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: if (!silent) cout << "Framebuffer incomplete, duplicate attachment\n"; return false; case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: if (!silent) cout << "Framebuffer incomplete, attached images must have same dimensions\n"; return false; case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: if (!silent) cout << "Framebuffer incomplete, attached images must have same format\n"; return false; case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: if (!silent) cout << "Framebuffer incomplete, missing draw buffer\n"; return false; case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: if (!silent) cout << "Framebuffer incomplete, missing read buffer\n"; return false; default: return false; } return true; }
// Standard OSG code for initializing osgViewer::Viewer with explicit // creation of own graphics context. This is also a good time to test // for valid frame buffer configurations; we have a valid graphics // context, but multithreading hasn't started, etc. GraphicsContext* setupGC(osgViewer::Viewer& viewer, ArgumentParser& arguments) { int x = -1, y = -1, width = -1, height = -1; while (arguments.read("--window",x,y,width,height)) {} GraphicsContext::WindowingSystemInterface* wsi = GraphicsContext::getWindowingSystemInterface(); if (!wsi) { OSG_NOTIFY(NOTICE)<<"View::setUpViewOnSingleScreen() : Error, no WindowSystemInterface available, cannot create windows."<<std::endl; return 0; } DisplaySettings* ds = viewer.getDisplaySettings() ? viewer.getDisplaySettings() : DisplaySettings::instance().get(); GraphicsContext::ScreenIdentifier si; si.readDISPLAY(); // displayNum has not been set so reset it to 0. if (si.displayNum<0) si.displayNum = 0; bool decoration = true; if (x < 0) { unsigned int w, h; wsi->getScreenResolution(si, w, h); x = 0; y = 0; width = w; height = h; decoration = false; } ref_ptr<GraphicsContext::Traits> traits = new GraphicsContext::Traits(ds); traits->hostName = si.hostName; traits->displayNum = si.displayNum; traits->screenNum = si.screenNum; traits->x = x; traits->y = y; traits->width = width; traits->height = height; traits->windowDecoration = decoration; traits->doubleBuffer = true; traits->sharedContext = 0; ref_ptr<GraphicsContext> gc = GraphicsContext::createGraphicsContext(traits.get()); osgViewer::GraphicsWindow* gw = dynamic_cast<osgViewer::GraphicsWindow*>(gc.get()); if (gw) { OSG_NOTIFY(INFO)<<"View::setUpViewOnSingleScreen - GraphicsWindow has been created successfully."<<std::endl; gw->getEventQueue()->getCurrentEventState() ->setWindowRectangle(0, 0, width, height); } else { OSG_NOTIFY(NOTICE)<<" GraphicsWindow has not been created successfully."<<std::endl; } double fovy, aspectRatio, zNear, zFar; viewer.getCamera()->getProjectionMatrixAsPerspective(fovy, aspectRatio, zNear, zFar); double newAspectRatio = double(traits->width) / double(traits->height); double aspectRatioChange = newAspectRatio / aspectRatio; if (aspectRatioChange != 1.0) { viewer.getCamera()->getProjectionMatrix() *= Matrix::scale(1.0/aspectRatioChange,1.0,1.0); } // Context has to be current to test for extensions gc->realize(); gc->makeCurrent(); unsigned int contextID = gc->getState()->getContextID(); FBOExtensions* fboe = FBOExtensions::instance(contextID, true); if (!fboe->isSupported()) { OSG_NOTIFY(NOTICE) << "Frame buffer objects are not supported\n"; gc->releaseContext(); gc->close(true); return 0; } if (isGLExtensionSupported(contextID, "GL_ARB_depth_buffer_float")) depthTextureEnum = GL_DEPTH_COMPONENT32F; else if (isGLExtensionSupported(contextID, "GL_NV_depth_buffer_float")) depthTextureEnum = GL_DEPTH_COMPONENT32F_NV; BufferConfigList colorConfigs; BufferConfigList depthConfigs; vector<int> coverageConfigs; getPossibleConfigs(gc.get(), colorConfigs, depthConfigs, coverageConfigs); int coverageSampleConfigs = (coverageConfigs.size() - 4) / 2; cout << "color configs\nname\tbits\n"; for (BufferConfigList::const_iterator colorItr = colorConfigs.begin(), colorEnd = colorConfigs.end(); colorItr != colorEnd; ++colorItr) { for (BufferConfigList::const_iterator depthItr = depthConfigs.begin(), depthEnd = depthConfigs.end(); depthItr != depthEnd; ++depthItr) { string root = colorItr->name + " " + depthItr->name; FboConfig config(root, colorItr->format, depthItr->format, colorItr->bits, depthItr->bits); FboData data; if (createFBO(gc.get(), config, data)) validConfigs.push_back(config); destroyFBO(gc.get(), data); if (coverageConfigs.size() > 0) { //CSAA provides a list of all supported AA modes for //quick enumeration for (int kk = 0; kk < coverageSampleConfigs; kk++) { stringstream msText; msText << root; config.depthSamples = coverageConfigs[kk*2+1]; config.coverageSamples = coverageConfigs[kk*2]; if ( config.coverageSamples == config.depthSamples ) { // Normal antialiasing msText << " - " << config.depthSamples << " MSAA"; } else { // coverage antialiasing msText << " - " << config.coverageSamples << "/" << config.depthSamples << " CSAA"; } config.name = msText.str(); if (createFBO(gc.get(), config, data)) { validConfigs.push_back( config); } destroyFBO(gc.get(), data); } } } } if (validConfigs.empty()) { cout << "no valid frame buffer configurations!\n"; return 0; } cout << "valid frame buffer configurations:\n"; for (vector<FboConfig>::iterator itr = validConfigs.begin(), end = validConfigs.end(); itr != end; ++itr) cout << itr->name << "\n"; gc->releaseContext(); return gc.release(); }
// Attempt to create an FBO with a certain configuration. If the FBO // is created with fewer bits in any of its parameters, the creation // is deemed to have failed. Even though the result is a valid FBO, // we're only interested in discrete, valid configurations. bool createFBO(GraphicsContext* gc, FboConfig &config, FboData &data) { bool result = true; bool multisample = config.depthSamples > 0; bool csaa = config.coverageSamples > config.depthSamples; data.fb = new FrameBufferObject; int texWidth = 512, texHeight = 512; data.tex = new Texture2D; data.tex->setTextureSize(texWidth, texHeight); data.tex->setInternalFormat(config.colorFormat); data.tex->setSourceFormat(GL_RGBA); data.tex->setSourceType(GL_FLOAT); data.tex->setFilter(Texture::MIN_FILTER, Texture::LINEAR_MIPMAP_LINEAR); data.tex->setFilter(Texture::MAG_FILTER, Texture::LINEAR); data.tex->setWrap(Texture::WRAP_S, Texture::CLAMP_TO_EDGE); data.tex->setWrap(Texture::WRAP_T, Texture::CLAMP_TO_EDGE); RenderBuffer* colorRB = 0; RenderBuffer* depthRB = 0; if (multisample) { data.resolveFB = new FrameBufferObject; data.resolveFB->setAttachment(Camera::COLOR_BUFFER, FrameBufferAttachment(data.tex.get())); colorRB = new RenderBuffer(texWidth, texHeight, config.colorFormat, config.coverageSamples, config.depthSamples); data.fb->setAttachment(Camera::COLOR_BUFFER, FrameBufferAttachment(colorRB)); depthRB = new RenderBuffer(texWidth, texHeight, config.depthFormat, config.coverageSamples, config.depthSamples); data.fb->setAttachment(Camera::DEPTH_BUFFER, FrameBufferAttachment(depthRB)); } else { data.depthTex = makeDepthTexture(texWidth, texHeight, config.depthFormat); data.fb->setAttachment(Camera::COLOR_BUFFER, FrameBufferAttachment(data.tex.get())); data.fb->setAttachment(Camera::DEPTH_BUFFER, FrameBufferAttachment(data.depthTex.get())); } State& state = *gc->getState(); unsigned int contextID = state.getContextID(); FBOExtensions* fboe = FBOExtensions::instance(contextID, true); data.fb->apply(state); result = checkFramebufferStatus(gc, true); if (!result) { fboe->glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0); return false; } int query; if (multisample) { GLuint colorRBID = colorRB->getObjectID(contextID, fboe); fboe->glBindRenderbuffer(GL_RENDERBUFFER_EXT, colorRBID); if (csaa) { fboe->glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_COVERAGE_SAMPLES_NV, &query); if (query < config.coverageSamples) result = false; else config.coverageSamples = query; fboe->glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_COLOR_SAMPLES_NV, &query); if ( query < config.depthSamples) result = false; else config.depthSamples = query; // report back the actual number } else { fboe->glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_SAMPLES_EXT, &query); if (query < config.depthSamples) result = false; else config.depthSamples = query; } } glGetIntegerv( GL_RED_BITS, &query); if (query != config.redbits) result = false; glGetIntegerv(GL_DEPTH_BITS, &query); if ( query != config.depthBits) result = false; if (result && multisample && data.resolveFB.valid()) { data.resolveFB->apply(state); result = checkFramebufferStatus(gc, true); if (result) { glGetIntegerv( GL_RED_BITS, &query); if (query != config.redbits) result = false; } } fboe->glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0); return result; }
void FrameBufferObject::apply(State &state, BindTarget target) const { unsigned int contextID = state.getContextID(); if (_unsupported[contextID]) return; FBOExtensions* ext = FBOExtensions::instance(contextID,true); if (!ext->isSupported()) { _unsupported[contextID] = 1; notify(WARN) << "Warning: EXT_framebuffer_object is not supported" << std::endl; return; } if (_attachments.empty()) { ext->glBindFramebufferEXT(target, 0); return; } int &dirtyAttachmentList = _dirtyAttachmentList[contextID]; GLuint &fboID = _fboID[contextID]; if (fboID == 0) { ext->glGenFramebuffersEXT(1, &fboID); if (fboID == 0) { notify(WARN) << "Warning: FrameBufferObject: could not create the FBO" << std::endl; return; } dirtyAttachmentList = 1; } if (dirtyAttachmentList) { // the set of of attachments appears to be thread sensitive, it shouldn't be because // OpenGL FBO handles osg::FrameBufferObject has are multi-buffered... // so as a temporary fix will stick in a mutex to ensure that only one thread passes through here // at one time. static OpenThreads::Mutex s_mutex; OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mutex); // create textures and mipmaps before we bind the frame buffer object for (AttachmentMap::const_iterator i=_attachments.begin(); i!=_attachments.end(); ++i) { const FrameBufferAttachment &fa = i->second; fa.createRequiredTexturesAndApplyGenerateMipMap(state, ext); } } ext->glBindFramebufferEXT(target, fboID); // enable drawing buffers to render the result to fbo if (_drawBuffers.size() > 0) { GL2Extensions *gl2e = GL2Extensions::Get(state.getContextID(), true ); if (gl2e) { gl2e->glDrawBuffers(_drawBuffers.size(), &(_drawBuffers[0])); } } if (dirtyAttachmentList) { for (AttachmentMap::const_iterator i=_attachments.begin(); i!=_attachments.end(); ++i) { const FrameBufferAttachment &fa = i->second; fa.attach(state, target, convertBufferComponentToGLenum(i->first), ext); } dirtyAttachmentList = 0; } }