//------------------------------------------------------------------ void GLES2HardwareOcclusionQuery::destroyQuery() { if(getGLSupport()->checkExtension("GL_EXT_occlusion_query_boolean") || gleswIsSupported(3, 0)) { OGRE_CHECK_GL_ERROR(glDeleteQueriesEXT(1, &mQueryID)); } }
//------------------------------------------------------------------ void GLES2HardwareOcclusionQuery::endOcclusionQuery() { if(getGLSupport()->checkExtension("GL_EXT_occlusion_query_boolean") || gleswIsSupported(3, 0)) { OGRE_CHECK_GL_ERROR(glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT)); } }
//------------------------------------------------------------------ void GLES2HardwareOcclusionQuery::beginOcclusionQuery() { if(getGLES2SupportRef()->checkExtension("GL_EXT_occlusion_query_boolean") || gleswIsSupported(3, 0)) { OGRE_CHECK_GL_ERROR(glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, mQueryID)); } }
Ogre::RenderToVertexBufferSharedPtr GLES2DefaultHardwareBufferManagerBase::createRenderToVertexBuffer( void ) { if(!gleswIsSupported(3, 0)) { OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Cannot create RenderToVertexBuffer in GLES2DefaultHardwareBufferManagerBase", "GLES2DefaultHardwareBufferManagerBase::createRenderToVertexBuffer"); } // return HardwareUniformBufferSharedPtr(new GLES2DefaultHardwareRenderToVertexBuffer(this, sizeBytes, usage, useShadowBuffer, name)); }
//------------------------------------------------------------------ bool GLES2HardwareOcclusionQuery::pullOcclusionQuery( unsigned int* NumOfFragments ) { if(getGLSupport()->checkExtension("GL_EXT_occlusion_query_boolean") || gleswIsSupported(3, 0)) { OGRE_CHECK_GL_ERROR(glGetQueryObjectuivEXT(mQueryID, GL_QUERY_RESULT_EXT, (GLuint*)NumOfFragments)); mPixelCount = *NumOfFragments; return true; } else return false; }
//------------------------------------------------------------------ bool GLES2HardwareOcclusionQuery::isStillOutstanding(void) { GLuint available = GL_FALSE; if(getGLSupport()->checkExtension("GL_EXT_occlusion_query_boolean") || gleswIsSupported(3, 0)) { OGRE_CHECK_GL_ERROR(glGetQueryObjectuivEXT(mQueryID, GL_QUERY_RESULT_AVAILABLE_EXT, &available)); } // GL_TRUE means a wait would occur return !(available == GL_TRUE); }
HardwareUniformBufferSharedPtr GLES2DefaultHardwareBufferManagerBase::createUniformBuffer(size_t sizeBytes, HardwareBuffer::Usage usage, bool useShadowBuffer, const String& name) { if(!gleswIsSupported(3, 0)) { OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "GLES2 does not support uniform buffer objects", "GLES2DefaultHardwareBufferManager::createUniformBuffer"); } return HardwareUniformBufferSharedPtr(new GLES2DefaultHardwareUniformBuffer(this, sizeBytes, usage, useShadowBuffer, name)); }
//----------------------------------------------------------------------------- GLES2FrameBufferObject::GLES2FrameBufferObject(GLES2FBOManager *manager, uint fsaa): mManager(manager), mNumSamples(fsaa) { // Generate framebuffer object OGRE_CHECK_GL_ERROR(glGenFramebuffers(1, &mFB)); if(getGLES2SupportRef()->checkExtension("GL_EXT_debug_label")) { OGRE_IF_IOS_VERSION_IS_GREATER_THAN(5.0) OGRE_CHECK_GL_ERROR(glLabelObjectEXT(GL_BUFFER_OBJECT_EXT, mFB, 0, ("FBO #" + StringConverter::toString(mFB)).c_str())); } mNumSamples = 0; mMultisampleFB = 0; // Check multisampling if supported if(gleswIsSupported(3, 0)) { // Check samples supported OGRE_CHECK_GL_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, mFB)); GLint maxSamples; OGRE_CHECK_GL_ERROR(glGetIntegerv(GL_MAX_SAMPLES_APPLE, &maxSamples)); OGRE_CHECK_GL_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, 0)); mNumSamples = std::min(mNumSamples, (GLsizei)maxSamples); } // Will we need a second FBO to do multisampling? if (mNumSamples) { OGRE_CHECK_GL_ERROR(glGenFramebuffers(1, &mMultisampleFB)); if(getGLES2SupportRef()->checkExtension("GL_EXT_debug_label")) { OGRE_IF_IOS_VERSION_IS_GREATER_THAN(5.0) OGRE_CHECK_GL_ERROR(glLabelObjectEXT(GL_BUFFER_OBJECT_EXT, mMultisampleFB, 0, ("MSAA FBO #" + StringConverter::toString(mMultisampleFB)).c_str())); } } else { mMultisampleFB = 0; } // Initialise state mDepth.buffer = 0; mStencil.buffer = 0; for(size_t x = 0; x < OGRE_MAX_MULTIPLE_RENDER_TARGETS; ++x) { mColour[x].buffer=0; } }
//------------------------------------------------------------------ void GLES2HardwareOcclusionQuery::createQuery() { // Check for hardware occlusion support if(getGLSupport()->checkExtension("GL_EXT_occlusion_query_boolean") || gleswIsSupported(3, 0)) { OGRE_CHECK_GL_ERROR(glGenQueriesEXT(1, &mQueryID)); } else { OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Cannot allocate a Hardware query. This video card doesn't support it, sorry.", "GLES2HardwareOcclusionQuery::GLES2HardwareOcclusionQuery" ); } }
HardwareIndexBufferSharedPtr GLES2HardwareBufferManagerBase::createIndexBuffer(HardwareIndexBuffer::IndexType itype, size_t numIndexes, HardwareBuffer::Usage usage, bool useShadowBuffer) { GLES2HardwareIndexBuffer* buf = 0; if(getGLES2SupportRef()->checkExtension("GL_EXT_map_buffer_range") || gleswIsSupported(3, 0)) buf = OGRE_NEW GLES2HardwareIndexBuffer(this, itype, numIndexes, usage, useShadowBuffer); else // always use shadowBuffer buf = OGRE_NEW GLES2HardwareIndexBuffer(this, itype, numIndexes, usage, true); { OGRE_LOCK_MUTEX(mIndexBuffersMutex); mIndexBuffers.insert(buf); } return HardwareIndexBufferSharedPtr(buf); }
//----------------------------------------------------------------------- void GLSLESProgramCommon::getMicrocodeFromCache(void) { GpuProgramManager::Microcode cacheMicrocode = GpuProgramManager::getSingleton().getMicrocodeFromCache(getCombinedName()); // add to the microcode to the cache String name; name = getCombinedName(); // turns out we need this param when loading GLenum binaryFormat = 0; cacheMicrocode->seek(0); // get size of binary cacheMicrocode->read(&binaryFormat, sizeof(GLenum)); if(getGLES2SupportRef()->checkExtension("GL_OES_get_program_binary") || gleswIsSupported(3, 0)) { GLint binaryLength = static_cast<GLint>(cacheMicrocode->size() - sizeof(GLenum)); // load binary OGRE_CHECK_GL_ERROR(glProgramBinaryOES(mGLProgramHandle, binaryFormat, cacheMicrocode->getPtr(), binaryLength)); } GLint success = 0; OGRE_CHECK_GL_ERROR(glGetProgramiv(mGLProgramHandle, GL_LINK_STATUS, &success)); if (!success) { // // Something must have changed since the program binaries // were cached away. Fallback to source shader loading path, // and then retrieve and cache new program binaries once again. // compileAndLink(); } }
void GLES2HardwareIndexBuffer::readData(size_t offset, size_t length, void* pDest) { if(mUseShadowBuffer) { // Get data from the shadow buffer void* srcData = mShadowBuffer->lock(offset, length, HBL_READ_ONLY); memcpy(pDest, srcData, length); mShadowBuffer->unlock(); } else { if(getGLES2SupportRef()->checkExtension("GL_EXT_map_buffer_range") || gleswIsSupported(3, 0)) { // Map the buffer range then copy out of it into our destination buffer void* srcData; OGRE_CHECK_GL_ERROR(srcData = glMapBufferRangeEXT(GL_ELEMENT_ARRAY_BUFFER, offset, length, GL_MAP_READ_BIT_EXT)); memcpy(pDest, srcData, length); // Unmap the buffer since we are done. GLboolean mapped; OGRE_CHECK_GL_ERROR(mapped = glUnmapBufferOES(GL_ELEMENT_ARRAY_BUFFER)); if(!mapped) { OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Buffer data corrupted, please reload", "GLES2HardwareIndexBuffer::readData"); } } else { OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Reading hardware buffer is not supported", "GLES2HardwareIndexBuffer::readData"); } } }
void GLES2Texture::_createGLTexResource() { if(!Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_NON_POWER_OF_2_TEXTURES) || (Root::getSingleton().getRenderSystem()->getCapabilities()->getNonPOW2TexturesLimited() && mNumRequestedMipmaps > 0)) { // Convert to nearest power-of-two size if required mWidth = GLES2PixelUtil::optionalPO2(mWidth); mHeight = GLES2PixelUtil::optionalPO2(mHeight); mDepth = GLES2PixelUtil::optionalPO2(mDepth); } // Adjust format if required mFormat = TextureManager::getSingleton().getNativeFormat(mTextureType, mFormat, mUsage); GLenum texTarget = getGLES2TextureTarget(); // Check requested number of mipmaps size_t maxMips = GLES2PixelUtil::getMaxMipmaps(mWidth, mHeight, mDepth, mFormat); if(PixelUtil::isCompressed(mFormat) && (mNumMipmaps == 0)) mNumRequestedMipmaps = 0; mNumMipmaps = mNumRequestedMipmaps; if (mNumMipmaps > maxMips) mNumMipmaps = maxMips; // Generate texture name OGRE_CHECK_GL_ERROR(glGenTextures(1, &mTextureID)); // Set texture type mGLSupport.getStateCacheManager()->bindGLTexture(texTarget, mTextureID); // If we can do automip generation and the user desires this, do so mMipmapsHardwareGenerated = Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_AUTOMIPMAP) && !PixelUtil::isCompressed(mFormat); if(!Bitwise::isPO2(mWidth) || !Bitwise::isPO2(mHeight)) mMipmapsHardwareGenerated = false; // glGenerateMipmap require all mip levels to be prepared. So override how many this texture has. if((mUsage & TU_AUTOMIPMAP) && mMipmapsHardwareGenerated && mNumRequestedMipmaps) mNumMipmaps = maxMips; if(getGLES2SupportRef()->checkExtension("GL_APPLE_texture_max_level") || gleswIsSupported(3, 0)) mGLSupport.getStateCacheManager()->setTexParameteri(texTarget, GL_TEXTURE_MAX_LEVEL_APPLE, mNumRequestedMipmaps ? mNumMipmaps + 1 : 0); // Set some misc default parameters, these can of course be changed later mGLSupport.getStateCacheManager()->setTexParameteri(texTarget, GL_TEXTURE_MIN_FILTER, ((mUsage & TU_AUTOMIPMAP) && mNumRequestedMipmaps) ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST); mGLSupport.getStateCacheManager()->setTexParameteri(texTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); mGLSupport.getStateCacheManager()->setTexParameteri(texTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); mGLSupport.getStateCacheManager()->setTexParameteri(texTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // Set up texture swizzling #if OGRE_NO_GLES3_SUPPORT == 0 if(gleswIsSupported(3, 0)) { OGRE_CHECK_GL_ERROR(glTexParameteri(texTarget, GL_TEXTURE_SWIZZLE_R, GL_RED)); OGRE_CHECK_GL_ERROR(glTexParameteri(texTarget, GL_TEXTURE_SWIZZLE_G, GL_GREEN)); OGRE_CHECK_GL_ERROR(glTexParameteri(texTarget, GL_TEXTURE_SWIZZLE_B, GL_BLUE)); OGRE_CHECK_GL_ERROR(glTexParameteri(texTarget, GL_TEXTURE_SWIZZLE_A, GL_ALPHA)); if(mFormat == PF_L8 || mFormat == PF_L16) { OGRE_CHECK_GL_ERROR(glTexParameteri(texTarget, GL_TEXTURE_SWIZZLE_R, GL_RED)); OGRE_CHECK_GL_ERROR(glTexParameteri(texTarget, GL_TEXTURE_SWIZZLE_G, GL_RED)); OGRE_CHECK_GL_ERROR(glTexParameteri(texTarget, GL_TEXTURE_SWIZZLE_B, GL_RED)); OGRE_CHECK_GL_ERROR(glTexParameteri(texTarget, GL_TEXTURE_SWIZZLE_A, GL_RED)); } } #endif // Allocate internal buffer so that glTexSubImageXD can be used // Internal format GLenum format = GLES2PixelUtil::getGLOriginFormat(mFormat); GLenum internalformat = GLES2PixelUtil::getClosestGLInternalFormat(mFormat, mHwGamma); uint32 width = mWidth; uint32 height = mHeight; uint32 depth = mDepth; if (PixelUtil::isCompressed(mFormat)) { // Compressed formats GLsizei size = static_cast<GLsizei>(PixelUtil::getMemorySize(mWidth, mHeight, mDepth, mFormat)); // Provide temporary buffer filled with zeroes as glCompressedTexImageXD does not // accept a 0 pointer like normal glTexImageXD // Run through this process for every mipmap to pregenerate mipmap pyramid uint8* tmpdata = new uint8[size]; memset(tmpdata, 0, size); for (GLint mip = 0; mip <= mNumMipmaps; mip++) { #if OGRE_DEBUG_MODE LogManager::getSingleton().logMessage("GLES2Texture::create - Mip: " + StringConverter::toString(mip) + " Width: " + StringConverter::toString(width) + " Height: " + StringConverter::toString(height) + " Internal Format: " + StringConverter::toString(internalformat, 0, ' ', std::ios::hex) + " Format: " + StringConverter::toString(format, 0, ' ', std::ios::hex) ); #endif size = static_cast<GLsizei>(PixelUtil::getMemorySize(width, height, depth, mFormat)); switch(mTextureType) { case TEX_TYPE_1D: case TEX_TYPE_2D: OGRE_CHECK_GL_ERROR(glCompressedTexImage2D(GL_TEXTURE_2D, mip, internalformat, width, height, 0, size, tmpdata)); break; case TEX_TYPE_CUBE_MAP: for(int face = 0; face < 6; face++) { OGRE_CHECK_GL_ERROR(glCompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, mip, internalformat, width, height, 0, size, tmpdata)); } break; #if OGRE_NO_GLES3_SUPPORT == 0 case TEX_TYPE_2D_ARRAY: case TEX_TYPE_3D: glCompressedTexImage3D(getGLES2TextureTarget(), mip, format, width, height, depth, 0, size, tmpdata); break; #endif default: break; }; if(width > 1) { width = width / 2; } if(height > 1) { height = height / 2; } if(depth > 1 && mTextureType != TEX_TYPE_2D_ARRAY) { depth = depth / 2; } } delete [] tmpdata; } else { #if OGRE_NO_GLES3_SUPPORT == 0 #if OGRE_DEBUG_MODE LogManager::getSingleton().logMessage("GLES2Texture::create - Name: " + mName + " ID: " + StringConverter::toString(mTextureID) + " Width: " + StringConverter::toString(width) + " Height: " + StringConverter::toString(height) + " Internal Format: " + StringConverter::toString(internalformat, 0, ' ', std::ios::hex)); #endif switch(mTextureType) { case TEX_TYPE_1D: case TEX_TYPE_2D: case TEX_TYPE_2D_RECT: OGRE_CHECK_GL_ERROR(glTexStorage2D(GL_TEXTURE_2D, GLsizei(mNumMipmaps+1), internalformat, GLsizei(width), GLsizei(height))); break; case TEX_TYPE_CUBE_MAP: OGRE_CHECK_GL_ERROR(glTexStorage2D(GL_TEXTURE_CUBE_MAP, GLsizei(mNumMipmaps+1), internalformat, GLsizei(width), GLsizei(height))); break; case TEX_TYPE_2D_ARRAY: OGRE_CHECK_GL_ERROR(glTexStorage3D(GL_TEXTURE_2D_ARRAY, GLsizei(mNumMipmaps+1), internalformat, GLsizei(width), GLsizei(height), GLsizei(depth))); break; case TEX_TYPE_3D: OGRE_CHECK_GL_ERROR(glTexStorage3D(GL_TEXTURE_3D, GLsizei(mNumMipmaps+1), internalformat, GLsizei(width), GLsizei(height), GLsizei(depth))); break; } #else GLenum datatype = GLES2PixelUtil::getGLOriginDataType(mFormat); // Run through this process to pregenerate mipmap pyramid for(GLint mip = 0; mip <= mNumMipmaps; mip++) { #if OGRE_DEBUG_MODE LogManager::getSingleton().logMessage("GLES2Texture::create - Mip: " + StringConverter::toString(mip) + " Name: " + mName + " ID: " + StringConverter::toString(mTextureID) + " Width: " + StringConverter::toString(width) + " Height: " + StringConverter::toString(height) + " Internal Format: " + StringConverter::toString(internalformat, 0, ' ', std::ios::hex) + " Format: " + StringConverter::toString(format, 0, ' ', std::ios::hex) + " Datatype: " + StringConverter::toString(datatype, 0, ' ', std::ios::hex) ); #endif // Normal formats switch(mTextureType) { case TEX_TYPE_1D: case TEX_TYPE_2D: #if OGRE_PLATFORM == OGRE_PLATFORM_NACL if(internalformat != format) { LogManager::getSingleton().logMessage("glTexImage2D: format != internalFormat, " "format=" + StringConverter::toString(format) + ", internalFormat=" + StringConverter::toString(internalformat)); } #endif OGRE_CHECK_GL_ERROR(glTexImage2D(GL_TEXTURE_2D, mip, internalformat, width, height, 0, format, datatype, 0)); break; case TEX_TYPE_CUBE_MAP: for(int face = 0; face < 6; face++) { OGRE_CHECK_GL_ERROR(glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, mip, internalformat, width, height, 0, format, datatype, 0)); } break; default: break; }; if (width > 1) { width = Bitwise::firstPO2From(width / 2); } if (height > 1) { height = Bitwise::firstPO2From(height / 2); } } #endif } }
//----------------------------------------------------------------------------- GLES2FrameBufferObject::GLES2FrameBufferObject(GLES2FBOManager *manager, uint fsaa): mManager(manager), mNumSamples(fsaa) { /// Generate framebuffer object OGRE_CHECK_GL_ERROR(glGenFramebuffers(1, &mFB)); mNumSamples = 0; mMultisampleFB = 0; // Check multisampling if supported if(getGLES2SupportRef()->checkExtension("GL_APPLE_framebuffer_multisample") || gleswIsSupported(3, 0)) { // Check samples supported OGRE_CHECK_GL_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, mFB)); GLint maxSamples; OGRE_CHECK_GL_ERROR(glGetIntegerv(GL_MAX_SAMPLES_APPLE, &maxSamples)); OGRE_CHECK_GL_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, 0)); mNumSamples = std::min(mNumSamples, (GLsizei)maxSamples); } // Will we need a second FBO to do multisampling? if (mNumSamples) { OGRE_CHECK_GL_ERROR(glGenFramebuffers(1, &mMultisampleFB)); } /// Initialise state mDepth.buffer=0; mStencil.buffer=0; for(size_t x=0; x<OGRE_MAX_MULTIPLE_RENDER_TARGETS; ++x) { mColour[x].buffer=0; } }