//----------------------------------------------------------------------------- void GLES2TextureBuffer::bindToFramebuffer(GLenum attachment, size_t zoffset) { assert(zoffset < mDepth); OGRE_CHECK_GL_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, mFaceTarget, mTextureID, mLevel)); }
//--------------------------------------------------------------------- void GLSLProgramManagerCommon::extractUniforms(GLuint programObject, const GpuConstantDefinitionMap* vertexConstantDefs, const GpuConstantDefinitionMap* geometryConstantDefs, const GpuConstantDefinitionMap* fragmentConstantDefs, const GpuConstantDefinitionMap* hullConstantDefs, const GpuConstantDefinitionMap* domainConstantDefs, const GpuConstantDefinitionMap* computeConstantDefs, GLUniformReferenceList& list, GLUniformBufferList& sharedList) { // Scan through the active uniforms and add them to the reference list GLint uniformCount = 0; #define uniformLength 200 // GLint uniformLength = 0; // glGetProgramiv(programObject, GL_ACTIVE_UNIFORM_MAX_LENGTH, &uniformLength); char uniformName[uniformLength]; GLUniformReference newGLUniformReference; // Get the number of active uniforms OGRE_CHECK_GL_ERROR(glGetProgramiv(programObject, GL_ACTIVE_UNIFORMS, &uniformCount)); // Loop over each of the active uniforms, and add them to the reference container // only do this for user defined uniforms, ignore built in gl state uniforms for (int index = 0; index < uniformCount; index++) { GLint arraySize; GLenum glType; OGRE_CHECK_GL_ERROR(glGetActiveUniform(programObject, index, uniformLength, NULL, &arraySize, &glType, uniformName)); // Don't add built in uniforms OGRE_CHECK_GL_ERROR(newGLUniformReference.mLocation = glGetUniformLocation(programObject, uniformName)); if (newGLUniformReference.mLocation >= 0) { // User defined uniform found, add it to the reference list String paramName = String( uniformName ); // Current ATI drivers (Catalyst 7.2 and earlier) and older NVidia drivers will include all array elements as uniforms but we only want the root array name and location // Also note that ATI Catalyst 6.8 to 7.2 there is a bug with glUniform that does not allow you to update a uniform array past the first uniform array element // ie you can't start updating an array starting at element 1, must always be element 0. // If the uniform name has a "[" in it then its an array element uniform. String::size_type arrayStart = paramName.find("["); if (arrayStart != String::npos) { // if not the first array element then skip it and continue to the next uniform if (paramName.compare(arrayStart, paramName.size() - 1, "[0]") != 0) continue; paramName = paramName.substr(0, arrayStart); } // Find out which params object this comes from bool foundSource = completeParamSource(paramName, vertexConstantDefs, geometryConstantDefs, fragmentConstantDefs, hullConstantDefs, domainConstantDefs, computeConstantDefs, newGLUniformReference); // Only add this parameter if we found the source if (foundSource) { assert(size_t (arraySize) == newGLUniformReference.mConstantDef->arraySize && "GL doesn't agree with our array size!"); list.push_back(newGLUniformReference); } // Don't bother adding individual array params, they will be // picked up in the 'parent' parameter can copied all at once // anyway, individual indexes are only needed for lookup from // user params } // end if } // end for // Now deal with uniform blocks GLint blockCount = 0; OGRE_CHECK_GL_ERROR(glGetProgramiv(programObject, GL_ACTIVE_UNIFORM_BLOCKS, &blockCount)); for (int index = 0; index < blockCount; index++) { OGRE_CHECK_GL_ERROR(glGetActiveUniformBlockName(programObject, index, uniformLength, NULL, uniformName)); GpuSharedParametersPtr blockSharedParams = GpuProgramManager::getSingleton().getSharedParameters(uniformName); GLint blockSize, blockBinding; OGRE_CHECK_GL_ERROR(glGetActiveUniformBlockiv(programObject, index, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize)); OGRE_CHECK_GL_ERROR(glGetActiveUniformBlockiv(programObject, index, GL_UNIFORM_BLOCK_BINDING, &blockBinding)); HardwareUniformBufferSharedPtr newUniformBuffer = HardwareBufferManager::getSingleton().createUniformBuffer(blockSize, HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE, false, uniformName); GL3PlusHardwareUniformBuffer* hwGlBuffer = static_cast<GL3PlusHardwareUniformBuffer*>(newUniformBuffer.get()); hwGlBuffer->setGLBufferBinding(blockBinding); sharedList.push_back(newUniformBuffer); } }
// Creation / loading methods void GL3PlusTexture::createInternalResourcesImpl(void) { // Adjust format if required mFormat = TextureManager::getSingleton().getNativeFormat(mTextureType, mFormat, mUsage); // Check requested number of mipmaps size_t maxMips = GL3PlusPixelUtil::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)); GLenum texTarget = getGL3PlusTextureTarget(); // Set texture type OGRE_CHECK_GL_ERROR(glBindTexture(texTarget, mTextureID)); OGRE_CHECK_GL_ERROR(glTexParameteri(texTarget, GL_TEXTURE_BASE_LEVEL, 0)); OGRE_CHECK_GL_ERROR(glTexParameteri(texTarget, GL_TEXTURE_MAX_LEVEL, (mMipmapsHardwareGenerated && (mUsage & TU_AUTOMIPMAP)) ? maxMips : mNumMipmaps )); // Set some misc default parameters, these can of course be changed later OGRE_CHECK_GL_ERROR(glTexParameteri(texTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); OGRE_CHECK_GL_ERROR(glTexParameteri(texTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); OGRE_CHECK_GL_ERROR(glTexParameteri(texTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); OGRE_CHECK_GL_ERROR(glTexParameteri(texTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); // Set up texture swizzling if(mGLSupport.checkExtension("GL_ARB_texture_swizzle") || gl3wIsSupported(3, 3)) { 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_BYTE_LA) { 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_GREEN)); } else 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)); } } // If we can do automip generation and the user desires this, do so mMipmapsHardwareGenerated = Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_AUTOMIPMAP); // Allocate internal buffer so that glTexSubImageXD can be used // Internal format GLenum format = GL3PlusPixelUtil::getClosestGLInternalFormat(mFormat, mHwGamma); GLenum datatype = GL3PlusPixelUtil::getGLOriginDataType(mFormat); size_t width = mWidth; size_t height = mHeight; size_t depth = mDepth; if (PixelUtil::isCompressed(mFormat)) { // Compressed formats size_t size = 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 (size_t mip = 0; mip <= mNumMipmaps; mip++) { size = PixelUtil::getMemorySize(width, height, depth, mFormat); switch(mTextureType) { case TEX_TYPE_1D: OGRE_CHECK_GL_ERROR(glCompressedTexImage1D(GL_TEXTURE_1D, mip, format, width, 0, size, tmpdata)); break; case TEX_TYPE_2D: OGRE_CHECK_GL_ERROR(glCompressedTexImage2D(GL_TEXTURE_2D, mip, format, width, height, 0, size, tmpdata)); break; case TEX_TYPE_2D_RECT: OGRE_CHECK_GL_ERROR(glCompressedTexImage2D(GL_TEXTURE_RECTANGLE, mip, format, width, height, 0, size, tmpdata)); break; case TEX_TYPE_2D_ARRAY: case TEX_TYPE_3D: OGRE_CHECK_GL_ERROR(glCompressedTexImage3D(texTarget, mip, format, width, height, depth, 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, format, width, height, 0, size, tmpdata)); } break; default: break; }; // LogManager::getSingleton().logMessage("GL3PlusTexture::create - " + StringConverter::toString(mTextureID) + // " Mip: " + StringConverter::toString(mip) + // " Width: " + StringConverter::toString(width) + // " Height: " + StringConverter::toString(height) + // " Internal Format: " + StringConverter::toString(format) // ); if(width > 1) { width = width / 2; } if(height > 1) { height = height / 2; } if(depth > 1) { depth = depth / 2; } } delete [] tmpdata; } else { if((mGLSupport.checkExtension("GL_ARB_texture_storage") || gl3wIsSupported(4, 2)) && mTextureType == TEX_TYPE_2D) { OGRE_CHECK_GL_ERROR(glTexStorage2D(GL_TEXTURE_2D, GLint(mNumMipmaps+1), format, GLsizei(width), GLsizei(height))); } else { // Run through this process to pregenerate mipmap pyramid for(size_t mip = 0; mip <= mNumMipmaps; mip++) { // Normal formats switch(mTextureType) { case TEX_TYPE_1D: OGRE_CHECK_GL_ERROR(glTexImage1D(GL_TEXTURE_1D, mip, format, width, 0, GL_RGBA, datatype, 0)); break; case TEX_TYPE_2D: OGRE_CHECK_GL_ERROR(glTexImage2D(GL_TEXTURE_2D, mip, format, width, height, 0, GL3PlusPixelUtil::getGLOriginFormat(mFormat), datatype, 0)); break; case TEX_TYPE_2D_RECT: OGRE_CHECK_GL_ERROR(glTexImage2D(GL_TEXTURE_RECTANGLE, mip, format, width, height, 0, GL3PlusPixelUtil::getGLOriginFormat(mFormat), datatype, 0)); break; case TEX_TYPE_3D: case TEX_TYPE_2D_ARRAY: OGRE_CHECK_GL_ERROR(glTexImage3D(texTarget, mip, format, width, height, depth, 0, GL_RGBA, 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, format, width, height, 0, GL3PlusPixelUtil::getGLOriginFormat(mFormat), datatype, 0)); } break; default: break; }; if (width > 1) { width = width / 2; } if (height > 1) { height = height / 2; } if (depth > 1) { depth = depth / 2; } } } } _createSurfaceList(); // Get final internal format mFormat = getBuffer(0,0)->getFormat(); }
void GL3PlusRenderToVertexBuffer::bindVerticesOutput(Pass* pass) { VertexDeclaration* declaration = mVertexData->vertexDeclaration; size_t elemCount = declaration->getElementCount(); if (elemCount == 0) return; // Get program object ID. GLuint programId = 0; if (Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_SEPARATE_SHADER_OBJECTS)) { GLSLSeparableProgram* separableProgram = GLSLSeparableProgramManager::getSingleton().getCurrentSeparableProgram(); GLSLShader* glslGpuProgram = 0; if ((glslGpuProgram = separableProgram->getGeometryShader())) programId = glslGpuProgram->getGLProgramHandle(); //TODO include tessellation stages else // vertex program programId = separableProgram->getVertexShader()->getGLProgramHandle(); } else { GLSLMonolithicProgram* monolithicProgram = GLSLMonolithicProgramManager::getSingleton().getActiveMonolithicProgram(); programId = monolithicProgram->getGLProgramHandle(); } // Store the output in a buffer. The buffer has the same // structure as the shader output vertex data. // Note: 64 is the minimum number of interleaved // attributes allowed by GL_EXT_transform_feedback so we // are using it. Otherwise we could query during // rendersystem initialisation and use a dynamic sized // array. But that would require C99. size_t sourceBufferIndex = mTargetBufferIndex == 0 ? 1 : 0; // Bind and fill vertex arrays + buffers. reallocateBuffer(sourceBufferIndex); reallocateBuffer(mTargetBufferIndex); // GL3PlusHardwareVertexBuffer* sourceVertexBuffer = static_cast<GL3PlusHardwareVertexBuffer*>(mVertexBuffers[mSourceBufferIndex].getPointer()); // GL3PlusHardwareVertexBuffer* targetVertexBuffer = static_cast<GL3PlusHardwareVertexBuffer*>(mVertexBuffers[mTargetBufferIndex].getPointer()); //TODO GL4+ glBindTransformFeedback // Dynamically determine shader output variable names. std::vector<String> nameStrings; std::vector<const GLchar*> names; for (uint e = 0; e < elemCount; e++) { const VertexElement* element = declaration->getElement(e); String name = getSemanticVaryingName(element->getSemantic(), element->getIndex()); nameStrings.push_back(name); } // Convert to const char * for GL for (uint e = 0; e < elemCount; e++) { names.push_back(nameStrings[e].c_str()); } //TODO replace glTransformFeedbackVaryings with in-shader specification (GL 4.4) OGRE_CHECK_GL_ERROR(glTransformFeedbackVaryings(programId, elemCount, &names[0], GL_INTERLEAVED_ATTRIBS)); if (Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_SEPARATE_SHADER_OBJECTS)) { GLSLSeparableProgram* separableProgram = GLSLSeparableProgramManager::getSingleton().getCurrentSeparableProgram(); separableProgram->activate(); } else { OGRE_CHECK_GL_ERROR(glLinkProgram(programId)); } #if OGRE_DEBUG_MODE // Check if program linking was successful. GLint didLink = 0; OGRE_CHECK_GL_ERROR(glGetProgramiv(programId, GL_LINK_STATUS, &didLink)); logObjectInfo(String("RVB GLSL link result : "), programId); if (glIsProgram(programId)) { glValidateProgram(programId); } logObjectInfo(String("RVB GLSL validation result : "), programId); // Check if varyings were successfully set. GLchar Name[64]; GLsizei Length(0); GLsizei Size(0); GLenum Type(0); // bool Validated = false; for (size_t i = 0; i < elemCount; i++) { OGRE_CHECK_GL_ERROR(glGetTransformFeedbackVarying( programId, i, 64, &Length, &Size, &Type, Name )); std::cout << "Varying " << i << ": " << Name <<" "<< Length <<" "<< Size <<" "<< Type << std::endl; // Validated = (Size == 1) && (Type == GL_FLOAT_VEC3); // std::cout << Validated << " " << GL_FLOAT_VEC3 << std::endl; } #endif }
GL3PlusRenderToVertexBuffer::~GL3PlusRenderToVertexBuffer() { OGRE_CHECK_GL_ERROR(glDeleteQueries(1, &mPrimitivesDrawnQuery)); }
void GLSLESProgramPipeline::compileAndLink() { #if GL_EXT_separate_shader_objects && OGRE_PLATFORM != OGRE_PLATFORM_NACL GLint linkStatus = 0; OGRE_CHECK_GL_ERROR(glGenProgramPipelinesEXT(1, &mGLProgramPipelineHandle)); OGRE_CHECK_GL_ERROR(glBindProgramPipelineEXT(mGLProgramPipelineHandle)); // Compile and attach Vertex Program if(mVertexProgram && !mVertexProgram->isLinked()) { try { mVertexProgram->getGLSLProgram()->compile(true); } catch (Exception& e) { LogManager::getSingleton().stream() << e.getDescription(); mTriedToLinkAndFailed = true; return; } GLuint programHandle = mVertexProgram->getGLSLProgram()->getGLProgramHandle(); OGRE_CHECK_GL_ERROR(glProgramParameteriEXT(programHandle, GL_PROGRAM_SEPARABLE_EXT, GL_TRUE)); mVertexProgram->getGLSLProgram()->attachToProgramObject(programHandle); OGRE_CHECK_GL_ERROR(glLinkProgram(programHandle)); OGRE_CHECK_GL_ERROR(glGetProgramiv(programHandle, GL_LINK_STATUS, &linkStatus)); if(linkStatus) { mVertexProgram->setLinked(linkStatus); mLinked |= VERTEX_PROGRAM_LINKED; } mTriedToLinkAndFailed = !linkStatus; logObjectInfo( getCombinedName() + String("GLSL vertex program result : "), programHandle ); setSkeletalAnimationIncluded(mVertexProgram->isSkeletalAnimationIncluded()); } // Compile and attach Fragment Program if(mFragmentProgram && !mFragmentProgram->isLinked()) { try { mFragmentProgram->getGLSLProgram()->compile(true); } catch (Exception& e) { LogManager::getSingleton().stream() << e.getDescription(); mTriedToLinkAndFailed = true; return; } GLuint programHandle = mFragmentProgram->getGLSLProgram()->getGLProgramHandle(); OGRE_CHECK_GL_ERROR(glProgramParameteriEXT(programHandle, GL_PROGRAM_SEPARABLE_EXT, GL_TRUE)); mFragmentProgram->getGLSLProgram()->attachToProgramObject(programHandle); OGRE_CHECK_GL_ERROR(glLinkProgram(programHandle)); OGRE_CHECK_GL_ERROR(glGetProgramiv(programHandle, GL_LINK_STATUS, &linkStatus)); if(linkStatus) { mFragmentProgram->setLinked(linkStatus); mLinked |= FRAGMENT_PROGRAM_LINKED; } mTriedToLinkAndFailed = !linkStatus; logObjectInfo( getCombinedName() + String("GLSL fragment program result : "), programHandle ); } if(mLinked) { if(mVertexProgram && mVertexProgram->isLinked()) { OGRE_CHECK_GL_ERROR(glUseProgramStagesEXT(mGLProgramPipelineHandle, GL_VERTEX_SHADER_BIT_EXT, mVertexProgram->getGLSLProgram()->getGLProgramHandle())); } if(mFragmentProgram && mFragmentProgram->isLinked()) { OGRE_CHECK_GL_ERROR(glUseProgramStagesEXT(mGLProgramPipelineHandle, GL_FRAGMENT_SHADER_BIT_EXT, mFragmentProgram->getGLSLProgram()->getGLProgramHandle())); } // Validate pipeline logObjectInfo( getCombinedName() + String("GLSL program pipeline result : "), mGLProgramPipelineHandle ); #if GL_EXT_debug_label && OGRE_PLATFORM != OGRE_PLATFORM_NACL if(mVertexProgram && mFragmentProgram) OGRE_IF_IOS_VERSION_IS_GREATER_THAN(5.0) glLabelObjectEXT(GL_PROGRAM_PIPELINE_OBJECT_EXT, mGLProgramPipelineHandle, 0, (mVertexProgram->getName() + "/" + mFragmentProgram->getName()).c_str()); #endif } #endif }
void* GL3PlusHardwareIndexBuffer::lockImpl(size_t offset, size_t length, LockOptions options) { if(mIsLocked) { OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Invalid attempt to lock an index buffer that has already been locked", "GL3PlusHardwareIndexBuffer::lock"); } void* retPtr = 0; GLenum access = 0; // GL3PlusHardwareBufferManager* glBufManager = static_cast<GL3PlusHardwareBufferManager*>(HardwareBufferManager::getSingletonPtr()); // // // Try to use scratch buffers for smaller buffers // if(length < glBufManager->getGLMapBufferThreshold()) // { // retPtr = glBufManager->allocateScratch((uint32)length); // if (retPtr) // { // mLockedToScratch = true; // mScratchOffset = offset; // mScratchSize = length; // mScratchPtr = retPtr; // mScratchUploadOnUnlock = (options != HBL_READ_ONLY); // // if (options != HBL_DISCARD) // { // // have to read back the data before returning the pointer // readData(offset, length, retPtr); // } // } // } if (!retPtr) { OGRE_CHECK_GL_ERROR(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mBufferId)); // Use glMapBuffer if (mUsage & HBU_WRITE_ONLY) { access |= GL_MAP_WRITE_BIT; access |= GL_MAP_FLUSH_EXPLICIT_BIT; if(options == HBL_DISCARD || options == HBL_NO_OVERWRITE) { // Discard the buffer access |= GL_MAP_INVALIDATE_RANGE_BIT; } // We explicitly flush when the buffer is unlocked access |= GL_MAP_UNSYNCHRONIZED_BIT; } else if (options == HBL_READ_ONLY) access |= GL_MAP_READ_BIT; else access |= GL_MAP_READ_BIT | GL_MAP_WRITE_BIT; void* pBuffer; OGRE_CHECK_GL_ERROR(pBuffer = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, offset, length, access)); if(pBuffer == 0) { OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Index Buffer: Out of memory", "GL3PlusHardwareIndexBuffer::lock"); } // return offsetted retPtr = static_cast<void*>(static_cast<unsigned char*>(pBuffer) + offset); mLockedToScratch = false; } mIsLocked = true; return retPtr; }
void GLSLProgramPipeline::compileAndLink() { OGRE_CHECK_GL_ERROR(glGenProgramPipelines(1, &mGLProgramPipelineHandle)); OGRE_CHECK_GL_ERROR(glBindProgramPipeline(mGLProgramPipelineHandle)); mVertexArrayObject = new GL3PlusVertexArrayObject(); mVertexArrayObject->bind(); compileIndividualProgram(mVertexProgram); compileIndividualProgram(mFragmentProgram); compileIndividualProgram(mGeometryProgram); compileIndividualProgram(mDomainProgram); compileIndividualProgram(mHullProgram); compileIndividualProgram(mComputeProgram); if(mLinked) { if ( GpuProgramManager::getSingleton().getSaveMicrocodesToCache() ) { // Add to the microcode to the cache String name; name = getCombinedName(); // Get buffer size GLint binaryLength = 0; OGRE_CHECK_GL_ERROR(glGetProgramiv(mGLProgramPipelineHandle, GL_PROGRAM_BINARY_LENGTH, &binaryLength)); // Create microcode GpuProgramManager::Microcode newMicrocode = GpuProgramManager::getSingleton().createMicrocode(binaryLength + sizeof(GLenum)); // Get binary OGRE_CHECK_GL_ERROR(glGetProgramBinary(mGLProgramPipelineHandle, binaryLength, NULL, (GLenum *)newMicrocode->getPtr(), newMicrocode->getPtr() + sizeof(GLenum))); // Add to the microcode to the cache GpuProgramManager::getSingleton().addMicrocodeToCache(name, newMicrocode); } if(mVertexProgram && mVertexProgram->isLinked()) { OGRE_CHECK_GL_ERROR(glUseProgramStages(mGLProgramPipelineHandle, GL_VERTEX_SHADER_BIT, mVertexProgram->getGLSLProgram()->getGLProgramHandle())); } if(mFragmentProgram && mFragmentProgram->isLinked()) { OGRE_CHECK_GL_ERROR(glUseProgramStages(mGLProgramPipelineHandle, GL_FRAGMENT_SHADER_BIT, mFragmentProgram->getGLSLProgram()->getGLProgramHandle())); } if(mGeometryProgram && mGeometryProgram->isLinked()) { OGRE_CHECK_GL_ERROR(glUseProgramStages(mGLProgramPipelineHandle, GL_GEOMETRY_SHADER_BIT, mGeometryProgram->getGLSLProgram()->getGLProgramHandle())); } if(mDomainProgram && mDomainProgram->isLinked()) { OGRE_CHECK_GL_ERROR(glUseProgramStages(mGLProgramPipelineHandle, GL_TESS_EVALUATION_SHADER_BIT, mDomainProgram->getGLSLProgram()->getGLProgramHandle())); } if(mHullProgram && mHullProgram->isLinked()) { OGRE_CHECK_GL_ERROR(glUseProgramStages(mGLProgramPipelineHandle, GL_TESS_CONTROL_SHADER_BIT, mHullProgram->getGLSLProgram()->getGLProgramHandle())); } if(mComputeProgram && mComputeProgram->isLinked()) { OGRE_CHECK_GL_ERROR(glUseProgramStages(mGLProgramPipelineHandle, GL_COMPUTE_SHADER_BIT, mComputeProgram->getGLSLProgram()->getGLProgramHandle())); } // Validate pipeline logObjectInfo( getCombinedName() + String("GLSL program pipeline result : "), mGLProgramPipelineHandle ); // if(getGLSupport()->checkExtension("GL_KHR_debug") || gl3wIsSupported(4, 3)) // glObjectLabel(GL_PROGRAM_PIPELINE, mGLProgramPipelineHandle, 0, // (mVertexProgram->getName() + "/" + mFragmentProgram->getName()).c_str()); } }
//----------------------------------------------------------------------- void GLSLLinkProgram::compileAndLink() { mVertexArrayObject = new GL3PlusVertexArrayObject(); mVertexArrayObject->bind(); // Compile and attach Vertex Program if (mVertexProgram) { if (!mVertexProgram->getGLSLProgram()->compile(true)) { mTriedToLinkAndFailed = true; return; } mVertexProgram->getGLSLProgram()->attachToProgramObject(mGLProgramHandle); setSkeletalAnimationIncluded(mVertexProgram->isSkeletalAnimationIncluded()); } // Compile and attach Fragment Program if (mFragmentProgram) { if (!mFragmentProgram->getGLSLProgram()->compile(true)) { mTriedToLinkAndFailed = true; return; } mFragmentProgram->getGLSLProgram()->attachToProgramObject(mGLProgramHandle); } // Compile and attach Geometry Program if (mGeometryProgram) { if (!mGeometryProgram->getGLSLProgram()->compile(true)) { return; } mGeometryProgram->getGLSLProgram()->attachToProgramObject(mGLProgramHandle); } // Compile and attach Tessellation Control Program if (mHullProgram) { if (!mHullProgram->getGLSLProgram()->compile(true)) { return; } mHullProgram->getGLSLProgram()->attachToProgramObject(mGLProgramHandle); } // Compile and attach Tessellation Evaluation Program if (mDomainProgram) { if (!mDomainProgram->getGLSLProgram()->compile(true)) { return; } mDomainProgram->getGLSLProgram()->attachToProgramObject(mGLProgramHandle); } // Compile and attach Compute Program if (mComputeProgram) { if (!mComputeProgram->getGLSLProgram()->compile(true)) { return; } mComputeProgram->getGLSLProgram()->attachToProgramObject(mGLProgramHandle); } // the link OGRE_CHECK_GL_ERROR(glLinkProgram( mGLProgramHandle )); OGRE_CHECK_GL_ERROR(glGetProgramiv( mGLProgramHandle, GL_LINK_STATUS, &mLinked )); mTriedToLinkAndFailed = !mLinked; logObjectInfo( getCombinedName() + String(" GLSL link result : "), mGLProgramHandle ); if(glIsProgram(mGLProgramHandle)) { OGRE_CHECK_GL_ERROR(glValidateProgram(mGLProgramHandle)); } logObjectInfo( getCombinedName() + String(" GLSL validation result : "), mGLProgramHandle ); if(mLinked) { if ( GpuProgramManager::getSingleton().getSaveMicrocodesToCache() ) { // add to the microcode to the cache String name; name = getCombinedName(); // get buffer size GLint binaryLength = 0; OGRE_CHECK_GL_ERROR(glGetProgramiv(mGLProgramHandle, GL_PROGRAM_BINARY_LENGTH, &binaryLength)); // create microcode GpuProgramManager::Microcode newMicrocode = GpuProgramManager::getSingleton().createMicrocode(binaryLength + sizeof(GLenum)); // get binary OGRE_CHECK_GL_ERROR(glGetProgramBinary(mGLProgramHandle, binaryLength, NULL, (GLenum *)newMicrocode->getPtr(), newMicrocode->getPtr() + sizeof(GLenum))); // add to the microcode to the cache GpuProgramManager::getSingleton().addMicrocodeToCache(name, newMicrocode); } } }
void GLES2TextureBuffer::buildMipmaps(const PixelBox &data) { int width; int height; int logW; int logH; int level; PixelBox scaled = data; scaled.data = data.data; scaled.left = data.left; scaled.right = data.right; scaled.top = data.top; scaled.bottom = data.bottom; scaled.front = data.front; scaled.back = data.back; width = data.getWidth(); height = data.getHeight(); logW = computeLog(width); logH = computeLog(height); level = (logW > logH ? logW : logH); for (int mip = 0; mip <= level; mip++) { GLenum glFormat = GLES2PixelUtil::getGLOriginFormat(scaled.format); GLenum dataType = GLES2PixelUtil::getGLOriginDataType(scaled.format); GLenum internalFormat = glFormat; #if OGRE_NO_GLES3_SUPPORT == 0 // In GL ES 3, the internalformat and format parameters do not need to be identical internalFormat = GLES2PixelUtil::getClosestGLInternalFormat(scaled.format); #endif switch(mTarget) { case GL_TEXTURE_2D: case GL_TEXTURE_CUBE_MAP: OGRE_CHECK_GL_ERROR(glTexImage2D(mFaceTarget, mip, internalFormat, width, height, 0, glFormat, dataType, scaled.data)); break; #if OGRE_NO_GLES3_SUPPORT == 0 case GL_TEXTURE_3D: case GL_TEXTURE_2D_ARRAY: OGRE_CHECK_GL_ERROR(glTexImage3D(mFaceTarget, mip, internalFormat, width, height, depth, 0, glFormat, dataType, scaled.data)); break; #endif } if (mip != 0) { OGRE_DELETE[] (uint8*) scaled.data; scaled.data = 0; } if (width > 1) { width = width / 2; } if (height > 1) { height = height / 2; } int sizeInBytes = PixelUtil::getMemorySize(width, height, 1, data.format); scaled = PixelBox(width, height, 1, data.format); scaled.data = new uint8[sizeInBytes]; Image::scale(data, scaled, Image::FILTER_LINEAR); }
GLSLProgramPipeline::~GLSLProgramPipeline() { OGRE_CHECK_GL_ERROR(glDeleteProgramPipelines(1, &mGLProgramPipelineHandle)); }
//----------------------------------------------------------------------------- // blitFromMemory doing hardware trilinear scaling void GLES2TextureBuffer::blitFromMemory(const PixelBox &src_orig, const Image::Box &dstBox) { // Fall back to normal GLHardwarePixelBuffer::blitFromMemory in case // - FBO is not supported // - Either source or target is luminance due doesn't looks like supported by hardware // - the source dimensions match the destination ones, in which case no scaling is needed // TODO: Check that extension is NOT available if(PixelUtil::isLuminance(src_orig.format) || PixelUtil::isLuminance(mFormat) || (src_orig.getWidth() == dstBox.getWidth() && src_orig.getHeight() == dstBox.getHeight() && src_orig.getDepth() == dstBox.getDepth())) { GLES2HardwarePixelBuffer::blitFromMemory(src_orig, dstBox); return; } if(!mBuffer.contains(dstBox)) OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Destination box out of range", "GLES2TextureBuffer::blitFromMemory"); // For scoped deletion of conversion buffer MemoryDataStreamPtr buf; PixelBox src; // First, convert the srcbox to a OpenGL compatible pixel format if(GLES2PixelUtil::getGLOriginFormat(src_orig.format) == 0) { // Convert to buffer internal format buf.bind(OGRE_NEW MemoryDataStream(PixelUtil::getMemorySize(src_orig.getWidth(), src_orig.getHeight(), src_orig.getDepth(), mFormat))); src = PixelBox(src_orig.getWidth(), src_orig.getHeight(), src_orig.getDepth(), mFormat, buf->getPtr()); PixelUtil::bulkPixelConversion(src_orig, src); } else { // No conversion needed src = src_orig; } // Create temporary texture to store source data GLuint id; GLenum target = #if OGRE_NO_GLES3_SUPPORT == 0 (src.getDepth() != 1) ? GL_TEXTURE_3D : #endif GL_TEXTURE_2D; GLsizei width = GLES2PixelUtil::optionalPO2(src.getWidth()); GLsizei height = GLES2PixelUtil::optionalPO2(src.getHeight()); GLenum format = GLES2PixelUtil::getClosestGLInternalFormat(src.format); GLenum datatype = GLES2PixelUtil::getGLOriginDataType(src.format); // Generate texture name OGRE_CHECK_GL_ERROR(glGenTextures(1, &id)); // Set texture type OGRE_CHECK_GL_ERROR(glBindTexture(target, id)); #if GL_APPLE_texture_max_level && OGRE_PLATFORM != OGRE_PLATFORM_NACL OGRE_CHECK_GL_ERROR(glTexParameteri(target, GL_TEXTURE_MAX_LEVEL_APPLE, 1000 )); #elif OGRE_NO_GLES3_SUPPORT == 0 OGRE_CHECK_GL_ERROR(glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, 1000 )); #endif // Allocate texture memory #if OGRE_NO_GLES3_SUPPORT == 0 if(target == GL_TEXTURE_3D || target == GL_TEXTURE_2D_ARRAY) glTexImage3D(target, 0, src.format, src.getWidth(), src.getHeight(), src.getDepth(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); else #endif OGRE_CHECK_GL_ERROR(glTexImage2D(target, 0, format, width, height, 0, format, datatype, 0)); // GL texture buffer GLES2TextureBuffer tex(StringUtil::BLANK, target, id, width, height, format, src.format, 0, 0, (Usage)(TU_AUTOMIPMAP|HBU_STATIC_WRITE_ONLY), false, false, 0); // Upload data to 0,0,0 in temporary texture Image::Box tempTarget(0, 0, 0, src.getWidth(), src.getHeight(), src.getDepth()); tex.upload(src, tempTarget); // Blit blitFromTexture(&tex, tempTarget, dstBox); // Delete temp texture OGRE_CHECK_GL_ERROR(glDeleteTextures(1, &id)); }
//----------------------------------------------------------------------------- // Very fast texture-to-texture blitter and hardware bi/trilinear scaling implementation using FBO // Destination texture must be 1D, 2D, 3D, or Cube // Source texture must be 1D, 2D or 3D // Supports compressed formats as both source and destination format, it will use the hardware DXT compressor // if available. // @author W.J. van der Laan void GLES2TextureBuffer::blitFromTexture(GLES2TextureBuffer *src, const Image::Box &srcBox, const Image::Box &dstBox) { return; // todo - add a shader attach... // std::cerr << "GLES2TextureBuffer::blitFromTexture " << // src->mTextureID << ":" << srcBox.left << "," << srcBox.top << "," << srcBox.right << "," << srcBox.bottom << " " << // mTextureID << ":" << dstBox.left << "," << dstBox.top << "," << dstBox.right << "," << dstBox.bottom << std::endl; // Store reference to FBO manager GLES2FBOManager *fboMan = static_cast<GLES2FBOManager *>(GLES2RTTManager::getSingletonPtr()); RenderSystem* rsys = Root::getSingleton().getRenderSystem(); rsys->_disableTextureUnitsFrom(0); glActiveTexture(GL_TEXTURE0); // Disable alpha, depth and scissor testing, disable blending, // and disable culling glDisable(GL_DEPTH_TEST); glDisable(GL_SCISSOR_TEST); glDisable(GL_BLEND); glDisable(GL_CULL_FACE); // Set up source texture OGRE_CHECK_GL_ERROR(glBindTexture(src->mTarget, src->mTextureID)); // Set filtering modes depending on the dimensions and source if(srcBox.getWidth()==dstBox.getWidth() && srcBox.getHeight()==dstBox.getHeight() && srcBox.getDepth()==dstBox.getDepth()) { // Dimensions match -- use nearest filtering (fastest and pixel correct) OGRE_CHECK_GL_ERROR(glTexParameteri(src->mTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); OGRE_CHECK_GL_ERROR(glTexParameteri(src->mTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); } else { // Dimensions don't match -- use bi or trilinear filtering depending on the // source texture. if(src->mUsage & TU_AUTOMIPMAP) { // Automatic mipmaps, we can safely use trilinear filter which // brings greatly improved quality for minimisation. OGRE_CHECK_GL_ERROR(glTexParameteri(src->mTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)); OGRE_CHECK_GL_ERROR(glTexParameteri(src->mTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); } else { // Manual mipmaps, stay safe with bilinear filtering so that no // intermipmap leakage occurs. OGRE_CHECK_GL_ERROR(glTexParameteri(src->mTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); OGRE_CHECK_GL_ERROR(glTexParameteri(src->mTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); } } // Clamp to edge (fastest) OGRE_CHECK_GL_ERROR(glTexParameteri(src->mTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); OGRE_CHECK_GL_ERROR(glTexParameteri(src->mTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); #if OGRE_NO_GLES3_SUPPORT == 0 OGRE_CHECK_GL_ERROR(glTexParameteri(src->mTarget, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE)); // Set origin base level mipmap to make sure we source from the right mip // level. OGRE_CHECK_GL_ERROR(glTexParameteri(src->mTarget, GL_TEXTURE_BASE_LEVEL, src->mLevel)); #endif // Store old binding so it can be restored later GLint oldfb; OGRE_CHECK_GL_ERROR(glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldfb)); // Set up temporary FBO OGRE_CHECK_GL_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, fboMan->getTemporaryFBO())); GLuint tempTex = 0; if(!fboMan->checkFormat(mFormat)) { // If target format not directly supported, create intermediate texture GLenum tempFormat = GLES2PixelUtil::getClosestGLInternalFormat(fboMan->getSupportedAlternative(mFormat)); OGRE_CHECK_GL_ERROR(glGenTextures(1, &tempTex)); OGRE_CHECK_GL_ERROR(glBindTexture(GL_TEXTURE_2D, tempTex)); #if GL_APPLE_texture_max_level && OGRE_PLATFORM != OGRE_PLATFORM_NACL OGRE_CHECK_GL_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL_APPLE, 0)); #elif OGRE_NO_GLES3_SUPPORT == 0 OGRE_CHECK_GL_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0)); #endif // Allocate temporary texture of the size of the destination area OGRE_CHECK_GL_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, tempFormat, GLES2PixelUtil::optionalPO2(dstBox.getWidth()), GLES2PixelUtil::optionalPO2(dstBox.getHeight()), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0)); OGRE_CHECK_GL_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tempTex, 0)); // Set viewport to size of destination slice OGRE_CHECK_GL_ERROR(glViewport(0, 0, dstBox.getWidth(), dstBox.getHeight())); } else { // We are going to bind directly, so set viewport to size and position of destination slice OGRE_CHECK_GL_ERROR(glViewport(dstBox.left, dstBox.top, dstBox.getWidth(), dstBox.getHeight())); } // Process each destination slice for(size_t slice=dstBox.front; slice<dstBox.back; ++slice) { if(!tempTex) { // Bind directly bindToFramebuffer(GL_COLOR_ATTACHMENT0, slice); } /// Calculate source texture coordinates float u1 = (float)srcBox.left / (float)src->mWidth; float v1 = (float)srcBox.top / (float)src->mHeight; float u2 = (float)srcBox.right / (float)src->mWidth; float v2 = (float)srcBox.bottom / (float)src->mHeight; /// Calculate source slice for this destination slice float w = (float)(slice - dstBox.front) / (float)dstBox.getDepth(); /// Get slice # in source w = w * (float)srcBox.getDepth() + srcBox.front; /// Normalise to texture coordinate in 0.0 .. 1.0 w = (w+0.5f) / (float)src->mDepth; /// Finally we're ready to rumble OGRE_CHECK_GL_ERROR(glBindTexture(src->mTarget, src->mTextureID)); OGRE_CHECK_GL_ERROR(glEnable(src->mTarget)); GLfloat squareVertices[] = { -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, }; GLfloat texCoords[] = { u1, v1, w, u2, v1, w, u2, v2, w, u1, v2, w }; GLuint posAttrIndex = 0; GLuint texAttrIndex = 0; if(Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_SEPARATE_SHADER_OBJECTS)) { GLSLESProgramPipeline* programPipeline = GLSLESProgramPipelineManager::getSingleton().getActiveProgramPipeline(); posAttrIndex = (GLuint)programPipeline->getAttributeIndex(VES_POSITION, 0); texAttrIndex = (GLuint)programPipeline->getAttributeIndex(VES_TEXTURE_COORDINATES, 0); } else { GLSLESLinkProgram* linkProgram = GLSLESLinkProgramManager::getSingleton().getActiveLinkProgram(); posAttrIndex = (GLuint)linkProgram->getAttributeIndex(VES_POSITION, 0); texAttrIndex = (GLuint)linkProgram->getAttributeIndex(VES_TEXTURE_COORDINATES, 0); } // Draw the textured quad OGRE_CHECK_GL_ERROR(glVertexAttribPointer(posAttrIndex, 2, GL_FLOAT, 0, 0, squareVertices)); OGRE_CHECK_GL_ERROR(glEnableVertexAttribArray(posAttrIndex)); OGRE_CHECK_GL_ERROR(glVertexAttribPointer(texAttrIndex, 3, GL_FLOAT, 0, 0, texCoords)); OGRE_CHECK_GL_ERROR(glEnableVertexAttribArray(texAttrIndex)); OGRE_CHECK_GL_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)); OGRE_CHECK_GL_ERROR(glDisable(src->mTarget)); if(tempTex) { // Copy temporary texture OGRE_CHECK_GL_ERROR(glBindTexture(mTarget, mTextureID)); switch(mTarget) { case GL_TEXTURE_2D: case GL_TEXTURE_CUBE_MAP: OGRE_CHECK_GL_ERROR(glCopyTexSubImage2D(mFaceTarget, mLevel, dstBox.left, dstBox.top, 0, 0, dstBox.getWidth(), dstBox.getHeight())); break; } } } // Finish up if(!tempTex) { // Generate mipmaps if(mUsage & TU_AUTOMIPMAP) { OGRE_CHECK_GL_ERROR(glBindTexture(mTarget, mTextureID)); OGRE_CHECK_GL_ERROR(glGenerateMipmap(mTarget)); } } // Reset source texture to sane state OGRE_CHECK_GL_ERROR(glBindTexture(src->mTarget, src->mTextureID)); #if OGRE_NO_GLES3_SUPPORT == 0 OGRE_CHECK_GL_ERROR(glTexParameteri(src->mTarget, GL_TEXTURE_BASE_LEVEL, 0)); // Detach texture from temporary framebuffer if(mFormat == PF_DEPTH) { OGRE_CHECK_GL_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0)); } else #endif { OGRE_CHECK_GL_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, 0)); } // Restore old framebuffer OGRE_CHECK_GL_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, oldfb)); OGRE_CHECK_GL_ERROR(glDeleteTextures(1, &tempTex)); }
void GLES2TextureBuffer::copyFromFramebuffer(size_t zoffset) { OGRE_CHECK_GL_ERROR(glBindTexture(mTarget, mTextureID)); OGRE_CHECK_GL_ERROR(glCopyTexSubImage2D(mFaceTarget, mLevel, 0, 0, 0, 0, mWidth, mHeight)); }
void GLES2FrameBufferObject::bind() { /// Bind it to FBO const GLuint fb = mMultisampleFB ? mMultisampleFB : mFB; OGRE_CHECK_GL_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, fb)); }
//----------------------------------------------------------------------- void GLSLLinkProgram::updateUniforms(GpuProgramParametersSharedPtr params, uint16 mask, GpuProgramType fromProgType) { // Iterate through uniform reference list and update uniform values GLUniformReferenceIterator currentUniform = mGLUniformReferences.begin(); GLUniformReferenceIterator endUniform = mGLUniformReferences.end(); // determine if we need to transpose matrices when binding int transpose = GL_TRUE; if ((fromProgType == GPT_FRAGMENT_PROGRAM && mVertexProgram && (!mVertexProgram->getGLSLProgram()->getColumnMajorMatrices())) || (fromProgType == GPT_VERTEX_PROGRAM && mFragmentProgram && (!mFragmentProgram->getGLSLProgram()->getColumnMajorMatrices())) || (fromProgType == GPT_GEOMETRY_PROGRAM && mGeometryProgram && (!mGeometryProgram->getGLSLProgram()->getColumnMajorMatrices())) || (fromProgType == GPT_HULL_PROGRAM && mHullProgram && (!mHullProgram->getGLSLProgram()->getColumnMajorMatrices())) || (fromProgType == GPT_DOMAIN_PROGRAM && mDomainProgram && (!mDomainProgram->getGLSLProgram()->getColumnMajorMatrices())) || (fromProgType == GPT_COMPUTE_PROGRAM && mComputeProgram && (!mComputeProgram->getGLSLProgram()->getColumnMajorMatrices()))) { transpose = GL_FALSE; } for (;currentUniform != endUniform; ++currentUniform) { // Only pull values from buffer it's supposed to be in (vertex or fragment) // This method will be called twice, once for vertex program params, // and once for fragment program params. if (fromProgType == currentUniform->mSourceProgType) { const GpuConstantDefinition* def = currentUniform->mConstantDef; if (def->variability & mask) { GLsizei glArraySize = (GLsizei)def->arraySize; // Get the index in the parameter real list switch (def->constType) { case GCT_FLOAT1: OGRE_CHECK_GL_ERROR(glUniform1fv(currentUniform->mLocation, glArraySize, params->getFloatPointer(def->physicalIndex))); break; case GCT_FLOAT2: OGRE_CHECK_GL_ERROR(glUniform2fv(currentUniform->mLocation, glArraySize, params->getFloatPointer(def->physicalIndex))); break; case GCT_FLOAT3: OGRE_CHECK_GL_ERROR(glUniform3fv(currentUniform->mLocation, glArraySize, params->getFloatPointer(def->physicalIndex))); break; case GCT_FLOAT4: OGRE_CHECK_GL_ERROR(glUniform4fv(currentUniform->mLocation, glArraySize, params->getFloatPointer(def->physicalIndex))); break; case GCT_DOUBLE1: OGRE_CHECK_GL_ERROR(glUniform1dv(currentUniform->mLocation, glArraySize, params->getDoublePointer(def->physicalIndex))); break; case GCT_DOUBLE2: OGRE_CHECK_GL_ERROR(glUniform2dv(currentUniform->mLocation, glArraySize, params->getDoublePointer(def->physicalIndex))); break; case GCT_DOUBLE3: OGRE_CHECK_GL_ERROR(glUniform3dv(currentUniform->mLocation, glArraySize, params->getDoublePointer(def->physicalIndex))); break; case GCT_DOUBLE4: OGRE_CHECK_GL_ERROR(glUniform4dv(currentUniform->mLocation, glArraySize, params->getDoublePointer(def->physicalIndex))); break; case GCT_MATRIX_DOUBLE_2X2: OGRE_CHECK_GL_ERROR(glUniformMatrix2dv(currentUniform->mLocation, glArraySize, transpose, params->getDoublePointer(def->physicalIndex))); break; case GCT_MATRIX_DOUBLE_2X3: OGRE_CHECK_GL_ERROR(glUniformMatrix2x3dv(currentUniform->mLocation, glArraySize, transpose, params->getDoublePointer(def->physicalIndex))); break; case GCT_MATRIX_DOUBLE_2X4: OGRE_CHECK_GL_ERROR(glUniformMatrix2x4dv(currentUniform->mLocation, glArraySize, transpose, params->getDoublePointer(def->physicalIndex))); break; case GCT_MATRIX_DOUBLE_3X2: OGRE_CHECK_GL_ERROR(glUniformMatrix3x2dv(currentUniform->mLocation, glArraySize, transpose, params->getDoublePointer(def->physicalIndex))); break; case GCT_MATRIX_DOUBLE_3X3: OGRE_CHECK_GL_ERROR(glUniformMatrix3dv(currentUniform->mLocation, glArraySize, transpose, params->getDoublePointer(def->physicalIndex))); break; case GCT_MATRIX_DOUBLE_3X4: OGRE_CHECK_GL_ERROR(glUniformMatrix3x4dv(currentUniform->mLocation, glArraySize, transpose, params->getDoublePointer(def->physicalIndex))); break; case GCT_MATRIX_DOUBLE_4X2: OGRE_CHECK_GL_ERROR(glUniformMatrix4x2dv(currentUniform->mLocation, glArraySize, transpose, params->getDoublePointer(def->physicalIndex))); break; case GCT_MATRIX_DOUBLE_4X3: OGRE_CHECK_GL_ERROR(glUniformMatrix4x3dv(currentUniform->mLocation, glArraySize, transpose, params->getDoublePointer(def->physicalIndex))); break; case GCT_MATRIX_DOUBLE_4X4: OGRE_CHECK_GL_ERROR(glUniformMatrix4dv(currentUniform->mLocation, glArraySize, transpose, params->getDoublePointer(def->physicalIndex))); break; case GCT_MATRIX_2X2: OGRE_CHECK_GL_ERROR(glUniformMatrix2fv(currentUniform->mLocation, glArraySize, transpose, params->getFloatPointer(def->physicalIndex))); break; case GCT_MATRIX_2X3: OGRE_CHECK_GL_ERROR(glUniformMatrix2x3fv(currentUniform->mLocation, glArraySize, transpose, params->getFloatPointer(def->physicalIndex))); break; case GCT_MATRIX_2X4: OGRE_CHECK_GL_ERROR(glUniformMatrix2x4fv(currentUniform->mLocation, glArraySize, transpose, params->getFloatPointer(def->physicalIndex))); break; case GCT_MATRIX_3X2: OGRE_CHECK_GL_ERROR(glUniformMatrix3x2fv(currentUniform->mLocation, glArraySize, transpose, params->getFloatPointer(def->physicalIndex))); break; case GCT_MATRIX_3X3: OGRE_CHECK_GL_ERROR(glUniformMatrix3fv(currentUniform->mLocation, glArraySize, transpose, params->getFloatPointer(def->physicalIndex))); break; case GCT_MATRIX_3X4: OGRE_CHECK_GL_ERROR(glUniformMatrix3x4fv(currentUniform->mLocation, glArraySize, transpose, params->getFloatPointer(def->physicalIndex))); break; case GCT_MATRIX_4X2: OGRE_CHECK_GL_ERROR(glUniformMatrix4x2fv(currentUniform->mLocation, glArraySize, transpose, params->getFloatPointer(def->physicalIndex))); break; case GCT_MATRIX_4X3: OGRE_CHECK_GL_ERROR(glUniformMatrix4x3fv(currentUniform->mLocation, glArraySize, transpose, params->getFloatPointer(def->physicalIndex))); break; case GCT_MATRIX_4X4: OGRE_CHECK_GL_ERROR(glUniformMatrix4fv(currentUniform->mLocation, glArraySize, transpose, params->getFloatPointer(def->physicalIndex))); break; case GCT_INT1: OGRE_CHECK_GL_ERROR(glUniform1iv(currentUniform->mLocation, glArraySize, (GLint*)params->getIntPointer(def->physicalIndex))); break; case GCT_INT2: OGRE_CHECK_GL_ERROR(glUniform2iv(currentUniform->mLocation, glArraySize, (GLint*)params->getIntPointer(def->physicalIndex))); break; case GCT_INT3: OGRE_CHECK_GL_ERROR(glUniform3iv(currentUniform->mLocation, glArraySize, (GLint*)params->getIntPointer(def->physicalIndex))); break; case GCT_INT4: OGRE_CHECK_GL_ERROR(glUniform4iv(currentUniform->mLocation, glArraySize, (GLint*)params->getIntPointer(def->physicalIndex))); break; case GCT_SAMPLER1D: case GCT_SAMPLER1DSHADOW: case GCT_SAMPLER2D: case GCT_SAMPLER2DSHADOW: case GCT_SAMPLER2DARRAY: case GCT_SAMPLER3D: case GCT_SAMPLERCUBE: case GCT_SAMPLERRECT: // Samplers handled like 1-element ints OGRE_CHECK_GL_ERROR(glUniform1iv(currentUniform->mLocation, 1, (GLint*)params->getIntPointer(def->physicalIndex))); break; case GCT_SUBROUTINE: case GCT_UNKNOWN: break; } // End switch } // Variability & mask } // fromProgType == currentUniform->mSourceProgType } // End for }
//----------------------------------------------------------------------- void GLSLESProgramPipeline::updateUniforms(GpuProgramParametersSharedPtr params, uint16 mask, GpuProgramType fromProgType) { // Iterate through uniform reference list and update uniform values GLUniformReferenceIterator currentUniform = mGLUniformReferences.begin(); GLUniformReferenceIterator endUniform = mGLUniformReferences.end(); #if GL_EXT_separate_shader_objects && OGRE_PLATFORM != OGRE_PLATFORM_NACL GLuint progID = 0; GLSLESGpuProgram *prog; if(fromProgType == GPT_VERTEX_PROGRAM) { progID = mVertexProgram->getGLSLProgram()->getGLProgramHandle(); prog = mVertexProgram; } else if(fromProgType == GPT_FRAGMENT_PROGRAM) { progID = mFragmentProgram->getGLSLProgram()->getGLProgramHandle(); prog = mFragmentProgram; } for (; currentUniform != endUniform; ++currentUniform) { // Only pull values from buffer it's supposed to be in (vertex or fragment) // This method will be called twice, once for vertex program params, // and once for fragment program params. if (fromProgType == currentUniform->mSourceProgType) { const GpuConstantDefinition* def = currentUniform->mConstantDef; if (def->variability & mask) { GLsizei glArraySize = (GLsizei)def->arraySize; bool shouldUpdate = true; switch (def->constType) { case GCT_INT1: case GCT_INT2: case GCT_INT3: case GCT_INT4: case GCT_SAMPLER1D: case GCT_SAMPLER1DSHADOW: case GCT_SAMPLER2D: case GCT_SAMPLER2DSHADOW: case GCT_SAMPLER3D: case GCT_SAMPLERCUBE: shouldUpdate = prog->getUniformCache()->updateUniform(currentUniform->mLocation, params->getIntPointer(def->physicalIndex), def->elementSize * def->arraySize * sizeof(int)); break; default: shouldUpdate = prog->getUniformCache()->updateUniform(currentUniform->mLocation, params->getFloatPointer(def->physicalIndex), def->elementSize * def->arraySize * sizeof(float)); break; } if(!shouldUpdate) continue; // Get the index in the parameter real list switch (def->constType) { case GCT_FLOAT1: OGRE_CHECK_GL_ERROR(glProgramUniform1fvEXT(progID, currentUniform->mLocation, glArraySize, params->getFloatPointer(def->physicalIndex))); break; case GCT_FLOAT2: OGRE_CHECK_GL_ERROR(glProgramUniform2fvEXT(progID, currentUniform->mLocation, glArraySize, params->getFloatPointer(def->physicalIndex))); break; case GCT_FLOAT3: OGRE_CHECK_GL_ERROR(glProgramUniform3fvEXT(progID, currentUniform->mLocation, glArraySize, params->getFloatPointer(def->physicalIndex))); break; case GCT_FLOAT4: OGRE_CHECK_GL_ERROR(glProgramUniform4fvEXT(progID, currentUniform->mLocation, glArraySize, params->getFloatPointer(def->physicalIndex))); break; case GCT_MATRIX_2X2: OGRE_CHECK_GL_ERROR(glProgramUniformMatrix2fvEXT(progID, currentUniform->mLocation, glArraySize, GL_FALSE, params->getFloatPointer(def->physicalIndex))); break; case GCT_MATRIX_3X3: OGRE_CHECK_GL_ERROR(glProgramUniformMatrix3fvEXT(progID, currentUniform->mLocation, glArraySize, GL_FALSE, params->getFloatPointer(def->physicalIndex))); break; case GCT_MATRIX_4X4: OGRE_CHECK_GL_ERROR(glProgramUniformMatrix4fvEXT(progID, currentUniform->mLocation, glArraySize, GL_FALSE, params->getFloatPointer(def->physicalIndex))); break; case GCT_INT1: OGRE_CHECK_GL_ERROR(glProgramUniform1ivEXT(progID, currentUniform->mLocation, glArraySize, params->getIntPointer(def->physicalIndex))); break; case GCT_INT2: OGRE_CHECK_GL_ERROR(glProgramUniform2ivEXT(progID, currentUniform->mLocation, glArraySize, params->getIntPointer(def->physicalIndex))); break; case GCT_INT3: OGRE_CHECK_GL_ERROR(glProgramUniform3ivEXT(progID, currentUniform->mLocation, glArraySize, params->getIntPointer(def->physicalIndex))); break; case GCT_INT4: OGRE_CHECK_GL_ERROR(glProgramUniform4ivEXT(progID, currentUniform->mLocation, glArraySize, params->getIntPointer(def->physicalIndex))); break; case GCT_SAMPLER1D: case GCT_SAMPLER1DSHADOW: case GCT_SAMPLER2D: case GCT_SAMPLER2DSHADOW: case GCT_SAMPLER3D: case GCT_SAMPLERCUBE: // Samplers handled like 1-element ints OGRE_CHECK_GL_ERROR(glProgramUniform1ivEXT(progID, currentUniform->mLocation, 1, params->getIntPointer(def->physicalIndex))); break; case GCT_MATRIX_2X3: case GCT_MATRIX_2X4: case GCT_MATRIX_3X2: case GCT_MATRIX_3X4: case GCT_MATRIX_4X2: case GCT_MATRIX_4X3: case GCT_SAMPLER2DARRAY: case GCT_UNKNOWN: case GCT_SUBROUTINE: case GCT_DOUBLE1: case GCT_DOUBLE2: case GCT_DOUBLE3: case GCT_DOUBLE4: case GCT_SAMPLERRECT: case GCT_MATRIX_DOUBLE_2X2: case GCT_MATRIX_DOUBLE_2X3: case GCT_MATRIX_DOUBLE_2X4: case GCT_MATRIX_DOUBLE_3X2: case GCT_MATRIX_DOUBLE_3X3: case GCT_MATRIX_DOUBLE_3X4: case GCT_MATRIX_DOUBLE_4X2: case GCT_MATRIX_DOUBLE_4X3: case GCT_MATRIX_DOUBLE_4X4: break; } // End switch } // Variability & mask } // fromProgType == currentUniform->mSourceProgType } // End for #endif }
//----------------------------------------------------------------------- GLSLLinkProgram::~GLSLLinkProgram(void) { OGRE_CHECK_GL_ERROR(glDeleteProgram(mGLProgramHandle)); }
GL3PlusHardwareIndexBuffer::~GL3PlusHardwareIndexBuffer() { OGRE_CHECK_GL_ERROR(glDeleteBuffers(1, &mBufferId)); }
GLES2HardwareUniformBuffer::~GLES2HardwareUniformBuffer() { OGRE_CHECK_GL_ERROR(glDeleteBuffers(1, &mBufferId)); }
//----------------------------------------------------------------------------- void GLES2RenderToVertexBuffer::update(SceneManager* sceneMgr) { size_t bufSize = mVertexData->vertexDeclaration->getVertexSize(0) * mMaxVertexCount; if (!mVertexBuffers[0] || mVertexBuffers[0]->getSizeInBytes() != bufSize) { // Buffers don't match. Need to reallocate. mResetRequested = true; } // Single pass only for now Ogre::Pass* r2vbPass = mMaterial->getBestTechnique()->getPass(0); // Set pass before binding buffers to activate the GPU programs sceneMgr->_setPass(r2vbPass); bindVerticesOutput(r2vbPass); RenderOperation renderOp; size_t targetBufferIndex; if (mResetRequested || mResetsEveryUpdate) { // Use source data to render to first buffer mSourceRenderable->getRenderOperation(renderOp); targetBufferIndex = 0; } else { // Use current front buffer to render to back buffer this->getRenderOperation(renderOp); targetBufferIndex = 1 - mFrontBufferIndex; } if (!mVertexBuffers[targetBufferIndex] || mVertexBuffers[targetBufferIndex]->getSizeInBytes() != bufSize) { reallocateBuffer(targetBufferIndex); } GLES2HardwareVertexBuffer* vertexBuffer = static_cast<GLES2HardwareVertexBuffer*>(mVertexBuffers[targetBufferIndex].get()); /* if(Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_SEPARATE_SHADER_OBJECTS)) { GLSLESProgramPipeline* programPipeline = GLSLESProgramPipelineManager::getSingleton().getActiveProgramPipeline(); programPipeline->getVertexArrayObject()->bind(); } else { GLSLESLinkProgram* linkProgram = GLSLESLinkProgramManager::getSingleton().getActiveLinkProgram(); linkProgram->getVertexArrayObject()->bind(); } */ // Bind the target buffer OGRE_CHECK_GL_ERROR(glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, vertexBuffer->getGLBufferId())); // Disable rasterization OGRE_CHECK_GL_ERROR(glEnable(GL_RASTERIZER_DISCARD)); RenderSystem* targetRenderSystem = Root::getSingleton().getRenderSystem(); // Draw the object targetRenderSystem->_setWorldMatrix(Matrix4::IDENTITY); targetRenderSystem->_setViewMatrix(Matrix4::IDENTITY); targetRenderSystem->_setProjectionMatrix(Matrix4::IDENTITY); if (r2vbPass->hasVertexProgram()) { targetRenderSystem->bindGpuProgramParameters(GPT_VERTEX_PROGRAM, r2vbPass->getVertexProgramParameters(), GPV_ALL); } if (r2vbPass->hasFragmentProgram()) { targetRenderSystem->bindGpuProgramParameters(GPT_FRAGMENT_PROGRAM, r2vbPass->getFragmentProgramParameters(), GPV_ALL); } if (r2vbPass->hasGeometryProgram()) { targetRenderSystem->bindGpuProgramParameters(GPT_GEOMETRY_PROGRAM, r2vbPass->getGeometryProgramParameters(), GPV_ALL); } OGRE_CHECK_GL_ERROR(glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, mPrimitivesDrawnQuery)); OGRE_CHECK_GL_ERROR(glBeginTransformFeedback(getR2VBPrimitiveType(mOperationType))); targetRenderSystem->_render(renderOp); OGRE_CHECK_GL_ERROR(glEndTransformFeedback()); // Finish the query OGRE_CHECK_GL_ERROR(glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN)); OGRE_CHECK_GL_ERROR(glDisable(GL_RASTERIZER_DISCARD)); // Read back query results GLuint primitivesWritten; OGRE_CHECK_GL_ERROR(glGetQueryObjectuiv(mPrimitivesDrawnQuery, GL_QUERY_RESULT, &primitivesWritten)); mVertexData->vertexCount = primitivesWritten * getVertexCountPerPrimitive(mOperationType); // Switch the vertex binding if necessary if (targetBufferIndex != mFrontBufferIndex) { mVertexData->vertexBufferBinding->unsetAllBindings(); mVertexData->vertexBufferBinding->setBinding(0, mVertexBuffers[targetBufferIndex]); mFrontBufferIndex = targetBufferIndex; } // Enable rasterization OGRE_CHECK_GL_ERROR(glDisable(GL_RASTERIZER_DISCARD)); // Clear the reset flag mResetRequested = false; }
//--------------------------------------------------------------------------- bool GLSLProgram::compile(const bool checkErrors) { if (mCompiled == 1) { return true; } // only create a shader object if glsl is supported if (isSupported()) { // create shader object GLenum shaderType = 0x0000; switch (mType) { case GPT_VERTEX_PROGRAM: shaderType = GL_VERTEX_SHADER; break; case GPT_FRAGMENT_PROGRAM: shaderType = GL_FRAGMENT_SHADER; break; case GPT_GEOMETRY_PROGRAM: shaderType = GL_GEOMETRY_SHADER; break; case GPT_DOMAIN_PROGRAM: shaderType = GL_TESS_EVALUATION_SHADER; break; case GPT_HULL_PROGRAM: shaderType = GL_TESS_CONTROL_SHADER; break; case GPT_COMPUTE_PROGRAM: shaderType = GL_COMPUTE_SHADER; break; } OGRE_CHECK_GL_ERROR(mGLShaderHandle = glCreateShader(shaderType)); // if(getGLSupport()->checkExtension("GL_KHR_debug") || gl3wIsSupported(4, 3)) // glObjectLabel(GL_SHADER, mGLShaderHandle, 0, mName.c_str()); if(Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_SEPARATE_SHADER_OBJECTS)) { OGRE_CHECK_GL_ERROR(mGLProgramHandle = glCreateProgram()); // if(getGLSupport()->checkExtension("GL_KHR_debug") || gl3wIsSupported(4, 3)) // glObjectLabel(GL_PROGRAM, mGLProgramHandle, 0, mName.c_str()); } } // Add preprocessor extras and main source if (!mSource.empty()) { // Fix up the source in case someone forgot to redeclare gl_Position if(Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_SEPARATE_SHADER_OBJECTS) && mType == GPT_VERTEX_PROGRAM) { // Check that it's missing and that this shader has a main function, ie. not a child shader. if(mSource.find("vec4 gl_Position") == String::npos) { size_t mainPos = mSource.find("void main"); if(mainPos != String::npos) { size_t versionPos = mSource.find("#version"); int shaderVersion = StringConverter::parseInt(mSource.substr(versionPos+9, 3)); if(shaderVersion >= 150) mSource.insert(mainPos, "out gl_PerVertex\n{\nvec4 gl_Position;\nfloat gl_PointSize;\nfloat gl_ClipDistance[];\n};\n"); } } } const char *source = mSource.c_str(); OGRE_CHECK_GL_ERROR(glShaderSource(mGLShaderHandle, 1, &source, NULL)); } OGRE_CHECK_GL_ERROR(glCompileShader(mGLShaderHandle)); // Check for compile errors OGRE_CHECK_GL_ERROR(glGetShaderiv(mGLShaderHandle, GL_COMPILE_STATUS, &mCompiled)); if(!mCompiled && checkErrors) { String message = logObjectInfo("GLSL compile log: " + mName, mGLShaderHandle); checkAndFixInvalidDefaultPrecisionError(message); } // Log a message that the shader compiled successfully. if (mCompiled && checkErrors) logObjectInfo("GLSL compiled: " + mName, mGLShaderHandle); if(!mCompiled) { String progType = "Fragment"; if (mType == GPT_VERTEX_PROGRAM) { progType = "Vertex"; } else if (mType == GPT_GEOMETRY_PROGRAM) { progType = "Geometry"; } else if (mType == GPT_DOMAIN_PROGRAM) { progType = "Tesselation Evaluation"; } else if (mType == GPT_HULL_PROGRAM) { progType = "Tesselation Control"; } else if (mType == GPT_COMPUTE_PROGRAM) { progType = "Compute"; } OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, progType + " Program " + mName + " failed to compile. See compile log above for details.", "GLSLProgram::compile"); } return (mCompiled == 1); }
void GL3PlusRenderToVertexBuffer::update(SceneManager* sceneMgr) { // size_t bufSize = mVertexData->vertexDeclaration->getVertexSize(0) * mMaxVertexCount; // if (mVertexBuffers[0].isNull() || mVertexBuffers[0]->getSizeInBytes() != bufSize) // { // // Buffers don't match. Need to reallocate. // mResetRequested = true; // } // if (mResetRequested || mResetsEveryUpdate) // { // // Use source data to render to first buffer. // mSourceRenderable->getRenderOperation(renderOp); // targetBufferIndex = 0; // } // else // { // // Use current front buffer to render to back buffer. // this->getRenderOperation(renderOp); // targetBufferIndex = 1 - mSourceBufferIndex; // } // if (mVertexBuffers[targetBufferIndex].isNull() || // mVertexBuffers[targetBufferIndex]->getSizeInBytes() != bufSize) // { // reallocateBuffer(targetBufferIndex); // } // Single pass only for now. Ogre::Pass* r2vbPass = mMaterial->getBestTechnique()->getPass(0); // Set pass before binding buffers to activate the GPU programs. //sceneMgr->_setPass(r2vbPass); TODO if (mFirstUpdate) { bindVerticesOutput(r2vbPass); mFirstUpdate = false; } // size_t targetBufferIndex = mSourceBufferIndex == 0 ? 0 : 1; // Disable rasterization. OGRE_CHECK_GL_ERROR(glEnable(GL_RASTERIZER_DISCARD)); // Bind shader parameters. RenderSystem* targetRenderSystem = Root::getSingleton().getRenderSystem(); targetRenderSystem->_setWorldMatrix(Matrix4::IDENTITY); targetRenderSystem->_setViewMatrix(Matrix4::IDENTITY); targetRenderSystem->_setProjectionMatrix(Matrix4::IDENTITY); if (r2vbPass->hasVertexProgram()) { targetRenderSystem->bindGpuProgramParameters(GPT_VERTEX_PROGRAM, r2vbPass->getVertexProgramParameters(), GPV_ALL); } if (r2vbPass->hasFragmentProgram()) { targetRenderSystem->bindGpuProgramParameters(GPT_FRAGMENT_PROGRAM, r2vbPass->getFragmentProgramParameters(), GPV_ALL); } if (r2vbPass->hasGeometryProgram()) { targetRenderSystem->bindGpuProgramParameters(GPT_GEOMETRY_PROGRAM, r2vbPass->getGeometryProgramParameters(), GPV_ALL); } //TODO add tessellation stages // Bind source vertex array + target tranform feedback buffer. GL3PlusHardwareVertexBuffer* targetVertexBuffer = static_cast<GL3PlusHardwareVertexBuffer*>(mVertexBuffers[mTargetBufferIndex].getPointer()); // OGRE_CHECK_GL_ERROR(glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, VertexBuffer[mTargetBufferIndex])); OGRE_CHECK_GL_ERROR(glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, targetVertexBuffer->getGLBufferId())); // OGRE_CHECK_GL_ERROR(glBindVertexArray(VertexArray[mSourceBufferIndex])); if (Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_SEPARATE_SHADER_OBJECTS)) { GLSLSeparableProgram* separableProgram = GLSLSeparableProgramManager::getSingleton().getCurrentSeparableProgram(); separableProgram->activate(); separableProgram->getVertexArrayObject()->bind(); } else { GLSLMonolithicProgram* monolithicProgram = GLSLMonolithicProgramManager::getSingleton().getActiveMonolithicProgram(); monolithicProgram->getVertexArrayObject()->bind(); } // 'Render' data to the transform buffer. OGRE_CHECK_GL_ERROR(glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, mPrimitivesDrawnQuery)); OGRE_CHECK_GL_ERROR(glBeginTransformFeedback(getR2VBPrimitiveType(mOperationType))); RenderOperation renderOp; if (mResetRequested || mResetsEveryUpdate) { // Use source data to render to first buffer. mSourceRenderable->getRenderOperation(renderOp, false); } else { // Use current front buffer to render to back buffer. this->getRenderOperation(renderOp); } renderOp.renderToVertexBuffer = true; targetRenderSystem->_render(renderOp); // OGRE_CHECK_GL_ERROR(glDrawArrays(GL_POINTS, 0, 1)); //TODO GL4+ //glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, mFeedbackObject); //glDrawTransformFeedback(getR2VBPrimitiveType(mOperationType), mFeedbackObject); OGRE_CHECK_GL_ERROR(glEndTransformFeedback()); OGRE_CHECK_GL_ERROR(glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN)); // Read back query results. GLuint primitivesWritten; OGRE_CHECK_GL_ERROR(glGetQueryObjectuiv(mPrimitivesDrawnQuery, GL_QUERY_RESULT, &primitivesWritten)); mVertexData->vertexCount = primitivesWritten * getVertexCountPerPrimitive(mOperationType); // Switch the vertex binding. mVertexData->vertexBufferBinding->unsetAllBindings(); mVertexData->vertexBufferBinding->setBinding(0, mVertexBuffers[mTargetBufferIndex]); mTargetBufferIndex = mTargetBufferIndex == 0 ? 1 : 0; // Enable rasterization. OGRE_CHECK_GL_ERROR(glDisable(GL_RASTERIZER_DISCARD)); // Clear the reset flag. mResetRequested = false; }
//--------------------------------------------------------------------- void GLSLESProgramManagerCommon::extractUniforms(GLuint programObject, const GpuConstantDefinitionMap* vertexConstantDefs, const GpuConstantDefinitionMap* fragmentConstantDefs, GLUniformReferenceList& list, GLUniformBufferList& sharedList) { // Scan through the active uniforms and add them to the reference list GLint uniformCount = 0; GLint maxLength = 0; char* uniformName = NULL; #define uniformLength 200 OGRE_CHECK_GL_ERROR(glGetProgramiv(programObject, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLength)); // If the max length of active uniforms is 0, then there are 0 active. // There won't be any to extract so we can return. if(maxLength == 0) return; uniformName = new char[maxLength + 1]; GLUniformReference newGLUniformReference; // Get the number of active uniforms OGRE_CHECK_GL_ERROR(glGetProgramiv(programObject, GL_ACTIVE_UNIFORMS, &uniformCount)); // Loop over each of the active uniforms, and add them to the reference container // only do this for user defined uniforms, ignore built in gl state uniforms for (GLuint index = 0; index < (GLuint)uniformCount; index++) { GLint arraySize = 0; GLenum glType = GL_NONE; OGRE_CHECK_GL_ERROR(glGetActiveUniform(programObject, index, maxLength, NULL, &arraySize, &glType, uniformName)); // Don't add built in uniforms newGLUniformReference.mLocation = glGetUniformLocation(programObject, uniformName); if (newGLUniformReference.mLocation >= 0) { // User defined uniform found, add it to the reference list String paramName = String( uniformName ); // If the uniform name has a "[" in it then its an array element uniform. String::size_type arrayStart = paramName.find("["); if (arrayStart != String::npos) { // If not the first array element then skip it and continue to the next uniform if (paramName.compare(arrayStart, paramName.size() - 1, "[0]") != 0) continue; paramName = paramName.substr(0, arrayStart); } // Find out which params object this comes from bool foundSource = completeParamSource(paramName, vertexConstantDefs, fragmentConstantDefs, newGLUniformReference); // Only add this parameter if we found the source if (foundSource) { assert(size_t (arraySize) == newGLUniformReference.mConstantDef->arraySize && "GL doesn't agree with our array size!"); list.push_back(newGLUniformReference); } // Don't bother adding individual array params, they will be // picked up in the 'parent' parameter can copied all at once // anyway, individual indexes are only needed for lookup from // user params } // end if } // end for if( uniformName != NULL ) { delete[] uniformName; } #if OGRE_NO_GLES3_SUPPORT == 0 // Now deal with uniform blocks GLint blockCount = 0; OGRE_CHECK_GL_ERROR(glGetProgramiv(programObject, GL_ACTIVE_UNIFORM_BLOCKS, &blockCount)); for (int index = 0; index < blockCount; index++) { OGRE_CHECK_GL_ERROR(glGetActiveUniformBlockName(programObject, index, uniformLength, NULL, uniformName)); GpuSharedParametersPtr blockSharedParams = GpuProgramManager::getSingleton().getSharedParameters(uniformName); GLint blockSize, blockBinding; OGRE_CHECK_GL_ERROR(glGetActiveUniformBlockiv(programObject, index, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize)); OGRE_CHECK_GL_ERROR(glGetActiveUniformBlockiv(programObject, index, GL_UNIFORM_BLOCK_BINDING, &blockBinding)); HardwareUniformBufferSharedPtr newUniformBuffer = HardwareBufferManager::getSingleton().createUniformBuffer(blockSize, HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE, false, uniformName); GLES2HardwareUniformBuffer* hwGlBuffer = static_cast<GLES2HardwareUniformBuffer*>(newUniformBuffer.get()); hwGlBuffer->setGLBufferBinding(blockBinding); sharedList.push_back(newUniformBuffer); } #endif }
void GL3PlusRenderBuffer::bindToFramebuffer(uint32 attachment, uint32 zoffset) { assert(zoffset < mDepth); OGRE_CHECK_GL_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, mRenderbufferID)); }
GL3PlusRenderBuffer::~GL3PlusRenderBuffer() { // Generate renderbuffer OGRE_CHECK_GL_ERROR(glDeleteRenderbuffers(1, &mRenderbufferID)); }
void GL3PlusTexture::freeInternalResourcesImpl() { mSurfaceList.clear(); OGRE_CHECK_GL_ERROR(glDeleteTextures(1, &mTextureID)); }
void GLES2FrameBufferObject::initialise() { // Release depth and stencil, if they were bound mManager->releaseRenderBuffer(mDepth); mManager->releaseRenderBuffer(mStencil); mManager->releaseRenderBuffer(mMultisampleColourBuffer); /// First buffer must be bound if(!mColour[0].buffer) { OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Attachment 0 must have surface attached", "GLES2FrameBufferObject::initialise"); } // If we're doing multisampling, then we need another FBO which contains a // renderbuffer which is set up to multisample, and we'll blit it to the final // FBO afterwards to perform the multisample resolve. In that case, the // mMultisampleFB is bound during rendering and is the one with a depth/stencil ushort maxSupportedMRTs = Root::getSingleton().getRenderSystem()->getCapabilities()->getNumMultiRenderTargets(); /// Store basic stats size_t width = mColour[0].buffer->getWidth(); size_t height = mColour[0].buffer->getHeight(); GLuint format = mColour[0].buffer->getGLFormat(); // Bind simple buffer to add colour attachments OGRE_CHECK_GL_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, mFB)); /// Bind all attachment points to frame buffer for(size_t x=0; x<maxSupportedMRTs; ++x) { if(mColour[x].buffer) { if(mColour[x].buffer->getWidth() != width || mColour[x].buffer->getHeight() != height) { StringStream ss; ss << "Attachment " << x << " has incompatible size "; ss << mColour[x].buffer->getWidth() << "x" << mColour[x].buffer->getHeight(); ss << ". It must be of the same as the size of surface 0, "; ss << width << "x" << height; ss << "."; OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, ss.str(), "GLES2FrameBufferObject::initialise"); } if(mColour[x].buffer->getGLFormat() != format) { StringStream ss; ss << "Attachment " << x << " has incompatible format."; OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, ss.str(), "GLES2FrameBufferObject::initialise"); } mColour[x].buffer->bindToFramebuffer(GL_COLOR_ATTACHMENT0+x, mColour[x].zoffset); } else { // Detach OGRE_CHECK_GL_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+x, GL_RENDERBUFFER, 0)); } } // Now deal with depth / stencil if (mMultisampleFB) { // Bind multisample buffer OGRE_CHECK_GL_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, mMultisampleFB)); // Create AA render buffer (colour) // note, this can be shared too because we blit it to the final FBO // right after the render is finished mMultisampleColourBuffer = mManager->requestRenderBuffer(format, width, height, mNumSamples); // Attach it, because we won't be attaching below and non-multisample has // actually been attached to other FBO mMultisampleColourBuffer.buffer->bindToFramebuffer(GL_COLOR_ATTACHMENT0, mMultisampleColourBuffer.zoffset); // depth & stencil will be dealt with below } /// Depth buffer is not handled here anymore. /// See GLES2FrameBufferObject::attachDepthBuffer() & RenderSystem::setDepthBufferFor() GLenum bufs[OGRE_MAX_MULTIPLE_RENDER_TARGETS]; GLsizei n=0; for(size_t x=0; x<OGRE_MAX_MULTIPLE_RENDER_TARGETS; ++x) { // Fill attached colour buffers if(mColour[x].buffer) { bufs[x] = GL_COLOR_ATTACHMENT0 + x; // Keep highest used buffer + 1 n = x+1; } else { bufs[x] = GL_NONE; } } #if OGRE_NO_GLES3_SUPPORT == 0 // Drawbuffer extension supported, use it OGRE_CHECK_GL_ERROR(glDrawBuffers(n, bufs)); if (mMultisampleFB) { // we need a read buffer because we'll be blitting to mFB OGRE_CHECK_GL_ERROR(glReadBuffer(bufs[0])); } else { // No read buffer, by default, if we want to read anyway we must not forget to set this. OGRE_CHECK_GL_ERROR(glReadBuffer(GL_NONE)); } #endif /// Check status GLuint status; OGRE_CHECK_GL_ERROR(status = glCheckFramebufferStatus(GL_FRAMEBUFFER)); /// Bind main buffer #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE_IOS // The screen buffer is 1 on iOS OGRE_CHECK_GL_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, 1)); #else OGRE_CHECK_GL_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, 0)); #endif switch(status) { case GL_FRAMEBUFFER_COMPLETE: // All is good break; case GL_FRAMEBUFFER_UNSUPPORTED: OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "All framebuffer formats with this texture internal format unsupported", "GLES2FrameBufferObject::initialise"); default: OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Framebuffer incomplete or other FBO status error", "GLES2FrameBufferObject::initialise"); } }
void* GLES2HardwareVertexBuffer::lockImpl(size_t offset, size_t length, LockOptions options) { if (mIsLocked) { OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Invalid attempt to lock an index buffer that has already been locked", "GLES2HardwareVertexBuffer::lock"); } GLenum access = 0; // Use glMapBuffer static_cast<GLES2HardwareBufferManagerBase*>(mMgr)->getStateCacheManager()->bindGLBuffer(GL_ARRAY_BUFFER, mBufferId); void* pBuffer; #if OGRE_NO_GLES3_SUPPORT == 0 || defined(GL_EXT_map_buffer_range) if (mUsage & HBU_WRITE_ONLY) { access = GL_MAP_WRITE_BIT_EXT; access |= GL_MAP_FLUSH_EXPLICIT_BIT_EXT; if(options == HBL_DISCARD || options == HBL_NO_OVERWRITE) { // Discard the buffer access |= GL_MAP_INVALIDATE_RANGE_BIT_EXT; } access |= GL_MAP_UNSYNCHRONIZED_BIT_EXT; } else if (options == HBL_READ_ONLY) access = GL_MAP_READ_BIT_EXT; else access = GL_MAP_READ_BIT_EXT | GL_MAP_WRITE_BIT_EXT; OGRE_CHECK_GL_ERROR(pBuffer = glMapBufferRangeEXT(GL_ARRAY_BUFFER, offset, length, access)); #else if(options == HBL_DISCARD || options == HBL_NO_OVERWRITE) { // Discard the buffer OGRE_CHECK_GL_ERROR(glBufferData(GL_ARRAY_BUFFER, mSizeInBytes, NULL, GLES2HardwareBufferManager::getGLUsage(mUsage))); } if (mUsage & HBU_WRITE_ONLY) access = GL_WRITE_ONLY_OES; OGRE_CHECK_GL_ERROR(pBuffer = glMapBufferOES(GL_ARRAY_BUFFER, access)); #endif if(pBuffer == 0) { OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Vertex Buffer: Out of memory", "GLES2HardwareVertexBuffer::lock"); } // return offsetted void* retPtr = static_cast<void*>( static_cast<unsigned char*>(pBuffer) + offset); mIsLocked = true; return retPtr; }
//----------------------------------------------------------------------------- void GLES2TextureBuffer::download(const PixelBox &data) { if(data.getWidth() != getWidth() || data.getHeight() != getHeight() || data.getDepth() != getDepth()) OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "only download of entire buffer is supported by GL ES", "GLES2TextureBuffer::download"); if(PixelUtil::isCompressed(data.format)) { OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Compressed images cannot be downloaded by GL ES", "GLES2TextureBuffer::download"); } GLenum texBinding = GL_NONE; switch (mTarget) { case GL_TEXTURE_2D: texBinding = GL_TEXTURE_BINDING_2D; break; case GL_TEXTURE_CUBE_MAP: texBinding = GL_TEXTURE_BINDING_CUBE_MAP; break; #if OGRE_NO_GLES3_SUPPORT == 0 case GL_TEXTURE_3D: texBinding = GL_TEXTURE_BINDING_3D; break; #endif default: return; } #if OGRE_NO_GLES3_SUPPORT == 0 if(data.getWidth() != data.rowPitch) OGRE_CHECK_GL_ERROR(glPixelStorei(GL_PACK_ROW_LENGTH, data.rowPitch)); if(data.getHeight()*data.getWidth() != data.slicePitch) OGRE_CHECK_GL_ERROR(glPixelStorei(GL_PACK_IMAGE_HEIGHT, (data.slicePitch/data.getWidth()))); if(data.left > 0 || data.top > 0 || data.front > 0) OGRE_CHECK_GL_ERROR(glPixelStorei(GL_PACK_SKIP_PIXELS, data.left + data.rowPitch * data.top + data.slicePitch * data.front)); #endif if((data.getWidth()*PixelUtil::getNumElemBytes(data.format)) & 3) { // Standard alignment of 4 is not right OGRE_CHECK_GL_ERROR(glPixelStorei(GL_PACK_ALIGNMENT, 1)); } GLint currentFBO = 0; GLuint tempFBO = 0; OGRE_CHECK_GL_ERROR(glGetIntegerv(GL_FRAMEBUFFER_BINDING, ¤tFBO)); OGRE_CHECK_GL_ERROR(glGenFramebuffers(1, &tempFBO)); OGRE_CHECK_GL_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, tempFBO)); switch (mTarget) { case GL_TEXTURE_2D: case GL_TEXTURE_CUBE_MAP: OGRE_CHECK_GL_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextureID, 0)); OGRE_CHECK_GL_ERROR(glCheckFramebufferStatus(GL_FRAMEBUFFER)); OGRE_CHECK_GL_ERROR(glReadPixels(0, 0, data.getWidth(), data.getHeight(), GLES2PixelUtil::getGLOriginFormat(data.format), GLES2PixelUtil::getGLOriginDataType(data.format), data.data)); break; #if OGRE_NO_GLES3_SUPPORT == 0 case GL_TEXTURE_3D: for (int i = 0; i < desc.depth; i++) { OGRE_CHECK_GL_ERROR(glFramebufferTexture3D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_3D, mTextureID, mLevel, i)); OGRE_CHECK_GL_ERROR(glReadPixels(0, 0, data.getWidth(), data.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, pixels + 4 * i * data.getWidth() * data.getHeight())); } break; #endif } // Restore defaults #if OGRE_NO_GLES3_SUPPORT == 0 OGRE_CHECK_GL_ERROR(glPixelStorei(GL_PACK_ROW_LENGTH, 0)); OGRE_CHECK_GL_ERROR(glPixelStorei(GL_PACK_IMAGE_HEIGHT, 0)); OGRE_CHECK_GL_ERROR(glPixelStorei(GL_PACK_SKIP_PIXELS, 0)); #endif OGRE_CHECK_GL_ERROR(glPixelStorei(GL_PACK_ALIGNMENT, 4)); OGRE_CHECK_GL_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, currentFBO)); OGRE_CHECK_GL_ERROR(glDeleteFramebuffers(1, &tempFBO)); }