U32 GFXGLDevice::getTotalVideoMemory_GL_EXT() { // Source: http://www.opengl.org/registry/specs/ATI/meminfo.txt if( gglHasExtension(ATI_meminfo) ) { GLint mem[4] = {0}; glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, mem); // Retrieve the texture pool /* With mem[0] i get only the total memory free in the pool in KB * * mem[0] - total memory free in the pool * mem[1] - largest available free block in the pool * mem[2] - total auxiliary memory free * mem[3] - largest auxiliary free block */ return mem[0] / 1024; } //source http://www.opengl.org/registry/specs/NVX/gpu_memory_info.txt else if( gglHasExtension(NVX_gpu_memory_info) ) { GLint mem = 0; glGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, &mem); return mem / 1024; } // TODO OPENGL, add supprt for INTEL cards. return 0; }
void GFXGLWindowTarget::resolveTo(GFXTextureObject* obj) { AssertFatal(dynamic_cast<GFXGLTextureObject*>(obj), "GFXGLTextureTarget::resolveTo - Incorrect type of texture, expected a GFXGLTextureObject"); GFXGLTextureObject* glTexture = static_cast<GFXGLTextureObject*>(obj); if( gglHasExtension(ARB_copy_image) ) { if(mBackBufferColorTex.getWidth() == glTexture->getWidth() && mBackBufferColorTex.getHeight() == glTexture->getHeight() && mBackBufferColorTex.getFormat() == glTexture->getFormat()) { glCopyImageSubData( static_cast<GFXGLTextureObject*>(mBackBufferColorTex.getPointer())->getHandle(), GL_TEXTURE_2D, 0, 0, 0, 0, glTexture->getHandle(), GL_TEXTURE_2D, 0, 0, 0, 0, getSize().x, getSize().y, 1); return; } } PRESERVE_FRAMEBUFFER(); if(!mCopyFBO) { glGenFramebuffers(1, &mCopyFBO); } glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mCopyFBO); glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glTexture->getHandle(), 0); glBindFramebuffer(GL_READ_FRAMEBUFFER, mBackBufferFBO); glBlitFramebuffer(0, 0, getSize().x, getSize().y, 0, 0, glTexture->getWidth(), glTexture->getHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST); }
GFXGLStateBlock::GFXGLStateBlock(const GFXStateBlockDesc& desc) : mDesc(desc), mCachedHashValue(desc.getHashValue()) { if( !gglHasExtension(ARB_sampler_objects) ) return; static Map<GFXSamplerStateDesc, U32> mSamplersMap; for(int i = 0; i < TEXTURE_STAGE_COUNT; ++i) { GLuint &id = mSamplerObjects[i]; GFXSamplerStateDesc &ssd = mDesc.samplers[i]; Map<GFXSamplerStateDesc, U32>::Iterator itr = mSamplersMap.find(ssd); if(itr == mSamplersMap.end()) { glGenSamplers(1, &id); glSamplerParameteri(id, GL_TEXTURE_MIN_FILTER, minificationFilter(ssd.minFilter, ssd.mipFilter, 1) ); glSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, GFXGLTextureFilter[ssd.magFilter]); glSamplerParameteri(id, GL_TEXTURE_WRAP_S, GFXGLTextureAddress[ssd.addressModeU]); glSamplerParameteri(id, GL_TEXTURE_WRAP_T, GFXGLTextureAddress[ssd.addressModeV]); glSamplerParameteri(id, GL_TEXTURE_WRAP_R, GFXGLTextureAddress[ssd.addressModeW]); if(static_cast< GFXGLDevice* >( GFX )->supportsAnisotropic() ) glSamplerParameterf(id, GL_TEXTURE_MAX_ANISOTROPY_EXT, ssd.maxAnisotropy); mSamplersMap[ssd] = id; } else id = itr->value; } }
void GFXGLCardProfiler::setupCardCapabilities() { GLint maxTexSize; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize); const char* versionString = reinterpret_cast<const char*>(glGetString(GL_VERSION)); F32 glVersion = dAtof(versionString); // OpenGL doesn't have separate maximum width/height. setCapability("maxTextureWidth", maxTexSize); setCapability("maxTextureHeight", maxTexSize); setCapability("maxTextureSize", maxTexSize); // If extensions haven't been inited, we're in trouble here. bool suppVBO = (gglHasExtension(GL_ARB_vertex_buffer_object) || glVersion >= 1.499f); setCapability("GL::suppVertexBufferObject", suppVBO); // check if render to texture supported is available bool suppRTT = gglHasExtension(GL_EXT_framebuffer_object); setCapability("GL::suppRenderTexture", suppRTT); bool suppBlit = gglHasExtension(GL_EXT_framebuffer_blit); setCapability("GL::suppRTBlit", suppBlit); bool suppFloatTex = gglHasExtension(GL_ATI_texture_float); setCapability("GL::suppFloatTexture", suppFloatTex); // Check for anisotropic filtering support. bool suppAnisotropic = gglHasExtension( GL_EXT_texture_filter_anisotropic ); setCapability( "GL::suppAnisotropic", suppAnisotropic ); // Check to see if mipmap lod bias is supported bool suppMipLodBias = gglHasExtension(GL_EXT_texture_lod_bias); setCapability("GL::suppMipLodBias", suppMipLodBias); // check to see if we have the fragment shader extension or the gl version is high enough for glsl to be core // also check to see if the language version is high enough F32 glslVersion = dAtof(reinterpret_cast<const char*>(glGetString( GL_SHADING_LANGUAGE_VERSION))); bool suppSPU = (gglHasExtension(GL_ARB_fragment_shader) || glVersion >= 1.999f) && glslVersion >= 1.0999; setCapability("GL::suppFragmentShader", suppSPU); bool suppAppleFence = gglHasExtension(GL_APPLE_fence); setCapability("GL::APPLE::suppFence", suppAppleFence); // When enabled, call glGenerateMipmapEXT() to generate mipmaps instead of relying on GL_GENERATE_MIPMAP setCapability("GL::Workaround::needsExplicitGenerateMipmap", false); // When enabled, binds and unbinds a texture target before doing the depth buffer copy. Failure to do // so will cause a hard freeze on Mac OS 10.4 with a Radeon X1600 setCapability("GL::Workaround::X1600DepthBufferCopy", false); // When enabled, does not copy the last column and row of the depth buffer in a depth buffer copy. Failure // to do so will cause a kernel panic on Mac OS 10.5(.1) with a Radeon HD 2600 (fixed in 10.5.2) setCapability("GL::Workaround::HD2600DepthBufferCopy", false); // Certain Intel drivers have a divide by 0 crash if mipmaps are specified with // glTexSubImage2D. setCapability("GL::Workaround::noManualMips", false); }
void GFXGLTextureObject::bind(U32 textureUnit) { glActiveTexture(GL_TEXTURE0 + textureUnit); glBindTexture(mBinding, mHandle); GFXGL->getOpenglCache()->setCacheBindedTex(textureUnit, mBinding, mHandle); if( gglHasExtension(ARB_sampler_objects) ) return; GFXGLStateBlockRef sb = mGLDevice->getCurrentStateBlock(); AssertFatal(sb, "GFXGLTextureObject::bind - No active stateblock!"); if (!sb) return; const GFXSamplerStateDesc ssd = sb->getDesc().samplers[textureUnit]; if(mNeedInitSamplerState) { initSamplerState(ssd); return; } if(mSampler.minFilter != ssd.minFilter || mSampler.mipFilter != ssd.mipFilter) glTexParameteri(mBinding, GL_TEXTURE_MIN_FILTER, minificationFilter(ssd.minFilter, ssd.mipFilter, mMipLevels)); if(mSampler.magFilter != ssd.magFilter) glTexParameteri(mBinding, GL_TEXTURE_MAG_FILTER, GFXGLTextureFilter[ssd.magFilter]); if(mSampler.addressModeU != ssd.addressModeU) glTexParameteri(mBinding, GL_TEXTURE_WRAP_S, !mIsNPoT2 ? GFXGLTextureAddress[ssd.addressModeU] : GL_CLAMP_TO_EDGE); if(mSampler.addressModeV != ssd.addressModeV) glTexParameteri(mBinding, GL_TEXTURE_WRAP_T, !mIsNPoT2 ? GFXGLTextureAddress[ssd.addressModeV] : GL_CLAMP_TO_EDGE); if(mBinding == GL_TEXTURE_3D && mSampler.addressModeW != ssd.addressModeW ) glTexParameteri(mBinding, GL_TEXTURE_WRAP_R, GFXGLTextureAddress[ssd.addressModeW]); if(mSampler.maxAnisotropy != ssd.maxAnisotropy && static_cast< GFXGLDevice* >( GFX )->supportsAnisotropic() ) glTexParameterf(mBinding, GL_TEXTURE_MAX_ANISOTROPY_EXT, ssd.maxAnisotropy); mSampler = ssd; }
void GFXGLCardProfiler::setupCardCapabilities() { GLint maxTexSize; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize); // OpenGL doesn't have separate maximum width/height. setCapability("maxTextureWidth", maxTexSize); setCapability("maxTextureHeight", maxTexSize); setCapability("maxTextureSize", maxTexSize); // Check for anisotropic filtering support. setCapability("GL_EXT_texture_filter_anisotropic", gglHasExtension(EXT_texture_filter_anisotropic)); // Check for buffer storage #ifdef TORQUE_NSIGHT_WORKAROUND setCapability("GL_ARB_buffer_storage", false); #else setCapability("GL_ARB_buffer_storage", gglHasExtension(ARB_buffer_storage)); #endif // Check for shader model 5.0 setCapability("GL_ARB_gpu_shader5", gglHasExtension(ARB_gpu_shader5)); // Check for texture storage setCapability("GL_ARB_texture_storage", gglHasExtension(ARB_texture_storage)); // Check for sampler objects setCapability("GL_ARB_sampler_objects", gglHasExtension(ARB_sampler_objects)); // Check for copy image support setCapability("GL_ARB_copy_image", gglHasExtension(ARB_copy_image)); // Check for vertex attrib binding setCapability("GL_ARB_vertex_attrib_binding", gglHasExtension(ARB_vertex_attrib_binding)); }
bool GFXGLShader::_loadShaderFromStream( GLuint shader, const Torque::Path &path, FileStream *s, const Vector<GFXShaderMacro> ¯os ) { Vector<char*> buffers; Vector<U32> lengths; // The GLSL version declaration must go first! const char *versionDecl = "#version 150\r\n"; buffers.push_back( dStrdup( versionDecl ) ); lengths.push_back( dStrlen( versionDecl ) ); if(gglHasExtension(EXT_gpu_shader4)) { const char *extension = "#extension GL_EXT_gpu_shader4 : enable\r\n"; buffers.push_back( dStrdup( extension ) ); lengths.push_back( dStrlen( extension ) ); } if(gglHasExtension(ARB_gpu_shader5)) { const char *extension = "#extension GL_ARB_gpu_shader5 : enable\r\n"; buffers.push_back( dStrdup( extension ) ); lengths.push_back( dStrlen( extension ) ); } const char *newLine = "\r\n"; buffers.push_back( dStrdup( newLine ) ); lengths.push_back( dStrlen( newLine ) ); // Now add all the macros. for( U32 i = 0; i < macros.size(); i++ ) { if(macros[i].name.isEmpty()) // TODO OPENGL continue; String define = String::ToString( "#define %s %s\n", macros[i].name.c_str(), macros[i].value.c_str() ); buffers.push_back( dStrdup( define.c_str() ) ); lengths.push_back( define.length() ); } // Now finally add the shader source. U32 shaderLen = s->getStreamSize(); char *buffer = _handleIncludes(path, s); if ( !buffer ) return false; buffers.push_back(buffer); lengths.push_back(shaderLen); glShaderSource(shader, buffers.size(), (const GLchar**)const_cast<const char**>(buffers.address()), NULL); #if defined(TORQUE_DEBUG) && defined(TORQUE_DEBUG_GFX) FileStream stream; if ( !stream.open( path.getFullPath()+"_DEBUG", Torque::FS::File::Write ) ) { AssertISV(false, avar("GFXGLShader::initShader - failed to write debug shader '%s'.", path.getFullPath().c_str())); } for(int i = 0; i < buffers.size(); ++i) stream.writeText(buffers[i]); #endif // Cleanup the shader source buffer. for ( U32 i=0; i < buffers.size(); i++ ) dFree( buffers[i] ); glCompileShader(shader); return true; }
/// Called by OpenGL device to active this state block. /// @param oldState The current state, used to make sure we don't set redundant states on the device. Pass NULL to reset all states. void GFXGLStateBlock::activate(const GFXGLStateBlock* oldState) { // Big scary warning copied from Apple docs // http://developer.apple.com/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_performance/chapter_13_section_2.html#//apple_ref/doc/uid/TP40001987-CH213-SW12 // Don't set a state that's already set. Once a feature is enabled, it does not need to be enabled again. // Calling an enable function more than once does nothing except waste time because OpenGL does not check // the state of a feature when you call glEnable or glDisable. For instance, if you call glEnable(GL_LIGHTING) // more than once, OpenGL does not check to see if the lighting state is already enabled. It simply updates // the state value even if that value is identical to the current value. #define STATE_CHANGE(state) (!oldState || oldState->mDesc.state != mDesc.state) #define TOGGLE_STATE(state, enum) if(mDesc.state) glEnable(enum); else glDisable(enum) #define CHECK_TOGGLE_STATE(state, enum) if(!oldState || oldState->mDesc.state != mDesc.state) if(mDesc.state) glEnable(enum); else glDisable(enum) // Blending CHECK_TOGGLE_STATE(blendEnable, GL_BLEND); if(STATE_CHANGE(blendSrc) || STATE_CHANGE(blendDest)) glBlendFunc(GFXGLBlend[mDesc.blendSrc], GFXGLBlend[mDesc.blendDest]); if(STATE_CHANGE(blendOp)) glBlendEquation(GFXGLBlendOp[mDesc.blendOp]); // Color write masks if(STATE_CHANGE(colorWriteRed) || STATE_CHANGE(colorWriteBlue) || STATE_CHANGE(colorWriteGreen) || STATE_CHANGE(colorWriteAlpha)) glColorMask(mDesc.colorWriteRed, mDesc.colorWriteBlue, mDesc.colorWriteGreen, mDesc.colorWriteAlpha); // Culling if(STATE_CHANGE(cullMode)) { TOGGLE_STATE(cullMode, GL_CULL_FACE); glCullFace(GFXGLCullMode[mDesc.cullMode]); } // Depth CHECK_TOGGLE_STATE(zEnable, GL_DEPTH_TEST); if(STATE_CHANGE(zFunc)) glDepthFunc(GFXGLCmpFunc[mDesc.zFunc]); if(STATE_CHANGE(zBias)) { if (mDesc.zBias == 0) { glDisable(GL_POLYGON_OFFSET_FILL); } else { F32 bias = mDesc.zBias * 10000.0f; glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(bias, bias); } } if(STATE_CHANGE(zWriteEnable)) glDepthMask(mDesc.zWriteEnable); // Stencil CHECK_TOGGLE_STATE(stencilEnable, GL_STENCIL_TEST); if(STATE_CHANGE(stencilFunc) || STATE_CHANGE(stencilRef) || STATE_CHANGE(stencilMask)) glStencilFunc(GFXGLCmpFunc[mDesc.stencilFunc], mDesc.stencilRef, mDesc.stencilMask); if(STATE_CHANGE(stencilFailOp) || STATE_CHANGE(stencilZFailOp) || STATE_CHANGE(stencilPassOp)) glStencilOp(GFXGLStencilOp[mDesc.stencilFailOp], GFXGLStencilOp[mDesc.stencilZFailOp], GFXGLStencilOp[mDesc.stencilPassOp]); if(STATE_CHANGE(stencilWriteMask)) glStencilMask(mDesc.stencilWriteMask); if(STATE_CHANGE(fillMode)) glPolygonMode(GL_FRONT_AND_BACK, GFXGLFillMode[mDesc.fillMode]); #undef CHECK_STATE #undef TOGGLE_STATE #undef CHECK_TOGGLE_STATE //sampler objects if( gglHasExtension(ARB_sampler_objects) ) { for (U32 i = 0; i < getMin(getOwningDevice()->getNumSamplers(), (U32) TEXTURE_STAGE_COUNT); i++) { if(!oldState || oldState->mSamplerObjects[i] != mSamplerObjects[i]) glBindSampler(i, mSamplerObjects[i] ); } } // TODO: states added for detail blend }
void GFXGLDevice::initGLState() { // We don't currently need to sync device state with a known good place because we are // going to set everything in GFXGLStateBlock, but if we change our GFXGLStateBlock strategy, this may // need to happen. // Deal with the card profiler here when we know we have a valid context. mCardProfiler = new GFXGLCardProfiler(); mCardProfiler->init(); glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, (GLint*)&mMaxShaderTextures); // JTH: Needs removed, ffp //glGetIntegerv(GL_MAX_TEXTURE_UNITS, (GLint*)&mMaxFFTextures); glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, (GLint*)&mMaxTRColors); mMaxTRColors = getMin( mMaxTRColors, (U32)(GFXTextureTarget::MaxRenderSlotId-1) ); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // [JTH 5/6/2016] GLSL 1.50 is really SM 4.0 // Setting mPixelShaderVersion to 3.0 will allow Advanced Lighting to run. mPixelShaderVersion = 3.0; // Set capability extensions. mCapabilities.anisotropicFiltering = mCardProfiler->queryProfile("GL_EXT_texture_filter_anisotropic"); mCapabilities.bufferStorage = mCardProfiler->queryProfile("GL_ARB_buffer_storage"); mCapabilities.shaderModel5 = mCardProfiler->queryProfile("GL_ARB_gpu_shader5"); mCapabilities.textureStorage = mCardProfiler->queryProfile("GL_ARB_texture_storage"); mCapabilities.samplerObjects = mCardProfiler->queryProfile("GL_ARB_sampler_objects"); mCapabilities.copyImage = mCardProfiler->queryProfile("GL_ARB_copy_image"); mCapabilities.vertexAttributeBinding = mCardProfiler->queryProfile("GL_ARB_vertex_attrib_binding"); String vendorStr = (const char*)glGetString( GL_VENDOR ); if( vendorStr.find("NVIDIA", 0, String::NoCase | String::Left) != String::NPos) mUseGlMap = false; // Workaround for all Mac's, has a problem using glMap* with volatile buffers #ifdef TORQUE_OS_MAC mUseGlMap = false; #endif #if TORQUE_DEBUG if( gglHasExtension(ARB_debug_output) ) { glEnable(GL_DEBUG_OUTPUT); glDebugMessageCallbackARB(glDebugCallback, NULL); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); GLuint unusedIds = 0; glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, &unusedIds, GL_TRUE); } else if(gglHasExtension(AMD_debug_output)) { glEnable(GL_DEBUG_OUTPUT); glDebugMessageCallbackAMD(glAmdDebugCallback, NULL); //glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); GLuint unusedIds = 0; glDebugMessageEnableAMD(GL_DONT_CARE, GL_DONT_CARE, 0,&unusedIds, GL_TRUE); } #endif PlatformGL::setVSync(smDisableVSync ? 0 : 1); //install vsync callback Con::NotifyDelegate clbk(this, &GFXGLDevice::vsyncCallback); Con::addVariableNotify("$pref::Video::disableVerticalSync", clbk); //OpenGL 3 need a binded VAO for render GLuint vao; glGenVertexArrays(1, &vao); glBindVertexArray(vao); }